Giter VIP home page Giter VIP logo

lile's Introduction

logo

Actions Status

Lile is a application generator (think create-react-app, rails new or django startproject) for gRPC services in Go and a set of tools/libraries.

The primary focus of Lile is to remove the boilerplate when creating new services by creating a basic structure, test examples, Dockerfile, Makefile etc.

Lile comes with basic pre setup with pluggable options for things like...

Installation

Installing Lile is easy, using go get you can install the cmd line app to generate new services and the required libraries. First you'll need Google's Protocol Buffers installed.

$ brew install protobuf
$ go get -u github.com/lileio/lile/...

Guide

Creating a Service

Lile comes with a 'generator' to quickly generate new Lile services.

Lile follows Go's conventions around $GOPATH (see How to Write Go) and is smart enough to parse your new service's name to create the service in the right place.

If your Github username was tessthedog and you wanted to create a new service for posting to Slack you might use the following command.

lile new --name tessthedog/slack

Follow the command line instructions and this will create a new project folder for you with everything you need to continue.

Service Definitions

Lile creates gRPC and therefore uses protocol buffers as the language for describing the service methods, the requests and responses.

I highly recommend reading the Google API Design docs for good advice around general naming of RPC methods and messages and how they might translate to REST/JSON, via the gRPC gateway

An example of a service definition can be found in the Lile example project account_service

service AccountService {
  rpc List (ListAccountsRequest) returns (ListAccountsResponse) {}
  rpc GetById (GetByIdRequest) returns (Account) {}
  rpc GetByEmail (GetByEmailRequest) returns (Account) {}
  rpc AuthenticateByEmail (AuthenticateByEmailRequest) returns (Account) {}
  rpc GeneratePasswordToken (GeneratePasswordTokenRequest) returns (GeneratePasswordTokenResponse) {}
  rpc ResetPassword (ResetPasswordRequest) returns (Account) {}
  rpc ConfirmAccount (ConfirmAccountRequest) returns (Account) {}
  rpc Create (CreateAccountRequest) returns (Account) {}
  rpc Update (UpdateAccountRequest) returns (Account) {}
  rpc Delete (DeleteAccountRequest) returns (google.protobuf.Empty) {}
}

Generating RPC Methods

By default Lile will create a example RPC method and a simple message for request and response.

syntax = "proto3";
option go_package = "github.com/tessthedog/slack";
package slack;

message Request {
  string id = 1;
}

message Response {
  string id = 1;
}

service Slack {
  rpc Read (Request) returns (Response) {}
}

Let's modify this to be a real service and add our own method.

We're going to create an Announce method that will announce a message to a Slack room.

We're assuming that the Slack team and authentication is already handled by the services configuration, so a user of our service only needs to provide a room and their message. The service is going to send the special Empty response, since we only need to know if an error occurred and don't need to know anything else.

Our proto file now looks like this...

syntax = "proto3";
option go_package = "github.com/tessthedog/slack";
import "google/protobuf/empty.proto";
package slack;

message AnnounceRequest {
  string channel = 1;
  string msg = 2;
}

service Slack {
  rpc Announce (AnnounceRequest) returns (google.protobuf.Empty) {}
}

We now run the protoc tool with our file and the Lile method generator plugin.

protoc -I . slack.proto --lile-server_out=. --go_out=plugins=grpc:$GOPATH/src

Handily, Lile provides a Makefile with each project that has a proto build step already configured. So we can just run that.

make proto

We can see that Lile will create two files for us in the server directory.

$ make proto
protoc -I . slack.proto --lile-server_out=. --go_out=plugins=grpc:$GOPATH/src
2017/07/12 15:44:01 [Creating] server/announce.go
2017/07/12 15:44:01 [Creating test] server/announce_test.go

Let's take a look at the announce.go file that's created for us.

package server

import (
    "errors"

    "github.com/golang/protobuf/ptypes/empty"
    "github.com/tessthedog/slack"
    context "golang.org/x/net/context"
)

