Giter Club home page Giter Club logo

envd's Introduction

envd cat wink envd cat wink

Development environment for AI/ML

discord invitation link trackgit-views Python Version all-contributors envd package downloads continuous integration Coverage Status

What is envd?

envd (ษชnหˆvdษช) is a command-line tool that helps you create the container-based development environment for AI/ML.

Creating development environments is not easy, especially with today's complex systems and dependencies. With everything from Python to CUDA, BASH scripts, and Dockerfiles constantly breaking, it can feel like a nightmare - until now!

Instantly get your environment running exactly as you need with a simple declaration of the packages you seek in build.envd and just one command: envd up!

Why use envd?

Environments built with envd provide the following features out-of-the-box:

Simple CLI and language

envd enables you to quickly and seamlessly integrate powerful CLI tools into your existing Python workflow to provision your programming environment without learning a new language or DSL.

def build():
    install.python_packages(name = [
        "numpy",
    ])
    shell("zsh")
    config.jupyter()

Isolation, compatible with OCI image

With envd, users can create an isolated space to train, fine-tune, or serve. By utilizing sophisticated virtualization technology as well as other features like buildkit, it's an ideal solution for environment setup.

envd environment image is compatible with OCI image specification. By leveraging the power of an OCI image, you can make your environment available to anyone and everyone! Make it happen with a container registry like Harbor or Docker Hub.

Local, and cloud

envd can now be used on a hybrid platform, ranging from local machines to clusters hosted by Kubernetes. Any of these options offers an efficient and versatile way for developers to create their projects!

$ envd context use local
# Run envd environments locally
$ envd up
...
$ envd context use cluster
# Run envd environments in the cluster with the same experience
$ envd up

Check out the doc for more details.

Build anywhere, faster

envd offers a wealth of advantages, such as remote build and software caching capabilities like pip index caches or apt cache, with the help of buildkit - all designed to make your life easier without ever having to step foot in the code itself!

Reusing previously downloaded packages from the PyPI/APT cache saves time and energy, making builds more efficient. No need to redownload what was already acquired before โ€“ a single download is enough for repeat usage!

With Dockerfile v1, users are unable to take advantage of PyPI caching for faster installation speeds - but envd offers this support and more!

Besides, envd also supports remote build, which means you can build your environment on a remote machine, such as a cloud server, and then push it to the registry. This is especially useful when you are working on a machine with limited resources, or when you expect a build machine with higher performance.

Knowledge reuse in your team

Forget copy-pasting Dockerfile instructions - use envd to easily build functions and reuse them by importing any Git repositories with the include function! Craft powerful custom solutions quickly.

envdlib = include("https://github.com/tensorchord/envdlib")

def build():
    base(os="ubuntu20.04", language="python")
    envdlib.tensorboard(host_port=8888)
envdlib.tensorboard is defined in github.com/tensorchord/envdlib
def tensorboard(
    envd_port=6006,
    envd_dir="/home/envd/logs",
    host_port=0,
    host_dir="/tmp",
):
    """Configure TensorBoard.

    Make sure you have permission for `host_dir`

    Args:
        envd_port (Optional[int]): port used by envd container
        envd_dir (Optional[str]): log storage mount path in the envd container
        host_port (Optional[int]): port used by the host, if not specified or equals to 0,
            envd will randomly choose a free port
        host_dir (Optional[str]): log storage mount path in the host
    """
    install.python_packages(["tensorboard"])
    runtime.mount(host_path=host_dir, envd_path=envd_dir)
    runtime.daemon(
        commands=[
            [
                "tensorboard",
                "--logdir",
                envd_dir,
                "--port",
                str(envd_port),
                "--host",
                "0.0.0.0",
            ],
        ]
    )
    runtime.expose(envd_port=envd_port, host_port=host_port, service="tensorboard")

Getting Started ๐Ÿš€

Requirements

  • Docker (20.10.0 or above)

Install and bootstrap envd

envd can be installed with pip, or you can download the binary release directly. After the installation, please run envd bootstrap to bootstrap.

