GithubHelp home page GithubHelp logo

openepcis / openepcis-event-hash-generator Goto Github PK

View Code? Open in Web Editor NEW
5.0 2.0 1.0 25.79 MB

Project to generate event hash for EPCIS document/event in XML/JSON-LD format.

Home Page: https://openepcis.io

License: Apache License 2.0

Java 100.00%
epcis epcis20 gs1 gs1-standard hash java

openepcis-event-hash-generator's People

Contributors

sboeckelmann avatar tnahddisttud avatar

Stargazers

 avatar  avatar  avatar  avatar

Watchers

 avatar  avatar

Forkers

thaingo

openepcis-event-hash-generator's Issues

Improve parameter names for REST

I am unhappy with RESTful parameter names and functionality and it just came to my mind that it might be a good idea to match parameter with cli.

hashAlgorithm

Proposal: rename to "algorithm", maybe also support short form "a"

Additional functionality:
allow list of algorithms. TDB: comma seperated?

beautifyPreHash

Proposal: change to "join", similar to what we have in cli and support short form "j"

prehash

Proposal: also support shot form "p"

Add Quarkus native image support

The Quarkus framework support GraalVM native image build.
To make the runtime even smaller and thus required less resource, the container images shall be provided a native images as well.

Hashing algorithm misses some rules listed in the official cbv standard

Hi,

I compared again the outputs of our algorithms and I think you forgot a few rules that are listed in the official algorithm (in the cbv standard).

For example, you don't order pre-hash strings based on case-sensitive lexical ordering. You also don't support the new GS1 Web URI ( 'https://ref.gs1.org/cbv' ).

Here is an example of an output of our algorithm:

