Git Product home page Git Product logo

em-proxy's Introduction

https://metrics.lecoq.io/igrigorik

em-proxy's People

Contributors

dblock avatar dsander avatar evilsocket avatar germano0 avatar iffyuva avatar igrigorik avatar imbriaco avatar karmi avatar kostya avatar olemchls avatar syd 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

em-proxy's Issues

No eventmachine 1.0 support?

Hi,

I am attempting to install em-proxy via 'gem install em-proxy' but it fails with:

gem install em-proxy

Building native extensions. This could take a while...
ERROR: Error installing em-proxy:
em-proxy requires eventmachine (>= 0)

I have installed eventmachine with 'gem install eventmachine' and it is version 1.0.3.

gem install eventmachine

Building native extensions. This could take a while...
Successfully installed eventmachine-1.0.3
1 gem installed
Installing ri documentation for eventmachine-1.0.3...
Building YARD (yri) index for eventmachine-1.0.3...
Installing RDoc documentation for eventmachine-1.0.3...

Any thoughts?

Early binding for proxy port

I am not sure whether this is a feature request or I'm doing something wrong :)

Trying to put a thin server behind a proxy (code almost identical to one in this post or this repo).

What I am seeing is that the proxy binds to the external port only once it was able to open a connection to the server it's proxying to, which for my purposes is too late. What I am trying to do is to start accepting requests and fail those until the backend comes up. Can this be accomplished?

Spec: duplex TCP traffic to two backends google & yahoo is hanging

The spec in spec/proxy_spec.rb:64 is hanging.

it "should duplex TCP traffic to two backends google & yahoo" do
    EM.run do
      EventMachine.add_timer(0.1) do
        EventMachine::HttpRequest.new('http://127.0.0.1:8080/test').get({:timeout => 1})
      end

      Proxy.start(:host => "0.0.0.0", :port => 8080) do |conn|
        conn.server :bing, :host => "google.com", :port => 80
        conn.server :yhoo, :host => "yahoo.com", :port => 80
        conn.on_data { |data| data }

        seen = []
        conn.on_response do |backend, resp|
          case backend
          when :goog then
            resp.should =~ /404/
            seen.push backend
          when :yhoo
            resp.should =~ /404/
            seen.push backend
          end
          seen.uniq!

          EventMachine.stop if seen.size == 2
        end
      end
    end
  end

I've corrected the conn.server :bing above to be :goog, but I think the actual duplex mechanism is broken - you get the first response with :goog, but never the second one with :yhoo.

2 network

I have 2 network and would like using a one browser to load files, web pages.
Is possible to using 2 different ip as one in this same time?
for example 2 providers
10.0.0.1 one default routing
and 10.0.0.2 for other default routing

undefined local variable or method `unbind' for main:Object

Tested with ruby 1.8.7 through 1.9.2 I get the following error when I run the example from the README.rdoc (with modified destination IP/port) after the first connection has been forwarded:

./rmineproxy.rb:25:in `block (2 levels) in <main>': undefined local variable or method `unbind' for main:Object (NameError)
from /home/mfischer/.rvm/gems/ruby-1.9.2-p0/gems/em-proxy-0.1.3/lib/em-proxy/connection.rb:96:in `call'
from /home/mfischer/.rvm/gems/ruby-1.9.2-p0/gems/em-proxy-0.1.3/lib/em-proxy/connection.rb:96:in `unbind_backend'
from /home/mfischer/.rvm/gems/ruby-1.9.2-p0/gems/em-proxy-0.1.3/lib/em-proxy/backend.rb:34:in `unbind'
from /home/mfischer/.rvm/gems/ruby-1.9.2-p0/gems/eventmachine-0.12.10/lib/eventmachine.rb:1417:in `event_callback'
from /home/mfischer/.rvm/gems/ruby-1.9.2-p0/gems/eventmachine-0.12.10/lib/eventmachine.rb:256:in `run_machine'
from /home/mfischer/.rvm/gems/ruby-1.9.2-p0/gems/eventmachine-0.12.10/lib/eventmachine.rb:256:in `run'
from /home/mfischer/.rvm/gems/ruby-1.9.2-p0/gems/em-proxy-0.1.3/lib/em-proxy/proxy.rb:5:in `start'
from ./rmineproxy.rb:5:in `<main>'

