tus / tus-py-client Goto Github PK
View Code? Open in Web Editor NEWA Python client for the tus resumable upload protocol
Home Page: https://tus.io/
License: MIT License
A Python client for the tus resumable upload protocol
Home Page: https://tus.io/
License: MIT License
The news pip version is 0.2.5 which not support async_upload one-year ago๏ผso, hope a new version on pip site.
I am trying to upload a file to Cloudflare Stream while following their documentation and they suggest the following command:
tus-upload --chunk-size 52428800 --header Authorization "Bearer {mytoken}" "{myfile}" https://api.cloudflare.com/client/v4/accounts/{myaccountid}/stream
Running this, I get the following stacktrace:
[2021-08-02 20:39:28,370] INFO Creating file endpoint
Traceback (most recent call last):
File "/home/pi/.local/bin/tus-upload", line 10, in <module>
sys.exit(_cmd_upload())
File "/home/pi/.local/lib/python3.7/site-packages/tus.py", line 101, in _cmd_upload
metadata=args.metadata)
File "/home/pi/.local/lib/python3.7/site-packages/tus.py", line 208, in create
raise TusError("Create failed", response=response)
tus.TusError: <exception str() failed>
This doesn't really tell me much so I don't know how to go about troubleshooting this without attaching a debugger. The only issue I can think of is that I'm using a Raspberry Pi which has an ARM CPU.
Either way, there should probably be a better exception message so this is easier to debug by an end-user.
This is a very important feature of the tus protocol.
Do I really have to save my file locally to use TUS?
The code:
@app.route('/upload', methods=['POST'])
def upload_file():
if 'file' not in request.files:
return jsonify({'error': 'No file part'})
file = request.files['file']
if file.filename == '':
return jsonify({'error': 'No selected file'})
tus_client = client.TusClient('http://tusd.tusdemo.net/files/')
uploader = tus_client.uploader(file.stream, chunk_size=200)
try:
# Upload the entire file
upload_response = uploader.upload()
file_url = upload_response.headers['Location']
return jsonify({'file_url': file_url})
except Exception as e:
return jsonify({'error': str(e)})
The error:
TypeError: stat: path should be string, bytes, os.PathLike or integer, not SpooledTemporaryFile
We need to automate the publishing of new versions.
I have used the Node client of the Tus Client, There was an issue with certificate. I have turned it off with the following code
const process = require('process')
process.env.NODE_TLS_REJECT_UNAUTHORIZED = 0
How can I do it in Python Client ?
this is the error I am getting
(Caused by SSLError(SSLError("bad handshake: Error([('SSL routines', 'ssl3_get_server_certificate', 'certificate verify failed')],)",),))
When using the uploader.py
file like so:
from tusclient.uploader import Uploader
my_uploader = Uploader('path/to/file.ext',
url='http://master.tus.io/files/abcdef123456',
chunk_size=200)
a 'NoneType' object has no attribute 'headers'
error is raised. This is because self.headers
is never set, resulting in the error when self.getoffset()
is called: https://github.com/tus/tus-py-client/blob/master/tusclient/uploader.py#L92
Uploads can be deleted using a DELETE
request but tus-py-client does not support this yet. See tus/tusd#469 (comment)
from tusclient.request import TusRequest
from tusclient import client
my_client = client.TusClient('https://master.tus.io/files/')
uploader = my_client.uploader(f'C:/Users/parastu/Documents/upload_vod/videos/1.MP4', chunk_size=20000000)
fs = open(f'C:/Users/parastu/Documents/upload_vod/videos/1.MP4','rb')
uploader = my_client.uploader(file_stream=fs, chunk_size=20000000)
uploader.upload()
request_tus = TusRequest(uploader)
response_tus = request_tus.response_content
when i upload video , i don't know how to get response and location of upload in tus server, in this code "request_tus " return none object, please help me.
It would make the library more flexible if the Uploader could be given a requests Session object which it uses to make all requests.
Custom requests sessions can be used for many things. For example, I use them myself to capture all 401 Unauthorized errors when my tokens are expired, make sure I'm re-authenticated and repeat the request. I've seen others use them to fix a URL base or adding custom headers.
Would tus-py-client
maintainers be open to providing the ability to initialize an Uploader
with a custom requests.Session
object to enable use cases like this?
This seems to be a bug introduced by 3bc58e5 (#78), which relocates set_url()
from upload_chunk()
to upload()
. Thus the following code:
headers = {"x-api-key": "foo"}
path = "/foo"
chunk_size = 10**7
client = tusclient.client.TusClient("https://example.org", headers=headers)
uploader = client.uploader(
file_path=path,
chunk_size=chunk_size,
metadata=None,
store_url=False,
url_storage=None,
)
file_size = uploader.get_file_size()
while uploader.offset < file_size:
uploader.upload_chunk()
Results in the following (irrelevant upper stack components trimmed):
Traceback (most recent call last):
File "/home/nate/.virtualenvs/galaxy-upload2/lib/python3.10/site-packages/galaxy_upload/upload.py", line 105, in upload_file
uploader.upload_chunk()
File "/home/nate/.virtualenvs/galaxy-upload2/lib/python3.10/site-packages/tusclient/uploader/uploader.py", line 54, in upload_chunk
self._do_request()
File "/home/nate/.virtualenvs/galaxy-upload2/lib/python3.10/site-packages/tusclient/uploader/uploader.py", line 80, in _do_request
self._retry_or_cry(error)
File "/home/nate/.virtualenvs/galaxy-upload2/lib/python3.10/site-packages/tusclient/uploader/uploader.py", line 94, in _retry_or_cry
raise error
File "/home/nate/.virtualenvs/galaxy-upload2/lib/python3.10/site-packages/tusclient/uploader/uploader.py", line 77, in _do_request
self.request.perform()
File "/home/nate/.virtualenvs/galaxy-upload2/lib/python3.10/site-packages/tusclient/request.py", line 87, in perform
raise TusUploadFailed(error)
tusclient.exceptions.TusUploadFailed: Invalid URL 'None': No scheme supplied. Perhaps you meant https://None?
I thought maybe we were using the uploader wrong (we specifically use the chunk method so we can show a progress bar) but this is essentially exactly how the example in the docs works.
Hi,
I noticed all the official clients are lacking support for parallel upload. Is it because this feature is not production ready or is it because it's just not implemented?
Thanks
Hi Team,
I have been using tus libraries developed in multiple languages for quite a few days and it's really a great library.
However I would like to suggest, it will be more acceptable if tus library does not block the complex json structure in metadata request while uploading a file, specifically while encoding the metadata, this library always throws error.
Here is what I did which worked for me as a work around while working with tus-js-client library, attaching sample code:
`function encodeMetadata(metadata) {
var encoded = [];
for (var key in metadata) {
if (Array.isArray(metadata[key])) {
encoded.push(key + " " + _jsBase.Base64.encode(JSON.stringify(metadata[key])));
} else {
encoded.push(key + " " + _jsBase.Base64.encode(metadata[key]));
}
}
return encoded.join(",");
}`
The Title sort of says it all ๐
I am using the Tus Py Client , in a macos High Sierra environment running Python 3.6.6. I am trying to make a HTTPS request to a tusd server.
The tusd server is running successfully behind an nginx proxy with an SSL terminated connection. I can visit the /files/ endpoint successfully in a browser via an SSL/TLS connection.
I am receiving an SSL: CERTIFICATE_VERIFY_FAILED error from
Tus Py Client when making the connection request. Looking at the source code, Tus Py Client uses the requests library to make a web request:
@_catch_requests_error
def create_url(self):
"""
Return upload url.
Makes request to tus server to create a new upload url for the required file upload.
"""
headers = self.headers
headers['upload-length'] = str(self.file_size)
headers['upload-metadata'] = ','.join(self.encode_metadata())
resp = requests.post(self.client.url, headers=headers)
url = resp.headers.get("location")
if url is None:
msg = 'Attempt to retrieve create file url with status {}'.format(resp.status_code)
raise TusCommunicationError(msg, resp.status_code, resp.content)
return urljoin(self.client.url, url)
If I make a HTTPS request to the tusd server manually from within a python shell, specifying the root certificate to the verify parameter, I can successfully connect:
import requests
resp=requests.get('https://test.example.com:1081/files',verify=<absolute path to cert file>)
However, the Tus Py Client does not appear to offer this override.
I understand that Python 3.6+ now has it's own internal certificate store, so that explains why the trusted certificate in the macos keystore is ignored.
Then I read the documentation for the requests library. This suggests using the REQUESTS_CA_BUNDLE environment variable to specify trusted CAs. Indeed, after setting the environment variable with the path to the root CA certificate I was able to make the HTTPS request using the Tus-Py-Client library.
Am I on the right track with this solution, or is there a better way?
Moving forward is there the possibility to raise a new feature request allowing the path to the CA certificate to be specified in TusClient constructor which then gets passed onto the requests library under the hood?
Updated on 13/11/2018
The environment variable SSL_CERT_FILE must also be set to the root CA certificate to receive a HTTPS connection for http.client. This is because upload.py uses the http.client library and request.py uses requests library.
Kind Regards
dcs3spp
I've been getting this error for a few days now whenever I try to install tuspy with pip
Collecting tuspy
Using cached tuspy-0.1.2.tar.gz
Complete output from command python setup.py egg_info:
Traceback (most recent call last):
File "", line 1, in
File "/tmp/pip-build-MLntjw/tuspy/setup.py", line 16, in
long_description = open('README.md').read()
IOError: [Errno 2] No such file or directory: 'README.md'
----------------------------------------
Command "python setup.py egg_info" failed with error code 1 in /tmp/pip-build-MLntjw/tuspy/
Would it be possible to expose the cert
options of the requests
calls so the client can be used with tus instance is running behind a reverse proxy requiring client certificate based authentication?
See: https://requests.readthedocs.io/en/latest/user/advanced/#client-side-certificates.
By default, the chunk_size
is set to 2MB (https://github.com/tus/tus-py-client/blob/master/tusclient/uploader.py#L47-L50). If I understand this comment correctly, it means that each HTTP request only contains a chunk of 2MB, assuming the user didn't change the default settings.
Is this correct? If so, a 2GiB request would use 1024 HTTP requests when thou the upload could be carried out in one request.
I am asking since a user reported slow uploads using tus-py-client in the #tus slack channel: https://transloadit.slack.com/archives/C03JWGFL4/p1532524797000257
Parth Doshi [15:19]
Hey guys, I am a newbie, and am trying to learn more about TUS. I have been using the tuspy client and the tusd server. One thing that I have noticed is that the time taken for large files is very long. For example, a 1.5 GB file took me around 15 minutes to upload to a remote server, on a very good internet connection. Is there any special reason for this? Any configurations that I need to change?
Dave Richardson [15:21]
How long does it take you to upload a file to the same remote location without using tus?
Parth Doshi [15:25]
Using normal TCP, it takes me around 6 minutes, whereas a transfer agent like File Catalyst takes around 3 minutes.
Dave Richardson [15:26]
How about regular http, without TUS?
Parth Doshi [15:26]
6 minutes
Dave Richardson [15:28]
Have you tried tuning the chunk size in tuspy?
Parth Doshi [15:29]
Yup, I got the 15 minute time with a 10 Mb chunk size.
Parth Doshi [15:36]
Another piece of information might be that it is taking around 1 minute for disk-to-disk transfer. By the way, thank you for helping. @dmr
Dave Richardson [16:10]
I'm not sure I've helped ๐ (edited)
We've done limited benchmarking with our servers with our biggest collaborator.
Using a 1.7Gb file, it takes them around 1 minute to transfer a file through FTP (we haven't setup a HTTP transfer)
Using TUS, it takes ~15 minutes with 0.256 megabyte chunks
It takes ~40 seconds with 25.6 megabyte chunks
Separately, we got much better rates when we used disc local to the machine. We are currently stuck with networked disc mounted over NFS.
Those transfer times are within the UK, between an academic site (absurd bandwidth) and top tier data centre.
All our tests used tuspy and tusd, so somewhat comparable with yours.
So maybe it's a good idea to set the default chunk_size to something bigger, maybe even infinite by default.
Hello! Running tusd v2 rc (which we will probably need to upgrade to for its improved hook support)
Uploading with Python 3 and tus-py-client v0.2.5 gives this error message on the server:
[tusd] 2021/12/13 11:33:16 event="RequestIncoming" method="POST" path="" requestId=""
[tusd] 2021/12/13 11:33:16 event="UploadCreated" id="1a661b35d4de35f3c51bd3ad3c05f8aa+157" size="11039934" url="http://localhost:8000/videos/upload/1a661b35d4de35f3c51bd3ad3c05f8aa+157"
[tusd] 2021/12/13 11:33:16 event="ResponseOutgoing" status="201" method="POST" path="" requestId="" body=""
[tusd] 2021/12/13 11:33:16 event="RequestIncoming" method="POST" path="" requestId=""
[tusd] 2021/12/13 11:33:16 event="UploadCreated" id="6b2eac297a64af476c168b6762fa0e5f+158" size="11039934" url="http://localhost:8000/videos/upload/6b2eac297a64af476c168b6762fa0e5f+158"
[tusd] 2021/12/13 11:33:16 event="ResponseOutgoing" status="201" method="POST" path="" requestId="" body=""
[tusd] 2021/12/13 11:33:16 event="RequestIncoming" method="HEAD" path="6b2eac297a64af476c168b6762fa0e5f+158" requestId=""
[tusd] 2021/12/13 11:33:16 event="ResponseOutgoing" status="200" method="HEAD" path="6b2eac297a64af476c168b6762fa0e5f+158" requestId="" body=""
[tusd] 2021/12/13 11:33:16 event="RequestIncoming" method="PATCH" path="6b2eac297a64af476c168b6762fa0e5f+158" requestId=""
[tusd] 2021/12/13 11:33:16 event="ChunkWriteStart" id="6b2eac297a64af476c168b6762fa0e5f+158" maxSize="1048576" offset="0"
[tusd] 2021/12/13 11:33:16 event="ChunkWriteComplete" id="6b2eac297a64af476c168b6762fa0e5f+158" bytesWritten="1048576"
[tusd] 2021/12/13 11:33:16 event="ResponseOutgoing" status="204" method="PATCH" path="6b2eac297a64af476c168b6762fa0e5f+158" requestId="" body=""
[tusd] 2021/12/13 11:33:16 event="RequestIncoming" method="PATCH" path="6b2eac297a64af476c168b6762fa0e5f+158" requestId=""
[tusd] 2021/12/13 11:33:16 event="ResponseOutgoing" status="409" method="PATCH" path="6b2eac297a64af476c168b6762fa0e5f+158" requestId="" body="ERR_MISMATCHED_OFFSET: mismatched offset
And the following from the client:
File "/home/toresbe/fk-cli/./fk", line 84, in <module>
upload_file('../CLUNKS-_8R64-WZwjw.mp4')
File "/home/toresbe/fk-cli/./fk", line 58, in upload_file
tus_uploader.upload_chunk()
File "/home/toresbe/fk-cli/.venv/lib/python3.9/site-packages/tusclient/uploader.py", line 299, in upload_chunk
self._do_request()
File "/home/toresbe/fk-cli/.venv/lib/python3.9/site-packages/tusclient/uploader.py", line 314, in _do_request
self._retry_or_cry(error)
File "/home/toresbe/fk-cli/.venv/lib/python3.9/site-packages/tusclient/uploader.py", line 330, in _retry_or_cry
raise error
File "/home/toresbe/fk-cli/.venv/lib/python3.9/site-packages/tusclient/uploader.py", line 311, in _do_request
self.verify_upload()
File "/home/toresbe/fk-cli/.venv/lib/python3.9/site-packages/tusclient/uploader.py", line 251, in verify_upload
raise TusUploadFailed('', self.request.status_code, self.request.response_content)
tusclient.exceptions.TusUploadFailed: Communication with tus server failed with status 409
Hi,
I have been trying to send the file name and another info via the Upload-Metadata
header value. But somehow i cant see it in the uploaded video in cloudflare dashboard.
Here is the cloudflare documentation https://developers.cloudflare.com/stream/uploading-videos/upload-video-file/#supported-options-in-upload-metadata
Here is my code.
headers, cloudflare_config = self.get_headers()
headers["Tus-Resumable"] = "1.0.0"
headers["Upload-Length"] = "900000000"
headers["Content-Length"] = "0"
headers["Upload-Metadata"] = "requiresignedurls" #trying here first
token_url = BASE_URL + 'accounts/' + cloudflare_config['ACCOUNT_ID'] + '/stream'
try:
data = {
'maxDurationSeconds': 21600,
'requireSignedURLs': True
}
my_client = client.TusClient(token_url, headers=headers)
my_client.set_headers({'Upload-Metadata': 'requiresignedurls'}) #trying here again
my_client.metadata = {'requiresignedurls': True} #trying here again
I have tried to send the metadata in three places in the above code. None of them are working.
Can anyone help me on this issue please?
The typing information of this package is not available for projects that import the tusclient
package. This is because it does not comply with PEP 561 which requires a py.typed
file in the root of the package.
For projects utilising MyPy this will result in the following error:
src/example.py:9: error: Skipping analyzing "tusclient": module is installed, but missing library stubs or py.typed marker [import]
Further reading:
Alt titles for searchability:
py.typed
missingHello,
I have installed tuspy v0.2.3, but it doesn't support the attribute upload_checksum in the class Uploader. I found that the newest code does not be released.
My client.py
from tusclient import client
# Set Authorization headers if it is required
# by the tus server.
my_client = client.TusClient('http://0.0.0.0:5000/resume_upload',
headers={'Authorization': 'Basic xxyyZZAAbbCC='})
# Set more headers.
#my_client.set_headers({'tag': 'value'})
# uploader = my_client.uploader('/home/sharif/Downloads/Customer_SpecialTerminationRates1_1_FRM_v20220930.xlsx', chunk_size=200)
# A file stream may also be passed in place of a file path.
fs = open('/home/sharif/Downloads/image.jpeg')
uploader = my_client.uploader(file_stream=fs, chunk_size=200, metadata={'filename':'aW5mby5tZXRh'})
# Upload a chunk i.e 200 bytes.
uploader.upload_chunk()
# Uploads the entire file.
# This uploads chunk by chunk.
uploader.upload()
# you could increase the chunk size to reduce the
# number of upload_chunk cycles.
uploader.chunk_size = 800
uploader.upload()
# Continue uploading chunks till total chunks uploaded reaches 1000 bytes.
uploader.upload(stop_at=1000)
Traceback (most recent call last):
File "/media/sharif/Backup/test/Debug/TUS/client/client.py", line 18, in <module>
uploader.upload_chunk()
File "/media/sharif/Backup/test/Debug/TUS/venv/lib/python3.10/site-packages/tusclient/uploader/uploader.py", line 49, in upload_chunk
self._do_request()
File "/media/sharif/Backup/test/Debug/TUS/venv/lib/python3.10/site-packages/tusclient/uploader/uploader.py", line 72, in _do_request
self.request.perform()
File "/media/sharif/Backup/test/Debug/TUS/venv/lib/python3.10/site-packages/tusclient/request.py", line 77, in perform
chunk = self.file.read(self._content_length)
File "/usr/lib/python3.10/codecs.py", line 322, in decode
(result, consumed) = self._buffer_decode(data, self.errors, final)
UnicodeDecodeError: 'utf-8' codec can't decode byte 0xff in position 0: invalid start byte
Hi there,
first of all, tuspy is really great and I already had a lot of easy success with it to communicate with my own tus.io server implementation.
the encoding of the "metadata" header however bugs me a bit. tuspy encodes with 'latin-1', while the official tus-js library for example uses 'utf-8'.
I think it would be a lot more convenient if the default would also be 'utf-8' for tuspy. or at least make an optional parameter to specifiy the encoding.
with the current situation the cleanest solution to determine the encoding is to add an extra header at the tus-server to specify which encoding is used and also add this header in the program using tuspy. all this would be unnecessary if we could specify the encoding.
yours
klaus
Hi,
I want to upload using short-lived tokens. Some requests may return with a 403 status code.
Is it possible to add a custom error handler that refreshes/re-inject the new token before performing a retry?
Kind regards
The requirments.txt
dependencies do not match the setup.py
dependencies. For example,
requirements.txt | setup.py | package |
---|---|---|
1.11.0 | 1.10.0 | six |
2018.1.18 | 2017.7.27.1 | certifi |
2.18.4 | 2.11.1 | requests |
This is causing issues for me since the versions in the setup.py
are very old. Moreover, setup.py
specifies strict dependencies instead of lower bounds.
Questions:
requirments.txt
and setup.py
?requirements.txt
does not appear to be used by setup.py
-- what is the purpose of having it in the repo?Hi. I use Uppy.io in webforms and I'm trying to replicate that usage with a cli interface. My use case demands metadata upload (just checked I can get that with tus-py-client!) and eventually multiple files at once. I could not find any mention on how to achieve this last feature in this client documentation. Would that be possible ? Many thanks in advance.
Hi Guys,
I am compiling an exe using pyinstaller 3.3 on Windows Server 2016, with Windows 10 SDK installed. This is a simple python 3.6.2 app importing tuspy 0.1 using pycurl 7.46.0.
60, SSL certificate problem: unable to get local issuer certificate
Obviously pycurl can't find my cert to compare against the url I am passing to tuspy which is https.
How can i...
a) turn off ssl verification with my call to tuspy
b) inform tuspy of the location of a valid cert file
c) fix this some other way
Thanks!!
`
fs = open('path/to/file.ext')
uploader = my_client.uploader(file_stream=fs, chunk_size=200)
class BaseUploader:
self.file_stream = file_stream
self.stop_at = self.get_file_size()
def get_file_stream(self):
if self.file_stream:
self.file_stream.seek(0)
return self.file_stream
elif os.path.isfile(self.file_path):
return open(self.file_path, 'rb')
else:
raise ValueError("invalid file {}".format(self.file_path))
def get_file_size(self):
with self.get_file_stream() as stream:
stream.seek(0, os.SEEK_END)
return stream.tell()
##Filestream is closed in get_file_size function , If you use it again, you will get an error: ValueError: I/O operation on closed file.**
uploader.upload()
Dear authors,
We have been using your package (quite satisfactory!) for a while now. Recently, we transitioned to using your package behind a corporate proxy. This led to some issues which were already outlined in this PR: #34
Obviously we were happy with that fix, but it was a tad dissapointing that this fix is not on the PyPI repositories. For now we fixed this by grabbing a local version of this repository, but we are wondering: Are there any plans to release a new version on PYPI with recent changes?
Kind regards,
Rob
the client.uploader class unconditionally prints in upload_chunk.
I'm happy to make a PR removing this, but if you want to keep the functionality behind a flag or something I'd appreciate some input into how you would like that to work.
Question
I have the below basice python client:
from tusclient import client
my_client = client.TusClient('http://localhost:9090/files/')
uploader = my_client.uploader('test.pptx', chunk_size=1000)
uploader.upload()
Everything seems to work as expected. But, if I stop the client execution (Ctrl+C) and then restart the exact same script without any changes whatsoever, it seems to me that the upload will start from the beginning.
Is this behavior normal?
Setup details
Please provide following details, if applicable to your situation:
As we have in the tus-java-client and the tus-js-client, we'd like to have a url storage interface on the tus-py-cient for upload resumability.
How can I turn off certificate check in Tus-Python client ? I have tried the following as suggested before,
import ssl
ssl._create_default_https_context = ssl._create_unverified_context
But this does not work still getting the following error
Caused by SSLError(SSLError("bad handshake: Error([('SSL routines', 'ssl3_get_server_certificate', 'certificate verify failed')],)",),))
On the Other Hand what would be the equivalent code for this nodejs client?
var file_to_upload = "./data_folder/text_csv.csv"
var file = fs.createReadStream(file_to_upload)
var size = fs.statSync(file_to_upload).size
const TOKEN = "<TOKEN>"
const DIR = "<DIR_ID>"
let upload = new tus.Upload(file, {
endpoint: 'URL',
retryDelays: [0, 1000, 3000, 5000],
uploadSize: size,
metadata: {
filename: "blahblah.txt",
directoryId: DIR,
authorization: TOKEN
},
onError: function(error) {
console.log(error)
},
onProgress: function(bytesUploaded, bytesTotal) {
console.log(bytesUploaded + "\t", bytesTotal)
},
onSuccess: function() {
console.log("done")
}
})
upload.start()
Seems our setup.py is too complicated for Dependabot. Maybe we should try to stick to this format: https://github.com/dependabot/dependabot-core/blob/main/python/spec/fixtures/setup_files/setup.py
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.