text:
import * as utils from './Utils';

/**
 * Create a Timeline Instance
 * @param {DOM node} args.element   	The SVG Node
 * @param {Array} args.levels 		   	SVG Levels object
 */
export default class Timeline {

	constructor(args) {

		this._element = args.element
		this._timeline = this.getTimeline()
		this._position = 0
		this._levels = args.levels || []
		this._levelsSelector = []

		this.setGlobalSettings()
		this.setLevels(this._levels)

	}

	/**
	 * Save levels and create Timeline
	 * @param {Array} l 	Levels array
	 */
	setLevels(l) {

		this._levels = l
		this.createTimeline()

	}

	/**
	 * Save position and sync Timeline
	 * @param {Number} c 	Timeline position
	 */
	setPosition(p) {

		this._position = p
		this.seekTo()

	}

	/**
	 * Create Timeline and append Tweens
	 * @return {Object}  	Timeline instance
	 */
	createTimeline() {

		this.reset()
		this.showSVG()
		this.createLevelsSelector()
		this.createLevelsTimeline()

		return this._timeline

	}

	/**
	 * Reset levels inline style and Timeline
	 */
	reset() {

		this.resetLevels()
		this.resetTimeline()

	}

	/**
	 * Show SVG Node hidden in getSvgNode method
	 */
	showSVG() {

		this.showElement({
			timeline: this._timeline,
			element: this._element,
			position: 0
		})

	}

	/**
	 * If empty, create Nodelist array of Levels
	 * IMPORTANT FOR PERFORMANCE: Unique querySelector is called here, in getElement method
	 */
	createLevelsSelector() {

		if (this._levelsSelector.length == 0) {

			this._levelsSelector = this._levels.map(e => this.getElement({
				id: e.id
			}))

		}

	}

	/**
	 * Complete level object data, create levels TM and append to main timeline
	 * IMPORTANT FOR PERFORMANCE: Unique for cycle on Levels is here!
	 */
	createLevelsTimeline() {

		for (var i = 0; i < this._levels.length; i++) {

			var tweens = this._levels[i].tweens

			for (var t = 0; t < tweens.length; t++) {

				var tween = tweens[t]

				this.completeLevelTweenObject({
					tween,
					index: i
				})

				this.createLevelTween({
					tween
				})

				this.appendObjectToTimeline({
					timeline: this._timeline,
					object: tween.timeline,
					position: tween.position
				})

			}

		}

		for (var i = 0; i < this._levels.length; i++) {

			var tweens = this._levels[i].tweens

			/**
			 * Hide the element at position 0, only if there isnt' any tween in position 0
			 */

			if (
				tweens.length > 0
				&& tweens.sort((a, b) => a.position - b.position)[0].position > 0
			) {

				this.hideElement({
					timeline: this._timeline,
					element: tweens[0].element,
					position: 0
				})

			}

			for (var t = 0; t < tweens.length; t++) {

				var tween = tweens[t]

				this.setLevelVisibility({
					tween
				})

			}

		}

	}

	/**
	 * Complete tween object data with element and empty timeline object
	 * @param {Object} 	data.tween 		Level tween object
	 * @param {index} 	data.index 		Level index, relative to Levels object
	 */
	completeLevelTweenObject(data) {
		data.tween.element = this._levelsSelector[data.index]
		data.tween.timeline = this.getTimeline()
	}

	/**
	 * Create tween for each level, if duration exist and it's not equal to 0
	 * @param {Object} 	data.level 		Level object
	 * @param {Object} 	data.tween 		Level tween
	 */
	createLevelTween(data) {

		var tween = data.tween

		if (
			!tween.duration
			|| tween.duration == 0
		) return

		this.createLevelEmptyTween({
			tween
		})

		this.createLevelPropertiesTimeline({
			tween
		})

	}

	/**
	 * Create empty tween, for set duration of level
	 * @param {Object} 	data.tween 		Level tween object
	 */
	createLevelEmptyTween(data) {

		var tween = data.tween
		var element = tween.element
		var timeline = tween.timeline

		var object = this.getStaticTween({
			element,
			property: {
				clearProps: 'all'
			}
		})

		this.appendObjectToTimeline({
			object,
			timeline,
			position: 0
		})

		var object = this.getStaticTween({
			element,
			property: {}
		})

		this.appendObjectToTimeline({
			object,
			timeline,
			position: tween.duration
		})

	}

	/**
	 * Hide level on main timeline
	 * Set visibility on level timeline based on its duration
	 * @param {Object} 	data.tween 		Level tween object
	 */
	setLevelVisibility(data) {

		var tween = data.tween
		var element = tween.element
		var timeline = tween.timeline

		var duration = this.getDuration({
			timeline: this._timeline
		})

		this.showElement({
			timeline,
			element,
			position: 0
		})

		if (
			tween.duration > 0
			&& utils.toFixedNumber(tween.position + tween.duration) < duration
		) {

			this.hideElement({
				timeline,
				element,
				position: tween.duration
			})

		}

	}

	/**
	 * Create Level Properties timeline and append to begin of Level timeline
	 * IMPORTANT FOR PERFORMANCE: unique for cycle over level properties object is here
	 * @param  {Object} data.tween  Level tween object
	 */
	createLevelPropertiesTimeline(data) {

		var properties = data.tween.properties

		for (var key in properties) {

			if (properties[key].length > 0) {

				var timeline = this.getLevelPropertyTimeline({
					tween: data.tween,
					properties: properties[key]
				})

				this.appendObjectToTimeline({
					position: 0,
					object: timeline,
					timeline: data.tween.timeline
				})

			}

		}

	}

	/**
	 * Get Level Property timeline
	 * IMPORTANT FOR PERFORMANCE: unique for cycle over property of properties key is here
	 * @param  {Object} data.level    		Level object
	 * @param  {Array} data.properties    	Property array
	 * @return  {Object} 					Properties timeline
	 */
	getLevelPropertyTimeline(data) {

		var timeline = this.getTimeline()

		var properties = this.sortPropertiesByPosition({
			properties: data.properties
		})

		/**
		 * Append first property with duration 0 to timeline
		 */

		let clonedFirstProperty = Object.assign({}, properties[0])

			this.createPropertyTween({
				timeline,
				tween: data.tween,
				property: Object.assign(clonedFirstProperty, {
					duration: 0,
					position: 0
				})
			})

		/**
		 * Create other property tween
		 */

		for (var i = 0; i < properties.length; i++) {

			let property = Object.assign({}, properties[i])
			let prevProperty = Object.assign({}, properties[i - 1])

			switch(i) {

				case(0):

					property.duration = data.tween.duration * property.position
					property.position = 0

				break;
				default:

					property.duration = data.tween.duration * (property.position - prevProperty.position)
					property.position = data.tween.duration * prevProperty.position

			}

			this.createPropertyTween({
				timeline,
				tween: data.tween,
				property
			})

		}

		return timeline

	}

	/**
	 * Sort properties array to property position
	 * @param  {Array} data.properties    		Level Properties array
	 * @return  {Object}  						Sortered Level Properties array
	 */

	sortPropertiesByPosition(data) {

		var properties = data.properties.sort((a, b) => {
			return a.position - b.position;
		});

		return properties

	}

	/**
	 * Create Level Property tween and append to properties timeline
	 * @param  {Object} data.timeline    		Level properties timeline
	 * @param  {Object} data.tween    			tween object
	 * @param  {Array} data.property    		Property object
	 */
	createPropertyTween(data) {

		var tween = this.getTweenByType({
			element: data.tween.element,
			type: data.property.type,
			property: data.property
		})

		this.appendObjectToTimeline({
			timeline: data.timeline,
			object: tween,
			position: data.property.position
		})

	}

	/**
	 * Get Element node
	 * @param {String} 	data.id 		Element id
	 * @return {Object} 				Element node
	 */
	getElement(data) {

		var element = this._element.querySelector(`[data-fresh-id="${data.id}"]`)
		return element

	}

	/**
	 * Hide element trough visibility property
	 * @param  {Object} data.timeline   	The Timeline object
	 * @param  {DOM Node} data.element   	The Level Dom Node
	 * @param  {Number} data.position   	Position of tween
	 */
	hideElement(data) {

		var tween = this.getStaticTween({
			element: data.element,
			property: {
				visibility: 'hidden'
			}
		})

		this.appendObjectToTimeline({
			timeline: data.timeline,
			object: tween,
			position: data.position
		})

	}