pip install --upgrade envd

After the installation, please run envd bootstrap to bootstrap:

envd bootstrap

Read the documentation for more alternative installation methods.

You can add --dockerhub-mirror or -m flag when running envd bootstrap, to configure the mirror for docker.io registry:

envd bootstrap --dockerhub-mirror https://docker.mirrors.sjtug.sjtu.edu.cn

Create an envd environment

Please clone the envd-quick-start:

git clone https://github.com/tensorchord/envd-quick-start.git

The build manifest build.envd looks like:

def build():
    base(os="ubuntu20.04", language="python3")
    # Configure the pip index if needed.
    # config.pip_index(url = "https://pypi.tuna.tsinghua.edu.cn/simple")
    install.python_packages(name = [
        "numpy",
    ])
    shell("zsh")

Note that we use Python here as an example but please check out examples for other languages such as R and Julia here.

Then please run the command below to set up a new environment:

cd envd-quick-start && envd up
$ cd envd-quick-start && envd up
[+] โŒš parse build.envd and download/cache dependencies 2.8s โœ… (finished)
 => download oh-my-zsh                                                    2.8s
[+] ๐Ÿ‹ build envd environment 18.3s (25/25) โœ… (finished)
 => create apt source dir                                                 0.0s
 => local://cache-dir                                                     0.1s
 => => transferring cache-dir: 5.12MB                                     0.1s
...
 => pip install numpy                                                    13.0s
 => copy /oh-my-zsh /home/envd/.oh-my-zsh                                 0.1s
 => mkfile /home/envd/install.sh                                          0.0s
 => install oh-my-zsh                                                     0.1s
 => mkfile /home/envd/.zshrc                                              0.0s
 => install shell                                                         0.0s
 => install PyPI packages                                                 0.0s
 => merging all components into one                                       0.3s
 => => merging                                                            0.3s
 => mkfile /home/envd/.gitconfig                                          0.0s
 => exporting to oci image format                                         2.4s
 => => exporting layers                                                   2.0s
 => => exporting manifest sha256:7dbe9494d2a7a39af16d514b997a5a8f08b637f  0.0s
 => => exporting config sha256:1da06b907d53cf8a7312c138c3221e590dedc2717  0.0s
 => => sending tarball                                                    0.4s
envd-quick-start via Py v3.9.13 via ๐Ÿ…’ envd
โฌข [envd]โฏ # You are in the container-based environment!

Set up Jupyter notebook

Please edit the build.envd to enable jupyter notebook:

def build():
    base(os="ubuntu20.04", language="python3")
    # Configure the pip index if needed.
    # config.pip_index(url = "https://pypi.tuna.tsinghua.edu.cn/simple")
    install.python_packages(name = [
        "numpy",
    ])
    shell("zsh")
    config.jupyter()

You can get the endpoint of the running Jupyter notebook via envd envs ls.

$ envd up --detach
$ envd envs ls
NAME                    JUPYTER                 SSH TARGET              CONTEXT                                 IMAGE                   GPU     CUDA    CUDNN   STATUS          CONTAINER ID
envd-quick-start        http://localhost:42779   envd-quick-start.envd   /home/gaocegege/code/envd-quick-start   envd-quick-start:dev    false   <none>  <none>  Up 54 seconds   bd3f6a729e94

Difference between v0 and v1

Note To use the v1 config file, add # syntax=v1 to the first line of your build.envd file.

Features v0 v1
is default for envd<v1.0 โœ… โŒ
support dev โœ… โœ…
support CUDA โœ… โœ…
support serving โš ๏ธ โœ…
support custom base image โš ๏ธ โœ…
support installing multiple languages โš ๏ธ โœ…
support moby builder โŒ โœ… (a)

Note (a) To use the moby builder, you will need to create a new context with envd context create --name moby-test --builder moby-worker --use. For more information about the moby builder, check the issue-1693.

Important For more details, check the upgrade to v1 doc.

