Specification

Esiur Protocol (EP) Specification

πŸ“„ Version 1.0 β€” 2026-07-22 πŸ”Œ TCP / WebSocket πŸ”’ Default port: 10518 πŸ”— URI scheme: ep:// πŸ“œ MIT License
Every claim in this document is verified directly against the reference implementations β€” esiur-dotnet and esiur-ts β€” including cross-checked byte-level test vectors shared between both codebases. Where the two implementations currently disagree in behavior, it's called out explicitly in Β§8 rather than papered over.

1. Overview

The Esiur Protocol (EP) [Zamil & Jasim, 2026] is a compact binary application-layer protocol for distributed object computing. It enables first-class sharing of object instances across a TCP or WebSocket connection: property values synchronize in real time, remote methods are called as if local, and events propagate transparently to every subscriber.

EP is fully self-describing: a client can discover the type schema of any resource at runtime (a TypeDef query) and generate strongly-typed proxies without out-of-band API documents. Actively maintained implementations exist for .NET and TypeScript, sharing wire concepts, packet layout, and command names byte-for-byte.

Key design properties:

2. Transport & URI scheme

TCP

EP runs natively over TCP. EpServer defaults to TCP port 10518 in both reference implementations; a bare ep://host URL (no explicit port) resolves to the same default. The server accepts incoming connections and immediately begins the Authentication Phase (Β§4).

WebSocket

EP also runs as a WebSocket sub-protocol, identifier EP (uppercase, compared case-sensitively/ordinally by both implementations). After the WebSocket handshake, the binary framing is identical to the TCP wire format: each WebSocket message carries exactly one EP packet.

URI scheme

Resources are addressed with an ep:// URL:

ep://<host>[:port]/<store>/<resource-path>

Examples
  ep://server.example.com/sys/thermostat
  ep://localhost:10518/sys/counter
  ep://iot-hub.local/sensors/temperature

The path maps directly to a resource in the server's store hierarchy, analogous to a filesystem path. Omitting the port uses 10518. A bare ep://host[:port] with no path resolves to the connection itself.

eps:// is transport-specific today, not universal. Over WebSocket, the TypeScript client maps eps:// to wss:// (TLS-protected WebSocket) β€” this is implemented and working. The .NET client's URL resolver does not currently register a distinct handler for an eps/EPS scheme, and neither implementation currently wraps raw TCP connections in TLS automatically. Confidentiality on a raw TCP connection today relies entirely on the application-layer session encryption negotiated during the auth handshake (Β§4.3), not on transport-layer TLS. See Β§8 and Β§9.

3. Connection lifecycle

Client                                        Server
  β”‚                                               β”‚
  │────────── TCP / WebSocket connect ───────────▢│
  β”‚                                               β”‚
  │◀─────── Auth: Initialize ─────────────────────│  server sends first
  β”‚                                               β”‚
  │──────── Auth: Action ─────────────────────────▢  zero or more rounds,
  │◀─────── Auth: Acknowledge ────────────────────│  protocol-dependent
  β”‚                                               β”‚
  │◀─────── Auth: SessionEstablished ─────────────│
  β”‚                                               β”‚
  │◀════════════ EP session packets ═════════════▢│
  β”‚   Request / Reply / Notification              β”‚
  β”‚                                               β”‚
  │────────── connection close ──────────────────▢│

Once the session is established, the connection is fully bidirectional β€” either peer may send Requests, Replies, or Notifications at any time. A resource attachment stays live until the connection closes or the client explicitly detaches; on reconnect, a client can reattach and resynchronize rather than re-fetch full state from scratch.

4. Authentication phase

Before any EP session packet is transmitted, both sides exchange one or more auth packets, a distinct binary format from session packets. The server always sends the first packet (Initialize). Even a connection configured for anonymous access completes this phase β€” it just negotiates AuthenticationMode.None with EncryptionMode.None in a single round trip.

4.1 Auth packet header byte