	/**
	 * Show element trough visibility property
	 * @param  {Object} data.timeline   	The Timeline object
	 * @param  {DOM Node} data.element   	The Level Dom Node
	 * @param  {Number} data.position   	Position of tween
	 */
	showElement(data) {

		var tween = this.getStaticTween({
			element: data.element,
			property: {
				visibility: 'visible'
			}
		})

		this.appendObjectToTimeline({
			timeline: data.timeline,
			object: tween,
			position: data.position
		})

	}

}


text:
Quality of Service (QoS): Guaranteed Minimum Bandwidth
======================================================

Most Networking Quality of Service (QoS) features are implemented solely
by OpenStack Neutron and they are already documented in the :doc:`QoS
configuration chapter of the Networking Guide <config-qos>`.  Some more
complex QoS features necessarily involve the scheduling of a cloud server,
therefore their implementation is shared between OpenStack Nova, Neutron
and Placement. As of the OpenStack Stein release the Guaranteed Minimum
Bandwidth feature is like the latter.

This Networking Guide chapter does not aim to replace Nova or Placement
documentation in any way, but it still hopes to give an overall
OpenStack-level guide to understanding and configuring a deployment to
use the Guaranteed Minimum Bandwidth feature.

A guarantee of minimum available bandwidth can be enforced on two levels:

* Scheduling a server on a compute host where the bandwidth is available.
  To be more precise: scheduling one or more ports of a server on a compute
  host's physical network interfaces where the bandwidth is available.
* Queueing network packets on a physical network interface to provide the
  guaranteed bandwidth.

In short the enforcement has two levels:

* (server) placement and
* data plane.

Since the data plane enforcement is already documented in the
:doc:`QoS chapter <config-qos>`,
here we only document the placement-level enforcement.

Limitations
-----------

* A pre-created port with a ``minimum-bandwidth`` rule must be passed
  when booting a server (``openstack server create``). Passing a network
  with a minimum-bandwidth rule at boot is not supported because of
  technical reasons (in this case the port is created too late for
  Neutron to affect scheduling).

* Bandwidth guarantees for ports can only be requested on networks
  backed by a physical network (physnet).

* In Stein there is no support for networks with multiple physnets.
  However some simpler multi-segment networks are still supported:

  * Networks with multiple segments all having the same physnet name.
  * Networks with only one physnet segment (the other segments being
    tunneled segments).

* If you mix ports with and without bandwidth guarantees on the same physical
  interface then the ports without a guarantee may starve. Therefore mixing
  them is not recommended. Instead it is recommended to separate them by
  :nova-doc:`Nova host aggregates <admin/aggregates>`.

* Changing the guarantee of a QoS policy (adding/deleting a
  ``minimum_bandwidth`` rule, or changing the ``min_kbps`` field of a
  ``minimum_bandwidth`` rule) is only possible while the policy is not in
  effect. That is ports of the QoS policy are not yet used by Nova. Requests
  to change guarantees of in-use policies are rejected.

* Changing the QoS policy of the port with new ``minimum_bandwidth`` rules
  changes placement ``allocations`` from Wallaby release.
  If the VM was booted with port without QoS policy and ``minimum_bandwidth``
  rules the port update succeeds but placement allocations will not change.
  The same is true if the port has no ``binding:profile``, thus no placement
  allocation record exists for it. But if the VM was booted with a port with
  QoS policy and ``minimum_bandwidth`` rules the update is possible and the
  allocations are changed in placement as well.

.. note::

  As it is possible to update a port to remove the QoS policy, updating it
  back to have QoS policy with ``minimum_bandwidth`` rule will not result in
  ``placement allocation`` record, only the dataplane enforcement will happen.

.. note::

  updating the ``minimum_bandwidth`` rule of a QoS policy that is attached
  to a port which is bound to a VM is still not possible.

* The first data-plane-only Guaranteed Minimum Bandwidth implementation
  (for SR-IOV egress traffic) was released in the Newton
  release of Neutron.  Because of the known lack of
  placement-level enforcement it was marked as "`best effort
  <https://docs.openstack.org/releasenotes/neutron/newton.html#other-notes>`_"
  (5th bullet point).  Since placement-level enforcement was not implemented
  bandwidth may have become overallocated and the system level
  resource inventory may have become inconsistent. Therefore for users
  of the data-plane-only implementation a migration/healing process is
  mandatory (see section `On Healing of Allocations`_) to bring the system
  level resource inventory to a consistent state. Further operations
  that would reintroduce inconsistency (e.g. migrating a server with
  ``minimum_bandwidth`` QoS rule, but no resource allocation in Placement)
  are rejected now in a backward-incompatible way.

* The Guaranteed Minimum Bandwidth feature is not complete in the Stein
  release. Not all Nova server lifecycle operations can be executed on a
  server with bandwidth guarantees. Since Stein (Nova API microversion
  2.72+) you can boot and delete a server with a guarantee and detach
  a port with a guarantee. Since Train you can also migrate and resize
  a server with a guarantee. Support for further server move operations
  (for example evacuate, live-migrate and unshelve after shelve-offload)
  is to be implemented later. For the definitive documentation please
  refer to the `Port with Resource Request chapter
  <https://docs.openstack.org/api-guide/compute/port_with_resource_request.html>`_
  of the OpenStack Compute API Guide.

* If an SR-IOV physical function is configured for use by the
  neutron-openvswitch-agent, and the same physical function's virtual
  functions are configured for use by the neutron-sriov-agent then the
  available bandwidth must be statically split between the corresponding
  resource providers by administrative choice. For example a 10 Gbps
  SR-IOV capable physical NIC could be treated as two independent NICs -
  a 5 Gbps NIC (technically the physical function of the NIC) added to
  an Open vSwitch bridge, and another 5 Gbps NIC whose virtual functions
  can be handed out to servers by neutron-sriov-agent.

* Neutron allows physnet names to be case sensitive. So physnet0 and
  Physnet0 are treated as different physnets. Physnets are mapped to
  traits in Placement for scheduling purposes. However Placement traits are
  case insensitive and normalized to full capital. Therefore the scheduling
  treats physnet0 and Physnet0 as the same physnet. It is advised not to use
  physnet names that are only differ by case.

* There are hardware platforms (e.g.: Cavium ThunderX) where it's possible
  to have virtual functions which are network devices that are not associated
  to a physical function. As bandwidth resources are tracked per physical
  function, for such hardware the placement enforcement of the QoS minimum
  bandwidth rules cannot be supported. Creating a server with ports using such
  QoS policy targeting such hardware backend will result in a ``NoValidHost``
  error during scheduling.

* When QoS is used with a trunk, Placement enforcement is applied only to the
  trunk's parent port. Subports are not going to have Placement allocation.
  As a workaround, parent port's QoS policy should take into account subports
  needs and request enough minimum bandwidth resources to accommodate every
  port in the trunk.

Placement pre-requisites
------------------------

Placement must support `microversion 1.29
<https://docs.openstack.org/placement/latest/placement-api-microversion-history.html#support-allocation-candidates-with-nested-resource-providers>`_.
This was first released in Rocky.

Nova pre-requisites
-------------------

Nova must support `microversion 2.72
<https://docs.openstack.org/nova/latest/reference/api-microversion-history.html#maximum-in-stein>`_.
This was first released in Stein.

Not all Nova virt drivers are supported, please refer to the
`Virt Driver Support section of the Nova Admin Guide
<https://docs.openstack.org/nova/latest/admin/port_with_resource_request.html#virt-driver-support>`_.

Neutron pre-requisites
----------------------

Neutron must support the following API extensions:

* ``agent-resources-synced``
* ``port-resource-request``
* ``qos-bw-minimum-ingress``

These were all first released in Stein.

Supported drivers and agents
~~~~~~~~~~~~~~~~~~~~~~~~~~~~

In release Stein the following agent-based ML2 mechanism drivers are
supported:

* Open vSwitch (``openvswitch``) vnic_types: ``normal``, ``direct``
* SR-IOV (``sriovnicswitch``) vnic_types: ``direct``, ``macvtap``, ``direct-physical``
* OVN (``ovn``) vnic_types: ``normal``

.. note::

  SR-IOV (``sriovnicswitch``) agent does not handle ``direct-physical`` ports. However
  the agent can report the bandwidth capacity of a network device that will be used
  by a ``direct-physical`` port.

neutron-server config
~~~~~~~~~~~~~~~~~~~~~