func (s SlackServer) Announce(ctx context.Context, r *slack.AnnounceRequest) (*empty.Empty, error) {
  return nil, errors.New("not yet implemented")
}

We can now fill in this generated method with the correct implementation. But let's start with a test!

Running & Writing Tests

When you generate an RPC method with Lile a counterpart test file is also created. For example, given our announce.go file, Lile will create announce_test.go in the same directory.

This should look something like the following..

package server

import (
	"testing"

	"github.com/tessthedog/slack"
	"github.com/stretchr/testify/assert"
	context "golang.org/x/net/context"
)

func TestAnnounce(t *testing.T) {
	ctx := context.Background()
	req := &slack.AnnounceRequest{}

	res, err := cli.Announce(ctx, req)
	assert.Nil(t, err)
	assert.NotNil(t, res)
}

You can now run the tests using the Makefile and running make test...

$ make test
=== RUN   TestAnnounce
--- FAIL: TestAnnounce (0.00s)
        Error Trace:    announce_test.go:16
        Error:          Expected nil, but got: &status.statusError{Code:2, Message:"not yet implemented", Details:[]*any.Any(nil)}
        Error Trace:    announce_test.go:17
        Error:          Expected value not to be nil.
FAIL
coverage: 100.0% of statements
FAIL    github.com/tessthedog/slack/server  0.011s
make: *** [test] Error 2

Our test failed because we haven't implemented our method, at the moment we're returning an error of "unimplemented" in our method.

Let's implement the Announce method in announce.go, here's an example using nlopes' slack library.

package server

import (
	"os"
	"google.golang.org/grpc/codes"
	"google.golang.org/grpc/status"

	"github.com/golang/protobuf/ptypes/empty"
	"github.com/tessthedog/slack"
	sl "github.com/nlopes/slack"
	context "golang.org/x/net/context"
)

var api = sl.New(os.Getenv("SLACK_TOKEN"))

func (s SlackServer) Announce(ctx context.Context, r *slack.AnnounceRequest) (*empty.Empty, error) {
	_, _, err := api.PostMessage(r.Channel, r.Msg, sl.PostMessageParameters{})
	if err != nil {
		return nil, status.Errorf(codes.Internal, err.Error())
	}

	return &empty.Empty{}, nil
}

Let's fill out our testing request and then run our tests again...

package server

import (
	"testing"

	"github.com/tessthedog/slack"
	"github.com/stretchr/testify/assert"
	context "golang.org/x/net/context"
)

func TestAnnounce(t *testing.T) {
	ctx := context.Background()
	req := &slack.AnnounceRequest{
		Channel: "@alex",
		Msg:     "hellooo",
	}

	res, err := cli.Announce(ctx, req)
	assert.Nil(t, err)
	assert.NotNil(t, res)
}

Now if I run the tests with my Slack token as an ENV variable, I should see a passing test!

$ alex@slack: SLACK_TOKEN=zbxkkausdkasugdk make test
go test -v ./... -cover
?       github.com/tessthedog/slack [no test files]
=== RUN   TestAnnounce
--- PASS: TestAnnounce (0.32s)
PASS
coverage: 75.0% of statements
ok      github.com/tessthedog/slack/server  0.331s  coverage: 75.0% of statements
?       github.com/tessthedog/slack/slack   [no test files]
?       github.com/tessthedog/slack/slack/cmd       [no test files]
?       github.com/tessthedog/slack/subscribers     [no test files]

Using the Generated cmds

Lile generates a cmd line application based on cobra when you generate your service. You can extend the app with your own cmds or use the built-in cmds to run the service.

Running the cmd line app without any arguments will print the generated help.

For example go run orders/main.go

up

Running up will run both the RPC server and the pubsub subscribers.

go run orders/main.go up

Adding your own cmds

To add your own cmd, you can use the built in generator from cobra which powers Lile's cmds

$ cd orders
$ cobra add import