More on documentation ๐Ÿ“

See envd documentation.

Roadmap ๐Ÿ—‚๏ธ

Please checkout ROADMAP.

Contribute ๐Ÿ˜Š

We welcome all kinds of contributions from the open-source community, individuals, and partners.

Open in Gitpod

Contributors โœจ

Thanks goes to these wonderful people (emoji key):

 Friends A.
Friends A.

๐Ÿ“– ๐ŸŽจ
Aaron Sun
Aaron Sun

๐Ÿ““ ๐Ÿ’ป
Aka.Fido
Aka.Fido

๐Ÿ“ฆ ๐Ÿ“– ๐Ÿ’ป
Alex Xi
Alex Xi

๐Ÿ’ป
Bingtan Lu
Bingtan Lu

๐Ÿ’ป
Bingyi Sun
Bingyi Sun

๐Ÿ’ป
Ce Gao
Ce Gao

๐Ÿ’ป ๐Ÿ“– ๐ŸŽจ ๐Ÿ“†
Frost Ming
Frost Ming

๐Ÿ’ป ๐Ÿ“–
Guangyang Li
Guangyang Li

๐Ÿ’ป
Gui-Yue
Gui-Yue

๐Ÿ’ป
Haiker Sun
Haiker Sun

๐Ÿ’ป
Ikko Ashimine
Ikko Ashimine

๐Ÿ’ป
Isaac
Isaac

๐Ÿ’ป
JasonZhu
JasonZhu

๐Ÿ’ป
Jian Zeng
Jian Zeng

๐ŸŽจ ๐Ÿค” ๐Ÿ”ฌ
Jinjing Zhou
Jinjing Zhou

๐Ÿ› ๐Ÿ’ป ๐ŸŽจ ๐Ÿ“–
Jun
Jun

๐Ÿ“ฆ ๐Ÿ’ป
Kaiyang Chen
Kaiyang Chen

๐Ÿ’ป
Keming
Keming

๐Ÿ’ป ๐Ÿ“– ๐Ÿค” ๐Ÿš‡
Kevin Su
Kevin Su

๐Ÿ’ป
Ling Jin
Ling Jin

๐Ÿ› ๐Ÿš‡
Manjusaka
Manjusaka

๐Ÿ’ป
Nino
Nino

๐ŸŽจ ๐Ÿ’ป
Pengyu Wang
Pengyu Wang

๐Ÿ“–
Sepush
Sepush

๐Ÿ“–
Shao Wang
Shao Wang

๐Ÿ’ป
Siyuan Wang
Siyuan Wang

๐Ÿ’ป ๐Ÿš‡ ๐Ÿšง
Suyan
Suyan

๐Ÿ“–
To My
To My

๐Ÿ“–
Tumushimire Yves
Tumushimire Yves

๐Ÿ’ป
Wei Zhang
Wei Zhang

๐Ÿ’ป
Weixiao Huang
Weixiao Huang

๐Ÿ’ป
Weizhen Wang
Weizhen Wang

๐Ÿ’ป
XRW
XRW

๐Ÿ’ป
Xu Jin
Xu Jin

๐Ÿ’ป
Xuanwo
Xuanwo

๐Ÿ’ฌ ๐ŸŽจ ๐Ÿค” ๐Ÿ‘€
Yijiang Liu
Yijiang Liu

๐Ÿ’ป
Yilong Li
Yilong Li

๐Ÿ“– ๐Ÿ› ๐Ÿ’ป
Yuan Tang
Yuan Tang

๐Ÿ’ป ๐ŸŽจ ๐Ÿ“– ๐Ÿค”
Yuchen Cheng
Yuchen Cheng

๐Ÿ› ๐Ÿš‡ ๐Ÿšง ๐Ÿ”ง
Yuedong Wu
Yuedong Wu

๐Ÿ’ป
Yunchuan Zheng
Yunchuan Zheng

๐Ÿ’ป
Zheming Li
Zheming Li

๐Ÿ’ป
Zhenguo.Li
Zhenguo.Li

