the emergence of asn.1 as an xml schema notation
Post on 11-Jan-2016
218 Views
Preview:
TRANSCRIPT
The emergence of The emergence of ASN.1ASN.1
as an XML Schema as an XML Schema NotationNotation
What is ASN.1? (1)What is ASN.1? (1) Today, it is a notation for defining the Today, it is a notation for defining the
content and form of an XML documentcontent and form of an XML document That is, it is an XML schema notationThat is, it is an XML schema notation But originally it was a notation for But originally it was a notation for
defining the content – the abstract syntax defining the content – the abstract syntax of documents, supported by binary of documents, supported by binary encoding rulesencoding rules
Hence Abstract Syntax Notation OneHence Abstract Syntax Notation One
What is ASN.1? (2)What is ASN.1? (2)
Quite old – early 1980s.Quite old – early 1980s. Mature! But still developing.Mature! But still developing. ISO Standards and ITU-T RecommendationsISO Standards and ITU-T Recommendations Heavily used to define messages in many Heavily used to define messages in many
industrial and commercial sectorsindustrial and commercial sectors Until recently, all ASN.1-defined messages Until recently, all ASN.1-defined messages
were encoded in binary.were encoded in binary.
ASN.1 - lineageASN.1 - lineage
ASN.1 was borne around 1982 ishASN.1 was borne around 1982 ish First ASN.1 Standard (CCITT X.409) in 1984First ASN.1 Standard (CCITT X.409) in 1984 Borne from X.400 (mother with an early child,Borne from X.400 (mother with an early child,
and the e-mail standard the world *should* have and the e-mail standard the world *should* have had!) had!)
Fathered by X.500 (certified insane at birth, butFathered by X.500 (certified insane at birth, but totally secure) totally secure)
Grand-parents (OSI) died prematurely and areGrand-parents (OSI) died prematurely and are not discussed in polite conversation today not discussed in polite conversation today
Waving a magic wandWaving a magic wand Without ASN.1-defined messages:Without ASN.1-defined messages:
– The lights go out!– Portable phones don’t work!– Parcels get lost!– Traffic lights fail!– Aircraft fall from the sky!– Your impending marriage suffers
as Net Meeting fails!
XX
XX XX
On second thoughts – it might be a betterOn second thoughts – it might be a better world? world?
A sample of ASN.1 A sample of ASN.1 notationnotation
BBCard ::= SEQUENCE {BBCard ::= SEQUENCE {
name name IA5String, IA5String,
team team IA5String, IA5String,
age age INTEGER, INTEGER,
position position IA5String, IA5String,
handedness ENUMERATED {handedness ENUMERATED {
left-handed,left-handed,
right-handed,right-handed,
ambidextrous },ambidextrous },
batting-average REAL }batting-average REAL }
A sample of ASN.1 A sample of ASN.1 notation with "facets"notation with "facets"
(encouraged)(encouraged)BBCard ::= SEQUENCE {BBCard ::= SEQUENCE {
name name IA5String (SIZE (1..60)), IA5String (SIZE (1..60)),
team team IA5String (SIZE (1..60)), IA5String (SIZE (1..60)),
age age INTEGER (1..100), INTEGER (1..100),
position position IA5String (SIZE (1..60)), IA5String (SIZE (1..60)),
handedness ENUMERATED {handedness ENUMERATED {
left-handed,left-handed,
right-handed,right-handed,
ambidextrous },ambidextrous },
batting-average REAL }batting-average REAL }
The C data-structure The C data-structure for the base-ball cardfor the base-ball card
typedef struct BBCard {typedef struct BBCard {char name [61] ;char name [61] ;char team [61] ;char team [61] ;short age ;short age ;char position [61] ;char position [61] ;enum {enum {
left_handed = 0,left_handed = 0,right_handed = 1,right_handed = 1,ambidextrous = 2,ambidextrous = 2,} handedness ;} handedness ;
float batting_average ;float batting_average ;} BBCard ;} BBCard ;
A base-ball card value A base-ball card value in XML syntaxin XML syntax
<BBCard><BBCard>
<name>Jorge Posada</name><name>Jorge Posada</name>
<team>New York Yankees</team><team>New York Yankees</team>
<age>29</age><age>29</age>
<position>C</position><position>C</position>
<handedness>right-handed</handedness><handedness>right-handed</handedness>
<batting-average>0.277</batting-average><batting-average>0.277</batting-average>
</BBCard></BBCard>
The Montagues The Montagues and the Capuletsand the Capulets
(A shorter history of (A shorter history of contending contending
philosophies)philosophies)
(With apologies to William (With apologies to William Shakespeare and to those from Shakespeare and to those from
a non-UK culture!)a non-UK culture!)
The Montagues and The Montagues and CapuletsCapulets
A long and on-going civil disputeA long and on-going civil dispute Montagues =>Montagues =>
Binary-based specification Binary-based specification Capulets =>Capulets =>
Character-based specification Character-based specification
Understanding of protocol Understanding of protocol specification techniquesspecification techniques 1.5 billion seconds ago …..1.5 billion seconds ago …..
Computers started to communicate Computers started to communicate Major advances every 150 million secondsMajor advances every 150 million seconds There was a need forThere was a need for
– A means of syntax (data structure) specification– Procedure (sequence) specification– Test suite specification– Validation
And tools to support rapid implementation!And tools to support rapid implementation!
The stone-age The stone-age Montagues Montagues
Diagrams of bits and bytes - e.g. IPv4Diagrams of bits and bytes - e.g. IPv4(The earliest approach, simple and clear, but focusing
totally on the bits-on-the-line.)
Tool support not possibleTool support not possibleExtensibility support crudeExtensibility support crude - based on reserved fields.
The stone-age CapuletsThe stone-age Capulets
Simple “command lines” – in ASCII!Simple “command lines” – in ASCII! Simple character mnemonics and error codesSimple character mnemonics and error codes
(eg “200 OK”) (eg “200 OK”) Simple comma-separated parametersSimple comma-separated parameters Good for simple dialoguesGood for simple dialogues Extensibility by adding commands in V2,Extensibility by adding commands in V2,
with unknown commands ignored by V1 with unknown commands ignored by V1 systems systems
The Bronze Age The Bronze Age Montagues invent TLV Montagues invent TLV and Tabular Notationand Tabular Notation
Each PDU and each parameter has an ID (or Each PDU and each parameter has an ID (or TTag), ag), a a LLength, and a ength, and a VValuealue
Nested TLVs in TLVs – sounds familiar?Nested TLVs in TLVs – sounds familiar? (Should have been patented? No XML!)(Should have been patented? No XML!) Tables list each parameter: Tables list each parameter: Tabular NotationTabular Notation
Tabular Notation and Tabular Notation and TLV was a break-TLV was a break-
throughthrough Extensibility was EXCELLENT.Extensibility was EXCELLENT. Version 1 systems just skipped (using Version 1 systems just skipped (using
TLV) anything they did not know.TLV) anything they did not know. Tool-support, however, not possible.Tool-support, however, not possible.
But it was verbose!But it was verbose!But not as verbose as the character-based encodings used by the Capulets!
The Bronze Age The Bronze Age Capulets invent BNFCapulets invent BNF
The Capulets’ main concern was withThe Capulets’ main concern was with precise specification of correct syntax precise specification of correct syntax
This was the dawning of Backus NaurThis was the dawning of Backus Naur Form (BNF) Form (BNF)
This potentially allowed more complexThis potentially allowed more complex information to be specified in a “command” information to be specified in a “command”
But it never really made it to the modern eraBut it never really made it to the modern era
of of automaticautomatic mapping to Java, C++, C mapping to Java, C++, C etc.etc.
150 Million seconds 150 Million seconds after the Bronze Ageafter the Bronze Age
Recognition of:Recognition of:– Separation of "abstract syntax" (content) from
encoding– Encoding rules
ASN.1 specifications define a de facto, platformASN.1 specifications define a de facto, platform and language independent API and language independent API
Tools emerge to support the transformationTools emerge to support the transformation of ASN.1 to a platform-specific API, and the of ASN.1 to a platform-specific API, and the encoding of data across that APIencoding of data across that API
Supported on a wide range of platforms andSupported on a wide range of platforms and languages – typically C, C++, Java languages – typically C, C++, Java
Profits for all!Profits for all!
300 Million seconds 300 Million seconds later, the Capulets later, the Capulets
develop XMLdevelop XML Don't really need to describe it to this audience!Don't really need to describe it to this audience! But focus still more on what is a syntactically correct But focus still more on what is a syntactically correct
document, rather than on its contentdocument, rather than on its content Can be seen as the TLV approach stolen from the Can be seen as the TLV approach stolen from the
Montagues (!) but with an end-tag instead of a length Montagues (!) but with an end-tag instead of a length field to delimit elementsfield to delimit elements
Rapidly gained popularity! Rapidly gained popularity! The encoding-of-choice for many applications todayThe encoding-of-choice for many applications today
And finally, after And finally, after another Million secondsanother Million seconds
ASN.1 develops XML Encoding RulesASN.1 develops XML Encoding Rules
Romeo and Juliet marry!Romeo and Juliet marry!
Back to the serious Back to the serious business!business!
The separation of the specification of The separation of the specification of document content from representation document content from representation issues has been retainedissues has been retained
XML is (just) another way of encoding XML is (just) another way of encoding data defined using ASN.1data defined using ASN.1
The same ASN.1 definition (schema) The same ASN.1 definition (schema) defines defines bothboth XML XML andand (very efficient) (very efficient) binary encodingsbinary encodings
This includes This includes canonicalcanonical encodings for encodings for security sensitive work and signaturessecurity sensitive work and signatures
Current work using Current work using ASN.1 as a schemaASN.1 as a schema
There are two pieces of OASIS work that There are two pieces of OASIS work that use ASN.1use ASN.1
The XCBF work (Extensible Common The XCBF work (Extensible Common Biometrics Formats) uses ASN.1 alone to Biometrics Formats) uses ASN.1 alone to define the XML documentdefine the XML document
The UBL (Universal Business Language) The UBL (Universal Business Language) work uses XSD as the master schema, but work uses XSD as the master schema, but this is algorithmically mapped into an this is algorithmically mapped into an ASN.1 schema by a mapping tool in order ASN.1 schema by a mapping tool in order to provide binary protocolsto provide binary protocols
Mapping between Mapping between binary and XMLbinary and XML
All existing message formats defined using All existing message formats defined using ASN.1 now also have a defined XML ASN.1 now also have a defined XML format (no additional work needed)format (no additional work needed)
Tools are available to map message formats Tools are available to map message formats between compact binary and XML formats between compact binary and XML formats for such protocols (in both directions)for such protocols (in both directions)
XSD definition of message formats can be XSD definition of message formats can be mapped to an ASN.1 definition using mapped to an ASN.1 definition using available tools, giving access to the efficient available tools, giving access to the efficient binary encodingsbinary encodings
Stage 1 of ASN.1 Stage 1 of ASN.1 support for XMLsupport for XML
The first Standard developed for XML The first Standard developed for XML support in ASN.1 was called "basic XML support in ASN.1 was called "basic XML encoding rules", or encoding rules", or BASIC-XERBASIC-XER
ThisThis provided no control over details of XML provided no control over details of XML representation such as use of attributes representation such as use of attributes instead of elements, space-separated lists, instead of elements, space-separated lists, xsi:type, or namespacesxsi:type, or namespaces
This was very much basic XML!This was very much basic XML! A A canonicalcanonical representation was also representation was also
defineddefined
Stage 2 of ASN.1 Stage 2 of ASN.1 support for XMLsupport for XML
Encoding Instructions were introduced into Encoding Instructions were introduced into the ASN.1 notationthe ASN.1 notation
These control things such as encoding as an These control things such as encoding as an attribute rather than as an element, or as a attribute rather than as an element, or as a space-separated listspace-separated list
Also support for XSD concepts such as Also support for XSD concepts such as union, default-for-empty, nillable, and so onunion, default-for-empty, nillable, and so on
Encoding instructions can be prefixed or can Encoding instructions can be prefixed or can be included separately in an Encoding be included separately in an Encoding Control Section (see later)Control Section (see later)
““Coloring” the BaseBall Coloring” the BaseBall card schema card schema
BBCard ::= SEQUENCE {BBCard ::= SEQUENCE {
name name [ATTRIBUTE][ATTRIBUTE] IA5String, IA5String,
team team [ATTRIBUTE][ATTRIBUTE] IA5String, IA5String,
age age INTEGER, INTEGER,
position position IA5String, IA5String,
handedness ENUMERATED {handedness ENUMERATED {
left-handed,left-handed,
right-handed,right-handed,
ambidextrous },ambidextrous },
batting-average REAL }batting-average REAL }
Unchanged Unchanged APIAPI
The new XML syntaxThe new XML syntax
<BBCard<BBCard name = “Jorge Posada” name = “Jorge Posada”
team = “New York Yankees” >team = “New York Yankees” >
<age>29</age><age>29</age>
<position>C</position><position>C</position>
<handedness>right-handed</handedness><handedness>right-handed</handedness>
<batting-average>0.277</batting-average><batting-average>0.277</batting-average>
</BBCard></BBCard>
Another exampleAnother example
Employee ::= Employee ::= [UNCAPITALIZED][UNCAPITALIZED] SEQUENCE { SEQUENCE {
id id [ATTRIBUTE][ATTRIBUTE] INTEGER(0..MAX), INTEGER(0..MAX), recruitedrecruited Date, Date,
salaries salaries [LIST][LIST] SEQUENCE SEQUENCE OF salary REAL } OF salary REAL }
Without the coloring, Without the coloring, we have basic XML:we have basic XML:
<Employee> <Employee> <id>239</id><id>239</id>
<recruited>27-11-2002</recruited> <recruited>27-11-2002</recruited> <salaries> <salaries> <salary>29876</salary> <salary>29876</salary> <salary>54375</salary> <salary>54375</salary> <salary>98435</salary> <salary>98435</salary> </salaries> </salaries></Employee> </Employee>
With the coloring, we With the coloring, we get:get:
<employee id = "239"> <employee id = "239"> <recruited>27-11-2002</recruited> <recruited>27-11-2002</recruited>
<salaries>29876 54375 98435</salaries> </employee> <salaries>29876 54375 98435</salaries> </employee>
Much less verbose, assuming you Much less verbose, assuming you care!care!
But the same information contentBut the same information content
Equivalently we could Equivalently we could write:write:
Employee ::= SEQUENCE {Employee ::= SEQUENCE {
id id INTEGER(0..MAX),INTEGER(0..MAX), recruitedrecruited Date, Date,
salaries salaries SEQUENCESEQUENCE OF salary REAL } OF salary REAL }
ENCODING-CONTROL XERENCODING-CONTROL XER NAME Employee AS UNCAPITALIZED NAME Employee AS UNCAPITALIZED
ATTRIBUTE Employee.idATTRIBUTE Employee.id
LIST Employee.salariesLIST Employee.salaries
At first sight this is more verbose and At first sight this is more verbose and less clear! But …..less clear! But …..
Advantages of the Advantages of the separate Encoding separate Encoding
Control SectionControl Section It keeps a much clearer separation of It keeps a much clearer separation of
encoding issues from contentencoding issues from content In most cases it is much less verbose, as you In most cases it is much less verbose, as you
are able to apply encoding instructions are able to apply encoding instructions globally, or to selected parts of the spec, and globally, or to selected parts of the spec, and also to use NOT on selected partsalso to use NOT on selected parts
The embedded form is usually good for The embedded form is usually good for examplesexamples
The separate section is best for real The separate section is best for real specificationsspecifications
Stage 3 of ASN.1 Stage 3 of ASN.1 support for XMLsupport for XML
Standardisation of the mapping from an Standardisation of the mapping from an arbitrary XSD definition into an ASN.1 arbitrary XSD definition into an ASN.1 schema (with coloring)schema (with coloring)
Provides exactly the same specification of the Provides exactly the same specification of the XML document as the XSDXML document as the XSD
Tools available to do the mappingTools available to do the mapping Enables binary encodings to be used for the Enables binary encodings to be used for the
XSD specification, and mapping of it into aXSD specification, and mapping of it into aC, C++ or Java datastructure.C, C++ or Java datastructure.
Part of an invoice in Part of an invoice in XSD and the ASN.1 XSD and the ASN.1
equivalentequivalent<xsd:complexType name=“LineItemPair"><xsd:complexType name=“LineItemPair"> <xsd:sequence><xsd:sequence>
<xsd:element <xsd:element name="part-no" type="xsd:number"/>name="part-no" type="xsd:number"/>
<xsd:element<xsd:element name="quantity" type="xsd:number"/>name="quantity" type="xsd:number"/>
</xsd:sequence></xsd:sequence></xsd:complexType> </xsd:complexType>
mapsmaps to:to:
LineItemPair ::= SEQUENCE {LineItemPair ::= SEQUENCE {part-nopart-no INTEGER,INTEGER,quantityquantity INTEGER }INTEGER }
The full invoice in The full invoice in ASN.1ASN.1
(couldn't get the XSD (couldn't get the XSD onto a single slide!)onto a single slide!)Invoice ::= SEQUENCE {Invoice ::= SEQUENCE {
numbernumber INTEGER,INTEGER,namename UTF8String,UTF8String,detailsdetails SEQUENCE OF SEQUENCE OF
LineItemPair,LineItemPair,chargecharge REAL,REAL,authenticatorauthenticator BIT STRING}BIT STRING}
LineItemPair ::= SEQUENCE {LineItemPair ::= SEQUENCE {part-nopart-no INTEGER,INTEGER,quantityquantity INTEGER }INTEGER }
The XML encoding of an The XML encoding of an Invoice (1)Invoice (1)
<Invoice><Invoice>
<number>32950</number><number>32950</number>
<name>funny-name with <</name><name>funny-name with <</name>
<details><details>
<Line-item><Line-item>
<part-no>296</part-no><part-no>296</part-no>
<quantity>2</quantity><quantity>2</quantity>
</Line-item></Line-item>
ContCont
The XML encoding of an The XML encoding of an Invoice (2)Invoice (2)
ContinuationContinuation
<Line-item><Line-item>
<part-no>4793</part-no><part-no>4793</part-no>
<quantity>74</quantity><quantity>74</quantity>
</Line-item> </Line-item> </details></details>
<charge>397.65</charge><charge>397.65</charge>
<authenticator><authenticator>
EFF8 E976 5403 629FEFF8 E976 5403 629F
</authenticator></authenticator>
</invoice></invoice>
Determinism, or Determinism, or "safety" versus power!"safety" versus power!
See the supporting paperSee the supporting paper BASIC-XER is totally "safe" – a total idiot can BASIC-XER is totally "safe" – a total idiot can
produce a specification where the XML is never produce a specification where the XML is never ambiguous!ambiguous!
Everything is wrapped upEverything is wrapped up With EXTENDED-XER you can remove wrappers With EXTENDED-XER you can remove wrappers
(XML tags) round repetitions, choices and sequences (XML tags) round repetitions, choices and sequences (that may have optional elements) using the (that may have optional elements) using the [UNTAGGED][UNTAGGED] encoding instruction encoding instruction
Caveat Emptor!Caveat Emptor!
ASN.1 and RELAX NG ASN.1 and RELAX NG (all on one slide!)(all on one slide!)
Invoice ::= SEQUENCE {Invoice ::= SEQUENCE {numbernumber INTEGER, INTEGER,namename UTF8String, UTF8String,detailsdetails SEQUENCE OF SEQUENCE OF
SEQUENCE { part-no INTEGER, SEQUENCE { part-no INTEGER, quantity INTEGER }, quantity INTEGER },
chargecharge REAL, REAL,authenticator authenticator BIT STRING} BIT STRING}
element Invoice {element Invoice {element number element number {integer}, {integer}, element name element name {text},{text},element details element details { element part-no {integer},{ element part-no {integer},
element quantity {integer} } * , element quantity {integer} } * ,element charge element charge {float},{float},element authenticator element authenticator {bits} }{bits} }
Pretty similar!Pretty similar!
The importance of The importance of having binary having binary
encodings available?encodings available? Re-opening the Montague and Capulet war!Re-opening the Montague and Capulet war! Romeo and Juliet, happily married for a few years, Romeo and Juliet, happily married for a few years,
get divorced! Maybe not!get divorced! Maybe not! There are real merits in using the same schema There are real merits in using the same schema
definition for both character and binary encodingsdefinition for both character and binary encodings Work on binary XSD recognises that, but is Work on binary XSD recognises that, but is
hampered because XSD basically defines allowed hampered because XSD basically defines allowed syntax, not content. ASN.1 binary encodings are syntax, not content. ASN.1 binary encodings are very mature! (And have canonical variants.)very mature! (And have canonical variants.)
The next example can be taken quicklyThe next example can be taken quickly
A personnel-record A personnel-record defined (1)defined (1)
PersonnelRecord ::= SEQUENCE {PersonnelRecord ::= SEQUENCE {name name Name,Name,title title VisibleString,VisibleString,number number EmployeeNumber,EmployeeNumber,dateOfHire dateOfHire DATE-TIME (Date),DATE-TIME (Date),nameOfSpouse nameOfSpouse Name,Name,children children SEQUENCE OFSEQUENCE OF
child ChildInformationchild ChildInformation DEFAULT {} }DEFAULT {} }
A personnel-record A personnel-record defined (2)defined (2)
ChildInformation ::= SEQUENCE {ChildInformation ::= SEQUENCE {
name name Name,Name,
dateOfBirth DATE-TIME dateOfBirth DATE-TIME (Date)}(Date)}
Name ::= SEQUENCE {Name ::= SEQUENCE {
givenName givenName VisibleString,VisibleString,
initial initial VisibleString,VisibleString,
familyName familyName VisibleString}VisibleString}
EmployeeNumber ::= INTEGEREmployeeNumber ::= INTEGER
An example personnel-An example personnel-record (1)record (1)
<PersonnelRecord><PersonnelRecord><name><name>
<givenName>John</givenName><givenName>John</givenName><initial>P</initial><initial>P</initial><familyName>Smith</familyName><familyName>Smith</familyName>
</name></name><title>Director</title><title>Director</title><number>51</number><number>51</number><dateOfHire>19710917</dateOfHire><dateOfHire>19710917</dateOfHire><nameOfSpouse><nameOfSpouse>
<givenName>Mary</givenName><givenName>Mary</givenName><initial>T</initial><initial>T</initial><familyName>Smith</familyName><familyName>Smith</familyName>
</nameOfSpouse</nameOfSpouseContCont
An example personnel-An example personnel-record (2)record (2)<children><children>
<child><child><name><name>
<givenName>Ralph</givenName><givenName>Ralph</givenName><initial>T</initial><initial>T</initial><familyName>Smith</familyName><familyName>Smith</familyName>
</name></name><dateOfBirth>19571111</dateOfBirth><dateOfBirth>19571111</dateOfBirth>
</child></child><child><child>
<name><name><givenName>Susan</givenName><givenName>Susan</givenName><initial>B</initial><initial>B</initial><familyName>Jones</familyName><familyName>Jones</familyName>
</name></name><dateOfBirth>19590717</dateOfBirth><dateOfBirth>19590717</dateOfBirth>
</child></child></children></children></PersonnelRecord></PersonnelRecord>
A count of octets for the A count of octets for the personnel-record valuepersonnel-record value
With white-space omitted, 653 octetsWith white-space omitted, 653 octets Fully human-readable with white-space, can Fully human-readable with white-space, can
be double that!be double that! Binary TLV-style encoding 136 octetsBinary TLV-style encoding 136 octets Compact binary encoding 94 octets (other Compact binary encoding 94 octets (other
examples compress better)examples compress better) ZIP compression ….. of XML or binary?ZIP compression ….. of XML or binary? But does size (or transaction processing speed) But does size (or transaction processing speed)
matter anyway?matter anyway?
Tail-end remarksTail-end remarks
Everyone is bored by now!Everyone is bored by now! One example is much like another.One example is much like another. Refer to the paper if you wish.Refer to the paper if you wish. Messages from these examples:Messages from these examples:
– Simplicity and clarity of specification– Content clearly separated from syntax– Ability to apply coloring– The same schema definition provides all forms
of encoding as well as C, C++ and Java APIs
Future developmentsFuture developments
Discussions are ongoing onDiscussions are ongoing on– The application of ASN.1 to SOAP– Use of ASN.1 in web services– An ASN.1 definition of the infoset– Mapping UML to ASN.1
Much is in place already, but work continues on Much is in place already, but work continues on the full integration of ASN.1 with XMLthe full integration of ASN.1 with XML
ASN.1 earlier shed its dependence on OSI and is ASN.1 earlier shed its dependence on OSI and is now shedding its dependence on binary encodingsnow shedding its dependence on binary encodings
SynergySynergy Never reject the new. But don't Never reject the new. But don't ignore what has been learned in ignore what has been learned in the past. Usually a combination the past. Usually a combination of the two will be best.of the two will be best.
We have learned a lot over the We have learned a lot over the years on message specification years on message specification and encoding techniques, and and encoding techniques, and XML was a big advance. But …. XML was a big advance. But …. Synergy!Synergy!
The End – clapping is The End – clapping is allowed!allowed!
top related