Bit 7Bit 6Bit 5Bit 4Bit 3Bit 2Bit 1Bit 0
Command2 bits hasTDU1 bit reserved1 bit AuthMode2 bits β€” Initialize only EncMode2 bits β€” Initialize only

For every command other than Initialize, bits 4–0 (with bit 5 masked off) are instead read as a single EpAuthPacketMethod byte (Β§4.3) β€” the low 5 bits given above only apply to the very first, server-sent Initialize packet. hasTDU (bit 5) β€” when set, a TDU payload (Β§5) follows, encoding a key–value map of handshake parameters (Β§4.4).

4.2 Auth commands (bits 7–6)

ValueNameDirectionDescription
0x0InitializeServer β†’ ClientOpens authentication; announces supported modes and algorithms
0x1AcknowledgeBothAccept, deny, or redirect an authentication step
0x2ActionClient β†’ ServerA handshake step β€” credentials or key material
0x3EventServer β†’ ClientSession established, an error, or an indication

AuthenticationMode (bits 3–2 of an Initialize packet):

ValueNameDescription
0x0NoneNo identity required from either party
0x1InitializerIdentityThe connecting client must authenticate
0x2ResponderIdentityThe server must present its identity to the client
0x3DualIdentityMutual authentication β€” both parties must prove identity

EncryptionMode (bits 1–0 of an Initialize packet):

ValueNameDescription
0x0NoneSession data transmitted without application-layer encryption
0x1EncryptWithSessionKeySymmetric session key (AES-256-GCM) derived during the handshake
0x2EncryptWithSessionKeyAndAddressSession key additionally bound to the connection's source address

4.3 EpAuthPacketMethod (Acknowledge / Action / Event byte)

For any command other than Initialize, the byte identifies the specific handshake step:

ValueNameCommandDescription
0x40DeniedAcknowledgeAuth denied β€” terminate connection
0x41NotSupportedAcknowledgeRequested method not supported β€” terminate
0x42TrySupportedAcknowledgeTry an alternative, supported method
0x43RetryAcknowledgeRetry with different parameters
0x44ProceedToHandshakeAcknowledgeProceed to the key-exchange step
0x45ProceedToFinalHandshakeAcknowledgeProceed to the final handshake step
0x46ProceedToEstablishSessionAcknowledgeDerive session keys
0x47SessionEstablishedAcknowledgeSession ready β€” switch to EP session packets
0x80HandshakeActionClient sends key material / credentials
0x81FinalHandshakeActionClient sends final confirmation
0x82KeyRotationActionRequest mid-session encryption-key rotation (.NET only β€” see Β§8)
0xC0EstablishedEventAuth flow complete
0xC1ErrorTerminateEventFatal auth error β€” connection will close
0xC2ErrorMustEncryptEventEncryption is required for this resource
0xC3ErrorRetryEventTransient error β€” client may retry
0xC8IndicationEstablishedEventInformational: (re-)established indication
0xC9KeyRotationEstablishedEventKey rotation completed (.NET only β€” see Β§8)
0xD0IAuthPlainEventIdentity assertion, unhashed
0xD1IAuthHashedEventIdentity assertion, hashed
0xD2IAuthEncryptedEventIdentity assertion, encrypted

4.4 Auth TDU header keys

The TDU payload of an auth packet is a keyed map. Integer keys 0–17 are defined:

#Key#Key
0Version9SoftwareIdentity
1Domain10Referrer
2SupportedAuthentications11Time
3SupportedHashAlgorithms12IPAddress
4SupportedCiphers13Identity
5SupportedCompression14AuthenticationProtocol
6SupportedMultiFactorAuthentications15AuthenticationData
7CipherType16ErrorMessage
8CipherKey17CipherNonce

5. TDU (Transmission Data Unit) encoding

Every value carried inside a session or auth packet β€” arguments, return values, property contents, handshake parameters β€” is encoded as a self-describing TDU. Decoders never need out-of-band schema information: each TDU carries its own type tag and, for variable-length types, its own length.

5.1 Identifier byte