The ``placement`` service plugin synchronizes the agents' resource
provider information from neutron-server to Placement.

Since neutron-server talks to Placement you need to configure how
neutron-server should find Placement and authenticate to it.

``/etc/neutron/neutron.conf`` (on controller nodes):

.. code-block:: ini

    [DEFAULT]
    service_plugins = placement,...
    auth_strategy = keystone

    [placement]
    auth_type = password
    auth_url = https://controller/identity
    password = secret
    project_domain_name = Default
    project_name = service
    user_domain_name = Default
    username = placement

If a vnic_type is supported by default by multiple ML2 mechanism
drivers (e.g. ``vnic_type=direct`` by both ``openvswitch`` and
``sriovnicswitch``) and multiple agents' resources are also meant to be
tracked by Placement, then the admin must decide which driver to take
ports of that vnic_type by prohibiting the vnic_type for the unwanted
drivers. Use :oslo.config:option:`ovs_driver.vnic_type_prohibit_list` in this
case. Valid values are all the ``supported_vnic_types`` of the
`respective mechanism drivers
<https://docs.openstack.org/neutron/latest/admin/config-ml2.html#supported-vnic-types>`_.

``/etc/neutron/plugins/ml2/ml2_conf.ini`` (on controller nodes):

.. code-block:: ini

    [ovs_driver]
    vnic_type_prohibit_list = direct

    [sriov_driver]
    #vnic_type_prohibit_list = direct

neutron-openvswitch-agent config
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Set the agent configuration as the authentic source of
the resources available. Set it on a per-bridge basis by
:oslo.config:option:`ovs.resource_provider_bandwidths`.
The format is: ``bridge:egress:ingress,...``
You may set only one direction and omit the other.

.. note::

    ``egress`` / ``ingress`` is meant from the perspective of a cloud server.
    That is ``egress`` = cloud server upload, ``ingress`` = download.

    Egress and ingress available bandwidth values are in ``kilobit/sec (kbps)``.

If desired, resource provider inventory fields can be tweaked on a
per-agent basis by setting
:oslo.config:option:`ovs.resource_provider_inventory_defaults`.
Valid values are all the
`optional parameters of the update resource provider inventory call
<https://docs.openstack.org/api-ref/placement/?expanded=update-resource-provider-inventory-detail#update-resource-provider-inventory>`_.

``/etc/neutron/plugins/ml2/ovs_agent.ini`` (on compute and network nodes):

.. code-block:: ini

    [ovs]
    bridge_mappings = physnet0:br-physnet0,...
    resource_provider_bandwidths = br-physnet0:10000000:10000000,...
    #resource_provider_inventory_defaults = step_size:1000,...

neutron-sriov-agent config
~~~~~~~~~~~~~~~~~~~~~~~~~~

The configuration of neutron-sriov-agent is analog to that of
neutron-openvswitch-agent. However look out for:

* The different .ini section names as you can see below.
* That neutron-sriov-agent allows a physnet to be backed by multiple physical
  devices.
* Of course refer to SR-IOV physical functions instead of bridges in
  :oslo.config:option:`sriov_nic.resource_provider_bandwidths`.

``/etc/neutron/plugins/ml2/sriov_agent.ini`` (on compute nodes):

.. code-block:: ini

    [sriov_nic]
    physical_device_mappings = physnet0:ens5,physnet0:ens6,...
    resource_provider_bandwidths = ens5:40000000:40000000,ens6:40000000:40000000,...
    #resource_provider_inventory_defaults = step_size:1000,...

OVN chassis config
~~~~~~~~~~~~~~~~~~

Bandwidth config values are stored in each SB chassis register, in
"external_ids:ovn-cms-options". The configuration options are the same as in
SR-IOV and OVS agents. This is how the values are registered:

.. code-block:: bash

    $ root@dev20:~# ovs-vsctl list Open_vSwitch
      ...
      external_ids        : {hostname=dev20.fistro.com, \
                             ovn-cms-options="resource_provider_bandwidths=br-ex:1001:2000;br-ex2:3000:4000, \
                                              resource_provider_inventory_defaults=allocation_ratio:1.0;min_unit:10, \
                                              resource_provider_hypervisors=br-ex:dev20.fistro.com;br-ex2:dev20.fistro.com", \
                             rundir="/var/run/openvswitch", \
                             system-id="029e7d3d-d2ab-4f2c-bc92-ec58c94a8fc1"}
      ...

Each configuration option defined in "external_ids:ovn-cms-options" is divided
by commas.

This information is retrieved from the OVN SB database during the Neutron
server initialization and when the "Chassis" registers are updated.

During the Neutron server initialization, a ``MaintenanceWorker`` thread will
call ``OvnSbSynchronizer.do_sync``, that will call
``OVNClientPlacementExtension.read_initial_chassis_config``. This method lists
all chassis and builds the resource provider information needed by Placement.
This information is stored in the "Chassis" registers, in
"external_ids:ovn-cms-options", with the same format as retrieved from the
local "Open_vSwitch" registers from each chassis.

The second method to update the Placement information is when a "Chassis"
registers is updated. The ``OVNClientPlacementExtension`` extension registers
an event handler that attends the OVN SB "Chassis" bandwidth configuration
changes. This event handler builds a ``PlacementState`` instance and sends it
to the Placement API. If a new chassis is added or an existing one changes its
resource provider configuration, this event updates it in the Placement
database.

Propagation of resource information
-----------------------------------

The flow of information is different for available and used resources.

The authentic source of available resources is neutron agent configuration -
where the resources actually exist, as described in the agent configuration
sections above. This information is propagated in the following chain:
``neutron-l2-agent -> neutron-server -> Placement``.

From neutron agent to server the information is included in the
``configurations`` field of the agent heartbeat message sent on the message
queue periodically.

.. code-block:: console

    # as admin
    $ openstack network agent list --agent-type open-vswitch --host devstack0
    +--------------------------------------+--------------------+-----------+-------------------+-------+-------+---------------------------+
    | ID                                   | Agent Type         | Host      | Availability Zone | Alive | State | Binary                    |
    +--------------------------------------+--------------------+-----------+-------------------+-------+-------+---------------------------+
    | 5e57b85f-b017-419a-8745-9c406e149f9e | Open vSwitch agent | devstack0 | None              | :-)   | UP    | neutron-openvswitch-agent |
    +--------------------------------------+--------------------+-----------+-------------------+-------+-------+---------------------------+

    # output shortened and pretty printed
    # note: 'configurations' on the wire, but 'configuration' in the cli
    $ openstack network agent show -f value -c configuration 5e57b85f-b017-419a-8745-9c406e149f9e
    {'bridge_mappings': {'physnet0': 'br-physnet0'},
     'resource_provider_bandwidths': {'br-physnet0': {'egress': 10000000,
                                                      'ingress': 10000000}},
     'resource_provider_inventory_defaults': {'allocation_ratio': 1.0,
                                              'min_unit': 1,
                                              'reserved': 0,
                                              'step_size': 1},
     ...
    }

Re-reading the resource related subset of configuration on ``SIGHUP`` is not
implemented. The agent must be restarted to pick up and send changed
configuration.

Neutron-server propagates the information further to Placement for
the resources of each agent via Placement's HTTP REST API. To avoid
overloading Placement this synchronization generally does not happen on
every received heartbeat message. Instead the re-synchronization of the
resources of one agent is triggered by:

* The creation of a network agent record (as queried by ``openstack network
  agent list``). Please note that deleting an agent record and letting the
  next heartbeat to re-create it can be used to trigger synchronization
  without restarting an agent.
* The restart of that agent (technically ``start_flag`` being present in the
  heartbeat message).

Both of these can be used by an admin to force a re-sync if needed.

The success of a synchronization attempt from neutron-server to Placement is
persisted into the relevant agent's ``resources_synced`` attribute. For
example:

.. code-block:: console

    # as admin
    $ openstack network agent show -f value -c resources_synced 5e57b85f-b017-419a-8745-9c406e149f9e
    True

``resources_synced`` may take the value True, False and None:

* None: No sync was attempted (normal for agents not reporting
  Placement-backed resources).
* True: The last sync attempt was completely successful.
* False: The last sync attempt was partially or utterly unsuccessful.

In case ``resources_synced`` is not True for an agent, neutron-server
does try to re-sync on receiving every heartbeat message from that
agent. Therefore it should be able to recover from transient errors
of Neutron-Placement communication (e.g. Placement being started later
than Neutron).

