naspeh / mailur Goto Github PK
View Code? Open in Web Editor NEWLightweight webmail inspired by Gmail
Home Page: https://pusto.org/mailur/
License: GNU General Public License v3.0
Lightweight webmail inspired by Gmail
Home Page: https://pusto.org/mailur/
License: GNU General Public License v3.0
This is a quite an impressive project. I am still trying to get my head around just how you handle tag implementation in Dovecot, but it seems to be smooth and that is something that I have wanted to accomplish for quite some time now as I use Dovecot locally on my machine with mbsync to pull down from Gmail.
Your Python implementation of fetching messages from Gmail is very nice (and it sounds like its significantly faster than mbsync though I haven't compared it myself - just taking your word for it). However, it does not seem like you have grabbed the X-GM-LABELS
attribute and mapped that IMAP Keywords. This would be very nice because it would enable the Dovecot backed storage and the web-based Gmail to remain in sync while your web interface is still in transition and allow easier mobile interaction before that interface is fully implemented as well. Furthermore, it would allow for the use case of company email on GSuite where it is not possible to abandon it altogether, in which case you would really want the two versions of the inbox and labels to be identical.
I think this enhancement is feasible and would be an important improvement. I am curious to hear whether you see it as possible to implement and of interest to you. Regardless, nice work!
Message deleted. Created a separate issue for it here.
Hi there,
How mailur manage contacts? Is it backed on Gmail contacts or just internal emails?
What do you think about contacts management in mailur (backed on Google or anywhere)?
Hello ๐
I run a security community that finds and fixes vulnerabilities in OSS. A researcher (@JeffreyGaor) has found a potential issue, which I would be eager to share with you.
Could you add a SECURITY.md
file with an e-mail address for me to send further details to? GitHub recommends a security policy to ensure issues are responsibly disclosed, and it would help direct researchers in the future.
Looking forward to hearing from you ๐
(cc @huntr-helper)
I'm going to use Dovecot as main storage, no Postgres in this case, I don't want to duplicate the storage, and I want to keep Mailur as simple as possible, this why I'm working on totally new version.
Dovecot pros:
Dovecot cons:
Development is going in new branch.
Hello,
I was wondering if there was a way to make it portable so that it could be hosted on a shared hosting account with limited privileges.
Hi,
I'm setting up Mailur in a brand-new CentOS 8 installation. My goal is to test the webmail, connecting it to my existing mail server using IMAP/SMTP.
The steps I did were:
bin/install
bin/env
, removed the demo user and password and replaced with my own.bin/install
again.bin/deploy
mlr demo remote-setup-imap {username} {password} --imap=mail.example.com:993 --smtp=mail.example.com:465
.Output is:
[2021-09-15 23:20:45CEST][DEB][20384][admin][timing] mailur.local.connect: done for 0.02s
[2021-09-15 23:20:45CEST][DEB][20384][admin][timing] select(Local{'admin*root', 'mlr/Sys'}, 'mlr/Sys', True): done for 0.00s
[2021-09-15 23:20:45CEST][DEB][20384][admin][timing] select(Local{'admin*root', 'mlr/Sys'}, 'mlr/Sys', True): done for 0.00s
[2021-09-15 23:20:45CEST][DEB][20384][admin][timing] fetch(Local{'admin*root', 'mlr/Sys'}, 1:*, '(UID BODY[HEADER.FIELDS (Subject)])'): done for 0.00s
[2021-09-15 23:20:45CEST][DEB][20384][admin][timing] metadata_uids.get_map: done for 0.00s
[2021-09-15 23:20:45CEST][DEB][20384][admin][timing] fetch(Local{'admin*root', 'mlr/Sys'}, "1 uids", 'BODY.PEEK[1]'): done for 0.00s
[2021-09-15 23:20:45CEST][DEB][20384][admin][timing] data_settings.fetch: done for 0.00s
[2021-09-15 23:20:45CEST][DEB][20384][admin][timing] append(Local{'admin*root', 'mlr/Sys'}, 'mlr/Sys', 'settings', None, b'MIME-Version: 1.0...): done for 0.00s
Then, I run mlr demo remote --parse
:
[2021-09-15 23:21:40CEST][DEB][20459][admin][timing] mailur.local.connect: done for 0.02s
[2021-09-15 23:21:40CEST][DEB][20459][admin][timing] select(Local{'admin*root', 'mlr/Sys'}, 'mlr/Sys', True): done for 0.00s
[2021-09-15 23:21:40CEST][DEB][20459][admin][timing] fetch(Local{'admin*root', 'mlr/Sys'}, 1:*, '(UID BODY[HEADER.FIELDS (Subject)])'): done for 0.00s
[2021-09-15 23:21:40CEST][DEB][20459][admin][timing] metadata_uids.get_map: done for 0.00s
[2021-09-15 23:21:40CEST][DEB][20459][admin][timing] fetch(Local{'admin*root', 'mlr/Sys'}, "1 uids", 'BODY.PEEK[1]'): done for 0.00s
[2021-09-15 23:21:40CEST][DEB][20459][admin][timing] data_settings.fetch: done for 0.00s
[2021-09-15 23:21:40CEST][DEB][20459][admin][timing] select(Local{'admin*root', 'mlr/Sys'}, 'mlr/Sys', True): done for 0.00s
[2021-09-15 23:21:40CEST][DEB][20459][admin][timing] mailur.remote.connect: done for 0.00s
Traceback (most recent call last):
File "/opt/mailur/env/bin/mlr", line 11, in <module>
load_entry_point('mailur', 'console_scripts', 'mlr')()
File "/opt/mailur/mailur/cli.py", line 26, in main
process(args)
File "/opt/mailur/mailur/cli.py", line 109, in process
remote.fetch(**fetch_opts)
File "/opt/mailur/mailur/remote.py", line 332, in fetch
for params in get_folders():
File "/opt/mailur/mailur/remote.py", line 345, in get_folders
with client(None) as c:
File "/opt/mailur/mailur/remote.py", line 85, in client
ctx = imap.client(connect, writable=writable)
File "/opt/mailur/mailur/imap.py", line 215, in client
con = start()
File "/opt/mailur/mailur/imap.py", line 202, in start
con = connect()
File "/opt/mailur/mailur/__init__.py", line 98, in inner_fn
return func(*a, **kw)
File "/opt/mailur/mailur/remote.py", line 79, in connect
con = Remote()
File "/opt/mailur/mailur/remote.py", line 64, in __init__
super().__init__(account['imap_host'], account['imap_port'])
File "/usr/lib64/python3.6/imaplib.py", line 198, in __init__
self.open(host, port)
File "/opt/mailur/mailur/remote.py", line 72, in open
super().open(host, port=imaplib.IMAP4_SSL_PORT)
File "/usr/lib64/python3.6/imaplib.py", line 299, in open
self.sock = self._create_socket()
File "/opt/mailur/mailur/remote.py", line 68, in _create_socket
sock = socket.create_connection((self.host, self.port))
File "/opt/mailur/env/lib64/python3.6/site-packages/gevent/socket.py", line 88, in create_connection
addrs = list(getaddrinfo(host, port, 0, SOCK_STREAM))
File "/opt/mailur/env/lib64/python3.6/site-packages/gevent/_socketcommon.py", line 247, in getaddrinfo
addrlist = get_hub().resolver.getaddrinfo(host, port, family, type, proto, flags)
File "/opt/mailur/env/lib64/python3.6/site-packages/gevent/resolver/thread.py", line 63, in getaddrinfo
return self.pool.apply(_socket.getaddrinfo, args, kwargs)
File "/opt/mailur/env/lib64/python3.6/site-packages/gevent/pool.py", line 161, in apply
return self.spawn(func, *args, **kwds).get()
File "src/gevent/event.py", line 329, in gevent._gevent_cevent.AsyncResult.get
File "src/gevent/event.py", line 359, in gevent._gevent_cevent.AsyncResult.get
File "src/gevent/event.py", line 347, in gevent._gevent_cevent.AsyncResult.get
File "src/gevent/event.py", line 327, in gevent._gevent_cevent.AsyncResult._raise_exception
File "/opt/mailur/env/lib64/python3.6/site-packages/gevent/_compat.py", line 65, in reraise
raise value.with_traceback(tb)
File "/opt/mailur/env/lib64/python3.6/site-packages/gevent/threadpool.py", line 167, in __run_task
thread_result.set(func(*args, **kwargs))
socket.gaierror: [Errno -2] Name or service not known
What am I missing?
I was just able to fetch all my messages off of FastMail in 12min (~50k conversations, ~80k messages) using the method here: https://wiki.dovecot.org/Migration/Dsync, replicated directly onto my Dovecot server. There are modifications for Gmail as well here: https://wiki.dovecot.org/Migration/Gmail. It seems they are already aware of Gmail labels as well. This might be worth considering using instead of the mlr remote ...
method if only to reduce the amount of code that has to be independently maintained. If not all the features are present in how doveadm
handles Gmail, it may be worth submitting a patch to add the parts needed.
Running run-lxc
successfully generates a container, but since /usr/sbin
is not on the default path within that container the bin/install
script silently fails when adding the vmail
group. This leads to many packages not being installed (which I then learned was why the whole rest of the install processes was screwing up on me). All that has to be done is to add /usr/sbin
to the path and this should be possible to automate in the run-lxc
script.
I ran bin/install-on-ubuntu but when I get to the bin/deploy it runs into problems with nginix paths. Thank you.
Hello again. I'm sorry to keep bringing issues here, let's see if you can help.
I'm able to receive emails, but not able to send. I'm using Mailur only as my webmail, and am using remote-setup-imap
.
The command used to set it up was: mlr lucas remote-setup-imap [email protected] password --imap=mx.example.com --smtp=mx.example.com --smtp-port=465 --imap-port=993
.
To be able to send emails from another mail client, I need the following:
IMAP port 993
SMTP port 465
IMAP and SMTP security: SSL or TLS
Username: the whole email address
When sending an email from Mailur, I only get a sending
message and later on a 504
error from Nginx. I can see the following logs on my mail server:
Sep 20 22:13:44 imap-login: Info: Login: user=<[email protected]>, method=PLAIN, rip=::1, lip=::1, mpid=8993, TLS, session=<mmY8iWrMGswAAAAAAAAAAAAAAAAAAAAB>
Sep 20 22:13:44 box postfix/submission/smtpd[8379]: SSL_accept error from webmail.example.com[2a03:______:7001]: lost connection
Sep 20 22:13:44 box postfix/submission/smtpd[8379]: lost connection after CONNECT from webmail.example.com[2a03:______:7001]
Sep 20 22:13:44 box postfix/submission/smtpd[8379]: disconnect from webmail.example.com[2a03:______:7001] commands=0/0
Sep 20 22:13:44 imap([email protected]): Info: Logged out in=1678 out=9167
Sep 20 22:13:49 box postfix/submission/smtpd[8379]: connect from webmail.example.com[2a03:______:7001]
webmail.example.com
is where Mailur is installed and running.mx.example.com
is my mail server.Maybe Mailur is using an old depreciated version of TLS, or ciphers? Any suggestions?
Thanks in advance!
@naspeh How is this your first GitHub issue or pull request? Is your software perfect? :-)
I learned of this project on the Pycoders Weekly mailing list. It looks promising! :-) I was at the Platform Cooperatives conference last weekend, where I saw growing interest amongst non-techies in alternatives to proprietary platforms such as Gmail. I think your project could gain traction if you work hard and market it right.
I'm writing to ask whether you've considered setting up a way for your users to voluntarily pay you for Mailur. Some options for this include:
https://flattr.com/
https://salt.bountysource.com/
https://gratipay.com/ (disclosure: I'm from Gratipay)
https://www.patreon.com/
... and of course PayPal. :-)
Accepting voluntary payments from users is one way to fund your open-source work, which is important so that you avoid burnout and are able to dedicate sufficient resources for your project to succeed.
One way or another, best of luck! :-)
Hi,
After a while with Mailur running, I stop getting new messages. Looking at the mailur-lucas.service
service, I can see the following log message:
Sep 21 01:54:35 webmail sh[14468]: During handling of the above exception, another exception occurred:
Sep 21 01:54:35 webmail sh[14468]: Traceback (most recent call last):
Sep 21 01:54:35 webmail sh[14468]: File "/opt/mailur/mailur/imap.py", line 104, in inner
Sep 21 01:54:35 webmail sh[14468]: return func(con, *a, **kw)
Sep 21 01:54:35 webmail sh[14468]: File "/opt/mailur/mailur/imap.py", line 87, in inner
Sep 21 01:54:35 webmail sh[14468]: return fn_time(func)(con, *a, **kw)
Sep 21 01:54:35 webmail sh[14468]: File "/opt/mailur/mailur/__init__.py", line 99, in inner_fn
Sep 21 01:54:35 webmail sh[14468]: return func(*a, **kw)
Sep 21 01:54:35 webmail sh[14468]: File "/opt/mailur/mailur/imap.py", line 415, in select
Sep 21 01:54:35 webmail sh[14468]: res = check(con.select(box, readonly))
Sep 21 01:54:35 webmail sh[14468]: File "/usr/lib64/python3.6/imaplib.py", line 745, in select
Sep 21 01:54:35 webmail sh[14468]: typ, dat = self._simple_command(name, mailbox)
Sep 21 01:54:35 webmail sh[14468]: File "/usr/lib64/python3.6/imaplib.py", line 1196, in _simple_command
Sep 21 01:54:35 webmail sh[14468]: return self._command_complete(name, self._command(name, *args))
Sep 21 01:54:35 webmail sh[14468]: File "/usr/lib64/python3.6/imaplib.py", line 981, in _command
Sep 21 01:54:35 webmail sh[14468]: raise self.abort('socket error: %s' % val)
Sep 21 01:54:35 webmail sh[14468]: imaplib.IMAP4.abort: socket error: [Errno 32] Broken pipe
Sep 21 01:54:35 webmail sh[14468]: During handling of the above exception, another exception occurred:
Sep 21 01:54:35 webmail sh[14468]: Traceback (most recent call last):
Sep 21 01:54:35 webmail sh[14468]: File "/opt/mailur/mailur/cli.py", line 133, in inner
Sep 21 01:54:35 webmail sh[14468]: fn(*a, **kw)
Sep 21 01:54:35 webmail sh[14468]: File "/opt/mailur/mailur/cli.py", line 144, in idle_remote
Sep 21 01:54:35 webmail sh[14468]: with remote.client(**params) as c:
Sep 21 01:54:35 webmail sh[14468]: File "/opt/mailur/mailur/remote.py", line 85, in client
Sep 21 01:54:35 webmail sh[14468]: ctx = imap.client(connect, writable=writable)
Sep 21 01:54:35 webmail sh[14468]: File "/opt/mailur/mailur/imap.py", line 215, in client
Sep 21 01:54:35 webmail sh[14468]: con = start()
Sep 21 01:54:35 webmail sh[14468]: File "/opt/mailur/mailur/imap.py", line 202, in start
Sep 21 01:54:35 webmail sh[14468]: con = connect()
Sep 21 01:54:35 webmail sh[14468]: File "/opt/mailur/mailur/__init__.py", line 99, in inner_fn
Sep 21 01:54:35 webmail sh[14468]: return func(*a, **kw)
Sep 21 01:54:35 webmail sh[14468]: File "/opt/mailur/mailur/remote.py", line 79, in connect
Sep 21 01:54:35 webmail sh[14468]: con = Remote()
Sep 21 01:54:35 webmail sh[14468]: File "/opt/mailur/mailur/remote.py", line 60, in __init__
Sep 21 01:54:35 webmail sh[14468]: account = data_account.get()
Sep 21 01:54:35 webmail sh[14468]: File "/opt/mailur/mailur/local.py", line 147, in get
Sep 21 01:54:35 webmail sh[14468]: value = metavalue.key(name)
Sep 21 01:54:35 webmail sh[14468]: File "/opt/mailur/mailur/local.py", line 125, in key
Sep 21 01:54:35 webmail sh[14468]: return get().get(name, default)
Sep 21 01:54:35 webmail sh[14468]: File "/opt/mailur/mailur/imap.py", line 61, in inner_fn
Sep 21 01:54:35 webmail sh[14468]: with use_or_create(kw):
Sep 21 01:54:35 webmail sh[14468]: File "/usr/lib64/python3.6/contextlib.py", line 81, in __enter__
Sep 21 01:54:35 webmail sh[14468]: return next(self.gen)
Sep 21 01:54:35 webmail sh[14468]: File "/opt/mailur/mailur/imap.py", line 38, in use_or_create
Sep 21 01:54:35 webmail sh[14468]: con.select(box, readonly)
Sep 21 01:54:35 webmail sh[14468]: File "/opt/mailur/mailur/imap.py", line 106, in inner
Sep 21 01:54:35 webmail sh[14468]: raise Error(e)
Sep 21 01:54:35 webmail sh[14468]: mailur.imap.Error: socket error: [Errno 32] Broken pipe
Sep 21 01:54:45 webmail sh[14468]: [2021-09-21 01:54:45UTC][DEB][14468][lucas][timing] select(Local{'lucas*root', 'mlr/Sys'}, 'mlr/Sys', True): done for 0.00s
Sep 21 01:54:45 webmail sh[14468]: [2021-09-21 01:54:45UTC][DEB][14468][lucas][timing] mailur.remote.connect: done for 0.00s
Sep 21 01:54:45 webmail sh[14468]: [2021-09-21 01:54:45UTC][ERR][14468][lucas][inner] socket error: [Errno 32] Broken pipe
Sep 21 01:54:45 webmail sh[14468]: Traceback (most recent call last):
Sep 21 01:54:45 webmail sh[14468]: File "/usr/lib64/python3.6/imaplib.py", line 979, in _command
Sep 21 01:54:45 webmail sh[14468]: self.send(data + CRLF)
Sep 21 01:54:45 webmail sh[14468]: File "/usr/lib64/python3.6/imaplib.py", line 318, in send
Sep 21 01:54:45 webmail sh[14468]: self.sock.sendall(data)
Sep 21 01:54:45 webmail sh[14468]: File "/opt/mailur/env/lib64/python3.6/site-packages/gevent/_socketcommon.py", line 699, in sendall
Sep 21 01:54:45 webmail sh[14468]: return _sendall(self, data_memory, flags)
Sep 21 01:54:45 webmail sh[14468]: File "/opt/mailur/env/lib64/python3.6/site-packages/gevent/_socketcommon.py", line 409, in _sendall
Sep 21 01:54:45 webmail sh[14468]: timeleft = __send_chunk(socket, chunk, flags, timeleft, end)
Sep 21 01:54:45 webmail sh[14468]: File "/opt/mailur/env/lib64/python3.6/site-packages/gevent/_socketcommon.py", line 338, in __send_chunk
Sep 21 01:54:45 webmail sh[14468]: data_sent += socket.send(chunk, flags)
Sep 21 01:54:45 webmail sh[14468]: File "/opt/mailur/env/lib64/python3.6/site-packages/gevent/_socketcommon.py", line 722, in send
Sep 21 01:54:45 webmail sh[14468]: return self._sock.send(data, flags)
Sep 21 01:54:45 webmail sh[14468]: BrokenPipeError: [Errno 32] Broken pipe
Sep 21 01:54:45 webmail sh[14468]: During handling of the above exception, another exception occurred:
Sep 21 01:54:45 webmail sh[14468]: Traceback (most recent call last):
Sep 21 01:54:45 webmail sh[14468]: File "/opt/mailur/mailur/imap.py", line 104, in inner
Sep 21 01:54:45 webmail sh[14468]: return func(con, *a, **kw)
Sep 21 01:54:45 webmail sh[14468]: File "/opt/mailur/mailur/imap.py", line 87, in inner
Sep 21 01:54:45 webmail sh[14468]: return fn_time(func)(con, *a, **kw)
Sep 21 01:54:45 webmail sh[14468]: File "/opt/mailur/mailur/__init__.py", line 99, in inner_fn
Sep 21 01:54:45 webmail sh[14468]: return func(*a, **kw)
Sep 21 01:54:45 webmail sh[14468]: File "/opt/mailur/mailur/imap.py", line 415, in select
Sep 21 01:54:45 webmail sh[14468]: res = check(con.select(box, readonly))
Sep 21 01:54:45 webmail sh[14468]: File "/usr/lib64/python3.6/imaplib.py", line 745, in select
Sep 21 01:54:45 webmail sh[14468]: typ, dat = self._simple_command(name, mailbox)
Sep 21 01:54:45 webmail sh[14468]: File "/usr/lib64/python3.6/imaplib.py", line 1196, in _simple_command
Sep 21 01:54:45 webmail sh[14468]: return self._command_complete(name, self._command(name, *args))
Sep 21 01:54:45 webmail sh[14468]: File "/usr/lib64/python3.6/imaplib.py", line 981, in _command
Sep 21 01:54:45 webmail sh[14468]: raise self.abort('socket error: %s' % val)
Sep 21 01:54:45 webmail sh[14468]: imaplib.IMAP4.abort: socket error: [Errno 32] Broken pipe
Sep 21 01:54:45 webmail sh[14468]: During handling of the above exception, another exception occurred:
Sep 21 01:54:45 webmail sh[14468]: Traceback (most recent call last):
Sep 21 01:54:45 webmail sh[14468]: File "/opt/mailur/mailur/cli.py", line 133, in inner
Sep 21 01:54:45 webmail sh[14468]: fn(*a, **kw)
Sep 21 01:54:45 webmail sh[14468]: File "/opt/mailur/mailur/cli.py", line 144, in idle_remote
Sep 21 01:54:45 webmail sh[14468]: with remote.client(**params) as c:
Sep 21 01:54:45 webmail sh[14468]: File "/opt/mailur/mailur/remote.py", line 85, in client
Sep 21 01:54:45 webmail sh[14468]: ctx = imap.client(connect, writable=writable)
Sep 21 01:54:45 webmail sh[14468]: File "/opt/mailur/mailur/imap.py", line 215, in client
Sep 21 01:54:45 webmail sh[14468]: con = start()
Sep 21 01:54:45 webmail sh[14468]: File "/opt/mailur/mailur/imap.py", line 202, in start
Sep 21 01:54:45 webmail sh[14468]: con = connect()
Sep 21 01:54:45 webmail sh[14468]: File "/opt/mailur/mailur/__init__.py", line 99, in inner_fn
Sep 21 01:54:45 webmail sh[14468]: return func(*a, **kw)
Sep 21 01:54:45 webmail sh[14468]: File "/opt/mailur/mailur/remote.py", line 79, in connect
Sep 21 01:54:45 webmail sh[14468]: con = Remote()
Sep 21 01:54:45 webmail sh[14468]: File "/opt/mailur/mailur/remote.py", line 60, in __init__
Sep 21 01:54:45 webmail sh[14468]: account = data_account.get()
Sep 21 01:54:45 webmail sh[14468]: File "/opt/mailur/mailur/local.py", line 147, in get
Sep 21 01:54:45 webmail sh[14468]: value = metavalue.key(name)
Sep 21 01:54:45 webmail sh[14468]: File "/opt/mailur/mailur/local.py", line 125, in key
Sep 21 01:54:45 webmail sh[14468]: return get().get(name, default)
Sep 21 01:54:45 webmail sh[14468]: File "/opt/mailur/mailur/imap.py", line 61, in inner_fn
Sep 21 01:54:45 webmail sh[14468]: with use_or_create(kw):
Sep 21 01:54:45 webmail sh[14468]: File "/usr/lib64/python3.6/contextlib.py", line 81, in __enter__
Sep 21 01:54:45 webmail sh[14468]: return next(self.gen)
Sep 21 01:54:45 webmail sh[14468]: File "/opt/mailur/mailur/imap.py", line 38, in use_or_create
Sep 21 01:54:45 webmail sh[14468]: con.select(box, readonly)
Sep 21 01:54:45 webmail sh[14468]: File "/opt/mailur/mailur/imap.py", line 106, in inner
Sep 21 01:54:45 webmail sh[14468]: raise Error(e)
Sep 21 01:54:45 webmail sh[14468]: mailur.imap.Error: socket error: [Errno 32] Broken pipe
Restarting the mailur-lucas.service
service fixes it, but then after a couple of minutes it happens again. I have recently activated firewalld
, can you please confirm which ports need to be allowed?
Thanks!
Sandstorm.io very much prefers that apps are packaged by the project maintainers.
You can see a packaging tutorial here.
Hi!
First of all, congrats on the project! The webmail looks awesome!
Second, I already have a mail server (which already uses Dovecot) and would like to just install Mailur. I was kinda not sure if I should just run the installer, or if that will override my existing Dovecot installation, etc.
Can you please advise?
Thanks in advance!
Does mailur support multiple inboxes? Unified inbox tags etc? Is this a feature we can expect to see in the future?
Really cool project, btw!
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.