dividebv / postnl Goto Github PK
View Code? Open in Web Editor NEWLibrary to connect to PostNL's SOAP service called CIF
License: GNU General Public License v2.0
Library to connect to PostNL's SOAP service called CIF
License: GNU General Public License v2.0
Hi,
How can we set the Evening delivery trhough this api?
Hello,
I am using your POSTNL API for almost an year to generate multiple labels in a single page (Basically 4 labels in one pdf) which was working successfully. Recently I updated the code so that i can upgrade to the new POSTNL API. After updating the code (using the lastest vserion of DivideBV/Postnl ) i am not able to generate multiple column shipment labels.
Below i have shared code. Can you please tell me what is the issue? Thank you.
$client = new Postnl(
000000 , // Customer number
'TSRV', // Customer code
'Customer name', // Customer name
'API key', // Password
111111, // Collection location
'CV0781', // Globalpack
false // Whether to use PostNL's sandbox environment.
);
$product_code_delivery = "3085";
$senderAddress = ComplexTypes\Address::create();
// fill in address
$num_collo = 4;
$package_count = 4;
$receiverAddress1 = ComplexTypes\Address::create();
$receiverAddress2 = ComplexTypes\Address::create();
$receiverAddress3 = ComplexTypes\Address::create();
$receiverAddress4 = ComplexTypes\Address::create();
// Parcel 1 of 4.
$barcode1 = $client->generateBarcodeByDestination($receiverAddress1->getCountrycode());
$shipment1 = ComplexTypes\Shipment::create()
->setBarcode($barcode1)
->setDimension(ComplexTypes\Dimension::create()
->setWeight(5000) // Weight in g
->setWidth(215) // Width in mm
->setLength(305) // Length in mm
->setHeight(280) // Height in mm
)
->setProductCodeDelivery($product_code_delivery)
->setAddresses(new ComplexTypes\ArrayOfAddress([
$receiverAddress1,
$senderAddress,
]));
// Set product code, dimension, etc...
$group1 = ComplexTypes\Group::create()
->setGroupSequence(1)
->setGroupCount($num_collo)
->setGroupType('01')
->setMainBarcode($barcode1);
$shipment1->setGroups(new ComplexTypes\ArrayOfGroup([$group1]));
// Parcel 2 of 4.
$barcode2 = $client->generateBarcodeByDestination($receiverAddress2->getCountrycode());
$shipment2 = ComplexTypes\Shipment::create()
->setBarcode($barcode2)
->setDimension(ComplexTypes\Dimension::create()
->setWeight(5000) // Weight in g
->setWidth(215) // Width in mm
->setLength(305) // Length in mm
->setHeight(280) // Height in mm
)
->setProductCodeDelivery($product_code_delivery)
->setAddresses(new ComplexTypes\ArrayOfAddress([
clone $receiverAddress2,
clone $senderAddress,
]));
// Set product code, address, dimension, etc...
$group2 = ComplexTypes\Group::create()
->setGroupSequence(2)
->setGroupCount($num_collo)
->setGroupType('01')
->setMainBarcode($barcode2);
$shipment2->setGroups(new ComplexTypes\ArrayOfGroup([$group2]));
// Parcel 3 of 4.
$barcode3 = $client->generateBarcodeByDestination($receiverAddress3->getCountrycode());
$shipment3 = ComplexTypes\Shipment::create()
->setBarcode($barcode3)
->setDimension(ComplexTypes\Dimension::create()
->setWeight(5000) // Weight in g
->setWidth(215) // Width in mm
->setLength(305) // Length in mm
->setHeight(280) // Height in mm
)
->setProductCodeDelivery($product_code_delivery)
->setAddresses(new ComplexTypes\ArrayOfAddress([
clone $receiverAddress3,
clone $senderAddress,
]));
// Set product code, address, dimension, etc...
$group3 = ComplexTypes\Group::create()
->setGroupSequence(3)
->setGroupCount($num_collo)
->setGroupType('01')
->setMainBarcode($barcode3);
$shipment3->setGroups(new ComplexTypes\ArrayOfGroup([$group3]));
// Parcel 4 of 4.
$barcode4 = $client->generateBarcodeByDestination($receiverAddress4->getCountrycode());
$shipment4 = ComplexTypes\Shipment::create()
->setBarcode($barcode4)
->setDimension(ComplexTypes\Dimension::create()
->setWeight(5000) // Weight in g
->setWidth(215) // Width in mm
->setLength(305) // Length in mm
->setHeight(280) // Height in mm
)
->setProductCodeDelivery($product_code_delivery)
->setAddresses(new ComplexTypes\ArrayOfAddress([
clone $receiverAddress4,
clone $senderAddress,
]));
// Set product code, address, dimension, etc...
$group4 = ComplexTypes\Group::create()
->setGroupSequence(4)
->setGroupCount($num_collo)
->setGroupType('01')
->setMainBarcode($barcode4);
$shipment4->setGroups(new ComplexTypes\ArrayOfGroup([$group4]));
$results = $client->generateLabels(new ComplexTypes\ArrayOfShipment([$shipment1,$shipment2,$shipment3,$shipment4]));
$i=0;
if(!empty($results)) {
foreach ($results->getResponseShipments() as $result) {
$file_n = $_SERVER['DOCUMENT_ROOT'] . '/controller/Export_History/EXPORT_DATA/LABELS/' . date('Y') . '/' . date('m') . '/' . date('d') . '/' . $i . '.pdf';
$file = new \SplFileObject($file_n, 'w',true);
$handle = fopen($file, "w");
if(count($package_count) > 1) {
fwrite($handle, $results->getMergedLabels()->getMergedLabel()->getLabels()->getLabel()->getContent());
}else{
fwrite($handle, $results->getResponseShipments()->getResponseShipment()->getLabels()->getLabel()->getContent());
}
fclose($handle);
}
}
Hello there,
Since we have a problem with implentation of a new product of PostNL we have problems with the implentation. PostNL ask us about the request URL and all logs of the request, but i can't give it to them because the API has no debugging features.
Can someone help me by adding those features?
Thanks in advance.
In the Location webservice, there is a function called GetNearestLocations
. It is implemented in this library as GetNearestLocation
(singular, without the 's'). This is quite confusing as (1) it returns multiple locations, and (2) people are likely to try the function from the documentation, which doesn't exist.
Is it okay if I fix this in a PR and create a GetNearestLocations
function which wraps GetNearestLocation
(to maintain backwards compatibility)? Or is this undesirable and should we consider this a non-issue (and I shouldn't complain 😛)?
Hello,
I'm trying to retrieve the status codes of my shipments. Iam using the following code:
$status = $client->currentStatus($barcode);
$shipments = $status->getShipments();
The response contains the data I want but I have no clue how to access it because it's protected.
I think I somehow need to access ResponseStatus->getCurrentStatusCode but I dont know how..
Any help would be appreciated!
README.md
says: requires PHP >= 5.4.
composer.json
however says: requires "php": "^5.4"
, which excludes PHP 7 (see doc).
I've briefly tested this on PHP 7.0, and everything seems to be working fine. I suggest you change the line in composer.json
to "php": ">=5.4"
.
For generating a pick-up label we need to set a address for the customer. See:
https://developer.postnl.nl/apis//pickup-postnl-location-shipment-labelling-example
It is not possible to setAddress for client.
This package requires the soap
PHP extension, but that wasn't immediately clear to me. Could you mention this in the readme (in the installation section maybe)?
Besides that, THANK YOU for this awesome package. I can't imagine how much work this has saved me. You rock!
The property StreetHouseNrExt is a combination of Street, HouseNr and HouseNrExt.
It isn't possible to use this property with this library, because there isn't a setter defined. There is a comment in this library about this, claiming this property isn't used:
https://github.com/DivideBV/Postnl/blob/master/src/ComplexTypes/Address.php#L86-L91
But according to the official PostNL repo the field setStreetHouseNrExt CAN be used for NL, BE and DE addresses.: https://developer.postnl.nl/apis/labelling-webservice/documentation#toc-6.
I would like to use this property, because I think PostNL does a better job at extracting the required fields from an address correctly.
Is there a reason this property isn't used in this library?
Hello there,
I'm using multi-colli labeling from the wiki, but the labels won't been displayed. Only the last label will. I don't know what i'm doing wrong. Here's my code:
`$receiverAddress = ComplexTypes\Address::create()
->setAddressType('01')
->setFirstName($item['first_name'])
->setName($item['name'])
->setCompanyName($item['company'])
->setStreet($item['street'])
->setHouseNr($item['housenr'])
->setHouseNrExt($item['housenr_extra'])
->setZipcode($item['zip'])
->setCity($item['city'])
->setCountrycode($item['country']);
//Set our address
$senderAddress = ComplexTypes\Address::create()
->setAddressType('02')
->setFirstName(' ')
->setName(' ')
->setCompanyName('B.V.')
->setStreet('weg')
->setHouseNr('2')
->setHouseNrExt('')
->setZipcode('1111AB')
->setCity('Plaats')
->setCountrycode('NL');
// Create a shipment.
$shipment = ComplexTypes\Shipment::create()
->setAddresses(new ComplexTypes\ArrayOfAddress([
$receiverAddress,
$senderAddress,
]))
->setBarcode($item['code'])
->setDimension(ComplexTypes\Dimension::create()
->setWeight($item['package_weight'].'00') // Weight in g
->setWidth($item['package_width'].'00') // Width in mm
->setLength($item['package_length'].'00') // Length in mm
->setHeight($item['package_height'].'00') // Height in mm
)
->setProductCodeDelivery('3085');
$results = $client->generateLabelsWithoutConfirm(new ComplexTypes\ArrayOfShipment([$shipment1,$shipment2,$shipment3]));
if(isset($results))
{
foreach($results->getResponseShipments() as $result)
{
// Save the label PDF locally
$label = $result->getLabels()[0];
$file = new \SplFileObject("$barcode.pdf", 'w');
file_put_contents("files/label.$barcode.pdf", $label->getContent());
}
}`
There is an foreach from the MySQL database and the code is a bit stripped.
Can any of you have a look on this?
Thanks in advance.
Best regards.
We don't use the latest available API interfaces from PostNL:
1_7
, latest is 1_9
(PR #25)1_8
, latest is 2_0
(PR #27)2_0
, latest is 2_1
(PR #30)I think the changes are minor, but it is always good to use the latest available version.
Hi,
Hope someone can help me out. Trying to get the Locations for drop points.
this is my code:
include ("./vendor/autoload.php");
use DivideBV\Postnl\Postnl;
use DivideBV\Postnl\ComplexTypes;
$client = new Postnl(
Customer number, // Customer number
'CCODE', // Customer code
'Customer name', // Customer name
'Username', // Username
'Password', // Password
Collection location, // Collection location
'Globalpack', // Globalpack
false // Whether to use PostNL's sandbox environment.
);
$test = $client->getLocation('1211GG');
Will result in this error:
PHP Fatal error: Uncaught exception 'DivideBV\\Postnl\\ComplexTypes\\CifException' in vendor/dividebv/postnl/src/Postnl.php:577 Stack trace: #0 vendor/dividebv/postnl/src/Postnl.php(503): DivideBV\\Postnl\\Postnl->call('LocationClient', 'getLocation', Object(DivideBV\\Postnl\\ComplexTypes\\GetLocationRequest)) #1 postnl-test.php(22): DivideBV\\Postnl\\Postnl->getLocation('1211GG') #2 {main} thrown in vendor/dividebv/postnl/src/Postnl.php on line 577
Hope someone can help me out.
After running "composer clear-cache" and "composer require dividebv/postnl" it installs version 1.2.1. For some reason the downloaded files don't contain the same source code as the files I see on GitHub. For example, the downloaded Postnl.php file contains the following code:
public function __construct(
$customerNumber,
$customerCode,
$customerName,
$username,
$password,
$collectionLocation,
$globalPack,
$sandbox = false
) {
$this->customerNumber = $customerNumber;
$this->customerCode = $customerCode;
$this->customerName = $customerName;
$this->securityHeader = new ComplexTypes\SecurityHeader($username, $password);
$this->collectionLocation = $collectionLocation;
$this->globalPackBarcodeType = preg_filter('/^(.{2})(.{4})$/', '$1', $globalPack);
$this->globalPackCustomerCode = preg_filter('/^(.{2})(.{4})$/', '$2', $globalPack);
$this->sandbox = $sandbox;
}
Am I doing something wrong or is something not working properly?
When creating a label with code (3087) the system is not creating a label. Proberly because there must be a value be send over with the ammount of increased responsibility.
Is this possible through the API?
How to use the code to also send the contact details to the api?
i have input a nonexistent postal code. If i turn it on debug mode the message is 'onbekend adres'
but if it bij the function getWarnings :
code:
$result = $client->generateLabel($shipment, 'GraphicFile|PDF|MergeA');
var_dump($result->getWarnings());
output:
object(DivideBV\Postnl\ComplexTypes\ArrayOfWarning)#27 (1) { ["Warning":protected]=> NULL }
or is there another way to show the warnings?
Interface Version | 2_2 |
---|---|
Sandbox endpoint | https://api-sandbox.postnl.nl/shipment/v2_2/calculate/date/ |
Sandbox WSDL | https://api-sandbox.postnl.nl/shipment/v2_2/calculate/date/ |
Production endpoint | https://api.postnl.nl/shipment/v2_2/calculate/date |
Production WSDL | https://api.postnl.nl/shipment/v2_2/calculate/date/soap.wsdl |
topic can be closed (sorry)
Error code 13308 seems to be undocumented by PostNL, but this means
Due to the COVID-19 pandemic we currently cannot ship to this destination
So PostNL does not ship to certain locations anymore, in this case Belgium.
Stay Safe everyone!
Hi,
How can we set the Receiver email and Phonenumber trhough this api?
Why is getSentDate not part of postnl class? getDeliveryDate is available.
Hello,
I've used the 0.6.0 version of the repository. Now I want to update and all seems to be working fine, except that I'm getting a PDF returned instead of a PNG. Now I figured out that it is possible to change the printerType
, which is default PDF
. But how to get a PNG?
I don't want a PDF, I need a PNG. The PNG is directly send to a Dymo printer, I'm not storing the labels.
Expected Behavior
When calling Postnl::getNearestLocations
I Expect a response with dropoff locations.
Current Behavior
When executed, the response is an error:
"Parameter 'Location.OpeningTime' may not be null."
Steps to Reproduce
// Codesnippet from Postnl::getNearestLocations with sample data
$message = new ComplexTypes\Message;
$location = new ComplexTypes\Location('4330AB', 'false', '15-10-2018');
$request = new ComplexTypes\GetNearestLocationsRequest($message, $location, 'NL');
Workaround
It looks like PostNL doesnt like the empty key OpeningTime
. A Quick workaround is to disable line 24 in BaseLocation:
/**
* @var string
*/
//protected $OpeningTime = null;
Version
v2.0.0-beta1
When I try to create a barcode using the generateBarcodeByDestination function it fails when I want to create one for a address in Germany using the country code DE
The error I get is:
Validation failed for shipment: 3STTWJ196232075, Messages: Barcode length must be 13 characters
Hi ,
I am trying to integrate the POSTNL api on local server whose php version is 5.5.15 and namespaces are also active in php.ini. I have created a index.php (inside /DivideBV/Postnl/ ) and has same code which you have mention in the example . But when i trying to run the index.php it give fatal error : "Fatal error: Class 'Postnl' not found".
Can you please help me regarding this .
Thank you
How can you get the current status of the transport?
Every time I trie to use the "currentStatus" function or the "currentStatusByReference" function I get this error:
"The user is not authorized for the method 'CurrentStatus'."
In the Postnl class, there are setters to set the various clients. However, there are no getters for them. Because of this, there is no easy way to call some parts of the api. (For example, completeStatus from ShippingStatusClient).
Two possible fixes: Proxy all methods from each client in the Postnl class, or make the clients themselves accessible.
When the PostNL webservice returns an error, I'm getting undefined notices because the ExceptionData
is not an array.
Notice Error: Trying to get property 'Description' of non-object in [/var/www/html/app/Vendor/dividebv/postnl/src/Postnl.php, line 566]
Notice Error: Trying to get property 'ErrorMsg' of non-object in [/var/www/html/app/Vendor/dividebv/postnl/src/Postnl.php, line 567]
Notice Error: Trying to get property 'ErrorNumber' of non-object in [/var/www/html/app/Vendor/dividebv/postnl/src/Postnl.php, line 568]
Notice Error: Trying to get property 'Description' of non-object in [/var/www/html/app/Vendor/dividebv/postnl/src/Postnl.php, line 566]
Notice Error: Trying to get property 'ErrorMsg' of non-object in [/var/www/html/app/Vendor/dividebv/postnl/src/Postnl.php, line 567]
Notice Error: Trying to get property 'ErrorNumber' of non-object in [/var/www/html/app/Vendor/dividebv/postnl/src/Postnl.php, line 568]
Notice Error: Trying to get property 'Description' of non-object in [/var/www/html/app/Vendor/dividebv/postnl/src/Postnl.php, line 566]
Notice Error: Trying to get property 'ErrorMsg' of non-object in [/var/www/html/app/Vendor/dividebv/postnl/src/Postnl.php, line 567]
Notice Error: Trying to get property 'ErrorNumber' of non-object in [/var/www/html/app/Vendor/dividebv/postnl/src/Postnl.php, line 568]
Debugging shows that $exception
(HERE) has the following data:
SoapFault {#64
#message: "Check CIFException in the detail section"
#code: 0
#file: "./app/Vendor/dividebv/postnl/src/LabellingClient.php"
#line: 59
+"faultstring": "Check CIFException in the detail section"
+"faultcode": "s:CIF Framework Message Interceptor"
+"detail": {#60
+"CifException": {#61
+"Errors": {#62
+"ExceptionData": {#63
+"Description": null
+"ErrorMsg": "Validation failed for shipment: xxxx, Messages: xxx: {[xxxx] Receiver Street is required}"
+"ErrorNumber": "1003"
}
}
}
}
trace: {
./app/Vendor/dividebv/postnl/src/LabellingClient.php:59 { …}
}
}
I can see in
DivideBV\Postnl\ComplexTypes\Label the method setLabeltype.
I would like to assume this can be used for the CN23 form (A5) labeltype.
But I cant see where it wil get it's use or how to put it in use.
Given the fact that PostNL will be updating their API in such a way;
The shipping API combines the functionalities of the following webservices:
Will this repository be updated to be able to connect to that API?
How to get the weight of the package?
Hi, Can we create labels in bulk?
I have a domestic 3089 shipment. The request works in the old CIF environment, but the environment with the new AUTH is broken. I get these errors:
<?xml version="1.0"?>
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
<s:Body>
<s:Fault>
<faultcode>s:CIF Framework Message Interceptor</faultcode>
<faultstring xml:lang="en-US">Check CIFException in the detail section</faultstring>
<detail>
<CifException xmlns="http://postnl.nl/cif/services/common/" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<Errors>
<ExceptionData>
<Description i:nil="true"/>
<ErrorMsg>Required parameter 'Customer.Address.AddressType' is missing.</ErrorMsg>
<ErrorNumber>4</ErrorNumber>
</ExceptionData>
<ExceptionData>
<Description i:nil="true"/>
<ErrorMsg>Required parameter 'Customer.Address.City' is missing.</ErrorMsg>
<ErrorNumber>4</ErrorNumber>
</ExceptionData>
<ExceptionData>
<Description i:nil="true"/>
<ErrorMsg>Required parameter 'Customer.Address.Countrycode' is missing.</ErrorMsg>
<ErrorNumber>4</ErrorNumber>
</ExceptionData>
<ExceptionData>
<Description i:nil="true"/>
<ErrorMsg>Required parameter 'Shipments.Shipment.0.Customs.HandleAsNonDeliverable' is missing.</ErrorMsg>
<ErrorNumber>4</ErrorNumber>
</ExceptionData>
<ExceptionData>
<Description i:nil="true"/>
<ErrorMsg>Required parameter 'Shipments.Shipment.0.Customs.ShipmentType' is missing.</ErrorMsg>
<ErrorNumber>4</ErrorNumber>
</ExceptionData>
<ExceptionData>
<Description i:nil="true"/>
<ErrorMsg>Required parameter 'Shipments.Shipment.0.Customs.Currency' is missing.</ErrorMsg>
<ErrorNumber>4</ErrorNumber>
</ExceptionData>
<ExceptionData>
<Description i:nil="true"/>
<ErrorMsg>Required parameter 'Shipments.Shipment.0.Customs.Content' is missing.</ErrorMsg>
<ErrorNumber>4</ErrorNumber>
</ExceptionData>
</Errors>
</CifException>
</detail>
</s:Fault>
</s:Body>
</s:Envelope>
The funny thing is that it complains about customs for a shipment within NL.
-so sorry, wrong field!-
The old PostNL API will be migrated at 1 November 2018.
One of the big changes is that the username and password will be replaced by an API key.
Is the 2.0 branch stable enough?
Hey , i am using your code to generate nl labels, everything works fine, the labels are generated. But for 'be' i am unable to generate a label.
I've used this $product_code_delivery = "4952"; for generating be labels, but it gives me this error.
Uncaught exception 'DivideBV\Postnl\ComplexTypes\CifException'
HI,
HOW TO SET LABEL TYPE?
thx
In order to create a 4944 package to Croatia, i had to change the countryCodeMapping variable.
protected $countryCodeMapping = [
// Dutch domestic product.
'NL' => '3S',
// EPS products.
'AT' => '3S',
'BE' => '3S',
'BG' => '3S',
'CZ' => '3S',
'CY' => '3S',
'DK' => '3S',
'EE' => '3S',
'FI' => '3S',
'FR' => '3S',
'DE' => '3S',
// 'GB' => '3S',
'GR' => '3S',
'HR' => '3S', //Croatia
'HU' => '3S',
'IE' => '3S',
'IT' => '3S',
'LV' => '3S',
'LT' => '3S',
'LU' => '3S',
'PL' => '3S',
'PT' => '3S',
'RO' => '3S',
'SK' => '3S',
'SI' => '3S',
'ES' => '3S',
'SE' => '3S',
// Everything else is GlobalPack.
];
Can this be added to the variable?
When i do:
$location->getName() on the ResponseLocation class it works. I get a string in return.
But when i do:
$location->getOpeningHours()->getMonday()
I get:
stdClass Object ( [string] => 08:00-18:30 ) 1
Sorry for the newbie question, but how do i get just the string in return?
I dont understand why it is not a string:
/**
* @return string
*/
public function getMonday()
{
return $this->Monday;
}
Hello there,
Has this class the possibility to request an multi-colli? And if this is possible, can someone give me an example how to use this?
Thanks in advance.
Best regards,
Mark.
PostNL announced that the old CIF platform users will be migrated to the new platform.
Endpoint will change and username/password combo's will be replaced by an API key.
How does this effect this lib?
Our account manager at PostNL gave us a Globalpack key that starts with CV, but in dividebv/postnl/src/Postnl.php on line 181 there is no support for this type.
By adding support for this type myself I can see that their API definitely accepts the type (whereas a made up type of CQ is not allowed), so it's unlikely to be a typo by our account manager.
Hi, how can the labeltype be set (normal package or brievenbuspakje etc)?
Thanks in advance.
In order to be able to generate a 4945 label, i had to remove GB from the EPS product list.
Could you remove GB from the list, since it's not EU anymore and the 3S codes won't work.
protected $countryCodeMapping = [
// Dutch domestic product.
'NL' => '3S',
// EPS products.
'AT' => '3S',
'BE' => '3S',
'BG' => '3S',
'CZ' => '3S',
'CY' => '3S',
'DK' => '3S',
'EE' => '3S',
'FI' => '3S',
'FR' => '3S',
'DE' => '3S',
// 'GB' => '3S',
'GR' => '3S',
'HU' => '3S',
'IE' => '3S',
'IT' => '3S',
'LV' => '3S',
'LT' => '3S',
'LU' => '3S',
'PL' => '3S',
'PT' => '3S',
'RO' => '3S',
'SK' => '3S',
'SI' => '3S',
'ES' => '3S',
'SE' => '3S',
// Everything else is GlobalPack.
];
How can i get the labels. This is working:
https://github.com/DivideBV/Postnl/wiki/Multi-collo-shipment
But what do need to do to get the labels? You cannot get it from GenerateLabelResponse.
I can get the labels deeper: $result->getResponseShipments()->getResponseShipment() but i want to have a MergedLabel.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.