It is important to note that the restart of neutron-server does not trigger
any kind of re-sync to Placement (to avoid an update storm).

As mentioned before, the information flow for resources requested and
(if proper) allocated is different. It involves a conversation between Nova,
Neutron and Placement.

#. Neutron exposes a port's resource needs in terms of resource classes and
   traits as the admin-only ``resource_request`` attribute of that port.

#. Nova reads this and `incorporates it as a numbered request group
   <https://docs.openstack.org/nova/latest/admin/port_with_resource_request.html#resource-group-policy>`_
   into the cloud servers overall allocation candidate request to Placement.

#. Nova selects (schedules) and allocates one candidate returned by Placement.

#. Nova informs Neutron when binding the port of which physical network
   interface resource provider had been selected for the port's resource
   request in the ``binding:profile.allocation`` sub-attribute of that port.

For details please see `slides 13-15
<https://www.openstack.org/videos/summits/berlin-2018/guaranteed-minimum-bandwidth-feature-demo>`_
of a (pre-release) demo that was presented on the Berlin Summit in November
2018.

Since Yoga, the ``resource_request`` attribute of the port changed. With the
extension ``port-resource-request-groups``, Neutron informs that the blob
passed to Nova can contain several bandwidth requests. Please check
`resource_request sanitization
<https://docs.openstack.org/neutron/latest/admin/config-qos-min-pps.html#neutron-db-sanitization>`_.

Sample usage
------------

Physnets and QoS policies (together with their rules) are usually pre-created
by a cloud admin:

.. code-block:: console

    # as admin

    $ openstack network create net0 \
        --provider-network-type vlan \
        --provider-physical-network physnet0 \
        --provider-segment 100

    $ openstack subnet create subnet0 \
        --network net0 \
        --subnet-range 10.0.4.0/24

    $ openstack network qos policy create policy0

    $ openstack network qos rule create policy0 \
        --type minimum-bandwidth \
        --min-kbps 1000000 \
        --egress

    $ openstack network qos rule create policy0 \
        --type minimum-bandwidth \
        --min-kbps 1000000 \
        --ingress

Then a normal user can use the pre-created policy to create ports and boot
servers with those ports:

.. code-block:: console

    # as an unprivileged user

    # an ordinary soft-switched port: ``--vnic-type normal`` is the default
    $ openstack port create port-normal-qos \
        --network net0 \
        --qos-policy policy0

    # alternatively an SR-IOV port, unused in this example
    $ openstack port create port-direct-qos \
        --network net0 \
        --vnic-type direct \
        --qos-policy policy0

    $ openstack server create server0 \
        --flavor cirros256 \
        --image cirros-0.5.1-x86_64-disk \
        --port port-normal-qos

On Healing of Allocations
-------------------------

Since Placement carries a global view of a cloud deployment's resources
(what is available, what is used) it may in some conditions get out of sync
with reality.

One important case is when the data-plane-only Minimum Guaranteed Bandwidth
feature was used before Stein (first released in Newton). Since before Stein
guarantees were not enforced during server placement the available resources
may have become overallocated without notice. In this case Placement's view
and the reality of resource usage should be made consistent during/after an
upgrade to Stein.

Another case stems from OpenStack not having distributed transactions to
allocate resources provided by multiple OpenStack components (here Nova and
Neutron). There are known race conditions in which Placement's view may get
out of sync with reality. The design knowingly minimizes the race condition
windows, but there are known problems:

* If a QoS policy is modified after Nova read a port's ``resource_request``
  but before the port is bound its state before the modification will be
  applied.
* If a bound port with a resource allocation is deleted. The port's allocation
  is leaked. `<https://bugs.launchpad.net/nova/+bug/1820588>`_

.. note::

  Deleting a bound port has no known use case. Please consider detaching
  the interface first by ``openstack server remove port`` instead.

Incorrect allocations may be fixed by:

* Moving the server, which will delete the wrong allocation and create the
  correct allocation as soon as move operations are implemented (not in Stein
  unfortunately). Moving servers fixes local overallocations.
* The need for an upgrade-helper allocation healing tool is being tracked in
  `bug 1819923 <https://bugs.launchpad.net/nova/+bug/1819923>`_.
* Manually, by using `openstack resource provider allocation set
  <https://docs.openstack.org/osc-placement/latest/cli/index.html#resource-provider-allocation-set>`_
  /`delete <https://docs.openstack.org/osc-placement/latest/cli/index.html#resource-provider-allocation-delete>`_.

Debugging
---------

* Are all components running at least the Stein release?

* Is the ``placement`` service plugin enabled in neutron-server?

* Is ``resource_provider_bandwidths`` configured for the relevant neutron
  agent?

* Is ``resource_provider_bandwidths`` aligned with ``bridge_mappings`` or
  ``physical_device_mappings``?

* Was the agent restarted since changing the configuration file?

* Is ``resource_provider_bandwidths`` reaching neutron-server?

.. code-block:: console

    # as admin
    $ openstack network agent show ... | grep configurations

Please find an example in section `Propagation of resource information`_.

* Did neutron-server successfully sync to Placement?

.. code-block:: console

    # as admin
    $ openstack network agent show ... | grep resources_synced

Please find an example in section `Propagation of resource information`_.

* Is the resource provider tree correct? Is the root a compute host? One level
  below the agents? Two levels below the physical network interfaces?

.. code-block:: console

    $ openstack --os-placement-api-version 1.17 resource provider list
    +--------------------------------------+------------------------------------------+------------+--------------------------------------+--------------------------------------+
    | uuid                                 | name                                     | generation | root_provider_uuid                   | parent_provider_uuid                 |
    +--------------------------------------+------------------------------------------+------------+--------------------------------------+--------------------------------------+
    | 3b36d91e-bf60-460f-b1f8-3322dee5cdfd | devstack0                                |          2 | 3b36d91e-bf60-460f-b1f8-3322dee5cdfd | None                                 |
    | 4a8a819d-61f9-5822-8c5c-3e9c7cb942d6 | devstack0:NIC Switch agent               |          0 | 3b36d91e-bf60-460f-b1f8-3322dee5cdfd | 3b36d91e-bf60-460f-b1f8-3322dee5cdfd |
    | 1c7e83f0-108d-5c35-ada7-7ebebbe43aad | devstack0:NIC Switch agent:ens5          |          2 | 3b36d91e-bf60-460f-b1f8-3322dee5cdfd | 4a8a819d-61f9-5822-8c5c-3e9c7cb942d6 |
    | 89ca1421-5117-5348-acab-6d0e2054239c | devstack0:Open vSwitch agent             |          0 | 3b36d91e-bf60-460f-b1f8-3322dee5cdfd | 3b36d91e-bf60-460f-b1f8-3322dee5cdfd |
    | f9c9ce07-679d-5d72-ac5f-31720811629a | devstack0:Open vSwitch agent:br-physnet0 |          2 | 3b36d91e-bf60-460f-b1f8-3322dee5cdfd | 89ca1421-5117-5348-acab-6d0e2054239c |
    +--------------------------------------+------------------------------------------+------------+--------------------------------------+--------------------------------------+

* Does Placement have the expected traits?

.. code-block:: console

    # as admin
    $ openstack --os-placement-api-version 1.17 trait list | awk '/CUSTOM_/ { print $2 }' | sort
    CUSTOM_PHYSNET_PHYSNET0
    CUSTOM_VNIC_TYPE_DIRECT
    CUSTOM_VNIC_TYPE_DIRECT_PHYSICAL
    CUSTOM_VNIC_TYPE_MACVTAP
    CUSTOM_VNIC_TYPE_NORMAL

* Do the physical network interface resource providers have the proper trait
  associations and inventories?

.. code-block:: console

    # as admin
    $ openstack --os-placement-api-version 1.17 resource provider trait list RP-UUID
    $ openstack --os-placement-api-version 1.17 resource provider inventory list RP-UUID

* Does the QoS policy have a ``minimum-bandwidth`` rule?

* Does the port have the proper policy?

* Does the port have a ``resource_request``?

.. code-block:: console

    # as admin
    $ openstack port show port-normal-qos | grep resource_request

* Was the server booted with a port (as opposed to a network)?

* Did nova allocate resources for the server in Placement?

.. code-block:: console

    # as admin
    $ openstack --os-placement-api-version 1.17 resource provider allocation show SERVER-UUID

