(4.0rc2, preparing v4.0)

* Python 3.7+ is now required
  Please note: as announced when releasing v3.3, support for py2.7 has been
  dropped

* Message delivery time improved by ~20%.  Thanks to Mathieu Cousy for his
  patch!

  The handling of subscriptions (regexps) has been moved from IvyClient to
  IvyServer.  As a consequence, the ivy.ivy API has changed, please refer to
  the code and its documentation.

* Fixed: an invalid regexp sent on the bus cannot crash an agent anymore

* std_api: add a new function IvyGetMessages() to get the agent's own
  subscriptions

* The delta between ping request and pong answers is now calculated using a
  monotonic clock instead of the system clock.
  New method: IvyServer.get_next_ping_delta_ns(): the delta in nanoseconds

* Fix: the "ready" message is now correctly sent.  It was erroneously sent as
  is and attributed to subscription number 0, ignoring the client's
  subscriptions.
  Thanks to Mathieu Cousy for noticing and reporting the bug!

* ivyprobe:

  - now shows the number of connected agents when it changes;

  - can now send message that are empty or made of whitespaces only, and it
    now displays them unambiguously ('' for the empty string e.g.);

  - ensures that the user-supplied id for direct and error messages are
    integers;

  - has a new option (-r/--ready) to customize the "ready" message.

* Numerous code clean-ups and enhancements, such as the addition of type hints
  in the whole codebase.

v3.3
----

* Bug fixes:
  - Support for Python 2.7 was broken in v3.2

  - Ivy timers can now be used through std api's IvyTimerRepeatAfter()
    in Python 3.x.  Thanks to Alexandre Duchevet.

  - The Ivy bus could not be started when using Python v3.9+
    Thanks to Mathieu Cousy and to Fabien-B for their independent
    reports.

v3.2
----

* Fixed: the Ivy agent crashed, was disconnected and not functional
  anymore when a callback raised upon:
  - noticing an agent has joined or left the bus,
  - receiving a message,
  - receiving a direct message,
  - receiving a pong reply,
  - receiving modifications of an other agent's subscriptions
    (addition or removal)
  - receiving a request to terminate itself (the "die" message)
  The exception is now logged at the ERROR level and ignored.

* Handle misformatted MSG protocol message as ivy-c does.  This
  concerns messages where the last ETX was missing, and it was the
  cause of interoperability errors between different implementations
  of the Ivy bus.
  See commit 94675918b57fc71e for the full details.
  Thanks to Duminda Ratnayake for the bug report.

* ivyprobe.py:
  - Add the option -s/--show-bindings to the ivyprobe CLI
  - When called with a name corresponding to no agent on the bus, the
    command .regexps now notifies the user that no such agent exists
    (it was previously showing its own bindings instead).

* Updated the documentation, a tutorial was added.
  Documentation is available online at https://ivy-python.readthedocs.io/

v3.1
----
* code cleanup: removed unnecessary calls to list() --introduced by
  the 2to3 tool. Thanks to Aurélien Pardon for noticing and reporting!

v3.0
----
* Support for both python2.7+ and python 3.x

* Fix a bug in examples/ivyprobes where IvyServer.stop() was called
  twice after the agent receives a "die" message.

v2.3-pre-2
----------

* The serial number for PING/PONG messages is not exposed anymore in the API.
  In fact, it is also not used anymore in the protocol.

* Removed the ability to mimic ivy-c behaviour.

v2.3-pre-1
----------

* ping/pong: fully implemented

* Fixed: any error occurring when an agent tried to establish the
  connection to a new client on the bus, triggered an AttributeError
  exception within UDP_init_and_listen(): as a result, that agent was
  not detecting any new clients on the bus afterwards.  Thanks to
  Antoine Drouin for noticing it and proposing the patch.

* ivy-python agents now properly reply to ping requests, thanks to
  Fabien André.  They cannot ping other agents yet.

* std_api.IvyMainLoop(): now honors SIGINT, thanks to Fabien André

* Fixed: when a message was sent on the bus matching two or more
  subscriptions of an agent, only one message was actually sent to
  this agent, meaning that only one of the corresponding callbacks was
  called.  This is no longer the case, and ivy-python now behaves as
  expected: all callbacks bound to subscriptions that a message posted
  on the bus matches are now triggered, no matter how many such
  subscriptions one agent has.

  All credits go to Felix Ruess, member of the paparazzi UAV project's
  team, who reported the bug and submitted the fix. Many thanks, Felix!

