Home
Name Modified Size InfoDownloads / Week
Binaries < 9 hours ago
Manuals < 9 hours ago
Sources < 9 hours ago
Packages 2024-04-13
Lua for OS2 and DOS 2023-05-18
README.TXT < 9 hours ago 640.5 kB
Totals: 6 Items   640.5 kB 148
                                            agena >>
                              `The Power of Procedural Programming`

3.13.4 Cade, April 19, 2024

- `csc`, `sec` and `cot` returned `undefined` in the epsilon neighbourhood of the poles. This has been fixed. The functions now return finite values except for the poles themselves. `csc` and `sec` have also become 15 percent faster.

- The accuracy of `cot` with large negative and positive real arguments has been significantly improved by a factor of 3.

- On some platforms, `cot` and `coth` could crash in the complex domain. This has been fixed.

- `arcsech` has been tweaked in the complex domain.

- New `stack.cotd`, `stack.cscd` and `stack.secd` compute the cotangent, cosecant and secant of the top element of the current numeric stack, and new `stack.erfd` computes the error function.


3.13.3 Cade, April 17, 2024

- Besides a sequence, `ops` now accepts a table or register with index positions. Example:

  > f := << () -> 10, 20, 30, 40 >>

  > ops([2, 4], f()):
  20      40

- `member` can now search sets and does not return an index in case of success, but just `true` and `null` otherwise.

- `augment` has become ten to 20 percent faster with two to five arguments.

- Corrected error messages of `reverse`.

- `implies` now returns an error if given no numbers or booleans.

- Cleansed the code to prevent compiler warnings on OS/2 and Mac OS X.

- Extended the regression test cases.

- This release has been Valgrind-checked on x86 and AMD64 Linux to ensure there are no internal errors or memory leaks.


3.13.2 Cade, April 13, 2024

- Added the new `cuckoo` package which implements a Cuckoo filter for string dictionaries, an alternative to a Bloom filter. Both are space-efficient data structures designed to answer approximate membership queries:

  - Is a string _definitely not_ part of a dictionary ?
  - Is a string _likely_ to be part of a dictionary ?

  Contrary to the `bloom` package, `cuckoo` allows to delete entries from the filter and is 10 % faster when creating new filters and 15 % faster when querying them. Example:

  > import cuckoo;

  > c := cuckoo.new(13500);    # max. of 13,500 hash entries

  > cuckoo.include(c, 'abc');  # insert an entry

  > cuckoo.find(c, 'abc'):     # find an entry
  true

  > cuckoo.remove(c, 'abc');   # remove the entry

  > cuckoo.find(c, 'abc'):     # find the entry removed
  false

  The package is based on the C `libcuckoofilter` library created by Jonah H. Harris and published on Github.

- `bloom.include` and `bloom.find` now accept a string instead of a hash value for the second argument. If given a string, the functions internally compute its MurmurHash3 hash value and then proceed as already implemented. In this mode, the functions are around 15 percent faster than before.

- New `skycrane.obcount` takes a table, sequence or register and counts the number of occurrences of each of its values.

  Example:

  > import skycrane

  1 is included 4 times, 2 is included twice, 3 only once, etc.:

  > skycrane.obcount([1, 1, 1, 2, 2, 1, 3, 8, 9, 8, 9]):
  [1 ~ 4, 2 ~ 2, 3 ~ 1, 8 ~ 2, 9 ~ 2]

- Some underlying administrative data structure, sorting and hashing functions have been tweaked a little bit by forced inlining. Also tuned auxiliary 64-bit trigonometric, logarithmic and error functions this way plus ZX Spectrum math and 80-bit floating point functions.

- This release has been Valgrind-checked on x86 and AMD64 Linux to ensure there are no internal errors or memory leaks.


3.13.1 Cade, April 11, 2024

- New `calc.harmonic` computes the harmonic function calc.Psi(x + 1) + EulerGamma for both real and complex arguments.

- New `math.hgm` computes the harmonic-geometric mean.

- `math.agm` returned a real result on some platforms when given `undefined` as one of its arguments, or both. This has been fixed.

- `bags.minclude` can now insert elements from a table or register into a bag.

- In non-destructive mode, `duplicates` has become around 15 percent faster.

- `skycrane.sorted` and thus the `bags` pretty-printer did not work. This has been fixed.

- Adapted the sources to prevent compiler warnings on Raspberry Pi OS/Bookworm.


3.13.0 Cade Library Update 1, April 07, 2024

- Tweaked `pipeline` in multivariate mode by around 15 percent.

- Added two sheets on printing values to the screen to the Agena Crash Course.

- Added the new Chapter 3.19 `Printing Values` to the Primer and Reference and extended Chapter 5.2.12 `Conditional for Loops`.

- Functional-style programming with Agena is explained in the new Chapter 6.32 of the Primer and Reference.

- You will find the update in the Binaries/Agena 3.13.0 Sourceforge folder, file `agena-3.13.0-update1.zip`. Download it and check the instructions on how to install this library update on all operating systems, see `libupdate.readme` file at the root of the ZIP archive. The installation process is quite easy and straightforward.


3.13.0 Cade, April 02, 2024

- Introduced the C-style conditional `for` loop. It initialises a new local control variable, checks a `while` or `until` condition and then executes the loop body. When the loop exits, the last value of the loop control variable is available in the block that is surrounding the loop.

  Note that you explicitly have to change the loop control variable in the loop block or you might go into an infinite loop otherwise. Also note if you change the loop control variable by a fractional value, the `while` or `until` condition might never be met due to accumulating round-off errors.

  The `redo` and `relaunch` statements are not accepted within the loop body, while `skip` and `break` are.

  Examples:

  > for i := 1 until i = 4 do print(i); i +:= 1 od
  1
  2
  3

  > i:
  4

  > for i := 1 while i <= 3 do print(i); i++ od
  1
  2
  3

  > i:
  4

  Instead of the `while` keyword, you might use a comma instead:

  > for i := 1, i <= 3 do print(i++) od
  1
  2
  3

- `calc.sections` has been precautiously hardened against stack corruption.

- This release has been named after the place of Cade in St. Martin Parish, Louisiana, and has been Valgrind-checked on x86 and AMD64 Linux to ensure there are no internal errors or memory leaks.

- From now on, due to lack of public interest there will no longer be Raspberry Pi, Solaris, Red Hat and rase distributions available in the Sourceforge Download section. If you need one, request it via the Agena Sourceforge Forum, please.


3.12.1 Berwick, April 01, 2024

- The new function `calc.fmaxbr` estimates the maximum location of a univariate or multivariate function over a given range, combining Golden section search with parabolic interpolation. Example:

  > calc.fmaxbr(<< x -> -x^2 >>, -0.1, 0.1):
  0

- New `calc.fmaxgs` is similar to `calc.fmaxbr` but uses Golden section search only.

- `calc.maximum` has become 40 percent faster.

- `calc.maximum` and `calc.minimum` now check whether their results really exist by checking whether the input function is defined at the calculated points.

- `calc.arclen` and `calc.sinuosity` now accept multivariate functions. See the Primer and Reference on how to pass the second, third, etc. argument in the respective calls.

  With univariate functions, as before, you do not have to change the code if - but only if - you have not been passing optional arguments as the defaults did not change. Example:

  > calc.arclen(<< x, a -> sin(x + a) >>, 0, 1, 1, eps=1e-5):
  1.0402463016211 4.1593273947496e-005

- Added further calculus cases to the testsuite.


3.12.0 Berwick, March 31, 2024

- The new function `calc.eps` computes a mathematical epsilon value that takes into account the magnitude of the function value at a given point.

- `calc.fminbr`, `calc.fmings`, `calc.simaptive`, `calc.gtrap`, `calc.sections`, `calc.regulafalsi`, `calc.zeros`,  `calc.zeroin`, `calc.variance`, `calc.minimum` and `calc.maximum` now accept multivariate functions. See the Primer and Reference on how to pass the second, third, etc. arguments in the respective calls.

  With univariate functions, as before, you do not have to change the code if - but only if - you have not been passing optional arguments as the defaults did not change.

  If you want to pass options, you now have to give them in the explicit `optionname = value` notation. Example:

  > calc.regulafalsi(<< x, a -> sin(x + a) >>, 0, 2, Pi/2, eps = DoubleEps):  # root of cosine, actually, due to a = Pi/2 shift.
  1.5707963267949

- The `checkrange` option to `calc.regulafalsi` has been removed. Now, the root is always being checked whether it is in the interval of interest. This was the default behaviour before, anyway.

- `calc.variance` can no longer optionally return absolute values. All results will be given per unit on the abscissa, which was the default mode before. Multiply the return by `round(left border) - round(round border)` to get an absolute value.

- `calc.gauleg`, `calc.intcc`, `calc.intde`, `calc.intdei` and `calc.intdeo` now require options to be explicitely given in `optionname = value` notation. See the Primer and Reference on how to pass the second, third, etc. arguments in the respective calls. If you have been passing options to these functions, you have to change the code.

  Example:

  > calc.intdeo(<< x, a -> sin(x)/(x + a) >>, 1, 0, omega = 1, eps = Eps):
  0.62471325639277        8.3556975456747e-008

- Improved error messages of `calc.diff`, `calc.xpdiff`, `calc.limit`, `calc.iscont` and `calc.eulerdiff`.

- `calc.arclen` has been tuned by 33 percent.

- `calc.differ` has become 25 percent faster. It will also no longer throw exceptions with multivariate functions.

- `calc.sections` often returned empty sequences indicating no roots, causing problems with `calc.zeros`, as well. This has been fixed.

- `calc.zeroin` often did not return roots, also adversely affecting `calc.zeros`. This has been fixed.

- `checkoptions` incorrectly validated the `posint`, `negint` and `nonnegint` pseudo-types. This has been fixed.

- Extended the calculus test cases.

- This release has been named after the town of Berwick in St. Mary Parish, Louisiana, and has been Valgrind-checked on x86 and AMD64 Linux to ensure there are no internal errors or memory leaks.


3.11.5 Converse, March 24, 2024

Tuned, extended and fixed calculus functions that compute integrals:

- `calc.intdei` and `calc.intdeo` now remember the last epsilon setting given by the user and run 40 % faster with succeeding calls done with the same epsilon value. This also benefits the wrapper function `calc.integ` (see below).

- `calc.gauleg`, `calc.intde`, calc.intdei`, `calc.intdeo` and `calc.intcc` now accept multivariate functions. See the Primer and Reference on how to pass the second, third, etc. arguments in the respective calls. With univariate functions, as before, you do not have to change the code.

- `calc.integ` has been rewritten to support multivariate functions. Optional epsilon, omega and sample values must now be given as explicit options, so you may have to adapt your code. Example:

  > calc.integ(<< x, a -> x + a >>, 1, 2, 0, eps=hEps, omega=1, samples=100):
  1.5     2.999999997239e-015

- If the third argument to `calc.intdeo` was zero, the interpreter could crash on some platforms. This has been fixed.

- If the number of sample points is zero, `calc.gauleg` now automatically sets it to 20 points internally. This prevents segmentation faults on some platforms and also false results of exactly zero.

- If you pass zero as an epsilon value to `calc.intde`, calc.intdei`, `calc.intdeo` and `calc.intcc`, then it is automatically reset to the default setting 1e-15 to avert any infinite loops.

- This release has been Valgrind-checked on x86 and AMD64 Linux to ensure there are no internal errors or memory leaks.


3.11.4 Converse, March 20, 2024

- The `addup` and `mulup` operators can now intuitively approximate series and products and are easier to use and consume much less memory than the `foreach` operator or the other flavours of `addup` and `mulup`. Just pass the function representing the series or product plus the start and stop value and optionally a step size. Multivariate functions are supported. `addup` uses Kahan-Babuska summation on all platforms to keep round-off errors as small as possible and `mulup` internally uses 80-bit precision on Intel/AMD platforms to do the same.

  Example 1: Compute the sum

                                50
                               -----
                                \     1
                                 )   ----  ~ ln(2)
                                /     k
                               ----- 2  k
                               k = 1

  > addup(<< k -> recip(2**k*k) >>, 1, 50):
  0.69314718055995

  Example 2: Compute the product

                              50
                           --------'
                          '  |  |    /     1  \   51
                             |  |    |1 - ----| = --- ~ 0.5
                             |  |    |      2 |   100
                             |  |    \     k  /
                            k = 2

  > mulup(<< k -> (1 - recip square k) >>, 2, 50):
  0.51

  The operators approximate series and products more than twice as fast as numeric for loops combined with `math.kbadd` for Kahan-Babuska summation (series) and `long` 80-bit precision package functions (products) to minimise round-off errors.

- `calc.fprod` now accepts multivariate functions.

- With fractional step sizes, the `foreach` operator could go into an infinite loop if function calls did not result into numbers. This has been fixed.

- This release has been Valgrind-checked on x86 and AMD64 Linux to ensure there are no internal errors or memory leaks.


3.11.3 Converse, March 16, 2024

- `units.cm` did not correctly convert Russian handspans. This has been fixed. Plus, the function now accepts the following options:

  - 'piad', the argument is taken to be in Russian handspans (piads) with 1 piad = 17.8 cm.
  - 'span', the argument is taken to be in US spans with 1 span = 22.86005 cm.
  - 'hand', the argument is taken to be in US hands with 1 hand = 4 inches = 10.16002 cm.
  - 'link', the argument is taken to be in US links with 1 link = 2/3 feet = 20.11684 cm.

  Also changed conversion factor from 1 inch = 2.54 cm to 1 inch = 2.54000508 cm. Example:

  > units.cm(1, 'piad'):
  17.8

- `units.inch` now accepts the following options:

  - 'piad', the argument is taken to be in Russian handspans (piads) with 1 piad = 7.01 inches.
  - 'span', the argument is taken to be in US spans with 1 span = 9 inches.
  - 'hand', the argument is taken to be in US hands with 1 hand = 4 inches.
  - 'link', the argument is taken to be in US links with 1 link = 7.92 inches.

  Also changed default conversion factor from 1 inch = 2.54 cm to 1 inch = 2.54000508 cm. Example:

  > units.inch(2, 'span'):
  18

- Changed conversion factors in `units.km` and `units.mile` from 1 standard mile = 1.609344 km to 1 std. mile = 1.6093440006 km and from 1 nautical mile = 1.852 km to 1 nmi = 1.852216 km.


3.11.2 Converse, March 13, 2024

- `addup` can now sum up only those elements in a structure that satisfy a given condition:

  > addup(<< x -> even x >>, [1, 2, 3, 4, 5, 6]):  # add only even numbers
  12

- You can now pass a function f as the first argument and a structure as the second argument to `mulup`: if f returns a number then f is applied on each value in the structure before multiplication. If f returns the Boolean value `true`, then the values in the structure that satisfy the given condition are multiplied, only.

  > mulup(<< x -> sqrt x >>, [1, 2, 3, 4, 5]):  # apply square root on each element and multiply, equals 5! = fact(5)
  10.954451150103

  > square ans:  # `convert back`
  120

  > mulup(<< x -> even x >>, [1, 2, 3, 4, 5]):  # multiply even numbers only
  8

- New `units.cm` converts from inches to centimetres; example:

  > units.cm(1):
  2.54

  When given any second argument, then the argument is taken to be in Russian handspans with 1 piad = 17.8 cm.

- New `units.inch` converts from centimetres to inches; example:

  > units.inch(1):
  0.39370078740157

- New `units.ounce` converts from grams to ounces.

- New `units.gram` converts from ounces to grams.

- New `units.floz` converts litres to US or imperial fluid ounces.

- New `units.litre` converts from ounces or (US liquid, US dry, British imperial) gallons to litres.

- New `units.gallon` converts from litres to (US liquid, US dry or British imperial) gallons. Examples:

  > units.litre(1, 'dry gallon'):
  4.40488377086

  > units.gallon(ans, 'dry gallon'):  # convert back
  1

- This release has been Valgrind-checked on x86 and AMD64 Linux to ensure there are no internal errors or memory leaks.


3.11.1 Converse, March 06, 2024

- New `math.cscd` and `math.secd` take an argument in degrees and compute the cosecant and secant, respectively.

- Introduced the new `units` package which converts between physical units. It is some sort of a quick-and-dirty solution in the sense that it spares you a lot of typing and to get results as fast as possible:

  - `units.celsius` takes a value in Fahrenheit and converts it to degrees Celsius. Example:

    > units.celsius(77):  # annual high temperature in New Orleans, LA: 77 deg F = 25 deg C
    25

  - `units.fahren` takes a value in Celsius and converts it to degrees Fahrenheit.

    > units.fahren(26+2/3):  # annual high temperature in San Antonio, TX: 26 2/3 deg C = 80 deg F
    80

  - `units.mile` takes a value in kilometres and converts it to statute miles. Nautical miles are supported by passing any second argument.

  - `units.km` takes a value in statute miles and converts it to kilometres. Nautical miles for the input are supported by passing any second argument.

  - `units.foot` takes a value in metres and converts it to International feet. US, UK, Indian and historical Rhineland feet are supported by providing the option 'US', 'UK', 'India' or 'Rhineland', respectively. Likewise, new `utils.meter` takes a value in feet and converts it to metres, with the beforementioned options supported, as well.

  - `units.yard` converts from metres to yards.

- By passing the new fifth argument `false` to `calc.regulafalsi`, you can switch off the check on whether the computed result is within the given borders. In this case the function does not return `null` but the iterated value. The function now in general also automatically stops computation if it took more than 250 iterations, so it cannot go into an infinite loop any longer.

- `math.epsilon` returned exactly zero with methods 0 and 1 when its argument was zero. This has been fixed, and now `ulp` will be returned, see the Primer and Reference for details. Thus, `calc.differ` no longer issues an error when differentiating a function at the origin.


3.11.0 Converse, March 03, 2024

- New `linalg.eigen` returns both the eigenvectors and the eigenvalues of a symmetric matrix.

- New `linalg.islower` checks whether a square matrix is in lower triangular form, that is all the entries above the main diagonal are zero.

- New `linalg.isupper` checks whether a square matrix is in upper triangular form, that is all the entries below the main diagonal are zero.

- Removed a memory leak from `linalg.eigenval` that occurred when internal memory allocation failed.

- New `math.sind`, `math.cosd`, `math.cotd` and `math.tand` take an argument in degrees and compute the sine, cosine, cotangent and tangent, respectively, in radians.

- `math.agm` now accepts complex numbers.

- New `math.tocomplex` converts a number x into the complex number x + I*0. When given a complex number, it is simply returned.

- New `calc.bessel0` and `calc.bessel1` return the modified Bessel function of order zero and one, respectively. Both functions can also exponentially scale their results.

- Documented `fractals.esctime` with which you can compute (and draw) escape-time fractals. See file `lib/fractals.agn` for a lot of examples.

- The DOS edition now includes the `fractals` package.

- The C API function `agn_ccall` has been extended to accept functions that return a number instead of a complex number.

- This release has been named after the village of Converse in Sabine Parish, Louisiana, close to Texas and has been Valgrind-checked on x86 and AMD64 Linux to ensure there are no internal errors or memory leaks.


3.10.7 Vinton, February 28, 2024

- New `math.agm` approximates the arithmetic-geometric mean of two real numbers.

- New `calc.elliptic1` computes the complete and incomplete elliptic integral of the first kind.

- New `calc.elliptic2` computes the complete and incomplete elliptic integral of the second kind.

- New `calc.jacobian` computes the Jacobian elliptic functions sn, cn and dn.

- The `skipfaulty` option to `io.lines` has been extended to deal with empty lines, that is, if a line read in is of zero length, it will be ignored and the next line will be read immediately. This also works with files ending in an empty line.

- This release has been Valgrind-checked on x86 and AMD64 Linux to ensure there are no internal errors or memory leaks.


3.10.6 Vinton, February 26, 2024

- New `linalg.eigenval` computes the eigenvalues of a square matrix. Example:

  > linalg.eigenval( linalg.matrix([1, 2, 4], [3, 7, 2], [5, 6, 9]) ):
  [-0.89460254283572, 13.747889058727, 4.1467134841089]

- New `calc.hyp1f1` computes the confluent hypergeometric function 1F1 aka Kummer's function of the first kind. Example:

  > calc.hyp1f1(1, 2, 0.9):
  1.6217812346188

- New `calc.hyp2f1` computes the Gaussian or ordinary hypergeometric function 2F1, for example:

  > calc.hyp2f1(1, 2, 3, 0.9):
  3.4631730691211

- On Intel/AMD platforms, the accuracy of `calc.cheby` deteriorated in Agena 3.10.5. This has been fixed.


3.10.5 Vinton, February 21, 2024

- The new `!!` operator takes a magnitude and an argument and creates a complex number in Cartesian form. It is equal to the `cartesian` function but 25 percent faster. Example:

  > 2 !! 3:
  -1.9799849932009+0.28224001611973*I

- The new functions `os.isarm32` and `os.isarm64` check whether Agena is running on Raspberry Pi OS 32-bit or 64-bit.

- Reduced memory consumption of `calc.cheby` and `calc.chebycoeffs` on all supported platforms by one kByte.

- The accuracy of `calc.cheby` on 32-bit and 64-bit Raspberry Pi has been slightly improved. You may also change its fourth argument, the order of the interpolant, to another value to get better accuracy. Remember that on ARM CPUs, the function can only calculate with 64-bit presision, and not 80-bit.

- Source file `agnhlps.c` did not compile on Raspberry Pi 64-bit. This has been fixed.

- The Primer and Reference and the Quick Reference have been improved.

- This release has been Valgrind-checked on x86 and AMD64 Linux to ensure there are no internal errors or memory leaks.


3.10.4 Vinton, February 11, 2024

- Added the following new options to `io.lines`:

  - `skipfaulty`: when set to `true`, all lines with incorrect field numbers are skipped and the function will not return `fail`; default is: `false`.

  - `header`: when given, the very first line in a file will be skipped, default is `false`.

  - `ignore`: applies a function on every line and if it evaluates to `true`, the line will be skipped.

  Example: Consider a CSV file with US ZIP codes which is set up like this:

  "Zip";"City";"State Id";"State";"Parish/County/Borough";"Latitude";"Longitude"
  "00601";"Adjuntas";"PR";"Puerto Rico";"Adjuntas";"18.1788";"-66.7516"
  [further lines]
  "70001";"Metairie";"LA";"Louisiana";"Jefferson Parish";"29.987138";"-90.169513"
  "70002";"Metairie";"LA";"Louisiana";"Jefferson Parish";"29.987138";"-90.169513"
  [further lines]

  To skip the file header, remove the wrapping double quotes and select some fields for entire Louisiana only, issue:

  > f := io.lines('uszips.csv', 1, 2, 5,
  >    header = true, unwrap = '"',
  >    ignore = << x -> '"LA"' notin x >>);

  > f():
  seq(70001, Metairie, Jefferson Parish)

  > f():
  seq(70002, Metairie, Jefferson Parish)

- `utils.readcsv`: besides accepting the existing `skipemptylines` option, the shorter name `skipempty` will now be accepted, as well.


3.10.3 Vinton, February 09, 2024

- When given two or more arguments, `io.lines` can now return lines split into their fields, ideal for processing CSV files and other table-style text files.

  To fetch the second and third field delimited by a comma and enclosed in double quotes from a line and to automatically convert strings representing numbers to Agena (complex) numbers, issue:

  > f := io.lines('onemillion.csv', 2, 3, delim=',', unwrap='"', convert=true);

  > f():
  seq(170, 123456789)

  > f():
  seq(170, 234567890)

  etc. If the file does not contain the given fields, the iterator just returns `fail` and when called subsequently, reads the next line, that is, it does not quit reading the file.

  To split all fields in a line, the following suffices:

  > f := io.lines('onemillion.csv', delim=',', unwrap='"', convert=true);

  > f():
  seq(9e9887c2-fd70-44cb-a0f2-1a4215b8fa82, 170, 123456789)

  > f():
  seq(495b7dd4-b4e9-405c-9ee2-b8e1010ee4c8, 170, 234567890)

- The error messages of `io.lines` have become more specific.

- The new `utils.encodeb32` and `utils.decodeb32` functions convert to and from Base-32 data.

- When called with the `bailout=false` option, `strings.fields` will return `fail` instead of an empty sequence in case of an error.

- `strings.fields` did not convert a string representing a complex number if it were contained in the very last field. This has been fixed.

- Removed yet another memory leak from `strings.fields` in case memory could not be allocated internally.

- Corrected the Primer and Reference.

- This release has been Valgrind-checked on x86 and AMD64 Linux to ensure there are no internal errors or memory leaks.


3.10.2 Vinton, February 03, 2024

- With structures containing numbers only, both `sort` and `sorted` have become at least four times faster when being called with the new 'number' option, by using Introsort or Heapsort, depending on the size. Note that when given, you cannot provide a sorting function as this mode supports sorting in ascending order only.

  As a by-product, `stats.freqd`, `skycrane.sorted` and `avl.indices` have become faster, as well.

- With the new `bailout=false` option, `strings.fields` no longer issues an error if a given field has not been found in the input string. Instead, the function in this case will return an empty sequence giving the programmer more flexibility to handle exceptions. By default, the function still issues an error if a field does not exist, so you do not have to change your code.

- Strings can now be printed in single quotes at the console by passing the new -q command-line switch or by setting

  > environ.kernel(enclose=true)

  in the Agena session.

  Likewise, the new -Q and -b command-line switches set strings in double quotes or in backquotes, respectively, which is equal to setting

  > environ.kernel(enclosedouble=true)

  or

  > environ.kernel(encloseback=true)

- The new function `tables.isall` checks whether all elements in a table are of a given type. Eligible types that the function accepts are 'number', 'integer' (numbers that are all integral), 'complex', 'string' and 'boolean'. With tables, sequences and registers, you can also query 'posint' (positive integers), 'positive' (positive numbers), 'nonnegint' (non-negative integers) and 'nonnegative' (non-negative numbers). The function is at least fifteen times faster than checking structures with the `satisfy` function. Examples:

  > tables.isall([1, 2, Pi], 'number'):
  true

  which is equal to:

  > tables.isall([1, 2, Pi], number):
  true

  > tables.isall([1, 2, 3], 'integer'):
  true

  > tables.isall([1, 2, 3], integer):
  true

  > satisfy(<< x -> x :: integer >>, [1, 2, 3]):
  true

  Likewise, `sequences.isall` is checking sequences, `registers.isall` is checking registers and `sets.isall` is checking sets. Numeric arrays with C doubles are being checked with new `numarray.isall`.

- Tweaked `tables.indices` and `tables.entries` by avoiding internal memory re-allocation. Also revised and cleaned up the underlying `intvec` C library that is used to collect integer indices.

- Removed a memory leak from `strings.fields` in case memory could not be allocated internally.

- In the C API, you can now also pass a positive stack index to `agn_seqsetinumber` and `agn_regsetinumber`.

- The new C API function `agn_setinumber` sets a number to a table array.

- This release has been Valgrind-checked on x86 and AMD64 Linux to ensure there are no internal errors or memory leaks.


3.10.1 Vinton Library Update 1, January 31, 2024

- Added 300 more languages and countries to the internal mapping table used by `skycrane.getlocales`, improving the results when given a Boolean option or a string. The table has also been externalised to reduce its memory imprint and can now be found in the new `data` folder of your Agena installation.

- `utils.readcsv` did not cope well with both the `flat` and `dictionary` options given, throwing exceptions instead. This has been fixed.

- You will find the update in the Binaries/Agena 3.10.1 Sourceforge folder, file `agena-3.10.1-update1.zip`. Download it and check the instructions on how to install this library update on all operating systems, see libupdate.readme file at the root of the ZIP archive. The installation process is quite easy and straightforward.


3.10.1 Vinton, January 30, 2024

- New `strings.jaro` computes either the Jaro-Winkler or Jaro similarity of two strings, returning a value between 0 and 1. Example:

  > strings.jaro('similarity', 'similariyt'):  # Jaro-Winkler
  0.98

  > strings.jaro('similarity', 'similariyt', false):  # Jaro
  0.96666666666667

- `strings.dleven` has been extended and computes the Damerau-Levenshtein similarity, a normalised value between 0 and 1, if given `true` as the third argument. Example:

  > strings.dleven('similarity', 'similariyt', true):
  0.94

- New `strings.ngrams` produces all the n-grams of a string.

- New `strings.obfusxor` obfuscates a string by XORing.

- `strings.strcoll` now accepts a third argument that determines the locale to be used for the comparison of two strings, just for the single call and without permanently changing the locale on the system. Examples:

  > strings.strcoll('aäüßou', 'aausou'):
  1

  > strings.strcoll('aäüßou', 'aausou', 'German'):
  -1

  On some platforms you may have to pass a combination of the ISO 639 language code and the ISO 3166 region code instead of the full language name, e.g.:

  > strings.strcoll('aäüßou', 'aausou', 'de_DE'):

- When called with a string, `skycrane.getlocales` now returns the full name of the language and country for a combination of the ISO 639 language code and the ISO 3166 region code. Examples:

  > skycrane.getlocales('he'):
  Hebrew

  > skycrane.getlocales('he_IL'):
  Hebrew (Israel)

  When called with any Boolean, then the function now determines whether the locales included in an internal mapping list (see file lib/skycrane.agn) are supported by the operating system, and returns the supported ones in a table.

  When called the very first time in a session, the function has become 13 times faster, by using internal tables with currently used language and country/region codes.

  Furthermore, when called subseqently again with the same argument, the function takes the result from its internal store, significantly speeding it up.

- New `hashes.superfast` computes the SuperFastHash of a string.

- New `hashes.ispell` computes the ISpell hash of a string.

- `hashes.bkdr` now accepts a fourth argument, the initial hash value which defaults to 0 for downward compatibility.

- For better portability of Lua code to Agena, added the Lua 5.4 functions `tables.concat`, `tables.pack` and `tables.unpack`:

  - `tables.concat` is similar to the `join` operator and concatenates all the strings and/or numbers in a table to a string.

  - `tables.pack` returns a new table with all arguments stored into keys 1, 2, etc. and with a field "n" with the total number of arguments.

  - `tables.unpack` is equal to `unpack`, but for tables only.

- This release has been Valgrind-checked on x86 and AMD64 Linux to ensure there are no internal errors or memory leaks.


3.10.0 Vinton, January 28, 2024

- Introduced the new `unless` keyword which can be used along with `skip`, `break` and `return`. It does the opposite of the `when` clause:

  - `break unless`: The loop will _not_ be left if the condition, evaluated to a boolean, results to `true`:

  > for i to 10 do
  >    break unless i < 4;
  >    print(i)
  > od
  1
  2
  3

  - `skip unless`: The rest of the loop will _not_ be skipped if the condition, evaluated to a boolean, results to `true`:

  > for i to 10 do
  >    skip unless i < 4;
  >    print(i)
  > od
  1
  2
  3

  - `return unless`: The code immediately returns if the given condition evaluates to `false` and can be combined with the `with` clause:

    > a := 0;

    > return unless a <> 0 with true;  # bail out if a is zero

  The idea has been taken from Perl.

- New `strings.bigrams` computes the bigrams of a string, either as substrings or encoded signed 4-byte integers.

  > strings.bigrams('abcd'):
  seq(ab, bc, cd)

  > strings.bigrams('abcd', true):
  seq(6357090, 6422627, 6488164)

- New `strings.dice` returns the Dice's coefficient of two strings.

- New `math.hamming` computes the Hamming distance of two integers considered as binary values, that is, as sequences of bits.

- Introduced new functions that count the number of elements in unions, intersections and differences of tables, sequences, registers and sets, without the overhead of creating these structures: They are roughly thrice as fast as first creating and then counting them:

  - tables.numunion,
  - tables.numintersect,
  - tables.numminus,
  - sets.numunion,
  - sets.numintersect,
  - sets.numminus,
  - sequences.numunion,
  - sequences.numintersect,
  - sequences.numminus,
  - registers.numunion,
  - registers.numintersect,
  - registers.numminus.

  Examples:

  > tables.numunion([1, 2, 3], [4, 5, 6, 10]):  # = size([1, 2, 3] union [4, 5, 6, 10])
  7

  > tables.numintersect([1, 2, 3], [3, 4, 5]):  # = size([1, 2, 3] intersect [3, 4, 5])
  1

  > tables.numminus([1, 2, 3], [1]):            # = size([1, 2, 3] minus [1])
  2

- `tables.ishash` has been tuned and computes in O(1) time instead of O(n).

- Tweaked `augment` a little bit.

- The new C API function `agn_in` checks whether an element is part of a structure. It optionally pushes the result onto the stack.

- The new C API function `agn_hasarraypart` checks whether at least one element has been assigned to the array part of a table, in O(1) time.

- The new C API function `agn_hashashpart` checks whether at least one element has been assigned to the hash part of a table, in O(1) time.

- The new C API function `agn_numintersect` counts the number of elements in the intersection of two structures.

- The new C API function `agn_numminus` counts the number of elements in the difference of two structures.

- The new C API function `agn_numunion` counts the number of elements in the union of two structures.

- Improved the index of the Primer and Reference.

- This release has been named after the City of Vinton, Calcasieu Parish, Louisiana, close to Texas, and has been Valgrind-checked on x86 and AMD64 Linux to ensure there are no internal errors or memory leaks.


3.9.6 Rayne, January 24, 2024

- Added the '__index' metamethod to the `lookup` package, which is an alternative to `lookup.gettable` called with a lookup table and one of its keys. Example:

  > a := lookup.new();

  > lookup.include(a, 'xyz', -1, -2, -3, -4);

  Check what we have at index 'xyz', in two different ways:

  > lookup.gettable(a, 'xyz'):
  [-1, -2, -3, -4]

  > a['xyz']:
  [-1, -2, -3, -4]

- Added '__in' and '__notin' metamethods so that you can search for values in the subtables of a lookup table:

  > -1 in a:
  true

  > 100 notin a:
  true

- New `lookup.iterate` is a factory that produces iterators to traverse lookup tables. It is an alternative to `lookup.next`.

  > a := lookup.new();

  > lookup.include(a, 'abc', 1, 2, 3, 4)
  > lookup.include(a, 'xyz', -1, -2, -3, -4)

  > f := lookup.iterate(a);

  > while x := [f()] do
  >   break when empty x;
  >   print(x)
  > od;
  [xyz, [-1, -2, -3, -4]]
  [abc, [1, 2, 3, 4]]

  As a second argument to `lookup.iterate` you might give a key for the next iteration.

- `pipeline` has been tuned by at least 25 percent.

- Any issues with the source files have now been fixed.


3.9.5a Rayne, January 22, 2024

- Some few source files did not compile correctly on Raspberry Pi 4 32 and 64-bit, all related to the `long` package. This has been fixed. Also uploaded updated Raspberry Pi installers.


3.9.5 Rayne, January 21, 2024

- The new `lookup` package implements an easy-to-use lookup table, closely related to the `bags` package, examples:

  Create a new lookup table:

  > a := lookup.new();

  Insert some values:

  > lookup.include(a, 'abc', 1, 2, 3, 4)
  > lookup.include(a, 'xyz', -1, -2, -3, -4)

  Inspect the lookup table:

  > lookup.gettable(a):
  [abc ~ [1, 2, 3, 4], xyz ~ [-1, -2, -3, -4]]

  Check what we have at index 'xyz':

  > lookup.gettable(a, 'xyz'):
  [-1, -2, -3, -4]

  Get all the indices:

  > lookup.indices(a):
  [xyz, abc]

  Traverse the table:

  > lookup.next(a, null):
  xyz     [-1, -2, -3, -4]

  > lookup.next(a, 'xyz'):
  abc     [1, 2, 3, 4]

  > lookup.next(a, 'abc'):
  null

  Map a function on all elements, in-place:

  > lookup.map(<< x -> 2*x >>, a):
  [abc ~ [2, 4, 6, 8], xyz ~ [-2, -4, -6, -8]]

  Substitute values, also in-place:

  > lookup.subs(2:0, -2:0, a):
  [abc ~ [0, 4, 6, 8], xyz ~ [0, -4, -6, -8]]

  Get the number of all indices and of all table values:

  > lookup.getsizes(a):
  2       8

  Delete the entry indexed by 'xyz':

  > lookup.purge(a, 'xyz'):
  [0, -4, -6, -8]

  > lookup.gettable(a), lookup.getsizes(a):
  [abc ~ [0, 4, 6, 8]]    1       4

  `lookup.gettable` allows to modify the table via the table reference returned. If you add or delete new values via self-written functions, do not forget to set the new sizes for the number of indices and entries:

  > lookup.setsizes(a, 1, 4);  # one key, four values

- Adapted the souces to compile again on Raspberry Pi, both 32- and 64-bit.

- Fixed error message of `next`.


3.9.4 Rayne, January 20, 2024

- Adapted the souces to compile again on Raspberry Pi, both 32- and 64-bit.

- Uploaded Raspberry Pi installers.


3.9.4 Rayne, January 16, 2024

- `map` and `subs` use tweaked functionality when in `descend=true` mode, avoiding re-creation of values where possible.

- When given an explicit alphabet, `strings.random` now accepts a third optional argument: `true` or `false`. When set the `true`, the default, `strings.random` will always produce really random strings, as it does now. When set to `false` and the function is subsequently called in a session, it will always produce the same sequence of random `random` strings.

- `hashes.md5` when given a string computed a wrong hash as the string was internally not split apart into chunks of 64 bytes each but was taken as one whole chunk. This has been fixed. You can reproduce the former behaviour by either passing zero or the length of the input string as a second argument. This also means if you want to determine the MD5 hash of a _file_, you must now pass a non-numeric option.

- The red-black tree package has now been fully documented, see Chapter 10.11 in the Primer & Reference.


3.9.3 Rayne, January 14, 2024

- `prepend` has been ported to C and has become around twice as fast.

- Just for `consistency`, a new function has been introduced that does the opposite of `prepend`: `append` adds a value to the end of a structure.

- New `include` inserts one or more values to the end of a structure, not discarding multiple returns if its last argument is a function call. Note that the `insert` statement ignores all but the first return when given a function call:

  > a := []; f := << () -> 1, 2, 3 >>;

  > insert f() into a;

  > a:
  [1]

  > a := [];

  > include(a, f()):
  [1, 2, 3]

- `map` and `subs` in `descend=true` mode now accept and process sequences, registers, sets, pairs and complex numbers. Example:

  > a := seq(1, 2, reg(3, [4], seq(5:6, 7!8)))

  > map(<< x -> 2*x >>, a, descend=true):
  seq(2, 4, reg(6, [8], seq(10:12, 14+16*I)))

  > subs(7!8:1!1, a, descend=true):
  seq(1, 2, reg(3, [4], seq(5:6, 1+I)))

- When given a second argument to `tables.indices`, the returned table of integral table indices is now sorted in ascending order.

- When given any second argument to `tables.entries`, the function returns all the table values that have integral keys - in ascending order of these integral keys:

  > a := [10, 20, 30, 40, 50, -1~0, -2~-1];

  > tables.indices(a, true):
  [-2, -1, 1, 2, 3, 4, 5]     true

  > tables.entries(a, true):
  [-1, 0, 10, 20, 30, 40, 50]     true

- This release contains an implementation of a red-black tree, in the new plus package `rbtree`. It creates a binary search tree for numbers and assures that when inserting a number, all its elements are always stored in ascending order. The package has been added primarily to guarantee that the internal red-black tree C implementation works and is safe, otherwise it might be of use only in some special situations, this is why it currently has not been documented in the Primer and Reference and the Quick Reference.

  > import rbtree;

  > a := rbtree.new();  # create a new red-black tree

  > tostring(a):        # pretty-printing
  rbtree(01F16AC0)

  > for i from 10 downto 1 do
  >    rbtree.include(a, i)  # insert numbers 1 to 10 in `reverse` order
  > od;

  > rbtree.entries(a):  # all the elements in a are in ascending order
  [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

  > 10 in a, 11 in a:   # is ten in a - and is 11, as well ?
  true    false

  > rbtree.find(a, 0):  # try to find zero in a
  false

  > empty a, filled a:  # is the structure empty or filled ?
  false   true

  > rbtree.remove(a, 10);  # remove ten from a

  > 10 in a:  # ten no longer in red-black tree
  false

  > size a:   # current number of elements in a
  9

- This release has been Valgrind-checked on x86 and AMD64 Linux to ensure there are no internal errors or memory leaks.


3.9.2 Rayne, January 09, 2024

- With (deeply) nested tables, `map` and `subs` can recursively descend into the entire structure and map a function or substitute values with only just one call, with the new `descend=true` option:

  > map(<< x -> 2*x >>, [1, 2, 3, [4, 5, [6]]], descend=true):
  [2, 4, 6, [8, 10, [12]]]

  > subs(1:0, 6:10, [1, 2, 3, [4, 5, [6]]], descend=true):
  [0, 2, 3, [4, 5, [10]]]

  Sequences, registers, sets, pairs and complex numbers, however, are not accepted in the input structure.

- With tables as input, `map` now supports the 'reshuffle' option, removing any holes in the result before returning it. Just an example:

  > a := [1, 2, 3, 4, 5];

  > a[3] := null;  # we create a hole

  > a:
  [1 ~ 1, 2 ~ 2, 4 ~ 4, 5 ~ 5]

  > map(<< x -> 2*x >>, a):  # no reordering, index 3 is still not assigned a value
  [1 ~ 2, 2 ~ 4, 4 ~ 8, 5 ~ 10]

  > map(<< x -> 2*x >>, a, reshuffle=true):  # return a concise table array with consecutive integral indices
  [2, 4, 8, 10]

- Hardened `map` against stack corruption in `multret=true` mode.

- When given a non-supported option, `map`, `subs, `subsop`, `select`, `remove` and `selectremove` now issue an error.

- The C API function `lua_call` now returns the number of results actually pushed onto the stack in a function call.

- This release has been Valgrind-checked on x86 and AMD64 Linux to ensure there are no internal errors or memory leaks.


3.9.1 Rayne, January 08, 2024

- With tables, sequences, registers and strings, you can now pass the new `multret` option. When given, then contrary to the default behaviour that did not change, all elements in a structure or string will be replaced by _all_ the returns of the giving mapping function. Compare:

  > map(<< x -> 2*x, 0 >>, [1, 2, 3]):  # the anonymous function returns both 2*x and zero, the zero has been ignored
  [2, 4, 6]

  > map(<< x -> 2*x, 0 >>, [1, 2, 3], multret=true):  # each element x is replaced by both 2*x and zero
  [2, 0, 4, 0, 6, 0]

  With tables, the operation is destructive in the sense that all elements in the resulting structure are put into a new table array with consecutive positive integer keys starting from one, replacing the orginal indices.

- `combinat.choose` did not return all the combinations when called in multiset mode (the input table contains at least one element twice or more and no second argument is given). This has been fixed.


3.9.0 Rayne, January 04, 2024

- When indexing a table with a range `t[a to b]`, and the lower bound a greater than the upper bound b, then Agena now returns an empty table instead of throwing an error. Thus, Agena now behaves like Maple in this situation, making porting code much easier.

  The same behaviour has been implemented for sequences and registers, in the latter case a register with 16 `null` values will be returned which is equal to the `reg()` expression.

- When indexing a table with a range, such like `t[a to b]`, Agena now tries to put the subtable elements into the array part instead of the hash part of the subtable, making internal sequential traversal easier, more reliable and faster, especially for `tables.reshuffle` which sometimes put elements in the wrong order.

  Before:

  > a := [10, 20, 30, 40, 50];

  > b := a[2 to 3];

  > tables.parts(b):  # the first table is the array part, the second the hash part: the subtable was in the hash part
  []      [2 ~ 20, 3 ~ 30]

  After:

  > a := [10, 20, 30, 40, 50];

  > b := a[2 to 3];

  > tables.parts(b):  # the subtable now is in the array part
  [2 ~ 20, 3 ~ 30]        []

- With a table array, by passing the new 'reshuffle' option, both `subs` and `subsop` will no longer leave holes when deleting values from it, so a subsequent call to `tables.entries` is unnecessary. Compare:

  > subs(2:null, [1, 2, 3]):
  [1 ~ 1, 3 ~ 3]

  > subs(2:null, [1, 2, 3], reshuffle=true):
  [1, 3]

- The `newarray` option for functions `map`, `select`, `remove, `selectremove` has been replaced by the `reshuffle` option, providing the same functionality. The old name `newarray`, however, is still supported so that you do not have to change your code.

- The new function `tables.isnullarray` checks whether a table consists of an array part only and whether at least one of its values is `null`.

- The new function `tables.hashole` checks whether the array part of a table contains at least one `null` value, i.e. a hole. The table may or may not have a hash part. An example:

  > a := [10, 20, 30, 40, 50 ~ 0]

  > tables.hashole(a):
  false

  > a[3] := null

  > tables.hashole(a):
  true

- `tables.reshuffle` can now remove one or more holes from the array part of a table without moving the values in the hash part to the array part, by passing any second argument. See the difference:

  > a := [10, 20, 30, 40, 50 ~ 0]

  > a[3] := null         # remove a[3] = 30, leave a hole in the array part

  > tables.reshuffle(a)  # hash part element a[50] = 0 is added to end of array part

  > a:
  [10, 20, 40, 0]

  > a := [10, 20, 30, 40, 50 ~ 0]

  > a[3] := null         # remove a[3] = 30, leave a hole in the array part

  > tables.reshuffle(a, true)  # remove hole in array part only, leave hash part element a[50] untouched

  > a:
  [1 ~ 10, 2 ~ 20, 3 ~ 40, 50 ~ 0]

- New `combinat.choose` constructs the combinations of table elements; it is a clone of the Maple function of the same name:

  > combinat.choose([1, 2, 3]):
  [[], [3], [2], [2, 3], [1], [1, 3], [1, 2], [1, 2, 3]]

  > combinat.choose([1, 2, 3], 2):
  [[1, 2], [1, 3], [2, 3]]

- `combinat.cartprod` now only returns a generating function if you pass any non-null second argument. Otherwise it now returns the complete Cartesian product with just one call. An example:

  > combinat.cartprod([[1, 2, 3], [30], [50, 100]]):
  [[1, 30, 50], [1, 30, 100], [2, 30, 50], [2, 30, 100], [3, 30, 50], [3, 30, 100]]

- With sequences and registers, you can now pass negative positions k to `purge`, deleting the k'th element from the end of the structures.

- There was a bug with the colon pretty-printer, that did not worsely affect Agena evaluating code: when printing the result of an assignment statement at the prompt, the expression to the right of the `:=` token had been evaluated twice:

  > a := 0;

  > a := a + 1:  # the result is 1, but the pretty-printer output:
  2

  The assignment statement, however, had been correctly executed:

  > a:
  1

  This bug has been fixed.

- The new C API function `agn_tabpurge` deletes a value from the array part of a table that does not include `null` without leaving a hole.

- The release has been named after the City of Rayne, Acadia Parish, Louisiana.

- This release has been Valgrind-checked on x86 and AMD64 Linux to ensure there are no internal errors or memory leaks.


3.8.0 Iberia, January 01, 2024

- The new function `subsop` replaces all the values in a table, sequence or register at the given index positions. It emulates more or less the Maple function of the same name. Depending on the structure, the function also allows to delete values. Examples:

  > a := [10, 20, 30]

  Substitute the value at index 2 with zero and delete the third element:

  > subsop(2:0, 3:null, a):
  [10, 0]

  The function is non-destructive by default,

  > a:
  [10, 20, 30]

  but by passing an option (here `true`) you can conduct in-place substitution, altering the input structure:

  > subsop(2:0, 3:null, a, true):
  [10, 0]

  > a:
  [10, 0]

- `member` now returns only one value: In case a value has been found in a structure, its first index is returned, and `null` otherwise. This makes its result more easier to use and also speeds up the function. A possible usage is this:

  > a := [10, 20, 30];

  > if k := member(20, a) then print(k, a[k]) else print('no hit') fi;
  2   20

  > if k := member(40, a) then print(k, a[k]) else print('no hit') fi;
  no hit

- New function `combinat.permute` constructs the permutations of table elements. Examples:

  > combinat.permute([1, 2, 3], 3):
    [[1, 2, 3], [1, 3, 2], [2, 1, 3], [2, 3, 1], [3, 1, 2], [3, 2, 1]]

  > combinat.permute(3, 2):
    [[1, 2], [1, 3], [2, 1], [2, 3], [3, 1], [3, 2]]

  The function intensively uses both `member` and `subsop`.

- New `hashes.sha256` computes the SHA256 hash.

- Improved error messages of various operators and functions.

- Improved Chapter Four in the Primer and Reference a little bit with respect to tables, sequences and registers.

- The release has been named after Iberia Parish in Southern Louisiana.

- This release has been Valgrind-checked on x86 and AMD64 Linux to ensure there are no internal errors or memory leaks.


3.7.7 Carlyss, December 30, 2023

- `foreach` now has a third flavour that resembles the `reduce` function and thus makes the operator more generic and versatile: By passing an interval with an optional step size, a two-parameter accumulator function and an initialiser of any type, you can create short one-liners.

  Two examples: To compute the tenth factorial 10! = fact(10) issue

  > foreach(true, 1, 10, 1, << x, a -> a*x >>, 1):
  3628800

  In this example, the operator receives the range [1, 10] and step size 1. The accumulator function with its first argument receives the iteration value and with its second argument the accumulator which is initialised to 1 (last argument). The function returns the updated accumulator.

  To compute a list of the first ten factorials, enter:

  > foreach(true, 1, 10, proc(x, a) is insert a[size a]*x into a; return a end, [1]):
  [1, 1, 2, 6, 24, 120, 720, 5040, 40320, 362880, 3628800]

  The first value in the return is the initialiser - you can provide a more sophisticated function that omits it from the result.

  Compared to `reduce` and `fold`, the new feature is great to save a lot of memory for you pass only a left and right border and a step size and not a structure of - often many - individual values.

- `foreach` now accepts fractional start and step values, uses Kahan-Babuska summation only if the start or the step values are fractional, and can `count backwards` if the start value is greater than the stop value.

- To avoid confusion, `stats.poissonpdf` has been renamed to `stats.poisson`. An alias has been provided to ensure backward-compatibility.

- `stats.poisson` accepted negative first arguments. It also returned a wrong value if both arguments had been zero. All has been fixed.

- `stats.logistic` now returns a real result instead of `undefined` if its third argument is non-positive.

- The `beta` function returned `undefined` instead of a real result in various situations. This has been fixed.

- `tonumber` now returns `fail` if it receives a value that could not be converted to a number, so it now behaves as described in the Primer & Reference. Exception: With a non-convertible string, the function still returns this string.

- Extended the test cases for the `stats` package and laid the foundation for three and four argument mass test cases.

- This release has been Valgrind-checked on x86 and AMD64 Linux to ensure there are no internal errors or memory leaks.


3.7.6a Carlyss, December 23, 2023

- Just updated the documentation and test cases, no further changes. You can also individually download the updated documentation from the `Manuals` subfolder.


3.7.6 Carlyss, December 21, 2023

- `math.beta` and thus `beta` have been optimised
   - for the Central Beta function case where both real arguments are equal (30 percent faster),
   - for positive integral arguments which are both less than 512 (40 percent faster).

- With positive integers less than 512, `lngamma` has become 40 percent faster, and `gamma` 20 percent faster, also benefitting other functions that use the underlying logic in this situation, e.g. `math.pochhammer`, `stats.studentst`, `stats.chisquare`, `stats.fratio`, `stats.gammad`, `stats.gammapdf`, `stats.gammacdf`, `combinat.numbperm`, `calc.expn`, `calc.ibeta`, `calc.igamma`, `calc.igammac`, etc.

- `math.lnfact` has been tweaked a little bit by avoiding internal conversion between C doubles and C long doubles.

- Fixed `instr` once more which with large sets of strings could cause `stack overflow` exceptions, interrupting computations.

- `bytes.getieee` and `registry.get` crashed the interpreter when they encountered non-strings in their input. This has been fixed.

- Cleansed the code to prevent compiler warnings on Mac OS X.

- This release has been Valgrind-checked on x86 and AMD64 Linux to ensure there are no internal errors or memory leaks.


3.7.5 Carlyss, December 19, 2023

- The new `stats.beta` function implements Maple's function of the same name and computes the probability density function 1/beta(nu1, nu2) * x^(nu1-1) * (1-x)^(nu2-1) of the Beta distribution.

- New `stats.negbinompdf` implements Maple's negativebinomial function and computes the probability density function equal to binomial(n + x - 1, x) * p^n * (1 - p)^x.

- `stats.logistic` in its new multi-argument form computes the probability density function of the Logistic[a, b] distribution, as implemented in Maple. Likewise, the new multi-argument form of `stats.laplace` computes the probability density function of the Laplace[a, b] distribution, also as implemented in Maple.

- New `math.gammasign` returns the sign of the gamma(x) function, i.e. -1 if x < 0 and odd(entier(x)), and 1 otherwise. When given multiple numbers, the respective `gamma signs` are multiplied with each other.

- With negative real arguments, `math.beta` and thus `beta` could return `undefined` although real solutions exist or they could return the result with the wrong sign. This has all been fixed.

- `instr` sometimes did not work if the second argument was a set of strings, claiming it found non-strings. Also with sets, the function could corrupt the stack. Both has been fixed.

- This release has been Valgrind-checked on x86 and AMD64 Linux to ensure there are no internal errors or memory leaks.


3.7.4 Carlyss, December 17, 2023

- `stats.normald` only accepted integers for the second argument mu. This has been changed to accept any number.

- New `stats.lognormald` computes Maple's probability density function 1/(x*sqrt(2*Pi)*sigma) * exp(-((ln(x)-mu)/sigma)^2/2).

- New `stats.hypergeom` implements Maple's hypergeometric probability density function.

- Tweaked `math.relerror` and `math.isinfinity` a little bit.

- When given any second argument, `long.tonumber` now returns a second result indicating whether its 80-bit argument is less or greater the minimum or maximum value an Agena number can represent. Likewise, new `long.overflow` checks whether a long double is outside the range of an ordinary 64-bit Agena number.

- `long.lnbinomial` did not return an 80-bit precision result, but mostly a 64-bit one. This has been fixed.

- This release has been Valgrind-checked on x86 and AMD64 Linux to ensure there are no internal errors or memory leaks.


3.7.3 Carlyss, December 15, 2023

- New `math.lnbinomial` and `long.lnbinomial` compute the natural logarithm of the binomial coefficent, avoiding overflow with large values.

- `stats.binomd`, `stats.binompdf`, `stats.poissond` and `stats.poissonpdf` overflowed with larger arguments, returning `undefined` in such cases. This has been fixed.

- `binomial` and thus `combinat.numbcomb` overflowed with a larger negative integral first argument or with large fractional arguments. This has been fixed, too.

- The `qmdev` operator now uses Kahan-Babuska summation for better internal round-off error prevention. The `qmdev` metamethod of the `numarray` package does so, as well.

- This release has been Valgrind-checked on x86 and AMD64 Linux to ensure there are no internal errors or memory leaks.


3.7.2 Carlyss, December 12, 2023

- `stats.binomd`, `stats.poisson`, `stats.ad`, `stats.md`, `stats.ios`, `stats.rownorm`, `stats.gini`, `stats.acf`, `stats.acv`, `linalg.dotprod`, `linalg.det`, `linalg.mmul`, `linalg.trace`, `math.compose`, `numarray/qmdev` metamethod and `calc.eps` use Kahan-Babuska summation for better internal round-off error prevention.

- New `math.kbadd` conducts Kahan-Babuska summation to be used primarily in iterations if advanced round-off error prevention is needed while summing up Agena numbers.

- `math.ndigits` returned wrong results with the integral part of Agena Numbers. This has been fixed.

- `environ.kernel` returns the number of digits in the floating point mantissa for C data long doubles in the new field 'longmantdigs' and the largest possible exponent value in C long doubles in the new field 'longmaxexp'. The values vary across platforms.

- This release has been Valgrind-checked on x86 and AMD64 Linux to ensure there are no internal errors or memory leaks.


3.7.1 Carlyss, December 10, 2023

- The new two-argument variant of `calc.Psi` computes the digamma, trigamma and tetragamma functions:

  > calc.Psi(0, Pi):  # digamma = calc.Psi(Pi)
  0.97721330794201

  > calc.Psi(1, Pi):  # trigamma
  0.37424376965454

  > calc.Psi(2, Pi):  # tetragamma
  -0.13854737032139

- The new `member` function emulates Maple's function of the same name and checks whether an element is included in a table, sequence or register. If there is a hit, it returns `true` plus the position of the first hit in the structure as a second result, otherwise it returns `false` and `null`. Examples:

  > member(10, [0, 5, 10, 10, 0]):
  true    3

  > member(undefined, [0, 5, 10, 10, 0]):
  false   null

  The function is around 40 percent faster than related `whereis` if you just need the index of the first hit. Note that with respect to `whereis`, the parameters are in reverse.

- Tweaked various `calc` functions a little bit: `calc.Ei`, `calc.Si`, `calc.Ci`, `calc.Shi`, `calc.Chi`, `calc.Psi`, `calc.dilog`, `calc.fresnelc`, `calc.fresnels`, `gamma` (OS/2 and DOS), `calc.Ai`, `calc.Bi`, `calc.zeta`, `calc.En`, `calc.igamma`, `calc.igammac`, `calc.ibeta` and `calc.invibeta`.

- `long.lnabs` did not compute the absolute value before determining the natural logarithm. This has been fixed.

- In the Primer and Reference, the description of the `numarray` package has been improved by various examples.

- The Proton editor schema file was corrupt. This has been fixed.

- This release has been Valgrind-checked on x86 and AMD64 Linux to ensure there are no internal errors or memory leaks.


3.7.0 Carlyss, December 06, 2023

- The following former plus packages have been integrated into the core interpreter: `calc`, `linalg`, `stats`, `xbase`, `bags`, `llist`, `numarray`, `ulist`, `dlist`, `long`, `bytes`, `factory`, `sema` and `utf8`.

  Thus they are immediately available at start-up and you do not have to use the `import` statement or the `readlib` function any longer to load them.

- The following combinatorical functions have been moved to the new `combinat` package:

  - calc.bernoulli` moved to `combinat.bernoulli`,
  - calc.euler` moved to `combinat.euler`,
  - stats.bell` moved to `combinat.bell`,
  - stats.cartprod` moved to `combinat.cartprod`,
  - stats.numbcomb` moved to `combinat.numbcomb`,
  - stats.numbpart` moved to `combinat.numbpart`,
  - stats.numbperm` moved to `combinat.numbperm`.

  In all cases aliases have been provided for backward-compatibility.

- New `combinat.stirling1` and `combinat.stirling2` compute the Stirling number of the first and second kind, respectively. The equivalent function `math.stirnum` has been deprecated but an alias has been provided to ensure backward-compatibility.

- New `combinat.catalan` computes the n-th Catalan number.

- The deprecated `stats.sum` function has been removed. You may use `stats.sumdata` or the `addup` operator.

- Deprecated `llist.listtotable` has been deleted. Use `llist.totable` instead.

- Deprecated `bytes.getwordsofdouble` has been removed. Use `bytes.numwords` instead.

- Deprecated `bytes.gethighofdouble` has been removed. Use `bytes.numhigh` instead.

- Deprecated `bytes.getlowofdouble` has been removed. Use `bytes.numlow` instead.

- Deprecated `bytes.setwordsofdouble` has been removed. Use `bytes.setnumwords` instead.

- Deprecated `bytes.sethighofdouble` has been removed. Use `bytes.setnumhigh` instead.

- Deprecated `bytes.setlowofdouble` has been removed. Use `bytes.setnumlow` instead.

- Deprecated `numarray.get` has been removed. Use `numarray.getitem` instead.

- Deprecated `numarray.put` has been removed. Use `numarray.setitem` instead.

- The release has been named after the place of Carlyss in Calcasieu Parish, Louisiana.

- This release has been Valgrind-checked on x86 and AMD64 Linux to ensure there are no internal errors or memory leaks.


3.6.3 Charon, December 05, 2023

- `erf` has been extended to compute the integral of the Gaussian distribution from z to w, with erf(z, w) = erf(w) - erf(z). Complex numbers are supported, too.

- New `math.chi` implements the piecewise indicator function.

- New `stats.binompdf` determines to the binomial probability density.

- New `stats.binomd` simplifies to the cumulative probability binomial distribution function.

- New `stats.poissonpdf` calculates the Poisson probability density.

- New `stats.poissond` implements the cumulative probability Poisson distribution function.

- `stats.numbcomb` has been reimplemented in C and has become 30 percent faster.

- `stats.numbperm` has been reimplemented in C and has become 40 percent faster.

- New `utils.numiters` returns the number of iterations in the interval [a, b], with a <= b and with an optional positive step size, which is one by default. The result is equal to int(|b - a|/step) + 1.

- This release has been Valgrind-checked on x86 and AMD64 Linux to ensure there are no internal errors or memory leaks.


3.6.2 Charon, November 29, 2023

- Under heavy load and in Linux 64-bit environments only (ARM & Intel/AMD), sporadic stack corruption has been observed during recent regression tests causing confusing error messages but no memory leaks or segmentation faults. This has been solved by raising the default minimum stack size from 40 to 128 slots on all platforms, including the 32-bit editions of Agena. It is generally advised to install this fix. You can query the setting with

  > environ.kernel('minstack'):
  128

  The minimum stack size cannot be changed at runtime, but only by re-compiling the sources (see LUA_MINSTACK in agena.h).

- The new `addup` keyword has been added to AgenaEdit.

- AgenaEdit for Solaris and Intel Debian now use the latest Agena version.


3.6.1 Charon, November 28, 2023

- In p-moment mode, the `addup` operator now accepts `undefined` as the second argument and sets it to the size of the given structure.

- For additional stability, forehandedly improved internal garbage collection of the `mulup`, `addup` and `foreach` operators.

- The `times` and `foreach` operators could corrupt the stack. This has been fixed.

- The binary operators `mul`, `div`, `intdiv`, `mod`, `inc` and `dec` have been hardened against stack corruption.

- This release has been Valgrind-checked on x86 and AMD64 Linux to ensure there are no internal errors or memory leaks.


3.6.0 Charon, November 26, 2023

- The new operator `addup` sums up all elements in a table, sequence, register or userdata, optionally dividing by a number or the size of the distribution, or applying a function on each element before adding it to the sum, or calculating the p-moment. In arithmetic mean mode, the operator is 45 percent faster than `stats.amean`, and in p-moment mode 15 percent faster than `stats.moment`.

- The `qmdev` and `mulup` operators now call metamethods exactly as `sumup`, `qsumup` and all the other operators do: they no longer ignore a metamethod if it is attached to a table, sequence or register.

- The `mulup` and `foreach` operators could have thrown out-of-memory errors. This has been fixed.

- `stats.mean`, `stats.qmean` and `stats.kurtosis` have been tuned by twelve percent with tables and sequences and 40 percent with numarrays.

- `stats.trimmean` has become eight percent faster.

- With numarrays, `stats.var` has become seven times faster.

- Problems with sporadic `missing entry point` issues observed in Windows 11 - and only there - when initialising the `mapm` package may hopefully have been solved.

- The release has been named after the place of Charon in Vermilion Parish, Louisiana (and Pluto's largest moon).

- This release has been Valgrind-checked on x86 and AMD64 Linux to ensure there are no internal errors or memory leaks.


3.5.6 Amelia, November 23, 2023

- The `mulup` and `qmdev` operators can now call metamethods for any datatype.

- `stats.mode`, `stats.spread`, `stats.skewness` and `stats.kurtosis` now support numarrays.

- The `sumup`, `qsumup`, `mulup` and `qmdev` operators can now process numarrays.

- New `numarray.totable` returns a table with all the numbers stored to a numarray.

- Tuned `calc.bernoulli` a little bit.

- `stats.bell` crashed Agena when given a large argument. This has been fixed.

- Patched `stats.trimmean` which returned wrong results when given a table.

- The statistics test cases have been extended.

- This release has been Valgrind-checked on x86 and AMD64 Linux to ensure there are no internal errors or memory leaks.


3.5.5 Amelia, November 22, 2023

- The `times` operator, `registers.new`, `sequences.new` and `tables.new`, `memfile.map`, `tuples.map`, `utils.speed`, `xbase.header` plus the functions produced by `factory.anyof` and `factory.pick` have all been hardened against stack corruption.

- The `copy` operator did not deep-copy registers that reside in the array part of tables. This has been fixed.

- The MacOS X version of AgenaEdit may have crashed when printing - this has been fixed.

- This release has been Valgrind-checked on x86 and AMD64 Linux to ensure there are no internal errors or memory leaks.


3.5.4 Amelia, November 21, 2023

- New `numarray.attrib` returns the type of a numarray, the current number of slots allocated and the number of bytes occupied.

- `stats.fivenum` now _always_ includes the maximum and minimum value of a distribution, plus the arithmetic mean, regardless of the number of observations. The order of the values in the result remains the same. You can also give another rule for the first and third quartile: instead of the NIST method, they can be determined according to the Wikipedia or Excel methods.

- `stats.percentile` now automatically sorts a distribution internally and non-destructively to avoid confusion with wrong values in case the distribution is unsorted. The function has also been ported to C and has become 10 percent faster altogether.

- `stats.sorted`, `stats.scale`, `stats.isall` and `stats.isany` can now process numarrays.

- Almost all the functions and metamethods in the `mapm` package have been tuned a little bit by removing unnecessary stack thresholding.

- `stats.neighbours` and `stats.nearby` could crash agena when not passed a sequence. This has been fixed.

- When given a numarray, `stats.colnorm`, `stats.cumsum`, `stats.deltalist`, `stats.issorted`, `stats.rownorm`, `stats.sumdata` and `stats.sumdataln` now issue an error if the numarray does not include Agena numbers (C doubles), to prevent any undefined behaviour and segmentation faults.

- Various functions in the base library and the `numarray`, `stats` and `linalg` packages have been hardened against stack corruption.

- The index of the Primer and Reference has been updated.

- This release has been Valgrind-checked on x86 and AMD64 Linux to ensure there are no internal errors or memory leaks.


3.5.3 Amelia, November 12, 2023

- `regex.find` and `regex.match` have become three times faster and also use much less memory, thus preventing out-of-memory errors that might occur in Windows 11, but not in other Windows versions or other operating systems.

- New `dual.tostring` converts a dual number to a string.

- As a preparatory measure for the future, `debug.setstore` can now set an internal storage table to a procedure implemented in C. It still allows to add new entries to an existing storage table, regardless whether the function has been implemented in Agena or C. The function now also allows to delete storage tables and has also been implemented in C.

- The new C API function `agn_setstorage` sets a storage table to a procedure or deletes it. It also allows to add entries to an existing storage table.

- A few changes under the hood without influence on functionality.

- Improved the documentation a little bit.

- Extended the test cases.

- The Mac OS X installer now includes the latest version of AgenaEdit.

- This release has been Valgrind-checked on x86 and AMD64 Linux to ensure there are no internal errors or memory leaks.


3.5.2 Amelia, November 05, 2023

- New `mapm.xsinhcosh` returns both the real hyperbolic sine and hyperbolic cosine in one call.

- New `mapm.xsec` computes the real secant, `mapm.xcot` computes the real cotangent and `mapm.xcsc` the real cosecant.

- New `mapm.xsech` computes the real hyperbolic secant, `mapm.xcoth` computes the real hyperbolic cotangent and `mapm.xcsch` the real hyperbolic cosecant.

- New `mapm.xsinc`, `mapm.xcosc` and `mapm.xtanc` compute the real un-normalised cardinal sine, cosine and tangent.

- New `mapm.csec` computes the complex secant, `mapm.ccot` computes the complex cotangent and `mapm.ccsc` the complex cosecant.

- New `mapm.csech` computes the complex hyperbolic secant, `mapm.ccoth` computes the complex hyperbolic cotangent and `mapm.ccsch` the complex hyperbolic cosecant.

- New `mapm.csinc`, `mapm.ccosc`, `mapm.ctanc` compute the complex un-normalised cardinal sine, cosine, tangent.

- New `mapm.xrandom` generates a random real mapm number, and `mapm.xrandomseed` sets the seed.

- The `\`, `even` and `odd` operators now support real mapm numbers.

- The pretty-printer has been fixed for negative imaginary parts.

- The `-` operator when applied to real mapm numbers could corrupt the stack. This has been fixed.

- Arithmetic binary operators and relational operators, both in the real and complex domain, sometimes corrupted the stack. This has been fixed.

- `mapm.xlog2` has become twice as fast.

- Extended the mapm test cases.

- Cleansed the code to avoid some compiler warning messages in Linux and Solaris.

- This release has been Valgrind-checked on x86 and AMD64 Linux to ensure there are no internal errors or memory leaks.


3.5.1 Amelia, November 04, 2023

- `mapm.cnumber` did not correctly store real mapm numbers, which caused segmentation faults. This has been fixed.

- The metatable for complex mapm numbers contained mapm library functions and constants. This has been fixed.

- `real` and `imag` sometimes returned `null` or even corrupted the stack. This has been fixed.

- Real mapm numbers are now of user-defined type `xnumber` and complex mapm numbers of user-defined type `cnumber`. This allows type checks with the `::` operator and the `::` type check facility in parameter lists.

- When printing complex mapm numbers, or converting them to strings, the standard mathematical notation `a+I*b` is being used now.

- Tuned `mapm.ctonumber` and `mapm.ctocomplex`.

- Added the C API function `luaL_str2d` to convert strings to Agena numbers.

- Extended the mapm test cases.


3.5.0 Amelia, October 31, 2023

- The `mapm` package for arbitrary-precision math now includes various operators and functions that work in the complex domain:

  > import mapm;

  > mapm.xdigits(17);         # precision

  > x := mapm.cnumber(1, 2);  # define x = 1 + 2*I

  > y := mapm.cnumber(3, 4);  # define y = 3 + 4*I

  Addition:

  > x + y:
  mapm.cnumber(4.00000000000000000, 6.00000000000000000)

  Convert the result to a complex Agena number:

  > mapm.ctocomplex(ans):
  4+6*I

  Determine the absolute value, the return is a real mapm number:

  > abs(x):
  2.23606797749978970

  Get the natural logarithm:

  > ln(x):
  mapm.cnumber(0.80471895621705019, 1.10714871779409050)

  Get real and complex part of the previous calculation, to be returned as real mapm numbers:

  > real(ans), imag(ans):
  0.80471895621705019     1.10714871779409050

- In OS/2 and DOS `arcsinh` has been tuned, also benefitting `arcsin` and `arccos`.

- Tested the Windows installer for any missing dependencies on a fresh Windows 2000 installation.

- This release has been Valgrind-checked on x86 and AMD64 Linux to ensure there are no internal errors or memory leaks.

- The release has been named after the place of Amelia, Southern Louisiana.


3.4.10 Eunice, October 06, 2023

- The multi-line colon pretty-printer has been further refined and its error messages have been improved. It now rejects previously accepted invalid input such as

  > sin(:
  > Pi/2)
  Error: invalid or ambiguous syntax near `:`

  and just accepts expressions and statements like this:

  > sin(
  > Pi/2):
  1


3.4.9 Eunice, October 04, 2023

- The colon facility to easily print results at the console now also works with multi-line expressions and statements, for example

  > sin(
  >    Pi/2) + ln
  >    (2):
  1.6931471805599

  will no longer throw a syntax error or get the input stuck.

- `strings.fields` can now convert a string representing a complex number to that complex number when given the `convert=true` option. The string value must be of the form `a+I*b`.

- In-place sorting has become twelve percent faster when (and only when) passing an ordering function as the last argument to `sort`. The ordering function must now be strict, e.g. pass

  > sort(tbl, << x, y -> strings.strverscmp(x, y) < 0 >> );   # now: less than zero

  instead of

  > sort(tbl, << x, y -> strings.strverscmp(x, y) <= 0 >> );  # then: less than _or equals_ zero

- The new API C function `agnL_strtocomplex` tries to convert a string representing a complex number to that complex number.


3.4.8 Eunice, October 03, 2023

- You can now pass a string to `linalg.matrix` for easier input: The row vectors are separated by commas and the vector components by one or more white spaces. Carriage returns and newlines, if any, will be ignored. So, for example

  > linalg.matrix('1 2 3, 4 5 6, 7 8 9'):

  results in

  [ 1, 2, 3 ]
  [ 4, 5, 6 ]
  [ 7, 8, 9 ]

- Likewise, `linalg.vector` now also accepts strings with the vector components separated by one or more white spaces. Example:

  > linalg.vector(' 1  2 3 '):
  [ 1, 2, 3 ]

- The Mac OS X installer did not include all components of AgenaEdit. This has been fixed.


3.4.7 Eunice, October 03, 2023

- The new `foreach` operator traverses a numeric range, applies a univariate function on each intermediate value and puts the result into a given structure. Thus, for example,

  > foreach(1, 5, 0.5, << x -> 2*x >>, seq()):
  seq(2, 3, 4, 5, 6, 7, 8, 9, 10)

  is equivalent to

  > s := seq();
  > f := << x -> 2*x >>;
  > for i from 1 to 5 by 0.5 do
  >    insert f(i) into s
  > end;

  With a fractional start value or fractional step size, the operator uses Kahan-Babuska summation to prevent round-off errors.

  If the given structure already includes elements, they are not overwritten, and the function values are appended instead.

  The operator allows to omit the step size (defaulting to one) or the structure (in this case returning a table of function values).

  The operator is 25 percent faster than `tables.new` or `sequences.new`, and twice as fast as the statement sequence given above.

  If you pass a number, preferably zero, as the last argument, the operator computes the sum of all function values, also applying Kahan-Babuska summation:

  > # Pi approximation by Indian mathematician and astronomer Madhava of Sangamagrama, 14th century AD:

  > sqrt(12)*foreach(0, 25, << k -> (-3)^(-k)/(2*k + 1) >>, 0):
  3.1415926535898

- AgenaEdit is now shipped with the Mac OS X installer.


3.4.6b Eunice, September 27, 2023

- AgenaEdit now supports the following command-line options:

  Usage: agenaedit [options] [file to be opened]

  -F number  set text font size to given number, default is 14
  -a         ignore AGENAPATH environment variable
  -d         print debugging information during startup and within a session
  -h, -?     display this help
  -n         do not run initialisation file(s) `agena.ini`
  -p path    sets <path> to libname, overriding default libname initialisation
  -r name    readlib library <name> (no quotes needed)
  -x         do not run main library file lib/library.agn
  -B         throw syntax error when numeric constants are too big
  -C         allow constants to be overwritten
  -D number  set number of digits in output of floats to number (1 to 17)

  Check new menu item `Help/Command-Line Options` for further information.

- Added the experimental AgenaEdit menu item `Edit/Preferences/Font Size` to change the text font size. Setting the font size via command-line option from a shell, however, for example

  > agenaedit -F 20

  may work better.

- In Solaris, the AgenaEdit background colour of the text input field has been set to white instead of grey.

- The Debian x86 version of AgenaEdit crashed. This has been fixed.


3.4.6a Eunice, September 26, 2023

- The portable Windows edition included an outdated version of AgenaEdit. This has been fixed. The binary NSIS Windows installer is already containing the latest AgenaEdit edition and thus did not need to be updated.


3.4.6 Eunice, September 25, 2023

- AgenaEdit is now available in the i386 and x64 Debian distributions, and in the Solaris x86 edition.

- Beautification of AgenaEdit for all supported platforms.

- When the `mpf` library had been invoked and later on the `restart` statement was run, Agena crashed. This has been fixed.

- The Solaris dynamic link libraries have been updated and rebuilt.


3.4.5c Eunice, September 20, 2023

- Some fixes to AgenaEdit for Windows:

  - Changed colour and style of comments to grey and Courier font for better formatting and readability.

  - Aligned `Break`, `Restart` and `Close` buttons of the execution screens around the centre.

- Further code streamlining of the Agena sources to get AgenaEdit compiled in Solaris, Linux and Mac OS X, especially due to previous clashes between ANSI C and C++ source files.


3.4.5b Eunice, September 19, 2023

- Various extensions and fixes to AgenaEdit for Windows:

  - Migrated the code from FLTK-1.1.10 to FLTK-1.3.8.

  - Formerly missing dependency file `libstdc++-6.dll` is now included in the Windows distributions.

  - Added line numbers to the left of the editor window.

  - Via new menu item `Edit/Preferences` you can switch on or off word wrapping and display of line numbers.

  - Structures and complex numbers are now being displayed properly and in full detail.

  - Added a `Close` button to the execution screens.

  - When choosing the `Run/Execute Selected` menu item, the `Break` and `Restart` buttons were not displayed. This has been fixed.

  - In the `Help/System Information` window, the home directory is now being given, again.


3.4.5a Eunice, September 17, 2023

- In Windows only, reintroduced AgenaEdit, a simple, light-weight editor with syntax highlighting that also allows to try out your code. Check Chapter 3.2 of the Primer and Reference for a short introduction.

- Improved the description on how to install the portable Windows version.

- In the Windows distributions the documentation was not up-to-date. This has been fixed.

- Streamlined the code, no functional changes.

- Fixed a Windows compilation batch file that accidently deleted the PATH environment variable from the current Windows shell session. It did not delete or modify the PATH settings in the registry.


3.4.5 Eunice, September 09, 2023

- When Agena was in debug mode, a lot of stray formatting specifiers have been printed on screen. This has been fixed. Duplicate debug messages have been removed, too.

- Potential issues with complex arguments and resulting wrong results of `besselj` (all platforms), `bessely` (all platforms) and `cosc` (all platforms except OS/2, DOS and Solaris) have been fixed.

- In OS/2, complex math generally has been tuned by five percent.

- The OS/2 makefile has been completely reworked and now also produces a DLL file which is included in the WarpIN installer from now on.


3.4.4 Eunice, September 02, 2023

- `xbase.writenumber`, `xbase.writefloat`, `xbase.writedouble`, `xbase.writecomplex`, `xbase.writebyte` and  `xbase.write` could write truncated content to a dBASE file, resulting in wrong field sizes. This bug has been fixed.

- The new C API function `agnL_pushvstring` takes one or more strings and pushes their concatenation onto the top of the stack.

- The new C API function `agnL_strtonumber` tries to convert a string in the stack to a number and if successful replaces that string with that number.

- The new C API function `agnL_strunwrap` removes an enclosing substring from a string in the stack.

- Cleansed the code to prevent compiler warnings.

- Improved the index of the Primer and Reference.

- This release has been Valgrind-checked on x86 and AMD64 Linux to ensure there are no internal errors or memory leaks.


3.4.3 Eunice, August 30, 2023

- The `import` statement now optionally prints various debugging information while it is initialising a library. Just set

  > environ.kernel(debug = true)

  before. Examples:

  > import ads

  Processing library: ads.
     ads is an external (plus) package.

     Checking path C:\agena\src.
     Checking C library file C:\agena\src/ads.dll.
     C:\agena\src/ads.dll not present.
     Checking agn library file C:\agena\src/ads.agn: not present.

     Checking path c:/agena/lib.
     Checking C library file c:/agena/lib/ads.dll.
     c:/agena/lib/ads.dll successfully initialised.
     Checking agn library file c:/agena/lib/ads.agn: found.

     All fine, now registering ads.

  > import math

  Processing library: math.
     math is a standard library.
     Nothing to be done.

- In Windows, new `os.getloadeddlls` returns all the DLLs along with their absolute paths used by the interpreter, plus Agena's process id. You can pass any valid Windows process id to explore the modules loaded by another application, as well.

- In Windows, new `os.getwinsysdirs` retrieves both the Windows directory and the system directory.

- When given one or more relative paths at startup via the command-line -p option or the AGENAPATH environment variable, Agena could not find external libraries. This has been fixed.

- Potential duplicate initialisation of libraries by the `import` and `import/alias` statements (aka functions `readlib`, `initialise`) is now being prevented.

- The portable Windows version now includes the batch file `run.bat`. It allows to easily run the interpreter without having to manually change environment variables, etc. Check the `readme.w32` file at the root of the ZIP archive for further information.

- Since some plus packages compiled with MinGW/GCC 10.2.0 such as the MPFR binding `mpf` crashed the interpreter on Windows platforms prior to Windows 7 or 2008 Server, it has been decided to entirely switch back to GCC 9.2.0 to ensure 100 percent compatibility and stability of the Windows binaries.

- Some minor issues with the Windows NSIS installer (missing icon, orphaned link) have been fixed.


3.4.2 Eunice, August 29, 2023

- In the `mpf` package, a binding to the MPFR library with some extensions, division by zero now returns `undefined` instead of `infinity`, same with the `recip` operator.

- With MPFR numbers, the `recip` operator has become 25 percent faster, `cube` 13 percent faster and `square` twice as fast.

- New `mpf.hypot4` returns sqrt(x^2 - y^2), new `mpf.pytha` x^2 + y^2 and new `mpf.pytha4` x^2 - y^2.

- New `mpf.root` computes the n-th root.

- New `mpf.arccsch` computes the inverse hyperbolic cosecant.

- New `mpf.arcsech` computes the inverse hyperbolic secant.

- New `mpf.arccoth` computes the inverse hyperbolic cotangent.

- New `mpf.relerror` computes the relative difference |b - a|/a.

- New `mpf.cmpd` compares an MPFR value with an Agena number.

- When initialised multiple times in the same Agena session, the `mpf` package did not free all allocated memory at exit. This has been fixed.

- The `mpf` package is now fully described in the Quick Reference. Also added all `mpf` functions to the index of the Primer & Reference.

- New `os.islinux386` checks whether the Agena executable has been compiled on 32-bit x86 Linux.

- This release has been Valgrind-checked on x86 and AMD64 Linux to ensure there are no internal errors or memory leaks.


3.4.1 Eunice, August 26, 2023

- `os.islinux` and `os.ismac` have been ported to C and have become 525 times faster.


3.4.0 Eunice, August 23, 2023

- New `os.ismac` checks whether Agena is being run on Mac OS X (Darwin).

- The `mpf` package is now bound to the latest MPFR 4.2.1 library edition.

- The `square`, `cube` and `recip` operators now support MPFR numbers.

- Added functions `mpf.sech` (hyperbolic secant), `mpf.csch` (hyperbolic cosecant), `mpf.coth` (hyperbolic cotangent), `mpf.arccosh` (inverse hyperbolic cosine), `mpf.arcsinh` (inverse hyperbolic sine) and `mpf.arctanh` (inverse hyperbolic tangent).

- Added constants `mpf.nought`, `mpf.one`, `mpf.two`, `mpf.three`, `mpf.half`, `mpf.quarter`, `mpf.tenth`, etc. See Chapter 11.5, p. 544, of the Primer & Reference for all of them.

- `mpf.new` and `mpf.tostring` have been patched to prevent segmentation faults when given or converting `+/-infinity` and `undefined`.

- The `copy` operator could corrupt the internal stack and thus crash Agena. This has been fixed. When run under high load, this also prevents possible quarrels with: `bintersect`, `bminus`, `bisequal`, `duplicates`, `columns`, `pipeline`, `utils.readcsv`, `gdi` package initialisation, `gdi.plot`, `tables.dimension`, `sequences.dimension`, `registers.dimension`, `linalg.swaprow`, `linalg.swapcol`, `linalg.scale`, `stats.cartprod` and `stats.chauvenet`.

- `calc.isdiff` often returned wrong results, especially with points where the graph of a function is steep. This has been fixed by introducting a more adaptive approach. The function may still return wrong results around poles, but has been significantly improved compared to the former version. If no `eps` option is given, the function now uses the setting of Eps for comparison at a point x instead of varying math.eps(x).

- The Solaris installer did not contain the latest version of the `mpf` package. This has been fixed.

- Extended the regression test cases.

- The release has been named after the City of Eunice, Louisiana.


3.3.6 Alamo, August 22, 2023

- Type `negative` described in Chapters 6.7 and 6.8.2 of the Primer and Reference did not exist. This has been fixed.

- `checkoptions` now accepts the numerical pseudo-types `negative`, `nonnegative`, `positive`, `integer`, `posint` and `nonnegint`. It also accepts pseudo-types `basic`, `listing` and `anything`, see Chapter 6.8.2 of the Primer and Reference.

- The new `span` option to `calc.differ` gives control on the computation of Chebyshev coefficients should the logic decide to call `calc.cheby` and also controls the checks for undefined realms in the vicinity of the given point.

  For example with the call

  > calc.differ(<< x -> ln x >>, 2.5, deriv = 3, span = 2):  # third derivative of ln(x) is 2/x^3
  0.12800000000058

  and point x = 2.5 (the second argument) the function will compute Chebyshev coefficients over [x - span/2, x + span/2] = [1.5, 3.5] and would call `calc.diff` or `calc.xpdiff` instead of `calc.cheby` if x is less than span = 2 units away from any undefined realm.

  The default is span = 2 and has been left unchanged.

- `calc.intde` now remembers the last epsilon setting given by the user and runs the function 40 % faster with succeeding calls done with the same epsilon value.


3.3.5 Alamo, August 19, 2023

- New `calc.intcc` integrates a univariate function over an interval, using Clenshaw-Curtis-Quadrature. The function is almost thrice as fast as `calc.intde` - with equal quality.

- `calc.intde` has become 40 percent faster if you do not change the default epsilon value 1e-15, optionally passed as the fourth argument. It now also issues an error if the left boundary is greater than or equals the right boundary.

- New `long.inverf` implements the inverse error function.

- The `$$` operator, which checks whether at least one element in a structure satisfies a condition, could corrupt the stack, thus returning wrong results or even causing segmentation faults. This has been fixed.

- Extended the regression test cases.

- This release has been Valgrind-checked on x86 and AMD64 Linux to ensure there are no internal errors or memory leaks.


3.3.4 Alamo, August 18, 2023

- The accuracy of the second derivative computed by `calc.diff` has been increased 4-fold. The quality of the third derivative has been slightly improved. The function can now also compute the fourth and fifth derivative.

- `calc.differ` has been extended to compute the fourth and fifth derivative and significantly improved by internally calling `calc.cheby` if the point to be evaluated is not near an undefined realm, or by calling `calc.diff` with higher-order derivatives (> 3) if the the point is near an undefined realm.

- `mapm.xerf` and thus also `mapm.xerfc` have become 35 % faster.

- New `zx.LGAM` implements the logarithmic gamma function.

- `zx.GAM` has been fixed to prevent internal division by zero.


3.3.3 Alamo, August 13, 2023

Extended the `mapm` package, based on late Mike Ring's MAPM package, for arbitrary-precision real math:

- New `mapm.xint` truncates a float, that is rounds it towards zero to the nearest integer.

- New `mapm.xarcsec` and `mapm.xarccsc` implement arcsecant and arccosecant.

- The `int` and `arcsec` operators support MAPM numbers.

- New `mapm.xhypot4` computes sqrt(a^2 - b^2).

- Added `mapm.xrecip` which is just an alias to `mapm.xinv`. Also added functions `mapm.xcube` and `mapm.square` which work like the `square` and `cube` metamethods.

- Added new test cases and improved description of the package in the Primer and Reference.

Miscellaneous:

- The OS/2 installer is shipped with more recent gmp, mpfr, expat, history and readline dependency DLL files.

- On x86 Solaris, when statically linked, Agena libraries are now bound against the latest versions of: expat-2.5.0, gmp-6.3.0, mpfr-4.2.0, libiconv-1.17 and libpng-1.6.40.

- On x86 Linux and Raspberry Pi ARM, when statically linked, Agena libraries now bind against the latest versions of: expat-2.5.0, fontconfig-2.14.2, freetype-2.13.1, gmp-6.3.0, mpfr-4.2.0, libiconv-1.17 and libpng-1.6.40.

- This release has been Valgrind-checked on x86 and AMD64 Linux to ensure there are no internal errors or memory leaks.


3.3.2 Alamo, August 11, 2023

- `calc.cheby` can now approximate the sixth, seventh and eighth derivative of a function:

  > import calc

  > f := calc.cheby(<< x -> ln x >>, 3, 7, 30, deriv = 6);  # for 3 <= x <= 7

  > f(5):  # 6th derivative of ln(x) <=> -120/x^6, at x=5, exact value is -0.00768:
  -0.0076800000481259

- `calc.chebycoeffs` has been ported to C, has become thrice as fast and also more accurate as it is internally computing with 80-bit floating-point numbers. See next point for an example.

- The new function `calc.chebygen` takes a table of Chebyshev coefficients and generates a factory computing approximations:

  > coeffs := calc.chebycoeffs(<< x -> ln x >>, 3, 7, 30):
  [1 ~ 3.1335984739448, 2 ~ 0.41742430504416, 3 ~ -0.0435607626104, ..., domain ~ 3:7]

  Return a factory computing the sixth derivative of ln(x) = -120/x^6:

  > f := calc.chebygen(coeffs, deriv = 6);

  Evaluate derivative at x=5:

  > f(5):
  -0.0076800000481259

  So by combining `calc.chebycoeffs` with new `calc.chebygen` you actually emulate `calc.cheby`, but have much more control about the evaluation process.

- The `import` statement often issued one and the same error message multiple times when trying to initialise the same corrupt or incompatible DLL/so library. This has been fixed.

- Minor tweak to `zx.genseries`.

- The sources have been adapted to compile without warnings up to GCC 12.3.0. The Windows binaries, however, are still being compiled with MinGW/GCC 10.2.0 for backward-compatibility with Windows 2000 and later. Compiling with a more recent version will not result in improved speed - sometimes quite the contrary - and 10.2.0 is the last version that guarantees Agena to run on Windows 2000.


3.3.1 Alamo, August 07, 2023

- Sped up initialisation of the main library file.

- `os.list` has been tweaked by avoiding internal duplicate buffer operations.

- In Linux, `os.now`, `os.date` and `os.time` now return actual milliseconds.

- Corrected error messages of the `$$` operator.

- The Windows installers include the latest DLLs for zlib, libiconv, libmpfr, libgmp, libfreetype, libexpat and libpcre and successfully set up Agena on Windows 2000 SP4, Windows 2003 Server, Windows XP SP3, Vista, Windows 7, 8.1, 10 and 11.


3.3.0 Alamo, August 06, 2023

- The `@` and `$` operators have become 25 percent faster.

- In Windows, by adapting and compiling the sources with GCC 10.2.0, at least numeric `for` loops have become five percent faster.

- `zx.reduce` has been tuned by eight percent.

- Added `fastmath.floor` which is eight percent faster than the `floor` function. It is always recommended to use the `entier` operator which is much faster and 100 percent portable across platforms.

- The release has been named after the Shrine of Texas Liberty in San Antonio, the Alamo.


3.2.1 Covington, August 01, 2023

- Internal argument reduction of trigonometric functions has been tuned, speeding the functions up by five to nine percent: among them `sin`, `cos`, `tan`, `math.sincos` and many other functions, including those computing in the complex domain.


3.2.0 Covington, July 30, 2023

- New `invgamma` computes the inverse gamma function 1/gamma(x).

- New `calc.gammainc` computes either the upper or lower incomplete gamma function.

- New `stats.gammacdf` realises the gamma cumulative distribution function.

- New `stats.gammapdf` implements the gamma distribution probability density function.

- New `stats.F` computes the F distribution, new `stats.Fc ` the complemented F distribution and new `stats.invF` the inverse of the complemented F distribution.

- New `calc.expn` computes the exponential sum function e_n(x).

- New `calc.zeta2` computes the Riemann zeta function of two arguments.

- `calc.Psi` now accepts complex numbers.

- The release has been named after the City of Covington, Louisiana.


3.1.3 Conroe, July 25, 2023

- New `pytha4` computes x^2 - y^2 without undue underflow or overflow and treating subnormal numbers accordingly. The function also internally computes in 80-bit precision instead of 64-bit precision. Please note that all these features make the function slower than the naive `x**2 - y**2` approach.

- `erfc` has become 13 percent faster in the real domain, also benefitting `stats.cdfnormald`.

- Slight tweak to `bessely`.

- Improved accuracy of `hypot4` in the real domain.

- Auxiliary functions computing polynomials have been reduced to the absolute minimum, still providing all the speed benefits introduced with the last update.

- `hypot4` returned wrong results with arguments close to +/- infinity. This has been fixed.

- All undocumented mathematical reference functions have been moved from the `fastmath` package to the new `testlib` package. All duplicates have been removed.


3.1.2 Conroe, July 23, 2023

- The factories produced by `calc.polygen`, for polynomials of degree 0 to 30, have been tuned by up to 135 percent. The larger the degree, the faster the factories have become.

- The following integral functions have been tuned: `calc.intde` has become 45 percent faster, `calc.intdei` 39 percent faster, and `calc.intdeo` 20 percent faster, also benefitting the `calc.integ` wrapper.

- `calc.fmings` has become five percent faster.

- Both `calc.sigmoid` and `calc.logistic` have been tuned by 13 percent.

- `stats.cdf` has been tuned by 40 percent.

- The following 80-bit floating-point operators have been tuned: `exp` by two percent, `ln` by seven percent, `gamma` by 17 percent.

- Significantly improved Chapters 10.1 Tables, 10.2 Sets, 10.3 Sequences and 10.4 Registers of the Primer and Reference.

- Improved the Quick Reference, tabs `Tables`, `Sequences` and `Registers`.


3.1.1 Conroe, July 19, 2023

- The factories produced by `factory.pick` have been tuned quite a bit.

- Improved Chapters 10.1 Tables, 10.3 Sequences, 10.4 Registers and the index of the Primer and Reference.


3.1.0 Conroe, July 12, 2023

- The new function `factory.anyof` creates a factory that when called tries each given function with the arguments passed to the factory. It also accepts structures that have a '__call' metamethod. Example:

  > import factory;

  > isalphanumeric := factory.anyof(strings.isnumber, strings.islatin);

  > isalphanumeric('1'):
  true

  > isalphanumeric('i'):
  true

  > isalphanumeric('ü'):
  null

  The function has originally been conceived by Gary V. Vaughan, written in Lua, and has been ported to C for much better speed.

- New `factory.pick` picks only given results from a function call, by taking a function and the positions of the results to be returned and producing a factory that when called delivers the results of interest. Imagine a function g

   > g := proc() is return 10, 11, 12, 13, end;

   where we want to have only the first and third result of its call, that is numbers 10 and 12. We define

   > import factory;

   > f := factory.pick(g, 1, 3);

   > f():
   10      12

- `curry` has been moved to the `factory` package. There is no alias for backward-compatibility. If you want to use it, initialise the `factory` package first:

  > import factory;

  > f := << x, y, z -> x*y + z >>;

  > t := factory.curry(f, 10);  # returns f(10, y, z)

- The new function `tables.isarray` checks whether a table is a pure array, i.e. only contains one or more elements in the array part of the table but none in the hash part. Also determines whether there are holes in the array.

- The new function `tables.ishash` checks whether a table is a pure dictionary, i.e. only contains one or more elements in the hash part of the table but none in the array part.

- New `environ.callable` returns its argument if it is a function. If the argument is a structure and has a '__call' metamethod, returns this metamethod. The function is useful to first check whether a value can be successfully called like a function without triggering exceptions:

  > r := environ.callable(f) and f(...);

  The idea has been taken from Gary V. Vaughan's lyaml package, but translated into C.

- New `strings.sub` has been taken from Lua 5.4 and returns a substring with automatic correction of both the left and the right border if they are out-of-range. In the following example both borders are wrong but no error will be issued, returning the whole string instead:

  > strings.sub('agena', 0, 10):

- The new C API function `agnL_iscallable` checks whether a value is callable like a function.

- The new C API function `agn_isposint` checks for a positive integral number in the stack.

- The new C API function `agn_isnonnegintint` checks for a non-negative integral number in the stack.

- The new C API macro `lua_isfalseorfail` checks whether a value in the stack is either `false` or `fail`.

- The new C API macro `lua_isnilfalseorfail` checks whether a value in the stack is either `null`, `false` or `fail`.

- The 'json' package could not treat UTF-8 characters and JSON arrays. This has been fixed. Also did some minor tuning of both `json.encode` and `json.decode`.

- The release has been named after the the City of Conroe, Texas.


3.0.0 Tel Aviv, July 04, 2023

- The `is` token in procedure definitions with `proc` and `procedure` has become optional.

- The behaviour of substring indexing when using the `to` token has been changed: if the right border is greater than the length of the string, then it is auto-corrected to the string length, thus no longer issuing out-of-range errors. If the left border is 0 or greater than the length of the string, however, there will still be an error:

  > s := 'agena'

  > s[2 to 6]:  # resulted in an error before
  gena

  > s[6 to 7]:
  Error in substring op: left index 6 out of range.

- Added the 'json' package which has originally been written by David Heiko Kolf for Lua 5.1+. It encodes a table to a string representing a JSON object and can also decode a JSON object represented by a string to an Agena table:

  > import json

  > data := [
  >    'city' ~ 'Tel Aviv',
  >    'iscapital' ~ false,
  >    'founded' ~ 1909,
  >    'details' ~ ['population' ~ 467875, 'area' ~ 52]
  > ]

  > s := json.encode(data):
  {"details":{"population":467875,"area":52},"iscapital":false,"city":"Tel Aviv","founded":1909}

  > json.decode(s):
  [city ~ Tel Aviv, details ~ [area ~ 52, population ~ 467875], founded ~ 1909, iscapital ~ false]        95

- For better portability of Lua code to Agena, added the Lua 5.4 function `strings.byte` which returns all the ASCII codes of the characters in a string. Examples:

  > strings.byte('agena'):
  97

  > strings.byte('agena', 1, 5):
  97      103     101     110     97

- New `os.mklink` creates symbolic or hard links on the file system.

- In OS/2, `os.fattrib` can now change file timestamps, at last.

- `stats.minmax`, when given a sequence, did not ignore `undefined` values as it should have. This has been fixed.

- Removed the following aliases to deprecated functions and constants:

  - `strings.splitfields`, call `strings.fields` instead;
  - `strings.wrapmissing`, call `strings.wrap` with the `true` option instead;
  - `math.arctanh`,        call `arctanh` instead.
  - `environ.pathmax`,     call `environ.kernel('pathmax')` instead;
  - `environ.buffersize`,  call `environ.kernel('buffersize')` instead;
  - `environ.minlong`,     call `environ.kernel('minlong')` instead;
  - `environ.maxlong`,     call `environ.kernel('maxlong')` instead;
  - `environ.maxinteger`,  call `environ.kernel('maxinteger')` instead.

- Removed various experimental, test and obsolete functions, all undocumented, from the `math`, `fastmath`, `strings`, `os`, `hashes`, `tables` and `sequences` packages.

- Cleansed the header files and UNIX build scripts. Also improved description on how to compile Agena in OS/2, in file src/makefile.os2.

- Besides a version number, each major Agena release will now have a codename. We are starting with the city of Tel Aviv, State of Israel.


2.41.3, July 04, 2023

- `calc.chebyt` has become more than thrice as fast for arguments x with |x| <= 1. The results have become more accurate, as well. With arguments |x| > 1, the function now no longer computes cos(n*arccos(x)), but returns cosh(n*arccosh(x)) instead, even for x < -1.

- In OS/2 and DOS, the complex versions of `arcsin`, `arccos` and `arcsec` have been tuned.

- Although not present on the ZX Spectrum, the following functions are now available in the `zx` package, most of them implemented upon existing ZX CORDIC logic:

  - The functions `zx.ASNH` for inverse hyperbolic sine, `zx.ACSH` for inverse hyperbolic cosine and `zx.ATNH` for inverse hyperbolic tangent have been added.

  - New `zx.SINH` approximates the hyperbolic sine, `zx.COSH` the hyperbolic cosine, `zx.TANH` the hyperbolic tangent, `zx.SECH` the hyperbolic secant, `zx.CSCH` the hyperbolic cosecant and `zx.COTH` the hyperbolic cotangent. Also added secant, cosecant and cotangent functions `zx.SEC`, `zx.CSC` and `zx.COT`.

  - The new function `zx.ERF` implements the error function and `zx.GAM` the Gamma function.

  - The new constant `zx.E` represents Euler's constant zx.EXP(1) = 2.7182818...

  - The constant `zx.PI` has been changed from Agena's Pi constant to 4*zx.ATN(1) which is much closer to the ZX Spectrum implementation.

- Improved the index of the Primer & Reference.


2.41.2, June 30, 2023

- `strings.format` and thus also `printf` support the new '%le' specifier, printing numbers in scientific notation with 16 fractional digits by default.

- With argument n, 255 < n < 512, `math.lnfact` has been tuned by seven percent, fetching the result from an extended look-up table.

- `math.zeroin` inadvertently returned the absolute value of its argument if it was not within the given epsilon range. This has been fixed and now the original argument is returned.

- The new function `long.lnfact` computes the logarithmic factorial ln n! in 80-bit precision.

- The new function `long.lnabs` implements the natural logarithm of the absolute value of its argument.

- New `long.redupi` subtracts the nearest integer multiple of Pi from its argument.

- Introduced the new constant `long.DoubleEps` which represents a 80-bit machine epsilon value, around 1.0842e-19.

- New constant `long.MinDouble` represents the smallest normalised positive longdouble value, around 3.3621e-4932.

- New `long.zeroin` "sets" its argument to zero if it is less than or equal to `long.DoubleEps`. You may additionally pass an alternative epsilon value.

- The new function `long.zerosubnormal` checks whether its longdouble argument is subnormal and in this case returns 0, otherwise returns its argument.

- New `long.normalise` converts a subnormal longdouble into the smallest nearby normal longdouble value.

- The `long` pretty-printer has been improved by no longer outputting numbers with too many digits. If a value "absolutely" is less than 1e-20 or greater than 1e20, then it is formatted in scientific notation.


2.41.1, June 26, 2023

- New `stats.laplace` implements the Laplace distribution and the corresponding probability density function.

- New `long.gamma` computes the gamma function in 80-bit precision.

- The `lngamma` operator can now process longdoubles, and the new corresponding `long.xlngamma` function, too. Both compute the logarithmic gamma function in 80-bit precision.

- New `long.fact` returns the factorial n! in 80-bit precision.

- Processing of long doubles by the `exp` operator and by `long.xexp` has been tuned, same with the `^` exponentiation operator.

- With very big numbers, the `long` package pretty-printer `long.tostring` crashed Agena. This has been fixed.


2.41.0, June 25, 2023

- New `math.dblfact` computes the double factorial n!! and `math.trifact` the triple factorial n!!!.

- Previously undocumented `calc.lnfact`, which computes the logarithmic factorial, has been described in the Primer and Reference.

- New `calc.auxSiCi` implements auxiliary sine and cosine integrals.

- New `calc.Cin` computes the entire cosine integral.

- New `calc.Ein` implements the entire exponential integral.

- New `calc.eta` computes the Dirichlet Eta function.

- New `stats.logistic` computes both the logistic distribution and the corresponding probability density function.

- New `stats.geometric` computes the geometric cumulative distribution, and alternatively the geometric probability point distribution.

- New `stats.logseries` computes the log(arithmic) series cumulative distribution.

- In the real domain, `beta` has become seven times faster.

- Integer exponentiation in the complex domain with the `**` operator has been tweaked with larger powers and with OS/2 and DOS in general.

- Tuned `proot` in the complex domain a little bit.

- Improved accuracy of `fma` and `squareadd` in both the real and complex domain, at the expense of speed.

- `astro.moonriseset`, `astro.sunriseset`, `fractals.lsin` and `fractals.lbea` have been tuned.

- `calc.euler` now computes in O(1) time instead of O(n) with argument n <= 186.

- In OS/2 and DOS, `arctan2` has been tweaked.

- In OS/2 and DOS, the complex versions of `arcsin`, `arccos`, `arcsec` and `arcsinh` have been completely rewritten, with the code much shorter than before. The speed of all four functions, however, remains the same.


2.40.1, June 18, 2023

- A `catch` statement in the code could cause Agena to crash every time the parser could not distinguish between a user-given error variable and the start of the actual `catch` block. When an explicit error variable is given, then the `catch` token must now be succeeded by the `in` token:

  > try
  >    error('my error')
  > catch in errmsg then
  >    print(errmsg)
  > end;

  The old syntax without an explicit error variable name still works as before:

  > try
  >    error('my error')
  > catch
  >    print(lasterror)
  > end;


2.40.0, June 18, 2023

- `signum` accepts booleans: with `true` returns +1, and with `false` or `fail` returns -1. Like `abs`, this allows for conditional arithmetics without using `if`s.

- New `math.redupi` subtracts the nearest integer multiple of Pi from its argument.

- `exp2` has been tuned by 35 percent in the real domain. The speed in the complex domain remains the same.

- In the complex domain, the `log` operator has been tuned by a factor of 2.3.

- In the complex domain, `arcsech` has been tuned by a factor of 2.7. It has become 20 % faster in the real domain, too.

- In the complex domain, `arccsc` has been tuned by 15 percent, and by 12 percent in the real domain.

- In the complex domain, `arccsch` has been become twice as fast. In the real domain, its speed has been increased by 18 percent and the function has become more accurate around the pole.

- `arctanh` has become 15 percent faster in the real domain. The speed in the complex domain remains the same.

- `dual.arctanh` has been tweaked by 15 percent.

- The 'pathmax' and 'maxinteger' settings are now being returned when calling `environ.kernel` without arguments.

- Reduced memory consumption of `os.listcore` and `os.iterate` primarily on UNIX-based systems.

- The system variable `environ.pathmax` has been deprecated. Use environ.kernel('pathmax') instead.

- The system variable `environ.buffersize` has been deprecated. Use environ.kernel('buffersize') instead.

- The system variable `environ.minlong` has been deprecated. Use environ.kernel('minlong') instead.

- The system variable `environ.maxlong` has been deprecated. Use environ.kernel('maxlong') instead.

- The system variable `environ.maxinteger` has been deprecated. Use environ.kernel('maxinteger') instead.

- Aliases for all the above mentioned system variables have been provided to ensure backward-compatibility.

- `math.arctanh` has been deprecated. Use `arctanh` instead. An alias has been provided to ensure backward-compatibility.

- Alias `math.modinv` has been removed. Use `math.invmod` instead.

- Alias `strings.isabbrev` has been removed. Use `strings.isstarting` instead.

- Alias `math.hEps` has been removed. Use `hEps` instead.

- Alias `math.Phi` has been removed. Use `Phi` instead.

- Alias `rtable.rdelete` has been removed. Use `rtable.purge` instead.

- Alias `rtable.rget` has been removed. Use `rtable.get` instead.

- Alias `rtable.rinit` has been removed. Use `rtable.init` instead.

- Alias `rtable.rmode` has been removed. Use `rtable.mode` instead.

- Alias `rtable.rset` has been removed. Use `rtable.put` instead.

- Alias `math.arcsinh` has been removed. Use `arcsinh` instead.

- Alias `math.arccosh` has been removed. Use `arccosh` instead.

- Alias `math.exp2` has been removed. Use `exp2` instead.

- Alias `math.exp10` has been removed. Use `exp10` instead.

- Alias `sadd` has been removed. Use `sumup` instead.

- Alias `smul` has been removed. Use `mulup` instead.

- Alias `qsadd` has been removed. Use `qsumup` instead.

- Alias `tables.swap` has been removed. Use `swap` instead.

- Alias `sequences.swap` has been removed. Use `swap` instead.

- Alias `registers.swap` has been removed. Use `swap` instead.

- Alias `os.mkstemp` has been removed. Use `io.mkstemp` instead.

- Alias `os.iseCS` has been removed. Use `os.isos2` instead.

- Alias `os.isUNIX` has been removed. Use `os.isunix` instead.

- Alias `os.isANSI` has been removed. Use `os.isansi` instead.

- Alias `os.mousebuttons` has been removed. Use `os.mouse().mousebuttons` instead.

- Cleansed the source file distribution.


2.39.12, June 11, 2023

- New `os.isdriveletter` checks whether its input string represents a drive letter, such as `c:` or `d:\`.

- New `os.isdow` returns `true` in DOS, OS/2 and Windows, and `false` otherwise.

- New `os.getdirpathsep` returns both the directory and path separators. Examples are '\' and ';' in DOS-based systems.

- `os.getmodulefilename` now supports OS/2.

- `strings.tolower`, `strings.toupper`, `strings.isolower` and `strings.isoupper` now work with strings that include embedded zeros, which are preserved in the output.

- The following functions now ignore embedded zeros and check the entire string: `strings.isupperlatin`, `strings.islowerlatin`, `strings.isloweralpha`, `strings.isupperalpha`, `strings.ismagic`, `strings.islatin`, `strings.islatinnumeric`, `strings.isnumber`, `strings.isspace`, `strings.isalpha`, `strings.isalphaspace`, `strings.isalphanumeric`, `strings.isascii`, `strings.words`.

- Tweaked `os.listcore` and `os.iterate` by avoiding internal string duplication.

- Tuned `strings.capitalise` and `strings.uncapitalise` by 13 percent.

- The internal character buffer library contained a flaw that could crash Agena, especially with larger strings. This has been fixed. The operators and functions affected were: `join`, `replace`, `bytes.pack`, `com.read`, `strings.remove`, `memfile.charbuf`, `memfile.bytebuf`, `memfile.bitfield`, `memfile.dump` and `memfile.replicate`.

- `bytes.trailzeros` now correctly fills trailing zeros with 1's in the second return.


2.39.11, June 06, 2023

- `os.isvaliddrive` now supports OS/2 and DOS.

- `os.isremovable` now also works in DOS.

- In OS/2, `os.drivestat` now returns FSD Attach Data - if it is available - with the new 'rgFSAData' field. The numeric values represented by the 'iType' field have been explained in the Primer and Reference. The function now accepts alphabetical drive letters only - previously, '[' and '@' were erroneously taken in OS/2, as well.

- In OS/2, DOS and Windows, the drive letter may be given as a single character (e.g. 'c'), a letter followed by a colon ('c:') or a letter followed by a colon and a (back)slash ('c:/', 'c:\\') to the following functions: `os.drivestat`, `os.ismounted`, `os.isremovable` and `os.isvaliddrive`.

- `strings.strlen` no longer inadvertently returns four values.

- Various cross-references have been added to Chapter 9 `Strings` of the Primer and Reference.


2.39.10 Library Update 1, May 31, 2023

- When given '.' as a second argument, `os.whereis` sliced off parts of the resulting file names. This has been fixed.

- When given '*' as a second argument, `os.whereis` will now search the current working directory, as '.' does, and will no longer throw an error.

- Corrected the Primer and Reference.

- You will find the update in the Binaries/Agena 2.39.10 Sourceforge folder, file `agena-2.39.10-update1.zip`. Download it and check the instructions on how to install this library update on any supported operating system, see `libupdate.readme` file at the root of the ZIP archive.

- Updated the `rase` package which now includes a Windows command-line utility to search for a file in a path, optionally also printing file sizes and dates.

  For a quick demo, unpack all the files into a new, fresh directory, change into this directory and run the `whereis.exe` binary in an NT shell as follows (type `whereis /h` for help):

  whereis /r /a "agena.*" c:/agena


2.39.10, May 30, 2023

- `strings.isending`, `strings.chomp`, `strings.ltrim`, `strings.rtrim` and `strings.lrtrim` could modify their input strings. This security issue has been fixed.

- `strings.rtrim` and `strings.lrtrim` could return a garbled string, causing memory leaks, if the second argument consisted of more than one character. This has been fixed.

- `strings.rotateleft` and `strings.rotateright` could theoretically cause memory leaks. A patch has prophylactically been applied.

- In Windows, `os.symlink` modified its input strings and could even crash Agena. This has been fixed.

- The error messages of `strings.isending`, `strings.ltrim` and `strings.rtrim` have been fixed.


2.39.9, May 29, 2023

- In Windows, `os.iterate` did not properly clean up internal directory handles. This has been fixed.

- `os.whereis` now conducts an automatic garbage collection before returning the result, so that all open directory handles are closed and directories traversed before can be changed.

- `os.iterate` did not work in Windows 2000. This has been fixed.

- In Windows, `os.realpath` on failure just returned its first argument. Now it returns `fail` as on all other platforms.

- In OS/2, DOS and Windows, `os.realpath` no longer returns the current working directory when given just the drive (such as `c:` or `c:\`), but now just returns the drive letter, followed by a colon and a slash.


2.39.8, May 27, 2023

- `os.iterate` has been patched to properly iterate an entire Windows drive. It also automatically skips Windows system directories instead of issuing an error. Examples for system directories are `PerfLogs` or `AppData`.

- The new function `os.issysdir` checks whether a Windows folder is a system directory.

- `os.fstat` can now properly detect all kinds of Windows system directories and sets the 'system' entry to `true` instead of `false`.

- When only a drive letter along with a colon is passed to `os.dirname`, then the function appends a trailing slash to the result, e.g. 'c:' -> 'c:/'.

- `os.whereis` has become around 25 percent faster while using much less memory than the previous version did.

- `strings.glob` modified the input strings. This has been fixed.


2.39.7, May 23, 2023

- The factory created by `os.iterate` no longer returns the '.' and '..' placeholders depicting the current and parent directories.

- `os.dirname` - when given a path to an actual directory on the file system - returned a string with a trailing embedded zero ('\0'). This could confuse other functions, such as `os.iterate`, when passed as input. This has been fixed.

- The new -D command-line switch, along with an integer in the range 1 to 17, sets the number of digits used in the output of numbers. Note that this setting does not affect the precision of arithmetic operations. The default is 14.

- The -s command-line switch will now be ignored if given no slogan text.

- Improved description of `environ` package functions and of `os.iterate` in the Primer and Reference.


2.39.6, May 22, 2023

- The `tuples` package has become a standard library, you no longer have to invoke it with the `import` statement.

- `tuples.tuple` did not assign a metatable to the resulting object. This has been fixed. Likewise, `tuples.map`, `tuples.select`, `tuples.remove` and `tuples.subs` have been patched.

- `tuples.getsize` no longer issues an error if a tuple is empty, and now returns zero.

- With an empty tuple, `tuples.toseq`, `tuples.toreg` and `tuples.totable` return empty structures and no longer throw an error.

- New `tuples.unpack` works like `unpack`, dumping the entire contents, but for tuples only.

- `math.convertbase` has been tweaked by five percent.

- `setmetatable` can now assign metatables to functions written in the Agena language, but not to C library functions or C closures as this would cause memory leaks when overwriting their garbage collection methods.

- When passing the new -C switch on the command-line, constants defined with the `constant` keyword can be overwritten.

- The Mac OS X installer no longer writes obsolete packages to disk.


May 20, 2023

- The Sourceforge discussion forum has been reopened. There is also a thread for compiling Lua on OS/2 and DOS.


2.39.5, May 20, 2023

- A statement can no longer consist of just a constant or an isolated call to an operator, thus fully reintroducing the parsing behaviour as before Agena 2.37.2. It proved that such stand-alone statements - mostly with no effect - did not work well in loops and also caused problematic side effects. In this context, the `popd` operator has been converted back to a function in order to work.

- Furthermore, for the sake of continuity, the automatic check for oversized numeric constants that has been introduced in 2.39.4 has been switched off. You can switch it on by setting

  > environ.kernel(constanttoobig = true);

  in a session, or by passing the -B switch at startup on the command-line.

- On Windows 2000 and probably further older Windows versions and non-Windows platforms, the error tracker for oversized constants was not properly reset, causing Agena to complain about constants that were well within limits. This has been fixed.

- To avert potential problems with uncleared internal C error handles in Windows 2000 and maybe other platforms, the following packages have prophylactically been patched on all operating systems by explicitly resetting the C error handle before invoking the C function to be tracked: `stack`, `numarray`, `memfile`, `io`, `binio`, `com` and `os`. Other packages and functions are not subject to this potential flaw.

- When converting to base 10 and depending on the magnitude of a value, `math.convertbase` often returned a string in scientic e-notation. This has been fixed.

- Some code-cleansing.


2.39.4, May 19, 2023

- Binary and octal constants now cover a wider numeric range and may even include a fraction and a `p-exponent` part. Try this:

  > -0b1111.11110101:
  -15.95703125

  > 0o1212111121211111p0:
  44677479076425

- Agena now issues a syntax error if a binary, octal, decimal or hexadecimal constant is too big. This prevents you from using constants that have already overflown, avoiding wrong results. You can switch off this behaviour by setting:

  > environ.kernel(constanttoobig = false);

  in a session, or by passing the new -B switch at startup on the command-line.

- Likewise, the range of values `strings.strtoul` and `math.octtodec` can process has been extended well beyond 2^32 - 1.

- `math.convertbase` has become twice as fast when converting to a base other than 10 or 16.

- New `math.bintodec` converts a string representing a binary value into a number. The string may or may not start with `0b`, and also may contain a sign, a fraction and a `p-exponent` part.

- `math.octtodec` now returns `undefined` if the value to be converted is too big; previously the decimal 2^32 - 1 has been returned in those cases.

- Added Lua 5.4.4 patch 8 to the `utf8` package: 'utf8.codes does not raise an error on spurious continuation bytes.'

- Agena crashed with a segmentation fault when given an invalid switch at start-up, or when just printing the help with the -h switch. This has been fixed.

- The OS/2 WarpIN installer no longer adds additional icons to the Agena WPS folder when overinstalling a previous release, but just replaces them.


2.39.3, May 18, 2023

- The new function `strings.strtoul` tries to convert an integer of a given base represented by a string to a decimal value. The function provides an interface to the underlying strtoul C function.

- New `math.hextodec` converts a string representing a hexadecimal value into a number. The string may or may not start with `0x`, and also may contain a sign, a fraction or a `p-exponent` part.

- New `math.octtodec` converts a string representing an octal value into a number. The string may or may not start with `0o` and contain a sign.

- Generally, `math.convertbase` has become eleven percent faster, conversion of hexadecimals to decimals has been sped up by 33 percent and any other conversion to decimals by 40 percent - by calling optimised functions if possible. You may skip optimisation by passing any fourth argument.

- `strings.contains` has become 20 percent faster in the Agena 32-bit editions.

- `tar.list` has become 20 percent faster.

- On Windows only, new `os.getmac` returns the MAC address for an IP address and new `os.getadapter` returns various information on the network adapters installed on the host.


2.39.2, May 12, 2023

- Starting with release 2.37.2, Agena became more lenient with stand-alone expressions that do not make sense and were simply ignored. The rules have, however, been tightened to prevent expressions such as null[2] or 2[1] from being accepted.

- Added the -S switch as a command-line option, preventing Agena from printing the start-up copyright notice.


2.39.1, April 30, 2023

- New `os.getip` returns the IP address of a domain. If no domain is given, the function tries to retrieve the IP of the host. The function is not available in DOS.

- `os.clock` can now count beyond 24.8 days, only resetting after many years, and always returns the elapsed time in milliseconds on all platforms.

- `os.pause` now returns the elapsed time until a keypress in seconds including milliseconds on all platforms.

- In Windows only, `os.uptime` queries the current performance counter, a high resolution (1 microsecond or better) time stamp, if any argument is given.

- New `strings.unwrap` removes enclosing characters from a string. Related `skycrane.removedquotes` has been removed but an alias has been provided to ensure backward compatibility.

- `strings.wrap` now also accepts numbers, Booleans or `null` and converts them to strings before wrapping. Corresponding `skycrane.enclose` has been removed but an alias has been provided for backward compatibility.

- `strings.fields` returns all fields when given no indices, and also removes enclosing quotes or other characters with the new `unwrap` option. Further new options are: `delim` indicating the separator and `convert` for converting fields to numbers.

- `strings.iterate` and `strings.gseparate` now support automatic conversion of fields to numbers with the new `convert` option and also remove enclosing characters with the new `unwrap` option.

- The new `init` option to `strings.gseparate` allows to define an alternative start position.

- `strings.splitfields` has been deprecated, use `strings.fields` instead which is four times faster. An alias has been provided for backward compatibility.

- `strings.wrapmissing` has also been deprecated, use `strings.wrap` instead and pass `true` as the third argument. An alias has been provided for backward compatibility.

- `strings.iterate` and `strings.gseparate` in ill-fated situation could have corrupted the stack - this has been fixed.

- The `regex` package is now available in the DOS edition.

- The DOS edition has been compiled with latest DJGPP/GCC 12.2.0.

- `os.system` and `os.winver` detect Windows 11.

- os.monitor('on') did not work on some Windows flavours. A workaround has now been implemented so that the screen is woken up, but this still does not succeed on every hardware.

- In Mac OS X, the bitwise operators &&, ||, ^^, `bytes.numto32` and the like now return the same results in overflow situations as on every other x86-based platform. This also applies to various `hashes` package functions.

- `hashes.squirrel64` has been fixed on OS/2 and Mac OS X.


2.39.0, April 19, 2023

- Strings enclosed in backquotes are now evaluated differently than strings in single or double quotes: A backslash in a string enclosed in backquotes will not be escaped any longer. This spares you from entering the backslash twice when it shall be part of the string. This is useful especially when working with regular expressions.

  The only exception is the character sequence \q which denotes a backquote.

- The new `regex` library is a regular expression library providing a PCRE2 binding. It has originally been written by Reuben Thomas and Shmuel Zeigerman for Lua 5.x. It is available in OS/2, Windows, Intel Linux, x86 Mac OS X and x86 Solaris as well as Raspian ARM. UNIX users may need to install the pcre2-8 library before using the binding.

- New `strings.stricmp` compares two strings like `strings.strcmp`, but case-insensitively.

- New `strings.strncmp` works like `strings.strcmp` but just compares the first n characters only.

- A bug in the colon pretty-printer, causing a memory leak if the input line contained leading spaces, has been fixed.

- In Solaris, the `xml` and `gzip` packages have been updated to the latest versions.


2.38.3, April 07, 2023

- The new unary `unity` operator returns just its only argument, and with function calls returning multiple results, returns just the first, which is useful to prevent passing additional arguments to other functions that might not expect them. Example:

  `tables.entries` always returns two results, the table entries and a Boolean, but the sorted function does not accept the latter:

  > tables.entries([3, 2, 1]):
  [3, 2, 1]       false

  > sorted(tables.entries([3, 2, 1])):
  Wrong argument #2 to `sorted`: procedure expected, got boolean.

  > sorted(unity tables.entries([3, 2, 1])):
  [1, 2, 3]

  If a function call does not return anything, `unity` returns `null`.

- New `bytes.swap` swaps all bytes in an unsigned 4-byte integer.

- New `bytes.swaplower` swaps the lower bytes of an unsigned 4-byte integer, new `bytes.swapupper` does so for the upper bytes.

- New `bytes.interweave` combines two unsigned 4-byte integers with the XOR, AND or OR binary operation, optionally applying a mask and taking either the C % or Fibonacci modulus, all in only one call.

- `bytes.tobytes` can now convert signed 2-byte integers, by passing -2 as the second argument.

- `bytes.tobytes` could not convert signed 4-byte integers. This has been fixed.

- `hashes.derpy` now by default returns a XOR-interweaved unsigend 4-byte integer result, as this produces even less hash collisions. You can return the original higher and lower parts by passing the new 'false' option as the third argument.

- `hashes.bsd` now can process strings with embedded zeros. However, this doesn't make the quality of the results any better as it still is poor.

- Fixed error messages of `values` and `times`.


2.38.2, April 05, 2023

- `math.isprime` has been tuned by yet another ten percent.

- `math.gcd` and thus `math.lcm` have become 12 % faster.

- `bytes.mostsigbit` has been tweaked by 7 percent.

- `binsearch` could not search elements in structures of size 2 or less. This has been fixed, also benefiting `bintersect`, `bminus` and `bisequal`.

- Fixed binary search in very large data structures by preventing arithmetic overflow.

- `hashes.fibmod` has become 25 percent faster if its second argument is a power of 2 and the third argument has been set to `true`.

- New `hashes.fibmod2` takes any integer and the exponent of a power of two and computes a more evenly distributed sequence of numbers than the classic % modulus operator does. It is 20 % faster than `hashes.fibmod` called with a power of 2.

- New `hashes.squirrel32` applies Squirrel Eiserloh's hash function on an integer.

- New `hashes.squirrel64` takes a floating-point Agena number, integral or fractional, and applies Squirrel Eiserloh's hash function, returning two unsigned 4-byte integers as the higher and lower words of the hash.

- New `hashes.derpy` computes the Derpy hash for a given string.


2.38.1, March 30, 2023

- New `math.mulmod` performs modular multiplication (a*b)%n, avoiding overflow and underflow.

- New `math.invmod` computes the modular multiplicative inverse, avoiding overflow and underflow.

- `math.modiv` has been deprecated, use `math.invmod` instead. An alias is available for backward compatibility.

- Fixed various issues in `math.powmod` which performs modular exponentiation, especially with small values and previously negative results.

- Tweaked `math.isprime`, `math.prevprime` and `math.nextprime`.


2.38.0, March 26, 2023

- New `memfile.match` searches for a string in a buffer and supports pattern matching.

- New `memfile.mfind` searches for all the occurrences of a substring in a buffer and returns a sequence of pairs representing the respective start and end positions. The function supports pattern matching.

- New `memfile.replace` substitutes a substring or sequence of bytes in a buffer, in-place. Pattern matching is supported.

- If the pattern given to `memfile.find` is the empty string, the function now returns `null` instead of returning a fake position.

- `memfile.dump` now returns `null` instead of issueing an error if the buffer is empty.

- When given just the memory file, but no positions, `memfile.substring` now returns its whole contents without dumping it. The function now also returns `null` instead of issueing an error if the buffer is empty.

- If given no third argument, `memfile.purge` deletes just the character or byte at the given position.

- Protected `memfile.put` against illegal positions which could result into memory leaks.

- The `in` and `notin` metamethods for memory files now return `null` and `true`, respectively, when searching for the empty string. This is the same behaviour as with ordinary strings.

- `strings.random` now accepts a character set and returns a random string consisting entirely of the given characters:

  > strings.random(16, 'abcdef01234'):
  cdbfe314f00af1be

- To delete a comment or description, you might now pass `null` instead of an empty string to `ads.desc` and `ads.comment`.

- For consistency with the `in` operator, `instr` and `strings.find` now return `null` if the pattern to be searched is the empty string. Previously, a confusing result such as 1:0 had been returned.

- With strings, the `has` function has been tuned by up to 25 percent. The function now also returns `false` instead of issueing an error if the second argument is the empty string.

- The new C API function `luaL_checklstringornil` either checks for a string or `null`, and with the latter returns the empty string of length 0.


2.37.9, March 19, 2023

- On Intel platforms, `os.cpuinfo` returns information on L1/L2/L3 caches with the new 'cache' entry. Mac OS X is not supported.

- On Debian-based systems, `os.cpuinfo` returns detailed information on the underlying CPU hardware in the 'cpuid' field.

- `math.isprime` has become 20 % faster.

- `math.nextprime` has been tuned by 15 %.

- Tweaked `approx`, `long.approx`, `math.triangular` and `math.chop` a little bit.


2.37.8, March 15, 2023

- New `strings.strcoll` compares two strings dependent on the current locale, see  `os.setlocale`.

- New `strings.strspn` and `strings.strcspn` get the span of a given character set in a string.

- If the right operand to `split` is the empty string, then the operator will split a string into its individual characters.

- Improved `io.sync` and `binio.sync` by both flushing and synchronising all internal buffers for a given file.

- Tuned internal array and string creation, benefitting various string processing operators and functions.


2.37.7, March 11, 2023

- `strings.capitalise` and `strings.uncapitalise` can now process multiple words in a sting, by passing an optional word separator:

  > strings.capitalise('san antonio, texas'):  # capitalise first word only
  San antonio, texas

  > strings.capitalise('san antonio, texas', ' '):  # capitalise all words
  San Antonio, Texas

- `strings.splitfields` and thus also `utils.readcsv` could not remove enclosing quotes if the field included the delimiter - now they do.

- `utils.writecsv` now accepts a file handle and in this case writes a full line only:

   > utils.writecsv(io.stdout, ['Zip', 'City', 'State Id', 'State', 'Parish/County/Borough'], enclose='\"');
   "Zip";"City";"State Id";"State";"Parish/County/Borough"

- Renamed `ads.openbase` to `ads.open`, `ads.closebase` to `ads.close`, `ads.readbase` to `ads.read`, `ads.writebase` to `ads.write` and `ads.rawsearch` to `ads.find`. Aliases have been provided to ensure backward compatibility.

- `ads.find` supports pattern matching and can search all columns but the first if called with 0 as the third argument.

- `ads.iterate` now puts data in a table, so that the function return can be used efficiently and stack overflow errors are avoided with databases that contain a large number of columns.

- On error, all `ads` functions now reset the file position to the start.


2.37.6, March 07, 2023

- `ads.createbase` can now be given options in any order instead of a fixed sequence of arguments, such as:

  > ads.createbase('test.agb', base = 'database', desc = 'my database', cols = 5);

  instead of

  > ads.createbase('test.agb', 20k, 'database', 5, 30, 'my database');

  The function now issues an error instead of crashing the interpreter when not being able to create a file.

  It could also crash when given a description. This has been fixed, as well.

- `ads.writebase` could issue errors or even corrupt the database file when given invalid arguments. This has been fixed. The function has also been protected against potential crashes if there are more columns in a database than there are arguments in the call.

- Improved error handling of `ads.getvalues`, `ads.clean`, `ads.lock` and `ads.unlock` by resetting the file position to the start.

- `tostringx` now properly converts complex numbers to strings.

- In Solaris, `os.fstat` crashed when given a file handle. This has been fixed.

- On OS/2, `os.fstat` crashed when given a file handle. This has been hot-fixed by rejecting handles.


2.37.5, March 05, 2023

- `os.fstat` now accepts file handles returned by `io.open` and `binio.open`.

- In Windows, `binio.length` and `io.filesize` returned negative sizes with large files or issued errors. This has been fixed.

- `memfile.write` ignored the optional start position. This has been fixed. The function now also internally writes data in pieces of environ.kernel().buffersize bytes each, to prevent errors with large data chunks.

- With byte buffers, `memfile.append` now by default inserts integers passed as the second and following arguments as bytes, not as numbers converted to strings. You can override this by passing `false` as optional last argument.

- Improved error handling of `binio`, `memfile` and `numarray` package functions with invalid file handles.

- In OS/2, `os.memstate` returns the number of free memory bytes for the current process with the new 'freephysical' entry. It is equal to the 'maxprmem' entry and has been added for better portability of code.


2.37.4, February 27, 2023

- New `memfile.prepend` inserts strings or bytes at the beginning of a memory file. The function automatically grows the buffer if needed.

- You can now alternatively pass a sequence of bytes instead of a string as a search pattern to `memfile.find`.

- The first argument to `memfile.bytebuf` has become optional and defaults to zero.

- When inserting or deleting data at the start of a memory file with `memfile.put` or `memfile.purge`, Agena crashed. This has been fixed.

- When passing a sequence of bytes to `memfile.append`, Agena crashed. This bug has been fixed, too.

- Removed a memory leak stemming from the Agena initialisation of the `libname` system variable.

- This release has been Valgrind-checked on x86 and AMD64 Linux to ensure there are no internal errors or memory leaks.


2.37.3, February 26, 2023

- The new function `memfile.put` inserts characters or bytes into a memory file at a given position, shifting all other elements into open space. The function automatically grows the buffer if needed.

- The new function `memfile.purge` removes characters or bytes from a memory file at a given position, shifting down other elements to close the space.

- `memfile.append` can now add bytes to a byte buffer if the very last argument is `true` or the new `bytes = true` option has been given. The bytes should be in the range 0 to 255.

- You can now define a byte buffer of size zero with no pre-filled slots. Succeeding calls to `memfile.append` automatically enlarge the buffer if needed:

  > m := memfile.bytebuf(0);

  > memfile.append(m, 97, 98, 99, true);

- New `memfile.tostring` converts a sequence of bytes into a string.

- Some flaws in `memfile.setbyte` have been fixed.

- The new function `tables.getarray` tries to find a value with an integral key in the array part of a table.

- The new function `tables.gethash` tries to find a value with an integral key in the hash part of a table.

- New `hashes.numlua` returns the integral hash for any number, used internally to refer to numeric keys in the hash parts of tables.

- New `tables.geti`, `tables.getfield` and `tables.gettable` return table values, triggering metamethods if needed. Useful to explore the behaviour of the underlying lua_geti, lua_getfield and lua_gettable C API functions.

- New `tables.setfield` and `table.settable` set values into tables, triggering metamethods if needed. Useful to explore the behaviour of the underlying lua_setfield and lua_settable C API functions.

- `allotted` now works with the value cache (stack #7).

- When `memfile.write` tried to write to a file that has not been successfully opened before, Agena could crash. Potentially also affected had been various functions in the `binio` and `numarray` packages. This has been fixed.

- The C API function `agn_checkboolean` did not return 0 with `fail`. This has been fixed.


2.37.2, February 19, 2023

- `popd` has become an operator and is 2.5 times faster now.

- `switchd` and `stack.switchto` now memorise the current stack number before switching to another stack. You can switch back to the former stack by simply passing -1 to the `switchd` operator. This spares you adding code that stores the former stack number in order to change back later.

- `stack.selected` returns the number of both the current active stack and the formerly active one.

- `stack.dumpd` and `stack.explored`, `stack.removed`, `stack.dequeued` and `stack.replaced` have been tweaked.

- `pushd` could not put sequences and pairs onto cache stack #7. This has been fixed.

- Switching to non-existing stack #8 is no longer possible, which could crash Agena if any stack operations had been done on it.

- When removing values from value cache #7 with `stack.removed` or `stack.dequeued`, the stack top is now automatically nullified.

- `stack.resetd` did not nullify all the value cache positions cleared. This has been fixed.

- The parser no longer complains about statements such like

  > -1;

  > cos(x);

  etc. In most situations, these statements are without effect unless an operator has intentional side-effects, with `popd` currently the only one.


2.37.1, February 15, 2023

- When called with any second argument, `popd` did not properly reset the stack top of the value cache (stack #7). This has been fixed.

- When popping or removing values from the cache stack with `popd`, `stack.resetd` or `stack.dumpd`, all affected stack positions are now automatically nullified.

- `stack.enqueued` now requires at least one argument.

- `skycrane.removedquotes` has become twice as fast.

- `os.fcopy`, `os.dirname`, `os.filename`, `os.listcore` and `skycrane.trimpath` inadvertently changed their original input arguments. This has been fixed.

- `os.isarm` did not check for ARM, but for PowerPC platforms. This has been fixed.

- The sources have been adapted to compile again on both 32-bit and 64-bit Raspberry Pi. The regression tests have been successful. Note that the `long` package is not available on ARM platforms, and the `numarray` package does not process long doubles.

- The Agena Quick Reference has been resorted. A table of contents with hyperlinks to the various sheets in the Excel workbook has been added.


2.37.0, February 12, 2023

- Added a value cache that stores any kind of data and can be accessed via stack number 7, providing a maximum of 2,048 slots.

  Compared to corresponding table, sequence or register operations, those on the cache are twice as fast when adding values, 35 % faster when popping values, thrice as fast when swapping values and 30 times faster when both inserting and shifting into open space. Almost all functions in the `stack` package support the value cache.

  Examples:

  > switchd(7);
  > pushd 10, 20, 30;
  > popd():
  30

  > popd():
  20

  > popd():
  10

  > popd():
  null

  > pushd 10, 20, 30;

  > stack.swapd(0, 2);    # swap first and third value

  > stack.explored():     # view current cache contents
  seq(30, 20, 10)

  > stack.insertd(0, 0);  # insert zero to the bottom of the cache

  > stack.explored():
  seq(0, 30, 20, 10)

- Patched `strings.dump` to properly serialise functions.

- The Mac OS X version has been switched to word-aligned 4-byte strings to avoid bus errors.

- The new C API function `luaL_checkcache` reserves a given number of slots in a cache stack and issues an error if it could not.


2.36.3, February 11, 2023

- The new function `stack.writebytes` writes values from a number or character stack into a file.

- `stack.mapd` in some cases did not work with character stacks. This has been fixed.

- `strings.contains` always returned `true` if the first argument was the empty string. This has been fixed.

- `strings.contains` can now check for embedded zeros, expressed by the character sequence '\000'.

- `strings.strchr` now accepts both a number (an ASCII code) or a single character or empty string as the second argument.

- New function `strings.walker` returns the Shannon entropy of a string, the serial correlation coefficient, the Chi square distribution, the mean of the ASCII values in the string and the Monte Carlo value for Pi. It is an alternative to `strings.shannon`.

- `gzip.deflate` returns additional statistical data if the third argument `true` is given: the compression rate, size of the input string, the number of internally allocated bytes and the number of 16K blocks.

- `skycrane.isemail` has been improved yet another time.

- `os.date` has been fixed because it did not accept a format and the number of seconds since a given epoch. Also corrected the description in the Primer and Reference.


2.36.2, February 05, 2023

- New `curry` transforms a function with multiple arguments into a sequence of single-argument functions, i.e. f(a, b, c, ...) becomes f(a)(b)(c)...

  > f := << x, y, z -> x*y + z >>
  > t := curry(f, 10);  # returns f(10, y, z)
  > t(20, 30):
  230

  > u := curry(t, 20);  # returns t(10, 20)(z) = f(10, 20, z)
  > u(30):
  230

- `reduce` now accepts a new option, counter=true, which will assign an internal counter value, starting from one and incremented by one, to the last argument of the given function. This is 20 % faster than the existing _c=true option.

- `reduce` now supports folding, which means that the first value in a structure or string is taken as the initialiser, with the new fold=true option. In this case you do not need to - and should not - pass an initialiser explicitly as the first argument. Examples:

  > reduce(<< x, a, c -> a + x * 10^(c - 1) >>, seq(0, 3, 3, 3), counter = true, fold = true):
  333

  With strings, you should place an embedded zero, represented by '\000', at its start:

  > reduce(<< x, a -> a & x & '|' >>, '\0001234', fold=true):
  1|2|3|4|

- The new function `fold` works like `reduce` with the fold = true option:

  > fold(<< x, a -> a & x & '|' >>, '\0001234'):
  1|2|3|4|

- `skycrane.isemail` has been further improved and now also returns a reason why an address is invalid.

- Metamethods can now be assigned to procedures. This may be useful only with closures, which can be used to store data for faster access than is possible with tables, sequences or registers. Data stored in closures usually are called `upvalues`. Depending on the platform, the increase in speed when reading or writing upvalues is zero to nine percent, with generally less memory required.

- To store data in closures, use the `tuples.tuple` function:

  > import tuples

  > t := tuples.tuple(10, 20, 30)

  The `tuples` package provides functions and metamethods to work with tuples, see Chapter 10.12 of the Primer and Reference.

- If a procedure name is indexed with square brackets, the respective upvalues are returned if the procedure is a closure:

  > t[1], t[2], t[3]:
  10    20    30

- Procedures now support the '__index', '__writeindex', '__tostring', '__in', '__notin', '__filled', '__empty', '__union', '__minus', '__intersect', '__eq', '__aeq', '__eeq' and '__size' metamethods.


2.36.1, January 29, 2023

- `io.open` did not accept the 'a+', 'r+' and 'w+' options and also did not recognise the 'b' switch. This has been fixed.

- `io.infile` and `io.readfile` now support pattern matching.

- `skycrane.isemail` has been significantly improved, now also accepting preceding or trailing comments in the local-part of an address.

- The new C API function `agn_strmatch` searches a string for a substring, supporting pattern matching.

- The new C API functions `luaL_newref`, `luaL_pushref` and `luaL_freeref` originally written by Rici Lake for Lua 5.1 allow to work with C references to objects in the Agena stack.


2.36.0, January 25, 2023

- The new function `stack.cbrtd` computes the cubic root of the top element of the current numeric stack.

- The new function `stack.hypotd` computes the hypotenuse of the two top elements of the current numeric stack.

- The new function `stack.hypot4d` computes sqrt(x^2 - y^2) of the two top elements of the current numeric stack.

- The new function `stack.invhypotd` computes the inverse hypotenuse of the two top elements of the current numeric stack.

- The new function `stack.pythad` computes the Pythagorean equation a^2 + b^2 of the two top elements of the current numeric stack.

- The new function `stack.fmad` conducts the fused multiply-add operation x*y+z for the top three elements of the current numeric stack.

- The new function `stack.sinhd` computes the hyperbolic sine of the top element of the current numeric stack, in radians.

- The new function `stack.coshd` computes the hyperbolic cosine of the top element of the current numeric stack, in radians.

- The new function `stack.tanhd` computes the hyperbolic tangent of the top element of the current numeric stack, in radians.

- The new function `stack.arcsinhd` computes the inverse hyperbolic sine of the top element of the current numeric stack, in radians.

- The new function `stack.arccoshd` computes the inverse hyperbolic cosine of the top element of the current numeric stack, in radians.

- The new function `stack.arctanhd` computes the inverse hyperbolic tangent of the top element of the current numeric stack, in radians.

- The new function `stack.arctan2d` computes the arc tangent of y/x of the two top elements of the current numeric stack, in radians.

- `stack.mapd` can now entirely work on the stack and not only process one stack element, but others too, if the first argument `true` is given. Example: We have a function of three parameters x, y, z that returns x*y + z. The call puts the top three argumements 3, 2, 4

  > pushd 3, 2, 4

  into the argument list, pops them from the stack, pushes the result of the function call onto the stack and also returns it:

  > stack.mapd(true, << x, y, z -> fma(x, y, z) >>):
  10

- `stack.mapd` did not properly check for invalid indexes. This has been fixed. Also improved error messages.

- Extended the C API: The new C macros `lua_istrue`, `lua_isfalse` and `lua_isfail` first check whether a stack value is a boolean and then whether is true, false or fail.

- For speed, the C API functions `agn_istrue`, `agn_isfalse` and `agn_isfail` have become C macros.


2.35.5, January 21, 2023

- The `&` string concatenation operator now accepts Booleans as the left-hand and/or right-hand side operand.

- Usage of functions in `binary operator mode`, e.g.

  > '123' strings.isending '23':

  instead of

  > strings.isending('123' , '23'):

  caused the parser to get stuck in many situations. This has been fixed.

- `strings.isabbrev` has been renamed to `strings.isstarting`. An alias has been provided for backward compatibility so that you do not need to change your code.

- `os.inode` and `os.ftok` now work in the DOS edition.

- New `hashes.ftok` computes the System V Inter Process Communications key from three 4-byte integers.


2.35.4, January 17, 2023

- On all platforms, `os.getlocale` returns the current character classification of the C locale in the new field 'charset'. It is usually much shorter than the value returned in the 'locale' field on non-Windows versions.

- In Windows, `os.getlocale` returns the keyboard `locale` with the new field 'keyboard' containing the hexcode country string, language id and associated name, language primary ID and language sub-ID. Warning: On mixed systems (e.g. default system language UK and German keyboard) the information returned may be wrong.

- On Windows, and Windows only, new `os.getlanguage` returns the name of a language for a given language id.

- For standardisation, in Windows `os.fstat` now returns the volume ID in the field 'device'. The 'volume' field has been removed as it was unique in the Windows version, and you may have to change your code if you use the volume ID.

- In non-Windows versions, `os.fstat` now returns a pair in the field 'inode', where the left-hand side is always 0 and the right-hand side contains the actual inode, thus standardising the Windows and non-Windows returns. You may have to change your code if you use the inode.

- On OS/2, Windows and UNIX-like systems, new `os.ftok` generates a System V Inter Process Communications (IPC) key.

- On OS/2, Windows and UNIX-like systems, new `os.inode` returns unique device ID and inode for a given file.

- In OS/2, `os.fstat` returned invalid inodes. This has been fixed.

- Added the -a switch as a command-line option, causing Agena to ignore the setting of the AGENAPATH environment variable at start-up. The interpreter will try to initialise by searching the file system for an Agena installation. You can query the setting from the Agena prompt with `environ.kernel`, field 'skipagenapath'. This feature is useful if you have AGENAPATH set but want to use an alternative main Agena library file.

- Initialisation at start-up has become less strict regarding the location of the interpreter on the file system if AGENAPATH has not been set on your platform. Before, Agena in this situation always had to reside in a folder called exactly 'agena'. Now paths such like 'agena-2' or any other eligible folder name are supported.


2.35.3, January 07, 2023

- Integer exponentiation of complex numbers with the `^` and `**` operators has become 35 percent faster. Also tweaked accuracy of the two operators when raising a complex number to the power of a negative integer.

- Over the last releases and in the real domain, the `**` exponentiation operator had grown slower than the `^` operator. Now it has become around 20 percent faster.

- In the real domain, the new function invhypot(a, b) computes 1/sqrt(a^2 + b ^2), is 35 percent faster than a naive 1/hypot implementation and slightly more accurate.

- The accuracy of the `invsqrt` operator in the complex domain has been improved.

- The new function `os.prefix` returns a filename without suffix if there is one.


2.35.2, January 04, 2023

- The accuracy of the `sqrt` and the `^` operators in the complex domain has been significantly improved, especially with small real and imaginary parts, also benefiting `calc.eulerdiff` when computing the first derivative of a function that includes square roots or powers.

- When given an empty sample plus a point to be evaluated, `calc.interp` and `calc.neville` accessed invalid memory. This has been fixed by issuing an error in this case.

- Passing data other than a table or sequence as the first argument to the following functions could cause invalid memory access or lost memory: `calc.neville`, `calc.polyfit`, `calc.interp`, `calc.newtoncoeffs`, `calc.naksplinecoeffs`, `calc.clampedsplinecoeffs`, `calc.nakspline`, `calc.clampedspline`. This has been fixed by issuing a proper error.


2.35.1, January 02, 2023

- The generators that `calc.polygen` produces have become at least twice as fast while keeping accuracy.

- When given a vector of zero coefficients, `calc.polygen` accessed invalid memory. This has been fixed by issuing an error in this case. The description of the function in the Primer and Reference has been corrected, as well.

- Tweaked `math.sincospi`, and also `math.sinpi`, `math.cospi` and `math.tanpi`.

- `fractals.dragon` has been patched and tweaked.

- New `math.nearbyint` rounds to the nearest integer and `math.trunc` to the nearest integer towards zero. The functions have been included for C math library compatibility reasons only.

- New `long.unm` negates a number or longdouble.

- The following functions now accept 64-bit Agena numbers as input and return longdouble 80-bit results, the 2.35.0 implementation was faulty: `xcbrt`, `xcube`, `xexp`, `xrecip`, `xinvsqrt`, `xsquare`, `xsqrt`, `xsin`, `xcos`, `xtan`, `xarcsin`, `xarccos`, `xarctan`, `xarcsec`, `xsinh`, `xcosh`, `xtanh`, `xsinc`, `xsignum`, `xantilog2`, `xantilog10`, `xabs`, `xsign`, `xint`, `xfrac`, `xentier`, `xunm`.


2.35.0, December 30, 2022

- The new function `math.sincospi` returns both sin(Pi*x) and cos(Pi*x) for a given number x, with better precision than just calling the respective standard operators. If any option is given, the function returns tan(Pi*x), too. Likewise, new `math.sinpi`, `math.cospi` and `math.tanpi` solely compute the sine, cosine and tangent of their argument multiplied by Pi, respectively.

- Further extensions to the `long` and `numarray` packages to do 80-bit floating-point arithmetic:

  - The `square` operator has been protected against overflow and underflow, and treats subnormal numbers accordingly.

  - New long.pytha4(a, b) computes a^2 - b^2, avoiding undue overflow and underflow.

  - New long.hypot2(a) computes sqrt(1 + a^2), avoiding overflow and underflow.

  - New long.hypot3(a) computes sqrt(1 - a^2), avoiding overflow and underflow.

  - New long.hypot4(a, b) computes sqrt(a^2 - b^2), avoiding undue overflow and underflow.

  - The following functions now accept 64-bit Agena numbers as input and return longdouble 80-bit results: `xcbrt`, `xcube`, `xexp`, `xrecip`, `xinvsqrt`, `xsquare`, `xsqrt`, `xsin`, `xcos`, `xtan`, `xarcsin`, `xarccos`, `xarctan`, `xarcsec`, `xsinh`, `xcosh`, `xtanh`, `xsinc`, `xsignum`, `xantilog2`, `xantilog10`, `xabs`, `xsign`, `xint`, `xfrac`, `xentier`.

  - `environ.system` returns the size of long doubles in bytes in the new 'longdouble' field.

  - The `numarray` package has been extended to support longdouble arrays.

  - `numarray.write` can now write longdoubles to a file.

  - New `numarray.readlongdoubles` reads longdoubles from a file into a numarray.

  - New `binio.readlongdouble` and `binio.writelongdouble` read from and write longdoubles to a file. Big Endian platforms are not supported.

  - The pretty-printer has been enhanced, removing trailing zeros and better dealing with `undefined` and `infinity`.

  - `long.pytha` returned a wrong result if one of its arguments was zero. This has been fixed.

  - The new C API function `agnL_isdlong` checks for a longdouble value.

- Bug fixes:

  - `hypot4` now copes with subnormal numbers and is protected against overflow and underflow. The function also always returns 0 if the absolute values of both arguments are the same; in the past, with larger arguments, the result was near-zero. The loss in speed is one percent only.

  - `csc`, `sec` and `cot` now return `undefined` instead of a huge value if their arguments are very close to Pi or a a multiple of Pi.

  - In Windows and with GCC 9.2.0, the `int` truncation operator could sometimes return wrongs results since version 2.34.11. This has been fixed by switching to a portable implementation based on Sun Microsystems code.

  - `registers.new` when given a non-integral step size sometimes returned a register with the final element missing. This has been fixed.

  - `numarray.select` and `numarray.remove` have been patched when processing unsigned 4-byte integers.

  - `numarray.toarray` could not process ushorts and uint32s. This has been fixed.

  - The agena.xml scheme file has been fixed.

  - The Solaris, Mac and Red Hat installers no longer write any header files to subfolders in /usr/include or /usr/local/include.


2.34.11, December 24, 2022

This is a Windows-only update:

- The Windows version has now been compiled with MinGW GCC 9.2.0 and has become five percent faster.

- Adapted the sources to compile with GCC 6.5.0 in Solaris.

- `os.system` in theory could cause segmentation faults in Windows. This has been fixed.

- The Windows installer now includes a copy of the library file `libiconv2.dll` needed by the `gdi` and `gzip` packages on Windows XP and Vista. `libiconv-2.dll` is still being shipped, as well.


2.34.10, December 20, 2022

- If the left operand to the `**` exponentiation operator is non-integral, the operator now internally calculates with 80-bit instead of 64-bit precision and is also taking care of subnormal values.

- The accuracy of derivatives computed by `calc.savgol` has been slightly improved by internally computing in 80-bit floating-point mode. Also now internally computing with 80-bit precision with slight improvements in accuracy:  `calc.aitken`, `calc.bernoulli`, `calc.cheby`, `calc.chebyt`, `calc.clampedspline`, `calc.clampedsplinecoeffs`, `calc.eucliddist`, `calc.euler`, `calc.fmings`, `calc.fprod`, `calc.fsum`, `calc.gauleg`, `calc.gtrap`, `calc_intde`,  `calc_intdei`, `calc_intdeo`, `calc.interp`, `calc.iscont`, `calc.isdiff`, `calc.lambda`, `calc.limit`, `calc.linterp`, `calc.logistic`, `calc.logit`, `calc.nakspline`, `calc.neville`, `calc.polyfit`, `calc.polygen`, `calc.polygen`, `calc.regulafalsi`, `calc.sections`, `calc.sigmoid`, `calc.softsign`, `calc.variance`, `calc.weier`, `calc.zeroin`, `linalg.gsolve`, `linalg.rref`, `linalg_backsub`, `linalg_forsub`, `linalg.ludecomp`.

- `calc.intde`, `calc.intdei` and `calc.intdeo` have been protected against non-convergence, resulting in invalid memory access in previous versions in rare situations.

- `calc.eulerdiff` allows to compute the third derivative.

- To format 80-bit longdoubles, `strings.format` now accepts the new `ld` specifier. You may alternatively use the new `long.tostring` function allowing to format the string as `strings.format` does, see below.

- In OS/2 and Windows, `os.fstat` returns inode and device number in the new 'inode' and 'device' fields of the return.

- In UNIX, `os.fstat` now returns user and group IDs in the 'uid' and 'gid' fields.

- Further extensions and bug fixes to the `long` package providing 80-bit floating-point arithmetic:

  - The pretty printer now outputs longdoubles with 19 instead of 13 fractional digits.

  - New `long.tostring` converts a longdouble to a string and supports an optional format string, e.g.

    > long.tostring(long.Pi), long.tostring(long.Pi, "%.3ld"):

    returns

    3.1415926535897932385   3.142

  - The `**` exponentiation operator for integral powers now better handles subnormal long double values.

  - New `long.gsolve` solves a system of linear equations with 80-bit precision and returns a solution vector of longdoubles.


2.34.9a, December 16, 2022

This is a DOS-only update:

- The `long` package providing 80-bit floating-point arithmetic is now fully available in the DOS edition, see file `agena-2.34.9a-dos.zip` in the Sourceforge Binaries download folder.

- Removed duplicate information printed in debugging mode, when Agena is run with the -d switch. Also removed duplicate information when the main Agena library file could not be found at start-up.


2.34.9, December 15, 2022

- In a shell and in all supported operating systems, Agena switches can now be given with a preceding slash instead of a hyphen, e.g. `agena /d` and `agena -d` for debugging mode are accepted.

- `environ.kernel` could not change buffer sizes with the `buffersize` option. This has been fixed.

- In OS/2, DOS and Linux, internal buffers used by various string and I/O functions have been set to 512 bytes by default instead of the former 8,192 (OS/2 & Linux) and 16,384 bytes (DOS), reducing the memory imprint. The Solaris and Mac OS X (1,024 bytes) and Windows (512 bytes) settings have been left unchanged.

- In FreeDOS, the above mentioned change resulted in an increase of run-times of the reading and writing functions of the `binio`, `io`, `memfile` and `ads` packages by at least 250 %. In the other operating systems, the speed increase is marginal only.

- Improved debugging messages during start-up.

- Improved help message in the DOS version if AGENAPATH has not been set.

- Further extensions to the `long` package providing 80-bit floating-point arithmetic:

  - New `long.mantissa` and `long.significand` return the mantissa of a longdouble, whereas new `long.exponent` computes the exponent. For the difference, check the Primer and Reference.

  - New `long.pytha` computes the Pythagorean equation, avoiding underflow or overflow.

  - The `arcsin`, `arccos`, `arctan` and `arcsec` operators on longdoubles have been tuned by eight percent.


2.34.8a, December 14, 2022

- The OS/2 binary `agena-2.34.8a-os2.wpi` now includes the latest Agena version. The previous WarpIN installer accidently installed version 2.34.7.


2.34.8, December 09, 2022

- `ceil` with complex numbers has been tuned by 15 percent.

- New `floor` is just an alias to the `entier` operator, rounding downwards to the nearest integer.

- Further extensions and bug fixes to the `long` package providing 80-bit floating-point arithmetic:

  - New `long.multiple` checks whether a value is a multiple of another value.

  - New `long.chop` shrinks a value near zero to exactly zero, using one of several methods.

  - Added the constants `long.third`, `long.sixth`, `long.eighth`, `long.twelfth`, `long.sixteenth` and `long.threequarter`.

  - `signum` did not properly check for `long.undefined` and `long.infinity`. This has been fixed.

  - `long.modf` and `integral` have been tuned by 15 percent.

  - Tweaked `long.erf` and `long.erfc` a little bit.

- Cleansed and corrected the index of the Primer and Reference.


2.34.7, December 05, 2022

- The `integral`, `float` and `log` operators now support metamethods in general.

- Further extensions and bug fixes to the `long` package that provides 80-bit floating-point arithmetic:

  - The new function `long.count` can be used to implement iterators that count up or down, with a start and optional stop value and step size. It can be used to iterate over longdoubles, preserving 80-bit precision of the `loop control variable`. The function uses Neumaier summation for round-off error prevention. Example:

    > import long;
    > f := long.count(long.double(1), long.double(-0.1), long.double(-1));  # count down
    > while c := f() do print(c) od;

  - The `integral` and `float` operators can check whether a longdouble represents an integral or fractional value, respectively.

  - The `log`, `sinc`, `antilog2`, `antilog10` and `signum` operators now support longdoubles.

  - New `long.rempio2` conducts an argument reduction into the range [0, Pi/2).

  - New `long.ilog2` extracts the integral base-2 exponent of a longdouble.

  - New `long.frexp` returns the mantissa and the base-2 exponent of a longdouble.

  - New `long.ldexp` computes a longdouble from the given mantissa and base-2 exponent.

  - The error functions `long.erf` and `long.erfc` are now available in OS/2.

  - `long.log2` and `long.log10` now return `long.undefined` if their arguments are zero, `long.lnplusone` now returns `long.undefined` if its argument is -1.

  - The `frac` operator when applied to a negative longdouble did not preserve the sign of its argument. This has been fixed.

  - The `=`, `==` and `<>` operators as well as `long.isequal` and `long.isunequal` could not correctly compare longdoubles with `long.undefined`. This has been fixed.

  - Improved the OpenSUSE 32-bit edition.


2.34.6, December 04, 2022

- The '__squareadd' metamethod did not work in general, i.e. if there was one it was not called. This has been fixed.

- All the `long` operators and functions have now been properly documented in the Primer and Reference.

- Further extensions and bug fixes to the `long` package that provides 80-bit floating-point arithmetic:

  - The new function `long.fpclassify` classifies longdoubles.

  - The new function `long.issubnormal` checks whether a longdouble is subnormal.

  - The new function `long.root` calculates the non-principal n-th root.

  - New `long.erf` and `long.erfc` implement the error and the complementary error function.

  - The new function `long.csc` computes the cosecant.

  - The new function `long.sec` computes the secant.

  - The new function `long.cot` computes the cotangent.

  - The new function `long.cas` returns the sum of the sine and the cosine.

  - The new function `long.arccsc` computes the inverse cosecant.

  - The `arcsec` operator now processes longdoubles.

  - The new function `long.arccot` computes the inverse cotangent.

  - The new function `long.norm` converts a longdouble from one range to another.

  - The new function `long.wrap` conducts a range reduction of a longdouble to a given interval.

  - The new function `long.eps` returns the machine epsilon or a very small epsilon value dependent on the magnitude.

  - The new function `long.approx` checks whether two longdoubles are approximately equal.

  - The new function `long.koadd` adds two longdoubles using Kahan-Ozawa round-off error prevention.

  - The new function `long.isless` checks whether a longdouble is less than another one.

  - The new function `long.islessequal` checks whether a longdouble is less then or equal to another.

  - The new function `long.round` rounds a longdouble to a given digit.

  - The `invsqrt` operator now supports longdoubles and computes the inverse square root.

  - The `squareadd` operator now supports longdoubles and performs a fused multiply-add operation.

  - The `int` and `frac` operators now work with longdoubles, returning their integral and fractional parts. `entier` rounds down a longdouble to the nearest integer.

  - The `zero` and `nonzero` operators check whether a longdouble is zero or non-zero.

  - The `even` and `odd` operators check whether a longdouble represents an even or odd integral value.

  - Exponentiation of longdoubles was faulty when the left operand was zero. This has been fixed.

  - `tools.isfinite` has been fixed.

  - `long.isequal` could not compare a longdouble with a number. This has been fixed.

  - The `ln` operator now returns `long.undefined` if its argument is zero.

  - The `sign` operator now returns `long.undefined` instead of 1 if its argument is undefined.

  - `long.isnormal` now also can detect a normal longdouble on Solaris and Red Hat.


2.34.5, November 29, 2022

- The `replace`, `instr` and `join` operators have become functions so that the user can overload them. The new names are `strings.replace`, `strings.instr` and `strings.join`. The respective keywords `replace`, `instr` and `join` have been removed from the namespace. Aliases have been provided to ensure backward compatibility.

- The `values` and `times` operators have become functions so that the user can overload them. The respective keywords have been removed from the namespace. You do not have to change your code.

- The new function `math.todec` converts a number in DMS notation to its decimal representation, e.g. 10.3045, representing 10°30'45'', returns 10.5125.

- Various changes to the `long` package:

  - Most of the operators accidently worked in 64-bit instead of 80-bit mode, and the pretty printer did not work correctly. This has all been fixed.

  - The `\` integer division and `%` modulus operators now accept longdoubles.

  - The new function `long.fma` performs a fused multiply-add operation.

  - The new function `long.fdim` returns the positive difference.

  - The new function `long.modf` decomposes a longdouble into its integer and fractional parts.

  - The new function `long.ceil` returns the nearest integer not less than a given value.

  - The new function `long.floor` returns the nearest integer not greater than a given value.

  - The new function `long.trunc` returns the nearest integer not greater in magnitude than a given value.

  - The new function `long.fraction` returns the fractional part of a longdouble.

  - The new function `long.fmod` computes the remainder from the division of numerator by denominator.

  - The new function `long.fmin` determines the smaller of two values.

  - The new function `long.fmax` determines the larger of two values.

  - The new function `long.nextafter` returns the next representable floating-point value of a longdouble in a given direction.

  - The new function `long.isequal` and `long.isunequal` compare long doubles or a mix of longdoubles and numbers.

  - The new function `long.signbit` returns 1 if the argument is negative, and 0 otherwise.

  - The new function `long.copysign` composes a longdouble with the magnitude of the first argument and the sign of the second.

  - The new function `long.isnormal` checks whether a longdouble is normal.

  - The new function `long.isfinite` checks whether a longdouble is finite.

  - The new function `long.isinfinite` checks whether a longdouble represents +/-infinity.

  - The new function `long.isundefined` checks whether a longdouble represents undefined.

  - The new constants `long.infinity` and `long.undefined` represent infinity and undefined, respectively.

  - `long.pow` now accepts a mix of longdoubles and numbers.


2.34.4, November 27, 2022

- The `unique` and `copy` operators have become functions so that the user can overload them. The respective keywords have been removed from the namespace.

- With pairs, `map` sometimes may have corrupted the stack. The following functions may have also been affected: `calc.sections`, `linalg.inverse`, `linalg.transpose`, `linalg.gsolve`, `linalg.mulrow`, `linalg.mulrowadd`,  `linalg.ludecomp`, `linalg.rref`, `linalg.mmul`, `linalg.diagonal`, `linalg.identity`, `linalg.submatrix`, `os.screensize`, `xbase.readdbf`, `xbase.readvalue`, `xbase.record` and `binio.readobject`. This has been fixed.

- To prevent stack corruption, `sorted`, `copyadd`, `rtable.get` and the C API functions `agn_copy`, `agn_toset`, `agn_createpair` and `agn_createpairnumbers` now perform a precautionary garbage collection.


2.34.3, November 23, 2022

- Metamethods in some rare cases excessively called the garbage collector, corrupting the VM stack as observed in OS/2 and Red Hat Linux only. This has been fixed in general, regardless of the operating system.

- With procedures, the `size`, `in`, `notin`, `zero`, `nonzero`, `empty` and `filled` operators can no longer call metamethods as this proved to be esoteric.

- Removed redundant code.

- The Red Hat installer now includes the `long` package.

- The C API function `agn_copy` has been extended by a third parameter indicating what to copy: array part only, hash part only, both array and hash parts, and also whether to copy a metatable and user-defined type.


2.34.2, November 16, 2022

- `copyadd` has been rewritten in C and has become around 40 percent faster.

- `multiple` printed debugging information on screen. This has been fixed.

- The new C API function `lua_reginsert` inserts an element at the first slot that is currently set to `null`.

- The new C API function `agn_structinsert` inserts an element into a table, set, sequence or register.


2.34.1, November 02, 2022

- Numeric `for` loops with fractional step sizes by default adjusted the loop control variable in the range [-1-|step|, 1+|step|]. This sometimes could do more harm than good and the feature has been removed. The `environ.kernel/foradjust` setting now only controls whether an iteration value close to zero will be set to zero and is set to `true` by default.

  The same applies to `factory.count`.

- `math.ndigits` sometimes went into an infinite loop in some situations when counting fractional digits. This has been fixed.

- `calc.interp` when called with only a table of interpolation points now returns a factory that is 3.5 times faster, and `calc.neville` returns a factory almost twice as fast as before.

- The factories produced by `calc.nakspline` and `calc.clampedspline` have become 6.6 and 8.8 times faster, respectively.

- The C API function `agn_createpairnumbers` has now been documented and hardened against stack corruption.

- Some `calc` functions programmed in C have been hardened against stack corruption.

- The auxiliary C API function `agnL_createpairofnumbers` has been deprecated, use `agn_createpairnumbers` instead. An alias has been provided for backward compatibility.


2.34.0, October 29, 2022

- Numeric `for` loops with fractional step size counted wrong in the interval [-1 - |step|, 1 + |step|] if the number of fractional places in the start value was greater than those in the step size. This has been fixed. Also, an iteration value x very close to zero will now be set to zero if |x| < hEps.

- `factory.count` iterators sometimes did not count till the stop value but left prematurely. This has been fixed by automatically adding `hEps` to the stop value. Thus, if the step size is less than or equal to `hEps`, the generator will now issue an error.

  With Neumaier, Kahan-Ozawa, Kahan-Babuska and Kahan-Babuska-Neumaier summation, the iterators now automatically correct iteration values in the range [-1 - |step|, 1 + |step|] as summation algorithms traditionally are inaccurate in this domain.

- `factory.count` could not count down. This has been fixed. Example:

  > import factory;

  > f := factory.count(1, -0.1, -1);

  > while c := f() do print(c) od;
  1
  0.9
  0.8
  ...

  The function now issues an error if the step size is zero.

- `calc.polygen` now accepts tables, sequences and registers containing coefficients for input. This will spare you a call to `unpack` in many situations. Also improved the documentation on `calc.polygen` and `calc.polyfit`.

- `calc.fsum` now uses advanced Kahan-Babuska advanced round-off error prevention.

- `calc.sections` now uses advanced Adapted Neumaier summation for round-off error prevention.

- `math.hEps` has been renamed to `hEps`. An alias is available for backward compatibility.

- This release has been Valgrind-checked on x86 and AMD64 Linux to ensure there are no internal errors or memory leaks.


2.33.4, October 26, 2022

- `strings.format` and thus also `printf` now recognise the '%lf' specifier, printing numbers with 16 fractional digits.

- With sets, `cleanse` now frees the memory previously occupied by deleted elements so that it can be reused by the interpreter.

- The new function `sets.resize` shrinks or enlarges the allocated memory of a set.

- The new function `sets.newset` creates a set with a user-defined number of pre-allocated slots. This is useful only if you have to pass a set initialiser as a function argument, otherwise it is recommended to use the `create set` statement.

- `copyadd` now also works with sets.

- Tweaked numeric `for` loops with fractional step sizes a little bit.

- With sets, `environ.attrib` returned a wrong value with the 'hash_allocated' entry if exactly one element has been stored. This has been fixed.

- The new C API function `agn_setresize` resizes a set to a given number of pre-allocated slots.


2.33.3, October 23, 2022

- Numeric `for` loops with fractional step sizes might have started with a wrong initial value if the start value had been in the interval [-1 - step_size, 1 + step_size]. This has been fixed.

- All UNIX-based binary installers missed the up-to-date version of the `mapm` package. This has been fixed.

- Improved the grammar in the Primer and Reference a little bit. Also documented the changes to the `rtable` package. See the `Manuals` download folder for the latest issue.

- Updated the regression test cases.

- The released source files did not compile in DOS. This has been changed.


2.33.2, October 21, 2022

- The new function `cleanse` empties a table, set or sequence. With a register, sets all its places to `null`.

- The new function `rtable.forget` empties the remember table of a function but does not delete it. The memory previously occupied by cached function arguments and results can be reused for other purposes.

- `rtable.rdelete` now expclitly empties a remember table before deleting it. It also enforces an immediate garbage collection.

- The following rtable functions have been renamed: `rtable.rdelete` to `rtable.purge`, `rtable.rget` to `rtable.get`, `rtable.rinit` to `rtable.init` , `rtable.rmode` to `rtable.mode` and `rtable.rset` to `rtable.put`. Aliases have been provided to ensure backward compatibility.

- The new function `debug.setstore` sets values into the store of a procedure.

- New `mapm.xlog` computes the logarithm of a given base.

- New `mapm.xlog2` computes base-2 logarithms.

- New `mapm.xexp2` computes base-2 exponentials and new `mapm.xexp10` computes base-10 exponentials.

- Added ZX Spectrum-style addition, subtraction, multiplication and divison to the `zx` package: `zx.ADD`, `zx.SUB`, `zx.MUL` and `zx.DIV`.

- The new C API functions `agn_cleanse` and `agn_cleanseset` empty a table or set entirely.

- This release has been Valgrind-checked on x86 and AMD64 Linux to ensure there are no internal errors or memory leaks.


2.33.1, October 18, 2022

- The new functions `calc.chebyt` and `mapm.xchebyt` compute the n-th Chebyshev polynomial of the first kind.

- Added the `long` package to the DOS edition. Since the compiler used to create the DOS binaries does not support 80-bit floats, in DOS the `long` package interfaces to the `mapm` package using a precision of 19 decimal places, i.e. 80-bit precision.

- Added the cubic root function `cbrt` to the `long` package.

- All constants available in the `long` package have been documented.

- The `mapm` package now supports the `square`, `cube`, `sign` and `abs` metamethods. Integer exponentiation with `**` has become available, as well, and is 15 percent faster than the `^` operator.

- The new `mapm` package function `mapm.xerf` computes the error function, and `mapm.xerfc` the complementary error function.

- New `mapm.xhypot` calculates hypotenuses.

- New `mapm.xfma` implements the fused multiply-add operation.

- New `mapm.xterm` computes the term c*x^n.

- Introduced the constants `mapm.fifth` and `long.fifth` which represent 1/5 = 0.2.

- `environ.attrib` now returns information about the existence of an internal storage table of a procedure with the new 'storage' entry.

- The new function `debug.getstore` returns a reference to the internal storage table of a procedure. You can both inspect this table as well as inject values into it. Here is an example:

  zxsine := proc(x :: number) is  # sine as implemented in the Sinclair ZX Spectrum 48K ROM
     feature store;  # activate the internal store
     local w, z;
     x *:= 0.5/Pi;
     x -:= entier(x + 0.5);
     w := 4*x;
     if w > 1 then w := 2 - w elif w < -1 then w := -w - 2 fi;
     z := 2*w*w - 1;
     return w*(store[1] + z*(store[2] + z*(store[3] + z*(store[4] + z*(store[5] + z*store[6])))))
  end;

  _coeffs := // 1.267162131 -0.284851843 0.18226552e-1 -0.546208e-3 0.9480e-5 -0.112e-6 \\;

  _store := debug.getstore(zxsine);  # get reference to the procedure store

  for i in _coeffs do  # insert coefficients into the procedure store
     insert i into _store
  od;

  _store, _coeffs -> null;  # clean up

  zxsine(Pi/4):
  0.70710678125

- The new function `debug.getrtable` returns a reference to the internal remember table of a procedure. Opposed to `rtable.rget`, the function gives direct read and write access to the remember table, so use it with care.

- Did some minor tweaking of the Sinclair ZX Spectrum functions SIN, COS and TAN.

- The new C API function `agn_getstorage` refers to the internal storage table of a procedure.

- This release has been Valgrind-checked on x86 and AMD64 Linux to ensure there are no internal errors or memory leaks.


2.33.0, October 16, 2022

- The new `muladd` operator implements the fused multiply-add operation with extended internal precision. It multiplies the first two arguments and adds the third argument to the resulting product. It is twice as fast as the `fma` function which is still available. Example:

  > muladd(2, 3, 1):
  7

- The new `long` package implements 80-bit floating-point numbers and arithmetic. It is at least 80 times faster than the `mapm` package with the same precision. Note that 80-bit floating-point arithmetic provided by this new package is still at least 12 times slower than Agena's built-in 64-bit arithmetic so it is useful only if you need extended precision. Example:

  > import long;

  > exp(long.double(1)):
  longdouble(2.7182818284590452354)

  > long.tonumber(ans):
  2.718281828459

  The package is not available in DOS.

- The `mapm` package now supports the following standard operators: `recip`, `sqrt`, `ln`, `exp`, `sin`, `cos`, `tan`, `arcsin`, `arccos`, `arctan`, `sinh`, `cosh` and `tanh`.

- The Windows uninstaller no longer deletes folders set up by the user in <installdir>/share, for example the share/fractint folder if present is left untouched. Also, when overinstalling, the current installed version number is displayed in the respective installer dialogue.

- Cleansed the code so that Agena compiles in OS/2 without warning.

- This release has been Valgrind-checked on x86 and AMD64 Linux to ensure there are no internal errors or memory leaks.


2.32.6, October 10, 2022

- The `ln` operator that computes the natural logarithm has become ten percent faster with complex arguments.

- In the complex domain, the following functions and operators have become 30 percent faster: `tanh`, `bea`.

- `sin`, `cos`, `sinh`, `cosh`, `cas`, `csc`, `sec`, `sinc`, `cosc`, `tanc` and `cosxx` have become 25 percent faster with complex arguments.

- With complex numbers, `cot` and `coth` have become 20 percent faster.

- Also benefitting are `csch`, `sech` and the `sinh` and `cosh` metamethods of the `dual` package plus the `fractals` package.

- In the Solaris edition, all the functions and operators mentioned above have become even faster, by around 40 to 50 percent.


2.32.5, October 09, 2022

- `csc` has been ported to C and has become 37 percent faster in the real domain and 13 percent faster in the complex domain.

- `sec` has been ported to C and has become 56 percent faster in the real domain and 21 percent faster in the complex domain.

- `cot` has been ported to C and has become 35 percent faster in both the real and complex domain.

- `coth` has been ported to C and has become 10 percent faster in both the real and complex domain.

- `arcsech` has been ported to C and has become 7 times faster in the real domain and 12 percent faster in the complex domain.

- `instr` how accepts a set of pattern strings and checks whether at least one of them matches a given string.

- The approximate equality operators `~=` and `~<>` did not correctly compare numbers with complex numbers. This has been fixed.

- This release has been Valgrind-checked on x86 and AMD64 Linux to ensure there are no internal errors or memory leaks.


2.32.4, October 05, 2022

- `strings.find` now accepts a table, set, sequence or register of patterns to be found and at the first match returns the start and end position plus the matching pattern. If no pattern could be found at all, the function returns `null`:

  > strings.find('agena', ['x', 'ge', 'na']):
  2       3       ge

- Improved complex versions of `arcsinh` and `arccosh` for borderline cases.

- A lot of error messages have been improved by not only printing the expected type, but also the type actually passed so that bug fixing becomes a bit easier.

- Extended the test cases.

- This release has been Valgrind-checked on x86 and AMD64 Linux to ensure there are no internal errors or memory leaks.


2.32.3, October 04, 2022

- `math.ispow2` can now check whether fractions (such as 1/2, 1/4, 1/8, ...) are powers of two.

- The new functions `exp2` and `exp10` compute 2^x and 10^x. Both accept both numbers and complex numbers. The real functions `math.exp2` and `math.exp10` have been removed but aliases are available for backward compatibility.

- `arcsinh` has been ported to C and has become nearly twice as fast.

- `arccosh` has been ported to C and has become 32 percent faster.


2.32.2, October 02, 2022

- The new function `math.exp10` raises ten to a given power, i.e. math.exp10(x) = 10^x.

- `math.exp2` has been tuned by 22 percent.

- Introduced the new `ieee` data structure to the `bytes` package. It represents a double-precision float; its sign, biased exponent, high and low parts of the mantissa can be set and read individually:

  > import bytes;

  > f := bytes.ieee(-Pi);

  > bytes.getieee(f):
  -3.1415926535898        1       1024    598523  1413754136

  > bytes.setieee(f, signbit = 0);  # make value positive, i.e. unset sign flag

  >  bytes.getieee(f, 'double'):
  3.1415926535898

- The exponentiation operator `^` returned `infinity` instead of `undefined` with base 0 and negative integral exponent. This has been fixed.

- The initial internal stack size used by the virtual machine has been prophylactically increased to 40 slots again.

- This release has been Valgrind-checked on x86 and AMD64 Linux to ensure there are no internal errors or memory leaks.


2.32.1, September 27, 2022

- `strings.find`, `strings.match`, `strings.gmatch`, `strings.gmatches` and `strings.gseparate` now can easily fetch floats and integers in strings with the new `%n`, `%N` and `%i` classes. The `%n` and `%N` classes also support integers, scientific E-notation, and dots (`%n`) or commas (`%N`) as decimal separators. Examples:

  > strings.match('123', '(%i)'):
  123

  > strings.match('123', '(%n)'):
  123

  > strings.match('-3.14e+2', '(%n)'):
  -3.14e+2

  > strings.match('-3,14e+2', '(%N)'):
  -3,14e+2

  Also introduced new classes 'o' and 'O' to recognise letters a to z plus A to Z including diacritics and ligatures, provided Latin-1 codepage is active.

- `strings.charmap` now returns a complete ASCII table, see the new 'ascii' entry. As with all the other data returned by the function, the contents may vary across platforms and active codepage.

- The bitfields that the six new binary arithmetic operators `inc`, `dec`, `mul`, `div`, `intdiv` and `mod` return have been unified so that you do not have to discern among the respective arithmetic operations any longer. The common layout now is as follows:

  bit 1:  division by zero
  bit 2:  log2(operand 1) - log2(operand 2) > log2(environ.system().numberranges.maxdouble
  bit 3:  log2(operand 1) + log2(operand 2) > log2(environ.system().numberranges.maxdouble
  bit 4:  both operands are close to zero

  You may have to change your code if you have redefined one of the functions that the operators call, e.g. `math.divide`, `math.multiply` etc.


2.32.0, September 24, 2022

- Added six arithmetic binary operators that detect potential numeric overflow, underflow and division by zero and allow the user to invoke proper self-written functions that handle them: `inc` for addition, `dec` for subtraction, `mul` for multiplication, `div` for division and `intdiv` for integer division, plus `mod` for modulus.

  The operators after checking possible exceptions call user-defined handlers along with the operands and information on the kind of exception: `inc` calls `math.add`, `dec` calls `math.subtract`, `mul` calls `math.multiply`, `div` calls `math.divide`, `intdiv` calls `math.intdivide` and `mod` calls `math.modulo` (not `math.modulus`). One example:

  Division: the handler might look like this (`math.intdivide` and `math.modulo` may be similar, since the values for `kind` are the same):

  > math.divide := proc(n, d, kind) is
  >    case kind
  >       of 0b000 then return n/d                 # no exception
  >       of 0b001 then error('division by zero')  # denominator is zero, do not return `undefined` but throw an exception
  >       of 0b010 then error('underflow')         # very large value to be divided by very small value close to 0
  >       of 0b100 then return n/d                 # both numerator and denominator are close to 0
  >    esac
  > end;

  > 1 div 0:
  division by zero

  See Chapters 4.6.8 and 14.2 of the Primer and Reference for more examples, including addition and multiplication.

  The threshold that defines whether a value is `close to zero` can be set with `environ.kernel/closetozero`, which by default is `DoubleEps`, e.g.:

  > environ.kernel(closetozero = 1e-20);

  The type of numerical exception that occurred the last time one the six new operators has been invoked can also be queried by calling the new function `environ.arithstate` which returns the type of exception as a bit field, see case/of clauses above:

  > 1e308 inc 1e308:
  overflow

  > environ.arithstate():
  1

- Added various constants with a precision of 1,000 digits to the arbitrary precision MAPM package: Pi, E, sqrt(2), ln(2), Golden Ratio, etc. See the Primer and Reference, Chapter 11.3, for a list.

- `mapm.xnumber` now accepts a second optional argument, the precision, that will be used for the specific value to be defined. The default still is 20.

- In OS/2 and DOS, the `mapm` package did not correctly clean up memory, causing lost bytes at exit. This has been fixed.

- Included examples on how to use the MAPM package in the Primer and Reference.


2.31.10 & 2.31.11, September 21, 2022

- The new function `calc.aitken` finds the limit of a sequence (represented by a mathematical function) using Aitken extrapolation.

- The `~=` and `~<>`approximate (in)equality operators, `multiple`, `registers.new`, `calc.zeroin`, `calc.limit`, `calc.iscont`, `calc.isdiff`, `calc.aitken`, `linalg.gsolve`, `divs.equals` and the `linalg` vector ~= metamethod used an underlying approximation routine that did not properly check for +/-infinity, causing false results. This has been fixed. The `approx` function was not affected by this bug, however.

- The two API functions `agn_ncall` and `agn_call` actually did not level the stack and returned confusing results if the number of returns in a call to a user-given function was not one. (They actually returned the last instead of the first result and conducted excessive garbage collection.) This has all been fixed.

  The `calc` functions which especially are benefiting from this fix are: `cheby`, `diff`, `eps`, `eucliddist`, `eulerdiff`, `fminbr`, `fmings`, `fprod`, `fsum`, `gauleg`, `gtrap`, `iscont`, `isdiff`, `limit`, `savgol`, `sections`, `simaptive`, `variance` and `xpdiff`.

  Also benefiting are `stats.fsum`, `stats.fprod` and `fractals.esctime`.

- Fixed error messages of `allotted` and `approx`.

- Cosmetic changes to the pretty-printer and some few optimisations under the hood.

- To reduce the memory footprint, the initial internal stack size used by the virtual machine has been changed back from 40 to 20 slots without compromising stability.


2.31.9, September 19, 2022

- Garbage collection of `xbase` file handles did not work, causing lost bytes. This security issue has been fixed.

- The `heaps` package can now be re-initialised on all platforms.

- `package.packages` did not return the "coroutine" package name. This has been fixed.

- In OS/2 and DOS, built-in packages including metatables have not been correctly re-registered by the `restart` statement, causing failures after restarting the environment. This has been fixed.

- An internal help table to the `restart` statement is now hidden in the Agena registry so that it cannot be accidently deleted by the user.


2.31.8, September 18, 2022

- The `restart` statement could not correctly delete userdata such as those available in the numarray package, etc., and issued errors. This has been fixed.

- The new function `numarray.sorted` sorts a numeric array non-destructively.

- The new C API function `agn_deletefield` deletes a field from a table without invoking metamethods.


2.31.7, September 14, 2022

- Two internal API functions that run mathematical functions did not correctly reserve enough stack space, causing sporadic invalid memory read operations on some operating systems. Sometimes the stack has been corrupted due to this so that Agena issued errors at least on one older Linux flavour. This has all been fixed, also by assigning more stack space to the interpreter in general.

  The `calc` functions which especially will benefit from the measures are: `cheby`, `diff`, `eps`, `eucliddist`, `eulerdiff`, `fminbr`, `fmings`, `fprod`, `fsum`, `gauleg`, `gtrap`, `iscont`, `isdiff`, `limit`, `savgol`, `sections`, `simaptive`, `variance` and `xpdiff`.

- Also hardened the `copy` operator, `stats.minmax`, `stats.sumdata`, `stats.sumdataln`, `stats.issorted`, the `xml` and `dual` packages, `recurse`, `descend`, `satisfy`, `fractals.esctime`, `readlib´ and the `import` statement against stack corruption.

- The `aconv` package garbage collector did not correctly clean up the environment, causing subsequent `restart` statements to fail. This has been fixed.

- This release has been Valgrind-checked on x86 and AMD64 Linux to ensure there are no internal errors or memory leaks.


2.31.6, September 13, 2022

- By default, `tostring` with complex numbers still returns two strings representing the real and imaginary parts. If you now pass any option to the function, the return is just one string of the form +/- `re+im*I' or `re-im*I', depending on the sign of the imaginary part.

- Added three new proprietary dBASE field types to the `xbase` package:

  a) Type `Complex` denotes a complex number, stored as two doubles in Little Endian notation. You can write complex numbers by calling the new function `xbase.writecomplex` or `xbase.writenumber`. `xbase.readdbf`, `xbase.record` and `xbase.readvalue` read complex numbers implicitly.

  b) Type `Byte` denotes an 8-bit integer in the range 0 .. 255, stored as one unsigned character. You can write bytes by calling the new function `xbase.writebyte` or `xbase.writenumber`. `xbase.readdbf`, `xbase.record` and `xbase.readvalue` read bytes implicitly.

  c) The purely experimental type 'Decimal' depicts Little Endian 4-byte signed floats. You can write them with the new function `xbase.writedecimal` or `xbase.writenumber`. Note that 8-byte Agena numbers stored as 4-byte floats are extremely inaccurate when converting them back as they will contain stray bits. `xbase.readdbf`, `xbase.record` and `xbase.readvalue` read decimals implicitly.

  Note that these three types do not exist in dBASE Level 7, and files including them are marked with the dBase version 0x07 stamp in the very first byte of the header.

- `xbase.attrib` now returns the xBASE version name as a string, see new field 'versionname'.

- The xbase package in some few cases could not cope with binary data: If the first byte in a binary double or binary integer in a dBASE Level 7 file was 42 (...), all functions reading dBASE files returned just 0. This has been fixed.

- Most of the test data is now stored in (extended) dBASE files and their size on average has been significantly reduced. Also removed superfluous checks on numeric data, so the regression tests run a little bit faster.

- Hardened the following functions against internal stack corruption: `aconv.list`, `stats.fprod`, `stats.fsum`, `stats.sumdata`, `stats.sumdataln`, `strings.transform` and `strings.chop`.

- `aconv.list` could confuse the stack. This has been fixed.

- The C API function `agn_getcmplxparts` now accepts numbers.


2.31.5, September 11, 2022

- In the `xbase` package, the 'T' field type to indicate date and time to be stored in binary format has been removed. Use '@' instead. (In dBASE, '@' marks a DateTime field whereas in Visual FoxPro it is the 'T' identifier.)

- When writing a binary double into a .dbf file, it is now correctly marked as dBASE Level 7 instead of Visual FoxPro. Also, the field type identifier now is 'O' only. (Previously also Visual FoxPro 'B' has been incorrectly accepted, but in dBASE 'B' marks a .DBT block number.) Reading binary doubles has been fixed, as well.

- `xbase.record` and `xbase.readdbf` now support Binary, Memo and OLE fields.

- The new function `xbase.kernel` allows to set the endianness for binary integers and doubles and the layout of binary timestamps.

- If a binary double or binary timestamp is written to a file, the layout is now set to dBASE Level 7 instead of Visual FoxPro.

- `xbase.writetime` can write time stamps as either two signed 32-bit integers (the default) or as a binary double. To write doubles, set:

  > xbase.kernel(TimestampIsDouble = true);

- `xbase.writedouble` can now write numbers in either Big (default) or Little Endian notation. To write Little Endian doubles, set:

  > xbase.kernel(DoubleIsBigEndian = false);

- `xbase.writelong` can now write integers in either Big or Little Endian (default) notation. To write Big Endian 32-bit signed integers, set:

  > xbase.kernel(LongIsBigEndian = true);

- `bytes.tobig` and `bytes.tolittle` which convert a number from one endianness to another now support signed 4-byte integers; just pass -4 as the second argument.

- By default, `subs` is still replacing the elements in a structure with _all_ the replacements given, including intermediate substitutions. So if we have an expression like

  > subs(1:2, 2:3, 3:4, [1, 2, 3])

  we will get:

  [4, 4, 4].

  By passing the new `multipass=false' option, the rest of the replacement list will be skipped as soon as a substitution has been done:

  > subs(1:2, 2:3, 3:4, [1, 2, 3], multipass=false):
  [2, 3, 4]

- `subs` and `numarray.subs` can now check numbers for approximate instead of strict equality by passing the new `strict=false' option.

- With sets, `select`, `remove` and `subs` could not work in-place and returned a new set instead. This has been fixed.

- The new C API function `agnL_pairgetinumber` retrieves a number from the left-hand or right-hand side of a pair; it issues an error at failure.

- The new C API function `lua_shas` checks whether the value at the stack top exists in a set.

- This release has been Valgrind-checked on x86 and AMD64 Linux as well as x86 Max OS X to ensure there are no internal errors or memory leaks.


2.31.4, September 07, 2022

- The garbage collector did not cope well with values deleted from sets, resulting in sporadic, random invalid memory reads. Functionally, however, no incorrect set operations had been observed. This security issue has been fixed.

- Since the last release, the `xbase` package could not correctly write binary double floating-point numbers as well as memo and OLE reference fields to dBASE files, also sometimes causing memory leaks. This has been fixed.

- The `xml` package could not be used in Windows 2000, Windows 2000 Server, XP and Windows 2003 Server. This has been fixed by migrating back to the underlying 2.1.1 version of the expat C library. (All the other operating systems still use expat 2.4.7.)

- The new `bfield` package implements lean, low-level functions to work with bit fields which are faster and have a lower memory imprint than those available in the `memfile` package.

- The OS/2 makefile shipped with the sources was corrupt. This has been fixed.

- This release has been Valgrind-checked on x86 and AMD64 Linux to ensure there are no internal errors or memory leaks.


2.31.3, September 04, 2022

- Short-cut procedures now support the varargs functionality, so something like:

  > f := << x, ? -> ?, x >>  # which is equal to:

  > def f(x, ?) := ?, x

  > f(0, 10, 20):
  [10, 20]        0

  has become valid code and will not throw syntax errors any longer.

- `stats.cumsum` uses Kahan-Babuska summation which is more accurate than the formerly used Kahan-Ozawa algorithm.

- `numarray.toarray` accepts tables to be converted to numeric arrays.

- `numarrary.map` can now work in-place if the last argument `true` is given.

- The new function `numarray.select` picks elements and puts them into a new numeric array. It can optionally work in-place.

- The new function `numarray.remove` puts all elements that do not satisfy a condition into a new numeric array. The function can also work in-place.

- The new function `numarrray.subs` substitutes values in an array and can optionally work in-place.

- The new function `numarray.replicate` copies all elements in an array into a new one.

- The new function `numarray.subarray` retrieves a portion of an array.

- The `numarray` pretty-printer output the wrong data type. This has been fixed.

- Corrected error messages of `numarray.convert`.

- The xBase package does not stumble any longer over memo and OLE fields but just returns their original contents. Also, the TimeStamp `@` field is now being correctly recognised.

- Two annoyances with the terminating-colon facility on the command-line prompt to print results have been removed:

   - Implicate double `return` statements resulting in syntax errors will no longer happen.

   - Anonymous functions featuring `with` clauses no longer send the parser into an infinite loop.

- Documented all metamethods available in the `numarray` package.


2.31.2 Library Update 1, August 30, 2022

- `calc.zeros` issued an error when finding no roots. This has been fixed and the function returns `null` in such cases.


2.31.2, August 27, 2022

- `strings.isalpha`, `strings.isalphaspace`, `strings.isalphanumeric`, `strings.isupperalpha`, `strings.isupperlatin`, `strings.isloweralpha`, `strings.islowerlatin`, `strings.islatin` and `strings.islatinnumeric` now accept an optional set of further characters to be validated.

- `has` can now process strings and checks whether at least one character in a string is included in another string. It is the complement to `strings.contains`.

- `sort`, `reverse`, `put` and `prepend` now return the modified structure, but still work in-place.

- The `squareadd` operator and the `fma` function now accept a mix of numeric and complex operands.

- Documented `math.significand` which returns the normalised mantissa of a number in the range [1, 2), i.e. math.significand(x) = 2*math.mantissa(x).

- Tuned `bytes.numto32` and many other `bytes` package functions for PowerPC, ARM and legacy Intel Apple that process unsigned integers by 80 percent.

- `math.uexponent`, by giving any option, now returns a more uniform base-2 exponent. The function in this mode computes:

     math.uexponent(x, true) = sign(x)*math.uexponent(x),

  thus returning zero for x = 0 or subnormal x, instead of -1023, and `retaining` the sign of x.

- The new function `memfile.getbytes` returns a register with all the bytes stored in a memory file.

- The new function `memfile.get` returns the contents of a memory file as a string, without dumping any content. It is similar to `memfile.substring`, but easier to use.

- The new function `memfile.bitfield` creates a bit field and optionally sets zeros, ones or Booleans into this field. It also assigns a specialised metatable supporting standard indexing and printing methods for bit fields.

- The new function `memfile.setfield` easily sets or clears a bit in a bit field.

- The new function `memfile.getfield` is the lean version of `memory.getbit` only supporting bit positions, but not byte positions.

- `memfile.getbyte` now optionally returns a binary representation of a given byte as a string, e.g. '0b10000000'.

- Documented `memfile.clearbit` which unsets a given bit in a bit field.

- Added an example of how to define and use bitfields to Chapter 9.2 of the Primer and Reference.

- Corrected Chapter 9.2 on memory files.

- The print quality of the Primer and Reference has been significantly enhanced to `press mode`.


2.31.1, August 21, 2022

- The new constant `math.hEps` represents the value 1.4901161193847656e-12, an epsilon value more or less in the middle of `Eps` and `DoubleEps`.

- By default, numeric for loops with fractional step sizes now automatically increase the stop limit by the value of the constant `math.hEps` so that it is made sure that they iterate until the limit has actually been reached. If a you pass a step size that is equals or less then `math.hEps`, Agena now issues an error. You can entirely switch off these new features by setting `math.Eps` to zero, but only by calling `environ.kernel`:

  > environ.kernel(hEps = 0);

  The current setting of `math.hEps` can be queried by:

  > environ.kernel('hEps'):
  0

- The new function `hashes.jnumber` maps a number to one or two unsigned 4 byte integers, Julia-style.

- You can now apply the unary minus operator to Booleans, converting them to either 0 or -1:

  > -true, -false, -fail:
  -1      0       0

- Hardened `reduce`, `countitems`, `map`, `select`, `selectremove` and `remove` against internal stack corruption. Also hardened the internal set creation process.

- On older Intel Apple platforms and on ARM- and PowerPC-based systems and in unsigned bits mode, if you tried to left-shift a value x >= 2^32, with the `<<<` operator or left-rotate it with the `<<<<` operator, then the result was different than on OS/2, DOS, Windows and x86/AMD64 Linux. This has been fixed by forcing a wrap-around for large x, taking them modulo 2^32, before shifting.

- Also patched `bytes.numto32` and many other `bytes` package functions for PowerPC, ARM and legacy Intel Apple to return the same results with large arguments as on all other supported platforms by changing the underlying C API function `lua_touint32_t`.

- Two new C API features set or retrieve the value of `math.hEps`: the `agn_sethepsilon` function and the `agn_gethepsilon` macro.

- This release has been Valgrind-checked on x86, AMD64 Linux and x86 Mac OS X to ensure there are no internal errors or memory leaks.


2.31.0, August 16, 2022

- With numeric `for` loops and non-integral step sizes, Agena now by default uses adapted Neumaier summation which not only is eight percent faster than the classic Kahan summation algorithm previously used, but also more accurate.

- Also with numeric `for` loops and non-integral step sizes, introduced the `environ.kernel/foradjust` setting which by default is set to `true` and corrects iteration values over the interval -step_size - 1 .. step_size + 1. This adjustment has been introduced because Kahan-style summation algorithms including Neumaier's are traditionally imprecise in the aforementioned range. You can switch autoadjustment off by explicitly setting:

  > environ.kernel(foradjust=false);

- Starting with this release, Agena behaves the same on all platforms when shifting negative values to the right with the `>>>` operator: it performs an arithmetic shift, thus preserving the sign of the value shifted. This behaviour is the defacto-standard for most C compilers.

- `bytes.arshift32` now accepts negative values to be arithmetically shifted.

- `math.ndigits` can now also count the number of decimal places (number of digits after the dot) in a number of base 10.

- In OS/2 and DOS and with complex arguments, `hypot`, `hypot2`, `hypot3` and `hypot4` returned `undefined` instead of a complex result if either the real or the imaginary unit of an argument was zero. This has all been fixed and the functions have been sped up a little bit on all platforms.

- Extended the test cases.

- This release has been Valgrind-checked on x86 and amd64 Linux to ensure there are no internal errors or memory leaks.


2.30.5, August 14, 2022

- Numeric `for` loops with fractional step sizes can now alternatively use enhanced Kahan-Babuska summation instead of the default Kahan summation, by the explicit setting:

  > environ.kernel(kahanbabuska = true);

  While this may produce much more accurate iteration values, the speed loss is 20 percent.

- `math.accu` now has a `raw` mode with no auto-correction at all. Just pass the string 'raw' as the last argument.

- `math.accu` did not work correctly with the 'kbn' option. This has been fixed.

- `factory.count` with non-integral arguments by default now uses Kahan-Babuska autocorrection which is more accurate than the Kahan-Ozawa algorithm used before, with a performance loss of just one percent. To use Kahan-Ozawa summation, pass the string 'ozawa' as the last argument to the function.

- `factory.count` also supports Neumaier and Kahan-Babuska-Neumeier summation, just pass the string 'neumaier' or 'kbn' as the last argument.

- The new function `math.logs` implements the iterated logarithm (`log star`) and counts the number of times the logarithm function to a given base must be iteratively applied until the result reaches or drops below 1.


2.30.4, August 10, 2022

- In some special cases and in the complex domain only, `hypot`, `hypot2`, `hypot3` and `hypot4` suffered from peculiar round-off errors. This has been fixed by simplifying formulas.

- Tweaked the `sqrt` and `entier` operators in the complex domain.


2.30.3, August 07, 2022

- `frexp`, `modf`, `hypot`, `hypot2`, `hypot3`, `hypot4`, `mdf`, `xdf` and `math.rint` can now process complex numbers.

- `math.normalise`, `math.zerosubnormal`, `math.isnormal` `math.issubnormal` and `math.isirregular` now also process complex numbers.

- `math.sincos` and `math.sinhcosh` now also work in the complex domain and are 10 to 35 percent faster than calling `sin`, `cos`, `sinh`, `cosh` separately.

- Tweaked `math.normalise` and `math.isfib` a little bit.

- `ilog10` now accepts non-integral numbers. The function has also been documented in the Primer and Reference.

- In the complex domain and in Windows, Solaris, Linux and Mac, `arccoth`, `cas`, `root`, `proot`, `expx2` and `fma` did not handle infinite situations properly, returning `undefined` instead of an infinite value. This has all been fixed.

- Streamlined error messages for mathematical functions that process both numbers and complex numbers.

- Beautified error message for arguments not satisfying a user-given set of eligible types.

- Corrected misleading error message of `arctan2`.

- The new function `frexp10` returns the mantissa m and the exponent e of a number or complex number x such that x = m*10^e.

- Reintroduced `math.zeroin` which sets a number or complex number x to zero if |x| is close to zero.


2.30.2, August 03, 2022

- You can alternatively define short-cut functions with the new `define` keyword, for example:

  > define f(x, y) := x + y

- Tuned `toset` by around 20 to 30 percent, depending on the structure to be converted.

- To improve accuracy, `qsadd` now applies a combination of fused multiply-add operations and Kahan-Babuška summation.

- For better accuracy, `mulup` now internally uses 8-byte long C doubles.

- For streamlining, `qmdev` and `mulup` now return `fail` instead of `null` if there was no number in a structure.

- The new `calc.logit` function is the inverse of the sigmoid or logistic function (see `calc.sigmoid` and `calc.logistic`).

- The new `calc.probit` function computes the inverse of the cumulative distribution function of the standard normal distribution.

- If you try to apply the `++` or `--` operator on a numeric constant, Agena now issues an error.

- This release has been Valgrind-checked on x86 Linux to ensure there are no internal errors or memory leaks.


2.30.1, July 31, 2022

- `sort` and `sorted` now allow for a start and an end index which limits the sorting operation to a given range in a structure.

- The `union`, `minus` and `intersect` operators now automatically copy metatables and types, so do `bminus` and `bintersect`.

- If you pass any optional argument to `tables.indices`, the function will return the integral indices of a table only. Its second result indicates whether at least one integral key has been found in the hash part, so you might sort the table if needed. This mode is 40 % faster than the standard mode of the function.

- `tables.entries` has become 40 percent faster. Its new second result indicates whether a value has been found in the hash part of a table.

- The new function `tables.parts` returns both the array and the hash part of a table.

- The new function `tables.array` returns the array part of a table.

- The new function `tables.hash` returns the hash part of a table.

- The new function `tables.reshuffle` moves all values in the hash part of a table into its array part, thus emptying the hash part.

- Extended the C API:

  - `agn_arraypart` returns the array part of a table,
  - `agn_hashpart` returns the hash part of a table,
  - `agn_parts` returns both the array and hash part of a table,
  - `agn_borders` determines the smallest and the largest integer index of a table,
  - `agn_integerindices` returns all integral keys of a table,
  - `agn_entries` returns all the values stored in a table.

- This release has been Valgrind-checked on x86 and amd64 Linux to ensure there are no internal errors or memory leaks.


2.30.0, July 27, 2022

- The `union`, `intersect` and `minus` operators now treat the hash parts of tables differently, preserving instead of dissolving the hash key ~ value pairs before conducting an operation:

  > x := [ a = 1, b = 2 ]
  > y := [ c = 3, d = 4 ]
  > x union y:
  [a ~ 1, b ~ 2, c ~ 3, d ~ 4]

  In previous Agena versions, we just got:

  > x union y:
  [1, 2, 3, 4]

  This allows to easily add entries to existing tables with less typing, for example the new math constants `exa`, `peta`, etc. have been implemented by the statement:

  math := math union [ exa = 10^18, peta = 10^15, etc. ]

  `intersect`:

  > x := [ a = 1, b = 2 ]
  > y := [ b = 2, c = 3 ]
  > x intersect y:
  [b ~ 2]

  Before, the result was:

  > x intersect y:
  [2]

  `minus`:

  > x := [ a = 1, b = 2 ]
  > y := [ b = 2, c = 3 ]
  > x minus y:
  [a ~ 1]

  Before we had:

  > x minus y:
  [1]

- The `unique` operator now considers the hash part of a table to be unique by definition, so it just copies it to the result:

  > x := [ a = 1, b = 1, c = 1, 1, 1, 2, 2 ]
  > unique(x):
  [1 ~ 1, 2 ~ 2, a ~ 1, b ~ 1, c ~ 1]

  We had a rather confusing result in older Agena versions:
  [1, 2, 1]

- The table constructor now allows for _all_ kinds of keys and values to be separated by a tilde:

  > a := [ 0 ~ 0, abc ~ 1, 2 ]:
  [0 ~ 0, 1 ~ 2, abc ~ 1]

  In earlier versions, names like `abc` could not be used this way. If in the example above `abc` shall not just be a name but shall represent a value, put `abc` into a call to the new `eval` function:

  > abc := 'label';
  > a := [ 0 ~ 0, eval(abc) ~ 1, 2 ]:
  [0 ~ 0, 1 ~ 2, label ~ 1]

- The new `eval` function just returns the values represented by its arguments.

- Changed the name of the `sadd` operator to `sumup`, as the latter better depicts its purpose. An alias has been provided for backward compatibility. You have to change your code if you are using `__sadd` metamethods: Just rename `__sadd` to `__sumup`.

- Likewise, changed `qsadd` to `qsumup` (rename `__qsadd` metamethod to `__qsumup`), and `smul` to `mulup`. Backward compatibility aliases have also been provided.

- This release has been Valgrind-checked on x86 and amd64 Linux to ensure there are no internal errors or memory leaks.


2.29.7, July 25, 2022

- Introduced a new bailout method to the `times` operator:

  > times(f, x, infinity, eps [, ...])

  In this form, the operator takes a start value x, applies function `f` to it and repeatedly applies `f` to its previous result until the absolute difference of the last two function calls reaches or drops below the numeric threshold `eps`. The third argument `infinity` just signals that the user wants to use this new mode. If `f` is multivariate, all arguments but the first are passed right after `eps`.

  Example: Solve the equation 7*x^3 + 2*x - 5 = 0 using Newton's method.

  > import calc

  > f := << x -> 7*x^3 + 2*x - 5 >>

  > times(<< x -> x - f(x)/calc.eulerdiff(f, x) >>, 4, infinity, DoubleEps):
  0.78792505251729

  > f(ans):
  0

- Added the following prefices to the `math` package: exa, peta, tera, giga, mega, kilo, deka, deci, centi, milli, micro, nano, pico, femto, atto, e.g. `math.atto` is assigned 10^(-18).

- If any package has been deleted from the environment, for example by the `clear` statement or by setting the package name to `null`, it could not be re-imported in the current session, neither by the `import` statement, `readlib` nor any other means. This has been fixed.

- For informational purposes only, introduced the function `package.packages` which returns a set of all the standard Agena libraries initialised at startup.

- This release has been Valgrind-checked on x86 and amd64 Linux to ensure there are no internal errors or memory leaks.


2.29.6, July 20, 2022

- The `seq` constructor and its `(/ \)` short form - and only when being passed default elements, such like seq(1, 2, 3) - could not store more than 50 elements and in some cases created maimed sequences. The same happened with registers, i.e. the `reg` constructor. All these bugs have been fixed.

- Improved the C source code a little bit.

- This release has been Valgrind-checked on x86 and amd64 Linux to ensure there are no internal errors or memory leaks.


2.29.5, July 17, 2022

- The `times` operator has been extended: You can now bail out prematurely by including a Boolean condition in the function definition. As soon as the expression evaluates to `false`, the iteration will stop and the previous interim result will be returned, e.g.:

  > times( << x -> x < 3 and x + 1 >>, 1, 33):
  3

  When not including a Boolean condition, the operator works as before. For example to compute the Golden ratio iteratively, we still have:

  > times( << x -> 1 + recip x >>, 1, 33):
  1.6180339887499

- For integral exponents e and |e| < 64, the exponentiation operator `^` has become twice as fast in the real domain, without impairing overall performance or accuracy if the exponent is non-integral or greater than 63.

- Integer division with the `\` operator and `intdiv` statement has become ten percent faster.

- `iqr` has been tuned by 32 percent.

- The `frac` operator has become three percent faster.

- Tuned `calc.xpdiff`, `calc.bernoulli`, `calc.euler` and `calc.polyfit`.

- Described the `@`, `$` and `$$` operators in Chapters 8 ff. of the Primer and Reference.

- This release has been Valgrind-checked on x86 and amd64 Linux to ensure there are no internal errors or memory leaks.


2.29.4, July 12, 2022

- The `while` and `if` statements now support a combination of an assignment and a condition in the respective `while` and `if` clauses:

  > while c := 0, c < 3 do
  >    print('while body, c = ' & c++)
  > od;
  while body, c = 0
  while body, c = 1
  while body, c = 2

  > c:
  3

  Combined `for/while` loops do not support this new feature.

  > if c := 0, c >= 0 then
  >    print('if body')
  > fi;
  if body

  > c:
  0

- With registers, `select` crashed Agena when in in-place mode. This has been fixed.


2.29.3, July 09, 2022

- The following operators have been hardened against ill-fated situations: `in`, `notin`, `split` and `instr`.

- Memory usage of the '$$' and `times` operators in high-load situations has been enhanced.

- Improved internal memory management of `utils.readcsv`.

- Under heavy load, Valgrind sometimes reported invalid read attempts by the `@` and the `$` operator. This has been fixed by re-implementing the code. When run under high load, this also prevents possible quarrels with:  `astro.sun`, `astro.moon`, `gdi.pointplot`, `skew.entries`, `linalg` metamethods for matrices, `linalg.norm`, `skycrane.getlocales`, `skycrane.tee`, `stats.cartprod`, `stats.herfindahl`, `tar.list`, `telex` package initialisation,  `telex.encode`, `telex.decode`, `fractals.draw`, the table and set pretty-printer, and `os.cpuinfo` (Linux version only).

- In OpenSUSE and DOS, the `int` operator returned wrong results with very large or very small values. This has been fixed.

- On all platforms, `binomial` has been fixed for very large or very small arguments. Also, the function will no longer return fractional results with large integral arguments.

- The `select`, `remove` and `selectremove` functions did not correctly process registers. This has been fixed.

- This release has been Valgrind-checked on x86 and amd64 Linux to ensure there are no internal errors or memory leaks.


2.29.2, July 04, 2022

- The mapping `@` operator can now be used to perform a conditional multiplication of numbers, complex numbers or Booleans a, b:

  (a) a @ b <=> if b = 0 then a else a * b fi, which is equals to:

  (b) a @ b <=> a * if b = 0 then 1 else b fi, which is equals to:

  (c) a @ b <=> (b = 0)*a + (b <> 0)*a*b

  or in other words: if b is zero, then return a else multiply a by b and return the product.

  The `@` operator is around 20 percent faster than an implementation with the conditional `if` operator (a) and (b) and at least 45 percent faster than simple arithmetics (c). The feature has been introduced in order to save time when - depending on a condition - multiplying two values and to make the code a little bit shorter.

- Likewise, the new compound assignment `@:=` statement conducts conditional multiplications as described above, for example:

  > x := 2
  > x @:= 0
  > x:
  2

  > x @:= 3
  > x:
  6

- In the OS/2 edition, `os.isdir`, `os.isfile`, `os.islink`, `int`, `fma`, `math.fdim` have been optimised.

- In the DOS edition, the `int` operator has been tuned.


2.29.1, July 02, 2022

- Short-cut functions can now be defined with the new `def` statement:

  > def f(x, y) := x + y       # which is equal to:

  > def f(x, y) x + y          # which is finally equal to:

  > f := << x, y -> x + y >>

  The `:=` assignment token is optional. Alternatively, you can also use an `=` or `->` sign or the `is` keyword.

- Added further functions to do arithmetics in the real domain on numeric stacks:

  - The new function `stack.negated` multiplies the top numeric stack element by -1.

  - The new function `stack.intd` rounds the number on the top of a numeric stack to the nearest integer towards 0.

  - The new function `stack.fracd` converts the number on the stack top to its fractional part.

  - The new function `stack.addtwod` adds up the two numbers on top of the current stack.

  - The new function `stack.subtwod` substracts the number on top of the current stack from the number below it.

  - The new function `stack.multwod` multiplies the number on top of the current stack by the number below it.

  - The new function `stack.divtwod` divides the number below the stack top by the number on the top.

  - The new function `stack.intdivtwod` performs an integer division of the number below the stack top by the number on the top.

  - The new function `stack.modtwod` works like `stack.intdivtwod` but computes the modulus.

  - The new function `stack.powtwod` raises the number below the stack top to the power on the top.

  - The new function `stack.expd` raises E to the power of the number at the stack top.

  - The new function `stack.exp2d` raises 2 to the power of the number at the stack top.

  - The new function `stack.exp10d` raises 10 to the power of the number at the stack top.

- Various mathematical functions in the `stack` package have been tuned a little bit.

- In the real domain, `antilog2` has become 25 percent faster.

- `math.nextpower` in greater-than-or-equal mode returned a wrong result with base 2 and argument 1. This has been fixed. Also tuned the function for base 2 and non-integral arguments.

- The `copy`, `map` and `$` operators might not have properly registered metatables and user-defined types with the garbage collector. This has been fixed.


2.29.0, June 26, 2022

- With sequences, Agena now automatically frees allocated but unoccupied memory when deleting values. This is done carefully to not slow down the interpreter: Only if the number of remaining values a) is greater than 63 and b) falling below a power of two will Agena give back memory. Of course, no assigned values will be dropped.

  You can turn off this feature by issuing:

  > environ.kernel(seqautoshrink = false);

- Improved internal memory allocation when growing sequences: The new number of pre-allocated slots will no longer be just twice the current number, but the smallest power of 2 greater than or equal to the current number of slots, thus not wasting space unnecessarily.

- The `delete` statement for sequences has become 1,580 times [one thousand five ...] faster.

- The new function `sequences.resize` explicitly resizes a sequence, i.e. can expand or shrink it. It also features an auto-mode.

- `map` can now substitute values in-place, saving memory, by passing the `true` option as the last argument. This gives you a speed increase of about 30 percent if you no longer need the original contents of a structure. The new option is available for tables, pairs, sequences and registers.

- Like `map`, `subs`, `select` and `remove` now also support in-place operations.

- If given a table or sequence, `select`, `remove` and `selectremove` now return their result, i.e. the new table(s) or sequence(s), with the smallest number of pre-allocated slots if possible, preventing waste of memory. (The functions have already returned properly-sized registers.) Also, internal memory consumption has been cut in half.

- `math.nextpower` could underflow in non-Windows environments with argument 0 and base 2. This has been fixed.

- The new C API function `agn_pairseti` sets the value at the stack top to a pair and pops the value.

- The new C API function `agn_pairset` sets two values to a pair.

- The new C API function `agn_tabresize` resizes the array part of a table.

- `select` did not copy the user-defined type of a register to the result. This has been fixed.

- With sequences, the `copy` operator might have spoiled the value stack that is used to send data to the virtual machine and to write back results. This has been fixed.

- The `split` operator has been hardened against unusual situations that corrupted the value stack mentioned above under heavy load.

- The implementation of sequences has been streamlined, with previous allocation procedures unified into just one and a new algorithm implemented to calculate the optimum number of pre-allocated slots.

- Extended the test cases.


2.28.6, June 19, 2022

- The new function `stack.readbytes` puts the contents of a file directly into one of Agena's internal number or character stacks. You can also define bytes to be ignored, e.g. carriage returns, white spaces, embedded zeros, etc.

- The new function `stack.writebytes` writes the contents of the current number or character stack to a file. You can either write the entire stack contents or a given number of values from the stack top. The function does not modify the stack.

- `binio.readbytes` now accepts a set of bytes to be ignored at file import, for example the statement

  > s := binio.readbytes(fh, ignore='\n\r .')

  will skip all newlines, carriage returns, white spaces and dots.

- To avoid confusion, `binio.open` now accepts explicit write requests via 'write' or 'w' attributes.

- `stack.mapd` can now be run on all stack values, not just the one on the stack top.

- Corrected error messages of `utils.readini`, `stack.mapd` and `environ.ref`.

- The new C API function `agn_checkboolean` implements a fast Boolean check; returns 0 for `false` and `fail`, 1 for `true`, and issues an error otherwise.


2.28.5, June 15, 2022

- `strings.chomp` now accepts more than one pattern to be removed from the end of a string.

- The new function `strings.matches` works like `strings.match`, but returns all matches in only one call.

- `strings.lrtrim`, `strings.ltrim` and `strings.rtrim` - which all trim strings - now support multiple-character pattern strings as well as pattern matching. Example:

  > strings.lrtrim('123abc123', '(%d+)'):
  abc

  > strings.rtrim('abc//', '//'):
  abc

  > strings.ltrim('//abc//', '//'):
  abc//

- `strings.hits`, when given patterns, counted excessive matches. This has been fixed. Try `strings.hits('abc de f', '(%w+)')` then and now.

- `strings.chomp` and `strings.isending`: Fixed a bug if the user passed a pattern with a closing `$'.

- Hardened the following functions against low memory situations: `strings.format`, `strings.isending`, `os.date`, `os.listcore`, `os.fcopy`, `os.cdrom`, `os.netsend`.

- Hardened an internal string search C function against weird situations.

- Revised Chapter 1 `Introduction`, Chapter 2 `Installing and Running Agena` and Chapter 3 `Summary` of the Primer and Reference.

- This release has been Valgrind-checked on x86 Linux to ensure there are no internal errors or memory leaks.


2.28.4, June 12, 2022

- The `++`/`--` increment/decrement operators could not be used along with the the `store` keyword to access the internal administration table of a procedure. This has been fixed, i.e. an expression, in the procedure body, like `store.count++` or `--store.count` no longer throws a syntax error.

- With numbers, the binary `xor` operator no longer computes the bitwise exclusive-or, but behaves as described for years in the Primer and Reference in Chapter 4.8: "With non-booleans: returns the first operand if the second operand evaluates to null, otherwise the second operand is returned." Please use the `^^` operator for bitwise XORing of numbers.

- Revised Chapter 4 `Data`, Chapter 5 `Control` and Chapter 6 `Programming` of the Primer and Reference.

- As always, this release has been Valgrind-checked on x86 Linux to ensure there are no internal errors or memory leaks.


2.28.3, June 09, 2022

- In Windows, `os.gettemppath` returned a path including embedded zeros, which confused other operating system functions, e.g. `os.exists`. This has been fixed. All other operating systems were not affected by this bug.

- Added Solaris version of `os.tmpdir`, written in Agena.

- In the past, `pushd` when passed a string of more than one character, inserted only the first character into the stack. This has been changed: now all the characters in the string are pushed, with the last character put at the stack top, and all the preceding characters below.

- `stack.mapd` now also works with character stacks.

- With a character stack, `stack.absd` now returns the ASCII code of the top element.

- The new function `stack.upperd` converts the character at the stack top to upper-case.

- The new function `stack.lowerd` converts the character at the stack top to lower-case.


2.28.2, June 06, 2022

- Agena no longer issues a syntax error when trying to index a `real` table (i.e. an expression put into square brackets), sequence or register, e.g.

  > f := << x -> x, x + 1 >>

  > x := [f(0)][2]:
  1

  have become valid expressions. You no longer have to put the structure in brackets before appending an index.

- _Expressions_ such like `++a++' - formerly undocumented - are no longer supported for they computed wrong results. Agena now issues a syntax error. When run as a statement, however, the results are correct so Agena will not complain in this case.

- The new basic function `swap` exchanges two elements in a table, sequence or register. The respective functions `tables.swap`, `sequences.swap` and `registers.swap` have been deprecated. Aliases have been provided to ensure backward compatibility.

- The new function `shift` moves an element in a structure from one position to another, shifting all the other elements accordingly (which might also cause a rotation).

- The new function `environ.getopt` parses command-line switches. It is a port to a modified version of the C library function getopt.

- The new function `os.tmpdir` creates a unique temporary directory. It is not available in Solaris.

- `os.tmpname` no longer returns a preceding slash or backslash if the temporary filename is relative.

- `tables.dimension`, `sequence.dimension` and `registers.dimension` now accept the 'init' option to pass an initialiser of any type, including pairs. Always pass this new option as the very last argument. Example:

   > tables.dimension(1:3, 1:2, init = 0:0):
   [[0:0, 0:0], [0:0, 0:0], [0:0, 0:0]]

- You can now do basic arithmetics in the real domain on numeric stacks:

  - The new function `stack.addtod` adds its argument to the top element of the current numeric stack.

  - The new function `stack.mulbyd` multiplies its argument by the top element of the current numeric stack.

  - The new function `stack.powd` raises the top element of the current numeric stack to a given power.

  - The new function `stack.squared` raises the top element of the current numeric stack to the power of 2.

  - The new function `stack.rootd` computes the non-principal n-th root of the top element of the current numeric stack.

  - The new function `stack.sqrtd` computes the root of the top element of the current numeric stack.

  - The new function `stack.logd` returns the logarithm of the top element of the current numeric stack to a given base.

  - The new function `stack.lnd` returns the natural logarithm of the top element of the current numeric stack.

  - The new function `stack.antilogd` raises a given base to the power of the top element of the current numeric stack.

  - The new function `stack.mapd` maps a function on the top element of the current numeric stack. Multivariate functions are supported.

  - The new function `stack.sumupd` sums up all or a given number of values in a numeric stack, using Kahan-Babuška summation.

  - The new function `stack.mulupd` multiplies all or a given number of values in a numeric stack.

  - The new function `stack.sind` computes the sine of the top element of the current numeric stack, in radians.

  - The new function `stack.cosd` computes the cosine of the top element of the current numeric stack, in radians.

  - The new function `stack.tand` computes the tangent of the top element of the current numeric stack, in radians.

  - The new function `stack.arcsind` computes the arcus sine of the power of the top element of the current numeric stack, in radians.

  - The new function `stack.arccosd` computes the arcus cosine of the power of the top element of the current numeric stack, in radians.

  - The new function `stack.arctand` computes the arcus tangent of the power of the top element of the current numeric stack, in radians.

  - The new function `stack.abs` computes the absolute value of the top element of the current numeric stack.

  - The new function `stack.recipd` computes the reciprocal of the top element of the current numeric stack.

  - The new function `stack.intdivd` integer-divides the top element of the current numeric stack by its argument.

  - The new function `stack.modd` computes the modulus of the top element of the current numeric stack and its argument.

  - The new function `stack.meand` computes the arithmetic mean of all or a given number of values in a numeric stack, using Kahan-Babuška summation.

  Just some few examples:

  > # compute the arithmetic mean (1 + 2 + 3)/(number of elements)
  > pushd 1, 2, 3
  > stack.meand():  # pops all elements, pushes arithmetic mean
  2
  > popd():  # pop the arithmetic mean from the stack
  2
  > popd():  # the stack is empty
  null

  > # compute 2^(1/3)
  > pushd 2
  > stack.pushvalued(-1)  # duplicate the value we just pushed
  > stack.rootd(3):
  1.2599210498949
  > popd():
  1.2599210498949
  > popd():
  2
  > popd():  # the stack is empty
  null

  > # hypothenuse sqrt(2*2 + 3*3)
  > pushd 2
  > stack.squared()
  > pushd 3
  > stack.squared()
  > stack.sumupd()
  > stack.sqrtd()
  > popd():
  3.605551275464
  > popd():  # stack is levelled.
  null

- In the Primer and Reference improved Chapter 14.6 on stacks.

- If no argument is given to `stack.pushvalued`, the index is now set to -1 by default, i.e. the top element.

- `stack.swapd` has been implemented in C and has become thrice as fast.

- The DOS version has now been compiled with DJGPP/GCC 12.1.


2.28.1, May 31, 2022

- `nseq` - when creating linearly spaced sequences - caused out-of-memory errors in rare situations, and also did not correctly pre-allocate enough memory slots, thus forcing unnecessary re-allocations. This has all been fixed.

- `tables.dimension` did not correctly pre-allocate slots, causing unnecessary resizes/rehashes and memory waste. Also, when passing a structure as a default, a subsequent modification of this structure unintentionally modified all the other defaults returned by the function. This has all been fixed.

- `utils.writecsv` issued errors in most cases at invocation. This has been patched.

- `nseq` can now create a new sequence and fill it with a given default value of any type. Thus, for example,

  > nseq(8, init = 0):
  seq(0, 0, 0, 0, 0, 0, 0, 0)

  creates a structure with eight slots, prefilled with zeros. The same feature has been built into `nreg`.

- `nreg` can now create linearly spaced registers, e.g.:

  > nreg(true, << x -> x >>, 1, 10, 3):
  reg(1, 5.5, 10)

- Finally, `nseq` and `nreg` have been renamed to `sequences.new` and `registers.new`. Aliases have been provided to ensure backward compatibility.

- The new function `tables.new` works like `sequences.new`, but returns a table.

- The new function `registers.dimension` creates a multidimensional register, optionally filling it with a default value. Example:

  > registers.dimension(1:4, 1:2, 0):
  reg(reg(0, 0), reg(0, 0), reg(0, 0), reg(0, 0))

- The new function `sequences.dimension` creates a multidimensional sequence, optionally filling it with a default value.

- The new function `sequences.newseq` creates a sequence with a user-defined number of pre-allocated slots. This is useful only if you have to pass a sequence initialiser as a function argument, otherwise it is recommended to use the `create sequence` statement. The new function `sequences.newreg` does the same for registers.

- The new function `sequences.swap` swaps two elements in a sequence. Likewise, `registers.swap` does so with registers.

- Chapter 7 of the Primer and Reference has been split into logical sections for basics, strings, numbers, structures, I/O, system & environment, etc. Also updated the index.


2.28.0, May 29, 2022

- You can now add the `until` keyword along with a condition to numeric `for` loops that do not have a `from` or `to` clause:

  > for i until i = 4 do
  >   print(i)
  > od
  1
  2
  3

- Renamed the `++` and `--` epsilon operators which determine the next representable neighbour of a number to `+++` and `---`, respectively. You have to change the code of you have been using them.

- The new prefix `++` and `--` unary operators increase or decrease a number by 1. In expressions, the operators also return the updated value:

  > c := 0;

  > ++c;

  > c:
  1

  > square(++c):
  4

  Note that in expressions, the postfix `++` and `--` operators first return the current value of a variable and subsequently increase or decrease it by 1.

  > c := 1

  > square(c++):
  1

  > c:
  2

- The `clear` statement accepted function calls. This has been fixed.

- Spell-checked the entire documentation.

- Added an ASCII table to the `doc` folder of the Agena installation, see file ascii.xls.


2.27.10, May 25, 2022

- Agena now processes hexadecimal floating point constants, so

  > 0x0.1:
  0.0625

  > 0x0.1E:
  0.1171875

  > 0xA23p-4:
  162.1875

  or even

  > 0X1.921FB54442D18P+1:
  3.1415926535898

  have become valid expressions.

- The random number generator functions `math.random` and `math.randomseed` have been replaced with the ones implemented in Lua 5.4 for they are slightly better regarding distribution and the generator is also 30 % faster. `math.random` now by default generates different sequences of results each time the programme runs. To always return the same sequence, call `math.randomseed` with explicit arguments. The former Agena implementations are still available under the names `math.randoms` and `math.randomseeds`.

- The new 'P' modifier to `strings.format` formats a pointer. That gives a unique string identifier for structures, userdata, threads, strings, and functions (see also `environ.pointer`).

- `utf8.codes` has been patched.


2.27.9, May 23, 2022

- Added doubly-linked lists to the `llist` package. Read and write access to elements in doubly-linked lists is almost twice as fast as for singly-linked lists, boosting performance. The functions implemented for doubly-linked lists work the same and have the same syntax as those for singly-linked lists.
  Example:

  > l := dlist.list('Algol 68', 'Maple', 'Lua', 'SQL');
  > dlist.append(l, 'Agena');   # add new entry to the end of the list
  > l[-1]:
  Agena
  > dlist.prepend(l, 'Agena');  # add new entry to the start of the list
  > l[1]:
  Agena
  > dlist.purge(l, 1);          # delete first entry
  > l[1]:
  Algol 68
  > dlist.purge(l, -1);         # delete last entry
  > l[-1]:
  SQL
  > dlist.put(l, 3, 'Agena');   # insert new value into the middle of the list, shifting elements into open space
  > dlist.toseq(l):
  seq(Algol 68, Maple, Agena, Lua, SQL)
  > f := dlist.iterate(l);      # iterate through the list
  > f():
  Algol 68
  > f():
  Maple
  > f():
  Agena
  > f():
  Lua
  > f():
  SQL
  > f():                        # end has been reached
  null


2.27.8, May 22, 2022

- AVL trees have been added to the `heaps` package. Examples:

  > import heaps
  > a := avl.new()
  > avl.include(a,  1, 'Algol 68'):
  > avl.include(a,  2, 'Maple'):
  > avl.include(a,  3, 'SQL'):
  > avl.include(a, -1, 'Agena'):
  > avl.include(a,  0, 'Lua'):
  > 'Algol 68' in a:
  1
  > avl.remove(a, -1);
  > f := avl.iterate(a);
  > f():
  0       Lua
  > f():
  1       Algol 68
  > f():
  2       Maple
  > f():
  3       SQL
  > f():
  null
  > avl.entries(a):
  [Lua, Algol 68, Maple, SQL]
  > avl.attrib(a):
  [balancefactor ~ 1, length ~ 4, maxheight ~ 3]

- The `in` and `notin` metamethods for binary heaps did not work. This has been fixed.

- Corrected Agena version information.

- Corrected the Windows installer and regrouped the package selection menu.

- The new C API function `agn_tointeger` converts a number to an integer without any validation of the input.


2.27.7, May 15, 2022

- `purge` can now delete a consecutive range of elements from a table array, sequence or register, moving excess elements down to close the space.

- The new function `skew.reorder` balances a skew heap.

- The `heaps` package now features binary heaps, providing almost the same functionality as already available for skew heaps while being at least 25 times faster. Examples:

  > import heaps
  > h := binary.new();
  > binary.include(h,  3, 'Florida')
  > binary.include(h,  0, 'Alabama')
  > binary.include(h,  1, 'Texas')
  > binary.include(h,  2, 'Louisiana')
  > binary.include(h,  4, 'Mississippi')
  > binary.include(h, 10, 'Georgia')
  > binary.include(h,  7, 'Virginia')
  > binary.indices(h):
  [0, 1, 2, 3, 4, 7, 10]
  > binary.entries(h):
  [Alabama, Texas, Louisiana, Florida, Mississippi, Virginia, Georgia]
  > f := binary.iterate(h);
  > f():
  0       Alabama
  > f():
  1       Texas
  > f():
  2       Louisiana
  (and so forth)
  > binary.remove(h):
  0       Alabama
  > binary.remove(h):
  1       Texas
  > binary.remove(h):
  2       Louisiana
  (and so forth)

- The scheme files have been corrected and updated.

- Extended the test cases.

- The Primer and Reference has been improved.


2.27.6, May 11, 2022

- The new `move` function is a generalised version of `tables.move` not only supporting tables, but also sequences, registers and userdata. The function shifts elements in a structure or copies them to another structure.

- `settype` if given just two arguments, i.e. an object and a string, now returns this object instead of `null`. In all other cases, the function still returns just `null`.

- The new `heaps` package implements skew heaps which for example can be used as priority queues. A skew heap is a mostly unbalanced binary tree, avoiding costly reshuffles with each insert. You can insert key~value pairs into the skew heap, where the key represents the priority, and remove the key~value pair with highest priority. The package is based on a Lua library written by Geoff Leyland, New Zealand, Incremental IP Ltd.

  Example:

  > import heaps;
  > h := skew.new()
  > skew.include(h, 2, 'world')
  > skew.include(h, 1, 'hello')
  > skew.include(h, 10, 'everybody')
  > k1, v1 := skew.remove(h)
  > k2, v2 := skew.remove(h)
  > k3, v3 := skew.remove(h)
  > print(v1, v2, v3)
  hello world everybody

  > skew.include(h, 2, "world"); skew.include(h, 1, "hello"); skew.include(h, 10, "everybody");
  > f := skew.iterate(h);
  > f():
  1 hello
  > f():
  2 world
  > f():
  10 everybody

- The new `environ.maxinteger` system variable depicts the maximum representable 4-byte signed integer used internally.

- The `Agena Crash Course` has been updated and extended.


2.27.5, April 26, 2022

- You can now declare local procedures as follows:

  local procedure f(x) is
     return x
  end;

  or alternatively:

  local proc f(x) is
     return x
  end;

  Both is equal to:

  local f := proc(x) is
     return x
  end;

- Likewise, you can now use the `procedure` keyword to declare functions in statements:

  procedure f(x) is
     return x
  end;

  which is equal to:

  proc f(x) is
     return x
  end;

  or

  f := proc(x) is
     return x
  end;

- The new function `math.compose` takes a list of coefficients and a base and returns a composed number. It is the complement to `math.decompose`.

- The new function `debug.getupvalues` returns all upvalues of an Agena closure in a table, plus the number of upvalues.

- The new function `debug.nupvalues` returns the number of upvalues in an Agena closure.

- The `in` and `notin` operators for bimaps have been tuned.

- `bimaps` package: If a value is already assigned to a key and the value once again shall be assigned to the same key, then Agena simply ignores the duplicate assignment instead of issuing an error.

- Added the new C API functions `agn_rawgetinumber`, `agn_seqrawgetinumber`, `agn_regrawgetinumber` and `agnL_tonumarray`, see Primer and Reference.

- In the Mac OS X edition, finally fixed all issues with `strings.iterate` in 4-byte mode and invalid memory reads indicated by Valgrind.


2.27.4a, April 25, 2022

- Fixed yet another problem with `strings.iterate` in 4-byte mode with invalid memory reads affecting Mac OS X only.


2.27.4, April 24, 2022

- The new `bimaps` package implements bi-directional maps through tables. It is intended to hold items, i and j, that have a 1-to-1 relationship and allows to look up item j from table i and look up i from table j. If a new item is inserted that already exists in the map, the add will fail.

  Examples:

  > import bimaps

  > l, r := bimaps.bimap()

  > l.foo := 1

  > l.bar := 2

  > l.spam := 'eggs'

  > l:
  [bar ~ 2, foo ~ 1, spam ~ eggs]

  > r:
  [1 ~ foo, 2 ~ bar, eggs ~ spam]

  > l = r:
  true

  > 'eggs' in l, 'eggs' in r:
  true    true

  The package has originally been written by Pierre Chapuis for Lua 5.

- The `empty` and `filled` operators now support metamethods for tables, sets, sequences and registers.

- By passing the new 'nometa' option to the `copy` operator, metatables and user-defined types will not be copied to the new structure.

- The new function `memfile.reverse` reverses a memory file in-place.

- The new `utils.encodea85` and `utils.decodea85` functions convert to and from ASCII85 data. The functions have originally been written by Luiz Henrique de Figueiredo for Lua 5.

- `environ.kernel` now has the new entries 'isARM' for the interpreter running on an ARM CPU, 'isDOS' the interpreter running in DOS, 'isMac' for MacOS X and 'isLinux' for Linux. The 'alignable' entry for word-alignedness is now determined at runtime and not compile time.

- `utils.uuid` did not work. This has been fixed.

- If `math.random` receives the third argument `null`, the function now simply ignores it instead of issuing an error.

- The manual now includes a list of all metamethods supported by the `bags` package.


2.27.3a, April 20, 2022

- Various problems with `strings.iterate` and `strings.tobytes` in the 64-bit edition have finally been fixed.


2.27.3, April 19, 2022

- `strings.iterate` in unsigned 4-byte mode did not work correctly when given a string with a size of a multiple of 4. This has been fixed for the 32-bit versions of Agena.


2.27.2, April 18, 2022

- The new `utils.encodeb85` and `utils.decodeb85` functions convert to and from Base85 Z85 data.

- The new functions `strings.pack`, `strings.packsize` and `strings.unpack`, taken from Lua 5.4.4, conduct user-defined serialisations.

- When given an alternative position, `strings.advance` returns the substring starting at this position up to the string end.

- `strings.iterate` in unsigned 4-byte mode can now return Big Endian results if the third argument `true` is given.

- In the 64-bits version, `strings.iterate` in unsigned 4-byte mode now returns only one integer at a time.

- In word-aligned 4-byte unsigned integer mode, `bytes.tobytes` returns the result in Big instead of Little Endian notation if the third argument `true` is given.

- `bytes.tobig` and `byte.tolittle` can now also process unsigned 4-byte integers, by passing the number 4 as an option.

- `memfile.setbyte` can now also set bytes at positions that have not yet been filled with bytes. You can also give a count to set subsequent places to a given byte - the same for `memfile.setchar`, but with letters instead of bytes.

- `memfile.setitem` now accepts either strings or integers as input.

- The `in` and `notin` memfile metamethods now better support byte buffers and allow for either a given byte or a single letter.

- If called with any argument, `os.computername` on Windows returns detailed information on the NetBIOS or DNS name associated with the local computer.

- On older Windows flavours, the new function `os.netsend` sends a message to a user on a given server.


2.27.1, April 13, 2022

These are Windows-specific enhancements only:

- You can now at last connect to and access network drives with the new `os.netuse` function.

- The new `os.netdomain` function returns the domain name and the name of the primary domain controller (PDC).

- `os.filename` now also returns short DOS 8.3 filenames if any second argument is given.

- `os.fstat` now returns the binary type of an executable with the new 'binarytype' entry.

- `os.system` now also returns service pack information if available, and a version summary string.

- To make porting Lua packages to Agena in the future easier, added some Lua 5.2 compatabilitry API functions.


2.27.0, April 10, 2022

- The `do/as` statement now accepts a simple assignment as the closing condition. If an assignment is given in the `as` clause, its right-hand side is evaluated and stored to the left-hand side non-local name. The result of the evaluation is then checked and either the loop body is executed once again or not. `do/until` loops also behave the same. Example:

  > a, c := [10, 20, 4 ~ 30], 1

  > do
  >    print(a[c], c++, t)
  > as t := a[c] <> null
  10      1       null
  20      2       true

- Likewise in `for` loops, the optional `while` and `until` clauses now accept a simple assignment. In such a case, the right-hand side of the assignment is evaluated and stored to the left-hand side non-local name. The result of the evaluation is then checked and either the loop body is executed or not. Example:

  > a := [10, 20, 4 ~ 30]  # the table has no index 3

  > for i to 4 while t := a[i] do  # since a[3] evaluates to null, which is equal to false in this context, the loop quits with i = 3.
  >    print(a[i], t)
  > od
  10    10
  20    20

- The new 'enclose' option to `print` encloses the values to be printed in a given substring. Also, all options to `print` can now be mixed.

- The new function `math.isnormal` returns true if a number is neither +0, -0, +infinity, -infinity, undefined nor subnormal. The result is equal to the expression math.fpclassify(x) = math.fp_normal.

- The new constant `math.two54` represents 2^54, a value with which subnormal numbers can be multiplied in order to become normal.

- The new function `hashes.roaat` works like `hashes.oaat`, but uses bit rotation internally instead of simple bit shifts.

- Extended `environ.kernel` with the new 'builtoncpu' entry which denotes the CPU architecture on which Agena has been built.

- Tweaked the `trim`, `lower` and `upper` operators, and the `xbase` package.

- Because of a namespace collision, the undocumented function `math.infinite` could not be called. The function has been removed since the existing `infinite` operator is much faster and has the same functionality.

- `math.nextpower` returned incorrect results on non-Intel and non-ARM platforms. This has been fixed.

- Streamlined memory allocation error messages.

- Various code-cleansing.

- This release has been Valgrind-checked on x86 Linux to ensure there are no internal errors or memory leaks.


2.26.3, April 02, 2022

- The new function `math.nextpower` returns the smallest power of a given base greater than its argument; optionally returns the smallest power equal or greater than its argument.

- The new function `memfile.rewind` sets the current size of a memory file to zero, effectively clearing the buffer without re-allocating memory. Likewise, the new function `memfile.move` resets the end of a buffer to a user-defined position.

- The new function `memfile.find` searches a memory file for a substring and returns its position.

- The new function `memfile.shift` rotates the contents of a buffer to the left or to the right.

- `memfile.dump` did not re-initialise the buffer with the original user-defined capacity but used a default instead. This has been fixed. Also, with a byte buffer, the function now refills it with zeros again after dumping the contents.

- In the Windows editions, the `xml` package has now been bound to the expat-2.4.7 library and the `gzip` package to zlib-1.2.12.

- The `mp` and `mpf` packages for Windows and Linux have been bound to gmp-6.2.1 and can run on at least Intel Sandybridge processors (2011 and later).

- Tweaked `strings.advance`, `strings.chomp`, `strings.gseparate`, `strings.hits`, `strings.isabbrev`, `strings.isending` and `strings.remove`.

- `pipeline` and `tar.extract` accidently declared some global variables. This has been fixed.


2.26.2, March 23, 2022

- The `memfile` package has been extended to make it more generic and to facilitate programming - for example - bitfields.

  - The new function `memfile.getchar` returns the character (a string) stored in a memfile at a given position.

  - The new function `memfile.getbyte` returns the byte (an integer) stored in a memfile at a given position.

  - The new function `memfile.getbit` returns a bit in a memfile at a given position.

  - The new function `memfile.setchar` sets a character (a string) to the given position in a memfile.

  - The new function `memfile.setbyte` sets a byte (an integer) to the given position in a memfile.

  - The new function `memfile.setbit` sets a bit in a memfile to either 0 or 1.

  - The new function `memfile.clearbit` unsets a bit in a memfile, i.e. sets it to zero.

  - The new function `memfile.bytebuf` creates a memfile of a fixed size and fills it with zeros by default. It can also initialise the buffer with bytes passed by the user. Since the memfile created is no different from the one created by `memfile.charbuf`, you can apply all the other `memfile` functions on it.

  - The new function `memfile.resize` grows or shrinks a memfile and optionally fills new space with zeros.

  - The new function `memfile.attrib` returns the total capacity of a memfile and the current number of bytes in a memfile.

- The new function `bytes.optsize` calculates the optimal number of bytes (places) in a C `array` (e.g. a memfile, numarray or string) if it shall be aligned on the 4- or 8-byte word boundary.

- To abide by established standards, `com.attribs` has been renamed to `com.attrib`.

- Tweaked `io.readlines`, `io.nlines` and `io.skiplines` a little bit.

- Added the `os.meminfo` alias to `os.memstate`.

- `strings.shannon` crashed with characters that have an ASCII code greater than 127. This has been fixed.

- Calling `aconv.list` in OS/2 may have been unsafe. This has been fixed.

- On all Linux flavours, the `xml` package now has been bound to the expat-2.4.7 library.

- `setbit` no longer accepts `fail` as its third argument.

- This release has been Valgrind-checked on x86 Linux and x86 Mac OS X to ensure there are no internal errors or memory leaks.


2.26.1, March 19, 2022

- The new `aconv` package is a port to the GNU iconv package and transforms strings from one codepage to another. At least on OS/2 and Windows and you can choose between more than 400 codepages. The package is based on Alexandre Erwin Ittner's Lua-iconv 7 package for Lua 5.1. The package is not available on Mac OS X.

- The new functions `strings.toupper` and `strings.tolower` convert a string to lower and upper case, respectively. By default, contrary to the `upper` and `lower` operators, they only convert the letters A to Z. If you pass any option, then they will also transform the diacritics listed at the start of Chapter 7.2 of the manual.

- `skycrane.enclose` now also accepts Booleans and 'null' as input.

- `utils.readcsv` now tracks all lines skipped if the `skipfaultylines` option has been given and returns them as a second result.

- The 64-bit Debian installers for ARM and Intel/AMD now include the following plus packages that were missing before: gzip, xml, mapm.

- The DOS version has now been built with DJGPP/GCC 10.3.

- The new C API function agnL_tostringx converts a number, a Boolean, null or a string to a string.

- This release has been Valgrind-checked on x86 Linux and x86 Mac OS X to ensure there are no internal errors or memory leaks.


2.26.0 Update 1, March 15, 2022

- The new 'skipfaultylines' option to `utils.readcsv`, if set to true, ignores all lines in a CSV file that do not have the same number of fields as there are in the CSV header (or the first CSV line if a header is non-existent).

- The new 'dictionary' option to `utils.readcsv` returns a dictionary instead of a sequence with the dictionary keys defined by the values in the row passed with this new option, where the row can be depicted by a field number or field id (a string). The values in the `key` row should be unique. Example:

  > utils.readcsv(file, ..., fields = ['ZIP', 'CITY', 'COUNTY'], dictionary = 'ZIP', ...)

- The new function `skycrane.formatline` is similar to `io.writeline`, but returns a string. Example:

  > skycrane.formatline([1, 'agena', true], delim = '|', enclose = '\''):
  '1'|'agena'|'true'

- You will find the update in the Binaries/Agena 2.26.0 Sourceforge folder, file `agena-2.26.0-update1.zip`. Download it and check the instructions on how to install this library update on all supported operating systems, see libupdate.readme file at the root of the ZIP archive.


2.26.0, March 12, 2022

- You can now use the `end` token instead of the closing `fi`, `od`, `esac`, `yrt` and `epocs` keywords.

- If you pass a set of more than five type names to the `::` and `:-` operators, Agena now issues an error.

- Agena compiles and runs successfully in 64-bit mode.

- The first 64-bit Debian installers of Agena are available, with the following plus packages missing: gdi, gzip, fractals, mapm, xml.

- The Debian installers no longer check for dependencies as this never worked well.

- With a set as the second operand, the `::` and `:-` type check operators sometimes did not correctly process set members, causing invalid memory reads. This has been fixed. Example: `[] :: {listing, set, pair)`.

- Function composition with the `@` operator has been fixed once again.

- This release has been Valgrind-checked on x86 Linux and x86 Mac OS X to ensure there are no internal errors or memory leaks.


2.25.5, March 10, 2022

- This is just a technical release preparing a future 64-bit version of Agena. Note that Agena does not yet run successfully in 64-bit mode but runs smoothly in 32-bit mode. It is still recommended to compile and run Agena with 32-bit GCC in Solaris, Mac OS X, Linux and Windows.

- The source code now compiles flawlessly without any warnings on modern and vintage UNIX flavours. As in the past, Agena compiles flawlessly without any warnings in OS/2, DOS, Windows and Solaris.

- As such, only the updated sources have been released, there are NO new binary installers since there are no functional changes.

- To support development of a 64-bit release, the following extensions to `environ.kernel` have been temporarily introduced:

  - The 'alignable' entry indicates whether your system aligns data along the 4- or 8-byte word boundary.
  - The 'is32bit' entry is true when Agena has been compiled in 32-bit mode.
  - The 'is64bit' entry is true when Agena has been compiled in 64-bit mode.
  - When compiled with GCC, the 'glibc' and 'glibcminor' entries denote the major and minor GLIBC version linked during compilation.

- This release has been Valgrind-checked on x86 Linux and x86 Mac OS X to ensure there are no internal errors or memory leaks.


2.25.4, March 05, 2022

- The new function `strings.strverscmp` compares two version strings and is an interface to the GNU C strverscmp function. From the GNU documentation: "If you have files jan1, jan2, ..., jan9, jan10, ..., it feels wrong when an application orders them jan1, jan10, ..., jan2, ..., jan9." This is what this function is for: it compares version strings in the anticipated manner.

- The new function `strings.strcmp` compares two strings and is an interface to the C strcmp function. It returns "a value that has the same sign as the difference between the first differing pair of characters" (GNU C Library manual). For backward-compatibility, `strings.compare` still calls C's strcmp if given any option, but this feature is no longer documented.

- The new function `strings.strstr` searches a string for a substring and returns a substring from the first match to the end of the string plus the position of the match. The function is an interface to the C strstr function.

- The new function `strings.strchr` searches a string for a single character represented by its ASCII code and returns a substring starting from the first match to the end of the string plus the position of the match. The function is an interface to the C strchr function.

- The new function `strings.strrchr` is like `strings.strchr` but searches backwards from the end of a string. It is an interface to the C strrchr function.

- `strings.iterate` can now also traverse fields in a string by passing a string of one or more delimiters as the second argument.

- To better distinguish between `ordinary` numbers, subnormal numbers, `undefined` and `infinity`, changed the enumeration of values returned by `math.fpclassify` to:

  0, if a number is `undefined',
  1, if a number is -`infinity' or +`infinity',
  2, if a number is subnormal,
  3, if a number is zero,
  4, if a number is normal, including irregular values >= 2^52.

  Thus, for example, `ordinary` numbers are now represented by results greater than 2.

  Changed the values of the constants `math.fp_nan`, `math.fp_infinite`, `math.fp_subnormal`, `math.fp_zero` and `math.fp_normal` accordingly.

  You may have to check your code calling `math.fpclassify` if it relies on the exact enumeration.

- Internal string reversal has further been patched to prevent invalid memory reads. This also fixes an undocument feature of `strings.reverse` and benefits `stacks.dumpd` when processing empty strings.

- This release has been Valgrind-checked on x86 Linux and x86 Mac OS X to ensure there are no internal errors or memory leaks.


2.25.3, February 26, 2022

- Fixed an invalid memory access error that sometimes happened on Mac OS X, but might also affect other platforms, with internal string reversals, which for example are executed by `stack.dumpd`.

- This release has been Valgrind-checked on x86 Linux and x86 Mac OS X to ensure there are no internal errors or memory leaks.


2.25.2, February 26, 2022

- The new function `strings.iterate` returns an iterator function that computes the next n characters stored in a string, starting at a user-defined position. There is also a mode that instead of substrings returns an unsigned integer for each consecutive four characters.

- The new function `strings.isaligned` checks whether a string is aligned on the 4-byte word boundary.

- Tweaked `strings.compare` by at least ten percent.

- Conducted further tweaking and some minor optimisations.

- Changed the sources to prevent a compiler warning in Solaris 10.

- This release has been Valgrind-checked on x86 Linux and x86 Mac OS X to ensure there are no internal errors or memory leaks.


2.25.1, February 21, 2022

- Performed a lot of code tweaking and optimisations. There are no functional changes.

- Fixed an internal memory operation for platforms not supporting word-aligned data.


2.25.0, February 14, 2022

New features:

- In procedure bodies, you can now refer to variable arguments with just the `?` token, which is some sort of shortcut to the `varargs` table reference, for example:

  > f := proc(?) is
  >    return ?, ?[1]
  > end;

  > f(1, 2, 3):
  [1, 2, 3]       1

- OOP methods can now also be defined by using the standard `:=' assignment statement, e.g.:

  > account := ['balance' ~ 0];

  > account@@deposit := proc(x) is
  >    inc self.balance, x;
  >    return self.balance
  > end;

  Call the method as usual:

  > account@@deposit(100);

- Likewise, OOP-style methods can now also be defined with short-cut functions:

  > account := ['balance' ~ 0];

  > account@@getbalance := << () -> self.balance >>

  > account@@getbalance():
  0

- For consistency, the `storage' feature that allows procedures to persist states between various invocations has been renamed to just `store'. You may have to change your code to upgrade.

- The left and right bitshift operators `<<<` and `>>>` now return zero if the right operand is greater or equals environ.kernel('nbits').

- `environ.kernel` returns the number of bits used in 4-byte and 8-byte integers with the new 'nbits' and 'nbits64' entries. The new entry 'bitsint' depicts the number of bits in a C int.

Improvements:

- Tweaked `calc.intde`, `calc.intdei`, `calc.intdeo` and `calc.sections`.

Bugs fixed:

- Function composition via the `@` operator, e.g. `g @ f` with g and f multivariate functions, did not work correctly when calling the composition. This has been fixed.

- There has been a long-standing bug in the Mac OS X edition with regards to string handling, causing memory leaks. This has been fixed.

- `os.cpuload` crashed on Windows 2003 Server. This has been fixed.

Miscellaneous:

- The sources have been adapted so that they compile successfully with MinGW/GCC 10.2. The Agena Windows binaries available for download, however, will still be produced with GCC 6.2.0 as there are no speed benefits with GCC 10, the reduction of binary file sizes is marginal only, and there are some few issues with the command line, legacy DLLs and with DLL stripping.

- This release has been Valgrind-checked on x86 Linux and x86 Mac OS X to ensure there are no internal errors or memory leaks.


2.24.3, February 05, 2022

- The new function `calc.zeroin` determines the root of a univariate function in a given interval. In general, the function will even return accurate results when `calc.regulafalsi` fails to do so - or even does not find a root at all-, but the runtime behaviour depends on some conditions, see the manual.

- `calc.zeros` internally now uses `calc.zeroin` instead of `calc.regulafalsi` to determine roots.

- The new function `calc.differ` is a wrapper to `calc.eulerdiff` if the `deriv=1` or no `deriv` option has been given, and to `calc.xpdiff` otherwise, thus automatically choosing the best method to compute a derivative.

- The fourth argument to `calc.regulafalsi`, the tolerance, has become optional.

- `math.sinhcosh` has been tuned by 15 percent for the domain |x| < 22.

- Renamed `dual.dhypot` to `dual.hypot`, `dual.darcsinh` to `dual.arcsinh` and did the same with `dual.arccosh`, `dual.arctanh`, `dual.expminusone`, `dual.lnplusone`, `dual.log2` and `dual.log10`. Aliases have been provided to ensure backward compatibility.

- Updated the scheme files.

- The new C API function `agnL_fnunicall` is a simplified wrapper function to `agnL_fncall`.


2.24.2, January 23, 2022

- The following inverse hyperbolic functions have been added to the `dual` package: `dual.darcsinh`, `dual.darccosh`, `dual.darctanh`. Also added the logarithmic functions `dual.dlog2` and `dual.dlog10`.

- The new procedure `dual.erfcx` implements the scaled complementary error function for dual numbers.

- Added functions `dual.dlnplusone` and `dual.dexpminusone` to compute ln(x + 1) and exp(x) - 1, respectively.

- `dual.dhypot` has been implemented in C, making it 33 percent faster. The `dual' package functions `sin`, `cos`, `sinh` and `cosh` have also been tuned by 33 percent.

- The `dual` package functions `derf`, `derfc` and `dhypot` have been renamed to `dual.derf`, `dual.derfc` and `dual.dhypot`, respectively. Aliases have been provided to ensure backward compatibility.

- Tweaked `sin`, `sinc`, `cos`, `cosxx`, `tan`, `tanc`, `tanh`, `exp`, `antilog2`, `antilog10`, `root`, `proot`, `ipow`, `cbrt`, `gamma`, `cas` and `bea` for the complex domain. Also tweaked `calc.lambda`.


2.24.1, January 17, 2022

- The `++' and `--' statements and operators now support indexed names, at last. Thus, commands like

  > a[1]++; a[2]++

  > c := a[1]++

  have become valid expressions.

- After issuing the `restart' statement, the `llist` and `ulist` packages could not be successfully imported. This has been fixed.


2.24.0, January 08, 2022

New features:

- The `with/in` statement has been significantly improved, but may cause incompatibilities with older code: All the values listed between the `with` and `in` tokens are now automatically written back to the table after leaving the block, so that:

  > zips := ['duedo' ~ 40210:40629,
  >          bonn    = 53111:53229,
  >          cologne = 50667:51149];

  > with duedo, cologne in zips do  # bonn has not been given here
  >    cologne := null;      # cologne entry will be deleted from table zips
  >    duedo := 40210:51149  # duedo entry in zips will be changed
  >    bonn := null          # bonn entry will not be changed since it is not listed in header
  > od;

  will result into:

  > zips:
  [bonn ~ 53111:53229, duedo ~ 40210:51149]

- The new `$$` operator applies a Boolean function onto each element of a structure and returns `true` if at least one element satisfies the given condition. Otherwise, the operator returns `false`.

- The new function `stats.cartprod` creates the Cartesian product of a table of tables or a sequence of sequences.

- The new function `stack.enqueued` inserts an element at the bottom of a stack, shifting all existing elements into open space.

- The new function `stack.dequeued` removes an element from the bottom of a stack and returns it, closing the space.

Improvements:

- `reverse` can now reverse the elements in the array part of a table, in-place.

- `strings.tochars` can now process sequences with word-aligned unsigned 4-byte integers by passing the optional argument 4.

- The following functions now accept numarrays as input: `stats.gmean`, `stats.herfindahl`, `stats.iqr`, `stats.mean`, `stats.percentile`, `stats.qmean`, `stats.sd`, `stats.var`, `stats.qcd`, `stats.trimmean`, `stats.zscore`.

- `stats.herfindahl` can now process more than 2,047 samples.

- If passed `true` as the very last argument to `stack.dumpd`, the selected elements are returned in reverse order. This saves an expensive call to `stack.reversed`.

Bug fixes:

- OOP functions actually did not work in most cases. This has been fixed:

  - There are no longer segmentation faults with OOP functions that do not have parameters.

  - Type checks are now working correctly.

- `binio.close` did not correctly close files and free associated memory, causing `invalid file handle` error messages later on in a session when doing file or network I/O. This has been fixed.

- Agena's six internal stacks cannot grow out of bounds any more due to internal overflows when trying to calculate the new size. Also, the internal allocated space is not doubled with each automatic resize, but grows by a factor of 5/4 only.

- Page numbers in the table of contents and the index of the Primer and Reference have been fixed.


November 09, 2020

- Version 23.0 has been taken offline due to instabilities reported by users which could all be reproduced.


2.22.1, October 25, 2020

- `io.open` and `io.popen` could crash if given an invalid mode. This has been fixed.

- The new function `math.nextmultiple` returns the next multiple of an integer to the given integer base.

- The new function `stats.numbpart` computes partition numbers.

- The new function `stats.bell` computes Bell numbers.

- Introduced unsigned 32-bit integers to the `numarray` package, to be created with the new function `numarray.uint32`. See also: `numarray.readuint32` in the Primer and Reference.

- `numarray.sort` can now sort all kinds of arrays.

- To prevent segmentation faults, `numarry.resize`, `numarray.uchar`, `numarray.ushort`, `numarray.double`, `numarray.int32` and `numarray.uint32` can no longer create arrays of more than 2,147,483,647 elements.

- Corrected error message in `numarray.getbit`.


2.22.0, October 01, 2020

- The `++' and `--' increment and decrement operators can be used in statments, i.e.

  > c := 0;

  > c++;

  is valid syntax now.

- Introduced a `no-operation` statement that does nothing, for example:

  > if 1 = 1 then
  >    do nothing
  > fi;

- `io.eof` has become 25 percent faster.

- The new function `io.ferror` checks the error indicator for a file.

- The new function `io.clearerror` clears the end-of-file and error indicators of a file.

- The new function `os.faccess` checks the read, write and execute permissions of a directory or file.

- The new function `environ.decpoint` returns the decimal point separator used in the current locale. It is an alternative to the expression `os.getlocale.decimal_point`, but is faster.

- `io.read` with the '*n' option can now also read hexadecimal numbers and numbers in scientific E notation. It can now also process floats that include the decimal point separator of the current locale that may be different from a dot.

- The new '*L' option to `io.read` reads the next line keeping the end-of-line character.

- `xpcall` now accepts optional function arguments.

- With pipes, `io.close` returns the exit code of the application run as a second result. Likewise, `io.pcall` returns the exit code, as well.

- `strings.repeat` accepts an optional delimiter and also protects against overflow or underflow.

- Added the '%f' frontier pattern. Please check Chapter 7.2.3 of the Primer and Reference for further details.

- Added '\x' hex escapes. See next example.

- The new escape sequence '\z' skips subsequent white-space characters, including line breaks; it is particularly useful to break and indent a long literal string into multiple lines without adding the newlines and spaces into the string contents. Example:

  > print('{\n\z
  >       \x20   \"\104ello\": \"world\"\n\z
  >       }')
  {
      "hello": "world"
  }

- The C API function `lua_stringtonumber` could not be used as its definition was missing in the `agena.h` header file. This has been fixed.

- In Solaris, the `gdi` package could not be initialised. This has been fixed.


2.21.11, September 22, 2020

- The new function `strings.fuzzy` compares two strings case-insensitively and returns an estimate of their similarity as both an absolute and relative score.

- If you pass any second argument to `os.chdir`, the function will no longer issue an error. Instead, it will return `false` if the given path does not exist, or `fail` if you have no permission to enter the directory. Otherwise, the function will return `true` and commit the change of directory.

- All installers now put the scheme files in share\schemes and the icons in share\icons. They also install sample script files in share\scripting, including one that searches for a given file in a path. Start-up batch files for ArcaOS, eCS, OS/2, DOS and Windows are provided, as well.

- The Windows uninstaller did not delete the share folder. This has been fixed.

- Rewrote Appendix A4 on command-line usage & scripting.

- The ArcaOS - OS/2 edition now includes experimental versions of the `gdi` and `fractals` packages.


2.21.10 Update 1, September 16, 2020

- `os.list` and thus also `os.whereis`, `os.findfiles`, `skycrane.fcopy` and `skycrane.move` could not recurse into subdirectories from root. This has been fixed.

- Likewise, `os.list` threw an error when trying to access a directory without proper permission. This has been fixed, as well.

- There are special cumulatative installers with the complete Agena edition for ArcaOS (OS/2), DOS and Windows. For all other operating systems, you will find the update in the Binaries/Agena 2.21.10 Sourceforge folder, file `agena-2.21.10-update1.zip`. Download it and check the instructions in the accompanying read.me file on how to install this library update.

- OS/2, eCS & ArcaOS: The installer is now created with WarpIN 1.0.24 under ArcaOS.


2.21.10b, September 04, 2020

- Windows only: The Windows installer could corrupt the PATH environment variable if it already consisted of around 1,000 or more characters. With the new installer, this threshold has been raised to around 8,000 characters and modification of PATH is now deselected by default. A proper warning text is displayed, too.


2.21.10, August 30, 2020

- Bessel functions `mpf.jn` and `mpf.yn` did not work. This has been fixed.

- The new functions `mpf.Inf` and `mpf.Zero` return +/-infinity and +/-0, respectively, as MPFR objects. `mpf.Nan` returns the MPFR equivalent of `undefined`.

- The new function `mpf.recsqrt` returns the inverse square root.

- The new function `mpf.swap` swaps two MPFR objects efficiently.

- The new function `mpf.clone` clones an MPFR value.

- The new functions `mpf.min` and `mpf.max` return the minimum and maximum of two MPFR values.

- The new function `mpf.nexttoward` works like `math.nextafter`, but for MPFR values.

- The new function `mpf.copysign` works like `math.copysign`, i.e. returns its first argument with the sign of its second one.

- The new function `mpf.signbit` checks the sign bit and returns `true` (value is negative) or `false`.

- The new function `mpf.random` returns a uniformly distributed random float on the interval [0, 1]. `mpf.randinit` resets the random number generator.

- Stripped down the binary size of the Windows distributions.

- The Solaris edition now again includes a working version of AgenaEdit.


2.21.9a, August 26, 2020

- The Windows GMP and MPFR DDLs had to be recompiled as they caused Agena segfaults on older Intel-compatible CPUs (e.g. Core 2 Duo E8500,
  i5-2400, i5-3470S). The recompiled DLLs now run fine on Windows 2000, 7, XP, Windows 8.1 and 10.


2.21.9, August 25, 2020

- Added a binding to the GNU Multiple Precision Floating-Point Reliable Library (MPFR). The binding unfortunately is not available on Mac OS X as it cannot be compiled there.

- Tuned `linalg.backsub`, `linalg.forsub` and `linalg.rref` by four percent.

- `calc.gtrap`, `calc.fminbr`, `calc.fmings`, `linalg.rref`, `linalg.backsub` and `linalg.forsub` have been tuned a little bit. If you want to change the precision of these functions, then you now have to call `envion.kernel` with the 'eps' key.

- The C API function `lua_setmetatabletoobject` has been extended to delete metatables and optionally user-defined types.


2.21.8, August 17, 2020

- The new function `math.rempio2` conducts argument reduction into the range -Pi/2 .. Pi/2, avoiding computational overhead.

- The new function `multiple` checks whether a number is a multiple of another number.

- `cot`, `csc` and `sec` returned a very large or very small value instead of `undefined` if their argument was a multiple of Pi. This has been fixed.

- `integral` can now evaluate complex numbers. If the real part is integral and the imaginary part is zero, then it returns `true` and `false` otherwise. Likewise, with a complex number, `float` returns `true` if its real part is non-integral and the imaginary part is zero.

- `environ.system` now returns the setting of the GNU C environment variable FLT_RADIX with the new 'floatradix' key. Its value usually is 2.

- You can get and set the current value of 'DoubleEps' with the new `environ.kernel/doubleeps` feature. `multiple`, `calc.bernoulli`, `calc.euler` and `calc.lambda` now query this real-time value instead of using a hard-coded one.

- `environ.kernel/eps` did not change the system variable "Eps" in the environment. This has been fixed.

- The C API function `agn_getepsilon` has been changed to a macro, speeding up access.

- The new C API macro `agn_getdblepsilon` returns the current value of "DoubleEps" as used in the environment.

- The new C API function `agn_setdblepsilon` sets the current value of "DoubleEps" for subsequent use in the environment.


2.21.7, August 10, 2020

- The new function `erfi` computes the imaginary error function erfi(z) = -I*erf(I*z) for real and complex z.

- The new function `pytha` computes the Pythagorean equation c^2 = a^2 + b^2, without undue underflow or overflow.

- Added two new value-based hashing functions for unsigned 4-byte integers, ported from Julia: `hashes.j32to32` and `hashes.jinteger`.

- With complex arguments `cosc` has become seven percent faster.

- In OS/2 and DOS, the `cis` operator has become 30 % faster with complex arguments.

- Extended mathematical test cases.


2.21.6, July 26, 2020

- `sinc` in the real domain has become more numerically stable near zero.

- For real and complex arguments, introduced the scaled complementary error function `erfcx`(x) = exp(x^2) * erfc(x) which can used instead of `erfc` to avoid arithmetic underflow.

- Added the new scaled Dawson integral function `calc.scaleddawson` which returns 2*calc.dawson(x)/sqrt(Pi).

- The new function `calc.w` computes the scaled complex complementary error function w(z) = exp(-z^2) * erfc(-I*z).

- The new function `math.relerror` computes the relative error function, handling case of `undefined` and `infinity`.

- Introduced the new conversion specifier `b` to `strings.format` to print binary values.

- In `strings.format`, the `a`, `A`, `q`, `Q` and `B` specifiers now recognise length indicators.

- The new C API function `agn_isfloat` checks whether a number is a non-integral float.


2.21.5, July 09, 2020

- Implemented the new inverse (complimentary) error functions `inverf` and `inverfc`.

- The new function `stats.probit` computes the inverse of the cumulative distribution function of the standard normal distribution.

- The new function `stats.cdfnormald` implements the cumulative density function for the standard normal distribution.

- Standardised error messages of `stats.studentst`, `stats.chisquare`, `stats.fratio`, `stats.cauchy`, `stats.pdf`, `stats.ndf`, `stats.nde`, `stats.neighbours`, `stats.nearby`.

- `io.readfile`, `io.readlines`, `io.nlines`, `io.skiplines` and `io.infile` each have become 20 percent faster.

- When calling `calc.chebycoeffs`, the left border must now always be less than the right border.

- The new functions `os.isarm`, `os.isppc` and `os.isx86` check whether Agena is being run on an ARM, PPC, or x86 CPU, 32- or 64-bit.

- The `stats` package could not be initialised for the parser thought that an upvalue in a closure was a constant which it was not. This has been hot-fixed. As for now, if you try to change a constant in a closure, the parser will not issue an error any longer.

- Updated the Primer & Reference according to the suggestions of an unknown user, primarily the description of `strings.format`.


2.21.4, Independence Day Edition, July 04, 2020

- The new function `copyadd` copies all elements in a table, sequence or register and any further arguments into a new structure.

- The new function `tables.getsizes` returns the estimated or the actual number of elements currently stored in the array and hash part of a table.

- The new function `calc.curvature` determines the curvature of a real univariate or multivariate function at a given point.

- `calc.eulerdiff` can now compute second derivatives by passing the new `deriv = 2` option. The quality of the second derivatives are close to, but not as good as, those of `calc.xpdiff`. (The first derivatives of `eulerdiff` are usually still better than those of `xpdiff`.)

- The new function `calc.gauleg` computes the integral of a univariate function using Gauss-Legendre integration. It is five times faster than `calc.integ` with comparable precision.

- The new function `calc.variance` returns an estimate on whether a univariate function changes slowly or rapidly on a given interval.

- The new function `calc.fmings` estimates the minimum location of a univariate function over a given range, using Golden section search only.

- Documented function `calc.fminbr` which estimates the minimum location of a univariate function over a given range, using Golden section search combined with parabolic interpolation.

- `calc.integ` has been improved in that with finite integrals, it switches to a second method if the first one fails.

- If `calc.arclen` could not find a solution at first, it will now automatically try an alternative to compute a result.


2.21.3, June 29, 2020

- The new `?-` token checks an expression and executes a one-line statement if it evaluates to `false`, `fail` or `null`. Example:

  > 1 = 2 ?- print('untrue')
  untrue

  > 1 = 1 ?- print('true')
  (nothing)

- The new function `os.whereis` searches for a given file, link or directory in a directory, optionally including subdirectories.

- If a string included the substring '*/' or '/#', Agena crashed. This long-time bug has been fixed.

- On the interactive level, if you define one and the same constant multiple times in a body, for example a `then` or `do` body, Agena will just print a one-time warning message and will change that constant. When executing a script file, however, Agena would quit execution with a proper error message. (This is due to the way the parser evaluates bodies on the command-line.)


2.21.2, June 21, 2020

- Fixed the following problems with constants:

  - If you try to change a constant by using the post-fix `++` or `--` increment and decrement operators, Agena now issues an error.

  - When trying to assign a value to a constant in `if` or `while` conditions, e.g. `if f := 1 then ...` or `while f := 1 do ...`, an error will be issued, as well.

  - `create` and `create local` statements do no longer overwrite constants.

  - Constants should no longer be overwritten in interactive mode.

- The C API function `lua_getfield` has become at least 10 percent faster, and `lua_gettable` 5 percent faster. They new also return the type pushed onto the stack. The tuning benefits some functions in the basic, `os`, `io`, `bags`, `linalg`, `llist`, `ulist` and `environ` libraries.

- `lua_toint32_t`, `lua_touint32_t`, `lua_tooff64_t`, `lua_tointegerx`, `lua_tounsignedx` have each been tuned by 40 percent. This speeds up functions in the `binio`, `calc`, `com`, `llist`, `ulist`, `memfile` and `numarray` packages.

- `agn_seqgetinumber`, `agn_reggetinumber` and `lua_seqrawgetinumber` have each been tuned by 4 percent, but the benfit to functions which use them (`calc`, `stats` and `numarray` packages) should be marginal.

- Added the following C API functions, taken from Lua 5.4.0 RC 5, in some cases just for compatibility with future code that might be merged into Agena:

  - `lua_absindex` converts an acceptable stack index into an absolute index.

  - `lua_getiuservalue` pushes onto the stack the n-th user value associated with a userdata, reduced to always n = 1.

  - `lua_newuserdatauv` is just a wrapper to lua_newuserdata.

  - `lua_numbertointeger` is a macro converting a float with an integral value to an integer.

  - `lua_pushglobaltable` is a macro that pushes the global environment onto the stack.

  - `lua_rawgetp` pushes a table value with the key a pointer to a lightuserdata.

  - `lua_rawsetp` sets any value to a table with the key being a lightuserdata.

  - `luaL_argexpected` checks whether a C condition is true.

  - `luaL_addgsub` adds a string to the buffer, first replaces any occurrence of a pattern in the string to be added with another pattern.

  - `luaL_getsubtable` pushes a subtable in a table to the stack, or adds a new empty subtable to the table and pushes the new subtable onto it.

  - `luaL_setfuncs` registers all functions in a luaL_Reg array into the table on the top of the stack.

- For source code consistency only, the C API functions `lua_settable` and `lua_setfield` have been updated to the Lua 5.4.0 RC 5 implementation, but there is no noticable performance gain.


2.21.1, June 14, 2020

- The new function `tables.swap` swaps two elements in a table.

- The new function `tables.move`, taken from Lua 5.4, copies elements, either from one table to another table or shifts elements within the same table.

- The new function `environ.warn`, taken from Lua 5.4, emits a warning with a message. It is an alternative to `environ.infolevel`/`environ.userinfo` but does not allow to switch info messages on or off for an individual function.

- `environ.kernel` allows to query and set the warning mode.

- `strings.dump` may now be given a Boolean option, which controls whether debug information shall be stripped from the binary representation, to save space.

- Instead of passing a function to `zip`, you can now pass a string indicating an arithmetic operator to be used to zip together two structures. This is twice as fast with sequences and registers, and 50 % faster with tables.

- Besides numbers and strings, `memfile.charbuf` and `memfile.append` can now also add Booleans and `null` to a memory file without having to convert them to strings before, by calling `tostring`. You can now also specify an optional delimiter that separates each value to be added to the memory file, e.g. `memfile.append(m, 'a', 'b', 'c', delim = ';')` actually adds the string 'a;b;c;'.

- By passing a non-zero optional number, `memfile.dump` can now delete the given number of characters from the end of a memory file. In addition, error messages have been improved.

- The new system variable `environ.version` represents the Agena version as a float, contrary to `environ.release` which contains version information in a sequence.

- Updated the `utf8` package to the UTF8 library implemented in Lua 5.4.0 RC 4:

  - As the decoding functions in the `utf8` library do not accept surrogates as valid code points, an extra parameter `lax` in the functions makes them more permissive.

  - In Agena, in error conditions, `null` is still being returned, instead of (Lua's) `fail`.

- With strings, `tonumber` and the C API functions `agn_tonumberx`, `lua_tonumber`, `lua_tointeger`, and `lua_isnumber` have become 40 % faster.

- `inc`, `dec`, `mul`, `div` and compound assignment statements like `+:=`, etc. could modify constants. This has been fixed. (Postfix `++` and `--` operators still do not check for constants und modify them.)

- The new C API function `agnL_getsetting` returns the integral representation for a given string in a list.

- The new C API function `luaL_checksetting` checks whether a string in the stack is part of a list.

- Added new C API functions, all taken from Lua 5.4:

  - `lua_rotate` rotates stack elements up- or downwards.

  - `lua_copy` copies a stack element to a given poition, overwriting the existing one.

  - `lua_compare` compares two stack values.

  - `lua_arith` performs arithmetic on stack values.

  - `lua_geti` pushes a table value onto the stack, for a given integral key.

  - `lua_seti` sets a value into a table, for a given integral key.

  - `lua_setwarnf` sets the system's warning status.

  - `lua_getwarnf` retrieves the system's current warning status.

  - `lua_warning` emits a warning, or can switch the warning system on or off.

  - `lua_stringtonumber` converts a string to a number and pushes it onto the stack.

  - `lua_isnone` checks whether a stack index is acceptable, but not valid.

  - `lua_isyieldable` checks whether a coroutine can yield.

- The `com` package did not compile on some Linux platforms. This has been fixed.

- Updated the Agena Crash Course.

- As always, this release has been checked on x86 Linux (Raspian Stretch) to ensure there are no memory leaks.


2.21.0, June 10, 2020

- Added a general alternative to the `..` table field separator that indicates Agena not to issue an error if a `null` value shall be indexed: curly braces.

  Example:

  > a := [1, 2, 3, 'a' ~ [0, -1]];

  There is no 'b' field in a, and indexing a non-existing field usually causes an error:

  > a['b', 1]:
  Error in stdin at line 1:
     attempt to index field `b` (a null value) with a number value

  By using curly braces, Agena just returns `null` in such cases:

  > a{'b', 1}:
  null

  Or more basically:

  > a := null;

  > a[1]:
  Error in stdin at line 1:
     attempt to index global `a` (a null value) with a number value

  > a{1}:
  null

  > a{1, 1}:
  null

- Added the new pseudo type 'basic' which stands for a number, string, Boolean, or 'null' type. If given in a parameter list of a function, then Agena checks whether the respective argument is of one of the types mentioned before - if not, an error is issued. The new type can also be passed as the right operand to `::` and `:-`.

- `io.write` and `io.writeline` now accept null's as arguments - you do not have to convert them with `tostring` any longer.

- The new function `tostringx` works like `tostring` but also formats structures, userdata and complex numbers the same way as the prettyprinter does, or in other words: it returns the argument as a string formatted the same way as the `print` function outputs it on screen. This is useful if you want to write structures or complex numbers to a file.

- The `memfile` package has now become an integral part of the interpreter and is no longer a plus package. Thus, you do not have to invoke it with the `import` statement any longer.

- If a userdata is part of a structure, the prettyprinter now fully prints userdata for which there is a __tostring metamethod, instead of just issuing 'userdata(<pointer>)'.

- The prettyprinter has been changed internally and now first collects all the data in memory before outputting it at the console.

- Error messages of `cis`, `notin`, `zero` and `nonzero` have been improved.

- The new C API function `lua_hasfield` checks whether a table includes a field and returns true (1) or false (0).

- In Windows, the `gdi` library has been recompiled with GCC 6.3.0, substituting the DLL from 2013.


2.20.3, May 21, 2020

Bug Fixes:

- `reduce` inadvertently deleted a user-defined global variable _c. This has been fixed.

- In ill-fated situations, factories written in C may have caused problems with the internal table that stores all constants, potentially causing segmentation faults. This has been fixed.

Changes to the C API:

- Removed unused or obsolete C API functions agn_stackborders, agn_isvalidindex, agn_absindex, agn_calloc, agn_free, agn_rawgetifield, lua_seqrawget2, agn_regrawget2, agn_getseqlstring.

- Renamed C API function agn_datetosecs to agnL_datetosecs, and agn_pairgetinumbers to agnL_pairgetinumbers, agn_paircheckbooloption to agnL_paircheckbooloption.

- `lua_seqrawget` and `lua_regrawget` now need a third argument which controls whether in case of a non-existent key `null` or an error will be issued.

- `agnL_geti` can now process pairs and strings.

- Removed various C API macros.


2.20.2, May 18, 2020

- The new function `calc.bernoulli` computes the n-th Bernoulli number Bn.

- The new function `calc.euler` computes the n-th Euler number En.

- The new function `calc.lambda` computes the Lambda function and its derivative of integral order.

- By passing any option to `debug.getlocals`, only an array of parameter and local variable names plus the number of parameters (first entries in the array) is returned.

- `debug.getinfo`, with the new 'V' option, returns a table with all parameters and locals of an Agena function.

- Where unfitting, functions do no longer print an indication of a given type in error messages.

- Removed all undocumented Lua 5.3.5 string buffer C API functions.

- Some few internal changes to the parser with no effect on functionality. Also documented almost all lcode.c functions.

- The new C API function agnL_geti returns the i'th entry in a table, register, sequence or numarray and pushes it onto the top of the stack.

- Improved the Primer and Reference as well as the Crash Course.


2.20.1, May 06, 2020

- The `::` and `:-` type check operators have been extended: If a user-defined type has been declared for an object, and if a basic type is passed to the operators as the right operand, they will now perform a check for the given basic type. Formerly, the operators in this situation always returned `false`. With registers, the `:-` operator now checks for user-defined types, as well.

- If an empty set has been passed to `::` or `:-` as the right operand, they now return an error.

- Added the new pseudo-type 'anything' which stands for any type, including 'null'. If given in a parameter list of a function, then Agena checks whether the corresponding argument, regardless of its type, even 'null', has been passed in a function call - if not, an error is issued. The idea has been taken from Maple. The new type can also be passed as the right operand to `::` and `:-`.

- Added the new pseudo-type 'listing' which identifies a table, sequence or register in the parameter list of a procedure. The new type can be passed as the right operand to `::` and `:-`, too.

- You can switch off all duplicates warnings (variables shadowed / declared multiple times) introduced with 2.20.0 by issueing:

> environ.kernel(duplicates = false)

  See also the lib/agenaini.spl sample initialisation file which now includes preparations to switch off duplicate warnings and the new constants feature. (Uncomment the respective settings in paragraph `User-defined Initialisation of Kernel Settings` and rename the file to agena.ini if you like.)

- The `:-` operator ignored a given user-defined type and always returned `true`. Also, the `:-` operator returned a wrong result with userdata for which no user-defined type has been declared. Both issues have been fixed.

- Added new C API functions agn_getduplicates and agn_setduplicates to read current duplicates-shadowing setting and to switch warnings on or off.

- Added new C API function (lset.c) agnUS_setstr2set to insert a string (exactly: TString) into a set.

Some features introduced with 2.20.0 had not been included in the change log and are now described here:

- Introduced the new function `pipeline` which maps one or more functions on a table, set, sequence, register or userdata, avoiding multiple internal copies of a structure if possible.

- Added new C API functions (lapi.c) agn_getconstants and agn_setconstants to switch the constants feature on or off.

- Added new C API function (lset.c) agnUS_delstr to easily and safely delete a string (exactly: TString) from a set.


2.20.0, May 03, 2020

- You can now declare constants. If you try to assign a new value to a constant later on in a session, the interpreter will issue an error:

  > constant a := 1;

  > a := 2;
  Error at line 1: attempt to assign to constant `a` near `:=`

  You can declare multiple constants at a time:

  > constant b, constant c := 2, 3;

  > b := 0;
  Error at line 1: attempt to assign to constant `b` near `:=`

  > c := 0;
  Error at line 1: attempt to assign to constant `c` near `:=`

  You can also declare local constants, e.g.:

  > local constant a, constant b := 1, 2;

  You can mix ordinary and constant declarations:

  > a, constant b := 1, 2;

  You should assign a value to a constant in one and the same declaration, otherwise you cannot use it:

  > a, constant b := 1; # assign 1 to name `a`, and no value to constant `b`

  > b := 0
  Error at line 1: attempt to assign to constant `b`, near `:=`

  For speed, the new feature has been completely built into the parser without invoking the virtual machine - so you will not notice any decrease in performance.

- You can switch off this new feature completely with the following statement: environ.kernel(constants = false).

- enumerations now automatically declare constants:

  > enum one, two, three;

  > one := 0;
  Error at line 1: attempt to assign to constant `one`, near `:=`

- Added parser warnings for duplicate local variable declaration. The feature has originally been written by Domingo Alvarez Duarte for Lua 5.1. As with the new constants feature, only the parser has been modified so that you will not notice any performance decrease.

- `E`, `EulerGamma`, `Pi`, `Pi2`, `PiO2`, `PiO4`, `degrees`, `infinity`, `radians` and `undefined` have become constants. You cannot overwrite them any longer.

- The golden ratio `math.Phi` has been renamed to just `Phi`, a constant. An alias has been provided to ensure backward compatibility.

- `everyth` now also accepts two integers k, n and returns the Agena equivalent k % n = 0, a Boolean.

- The `if is` operator now accepts a trailing semicolon in `return` statements.

- `debug.getconstants` returns the internal set that stores global constants.


2.19.1, April 21, 2020

- Re-introduced Lua 5.1 function `ipairs` with extended functionality to iterate over structures, strings and userdata - such like numarrays, ulists and llists, etc. - in a standardised fashion. Also re-introduced `pairs` to iterate dictionaries and bags.

- In Linux, `os.cpuinfo` now differentiates between frequency and BogoMips and no longer returns BogoMips with the `frequency` field.

- With negative out-of-range indices, `numarray.subarray` and thus numarray's '__index' metamethod always returned the internal registry table. This has been fixed.

- Significantly improved Chapter 5.2.8 `for/in Loops over Procedures` in the Primer and Reference.

- Corrected Chapter 7.50 `com - Serial RS-232 Communication through COM Ports` of the Primer and Reference.

- Described all RS-232 `com` package functions in the Quick Reference.

- The new C API function agnL_getmetafield fetches the given metamethod and contrary to luaL_getmetafield also checks whether it is a procedure.


2.19.0, April 15, 2020

A new major release with an important bug fix:

- The `while` statement now accepts a simple assignment as a condition. If an assignment is given in the `while` clause, its right-hand side is evaluated and stored to the left-hand side name. The result of the evaluation is then checked and either the loop body is executed or not.

  This allows for shorter code: Instead of

  > flag := true;
  > while flag do
  >    flag := io.read();
  >    if flag = 'Z' then break fi
  > od

  you can now simply write (no need to assign `flag` before):

  > while flag := io.read() do
  >    if flag = 'Z' then break fi
  > od

  The variable assigned in the while clause is _not_ local to the loop body but can be accessed later on on the level that includes the loop.

- `if` and `case of` statements also support this new feature, and their optional `elif` and `of` clauses, as well.

  Old style:

  > flag := io.read();
  > if flag then
  >    print(flag)
  > fi;

  New style:

  > if flag := io.read() then
  >    print(flag)
  > fi;

- The `if` operator now supports one or more optional `elif` clauses:

  > a := 10

  > x := if a < 5 then 'a' elif a < 10 then 'b' else 'c' fi:
  c

- In `case` statements, the `else` clause may now be finished by the `esle` keyword. This new keyword is just a code beautifier, it has no functionality at all. `case` statements do not support the new assignment feature described above.

  > case a
  >    of 1 to 4 then
  >       print('a')
  >    of 5 to 9 then
  >       print('b')
  >    else
  >       print('c');
  >    esle
  > esac;

- The `case` statement did not correctly evaluate function calls like "case os.winver() of ..." and always executed the `else` part if it existed. This has been fixed.

- The `com` package has now been documented in the Primer and Reference.

- `case of` statements have been described in Chapter 5.1.6 of the Primer and Reference.

- The Agena Crash Course has been updated.

- Fixed a table-of-contents issue in the Primer and Reference.

- As always, this release has been Valgrind-checked on x86 Linux to ensure there are no memory leaks.


2.18.2, April 14, 2020

- In UNIX, `io.maxopenfiles` can now also change the maximum number of open files.

- In Solaris, `os.cpuinfo` now returns information on the CPU installed, instead of just `fail`.

- The `numarray` package can now handle unsigned 2-byte integers (uint16_t's). To create an array of uint16_t's, call `numarray.ushort`. To read a file of uint16_t's, call `numarray.readushorts`.

- `environ.system` now returns the maximum value representable in an unsigned 2-byte integer in the new field 'maxushort', and the corresponding C type 'uint16_t'.

- `bytes.tobytes` and `bytes.tonumber` can now treat unsigned 2-byte integers.

- `math.ulp` now optionally returns the number of ULPs between two values.

- Introduced the new `com` package which allows to send and receive data through RS-232 COM ports. The package is still experimental but has been successfully tested in Windows using virtual COM ports. For an example and the documentation, please refer to the `com.c` source file.

- `select`, `selectremove` and `remove` could crash if given a wrong type to the right-hand side of the 'newarray' option. This has been fixed.

- Corrected error messages of `stack.insertd` and `stack.replaced`.

- The `memfile` package accidently was not included in the DOS version. This has been changed.

- Fixed a blank-page and page number issue with the Primer and Reference.

- Patched the sources to prevent compiler warnings in UNIX-like GCC environment, e.g. Mac OS X, Debian Stretch and DJGPP/DOS.

- Successfully compiled Agena in OS/2 with gcc 8.3.0. The interpreter, however, became 13 percent slower, so switched back to gcc 4.4.6.

- The new C macro `lua_rawsetstringchar` sets a C char value, converted to a string, into a table.


2.18.1, April 04, 2020

- `math.normalise` now computes the normalised value according to Sun Microsystems's implementation which is more precise. By passing any optional argument, the high 4-byte word of the normalised value is returned, too.

- The new function `math.mulsign` multiplies, not copies, its first argument with the sign of its second.

- The new function `skycrane.isemail` checks whether a string represents a valid E-mail address.

- The following functions now accept numarrays as input: `stats.colnorm`, `stats.cumsum`, `stats.deltalist`, `stats.fivenum`, `stats.fprod`, `stats.fsum`, `stats.ios`, `stats.iqmean`, `stats.issorted`, `stats.mad`, `stats.md`, `stats.meanmed`, `stats.median`, `stats.midrange`, `stats.minmax`, `stats.prange`, `stats.quartiles`, `stats.rownorm`, `stats.smallest`, `stats.sumdata`, `stats.sumdataln`, `stats.trimean`.

- Some mathematical baselib and `stats` functions have been tweaked a little bit.

- `os.cpuload` crashed on Windows XP. This has been fixed.

- In Windows 2000 and earlier, with more than 1024 MBytes of installed RAM, `os.memstate` returned wrong results. This has been fixed.

- On Windows XP and earlier, `strings.format` cannot process the %h and %H modifiers. The function now issues an error in these versions.


2.18.0, March 29, 2020

General updates and changes:

- You can now add, subtract, multiply and divide numbers with `true` or `false`, where `true` in this context represents number 1 and `false` or `fail` number 0. Thus, you do not have to call `abs` any longer, e.g. abs(x > 0)*x and (x > 0)*x are now equivalent expressions.

- Booleans can now be added, subtracted, multiplied and divided.

- Streamlined the order of parameters of `functional programming`-style procedures:

  - `satisfy` can now be called as described in the Primer and Reference: first pass the function, then the object, and after that optional function arguments.

  - Likewise, `recurse` and `descend` now accept the function as the first argument, and the object as its second.

  - The changes to `recurse`, `descend` and `satisfy` are all downward-compatible, so the arguments can alternatively still be given as in the past.

- The new function `math.ramp` gives x if x > 0 and 0 otherwise.

- The new function `math.unitstep` gives 0 for x < 0 and 1 otherwise.

- New `math.piecewiese` implements piecewise-continuous functions.

- The `notin` operator now supports metamethods for all structures plus userdata.

numarray package:

- The `obj[a to b]` indexing method to retrieve table items, substrings, etc. can now also be applied on numarrays.

- Three new metamethods have been added to the `numarray` package:

  - the `zero` operator can now check whether all alements in an array are zeros,

  - the `nonzero` operator can now check whether all alements in an array are non-zeros,

  - the `notin` operator can now check whether an elememt is not part of an array.

- The `__in` metamethod has been implemented in C instead of Agena.

- The new function `numarray.satisfy` checks whether all elements in an array satisfy a given condition.

- The new function `numarray.map` applies a function on each element of a numarray and returns a new numarray.

- The new function `numarray.convert` works like `numarray.map`, but processes in-place, just changing the contents of the given numarray.

- The new function `numarray.sort` sorts a double numarray in ascending order, in-place.

- `numarray.write` has been rewritten and consumes much less memory than before, avoiding out-of-memory errors with large arrays.

- Fixed error messages of `numarray.getitem`.

- The following `stats` functions can now process numarrays of type double: `acf`, `acv`, `ad`, `amean`, `covar`, `durbinwatson`, `gini`, `hmean`, `meanvar`,  `moment`, `standardise`.

memfile package:

- The new function `memfile.map` maps a function on each character in a memfile, in-place.

- The new function `memfile.replicate` creates a copy of a memory file.

- The `notin` operator can now check whether an elememt is not part of a memory file.

- `memfile.substring` did not accept a negative stop value. This has been fixed.

llist package:

- The `notin` operator can now check whether an elememt is not part of a llist or ulist.

bags package:

- Added the new function `bags.getsize` to quickly determine the number of unique elements in a bag without the overhead of calling `bags.attrib`.

- Added support of `size`, `notin`, `empty` and `filled` metamethods.


2.17.8, March 24, 2020

- The `obj[a to b]` indexing method to retrieve table items, substrings, etc. can now also be applied on userdata.

- Introduced the new `memfile` package which simply collects substrings, i.e. combines them together. It is 20 times faster than simply concatening them iteratively with the `&` operator.

- `binio.open` can now open a file in append mode, by passing the 'a' option, so you no longer have to call `binio.toend` after `binio.open` to prevent overwriting the beginning of a file.

- If `numarray.write` wrote the entire contents of a numarray, it now automatically flushes all unwritten content to the file so that you do not have to call `binio.sync` manually any longer.

- Tuned all functions and operators that internally compare strings or internally determine string lenghts.

- Tweaked `strings.tobytes`.

- The sources are now being checked with Valgrind 3.15.0 for security leaks.


2.17.7b, March 21, 2020

- The sources did not compile on Debian systems. This has been fixed.


2.17.7 & 2.17.7a, March 19, 2020

- In all editions, tweaked complex versions of `arccoth` and `cosc`. Also tuned `stats.chisquare`, `stats.fivenum`, `stats.fratio`, `stats.gsmm`, `stats.mad`, `stats.md`, `stats.meanmed`, `stats.median`, `stats.midrange`, `stats.normald`, `stats.smm`, `stats.studentst`, `stats.trimean`, `calc.fminbr`, `calc.gtrap`, `calc.limit`, `calc.savgol`.

- In DOS and OS/2, with complex arguments, tweaked `arcsin`, `arcsinh`, `arccos`, `arcsec`, `arctan`, `arctan2` and `erf`.

- On Big Endian systems, `strings.tobytes` has been fixed.

- Some source code cleansing.


2.17.6, March 15, 2020

- This edition implements changes in the OS/2 and DOS editions of Agena only.

- In OS/2 and DOS, the `recip` operator has been changed such that the imaginary unit can never be -0 (minus 0), thus preventing wrong results with inverse trigonometric functions in the complex domain.

- The implementation of `arccsc` in OS/2 and DOS has been changed back to the original one, thus boosting the function.

- The new C API function `agn_getcmplxparts` returns the real and imaginary parts of a complex number.

- The new C API macro `agn_pushcomplex` pushes a complex number onto the stack.


2.17.5a, March 13, 2020

- The bugs in `arcsin`, `arccos`, `arcsinh` and `arcsec` have finally been fixed in the OS/2 and DOS releases.

- The test cases have been extended.


2.17.5, March 11, 2020

- A long existing bug has been found: in the complex domain, arcsin(z) returned `undefined` instead of a complex result if imag(z) = 0 and real(z) notin -1:1.

- This bug also affected the following operators and functions with complex arguments since they internally call `arcsin`:

  - arccos(z), if imag(z) = 0 and real(z) notin -1:1.

  - arcsinh(z), if real(z) = 0 and imag(z) notin -1:1.

  - arcsec(z) and arccsc(z), if imag(z) = 0 and real(z) in -1:1 (open interval).

  There were no such bugs if numeric, non-complex arguments have been given.

- All the bugs mentioned above have been fully fixed in the Solaris, Windows, Linux and Max OS X versions. The fixes in OS/2 and DOS, however, are preliminary since they do not completely solve the problem.

- The test cases have been extended and a glitch in a complex arithmetic validation procedure has been removed.

- Sometimes `os.cpuload` issued an error when it could not read out performance values. This has been changed: the function now just returns `fail`.


2.17.4, March 09, 2020

- In OS/2 and Windows, the new function `os.mousestate` returns information on the position of the attached mouse and on button clicks plus some operating system-dependent data.

- In OS/2, `os.mouse` also returns the number of mickeys, whether mouse data is in mickeys, the threshold, and row and column scaling factors.

- In OS/2 the new functions `os.getextlibpath` and `os.setextlibpath` query and set the paths to be searched before and after system LIBPATH, when tyring to locate DLLs.

- In OS/2, the new function `os.mouseflush` flushes the mouse queue.

- `bytes.peek` has been removed as it was more or less a duplicate of `bytes.tobytes`. On Big Endian systems, `bytes.tobytes` can now alternatively suppress automatic conversion to Little Endian representation by passing the new third option `false`.

- `bytes.tobytes` no longer is dependent on the setting of `environ.kernel/signedbits`: if you pass +4 as the seond argument, independent of the setting, the bytes of an unsigned 4-byte integer are returned. If you pass -4 as the seond argument, the first argument is assumed to be a signed 4-byte integer.

- In the real domain, `besselj`, `bessely` and `lngamma` have become 15 percent faster each, thus also speeding up `beta`, `math.lnfact` and `math.pochhammer`.

- In the real domain, `gamma` has become 35 percent faster, thus also benefiting `stats.studentst`, `stats.chisquare`.

- `bytes.tobinary` has been tuned by 20 percent.

- In OS/2 and Windows, `os.beep` autocorrects invalid frequencies that are not in the range 37 .. 32767 Hz as the underlying C API operating system functions would not work otherwise.

- `binomial` returned `undefined` instead of 0 if the difference of its arguments was a negative integer. This has been fixed. The function has also become ten percent faster with fractional arguments, and its C code now is fully portable.

- Added C API macro `lua_rawsetiboolean` to set a Boolean into a table at a given position.


2.17.3, March 01, 2020

- This edition primarily implements improvements to the OS/2, DOS and Windows versions of Agena. Thus, there are no non-`DOS-based` installers for download available.

- The formerly undocumented function `os.codepage` gets and sets the input and output codepage in OS/2, DOS and Windows.

- `os.curdir`, which returns the current working directory, has been re-introduced.

- `os.beep` no longer accepts negative frequencies and duration. In DOS, the tone can now be modulated with a given frequency and duration. Furthermore, in OS/2, DOS and Windows, the function also autocorrects invalid frequencies into the range 0 .. 32767 without issueing errors.

- In OS/2, DOS, Windows and Linux, `os.vga` now returns the number of rows and columns of the active console. In OS/2, the number of colours and pixel depth is also determined.

- `os.mousebuttons` has been deprecated and its functionality has been migrated to `os.mouse`. In OS/2 and DOS, `os.mouse` now returns the number of mouse buttons. An alias has been provided to ensure backward compatibility.

- `strings.tobytes` did not correctly treat the non-word aligned rest of a string. This has been fixed.

- The new function `bytes.peek` returns all bytes of a number and works for unsigned and signed 4-byte integers and 8-byte C doubles.

- Removed the undocumented keywords `mne`, `mneop`, `peek`, `poke`, `up`, and its associated functionality.

- Removed commented C code from the source files.


2.17.2, February 25, 2020

- This edition primarily implements improvements to the OS/2, DOS and Windows versions of Agena. Thus, there are no non-`DOS-based` installers this time.

- `os.drives` (available drive letters) and `os.drivestat` (info on file systems) now return drive information in both the OS/2 and DOS version of Agena.

- Agena for DOS now supports `os.realpath`.

- In DOS, `io.sync`, `binio.sync` and `ads.sync` now flush the write-behind disk caches, as well.

- In DOS and Windows, `os.curdrive` has been rewritten and is 45 percent faster now. It now also returns the drive letter with an appending colon in OS/2, DOS and Windows.

- `os.drives` now appends a colon to each drive letter.

- `os.getmodulefilename` now also works in Windows NT 4.0 and Windows 2000.

- Initialisation of Agena in Windows NT 4.0 and 2000 has been improved.

- In Windows, `os.drivestat` now also returns the DOS device name, such as '\Device\HarddiskVolume3`.

- When being passed a 4-byte integer, `bytes.tobytes` now checks whether it is in signed or unsigned mode so that there are no accidental overflows. The description of the function in the Primer and Reference has been corrected, as well.

- `strings.tobytes` now alternatively splits a string into 4-byte unsigned integers instead of single bytes.


February 17, 2020

- Launched first version of agenaPad - a tool to run Agena script files in Windows NT 4.0 or later without invoking the interpreter via a batch file. See `binaries` folder for the download and read its README file.


2.17.1, February 15, 2020

- The new function `math.xlnplusone` computes x - ln(1 + x) in a way that is accurate even if x is near zero.

- The new factory `os.iterate` creates a function that when called traverses a directory and optionally also returns the `file system` type (file, directory, link, etc.).

- The new function `hashes.interweave` splits a number into its higher and lower unsigned 4-byte words and applies one of the following binary operations: `or`, `and` or `xor`. Optionally, it also condcts mask, bit-shift and modulus operations.

- The integer division operator `\` with non-complex numbers, and the `iqr` function have become six percent faster.

- With non-complex numbers, the `sign` and `signum` operators have become at least four percent faster.

- Removed glitches from both `os.list` and underlying `os.listcore` when passing an optional single `*` wildcard search pattern. Furthermore, on some operating systems unnecessary additional queries of file attributes are avoided, speeding up both functions.

- `utils.unhexlify` did not work. This has been fixed.

- `bytes.numwords` returned a wrong unbiased exponent with argument 0. This has been fixed.

- Hardened `strings.format`, `os.islocale` and `os.fcopy` against unexpected internal memory allocation errors.

- For at least the last six months, the portable version of Agena for Windows unfortunately included an `agena.ini` initialisation file that might have overwritten the user-created one. The file has now been removed from the ZIP distribution.


2.17.0a Update 1 (DOS only), February 03, 2020

- The DOS version has become twice as fast by compiling it with the latest DJGPP edition available (GCC 9.2.0, et al.).

- `os.isdos` returned excessive results. This has been fixed.

- `os.getenv` could crash if the given environment variable was unset. This bug occurred when Agena has been compiled with more recent editions of DJGPP only. This has been fixed.

- The sources have been adapted to compile with the latest DJGPP editions (GNU C for DOS).


2.17.0, February 02, 2020

- The new binary `notin` operator checks whether an element is not part of a table, pair, set, sequence or register. With strings, it checks whether a substring is not part of a string. Thus, `notin` is the negation of the `in` operator, i.e.: not(x in y) = x notin y. It is ten percent faster than the `not`/`in` combination.

- The DOS version now includes the readline command-line feature, making the prompt much more convenient.

- In the DOS version of Agena, `os.system` now returns a meaningful name instead of '??Unknow' with various DOS flavours different from MS-DOS.

- The `xml` package is now available in the DOS version.

- The new function `os.isdos` can detect various flavours of DOS and optionally also returns various internal version numbers.

- The new function `os.iswindows` checks whether the Windows edition of Agena is being run.

- In Windows, `os.fstat` now returns the compressed size of a file (new key 'compressed'), and the 8.3 DOS name of a file (new key 'dosname').

- `os.isUNIX` has been renamed to `os.isunix`. An alias has been provided to ensure backward compatibility.

- `os.isANSI` has been renamed to `os.isansi`. An alias has been provided to ensure backward compatibility.

- Improved runtime behaviour of the test suite.


January 28, 2020

- Adapted test suite to run successfully in FreeDOS 1.2, see Sources download folder for file `agena-2.16.13a-testsuite.7z`.


2.16.13, January 26, 2020

- Added the new function `math.issquare` which checks whether an integer is a perfect square.

- Added the new function `math.iscube` which checks whether an integer is a perfect cube.

- The new function `math.isfib` checks whether an integer is a Fibonacci number.

- The new function `math.lnabs` returns ln(abs(x)) for numeric or complex x. With complex numbers, takes care of underflows.

- The new `invsqrt` operator computes the inverse square root of a (complex) number.

- The new `squareadd` operator computes complex z^2 + c = fma(z, z, c), preventing round-off errors. It is as fast as the Agena expression z**2 + c.

- Fine-tuned internal string buffering functions used by the `replace` and `join` operators.

- Fine-tuned `sin`, `cos`, `sinc`, `tan`, `log2`, `dual` package `sin` and `cos` metamethods, `root`, `proot`, `cbrt`, `cosc`, `cerf`, `gamma`,  `tanc`, `cas`, `strings.shannon`, `stats.sorted`, `stats.smm`, `stats.gsmm`, `stats.prange`, `stats.iqmean`, `stats.trimean`, `stats.quartiles`, `stats.fivenum` and `stats.winsor`.

- Added additional application information to the Windows installer.


2.16.12, January 06, 2020

- The new function `math.uexponent` returns the unbiased exponent of number x, i.e. returns math.exponent(x) - 1, except for x = 0, where the result is -1023.

- `math.fibinv` has been ported to C and has become twice as fast.

- `bytes.getunbiased` has now been patched in C. The slower 2.16.11 Update 2 patch written in Agena has been removed.

- Various functions of the `bytes` package no longer check whether their arguments are in range and thus do not issue any errors any longer. Thus, the strict changes introduced with the previous release have been completely rolled back.

- Use the new `bytes.isint32` function to check whether an integer is in the 4-byte integer range. It returns `true` or `false`.

- Since Agena 2.16.5, `strings.find`, `strings.match`, `strings.isabbrev`, `strings.isending`, `strings.hits`, `strings.chomp`, `strings.gseparate` and `strings.advance` did not work efficiently with haystack strings of size 3 or less in case pattern matching was not necessary. The results, however, were correct. Also, on rare systems that do not store strings aligned along the 4 or 8 byte word boundary, the functions may have never returned or even crashed. Both issues have now been fixed.

- The `replace` operator has become ten percent faster.

- Many string search functions and operators have been tuned a little bit.

- The previously undocumented C API function `agn_stralloc` efficiently creates a string buffer of optimal size, aligned along the "long" boundary, and also automatically includes terminating zeros.

- Removed undocumented Agena test functions written in C.


2.16.11 Update 2, December 28, 2019

- Fixed a bug in `bytes.getunbiased` with a number x and |x| < 1.

- You will find the update in the Binaries/Agena 2.16.11 Sourceforge folder, file `agena-2.16.11-update2.zip`. Download it and check the instructions in the libupdate.read.me file on how to install this library update.


2.16.11, December 28, 2019

- Various functions of the `bytes` package now check whether their arguments are in range and issue an error otherwise.

- Renamed `bytes.gethighofdouble` to `bytes.numhigh`, `bytes.getlowofdouble` to `bytes.numlow`, and `bytes.getwordsofdouble` to `bytes.numwords`; also renamed `bytes.sethighofdouble` to `bytes.setnumhigh`, `bytes.setlowofdouble` to `bytes.setnumlow`, and `bytes.setwordsofdouble` to `bytes.setnumwords`. Aliases have been provided to ensure backward compatibility.

- `bytes.numwords` now also returns the unbiased exponent of its numeric argument as a third result.

- The new function `bytes.getunbiased` returns the unbiased exponent from a doublecast userdata a, equals math.exponent(bytes.getdouble(a)) - 1, except for bytes.getdouble(a) = 0, where it returns -1023.

- `os.remove` & `os.rmdir`: If you pass the new second argument `true`, then the function no longer issues an error if the file or directory to be deleted does not exist. Instead, the function returns `fail`.

- `os.move`: If you pass the new third argument `true`, then the function no longer issues an error if the file to be renamed does not exist or if the destination already exists. Instead, the function just returns `fail`. Also, by default and on all platforms (and if `true` is not given), the function now issues an error if the target destination already exists.

- Streamlined error messages of `os.move`, os.fcopy`, `os.remove` and `os.rmdir`.

- In OS/2, `os.getenv` and `os.gettemppath` now query the generic `DosScanEnv` C API function instead of the one provided by GCC.

- In UNIX, `os.getenv` should have never worked or may have even caused segmentation faults. This has been fixed.

- In Windows, `os.gettemppath` now returns the path with slashes instead of backslashes.

- In the Windows edition, a potential memory leak during initialisation has been removed.

- The new C API functions agn_checkuint16_t and agn_checkuint32_t check whether their arguments fit into the range of the C uint16_t and uint32_t data types, respectively.


2.16.10, November 30, 2019

- The new function `os.gettemppath` retrieves the path of the directory designated for temporary files.

- The new function `io.maxopenfiles` returns the maximum number of open files allowed on your system, or sets (Windows only) the maximum number of files that are allowed to be opened simultaneously.

- In Windows, the new function `net.isconnected` checks whether the system is currently connected to the Internet.

- In Windows, the new function `os.winver` is an alternative to `os.system` and returns the Windows major release, and alternatively the service pack major and minor version, whether the operating system is a workstation or server, and the build number, as well.

- `os.fcopy` now accepts a third optional argument, a Boolean, which indicates whether to simply overwrite existing files or issue an error. The default is `false`: issue an error.

- If a second argument is passed to `os.execute`, then the function executes an operating system command and returns its output as one string. (See also `io.pcall`.)

- Improved error messages of `io.lines`.

- `os.mkstemp` has been renamed to `io.mkstemp`. An alias has been provided to ensure backward compatibility.

- Corrected description of `io.mkstemp` in the Primer & Reference. Also updated Appendix A1 Operators.

- The new C API function `agnL_readlines` reads in a file or pipe and pushes its entire contents or output as a string onto the top of the stack.

- The new C API function `agnL_pexecute` executes an operating system command and puts the output - a string - onto the top of the stack.


2.16.9, November 12, 2019

- Some `->` assignment statements involving the `storage` token resulted in syntax errors. This has been fixed.

- The new C API function `agnL_optuint32_t` checks for an optional non-negative number and returns it if given, or a default, in both cases cast to uint32_t.


2.16.8, November 03, 2019

- The new `hashes.adler32` function computes the Adler32 string hash.

- Various `hashes` string hash functions now accept unsigned 4-byte integer arguments greater than 2^31: `djb`, `djb2`, `fnv`, `jen`, `oaat`, `pl`, `raw`, `sax`, `sdbm`, `sth`, `lua`, `murmur2`, `murmur3`, `murmur3128`, `varlen`, `djb2rot`, `asu`, `elf`, `ap`, `dek`, `bkdr`, `sysv`, `rs`, `bp`, `pjw`, `hashmap`.

- With integer arguments > 2^31, `bytes.cast` returned wrong results, the same with the following `bytes` library functions: `setwordsofdouble`, `sethighofdouble`, `setlowofdouble`, `onebits`, `leadzeros`, `trailzeros`, `mostsigbit`, `leastsigbit`, `reverse`, `setwords`, `sethigh`, `setlow`, `arshift32` and `nextbit`. This has all been fixed.

- Corrected error messages of `bytes.mod32` and `bytes.divmod32`.


2.16.7, October 31, 2019

- A table can now be assigned to a procedure with the new `storage` feature. This internal table will remain active during a whole session and you can read or write values to it in subsequent calls to the function. This new feature is at least thrice as fast as exchanging data with the registry but only half as fast as closures. See Chapter 6.25 and this example:

  > f := proc() is
  >   feature storage
  >   storage[1] := Pi
  >   storage.entry := E
  >   return storage, storage[1], storage.entry
  > end;

  > f():
  [1 ~ 3.1415926535898, entry ~ 2.718281828459]   3.1415926535898   2.718281828459

- Changed `watch` to work with an internal storage table instead of the registry.

- It was not possible to insert values into the internal status table of `numarrays`. This has been fixed.

- The way the `registry` package internally stored values caused invalid memory reads at garbage collection, but assertively caused no memory leaks. This issue, however, has been fixed. Just use unique strings, not lightuserdata objects, as the first argument to `registry.anchor` and `registry.get`. Thus, `registry.anyid`, which previously created lightuserdata objects, has become obsolete and now just returns the string given, for backward compatibility, so that code changes are unnecessary. Also corrected error message of `registry.anchor`.


2.16.6, October 26, 2019

- In Linux and Windows, `os.system` now also checks whether the underlying platform runs in 32 or 64-bit mode.

- `numarray.write` has become 3.5 % faster when writing numbers (C doubles).

- `math.ispow2` has been tuned by 5 %.

- The new function `watch` implements a simple stop watch.

- `registry.anchor` has been completely rewritten: You can now directly update a value without having to delete it before. Also, if a non-existent value shall be deleted, the function does not issue an error any longer.
  In summary, inserting new values into the registry has now become twice as fast and updating values thrice as fast. Unnecessary internal administrative overhead and memory consumption has been removed, as well.

  An example of how to use the registry to store data in an Agena session has been added to Chapter 6.31.

- The `mp` library did not work in Solaris. This has been fixed.

- Fixed `numarray.write` on Big Endian systems.

- Improved error messages of `setmetatable`.

- The new `agn_isinteger` C API function checks whether an integer is stored at a given stack position.


2.16.5, October 13, 2019

- `strings.random`, `hashes.varlen`, `os.fcopy` now behave correctly if internal memory allocation should fail, i.e. they issue an error now.

- `strings.rotateleft`, `strings.rotateright`, `utils.hexlify` and `utils.unhexlify` have become around 3 percent faster.

- `strings.find`, `strings.match`, `strings.isabbrev`, `strings.isending`, `strings.hits`, `strings.chomp`, `strings.gseparate` and  `strings.advance` have been tuned a little bit.

- Fixed internal overflow in the Mac OS X version of `os.time`.

- The new C API function `agn_stralloc` allocates a string buffer of the most efficient size, aligned along the "long" boundary of your system.


2.16.4, October 06, 2019

- The new function `bytes.muladd32` multiplies two numbers and adds further numbers, using 4-byte unsigned integer arithmetic.

- The new function `bytes.divmod32` returns the quotient and remainder of a 4-byte division.

- The new function `bytes.nextbit` gets and clears the next bit from an unsigned 4-byte mask, starting with the most significant bit.

- The new function `hashes.crc8` performs an 8-bit reversed cyclic redundancy check for a string.

- The C API function `agn_calloc` has been extended to optionally free values at failure.

- The `binio` package has been fixed to correctly read and write numbers on Big Endian platforms.

- The GMP dynamic link library is now included in the Windows installer.


2.16.3, October 01, 2019

- The new `mp` package is a binding to the GNU Multiple Precision Arithmetic Library (GMP), providing multiple functions to conduct signed and unsigned integer arithmetic of arbitrary precision. There are also some functions in lib/mp.agn which demonstrate RSA encryption with private and public keys. The package is not available in the Mac OS X edition.

- The new function `utils.hexlify` converts a string to its hexadecimal representation where each character is replaced by a two-digit hexadecimal value.

- The new function `utils.unhexlify` conducts the opposite operation of `utils.hexlify`.

- The new functions `strings.rotateleft` and `strings.rotateright` conduct bitwise rotation on strings, with optional xoring.

- `binio.writenumber` and `binio.readnumber` have become ten percent faster.

- `hashes.mix64` and `hashes.mix64to32` should now return correct results.

- The new C API function `agn_calloc` allocates memory using C's calloc function and includes error handling.


2.16.2, September 21, 2019

- `strings.isutf8` returned wrong results in the second return and confusing results in its first return. Thus, the algorithm used to check for UTF-8 strings has become much stricter and now returns only one value. If you still want to use the old algorithm, use the new function `strings.multibyte`.

- Added a new parameter to `strings.separate` which causes the function to return a sequence instead of `fail` in certain situations, so that it can be more comfortably used in for/in loops.

- In the Windows version, `os.lsd` and `os.esd` could no longer compute dates earlier than January 01, 1970. This has been fixed.

- In Windows, `os.date`, `os.now`, `os.tzdiff`, `os.settime`, and `os.isdst` crashed when passing a date earlier than 1970/1/2. This has been fixed.

- Argument check in `os.date` has been improved.

- Agena crashed when passing a sequence or register of more than six values to `os.time`. This has been fixed.

- The OS/2 WarpIN installer has been improved a little bit (at least I hope so).


2.16.1, September 02, 2019

- The new `negate` statement flips a Boolean from `true` to `false`, and `false` or `fail` to true. With a number, it converts its argument to 1 if it is 0, and a non-zero number to 0.

- The new function `strings.isgraph` checks whether a string consists of glyphs only. It is a direct port to the C function `isgraph`.

- The new function `strings.isascii` checks whether a string consists entirely of unsiged char 7-bit characters that fit into the UK/US character set. It is a direct port to the C function `isascii`.

- String indexing and the `for/in` loop on strings now work with embedded '\0' characters, i.e. embedded zeros are being processed and do not cause out-of-range errors or loop termination any longer.

  The prettyprinter now completely writes strings with embedded zeros at the console.

  Please note that most other string processing functions and operators cannot detect embedded zeros and still finish when they are encountered.

- The new function `strings.strlen` determines the lengths of a string by calling both the underlying C function strlen and Agena's `size` operator. By comparing the results, you can check whether embedded zeros are included in the string or not.

- `strings.iscontrol` now returns `true` if the empty string ('\0' = ASCII code 0) has been passed.

- Strings generated by `strings.random` with the 'ascii' option no longer by default contain the DEL key character (= ASCII code 127).

- The new function `os.getmodulefilename` returns the absolute path to the currently executing programme.

- If any argument is now passed to `io.getkey`, the function just waits until a key is pressed, but does not return anything.

- Windows only: The new function `io.keystroke` emulates a keystroke, i.e. sends a character to stdin.

- OS/2 only: The new function `io.kbdgetstatus` returns status information about the keyboard. It is a port to the C API function KbdGetStatus.

- OS/2 only: The new function `os.os2info` returns various environment settings; it is a port to the C API function DosQuerySysInfo.

- Syntax parsing of the `inc`, `dec` and related assignment statements has become much stricter: If you use an (optional) opening bracket to enclose an argument, then you must now also type in a closing bracket.

- The C API function `agnL_checkoption` can now check options case-insensitively by passing a flag as the last argument.


2.16.0, August 03, 2019

- The new operator `zero` checks whether a number or complex number is zero, and the new operator `nonzero` does the opposite. Both are around 8 percent faster than using the binary `=` or `<>` operators. The two new operators support metamethods.

- Because `zero` is now a keyword, the function `calc.zero` had to be renamed to `calc.zeros`, and `linalg.zero` to `linalg.zerovector`.

- The new function `math.floorpow2` is the opposite to `math.ceilpow2` and rounds down to the previous highest power of 2.

- `math.ispow2` now can detect powers of two if its argument is greater than 2^31. The function returns `fail` if its argument is greater than 2^53 or if it is negative.

- `math.ceilpow2` now returns `fail` instead of just overflowing if its agument is greater or equal 2^31.

- `math.isirregular` could not correctly detect non-representable integers in the vicinity of the 2^53 threshold. This has been fixed.


2.15.5a, July 29, 2019

- PowerPC edition: `numarray.writeindex` could not correctly write short strings. This probably also affected other platforms for which there are no binary Agena releases. The bug has been fixed.


2.15.5, July 24, 2019

- The new function `numarray.cycle` cycles through arrays.

- The new function `implies` implements the Boolean operation implies(a, b) = not(a) or b. The function also combines integers, where implies(a, b) = (~~a) || b.

- `factory.cycle` did not work with with registers, sequences and strings if no sentinel has been given. This has been fixed.

- `numarray.include` rejected index position 1. This has been fixed.

- The order of arguments of `numarray.whereis` has been changed to the one given in the Primer and Reference.

- `numarray.write`, `numarray.read`, `numarray.readintegers`, `numarray.readdoubles` and `numarray.readuchars` did not work. This has been fixed.

- Changed the way how `binio` file handles are written by the prettyprinter: instead of printing just a deceiving integer, the string 'BINIOFILE*' concatenated with an integer is written, as `binio` file handles are userdata and not integers.

- Many mathematical functions now internally use predictive branching if deemed reasonable.


2.15.4, July 07, 2019

- Updated the documentation: Primer and Reference, Crash Course, and Quick Reference.


2.15.4, July 06, 2019

- The new functions `llist.toseq` & `ulist.toseq` convert an llist and a ulist to a sequence.

- The new functions `llist.dump` & `ulist.dump` move one element after the other from a list to a sequence, leaving the list empty thereafter and ready for garbage collection. May be used in case of insufficient memory.

- The new function `llist.checkllist` checks whether its argument is a linked list.

- The factories produced by `ulist.iterate` have become 75 % faster.

- The '__size' metamethod for llists has become 40 % faster.

- `llist.iterate` can now also process ulists.

- In `llist.purge`, the index is now optional. If not given, the last (top) node will be deleted. The function now also returns the value purged.

- Created metamethods for the `empty` and `filled` operators (new metamethods '__empty' and '__filled', respectively) that work with userdata only. These two operators now support llists, ulists, and numarrays.

- `llist.totable` did not work. This has been fixed. The function has also become seven times faster by porting it to C.

- Added three new hash functions: `hashes.pjw` computes the P. J. Weinberger Hash, `hashes.rs` another string hash, and `hashes.bp` may be useful to classify words with the same endings.

- The new function `stack.attribd` returns various status information on the internal stacks.

- `stack.shrinkd` did not reset a stack to its default size when empty. This has been fixed.

- The `__imag` metamethod did not work. This has been fixed.

- Documented the `dual` package which processes dual numbers.


2.15.3, June 25, 2019

- `ulist.totable` has become at least thrice as fast, by porting it to C.

- `ulist.isequal` and thus also the `=` equality operator have been ported to C for better performance, it is 10 times faster now.

- `ulist.getitem` can now return more than one value by passing a third argument. This is around 90 % faster as individually reading the items.

- `ulist.purge` now returns the element deleted.

- The new function `ulist.sort` sorts ulists and has the same functionality as `sort`.

- The new function `ulist.swap` exchanges the positions of two elements.

- `ulist.put` ignored the filling factor. This has been fixed.


2.15.2 Library Update 1, June 17, 2019

- `ulist.totable` did not work. This has been fixed.

- `ulist.isequal` and thus also the `=` equality operator did not work. This has been fixed.

- You can now pass an additional optional argument to `ulist.list` that controls how many items (in percent) are inserted into each underlying sequence before a new sequence is internally created.

- You will find the update in the Binaries/Agena 2.15.2 Sourceforge folder, file `agena-2.15.2-update1.zip`. Download it and check the instructions in the libupdate.read.me file on how to install this library update.


2.15.2, June 15, 2019

- New release policy: While the OS/2, DOS, Debian Linux, Mac OS X and Windows versions of Agena will be further developed, the Raspberry Pi, Red Hat Linux, Linux PowerPC and Solaris editions due to lack of interest will no longer be permanently maintained.

- `numarray.getitem` can now also return succeeding values from a numeric array. It is at least twice as fast as individually reading the items.

- `llist.getitem` can now also return succeeding values from a singly-linked list. It is at least twice as fast as individually reading the items.

- ulists now have their own metatables, so you may index ulists as usual, using the squared bracket notation. The `size`, `=`, and `in` operators and the standard prettyprinter are now also supported. To gain read and write access to the sequences of the underlying singly-linked list, use the new function `ulist.getllist`.

- `ulist.getitem` has become eleven percent faster, and `ulist.setitem` six percent faster, by porting them to C.

- Tuned `ulist.iterate`.

- The new function `utils.posrelat` converts negative integer indices to their positive equivalents.

- `numarray.include` did not accept negative indices. This has been fixed.

- `ulist.put` did not work with empty ulists and index 1 and other odd situations. All this has been fixed.


2.15.1, June 02, 2019

- Added unrolled singly-linked lists to the `llist` package. They are usually at least ten times faster than singly-linked lists. See the descriptions of functions `ulist.list`, `ulist.append`, `ulist.prepend`, `ulist.put`, `ulist.purge`, etc. in the manual.

- The new function `llist.getitem` and `llist.setitem` expose the internal index read and index write procedures to the environment so that self-written metamethods do not run out-of-stack.

- You can now pass negative indices to `llist.purge`, `llist.put`, `llist.getitem`, `llist.setitem`, to access elements from the end of a linked list.

- Linked list can now store status information or other data in a special table that is available at pseudo-index 0. You can use the index metamethod or `llist.getitem` to read from or write data to this table. Examples:

  > print(a[0]);                 # print contents of status table

  > print(llist.getitem(a, 0));  # dito

  > a[0].cursor := 16;           # assign value 16 to status table key `cursor'

  > a[0, 'cursor'] := 16;        # dito

- `llist.listtotable` has been renamed to `llist.totable`. An alias has been provided to ensure backward compatibility.

- Numarrays can now store status information or other data in a special table that is available at pseudo-index 0. You can use the index metamethod or `numarray.getitem` to read from or write data to this table.

- You can now pass negative indices to various `numarray` package functions to access elements from the end of an array.

- `numarray.get` has been renamed to `numarray.getitem`. `numarray.put` has been renamed to `numarray.setitem`. Aliases have been provided to ensure backward compatibility.

- The new function `numarray.getsize` exposes the internal procedure to determine the size of an array to the environment.

- The new function `strings.xmlmatch` works like `strings.match`, but matches the contents enclosed by XML tags.

- The `++` and `--` suffix operators did not return correct results if used at least in function calls, e.g. `f(c++)' did not work as expected. This has been fixed.

- If called with no arguments, `math.randomseed` sometimes returned invalid seeds that could not be passed again to this function in order to reset the seeds. This has been fixed.

- Improved garbage collection of packages `numarray`, `bloom` and `bytes`.

- Changed the sources to prevent compiler warnings on some platforms.

- As always, this release has been Valgrind-checked on x86 Linux and Mac OS X to ensure there are no memory leaks.


2.15.0, May 13, 2019

- The new `\:=` compound assignment operator conducts integer division, i.e.: a \:= b <=> a := a \ b.

- All bit-twiddling operators `&&`, `||`, `<<<`, etc. now work in the 32-bit domain again, since 64-bit integers cannot be correctly represented by Agena numbers, i.e. C doubles.

- Four new binary operators have been added to add, subtract, multiply and divide 32-bit signed or unsigned integers: `&+`, `&-`, `&*`, and `&/`.

- The new function `hashes.sysv` computes the System V hash.

- The `~|` approximation operator never worked. This has been fixed.

- The `calc.symdiff` alias has finally been removed. Use `calc.xpdiff` instead.


2.14.13, May 08, 2019

- The `ln` operator has become 2 % faster, and `math.arcsinh` 12 % faster.

- `math.dirac` now returns `undefined` if its argument is `undefined`.

- `hypot`, `hypot2` and `hypot3` now use a more accurate and portable algorithm, at the expense of a 1 % speed loss. This also affects both `ilog2` and `abs` when called with complex numbers.

- Streamlined the code, fixed faulty header includes, mathematical functions now always use the same underlying C math functions, usually from Sun Microsystems if they are at least as fast as those implemented in GCC; removed unused auxiliary C functions (agnxlib.c, however, was left untouched), etc.


2.14.12, May 01, 2019

- Both `arccsch` and `arcsech` have become at least 20 % faster. `arccosh` has become 5 % faster.

- `skycrane.getlocales` erroneously changed the locale to 'C', this has been fixed.

- Fixed `beta` which could return wrong results if the sum of its arguments exceeded 171.

- The underlying implementation of `io.readfile`, `io.readlines`, `io.nlines` and `io.skiplines` has been standardised, no functional changes.

- Changes and fixes to the `dual` package (see file lib/dual.agn for documentation):

  - The addition `+`  and subtraction `-` operators now accept mixed number and dual number operands.

  - The division operator `/` now accepts a number as the first operand.

  - The multiplication operator `/` now accepts a number as the second operand.

  - `dual.tanh` returned wrong results, this has been fixed.

  - The `abs` operator now returns the absolute value of the real part.

  - The exponent to `^` can now also be a dual number.

  - Division by zero was not properly handled by the `/` and `recip` operators. This has been fixed: now `undefined` is returned.

  - `undefined` as input is now properly treated by all package functions and operators: now they simply return `undefined`.

  - Fixed output of dual numbers for dual part -0.


2.14.11, April 28, 2019

- The new compound operator `&:=` concatenates the contents of a string variable with another string and writes back the result to this variable, i.e.: a &:= b <=> a := a & b.

- The new function `os.islocale` checks whether the given locale is supported by the operating system.

- `skycrane.getlocales` no longer changes the locale if interrupted.

- The `beta` function has become more than twice as fast with positive integer arguments.

- `os.iseCS` has been renamed to `os.isos2`. An alias for `os.iseCS` has been provided to ensure backward compatibility.

- The `gdi` could not be used in the x86 Debian Stretch edition. This has been fixed.


2.14.10a, April 25, 2019

- In the OS/2 and DOS editions, `lngamma` returned inaccurate results with arguments 1 and 2, thus also affecting the accuracy of the `beta` function. This has been fixed.

- Also in OS/2 and DOS, the exponentiation operator `^` did not work well with very small imaginary parts close to zero. This has been fixed, as well, thus also significantly improving the quality of the `besselj` and `bessely` functions.


2.14.10, April 22, 2019

- `prepend` now works in-place, making it much more efficient, as its counterparts `put` and the `insert` statement already are.

- `arccosh` has become thrice as fast in the real domain.

- The new functions `math.arcsinh` and `math.arctanh` compute the inverse hyperbolic sine and tangent in the real domain.

- The new function `bytes.trailzeros` counts the number of trailing zeros in an unsigned 32-bit integer.

- The new function `tables.borders` returns the lowest and highest assigned index in the array part of a table. With tables, `environ.attrib` also returns them, represented by the 'lowest' and 'highest' keys.

- `debug.getlocals` crashed with invalid levels. This has been fixed. It now also returns a table of unassigned local variables.

- `hashes.murmur3128` could crash, this has been fixed. It now returns 4 unsigned 32-bit integers, accepts an optional seed as the third argument and is now available in the OS/2 and Raspberry Pi editions, as well.

- The new C API function `agn_arrayborders` returns the lowest and highest index of the array part of a table.


2.14.9, April 14, 2019

- The new `++` and `--` suffix operators return the current value of a variable and then increase or decrease the variable by one:

  > c := 0;
  > a := c++;
  > print(a, c);  -> 0, 1

- To new functions: `bytes.tolittle` converts a number into its Little Endian, and `bytes.tobig` into its Big Endian representation.

- Some few non-functional changes to clear internal buffers in some functions before they issue errors.

- Documented the formerly undocumented function `bytes.bcd`.

- With numbers, `arcsinh` has become 2 % faster and `arccosh` 15 % faster. `stats.countentries` have become 2.5 % faster, `stats.extrema` 8 %, and `stats.peaks` 9 % faster.

- Tuned `bytes.tobytes`. On Big Endian systems, it has also been fixed.

- The new function `cordic.cmul` multiplies two numbers.

- The new C API function `luaL_clearbuffer` clears the luaL_Buffer but does not push anything onto the stack.


2.14.8, April 07, 2019

- `io.readlines` can now apply a user-defined function to the lines being read from a file. Instead of the original lines, the results of the function call are put into the resulting table.

- `skycrane.timestamp` does not necessarily expect hours, minutes and seconds any longer.

- The new function `bytes.numto32` converts a number to its 4-byte signed or unsigned integer representation.

- The new function `bytes.parity32` determines the parity of an unsigned 4-byte integer.

- The new function `math.nearmod` returns the closest value to a number divisible by a given modulus.

- The new function `math.congruentprime` determines whether a number is a prime number congruent to a given modulo expression. Can be used to suggest `optimal` sizes for hash tables.

- The new function `hashes.fibmod` may compute more evenly distributed hash values using Fibonacci hashing.

- Added new string hash functions `hashes.asu`, `hashes.bkdr`, `hashes.dek`, `hashes.elf` - see the Primer and Reference for their description.

- Documented the formerly undocumented hash functions:

  - `hashes.strval` which is useful to classify words with the same ending,

  - `hashes.sumupchars` computes the Internet Checksum and other sums,

  - `hashes.varlen` returns variable-length integer hashes, and - depending on the user-given salt - can produce non-colliding hashes.

- `prepend` can now better treat large sequences.

- Improved and/or fixed error messages of `optnumber`, `optpositive`, `optnonnegative`, `optint`, `optposint`, `optnonnegint`, `optboolean`, `optstring` and `environ.kernel`.


2.14.7, March 28, 2019

- Added `bytes.add32` and `bytes.mul32` which add, respectively multiply two or more numbers using 4-byte signed or unsigned arithmetic. Likewise, `bytes.sub32`, `bytes.div32` and `bytes.mod32` are 4-byte subtraction, division and modulus operations. They may be useful if you would like to programme hash functions which return the same results as if programmed in C.

- The new function `hashes.djb2rot` is a modification of `hashes.djb2` with additional bitwise rotations. It produces less collisions and is also faster than `hashes.djb2`.


2.14.6, March 17, 2019

- The alternative table and sequence constructors `// ... \\' and `(/ ... \)' now accept keywords without the need to put them into quotes.

  Examples:

  > s := // 1, 2, opera print sqrt ~ while \\;

  > t := (/ 1, 2, opera print while \);

- Added functions `fastmath.sinfast`, `fastmath.cosfast`, `fastmath.tanfast` which approximate sine, cosine and tangent and depending on the CPU can be up to 40 percent faster than the - accurate - `sin`, `cos` and `tan` operators.

- Added function `fastmath.invsqrt` which approximates the inverse square root and is around five percent faster than inversing the result of the `sqrt` operator.

- `fastmath.lbfast` has become 1,800 times more accurate at around the same speed.

- The new function `os.suffix` returns the last suffix in a filename.

- The new function `skycrane.replaceinfile` replaces all occurences of one or more strings in a text file in-place.

- The new function `bytes.mask32` returns an integer with a given number of bits set to 1.

- The `sema` package now supports multiple instances of semaphores; to create them, use the new function `sema.new` and call them with the existing procedures with the semaphore instance as the very first argument. Also, the package now consumes much less memory unless you close a semaphore id that was not the last one opened just one step before.

- `math.isprime` should be a little bit faster now.

- Fixed `os.mkstemp` which often returned errors. The function does not return an additional file handle any longer.

- The new C API function `luaL_isudata` checks for a userdata object and also validates its metatable if present.

- Some minor code improvements.


2.14.5, January 17, 2019

- The new function `bytes.shift32` shifts the bits in a 32-bit integer to the left or the right.

- The new function `bytes.rotate32` rotates the bits in a 32-bit integer to the left or the right.

- The new function `bytes.arshift32` performs arithemtic shift of the bits in a 32-bit integer.

- The new function `bytes.extract32` returns the number formed by a given bit field in a 32-bit integer.

- The new function `bytes.replace32` replaces the bits in a bit field of an 32-bit integer with a new one.

- The new functions `bytes.and32`, `bytes.or32` and `bytes.xor32` conduct bitwise-AND, -OR and -XOR operations on one or more 32-bit integers. `bytes.not32` conducts bitwise negation of a 32-bit integer.

- The new functions `bytes.nand32`, `bytes.nor32` and `bytes.xnor32` conduct complementary bitwise-AND, -OR and -XOR operations on one or more 32-bit signed integers.

- `bytes.castdouble` has been removed as it has been identical to `bytes.castint`.

- The 64-bit rotation operators `<<<<` and `>>>>` did not correctly move bits beyond the 32 bits threshold. This has been fixed.

- `bloom.new` issued confusing error messages with missing arguments. This has been changed.

- Added tips for Linux users to Chapter 2.2 of the Primer and Reference.

- This release has been Valgrind-3.12.0-checked on x86 Linux x86 Raspian Stretch to ensure there are no memory leaks.


2.14.4, January 05, 2019

- The absolute value of an algebraic expression can now also be determined by using the pipe notation, e.g.: | x |, | sin(-1)/2 |, 2 * | x + y |, etc. Note that this currently does not work with relations and other non-mathematical expressions.

- The new function `fastmath.hypotfast` is 60 percent faster than `hypot' - but less accurate - and calculates sqrt(square x + square y).

- The new function `stack.switchto` automatically changes to the stack with the least number of elements.

- `max` and `min` can now also compare two numbers.

- Added functions to convert numbers into binary representations and vica versa, from Lua 5.3: `bytes.pack`, `bytes.packsize`, `bytes.unpack`.

- Added the `utf8` package from Lua 5.3 with some helpers for UTF-8 encoding.

- Described the formerly undocumented function `stats.accu` which memory-efficiently computes the arithmetic mean and standard deviation.

- Conducted some code cleansing regarding integer type declarations and better compatibility with current Linux distributions.

- Debian/Linux users should try the x86 Stretch version and install it with "sudo dpkg -i --force-all agena-2.14.4-raspi.stretch.i386.deb".


2.14.3, December 27, 2018

- The new function `strings.random` creates a random Base64 or ASCII string.

- The new function `os.mkstemp` creates a unique temporary filename and file handle and opens the file in read-write mode.

- The new function `bytes.castint` casts numbers to C integers.

- The new function `calc.eulerdiff` computes the first derivative of a univariate or multivariate function with high precision and speed.

- `os.cpuinfo` now returns information on the supported instruction sets in the new 'support' field and further information on the CPU in the 'cputype' field. The 'cpuid' field contains various information on the underlying CPU hardware.

- `environ.kernel` can now individually return the following read-only settings: "lastcontint", "smallestnormal" and "clockspersec".

- With a (real) number x, `cabs` now returns the complex number abs(x) + I*0 if any option is given.

- When given borders, the random integers generated by `math.random` where of bad quality, i.e. of low frequency. This has been fixed.

- Removed keywords `peek` and `poke`.

- There were memory leaks when `math.epsilon` threw errors. This has been fixed.

- The new C API function agnL_fneps determines an epsilon value by taking a function value into account, using a divided difference table.


2.14.2, December 15, 2018

- The `if` statement is now also available in an operator form, for example:

  > a := 10;

  > sgn := if is a < 0 then  # determines sign of `a'
  >           print('I am negative');
  >           [further statements ...]
  >           return -1
  >        elif a = 0 then
  >           print('I am zero');
  >           return 0
  >        else
  >           return 1
  >        fi;

  > sgn:
  1

  You may omit the `elif` and `else` clauses. Each clause may contain zero, one ore more statements, but it must always be finished by a `return` expression which defines the resulting value (-1, 0 or 1 in the example above). In procedures, this special `return` expression does _not_ cause a procedure to quit. The operator returns exactly one value. Note that if the `else` clause is omitted, the operator returns `null` if no condition is met.

- Extended `math.epsilon` with new formulas, see the manual.

- The new function `getorset` returns an element stored in a structure, or stores a new value to the structure if the given indices do not yet exist.

- `strings.format` now accepts the %A modifier which is equal to the %H modifier.

- Metamethods __real, __imag, __cis, __square and __cube have been introduced for the `real`, `imag`, `cis`, `square` and `cube` operators. Added formerly undocumented metamethods to the manual.

- When the current stack is a character stack, and when given numbers, `pushd` now checks whether a digit 0 .. 9 has been passed and issues an error otherwise.

- The `sema` package obviously was not included in the binary distributions. This has been fixed.

- New C API functions: lua_setmetatabletoobject, lua_seqgetinumber (function instead of macro now), agn_reggetinumber (function instead of macro now).

- `ads.peek` has been renamed to `ads.peekin`.

- `append` has been renamed to `prepend`.

- The OS/2 edition now includes the formerly missing gcc473.dll file.

- In OS/2, `os.tmpname` may have always returned an error. This has been fixed.

- The distribution contains a new package called `dual` which provides means to play with dual numbers of the form a + b*e, where e <> 0 and e^2 = 0. Currently, the only documentation is the code itself, which you may find in the lib/dual.agn file of the Agena folder. You may use it to conduct automatic differentiation, with the first derivative to be computed with astonishing machine epsilon precision. (The documentation is the code itself, it has not been described in the Primer and Reference as it is not of general interest.)


2.14.1, October 20, 2018

-  Added Algol 68-style compound assignment; i.e., statements like "c +:= 2" which is equivalent to "c := c + 2" or "inc c, 2". The operators supported are +, -, *, /, and %. This is syntactic sugar to the `inc`, `dec`, `mul`, `div` and `mod` statements.

- The new function `append` adds a single element to the front of a structure. It works non-destructively.

- `sema.open` can now be passed a non-negative integer id. If the id has not yet been created, the function creates it. This allows you to write functions dumping the current semaphore state to a file and re-load it later, see `binio.writechar`, `binio.readchar`, `bytes.tobytes`.

- `skycrane.timestamp` now by default returns the time in Daylight Saving Time if active. You can switch this off (always returning Standard Time) by passing the new option `standardtime=true`.

- `calc.diff` and `calc.xpdiff` now accept the option `deriv = 0` which just returns the function value at the given point.

- The new `calc.softsign` function computes the Softsign function << x -> x/(1 + abs x) >>. It is 40 percent faster than an Agena implementation.

- `calc.smoothstep` has been extended to alternatively compute a polynomial which has zero 1st- and 2nd-order derivatives at x = 0 and x = 1. The argument list of the function has also been corrected.

- In UNIX based systems, the global and personal initialisation files may also have the filename `agena.ini`.

- `os.system` now correctly detects Windows 8.1 and 10.

- `columns` could not process registers. This has been changed.

- Improved references in the Primer and References, also corrected the Quick Reference.

- Some cleaning of error messages with respect to punctuation.

- To clear the namespace, the following macros providing backward compatibility to deprecated functions in 2.13 have been finally removed: `rot`, `math.clamp`, `math.symtrunc`. For all the functions removed, check the end of the lib/library file, where you will find fully functioning "emulators". You may add them to your personal agena.ini or .agenainit files.

- This release has been Valgrind-checked on x86 Linux to ensure there are no memory leaks.


2.14.0, September 29, 2018

- A short-cut `if`-like statement has been introduced using the ? token: if any condition is met, then it executes exactly one statement.

  Example:

  > x := 0;

  > x = 0 ? x := 1;

  > x:
  1

- The new `sema` package provides tools to memory-efficiently retrieve and administer unique non-negative integer IDs.

- The new function `utils.speed` measures the speed of functions.

- The new function `skycrane.timestamp` converts a timestamp to a Lotus Serial Date and other time components.

- The new function `linalg.iszero` checks whether a vector or matrix contains only zeros.

- The new function `linalg.isallones` checks whether a vector or matrix contains only ones.

- `factory.count` now accepts an optional stop value.

- The new function `satisfy` checks whether an atomic data or _all_ atomic elements of a structure satisfy a given condition.

- `recurse` and `descend` can now be passed functions checking for inequality without issueing errors. Also with tables, if the new option skiphash=true is being passed, all non-numeric keys and their associated values are ignored.

- Syntax incompatibility: The arguments of `descend` have been swapped to comply with the `recurse` standard.

- `descend` did not work correctly with registers. This has been fixed.

- In DOS, `os.setenv` can now also delete environment variables.

- `utils.writecsv` has been patched.

- `reduce`, `nseq`, `nreg`, `stats.sumdata`, `stats.issorted` could crash if passed too many arguments. This has been fixed.

- The `net` package now cleans up memory correctly when terminating the Agena session with CTRL+C.

- This release has been Valgrind-checked on x86 Linux and Mac OS X to ensure there are no memory leaks.


2.13.0a, September 12, 2018

- With Debian PowerPC and Raspberry Pi only, there could have been overflows with very large integers in quite a lot of situations, especially with function arguments. This has been fixed.

- This release has been Valgrind-checked on x86 Linux and Mac OS X to ensure there are no memory leaks.


2.13.0, September 11, 2018

- The new function `math.stirnum` computes the Stirling number of the first or the second kind.

- The new function `math.pochhammer` computes the Pochhammer function (rising factorial).

- The new operator `cube` raises a number or complex number to the power of 3.

- The new binary operator `roll` rotates a two-dimensional vector, represented by a complex number, through a given angle. The corresponding function `rot` with the same functionality has been deprecated. A macro has been provided to ensure backward compatibility.
  The operator is around ten percent faster than `rot` on Windows, and 27 percent on Solaris.

- `math.clip`, `math.clamp` and `math.symtrunc` are almost equal in functionality, so all the different flavours have been combined into an extended version of `math.clip` which now also allows to user-define the return value if its argument is not in the given range. Thus, `math.clamp` and `math.symtrunc` have been deprecated. Macros, however, provide backward compatibility.

- `math.fdima` has been integrated into `math.fdim`. A macro has been provided to ensure backward compatibility.

- The new `bytes` package provides the userdata data structure 'double' storing an Agena number as both a C double (i.e. Agena number) and its two higher and lower 32-bit unsigned integer representations, along with functions to query and assign its individual components.

- The following related `math` functions have been moved to the `bytes` package which can be activated through the `import` statement: , `fpbtoint`, `gethigh`, `gethighlow`, `getlow`, `inttofpb`, `leadzeros`, `leastsigbit`, `mostsigbit`, `reverse`, `onebits`, `sethigh`, `setlow`, `tobinary`, `tobytes`, `tonumber`.

- `math.sethighlowuint64` and `math.gethighlowuint64` have been removed since they could not always process each unsigned 64-bit integer correctly with Agena's doubles-based numeric system.

- The following related `math` functions have been moved to the new `fastmath` package which can be activated through the `import` statement:
  `invroot`, `lbfast`, `reciprocal`, `sincosfast`, `sqroot`, `sqrtfast`.

- In OS/2 and DOS, the `gamma` function now also processes complex numbers.

- `integral` and `float` have become five percent faster.

- `calc.weier`, `calc.polyfit` and `calc.polygen` have become more precise by internally using Kahan-Ozawa summation.

- `math.fibinv` has not been correctly registered. This has been fixed.

- The following functions deprecated one or more years ago have been finally removed:

  Removed function                          Substitute
  ----------------                          ----------
  debug.system                              environ.system
  dimension                                 tables.dimension
  irem                                      << x, y -> x symmod y >>
  os.curdir                                 os.chdir()
  rect                                      math.rectangular
  resetd                                    stack.resetd
  roundf                                    round
  shift                                     << x, y -> if y > 0 then x <<< y else x >>> y fi >>

- The undocumented baselib function `sunlog2` has been removed.

- This release has been Valgrind-checked on x86 Linux to ensure there are no memory leaks.


2.12.7, August 12, 2018

- `math.convertbase` has become around thrice as fast.

- Three new stacks storing single characters have been introduced, with stack numbers 4 to 6. Except of `stack.sorted`, all stack functions and stack operators can be used with them. The new stacks can speed up processing time when relying on a lot of string concatenations, see `math.convertbase` for an example.

- `stack.insertd`, `stack.pushvalued`, `stack.removed` can now be given a nonnegative stack index number, where 0 represents the bottom of the stack, 1 the position just above the bottom, etc.

- If a stack position does not exist, `cell` now returns `null` instead of `fail`.

- If a stack is empty, `popd` now returns `null` instead of an error.

- If a stack is empty, `allotted` returns `null` instead of `false`.

- If a stack is empty, `allotted` now returns `null` instead of `false`.

- If a stack is empty, `stack.dumpd` now returns `null` instead of an empty sequence.

- The new function `stack.pushstringd` pushes all characters of a string onto a character stack.

- The new function `stack.replaced` replaces a stack value with another value.

- The new function `stack.swapd` swaps two values in a stack.

- The new function `stack.explored` returns the contents of a stack without modifying it.

- The number of pre-allocated slots per stack has been reduced from 256 to 128.

- When given a stack number, `switchd` switched to the wrong stack which could cause segmentation faults. This has been fixed.

- When given a stack number, `allotted` did not return correct results and could cause segmentation faults. This has been fixed.

- When inserting `too many` numbers into a number stack, Agena could crash with stacks #2 and #3. This has been fixed.

- Corrected various error messages of the `stack` package.

- All stack functions and operators have been described in the Agena Quick Reference (agena.xls).

- Extended test cases for stacks.

- This release has been Valgrind-checked on x86 Linux to ensure there are no memory leaks.


2.12.6, August 07, 2018

- The new operator `square` squares a number or complex number. It is 13 percent and five percent faster, respectively, than the `**` operator.

- The new function `strings.a64` converts between 32-bit long integers and little-endian base-64 ASCII strings.

- The new function `hashes.sha512` computes the SHA512 hash.

- `hashes.pl` and `hashes.djb2` now accept a third argument, a factor.

- `fma` can now also process complex numbers.

- `math.fibinv` has been ported to C and has become twice as fast.

- Patched `time` in OS/2, Mac OS X, UNIX and Windows, which sometimes returned incorrect milliseconds and could cause negative time differences.

- `skycrane.tee` could not write files created by `io.open`. This has been fixed.

- The `factory` package has been missing in nearly all installers. This has been fixed.

- This release has been Valgrind-checked on x86 Linux to ensure there are no memory leaks.


2.12.5, July 29, 2018

- The new function `binsearch` performs a binary search in a structure and is much faster than the `in` operator when dealing with large structures.

- The new function `math.fibinv` returns the index of a Fibonacci number.

- `fib` has been ported to C and has become at least twice as fast.

- `bminus` and `bintersect` have become twice to thrice as fast.

- With complex arguments, `beta` erroneously sometimes returned `undefined` instead of a finite result. This has been fixed.

- `bisequal` did not check structures for Cantor equality but whether one is a subset of the other. This has been fixed.

- The new C API functions `agnL_optnonnegative` and `agnL_optpositive` check for nonnegative and positive numbers and optionally return a default.

- This release has been Valgrind-checked on x86 Linux to ensure there are no memory leaks.


2.12.4, July 24, 2018

- `os.pause` has been implemented in C and does not strain the CPU any longer while waiting (none-busy wait). It can now also wait for a fractional number of seconds.

- `os.wait` can now wait for a fractional number of seconds.

- `time` now returns the number of seconds including milliseconds elapsed since January 01, 1970, instead of processor time consumed by Agena. It has thus become platform-independent.

- The new function `os.clock` returns the processor time used by the current Agena session.

- `environ.kernel` returns the CLOCKS_PER_SECOND setting on your platform in the new 'clockspersec' field.

- `environ.system` returns the number of bits in a C char in the new 'Ctypes' field 'bitschar'. The following values can now be found in the 'Ctypes' table instead of the 'numberranges' table: 'bitsint', 'luaint32', 'luauint32', 'luaint64', 'luauint64'.

- `getbit` and `setbit` now can retrieve or set the 32th bit of a 32-bit integer.

- `getnbits` returns bits in a 32-bit integer. `setnbits` sets bits in a 32-bit integer.

- `getbit` and `getbits` do not internally convert a negative argument to a positive value any longer before returning the bits.

- In OS/2, with a complex argument, `arcsin`, `arccos` and `arcsec` erroneously sometimes returned `undefined` instead of a finite result if the imaginary part of the argument was zero. This has been fixed.

- The new C API functions `agn_checkpositive` and `agn_checknonnegative` check for positive and nonnegative numbers.

- This release has been Valgrind-checked on x86 Linux to ensure there are no memory leaks.


2.12.3, July 22, 2018

- The operators `nand`, `nor`, `xnor` and `xor` can now also compute bitwise complement and, or, exclusive-nor and exclusive-or.

- The new function `implies`(a, b) computes bitwise and Boolean ~a || b, not(a or b), respectively.

- The complement operator `~~` now only works in signed mode and returns a signed result, regardless of the environ.kernel/signedbits setting, as unsigned computation does not make sense.

- The new `factory` package provides some functional programming-style iterator factories:

  - `factory.iterate` creates a function that iterates each element in a structure and each character in a string one by one. If there is nothing left, the function returns `null` and if called again, re-starts iteration.

  - `factory.cycle` creates a function that iterates each element in a structure and each character in a string one by one. If there is nothing left, the function does not return `null` but simply re-starts iteration if called again.

  - `factory.reset` sets the current index of an iterator.

- `skycrane.counter` has been moved to the `factory` package and is available there by the name `factory.count`. Any floating-point mode is ignored - it is always Kahan-Ozawa if any of the arguments is a float. An alias for `skycrane.counter` has been provided to ensure backward compatibility.

- `environ.arity` now returns the number of upvalues in a function as the third result.

- `envion.attrib` returns the number of upvalues in a function in the new `nupvals' field.

- The new functions `environ.ref` and `environ.unref` create a unique integer ID for any object.

- The new function `environ.isequal` checks two objects for equality, returning `false` with structures that have the same elements but where where one structure does not refer to the other.

- `registry.anchor` can now also delete values from the registry.

- The new function `math.mostsigbit` returns the position of the most significant 1-bit, and `math.leastsigbit` the position of the least significant 1-bit.

- The new function `math.reverse` reverses all the bits in an 32-bit integer.

- The new function `math.ulp` computes the unit of least precision (ULP), the spacing between floating-point numbers.

- `math.gcd` and `math.lcm` have been ported to C and have become 85 and 165 percent faster, respectively.

- `reduce` with the `counter` option did not correctly clean up its environment. This has been fixed.

- `registry.anchor` unintendedly returned its second argument. Now it returns nothing.

- `math.powmod` caused segmentation faults with some integer arguments. This has been fixed.

- The new C API function `agn_equalref` is the foundation of `environ.isequal`.

- This release has been Valgrind-checked on x86 Linux and Mac OS X to ensure there are no memory leaks.


2.12.2, July 15, 2018

- The new function `os.pause` waits for an amount of time or any user input. It emulates the ZX Spectrum command PAUSE.

- Improved performance of `nseq` and `nreg` by ten percent when given integers.

- Looping over functions and factories now works as expected, you no longer have to use the `keys' token in `for/in` loops. Example:

  for w in strings.gmatch('I am a string', '%a+') do print(w) od

- With functions, `environ.attrib` now returns the number of arguments and a `varargs' flag in the new fields "arity" and "varargs".

- Patched `nreg`: with fractional arguments, the last element was not included in the register, now it is.

- The `in` operator always returned `false` when searching for `null` values that have been stored in a register. This has been corrected.

- Edited and extended Chapter 6.22 `Closures: Procedures that Remember their State` of the Primer and Reference to further discuss looping over procedures and factories.

- This release has been Valgrind-checked on x86 Linux and Mac OS X to ensure there are no memory leaks.


July 11, 2018

- Removed orphan empty page from the PDF version of the Primer and Reference.


2.12.1, July 10, 2018

- In the parameter list and also the optional return type list of functions, you can now also pass the following numeric "type" names:

  - `integer`     checks for a number that represents a signed integer,
  - `posint`      checks for a number that represents a positive integer,
  - `nonnegint`   checks for a number that represents a non-negative integer,
  - `positive`    checks for a positive number (float or integer),
  - `nonnegative` checks for a non-negative number (float or integer).

  Example:

  > proc(x :: integer, y :: nonnegint, eps :: positive) :: integer is ... end;

  Note that in Agena, there still is only one type to represent floats and integers: type `number'. The above mentioned new `types' are only supported in procedure definitions and by the `::` and `:-` operators.

- With procedures, the number of types that can be checked with any parameter and the resulting return has been increased from four to five, example:

  > proc(x :: {integer, table, set, sequence, register}, y :: number) :: {integer, table, set, sequence, register} is ... end;

- When combined with a `when` and `with` clause, the `return` statement can now also return values, where

  > return when <condition> with <result>;

  is syntactic sugar for

  > if <condition> then
  >     return <result>
  > fi;

- The new operator `integral` checks for an integer and is at least twice as fast as `isint`.

- `reduce` has been extended:

   a) You can now pass further arguments to the given accumulator function by just passing them as the fourth and following argument(s) to `reduce`. Example to compute the arithmetic mean of all the numbers in table [10, 20, 30]:

      tbl := [10, 20, 30];

      a := reduce(f, tbl, 0, size tbl);

      for:

      a, n := 0, size tbl;
      for x in tbl do
         inc a, x/n
      od;

   b) A counter has been added: it can be accessed within the accumulator function by the name `_c' when passing the new `_c = true` option - with `_c' starting from 1. The performance penalty, however, may be quite significant:

      tbl := seq(3, 3, 3);

      a := reduce(<< x, a -> a + x * 10^(_c - 1) >>, tbl, 0, _c=true);

      may be up to four time slower than

      a := 0;
      for _c from 1 to size tbl do
         inc a, tbl[_c] * 10^(_c - 1)
      od;

- `numarray.integer` has been renamed to `numarray.int32`, and `calc.integral` to `calc.integ`.

- The new function `debug.getlocals` returns all local variables of a procedure.

- `nseq` has been modified in that it accepts functions that may return `null`. In this case, an element is not added to the resulting structure. Example:

  nseq(<< x -> if x % 3 = 0 then x else null fi >>, 0, 10) -> seq(0, 3, 6, 9)

- `nseq` and `nreg` now internally use Kahan-Babuska summation for most precise results. Also, error correction with values close to 0 has been added.

- `next` now accepts a sentinel as the optional third argument. If `next` during traversal encounters an element that equals this sentinel, the function just returns `null`, and you may start iterating the structure again from its beginning.

- `math.accu` now accepts a start value for the accumulator (first argument). Also added value correction if the intermediate sum is very close to 0.

- C API function `agn_rawgetfield` has been renamed to `agn_rawgetifield`.

- The new C API functions `agn_rawgetfield` and `agn_rawsetfield` retrieve or set a value from/to a table.

- The `bloom` package was not included in the Linux, Mac and Solaris binary distributions. Now they are.

- `log2` sometimes returned wrong results in OpenSUSE due to round-off errors with integer arguments in its standard underlying C function of the same name. This has been fixed by using Sun Microsystems code. All other operating systems have not been affected.

- With the `local' declaration, the parser accepted invalid statments like `local a a := 1`. This has been fixed.

- `hashes.murmur3128` now always issues an error when run in OS/2 and Raspberry Pi. Before, it caused segmentation faults on these platforms.

- This release has been Valgrind-checked on x86 Linux to ensure there are no memory leaks.


June 20, 2018

- The `bloom` package was not included in the Solaris, Linux and Max OS X installers of Agena 2.12.0. Please download the archive `bloom4UNIX.Agena-2.12.0-addon.tar.gz` and follow the simple instruction in the bloom.read.me file included.


2.12.0, June 18, 2018

New syntax:

- Local variables can now be defined in short-cut functions using the `with` clause, e.g.:

  > fact := << (x :: number)
  >    with n := 1
  >    -> exp(lngamma(x + n)) >>;

- The `import` statement can now also assign an alias to a library name when given the new `as` clause, e.g.:

  > import hashes as h;

  > a := h.crc32('agena');  # which is equal to:

  > b := hashes.crc32('agena');

- The `global` statement now checks whether the given variables have not been declared local before its invocation.

- If there are no parameters in a short-cut procedure, then an empty bracket pair has to be explicitly given:

  then, now wrong:  << -> 1 >>
  now, right:       << () -> 1 >>


Improvements:

- `map` and `@` now support function composition. (See also new function `reduce` below.)

- `min` and `max` can now process sets and registers.

- `os.fcopy` can now copy files if only a target directory is given. The function now no longer overwrites existing files and issues an error instead. Warning messages have been improved. The function now issues errors instead of returning `fail` if a file could not be read or created, or if the source and target file are identical.

- `os.list` returns a second argument, an explanatory text, if a given directory or given file could not be found.

- `os.fstat` now returns the date of last access and last date of a file attribute change in the new 'lastaccess' and 'attribchange' fields.

- You can now read and set individual bits of an unsigned char array with the new functions `numarray.getbit and `numarray.setbit`. `numarray. iterate` can traverse bitfields one by one if you pass the fourth argument `true`, e.g.: "f := numarray.iterate(a, 1, 1, true)".

- `stats.hmean` has been ported to C, has become five times faster and now internally uses Kahan-Babuška summation to compensate for rounding errors.

- `strings.tolatin` now returns unsupported code points in its result.

- `strings.chop` now accepts a function as a second argument, checks each character in the string from the right to the left for the given Boolean condition and returns the string from its beginning up to the character that no longer satisfies the condition.

- `strings.advance`, `strings.remove` and `strings.chomp` now support pattern matching.

- `strings.between` and `strings.fields` can now convert its result as a number(s).

- `strings.between` has been extended: the prefix string can now reside within the string, not only at its beginning. Empty pre- or postfixes are no longer accepted. The function now returns `null` if there was no match (instead of its third argument, which was wrong).


New Functions:

- The new function `reduce` applies a function on each item of a structure or string and returns one accumulated result.

- The new `bloom` package implements Bloom filters. A Bloom filter is a memory-efficient mean to check whether a string probably is part of a dictionary or whether it is definitely not part of a dictionary, with acceptable query times.

- The new function `stats.accu` returns a factory that computes the running mean, variance, median, and absolute deviation by mere accumulation of individual obervations. It consumes much less memory than other `stats` functions but is slower.

- The new function `math.accu` returns a function that gets a number with each call, adds it to an internal accumulator using one of five selectable algorithms, and returns the accumulated sum.

- `math.lbfast` approximates log2(x). 10 % faster than `log2`.

- The new function `math.gethighlowuint64` returns the higher and lower bytes of the unsigned 64-bit integer.

- The new function `math.sethighlowuint64` combines two unsigned 32-bit integers to an unsigned 64-bit integer.

- `calc.weier` implements the Weierstraß function, a function that is continuous but non-differentiable everywhere.

- `strings.charset` returns a set of all the unique characters included in a string.

- `strings.shannon` computes various Shannon entropies for a given string.

- The new function `strings.splitfields` splits a string containing fields into its individual fields; the user may pass any delimiter separating the fields and also any wrapper that might enclose the various fields. Suited to parse database or other dumps.

- `gzip.deflate` compresses a string using the zlib library.

- `gzip.inflate` uncompresses a deflated string.

- `hashes.crc16` computes the CRC16 value of a string.

- `hashes.murmur2`, `hashes.murmur3` and `hashes.murmur3128` compute MurmurHashes. (`hashes.murmur3128` is not supported in OS/2.)

- `environ.arity` returns the number of parameters of a function and additionally a Boolean indicating whether its parameter list includes a `?` (varargs) token.


Documentation of formerly undescribed functions:

- `strings.gseparate` creates a factory splitting a string into its tokens one after the other.

- `math.leadzeros` counts the number of leading zero bits in a 32-bit integer,

- `math.onebits` counts the number of bits set in a 32-bit integer,

- `math.sincosfast` returns approximations of sine and cosine,

- `math.sqrtfast` returns an approximation of the square root.

- `hashes.reflect` reflects the bits of an integer about its middle position.

- `hashes.bsd` returns an integer between 0 and 65536, alternatively an integer between 0 and 255.


Bug Fixes:

- The `restart` statement did not correctly reset Agena's three number stacks, causing segmentation faults if the stacks have been used thereafter. This has been fixed.

- The following `hashes` functions could cause segmentation faults (at least in Windows) if called `too often`: `djb`, `djb2`, `fnv`, `jen`, `lua`, `mix64`, `mix64to32`, `oaat`, `pl`, `raw`, `sax`, `sdbm`, `sth`. This has been fixed.

- The `import` statement / `readlib` function created memory leaks if the path to the main Agena library could not be found or other errors occurred. This has been fixed.

- Since Agena 2.11.1, `nan` worked incorrectly with complex values representing `undefined`. This has been fixed.

- The Linux version of `os.cdrom` has been fixed.

- The `default` keyword has been removed.

- The `telex` package now treats most ligatures and diacritics with Codepage 850 properly.

- `skycrane.scribe` has been repaired.

- In some Linux flavours, `ilog2` returned wrong results. This has been fixed.


Miscellaneous:

- Adapted sources to compile on Raspbian Stretch.

- Improved the index of the Primer and Reference.

- The new C API function lua_pushchar pushes a single character of type string onto the stack.

- This release has been Valgrind-checked on x86 Linux and Mac OS X to ensure there are no memory leaks.


2.11.6, May 29, 2018

This is a bug fix and maintenance release:

- Since Agena 2.11.1, `nan` worked incorrectly with complex values representing `undefined`. This has been fixed.

- The Linux version of `os.cdrom` has been fixed.

- The `restart` statement did not correctly reset Agena's three number stacks, causing segmentation faults if the stacks have been used thereafter. This has been fixed.

- The import statement / `readlib` function created memory leaks if the path to the main Agena library could not be found. This has been fixed.

- The `default` keyword has been removed.

- Adapted sources to compile on Raspbian Stretch.

- This release has been Valgrind-checked on x86 Linux and Mac OS X to ensure there are no memory leaks.


2.12.0 RC 3, May 27, 2018

- Local variables can now be defined in short-cut functions using the `with` clause, e.g.:

  > f := << x -> with m, n := 3, 4 -> m * n * x >>;

  > f(1):
  12

- The new function `math.accu` returns a function that gets a number with each call, adds it to an internal accumulator using one of five selectable algorithms, and returns the accumulated sum.

- Since Agena 2.11.1, `nan` worked incorrectly with complex values representing `undefined`. This has been fixed.

- The Linux version of `os.cdrom` haas been fixed.

- `stats.hmean` has been ported to C, has become five times faster and now internally uses Kahan-Babuška summation to compensate for rounding errors.

- The new function `math.gethighlowuint64` returns the higher and lower bytes of the unsigned 64-bit integer.

- The new function `math.sethighlowuint64` combines two unsigned 32-bit integers to an unsigned 64-bit integer.

- In the Primer and reference, described the formerly undocumented functions:

  - `math.leadzeros` counts the number of leading zero bits in a 32-bit integer,

  - `math.onebits` counts the number of bits set in a 32-bit integer,

  - `math.sincosfast` returns approximations of sine and cosine,

  - `math.sqrtfast` returns an approximation of the square root.

- Adapted sources to compile on Raspbian Stretch.

- Improved the index of the Primer and Reference.

- This release has been Valgrind-checked on x86 Linux and Mac OS X to ensure there are no memory leaks.


2.12.0 RC 2, May 25, 2018

- The `default` keyword has been removed.

- `strings.tolatin` now returns unsupported code points in its result.

- `os.fcopy` can now copy files if only a target directory is given. The function now no longer overwrites existing files and issues an error instead. Warning messages have been improved. The function now issues errors instead of returning `fail` if a file could not be read or created, or if the source and target file are identical.

- `os.list` returns a second argument, an explanatory text, if a given directory or given file could not be found.

- `strings.chop` now accepts a function as a second argument, checks each character in the string from the right to the left for the given Boolean condition and returns the string from its beginning up to the character that no longer satisfies the condition.

- The `telex` package now treats most ligatures and diacritics with Codepage 850 properly.

- The `restart` statement did not correctly reset Agena's three number stacks, causing segmentation faults if the stacks have been used thereafter. This has been fixed.

- The new C API function lua_pushchar pushes a single character of type string onto the stack.

- This release has been Valgrind-checked on x86 Linux and Mac OS X to ensure there are no memory leaks.


2.12.0 RC 1, May 19, 2018

- The `import` statement can now also assign an alias to a library name when given the new `as` clause, e.g.:

  > import hashes as h;

  > a := h.crc32('agena');  # which is equal to:

  > b := hashes.crc32('agena');

- The `global` statement now checks whether the given variables have not been declared local before its invocation.

- `map` and `@` now support function composition.

- The new function `reduce` applies a function on each item of a structure or string and returns one accumulated result.

- `strings.charset` returns a set of all the unique characters included in a string.

- `strings.shannon` computes various Shannon entropies for a given string.

- `gzip.deflate` compresses a string using the zlib library.

- `gzip.inflate` uncompresses a deflated string.

- `hashes.crc16` computes the CRC16 value of a string.

- Described the formerly undocumented function `hashes.reflect` in the primer & reference. The function reflects the bits of an integer   about its middle position.

- `environ.arity` returns the number of parameters of a function and additionally a Boolean indicating whether its parameter list includes    a `?` (varargs) token.

- This release has been Valgrind-checked on x86 Linux and Mac OS X to ensure there are no memory leaks.


2.11.5, April 02, 2018

- The binio package now supports methamethods. The metatable used by the package is called `BINIOFILE*`. Check the end of Chapter 6.19 of the manual on how to add new methods.

- `binio.readindex` and `binio.writeindex` read and write binary data with a given index and an optional offset allowing for a user defined header.

- `binio.readnumber` and `binio.readlong` can now be passed an optional file offset.

- `binio.readlong`, `binio.readnumber`, `binio.readstring` and `binio.readshortstring` now work like `binio.readchar`: if the end of file has been reached, they all return `null` and no longer issue an error.

- `binio.readshortstring` caused segmentation faults. This has been fixed.

- `binio.writeshortstring` and `binio.writestring` have been tuned.

- In Windows, `os.drivestat` now returns the `trim` flag that indicates a solid-state disk (with a high probability).

- The formerly undocumented function `reverse` has now been described. The function reverses all elements in a sequence or register in-place.

- In the UNIX versions, the `gzip` package uses zlib-1.2.11.

- This release has been Valgrind-checked on x86 Linux and Mac OS X to ensure there are no memory leaks.


2.11.4, January 01, 2018

- The new function `tables.include` inserts values into a table of (sub)tables. If necessary, it creates a subtable before insertion.

- The new function `hashes.lua` returns the hash of a string internally used by Agena.

- The following `hashes` functions no longer need a second argument, i.e. the number of slots, to make them comparable: Instead when given only a string or number, they return its actual hash: `djb`, `djb2`, `fnv`, `jen`, `oaat`, `pl`, `raw`, `sax`, `sdbm`, `sth`, `mix64`, `mix64to32`.

- Improved general error messages. The new `environ.kernel/errmlinebreak` setting allows to change the maximum number of characters to be displayed per line in syntax error messages.

- The new function `debug.funcname` returns the name of the function from which it has been called. It is a wrapper for "debug.getinfo(n, "n").name". The function may be useful to create more flexible error messages.

- `tables.dimension` did not work correctly if given a structure as the initialisor. This has been fixed.

- In `strings.ljustify` and `strings.rjustify`, the filler can now also be a number.

- `mprint`, `checkoptions` now detect whether they have been passed too many arguments.

- Added new API functions agn_rawgetfield, agn_rawinsert, agn_rawinsertfrom. See manual for their features.

- This release has been Valgrind-checked on x86 Linux and Mac OS X to ensure there are no memory leaks.



2.11.3, November 27, 2017

- The new function `math.tohex` converts a non-negative integer to its hexadecimal representation.

- `hashes.md5` can now also compute the MD5 hash value of a file.

- The new function `hashes.crc32` performs a 32-bit reversed cyclic redundancy check on a string.

- The new function `hashes.droot` computes the digital root and the additive persistence.

- The new function `hashes.parity` returns a byte with even parity for a given integer.

- The `llist` package, when loaded, caused problems with the `restart` statement - sometimes segmentation faults occurred. This has been fixed.

- In Solaris 10, `cosc`, `arctan` and thus `arccot` may have returned wrong results in the complex domain. This has all been fixed.

- `environ.kernel`: documented 'maxlong', 'minlong' and 'maxulong' defaults for signed and unsigned 32-bit integer limits. Also added 'lastcontint' and 'smallestnormal' keys which represent the largest accurately representable integer (2^53) and the small normal number (2^-1022).

- This release has been Valgrind-checked on x86 Linux to ensure there are no memory leaks.


2.11.2 November 07, 2017

- The new function math.sinhcosh(x) returns both sinh(x) and cosh(x). It is around 30 % faster than computing the values separately.

- With complex numbers, the following functions have become faster with respect to Agena 2.11.1:
  `antilog2` (3%), `antilog10` (3%), `arcsin` (twice), `arccos` (twice), `arcsec` (almost twice), `arctan` (20 %), `arctan2` (5 %), `cosc` (17 %), `csc` (42 %), `csch` (35 %), `sec` (42 %), `sech` (35 %), `sinc` (20 %), `tanh` (30 %).

- `arctan` has been patched for arguments z = 0 + b*I with b > 1 and b non-integral.

- It turned out that on Solaris some of the mathematical functions tuned in 2.11.0/1 have slowed down instead of sped up. The previous speed has been restored for the functions affected, some are them are faster than in Agena 2.10.4 or earlier. On Mac OS X, the tuning measures do not seem to have any effect.

- Extended numerical test cases.

- This release has been Valgrind-checked on x86 Linux to ensure there are no memory leaks.


2.11.1, October 31, 2017

Tuning:

- With real numbers, the following functions have become faster: `cbrt` (15 %), `ceil` (40 %), `cosh` (45 %), `frexp` (15 %), `ldexp` (15 %), `log` (20 %), `log10` (4 %), `sinh` (45 %), `tanh` (55 %), `math.expminusone`(twice as fast). Exponentiation now is 1.3 times faster.

- With complex numbers, the following functions have become faster: `|-` (twice), `abs` (thrice), `arctan2` (25 %), `argument` (13 %), `ceil` (20 %), `cos` (2.8 times), `exp` (70 %), `recip` (20 %), `rot` (35 %), `sin` (2.8 times), `tan` (25 %). Exponentiation and multiplication have become 10 percent faster, and division 25 percent faster.

Bug fixes:

- With 0, `ilog2` returnd 2^31 instead of `undefined`. The same happened with `infinity`. This has been fixed.

- With a real number as the first argument, `rot` returned a wrong result. This has been fixed.

- `hypot4` erroneously returned `undefined` in certain situations. This has been fixed.

Miscellanous:

- `math.chop` can now also process complex numbers.

- `ads.clean` uses a different internal library to prevent compiler warnings.

- Extended numeric test cases.

- This release has been Valgrind-checked on x86 Linux and MacOS X to ensure there are no memory leaks.


2.11.0, October 22, 2017

New Features:

- In functions, the new `pre` clause, placed right before the `is` keyword, checks one condition and issues an error if it is not met:

  golden := proc(n :: number)    # approximation of golden ratio
     pre isint(n) and n > -1 is  # if n <= 0 or float, quit with an error
     if n = 0 then return 1 fi;
     return 1 + recip(procname(n - 1));
  end;

  It is faster than checking arguments with calls to the `assume` function.

- The new `post` clause in `return` statements checks a condition and issues an error if it is not met:

  proc(x :: number) is
     [...]
     return post x <> 1 is x  # issue an error if x = 0, and return x otherwise
  end;

  A function can include both `pre` and `post` conditions.

- Single quotes can now be part of a variable name, e.g.: f' := << x -> cos(x) >>; print(f'(2));


New Functions and Operators:

- The new `~|` operator returns 0 if both operands are approximately equal, -1 if the first operator is less than the second one, and 1 if the second operator is greater than the first operator.

- `math.rectangular` computes the rectangular pulse function.

- `math.unitise` returns 0 if its number argument x is zero or close to zero, and 1 otherwise.

- `cosc` computes the cardinal cosine.

- `cartesian` function returns a complex number for a given magnitude and argument.

- `math.sincos` function computes both the sine and cosine.

- `hypot4` computes sqrt(x^2 - y^2), avoiding over- and underflow.

- `math.clip` clips its argument between two numbers.

- `math.chop` shrinks a number more or less near zero to exactly zero, using one of many methods.

- `math.triangular` computes the triangular function.

- `math.fpclassify` determines the type of a (floating-point) number; it is a port to C's fpclassify.

- `math.invroot` approximates the inverse root 1/root(x, degree) using the Quake III method.

- `math.dirac` computes the Dirac delta function.

- `calc.gaussian` computes the Gaussian function.

- `math.reciprocal` approximates the reciprocal of its argument of type number. The return is a number. The function is purely experimental.

- `math.sqroot` approximates the square root of its argument of type number. The return is a number. The function is purely experimental.


Extensions:

- `frac` has been processing complex numbers for a long time. This has now been documented.

- `roundf` has become 65 % faster when rounding to an integer and can now process complex numbers, and 15 % otherwise. The function has also been renamed to just `round`. An alias is provided for backward compatibility.

- `math.ndigits` can now be given an optional base.


Tuning:

- The `cis` operator has become twice as fast with real numbers.

- `modf`, `symmod`, `arctan2`, and `math.wrap` have become 20 % faster.

- `math.quadrant` has become 10 % faster and `polar` 15 % faster.

- With real numbers, `arctan` has become 45 % faster; `sin` and `cos` have become 30 % faster, `ln` is 25 % faster, `exp` 60 % faster, `tan` 8 % faster.


Bug Fixes:

- If `print` has been called without arguments, Agena crashed. This has been fixed.

- The `ads` package crashed if compiled in pre-2010 32-bit Debian PowerPC systems. This has been fixed.

- `math.epsilon` has been patched. It now always returns Eps if its absolute argument is less than 1.

- `ads.desc`: If no description has explicitely been written to the base, the function now returns the empty string instead of 74 blanks. Also, the function did not correctly write the description, this has been fixed.

- `ads.attrib`: The function now also returns the description in the 'description' field.

- `ads.getallindices`, `ads.invalids` returned wrong values. This has been fixed.

- `ads.clean` corrupted files. This has been fixed. Currently, the function does not clean a file of it contains a comment.

- Improved error handling of many `ads` functions.


Deprecations:

- The `rect` and `math.zeroin` functions have been removed. Use the more general functions `math.rectangular` and `math.chop` instead. Aliases have been provided, however, to provide backward compatibility.


Miscellanous:

- Mathematical interval notation like a < x < b (introduced with 2.11.0 RC3) is no longer supported.

- Changes to the sources to compile in DJGPP/GCC 7.2.0. GCC 4.7.3, however, is still used to compile the DOS version as DJGPP/GCC 7.2.0 features faulty math functions.

- This release has been Valgrind-checked on x86 Linux and Mac OS to ensure there are no memory leaks.


2.10.4, August 05, 2017

- The new keyword `procname` refers to the function in which it is used. You can thus programme recursive procedures without using its real name in the procedure body but with this reference. Note that `procname` refers to the function and does not return its name as a string. Example: instead of

  > fib := proc(n) is
  >    if n = 0 or n = 1 then return n fi; # exit conditions
  >    return fib(n - 2) + fib(n - 1)
  > end;

  you can write:

  > fib := proc(n) is
  >    if n = 0 or n = 1 then return n fi; # exit conditions
  >    return procname(n - 2) + procname(n - 1)
  > end;

- `binomial` has been extended to also process negative arguments and also floats.

- `fact` now accepts any rational argument that is non-integral.

- The second argument to `root` is now optional and by default is 2.

- Some bitwise operations on Solaris 10, DOS and Windows did not return the same results as on other platforms. This has been fixed (int64_t had four bytes instead of eight).

- The new `hypot3` function returns sqrt(1 - x^2), avoiding under- and overflows.

- The new function `calc.chebycoeffs` computes Chebyshev coefficients.

- The new function `calc.cheby` returns a function to compute the Chebyshev interpolant of a univariate or multivariate function, and optionally computes a derivative. Depending on the type of function to be differentiated it can be faster and more accurate than `calc.xpdiff` if you provide the proper window parameters.

- The new procedure `calc.savgol` computes a Savitzky–Golay filter for a univariate function f to smooth its data. `calc.savgolcoeffs` computes the Savitzky–Golay coefficients.

- The new procedure `calc.smoothstep` computes a sigmoid-like interpolation and clamping function.

- The new procedure `calc.sigmoid` computes the sigmoid function, and `calc.logistic` the logistic function.

- The new procedure `calc.gd` computes the Gudermannian function.

- The new function `hashes.digitsum` omputes the digit sum of a number to a given base.

- Improved error messages when comparing values of different types.

- Improved error messages of the `io` and `os` libraries.

- `debug.getinfo` now also checks whether the parameter list of a function contains `?`, i.e. the varargs placeholder, with the 'v' option. It is indicated by the 'varargs' key. If the parameters of a function include the `?` placeholder, the 'arity' entry denotes the number of all `static` parameters (without a count to `?`) instead of -2147483648.

- Moved and renamed some C API functions from lapi.c to agnxlib.c for consistency: agnL_fillarray, agnL_islinalgvector, agnL_onexit.

- The new C API function `agnL_fncall` conventiently runs a numerical Agena function and returns its result as a lua_Number.

- In Windows, some of the plus package DLLs have been reduced in size.

- The `Crash Course` has been updated.


2.10.3, July 02, 2017

- Functions could not be properly dumped and re-read with the `strings.dump` and `loadstring` function pair. This has been fixed. Thus, an out-of-the-box method to also serialise data is available again by putting them in `return` statements of functions.

- Date and time values can now be directly passed to `os.date`.

- Modified sources so that GCC 6.3.0 does not issue warnings.


2.10.2, June 19, 2017

- `for` loops can now also be combined with an additional `until` clause in the loop header, e.g.:
  > for i to 5 until i = 3 do print(i) od;
  1
  2

  > for i in [1, 2, 3, 4, 5] until i = 3 do print(i) od;
  1
  2

- The `in` operator could not detect structures in sequences and registers. This has been changed.

- The `|-` absolute difference operator can now also process complex numbers. Also reduced its precedence to the one of `in` so that complex values using the a+I*b instead of the a!b representation can be used without brackets.

- `tables.dimension` did not correctly set up rows and when updating a row later, also all other rows where overwritten - this has been fixed.

- Functions with remember tables caused memory faults if the respective `return` statement included a call to _another_ function. This has been fixed.

  Also, if this other function called has been written in the Agena language, its result has not been put into the remember table. This can currently not be fixed, but an error will be issued now. Define an auxiliary variable storing the result of the function call and then use this variable in the `return` statement.

- `calc.xpdiff` can now calculate the second and third derivative by passing the new `deriv=2` and `deriv=3` options. Corrected error message. The function now also returns results near undefined domains.

- `calc.minimum` and `calc.maximum` always returned exceptions. This has been fixed.

- `calc.zero` did not recognise the `eps` option, which has been fixed.

- `calc.symdiff` has been removed and a macro has been provided to `calc.xpdiff`.

- `math.fib` returned wrong results. This has been fixed, and the function now includes error handling.

- `math.convertbase` erroneously declared a global variable. This has been fixed.

- The new function `cas` returns sin(x) + cos(x), with x either a number or complex number, the efficient way.

- The falling factorial function `math.fall` computes x*(x - 1)*(x - 2)* ... *(x - n + 1). With negative n, it computes the rising factorial function.

- `arccot` and `cot` have become 9 percent faster.

- Removed unused keywords `apply`, `mne` and `let`.

- Added all available date specifiers supported by `os.date` to the manual.

- Cleaned up test cases a little bit.


2.10.1, May 14, 2017

- The new function `calc.isdiff` checks for the differentiability of a univariate or multivariate function at a point.

- `calc.xpdiff` can now process multivariate functions f. As such, the epsilon and delta arguments must now be passed as options of the form eps=<number>, delta=<number>, with both defaults now determined by the magnitude of f's first argument, e.g. diff.xpdiff(f, 1, 2, 3, delta=1e-7, eps=1e-8).

- Fixed `hashes.md5` which sometimes produced wrong MD5 values.

- `math.random` did not recognise its third argument when given. The function also did not recognise very large lower and upper bounds properly and sometimes returned out-of-range results when given a lower or upper limit. This has all been fixed.

- The `restart` statement did not reset the seeds for `math.random`. This has been fixed.

- If called without arguments, `math.randomseed` now returns the current seeds.

- `expx2` returned `undefined` with values towards -/+infinity. This has been fixed. The second argument has become optional and by default is positive, i.e. exp(x*x) is computed.

- `math.norm` did not recognise its third argument when given and always normalised to the range [0, 1]. This has been fixed. Optimised code of the `stats` and `calc` packages, and `linalg.gsolve`.

- The C API function `agn_getpairnumbers` has been renamed to `agn_getpairinumbers`. A macro has been provided to ensure backward compatibility.

- Added eComStation OS/2 YUM installation instructions to the manual.


2.10.0, April 30, 2017

New features:

- The `if` operator accepts an optional preceding `with` clause. It easily allows to define one or more auxiliary variables that are local to this operator only:

  > x := Pi;
  > a := with n := 2*x -> if x < 0 then n else 2*n fi;

  which is syntactic sugar for:

  > x := Pi;
  > scope
  >    local n := 2*x;
  >    a := if x < 0 then n else 2*n fi
  > epocs;

- The `with` statement now allows to define local variables existing only in the body of a statement, e.g.:

  > with a, b := 1, 2 do
  >    print(a + b)
  > od;

  which is syntactic sugar for:

  > scope
  >    local a, b := 1, 2;
  >    print(a + b)
  > epocs;

- The new `(/ ... \)` constructor allows to define a sequence of constant numbers and/or strings the simple way: items may not be separated by commas, and strings do not need to be put in quotes as long as they satisfy the criteria for valid variable names (name starting with a hyphen or letter, including diacritics). Expressions like `sin(0)` etc. are not parsed. Example:

  > a := (/ 0 -1 2 3 zero one two three '2and3' \):
  seq(0, -1, 2, 3, zero, one, two, three, 2and3)

- The new `empty` operator checks whether a table, set, sequence, register or string is empty. It returns the opposite of the `filled` operator.

- The new `infinite` operator checks a number for +/- infinity.

- The new `%%` operator returns the percentage change of two values a, b and is equal to b /% a - 100.

- The new `symmod` operator works like the `irem` function but is 30 percent faster. The `irem` function has been removed but an alias has been provided for backward compatibility.

- The new function `times` takes a start value and applies a function on it and its results for a given number of times. It optionally stores all its intermediate results to a given structure. It can be applied on any type. It can be used, for example, to easily compute the Golden ratio:
  times(<< x -> 1 + recip x >>, 1, 33) -> 1.6180339887499

- The new `math.lnfact` function computes the logarithmic factorial of its non-negative argument n, i.e. lngamma(n + 1).

- The new function `math.branch` returns its argument if x is non-negative, otherwise returns 0, and vice versa.

- The new `math.clamp` function returns x if a <= x <= b, a if x < a, and b if x > b.

- The new function `math.flipsign` returns its first argument with its sign flipped if the second argument is negative. For example, abs(x) = flipsign(x, x).

- The new function `math.fld` returns the largest integer less than or equal to the real quotient of its arguments. Likewise, the new function `math.cld` returns the smallest integer larger than or equal to the real quotient of its arguments.

- The new function `math.powmod` computes x^p % m.

- The new function `math.isqrt` returns the integer square root.

- The new functions `math.mantissa` and `math.exponent` return the mantissa and exponent of a number, respectively. Individually, they are around 20 percent faster than `frexp`.

- The new function `math.frexp` returns the signbit, the mantissa and the exponent of a number.

- The new function `math.ispow2` checks whether a given integer x is a power of base 2 and returns `true` or `false`.

- The new function `math.modulus` is a plain binding to the C `%` modulus operator.

- The new function `math.modinv` computes the modular inverse.

- The new function `math.epsilon` returns the relative spacing between |x| and its next larger number on the machine’s floating point system, taking into account the magnitude of its argument. It works like `math.eps` with the `true` option but is 20 percent faster.

- The new function `math.issubnormal` checks whether a number is subnormal. Subnormal numbers are very close to zero, have reduced precision and lead to excessive CPU usage.

- The new function `math.zerosubnormal` checks whether its argument is subnormal and in this case returns 0, otherwise returns its argument.

- The new function `math.normalise` normalises a subnormal number and returns a non-zero normalised value that is close to its argument.

- The new constant `math.lastcontint` denotes the largest integer i representable on the floating-point system with enough precision such that i - 1 <> i.

- The new constant `math.smallestnormal` denotes the smallest positive normal number representable on your system.

- The new function `math.gethighlow` retrieves the higher and the lower bytes from a number (i.e. C double).

- The new function `math.fib` returns the n-th Fibonacci number.

- The new function `stats.winsor` returns the winsorised mean.

- The new function `stats.weights` converts weighted observations.

- The new function `strings.between` returns the substring which is nested between a prefix and suffix.

- The new function `strings.chop` removes the last character from a string.

- The new function `strings.chomp` removes a substring from a string if it is at its end.

- The new function `strings.contains` checks whether all characters in a string are part of another string.

- The new function `strings.appendmissing` appends a suffix to a string if it is not already at its end.

- The new function `strings.uncapitalise` turns the first character in a string to lower case.

- The new function `strings.iswrapped` checks whether a string is wrapped by another one.

- The new function `strings.wrap` wraps a string with another one.

- The new function `strings.wrapmissing` wraps a string with another string if the latter is not wrapping the former.

- The new function `strings.gseparate` splits a string into its tokens step by step.

- The new function `strings.cut` splits a string into two pieces.

- The new function `strings.advance` returns the rest of a string marked by a substring.

- The new function `strings.isdia` checks for diacritics.

- The new function `strings.charmap` returns internal character maps with digits, upper and lower-case letters, diacritics, punctuations, etc.

- The new function `os.getlocale` returns various information on the current locale including decimal point and thousands separators, currency, and monetary formatting suggestions.

- On UNIX systems, the new functions `os.chown` and `os.chmod` work like the respective shell commands.

- The new functions `os.dirname` and `os.filename` retrieve the directory and filename of a path. `os.isdir` checks for directories, `os.isfile` for regular files, `os.islink` for links.

- The new `astro.hdate` function converts a Julian astronomical date to the Jewish calendar.

- The new function `astro.taiutc` returns the TAI-UTC lookup table value of leap seconds for a given Julian date.

- The new functions `hashes.mix64` and `hashes.mix64to32` compute 64 bit mix, and 64 bit to 32 bit mix hashes.

- The new functions `hashes.damm`, `hashes.luhn` and `hashes.verhoeff` compute one-digit checksums.

- The new function `hashes.fletcher` returns the position-dependent 8-bit checksum of a string according to Fletcher's algorithm.

+ The new function `hashes.bsd` returns the legacy BSD checksum for a string.

- The new function `hashes.mix` mixes three non-negative 32-bit integers.

- The new function `hashes.cksum` returns the same checksum as the UNIX cksum utility for a string.

- The new function `skycrane.tolerance` returns a maximum tolerance value especially suited for comparing similar strings.


Improvements:

- The `::` and `:-` type checkers can now also test for multiple types. Just pass them in a set at the right-hand side, e.g. 1 :: {number, string, 'bag'} returns `true`.

- If passed a string, the `filled` operator now checks whether it is non-empty and returns `true` or `false`.

- `strings.dleven` has been completely rewritten and has become around 25 percent faster.

- The domain of the bit-shift and bit-rotation operators (<<<, >>>, <<<<, >>>>) has been extended internally from 32 to 64 bits. Bitwise `and` (&&), `or` (||) and `xor` (^^) also now work with 64 bits instead of 32 bits. Warning: this might change the range of their return values, especially when used in user-defined hash functions.

- `math.convertbase` has become faster by up to 40 percent.

- `math.gcd` has become 5 percent faster.

- `odd` has become ten percent faster.

- `os.lsd` has been ported to C and is three times faster now. It now also accepts structures containing date and time information.

- `os.date`: The new '*sdn' option computes the Julian date in the Julian calendar (whereas '*j' computes it in the Gregorian calendar).

- If a single number denoting the respective Serial Date is being passed to `os.esd` and `os.usd`, the respective Gregorian date and time is returned.

- `utils.checkdate` no longer issues false if the given year is less than 1900 or greater than 2099. Also rewrote the code. The function now also accepts 24:00:00 hours (midnight).

- In Windows, `os.cpuload` now also returns the processor utilisation for kernel and user-mode processes, as well as the processor queue length, number of context switches and interrupts.

- `heaviside` now accepts a second argument that is being returned if the first argument is zero.

- If called with only one argument (equal to domain restriction to [-Pi, Pi]), `math.wrap` computes the result 33 percent faster.

- The new Q and B modifiers have been added to `strings.format`, enclosing a string in single quotes or backquotes, respectively.

- The new h and H modifiers to `strings.format` print a floating-point number in a hexadecimal fractional notation which the exponent to base 2 represented in decimal digits.

- The new p modifier to `strings.format` multiplies the given number by 100 and displays it in fixed (‘f’) format, followed by a percent sign.

- The new n and N modifiers to `strings.format` print a floating-point number with the decimal point separator used by the operating system.

- The new m modifier to `strings.format` prints a monetary amount with thousand and decimal point separators defined by the current locale.

- The 'tbytes' option for terabytes has been added to `os.memstate`, `os.freemem`, and `environ.used`.

- If a numeric constant is appended by the `p` character, it is converted to percent.

- Improved handling of the thousand seperator with numeric contants: It can now be also used with constants prefixed by `0x` (hex), `0b` (dual), and `0o` (octal), subsequent and trailing separators are no longer allowed.

- With `strings.match` and related functions, the search for vowels or consonants has become 33 percent faster.

- `math.setlow` and `math.sethigh` have been precautionarily hardened but are a little bit slower now.

- `hashes.collisions` now accepts a fractional factor and returns results in the following order: number of collisions, number of total slots (occupied or free), the time it took to run the procedure, and the hashing table (a bag). See also entry in `Changes / Incompatibilities`.

- Improved error messages of `bags.bag`, `bags.include` and `bags.remove`.

- The Windows edition of Agena has become 6 percent faster by compiling it with GCC 5.3.0.

- Fixed the agnhlps.* forced complete recompilation issue, at last.


Changes / Incompabilities:

- '\`' The backquote now delimites strings and can no longer be used to denote short strings which have been abolished altogether.

- The order of parameters of `hashes.collisions` and its return has been changed.


Bug Fixes:

- `os.lsd` returned a wrong result if the given date was older than March 01, 1900. This has been fixed.

- The fraction of day returned by `os.esd` and `os.usd` contained round-off errors. This has been fixed.

- `strings.isabbrev` and `strings.isending` did not work if the pattern (second argument) contained captures. This has been fixed.

- `setbits` did not correctly check its second argument. This has been fixed.

- `math.convertbase` now issues an error instead of a wrong result if the number to be converted is too large.

- Most of all the `hashes` procedures crashed when passed a zero size of slots. This has been fixed.

- At least with the Raspberry Pi edition, the `xml` package was missing. This has been changed by fixing the corresponding Linux makefile.

- The `xbase` package did not work on Big Endian systems, e.g. the Linux PowerPC edition. This has been fixed.

- The // ... \\ constructor did not recognise negative numbers. This has been fixed.


2.9.8, August 14, 2016

New features:

- The new `|` operator compares two numbers a, b, and returns -1 if a < b, 0 if a = b, and 1 if a > b. It is twice than fast as the `sign` operator.

- The new `|-` operator computes the absolute difference of two numbers x and y, i.e. abs(x - y).

- The new `identity` function just returns all its arguments.

- The new function `strings.compare` compares two strings and returns the first position where they differ, or 0 if both strings are equal. If called with any option, the function returns the result of the C function strcmp.

- The new `astro.cweek` function returns the calendar week of the given date, a number in the range 1 to 53, according to the ISO 8601 standard.

- The new function `astro.lastcweek` determines the last week of a year.

- The new function `astro.cweekmonsun` computes the Gregorian dates of the Monday and Sunday for a given calendar week.

- The new function `os.esd` computes the Excel Serial Date.

- The new function `os.tzdiff` computes the difference between the system's local time zone and UTC in minutes and a Boolean indicating whether daylight Saving Time is active for the given date.

- The new function `stats.freqd` returns a frequency distribution function for a sample that can be iterated subsequently to return the number of all occurrences step by step.

- The new `xbase.fieldtype` function returns the dBASE data type of the given field.

- The new `xbase.write` function writes a number, string, or boolean to a dBASE file. It can be used instead of `xbase.writenumber`, `xbase.writefloat`, `xbase.writestring`, `xbase.writeboolean`, etc.

- The new C API function `agn_checknonnegint` checks for non-negative integers.

- The new C API function `agn_datetosecs` takes a structure or at least three numbers and returns the number of seconds elapsed since the epoch of the system (usually January 01, 1970).

- The new C API function `agnL_createpairnumbers` puts a pair of two numbers on top of Agena's C stack.


Improvements:

- `hypot` has become around 40 % faster. `polar`, `approx`, `ilog2`, `calc.eucliddist`, `stats.neighbours` and various fractals package functions benefit from this increas in speed, as well.

- `math.roundf` has become 13 percent faster.

- `calc.eucliddist` now accepts multivariate functions and returns more precise results.

- `calc.iscont` and `calc.limit` now can also process multivariate functions. If you would like give a self-defined epsilon, it must be passed as an 'eps':<value> option as the very last argument. For example, if the function is f := << (x, y) -> x + y >>, with x = 1, y = 3, and eps = 1e-4, the call would be: `calc.limit(f, 1, 3, eps = 1e-4)`.

- `calc.diff` now can also process multivariate functions. If you want to pass a user-defined accuracy value h, pass the eps=h option as the very last argument instead of passing h as the third argument.

- `calc.limit` can now return the left-sided limit by passing the side='left' option, the right-sided limit by passing the side='right' option, the left- and right-sided limit by passing the side='both' option; and the bidirectional, the left-sided, and the right-sided limits with the side='all' option.

- `os.date`: the day of week ('wday' field) is now determined according to the ISO 8601 norm, where 1 is Monday, and 7 is Sunday. You may switch back to the old behaviour (1 for Sunday, 7 for Saturday) by issueing
  environ.kernel(iso8601 = false).

- `os.date`: The '*j' (Julian Date) and '*l' (Lotus Serial Date) options have been re-introduced as they have been inadvertently removed in Agena 2.8.4. Contrary to the former results returned with the '*l' format, the function now
  returns correct values.

- `os.now` and `os.settime` now accept year, month, and day, and optionally hours, minutes and seconds.

- `os.date` now also accepts a table array of integers representing year, month, day, and optionally hour, minute, second.

- `os.datetosecs` now accepts no argument at all and in this case returns the number of seconds elapsed till the current
  date and time.

- When passing `false` as the last argument to `os.lsd`, the function acknowledges daylight saving time (by default, the function always returns a Standard Time value even if Daylight Saving Time is active for the given date).

- `astro.cdate` now also returns hours, minutes and seconds in ordinary sexagesimal notation.

- In Windows and eComStation, `os.realpath` now by default returns a path with slashes instead of backslashes. You can override this by passing `false` as a second option.

- `stats.obcount` and `stats.obpart` can now be passed the number of classes into which a distribution shall be subdivided with the new 'classes' option. Also, if no third argument is passed to the function, it automatically computes the step size (aka class width), with no upper limit (it is suggested to choose between 5 or 30 classes).

- `stats.obcount` now accepts an optional fourth argument, a procedure that is applied on any element of a distribution before the function decides into which subinterval to sort it for the final count.

- Improved memory allocation error management of `stats.quartiles` and `stats.fivenum`.

- Improved error handling of `stats.checkcoordinate` `math.inttofpb`, `math.tobinary`.

- `xbase.new` now also accepts the data type name 'Numeric' which is equal to 'N' and 'Number'. (There is no dBASE data type called 'Number'.)

- The xbase package now supports signed 4-byte integers (Visual Fox Pro 'I' or 'Long' data type). Use `xbase.writelong` or `xbase.writenumber` to write 4-byte integers to a dbf file. The function automatically truncates Agena numbers to their integral part and issues an error if the numeric range [-2'147'483'647, +2'147'483'647] is exceeded. Longs can be read by LibreOffice 5.x Calc, but not by Excel.

- The xbase package now supports timestamps (Visual Fox Pro 'T' data type). Use `xbase.writetime` to write them.

- dBASE binary Double values can now be read by LibreOffice 5.x Calc. They can still not be read by current Excel editions.

- `xbase.attrib` now also returns the dBASE version number.

- `xbase.new` can now be given an explicit dBASE version number with the new version=x option. (See documentation of `xbase.new` for valid values for x). If no version option is passed, then by default the dBASE version is 0x03 = 3 decimal = dBASE III+. If at least one of the given fields is of type 'Double', then the version number is automatically changed to 0x30 = 48 decimal = Visual Fox Pro. This allows dBASE files created with Agena and containing binary Doubles to be imported into LibreOffice 5.x. Current versions of Excel still cannot read Visual Fox Pro dbf files, so you might pass the version option.

- Besides xBASE doubles, `xbase.writenumber` can now also write xBASE floats, longs, and binary doubles. Thus, you must no longer need to check whether to use `xbase.writefloat`, `xbase.writelong`, or `xbase.writedouble`. Also improved error message.

- The manual has been improved.


Bug Fixes:

- `calc.limit` sometimes returned wrong results with removable singularities. This has been fixed.

- The already documented `hypot2` function has now been implemented. It computes sqrt(1 + x^2), avoiding over- and underflows.

- `os.lsd` works again if one or more arguments have been passed to it, and also now returns a correct result with dates before March 01, 1900.

- `os.settime` now works as described in the manual.

- `os.drivestat` and `os.settime` are available (again) in Linux.

- `zx.genseries` always crashed. This has been fixed.

- `utils.readcsv` now returns an error if both enclosing single and double quotes shall be removed from field values.

- `skycrane.readcsv` now by default only deletes enclosing double quotes; single quotes around fields can no longer be
  removed.

- `stats.obcount` and `stats.obpart`: The following feature does now work as described in the manual: "[...] if an element in a distribution equals the right border of the overall interval, it is considered part of the last subinterval."

- `math.tosgesim` has been rewritten in C, improved in precision and no longer returns the second or minute 60 or greater. It has also become 30 percent faster.

- `math.nthdigit` could not retrieve a digit in the fractional part of a number. This has been fixed.

- `mdf` and `xdf` rounded all numbers to the wrong direction. This has been fixed. Thus, `xdf` can now be used to truncate floats to a given decimal place.

- `gdi.pointplot` may not have worked when evaluating thickness and linestyle options. This has been fixed.

- `os.drivestat` might not have worked in Sun Solaris. This has been fixed.


2.9.7, February 01, 2016

- The new `intdiv` statement conducts an integer division of its operands and reassigns the result to the first operand.

- The new function `calc.iscont` returns `true` if a real function is continuous at a given point, and `false` otherwise.

- The new function `calc.limit` returns the limit of a function at a given point.

- The new function `calc.eucliddist` computes the Euclidian distance, i.e. the straight-line distance, of two points on a curve defined by a function in one real.

- The new function `calc.arclen` returns the arc length (curvilinear length) of a function in one real between two points.

- The new function `calc.sinuosity` computes the ratio of the curvilinear length and the Euclidean distance between the end points of a curve.

- The new function `calc.symdiff` computes the symmetric derivative of a function at a point. The function is three times faster than `calc.xpdiff`, but a little less accurate.

- `math.eps` can now also compute a `mathematical` epsilon value that also takes into account the magnitude of its argument, by passing any second argument. It prevents huge precision errors with computations on very small and very large numbers.

- `environ.kernel` returns the maximum path length with the 'pathmax' option.

- `clock.tm` has been tuned.

- Added another fix to `math.convertbase` with respect to the internal stack used.

- `utils.readcsv` did not correctly strip empty quoted fields and fields enclosed by quotes containing delimiters - this has been fixed.

- `approx` returned a wrong result (i.e. `true`) if at one of its first two arguments was `infinity` and the other one was finite. This has been fixed.

- In Windows, when pressing CTRL + C to quit the interpreter, the warning `This application has requested the Runtime to terminate it in an unusual way. Please contact the application's support team for more information.` should no longer be issued.

- The test suite has been corrected.

- The number of internal number stacks has been extended from one to three stacks. You can switch between them by calling the new function `switchd` with its argument between 1 and 3. The default is stack #1. The new function `stack.selected` returns the currently selected/active stack.

  When given a stack number, `allotted` returns the current number of values in the given stack. `stack.resetd` now also accepts one or more stacks to be cleared by passing their number(s).

- The new function `stack.sorted` sorts all or the last given number of elements in the stack in ascending order.

- The new function `stack.choosed` returns the number of the stack with the least number of stored values.

- `stack.reversed` did not correctly check negative arguments. This has been fixed.

- `pushd` can now insert values into a given stack by passing the stack = <stack number> option as the last argument, avoiding explicit stack switches with calls to `switchd`. Using this option, however, may slow down the operation since processing an option takes quite some computation time. You may be better off calling `switchd`.


2.9.6, January 03, 2016

- The `create table` statement can now pre-allocate both the array _and_ hash parts of a new table, e.g. `create table a(10, 200)`.

- `math.convertbase` generally cleared the built-in numerical stack and thus could interfere with other functions still needing it. This has been changed.

- In Windows, the `bye` statement sometimes caused unnecessary warnings of the operating system. This has been fixed by now conducting a final standard garbage collection and completely closing the state of the interpreter.

- `os.exit` now by default clears the interpreter state before leaving. The description of the function in the manual has been corrected, too.

- `pushd` now accepts a sequence of numbers to be added to the built-in number stack.

- `stack.reversed` can now reverse the last n values pushed onto the stack, e.g. `stack.reversed(n)`.

- `resetd` has been moved to the `stack` library. An alias to this former base library function has been added for backward compatibility.

- If the initialiser of `tables.dimension` is a structure, the function now creates an indidual copy of it to avoid referencing to the same structure. This was the behaviour of the former `dimension` baselib function.

- The `mapm` package did not correctly free some of the consumed memory at exit. This has been fixed. Also, the garbage collection of the package trims the memory usage to significantly reduce general footprint of this library.

- In Debian, the `gdi` package has been recompiled and hopefully would now only need the zlib package as a dependency ... Also, libexpat2 and libgd2-xpm are no longer pre-requisites for the Debian installer.


2.9.5, December 30, 2015

- The new function `math.tobinary` converts a non-negative integer into its binary representation, a sequence of zeros and ones.

- The new function `tables.newtable` returns a table with a given number or pre-allocated array and hash slots.

- `dimension` has been completely rewritten and can now create any kind of n-dimensional table. The function has also been moved to the `tables` library (new function `tables.dimension`). An alias to the former `dimension` function in the basic library has been added for backward compatibility.

- The `to` indexing method for tables did not work properly with some types of index ranges and in theses cases wrongly returned all elements in the array part of a table. This has been fixed.

- With structures, the `case/of` statement now compares values for strict equality (like the `==` operator). Formerly, a Cantor-like equality check has been conducted where positions and the number of occurence of elements in a structure do not matter.

- `stack.dumpd` can now also dump the last n values pushed onto the stack.

- If `ads.iterate` receives a file handle only, the very first key ~ value pair in the base is returned (same as passing the empty string as the second argument). The function now can also read sequences: in this case, the function returns an iterator function that when called returns the next entry in the sequence database.

- `ads.getall` now returns an Agena sequence of all the entries stored in a sequence database if any second argument is given. The entries are returned in the order of their physical presence in the database file; if one and the same entry is stored multiple times, it is returned multiple times.

- `ads.createbase` now returns nothing, since returning the handle of a closed file did not make sense.

- Memory leaks in `ads.createbase` and `ads.iterate` have been removed.

- `ads.filepos` has been documented.


2.9.4a, December 26, 2015

- Windows only: Due to a very kind hint by an Agena user, the missing dynamic link library libgcc_s_dw2-1.dll needed by the gdi and gzip packages has been added to the Windows installers.


2.9.4, December 07, 2015

- The new function `stats.midrange` computes the sum of the minimum and maximum value of a distribution, divided by two.

- The new `|` operator compares two finite numbers a, b, determines whether a is less than b, a is equal to b, or a is greater than b, and returns -1, 0, or 1 respectively.

- A numerical stack has been built into Agena. It can store numbers only. See Chapter 7.41 of the Primer and Reference for details.

- Agena for Windows has been recompiled with GCC 4.8.1. The binaries are around 20 percent faster now.

- `math.tobytes` had been rewritten for it did not work correctly if Agena had been compiled with GCC 4.8.x or higher. Thus, it now also works in DOS.

- `mapm.xtonumber` could not convert a mapm arbitrary precision number into an Agena number. This has been fixed.

- Improved error messages of `gzip.lines` and of `run`.

- Some source files have been cleaned up, so Agena should compile better with very pedantic C compilers.

- Extended the test suite.


2.9.3, November 17, 2015

- The new `// ... \\` constructor allows to define a table of constant numbers and/or strings the simple way: items may not be separated by commas, and strings do not need to be put in quotes as long as they satisfy the criteria for valid variable names (name starting with a hyphen or letter, including diacritics). Records are supported as well. Expressions like `sin(0)` etc. are _not_ parsed. Example:

  > a := // 0~0 1 2 3 zero one two three '2and3' \\:
  [0 ~ 0, 1 ~ 1, 2 ~ 2, 3 ~ 3, 4 ~ zero, 5 ~ one, 6 ~ two, 7 ~ three, 8 ~ 2and3]

- The new function `math.wrap` conducts a range reduction of a number to a given interval [min, max).

- The new `inrange` operator checks whether a number is part of an interval. It is five times faster than the `in` operator. "inrange(x, a, b)" is equivalent to "x in a:b".

- C-style comments ( /* ... */ ) are now supported.

- The `**` operator turned into an infinite loop if the exponent was +/- `infinity` or `undefined`. This has been fixed.

- The new `zx` package provides various elimentary mathematical functions implementing Chebyshev polynomials for sine, cosine, tangent, arcus sine, arcus cosine, arcus tangent, natural logarithm, exponentiation to the base E, general exponentiation, and square root. These functions are C implementations of the corresponding Sinclair ZX Spectrum 48k ROM Z80 assembler routines.

  Furthermore, some auxiliary functions are provided to directly compute Chebyshev polynomial with a given coefficient vector, to reduce the range of arguments, and to retrieve or change Chebyshev coefficients. For completeness, pendents of all other ZX Spectrum math and Boolean functions are available, as well.


2.9.2, November 04, 2015

- The new `utils.uuid` function creates a random version 4 universally unique identifier (UUID), or the nil UUID.

- `os.exit` now closes the state of the interpreter before leaving for the operating system if its last argument is the Boolean `true`.

- In eComStation, the 'halt' switch to `os.terminate` can now halt the system, but it does not power it off.

- The new `registry` package provides limited access to the registry and should be used instead of the `debug.getregistry` function.

- The `system` function in the `debug` library has been moved to the `environ` package. An alias has been provided for backward compatibility.

- Garbage collection has been changed when deleting set entries via indexing.

- In the manual, the chapters on sandboxes and scripting have been improved. Also, userdata, lightuserdata, and the  registry are now briefly described. The Crash Course has been extended, as well.


2.9.1, October 30, 2015

- The new `++` operator returns the next representable number larger than its argument. Likewise, `--` returns the next representable number smaller than its argument. They can be used to create open intervals, e.g. "1 in ++1 : --2" returns false, and use the same underlying C function as math.nextafter. With variables passed as arguments, the operators do not modify, i.e. increase or decrease, them (see `inc` and `dec` statements instead).

- `put` now supports registers.

- With sets, the standard assignment `setname[key] := value` is now supported. If value is `null`, key is deleted from the set. If value is not `null`, key is added to the set.

- `rawset` can now delete a value from a set by passing the value as the second and `null` as the third argument.

- The new function `numarray.purge` removes a given element from an array.

- `numarray.include` can now insert a single number instead of an array into a numarray.

- The new function `numarray.used` returns the estimated number of bytes consumed by the given array.

- Arrays can now be reduced to zero size by `numarray.resize`.

- When shrinking an array, `numarray.resize` no longer fills slots to be deleted with zeros. This prevents arrays from being modified if memory re-allocation fails.

- The new environ.kernel/readlibbed setting returns a set of all the libraries imported in a session. The equivalent package.readlibbed set may be deprecated in the future. Likewise, environ.kernel/loaded returns the names of all standard libraries available after start-up.

- The `insert` and `delete` statements did not cope well with complex expressions, e.g. "insert 1 into f.g(x)", with function f.g returning a structure. This has been changed.

- With metamethods attached to tables, sequences and registers, the `insert` statement either failed or incorrectly added a value. This has all been fixed.

- The `delete` statement did not support metamethods and thus allowed to purge values from structures protected by a proper read-only metamethod. Now, the delete statement supports metamethods: it passes `null` as the value and the data to be deleted as its key to the __writeindex metamethod. To protect values stored to structures you might define:

  > readonly_mt.__writeindex := proc(t, k, v) is
  >    if unassigned v or assigned rawget(t, k) then
  >       error('cannot delete or modify')
  >    else
  >       rawset(t, k, v)
  >    fi
  > end;

- The `pop`, `rotate`, `duplicate`, and `exchange` statements now issue an error if a structure features a __writeindex metamethod. This prevents read-only structures from being modified.

- The `restart` statement did not delete loaded metatables from the environment. This has been fixed.

- In DOS, `math.tobytes` did not work. The function now just returns `fail` on this operating system.

- Improved the manual.


2.9.0, October 23, 2015

- The new `case of <condition>` syntax flavour is an alternative to the `if` statement, similar to the `switch` statement in the Go programming language. It may improve the readability of code. Example:

  > case
  >    of x < 0 then return -1
  >    of x = 0 then return 0
  >    else return 1
  > esac

- `case` statements can now check whether numbers or characters are included in ranges, e.g.:

  > case value
  >    of -1 to 1 then return true
  >    of 'a' to 'c' then return true
  > esac

- In `case` statements, the arrow token (->) can be used instead of the `then` keyword.

- The new `odd` operator checks for odd numbers (integers).

- The new `mod` statement computes the modulus of its operands and reassigns the result to the first operand.

- The new function `math.isinfinity` checks for positive or negative infinity in one call.

- The new `numarray` package implements arrays of C doubles, 32-bit integers, and unsigned chars and can also read and write binary files.

- `math.tobytes` can convert an integer into a sequence of four bytes if given the optional number 4. Likewise, `math.tonumber` can convert a sequence of four bytes to a number.

- The `environ.kernel/minlong` and `environ.kernel/maxlong` settings have been moved to `debug.system`. Two new constants have been added to the math package: `math.smallest` and `math.largest` represent the smallest and largest positive representable number and - contrary to the debug.system settings - are computed and assigned during start-up.

- In Solaris, eComStation - OS/2, and DOS, the `abs` operator returns a more precise result with complex numbers.

- `environ.kernel` can now return the smallest positive and largest representable Agena number (= C double). More number ranges have been added to `debug.system`.

- Sometimes the `print` funtion printed one and the same table value with a numeric key twice. This has been fixed.

- `calc.linterp`  and `calc.polygen` could possibly crash Agena, this has been fixed.

- In Windows 2000 and earlier, `os.cpuload` crashed Agena. This has been fixed.

- Corrected error message of `llist.purge`.

- The `hashes` package accidently also stored its package table to the registry. This has been changed.


2.8.6, September 29, 2015

- The new function `math.rint` rounds a float to an integer according to the current rounding mode (see environ.kernel/rounding).

- The new function `os.realpath` converts each pathname argument to an absolute pathname, with symbolic links resolved to their actual targets and no . or .. directory entries.

- The new function `os.strerror` returns the text message for the given error code, or the latest error issued by the underlying operating system.

- `os.setenv` now allows to remove environment variables by passing the second argument `null` (as already mentioned in the manual).

- A potential memory leak has been removed from the Windows version of `os.getenv`.

- Agena crashed in the Windows edition of `os.setenv` if the environment variable name or its value exceeded 32,766 characters. This has been fixed.

- The new command-line option `-s` issues a user-defined slogan at start-up.

- The new command-line option `-x` surpresses the initialisation of the main Agena library file lib/library.agn at start-up. Setting this switch may be useful for debugging purposes only, or to save memory. Many functions, however, will not be available if this option is used.

- The `-n` (do not run initialisation file(s)) command-line switch has been ignored by the `restart` statement. This has been fixed.

- The new `environ.kernel` settings `skipinis` and `skipmainlib` control whether Agena initialisation files and the main Agena library are loaded during a `restart`.

- The new `environ.kernel` setting `rounding` sets or retrieves the current rounding mode.

- `environ.kernel`: Agena could crash when reading or changing the `digits` setting. This has been fixed.

- The new C API functions `agn_isvalidindex` and `agn_stackborders` determine valid stack positions. The functions may be useful for debugging purposes, only.


2.8.5, September 01, 2015

- `antilog2` and `antilog10` now automatically use the same function called by the `^` exponentiation operator (i.e. C's pow) if their arguments are out of the bounds +/- 308.2547155599167 and +/- 1024, respectively, instead of simply returning 0 or `infinity`.

- The new `xnor` operator implements the if-and-only-if Boolean operator which return true if both its operands are the same, and `false` otherwise.

- With functions of two arguments called like binary operators: before, only simple names could be used in the call expression; now, indexed names and even esoteric calls to functions returning functions are allowed, as well:

  > add := << x, y -> x + y >>;

  > 1 add 2:       # -> 3

  > t := [add = << x, y -> x + y >>];

  > 1 t.add 2:     # -> 3

  > 1 t['add'] 2:  # -> 3

  > subtract := proc() is return << x, y -> x - y >> end

  > 2 subtract() 2:

- The new function `math.fdima` returns x - y if x >= y, and a default otherwise.

- `os.system` could not detect properly detect Windows 10. This has been fixed.

- `os.unmount` crashed in Sun Solaris 10. This has been fixed.

- The plus library DLL files in the portable Windows version of Agena 2.8.4 had been out-of-date. This has been changed.

- `xor`, `nand`, and `nor` have been tuned a little bit.


2.8.4, August 23, 2015

- The new function `math.quadrant` returns the quadrant of an angle given in radians and returns an integer in [1, 4].

- The new function `math.fdim` returns x - y if its argument x is greater than y, else returns 0.

- The new function `math.isminuszero` checks for minus zero (-0).

- The new function `math.symtrunc` returns its argument if it is in a given range, and a default otherwise.

- In Windows, Solaris, and Debian, `math.signbit`, `math.isordered`, `fma`, `finite`, `log2`, as well as `int`, `frac` and their related functions now use C functions provided by the underlying platform instead of self-defined implementations.

- `math.signbit` now returns correct values on formerly unsupported platforms, instead of just zero.

- Both `antilog10` and `antilog2` have become five times faster by using the respective Cephes Math Library implementations. Please note the new ranges for the arguments: +/- 308.2547155599167 and +/- 1024, respectively. If the argument is out of these bounds, the operators return 0 or `infinity`. For very small arguments, you might use the `^` operator.

- `stats.prange`, `stats.iqmean`, `stats.trimean`, `stats.quartiles`, `stats.fivenum`, `stats.smm`, and `stats.gsmm` now use the introsort algorithm to sort observations instead of traditional recursive Quicksort, to speed up computation times.

- Positive numbers can now be preceded with the `+` token, as asserted in the manual. This will not effect anything.

- `os.cpuload` crashed in Windows 2000 and earlier. This has been fixed.

- `os.symlink` may have crashed in Windows. This has been fixed.

- The `to` statement (not the `for` statement) could corrupt the stack in Agena 2.8.3. This has been fixed.

- Fixed the -0 constant bug when loading or running script files.

- Minor change to `os.system` et al: future Windows releases beyond 10 are now properly handled, provided no Win API changes will be made.

- `os.terminate` is no longer available in Mac OS X since the Carbon framework formerly being linked caused memory leaks in Agena.

- Improved the scheme files and parts of the Primer and Reference.


2.8.3, July 29, 2015

- A new flavour of the `with` statement is available: with <name> do: within the body of this statement, the table <name> can be referenced by just an underscore. It also allows to actively change values in the table <name>. Example:

  > zips := [duedo = 4000, bonn = 5300]

  > with zips do
  >    print(_.bonn);
  >    _.bonn := 53111
  > od
  5300

  > zips:
  [bonn ~ 53111, duedo ~ 4000]

  This is syntactic sugar for:

  > scope
  >    local _ := zips;
  >    print(_.bonn);
  >    _.bonn := 53111
  > epocs

  All flavours of the `with` statement now allow its block to be surrounded by the `do` and `od` - instead of the `scope` and `epocs` keywords - just as allowed by Modula-2.

- Numeric `for` loops with stop value 0 (zero) and a fractional step size did not stop at 0 but one step before. This has been fixed. Optimised internals of numeric for loops, as well.

- The new function `rot` rotates a two-dimensional vector, represented by a (complex) number, through a given angel.

- The new function `everyth` returns every given k-th element of a structure and returns a new structure.

- `stats.iqr` has become six times faster if the distribution is unsorted.

- `tanc` has become twelve percent faster.

- The new function `stats.qcd` determines the quartile coefficient of dispersion.

- `math.dms` returned imprecise results. This has been fixed. The function has also become 25 percent faster.

- `math.random` behaved poorly if called with no arguments. This has been fixed.


2.8.2, July 14, 2015

- The new function `calc.ibeta` implements the incomplete beta integral.

- The new function `calc.invibeta` evaluates the inverse of the incomplete beta integral.

- `stats.acf` now optionally accepts a pre-computed arithmetic mean and the sum of all values in a distribution. This option reduces computation time to a third.

- The new `tanc` function returns tan(x)/x for real or complex x <> 0, and 1 for x = 0.

- The new `stats.invnormald` implements the inverse Normal distribution function.

- The arguments of `calc.igamma` and `calc.igammac` have been swapped to comply with related integral functions.

- `stats.gammadc` evaluated the Gamma distribution function instead of the complemented one. This has been fixed.

- `calc.polygen` does not accept more than 256 arguments any longer for this could corrupt an internal stack.

- The following functions now properly free internal memory in case of errors: `stats.acf`, `stats.acv`, `stats.prange`, `stats.neighbours`, `stats.nearby`, `calc.interp`, `calc.newtoncoeffs`.


2.8.1, July 07, 2015

- `stats.trimean` now optionally accepts a given percentile rank determining the lower and upper margin.

- The new function `stats.fivenum` returns the five-number summary of a distribution, plus the arithmetic mean.

- The new functions `calc.Ai` and `calc.Bi` compute the Airy wave functions and their respective first derivatives.

- The new `calc.zeta` function computes the Riemann zeta function.

- The new `calc.polylog` function computes the polylogarithm of a given order and point in the real domain.

- The new function `calc.En` computes the exponential integral int(exp(-x*t)/t^n, t = 1 .. infinity).

- The new `calc.igamma` evaluates the incomplete gamma integral.

- The new `calc.igammac` evaluates the complemented incomplete gamma integral.

- The new `stats.gammad` Gamma distribution function returns the integral from zero to x of the gamma probability density function.

- The new `stats.gammadc` complemented Gamma distribution function returns the integral from x to infinity of the gamma probability density function.

- `calc.polygen` has become twenty times faster by using the same technique to access internal data as `calc.linterp` has done. The former bug that wrong results have been returned when passing more than 254 coefficients thus has also implicitely been fixed.

- The index of the Primer and Reference, and the Crash Course have been improved, as well.


2.8.0, June 23, 2015

- The new `with` statement unpacks values from a table, declares them local and then is able to access them in a block. The new names are variables on their own and do not refer to the indexed values in the table:

  zips := ['duedo' ~ 40210:40629, 'bonn' ~ 53111:53229, 'cologne' ~ 50667:51149];

  with duedo, bonn in zips scope
     print(duedo, bonn, cologne);
     duedo := null  # zips.duedo is not changed
  epocs;

  -> 40210:40629     53111:53229     null

  print(zips.duedo)

  -> 40210:40629

- The former `with` function has been renamed to `initialise`, but there are no changes to the `import` statement.

- The assignment statement has been extended to unpack values from a table, the `local` statement is supported, as well. Thus,

  duedo, bonn in zips

  is equal to

  (local) duedo, bonn := zips.duedo, zips.bonn

  Both extensions are based on a Lua 5.1 power patch written by Peter Shook.

- Record fields in tables can now be defined more easily by using the equals sign separating the - unquoted - record field name and the corresponding value. Thus,

  zips := ['duedo' ~ 40210:40629, 'bonn' ~ 53111:53229, 'cologne' ~ 50667:51149];

  is equal to

  zips := [duedo = 40210:40629, bonn = 53111:53229, cologne = 50667:51149];

  The old way to define record fields using tildes is still supported. Both styles can be mixed:

  zips := ['duedo' ~ 40210:40629, bonn = 53111:53229, cologne = 50667:51149];

  Please note that if you want to enter the result of a Boolean equality check into a table, use the `==` token instead of the `=` sign.

- `os.date` can return the Julian date if given the new '*j' format, or the Lotus 1-2-3 Serial Date if given the new '*l' format.

- The new function `os.lsd` computes the Lotus 1-2-3 Serial Date, which is also used in Excel (known there as `Excel Serial Date`), where January 01, 1900 is day 1. It returns a number. (Day 60 = non-existent February 29, 1900 is properly handled.)

- `os.now` also returns the Lotus 1-2-3 Serial Date with the 'lsd' key.

- `xbase.writedate` now accepts both strings and numbers as the date to be written to a dBASE file.

- `os.time` did not check for the existence of a given date and returned miraculous results with invalid dates. This has been fixed.

- Remember tables sometimes failed returning a cached result if too many entries have been stored to them. This bug has been fixed.

- The initialisation routine that searches for the main Agena library has become stricter to avoid unneccessary problems in UNIX.

- The `values` operator has been fixed to avoid problems with strict equality checks (`==` operator).

- On the interactive level, i.e. the Agena prompt, diacritics defined in the ISO 8859/1 Latin-1 codepage can now be part of names. Please note that within scripts stored to a file, diacratics still are not allowed within names.

- Deprecated `stats`, `linalg`, and `xbase` functions now are correctly initialised in the compat.agn compatibility file.


2.7.0, June 12, 2015

- Formerly, only one expected type of return could be defined for procedures, now you can specify up to four basic types by putting them in curly brackets, e.g.:

  > f := proc(x) :: {number, complex} is return 'a' end

  > f()
  In stdin at line 1:
    Error in `return`: unexpected type string in return.

- There has been a subtle change on how Agena treats the last iteration value of numeric for loops if such loops are executed _on the interactive level_, i.e. not within a function: if the loop is part of a block, then the last iteration value now is accessible only in this `scope` block, but not in outer blocks:

  > scope
  >    for i to 10 do od;
  >    print(i)
  > epocs
  11

  > print(i)
  null


  > for i to 10 do od

  > print(i)
  11

  This fix has been applied to comply with the description in the Primer and Reference, so that the behaviour now is the same both with functions and the interactive level.

- If you assign a procedure to `environ.onexit`, then when quittung Agena with `bye`, `os.exit`, or CTRL-C, this procedure will be called before exiting the interpreter. The procedure is also called when issuing the `restart` statement. Thus you may conduct file system clean-up, pass back information if Agena is being piped, save variables to disk, or anything else.

- Remember tables can now already be assigned during procedure definition: just put the statement `feature reminisce` right after the `is` keyword. You may thus save an explicit call to `rtable.rinit` after the procedure has been defined. Thus, also anonymous procedures support remember tables now.

- `os.system` can now directly detect Windows 10 and Windows 10 Server. The function also now correctly acknowledges Windows Server 2012 R2.

- The `tar` package (UNIX tape archive reader) has become a part of the Agena distribution.

- The new function `gdi.lineplot` plots lines between 2-dimensional points. It is just an easy-to-use wrapper around `gdi.pointplot` with the connect = true option.

- `gdi.pointplot` with the connect = true option now supports the `thickness` and `linestyle` options for lines.

- `gdi.setline`, `gdi.setcircle`, `gdi.setarc`, `gdi.setellipse`, `gdi.setrectangle`, `gdi.settriangle` now accept a thickness value as the very last argument. By default, it is 1 (= normal).

- The new function `math.decompose` splits an integer of any base into its digits.

- `math.ndigits` has been ported to C, and processes non-positive values, as well. It has not necessarily become faster.

- The new C API function `agn_checkposint` checks whether a value is a positive integer.

- The new C macro `lua_regsetinumber` sets an Agena number to the given index of a register.

- The scheme files have been improved.

- `environ.attrib` now checks whether a register has been assigned a user-defined type.


2.6.1, May 27, 2015

- A slightly improved version of the tar package including better documentation has been uploaded:

  http://sourceforge.net/projects/agena/files/Packages/tar.agn/download.

- Chapter 6.24 of the Primer and Reference on object-oriented programming has been extended:

  http://sourceforge.net/projects/agena/files/Manuals/agena.pdf/download.


2.6.1, May 25, 2015

- `environ.kernel` returns all current kernel settings when called with no argument.

- In Windows, eComStation, and UNIX incl. Mac OS X `os.memstate`, now also returns the page size in bytes. If the memory status could not be determined in eComStation, then `os.memstate` now returns a table with all the values set to `undefined` instead of just returng `fail`.

- `os.fattrib` now accepts a number (representing an octal value, like the argument to the UNIX chmod command)to change the mode of a file, so for example UNIX `chmod 755 file` = Agena `os.fattrib(file, 0o755)`.

- `strings.tochars` now also accepts a sequence of numbers (unsigned chars) to be converted to a string.

- The new function `binio.lines` creates an iterator that returns a line in a file step-by-step.

- The new function `binio.isfdesc` checks whether a file handle is valid.

- `binio.rewind` now accepts an optional position. If given, the function resets the file pointer to this position relative to the beginning of the file.

- The new function `math.tobytes` returns a sequence with all the bytes of a number in Little Endian order.

- The new function `math.tonumber` takes a sequence of numbers representing bytes and converts it into an Agena number.

- The error messages of various I/O functions in the io and binio packages now give more detail.

- `strings.tochars` has been patched to cope with embedded zeros.

- `os.fattrib` could not change the date and time of files. This has been fixed. Also, in UNIX, `os.settime` issued errors - this has been fixed, too.

- Corrected error messages of `os.datetosecs`.

- The `ignorespaces` default (formerly true) has been changed: now `utils.readcsv` does not delete spaces in 1fields any longer. Also, if fields are enclosed in double qoutes, the function also automatically deletes these quotes. You can set the new `removedoublequotes = false` option to avoid this.

- Agena for Windows now runs around 10 % faster, as it has been compiled with MinGW/GCC 4.5.2 instead of 4.6.2.

- Two new packages have been uploaded to http://sourceforge.net/projects/agena/files/Packages:

  - a package to list, read, and extract individual files from a UNIX tar archive, and
  - a package called `Agner` with phone line availability formulaes developed by Danish Scientist Agner Krarup Erlang.

  Please see the respective Agena source files for the documentation.


2.6.0, May 10/11, 2015

- You can now `define` your own binary operators just by using functions of two arguments,

  > plus := proc(x, y) is return x + y end;

  the following way:

  > 1 plus 2:
  3

  When using a function as a binary operator, it has always the highest precedence.

- Agena now supports OOP-style methods. To define a method for a table object,

  > account := ['balance' ~ 0]

  enter something like (please note the two `@` tokens):

  > proc account@@deposit(x) is
  >    inc self.balance, x;
  >    return self.balance
  > end

  The name `self` always refers to the table object. Call the method using two `@` characters:

  > account@@deposit(100)

  Query the object.

  > account:
  [balance ~ 100, deposit ~ procedure(016D6820)]

  For more information, check http://www.lua.org/pil/16.html.

- Added `divs.asine`, `divs.acosine`, `divs.asecant`, `divs.hsine`, `divs.hcosine`, `divs.htangent` and the proper metamethods for the arcsin, arccos, arcsec, sinh, cosh, and tanh operators, to the `divs` package. The `recip` and `~<>` operators now also support fractions.

- The new `<<<<` and `>>>>` operators return the number x (left operand) rotated a given amount of bits (right operand) to the left or the right.

- `inc`, `dec`, `mul`, and `div` accepted function calls as the first argument. This has been fixed.

- The `linalg` package now supports the division operator for vectors, and the `~<>` operator for both vectors and matrices.

- Some `linalg` functions have been marginally improved with regards to runtime behaviour.

- The list of available metamethods in Appendix A2 of the Primer and Reference has been extended.

- The `shift` operator has been removed. Please use the `<<<` operator for left-shift operations, and `>>>` for right-shifts. An alias, however, has been provided for backward compatibility.

- Extended the scheme files.

- The undocumented reserved words `algform` and `kthmoment` have been removed.

- The agena-2.6.0-win32-gcc452* installers feature a Windows version of Agena that runs around ten percent faster.


2.5.4, May 06, 2015

- Due to a suggestion by a forum user, you may now include double quotes in a string delimited by single quotes without using a backslash. The same applies to single quotes embedded in a string delimited by double quotes, e.g. "'agena'" is now a valid string.

- `inc`, `dec`, `mul`, and `div` accepted function calls as the first argument. This has been fixed.

- The `typeof` operator could not determine user-defined types for userdata. This has been fixed.

- The `cls` and `bye` statements can now be included in chunks (e.g. loop or procedure bodies), there are no longer syntax errors. Thus, os.execute('/usr/bin/clear') or os.exit() statements in chunks are no longer needed.

- Two variables in `gdi.plotfn` had been declared global. This has been fixed.

- The Linux build scripts have been corrected.


2.5.3, April 26, 2015

- A non-yum based WarpIN installer of Agena for eComStation has been uploaded due to a kind hint from Serenity Systems, Italy.


2.5.3, April 12, 2015

- Due to an idea from Serbia, a new type check metamethod '__oftype' has been introduced for all structures and for userdata. If a type check metamethod exists for such an object, then it is run with calls to the :: and :- operators. If the object does not satisfy the criteria defined in the metamethod, then Agena returns `false`.

This also applies to function calls: if the check fails, Agena issues an error, e.g.:

  > mt := [ '__oftype' ~ proc(x) is return type(x) = pair and left(x) :: number and right(x) :: number end ];

  > duo := 1:2;

  > setmetatable(duo, mt);

  > f := proc(x :: pair) is return x end;

  > f(duo):
  1:2

  > duo := 'a':'b';

  > setmetatable(duo, mt);

  > f(duo):
  In stdin:
    argument #1 does not satisfy type check metamethod

  '__oftype' metamethods can also check results to procedure calls if an expected result type is specified in a procedure definition (e.g. `f := proc(x :: pair) :: pair is return x end;`).

- User-defined types can now also be set to registers.

- `stats.sumdataln` returned incorrect results. This has been fixed.

- `stats.gmean` has been rewritten using logarithmic sums and now is twice as fast.

- The new function `stats.meanvar` returns both the artithmetic mean and the variance of a distribution.

- The new function `stats.standardise` normalises a distribution so that they become comparable.

- The new function `stats.covar` computes the covariance of two distributions.

- The '__sin' metamethod has been removed.


2.5.2, April 07, 2015

- `gdi.plotfn` now can also plot graphs of high slope functions correctly thanks to a contribution by a Serbian user.

- The following binary operators are now at least thrice as fast: `xor`, `atendof`, `&&`, `||`, `^^`, `~~`, `<<<`, `>>>`, `::`, `:-`, `*%`, `/%`, `+%`, `-%`, `@`, and `$`.

- The new `~<>` binary operator checks whether two numbers or complex numbers are not approximately equal, i.e. it is the negation of the `~=` operator.

- The new `nand` and `nor` operators are the negations of `and` and `or`, respectively.

- The new function `stats.cauchy` returns the probability density function 1/(Pi*b*(1+((x-a)/b)^2)), of the Cauchy distribution.

- The new function `stats.sumdataln` sums up the natural logarithms of the observations in a distribution.

- The new functions `stats.durbinwatson` tests the autocorrelation in the residuals from a linear regression.

- The functions `stats.sum` and `stats.sumdata` have been merged, i.e. `sumdata` now also accepts a data selection function. `stats.sum` has been deprecated, but an alias is provided for backward-compatibility.

- Most statistics functions now ignore `infinity` and `undefined` if present in tables. With sequences, the functions have already skipped these non-finite values.


2.5.1, March 30, 2015

- Agena allowed to start a string with a single quote and finish it with a double quote, and vice versa. This has been changed: string delimiters must now either be single or double quotes.

- Besides including one or more single quotes within a number to group digits, also underscores (like in Ada) can be used. Underscores and single quotes, however, cannot be mixed.

- Functions alternatively can be defined using the Algol-like syntax: proc <name>(<arguments>) is <statements> end, which is equal to <name> := proc(<arguments>) is <statements> end.

- The new `cis` operator computes the complex exponential function exp(I*x) = cos(x) + I*sin(x) for any real or complex argument x and is around 25 % faster than the equivalent expression exp(I*x).

- If any Boolean is given as the last argument to `math.random`, then the sequence of random numbers should be arbitrary.

- The new function `stats.chisquare` returns the probability density function
  x^((nu-2)/2) * exp(-x/2)/2^(nu/2)/gamma(nu/2), of the chisquare distribution.

- The new function `stats.fratio` returns the probability density function
     gamma( (nu1+nu2)/2)/gamma(nu1/2)/gamma(nu2/2)*(nu1/nu2)^(nu1/2)*
     x^((nu1-2)/2) / ( 1+ (nu1/nu2)*x) ^ ((nu1+nu2)/2),
  of Fisher's F distribution.

- The new function `stats.normald` returns the the probability density function
  exp( -(x-mu)^2/2/sigma^2 ) / sqrt(2*Pi*sigma^2), of the normal distribution.

- The new `stats.studentst` function returns the probability density function
     gamma( (nu+1)/2 )/gamma(nu/2)/sqrt(nu*Pi)/(1+t^2/nu)^((nu+1)/2),
  of the Student's t-distribution.

- `stats.skewness` can now compute the sample skewness of a distribution by passing an optional argument.

- The new function `stats.kurtosis` determines the kurtosis (peakedness) of symmetric and unimodal distributions.

- `skycrane.dice` now creates truely random numbers.

- Agena cow correctly returns `undefined` with the numeric expressions 0^0 and 0**0. For the sake of speed of the exponentiation operators, it still incorrectly returns 1 instead of `undefined` for infinity^0.


2.5.0, March 23, 2015

- `utils.writecsv` can now also write a header and enclose each value with a given string. Also, any option can now be given in the form `option = value`. The old way of sequentially passing options is still supported.

- `stats.gmean` has been rewritten for it returned wrong values with distributions containing very small or very large values provoking underflows or overflows. Also, the function no longer returns complex values if the sign of the product of all observations is negative (returning `undefined` instead), and issues an error if the distribution contains complex values for it now computes in the real domain, only. The function has become twice as fast.

- `<<<`, and `>>>`, `stats.skewness`, and `fractals.dragon` have been tuned a little bit.

- `unpack` with a given register may have crashed Agena if the interpreter had not been compiled with GCC.

- The `shift`, `<<<`, and `>>>` bitshift operators could crash Agena when called with non-numbers. This has been fixed.

- Registers had not been correctly garbage-collected, leading to out-of-memory errors with large registers. This has been fixed.

- The test suite now properly cleans up the namespace.

- The manual and the scheme files have been corrected.

- The following deprecated operators and functions have now been removed, the following list includes their substitutes right after the `->` token. Except is/si and ->, all of these functions can be used by running the `/lib/compat.agn' file.
  -> mapping -> @ operator
  bags.attribs -> bags.attrib
  calc.newton -> calc.interp
  clock.dectotm -> clock.totm
  clock.tmtodec -> clock.todec
  gethigh -> math.gethigh
  getlow -> math.getlow
  io.flush -> io.sync
  is and si -> if and fi
  linalg.backsubs -> linalg.gsolve
  linalg.meq -> linalg.maeq
  linalg.veq -> linalg.vaeq
  math.log2exp -> ilog2
  math.tworaised -> antilog2
  notisnegint -> isnonnegint
  notisposint -> isnonposint
  optnnonneg -> optnnonnegative;
  registers.gettop -> size
  sethigh -> math.sethigh
  setlow -> math.setlow
  stats.kosumdata -> stats.sumdata
  stats.ssd -> stats.sd
  utils.cdate -> astro.cdate
  utils.decode64 -> utils.decodeb64
  utils.isleapyear -> astro.isleapyear
  varprep -> qmdev
  xbase.field -> xbase.readdbf
  xbase.isVoid -> xbase.isvoid


2.4.5, March 10, 2015

- Two new modifiers for `strings.format`, `printf`, and related functions have been introduced to prevent quarrels with numerical functions that can return non-numbers in case of errors: 'D' prints an integer if the argument is a number, and the C double representation of undefined otherwise. 'F' likewise either prints a float, or the C double pendant of undefined.

- the q modifier to `strings.format`, `printf`, etc. now works as described in the manual. The new Maple-like a modifier works like the q modifier but does not include trailing and leading double quotes.

- The new function `strings.diffs` counts the differences between two strings: substitutions, transpositions, deletions, and insertions. Besides returning the number of differences, it can also return the types of differences. The function is thrice as fast as `strings.dleven`, but may count differently.

- The name of the former `varprep` operator has been changed to `qmdev`. An alias has been provided for backward-compatibility (put varprep's argument in brackets).

- The order of arguments to `stats.sd` has been changed:
  a) if any third argument is given (formerly second argument), the coefficient of variation is computed.
  b) if the optional second argument evaluates to `true`, the (unbiased) sample standard deviation is returned, otherwise the population standard deviation is computed.

- `stats.var` has been extended to also compute the (unbiased) sample variance or the index of dispersion.

- `stats.moment` can now also compute sample moments by passing `true` as the new fourth argument.

- `stats.trimean` returned some sort of garbage if the distribution contained less than two observations. This has been fixed.

- `stats.ssd` has been deprecated, please use `stats.sd(<distribution>, true)` instead.

- Improved error handling of `stats.checkcoordinate`.

- The former `gethigh`, `getlow`, `sethigh`, and `setlow` operators are now functions moved into the math library, i.e. the new names are `math.gethigh`, etc. Aliases have been provided for backward compatibility.

- Corrected the scheme files.


2.4.4, March 04, 2015

- The new function `descend` recursively descends into a deeply nested structure and returns all elements that satisfy a given condition.

- `recurse` now accepts multivariate functions.

- `stats.moment` now uses the Kahan-Babuška method to prevent round-off errors.

- `stats.kosumdata` has been renamed to `stats.sumdata`. For backward compatibility, an alias has been provided.

- Corrected error messages of `stats.acv`. Improved error messages in some other stats functions in case of memory allocation failures.

- `stats.iqmean`, `stats.trimean` and `stats.quartile` had to be patched once again to avoid crashes with distributions containing the value `undefined`.


2.4.3, February 18, 2015

- `stats.acf`, `stats.acv`, `stats.ad, `stats.amean`, `stats.ema`, `stats.gini`, `stats.gsm`, `stats.iqmean`, `stats.meanmed`, `stats.sma`, `stats.kosum`, and `stats.zscore` and now use the Kahan-Babushka instead of the Kahan-Ozawa summation algorithm, and thus have become up to 20 percent faster now. Kahan-Babuška adds a corrective value to the pre-computed result after the last iteration, whereas Kahan and Kahan-Ozawa adds it in each iteration.

- `stats.prange`, `stats.iqmean`, `stats.trimean`, `stats.quartiles` crashed Agena if an observation contained the value `undefined`. `stats.prange` sometimes also crashed Agena due to other reasons. This has all been fixed.

- The `sadd` operator now uses Kahan-Babushka summation to prevent round-off errors.


2.4.2, February 15, 2015

- The new operator `sinc` implements the unnormalised cardinal sine function, i.e. sin(x)/x.

- The new function `rect` implements the rectangular function.

- The new `linalg.reshape` function restructures a matrix to new dimensions and works like the corresponding Octave function of the same name.

- The new function `math.signbit` checks whether its numeric argument has its sign bit set.

- The new function `math.eps` returns the relative spacing between its numeric argument and its adjacent number in the machine’s floating point system.

- The new function `stats.iqmean` returns the arithmetic mean of the interquartile range of a distribution.

- The new function `stats.trimean` (not to be confused with `stats.trimmean`) returns the trimean and the median of a distribution to check whether it is biased.

- Numeric `for` loops with fractional step sizes can now alternatively use the enhanced Kahan-Ozawa summation algorithm instead of the default original Kahan one, by the setting: environ.kernel(kahanozawa = true).

- The `copy` operator can now explicitely extract the array or the hash part of a table by passing the new optional second argument 'array' or 'hash'.

- `stats.quartiles` has been ported to C and is at least twice as fast now. Furthermore, it no longer assumes a sorted distribution. Also, the function no longer issues an error if the distribution contains less than two observations, but just returns `fail`.

- The new `varprep` operator pre-computes a `variance sum` which must be divided either by the number of elements n in a distribution to calculate its population variance, or by n - 1 to compute its sample variance.

- `stats.var` and `stats.sd` returned wrong results especially if the variance is close to the arithmetic mean of a distribution; the results sometimes were even negative or had imprecise accuracy. This has been changed by using an algorithm published by Donald Knuth / B. P. Welford, which is much more accurate - to the disadvantage of speed.

- All statistics functions that determine or work with quartiles now determine the first and third quartile according to the NIST rule which has always been used by `stats.quartiles` (which had been wrongly documented): position of Q1 := entier(1/4*(n + 1)), position of Q3 := entier(3/4*(n + 1)), where n is the number of observations in a distribution.

- `stats.isany` and `stats.isall` crashed with sequences. This has been changed.

- Changed the `xbase` sources to prevent compiler warnings.

- This release has been Valgrind-checked on x86 Linux and Mac to ensure there are no memory leaks.


2.4.1a, February 03, 2015

- The `lower` and `upper` operators have been tuned by around 6 %.

- Applied changes to some source files to reduce compilation problems with GCC >= 4.6.

- The Windows version has become around 5 % faster (measured by comparing test suite runs) by recompiling the sources with GCC 4.6.2 and the -O3 switch.

- The eCS, Solaris, Windows, Linux, Mac OS X, and DOS versions have been recompiled.

- This release has been Valgrind-checked on x86 Linux and Mac to ensure there are no memory leaks.


2.4.1, February 01, 2015

- The new operators `antilog2` and `antilog10` raise 2 and 10 to the power of the given arguments, respectively. Depending on the support of the underlying C functions exp2 and exp10, they are around 30 % faster than the corresponding a^x operations.

- The new `signum` operator returns 1 if its real argument is non-negative, and -1 otherwise. For complex argument z, it returns z/|z|.

- The new function `math.koadd` adds two numbers using Kahan-Ozawa round-off error prevention.

- The new function `stats.peaks` uses an alternative algorithm to determine peaks and valleys in time-series.

- The new function `stats.md` returns the median deviation in a distribution.

- The new functions `stats.isany` and `stats.isall` check whether distributions contains non-zero elements.

- `stats.extrema` now is twice as fast than its former version.

- The new function `stats.checkcoordinate` checks whether its argument is a pair consisting of two numbers.

- The new function `optnumber` checks whether its argument is a number. If its argument is `null`, it returns a default number.

- The new function `optpositive` checks whether its argument is a positive number. If its argument is `null`, it returns a default positive number. Likewise, `optposint` checks for positive integers.

- The new function `optnonnegative` checks whether its argument is a non-negative number; if its argument is `null`, it returns a default non-negative number. Likewise, `optnonnegint` checks for positive integers.

- The new function `optboolean` checks whether its argument is a Boolean; if its argument is `null`, it returns a default Boolean.

- The new function `optstring` checks whether its argument is a string; if its argument is `null`, it returns a default string.

- The new function `optcomplex` checks whether its argument is a (complex) number. If its argument is `null`, it returns a default (complex) number.

- On Windows, `os.drivestat` returns further information on a drive: total number of clusters, number of free clusters, sectors per cluster, and bytes per sector.

- `os.unmount` might have crashed in Solaris. This has been fixed.

- `fma`, `isordered`, `trunc`, `log2`, and `isfinite` did not use the underlying C functions if available on the respective platform. Instead they used alternative definitions. This has been fixed.

- Minor non-functional changes to the standard library file `lib/library.agn`.

- The Agena Quick Reference is now edited with LibreOffice 3.4 instead of OpenOffice 4.1 due to issues with the latter application.

- This release has been Valgrind-checked on x86 Linux and Mac to ensure there are no memory leaks.


2.4.0, January 11, 2015

The following measures have been taken to totally hide data in registers:

- The `size` operator no longer returns the total size of a register regardless of the setting of the current top pointer. Instead, it simply returns the position of the top pointer at the time of its call. Since now there no longer is a way to determine the actual size of a register, you have to store its original size yourself. This measure also simplifies programming procedures that operate on registers, sequences, and tables.

- Agena formerly allowed to assign values above the current top of a register. This bug has been fixed.

- Error messages no longer indicate whether data has been hidden (obmission of the `current` word).


Other changes are:

- Both indices and and index ranges can now be mixed, e.g. a[2 to 3, 2] now is a valid expression.

- The following functions now also support registers: `replace`, `join`, `qsadd`, `sadd`, and `smul`, `bintersect`, `bminus`, `bisequal`, `augment`, `columns`, and `utils.writecsv`.

- The new function `os.iseCS` determines whether Agena is running on eComStation.

- The new function `os.islinux` determines whether Agena is running on Linux.

- The new function `os.unmount` unmounts filesystems in the UNIX-based editions.

- The new function `getbits` returns all 32 bits in an integer; the new function `setbits` sets the given bits to an integer.

- `qsadd` now uses fused-multiply add to compute more accurate results.

- The new function `os.terminate` halts, reboots, sleeps, or hibernates the system. It can also logoff or lock the current user session. It is available in the Windows, eCS, and Mac OS X editions.

- The new function `os.monitor` puts a monitor on and off, or on stand-by. It is available in the Windows and Linux editions, only.

- The new function `os.mouse` returns information on the number of mouse buttons, vertical and horizontal scroll wheels, a flag on whether the left and right buttons have been swapped, and the speed and threshold. It is available in the Windows edition, only.

- The new function `os.vga` returns information on the current screen resolution, the vertical refresh rate, the colour depth, and the number of monitors attached. It is available in the Windows and eCS editions, only. `os.screensize` is now available in eComStation, as well.

- The new function `os.hasnetwork` checks whether a network is currently present. It is available in the Windows edition, only.

- The new function `os.isdocked` returns the status of the docking mode. It is only available in the Windows edition of Agena.

- `os.cdrom` is now available in the Linux edition.

- `os.uptime` is now available in the Mac OS X edition.

- The new C API macro `lua_rawsetstringpairnumbers` sets a pair of two numbers to a table.

- This release has been Valgrind-checked on x86 Linux and Mac to ensure there are no memory leaks.


Bug fixes are:

- `fma`, `math.tworaised`, and `math.isordered` did not use the underlying C functions when available on the respective platforms, this has been fixed.

- Corrected error messages of some operators (missing reference to registers).


2.3.4, December 28, 2014

- If in a procedure definition a check of the return type has been given, but the procedure had not returned anything, Agena did not complain. Now it does. Try this before and after: f := proc() :: set is end; f(); The error messages have been improved, if the return type did not match the expected one, as well.

- The new function `strings.iscontrol` checks whether a string consists entirely of control characters such as backspaces, newlines, etc.

- The new function `strings.isprintable` tests whether all the characters in a string can be printed at the console.

- The new function `strings.ishex` checks whether a string represents a hexadecimal number.

- `strings.isblank` now can alternatively check for all existing blanks.

- `strings.glob` now can compare strings case-insensitively if the new Boolean option `true` is being passed.

- `math.tworaised` always returned `fail` with real arguments in obviously all versions of Agena. This has been fixed. The DOS and Windows editions use the underlying C function exp2 which is very fast - whereas all other editions use a pow-based version if either exp2 is missing (e.g. Solaris or Linux) or is too inaccurate (eCS).

- `ilog2` now also processes complex and fractional arguments, using the algorithm of the now defunct procedure `math.log2exp`. An alias to the latter has been provided for backward compatibility.

- `io.anykey` and `io.getkey` are now available in eComStation - OS/2.

- In eCS, `os.battery` internally did not close a handle after querying the power state. This has been changed.

- `os.uptime` now is also available in the Solaris version of Agena.

- `io.anykey` is now available in the DOS version.

- In the DOS version, `io.getkey` did not work and also corrupted stdin. This has been fixed.

- `strings.isalphaspace`, `strings.isloweralpha`, `strings.isupperalpha` returned wrong results in one case (ASCII #213 and 173 with codepage 850). This has been fixed.

- `strings.ismagic` returned a wrong results. This has been changed.

- `strings.isspec`, `strings.isalphaspec`, `strings.isloweralpha`, `strings.isupperalpha`, `strings.ismagic`, `strings.isalpha`, `strings.isalphaspace`, and `strings.isalphanumeric` have been tuned by around two percent.

- The schema files have been updated.

- The test suite has been improved.


2.3.3, December 05, 2014

- A `when` condition can now be added to a `return` statement that does not return any value including `null`.

- The new function `ilog10` returns the integral part of the logarithm of a value to the base 10.

- The new function `math.ceilpow2` rounds an integer up to the next highest power of 2.

- The new function `math.morton` interleaves the bits of two integers.

- The new function `math.expminusone` returns a value equivalent to exp(x) - 1. It is computed in a way that is accurate even if x is near 0.

- The new function `math.lnplusone` returns a value equivalent to ln(x - 1). It is computed in a way that is accurate even if x is near 1.

- The new function `math.log2exp` extracts the exponent of a number and returns entier(log2(x)), but is much faster.

- The new function `math.isordered` checks whether at least one of two numbers is `undefined`.

- `math.tworaised` returns 2^x, with x of type number or complex, but is much faster than the exponentiation operators ^ and **.

- The new function `math.copysign` returns a number with the magnitude of x and the sign of y.

- The new function `math.arccosh` determines the inverse hyperbolic cosine in the real domain and is around thrice as fast as the universal `arccosh` function.

- The new function `os.cdrom` opens and closes the tray of an optical disk drive. It can also eject any other removable drive. It is available in the Windows edition of Agena only.

- The new function `os.isremovable` checks whether a given drive is removable. It is available in the Windows edition of Agena only. `os.isvaliddrive` determines whether a drive is connected to the file system.

- The new function `os.ismounted` checks whether a given drive has been mounted. It is available in the Windows edition of Agena only.

- The new function `os.isvaliddrive` checks whether a drive has been mounted to the file system. It is available in the eCS and Windows editions of Agena only.

- The new function `os.curdrive` returns the letter of the current drive in eCS, DOS, and Windows.

- `ilog2` and `math.ceillog2` now return `undefined` instead of issuing an error if given a non-positive integer.

- `arccosh` returned a complex result with real argument zero. This has been fixed.

- `skycrane.scribe` did not correctly print elements when being passed more than one structure. This has been changed.

- `gdi.plotfn` issued an error if one of the `functions` to be plotted (in the first argument) was actually `null`. Now the function simply ignores these cases.

- There may have been problems on Mac OS X when importing the `gdi` package due to incorrect file access rights. This has been fixed.

- OS X returned a warning message when running `os.freemem`. This has been changed.

- `os.cpuinfo` has been fixed in the Linux editions of Agena.

- The `setbit`, `arccosh`, `arcsch` functions have been tweaked a little bit.

- The test suite did not feature the lew_nist.agb file. This has been corrected.


2.3.2, November 26, 2014

- The new function `os.uptime` returns the number of seconds a system has been running. It is available in eComStation - OS/2, Windows, and Linux.

- On eComStation, `os.memstate` now also returns the maximum number of bytes available for a process ('maxprmem' key), and the maximum number of shareable bytes available ('maxshmem' key).

- On Windows, `os.memstate` now also returns information on the current committed memory limit for the current process and the maximum amount of memory the current process can commit ('freepagefile' and 'totalpagefile' keys, respectively).

- `math.ceillog2` does not accept zero as an argument any longer.

- `ilog2` did not work, now it does.

- The `import`/`readlib` functionality returned misleading information in eCS - OS/2 and DOS if a `plus` package exists (compiled into the agena.exe binary), but a corresponding library agn file has not been found. This has been fixed.

- Version information compiled into the Agena Windows binary has been corrected.

- This release has been Valgrind-checked on x86 Linux and Mac to ensure there are no memory leaks.


2.3.1, November 23, 2014

- The new `hashes` package provides functions to compute string hashes.

- The new function `ilog2` returns the integral part of the logarithm of its argument to the base 2. It is 25 % faster than the int/log2 equivalent.

- The new `environ.kernel/maxulong` query returns the maximum value storable to C's unsigned long ints on the respective platform.

- The `reg` operator, when passed items, unvoluntarily sometimes returned a register with `null`s at its top. This has been fixed.

- Three functions have been added to the `math` package that are used in the Lua/Agena parser <-> virtual machine communication to pass numbers: `math.inttofpb`, `math.fpbtoint`, and `math.ceillog2`. For the algorithms used, please see the lmathlib.c and lobject.c file.

- The `@` and '$' operators sometimes did not correctly return results due to stack corruption. This has been fixed.

- Very minor tweaking to functions creating structures.

- The Windows Portable installation ZIP file now contains up-to-date C libraries, the DOS Portable installation ZIP file contains up-to-date versions of the bags and linalg libaries. The source file distribution also contains all library and C source files and various other files again.

- This release has been Valgrind-checked on x86 Linux and Mac to ensure there are no memory leaks.


2.3.0, November 08, 2014

- The new `<<<` operator shifts bits to the left (multiplication with 2), the new `>>>` operator to the right (division by 2). The `shift` operator performing bit shifts to either direction is and will still be maintained.

- The new functions `stats.dbscan` discovers clusters of n-dimensional observations with noise using a density-based algorithm, i.e. DBSCAN.

- The new function `stats.neighbours` returns all n-dimensional neighbouring points in a given radius, using the Euclidean distance method.

- The new function `stats.acf` computes the autocorrelation of a distribution at a given lag.

- The new function `stats.acv` returns all autocorrelations through a given lag.

- `environ.attrib` returns further information on tables: The 'dummynode' key indicates whether a table contains an unallocated hash part (a `dummynode`), the 'length' index returns the estimated number of items in a table using a logarithmic estimation method.

- The new function `tables.getsize` returns a guess on the number of elements in a table, an indicator on whether a table contains an unallocated hash part, and an indicator on whether null has been assigned to a table. The function is useful to determine the size of a table significantly faster than the `size` operator does, using a logarithmic instead of linear method, but may return incorrect results if the array part of a table has holes, so the programmer should make sure that the array part of a table has no holes. It also does not count the number of elements in the hash part of a table.

- The `xml` package, an expat binding, is now also available in the eComStation edition. The original WarpIN installer missed parts of this library, please download the fixed agena-2.3.0a-os2.wpi installer, which also includes an updated crash course and manual.

- The `print` function sometimes returned incorrect results with hash parts of tables. This has been fixed.

- When arguments have been missing, parts of error messages of various functions were incorrect. This has been fixed.

- The new C API function `agn_tablesize` returns the information needed by the new `tables.getsize` function.

- The new C API function `agn_asize` returns the current number of elements stored in the array part of a table.

- The new C API function `agn_islinalgvector` checks whether a value is a vector created with the `linalg.vector`
  function.

- Some source code cleansing.

- This release candidate has been Valgrind-checked on x86 Linux and Mac to ensure there are no memory leaks.


2.3.0 RC 3, October 26, 2014

- In the parameter list of a procedure, up to four type names may now be passed per parameter.

- The `llist` package has been re-implemented in C, yielding a performance gain of two (with appends and prepends) to more than twenty times (indexed read and write accesses, insertions, and deletions). The new `iterate` function, however, is as fast as the former one. Memory consumption and garbage collection have been significantly improved, as well.

- `llist.prepend` and `llist.append` can now insert more than one value into a list.

- The function returned by `llist.iterate` can now skip a given number of subsequent elements if it is called with any - optional - non-negative integer, i.e. f := llist.iterate(a); f(); f(1).

- The new function `llist.replicate` creates a copy of a linked list.

- Metamethods for the `=` and `~=` operators have been added to the llist package.

- `sadd` and `qsadd` can now sum up table values with non-numeric keys.

- `settype` and `gettype` could not set or retrieve user-defined types to and from userdata - this has been changed.

- When computing a union of sequences, Agena now properly reduces its size in memory, if appropriate.

- The `==`, `size`, `in`, `union`, `intersect`, `minus`, `sadd`, and `qsadd` operators now support userdata metamethods.

- `environ.attrib` now also determines whether a structure has a metatable assigned ('metatable') key.

- `skycrane.scribe` now can automatically print null's and also structures and does not issue errors with these values any longer.

- If a file could not be found, `io.readfile`, `io.infile`, `io.readlines`, `io.nlines`, `io.skiplines`, `writefile`, returned garbage in the error message. This has been fixed.

- Various error messages have been improved.

- A new data structure has been added: the the memory-saving register. It is a fixed-size Agena `sequence` that also stores null's, and it is not automatically extended if more values have to be added (but see `registers.extend` and `registers.reduce` on how to extend or shrink a register).

  Registers allow to hide data: by resetting the pointer to the top of a register using `registers.settop`, any values stored above this pointer can neither be read nor changed. Most existing statements, operators and functions are supported. See also: `registers.gettop`. Please read Chapter 6.15 `Sandboxes`.

  There usually are no performance gains with regards to sequences, but since registers do not automatically shift elements, they are eight times faster with the respective operations.

- The C API functions `agn_getutype` and `agn_setutype` support userdata, as well.

- The deprecated function `package.register` has been removed due to clashes with the new `register` token.


2.3.0 RC 2, September 30, 2014

- The new functions `utils.readini` and `utils.writeini` read and write traditional INI initalisation files.

- The new functions `io.filepos`, `binio.filepos`, and `xbase.filepos` return the current file position.

- `io.seek`, `io.filepos`, `io.move`, `io.rewind`, `io.toend`, and `io.filesize` now support files larger that 2 GBytes, provided your compiler supports this capability (MinGW/GCC 4.5.2 does not).

- `os.cpuload` now also works on Windows machines.

- A potential memory leak in the `net` package, that did not yet show up, has been fixed.

- If the `net` package had been re-initialised in a session, an error had been returned. This has been fixed.

- `os.date` and `os.time`, `os.now`, `os.settime`, `os.computername` now also run on OS/2 - eComStation.

- On OS/2 - eCS, `os.system` returns additional data on the operating system. `os.cpuinfo` now can also determine the number of cores, and the `gzip` package has become available in the OS/2 version of Agena, too.

- Improved the sources to prevent unneccessary compiler warnings.


2.3.0 RC 1 eCS - OS/2 Warp 4 edition, September 08, 2014

- The eCS edition does not yet feature the 'net', 'xml', 'gdi', and 'fractals' package. Every other package that is indicated in the Primer amd Reference as a 'plus package' does not need to be intialised with the 'import' statement, since they have been directly compiled into the Agena executable.


2.3.0 RC 1, August 14, 2014

- Numeric `for` loops now support the `downto' keyword so that you can count down without using an obligatory negative `by` step size. In the `downto' context, the `by' step size should always be positive. `from' start and `to' stop values are obligatory when using the `downto' keyword.

- The metamethods '__finite', '__entier', and '__sqrt' are no longer supported. Instead, three new metathods for operations on structures have been added: '__union' for union operations, '__intersect'  to determine intersections, and '__minus' for differences. Thus, the `bags` package now also supports these three operations.

- The `\` integer division operator did not support its metamethod and used the one for float divison (`/` operator) instead. This has been fixed.

- The new function `stats.gini` determines the Gini coefficient, a measure of (in-)equality.

- The new function `stats.zscore` returns a function computing the z-score (standard score) of a sample - the number of standard deviations the sample is above or below the mean of a distribution.

- `stats.sorted` now by default uses the Introsort algorithm instead of Quicksort. This can speed up computation time thrice in ill-conditioned situations (where Quicksort would need O(n^2) operations), while not sacrificing performance in ordinary situations. Actually, Introsort uses Quicksort by default and then automatically switches to Heapsort if the recursion depth reaches 2*log(n, 2), where n is the number of elements in a structure.

   You may override this logic by passing the new option 'quicksort' which solely uses the traditional recursive Quicksort method to sort numbers. Also, `stats.sorted` now also can use the Heapsort algorithm exclusively if the new option 'heapsort' is being passed, and a non-recursive Quicksort algorithm devised by Niklaus Wirth with the new option 'nrquicksort'.

- The new function `stats.meanmed` returns both the arithmetic mean and the median of a distribution, or alternatively the quotient of the mean and the median, speeding up computation times when these values are needed by around 20 percent.

- Improved the error message of the `size` operator.


2.2.6, July 27, 2014

- `stats.chauvenet` can now check specifically for lower or upper outliers by passing the option `outlier='lower'` or `outlier='upper'`, respectively.

- `bags.remove` caused segmentation faults. This has been fixed. Moreover, all `bags` functions implemented in C have been internally changed.

- The (undocumented) metamethods for `+`, `-`, and `*` did not work if the `bags` package has not been invoked with the `with` function or the `import/alias` statement. This has been fixed.


2.2.5 Library Update 1, July 22, 2014

For instructions on how to easily install the update, have a look at the read.me file residing on the root of the agena-2.2.5-update1.zip archive. This archive can be downloaded from the Binaries/Agena 2.2.5 folder and can be used on all platforms.

- Replaced calls to the `select` and `map` functions with `$` and `@` in various libraries.

- Replaced most of the calls to `protect` with `try/yrt´ statements.

- Extended the index of the `Primer and Reference` and updated the `Crash Course`.


2.2.5, July 20, 2014

- The new function `mdf` rounds up a number at its n-th digit, `xdf` rounds it down.

- The `@` (formerly `->`) operator has been fixed and can be used safely now. It still is around 40 % faster than `map`.

- The new `$` operator, reminiscent to `@`, selects all the elements in a table, set, or sequence that satisfy a given condition checked by a univariate function. It is around 40 % faster than `select`.

- The new 'status' option to `environ.gc` determines whether the garbage collector is running or has been stopped.


2.2.4, July 16, 2014

- `stats.percentile` now also returns the lower, the upper outlier limit and the interquartile range of a distribution.

- Improved error messages in case of wrong indexing attempts.

- The `@`/`->` operator has been switched off due to segmentation faults. Please use the `map` function instead. Library functions concerned have been adjusted properly.


2.2.3, July 07, 2014

- `gdi` package: improved display of axes tickmarks and axes labels.

- The new function `gdi.pointplot` plots one or more graphs of points.

- `stats.ad`, `stats.amean`, `stats.gmean`, `stats.hmean`, `stats.mad`, `stats.mean`, `stats.median`, `stats.qmean`, `stats.sd`, `stats.trimmean`, `stats.var` now return `fail` if a distribution contains less than two observations.

- `stats.chauvenet` looped infinitely if the distribution contained no elements. Now it returns `fail` if a distribution contains less than two elements. Also, the function now accepts alternative functions to compute the mean and deviation.

- Corrected error messages of `stats.countentries`.

- Standardised and modulised the C code of some `stats` functions.


2.2.2, June 29, 2014

- `if` conditions can now also be used as expressions, e.g.: a := if cond then expr1 else expr2 fi. The `is` operator is still supported but will be deprecated in one of the next major releases.

- Syntactical sugar has been introduced for the `skip` and `break` statements: instead of putting them into `if` clauses just add the new `when` token followed by a condition, e.g.: "skip when a > 5" is equivalent to "if a > 5 then skip fi".

- The symbol of the mapping operator has been changed to make code easier to read: please use `@` instead of `->`. The `->` symbol, however, is still supported but will be abolished in one of the next major releases.

- The `xor` operator now works differently with non-Boolean values: it returns the first operand if the second operand evaluates to `null`, otherwise the second operand is returned, like the `alternate` function.


2.2.1, June 23, 2014

- This version is functionally equivalent to 2.2.0 Library Update 2 instead that all patches listed have now been compiled into the binaries and are no longer being implemented in the Agena language. Installers are provided for x86 Solaris, Windows, DOS, x86 Debian Linux, and x86 Mac OS X only.


2.2.0 Cumulative Library Update 2, June 23, 2014

For instructions on how to easily install the update, have a look at the read.me file residing on the root of the agena-2.2.0-update2.zip archive which can be downloaded from the Binaries/Agena 2.2.0 folder and used on all platforms. This ZIP file is a cumulative update.

- The `divs` package now tries to avoid to return fractional numerators or denominators.

- The `divs` package now supports the `**` operator to raise a fraction to an integer power. The `==` and `~=` equality operators are now supported, too. Furthermore, the equality operators (`=`, `==`) internally no longer convert fractions to floats before conducting a check. To compare a fraction and a simple Agena number for strict or approximate equality, use the new `divs.equals` function.

- The `int` operator is now supported by the `divs` package and computes the integer quotient of the numerator of a fraction divided by the denominator.

-`stats.extrema` and `stats.obcount` each defined a global variable of no use. This has been fixed.

- The `libusb` package is now briefly documented in the Primer and Reference.

- Restructured parts of Chapter 7 of the Primer and Reference. Added a comment on metamethods and relational operators to Chapter 6.19.

- The configuration utility which prepares the build of the Agena C sources has been patched (file `config.c`). This is only of concern to those users who wish to compile the Agena sources themselves.

- The test suite has been extended and also takes 50 percent less time to complete all the checks (see file agena-2.2.0-update2-testsuite.7z in the Sources download subdirectory).


2.2.0 Update 1, June 19, 2014

For instructions on how to easily install the update, have a look at the read.me file residing on the root of the agena-2.2.0-update1.zip archive. This archive can be downloaded from the Binaries/Agena 2.2.0 folder and can be used on all platforms.

- Fixed `math.norm` for it returned incorrect results if the left border of the target interval was not equal to 0.

- Fixed: `io.eof` returned the opposite of the expected result.

- New: When given a second option to `stats.scale`, the function normalises all its observations to the range [0, 1].

- New: `stats.extrema` determines all local maxima and minima in a structure of points.

- When given any option, `stats.ios` now first normalises the distribution to the range (-infinity, 1] (see `stats.scale`), determines the difference list, sums of its absolute differences and divides the sum of the number of occurrences minus 1 to make a distribution comparable to other ones. It thus no longer divides the sum of absolute differences by the arithmetic mean of the observations.

- `stats.obcount`, `utils.readcsv`, `llist.append` accidently defined a global variable each. This has been fixed.

- `environ.globals` has been changed: instead of printing the name of an undefined global variable and the corresponding line number at the console, it now returns both name and line number in a sequence of pairs.

- Cleansed the index of the `Primer and Reference`.


2.2.0, June 16, 2014

New statements and operators

- The new `relaunch` statement restarts a `for/to` and `for/in` loop from its beginning, i.e. resets the control variable to its start value (`from` clause or first element, respectively).

- The new `->` operator maps a univariate function on the elements of a table, set, sequence, and pair. It is up to 40 percent faster than the `map` function.

- The new `duplicate` statement puts a copy of the top item of a sequence onto its top.

- The new `exchange` statement exchanges the two topmost items of a sequence.

- The new `rotate` statement moves elements in a sequence or table up- or downwards.

- The new `pop` operator returns the last element of a sequence and then removes it from the sequence.

- The new `smul` operator multiplies all numbers in a table or sequence.

- The new `mul` statement multiplies its argument by a scalar.

- The new `div` statement divides its argument by a scalar.


io package

- The new functions `io.eof` and `binio.eof` check whether the end of a file has been reached.

- `io.infile`, `io.readfile`, `io.writefile` now accept file handles.

- `io.open` now accepts the strings 'read' for second argument 'r', 'write' for 'w', and 'append' for 'a'.

- `io.write` and related functions can now directly output Booleans without applying the `tostring` function before.

- Error handling of `io.skiplines` has been improved.


stats package

- The new function `stats.chauvenet` determines outliers in a distribution.

- The new function `stats.fsum` applies a function on each of its elements and then sums the results up.

- The new function `stats.fprod` applies a function on each of its elements and then multiplies the results.

- `stats.ios` returns an experimental variation coefficient if any second argument is given.

- `stats.mad` returns an experimental variation coefficient if any second argument is given. It also 10 % faster now.

- `stats.gmean` conducts very fast real multiplication if the new option `true` is given.

- `stats.ad` and `stats.sd` now return the variation coefficient if any second argument is given.

- Code-tweaked `stats.scale` and `stats.smallest`.


xbase package

- The new function `xbase.mark` marks a record in an xBase file to be deleted - it does not, however, physically delete or overwrite the corresponding fields. The new function `xbase.ismarked` checks whether a record has been marked to be deleted.

- The new functions `xbase.fields` and `xbase.records` return the number of fields and records in an xBase file, respectively.

- The new function `xbase.isopen` checks whether its argument is a valid file handle that points to an open xBase file.

- The new function `xbase.wipe` deletes all fields of a given record.

- The new function `xbase.header` returns the field names of an xBASE file along with the corresponding types.

- `xbase.readdbf` now also accepts file handles. Furthermore, a list of field numbers can be optionally passed in order to extract only certain columns.

- The `xbase` package now supports dBASE 7 Doubles, i.e. numbers stored in binary Little Endian format.

- `xbase.new` now accepts the names 'Logical' or 'L', 'Number' or 'N', 'Float' or 'F', (binary) 'Double' or 'O', 'Character' or 'C' (for strings up to 254 characters long), and 'Date' or 'D' to define fields.

- `xbase.sync` now returns true even if nothing had to be flushed.

- Improved error handling of `xbase.purge`.

- `xbase.field` has been deprecated, please use `xbase.readdbf` instead. An `alias`, however, is provided to ensure backward compatibility.

- Error handling of `xbase.record` has been improved.


astro package

- `astro.cdate` often returned wrong results - this has been fixed. It now also returns the fraction of the day.

- Improved error messages of the `astro` package.


math package

- `math.ndigits` and `ceil` now properly check their argument.

- `math.todecimal` has been extended to handle negative sexagesimal values intuitively.

- The new functions `math.dd` and `math.dms` convert between TI-30 pocket calculator `decimal` sexagesimals. The new function `math.splitdms` returns the hours, degrees, and minutes of a TI-30 sexagesimal `decimal`. The functions have been added to allow easy sexagesimal arithmethic TI-30 style.

- `math.convertbase` has become thrice as fast with decimal input, and around twice as fast otherwise.


Miscellaneous

- The Windows version of Agena now includes a libusb 1.0 binding that has originally been written by Tom N. Harris for Lua 5. No documentation is provided, please check the libusb man pages, as the binding provides 1:1 functions.

- `calc.neville` now can also return a generating function.

- Improved error message of `approx`, `getbit`, and `setbit`.

- Optimised internal sequence operations.

- The new C API function `agn_seqgetinumber` returns a lua_Number from a sequence; if a value in the sequence is not a number, then opposed to `lua_seqgetinumber`, it returns 0.

- Recompiled AgenaEdit for Windows.

- Added two high-resolution icons for both Agena and AgenaEdit.

- Improved the manual.

- This release has been Valgrind-checked on Linux and Mac to ensure there are no memory leaks.


Changes

- The `div` package has been renamed to `divs`. `div.div` has been renamed to `divs.divs`.

- Reserved the token `when` for future use, it cannot be used as a name any longer.

- The contents of `environ.minlong`, `environ.maxlong`, `environ.pathsep`, and `environ.buffersize` should now be queried by calls to `environ.kernel('minlong')`, `environ.kernel('maxlong')`, `environ.kernel('pathsep')`, and `environ.kernel('buffersize'), only. Any original Agena library functions can no longer be maliciously manipulated by changing these now deprecate environment variables.

- `The functions `notisposint` and `notisnegint` have been removed since they are redundant and also could return wrong results when given two or more arguments. Use `isnonposint` and `isnnonnegint`, respectively. Aliases, however, have been provided to ensure backward-compatibility.


Bug fixes

- In short-cut functions, the `?` varargs token is no longer accepted. vararg handling in short-cut functions has never been supported, anyway. An example for a short-cut function is "<< x -> x >>".

- `linalg.ludecomp` did not correctly check for singular matrices. This has been fixed.

- The `stats`, `linalg`, `calc`, and `xbase` packages have been modified to clear allocated memory in case errors occur.

- The variation coefficient returned by `stats.ad` since 2.2.0 RC 1 has been incorrect. This has been fixed.

- `stats.mad` and `stats.smallest` caused memory leaks if a distribution included `undefined`s or non-numbers. This has been fixed.

- `skycrane.tee` did not correctly output contents when given the the format option. This has been fixed.

- `xbase.readdbf` crashed when reading date values and also crashed when it encountered IO errors when reading doubles. It also ignored Float values. This has all been fixed.

- The deprecate `xbase.field` ignored Date and Float values. This has been fixed. It is advised, however, to use the extended `xbase.readdbf` function instead of `xbase.field`.

- The makefile for the DOS edition has been fixed.



2.1.8, April 28, 2014

- When specifying two permitted types for a parameter in the parameter list of a procedure, Agena when calling the procedure crashed if the passed value was not of one of the permitted types. Also, when passing `null` at a function call, the type check often did not work correctly. All this has been fixed. Type check error messages have been improved, too.

- The new function `stats.trimmean` returns the arithmetic mean of the interior of an observation.

- In Windows, the function to automatically determine the path to the main Agena library at start-up by looking for the directory containing the agena.exe binary, sometimes did not work. This has been changed.

- In the DOS and ANSI versions of Agena, `arctan2` returned incorrect results with complex numbers 0!x and 0!y and x = y. This has been fixed.

- Improvement of the manual.


2.1.7, April 09, 2014

- When specifying types in the parameter list of a procedure, Agena when calling the procedure only checked the first data type and sometimes returned confusing error messages otherwise if more than one data type has been defined in the parameter list. This has been fixed.

- `xbase.attrib` now returns concise information on all supported dBASE data types.

- In the manual, the page numbers of the table of contents were incorrect. This has been changed.

- `xbase` test cases have explicitly been added to the test suite.

- The compilation scripts for the cordic package have been changed.


2.1.6, April 08, 2014

- `os.system` can now detect Windows 8.l and Windows Server 2012 R2.

- In the portable Windows edition, it is no longer needed to set the AGENAPATH environment variable in XP or later.

- A long-standing bug in `xbase.new` has been patched to avoid segmentation faults.

- The new function `xbase.writedate` writes a DATE value to an xBASE file, a string in the format YYYYMMDD.

- The new function `xbase.writefloat` writes a FLOAT value to an xBASE file, a decimal number with a total number of 20 digits, including a maximum of 18 digits following the decimal point.

- `xbase.readdbf`, `xbase.record`, and `xbase.readvalue` now can now read DATE and FLOAT values.

- `xbase.record` returns LOGICAL values as either the Booleans `true` or `false`.

- The codepage used is now stored to xBASE files.

- The new cordic package computes various real functions (logarithm, sine, square root, etc.) with algorithms only using addition, subtraction, multiplication, division, and table lookups.

- `xbase.isVoid` has been renamed to `xbase.isvoid`. An alias to the old function name is provided for backward compatibility.

- `bags.attribs` has been renamed to `bags.attrib`. An alias to the old function name has been defined to assure backward compatibility.

- The unused C API function agn_checkboolean has been removed.

- The backward-compatibility file `compat.0.agn`, providing aliases for Agena 0.31 and earlier functions, has been removed due to clashes with the current Agena 2.x namespace.

- The following undocumented C API functions have at least been identified: agn_usedbytes, lua_strnext, agn_getfunctiontype, agn_getrtablewritemode, agn_setreadlibbed, agn_getbitwise, agn_setbitwise, luaL_checkoff64_t, agn_setbitwise, agn_getbitwise, agn_setdebug, agn_getdebug, agn_setgui.


2.1.5, March 09, 2014

- The new function `linalg.rref` computes the reduced row echelon form of any matrix.

- The new functions `linalg.backsub` and `linalg.forsub` perform backward and forward substitutions on augmented or square triangular matrices.

- The new function `calc.simaptive` computes the integral of a univariate function using Simpson-Simpson Adaptive Quadrature. It around 50 times faster than the C version of `calc.gtrap`, and thrice as fast as `calc.integral`. However, it is not as versatile as `calc.interp`, primarily with singularities around or within its borders.

- `calc.gtrap` has been rewritten in C and is 20 % faster now.

- `calc.Ei` now accepts negative values.

- Added a subchapter on pairs to the manual and improved the Quick Reference.

- Uploaded patched source files of the `gzip` package.


2.1.4, March 02, 2014

New operator

- The new '~=' operator checks for the approximate equality of objects, using Donald Knuth's numerical method. The operator is very useful to cope with round-off errors in floating point operations. To change the epsilon threshold, please use the environ.kernel/eps facility, changing the value of the   global system variable `Eps` will not work due to performance and consistency reasons, e.g.:

  > environ.kernel('eps':1e5);

  To check the current setting of the '~=' epsilon setting, just enter:

  > environ.kernel('eps'):


Miscellaneous

- `calc.fsum` has been extended to also process multivariate functions.

- The new C API function `agn_getepsilon` returns the setting of the accuracy threshold epsilon used by the '~=' operator and the `approx` function. `agn_setepsilon` sets the threshold.


Improvement of the `linalg` package

- The new function `trace' determines the trace of a square matrix using Kahan-Ozawa summation to prevent (or at least minimize) roundoff errors.

- The new function `getdiagonal` returns the diagonal of a square matrix.

- The new function `mulrow` multiplies each element of a specific matrix row by a number.

- The new function `mulrowadd` multiplies each element of a specific matrix row by a number and adds it to the respective element of another matrix row.

- The new function `submatrix` returns submatrices, or individual columns as row vectors.

- `diagonal` has been rewritten in C and has become 40 % faster.

- `ludecomp` has been rewritten in C, and due to a new algorithm used its output is much more consistent to that of Maple V Release 4 and TI Nspire CX CAS. The pivot vector now is of type vector instead of sequence. It also returns a fourth value, `fail`, if the matrix is singular.

- Instead of issueing an error if a singular matrix has been found, `gsolve` now returns `infinity` if an infinite number of solutions has been found, and `undefined` if no solutions exists. It returns `fail` if it could not determine whether no or an infinite number of solutions exist.

- The '__writeindex' metamethod for vectors now issues an error if a given index is not an integer.

- For consistency, the '==' operator now checks matrix or vector components for strict equality, and the '~=' operator approximate equality. Please also have a look at the '__aeq' and '__eeq' metamethods in the lib/linalg.agn library file.

- The new functions `maeq` and `meeq` conduct matrix equality checks, the former checking approximate equality of the respective matrix components using Donald Knuth's algorithm, the latter conducting a strict equality check of the respective components with out any tolerances. Likewise, the new `linalg` functions `vaeq` and `veeq` do the same with vectors.

- `veq` and `meq` and their respective metamethods to check for the approximate equality of vector and matrix components have been deprecated. They are still available but might be removed in future releases of Agena. Please use the '~=' operator instead, which is also faster.

- `backsubs` has been deprecated, please use `gsolve` instead. For backward compatibility, an alias is provided.

- Some error messages of the `linalg` now indicate the name of the function where a vector check failed.


2.1.3, February 21, 2014

New Functions

- The new function `calc.polyfit` returns a sequence of coefficients of an nth-degree polynomial of a sample, using polynomial regression. It tries to reproduce polynomial trend lines known from spreadsheet applications. There is no limit on the degree, but a degree of 7 or more is not regarded appropriate.

- The new function `calc.linterp` conducts a Lagrange interpolation.

- The new function `linalg.gsolve` performs Gaussian elimination and returns a solution vector plus the reduced linear system as an upper triangular matrix. It is at least ten times faster than `linalg.backsubs`.

- The new C API function `agn_geteps` returns the setting to the Agena system variable Eps (epsilon).


Miscellaneous improvements

- Optimised `calc.fminbr`.

- Error management of `beta`, `frac`, `math.zeroin`, and `calc.polygen` has been improved.

- `os.difftime` now is Year 2038-ready.

- `calc.sections` determining subintervals where a change of sign of a given function has been found, is now documented.

- Some few C source files and library.agn have been cleansed, there have been no technical or functional changes.

- The `gzip` package has been recompiled using the latest zlib 1.2.8 package. At least in Windows, this also results into a much smaller package binary.

- The index of the manual has been extended: new main topics `Statements` and `Data Types`, and improvement of the overview on mathematical functions, and a hint on how to compare `linalg` objects.


Bug Fixes

- A bug in the simple equality check of tables with filled array and hash parts has been fixed, e.g. [4, 1, 'a'~2] = [5, 1, 'a'~2] no longer returs `true`.

- `linalg.add`, `linalg.sub`, and `linalg.scalarmul` did not correctly operate with non-integral vector components. This has been fixed. Also tuned `linalg.add` and `linalg.sub` by 20 %, and `linalg.scalarmul` by 10 %.

- See also entry to `linalg.meq` below for a fix on the equality check.

- Applied Lua 5.1.5 patch 2: "When loading a file, Lua may call the reader function again after it returned end of input."


Improvement of the `linalg` package

- The multiplication metamethod for matrices has been extended to also support multiplication of two matrices. Also, with scalar multiplication, the scalar may now also be passed as the second operand. Also, the underlying matrix multiplication algorithm has been rewritten in C and now is at least four times faster.

- `linalg.scalarmul` has been extended to accept scalar and vector in any order. The vector scalar multiplication metamethod now allows to pass scalar and vector in any order, as well.

- `linalg.dotprod` has now been implemented in C and thus has become 40 % faster.

- `linalg.det` has been reimplemented in C and has become much more accurate. It also is twenty times faster now. Contrary to the former implementation, it returny 0 with singular matrices instead of issueing an error.

- `linalg.inverse` has been reprogrammed in C and has become at least ten times faster.

- `linalg.transpose` is now written in C. With square matrices, it has become 30 % faster, with other matrices, it is now three times faster.

- A new metamethod to compare two matrices has been added to the `linalg` package to fix a bug when comparing normal with sparse matrices. Also, Donald Knuth's approximation method is used to compare matrix elements (see the `approx` function for information on how this works). See also `linalg.meq`   in the manual.

- A new metamethod to compare two vectors has been added to the `linalg` package. It uses Donald Knuth's approximation method to compare vector elements (see the `approx` function for information on how this works). See also `linalg.veq` in the manual.

- Optimised `linalg.swapcol`, `linalg.swaprow`, and `linalg.identity`.


2.1.2, January 20, 2014

New expressions, operators, and functions for general use:

- In parameter lists, Agena can now validate up to two basic types for a given argument with the Maple-like arg :: { type[1], type[2] } parameter extension. Thus, for example, proc(x :: {number, complex}) checks for both rational and complex numbers x. User-defined types are not supported by this new feature.

- Memory management to handle parameters and local procedure variables has been changed. Thus, for example, Agena consumes 7 percent less memory after start-up.

- The new `nan` operator checks whether a number or complex number evaluates to `undefined`.

- `finite` now can also check complex numbers.

- `conjugate` has become an operator and is three times faster than before.

- `arcsec` is now an operator and has become 33 % faster.

- The new function `cabs` returns the real and imaginary absolute value of a complex number.

- The new function `net.smallping` conducts low-level network connection attempts to a server to see whether it is alive and also determines round-trip times.

- Improved error handling of `cot`, `coth`, `sec`, `csc`, `arctanh`, `arcsec`, `arccsc`, `arccsch`, `arccot`, `csch`, and `sech`. They thus have become 5% slower.

- `stats.prange` crashed Agena when it had to sort a structure at first. This has been fixed.

Operators for faster computation of fractals (see the `fractals` package):

- The new `cosxx` operator implements FRACTNT's v16 buggy cosxx function, i.e. if cos(x + I*y) = a + I*b, then cosxx(x + I*y) calculates a - I*b (i.e. the imaginary part of the result has the wrong sign). The function usually produces beautiful fractals, and is 33 % faster than the former `fractals.cosxx` function, which has been removed.

- With a complex number z = x + I*y, the new `bea` operator returns the complex number bea(x * I*y) = sin(x)*sinh(y) + I*cos(x)*cosh(y), and `undefined` if a number is passed. The function produces beautiful fractals, and is 33 % faster than the former `fractals.bea` function, which has been removed.

- The new `flip` operator swaps the real and imaginary parts of a number. It always returns 0 with numbers. It is 1.6 times faster than the former `fractals.flip` function which has been deleted.


2.1.1, January 03, 2014

- `try/catch`: explicit specification of an error variable right after the `catch` token is now optional. If no error variable is given, then the error message is automatically stored to the local `lasterror` variable, and the `then` keyword must be left out:

  > try
  >    error('oops !')
  > catch
  >    print(lasterror)
  > yrt;
  oops !

- The `try/catch` statement sometimes did not work in procedures (unassigned error variable). This has been fixed.

- The new `net.wget` function downloads HTML pages from the Web.

- Tuned `skycrane.counter` by 10 %. The function now optionally applies the Kahan-Ozawa instead of the original Kahan summation algorithm if the new third argument is the string 'ozawa'. The corresponding C sources have been modified to prevent compiler optimisation, which could cancel the optimisations, as well.

- `argerror` now prints the user-defined type name of a value received in its error message. If a value does not have a user-defined type, then its basic type is issued.

- The new 'a' option to `debug.getinfo` returns the number of arguments expected by a procedure, thanks to Rob Hoelz' LuaPowerPatch.

- Improved `index out-of-range` error message for strings.

- Modified the `stats.agn`, `linalg.agn`, `library.agn`, and `ansi.agn` files with respect to their error handling.

- On Macs, the agena-2.1.1a-mac-intel.pkg installer now also includes AgenaEdit.


2.1.0, December 30, 2013

- For a new kind of error handling, the new `try/catch` statement has been introduced. It has been invented and written by Hu Qiwei for Lua 5.1 back in 2008.

  In general, any statements where an exception might be expected can be put into a `try` clause. If an error is issued, generated by an explicit call to the `error` function or to any other expression, function, or statement, control immediately jumps to the corresponding `catch` clause if present or to the end of the `try/yrt` statement if no `catch` clause has been given, ignoring any other subsequent statements in the `try` clause.

  > try
  >    for i to 3 do
  >       print('before', i);
  >       if i = 2 then error('oops') fi;
  >       print('after', i)
  >    od
  > catch err then
  >    print('error', i, err);
  > yrt
  before  1
  after   1
  before  2
  error   1   oops

  The `protect/lasterror` error dealing facilities are still and will always be supported. The new control statement also works with the `break`, `skip`, `redo`, and `return` statements flawlessly.

- The new `redo` statement restarts the current iteration of a `for/to` and `for/in` loop from the beginning. Example:

  > flag := true;

  > for j in [10, 11, 12] do
  >    print('before', j, flag);
  >    if flag and j = 11 then
  >       clear flag;
  >       print('   -->', j, flag, 'jump back')
  >       redo
  >    fi;
  >    print('after', j, flag)
  > until j > 12;

  before  10      true
  after   10      true
  before  11      true
     -->  11      false      jump back
  before  11      false
  after   11      false
  before  12      false
  after   12      false

- The new `recip` operator returns the inverse of a number x. It is equivalent to the expression 1/x, but faster.

- The new `stats.ema` function computes the exponential moving average of a distribution. The new function `stats.gema` returns an iterator function returning the respective exponential moving average of a distribution.

- `*%`, `+%`, and `-%` returned `undefined` instead of a correct result if their right operand had been zero. This has been fixed.

- Fixed an error message in `net.survey`.

- Improved error messages for out-of-range indexing of pairs and strings.

- In the ANSI, Solaris, and DOS versions, the `int` operator has been tuned.

- The new C API function `agn_arraytoseq` converts a numeric array into a sequence and pushes this new sequence on top of the stack.

- Updated the manual.


2.0.0, December 01, 2013

- Agena 2.0 is downward-compatible to Agena 1.12, except that the tokens `import`, `alias`, `until`, and `onsuccess` are now keywords and can no longer be used as variables. Currently, there are Solaris, Debian (x86, PowerPC, Raspberry Pi), Windows, Mac, and DOS installers available for 2.0, including an updated Primer and Reference that explains all new features in detail.

- The new loop variants `for/as` and `for/until` check a condition at the end of the current iteration and either commence the next iteration or leave the loop. This works with both `for/to`, as well as `for/in` loops. In effect, both variants execute a loop at least once until the given condition is being checked.

  Examples:

  > for i to 5 do
  >    print(i)
  > as i < 3
  1
  2
  3

  > for i in [1, 2, 3, 4, 5] do
  >    print(i)
  > until i >= 3
  1
  2
  3

- The new `do/until` loop iterates until a certain condition is met:

  > c := 0;

  > do
  >   inc c;
  >   print(c)
  > until c >= 3
  1
  2
  3

- In numeric `for` loops, the `to` clause may not be given any longer. Instead, when leaving out the `to` clause, the loop iterates until the largest number representable on your platform, in C HUGE_VAL, has been reached:

  > for i do
  >    print(i)
  > od

- The new `onsuccess` clause in `if` and `case` statements executes a chunk if at least one of the conditions is true. Examples:

  > flag := false;
  > if 1 = 0 then
  >    print(0)
  > elif 1 = 1 then
  >    print(1)
  > onsuccess
  >    flag := true
  > else
  >    print(-1)
  > fi;
  1

  > print(flag);
  true


  > flag := false;
  > if 1 = 0 then
  >    print(0)
  > elif 1 = 0 then
  >    print(1)
  > onsuccess
  >    flag := true
  > else
  >    print(-1)
  > fi;
  -1

  > print(flag);
  false

  > flag := false;
  > a := 2;
  > case a
  >    of 1 then
  >       print(1)
  >    of 2 then
  >       print(2)
  >    onsuccess
  >       flag := true
  >    else
  >       print(-1)
  > esac;
  2

  > print(flag);
  true

- The new `import` statement allows to import one or more libraries without putting their names into quotes, e.g. "import calc, stats" is equivalent to "readlib('calc', 'stats')".

- The `alias` option to the `import` statement assigns one or more short names to the library functions initialised, e.g. "import calc alias xpdiff" is equivalent to "with('calc', 'xpdiff')", and "import calc alias" is equivalent to "with('calc')".

- The new `..` operator allows to index tables even if its left-hand side operand evaluates to `null`. In this case, `null` is returned and no `attempt to index field ... (a null value)` error is issued. It is similar to the `getentry` function but is three times faster. Examples:

  > create table a;
  > a.b:
    null
  > a.b.c:
    Error in stdin, at line 1:
      attempt to index field `b` (a null value)
  > a..b..c:
    null

  > create table a;
  > a[1]:
    null
  > a[1][2]:
    Error in stdin, at line 1:
      attempt to index field `?` (a null value)
  > a..[1]..[2]:
    null

- The new function `drem` evaluates the remainder of an integer division x/y, but contrary to `irem`, rounds the internal quotient x/y to the nearest integer instead of towards zero.

- The new function `skycrane.todate` returns the current date and time as a formatted string.

- The new function `io.truncate` truncates a file at the current file position.

- The new function `io.move` changes the file position a given number of characters to the left or right.

- The new function `io.filesize` returns the size of a file.

- `readlib` now accepts strings as its arguments, only. Numbers are not allowed any longer.

- If the last argument to `with` is the Boolean `false`, then the function does not write assigned short names to the console (stdout).

- `strings.fields` now also accepts a sequence of index numbers. It does not, however, accept the index `0` any longer.

- The Raspberry Pi Wheezy Debian installer now includes the `gdi` graphics package.

- The `change.log` file is now correctly displayed in Windows.


1.12.9, November 05, 2013

- The new functions `io.getclip` and `io.putclip` exchange texts between Agena and the clipboard (Windows only).

- `stats.prange` has been rewritten in C and has become up to 1.5 times faster.

- `os.cpuinfo` now returns correct and more information on ARM-based systems.

- In DOS and UNIX systems including Mac OS X and only in the complex domain, the exponentiation of the base 0 to the exponent 0 + r*I, with r any non-zero float, returned `undefined` instead of 0. This has been fixed.

- In DOS and UNIX systems including Mac OS X and only in the complex domain, the exponentiation of the base 0 to the exponent r + 0*I, with r any positive float, returned `undefined` instead of 0. This has been fixed.

- `stats.obcount` and `stats.obpart` could not include values into the rightmost subinterval. This has been fixed.

- `calc.nakspline`, `calc.naksplinecoeffs`, `calc_clampedspline`, and `calc_clampedsplinecoeffs` provoked segmentation faults if called with a structure that contained too few points, i.e. pairs. This has been fixed by returning `fail` in these cases.

- Potential memory deallocation errors have been removed from `calc.neville`, `calc.interp`, `calc.newtoncoeffs`, `calc.naksplinecoeffs`, `calc.clampedsplinecoeffs`, `calc.nakspline`, and `calc.clampedspline`.

- The new C API function `agn_checkinteger` checks whether an argument is a number and an integer and - contrary to `luaL_checkinteger` - issues an error otherwise.


1.12.8b, October 30, 2013

- Improvement to debug information.

- Minor improvements to the information displayed after entering `agena -h` in a shell.

- The sources have been updated, include correct Debian installer creation files for both PowerPC und Intel, and
  a corrected configuration source file to successfully compile Agena in DOS.

- A Raspberry Pi/Wheezy installer is now being provided.

- The former Mac installer could not set up Agena properly on Mac OS X 10.5. This has been changed.

- The x86 Debian installer did not correctly set up Agena, this has been fixed.

- A binary Linux Debian installer for PowerPC is now available for download.


1.12.8, September 13, 2013

- The new function `stats.mad` determines the median absolute deviation of a distribution.

- The new function `bags.minclude` inserts all elements in a sequence into a bag, thus de-coupling the number of elements to be included into a bag from the limited size of Agena's arguments stack.

- If bags included a non-numeric element, outputting the bag at the console failed. This has been hot-fixed.

- Updated the manual and Quick Reference.


1.12.7, August 29, 2013

- The new function `math.tosgesim` converts a decimal to its sexagesimal representation.

- The new function `proot` returns the principal root of a number or complex number.

- The new function `cbrt` determines the cubic root of a number or complex number, and is around 33 % faster than `root` with complex numbers.

- `math.todecimal` has now been implemented in C and is 33 % faster. It also does not require an obligatory second and third argument.

- `fractals.flip` has been implemented in C and is around 15 % faster now.

- Solaris, Linux, Mac, and Windows, and maybe DOS sometimes returned `undefined` instead of 0 when trying to raise the complex origin to a power. This has been fixed.

- In Solaris 10 and only with complex numbers, the underlying libc function cpow used to conduct complex exponentiation (`^` operator) sometimes returned incorrect results. This has been hot-fixed by replacing cpow with a self-written one.

- There have been problems when trying to compile the 1.12.6 sources. This has been changed.


1.12.6, August 21, 2013

- The iterator produced by `stats.gsma` always returned 0. This has been fixed.

- `stats.obcount` and `stats.obpart` returned errors if one of the elements in an observation matched the right border of the overall subinterval (second argument). This has been fixed.

- Added more examples on using Lua-style regular expressions to the manual.


1.12.5, August 15, 2013

- `stats.obcount` and `stats.obpart` have been tuned by 55 %, using an arithmetic method to determine the fitting subinterval instead of bifurcation; thus also values both situated at the right border of a subinterval and the left border of the neighbouring subinterval are now correctly collected according to the defintion in the manual.

- `io.infile` sometimes did not return correct results in case a line consisted of `environ.buffersize` or more bytes (currently >= 512 bytes on Windows, but depending on the C BUF_SIZ defintion). This has been fixed.

- The Mac OS installer did not include the patched `stats` package (`stats.sma`, etc.). This has been fixed.


1.12.4 Cumulative Update 3, August 08, 2013

- For instructions on how to easily install the update, have a look at the libupdate.read.me file residing on the root of the agena-1.12.4-update3.zip archive. This archive can be downloaded from the Binaries/Agena 1.12.4 folder.

- For Solaris, Windows, DOS, Mac, and Linux, the Agena 1.12.4 u3 installers include the 1.12.4 original release plus this cumulative update.

- The new `stats.obpart` function sorts occurrences into subintervals. Contrary to `stats.obcount`, it does not just count the occurences in each subinterval, but inserts the observations or parts of it into these intervals.

- u3: `stats.obpart` has been sped up significantly at least four times by avoiding unnecessary repetative identical function calls.

- The `skycrane.tee` function now also accepts a C-/Agena-style `printf`-like format string.

- `utils.readcsv` now allows to ignore certain lines in a CSV file with the new 'ignore' option. It now also returns the CSV line number in case of non-existing fields.


1.12.4 Update 1, July 30, 2013

- For instructions on how to easily install the update, have a look at the libupdate.read.me file residing on the root of the agena-1.12.4-update1.zip archive. This archive can be downloaded from the Binaries/Agena 1.12.4 folder.

- In Windows, DOS, and Mac, the Agena 1.12.4 u1 installers include the original 1.12.4 release plus this update.

- `clock` package: when subtracting `tm` values, debugging information had been printed at the console. This has been fixed.

- `gdi.plotfn` and `gdi.plot` did not properly print y-axis labels and the left x-axis label in some situations. This has been hot-fixed.

- Undocumented and unused `gdi.sync` and `gdi.autosync` aliases have been removed from the `gdi` package.

- Updated the scheme files.


1.12.4, July 25, 2013

- `os.date` returned an unusable string when given a time format string. This has been changed. Also, the descriptions of `os.date` and `os.time` have been corrected in the manual.

- `os.time` has become Year 2038-compatible and now also accepts a sequence of date and optionally time values.

- `clock.sgstr` now returns correct results if the seconds component is a fraction.

- The `clock` package now prevents round-off errors if the seconds component of a `tm` value also includes milliseconds.

- `stats.sma`, `stats.smm`, `stats.gsma`, `stats.gsmm` exposed a memory leak if the passed structure included `undefined`. This has been fixed.

- `stats.sma` and `stats.smm` have been tuned by removing an unnecessary Agena API call.

- `stats.sorted` and `calc.naksplinecoeffs`, `calc.nakspline`, `calc.clampedspline` exposed memory leaks if the structure contained too many values (i.e. if internal memory allocation errors occurred).  This has been changed.

- `calc.interp` created a memory leak if it issued the error `number of coefficients must be equal to number of points`. This has been fixed.

- `calc.interp` amd `calc.clampedspline` created a memory leak if they issued the error `expected a sequence of three sequences`. This has been fixed.


1.12.3, July 21, 2013

- The new functions `stats.gsmm` and `stats.gsma` are like `stats.smm` and `stats.sma`, respectively, but return iterator functions. The larger the size of an observation, the faster they are with respect to `stats.smm` and `stats.sma`.

- `calc.polygen` has been rewritten in C and thus is 60 % faster now.

- `os.datetosecs` now also accepts sequences and also three up to six integers representing the date and optionally time.

- `utils.checkdate` now also accepts tables or sequences of date/time values.

- Out-of-range detection in `stats.sma` and `stats.smm` has been improved.

- If the number of table entries to `os.datetosecs` is less then three, the function now returns an error.


1.12.2, July 17, 2013

- The new function `stats.sma` returns the simple moving average, both in its scientific as well as its financial variation.

- The new function `stats.smm` returns the simple moving median, both in its scientific as well as its financial variation.

- Improved error messages of almost all `binio` functions.

- `binio.readstring` crashed when not reading a string from a file, this has been fixed.

- `skycrane.semaphore` has been renamed to `skycrane.count`, and an alias has been set up to link to the new function for back-compatibility.


1.12.1, June 24, 2013

- The new function `os.symlink` creates a symbolic link.

- The new function `os.readlink` returns the name of the file a symbolic link is referring.

- The new function `strings.separate` splits a string into its tokens surrounded by a given set of delimiters. Contrary to `split`, the delimiter at the front of a token may be different from the delimiter at its end.

- `io.isopen` has been implemented in C and is at least 66 percent faster.

- `os.fstat` is now Year 2038-compatible, additionally returns the device number, and in UNIX/Mac also a file ID, the disk space occupied by a file, and the optimal block size for reading or writing the file. NTFS symbolic links including NTFS junctions are now detected by the Windows version of this procedure.

- `os.fstat`, `os.listcore` and thus `os.list` did not detect symbolic links on UNIX-based systems. This has been changed.

- `clock.sgstr` can now also convert `tm` values.

- `skycrane.trimpath` has become 25 percent faster.


1.12.0 (Cumulative) Update 1, June 14, 2013

- For instructions on how to easily install the update, have a look at the libupdate.read.me file residing on the root of the agena-1.12.0-update1.zip archive. This archive can be downloaded from the Binaries/Agena 1.12.0 folder.

- `printf` can now write a formatted string to a file if its first argument is a handle pointing to an open file.

- The new function `clock.sgstr` converts a float into its sexagesimal string representation of the format hh:mm:ss. Another delimiter to separate the time components can optionally be given.

- Fixed round-off errors in `clock.totm`.

- Added a hint to downloadable Library Updates and their installation notes to the manual in the new Chapter 2.9. In general, cumulatative updates are provided to minimize maintenance.


1.12.0, June 11, 2013

- Sequences can now be indexed with negative indices, determining elements from the right end of a sequence - provided that the indices are in the correct range. This also holds true when trying to index a sequence range with the `to` keyword.

- Corrected error messages with invalid sequence indices.

- The `create local` statement now also supports the `sequence` keyword - along with the `seq` keyword - to create local sequences.

- `os.date`, when called with no argument, did not correctly return milliseconds less than 100 msecs in the time string. This has been changed.

- Initalisation procedures for packages now should be of the form `<packagename>.aux.init`. The old style `<packagename>.init` is still supported but `with` will still assign a short name in this case for the initialisation procedure for backward compatibility, which you may want to avoid.

- Corrected Chapter 6.17 `Packages`.


1.11.7, June 09, 2013

- `os.date`, `os.time`, and `os.now` now also return milliseconds.

- `os.date`, when called with no argument, returned different strings on various platforms. This has been changed. It now returns a string of the format 'YYYY/MM/DD hh:mm:ss', plus '.' & milliseconds, if milliseconds could be determined, on all platforms.

- The new function `skycrane.tee` writes text to both the console and into a file.

- The `create` statement now accepts the `sequence` keyword to create new sequences. The `seq` keyword is still supported by `create`.

- `utils.readcsv` and thus `skycrane.readcsv` could not convert a numeric string into a number if the string had been enclosed by single or double quotes. This has been changed.


1.11.6, June 06, 2013

- `io.readfile` now can optionally only return the contents of a file if it includes a given substring, or if it does not include a given substring.

- The new function `io.infile` checks whether a file includes a given substring and returns `true` or `false`. It is 40 percent faster on Windows than `io.readfile` with the pattern option.

- `stats.sorted` can now optionally use an iterative Quicksort algorithm by passing the new `true` option. Using the iterative algorithm may be faster on older machines than using the default recursive one.

- Improved error handling of `io.readlines`, `io.nlines`, and `io.skiplines`.

- `utils.findfiles` did not work if only one file name had been given or if a procedure has been passed. This has been changed. The function now is 40 % faster in line-per-line mode.

- In the manual, improved Solaris and Linux installation instructions with regard to dependencies.


1.11.5, May 26, 2013

- `skycrane.enclose` has been rewritten in C, and is four times faster now.

- `skycrane.semaphore` has been rewritten in C and now is 20 % faster. The function now also applies Kahan summation if the start value is a non-integer.


1.11.4 Cumulative Update 3, May 23, 2013

- For instructions on how to easily install the update, have a look at the libupdate.read.me file residing on the root of the agena-1.11.4-update2.zip archive. This archive can be downloaded from the Binaries/Agena 1.11.4 folder.

  Windows, Mac, and DOS users may alternatively download the agena-1.11.4u3 installers providing Agena 1.11.4 plus all updates.

- The `clock` package now supports the following operators: `^`, `sqrt`, `ln`, `exp`, `abs`, `sign`, `sin`, `cos`, `tan`, and `arctan`.

- The `24-hour` threshold for `tm` values has been removed. Thus, the hours (or degrees) part of a `tm` value might be any non-negative number.

- In the `clock` package, the `/` operator did not work if the first argument had been an integer and the second argument a sexagesimal. This has been fixed.

- The `clock` package can now also multiply two sexagesimals or divide them.

- The new function `skycrane.enclose` encloses a string or number with a given character or string.

- The new function `skycrane.stopwatch` implements a stopwatch.

- The new function `skycrane.semaphore` returns an iterator function using - if needed - Kahan round-off prevention.

- `clock.dectotm` has been renamed to `clock.totm`. `clock.tmtodec` has been renamed to `clock.todec`. Aliases to the former function names are still provided.

- Updated the Quick Reference (agena.xls).

- Updated the scheme files.


1.11.4, May 14, 2013

- The new `*%` operator returns the percentage.

- The `/%` operator returned the percentage instead of the ratio. This has been fixed.

- Updated the Crash Course.

- Recompiled AgenaEdit for Windows.


1.11.3, May 12, 2013

- The new operators `+%` and `-%` add or subtract a percentage.

- The new function `io.writefile` writes all of the given numbers or strings to a new file. The function is around twice as fast than using a combination of `io.open`, `io.write`, and `io.close`.

- The `div` package now supports the following operators: `^`, `sqrt`, `ln`, `exp`, `abs`, `sign`, `sin`, `cos`, `tan`, and `arctan`.

- The new function `div.numer` returns the numerator in a `div` structure.

- The new function `div.denom` returns the denominator in a `div` structure.

- `notisposint` can now process more than one argument.

- The new function `notisnegint` checks whether all of its arguments are zero or positive.

- The new function `ispositive` checks whether all of its numeric arguments are positive.

- The new function `isnegative` checks whether all of its numeric arguments are negative.

- The new function `isnonneg` checks whether all of its numeric arguments are zero or positive.

- `/%` has been patched.

- `sign` returned 1 if its argument has been `undefined`. It now returns `undefined` in these cases.


1.11.2 Update 1, May 08, 2013

- The `div` and `clock` packages now support relations; thus, fractions and times can be compared with the `<`, `<=`, `=`, `=>`, and `>` operators.

- The new function `stats.numbcomb` returns the number of combinations.

- `strings.ljustify` and `strings.rjustify` now also accept numbers as their first argument.

- Documented `xml.decode` which receives a string containing an XML stream and which - contrary to `xml.decodexml` - can cope with situations where one and the same XML object is present multiple times on the same hierarchy.

- For instructions on how to easily install the update, have a look at the libupdate.read.me file residing on the root of the update ZIP archive.


1.11.2, May 02, 2013

- `io.readfile` now removes all newlines and all carriage returns, if the second argument `true` is being passed.

- The new function `strings.lrtrim` removes all leading and trailing white spaces or the given leading or trailing character from a string. It does not remove spaces or the given character within the string.

- The new constant `PiO4` is equivalent to Pi/4.

- The new function `stats.ssd` returns the sample standard deviation.

- `utils.decodexml` and thus `utils.readxml` now properly treat dots and underscores in XML tags and do not slice off trailing characters from these tags. Leading and trailing white spaces are now removed from the XML value. Line breaks within the XML value are still not being removed.

- `binio.writeshortstring` and thus also `save`, which uses the formerly mentioned function, crashed Agena when trying to save strings of 255 characters or less; this has now been fixed.

- The Quick Reference now also lists all mathematical constants available.

- AgenaEdit for Windows has been recompiled.


1.11.1, April 22, 2013

- The new function `polar` converts a number or complex number into its polar form.

- The new constant `E` is equivalent to the existing constant `Exp` = exp(1).

- The new constant `Pi2` is equivalent to 2*Pi.

- The new constant `PiO2` is equivalent to Pi/2.

- `stats.numbperm` now also accepts sets of any type of elements.

- Error handling in `stats.cdf` has been improved.

- The pure ANSI C API functions `agn_complexreal` and `agn_compleximag` have now been documented.


1.11.0, April 16, 2013

- The new `/%` operator divides two numbers and returns the result in percent.

- The new `iqr` function returns the integer quotient and integer remainder of two numbers.

- The new function `stats.pdf` computes the probability density function for a normal distribution.

- The new function `stats.cdf` implements the cumulative density function.

- The new functions `stats.ndf` and `stats.nde` help in writing new statistical distribution functions.

- The new function `strings.isspec` checks whether a string consists entirely of special characters.

- The new function `strings.isalphaspec` checks whether a string consists entirely of Latin letters, diacritics, and special characters.


1.10.5, April 09, 2013

- `binio.writechar`, `binio.writenumber`, `binio.writelong`, `binio.writestring`, and `binio.writeshortstring` now accept further data to be saved to a file.

- The new `div` package provides basic arithmetic functions to process fractions.

- The `clock` package has been internally improved.

- The `__tostring` metamethod in conjunction with `print` might have crashed Agena when trying to simply return its own non-numerical or non-string argument. This has been fixed.


1.10.4, April 02, 2013

- The `ìnstr` operator in conjunction with the new 'borders' option featured a memory leak due to premature garbage collection of the returned pair. `strings.mfind` thus had also been affected. This has been fixed.

- `os.listcore` and thus also the wrapper `os.list` procedure contained a memory leak, which has been removed.

- The test suite has been extended.

- Agena has been successfully Valgrind-verified with the new test suite.


1.10.3, March 31, 2013

- The `llist` package now uses pairs instead of dictionaries to hold values, resulting in a speed increase of around 10 %.

- `llist.append` can now append more than one value to a list.

- `llist.purge` issued an error if it tried to delete the last value in a list. This has been changed.

- `utils.findfiles` did not work any longer if a singfle file name had been passed. This has been corrected.


1.10.2, March 25, 2013

- `io.readfile` has been rewritten in C. While the increase in speed on Windows is almost unnoticable, the gain on Mac OS X is 8 %.

- In the manual, Chapter 7 Standard Libraries has been completely restructured and reformatted. Also, Chapter 8 C API Functions has been reformatted.


1.10.1, March 18, 2013

- The new function `io.skiplines` skips a given number of lines in a file and may boost processing a text file when looking for data always residing at a specific part of it.

- Improved Chapter 4.7.8 on patterns and captures in the manual.

- Recompiled the `mapm` package for Windows.


1.10.0, March 11, 2013

- The `instr` operator can now return the start and end positions of a pattern in a string with the new 'borders' option. The operator now also behaves like `strings.find` in case an invalid index has been passed (usually now resulting to `null`) instead of issuing an error.

- The new function `strings.mfind` returns all start and end positions of a pattern found in a string.

- The new function `strings.capitalise` capitalises a string.

- The third argument to `strings.remove` now is optional. If not given, it defaults to 1, i.e. only the character at the position given by the second argument is deleted from the string. Also, an index 0 (zero) is no longer accepted. An index n where n was the size of the string plus 1, did not issue an error, now it does.

- `strings.include` can now append strings, but string concatenation with the `&` operator should still be preferred in those cases due to performance reasons.

- The new character classes %v and %k for pattern matching recognise vowels including y, and consonants.

- The optional third argument to `utils.writecsv` (passing the delimitor) can now either be a string or an option of the form `delim = <any string>` or `'delim':<any string>`. If the third argument is none either, it now issues an error. This has been done to avoid confusion for `utils.readcsv` has been already been accepting the 'delim' option. Examples:

  > utils.writecsv(obj, 'd:/config/config.csv', delim='|');   # equal to:
  > utils.writecsv(obj, 'd:/config/config.csv', 'delim':'|');   # equal to:
  > utils.writecsv(obj, 'd:/config/config.csv', '|')

- `strings.remove` can no longer remove empty strings from a string. Instead an error is issued.

- Extended Chapter 4.7.8 on patterns and captures.

- The C auxiliary library function `agnL_optinteger` has now been documented. The C macro `agnL_optint` just simply referring to `agnL_optinteger` has been removed from the sources.


1.9.5, February 28, 2013

- The new function `io.readfile` reads the entire contents of a file given by its name, a string, in binary mode, and returns it as a string.

- If `os.remove` or `os.move` could not delete or move an existing file, they returned `true` without deleting or moving the respective file.  Now they correctly issue an error. At least with GCC compiled versions of Agena, file name jokers such as `.`, `..`, `*`, and `?` are still not accepted.

- `utils.findfiles` consumes less memory and besides a path now also accepts a list of specific files to be scanned for a text.

- `os.listcore` has been slightly tuned.

- The `case` statement could not properly treat indexed values in the `case` clause (e.g. case environ.os of ..., or case a[n] of ...). This has been fixed. Indexed values in the `of` clauses however have been working correctly.


1.9.4, February 21, 2013

- The new function `strings.glob` compares a string with a pattern including the wildcards `?` and `*`, where `?` represents exactly one unknown character, and `*` represents zero or more unknown characters.

- `os.listcore` and thus `os.list` are now much faster and more memory efficient when given file wildcards.

- `os.list` did not always properly descent recursively into subdirectories. This has been fixed. It also now returns the absolute path to the main directory scanned as a second return.

- `utils.findfiles` did not correctly treat wildcards, this has been changed.

- Due to improper internal stack management, `restart` crashed Agena if the library.agn file contained an error at invocation. This has been fixed. Also `restart` now properly treats the -d command line switch (debugging mode) and prints information on re-initialisation.


1.9.3, February 19, 2013

- The new function `os.cpuinfo` determines information on the processor in use, e.g. its type, number of cores and clock rate. It is fully available in Windows 2000 and above, Mac OS X, and in Linux.

  The only returns in common to all of the operating systems listed above are the `brand`, `frequency`, `vendor`, and `ncpu` fields. All other fields may be system-dependent.

  SPARCs and DOS are rudimently supported.

- The new function `io.isopen` checks whether a file is open and also - contrary to `io.isfdesc` checks for a valid file position.

- The new function `log2` returns the base-2 logarithm of a numeric or complex argument.

- `log10` now has been implemented in C and is around 10 % faster.

- `log` is now an operator and on average is four times faster.

- `approx` returned a wrong result if both arguments had been `undefined` and at least one of the arguments had been of type complex. This has been changed.

- If its second argument has multiple returns, `values` can now process all of them instead of only its first return. Thus, for example, the `unpack` function can now be used in calls to `values`.

- The `gzip` package now is available in the DOS binary distribution.

- Improved the index of the manual.


1.9.2, February 05, 2013

- The `llist` package has been changed:

  a) the package is now entirely implemented in Agena not using functions implemented in C any longer,

  b) linked lists including `null`s are now properly printed and converted to strings for output,

  c) `llist.listtoseq`, `llist.checklist`, `llist.getn` and `llist.seqtolist` have been removed, the first three possibly corrupting Agena's stack with maliciously manipulated llist structures.

  d) The new function `llist.listtotable` converts a linked list to a plain table.


1.9.1, February 04, 2013

- The new package `llist` implements linked lists which are at least six times faster than tables or sequences when having to conduct a large number of insertions or deletions.

- The new function `utils.checkdate` checks whether a date and optionally a time exists.

- The new function `os.cpuload` returns the 1, 5 and 15 minute load averages of the computer. It is available in Linux and Mac OS X only.

- The new function `os.pid` returns Agena's process ID.

- The new function `notisposint` checks whether a number is not a positive integer. It is 10 % faster than `not isposint`.

- `checkoptions` now does not issue its function name in case of errors, but the name of the function that called it.

- `os.setdate` now can set the system time in Windows.

- `os.execute` now issues an error if no command processor could be found.

- The `size` operator now also works with pairs.

- The `__size` metamethod did not work at all. This has been fixed.

- The `__in` metamethod did not work with sets. This has been fixed.

- `skycrane.removedquotes` has been implemented in C and thus is around three times faster.

- `skycrane.tocomma` and `skycrane.trimpath` have been implemented in C and thus are now both around twice as fast.

- `os.fattrib`, `os.datetosecs`, `os.settime`, `astro.sunriset`, and `astro.moonriset` did not correctly check the date and time values passed. This has been changed.

- `strings.dleven`, `strings.field`, `ads.getall`, and `net.receive` now correctly handle memory allocation failures.

- Removed some few unnecessary assignments reported by DJGPP/GCC 4.7.2 in the C sources.

- Extended the test suite and the scheme files.

- The new C API function `agn_malloc` conveniently allocates blocks of memory, and issues an error and optionally frees blocks in case of failure.

- The new C API function `agn_free` frees one or more blocks of memory.

- The C API function `agn_isutypeset` now also processes sets.

- The new C API function `agn_isutype` checks whether the given user-defined type has been set to a table, set, pair, sequence, or procedure.


1.9.0, January 27, 2013

- The new `alternate` function returns its first argument if its second argument is `null`. Otherwise it returns its second argument.

- The -b switch to the Agena executable has been removed since its output had been the same as the -v option.

- The Windows and UNIX/Mac versions of `strings.utf8size` contained a potential memory leak; this has been changed.

- All binary DLLs/SOs of the plus libraries no longer contain unused code, slimming their sizes by up to 10 percent, depending on the operating system. The makefile and the sources previously importing unused header files have been changed. For example, this at all reduces the size of the Windows binaries by 55 kBytes.

- Extended the test suite.

- Updated the scheme files.


1.8.17 Library Update 1, January 24, 2013

- This library patch corrects a problem in `utils.readcsv` and `skycrane.readcsv` which ignored certain options. It may be found in the Binaries/Agena 1.8.17 folder.


1.8.17, January 21, 2013

- C functions which are only used in the `calc` and `astro` packages are no longer part of the libagena SO/DLL, but are part of the SOs/DLLs of the mentioned packages, slimming down memory consumption a little bit if the packages are not used.

- Corrected typos in the Windows installer.


1.8.16, January 20, 2013

- `net.survey` now returns a fourth value, a Boolean, indicating if input is available, or if a timeout or exception occurred. For performance reasons, the function now also can check explicitly for reading, writing, or `exception` sockets instead of scanning all socket modes. Besides scanning all open sockets for their status, the function now also accepts a sequence of specific sockets and only scans these.

- The functions `net.address` and `net.remoteaddress` have now been documented.

- `net.lookup` now also accepts numeric IP addresses as input.

- `net.openwinsock` and `net.closewinsock` can now return `fail` plus a string containing an error message, instead of just throwing an error, by passing an argument of any type to them.

- `utils.decodeb64` did not exist (just under the name of `utils.decode64`, without the `b`). This has been changed.

- The new C API function `agn_pushboolean` pushes the Boolean value fail, true, or false onto the stack.

- In the manual, especially improved the chapter on the `net` package.

- The `astro` has not been delivered with the binary releases. This has been changed.

- The `xml` and `bags` packages had been missing in the binary installer of the Mac edition. This has been fixed.

- The source file distribution now features up-to-date editions of the clock and skycrane packages.

- The install option in the makefile now works again.

- Updated the scheme files.


1.8.15, January 10, 2013

Agena now features very basic UTF-8 support, can determine some basic astronomical data, and has additional `clock` functions:

- The new function `strings.toutf8` changes an ISO-8859-15 encoded string to UTF-8. ISO-8859-15 is ISO-8859-1 plus the EUR symbol.

- The new function `strings.tolatin` changes a UTF-8 encoded string to ISO 8859/15. ISO-8859-15 is ISO-8859-1 plus the EUR symbol.

- The new function `strings.isutf8` detects whether the given string is in UTF-8 encoding or in pure ASCII.

- The new function `strings.utf8size` determines the size of a UTF-8 string.

- The new function `skycrane.dice` returns random integers in the range [1 .. 6].

- The new function `clock.dectotm` converts a time value in decimals (of type number) into its `tm` representation.

- The new function `clock.tmtodec` converts a `tm` value into its decimal representation of type number.

- The new function `astro.sunriseset` determines sunrise and sunset times plus its civil, nautical, and astronomical twilight variations.

- The new function `astro.moonriseset` returns the times of Lunar rise and set for a location in GMT.

- The new function `astro.moonphase` returns the moon phase.

- The new function `astro.sun` provides an easier-to-use interface to `astro.sunriseset`.

- The new function `astro.moon` provides an easier-to-use interface to `astro.moonriseset`.

- The new function `astro.jdate` converts a Gregorian date to the corresponding Julian date.

- The new function `astro.dmstodec` converts coordinates in the form degree, minute, second, and their orientation 'N', 'S', 'W', or 'E' to their corresponding decimal degree (DegDec) representation.

- The new function `astro.dectodms` does the opposite.

- The former `utils.cdate` function has now been implemented in C and is around 60 % faster. Its new name is `astro.cdate`. An alias of `utils.cdate` to the new C version has been defined, but it may be deprecated in future Agena releases.

- The former `utils.isleapyear` function has now been implemented in C and is around 66 % faster. Its new name is `astro.isleapyear`. An alias of `utils.ispleapyear` to the new C version has been defined, but it may be deprecated in future Agena releases.


1.8.14, January 03, 2013

- `stats.median` now is 10 % faster. `stats.sorted` has become around 5 % faster.

- The new function `stats.smallest` returns the k-th smallest number in a numeric table or sequence.

- The new `utils.cdate` function converts a Julian date into its corresponding Gregorian calendar date representation.

- The new `strings.isisoalpha` function checks whether a string consists entirely of ISO 8859/1 Latin-1 alphabetic lower and upper-case characters.

- The new `strings.isisolower` function checks whether a string consists entirely of ISO 8859/1 Latin-1 alphabetic lower-case letters.

- The new `strings.isisoupper` function checks whether a string consists entirely of ISO 8859/1 Latin-1 alphabetic upper-case letters.

- The new `strings.isisospace` function checks whether a string consists entirely of ISO 8859/1 Latin-1 white spaces.

- The new `strings.isisoprint` function checks whether a string consists of printable ISO 8859/1 Latin-1 characters.

- The new `strings.isolower` and `strings.isoupper` functions convert a string to upper or lower case-letters using the ISO 8859/1 Latin-1 character set.

- `strings.transform` applies a function to the ASCII value of each character in a string and returns a new string.

- Updated the scheme files.


1.8.13, December 27, 2012

- The `size` operator had issues with some special kind of tables (new tables containing holes in their array part). Now the operator always returns the correct number of assigned elements, for the sake of performance. (The former binary search method has been dropped, and instead a linear search of the array part has been implemented.)

- Due to the above change, `read` does not return an `attempt to index a null value` error in the described situation any longer.

- Improved the index of the manual.

- Valgrind regression test: okay.


1.8.12, December 18, 2012

- Added `skycrane.iterate` returning a function that when called returns each element in the ascending order of the keys of the original table. It also works on sets and sequences.

- If you pass the Boolean value `true` as the very last argument to `checkoptions`, then any unknown option of type pair will be part of the resulting table, with no error issued. This makes `checkoptions` more tolerant.

- Optimized code of `utils.readcsv`.

- Improved error messages of `columns`.

- Updated the manual.

- Extended the editor scheme files.


1.8.11, December 09, 2012

- `stats.sorted` now properly sort floats.

- Removed a potential memory leak from `print` in connection with the `delim` option.


1.8.10, November 26, 2012

- The new function `skycrane.move` easily moves files and directories and is an interface to `os.move`.

- The issue with former out-of-memory errors of the new C implementation of `sorted` has been finally solved by fixing a Virtual Machine function I wrote that deeply-copies structures. The `copy` operator, however, worked flawlessly, because the Lua Virtual Machine, on which Agena is based, compensated for it. Thus,

  a) `sorted` has now been switched back to its faster C implementation. It is 14 % faster than the Agena version, but not the 100 % asserted before.

  b) `dimension` used with an initialiser should now work better although its massive usage did not seem to create out-of-memory errors.

  c) Users encountering problems with massive use of `rtable.rget` to query the current contents of the remember table of a function for informative purposes will also benefit from the patch. The internal remember table admin functions did not use deep-copying, so usage of remember tables in general has not been affected by the flaw.


1.8.9 Update 1, November 21, 2012

- The new `sorted` function threw ot-of-memory errors. This has been hot-fixed by re-instating the old function that worked.

- Quarrels with the extended `calc` package under Linux have finally been solved.

- To download the Library Update, please have a look into the binaries sourceforge.net folder, file `agena-1.8.9.1-update-os-independent.zip` and also read the `read.me` file for proper installation instructions.

  Updated installers are provided for Solaris, Windows, Mac, Linux, and DOS. All other users are kindly asked to install the above mentioned update.


1.8.9, November 20, 2012

- The new function `selectremove` combines the functionality of `select` with the one of `remove`: The first result contains all the elements of the given structure that satisfy a given condition, the second result contains the elements of the given structure not satisfying the condition. This may speed-up computations when you need both results, maybe for post-processing, by around 33 %.

- If a table is passed to `select` and `remove`, the new `newarray` option makes sure that the results are returned in an array with consecutive positive integral keys, not preserving the original keys of the the respective values determined. Thus, select(<< x -> x :: number >>, ['a', 10, 20, 30, 40, 'z'], newarray=true) returns [10, 20, 30, 40] instead of [2 ~ 10, 3 ~ 20, 4 ~ 30, 5 ~ 40]. This saves you from passing the result to `tables.entries` when needed.

- The new function `skycrane.sorted` sorts a table or sequence non-destructively but contrary to `sort` and `sorted` can cope with structures including values of different types. First, numbers are sorted, then strings, the others are not. The function, however, is three times slower than `sorted`.

- `stats.issorted` now accepts a function as its second argument to determine the expected sorting order.

- Contrary to previous claims in the manual, the `copy` operator could not (deep-)copy pairs. Now it can do so.

- `environ.isselfref` did not work well with self-referencing pairs. This has been changed.

- `sorted` has now been implemented in C and is around twice as fast as before.

- The new C API function `agn_paircheckbooloption` checks whether the value at the given stack index is a pair, whether its left operand is the given string, and whether the right operand is a boolean. Returns the boolean as a number.

- The new C API function `agn_pairgetnumbers` retrieves the numbers from the pair residing at a given stack index.

- Documented the API C macros `lua_iscomplex`, `lua_ispair`, `lua_isset`, and `lua_isseq`.

- Improved the manual.

- Extended the test suite.


1.8.8, November 08, 2012

- In the past, when passing a function, `nseq` could only create sequences of numbers. This has been changed by allowing `nseq` to add any type of value to the resulting sequence; try for example: "nseq(<< x -> x:x^2 >>, 1, 5)". This spares you from applying `map` to the result of `nseq`.

- `map` now also works on pairs (if this should be of any use).

- Improved the manual and added information on the C API.


1.8.7, November 04, 2012

- `calc.interp` and `calc.newton` have now been merged, and their functionality has been implemented in C. The name of the new function is `calc.interp`, and an alias `calc.newton` has been set up to link to the new function. If `calc.interp` is called with only one argument, the function returned is at least twice as fast when evaluating interpolation values. The new `calc.interp` version is also numerically more stable.

- Added two new interpolating functions:

  a) `calc.clampedspline` is a clamped cubic spline interpolation function.

  b) `calc.clampedsplinecoeffs` determines the linear, quadratic, and cubic coefficients of a clamped cubic spline.


1.8.6, November 01, 2012

- `checkoptions` has now been implemented in C and thus is at least twice as fast.

- Added five new interpolation functions:

  a) `calc.nakspline` is a `not-a-knot` interpolation function.

  b) `calc.neville` interpolates according to the Aitken-Neville algorithm.

  c) `calc.newton` interpolates according to the Newton rule.

  d) `calc.naksplinecoeffs` determines the linear, quadratic, and cubic coefficients of a `not-a-knot`-cubic spline.

  e) `calc.newtoncoeffs` computes the coefficients of the Newton form for the given points.


1.8.5 Update 1, October 24, 2012

- The new function `argerror` works like `error`, but is a littler bit smarter.

- The new function `checkoptions` checks options, saving many lines of code.

- The new function `skycrane.scribe` works like `io.write` and `io.writeline`, but also accepts tables and sequences. Else, it works like `io.write/line`.

- `io.flush` has been renamed to `io.sync`. The function `io.flush` will be depracated in a future release of Agena.

- Windows, Mac, and DOS installers including the update are available in the Binaries folder.

- Linux and Solaris users are asked to install the update file agena-1.8.5-update1.tar.gz (also in the Binaries folder) over the Agena 1.8.5 installation. See the read.me file in agena-1.8.5-update1.tar.gz for how to easily install the update.


1.8.5, October 17, 2012

- `save` now locks the file before writing to it. This prevents file corruption if another application wants to write to the file at the same time, too.

- `recurse` could not correctly traverse pairs resulting in (more or less sporadic) segmentation faults. This has been fixed.

- `binio.readobject` and thus also `read` crashed when trying to read deeply nested structures, such as e.g. linked pairs. This has been fixed by properly increasing the internal stack when reading deeply-nested structures.

- In the manual, improved the chapters on type checking, error processing, and user-defined types. There are also many other minor improvements throughout the text.


1.8.4, October 14, 2012

- Added charts on programme flows and features of procedures to the manual and improved it a little bit.

- `recurse` can now also traverse pairs. It now also returns `fail` when evaluating `null` instead of issueing an error.

- `checktype` can now check empty structures.

- `print` could not output pairs with at least one of its components evaluating to `null`. Now it can do so.

- `binio.writeobject` and thus also `save` could not write integers. This has been fixed.

- Corrected error messages of `recurse` and the internal table assignment procedure in case undefined has been passed as then index.


1.8.3, October 09, 2012

- The new `subs` option to `utils.readcsv` replaces one or more occurence of a value in a line with another one.

- The new `comma` option to `utils.readcsv` allows to transform a float with a comma in the CSV file, separating its integral from its fractional part, to an Agena float.

- The new `dot` option in `utils.writecsv` writes floats with the decimal dot replaced by the given single character, to the CSV file, thus allowing floats with a decimal comma.

- `stats.sum` and `stats.countitems` now accept multivariate functions.

- Some few corrections to the manual.


1.8.2, October 07, 2012

- `whereis` has now been implemented in C. Thus it is at least twice to three times as fast as before.

- `os.now` now returns the difference between your local time zone and GMT in minutes including daylight saving time, and east of Greenwich, in the new `td` entry. The new `dst` entry indicates whether daylight saving time is in effect in your local time zone (the same as the 9th value in the `localtime` entry). The Julian Date and the English names of the month and day queried are returned, too.

- `stats.scale` is a version of `linalg.scale` just for plain tables and sequences, but implemented in C.

- The new function `stats.colnorm` returns the largest absolute value of the numbers in a table or sequence, and the value with the largest absolute value.

- The new function `stats.rownorm` returns the sum of the absolute values of the numbers in a table or sequence.

- The new function `stats.sum` computes the sums of all numbers in a table or sequence. Contrary to the `sadd` operator, it prevents round-off errors during summation.

- The following functions now also accept structures including the value `undefined`. In this case, all `undefined's` are ignored in the respective computations, so that the functions can be used with incomplete observations: `stats.amean`, `stats.cumsum`, `stats.median`, `stats.sum`, and inherently `stats.minmax` and `stats.issorted`.

- `stats.median` now longer requires a sorted structure. It checks automatically whether the input is sorted or unsorted.

- The new function `stats.sort` sorts tables or sequences of numbers in ascending order twice as fast if the structure contains (around) more then seven elements. It also ignores `undefined's`.

- Fixed error message of `linalg.scale` in case of a wrong first argument.


1.8.1, September 30, 2012

- `utils.readcsv`:

  a) If a CSV file includes only one field, i.e. one value per line, the new option `newseq` now puts this value into a new sequence, resulting in a sequence of sequences returned by the function, as is already the case if the CSV file includes two or more fields, thus not changing the default bahaviour.

  b) The new `field` option allows to extract only the given field in a CSV file.

  c) The new `fields` option allows to return only the given fields in a CSV file, and in the order given by the user.

  d) The optional function to be mapped on all fields is now only mapped on the fields to be actually returned.

  e) The new `mapfields` option applies a function to the specified fields in a CSV file.

  f) If the output = 'record' and header = false options are passed, then a table array is returned instead of a dictionary, so the keys of the returned table are numbers instead of strings.

  g) The new output = 'matrix' option returns a matrix instead of a table (see linalg package).

- The new `skycrane.readcsv` function works like `utils.readcsv`, but with the following default options, which can be overridden: convert=false, ignorespaces=false, remove='quotes', remove='doublequotes'.

- The new function `linalg.norm` returns the norm of a matrix or vector.

- The new function `linalg.scale` normalises the columns of a matrix in such a way that, in each column, an element of maximum absolute value equals 1.

- Improved error handling of `linalg.checkmatrix`, `linalg.vector`, and `linalg.matrix`.

- Some improvements to the manual.


1.8.0, September 25, 2012

- `os.fattrib` can now also change the file access and modification time.

- The new function `os.now` returns various information on the current date and time, both for your local time zone and UTC/GMT, plus an indicator for your time zone, and the number of seconds elapsed since the start of the epoch. Please note that in the DOS version, local time and GMT cannot be distinguished.

- The new function `os.datetosec` converts a date into the number of seconds elapsed since the start of an epoch.

- The new function `os.sectodatec` takes the number of seconds elapsed since the start of an epoch and returns the date and time.

- The new function `os.settime` sets the system clock. It is available only in the UNIX editions of Agena.

- The new function `strings.isblank` checks whether a string consists entirely of white spaces and/or tabulators.

- The new function `strings.isspace` checks whether a string consists entirely of white spaces.

- `os.fcopy` destroyed a file if it was copied to itself. This will now be prevented. Also, the function now sets the file time stamp of the file to be copied to the target file.

- `xml.decodexml` and thus `xml.readxml` could not interpret indented tags and certain XML structures. This has been changed.

- Applied the Year 2038 fix to `os.time` and `utils.calendar`.


1.7.10, September 13, 2012

- Patched the VM routine that creates table arrays and dictionaries with a preallocated number of slots, so that the `size` operator can determine the number of elements actually assigned correctly.

- The new agn_createtable C API function creates a table so that the `size` operator always returns a correct result if the array part contains holes.

- The `select`, `remove`, and `bags.bag` functions now use the above mentioned new API function.

- Fixed `strings.isnumeric` and `strings.iscenumeric` which wrongly returned true with empty strings.

- Improved error handling of the `columns` function.

- Improved and updated the regression test suite.


1.7.9a, September 11, 2012

- `os.system` can now directly detect Windows 8 and Server 2012.

- The `size` operator returned twice the number of items actually stored in a dictionary that has been created with the `create table` statement or similar C API functions. This has been fixed.

- `bags.attribs` has thus also indirectly been fixed for it returned a wrong number of entries in its first return if elements had been passed in a call to `bags.bag`.

- Agena crashed at exit if the `net` package has been readlib'ed twice or more. This has been changed.

- The new function `stats.cumsum` returns a structure of the cumulative sums of the numbers in a table or sequence.


1.7.8 Update 2, September 03, 2012

- The new function `stats.obcount` divides a numeric range into its subintervals, sorts all occurrences in an observation into these subranges and finally counts all elements in these subranges.

- The new function `skycrane.bagtable` returns a table of bags with its keys determined by the given indices.

- `gdi.setellipse` and `gdi.setellipsefilled` ignored the `colour` option. This has been changed.

- `gdi.plot` used wrong axis dimensions if the `square` option has been passed. This has been fixed.

- `linalg.ludecomp` inadvertently created a global variable. This has been corrected.


1.7.8 Update 1, August 29, 2012

- Corrected error handling of `stats.percentile`, `stats.prange`, `stats.skewness`, and `stats.iqr`.

- Improved error handling of `stats.quartiles`.

- Improved the manual.


1.7.8, August 28, 2012

- Patched `stats.amean` which returned wrong results if called multiple times from within procedures.

- Removed `stats.iosplus`.

- The agena.xls Quick Reference file contained invalid tab names. This has been corrected.


1.7.7, August 26, 2012

- Like `stats.mean`, the new function `stats.amean` returns the arithmetic mean of an observation but is more robust by avoiding arithemtic overflow and round-off errors. Thus it is, however, slower than `stats.mean`.

- The new function `stats.iosplus` determines the volatility of an observation and contrary to `stats.ios` also allows to compare observations of different magnitudes.

- The new function `strings.isnumeric` checks whether a string represents an integer or a float.

- The new function `strings.iscenumeric` checks whether a string represents an integer or a float that includes one decimal-comma.

- The new function `skycrane.getlocales` returns all locales available on your operating system.

- The new function `skycrane.tocomma` converts a number or a numeric string to a string with an optional decimal-dot replaced by a comma.

- Minor improvement to the C code of `stats.ios`.

- Improvements to the Statistics Library chapter.


1.7.6 Library Update 1, August 21, 2012

- The `in` operator did not work correctly on bags (see `bags` package). This has been fixed.

- `strings.diamap` unnecessarily polluted the namespace with two rather large mapping tables. This has been changed.

- Some few corrections to the manual.

- To download the Library Update, please have a look into the binaries sourceforge.net folder, file `agena-1.7.6.1-update-os-independent.zip`.


1.7.6, August 19, 2012

- The contents of a bag is now printed in ascending order of its keys.

- The new function `bags.attribs` returns the number of occurrence of all unique elements in a bag and also the accumulated number of all occurrences of these elements in a bag. For example, bag('Mars 2' ~ 1, 'Mars 3' ~ 1, 'Viking' ~ 2) results to 3, 4.

- If `os.fcopy` fails, the name of the file that could not be copied is returned as a second result.

- The new `Skycrane` package includes auxiliary functions: an extended version of `os.fcopy`, and two little helpers.

- The `environ.printcomplexzeroed` setting has been removed. Use the `environ.kernel/zeroedcomplex` option instead.

- The new, or undocumented, `environ.kernel/promptnewline` option, if set to true, prints an empty line between the input and output regions. Just try it out.

- In Solaris, the `gzip` package could not be loaded. This has been fixed.

- In the manual, the chapter on Booleans has been extended and corrected. Also a subchapter on pattern matching and linked lists has been added. The Quick Reference has been corrected, as well.


August 12, 2012

- In the manual, the chapter on Booleans has been extended and corrected. Also a subchapter on pattern matching and linked lists has been added. The Quick Reference has been corrected, as well.


1.7.5, August 05, 2012

- Added the XML/LuaExpat package. It includes functions which are five times faster than `utils.decodexml` or `utils.readxml`.

- Fixed a bug in `readlib` that caused segmentation faults when a C library could not be read.

- In Solaris, the `mapm` package could not be loaded. This has been changed.


1.7.4, July 29, 2012

- The core functions of the `bags` (multisets) package have now been implemented in C: `bags.bag`, `bags.include`, `bags.remove`, and `bags.bagtoset`. Thus they are around twice as fast as the former Agena implementations.

- The `in` metamethod of the bags package has been tuned. It is now at least 4 times faster than before.

- Some hardening of the `restart` statement.


1.7.3, July 24, 2012

- The `create` statement threw `out of memory` errors if the user tried to assign a negative number of preallocated slots. This has been changed by preallocating zero slots in this case, which is valid a valid setting.

- `bags.bag` threw `out of memory` exceptions if called with no argument. This has been fixed (see above for the reason).

- Coroutines could not be created because of a name conflict with the `create` statement. This has been changed by renaming `coroutine.create` to `coroutine.setup`. To see what coroutines are, please have a look at the official Lua programming language website.


1.7.2, July 24, 2012

- Extended the metamethod chapter of the manual and added a subchapter on weak tables and sequences, and garbage collection.

- Lua's concept of weak tables has been extended to sequences. The `insert` statement now cannot be applied to weak tables.

- `environ.attrib` now can also process pairs - and with structures, returns the user-defined type of a structure or procedure if defined. It also returns information on weak tables and sequences.

- The new multiset package has been added, called `bags`. A bag is a kind of Cantor set that also stores the number of occurrence of each unique element.


1.7.1 Update 1, July 19, 2012

- The new function `augment` joins two or more tables or sequences horizontally.

- The new function `columns` extracts the given columns from a two-dimensional table or sequence.

- `utils.readcsv` can now remove quotes or double quotes from fields while parsing a CSV file with the new `remove` option.

- Windows and DOS users can just download the agena-1.7.1.1-win32-setup.exe or agena-1.7.1.1-dos.zip installers provided in the Sourceforge/Agena/binaries folder to easily circumvent the below mentioned update procedure.

- The UNIX update can be found in the Sourceforge/Agena/binaries folder, file agena-1.7.1-update1-os-independent.zip. Please have a look at the read.me file in this archive for hints on how to update your Agena installation.


1.7.1, July 15, 2012

- `copy` can now also copy a table if one of its keys is this table itself (see for example `_G._G`).

- `copy` crashed if it tried to copy structures with cycles, i.e. if it contained any structure that directly or indirectly referenced to itself. This has been fixed.

- If the global system table `_G` has been deleted (a table containing all currently assigned global names), `restart` crashed Agena. This has been fixed.

- Improved the manual and added subchapters on sandboxing and handling the environment, and some notes on self-referencing structures.


1.7.0, July 11, 2012

- Setting `environ.printZeroedCmplxVals` did not accomplish anything. Please use `environ.printzeroedcmplxvals` instead.

- The prettyprinters `environ.printtable`, `environ.printlongtable`, `environ.printset`, `environ.printsequence`, `environ.printpair`, and `environ.printcomplex` have been renamed to `environ.aux.printtable`, `environ.aux.printlongtable`, `environ.aux.printset`, `environ.aux.printsequence`, `environ.aux.printpair`, and `environ.aux.printcomplex`, respectively.

- `os.curdir` will be deprecated in the next Agena 1.8 release. Please use `os.chdir()` instead to determine the current working directory.

- As announced earlier, the following left-hand side functions have now been deleted and have been substituted by their lower-case right-hand equivalents:

  environ.MinLong := environ.minlong
  environ.MaxLong := environ.maxlong
  environ.BufferSize := environ.buffersize
  environ.PathSep := environ.pathsep
  environ.More := environ.More
  environ.WithProtected := environ.withprotected
  environ.WithVerbose := environ.withverbose
  environ.Os := environ.os
  environ.Cpu := environ.cpu
  environ.Release := environ.release
  environ.GdiDefaultOptions := environ.gdidefaultoptions
  environ.PrintEncloseStrings := environ.printenclosestrings
  environ.PrintLongTable := environ.aux.printlongtable
  environ.PrintTable := environ.aux.printtable
  environ.PrintSet := environ.aux.printset
  environ.PrintSequence := environ.aux.printsequence
  environ.PrintPair := environ.aux.printpair
  environ.PrintProcedure := environ.aux.printprocedure
  environ.PrintComplex := environ.aux.printcomplex
  environ.PrintEmptyLine := environ.printemptyline
  environ.FractScreenUpdates := environ.fractscreenupdates
  environ.FractintColorMaps := environ.fractintcolourmaps

  Please readlib lib/compat.agn for backward compatibility.


1.6.15, July 08, 2012

- The new function `sorted` returns a sorted structure whithout modifiying the original structure.

- The new function `recurse` checks each element of a table, set, or sequence by applying a function on each of its elements.

- The previously undocumented `printf` function is finally explained in the manual. `printf` works like C's printf which allows to format contents written to stdout.

- `has` crashed if applied on self-referencing structures (cycles), this has been fixed.

- `environ.isselfref` has been tuned by 600 %.

- Improved the manual and the Quick Reference.


1.6.14, July 04, 2012

- The `has` function has been tuned by a further 35 percent.


1.6.13, July 01, 2012

- `has` is now a C base library function and thus is three to six times faster than the former Agena implementation.


1.6.12, June 26, 2012

- Patched `os.list` (and thus implicitely also `utils.findfiles`) which did not properly acknowledge filename wildcards when descending into subdirectories.

- Further slimmed the C API by transforming lua_rawsetstringnumber, lua_rawsetstringstring, and lua_rawsetstringboolean into pre-processor macros.

- `environ.release` now also includes the patchlevel of the lib/library.agn file as its fourth entry.

- If the new global variable `environ.libpatchlevel` is defined in the lib/library.agn file, the main Agena Library patchlevel is also printed at start-up.

- Slimmed down the start-up message. Type `agena -m` to get the amount of free RAM at start-up.

- Readied Agena for lib/library.agn updates.


1.6.11, June 24, 2012

- 'utils.findfiles' can now also process a single file.

- Hardened Agena.

- Converted the C API functions lua_rawsetinumber, lua_seqsetinumber, lua_seqrawsetilstring, lua_seqsetistring, lua_sinsertnumber, lua_seqrawgeti, and lua_sinsertstring to pre-processor macros.

- Deleted the internal C API function agnSeq_rawseti.


1.6.10, June 22, 2012

- `utils.decodexml` and `utils.readxml` can now ignore XML comments with the new 'nocomment' option.

- The new function `utils.findfiles` returns all names of files that include a given search criterion.

- Since Agena 1.6.8, `io.readlines` could crash when trying to read thousands of characters from one single line. This has been fixed.

- Corrected storage of multiple entries with the same XML object name in `utils.decodexml`. All entries are now in the same hierarchy.


1.6.9, June 20, 2012

- Since Agena 1.6.8, 'size' returned wrong results if elements have been deleted from tables. This has been fixed.


1.6.8, June 19, 2012

- Re-instated `io.readlines`.

- The following former C API functions have been deprecated but have been replaced by C pre-processor define's: lua_rawsetistring, lua_rawsetilstring, lua_sinsertlstring, lua_sinsert.

- Removed an unnecessary C function call from the lua_rawseti procedure.

- Removed old and unused code from the ADS library.


1.6.7, June 17, 2012

- Extended `utils.decodexml` and `utils.encodexml` to recognize multiple occurences of the same XML objects.

- `ads.openbase` crashed when trying to open non-ADS files. This has been fixed.

- Shortened the C code of the lexer and the C API.


1.6.6, June 12, 2012

- Upon Agena exit, the `net` package now cleans its internal open socket admin table.

- Removed an unnecessary internal function call when printing results at the console.

- Hardened Agena.


1.6.5, June 10, 2012

- `setbit` has been rewritten in C and thus is around eight times faster than before.

- `getbit` has been rewritten in C and thus is around five times faster than before. It also now works correctly with negative numbers.

- In Windows, the `net` package now cleans up the Winsock environment upon exit.

- In Windows, `net.lookup` closed Winsock. This has been fixed.


1.6.4, June 07, 2012

- The new function `net.shutdown` stops further sends and receives on a socket.

- The net package now supports black and white lists for outgoing and incoming connections, Chapter 7.26.2 of the manual includes a description of their functionality (see functions `net.connect` and `net.accept`) and Chapter 7.26.1 includes examples.

- `net.send` now returns 'fail' if the socket has not been connected by either `net.connect` or `net.accept`.

- `net.openfiles` now also returns the read/write modes of a socket.

- The `fractals` package: The following environment variables have been renamed: `environ.FractScreenUpdates` to `environ.fractscreenupdates`, `environ.FractintColorMaps` to `environ.fractintcolourmaps`. Aliases for the old names (in capital letters), have surely been provided but will be relinquished in Agena 1.7.

- In Windows, `net.lookup` unnecessarily initialised Winsock, but worked flawlessly. However, this has been patched.

- `io.open` and `io.close` crashed Agena if the global table `io.openfiles` has been deleted or set to another data type. This has been fixed.

- Malicious code crashed Agena, this has been patched:
  > environ := null
  > a:

- At least in Linux, Agena crashed if `net.send` tried to send data to a partner that has already closed the connection. This has been fixed also for all other `net` functions by generally intercepting and ignoring C's SIGPIPE signal in all supported UNIX versions of Agena.

- Hardened the 'net' and 'binio' packages, as well as 'os.fcopy'.

- The C API function `agn_getenv` has been deleted. Use the new `agnL_gettablefield` C function instead.

- Some code optimisations. At least with gcc for Linux, no warnings should be issued any longer during compilation.

- Improved the manual and its index.

- Adapted AgenaEdit.


1.6.3, June 04, 2012

- The new function `utils.encodexml` creates an XML stream from a dictionary.

- The new function `utils.writexml` writes an XML stream from a a dictionary into a file.

- The new function `getbit` checks whether a bit is set in an integer at a given position.

- In nested expressions, the `&&`, `||`, `^^`, `xor`, `::`, `:-`, and `atendof` could return 'null' instead of a correct result. This has been fixed, so that also `setbit` does now work properly.

- `net.receive` no longer issues an error if an error occurs during receipt, but returns 'false' and a string with an error message. It also does not close the socket any longer in case of failure.

- Added some more examples to Chapter 7.26, `The net package`.


1.6.2, May 31, 2012

- You can now exchange unencrypted data over the Internet and local LANs using the IPv4 protocol (Windows, Linux, and Mac versions only). Please read chapter 7.26 `net package` carefully for further information.

- `utils.readxml` unfortunately did not close the XML file after reading it. This has been fixed.


1.6.1, May 28, 2012

- Extended `save` and `read` to store and restore Agena procedures.

- Added the new `utils.readxml` function to convert XML files into an Agena dictionary.

- Added the new `utils.decodexml` function to convert a XML stream represented by a string into an Agena dictionary.

- Added the new Base64 functions `utils.encodeb64` and `utils.decodeb64` to Base64-encode and decode strings.

- `loadstring` in many cases could not read binary chunks created by `strings.dump`. This has been fixed.

- Further hardening of functions and features.

- Updated the keyword and function name lists of AgenaEdit and hardened some of its features.


1.6.0, May 21, 2012

New Functions and Features:

- The new function `checktype` determines whether all values in a structure are of a given type.

- The new function `isint` checks whether all of its arguments are integers.

- The new function `strings.dleven` returns the Damerau-Levenshtein distance of two strings.

- The new function `stats.ad` determines the absolute deviation of all the values in a structure.

- The new function `stats.countentries` counts the number of occurrence of all the elements in a structure.

- The new function `stats.deltalist` returns a structure of the deltas of the respective neighbouring elements.

- The new function `stats.gmean` returns the geometric mean of a structure.

- The new function `stats.hmean` returns the harmonic mean of a structure.

- The new function `stats.ios` returns a proven indicator on stability in a distribution.

- The new function `stats.iqr` returns the interquartile range.

- The new function `stats.issorted` checks whether all numbers in a structure are sorted in ascending order.

- The new function `stats.moment` computes the moment of the given data about an origin.

- The new function `stats.numbperm` returns the number of permutations.

- The new function `stats.percentile` determines percentiles.

- The new function `stats.skewness` returns the skewness, an indicator of the symmetry of a probability distribution.

- The new function `stats.sumdata` sums up all the powers of a structure about an origin.

- `stats.tovals` is now a C library function and thus is up to 40 percent faster.

- With an empty table or sequence, `stats.qmean`, `stats.mean`, `stats.gmean`, `stats.sd`, `stats.median`, `stats.var` now return fail.

- The maximum length for an input line in the stand-alone interpreter has been changed from 512 to 2048 characters.

- The new environment variable `environ.maxpathlength` stores the maximum number of characters for a file path (excluding C's \0 character).

- The new environment variables `environ.minnumber` and `environ.maxnumber` hold the minimum and maximum value an Agena number (currently an ANSI-C double) can store.

- The new environment variable `environ.umaxlong` includes the maximum integral value of the C type unsigned long on 32+bit systems, and unsigned long on 16bit machines.

C API:

- 100 % compatibility of the Agena C API to Lua's C API has been re-established by introducing Lua's *dump functions. Thus you are now able to store functions in a binary representation, e.g. by using `strings.dump` or lua_dump on the C level.

- Introduced the new `agnL_optboolean` function to check for optional Boolean arguments and return them in case of success.

Bug Fixes:

- `environ.globals` always quit with an error, this has been fixed.

- `approx` returned false with both of its arguments being or evaluating to 'undefined'. It now returns true in this case.

- Agena crashed when passing an empty table _and_ a delimitor to `join` - this has been fixed.

- The `colour` option is no longer being ignored by `gdi.plot`.

- With tables, `stats.minmax` returned a wrong value for the minimum. It now works correctly.

- With an empty table, `stats.median` returned 0, now it returns fail.

- Contrary to the documentation, `strings.isending` returned 'true' with both strings being equal. This has been fixed.

- `run` returned `could not open file` if an existing Agena script included a syntax error. This has been changed to a more comprehensible error message by completely rewriting the function.

- Added Lua 5.1.4 patch 9: "Wrong code generation for some particular [e.g. complex] boolean expressions."

- Added Lua 5.1.4 patch 11: "Parser may collect a prototype while building it."

* Info: Adding Lua 5.1.4 patch 10, "[__write/__new]index metamethod may not work if metatable is its own metatable", to Agena is not necessary, for Agena already works correctly in this case.

- Removed the unused keyword `default`.

- Some hardening of functions and features.

Enhancements:

- Added an _experimental_ version of `io.anykey` to the Mac version. However, at least on Lion, the key being pressed sometimes is echoed on the shell.

- `utils.readcsv` now can optionally return all values in a CSV file in a flat sequence.

- The `clock` package now supports the division operator `/` by adding it to its `tm` operator's metatable.

- The behaviour of `with` has been changed for it could not assign short names for many library functions: If functions have been put into the <pkgname>.aux table, it does not assign short names for these function names; otherwise it assigns short names for _all_ other package functions. Thus:

- `package.register` to register all the library functions for `with` to assign short names, is no longer needed. It will be deprecated in one of the following releases.

- Improved the test suite.

Manual:

- Improved the manual and extended its index.

Consistency:

For all of the following renamings, the following old variable names are still supported.

- `environ.MinLong` has been renamed to `environ.minlong`.

- `environ.MaxLong` has been renamed to `environ.maxlong`.

- `environ.BufferSize` has been renamed to `environ.buffersize`.

- `environ.PathSep` has been renamed to `environ.pathsep`.

- `environ.More` has has been renamed to `environ.more`.

- `environ.WithProtected` has been renamed to `environ.withprotected`.

- `environ.Os` has been renamed to `environ.os`.

- `environ.Cpu` has been renamed to `environ.cpu`.

- `environ.Release` has been renamed to `environ.release`.

- `environ.GdiDefaultOptions` has been renamed to `environ.gdidefaultoptions`.

- In Windows, `os.login` and `os.computername` now return 'fail' like the UNIX and OS/2 versions do.

- The `-DCOMPAT13` switch has been finally removed for compiling an Agena 1.3.x complient version.

Other:

- Deprecated `calc.fseq` has been deleted. Please use `nseq` instead.
Source: README.TXT, updated 2024-04-19