GithubHelp home page GithubHelp logo

ninenines / bullet Goto Github PK

View Code? Open in Web Editor NEW
302.0 302.0 69.0 69 KB

Simple, reliable, efficient streaming for Cowboy.

Home Page: http://ninenines.eu

License: ISC License

Erlang 51.80% JavaScript 47.00% Makefile 1.20%

bullet's People

Contributors

acautin avatar essen avatar fgallaire avatar jdavisp3 avatar jlouis avatar joaohf avatar lpgauth avatar marianoguerra avatar marshall-lee avatar mongws 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

bullet's Issues

bullet and mobile devices

I got bullet working nicely across IE,Firefox and Chrome. The library seems to give up on browsers running on mobile devices, I tried Safari (tested on new IOS on an ipad) Browser (Mozilla) and Chrome running on an android phone. Neither of the transports works, no matter if it is over ssl or not.

As you may have guessed I want to have secure full duplex connection with a long polling and the like fallback if websockets are not available. I thought bullet would be the best for that as n2o uses it.

Can anyone advise whether

  1. There is a way to get bullet working on mobile devices?
  2. Is this something that will be implemented in future?
  3. And, this is slightly on another note, if I get bullet working across all devices and go with it for the production, can I do the usual ensuring of a valid session for every websocket handler request using cookies? If not how else would I do the authorisation?

I looked at sockjs but bullet seems much cleaner, no parse transforms and iframe tricks on the client side?

BTW: very good job! and sorry if this is not the place to post comments like that, if not can you direct me to the relevant place?

Bullet long-polling unexpected behaviour with cowboy 0.8.1+

Bullet master still depends on cowboy 0.8.0, but while trying to upgrade, I've seen unexpected flooding only in long-polling mode.

With using the simple bullet/examples/clock app I get the following

the current working behaviour of long-polling:

~/git/bullet/examples/clock/deps/cowboy (46cce48)  "Update to 0.8.0"

~/git/bullet/examples/clock (master)
$ start.sh
Eshell V5.10.1  (abort with ^G)
1> Point your browser at http://localhost:8080
1> bullet init
1> clock refresh timeout: <<"Sun, 21 Apr 2013 22:34:49 GMT">> <0.156.0>
1> bullet terminate
1> bullet init
1> clock refresh timeout: <<"Sun, 21 Apr 2013 22:34:50 GMT">> <0.157.0>
1> bullet terminate
1> bullet init
1> clock refresh timeout: <<"Sun, 21 Apr 2013 22:34:52 GMT">> <0.158.0>
1> bullet terminate
1> bullet init
1> clock refresh timeout: <<"Sun, 21 Apr 2013 22:34:53 GMT">> <0.159.0>
1> bullet terminate
1> bullet init
1> clock refresh timeout: <<"Sun, 21 Apr 2013 22:34:54 GMT">> <0.160.0>
1> bullet terminate
1> bullet init
1> clock refresh timeout: <<"Sun, 21 Apr 2013 22:34:55 GMT">> <0.161.0>
1> bullet terminate
1> bullet init
1> clock refresh timeout: <<"Sun, 21 Apr 2013 22:34:57 GMT">> <0.162.0>
1> bullet terminate
1> bullet init
1> clock refresh timeout: <<"Sun, 21 Apr 2013 22:34:58 GMT">> <0.163.0>
1> bullet terminate
1> bullet init
1> clock refresh timeout: <<"Sun, 21 Apr 2013 22:34:59 GMT">> <0.164.0>
1> bullet terminate
1> bullet init
1> clock refresh timeout: <<"Sun, 21 Apr 2013 22:35:00 GMT">> <0.165.0>
1> bullet terminate
1>

then testing with cowboy master, or just after commit 3ea8551:
the handler gives a first reply as expected, after it starts fllooding, with more than 1 response

~/git/bullet/examples/clock/deps/cowboy (3ea8551)  "Make sure socket is passive once we've done with loop handler"