Bit 7Bit 6Bit 5Bit 4Bit 3Bit 2Bit 1Bit 0
Class2 bits Fixed: exponent / Var-length: size-field count3 bits Sub-type3 bits
Bits 7–6ClassBits 5–3 meaning
00FixedExponent β€” payload width = 0 if exponent is 0, else 1 << (exponentβˆ’1) bytes.
01DynamicLength-field byte count (0–7, see Β§5.3) β€” how many big-endian length bytes follow the identifier.
10TypedSame length-field encoding as Dynamic. Carries a type reference (record/enum/tuple).
11ExtensionSame length-field encoding as Dynamic. Protocol-level markers.

For Dynamic, Typed, and Extension classes, the identifier recovered by a parser is headerByte & 0xC7 (class bits + sub-type bits only β€” the length-field-count bits are stripped once the length has been read). The length bytes themselves are big-endian (most-significant byte first):

Bits 5–3OR-maskLength-field sizeMax payload
0000x00none β€” zero-length value0 B
0010x081 byte255 B
0100x102 bytes64 KB
0110x183 bytes16 MB
1000x204 bytes4 GB
101–1110x28–0x385–7 bytesup to 72 PB

5.2 Fixed class (0x00–0x2F)

WidthIdentifiers
0 bytes0x00 Null, 0x01 False, 0x02 True, 0x03 NotModified, 0x04 Infinity
1 byte0x08 UInt8, 0x09 Int8, 0x0A Char8, 0x0B LocalResource8, 0x0C RemoteResource8, 0x0D LocalProcedure8, 0x0E RemoteProcedure8
2 bytes0x10 UInt16, 0x11 Int16, 0x12 Char16, 0x13 LocalResource16, 0x14 RemoteResource16, 0x15 LocalProcedure16, 0x16 RemoteProcedure16
4 bytes0x18 UInt32, 0x19 Int32, 0x1A Float32, 0x1B LocalResource32, 0x1C RemoteResource32, 0x1D LocalProcedure32, 0x1E RemoteProcedure32
8 bytes0x20 UInt64, 0x21 Int64, 0x22 Float64, 0x23 DateTime (ticks, signed 64-bit)
16 bytes0x28 UInt128, 0x29 Int128, 0x2A Decimal128, 0x2B UUID (RFC 4122, 16 raw bytes)

Multi-byte Fixed-class payload contents (integers, floats, DateTime ticks) are little-endian β€” see Β§5.5 for verified examples. 128-bit integers are two little-endian 64-bit halves, low word first.

5.3 Dynamic class (0x40–0x47)

Base IDNameDescription
0x40RawDataOpaque byte array
0x41StringUTF-8 text
0x42ListOrdered list of heterogeneous TDUs
0x43ResourceListList of resource references
0x44RecordListList of typed records
0x45ResourceLinkResource path, as a string
0x46MapKey–value map
0x47MapListOrdered list of maps

5.4 Typed & Extension classes

IdentifierClassNameDescription
0x80TypedTypedRecord or enum value (built-in TypedList/TypedMap/Tuple use it too); embeds a TRU metadata block before its content β€” see Β§5.5
0x81TypedTypeDefA full type definition, returned in answer to a TypeDef query β€” see Β§5.7
0x82TypedTRUA standalone TRU value β€” see Β§5.5
0xC0ExtensionTypeContinuationMulti-part type reference β€” continuation fragment
0xC1ExtensionTypeOfTargetUse the enclosing resource's own type as the type reference

5.5 TRU (Type-Representation Unit)

A TRU describes the type of a value β€” either as a self-contained shape (a primitive kind, or a built-in generic like a typed list, map, or tuple) or as a compact reference to a type registered elsewhere. In source, the class is named Tru; the one place in either codebase that spells the abbreviation out (a comment in the .NET implementation) calls it a "type-representation unit."

A TRU appears on the wire in exactly two places:

The TRU header byte is laid out as follows:

Bit 7Bit 6Bit 5Bit 4Bit 3Bit 2Bit 1Bit 0
Nullable1 bit Extended1 bit Identifier / sub-count6 bits β€” meaning depends on Extended

