Comments (30)
I just installed Automad on OpenBSD with httpd and I'm having the same issue. As @marcantondahmen said, the PATH_INFO variable is defined but empty. The problem is that OpenBSD's httpd seems to always defines the variable and sets it to an empty string if no path is appended after the script name. Perhaps we could check if the variable is not empty instead of checking if the variable is set?
diff --git a/automad/src/server/Core/Request.php b/automad/src/server/Core/Request.php
index 0a6ab8af..6c969a10 100644
--- a/automad/src/server/Core/Request.php
+++ b/automad/src/server/Core/Request.php
@@ -84,7 +84,7 @@ class Request {
} else {
// The requested page gets passed 'index.php/page/path'.
// That can be the case if rewriting is disabled and AM_BASE_INDEX ends with '/index.php'.
- if (isset($_SERVER['PATH_INFO'])) {
+ if (!empty($_SERVER['PATH_INFO'])) {
$request = $_SERVER['PATH_INFO'];
Debug::log('Getting request from PATH_INFO');
} elseif (isset($_SERVER['ORIG_PATH_INFO'])) {
With this change Automad seems to be working as intended on OpenBSD with httpd.
from automad.
I have the same issue on debian 11 with apache2.4 I took you block at line 88 and created a test file:
Getting request from REQUEST_URI
is the TLDR. Request URI and Query parameter are there. Presumably a config issue.I'm running php fpm 7.4 and other sites work fine (drupal, werkzeug).
It was a missing directive AllowOverride.
EDIT: I also took it out from behind varnish. I run haproxy with varnish in front of apache2.4 but this seems to cause issues.
I've switched to caching in haproxy and that seems ok.
from automad.
The requested page and the server variable it was generated from are already on top of the debug log. You just have to filter for
request
.
Sorry I'm not sure what you mean. What exactly do you need from the console? Here's what I get when filtering for request
:
And it also should be enough to just set
AM_BASE_INDEX
to""
in order to make images work. This has to be done on all servers except Apache and Nginx.
Yes! This seems to fix the image issue that I reported in #97. Great!
I'm just now noticing a weird behavior that seems related to this issue: when in example.com/dashboard/login
, after entering the credentials, the page is reloaded and I'm prompted for my login credentials again. This happens with and without setting AM_BASE_INDEX
to ""
. However it seems that it does log in as clicking on the X
on the top right corner takes me to the dashboard on which I'm logged in. Do you think this is also related to the PATH_INFO
issue? By the way this happens when using Automad with the diff I sent of course, otherwise I wouldn't be able to use it at all.
EDIT: The above issue was due to a mistake of mine. It's working now. Apologies for the noise.
from automad.
Hi there, it looks like your PHP configuration is missing a few items that are responsible for making URL rewriting work. Or are they maybe part of the includes? However, there is an example for a working nginx.conf
in the getting started guide of the docs.
from automad.
Hi there, it looks like your PHP configuration is missing a few items that are responsible for making URL rewriting work. Or are they maybe part of the includes? However, there is an example for a working
nginx.conf
in the getting started guide of the docs.
I know what you mean. But those are part of the config file included from the snippets
folder. That's why they are not included in the example config I gave.
from automad.
This is the included snippets/fastcgi-php.conf
# regex to split $uri to $fastcgi_script_name and $fastcgi_path
fastcgi_split_path_info ^(.+?\.php)(/.*)$;
# Check that the PHP script exists before passing it
try_files $fastcgi_script_name =404;
# Bypass the fact that try_files resets $fastcgi_path_info
# see: http://trac.nginx.org/nginx/ticket/321
set $path_info $fastcgi_path_info;
fastcgi_param PATH_INFO $path_info;
fastcgi_index index.php;
include fastcgi.conf;
Which includes:
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param QUERY_STRING $query_string;
fastcgi_param REQUEST_METHOD $request_method;
fastcgi_param CONTENT_TYPE $content_type;
fastcgi_param CONTENT_LENGTH $content_length;
fastcgi_param SCRIPT_NAME $fastcgi_script_name;
fastcgi_param REQUEST_URI $request_uri;
fastcgi_param DOCUMENT_URI $document_uri;
fastcgi_param DOCUMENT_ROOT $document_root;
fastcgi_param SERVER_PROTOCOL $server_protocol;
fastcgi_param REQUEST_SCHEME $scheme;
fastcgi_param HTTPS $https if_not_empty;
fastcgi_param GATEWAY_INTERFACE CGI/1.1;
fastcgi_param SERVER_SOFTWARE nginx/$nginx_version;
fastcgi_param REMOTE_ADDR $remote_addr;
fastcgi_param REMOTE_PORT $remote_port;
fastcgi_param SERVER_ADDR $server_addr;
fastcgi_param SERVER_PORT $server_port;
fastcgi_param SERVER_NAME $server_name;
# PHP only, required if PHP was built with --enable-force-cgi-redirect
fastcgi_param REDIRECT_STATUS 200;
As you can see fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
is part of the config. And just about everything else.
from automad.
Fresh installation of Nginx, PHP8.1-FPM on Ubuntu 21.04 the issue reported by @iSLC is very much a problem.
First time I've looked at Automad and it's borked out of the box.
from automad.
It is difficult to help without any context. What did you try so far? Did you enable debugging and checked whether the required environment variables are populated in order to verify that there is no issue with the included Nginx configuration?
In case you are not able to set up Nginx yourself, you can alternatively also use the official Docker image. That one is also running Nginx with PHP-fpm. It also includes a working nginx.conf
.
from automad.
I applied some context already; this is with a fresh installation of Nginx and PHP8.1-FPM, following the instructions as specifically documented here.
What are the other environment variables you're suggesting should be set and why is this not documented?
A working nginx.conf file should be regarded as the one out of the box on a fresh install.
Given that I have only got as far as attempting a fresh install, I had not looked to turn on debugging. I've turned on PHP error reporting for all types of errors and nothing is thrown.
site-nginx-config.conf
server {
listen 80;
listen [::]:80;
server_name domain.com;
root /srv/www/domain.com/www;
index index.php index.html index.htm;
access_log /srv/www/domain.com/_logs/access.log;
error_log /srv/www/domain.com/_logs/error.log;
client_max_body_size 200M;
location / {
try_files $uri $uri/ /index.php$is_args$args;
}
location ~ \.php$ {
include snippets/fastcgi-php.conf;
fastcgi_pass unix:/var/run/php/php8.1-fpm-domain.com.sock;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
}
}
from automad.
I just try to help you. A fresh installation of Nginx is not a very helpful context — there are many sites working very well with Nginx. The PHP version and error reporting is irrelevant here.
The config you posted is similar but not the one from the documentation. Yours uses sockets and you don't provide the config for that. We should focus on finding the little difference that breaks the rewriting.
Since you decided to go for Nginx instead of Apache, I have assumed that you know what environment is essential to make URL rewriting work. And I think it is not in the scope of a CMS to document Nginx. It has already a pretty good documentation.
After you have enabled debugging you will notice that it tells you what environment variable is used by your server and how. There are several options. That would maybe even resolve the issue already.
And again the Docker image uses out of the box Nginx as well.
You should not forget that there are many people out there working unpaid on open-source projects like this one and contribute most of there spare time in order to provide useful and working products. Asking in a kind way for help without only complaining and doing the homework of providing the required context for an issue is not too much to expect.
from automad.
July 2022 and it looks like I'm not alone in discovering that the "vanilla manual installation" on Debian 10 & 11 is still broken.
I've dug through the comments here, investigated the content of the docker image and there's minimal differences between the Alpine Linux image and the Debian config files. The Debian fastcgi config files have an extra parameter but nothing that would imply 'b0rked'.
I manually enabled debug mode in the config/config.php (setting AM_DEBUG_ENABLED to true) but nothing got spat out in the nginx error logs. (the displayed url and access log confirmed that content was attempting to be loaded from /dashboard/
Tried converting the file-socket to a TCP socket - again no change.
Where are the debug logs sent to?
from automad.
The debug log is send to the browser console.
It is very difficult to address such an issue without being able to reproduce it. But I guess it has to do with one of the environment variables being set to an empty string. It would be great if you could quickly test to comment out the different checks for those $_SERVER
variables one by one from top to bottom in the following location and then check if it works:
automad/automad/src/Core/Request.php
Line 88 in 776a2d1
That would really help to understand what variable has an incorrect value on Debian systems.
It could be that PATH_INFO
or ORIG_PATH_INFO
are here problematic.
from automad.
I have the same issue on debian 11 with apache2.4 I took you block at line 88 and created a test file:
Getting request from REQUEST_URI
is the TLDR. Request URI and Query parameter are there. Presumably a config issue.
I'm running php fpm 7.4 and other sites work fine (drupal, werkzeug).
from automad.
Hey, let me know if I am missing anything, but I am experiencing the same issue on php8.0, nginx, and debian 10
docs.kleionode.net
server {
root /var/www/docs.kleionode.net;
index index.php index.html index.htm;
server_name docs.kleionode.net;
client_max_body_size 100M;
location / {
try_files $uri /index.php?$query_string;
}
location ~ \.php$ {
include snippets/fastcgi-php.conf;
fastcgi_pass unix:/var/run/php/php8.0-fpm.sock;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
listen 443 ssl; # managed by Certbot
ssl_certificate /etc/letsencrypt/live/coop.myco.systems/fullchain.pem; # managed by Certbot
ssl_certificate_key /etc/letsencrypt/live/coop.myco.systems/privkey.pem; # managed by Certbot
include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
}
server {
if ($host = docs.kleionode.net) {
return 301 https://$host$request_uri;
} # managed by Certbot
server_name docs.kleionode.net;
listen 80;
return 404; # managed by Certbot
}
After enabling debugging in automad config I got, not sure if this is what you were referring to @marcantondahmen
Object { "Debug::consoleLog(): Server": {…} }
"Debug::consoleLog(): Server": Object { USER: "www-data", HOME: "/var/www", HTTP_SEC_GPC: "1", … }
CONTENT_LENGTH: ""
CONTENT_TYPE: ""
DOCUMENT_ROOT: "/var/www/docs.kleionode.net"
DOCUMENT_URI: "/index.php"
FCGI_ROLE: "RESPONDER"
GATEWAY_INTERFACE: "CGI/1.1"
HOME: "/var/www"
HTTPS: "on"
HTTP_ACCEPT: "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8"
HTTP_ACCEPT_ENCODING: "gzip, deflate, br"
HTTP_ACCEPT_LANGUAGE: "en-US,en;q=0.5"
HTTP_CONNECTION: "keep-alive"
HTTP_COOKIE: "Automad-64f42de4380af346d51b1f5ce5d1fe0a=t5o6ovplosq23suacg8q9reg6f"
HTTP_DNT: "1"
HTTP_HOST: "docs.kleionode.net"
HTTP_REFERER: "https://docs.kleionode.net/"
HTTP_SEC_FETCH_DEST: "document"
HTTP_SEC_FETCH_MODE: "navigate"
HTTP_SEC_FETCH_SITE: "same-origin"
HTTP_SEC_FETCH_USER: "?1"
HTTP_SEC_GPC: "1"
HTTP_UPGRADE_INSECURE_REQUESTS: "1"
HTTP_USER_AGENT: "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/111.0"
PATH_INFO: ""
PHP_SELF: ""
QUERY_STRING: ""
REDIRECT_STATUS: "200"
REMOTE_ADDR: "45.134.140.155"
REMOTE_PORT: "50456"
REQUEST_METHOD: "GET"
REQUEST_SCHEME: "https"
REQUEST_TIME: 1679609783
REQUEST_TIME_FLOAT: 1679609783.618575
REQUEST_URI: "/dashboard"
SCRIPT_FILENAME: "/var/www/docs.kleionode.net/index.php"
SCRIPT_NAME: "/index.php"
SERVER_ADDR: "147.135.115.92"
SERVER_NAME: "docs.kleionode.net"
SERVER_PORT: "443"
SERVER_PROTOCOL: "HTTP/1.1"
SERVER_SOFTWARE: "nginx/1.14.2"
USER: "www-data"
<prototype>: Object { … }
<prototype>: Object { … }
Thanks, if I can get this working then it will be my first nginx flat-file cms I've hosted, so I am fairly unfamiliar with cms platforms outside of wordpress.
from automad.
Hi, what route did you hit that produced that log?
The PATH_INFO
should reflect the actually requested route. So you have to make sure that the included fast cgi parameters include the correct path info.
In debug mode, you can check the resolved requested page at the very top.
Could you post here a route you try to access with the related log?
Thx
from automad.
Hey,
I think this is what you're requesting but I am not certain,
Object { "Request::page(): REQUEST_URI": "/dashboard" }
"Request::page(): REQUEST_URI": "/dashboard"
<prototype>: Object { … }
dashboard:162:9
Object { "Request::page(): REQUEST_URI": "/dashboard" }
"Request::page(): REQUEST_URI": "/dashboard"
<prototype>: Object { … }
dashboard:162:9
Object { "Request::page()": "Getting request from PATH_INFO" }
dashboard:161:9
I am backing up the nginx config and switching to docker for the time being to see if that will work. Though it would be nice to see this get resolved so let me know if there is more I can provide so that I can spin up another instance on a different machine.
Also, let me know if I am looking in the right place here:
from automad.
Yes, that is the correct log. As you can see here, PATH_INFO
exists but is empty. That's where the problem is.
In your included fcgi parameters, make sure that PATH_INFO
should either be not defined or correct. In your case it defined but wrong. Therefore the requested page falls back to the home page.
The official Docker image also uses Nginx. But it uses Alpine as OS. There, PATH_INFO
is set correctly out of the box. Maybe that helps you somehow.
from automad.
I had the same problem on Ubuntu 20.04.6 / focal / with php7.4 and nginx. this is the entry in the virtual host conf that made it work - at least getting past unworking signin link:
location ~ \.php$ {
# include snippets/fastcgi-php.conf;
fastcgi_pass unix:/run/php/php7.4-fpm.sock;
# fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
While the fastcgi_pass difference makes sense, this is what is in the fastcgi-php.conf (that is disabled):
# regex to split $uri to $fastcgi_script_name and $fastcgi_path
fastcgi_split_path_info ^(.+?\.php)(/.*)$;
# Check that the PHP script exists before passing it
try_files $fastcgi_script_name =404;
# Bypass the fact that try_files resets $fastcgi_path_info
# see: http://trac.nginx.org/nginx/ticket/321
set $path_info $fastcgi_path_info;
fastcgi_param PATH_INFO $path_info;
fastcgi_index index.php;
include fastcgi.conf;
and factcgi.conf (which is from above disabled) has this:
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param QUERY_STRING $query_string;
fastcgi_param REQUEST_METHOD $request_method;
fastcgi_param CONTENT_TYPE $content_type;
fastcgi_param CONTENT_LENGTH $content_length;
fastcgi_param SCRIPT_NAME $fastcgi_script_name;
fastcgi_param REQUEST_URI $request_uri;
fastcgi_param DOCUMENT_URI $document_uri;
fastcgi_param DOCUMENT_ROOT $document_root;
fastcgi_param SERVER_PROTOCOL $server_protocol;
fastcgi_param REQUEST_SCHEME $scheme;
fastcgi_param HTTPS $https if_not_empty;
fastcgi_param GATEWAY_INTERFACE CGI/1.1;
fastcgi_param SERVER_SOFTWARE nginx/$nginx_version;
fastcgi_param REMOTE_ADDR $remote_addr;
fastcgi_param REMOTE_PORT $remote_port;
fastcgi_param SERVER_ADDR $server_addr;
fastcgi_param SERVER_PORT $server_port;
fastcgi_param SERVER_NAME $server_name;
# PHP only, required if PHP was built with --enable-force-cgi-redirect
fastcgi_param REDIRECT_STATUS 200;
just to provide all the info what is being disabled by uncommenting that snippets line.
from automad.
Hi, yeah the problem with this fix is that it will break probably other environments. PATH_INFO
could also be empty when hitting the homepage. The test should then stop. With this fix it will continue to try the next option which could be undefined on other systems. It will probably work but is difficult to test without actually running it on all those systems.
However, I personally think the issue is lying in how OpenBSD defines PATH_INFO
. Why is it wrong?
I would be happy to actually fix it as you have proposed, but I will need a bit more time to investigate side effects and try other environments first.
In order to fix this independent from a possible implementation, I guess there are two options:
- Figuring out how to set
PATH_INFO
somehow in the OpenBSD config - Use the query string for pretty URLs (this is how the default
.htaccess
works)
I would recommend going with the second one whenever possible.
from automad.
Thanks for the quick reply @marcantondahmen.
- Figuring out how to set
PATH_INFO
somehow in the OpenBSD config
There is a way to set it in httpd.conf
(where the webserver is configured) as you can see in the man page I linked:
fastcgi param PATH_INFO <value>
However I'm not sure what to set it to.
- Use the query string for pretty URLs (this is how the default
.htaccess
works)
I believe I'm already doing this in httpd.conf
:
location not found "*" {
request rewrite "/index.php?$QUERY_STRING"
fastcgi socket "/run/php-fpm.sock"
}
What I understand is that this block essentially works like try_files
in nginx which will match all URIs that are not static files (therefore not found). Those will be rewritten as calls to /index.php
internally, and then processed through the fastcgi socket. Should this be used to set PATH_INFO
as shown above?
from automad.
What web server are you using? OpenBSD is just the OS. Apache? Then PATH_INFO
is not required. But the rewrite module must be enabled in the httpd.conf
as mentioned in the system requirements.
Your example config appends the existing query string to the index.php
. The included .htaccess
is doing something different by first using the path as query string and then merging the exiting search parameters.
from automad.
What web server are you using? OpenBSD is just the OS. Apache? Then
PATH_INFO
is not required. But the rewrite module must be enabled in thehttpd.conf
as mentioned in the system requirements.
The webserver is called httpd and in included with OpenBSD. It's configuration file is also called httpd.conf
. The link to the man page of OpenBSD's httpd I sent before, shows that PATH_INFO
is by default empty.
Your example config appends the existing query string to the
index.php
. The included.htaccess
is doing something different by first using the path as query string and then merging the exiting search parameters.
Understood. I will need to figure out how to translate this from the .htaccess
syntax into the one from OpenBSD's httpd.
from automad.
It should be enough to just enable rewriting in httpd.conf
. I am not sure but it should be just commented out in the config. Afterwards the included .htaccess
works out of the box.
Alternatively the official Docker image brings everything out of the box.
from automad.
It should be enough to just enable rewriting in
httpd.conf
. I am not sure but it should be just commented out in the config. Afterwards the included.htaccess
works out of the box.
Not on OpenBSD's httpd. It's a different webserver with a different config syntax. It also doesn't support .htaccess
. Rewrite rules have to be translated into OpenBSD's httpd configuration syntax as I have partially shown above in a previous comment.
Based on the solutions that we've proposed, I believe the only two viable solutions are the following:
- Apply the patch I posted, provided that it works with other webservers
- Set
PATH_INFO
in OpenBSDhttpd.conf
I'd be happy to go with Nr. 2, however I don't know what the PATH_INFO
should be set to. From what I understand it is dynamic as it is based on the URI, correct? Could you perhaps provide two URL examples and what PATH_INFO
should be set to for each please?
from automad.
Ah I understand. I was not aware that OpenBSD is cooking their own server with the same name that is used by Apache. They even name the config file the same.
The thing is that unfortunately there are so many options and combinations of OS, web servers and PHP versions to host a website, that it would be impossible for a maintainer to reliably support all of them. That's why Automad official only supports Apache and Nginx. And that's why just adding such a patch is difficult without putting quite some time into it testing effects on all other supported systems.
But I'm still optimistic we can make it work here. I guess OpenBSD supports Nginx as well, right? Personally I think that would be a good option too. However, with Nginx it is also important to get the config right. But you can take a look at the Docker image. It uses Nginx.
from automad.
The thing is that unfortunately there are so many options and combinations of OS, web servers and PHP versions to host a website, that it would be impossible for a maintainer to reliably support all of them. That's why Automad official only supports Apache and Nginx. And that's why just adding such a patch is difficult without putting quite some time into it testing effects on all other supported systems.
I understand, don't worry.
I'd be happy to go with Nr. 2, however I don't know what the
PATH_INFO
should be set to. From what I understand it is dynamic as it is based on the URI, correct? Could you perhaps provide two URL examples and whatPATH_INFO
should be set to for each please?
Could you please help me clarify this then?
from automad.
As far as I understand the docs PATH_INFO
should only be empty if there is no path in the URL. So it should just work and you shouldn't need to set it manually. I really can't say why these values are not propagated correctly to PHP. Please take a look at the debug console.
It is also worth mentioning that whenever you manage to make pretty URLs working with OpenBSD httpd, you will have to set AM_BASE_INDEX
to ""
in the config in order to remove index.php
from URLs.
from automad.
As far as I understand the docs
PATH_INFO
should only be empty if there is no path in the URL. So it should just work and you shouldn't need to set it manually. I really can't say why these values are not propagated correctly to PHP. Please take a look at the debug console.
I added a Debug::log($request, 'PATH_INFO');
(after reverting the patch I sent above) to check the value of PATH_INFO
and it is indeed empty. Here's the relevant output of the console:
It is also worth mentioning that whenever you manage to make pretty URLs working with OpenBSD httpd, you will have to set
AM_BASE_INDEX
to""
in the config in order to removeindex.php
from URLs.
Ah! Pretty URLs where already working (using the httpd.config
config I sent above), but this was the missing bit. This removed the index.php
from URLs in all links of the Dashboard as you said. I suppose I have to do this manually because the Pretty URLs are not detected automatically as shown in the console above?
from automad.
The requested page and the server variable it was generated from are already on top of the debug log. You just have to filter for request
. And it also should be enough to just set AM_BASE_INDEX
to ""
in order to make images work. This has to be done on all servers except Apache and Nginx.
from automad.
Great!
from automad.
Related Issues (20)
- Please, add a normal localization system and commenting system! HOT 1
- Feature Request: Option to open link in new tab HOT 2
- "No main theme defined" error on scratch v2 installation. HOT 1
- Docker Installation: Provide Folder Option for Persistent Data HOT 1
- Login broken: UserCollectionModel.php HOT 6
- When version 2 is going to release? HOT 4
- HTML anchor tags break the caption editor
- PageList sort by publication date HOT 2
- Localized date HOT 2
- File upload broken by huge images HOT 3
- Pagelist: display only future events HOT 2
- automad/dist/blocks/main.bundle.css is not exists in release HOT 3
- Migration assistant for version 2 HOT 2
- Cache Issue
- Internationalization Issue
- Small Cosmetic Issue
- Automad v2 template selection problem. HOT 5
- [QUESTION] placement or removal of copyright footer HOT 2
- Internal corruption of phar error HOT 9
- Error in loading the image HOT 4
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
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.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from automad.