harwey / cups4j Goto Github PK
View Code? Open in Web Editor NEWCups4j Java printing library for CUPS/IPP
Home Page: http://cups4j.org
License: GNU Lesser General Public License v3.0
Cups4j Java printing library for CUPS/IPP
Home Page: http://cups4j.org
License: GNU Lesser General Public License v3.0
Hi,
I'm working on a printer service and i'm trying to access a Canon printers' SECURE PRINT feature by setting these attributes
in the screenshot.
I get this error at CUPS admin (ver 2.2.12) when i try to print
"src = job.c, line = 1385, log = none of secured print password and username"
Please help.
I'm currently using this code block to print over my remote linux cups server:
org.cups4j.PrintJob printJob = new PrintJob.Builder(payload.toByteArray())
.jobName("cupboard-api.label")
.resolution("300x600dpi")
.userName("cupboard-api")
.pageFormat("w54h144.1")
.build();
It prints the document just fine without the resolution but if I look at the job in the CUPS server the jobname and username is not set and the page format is probably also ignored and it only works because that's also the default pageformat of the printer. However I don't know how to look at the exact details of a job like printer settings.
Now comes the bigger problem. If I try to set resolution like "300x600dpi" or "300x600 DPI" I always get a Numberformat Exception because the string is split by ',' and it excpets to get 3 parts. But setting it to "300,600,DPI" also doesn't work because it doesn't like "DPI" so I'm completely lost on how to correctly set the resolution now. This is the lines from the PPD:
*Resolution 300dpi/300 DPI: "<</HWResolution[300 300]>>setpagedevice"
*Resolution 300x600dpi/300x600 DPI: "<</HWResolution[300 600]>>setpagedevice"
Please have a look and fix especially the resolution stuff.
FYI: I'm using cups 2.3.3
Thanks a lot
To be able to print multiple documents the CUPS protocoll provides a 'create-job' operation. With 'send-document' you can send several documents. It would be nice if cups4j allows also support print jobs with more than 1 document.
I know this might seem out of scope for a linux/macos java library but in my app I support printing in all supported environments in which there is a java runtime including windows.
It would be great if the library also implements windows as an operating system by detecting the OS it’s running on and calling windows to replicate the same functionality. You would then be able to write code which is truly OS independent.
I specially need to send print jobs (jaserreports) to a user selected print queue.
Originally posted by @C4J in #12 (comment)
In some situations you'll get a 401-error you send several jobs as one job:
int id = cupsPrinter.createJob("test-job");
String user = "james",
PrintJob printJob = new PrintJob.Builder(content).jobName("test-job").userName(user).build();
cupsPrinter.print(printJob, id, true);
If the user who is logged in is not user "james" you probably get the following error message:
[main] WARN ch.ethz.vppserver.ippclient.IppResponse - <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<HTML>
<HEAD>
<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=utf-8">
<TITLE>401 Unauthorized</TITLE>
<LINK REL="STYLESHEET" TYPE="text/css" HREF="/cups.css">
</HEAD>
<BODY>
<H1>401 Unauthorized</H1>
<P>Enter your username and password or the root username and password to access this page. If you are using Kerberos authentication, make sure you have a valid Kerberos ticket.</P>
</BODY>
</HTML>
java.lang.NullPointerException
at org.cups4j.operations.ipp.IppSendDocumentOperation.request(IppSendDocumentOperation.java:148)
at org.cups4j.CupsPrinter.print(CupsPrinter.java:218)
Set the user to the user who is logged in:
...
String user = System.getProperty("user.name"),
PrintJob printJob = new PrintJob.Builder(content).jobName("test-job").userName(user).build();
...
I will fix it in the next few days...
There is a 0.7.9 version out with at least commons-io and http-client libs upgraded to avoid vulnerabilities.
I can't see this comming from this repo. Is 0.7.9 official?
See
cups4j/src/main/java/org/cups4j/CupsClient.java
Lines 137 to 150 in 1102886
default
property altogether and only make access to the default printer available via a separate method.If I understand correctly I need the followiing jars to get cup4j working. However my project also uses jasperreports which includes an older version of the httpclient jar file. Do you think it would be ok to use an older version with cups4j ?
cups4j-0.7.6.jar
commons-io-2.6.jar
httpclient-4.5.7.jar
simple-xml-2.7.1.jar
slf4j-api-1.7.26.jar
httpclient-4.3.6.jar
From time to time it happens that our CUPS server does not response within 10 seconds and we get a SocketTimeoutException. What we need is longer timeout or a configurable timeout.
CupsClient.getPrinters() normally returns a list of printers. But in our case this list was empty. By examing the log files on the CUPS server we saw, that a 403 (forbidden) was sent as answer. In this case I expect a corresponding exception on the client site - otherwise it is hard to find the cause of an empty list.
PrintJob printJob = new PrintJob.Builder(is)
.jobName("job-name")
.userName("user-name")
.copies(1)
.duplex(false) //双面
.portrait(true) //纵向
.color(false)
// .resolution("600,600,9")
.pageFormat("iso-a4")//iso-a4
.attributes(attributes)
.build();
cupsClient return no printers when I change no connection ip to 192.168.0.213 (the server address which has cups running).
After I change it to 127.0.0.1, it works great.
Also, I can get all printers when I open 192.168.0.213:631 from Chorme. What is the reason for it? Anyone can help>
When setting duplex to false the printer default options are used. This makes it impossible to unset duplex for printers that have duplex as a default option in lpoptions.
It would be nice if it were possible to unset duplex mode by setting duplex to false, in the same way that color and page format work. This would add sides:keyword:one-sided
to the list of options passed to cups.
Accoding to ngallagher/simplexml#18 there is an XXE vulnerability in simple-xml, which is used by cups4j.
So in my understanding, a malicious printer or MITM could exploit cup4j Users.
Can you clarify on the subject? Does cups4j mitigate against such attacks by controlling the underlying XML Parsers, as is for example implemented in https://github.com/carrotsearch/simplexml-safe?
PrintJob properties have a side effect.
The map passed on the PrintJob/PrintJob.Builder is used on CupsPrinter/IppSendDocumentOperation adding more properties. So the original map is changed changing the state of the client's map.
PrintJob.getProperties should return a new instance of the map for preserve original collection immutability avoiding the side effect
I suppose it's not a cups4j issue, but because I can't find a solution I decided to ask here.
//some code here
CupsPrinter cupsPrinter = cupsClient.getPrinter(printerURL);
System.err.println(cupsPrinter.getName());
//some code here
why cupsPrinter.getName() returns null? (cupsClient.getPrinters() returns available printer list)
I think it's related to cupsd.conf permissions. (OS ubuntu)
It works correctly in the local mac os system.
Can anyone help?
Regards,
Samvel
Can you help me with build errors please.
I have downloaded the source and I'm compiling with maven 3.5 and Java 1.8 - but I get the following errors
[INFO] ------------------------------------------------------------------------
[INFO] BUILD FAILURE
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 6.046 s
[INFO] Finished at: 2018-07-03T20:34:33+01:00
[INFO] Final Memory: 29M/307M
[INFO] ------------------------------------------------------------------------
[ERROR] Failed to execute goal org.apache.maven.plugins:maven-javadoc-plugin:3.0.0:jar (attach-javadocs) on project cups4j: MavenReportException: Error while generating Javadoc:
[ERROR] Exit code: 1 - /Users/dave/Downloads/cups4j-master/src/main/java/org/cups4j/CupsClient.java:107: warning: no description for @throws
[ERROR] * @throws Exception
[ERROR] ^
[ERROR] /Users/dave/Downloads/cups4j-master/src/main/java/org/cups4j/CupsClient.java:129: warning: no description for @throws
[ERROR] * @throws Exception
[ERROR] ^
[ERROR] /Users/dave/Downloads/cups4j-master/src/main/java/org/cups4j/CupsClient.java:155: warning: no description for @throws
Hello,
I have a rather old instance of CUPS (1.6.3) I'm working with and I'm not able to obtain the list of printers for my cups server.
CupsClient cupsClient = new CupsClient("cupsServer", 631);
cupsClient.getPrinters(); // returns empty List
When I try the URL through my browser, http://cupsServer:631/printers , the list of 6 printers is shown in a nice html page, as an anonymous user.
When creating the cupsClient, I tried adding the administrator credentials in a CupsAuthentication object with no success.
Is cups4j compatible with this version of cups ?
Do I need to pay attention to other parameters ?
What can I test to ensure I correctly initialized the cups client ?
This parameter number-up-layout was not found in ipp-list-of-attributes.xml ,
but in this website https://www.cups.org/doc/options.html, I can find it.
is there a substitute for this parameter?
Can this parameter(presentation-direction-number-up) achieve the same effect?
Looking forward to your reply!
If my code currently uses cups4j.runnable-0.6.4.jar can I simply replace it with the current cups4j-0.7.6.jar or do I need to include additional jars in the classpath for the latest version ?
I want to fetch cups all data job attributes i.e (job-id, job-name, job-state and job-completion-time)
Repo : https://github.com/harwey/cups4j There are two methods to fetch :
The cups-2.2.10-6 + deb10u1 I installed on the Raspberry Pi works fine on the Raspberry Pi, but with cups4j, I can only print .txt, not pdf, word. Is there a requirement for the version of cups?
Is there anyway to specify the paper tray to use when printing?
In IPP paper trays are specified as media-source keywords which are part of the media-col collection.
How does one specify the media-col collection as "media-source:keyword:tray-3" does not work?
Issue #12 suggested using the method mediaSource() on the job builder however, this method does not exist.
Hello, not sure if this is the right question for cups4j but I'll still give it a try.
I want to print .docx files using cups4j and I am using cups-pdf as the printer.
When I try to print .docx files, the output pdf is always empty using cups-pdf.
Is there a way, I can leverage cups4j's capabilities to print a .docx file?
I see from cups config files that three following application file formats are supported by cups ootb to print:
application/msword (this one prints only .doc files and not .docx)
application/pdf
application/postscript
So, .docx files are not supported by cups but I want to know if there are any optios/ways to do it using cups4j
Firstly - apologies for posting here when it's not specifically a cups4j issue but I'm hoping your experience with Java and printers may be able to shed some light on a problem which seems to defy all logic. I do use cups4j in my project if that's a consolation but this question does not use it's API.
I have the following java statement in my code.
PrinterJob.lookupPrintServices()
I written a very simple routine which queries the print queues on my MacOS machine and prints out their names. All good and well.
If I run using the last Java 8 202 from Oracle which has compatible licences from the command line it works.
Here comes the "crunch". For my main open source project i use a packaging tool called Install4j which provides a multi platform installer and also a java application launcher.
If I use version 7 of their software my application runs fine and the gui jframe which displays the print queue lists all the printers fine. If I use v8 of their software the application still launches fine but the above statement does not return any printers.
I have googled to death all problems with the above statement and macOS/linux problems and several people have reported the same problem but no conclusion has been drawn. All theories seem to either suggest moving to Java 9 (which I cannot do yet) or having issues with DocFlavour when querying the queues.
Those theories may be valid - but in my scenario I'm running the exact same java code with the same bundled version of java (I print out the version number at the start) and I'm getting 2 results.
I've exchanged a great number of emails with the developers of install4j and they are unable to explain or understand what might cause the different behaviour between v7 and v8 of their java launcher.
So - I was hoping if you might have any insight into the MacOS / Linux Cups printing service which might shed some light on ANYTHING which could explain the different behaviour I'm seeing.
I develop on MacOS - I've created virtual machines - one with another copy of MacOS Mojave which replicates the problem and another with Centos 7 which does not show the problem.
I cannot just blame Mojave or Java as I can make the program work successfully using v7 of their launcher - but neither me or the developers have any idea what could influence the results.
Sorry for such a long email but I've totally run out of ideas and I'm hoping you might be able to throw in some fresh ideas.
Hello, all I am using cups4j to connect to cups service and my project is running on gcloud.
Every few days I get a Connection refused error. I am very curious why it works some days and not others.
Any thoughts?
Is there a way to make cups4j try to reconnect a few times before erroring out?
Adding ipps support to cups4j API while connecting to printers secured via https protocol.
I'm currently using Cups Version 1.2.4 for a print-application.
A mandatory feature is to read the paper color (White Paper, Blue Paper, ..). This is done by reading the mediaSupported tag with an old print library called jipsi.
The print-application is now going to be updated with a new CUPS version 2.0.2 and the print library Cups4j.
If I try to read the paper color with the mediaSupported tag, the resultset outputs me papersizes like "iso_b4_250x352mm" instead of the paper colors I need to get.
The other data that Cups4j provides me for the printer also doesnt include the paper color.
Cups4j printer information new Cups
If I use the old Cups Version 1.2.4 and cups4j, the mediaSupported tag contains the paper colors, that I need to get.
Cups4j printer information old Cups
However the webinterface of the new Cups lists the paper colors that I need to access.
Pic of Cups Webinterface
Now my question:
Is there any way to get the paper color, maybe by asking the IPP protocol directly?
I'm searching for alternative to standard Java Printer Job, because I wasn't able to find a way to set and/or query special printer attributes.
Mainly, I'm interest in paper type, which is printer specific. For example normal plain paper, light paper, heavy paper, labels, envelope, matte paper.. It depends on printer driver.. And, it produces better output when printing on these special papers.
Is it possible with this library to get a list of possible extra options, and also get list/specification of possible values for each option?
Thank you very much for providing such a good class library, which is currently in version 0.7.6. I found that I could not get the status of the printer, so I came to check the source code and was surprised to find that a new version was recently released (0.7.7).
Unfortunately, it is found that this version is compiled based on jdk11, given that the server has been stable in jdk1.8.
So I would like to ask if it is possible to release a version of jdk1.8.
Not being that familiar with Maven I was wondering if someone could confirm the runtime dependencies required for version 0.7.8
The list I have generated is shown below.
commons-codec-1.9.jar
commons-io-2.6.jar
commons-lang-2.6.jar
commons-logging-1.2.jar
hamcrest-core-1.3.jar
httpclient-4.5.2.jar
httpcore-4.4.4.jar
jgoodies-common-1.6.0.jar
jgoodies-forms-1.7.1.jar
junit-4.13.1.jar
simple-xml-2.7.1.jar
slf4j-api-1.7.25.jar
slf4j-simple-1.7.25.jar
stax-1.2.0.jar
stax-api-1.0.1.jar
xpp3-1.1.3.3.jar
We should publish this to Maven Central.
Now, the only way to lookup any printer is by printer URL.
I think it could be a feature for lookup any printer by name.
RFC says:
- Each Printer object is identified with one or more URIs. The
Printer's "printer-uri-supported" attribute contains the URI(s).
However, you use URLs, not URIs. Since ipp://
is not a valid protocol for a java.net.URL
class, you simply replace ipp
with http
. This is already error-prone since some printers URIs have ipps://
protocol and you fail to process them.
To prove the issue, you can call getDefaultPrinter()
on a cups client with 127.0.0.1
as host and 631
as port. You will get the following error:
java.net.MalformedURLException: unknown protocol: ipps
at java.net.URL.<init>(URL.java:618)
at java.net.URL.<init>(URL.java:508)
at java.net.URL.<init>(URL.java:457)
at org.cups4j.operations.cups.CupsGetDefaultOperation.getDefaultPrinter(CupsGetDefaultOperation.java:62)
at org.cups4j.CupsClient.getDefaultPrinter(CupsClient.java:154)
If you use localhost
as the host, you won't get an error.
In addition to that, I see that to compare two URLs you call toString()
on them and compare the resulting strings which doesn't seem right. Maybe you are doing the comparison this way because equals
cannot be used on java.net.URL
since it has some issues (tries to resolve the hostname to an IP address).
Since URIs in IPP have the same meaning as java.net.URI
in Java (they both conform to RFC2396), I suggest that you switch to java.net.URI
. You won't have issues with ipp(s)
protocol and could also use equals()
to compare them because it is not broken as in java.net.URL
.
I am trying to use CUPS4J to help in printing the docs with a specified Tray and media type but somehow what ever I do/give params, it prints from the default Tray of the printer.
Below is the code I am using to test out the functionality, can you please help me pointing out what am I missing here.
Rest of the params are working fine and I get the desired result except the Tray.
Commented code are the different options I tried but none worked. Please help in resolving.
-----code ------
package com.test.printer;
import java.io.File;
import java.net.URL;
import java.nio.file.Files;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.cups4j.CupsClient;
import org.cups4j.CupsPrinter;
import org.cups4j.PrintJob;
import org.cups4j.PrintRequestResult;
public class CupsPrintTest {
static Logger LOG = LogManager.getLogger(App.class);
public enum MimeTypes {
TEXT, PDF;
}
private MimeTypes mimeType;
public static void main(String[] args) {
CupsPrintTest app = new CupsPrintTest();
app.printThruPenndotCups("PR3311");
}
@SuppressWarnings("unused")
private boolean printThruPenndotCups(String printerName) {
try {
String strCupsURI = "http://localhost:631/printers/"; /*Local CUPS Service running on Docker*/
URL cupsURI = new URL(strCupsURI);
// File file = new File("FILE-PATH\ABCD.pdf"); // PDF file path
byte[] byteArray = Files.readAllBytes(file.toPath());
int copies = 1;
CupsClient cupsClient;
cupsClient = new CupsClient(cupsURI.getHost(), cupsURI.getPort(), "user");
printerName = "PR3311";//@network printer
String strPrinterURL = strCupsURI + printerName;
URL printerURL = new URL(strPrinterURL);
CupsPrinter cupsPrinter = cupsClient.getPrinter(printerURL);
boolean isDuplex = true;
// String tray = "upper";
// String tray = "middle";
// String tray = "lower";
// String tray = "Tray 1";
// String tray = "Tray 2";
// String tray = "Tray2";
String tray = "na_legal_8.5x14in";
// String tray = "legal";
mimeType = MimeTypes.PDF;
if (mimeType == MimeTypes.TEXT) {
cupsPrinter.setMimeTypesSupported(Arrays.asList("text/plain"));
isDuplex = false;
cupsPrinter.setMediaDefault(tray);
} else {
cupsPrinter.setMimeTypesSupported(Arrays.asList("application/vnd.cups-ppd"));
cupsPrinter.setMediaDefault(tray);
cupsPrinter.setMediaSupported(Arrays.asList(tray));
isDuplex = true;
}
Map<String, String> attributes = new HashMap<>();
// attributes.put("compression", "none");
// attributes.put("job-attributes", "print-quality:enum:9#fit-to-page:boolean:false#sheet-collate:keyword:collated");
// attributes.put("job-attributes", "media:keyword:bottom#media-default:keyword:bottom#media-supported:keyword:bottom#media-ready:keyword:bottom");
// attributes.put("job-attributes", tray);
// attributes.put("job-attributes", "media:bottom");
attributes.put("job-attributes", "media-source:keyword:Tray-2");
PrintJob printJob = new PrintJob.Builder(byteArray)
.userName("loggedInUser")
.jobName("JobName")
.duplex(isDuplex)
.copies(copies)
// .pageFormat(tray)
.attributes(attributes)
.build();
PrintRequestResult printRequestResult = null;
printRequestResult = cupsPrinter.print(printJob);
if (printRequestResult != null)
System.out.println(" Done with printing with ID = "+ printRequestResult.getJobId());
else
System.out.println("Did NOT print");
return true;
} catch (Exception e) {
System.out.println("In exception block" + e);
}
return false;
}
}
-------code ends ----------
I am using 0.7.8 release along with CUPS v2.2.1. However when I try to get the state of a printer I get 'null' value. I have investigated and found that in class 'PrinterStateEnum' you've compared incoming state value (string, eg 'idle') with toString of enum getValue. If you see your enum declaration the values are in integer, however the incoming state value is string - something like 'idle' or so. Hence we get a 'null' assigned to printer state as if condition fails. For example see below code, so instead of using getValue, getStateName should solve this issue.
for (PrinterStateEnum printerState : PrinterStateEnum.values()) {
System.out.println(printerState.getValue().toString());
}
output: 3 4 5
for (PrinterStateEnum printerState : PrinterStateEnum.values()) {
System.out.println(printerState.getStateName().toString());
}
output: idle printing stopped
I am using cups 0.7.8 jar, and want to check the printer status by using the following method of the cups API
public PrinterStateEnum getState()
The code is as follows:
String cupsHost = rb.getString("cups.server.hostname");
String cupsPort = rb.getString("cups.server.port");
CupsClient client = new CupsClient(cupsHost, new Integer(cupsPort));
List printers = client.getPrinters();
logger.info("Found printers: " + printers.toString());
for (CupsPrinter printer : printers) {
logger.info("printer available: " + printer.getName());
PrinterStateEnum printerState = printer.getState();
}
However the getState() method is returning null
I checked the cups server end and it is possible to access the printer status over the browser. This is what is seen:
I wanted to know if this API [ public PrinterStateEnum getState() ] is fully functional and tested for the cups jar version 0.7.8, and if so, why it may be returning null in the code, even though other API methods like CupsPrinter::getName() and CupsPrinter::getURL() are working fine
Is there a way to add a new printer from java and save it in cups?
Hi Team,
I would like to add the network printer to cups server using http call ( printer_host_name, port).
I couldn't find the way to add the printer to cupserver from cups api documentation.
Please share the cup api which allows to add ipp network printer into cups and share the different approaches to connect the printer.
Currently, I have connecting the cup server with cups4j library through java.
Additional Links :
OpenPrinting/cups#514
OpenPrinting/cups#516
Thanks
Does this library support the classes or groups of printers?
If not, do you plan to add the support?
Hi
've been trying to use this library to list printers on a Windows Server
the code being:
CupsClient cupsClient = new CupsClient("t-print1.corp.domain", 631, "my.name");
for (CupsPrinter printer: cupsClient.getPrinters()) {
System.out.println(printer.getDescription());
}
and it ends up with
Exception in thread "main" java.io.IOException: HTTP error! Status code: HTTP/1.1 401 Unauthorized
at org.cups4j.operations.IppOperation.sendRequest(IppOperation.java:133)
at org.cups4j.operations.IppOperation.request(IppOperation.java:67)
at org.cups4j.operations.cups.CupsGetPrintersOperation.getPrinters(CupsGetPrintersOperation.java:56)
at org.cups4j.CupsClient.getPrinters(CupsClient.java:106)
at ee.mkv.demo.CupsDemoApplication.main(CupsDemoApplication.java:19)
with the following being in the response:
Hypertext Transfer Protocol
HTTP/1.1 401 Unauthorized\r\n
Content-Type: text/html\r\n
Server: Microsoft-IIS/10.0\r\n
WWW-Authenticate: Negotiate\r\n
WWW-Authenticate: NTLM\r\n
X-Powered-By: ASP.NET\r\n
Date: Fri, 28 Feb 2020 12:30:51 GMT\r\n
Content-Length: 1293\r\n
\r\n
My understanding is that there's no support of authentication whatsoever in the cups4j. Is there a way to add it or to use some other library alongside this one ?
I have a requirement to know the make and model of the cups printer.
I will follow up with a pull request as it looks like a simple addition to the CupsGetPrintersOperation and CupsPrinter classes.
Had the following issue.
Is it possible to get the extra informations which cups gave you via API for Printers.
It is called PrinterAttributes.
http://www.malinovski.de/15/sym.html/usr/share/doc/cups/help/api-cups.html#PRINTERS_AND_CLASSES
I would like the option to get the printer-state from cups.
printer-state" | "3" if the destination is idle, "4" if the destination is printing
| a job, and "5" if the destination is stopped.
This cups4j client only work with Cups server ? or this will work on direct IPP enable printer ?
Originally posted by @rohitdobariya in https://github.com/harwey/cups4j/issue_comments/710051963
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.