Three shapes, selected by the Extended bit (bit 6):

ExtendedShapeWire layout
0PrimitiveThe header byte alone is the whole TRU (1 byte total) β€” a bare scalar kind such as a string or a fixed-width number.
1, sub-count = 0Type referenceHeader byte + a little-endian numeric type-definition ID. ID width (1/2/4/8 bytes) is selected by which of the eight Local/Remote Γ— 8/16/32/64 identifiers is used; Local vs. Remote selects whose Warehouse resolves the ID.
1, sub-count 1–7CompositeHeader byte + that many nested TRUs, back-to-back (a typed list has 1 nested TRU for its element type; a typed map has 2, for key and value; a tuple has 2–7, one per element).

Confirmed identifiers for the reference and composite shapes:

IdentifierNameShape
0x40 / 0x41LocalType8 / RemoteType8Reference, 1-byte ID
0x42 / 0x43LocalType16 / RemoteType16Reference, 2-byte ID
0x44 / 0x45LocalType32 / RemoteType32Reference, 4-byte ID
0x46 / 0x47LocalType64 / RemoteType64Reference, 8-byte ID
0x48TypedListComposite, 1 sub-TRU (element type)
0x50Tuple2Composite, 2 sub-TRUs
0x51TypedMapComposite, 2 sub-TRUs (key, value)
0x58 / 0x60 / 0x68 / 0x70 / 0x78Tuple3 … Tuple7Composite, 3–7 sub-TRUs

The full set of primitive-shape identifiers (bare scalar kinds below 0x40) isn't reproduced here β€” consult TruIdentifier in either implementation's source for the exhaustive list; the mechanism above is complete regardless.

5.6 Group-varint integer encoding (GVWIE)

When a TypedList or TypedMap's element TRU is one of Int16/Int32/Int64/UInt16/UInt32/UInt64, its elements are packed with a dedicated compaction codec both codebases call GVWIE β€” a proper name, not an acronym expansion found anywhere in either implementation's source, comments, or commit history. (Int8/UInt8 lists have no such codec and fall back to per-element encoding.) This is a payload sub-encoding, not a TDU or TRU identifier of its own.

Each value is zig-zag encoded, then: a value whose zig-zagged magnitude fits in 7 bits is written as a single literal byte with the top bit clear ("fast path"). A run of consecutive values that don't fit is grouped behind one header byte packing a count and a shared byte width, followed by that many values at that width, least-significant byte first. Exact bit allocation for the grouped-run header differs slightly by integer width β€” see GroupInt16Codec/GroupInt32Codec/GroupInt64Codec (and their unsigned counterparts) in either implementation's source for the precise formula.

Verified example β€” the payload of a TypedList<Int32> holding [1, 2, 3], taken from a golden test vector byte-for-byte identical in both test suites:

88 05 48 09 02 04 06 88 = Typed(0x80), 1-byte length 05 = content length = 5 48 = TRU: TypedList (composite, 1 sub-TRU) 09 = nested TRU: Int32 (primitive) 02 04 06 = GVWIE payload β€” zig-zag(1,2,3) = (2,4,6), all fast-path bytes

5.7 TypeDef

A TypeDef is the schema returned in answer to a TypeDefById or TypeDefByResourceId request (Β§7): the name, kind, base type, and full set of exported properties, methods, events, and constants for a resource, record, enum, or function type.

Wire mechanism: a TypeDef (0x81) TDU's payload is itself a complete, self-contained plain Typed (0x80) TDU β€” own length prefix and TRU metadata included β€” whose content is a sparse map from a one-byte field index to a dynamically-typed value. Only fields that are actually present are written; there is no zero-fill for absent ones, and a receiver ignores any field index it doesn't recognize. This is what lets new optional fields be added at new indices in the future without breaking existing parsers. Every member record below (property, function, argument, event, constant) uses the same indexed-map mechanism recursively.