You can now edit the file generated to create your cmd, cobra will automatically add the cmd's name to the help.

lile's People

Contributors

arbarlow avatar baopham avatar feruzoripov avatar jonbretman avatar jstrachan avatar liukgg avatar mattn avatar mattvagni avatar mrwinstead avatar orisano avatar oz avatar sago35 avatar stuartgrigg avatar warrn 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  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

lile's Issues

Go modules

Hey!

Do you have plans to support Go 1.11 modules ?

Issue trying to install using go get -u github.com/lileio/lile/...

I tried to install the package but the terminal shows this:

# cd /home/user/go/src/google.golang.org/api; git pull --ff-only
From https://github.com/googleapis/google-api-go-client
 * [new branch]      master          -> origin/master
 * [new branch]      release-v0.38.0 -> origin/release-v0.38.0
 * [new tag]               v0              -> v0
 * [new tag]               v0.1.0          -> v0.1.0
 * [new tag]               v0.10.0         -> v0.10.0
 * [new tag]               v0.11.0         -> v0.11.0
 * [new tag]               v0.12.0         -> v0.12.0
 * [new tag]               v0.13.0         -> v0.13.0
 * [new tag]               v0.14.0         -> v0.14.0
 * [new tag]               v0.15.0         -> v0.15.0
 * [new tag]               v0.16.0         -> v0.16.0
 * [new tag]               v0.17.0         -> v0.17.0
 * [new tag]               v0.18.0         -> v0.18.0
 * [new tag]               v0.19.0         -> v0.19.0
 * [new tag]               v0.2.0          -> v0.2.0
 * [new tag]               v0.20.0         -> v0.20.0
 * [new tag]               v0.21.0         -> v0.21.0
 * [new tag]               v0.22.0         -> v0.22.0
 * [new tag]               v0.23.0         -> v0.23.0
 * [new tag]               v0.24.0         -> v0.24.0
 * [new tag]               v0.25.0         -> v0.25.0
 * [new tag]               v0.26.0         -> v0.26.0
 * [new tag]               v0.27.0         -> v0.27.0
 * [new tag]               v0.28.0         -> v0.28.0
 * [new tag]               v0.29.0         -> v0.29.0
 * [new tag]               v0.3.0          -> v0.3.0
 * [new tag]               v0.3.1          -> v0.3.1
 * [new tag]               v0.3.1+alpha    -> v0.3.1+alpha
 * [new tag]               v0.3.1-alpha    -> v0.3.1-alpha
 * [new tag]               v0.3.2          -> v0.3.2
 * [new tag]               v0.30.0         -> v0.30.0
 * [new tag]               v0.31.0         -> v0.31.0
 * [new tag]               v0.32.0         -> v0.32.0
 * [new tag]               v0.33.0         -> v0.33.0
 * [new tag]               v0.34.0         -> v0.34.0
 * [new tag]               v0.35.0         -> v0.35.0
 * [new tag]               v0.36.0         -> v0.36.0
 * [new tag]               v0.37.0         -> v0.37.0
 * [new tag]               v0.4.0          -> v0.4.0
 * [new tag]               v0.5.0          -> v0.5.0
 * [new tag]               v0.6.0          -> v0.6.0
 * [new tag]               v0.7.0          -> v0.7.0
 * [new tag]               v0.8.0          -> v0.8.0
 * [new tag]               v0.9.0          -> v0.9.0
There is no tracking information for the current branch.
Please specify which branch you want to merge with.
See git-pull(1) for details.

    git pull <remote> <branch>

If you wish to set tracking information for this branch you can do so with:

    git branch --set-upstream-to=origin/<branch> master

package google.golang.org/api/iterator: exit status 1
cannot find package "google.golang.org/api/option" in any of:
        /usr/local/go/src/google.golang.org/api/option (from $GOROOT)
        /home/user/go/src/google.golang.org/api/option (from $GOPATH)