* Fixed: an exception was raised when trying to send a message
  corresponding to a subscription in which an optional group is not
  participating to the match (example: subscription regexp='MSG(.*)?',
  msg='MSG'). Thanks to github user «alonsoac» for reporting the bug
  and to Felix Ruess for telling me!

* IvyServer.send_direct_message(): new parameter 'stop_on_first' added

* Bohdan Mushkevych has done a lot of work on the source code to clean
  it up, to correct misspellings, and to make it more "Pythonic"
  (especially by following pep8 recommendations).
  Great job, thanks a lot Dan!

v2.2
----

* It is now possible to stop and restart an IvyServer, without recreating it.
  This is particularly useful for the std_api, where IvyStart() can be called
  again after IvyStop().
  Thanks to Jiri Borovec for reporting the problem.

v2.1
----

* ivyprobe.py is now declared as a runnable script and installed as such when
  installing or upgrading ivy-python

* Fixed: an exception raised while connecting to a new agent which has just
  sent its initial UDP broadcast message was not handled, stopping the agent
  from listening to broadcast messages and as result, new agents connecting to
  the bus were ignored after this happened.  This is no longer the case:
  exceptions occuring while connecting to new clients (e.g. timeout) are
  logged but ignored, as expected.

* Fixed std_api.IvyInit(): the default values for parameters on_cnx_fct and
  on_die_cnx were wrong

v2.0
----

* Signatures of ALL callbacks have been changed: 1st parameter passed to the
  callbacks is now *always* an IvyClient object, representing the agent
  whose message/behaviour triggered the callback.

  Example: a callback given to IvyBindMsg() was::

    def on_msg(*regexp_groups)

  must be changed to::

    def on_msg(agent, *regexp_groups)

  Based on an original patch by Olivier Saal who did most of the work, thanks
  Olivier.

  **IMPORTANT** Please note that this changes breaks backward compatibility:
                agents coded for ivy-python v1.x must be adapted so that their
                callbacks accept the new parameter.


v1.2
----

* The official subversion repository is now located at
  https://svn.tls.cena.fr/svn/ivy/
  Many thanks to the CENA team, and to Olivier Fourdan in particular,
  for setting up the global repository for ivy implementations.

* New format of UDP broadcast messages, including the agent's id and name is
  now correctly handled.
  (cf. https://sympa.tls.cena.fr/wws/arc/ivy/2006-05/msg00004.html
   &   https://sympa.tls.cena.fr/wws/arc/ivy/2006-11/msg00010.html).

  Thanks to Olivier Saal for reporting.

* Added examples/ivyprobe.py, a fully-featured ivyprobe in pure-python

* Added: ivy.IvyClient.get_regexps() and std_api.IvyGetApplicationMessages()

* Added: ivy.IvyClient.send_error() and std_api.IvySendError()

* Added the ability to bind a callback for monitoring changes in other agents'
  subscriptions/bindings

    stdapi: IvyBindRegexpChange()
    ivy: IvyServer.bind_regexp_change()

  Callback signature: on_regexp_change(client, event, regexp_id, regexp)
  where
   - 'client' is an IvyClient object,
   - 'event' is either ivy.ivy.IvyRegexpAdded or IvyRegexpRemoved

* Added the ability to bind a callback for direct messages

    stdapi: IvyBindDirectMsg()
    ivy:    IvyServer.bind_direct_msg()

  Callback signature: on_direct_msg_callback(client, num_id, msg)
  (where 'client' is an IvyClient object)

* Fixed: stdapi.IvySendMsg() was not returning the number of peers to which
  the message was sent

* Fixed: the UDP listening socket did not set the SO_REUSEPORT on systems where
  this flag is defined (such as: mac os x). On such systems, when more than one
  ivy-process was launched on the same bus, all processes but one failed with
  an error stating that the (udp broadcast) port was already in use.

v1.1
----

* Implementation is now MT-safe

* added support for class D/multicast addresses

* Implemented std_api.IvyUnBindMsg() and related methods in ivy.py

* Fixed: IvyServer.send_msg() and IvyClient.send_msg() do not fail anymore
  when a client disconnects abruptly (it could fail when send_msg() was called
  just before the server notices the faulty connecion and unregisters the
  corresponding agent)

v1.0
----

First public release
