wendlers / mpfshell Goto Github PK
View Code? Open in Web Editor NEWA simple shell based file explorer for ESP8266 Micropython based devices ⛺
License: MIT License
A simple shell based file explorer for ESP8266 Micropython based devices ⛺
License: MIT License
I realize you removed it... and looking at it, I wonder if it would still be possible to use it with WebREPL or only local ports?
Using...
** Micropython File Shell v0.7.3, [email protected] **
-- Running on Python 2.7 using PySerial 3.1 --
...repl
via ws: uses 100% cpu and is slow like typing thru a 300Bd modem.
Leaving repl
frees cpu usage again.
Happens with:
Hi;
Is it possible to backup the entire file system folders * files and restore it ?
To backup I tried mget .* but that did not appear to work ??
Connecting to webrepl via the ws option of mpfshell seems a little less reliable than using webrepl from https://github.com/micropython/webrepl.
Connecting the first time to freshly booted esp8266 usually seems to work (even if I have the feeling that it also sometimes fails when the wireless connection is weak - don't have proof for that yet). However, re-opening the websocket or even closing and re-connecting usually does not work the first time. A second re-connect often succeeds.
The webrepl web frontend seems to work nearly always (only sometimes fails when I used mpfshell in between).
Any idea why this is? What is done differently? Can this be fixed or circumvented?
A transcript of my testsession looks like this:
ulno#ulnoiot:$ mpfshell --loglevel DEBUG --logfile /tmp/mpfshell.log
** Micropython File Shell v0.8.0, [email protected] **
-- Running on Python 3.5 using PySerial 3.3 --
mpfs [/]> open ws:192.168.12.57,ulnoiot
Connected to esp8266
mpfs [/]> close
mpfs [/]> open ws:192.168.12.57,ulnoiot
Failed to open: ws:192.168.12.57,ulnoiot
mpfs [/]> open ws:192.168.12.57,ulnoiot
Connected to esp8266
mpfs [/]> open ws:192.168.12.57,ulnoiot
Failed to open: ws:192.168.12.57,ulnoiot
mpfs [/]> open ws:192.168.12.57,ulnoiot
Connected to esp8266
mpfs [/]> exit
The corresponding debug.log
tail -f /tmp/mpfshell.log
2017-04-27 13:48:08,883 INFO Micropython File Shell v0.8.0 started
2017-04-27 13:48:08,883 INFO Running on Python 3.5 using PySerial 3.3
2017-04-27 13:48:27,619 INFO websocket connected to ws://192.168.12.57:8266
2017-04-27 13:48:34,338 INFO websocket closed
2017-04-27 13:48:35,957 ERROR websocket error: Connection is already closed.
2017-04-27 13:48:35,962 INFO websocket closed
2017-04-27 13:48:40,807 ERROR
2017-04-27 13:48:57,758 INFO websocket connected to ws://192.168.12.57:8266
2017-04-27 13:49:04,248 INFO websocket closed
2017-04-27 13:49:04,275 ERROR websocket error: Connection is already closed.
2017-04-27 13:49:04,281 INFO websocket closed
2017-04-27 13:49:09,249 ERROR
2017-04-27 13:49:23,899 INFO websocket connected to ws://192.168.12.57:8266
2017-04-27 13:49:28,621 INFO websocket closed
$ ./mpfshell
** Micropython File Shell v0.7.3, [email protected] **
-- Running on Python 2.7 using PySerial 3.1 --
mpfs [/]> lcd ../localfiles
mpfs [/]> lls
Local files:
port_config.py
boot.py
mpfs [/]> open ttyUSB3
Connected to esp8266
mpfs [/]> mput *
nothing to repeat
$ _
mpfshell
terminates.
...okay: Regex instead of shell patterns:
$ ./mpfshell
** Micropython File Shell v0.7.3, [email protected] **
-- Running on Python 2.7 using PySerial 3.1 --
mpfs [/]> lcd ../localfiles
mpfs [/]> open ttyUSB3
Connected to esp8266
mpfs [/]> mput .*
* put port_config.py
* put boot.py
mpfs [/]> _
Kinda pebcac... ok!
But is it neccesary or unavoidable, that giving a wrong pattern/regex terminates mpfshell
?
It is not your fault, but it seams that adafruit made some changes in their circuitpython code.
See here: adafruit/circuitpython#1029
I get the same error when i try to connect to a circuitpython board.
Could u fix this, plz
Local echo in mpfshell's command loop is off after leaving the REPL .
I need to blindly leave mpfshell and type "reset" to get my "xterm" back on trails...
Leaving the REPL and reentering it blindly gives echo again in the REPL.
Configuration:
What does it do?
:-)
Mike
Not sure if I'm doing something wrong but when in repl mode and try to backspace, it adds in special characters. Probably an encoding issue or something. On windows 10.
I have mpfshell installed on my W10 machine with Python 2.7. Unlike esptool.py, mpfshell.py can't be just called from anywhere in the cmd-shell of W10. I have to cd C:\Python27\Lib\site-packages\mp
before I can successfully call mpfshell.py
. The reason seems to be because mpfshell keep its files under \site-packages\mp\
and doesn't have the .py and .pyc files in the \site-packages\
folder like esptool does
I'm new to Python, so I don't know how Python handles that kind of global calls at all.
Being a lazy person 😅 I wonder if it would not be possible to use mpfshell
as follows:
mpfshell --open tty.SLAB_USBtoUART
or (even quicker)
mpfshell tty.SLAB_USBtoUART
instead of:
mpfshell
mpfs [/]> open tty.SLAB_USBtoUART
That way, one could use the shell's history to connect to the board: I tend to forget what tty.*
my board is connected to... 😳
Trying to scroll through history lines, the 1st line is not displayed until hitting the up key again or CTRL-L
.
While edititing a line, the cursor often is displaced by 1 position, again CTRL-L
helps.
This happens while being connected serially or over websocket running mpfshell
in an xterm
with screen
.
It does not happen when connecting using webrepl.html or using screen /dev/ttyUSB0 115200
inside the same xterm
like above.
"repl" command crashes if invoked more than once on ESP8266 via sockets. I can't test via com port as on windows I can't connect via COM port
mpfs [/]> repl
'Out' object has no attribute 'buffer'
Exception ignored in: <bound method Console.del of <serial.tools.miniterm.Console object at 0x02CEBC70>>
Traceback (most recent call last):
File "C:\Python\lib\site-packages\serial\tools\miniterm.py", line 116, in del
ctypes.windll.kernel32.SetConsoleOutputCP(self._saved_ocp)
AttributeError: 'Console' object has no attribute '_saved_ocp'
this is what I see on the serial connection when I try to reconnect after exiting mpfshell using "exit".
dupterm: Exception in write() method, deactivating: OSError: [Errno 104] ECONNRESET
Concurrent WebREPL connection from ('192.168.178.22', 52858) rejected
the webrepl.html thingy works ok, so I'd say the issue is on the mpfshell side.
I suggest editing the readme.md to read:
mpfs> open ws:192.168.1.1,password (substitute correct IP address and password)
instead of:
mpfs> open ws:192.168.1.1,python
Which is the right version pyserial to install?
Hi,
After I launch mpfshell I am presented with a prompt, however I cannot see what I am typing, its hidden almost like a password. I can type in commands and hit enter and they work, but I can't actually see what I am typing... am I missing a library perhaps?
when mpfshell is connected to the ESP8266 via serial under W10, I attemted to execute:
mpfs[/]put c:\scripts\awesomescript.py
and get the error message:
Invalid file name given: :scripts\awesomescript.py
(notice the missing drive letter c)
If I put the script I want to upload in the same directory as mpfshell.py, it works fine. Maybe it is connected to issue #28
Cannot exit REPL mode using CTRL ALT ] combination. Overall very nice and helpful application!
Attempting to navigate around the local file system using lcd in Windows does not work and returns error
Invalid filename given:
Note that lls and lpwd work OK and return correct.
Hi,
I am facing many problems to upload/download (large) files with mpfshell, while it looks better with the ampy tool from adafruit.
I have the feeling mpfshell transfers all data in ascii while ampy does this binary but I am not completely sure about that.
Can you confirm ? how difficult would it be to offer another transfer mode ?
Cheers,
Jerome
Hi
Runing mpfshell v0.9.0 on Windows 7, I am trying to upload files for my embedded webserver in /www/ directory.
No problems to upload index.html and default.css, but mpfshell fails to upload b.png and favicon.ico
No problem to upload them at root /
Beside, this is really cool tool 👍
Many thanks
mpfs [/]> get boot.py
Traceback (most recent call last):
File "/usr/local/bin/mpfshell", line 8, in
main()
File "/Library/Python/2.7/site-packages/mp/mpfshell.py", line 704, in main
mpfs.cmdloop()
File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/cmd.py", line 142, in cmdloop
stop = self.onecmd(line)
File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/cmd.py", line 221, in onecmd
return func(arg)
File "/Library/Python/2.7/site-packages/mp/mpfshell.py", line 422, in do_get
self.fe.get(rfile_name, lfile_name)
File "/Library/Python/2.7/site-packages/mp/retry.py", line 43, in f_retry
return f(*args, **kwargs)
File "/Library/Python/2.7/site-packages/mp/mpfexp.py", line 347, in get
raise e
mp.pyboard.PyboardError: ('exception', '', 'Traceback (most recent call last):\r\n File "", line 3, in \r\nTypeError: 'int' object is not callable\r\n')
I've been trying to interpret and debug, but I'm not that familiar with mpfshell yet.
Steps to reproduce:
>>> with open('app', 'w') as f:
>>> f.write("hello")
mpfs [/]> ls
Remote files in '/':
>>> import os
>>> os.listdir()
['app']
mpfs [/]> cat app
hello
I would be nice that we won't need to clone this to use it
Hi,
I am user of archlinux (unfortunetly) and it seems like your app is not python3 compatible, sad thing is that on archlinux 'python' library points to python3...
would you mind to explicitly use "python2" binary in your 'mpfshell' bash executable?
Hey,
If I don't open the serial port and try to use the pwd command (I know I'm not supposed to :)) I get:
** Micropython File Shell v0.6, 2016 [email protected] **
mpfs [/]> pwd
'NoneType' object has no attribute 'pwd'
And then I get thrown back into my terminal. Perhaps need a similar message as you have for other commands Not connected to device. Use 'open' first.
This is not quite a duplicate of #18.
Since I upgraded my python engine to Python 3.5.3 (anaconda custom (x86_64)), I cannot exit repl using ctrl-] (or ctrl-Q) anymore.
As a matter of fact, the ctrl-] shortcut was already quite a bother: the ] key cannot be accessed directly on a French keyboard. One had to switch to a US keyboard, type the sequence and then switch back to the French keyboard. All in all, a minimum of 3 key combinations (cmd-space, ctrl-], cmd-space)
Would it be possible to have ctrl-Q (or any other) as the exit key? I tried toying with the source (mpfshell.py around line 575) by replacing chr(0x1d)
by chr(0x11)
, but it did not change anything...
On micropython systems with the /flash subdirectory, all get/put commands fail when running mpfshell from Windows. This is caused by the use of os.path.join
in mpfexp.py which results in file paths joined with \\ instead of /. Micropython's file system uses /.
I managed to fix it by import posixpath
in mpfexp.py followed by replacing all instances of os.path.join
with posixpath.join
.
Using cat <remote-file>
on a non ASCII file hangs the shell. Underlying gets
command should use binary transfer (as done by get
) to fix the problem.
if no login name password is given is it possible to just setup your nice connection. I have a very simple local area telnet server that I would like to work with your tool. my server works with telnet but your tool is much better in that it has all of the other command stuff for getting and putting files.
diff --git a/mp/contelnet.py b/mp/contelnet.py
index 55c726e..9e328fc 100644
--- a/mp/contelnet.py
+++ b/mp/contelnet.py
@@ -42,6 +42,9 @@ class ConTelnet(ConBase):
self.read = self.__read3
self.tn = telnetlib.Telnet(ip)
if user=='':
self.fifo = deque()
return
if b'Login as:' in self.tn.read_until(b'Login as:', timeout=5.0):
self.tn.write(bytes(user.encode('ascii')) + b"\r\n")
I had to leave off the ,python
in order to get it to properly connect to my ESP8266 running uPy 1.8.7-7 from mpfs 0.8.0 using Python 3.5 and PySerial 3.3.
I hope you can give me a development branch, because I have on a variety of platforms for the basis of user experience, so I can modify on this branch is more aggressive, more testing, and then the main branch (master) think I update is good, can also pull or select into mainstream generate release, at the same time I would be happy to continue on the basis of the maintenance and development.
My board is the nodeMCU with CP2102 USB to serial converter running MicroPython 1.8.7. I have a test script running that doesn't do much more than blinking neopixel LEDs. That script is started via function call from the boot.py script on the ESP8266. When I connect with open COM5
to the ESP8266 the execution of my script stops (no blinking). Otherwise mpfshell and MicroPython on the ESP seems to be fine because ls
command works and prints out the files on the file system. I can get the script working (LEDs blinking) again by using the reset button on the NodeMCU board.
So it doesn't seem like the establishment of the serial connection with mpfshell causes a reset of the MicroPython firmware.
I tried the same with putty, but putty can connect to the NodeMCU without stopping the script (LEDs keep blinking).
Currently it is not possible in the shell to use file/directory names including white spaces (also the underlying mpfexp
supports this). It should be possible to access names with white spaces by using strings quoted in "..".
Hello.
Very sorry if I'm mistaken but it would appear that files are not closed on the actual MicroPython target device.
I'm using an ESP32-based device (the SHA2017 badge) and notice that I eventually run out of file descriptors and am unable to read more files.
mpfs [/]> cat config.json
{}
mpfs [/]> cat config.json
Failed to read file: config.json
mpfs [/]> repl
*** Exit REPL with Ctrl+] ***>
MicroPython v1.9.1-1344-g5677ea1 on 2017-08-20; SHA2017-Badge with ESP32
Type "help()" for more information.
>>> f.close()
>>>
mpfs [/]> cat config.json
{}
mpfs [/]> cat config.json
Failed to read file: config.json
mpfs [/]>
The apparent opened file descriptor seems to originate from this line below:
Line 349 in e2a2d2d
Many thanks.
The hashbang in mpfshell should read #!/usr/bin/env python
instead of /usr/bin/python
so that mpfshell can be used with virtual environments.
I am currently experiencing issues when trying to connect using mpfshell (i.e. failure 19 cases in 20) with my wemos D1 mini. The error message being: "could not enter raw repl".
Browsing around I discovered that in ampy, which uses a slightly different version of pyboard.py, a delay is added before sending the double ctrl-C when entering raw repl.
So I added a 1 second delay just before line 63 in pyboard.py, in enter_raw_repl
(i.e. just before self.con.write(b'\r\x03\x03')
). The code now looks like
def enter_raw_repl(self):
time.sleep(1)
self.con.write(b'\r\x03\x03') # ctrl-C twice: interrupt any running program
The result being that I can now consistently open the board. I tried reducing the delay. 0.2 second works, 0.15 doesn't. Currently I am working with a 0.5 second delay.
Hi guys.
I've been trying to use mpfshell with my Wemos D1 mini pro and noticed that it won't connect through ws: if websocket-client version is > 0.48.0.
In debug I see:
2018-09-01 10:51:36,860 ERROR error from callback <bound method ConWebsock.on_message of <ConWebsock(Thread-1, started daemon 140001679963904)>>: on_message() missing 1 required positional argument: 'message'
2018-09-01 10:51:36,964 ERROR error from callback <bound method ConWebsock.on_error of <ConWebsock(Thread-1, started daemon 140001679963904)>>: on_error() missing 1 required positional argument: 'error'
2018-09-01 10:51:37,005 ERROR error from callback <bound method ConWebsock.on_close of <ConWebsock(Thread-1, started daemon 140001679963904)>>: on_close() missing 1 required positional argument: 'ws'
2018-09-01 10:51:41,535 ERROR
First I want to say many thanks for this fantastic tool. I use mpfshell for all my micropython projects for quite a while now and really like the simplicity and functionality of it.
I want to suggest a small but - in my opinion - very useful extension to make the workflow even more smooth. I often find myself starting and leaving mpfshell in the process of development. It would be great to have a command-line argument that opens the given port automatically on startup of mpfshell. Something as simple as:
$ mpfshell /dev/tty.wchusbserialfd120
This way one could skip the open myspecificport
command at the beginning of a mpfshell session which otherwise has to be typed again and again on the beginning of each mpfshell session. With a port command-line argument the user will be able to make use of the reverse-search and autocomplete features of the shell or even use an alias to get mpfshell up and running on the right port at once.
I think this would be a great improvement to the general workflow and I would also be willing to implement it.
Kind Regards
Stefan
mfpshell uses the uname
function to get information about the board that it connects to. In the Micropython documentation this function lives in the "uos" module. However mpfshell uses os.uname()
which is not a problem as long as one does not install the "os" module from micropython-lib which offers advanced functionality. This os module does not support uname
as it is meant to lean on to CPythons os
module.
A proper solution is to use uos.uname
in the mpshell code. I fixed this in #51.
open COM5
fails with:
** Micropython File Shell v0.7.0, [email protected] **
mpfs [/]> open COM5
Failed to open: ser:/dev/COM5
I'm using a LoPy from Pycom, the esptool expects RTS to be used for reset, so we have designed our production PCBs with this in mind. We would like to use mpfshell to copy files to our devices. You have used DTR in ConSerial as the reset line. It would be nice if this was configurable so that the ESP32 device would work correctly over serial.
For what its worth, Mpfshell works well with ESP32 over Telnet.
I should state I'm using Windows and its possible that Windows opens the COM port in a different state than ComSerial might expect with regards to DTR and RTS lines, for best configuration perhaps two states could be given as for "reset" and "nominal", with the high/low lines of both DTR and RTS set accordingly, something like.
def set_control_lines(nominal, reset):
""" Change the state of the serial control lines during typical state or reset state """
# nominal and reset are tuples of (Boolean, Boolean), DTR, RTS respectively
self.ctrl_nominal = nominal
self.ctrl_reset = reset
def _do_reset(self):
self.serial.setDTR(self.ctrl_reset[0])
self.serial.setRTS(self.ctrl_reset[1])
time.sleep(0.25)
self.serial.setDTR(self.ctrl_nominal[0])
self.serial.setRTS(self.ctrl_nominal[1])
def __init__(...):
...
if reset:
logging.info("Hard resetting device at port: %s" % port)
self._do_reset()
...
Let's discuss the best implementation of this, I can provide a PR once we have nailed down any concerns.
Kind regards,
Josh.
I'm trying to use this with a LoPy board but I have some trouble with the ls function. What happens is that the excepted PyboardError for directories doesn't include the word "ENOENT" but is rather the normal "OSError: no such file or directory". This leads to the exception being raised and mpfshell crashing. Changing the check to look for that string works fine but that entire code should be changed for something that actually checks if it is a file or a directory.
setup.py
:
requires=['pyserial', 'colorama', 'websocket_client'],
should be:
install_requires=['pyserial', 'colorama', 'websocket_client'],
Env:
Windows 10
Anaconda 3
Both NodeMCU ESP8266 And ESP32
MicroPython latest version
I have a python file named Ultrasonic.py.
And when I do next command:
python -m mp.mpfshell -o COM5
md ezmpy
cd ezmpy
put Ultrasonic.py
There have an Error:
Traceback (most recent call last):
File "C:\Anaconda3\lib\runpy.py", line 193, in _run_module_as_main
"main", mod_spec)
File "C:\Anaconda3\lib\runpy.py", line 85, in run_code
exec(code, run_globals)
File "C:\Anaconda3\lib\site-packages\mp\mpfshell.py", line 711, in
main()
File "C:\Anaconda3\lib\site-packages\mp\mpfshell.py", line 704, in main
mpfs.cmdloop()
File "C:\Anaconda3\lib\cmd.py", line 138, in cmdloop
stop = self.onecmd(line)
File "C:\Anaconda3\lib\cmd.py", line 217, in onecmd
return func(arg)
File "C:\Anaconda3\lib\site-packages\mp\mpfshell.py", line 369, in do_put
self.fe.put(lfile_name, rfile_name)
File "C:\Anaconda3\lib\site-packages\mp\mpfexp.py", line 537, in put
MpFileExplorer.put(self, src, dst)
File "C:\Anaconda3\lib\site-packages\mp\retry.py", line 43, in f_retry
return f(*args, **kwargs)
File "C:\Anaconda3\lib\site-packages\mp\mpfexp.py", line 302, in put
raise e
File "C:\Anaconda3\lib\site-packages\mp\mpfexp.py", line 284, in put
self.exec("f = open('%s', 'wb')" % self.fqn(dst))
File "C:\Anaconda3\lib\site-packages\mp\pyboard.py", line 157, in exec
raise PyboardError('exception', ret, ret_err)
mp.pyboard.PyboardError: ('exception', b'', b'Traceback (most recent call last):\r\n File "", line 1\r\nSyntaxError: invalid syntax\r\n')
And if I rename Ultrasonic.py to u.py, and retry, it is all good, no error.
I met many times this problem, sometimes is Ultrasonic.py, sometimes is finger.py
Starting with Micropython/master @ f5f4cdae89ed040ae9209a380cf968254434e819 the file upload does not work anymore on ESP8266 devices. Other devices might be affected, too.
I nailed it down by bisecting.
How to reproduce:
Check out Micropython master with at least the mentioned commit.
Compile it
Flash it
Try to transfer a file
( echo "open ttyUSB0"; echo "put boot.py" ) | mpfshell --nocolor --nocache
With a working version f5f4cdae89ed040ae9209a380cf968254434e819~1 it will work.
With later version you get this:
$ ( echo "open ttyUSB0"; echo "put boot.py" ) | mpfshell --nocolor --nocache
** Micropython File Shell v0.7.6, [email protected] **
-- Running on Python 3.4 using PySerial 3.2.1 --mpfs [/]> Connected to esp8266
mpfs [/]> Traceback (most recent call last):
File "/home/abra/opt/python3-venv/bin/mpfshell", line 8, in
main()
File "/home/abra/opt/python3-venv/lib/python3.4/site-packages/mp/mpfshell.py", line 687, in main
mpfs.cmdloop()
File "/usr/lib/python3.4/cmd.py", line 138, in cmdloop
stop = self.onecmd(line)
File "/usr/lib/python3.4/cmd.py", line 217, in onecmd
< return func(arg)
File "/home/abra/opt/python3-venv/lib/python3.4/site-packages/mp/mpfshell.py", line 365, in do_put
self.fe.put(lfile_name, rfile_name)
File "/home/abra/opt/python3-venv/lib/python3.4/site-packages/mp/retry.py", line 43, in f_retry
return f(*args, **kwargs)
File "/home/abra/opt/python3-venv/lib/python3.4/site-packages/mp/mpfexp.py", line 277, in put
raise e
File "/home/abra/opt/python3-venv/lib/python3.4/site-packages/mp/mpfexp.py", line 259, in put
self.exec_("f = open('%s', 'wb')" % self.fqn(dst))
File "/home/abra/opt/python3-venv/lib/python3.4/site-packages/mp/pyboard.py", line 157, in exec
raise PyboardError('exception', ret, ret_err)
mp.pyboard.PyboardError: ('exception', b'', b'Traceback (most recent call last):\r\n File "", line 1, in >\r\nOSError: [Errno 19] ENODEV\r\n')
Line 57 in 58e8457
the way it's now, I have to wait 5 seconds to see a failed connection and 10 seconds to see a successful connection. I'd expect this to proceed once the password prompt etc has been received, not wait for a full 256 chars or full timeout time.
$ ./mpfshell
** Micropython File Shell v0.7.3, [email protected] **
-- Running on Python 2.7 using PySerial 3.1 --
mpfs [/]> open ws:lolin-v3-3
webrepl passwd:
Connected to esp8266
mpfs [/]> exit
No handlers could be found for logger "root"
$ _
Is that something to take care of?
$ ./mpfshell
** Micropython File Shell v0.7.3, [email protected] **
-- Running on Python 2.7 using PySerial 3.1 --
mpfs [/]> open ws:lolin-v3-3
webrepl passwd:
Connected to esp8266
mpfs [/]> close
mpfs [/]> exit
$ _
close
before exit
does not yield that message.
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.