~/git/bullet/examples/clock (master)
$ start.sh
Eshell V5.10.1  (abort with ^G)
1> Point your browser at http://localhost:8080
1> bullet init
1> clock refresh timeout: <<"Sun, 21 Apr 2013 22:40:46 GMT">> <0.156.0>
1> bullet terminate
1> bullet init
1> clock refresh timeout: <<"Sun, 21 Apr 2013 22:40:47 GMT">> <0.156.0>
1> bullet terminate
1> bullet init
1> clock refresh timeout: <<"Sun, 21 Apr 2013 22:40:47 GMT">> <0.156.0>
1> bullet terminate
1> bullet init
1> clock refresh timeout: <<"Sun, 21 Apr 2013 22:40:48 GMT">> <0.156.0>
1> bullet terminate
1> bullet init
1> clock refresh timeout: <<"Sun, 21 Apr 2013 22:40:48 GMT">> <0.156.0>
1> bullet terminate
1> bullet init
1> clock refresh timeout: <<"Sun, 21 Apr 2013 22:40:48 GMT">> <0.156.0>
1> bullet terminate
1> bullet init
1> clock refresh timeout: <<"Sun, 21 Apr 2013 22:40:48 GMT">> <0.156.0>
1> bullet terminate
1> bullet init
1> clock refresh timeout: <<"Sun, 21 Apr 2013 22:40:49 GMT">> <0.156.0>
1> bullet terminate
1> bullet init
1> clock refresh timeout: <<"Sun, 21 Apr 2013 22:40:49 GMT">> <0.156.0>
1> bullet terminate
1> bullet init
1> clock refresh timeout: <<"Sun, 21 Apr 2013 22:40:49 GMT">> <0.156.0>
1> bullet terminate
1> bullet init
1> clock refresh timeout: <<"Sun, 21 Apr 2013 22:40:49 GMT">> <0.156.0>
1> bullet terminate
1> bullet init
1> clock refresh timeout: <<"Sun, 21 Apr 2013 22:40:49 GMT">> <0.156.0>
1> bullet terminate
1> bullet init
1> clock refresh timeout: <<"Sun, 21 Apr 2013 22:40:49 GMT">> <0.156.0>
1> bullet terminate
1> bullet init
1> clock refresh timeout: <<"Sun, 21 Apr 2013 22:40:49 GMT">> <0.156.0>
1> bullet terminate
1> bullet init
1> clock refresh timeout: <<"Sun, 21 Apr 2013 22:40:50 GMT">> <0.156.0>
1> bullet terminate
1>

handle/3 incorrectly matches an atom rather than a binary

In testing long polling locally in an implementation that uses Bullet, I noticed I received server errors in bullet_handler whenever the client attempted to send data. In tracing it down, it appears that line 80 in bullet_handler,

handle(Req, State=#state{handler=Handler, handler_state=HandlerState},
'POST')

should instead be

handle(Req, State=#state{handler=Handler, handler_state=HandlerState},
<<"POST">>)

Error test websocket o heroku

I try start this example on heroku and when i chek WebSocket i have this error:

 =ERROR REPORT==== 13-Dec-2013::06:58:43 ===