* Does the allocation have a part on the expected physical network interface
  resource provider?

.. code-block:: console

    # as admin
    $ openstack --os-placement-api-version 1.17 resource provider show --allocations RP-UUID

* Did placement manage to produce an allocation candidate list to nova during
  scheduling?

* Did nova manage to schedule the server?

* Did nova tell neutron which physical network interface resource provider
  was allocated to satisfy the bandwidth request?

.. code-block:: console

    # as admin
    $ openstack port show port-normal-qos | grep binding.profile.*allocation

* Did neutron manage to bind the port?

Links
-----

* Pre-release `feature demo <https://www.openstack.org/videos/summits/berlin-2018/guaranteed-minimum-bandwidth-feature-demo>`_ presented on the Berlin Summit in November 2018

* Nova documentation on using a port with ``resource_request``

  * `API Guide <https://docs.openstack.org/api-guide/compute/port_with_resource_request.html>`_
  * `Admin Guide <https://docs.openstack.org/nova/latest/admin/port_with_resource_request.html>`_

* Neutron spec: QoS minimum bandwidth allocation in Placement API

  * `on specs.openstack.org <https://specs.openstack.org/openstack/neutron-specs/specs/rocky/minimum-bandwidth-allocation-placement-api.html>`__
  * `on review.opendev.org <https://review.opendev.org/508149>`__

* Nova spec: Network Bandwidth resource provider

  * `on specs.openstack.org
    <https://specs.openstack.org/openstack/nova-specs/specs/stein/approved/bandwidth-resource-provider.html>`__
  * `on review.opendev.org
    <https://review.opendev.org/502306>`__

* Nova spec: QoS minimum guaranteed packet rate

  * `on specs.openstack.org
    <https://specs.openstack.org/openstack/nova-specs/specs/yoga/implemented/qos-minimum-guaranteed-packet-rate.html>`__

* Relevant OpenStack Networking API references

  * https://docs.openstack.org/api-ref/network/v2/#agent-resources-synced-extension
  * https://docs.openstack.org/api-ref/network/v2/#port-resource-request
  * https://docs.openstack.org/api-ref/network/v2/#qos-minimum-bandwidth-rules

* Microversion histories

  * `Compute 2.72
    <https://docs.openstack.org/nova/latest/reference/api-microversion-history.html#maximum-in-stein>`_
  * `Placement 1.29
    <https://docs.openstack.org/placement/latest/placement-api-microversion-history.html#support-allocation-candidates-with-nested-resource-providers>`_

* Implementation

  * `on review.opendev.org
    <https://review.opendev.org/#/q/topic:minimum-bandwidth-allocation-placement-api+OR+topic:bp/bandwidth-resource-provider>`_

* Known Bugs

  * `Missing tool to heal allocations
    <https://bugs.launchpad.net/nova/+bug/1819923>`_
  * `Bandwidth resource is leaked
    <https://bugs.launchpad.net/nova/+bug/1820588>`_

redpajama_set_name: RedPajamaGithub


text:
.swap .swap-show-list {
  max-height: 220px;
  overflow: hidden;
  overflow-y: auto;
}
.swap {
  min-height: 150px;
}

.swap-show-list--empty {
  cursor: default;
  pointer-events : none;
}

.authors-edit__list {
  display: inline-block;
  vertical-align: top;
  width: 35%;
}

.authors-edit__list--available {
  width: 45%;
}

.swap__head {
  text-align: center;
}