๐Ÿ’ป ๐Ÿ“–
Zhenzhen Zhao
Zhenzhen Zhao

๐Ÿš‡ ๐Ÿ““ ๐Ÿ’ป
Zhizhen He
Zhizhen He

๐Ÿ’ป ๐Ÿ“–
cutecutecat
cutecutecat

๐Ÿ’ป
dqhl76
dqhl76

๐Ÿ“– ๐Ÿ’ป
heyjude
heyjude

๐Ÿ’ป
jimoosciuc
jimoosciuc

๐Ÿ““
kenwoodjw
kenwoodjw

๐Ÿ’ป
li mengyang
li mengyang

๐Ÿ’ป
nullday
nullday

๐Ÿค” ๐Ÿ’ป
rrain7
rrain7

๐Ÿ’ป
tison
tison

๐Ÿ’ป
wangxiaolei
wangxiaolei

๐Ÿ’ป
wyq
wyq

๐Ÿ› ๐ŸŽจ ๐Ÿ’ป
x0oo0x
x0oo0x

๐Ÿ’ป
xiangtianyu
xiangtianyu

๐Ÿ“–
xieydd
xieydd

๐Ÿ’ป
xing0821
xing0821

๐Ÿค” ๐Ÿ““ ๐Ÿ’ป
xxchan
xxchan

๐Ÿ“–
zhang-wei
zhang-wei

๐Ÿ’ป
zhyon404
zhyon404

๐Ÿ’ป
ๆจๆˆ้”ด
ๆจๆˆ้”ด

๐Ÿ’ป

This project follows the all-contributors specification. Contributions of any kind welcome!

License ๐Ÿ“‹

Apache 2.0

trackgit-views

envd's People

Contributors

alexxi19 avatar allcontributors[bot] avatar arugal avatar aseaday avatar dependabot[bot] avatar dragonly avatar electronic-waste avatar frostming avatar gaocegege avatar github-actions[bot] avatar hezhizhen avatar kaiyang-chen avatar kemingy avatar kenwoodjw avatar lxb1226 avatar n063h avatar oubotong avatar pingsutw avatar rrain7 avatar rudeigerc avatar terrytangyuan avatar tisonkun avatar triple-z avatar vovallen avatar xiaoaier-z-l avatar xing0821 avatar xxchan avatar yvestumushimire avatar zheaoli avatar zwpaper avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

envd's Issues

tech-debt(lang): Refactor IR

Now we use a simple struct to keep the packages and dependencies. It works in most cases. But if users need to run some custom commands, the expression can be hard to support in the current design.

Thus we may need to re-design this in the future.

feat(CLI): Support denpendency sync command

Description

Users may install some new dependencies in the environment and they are not tacked by the declarative manifest file. We need to support a command like MIDI sync to sync the change to the manifest file.

chore(test): Add unit test and integration test

Description

We need set up the test process and add more unit/integration test cases. There are many interfaces in the code, thus it should be easy to mock them and test the main logic.

Acceptance Criteria

  • test for IR and frontend
  • test for cache
  • test for docker client

feat(docker): Support buildkitd moby worker in dockerd 22.06-beta

Description