Error in process <0.1286.0> with exit value: {[{reason,function_clause},{mfa,{bullet_handler,init,3}},{stacktrace,[
{bullet_handler,get_mode,[undefined,{http_req,#Port<0.2750>,ranch_tcp,close,<0.1286.0>,<<3 bytes>>,'HTTP/1.1',
{{10,238,165,77},39733},<<22 bytes>>,undefined,80,<<7 bytes>>,undefined,<<0 bytes>>,undefined,[],[{<<15 bytes>>,
<<13 bytes>>},{<<17 bytes>>,<<4 bytes>>},{<<15 bytes>>,<<25 bytes>>},{<<3 bytes>>,<<28 bytes>>},{<<10 bytes>>,
<<101 bytes>>},{<<21 bytes>>,...
 =ERROR REPORT==== 13-Dec-2013::06:58:43 ===
Ranch listener http had connection process started with cowboy_protocol:start_link/4 at <0.1286.0> exit with reason
: {[{reason,function_clause},{mfa,{bullet_handler,init,3}},{stacktrace,[{bullet_handler,get_mode,[undefined,
{http_req,#Port<0.2750>,ranch_tcp,close,<0.1286.0>,<<"GET">>,'HTTP/1.1',{{10,238,165,77},39733},
<<"uucs1.herokuapp.com">>,undefined,80,<<"/bullet">>,undefined,<<>>,undefined,[],[{<<"x-request-start">>,<<"13869
17923765">>},{<<"x-forwarded-proto">>,<<"http">>},{<<"x-forwarded-for">>,<<"197.8.155.61, 192.168.0.99">>},
{<<"via">>,<<"1.1 wall.local (squid/3.3.9)">>},{<<"user-agent">>,<<"Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, 
like Gecko) Chrome/31.0.1650.63 Safari/537.36">>},{<<"sec-websocket-version">>,<<"13">>},{<<"sec-websocket-key">>,
<<"AlfdfQ9Z08d4WncgR4qQsw==">>},{<<"sec-websocket-extensions">>,<<"x-webkit-deflate-frame">>},{<<"pragma">>,
<<"no-cache">>},{<<"origin">>,<<"http://uucs1.herokuapp.com">>},{<<"host">>,<<"uucs1.herokuapp.com">>}
,{<<"connection">>,<<"close">>},{<<"cache-control">>,<<"no-cache">>}],[{<<"accept">>,undefined},{<<"connection">>,
[<<"close">>]}],undefined,[],waiting,undefined,<<>>,false,waiting,[],<<>>,undefined}],[{file,"src/bullet_handler.erl"},{line,175}]},
{bullet_handler,init,4,[{file,"src/bullet_handler.erl"},{line,57}]},{cowboy_handler,handler_init,4,[{file,"src/cowboy_handler.erl"},{line
,69}]},{cowboy_protocol,execute,4,[{file,"src/cowboy_protocol.erl"},{line,529}]}]},{req,[{socket,#Port<0.2750>},{transport,ranch_tcp},
{connection,close},{pid,<0.1286.0>},{method,<<"GET">>},{version,'HTTP/1.1'},{peer,{{10,238,165,77},39733}},{host,<<"uucs1.
herokuapp.com">>},{host_info,undefined},{port,80},{path,<<"/bullet">>},{path_info,undefined},{qs,<<>>},{qs_vals,undefined},
{bindings,[]},{headers,[{<<"x-request-start">>,<<"1386917923765">>},{<<"x-forwarded-proto">>,<<"http">>},
{<<"x-forwarded-for">>,<<"197.8.155.61, 192.168.0.99">>},{<<"via">>,<<"1.1wall.local (squid/3.3.9)">>},{<<"user-agent">>,
<<"Mozilla/5.0 (Windows NT 6.1)AppleWebKit/537.36 (KHTML, like Gecko) Chrome/31.0.1650.63 Safari/537.36">>},
{<<"sec-websocket-version">>,<<"13">>},{<<"sec-websocket-key">>,<<"AlfdfQ9Z08d4WncgR4qQsw==">>},
{<<"sec-websocket-extensions">>,<<"x-webkit-deflate-frame">>},{<<"pragma">>,<<"no-cache">>},{<<"origin">>,
<<"http://uucs1.herokuapp.com">>},{<<"host">>,<<"uucs1.herokuapp.com">>},{<<"connection">>,<<"close">>},
{<<"cache-control">>,<<"no-cache">>}]},{p_headers,[{<<"connection">>,[<<"close">>]}]},{cookies,undefined},{meta,[]},
{body_state,waiting},{multipart,undefined},{buffer,<<>>},{resp_compress,false},{resp_state,waiting},{resp_headers,[]},
{resp_body,<<>>},{onresponse,undefined}]},{opts,[{handler,stream_handler}]}],[{cowboy_protocol,execute,4,
[{file,"src/cowboy_protocol.erl"},{line,529}]}]}

way to shutdown connection on info when using eventsource

when Handler:info is called and the message received requires to shutdown the connection it can be done on COMET (reply some empty thing), on websocket return shutdown https://github.com/ninenines/bullet/blob/master/src/bullet_handler.erl#L136 but not with eventsource (sse).

what I propose is to allow eventsource to reply shutdown and add a new case clause here https://github.com/ninenines/bullet/blob/master/src/bullet_handler.erl#L107 with

{shutdown, Req2, HandlerState2} when GetMode == eventsource -> {ok, Req2, State2}

it could also handle the case where GetMode == poll by replying 204.

will you accept the pull request? if so, only for eventsource or for poll too?
do you recommend an alternative way?

Close connection with 'stream' and 'info' callback return values, like with 'init'

The connection can be closed from the 'init' callback by replying with 'shutdown', but this option is not available for the 'stream' and 'info' callbacks. There does not seem to be any way to do it from those callbacks.

As far as I can tell, once a connection is opened, after 'init' returns, there is no way for the server to close that connection. It stays open forever until closed by the client. Unless there is some indirect method based on the connection's PID or by altering the callback's returned Req value, but I was not able to find a way using either of those methods.

handle close more gracefully

right now it crashes on a bad match and my logs have a lot of entries like this:

2015-07-13 11:54:01.305 [error] emulator Error in process <0.16957.914> on node '[email protected]' with exit value: {[{reason,{badmatch,{error,closed}}},{mfa,{bullet_handler,info,3}},{stacktrace,[{bullet_handler,reply_get_mode,3,[{file,"src/bullet_handler.erl"},{line,201}]},{bullet_handler,info,3,[{file,"src/bullet_handler.erl"},{line...

I would do the change, it's matching against close here: https://github.com/extend/bullet/blob/master/src/bullet_handler.erl#L201

the thing is that I don't know what to do when I get a close, maybe add a new return value and match it here: https://github.com/extend/bullet/blob/master/src/bullet_handler.erl#L112 and then stop?

badmatch in clock example

Compile and run the clock example from Ubuntu and I get.

The plain cowboy samples work (and a lot of others).

mattias@ubuntu:~/erl-src/erlang/bullet/examples/clock$ rebar get-deps compile
==> cowlib (get-deps)
==> ranch (get-deps)
==> cowboy (get-deps)
==> bullet (get-deps)
==> clock (get-deps)
==> cowlib (compile)
==> ranch (compile)
==> cowboy (compile)
==> bullet (compile)
==> clock (compile)
mattias@ubuntu:~/erl-src/erlang/bullet/examples/clock$ ./start.sh 
Erlang R16B03-1 (erts-5.10.4) [source] [64-bit] [smp:2:2] [async-threads:10] [hipe] [kernel-poll:false]

Eshell V5.10.4  (abort with ^G)
1> {"init terminating in do_boot",{{badmatch,{error,{bad_return,{{clock_app,start,[normal,[]]},{'EXIT',{{badmatch,{error,{{shutdown,{failed_to_start_child,ranch_acceptors_sup,{{badmatch,{error,eaddrinuse}},[{ranch_acceptors_sup,init,1,[{file,"src/ranch_acceptors_sup.erl"},{line,38}]},{supervisor,init,1,[{file,"supervisor.erl"},{line,239}]},{gen_server,init_it,6,[{file,"gen_server.erl"},{line,304}]},{proc_lib,init_p_do_apply,3,[{file,"proc_lib.erl"},{line,239}]}]}}},{child,undefined,{ranch_listener_sup,http},{ranch_listener_sup,start_link,[http,100,ranch_tcp,[{port,8080}],cowboy_protocol,[{env,[{dispatch,[{'_',[],[{[],[],toppage_handler,[]},{[<<6 bytes>>],[],bullet_handler,[{handler,stream_handler}]},{[<<6 bytes>>,'...'],[],cowboy_static,{priv_dir,bullet,[]}}]}]}]}]]},permanent,5000,supervisor,[ranch_listener_sup]}}}},[{clock_app,start,2,[{file,"src/clock_app.erl"},{line,21}]},{application_master,start_it_old,4,[{file,"application_master.erl"},{line,269}]}]}}}}}},[{clock,start,0,[{file,"src/clock.erl"},{line,27}]},{init,start_it,1,[]},{init,start_em,1,[]}]}}

Crash dump was written to: erl_crash.dump
init terminating in do_boot ()
mattias@ubuntu:~/erl-src/erlang/bullet/examples/clock$ 

clock example is not working

The clock example is not working as is. Raising issue as per suggestion from essen in irc/erlang.

The issue is in the line lines below

{"/static/[...]", cowboy_static, [
{directory, {priv_dir, bullet, []}},
{mimetypes, [
{<<".js">>, [<<"application/javascript">>]}
]}
]}

Long polling support for CORS

Currently Bullet offers no cross origin support for the long polling fallback. I'm not sure it makes sense to add this (all browsers other than IE have supported websockets for the past 9 months, and IE 10 supports it natively so it's only a matter of time before it is made obsolete), but adding it would not be hard, and it seems like it could be an interesting WTF for a developer in the mean time if they were lackadaisical in testing the long polling fallback in a cross domain context.

Adding it would not be difficult, however, to what extent user participation should be required would need to be decided upon.

Essentially, the bullet_handler would need to accept an "OPTIONS" request, that returns a response with the header "Access-Control-Allow-Origin", and the domain(s) to allow as the value, as well as a "Access-Control-Allow-Headers" with the headers the response needs as declared in the request header "Access-Control-Request-Headers" (by default; it might also make sense to allow the user to configure this should they need to). The "Access-Control-Allow-Origin" header would need to be supplied for the POST as well.

I'd not be averse to taking a stab at implementing this on a fork, but it begs the question, A. What should the interface look like, and B. Should restricting the allowed domains also be included as part of the websocket connection? I.e., the handler to supply to Bullet has an optional function to declare the allowed domains, otherwise it defaults to all. Then use that for the CORS header value in case of long polling, as well as check against it before allowing a websocket connection to be opened.

No fallback for ERR_TUNNEL_CONNECTION_FAILED

I am getting:
WebSocket connection to 'ws://xxx.xxx.xxxx.xxxx:8000/path' failed: Error in connection establishment: net::ERR_TUNNEL_CONNECTION_FAILED
on line 223:
var ret = new t.transport(url);

Would be nice if bullet detected the error and fell back onto xhr...

Spdy fallback

Would be nice if bullet attempted spdy first before falling back onto ws and http. If not possible please advise what would have to be changed in Cowboy first.

How to "split channels"

I'm conscious it's a bit of a newbie question but what would be the best way to achieve this :
Let's imagine that each user connected has its own process, what's the best way to link one ( or multiple bullet handlers depending on the opened tabs / browser of the user ) bullet handler to the user process ?

erlang / utf / bullet

When using https://raw.github.com/extend/bullet/master/src/bullet_handler.erl

I get an error of:

src/bullet_handler.erl:5: cannot parse file, giving up
src/bullet_handler.erl:5: cannot translate from UTF-8

(I reordered the lines so that it looked like:

-module(bullet_handler).
-behaviour(cowboy_http_handler).
-behaviour(cowboy_websocket_handler).

%% Copyright (c) 2011-2012, Loic Hoguin [email protected]
%%
%% Permission to use, copy, modify, and/or distribute this software for any
%% purpose with or without fee is hereby granted, provided that the above
%% copyright notice and this permission notice appear in all copies.

)

Anyway, the problem is that erlang (r17-rc2 on Ubuntu 64) seems to
dislike the " ï " in Loic, and changing it to " i " fixed it.

WebSocket die after 60 seconds of nothing

In Chrome/Safari - after 60 seconds without message - websocket will be closed.

It's bug, or feature? Or without "ping-pong" - no chance to have undead websocket connect?

Not Working On Android Tablet

hi guys,

I tested clock example on my android tablet with the stock browser and it doesn't work. It says "bullet not started". Isn't bullet supposed to work on browsers that don't support websockets?

Encoding issue in bullet_handler

When we have dependency on bullet, the below error is shown after rebar downloads dependencies and compiles. The error goes away after adding the mentioned latin-1 inline as the first line. The file should basically be with UTF-8 encoding or the mentioned latin-1 line should be added in repository so that this error need not be fixed by every individual after reps are downloaded.

src/bullet_handler.erl:1: Non-UTF-8 character(s) detected, but no encoding declared. Encode the file in UTF-8 or add "%% coding: latin-1" at the beginning of the file. Retrying with latin-1 encoding.

Event "OnDisconnect"

(As for me) must happened once.

Now - this event happened every time after unsuccessful connection.

I just add boolean variable for check status - (if we lost connection - we run ondisconnect. If we had "no connection" and lost connect - it's not "OnDisconnect")

(Sorry for my english)

Reconnect

How to make reconnect on easy way?

When I made connect, then off/on server - I didn't saw onerror handler. Just error. And no auto reconnect on this way.

Error handler doesn't working?

Better solution - restart bullet when I don't take "ping-pong timestamp" from server more then N seconds?

Q: Debugging WebSockets with CURL

My WebSocketon web page based on javascript and Bullet.js work fine! thank you @essen
But i have any problem...
How i may debugging WebSockets server based on Bullet with CURL
how to send a command to test server WebSocket bullet?
I try this:

curl -i -N -H "Connection: Upgrade" \
-H "Upgrade: websocket" \
http://websocket1.herokuapp.com/bullet/

but get in return this:

HTTP/1.1 400 Bad Request
Server: Cowboy
Date: Sun, 05 Jan 2014 11:41:10 GMT
Content-Length: 0
Connection: close

[Suggestion] upgrade to use cowboy 2

I'm new to bullet, the demo is impressive.
However, when I try to plug in bullet into my project, I realise it is depending on cowboy 1, and erlang vm doesn't allow nested dependency like nodejs do (only flat dependecies). So, to gain the performance improvement from cowboy 2, I've to not use bullet for now.

DOM Exception 11

Hello,

I'm trying to implement communication between server and client using bullet but i have the following error when i call bullet.send('some-text') :

Error: InvalidStateError: DOM Exception 11
Error: An attempt was made to use an object that is not, or is no longer, usable.

This exception is thrown by the line 253 in bullet.js

this.send = function(data){
    return transport.send(data);
};

I can use bullet.send in bullet.onopen only. Is it normal ? Should we use ajax requests to send to the server at any time ?

Thank you

behaviour cowboy_http_handler undefined

Using erlang.mk in my project with Cowboy and Bullet as dependencies.

ERLC   bullet_handler.erl
compile: warnings being treated as errors
src/bullet_handler.erl:16: behaviour cowboy_http_handler undefined
src/bullet_handler.erl:17: behaviour cowboy_websocket_handler undefined
make[1]: *** [ebin/bullet.app] Error 1

Tip: Would be nice if localhost wasn't hardcoded in the clock example

In toppage_handler.erl there is a row

bullet = $.bullet('ws://localhost:8080/bullet', options);

So, if you want to try with other clients on other computers, you will just get "offline".

Confuses newbies like me. Nice to be able to compare difference browers, like IE11, which doesn't support "eventsource only".

No correct transport switch in FireFox 13.0.1

We got an error in FireFox when put bullet after nginx:

Firefox can't establish a connection to the server at ws://demo/pull/connect/.

Then a lots of:

Firefox can't establish a connection to the server at ws://demo/pull/connect/.
var ret = new t.transport(url);

(Like 20th attempt).

Then, we've got a same XHR instance works in "parallels mode"
Sounds like troubles with switch transport to XHR, because nginx doesn't support websockets yet.

Add some example, please

Loïc. Would You be so kindly to add some example of usage for this code?

How should handler properly behave on once/false flags, etc?

No nextpoll() after POST

I think, you forgot to add this:

in "success" key in post (XHR)

if (fake.readyState == OPEN){
nextPoll();
}

Without this "if" we send data (by POST) and lost connect.

Sorry - don't find how to send Pull Request to you ;)

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.