.authors-edit {
  cursor: pointer;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.swap-show-list .authors-edit.active,
.swap-show-list .authors-edit.active:hover,
.swap-show-list .authors-edit:hover {
  border-color: #fff;
}

.authors-edit__list .authors-edit--actual.active {
  background-color: #8a6d3b;
}

.authors-edit__list .author-edit--search.active {
  background-color: #31708f;
}

.authors-edit--actual:hover {
  background-color: #faf2cc;
}

.author-edit--search:hover {
  background-color: #c4e3f3;
}

.authors-controls {
  display: inline-block;
  bottom: -40px;
  position: relative;
}

.authors-controls__button {
  display: inline-block;
  padding: 5px 14px;
  background-color: #fff;
  border: 1px solid #ddd;
  border-radius: 15px;
  cursor: pointer;
}
.authors-controls__button--add:hover {
  background: goldenrod;
}

.authors-controls__button--remove:hover {
  background: rosybrown;
}

.authors-controls .authors-controls__item {
  margin-bottom: 10px;
  display: block;
}

.authors-search {
  padding: 2px;
}

.authors-search__input {
  display: inline-block;
  width: 40%;
}

@keyframes spinner {
  from {opacity: 0;}
  to {opacity: 1;}
}

.search--loading {
  animation: spinner 2s linear infinite ;
}


text:
slumpslider
===========

Interactive html5 slider


text:
// 32feet.NET - Personal Area Networking for .NET
//
// Copyright (c) 2013 Alan J McFarlane, All rights reserved.
// Copyright (c) 2013 In The Hand Ltd, All rights reserved.
// This source code is licensed under the MIT License

#if ANDROID
using System;
using System.Collections.Generic;
using System.IO;
using Android.Bluetooth;
using InTheHand.Net.Bluetooth.Droid;
using InTheHand.Net.Bluetooth.Factory;
using Java.Util;
using Moq;
using NUnit.Framework;

namespace TtfTests.Droid
{
    class AndroidTesting
    {
        //copied from LsnrTests
        class FooAndroidBthFactory : AndroidBthFactoryBase
        {
            public FooAndroidBthFactory(BluetoothAdapter a)
                : base(a)
            {
            }
        }

        //--
        static Stream DoInputStream(TestState state, bool accessed)
        {
            bool? canCalled = accessed ? (bool?)true : null;
            return DoStream(state, canCalled, null);
        }

        static Stream DoOutputStream(TestState state, bool accessed)
        {
            bool? canCalled = accessed ? (bool?)true : null;
            return DoStream(state, null, canCalled);
        }

        static Stream DoStream(TestState state, bool? canRead, bool? canWrite)
        {
            var sMock = new Mock<Stream>(MockBehavior.Strict);
            state.AddMock(sMock);
            if (canRead.HasValue) {
                sMock.Setup(x => x.CanRead).Returns(canRead.Value);
            }
            if (canWrite.HasValue) {
                sMock.Setup(x => x.CanWrite).Returns(canWrite.Value);
            }
            return sMock.Object;
        }

        //--
        internal class Options
        {
            // Device.Create[...]RfcommSocket
            public bool? Insecure { get; set; }
            // In Connect(...)
            public bool? GetRemoteDevice { get; set; }
            public bool? CreateSocket { get; set; }
            //TODO public int? CreateSocketToPort  { get; set; }
            public Guid ExpectedSvcClass { get; set; }
            public bool? Connect { get; set; }
            // In GetStream()
            public bool? GetStream1 { get; set; }
            //
            public bool? ClientDispose { get; set; }
        }

        internal static TestState Init(Options options)
        {
            var state = new TestState();
            //
            var aMock = new Mock<Android.Bluetooth.BluetoothAdapter>(MockBehavior.Strict);
            state.AddMock(aMock);
            //--
            var dMock = new Mock<Android.Bluetooth.BluetoothDevice>(MockBehavior.Strict);
            state.AddMock(dMock);
            //--
            // Socket
            Func<BluetoothSocket> setupSocketConnectStop = delegate()
            {
                var sMock = new Mock<BluetoothSocket>(MockBehavior.Strict);
                state.AddMock(sMock);
                if (GetValueOrReport(() => options.Connect)) {
                    sMock.Setup(x => x.Connect())
                        ;//.Callback(doConnect);
                    if (true) {
                        bool gs = GetValueOrReport(() => options.GetStream1);
                        //bool? gs = gsV ? true : (bool?)null;
                        sMock.Setup(x => x.InputStream).Returns(DoInputStream(state, gs));
                        sMock.Setup(x => x.OutputStream).Returns(DoOutputStream(state, gs));
                    }
                }
                if (GetValueOrReport(() => options.ClientDispose)) {
                    sMock.Setup(x => x.Close()).Callback(() =>
                    {
                    });
                }
                return sMock.Object;
            };
            // CreateSocket
            Moq.Language.Flow.ISetup<BluetoothDevice, BluetoothSocket> setupDeviceCreateSocket;
            if (GetValueOrReport(() => options.CreateSocket)) {
                if (GetValueOrReport(() => options.Insecure)) {
                    setupDeviceCreateSocket = dMock.Setup(x => x.CreateInsecureRfcommSocketToServiceRecord(
                        It.IsAny<UUID>())); // TODO !
                } else {
                    setupDeviceCreateSocket = dMock.Setup(x => x.CreateRfcommSocketToServiceRecord(
                        It.IsAny<UUID>())); // TODO !
                }
                setupDeviceCreateSocket.Returns(setupSocketConnectStop);
            }
            // BluetoothClass
            Func<BluetoothClass> setupDeviceGetClass = delegate
            {
                var cMock = new Mock<BluetoothClass>();
                return cMock.Object;
            };
            // GetRemoteDevice
            //-Func<BluetoothDevice> setupAdapterGetDevice= delegate
            //
            Func<UUID> doUUID = () =>
            {
                var uMock = new Mock<UUID>(Guid.Empty);
                return uMock.Object;
            };
            //----
            //
            // Radio init
            aMock.Setup(x => x.Address).Returns("0000000000aa");
            if (GetValueOrReport(() => options.GetRemoteDevice)) {
                // Device Init
                // TODO Have AndroidBtCli not need BondState/Class
                dMock.Setup(x => x.Address).Returns("0000000000dd");
                //dMock.Setup(x => x.BondState).Returns((Bond)999);
                //dMock.Setup(x => x.BluetoothClass).Returns(setupDeviceGetClass);
                // Adapter init
                aMock.Setup(x => x.GetRemoteDevice(
                                    It.IsAny<string>())) //TODO
                    .Returns(dMock.Object);
            }
            //
            var a = aMock.Object;
            //var f = new FooAndroidBthFactory(a);
            var fMock = new Mock<AndroidBthFactoryBase>(MockBehavior.Loose, a) { CallBase = true, };
            fMock.Setup(x => x.ToJavaUuid(options.ExpectedSvcClass))
                .Returns(doUUID);
            fMock.Setup(x => x.ToJavaUuid(It.IsAny<Guid>()))
#if true
.Throws(new AssertionException("Expected Service Class Guid not found."));
#else
                .Returns(doUUID)
                .Callback((Guid gggg) =>
                {
                });
#endif
            fMock.Setup(x => x.ToJavaUuid(options.ExpectedSvcClass))
                .Returns(doUUID);
            var f = fMock.Object;
            //
            var cli = f.DoGetBluetoothClient();
            state.Cli = cli;
            return state;
        }

        static internal void AllowClientClose_WillRunOnFinalizer(IBluetoothClient cli0)
        {
            AllowClientClose_WillRunOnFinalizer(cli0, true);
        }

        static internal void AllowClientClose_WillRunOnFinalizer(IBluetoothClient cli0, bool disposal)
        {
            var cli = (AndroidBthClient)cli0;
            BluetoothSocket sock; Stream inStream; Stream outStream;
            cli.GetObjectsForTest(out sock, out inStream, out outStream);
            //
            if (disposal) { // We don't close these in the finalizer.
                var isMock = Mock.Get(inStream);
                isMock.Setup(xi => xi.Close()).Callback(() =>
                {
                });
                var osMock = Mock.Get(outStream);
                osMock.Setup(xo => xo.Close()).Callback(() =>
                {
                });
            }
            var sMock = Mock.Get(sock);
            sMock.Setup(xs => xs.Close()).Callback(() =>
            {
            });
        }

        public static bool GetValueOrReport(System.Linq.Expressions.Expression<Func<bool?>> f)
        {
            return AndroidLsnrTests.GetValueOrReport(f);
        }

        //--
        internal class TestState
        {
            public IBluetoothClient Cli { get; set; }
            public IBluetoothListener Lsnr { get; set; }

            List<Mock> _allMocks = new List<Mock>();

            public void AddMock(Mock mock)
            {
                _allMocks.Add(mock);
            }

            public void VerifyAll()
            {
                foreach (var cur in _allMocks) {
                    cur.VerifyAll();
                }
                _allMocks.Clear();
            }
        }

        //---------------------
        internal enum Disposal
        {
            No, Client, Stream
        }

    }
}
#endif


text:
'''Module containing the Entity type, and mixins useful for defining
entity behaviour using the Component model.'''

from cocos.cocosnode import CocosNode
from cocos.draw import Canvas
from cocos.euclid import Vector2
from cocos.mapcolliders import RectMapWithPropsCollider
from cocos.rect import Rect
from pyglet.event import EventDispatcher

from ..sprite import sheet
from ..constants import *

def getvec2(x, y=None):
    if isinstance(x, int):
        x = float(x)
    if isinstance(y, int):
        y = float(y)
    if isinstance(x, float):
        assert isinstance(y, float)
        x = x, y

    if isinstance(x, tuple):
        x = Vector2(x[0], x[1])

    if isinstance(x, Vector2):
        return x
    else:
        raise ValueError('Could not convert ({!r}, {!r}) to Vector2'.format(
            x, y
        ))

def _sendonmove(e):
    e.dispatch_event('on_move', e, e.rect.position)

class EntityMeta(type):
    '''Metaclass for entities.

    Allows components to use an `EVENTS` property to declare the events they may
    emit.'''
    def __init__(cls, name, bases, attrs, **kwargs):
        if 'EVENTS' in attrs:
            for event in cls.EVENTS:
                cls.register_event_type(event)

        for base in bases:
            events = base.EVENTS if hasattr(base, 'EVENTS') \
                    else base._EVENTS if hasattr(base, '_EVENTS') \
                    else tuple()
            for event in events:
                cls.register_event_type(event)

        super().__init__(name, bases, attrs)

class Entity(CocosNode, EventDispatcher, metaclass=EntityMeta):
    '''Entity super-type.

    All entities have a position and size (under the `rect` property), and a
    velocity. When active, the position is automatically updated based on
    velocity. They emit the `on_move` event when their position changes.

    They are automatically registered to dispatch events as specified in
    `EVENTS`.
    '''

    EVENTS = 'on_move', 'on_accelerate',

    def __init__(self, pos, size=(0, 0)):
        CocosNode.__init__(self)

        self._rect = Rect(*pos, *size)
        self._vel = Vector2(0.0, 0.0)

        self.push_handlers(self)

    def on_enter(self):
        self.schedule(self.tick)
        super().on_enter()

    def on_exit(self):
        self.unschedule(self.tick)
        super().on_exit()

    def tick(self, dt):
        '''Perform necessary update operations.'''
        self._apply_velocity(dt)

    def _apply_velocity(self, dt):
        '''Naïve velocity calculation implementation. Does not account for any
        collisions; use *Collidable components to make these considerations.'''
        self.pos += self._vel * dt

    @property
    def rect(self):
        return self._rect.copy()

    @rect.setter
    def rect(self, newrect):
        self._rect = newrect.copy()
        _sendonmove(self)

    @property
    def pos(self):
        return Vector2(*self._rect.position)

    @pos.setter
    def pos(self, value):
        self._rect.position = value
        _sendonmove(self)

    @property
    def center(self):
        return Vector2(*self._rect.center)

    @center.setter
    def center(self, value):
        self._rect.center = value
        _sendonmove(self)

    @property
    def size(self):
        return Vector2(*self._rect.size)

    @size.setter
    def size(self, value):
        self._rect.size = value

    @property
    def vel(self):
        return self._vel.copy()

    @vel.setter
    def vel(self, value):
        oldvel = self.vel
        newvel = getvec2(value)
        self._vel = newvel
        # Emit event
        if oldvel != newvel:
            self.dispatch_event('on_accelerate', self, newvel - oldvel)

class Spritable:
    '''The Spritable component indicates that an entity has a sprite.

    This sprite is passed to the constructor. It is automatically added as a
    child node. Its position is kept in sync with the entity's.'''

    EVENTS = ('on_animation_end',)

    def __init__(self, sprite):
        self._Spritable_sprite = None
        self.sprite = sprite
        # Update sprite position when the entity moves
        def setpos(_, pos):
            self._Spritable_sprite.position = self.center
        self.push_handlers(on_move=setpos)

    @property
    def sprite(self):
        return self._Spritable_sprite

    @sprite.setter
    def sprite(self, new):
        if isinstance(new, sheet.Sprite):
            new = new(self.center)
        else:
            new.position = self.center
        # Ensure rect size matches sprite
        self.size = new.width, new.height
        # Set sprite on self
        old = self._Spritable_sprite
        self._Spritable_sprite = new
        # Set sprite as child node
        if old is not None:
            self.remove(old)
        self.add(new)
        # Prepare on_animation_end event
        new.push_handlers(
            on_animation_end=lambda: \
                self.dispatch_event('on_animation_end', self, new)
        )

class Killable:
    '''The Killable component indicates that an entity has health.

    The starting health is passed as an argument to the constructor. The
    `health` property allows manipulating this entity's health. Events are
    emitted when the health changes, and when the health decreases to zero
    ("death"). The `dead` property returns true when this is the case.'''

    EVENTS = 'on_heal', 'on_damage', 'on_death'

    def __init__(self, start_health, enable_events=True):
        self._Killable_health = start_health
        self._Killable_enable_events = enable_events

    @property
    def health(self):
        return self._Killable_health

    @health.setter
    def health(self, value):
        oldvalue = self._Killable_health
        self._Killable_health = value

        if self._Killable_enable_events:
            if value < oldvalue:    # Taking damage
                self.dispatch_event('on_damage', self, oldvalue - value)
            elif value > oldvalue:  # Restoring health
                self.dispatch_event('on_heal', self, value - oldvalue)

            if self.dead:
                self.dispatch_event('on_death', self)

    @property
    def dead(self):
        return self._Killable_health <= 0

class MapCollidable:
    '''The MapCollidable component indicates that an entity can collide with
    the map.

    It stores the map collider and the map to collide with, and accounts for the
    map by overriding the per-tick movement code. The `grounded` property is
    made available for checking whether or not this entity is touching the
    ground.'''

    EVENTS = 'on_map_connect', 'on_map_disconnect'

    def __init__(self, map, collide_strategy):
        self._MapCollidable_collider = \
            _CustomMapCollider(self, collide_strategy)
        self._MapCollidable_map = map
        self._MapCollidable_connected = {
            'up': False, 'down': False,
            'left': False, 'right': False
        }

        def on_connect(self, direction, obj):
            self._MapCollidable_connected[direction] = True
        def on_disconnect(self, direction):
            self._MapCollidable_connected[direction] = False
        self.push_handlers(on_map_connect=on_connect,
                           on_map_disconnect=on_disconnect)

    @property
    def grounded(self):
        return self._MapCollidable_connected['down']

    def _apply_velocity(self, dt):
        '''Account for map when applying velocity'''
        old = self.rect
        vel = self.vel
        # Calculate main changes
        disp = vel * dt
        new = old.copy()
        new.x += disp.x
        new.y += disp.y
        # Account for collisions
        # Modifies `new` and returns an updated velocity
        # that takes collisions into account
        newvel = self._MapCollidable_collider.collide_map(
            self._MapCollidable_map,
            old, new, vel.x, vel.y
        )
        self.vel = newvel
        # Update self with new position
        self.rect = new

        # Unset any connections that no longer apply
        connected = self._MapCollidable_connected
        if connected['up'] and self.vel.y:
            # Moved down so no longer connected
            self.dispatch_event('on_map_disconnect', self, 'up')
        if connected['down'] and self.vel.y:
            # Moved up so no longer connected
            self.dispatch_event('on_map_disconnect', self, 'down')
        if connected['left'] and self.vel.x:
            # Moved right so no longer connected
            self.dispatch_event('on_map_disconnect', self, 'left')
        if connected['right'] and self.vel.x:
            # Moved left so no longer connected
            self.dispatch_event('on_map_disconnect', self, 'right')

class _CustomMapCollider(RectMapWithPropsCollider):
    '''Custom MapCollider to dispatch events to a MapCollidable entity.'''

    def __init__(self, entity, *args):
        super().__init__(*args)
        self.entity = entity

    def collide_bottom(self, obj):
        '''Bottom of entity collided with top of obj'''
        self.entity.dispatch_event('on_map_connect', self.entity, 'down', obj)

    def collide_left(self, obj):
        '''Left of entity collided with right of obj'''
        self.entity.dispatch_event('on_map_connect', self.entity, 'left', obj)

    def collide_right(self, obj):
        '''Right of entity collided with left of obj'''
        self.entity.dispatch_event('on_map_connect', self.entity, 'right', obj)

    def collide_top(self, obj):
        '''Top of entity collided with bottom of obj'''
        self.entity.dispatch_event('on_map_connect', self.entity, 'up', obj)

# Accel due to grav, in px/s/s
_a_g = Vector2(0.0, -9.8) * mtr
class Droppable:
    '''The Droppable component indicates that an entity should be affected by
    gravity.

    If `self.grounded` exists, it will be checked and gravity disabled when it
    is true. This allows seamless cooperation with MapCollidable.'''
    def __init__(self):
        self.schedule(self._Droppable_apply_gravity)

    def _Droppable_apply_gravity(self, dt):
        self.vel += _a_g * dt

class State:
    def __init__(self, name, duration=float('inf'),
                 active_duration=float('inf')):
        self.name = name
        self.time_active = 0
        self.time_since_creation = 0
        self.duration = duration
        self.active_duration = active_duration

    def __eq__(self, other):
        if isinstance(other, str):
            return self.name == other
        elif isinstance(other, State):
            return self.name == other.name
        else:
            return ValueError("Comparison not defined for non-string and "
                              "non-State objects")

    def __ne__(self, other):
        return not (self == other)

    @property
    def is_dead(self):
        return (self.time_active > self.active_duration or
                self.time_since_creation > self.duration)

class Stateable:
    def __init__(self, default_state=None):
        if default_state is None:
            default_state = State('idle_right')
        self._Stateable_stack = [default_state]

    def state_update(self, dt):
        """
        Updates timers for all states
        :param dt: time elapsed since last update (ms)
        :return: None
        """

        # Update all states, and remove any states that are past end-duration
        for i in range(len(self._Stateable_stack)-1, -1, -1):
            state = self._Stateable_stack[i]
            if state.is_dead:
                self.pop_state(i)
                continue
            state.time_since_creation += dt

        # Update current state as well
        self.cur_state.time_active += dt

    def push_state(self, state):
        self._Stateable_stack.append(state)

    def pop_state(self, i=-1):
        """
        i should only be used internally.
        :param i: Index of state to remove.
        :return: The topmost State
        """
        if self.num_states > 1 and self.num_states > i:
            return self._Stateable_stack.pop(i)
        else:
            if self.num_states == 0:
                raise ValueError("Can not pop state, only one state in stack")
            else:
                raise ValueError("Can't pop state at %i, only %i states" % (
                    i, self.num_states
                ))

    def swap_active_state(self, state):
        self._Stateable_stack.pop()
        self.push_state(state)

    @property
    def cur_state(self):
        return self._Stateable_stack[-1]

    @property
    def num_states(self):
        return len(self._Stateable_stack)


text:
<?php

namespace ObjectiveWP\Framework\Foundation\Test\Factories;

use ObjectiveWP\Framework\Contracts\Kernel;
use ObjectiveWP\Framework\Foundation\Application;

class ApplicationFactory
{
    /**
     * @param $version
     * @param $baseUrl
     * @param array $definitions
     * @param array $kernels
     * @return Application
     */
    public function makeApplication($version, $baseUrl, $definitions = [], $kernels = []) {
        /** @var Application $app */
        $app =  new class($version, $baseUrl, $definitions, $kernels) extends Application {

            protected $injectedKernels;

            public function __construct($version, $applicationPath, $definitions = [], $kernels) {
                parent::__construct($version, $applicationPath, $definitions = []);
                $this->injectedKernels = $kernels;
            }

            /**
             * A list of the kernels to bootstrap
             * @return Kernel[]
             */
            protected function kernels()
            {
                return $this->injectedKernels;
            }
        };
        return $app;
    }
}


text:
StroikaRoot=$(abspath ../../../../../../../)/

ifneq ($(CONFIGURATION),)
	#no error if missing cuz could be doing make clobber
	-include $(StroikaRoot)IntermediateFiles/$(CONFIGURATION)/Configuration.mk
endif

SrcDir	=   $(StroikaRoot)Library/Sources/Stroika/Foundation/Execution/Platform/POSIX/
ObjDir	=	$(StroikaRoot)IntermediateFiles/$(CONFIGURATION)/Library/Foundation/Execution/Platform/POSIX/

include $(StroikaRoot)ScriptsLib/Makefile-Common.mk
include $(StroikaRoot)ScriptsLib/SharedBuildRules-Default.mk
include $(StroikaRoot)ScriptsLib/SharedMakeVariables-Default.mk

ifeq ($(WIN_USE_PROGRAM_DATABASE),1)
CXXFLAGS+=-Fd$(call FUNCTION_CONVERT_FILEPATH_TO_COMPILER_NATIVE,$(StroikaRoot)Builds/$(CONFIGURATION)/Stroika-Foundation.pdb)
endif

vpath %cpp $(SrcDir)

Objs	=

ifneq ($(findstring POSIX,$(TARGET_PLATFORMS)),)
Objs+=	$(ObjDir)SemWaitableEvent${OBJ_SUFFIX}
Objs+=	$(ObjDir)SignalBlock${OBJ_SUFFIX}
Objs+=	$(ObjDir)Users${OBJ_SUFFIX}
endif

all:	 $(Objs)


text:
using System;
using System.Linq;
using FluentAssertions;
using OcularPlane.Exceptions;
using Xunit;

namespace OcularPlane.Tests
{
    public class ContainerManagerTests
    {
        [Fact]
        public void No_Instances_In_Empty_Container()
        {
            var containerManager = new ContainerManager();
            var results = containerManager.GetInstancesInContainer("container");

            results.Should().NotBeNull();
            results.Length.Should().Be(0);
        }

        [Fact]
        public void Can_Add_Object_To_Container()
        {
            var containerManager = new ContainerManager();

            var instanceId = containerManager.AddObjectToContainer("container", this, "obj");
            var results = containerManager.GetInstancesInContainer("container");

            results.Should().NotBeNull();
            results.Length.Should().Be(1);
            results[0].InstanceId.Should().Be(instanceId);
            results[0].Should().NotBeNull();
            results[0].Name.Should().Be("obj");
            results[0].TypeName.Should().Be(this.GetType().FullName);
            results[0].InstanceId.Should().NotBe(Guid.Empty);
        }

        [Fact]
        public void No_Containers_Listed_Before_Adding_An_Object()
        {
            var containerManager = new ContainerManager();
            var results = containerManager.GetContainerNames();

            results.Should().NotBeNull();
            results.Length.Should().Be(0);
        }

        [Fact]
        public void Container_Added_When_Item_Added_To_It()
        {
            var containerManager = new ContainerManager();

            containerManager.AddObjectToContainer("container", this, "obj");
            var results = containerManager.GetContainerNames();

            results.Should().NotBeNull();
            results.Length.Should().Be(1);
            results[0].Should().Be("container");
        }

        [Fact]
        public void Can_Delete_Container()
        {
            var containerManager = new ContainerManager();

            containerManager.AddObjectToContainer("container", this, "obj");
            containerManager.DeleteContainer("container");
            var results = containerManager.GetContainerNames();

            results.Should().NotBeNull();
            results.Length.Should().Be(0);
        }

        [Fact]
        public void Same_Object_In_Different_Containers_Has_Different_Instance_Id()
        {
            var containerManager = new ContainerManager();
            var testObj1 = new TestClass();

            containerManager.AddObjectToContainer("container1", testObj1, "obj");
            containerManager.AddObjectToContainer("container2", testObj1, "obj");

            var instance1 = containerManager.GetInstancesInContainer("container1")
                .Select(x => x.InstanceId)
                .FirstOrDefault();

            var instance2 = containerManager.GetInstancesInContainer("container2")
                .Select(x => x.InstanceId)
                .FirstOrDefault();

            instance1.Should().NotBeEmpty();
            instance2.Should().NotBeEmpty();
            instance1.Should().NotBe(instance2);
        }

        [Fact]
        public void Can_Get_Details_For_Instance()
        {
            var containerManager = new ContainerManager();
            var testObject = new TestClass
            {
                NumberProperty = 123,
                StringProperty = "abc"
            };

            containerManager.AddObjectToContainer("container", testObject, "obj");
            var reference = containerManager.GetInstancesInContainer("container")
                .Single(x => x.Name == "obj");

            var details = containerManager.GetInstanceDetails(reference.InstanceId);

            details.Should().NotBeNull();
            details.InstanceId.Should().Be(reference.InstanceId);
            details.Name.Should().Be(reference.Name);
            details.Properties.Should().NotBeNull();
            details.Properties.Length.Should().Be(2);

            var stringProperty = details.Properties.Single(x => x.Name == nameof(TestClass.StringProperty));
            stringProperty.TypeName.Should().Be(typeof (string).FullName);
            stringProperty.ValueAsString.Should().Be(testObject.StringProperty);

            var numberProperty = details.Properties.Single(x => x.Name == nameof(TestClass.NumberProperty));
            numberProperty.TypeName.Should().Be(typeof (int).FullName);
            numberProperty.ValueAsString.Should().Be(testObject.NumberProperty.ToString());
        }

        [Fact]
        public void Fields_Are_Included_In_Instance_Details()
        {
            var containerManager = new ContainerManager();
            var testObject = new ClassWithField {IntField = 1};

            containerManager.AddObjectToContainer("container", testObject, "obj");
            var reference = containerManager.GetInstancesInContainer("container")
                .Single(x => x.Name == "obj");

            var details = containerManager.GetInstanceDetails(reference.InstanceId);

            details.Should().NotBeNull();
            details.Properties.Length.Should().Be(1);
            details.Properties[0].Name.Should().Be(nameof(ClassWithField.IntField));
            details.Properties[0].ValueAsString.Should().Be("1");
        }

        [Fact]
        public void Can_Remove_Instance_From_Container()
        {
            var containerManager = new ContainerManager();

            containerManager.AddObjectToContainer("container", this, "obj");
            var instance = containerManager.GetInstancesInContainer("container").First();
            containerManager.RemoveInstance(instance.InstanceId);

            var results = containerManager.GetInstancesInContainer("container");
            results.Length.Should().Be(0);
        }

        [Fact]
        public void Can_Tell_If_Properties_Are_Read_Or_Write_Only()
        {
            var containerManager = new ContainerManager();
            var testObject = new ReadWriteOnlyTestClass {WriteOnlyProperty = 33};

            containerManager.AddObjectToContainer("container", testObject, "obj");
            var reference = containerManager.GetInstancesInContainer("container")
                .Single(x => x.Name == "obj");

            var details = containerManager.GetInstanceDetails(reference.InstanceId);

            details.Properties.Length.Should().Be(2);

            var readProperty = details.Properties.Single(x => x.Name == nameof(ReadWriteOnlyTestClass.ReadOnlyProperty));
            readProperty.IsReadable.Should().BeTrue();
            readProperty.IsWritable.Should().BeFalse();
            readProperty.ValueAsString.Should().Be("33");

            var writeProperty = details.Properties.Single(x => x.Name == nameof(ReadWriteOnlyTestClass.WriteOnlyProperty));
            writeProperty.IsReadable.Should().BeFalse();
            writeProperty.IsWritable.Should().BeTrue();
            writeProperty.ValueAsString.Should().BeNull();
        }

        [Fact]
        public void Indexer_Properties_Are_Ignored()
        {
            var containerManager = new ContainerManager();
            var testObject = new IndexerClass();

            containerManager.AddObjectToContainer("container", testObject, "obj");
            var reference = containerManager.GetInstancesInContainer("container")
                .Single(x => x.Name == "obj");

            var details = containerManager.GetInstanceDetails(reference.InstanceId);

            details.Properties.Length.Should().Be(0);
        }

        [Fact]
        public void Can_Mark_Instance_As_Child_Of_Another_Instance()
        {
            var containerManager = new ContainerManager();

            var parentId = containerManager.AddObjectToContainer("container", this, "parent");
            var childId = containerManager.AddObjectToContainer("container", this, "child", parentId);

            var details = containerManager.GetInstanceDetails(childId);

            details.ParentInstanceId.Should().Be(parentId);
        }

        private class TestClass
        {
            public string StringProperty { get; set; }
            public int NumberProperty { get; set; }
            public void Method() { }
        }

        private class ClassWithField
        {
            public int IntField;
        }

        private class ReadWriteOnlyTestClass
        {
            private int _internalValue;

            public int ReadOnlyProperty => _internalValue;
            public int WriteOnlyProperty { set { _internalValue = value; } }
        }

        private class IndexerClass
        {
            private readonly int[] _array = new[] {1, 2, 3, 4, 5};

            public int this[int index]
            {
                get { return _array[index]; }
                set { _array[index] = value; }
            }
        }
    }
}