[+] Building 103.2s (11/11) FINISHED                                                                                                                                                                       
 => docker-image://docker.io/nvidia/cuda:11.2.0-cudnn8-devel-ubuntu20.04                                                                                                                              2.8s
 => => resolve docker.io/nvidia/cuda:11.2.0-cudnn8-devel-ubuntu20.04                                                                                                                                  2.6s
 => local://context                                                                                                                                                                                   3.1s
 => => transferring context: 50.52kB                                                                                                                                                                  0.1s
 => CACHED sh -c apt-get update && apt-get install -y --no-install-recommends python3 python3-pip                                                                                                     0.0s
 => CACHED apt install gcc                                                                                                                                                                            0.0s
 => CACHED pip install -i https://mirror.sjtu.edu.cn/pypi/web/simple jupyter ormb                                                                                                                     0.0s
 => CACHED mkdir /var/midi/remote                                                                                                                                                                     0.0s
 => CACHED mkdir /var/midi/bin                                                                                                                                                                        0.0s
 => CACHED copy /examples/ssh_keypairs/public.pub /var/midi/remote/authorized_keys                                                                                                                    0.0s
 => CACHED copy /bin/midi-ssh /var/midi/bin/midi-ssh                                                                                                                                                  0.0s
 => CACHED merge (apt install gcc, pip install -i https://mirror.sjtu.edu.cn/pypi/web/simple jupyter ormb, copy /bin/midi-ssh /var/midi/bin/midi-ssh)                                                 0.0s
 => exporting to oci image format                                                                                                                                                                    96.6s
 => => exporting layers                                                                                                                                                                               0.0s
 => => exporting manifest sha256:32bbf82b70e17ca70b11b88310ef02450db2bed3b94765415650a2227baa63cf                                                                                                     3.1s
 => => exporting config sha256:9bcaf4d291970033f2a6316dbf11912e77de402c81f0b11896f16c8bab19360b                                                                                                       1.2s
 => => sending tarball                                                                                                                                                                               91.6s

The image is built in buildkit, and it does not exist in the docker host. Thus we need to pipe the buildkit build image into the docker host. It takes about 100s for a 20G base image docker load. It is too slow. We need to optimize it.

feat(lang): Support built-in variables

Description

base(os="ubuntu20.04", language="python3")
print(midi.os)

We need to provide some built-in variables to support conditional build like this

if midi.os == "ubuntu":
    ubuntu_apt_source("xxx")

feat(lang): Support IDE

Description

vscode remote, jupyter and terminal are the most used tools for data scientists to develop models. Thus we need to support them as first-class object.

Feature lists

  • Support vscode remote, jupyter, ssh, and other possible editors
  • Support plugins for editors (e.g. python plugin for vscode remote)
  • Support other configurations for the editors (e.g. TCP port used or jupyter password)
  • Support per-user config. There is no need for users to config in every project
  • Support runtime override. It is to support remote config. Imagine that, you want to create an environment from a manifest file in the remote git repository. But the manifest defines jupyter as the default IDE, but you want to use vscode remote. Runtime override can help you with this.

Acceptance Criteria

bug(lang): Consider a good way to parse vscode plugins

Description

Now we have a simple way to extract the publisher/version/extension from the frontend func calls. But it does not always work

For example dbaeumer.vscode-eslint-1.1.1. Current implementation gets the version eslint-1.1.1

We need to find the right first -, instead of the left first - for indexExtension

func ParsePlugin(p string) (Plugin, error) {
	indexPublisher := strings.Index(p, ".")
	publisher := p[:indexPublisher]
	indexExtension := strings.Index(p[indexPublisher:], "-") + indexPublisher
	extension := p[indexPublisher+1 : indexExtension]
	version := p[indexExtension+1:]
	logrus.WithFields(logrus.Fields{
		"publisher": publisher,
		"extension": extension,
		"version":   version,
	}).Debug("vscode plugin is parsed")
	return Plugin{
		Publisher: publisher,
		Extension: extension,
		Version:   version,
	}, nil
}

chore(fs): Mount file system

To mount the folder into the container, several options available:

  • docker run -v ... We map the host dir to the container at runtime
  • sshfs Use volume plugin to mount the fs through ssh(sftp). Worse performance comparing to -v solution, but works when the container runs on the different machines

feat(CLI): Support build context dir flag

Description

Just like docker build ./subdir, we need to support users to use other dirs instead of the current working dir to build MIDI.

		&cli.PathFlag{
			Name:  "path",
			Usage: "Path to the directory containing the build.MIDI (Default is current directory)",
			Value: ".",
		},

Ref #43 (comment)

feat(lang): Data Volume Mount

Description

Users need to get the data to run the training jobs. Thus the build language needs to support it

Feature lists

  • Runtime fetch. We should not place data in the output artifact. Instead, we fetch the data when the container is initialized.
  • Credentials (per-user maybe) to get the data from S3 or other OSS.

feat(docker): non-root users

Description

Not sure whether we should choose /root/ as the default directory. What's the common practise for the user when using docker? Does people use root or create other users?

#54 (comment)

feat(lang): Support Source Code Management

Description

Code may be one of the first-class objects in the build language. The code will exist in the resulting container and users develop models and update them. After the code is changed, you can commit and push to remote.

CODE:
    GIT SSH /root/.ssh/github-key
    GIT LOCAL $HOME/private-repo
    GIT CLONE [email protected]/tensorchord/private-repo.git
    # TODO: Support branch and commit

Feature lists

  • #23
  • Support public repos
  • SSH keys to support private repos
  • Cache if the repo exists locally

feat(lang): Support package manager mirror

Description

We need to support mirrors in the frontend lang.

apt_source("""
deb https://mirror.sjtu.edu.cn/ubuntu focal main restricted
deb https://mirror.sjtu.edu.cn/ubuntu focal-updates main restricted
deb https://mirror.sjtu.edu.cn/ubuntu focal universe
deb https://mirror.sjtu.edu.cn/ubuntu focal-updates universe
deb https://mirror.sjtu.edu.cn/ubuntu focal multiverse
deb https://mirror.sjtu.edu.cn/ubuntu focal-updates multiverse
deb https://mirror.sjtu.edu.cn/ubuntu focal-backports main restricted universe multiverse
deb http://archive.canonical.com/ubuntu focal partner
deb https://mirror.sjtu.edu.cn/ubuntu focal-security main restricted universe multiverse
""")

Discussion(lang): Expose low-level primitive of buildkit in starlark

Discuss whether we can expose the lower level primitive of buildkit into starlark

For example, the torch installation logic is complex. https://pytorch.org/get-started/locally/

We can write the logic as below, which is quite straightforward

# expose p as the builtin command
def pip_package(name):
    p.cache("/root/.pip/cache")
    p.exec("pip install {}".format(name))

def install_torch():
    if global.cuda_version == '10.2': 
       pip_package("torch torchvision torchaudio")
    elif global.cuda_version == '11.3':
       pip_package("torch torchvision torchaudio --extra-index-url https://download.pytorch.org/whl/cu113")
    elif global.cuda_verion is None:
       pip_package("torch torchvision torchaudio --extra-index-url https://download.pytorch.org/whl/cpu")

@gaocegege

feat(lang): Support SSH

Description

Support ssh with rules to attach into the environment

Ref #1

Feature lists

  • Support setting up the sshd server in the container
  • Port forward from the container to localhost.

chore(README): Prototype the README

We can prototype the desired README although there is no runnable code, to help us understand the benefit of the project and the features that we need.

bug(CLI): midi up does not ssh successfully

Description

I think the sshd server may be not running when the client is trying to connect. We can add some retry to avoid it.

midi up
error: dial to [172.17.0.2:2222](http://172.17.0.2:2222/) failed dial tcp [172.17.0.2:2222](http://172.17.0.2:2222/): connect: connection refused

Additional Info

feat(lang): Install Dependencies

Description

We need to provide built-in support for dependencies.

Feature lists

  • System dependencies
  • PyPI depencies (and conda)
  • Cache

feat(lang): Support Jupyter

Description

Support jupyter to develop.

Feature lists

  • Support jupyter rules
  • Support custom config like port, pwd and so on.

Ref #1

chore(error): Suggest setting env var DOCKER_API_VERSION when docker client fails to create.

Description

We need to init a docker client to load the image into the docker host. But we may got the error here

ERRO[2022-04-21T22:08:35+08:00] failed to load docker image: Error response from daemon: client version 1.42 is too new. Maximum supported API version is 1.41 

We should suggest setting the envvar DOCKER_API_VERSION to avoid the issue when encountering this.

export DOCKER_API_VERSION=1.41

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo 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.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.