IndexFieldType
0x00Versioninteger
0x01Idinteger β€” the numeric type ID other TRUs reference
0x02Namestring
0x03Namespacestring
0x04Kindbyte β€” see table below
0x05Parentinteger β€” base type's numeric ID
0x06Propertieslist of property records
0x07Functionslist of function records
0x08Eventslist of event records
0x09Constantslist of constant records

Indices 0x20–0x25 carry optional descriptive metadata (usage, description, example, category, since, and a string-to-string annotation map) β€” documentation aids, not load-bearing for interoperability.

Kind (field 0x04):

ValueName
0Resource
1Record
2Enum
3Function (defined; not currently produced by either reference implementation)

Every property, function, argument, event, and constant record shares a base shape β€” index 0x00 (its own member index), 0x01 (name), 0x02 (flags), plus an optional documentation block from 0x20 onward β€” and adds its own fields from 0x03:

RecordOwn fields (from 0x03)Flags (bit values)
Property0x03 ValueType (TRU), 0x04 OrderingControl, 0x05 HistoryControl, 0x06 DefaultValueInherited=1, Deprecated=2, ReadOnly=4, Constant=8, Volatile=0x10, Historical=0x20
Function0x03 Arguments (list of Argument records), 0x04 ReturnType (TRU), 0x05 StreamModeInherited=1, Deprecated=2, Static=4, ReadOnly=8, Idempotent=0x10, Cancellable=0x20, Pausable=0x40
Argument0x03 ValueType (TRU), 0x04 DefaultValueOptional=1, Variadic=2
Event0x03 ArgumentType (TRU), 0x04 ArgumentName, 0x05 OrderingControl, 0x06 HistoryControlInherited=1, Deprecated=2, AutoDelivered=4, Historical=8
Constant0x03 ValueType (TRU), 0x04 ValueInherited=1, Deprecated=2

5.8 Verified wire examples

Each of these is a complete TDU (identifier byte, any length bytes, payload), taken from byte-for-byte matching test vectors shared between the .NET and TypeScript test suites. See Β§5.6 above for a TRU/GVWIE example.

49 02 48 69 β€” String "Hi": id 0x41|0x08 (1-byte length), length 2, UTF-8 "Hi" 19 40 9c 00 00 β€” Int32 40000: id 0x19, payload 40 9c 00 00 (little-endian) 21 00 f2 05 2a 01 00 00 00 β€” Int64 5,000,000,000: id 0x21, 8-byte little-endian payload

The Int32/Int64 examples above intentionally show a multi-byte payload: note the least-significant byte comes first. This is the opposite byte order from the TDU length-prefix field (Β§5.1), which is big-endian β€” the two fields are independent and use different conventions.

6. EP packet format

After the authentication phase completes, all traffic uses EP session packets. Every packet begins with a single header byte; Request and Reply packets additionally carry a 4-byte callback ID. Payloads, when present, are TDU-encoded (Β§5).

Bit 7Bit 6Bit 5Bit 4Bit 3Bit 2Bit 1Bit 0
Method2 bits hasTDU1 bit Command5 bits
Bits 7–6MethodCallback ID?Notes
00NotificationNo β€” 1-byte minimum packetUnsolicited; no reply expected
01RequestYes β€” 4-byte little-endian uint325-byte minimum packet
10ReplyYes β€” echoes the Request's callback ID5-byte minimum packet
11ExtensionNoReserved β€” parsed by both implementations, emitted by neither (see Β§8)
Notification (1+ bytes) β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ 00 hasTDU cmd:5 β”‚ β”‚ TDU (if set) β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ Request / Reply (5+ bytes) β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ 01/10 hasTDU cmd:5 β”‚ β”‚ callback id, u32 LE β”‚ β”‚ TDU (if set) β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Verified example β€” a KeepAlive request (no payload) with callback ID 12:

58 0c 00 00 00 58 = Request(01)<<6 | hasTDU(0)<<5 | KeepAlive(0x18) 0c 00 00 00 = callback id 12, little-endian

7. Commands reference

Request commands