eventType=ObjectEvent
eventTime=2005-04-05T02:33:31.116Z
eventTimeZoneOffset=-06:00
epcListepc=https://id.gs1.org/01/10614141073464/21/2017
epc=https://id.gs1.org/01/10614141073464/21/2018
epc=https://id.gs1.org/01/10614141073464/21/2019
action=ADD
bizStep=https://ref.gs1.org/cbv/BizStep-receiving
disposition=https://ref.gs1.org/cbv/Disp-in_progress
readPointid=https://id.gs1.org/414/0012345111112/254/593
bizLocationid=https://id.gs1.org/414/0012345111112/254/3
destinationListtype=https://ref.gs1.org/cbv/SDT-location
destination=https://id.gs1.org/414/0614141007776
type=https://ref.gs1.org/cbv/SDT-location
destination=https://id.gs1.org/414/0614141007776
type=https://ref.gs1.org/cbv/SDT-location
destination=https://id.gs1.org/414/0614141007776
sensorElementListsensorElementsensorMetadatatime=2023-01-16T16:54:06.227Z
startTime=2019-04-02T12:55:01.000Z
endTime=2019-04-02T13:55:00.000Z
deviceID=https://id.gs1.org/8004/4000001111
deviceMetadata=https://id.gs1.org/8004/4000001111
rawData=https://id.gs1.org/8004/401234599999
dataProcessingMethod=https://id.gs1.org/253/4012345000054987
bizRules=https://id.gs1.org/253/4012345000054987
sensorReporttype=https://gs1.org/voc/Temperature
deviceID=https://id.gs1.org/8004/4000001252
deviceMetadata=https://id.gs1.org/8004/4000001111
rawData=https://id.gs1.org/8004/401234599999
dataProcessingMethod=https://id.gs1.org/253/4012345000054987
time=2019-07-19T13:00:00.000Z
microorganism=https://www.ncbi.nlm.nih.gov/taxonomy/1126011
chemicalSubstance=https://identifiers.org/inchikey:CZMRCDWAGMRECN-UGDNZRGBSA-N
value=26
component=https://ref.gs1.org/cbv/Comp-x
stringValue=SomeString
booleanValue=true
hexBinaryValue=f0f0f0
uriValue=https://id.gs1.org/8004/4000001111
minValue=26
maxValue=26.2
meanValue=13.2
sDev=0.1
percRank=50
percValue=12.7
uom=CEL
sensorReporttype=https://gs1.org/voc/Temperature
deviceID=https://id.gs1.org/8004/400000134
deviceMetadata=https://id.gs1.org/8004/4000001111
rawData=https://id.gs1.org/8004/401234599999
dataProcessingMethod=https://id.gs1.org/253/4012345000054987
time=2019-07-19T13:00:00.000Z
microorganism=https://www.ncbi.nlm.nih.gov/taxonomy/1126011
chemicalSubstance=https://identifiers.org/inchikey:CZMRCDWAGMRECN-UGDNZRGBSA-N
value=26
component=https://ref.gs1.org/cbv/Comp-x
stringValue=SomeString
booleanValue=true
hexBinaryValue=f0f0f0
uriValue=https://id.gs1.org/8004/4000001111
minValue=26
maxValue=26.2
meanValue=13.2
sDev=0.1
percRank=50
percValue=12.7
uom=CEL
sensorReporttype=https://gs1.org/voc/Temperature
deviceID=https://id.gs1.org/8004/4000001799
deviceMetadata=https://id.gs1.org/8004/4000001111
rawData=https://id.gs1.org/8004/401234599999
dataProcessingMethod=https://id.gs1.org/253/4012345000054987
time=2019-07-19T13:00:00.000Z
microorganism=https://www.ncbi.nlm.nih.gov/taxonomy/1126011
chemicalSubstance=https://identifiers.org/inchikey:CZMRCDWAGMRECN-UGDNZRGBSA-N
value=26
component=https://ref.gs1.org/cbv/Comp-x
stringValue=SomeString
booleanValue=true
hexBinaryValue=f0f0f0
uriValue=https://id.gs1.org/8004/4000001111
minValue=26
maxValue=26.2
meanValue=13.2
sDev=0.1
percRank=50
percValue=12.7
uom=CEL
sensorElementListsensorElementsensorMetadata{http://ns.example.com/epcis/}someFurtherMetadata=someText
sensorReport{http://ns.example.com/epcis/}someFurtherMetadata=someText
sensorReport{http://ns.example.com/epcis/}someFurtherMetadata=someText
sensorReport{http://ns.example.com/epcis/}someFurtherMetadata=someText
{http://ns.example.com/epcis/}myField=my_custom_value

Here is the associated document:

{
  "type": "EPCISDocument",
  "@context": [
    "https://ref.gs1.org/standards/epcis/2.0.0/epcis-context.jsonld",
    {
      "example": "http://ns.example.com/epcis/",
      "ext1": "http://example.com/ext1/",
      "ext2": "http://example.com/ext2/",
      "ext3": "http://example.com/ext3/",
      "evt": "https://evrythng.com/context"
    }
  ],
  "schemaVersion": "2.0",
  "creationDate": "2013-06-04T14:59:02.099+02:00",
  "epcisBody": {
    "eventList": [
      {
        "eventTimeZoneOffset": "-06:00",
        "eventTime": "2005-04-05T02:33:31.116Z",
        "type": "ObjectEvent",
        "recordTime": "2005-04-05T02:33:31.116Z",
        "epcList": [
          "urn:epc:id:sgtin:0614141.107346.2019",
          "urn:epc:id:sgtin:0614141.107346.2018",
          "urn:epc:id:sgtin:0614141.107346.2017"
        ],
        "@context": {
          "example": "http://ns.example.com/epcis/",
          "ext1": "http://example.com/ext1/"
        },
        "action": "ADD",
        "bizStep": "receiving",
        "disposition": "in_progress",
        "readPoint": {
          "id": "urn:epc:id:sgln:0012345.11111.593"
        },
        "bizLocation": {
          "id": "urn:epc:id:sgln:0012345.11111.3"
        },
        "destinationList": [
          {
            "type": "location",
            "destination": "urn:epc:id:sgln:0614141.00777.0"
          },
          {
            "type": "location",
            "destination": "urn:epc:id:sgln:0614141.00777.0"
          },
          {
            "type": "location",
            "destination": "urn:epc:id:sgln:0614141.00777.0"
          }
        ],
        "sensorElementList": [
          {
            "sensorMetadata": {
              "time": "2023-01-16T16:54:06.227Z",
              "deviceID": "urn:epc:id:giai:4000001.111",
              "deviceMetadata": "https://id.gs1.org/giai/4000001111",
              "rawData": "https://example.org/giai/401234599999",
              "startTime": "2019-04-02T12:55:01.000Z",
              "endTime": "2019-04-02T13:55:00.000Z",
              "dataProcessingMethod": "https://example.com/gdti/4012345000054987",
              "bizRules": "https://example.com/gdti/4012345000054987",
              "example:someFurtherMetadata": "someText"
            },
            "sensorReport": [
              {
                "type": "Temperature",
                "deviceID": "urn:epc:id:giai:4000001.252",
                "rawData": "https://example.org/giai/401234599999",
                "dataProcessingMethod": "https://example.com/gdti/4012345000054987",
                "time": "2019-07-19T13:00:00.000Z",
                "microorganism": "https://www.ncbi.nlm.nih.gov/taxonomy/1126011",
                "chemicalSubstance": "https://identifiers.org/inchikey:CZMRCDWAGMRECN-UGDNZRGBSA-N",
                "value": 26,
                "component": "x",
                "stringValue": "SomeString",
                "booleanValue": true,
                "hexBinaryValue": "f0f0f0",
                "uriValue": "https://id.gs1.org/giai/4000001111",
                "minValue": 26,
                "maxValue": 26.2,
                "meanValue": 13.2,
                "percRank": 50,
                "percValue": 12.7,
                "uom": "CEL",
                "sDev": 0.1,
                "deviceMetadata": "https://id.gs1.org/giai/4000001111",
                "example:someFurtherMetadata": "someText"
              },
              {
                "type": "Temperature",
                "deviceID": "urn:epc:id:giai:4000001.799",
                "rawData": "https://example.org/giai/401234599999",
                "dataProcessingMethod": "https://example.com/gdti/4012345000054987",
                "time": "2019-07-19T13:00:00.000Z",
                "microorganism": "https://www.ncbi.nlm.nih.gov/taxonomy/1126011",
                "chemicalSubstance": "https://identifiers.org/inchikey:CZMRCDWAGMRECN-UGDNZRGBSA-N",
                "value": 26,
                "component": "x",
                "stringValue": "SomeString",
                "booleanValue": true,
                "hexBinaryValue": "f0f0f0",
                "uriValue": "https://id.gs1.org/giai/4000001111",
                "minValue": 26,
                "maxValue": 26.2,
                "meanValue": 13.2,
                "percRank": 50,
                "percValue": 12.7,
                "uom": "CEL",
                "sDev": 0.1,
                "deviceMetadata": "https://id.gs1.org/giai/4000001111",
                "example:someFurtherMetadata": "someText"
              },
              {
                "type": "Temperature",
                "deviceID": "urn:epc:id:giai:4000001.34",
                "rawData": "https://example.org/giai/401234599999",
                "dataProcessingMethod": "https://example.com/gdti/4012345000054987",
                "time": "2019-07-19T13:00:00.000Z",
                "microorganism": "https://www.ncbi.nlm.nih.gov/taxonomy/1126011",
                "chemicalSubstance": "https://identifiers.org/inchikey:CZMRCDWAGMRECN-UGDNZRGBSA-N",
                "value": 26,
                "component": "x",
                "stringValue": "SomeString",
                "booleanValue": true,
                "hexBinaryValue": "f0f0f0",
                "uriValue": "https://id.gs1.org/giai/4000001111",
                "minValue": 26,
                "maxValue": 26.2,
                "meanValue": 13.2,
                "percRank": 50,
                "percValue": 12.7,
                "uom": "CEL",
                "sDev": 0.1,
                "deviceMetadata": "https://id.gs1.org/giai/4000001111",
                "example:someFurtherMetadata": "someText"
              }
            ],
            "example:myField": "my_custom_value"
          }
        ],
        "eventID": "ni:///sha-256;9b64040b80d4d8a63fd694a3bed949ccf7c8bd402506f9eaed3f7e1f01d5f8ca?ver=CBV2.0"
      }
    ]
  }
}

Here is yours:

eventType=ObjectEvent
eventTime=2005-04-05T02:33:31.116Z
eventTimeZoneOffset=-06:00
epcList
epc=https://id.gs1.org/01/10614141073464/21/2017
epc=https://id.gs1.org/01/10614141073464/21/2018
epc=https://id.gs1.org/01/10614141073464/21/2019
action=ADD
bizStep=https://ref.gs1.org/cbv/BizStep-receiving
disposition=https://ref.gs1.org/cbv/Disp-in_progress
readPoint
id=https://id.gs1.org/414/0012345111112/254/593
bizLocation
id=https://id.gs1.org/414/0012345111112/254/3
destinationList
type=https://ref.gs1.org/cbv/SDT-location
destination=https://id.gs1.org/414/0614141007776/254/0
type=https://ref.gs1.org/cbv/SDT-location
destination=https://id.gs1.org/414/0614141007776/254/0
type=https://ref.gs1.org/cbv/SDT-location
destination=https://id.gs1.org/414/0614141007776/254/0
sensorElementList
sensorElement
sensorMetadata
time=2023-01-16T16:54:06.227Z
startTime=2019-04-02T12:55:01.000Z
endTime=2019-04-02T13:55:00.000Z
deviceID=https://id.gs1.org/8004/4000001111
deviceMetadata=https://id.gs1.org/giai/4000001111
rawData=https://example.org/giai/401234599999
dataProcessingMethod=https://example.com/gdti/4012345000054987
bizRules=https://example.com/gdti/4012345000054987
sensorReport
type=Temperature
deviceID=https://id.gs1.org/8004/4000001252
deviceMetadata=https://id.gs1.org/giai/4000001111
rawData=https://example.org/giai/401234599999
dataProcessingMethod=https://example.com/gdti/4012345000054987
time=2019-07-19T13:00:00.000Z
microorganism=https://www.ncbi.nlm.nih.gov/taxonomy/1126011
chemicalSubstance=https://identifiers.org/inchikey:CZMRCDWAGMRECN-UGDNZRGBSA-N
value=26
component=x
stringValue=SomeString
booleanValue=true
hexBinaryValue=f0f0f0
uriValue=https://id.gs1.org/giai/4000001111
minValue=26
maxValue=26.2
meanValue=13.2
sDev=0.1
percRank=50
percValue=12.7
uom=CEL
sensorReport
type=Temperature
deviceID=https://id.gs1.org/8004/4000001799
deviceMetadata=https://id.gs1.org/giai/4000001111
rawData=https://example.org/giai/401234599999
dataProcessingMethod=https://example.com/gdti/4012345000054987
time=2019-07-19T13:00:00.000Z
microorganism=https://www.ncbi.nlm.nih.gov/taxonomy/1126011
chemicalSubstance=https://identifiers.org/inchikey:CZMRCDWAGMRECN-UGDNZRGBSA-N
value=26
component=x
stringValue=SomeString
booleanValue=true
hexBinaryValue=f0f0f0
uriValue=https://id.gs1.org/giai/4000001111
minValue=26
maxValue=26.2
meanValue=13.2
sDev=0.1
percRank=50
percValue=12.7
uom=CEL
sensorReport
type=Temperature
deviceID=https://id.gs1.org/8004/400000134
deviceMetadata=https://id.gs1.org/giai/4000001111
rawData=https://example.org/giai/401234599999
dataProcessingMethod=https://example.com/gdti/4012345000054987
time=2019-07-19T13:00:00.000Z
microorganism=https://www.ncbi.nlm.nih.gov/taxonomy/1126011
chemicalSubstance=https://identifiers.org/inchikey:CZMRCDWAGMRECN-UGDNZRGBSA-N
value=26
component=x
stringValue=SomeString
booleanValue=true
hexBinaryValue=f0f0f0
uriValue=https://id.gs1.org/giai/4000001111
minValue=26
maxValue=26.2
meanValue=13.2
sDev=0.1
percRank=50
percValue=12.7
uom=CEL
sensorElementList
sensorElement
sensorMetadata
{http://ns.example.com/epcis/}someFurtherMetadata=someText
sensorReport
{http://ns.example.com/epcis/}someFurtherMetadata=someText
sensorReport
{http://ns.example.com/epcis/}someFurtherMetadata=someText
sensorReport
{http://ns.example.com/epcis/}someFurtherMetadata=someText
{http://ns.example.com/epcis/}myField=my_custom_value

I am sorry, I know we don't have the same indentation format for the pre-hash string, but I hope it still helps!

Adding support for CBV 2.1 and making changes to pre-hash string accordingly

As per the recommendation from @RalphTro, according to the latest changes to the CBV document (i.e. CBV 2.1) need to adjust the Event Hash Generator pre-hash string as follows:

  • sensorElementList should appear before the sensorElement.
  • User Extensions that are part of the EPCIS standard fields and should appear directly beneath the respective standard field instead of at the end.
  • Adjust the generated Hash-ID to include CBV2.1 instead of CBV 2.0 (?ver=CBV2.1)

@RalphTro Please let us know if something is missing or needs to be corrected.

Potential issues on the implementation of the algorithm

Hi,

First of all, thanks a lot for you open source implementation. It is super useful.
I tested your algorithm, and compared it to ours (https://github.com/evrythng/epcis2.js#generating-a-hashed-id-for-an-event)

I compared with this EPCIS document:

{
  "@context": "https://ref.gs1.org/standards/epcis/2.0.0/epcis-context.jsonld",

  "id": "_:document1",
  "type": "EPCISDocument",
  "schemaVersion": "2.0",
  "creationDate": "2005-07-11T11:30:47.0Z",
  "epcisBody": {
    "eventList": [
      {
        "type": "ObjectEvent",
        "action": "OBSERVE",
        "bizStep": "shipping",
        "disposition": "in_transit",
        "epcList": ["urn:epc:id:sgtin:0614141.107346.2017", "urn:epc:id:sgtin:0614141.107346.2018"],
        "eventTime": "2005-04-03T20:33:31.116000-06:00",
        "eventTimeZoneOffset": "-06:00",
        "readPoint": { "id": "urn:epc:id:sgln:0614141.07346.1234" },
        "bizTransactionList": [
          {
            "type": "po",
            "bizTransaction": "http://transaction.acme.com/po/12345678"
          }
        ]
      }
    ]
  }
}

The pre-hash string I got from your algorithm is:

eventType=ObjectEvent
eventTime=2005-04-04T02:33:31.116Z
eventTimeZoneOffset=-06:00
epcList
epc=https://id.gs1.org/01/10614141073464/21/2017
epc=https://id.gs1.org/01/10614141073464/21/2018
action=OBSERVE
bizStep=https://ref.gs1.org/voc/Bizstep-shipping
disposition=https://ref.gs1.org/voc/Disp-in_transit
readPoint
id=https://id.gs1.org/414/0614141073467/254/1234
bizTransactionList
bizTransaction=http://transaction.acme.com/po/12345678
type=https://ref.gs1.org/voc/BTT-po

Whereas I got this from ours:

eventType=ObjectEvent
eventTime=2005-04-04T02:33:31.116Ze
ventTimeZoneOffset=-06:00
epcList
epc=https://id.gs1.org/01/10614141073464/21/2017
epc=https://id.gs1.org/01/10614141073464/21/2018
action=OBSERVE
bizStep=https://ref.gs1.org/cbv/BizStep-shipping
disposition=https://ref.gs1.org/cbv/Disp-in_transit
readPoint
id=https://id.gs1.org/414/0614141073467/254/1234
bizTransactionList
type=https://ref.gs1.org/cbv/BTT-po
bizTransaction=http://transaction.acme.com/po/12345678

There are two differences:

  1. For the CBV URL, you use https://ref.gs1.org/voc/ whereas we use https://ref.gs1.org/cbv/. I think the second option is the correct path. Here is how it is defined in the CBV standard:

If an EPCIS event is represented in JSON/JSON-LD, standard vocabulary elements are not expressed as URIs, but in bare string notation (i.e. 'in_transit' instead of 'https://ref.gs1.org/cbv/Disp-in_transit'). All standard vocabulary elements expressed in bare string notation SHALL be expanded to their corresponding GS1 Web URI (starting with 'https://ref.gs1.org/cbv').

  1. For bizTransactionLists, you put the bizTransaction first and then the type. However, here is what I got from the canonical order, defined in the standard:
  1. bizTransactionList – bizTransaction (business transaction type, business transaction ID)
    For most of the fields that has a type field, the latter should be first in the associated prehash string.

I hope this helps! :)

Regards,

Clément

User Extensions are not sorted correctly

Creating the issue on behalf of @RalphTro to track all the issues that were reported by him and also support OpenEPCIS Event Hash Generator for both CBV 2.0 and CBV 2.1:

User Extensions are not sorted correctly:

When the following EPCIS document is passed then the generated userextensions in pre-hash are ordered as follows:

sensorElement
sensorReport
{https://ns.example.com/epcis/}sameFieldName=SameValueB
sensorElement
sensorReport
{https://ns.example.com/epcis/}sameFieldName=SameValueA
EPCIS Document
{
  "@context": [
    "https://ref.gs1.org/standards/epcis/2.0.0/epcis-context.jsonld",
    {
      "example": "https://ns.example.com/epcis/"
    }
  ],
  "type": "EPCISDocument",
  "schemaVersion": "2.0",
  "creationDate": "2023-08-25T15:00:00.1+01:00",
  "epcisBody": {
    "eventList": [
      {
        "type": "ObjectEvent",
        "sensorElementList": [
          {
            "sensorReport": [
              {
                "type": "Temperature",
                "value": 12.4,
                "uom": "CEL",
                "example:sameFieldName": "SameValueB"
              }
            ]
          },
          {
            "sensorReport": [
              {
                "type": "Temperature",
                "value": 20.6,
                "uom": "CEL",
                "example:sameFieldName": "SameValueA"
              }
            ]
          }
        ]
      }
    ]
  }
}

ideally it should be ordered as follows:

sensorElement
sensorReport
{https://ns.example.com/epcis/}sameFieldName=SameValueA
sensorElement
sensorReport
{https://ns.example.com/epcis/}sameFieldName=SameValueB

Failing for EPCIS events with eventID

hash generator fails for EPCIS events having a custom eventID

partial example:

...
    "eventList": [
      {
        "type": "AggregationEvent",
        "eventTime": "2013-06-08T14:58:56.591Z",
        "eventTimeZoneOffset": "+02:00",
        "eventID": "urn:uuid:5d3c82cc-3fb2-4b70-af4a-914f1f839c5b",
        "parentID": "urn:epc:id:sscc:0614141.1234567890",
        "childEPCs": [
          "urn:epc:id:sgtin:0614141.107346.2017",
....

Extension field ordering (http vs. https)

Dear @sboeckelmann ,

I presume that the (great) web tool residing on https://tools.openepcis.io/openepcis-ui/EventHash is based on this library.

If this holds true, I am happy to share the following observation. Then I passed the tool the following JSON-LD structure:

{ "@context": [ "https://ref.gs1.org/standards/epcis/2.0.0/epcis-context.jsonld", { "abc": "https://ns.abc.de/epcis/", "example": "http://ns.example.com/epcis/", "fgh": "https://ns.fgh.co.uk/epcis/", "schema": "https://schema.org/", "sdo": "https://schema.org/" } ], "type": "EPCISDocument", "schemaVersion": "2.0", "creationDate": "2005-07-11T11:30:47.0Z", "epcisBody": { "eventList": [ { "type": "ObjectEvent", "action": "OBSERVE", "bizStep": "receiving", "disposition": "in_progress", "epcList": [ "https://id.gs1.org/01/70614141123451/21/2018" ], "eventTime": "2005-04-04T20:33:31.116-06:00", "eventTimeZoneOffset": "-06:00", "readPoint": { "id": "urn:epc:id:sgln:0012345.11111.400" }, "bizLocation": { "id": "urn:epc:id:sgln:0012345.11111.0" }, "fgh:a-date": "2023-10-09", "example:myField": "Example of a vendor/user extension", "abc:a-integer": 2, "abc:z-integer": 1, "schema:award": "Order of Standards", "schema:mpn": "4711", "sdo:nsn": "4712" } ] } }

...the ordering works ALMOST flawlessly, with one exception. When you look at the extension fields further below, the field with 'http:' should in my POV be the first extension field as ":" comes before "s" in the UTF8 encoding table.

eventType=ObjectEvent
eventTime=2005-04-05T02:33:31.116Z
eventTimeZoneOffset=-06:00
epcList
epc=https://id.gs1.org/01/70614141123451/21/2018
action=OBSERVE
bizStep=https://ref.gs1.org/voc/Bizstep-receiving
disposition=https://ref.gs1.org/voc/Disp-in_progress
readPointid=https://id.gs1.org/414/0012345111112/254/400
bizLocationid=https://id.gs1.org/414/0012345111112/254/0
{https://ns.abc.de/epcis/}a-integer=2
{https://ns.abc.de/epcis/}z-integer=1
{http://ns.example.com/epcis/}myField=Example of a vendor/user extension
{https://ns.fgh.co.uk/epcis/}a-date=2023-10-09
{https://schema.org/}award=Order of Standards{https://schema.org/}mpn=4711
{https://schema.org/}nsn=4712

Would you agree to this?

Hope this helps.

Kind regards,
Ralph

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.