cannot find package "google.golang.org/api/option/internaloption" in any of:
        /usr/local/go/src/google.golang.org/api/option/internaloption (from $GOROOT)
        /home/user/go/src/google.golang.org/api/option/internaloption (from $GOPATH)
cannot find package "google.golang.org/api/transport/grpc" in any of:
        /usr/local/go/src/google.golang.org/api/transport/grpc (from $GOROOT)
        /home/user/go/src/google.golang.org/api/transport/grpc (from $GOPATH)
cannot find package "google.golang.org/api/support/bundler" in any of:
        /usr/local/go/src/google.golang.org/api/support/bundler (from $GOROOT)
        /home/user/go/src/google.golang.org/api/support/bundler (from $GOPATH)```

Anything I can do?

Registery ?

Hi!

Could we rename lile.Service.Registery to lile.Service.Registry? I think it's a small typo error. 🐾

I can submit a PR for this too. 😇

Service Discovery integration

As discussed a consul integration would be nice. I am currently looking at a shutdown hook, to deregister the service. I can't seem to find, where do you stop the service?

Question about import other protos

I want to import other protos like import "common/common.proto"; but it shows:

2019/03/20 18:23:02 No go_package option defined for import common/common.proto
--lile-server_out: protoc-gen-lile-server: Plugin failed with status code 1.

once I do not use lile the protoc works fine.

lile new throws [ERROR]: 1:13: expected ';', found '-'

I tried to generate a new service, but got this error:

$ protoc --version
libprotoc 3.5.1

$ lile new arne-cl/grpc-test
Creating project in /home/arne/go/src/github.com/arne-cl/grpc-test
Is this OK? [y]es/[n]o
y
[ERROR]: 1:13: expected ';', found '-'

Interestingly, if I use your example repo name, it works:

$ lile new lileio/slack
Creating project in /home/arne/go/src/github.com/lileio/slack
Is this OK? [y]es/[n]o
y
.
├── server
│   ├── server.go
│   └── server_test.go
├── subscribers
│   └── subscribers.go
├── slack
│   ├── cmd
│   │   ├── root.go
│   │   └── up.go
│   └── main.go
├── slack.proto
├── client.go
├── Makefile
├── Dockerfile
└── .gitignore

make build error

[jinqing@localhost src]$ go get -u github.com/lileio/lile/...
[jinqing@localhost src]$ lile new lileio/users
Creating project in /home/jinqing/go/src/github.com/lileio/users
Is this OK? [y]es/[n]o
y
...
[jinqing@localhost users]$ make build
go build -o build/lileio/users lileio/users/main.go
stat lileio/users/main.go: no such file or directory
make: *** [build] Error 1
[jinqing@localhost users]$ cat Makefile
# vi: ft=make

GOPATH:=$(shell go env GOPATH)

.PHONY: proto test

proto:
        go get github.com/golang/protobuf/protoc-gen-go
        protoc -I . users.proto --lile-server_out=. --go_out=plugins=grpc:${GOPATH}/src

build: proto
        go build -o build/lileio/users lileio/users/main.go

test:
        @go get github.com/rakyll/gotest
        gotest -p 1 -v ./...
[jinqing@localhost users]$ ls
client.go  Dockerfile  Makefile  server  subscribers  users  users.proto
[jinqing@localhost users]$ pwd
/home/jinqing/go/src/github.com/lileio/users
[jinqing@localhost users]$

Adding Client-side code generators and Ask Advise for dependent servers

Let's take a look at your slack example and say we have two server:

  1. ServerOne implements Announce() via gRPC interface (say to announce notif to slack)
  2. ServerTwo needs a server to announce something to slack. It needs to call ServerOne

Well then, I build ServerOne with lileio/lile and get an autogenerated code in Go. Neat and pretty.

How about ServerTwo? Hmmm its a bit tedious because:

  1. To commnicate with ServerOne, developer need to read and understand the proto file of ServerOne. Good thing if ServerOne developers kindly have an API docs.
  2. Then come changes in ServerOne proto file which change the comminication contract between ServerOne and ServerTwo. Then these changes also affect the dependent microservice (ServerTwo)

Ideas

There are two ideas for Go developer to resolve this:

  1. Versioning of API: ServerOne do two version of API: the old schema and new schema. Allowing ServerTwo to slowly migrate.
  2. Autogenerated Client-side: ServerOne can give its protofile to ServerTwo and we can build a code generator for client side.

I want to highlight on the (2) Ideas here and whether it should be supported, what are the Pros and Cons.

Pros

  • Easy migration for dependent services. Using protofile as single source of truth

Cons

  • Generated code in Golang doesn't always adhere to how Go code is written. Some developers think its OK because its an autogenerated code. Hence, if we want this feature we have to make it autgenerated but clean
  • Same problem as above, but this time autogenerated code like that of thrift can yield freaking 50,000 lines of code just
    for 12 endpoints. This pollute the codebase, git commits, and slows down IDE and code intellisense (VSCode, Vim, GoLand, you name it).

Prometheus port is always 9000 in log

We should set the port before log.

        logrus.Infof("Prometheus metrics at :9000/metrics")
	port := "9000"
	if p := os.Getenv("PROMETHEUS_PORT"); p != "" {
		port = p
        }

vendoring lile

I would like to use dep or vgo to vendor the lile framework. unfortunately, both currently fail due to transitive package dependencies.

This is due to a transitive dependency on github.com/apache/thrift/lib/go and github.com/satori/go.uuid, where the authors broke the contract and did not increment the package version. dep ensure and vgo get create broken builds.

satori.uid, where the later version changes the NewV1() signature to return two variables (uid, error)
TProtobuff.Flush(ctx) now takes a context parameter

Would be helpful to include a normative Gopkg.toml/Gopkg.lock, and Go.mod .

I had to adjust the GoPkg files like so:

GoPkg.toml
[[override]]
name = "github.com/apache/thrift"
branch = "master"

[[override]]
name = "github.com/satori/go.uuid"
branch="master"

Running tests on windows isn't supported

Current Behavior

If one tries to run lile-generated tests on Windows, lile will try to use a UNIX socket. This should use something like a named pipe (less realistic, more resilient) or an in-memory transport (more realistic, more complex).

Expected Behavior

Given a lile-generated test suite
When running go test
Then tests will execute successfully on Linux
and the tests will execute successfully on Windows

Allow to use gogo/protobuf (importing files with no go_package)

When I try to use gogo along with lile (protoc -I../vendor -I ../models -I . ecommerce.proto --lile-server_out=. --gogo_out=plugins=grpc:$$GOPATH/src)

I get

2017/09/29 18:35:42 No go_package option defined for import github.com/gogo/protobuf/gogoproto/gogo.proto

Test failed on Windows

D:/Go/bin/go.exe test -v [E:/gopath/src/github.com/jinq0123/users/server]
panic: listen unix /tmp/008531f5-cf69-11e7-a9eb-00ff198f3a8c: socket: An address incompatible with the requested protocol was used.

goroutine 1 [running]:
github.com/lileio/lile.NewTestServer(0xc042020c00, 0x0, 0x0, 0xc042020c00)
	e:/gopath/src/github.com/lileio/lile/lile.go:147 +0x1bb
github.com/jinq0123/users/server.TestMain(0xc04206bf18)
	e:/gopath/src/github.com/jinq0123/users/server/server_test.go:24 +0x73
main.main()
	github.com/jinq0123/users/server/_test/_testmain.go:44 +0xe2
exit status 2
FAIL	github.com/jinq0123/users/server	1.097s

Plugin support

Find a way to enable some sort of "plugin" so for example, an service can be created with a setup cassandra database and migrator or with a JSON gateway

Lile bootstrap does not work as in README

In README:

Getting Started
To generate a new service, run lile new with a short folder path.

$ lile new lileio/users

In real life:

➜  ~ lile new piotrkochan/lile-test
Error: required flag(s) "name" not set

Trying with --name arg as in example (--name string the module name i.e (github.com/username/project):

➜  ~ lile new piotrkochan/lile-test --name "github.com/piotrkochan/lile-test"
Creating project in lile-test
Is this OK? [y]es/[n]o
Y
[...some code output...]
Could not format Go file {client.go lile-test/client.go client.tmpl}
[ERROR]: 1:13: expected ';', found '-'
panic: 1:13: expected ';', found '-'

Other try:

➜  ~ lile new piotrkochan/lile-test --name "github.com/piotrkochan"
Creating project in piotrkochan
Is this OK? [y]es/[n]o
Y
.
├── server
│   ├── server.go
│   └── server_test.go
├── subscribers
│   └── subscribers.go
├── piotrkochan
│   ├── cmd
│   │   ├── root.go
│   │   └── up.go
│   └── main.go
├── piotrkochan.proto
├── client.go
├── Makefile
├── Dockerfile
├── go.mod
└── .gitignore

l➜  ~ pwd
<my home>
l➜  ~ ls -l | grep lile
drwxr-xr-x   4 piotr  staff   128 Nov 20 20:55 lile-test

Generated code is not placed in $GOPATH as described but in the directory I'm currently in (is smart enough to parse your new service's name to create the service in the right place. seems a little bit wrong :))

➜  ~ go version
go version go1.12.5 darwin/amd64

Add TODOs Badge to README

Hi there! I wanted to propose adding the following badge to the README to indicate how many TODO comments are in this codebase:

TODOs

The badge links to tickgit.com which is a free service that indexes and displays TODO comments in public github repos. It can help surface latent work and be a way for contributors to find areas of code to improve, that might not be otherwise documented.

The markdown is:

[![TODOs](https://badgen.net/https/api.tickgit.com/badgen/github.comgithub.com/lileio/lile)](https://www.tickgit.com/browse?repo=github.com/lileio/lile)

Thanks for considering, feel free to close this issue if it's not appropriate or you prefer not to!

GO111MODULE=on go get -u github.com/lileio/lile/... fails

Problem: Running GO111MODULE=on go get -u github.com/lileio/lile/... fails with:

go get: github.com/openzipkin/[email protected] updating to
	github.com/openzipkin/[email protected]: parsing go.mod:
	module declares its path as: github.com/openzipkin-contrib/zipkin-go-opentracing
	        but was required as: github.com/openzipkin/zipkin-go-opentracing

Solutions:

Short Term Fix: I haven't found one, adding the following to go.mod

replace (
	github.com/openzipkin/zipkin-go-opentracing v0.3.4 => github.com/openzipkin-contrib/zipkin-go-opentracing v0.3.4
	github.com/openzipkin/zipkin-go-opentracing v0.4.3 => github.com/openzipkin-contrib/zipkin-go-opentracing v0.4.3
	github.com/openzipkin/zipkin-go-opentracing v0.4.5 => github.com/openzipkin-contrib/zipkin-go-opentracing v0.4.5
)

leads to the following new error

go: github.com/openzipkin-contrib/[email protected] used for two different module paths (github.com/openzipkin-contrib/zipkin-go-opentracing and github.com/openzipkin/zipkin-go-opentracing)

Longer Term Fix:

  • Change dependency name to github.com/openzipkin-contrib/zipkin-go-opentracing and bump version if needed (GO111MODULE=on go get github.com/openzipkin-contrib/zipkin-go-opentracing@latest). Happy to submit a PR if this feels like the right approach.

Cannot compile with lile parameter

I'm trying to run the command: protoc XXXX.proto --lile-server_out=. --go_out=plugins=grpc:.

I get this error:

protoc-gen-lile-server: program not found or is not executable
--lile-server_out: protoc-gen-lile-server: Plugin failed with status code 1.

why? I already have protobuf installed and also run the go get command for lile.

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.