ValueNameGroupDescription
0x00InvokeFunctionInvokeCall a method on a resource instance by index
0x01SetPropertyInvokeSet a resource property by index
0x02SubscribeInvokeSubscribe to property/event change notifications
0x03UnsubscribeInvokeCancel a subscription
0x08TypeDefIdsByNamesInquireResolve numeric type IDs from class name strings
0x09TypeDefByIdInquireFetch a full type definition by numeric ID
0x0ATypeDefByResourceIdInquireFetch the type definition for an attached resource
0x0BQueryInquireSearch resources by path pattern
0x0CLinkTypeDefsInquireGet all type definitions reachable from a resource link
0x0DTokenInquireRequest an authentication token
0x0EGetResourceIdByLinkInquireResolve a resource path to its server-assigned numeric ID
0x10AttachResourceManageAttach to a resource; server returns its full current state
0x11ReattachResourceManageRe-sync after reconnection
0x12DetachResourceManageStop receiving updates for this resource
0x13CreateResourceManageInstantiate a new resource on the server
0x14DeleteResourceManageDestroy a server-side resource
0x15MoveResourceManageRename or relocate a resource
0x18KeepAliveStaticConnection heartbeat β€” no payload
0x19ProcedureCallStaticCall a named server-side procedure
0x1AStaticCallStaticCall a static/class-level method β€” no instance required
0x1BIndirectCallStaticIndirect invocation via a callable reference. Declared, not yet dispatched by the reference server β€” see Β§8.
0x1CPullStreamStaticPull the next chunk from a server-side stream
0x1DTerminateExecutionStaticAbort an in-progress execution
0x1EHaltExecutionStaticPause an in-progress (pausable) execution
0x1FResumeExecutionStaticResume a halted execution

Reply commands carry the Request's callback ID

ValueNameGroupDescription
0x00CompletedSuccessOperation completed; payload is the return value, if any
0x01PropagatedSuccessResult delivered to a downstream subscriber
0x02StreamSuccessOperation returned a stream handle
0x04PermissionErrorErrorRequest denied β€” insufficient permissions
0x05ExecutionErrorErrorException thrown during method execution
0x08ProgressPartialIntermediate progress update; request still pending
0x09ChunkPartialOne chunk of a streamed response; more may follow
0x0AWarningPartialNon-fatal warning; operation continues

Notification commands no callback ID β€” unsolicited

ValueNameGroupDescription
0x00PropertyModifiedInvokeA subscribed property value changed
0x01EventOccurredInvokeA subscribed event was raised
0x08ResourceDestroyedManageAn attached resource was deleted on the server
0x09ResourceReassignedManageAn attached resource was assigned a new server ID
0x0AResourceMovedManageAn attached resource was renamed or relocated
0x0BSystemFailureManageSystem-level failure affecting the connection

8. Implementation notes

EP is specified so that independent implementations interoperate over the wire without a translation layer, and the two reference implementations agree on every packet, command, and TDU value covered above. As of this writing, a few areas are implemented in one reference implementation but not (yet) the other:

Area.NETTypeScript
WebSocket subprotocol enforcement on acceptRequired β€” rejects the upgrade with HTTP 400 if the client didn't request EPNot currently validated β€” EpServer accepts the upgrade regardless of the requested subprotocol
eps:// URI schemeNot currently registered as a distinct handlerMaps to wss:// (TLS-protected WebSocket)
Mid-session key rotation (KeyRotation / KeyRotationEstablished, Β§4.3)Implemented, used by the PPAP authentication providerNot yet implemented
Untrusted-input TDU length guardsConfigurable maximum payload/allocation limits (WarehouseConfiguration)No equivalent limit yet at the TDU-parsing layer
EpPacketMethod.Extension (session packets, Β§6) and IndirectCall (Β§7)Parsed if received; not currently emitted or dispatchedNot currently emitted

None of this affects wire compatibility for the features both implementations do support today β€” it's listed here so implementers building a third party don't assume behavior that isn't universal yet.

9. Security considerations

AuthenticationMode.None deployments should be restricted to trusted, private networks. Combined with EncryptionMode.None, a connection has no identity verification and no application-layer confidentiality at all.

10. References