This is on Ubuntu 10.04.

Em proxy with Em Websocket

It would be nice to add an example of how to use em-proxy with em-websocket (to handle websocket queries). Thanks :)

Skip proxying and just send a response

I'm trying to implement a basic reverse proxy, and mostly got it working, it uses a regular expression to pull the Host field from the request and picks a local server to proxy from based on that. I would like it if it doesn't find a server based on that regular expression, to simply reply with a 404 or "it works" or something. But it won't let me not configure a server, I get:

home/vince/.gem/ruby/2.1.3/gems/em-proxy-0.1.8/lib/em-proxy/connection.rb:31:in `relay_to_servers': undefined method `collect' for nil:NilClass (NoMethodError)

Is there a way to get it to just stop and return a response?

Can't proxy to pow's domains

Hello,

I have an app setup with pow(http://foo.dev) and try to use em-proxy to proxy to it like this:

em-proxy -l 8080 -r foo.dev:80

But it proxy me to the local home page of pow (http://localhost) instead. Looks like the domain name has been resolved to 127.0.0.1 before it's passed to pow.

Thanks,
Owen

HTTPProxy Example Incorrect

I am new the EventMachien and em-proxy but, it doesn't take long to realize that the HTTPProxy example is either incorrect or not robust enough for actual use.

I ran the proxy and then accessed Google Maps in my web browser and the results were very interesting. Various images were swapped and loaded incorrectly. I tried a variety of other sites and the same problem kept appearing. It seems that the proxy was sending the wrong response for the requests. If the web page requested an icon picture, it might return the profile picture instead.

It would be really helpful if this example could be updated to be more robust. In it's current state, it is a poor example. I would like to contribute to this example. However, I have unfortunately been banging my head against the wall for too long now and have moved on to using the Webrick HTTPProxy for now as it serves my current needs well. I'm am not sure how to approach this problem and will not know until I take more time to learn EventMachine (a relatively new item on my list).

Select backend on request data

I'm starting to understand that maybe this is not possible, but I need to know for sure.
It's possible to select a backend based on the value of a params request or/and Header value?

I know some proxies do this, that's why we have sticky session, but for what I have been trying, em-proxy start to relay data to the backend as soon as it receives it.

Is there anyway to implement this with em-proxy?

Conditional Relaying

Please forgive my English. I'm looking at the load -balancing example, and try to write a proxy that only sends to one of the backend based on the client source IP. Is this even possible with em-proxy?

NoMethodError: undefined method `on_headers_complete=' for #<Http::NativeParser

Hi i'm having an issue with the http_proxy.rb.

when i run

ruby http_proxy.rb 

the proxy starts up, but when i make a call of

curl --proxy localhost:9889 www.google.com

I get an error on the request

curl: (52) Empty reply from server

And the stack track is

listening on 0.0.0.0:9889...
http_proxy.rb:16: undefined method `on_headers_complete=' for #<Http::NativeParser:0x1012ffd30> (NoMethodError)
    from /Users/dima/.rvm/gems/ree-1.8.7-2011.03@em-proxy/gems/em-proxy-0.1.6/lib/../lib/em-proxy/proxy.rb:12:in `instance_eval'
    from /Users/dima/.rvm/gems/ree-1.8.7-2011.03@em-proxy/gems/em-proxy-0.1.6/lib/../lib/em-proxy/proxy.rb:12:in `start'
    from /Users/dima/.rvm/gems/ree-1.8.7-2011.03@em-proxy/gems/eventmachine-1.0.0.beta.4/lib/eventmachine.rb:1418:in `call'
    from /Users/dima/.rvm/gems/ree-1.8.7-2011.03@em-proxy/gems/eventmachine-1.0.0.beta.4/lib/eventmachine.rb:1418:in `event_callback'
    from /Users/dima/.rvm/gems/ree-1.8.7-2011.03@em-proxy/gems/eventmachine-1.0.0.beta.4/lib/eventmachine.rb:179:in `run_machine'
    from /Users/dima/.rvm/gems/ree-1.8.7-2011.03@em-proxy/gems/eventmachine-1.0.0.beta.4/lib/eventmachine.rb:179:in `run'
    from /Users/dima/.rvm/gems/ree-1.8.7-2011.03@em-proxy/gems/em-proxy-0.1.6/lib/../lib/em-proxy/proxy.rb:5:in `start'
    from http_proxy.rb:13

i did do the

gem install http_parser.rb

as was recomended in the file, but not sure why it's not working.

Thanks.

Question, not Issue, about UDP

What other changes than opening UDP port (EventMachine::open_datagram_socket) will it take to proxy UDP traffic? Thanks.

Backend Errors

Currently, I don't believe there's a way to know if a connection was unbound from the backend due to a connection error.

I think that the Backend class should have an unbind method that looks like this:

 def unbind
    debug [@name, :unbind]
    @plexer.unbind_backend(@name, error?)
 end

Finally, the Connection class should be:

 def unbind_backend(name, error)
    debug [:unbind_backend, name, error]
    @servers[name] = nil

    # if all connections are terminated downstream, then notify client
    close_connection_after_writing if @servers.values.compact.size.zero?

    if @on_finish
      @on_finish.call(name, error)

      # not sure if this is required
      # @on_finish.call(:done) if @servers.values.compact.size.zero?
    end
  end

Thanks!
Mike

http_proxy.rb -- invalid request URI

Unfortunately, http_proxy.rb example have bug when used with HTTP/1.0 servers, because, it does not strip http://server prefix from the proxied HTTP request. As a consequence, some web servers return 400 Bad Request invalid request URI error.

When HTTP proxy requested with GET http://server/uri HTTP/1.0 it should pass to real server GET /uri HTTP/1.0. RFC1945: "The absoluteURI form is only allowed when the request is being made to a proxy." Thus, to real servers absoluteURI is not allowed.

http_proxy.rb -- breaking proxy request by adding/duplicating data

When proxying, I get additional "\r\n" added at the end of headers, which break request to sensitive servers (like Icecast Streaming Media Server).

How to reproduce:

I download this version of http_proxy.rb (latest):
https://github.com/igrigorik/em-proxy/blob/443da1df719ea62b6803dbf4f605a79da3b01f72/examples/http_proxy.rb

To make it work on ruby 1.8 (which is default on Centos 6) I only add this code at the top:

require 'rubygems'
class String
  instance_method(:clear) rescue \
  def clear
    replace ""
  end
end

Then run ruby http_proxy.rb, otherwise unmodified, and and check packet data with tcpdump -X.

Also, for bug visibility I modify /usr/lib/ruby/gems/1.8/gems/em-proxy-0.1.8/lib/em-proxy/connection.rb by adding into relay_to_servers() debugging p [:relay_to_servers, data] before s.send_data loop like this:

      def relay_to_servers(processed)
        if processed.is_a? Array
          data, servers = *processed

          # guard for "unbound" servers
          servers = servers.collect {|s| @servers[s]}.compact
        else
          data = processed
          servers ||= @servers.values.compact
        end

p [:relay_to_servers, data] # <-- debugging for your pleasure
        servers.each do |s|
          s.send_data data unless data.nil?
        end
      end

Then, I connect to proxy and copy-paste simple request, like this:

$ telnet proxy 9889
GET http://www.google.com/test HTTP/1.1
Host: www.google.com
Proxy-Connection: keep-alive
Cache-Control: max-age=0
Accept: */*
User-Agent: Mozilla/5.0 (Windows NT 5.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/47.0.2526.106 Safari/537.36
DNT: 1
Accept-Encoding: gzip, deflate, sdch
Accept-Language: en-US,en;q=0.8,ru;q=0.6,es;q=0.4

(Request headers are taken from real browser request.)

Results

This is what I see in the stdout:

# ruby http_proxy.rb
listening on 0.0.0.0:9889...
[:relay_to_servers, "GET http://www.google.com/test HTTP/1.1\r\n"]
[:relay_to_servers, "Host: www.google.com\r\n"]
[:relay_to_servers, "Proxy-Connection: keep-alive\r\n"]
[:relay_to_servers, "Cache-Control: max-age=0\r\n"]
[:relay_to_servers, "Accept: */*\r\n"]
[:relay_to_servers, "User-Agent: Mozilla/5.0 (Windows NT 5.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/47.0.2526.106 Safari/537.36\r\n"]
[:relay_to_servers, "DNT: 1\r\n"]
[:relay_to_servers, "Accept-Encoding: gzip, deflate, sdch\r\n"]
[:relay_to_servers, "Accept-Language: en-US,en;q=0.8,ru;q=0.6,es;q=0.4\r\n"]
New session: 7bffb510-9687-0133-c161-0dc54655ffbe ({"Accept-Encoding"=>"gzip, deflate, sdch", "Host"=>"www.google.com", "Cache-Control"=>"max-age=0", "DNT"=>"1", "User-Agent"=>"Mozilla/5.0 (Windows NT 5.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/47.0.2526.106 Safari/537.36", "Proxy-Connection"=>"keep-alive", "Accept-Language"=>"en-US,en;q=0.8,ru;q=0.6,es;q=0.4", "Accept"=>"*/*"})
GET http://www.google.com/test HTTP/1.1
Host: www.google.com
Proxy-Connection: keep-alive
Cache-Control: max-age=0
Accept: */*
User-Agent: Mozilla/5.0 (Windows NT 5.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/47.0.2526.106 Safari/537.36
DNT: 1
Accept-Encoding: gzip, deflate, sdch
Accept-Language: en-US,en;q=0.8,ru;q=0.6,es;q=0.4

[:relay_to_servers, "GET http://www.google.com/test HTTP/1.1\r\nHost: www.google.com\r\nProxy-Connection: keep-alive\r\nCache-Control: max-age=0\r\nAccept: */*\r\nUser-Agent: Mozilla/5.0 (Windows NT 5.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/47.0.2526.106 Safari/537.36\r\nDNT: 1\r\nAccept-Encoding: gzip, deflate, sdch\r\nAccept-Language: en-US,en;q=0.8,ru;q=0.6,es;q=0.4\r\n\r\n"]
[:relay_to_servers, "\r\n"]
[:on_connect, "7bffb510-9687-0133-c161-0dc54655ffbe", nil]
[:on_response,  etc.....

As you can see there is invalid additional [:relay_to_servers, "\r\n"].

Tcpdump output:

12:40:45.755302 IP xxxxxxxx.53790 > 173.194.71.106.http: Flags [P.], seq 1:350, ack 1, win 115, options [nop,nop,TS val 1531852163 ecr 2940865000], length 349
        0x0000:  4500 0191 82af 4000 4006 3b89 xxxx xxxx  E.....@.@.;....C
        0x0010:  adc2 476a d21e 0050 6622 b7dd 951f c590  ..Gj...Pf"......
        0x0020:  8018 0073 0d75 0000 0101 080a 5b4e 3583  ...s.u......[N5.
        0x0030:  af4a 09e8 4745 5420 6874 7470 3a2f 2f77  .J..GET.http://w
        0x0040:  7777 2e67 6f6f 676c 652e 636f 6d2f 7465  ww.google.com/te
        0x0050:  7374 2048 5454 502f 312e 310d 0a48 6f73  st.HTTP/1.1..Hos
        0x0060:  743a 2077 7777 2e67 6f6f 676c 652e 636f  t:.www.google.co
        0x0070:  6d0d 0a50 726f 7879 2d43 6f6e 6e65 6374  m..Proxy-Connect
        0x0080:  696f 6e3a 206b 6565 702d 616c 6976 650d  ion:.keep-alive.
        0x0090:  0a43 6163 6865 2d43 6f6e 7472 6f6c 3a20  .Cache-Control:.
        0x00a0:  6d61 782d 6167 653d 300d 0a41 6363 6570  max-age=0..Accep
        0x00b0:  743a 202a 2f2a 0d0a 5573 6572 2d41 6765  t:.*/*..User-Age
        0x00c0:  6e74 3a20 4d6f 7a69 6c6c 612f 352e 3020  nt:.Mozilla/5.0.
        0x00d0:  2857 696e 646f 7773 204e 5420 352e 3129  (Windows.NT.5.1)
        0x00e0:  2041 7070 6c65 5765 624b 6974 2f35 3337  .AppleWebKit/537
        0x00f0:  2e33 3620 284b 4854 4d4c 2c20 6c69 6b65  .36.(KHTML,.like
        0x0100:  2047 6563 6b6f 2920 4368 726f 6d65 2f34  .Gecko).Chrome/4
        0x0110:  372e 302e 3235 3236 2e31 3036 2053 6166  7.0.2526.106.Saf
        0x0120:  6172 692f 3533 372e 3336 0d0a 444e 543a  ari/537.36..DNT:
        0x0130:  2031 0d0a 4163 6365 7074 2d45 6e63 6f64  .1..Accept-Encod
        0x0140:  696e 673a 2067 7a69 702c 2064 6566 6c61  ing:.gzip,.defla
        0x0150:  7465 2c20 7364 6368 0d0a 4163 6365 7074  te,.sdch..Accept
        0x0160:  2d4c 616e 6775 6167 653a 2065 6e2d 5553  -Language:.en-US
        0x0170:  2c65 6e3b 713d 302e 382c 7275 3b71 3d30  ,en;q=0.8,ru;q=0
        0x0180:  2e36 2c65 733b 713d 302e 340d 0a0d 0a0d  .6,es;q=0.4.....
        0x0190:  0a                                       .

As you can see there is triple times 0d 0a (which is "\r\n"), where it should be only two to finish HTTP request header.

Bug. ๐Ÿœ

Error

em-proxy -l 80 -r localhost:3000 -v
/.../gems/em-proxy-0.1.8/lib/em-proxy/proxy.rb:4: warning: epoll is not supported on this platform`

Ruby 2.2.0

Backend Errors: Reopening

I apologize... I created an issue and closed it by mistake:

Currently, I don't believe there's a way to know if a connection was unbound from the backend due to a connection error.

I think that the Backend class should have an unbind method that looks like this:

 def unbind
    debug [@name, :unbind]
    @plexer.unbind_backend(@name, error?)
 end

Finally, the Connection class should be:

 def unbind_backend(name, error)
    debug [:unbind_backend, name, error]
    @servers[name] = nil

    # if all connections are terminated downstream, then notify client
    close_connection_after_writing if @servers.values.compact.size.zero?

    if @on_finish
      @on_finish.call(name, error)

      # not sure if this is required
      # @on_finish.call(:done) if @servers.values.compact.size.zero?
    end
  end

Thanks!
Mike

Getting a NoMethodError while running the Simple Port Forwarding Example

The error I'm getting is:

[:unbind_backend, :google]
./em-proxy/lib/../lib/em-proxy/connection.rb:69:in `unbind_backend': undefined method `call' for nil:NilClass (NoMethodError)
    from ./em-proxy/lib/../lib/em-proxy/backend.rb:32:in `unbind'
    from /opt/local/lib/ruby/gems/1.8/gems/eventmachine-eventmachine-0.12.7/lib/eventmachine.rb:1256:in `event_callback'
    from /opt/local/lib/ruby/gems/1.8/gems/eventmachine-eventmachine-0.12.7/lib/eventmachine.rb:240:in `run_machine'
    from /opt/local/lib/ruby/gems/1.8/gems/eventmachine-eventmachine-0.12.7/lib/eventmachine.rb:240:in `run'
    from ./em-proxy/lib/../lib/em-proxy/proxy.rb:5:in `start'
    from proxy_testing.rb:5

It's easy to fix by just adding a check to see if it's nil, but I'm not too sure what the side effects would be

Manipulating Request/Response data

Hi,

Sorry for posting this here since it not really an issue but more of a question.

Can you advise on how I could modify the content on the fly for form data within the HTTP request/responses as its proxied between the browser and a web application?

Also does em-proxy support HTTPS? If so is it still possible to achieve the above? It seems that node-http-proxy does, although I'm not sure how since I would have thought it would defeat the purpose if it was possible to perform man in the middle type modifications of the data.

https://github.com/nodejitsu/node-http-proxy

Best Regards,

Carl

On SIGINT foreman throws an error

I get an error whenever I stop foreman (CTRL + C):

^CSIGINT received
/usr/local/foreman/lib/foreman/engine.rb:226:in `synchronize': can't be called from trap context (ThreadError)
    from /usr/local/foreman/lib/foreman/engine.rb:226:in `output_with_mutex'
    from /usr/local/foreman/lib/foreman/engine.rb:232:in `system'
    from /usr/local/foreman/lib/foreman/engine.rb:304:in `terminate_gracefully'
    from /usr/local/foreman/lib/foreman/engine.rb:41:in `block in start'
    from /usr/local/foreman/lib/foreman/engine.rb:289:in `call'
    from /usr/local/foreman/lib/foreman/engine.rb:289:in `wait2'
    from /usr/local/foreman/lib/foreman/engine.rb:289:in `watch_for_termination'
    from /usr/local/foreman/lib/foreman/engine.rb:48:in `start'
    from /usr/local/foreman/lib/foreman/cli.rb:40:in `start'
    from /usr/local/foreman/vendor/gems/thor-0.16.0/lib/thor/task.rb:27:in `run'
    from /usr/local/foreman/vendor/gems/thor-0.16.0/lib/thor/invocation.rb:120:in `invoke_task'
    from /usr/local/foreman/vendor/gems/thor-0.16.0/lib/thor.rb:275:in `dispatch'
    from /usr/local/foreman/vendor/gems/thor-0.16.0/lib/thor/base.rb:425:in `start'
    from /usr/bin/foreman:15:in `<main>'

I have found this while using the heroku-forward gem. It seems to be a EM issue that has an easy fix.

EDIT It might actually be foreman and it doesn't seem like there is an active development on the project.

Closing the client connection immediately after servers connection are closed

If servers close all their connections to proxy, em-proxy immediately close (after writing currently written data) the connection to client too:

  def unbind_backend(name)
    debug [:unbind_backend, name]
    @servers[name] = nil

    # if all connections are terminated downstream, then notify client
    close_connection_after_writing if @servers.values.compact.size.zero?

    if @on_finish
      @on_finish.call(name)

      # not sure if this is required
      # @on_finish.call(:done) if @servers.values.compact.size.zero?
    end
  end

Problem occurs in cases, when we have some data from downstream in processing and server close the connection before our data for client is prepared for send. At these cases we need to say, we don't want to close connection to client just now, but manually later.

Some appropriate solution can be for example something similar to:

  def unbind_backend(name)
   debug [:unbind_backend, name]
    @servers[name] = nil
    close = :close

    if @on_finish
      close = @on_finish.call(name)
    end

    # if all connections are terminated downstream, then notify client
    if @servers.values.compact.size.zero? and close != :keep
      close_connection_after_writing
    end

  end

memory usage

In Backend you use

def receive_data(data)
    ...
    @data.push data
    ...
end

Variable size is growing, what for it used?

Choosing outgoing IP

My machine has a pool of IPs. Is it possible to choose the outgoing IP the proxy will use to make the requests? Would it be possible to randomly use more than one IP?

Thanks

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.