Git Product home page Git Product logo

fishwife's People

Contributors

dekellum avatar greghuc avatar iconara avatar matadon avatar olleolleolle avatar pjhyett 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

Watchers

 avatar  avatar  avatar  avatar

fishwife's Issues

Rack 2.x support

Fishwife cannot be used with recently-released Rails 5 unless it supports Rack 2.x. Please add this support when you get a chance. Thank you.

Silently fallback to WEBrick or panic: failed to coerce org.slf4j.helpers.NOPLoggerFactory to ch.qos.logback.core.Context

rackup -s Fishwife causes load exception:

stone$ rackup -s Fishwife
SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder".
SLF4J: Defaulting to no-operation (NOP) logger implementation
SLF4J: See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details.
Bundler::GemRequireError: There was an error while trying to load the gem 'rjack-logback'.
Gem Load Error is: failed to coerce org.slf4j.helpers.NOPLoggerFactory to ch.qos.logback.core.Context
Backtrace for gem load error is:
/Users/stone/.rbenv/versions/jruby-9.1.17.0/lib/ruby/gems/shared/gems/rjack-logback-1.9.0-java/lib/rjack-logback.rb:191:in `initialize'
/Users/stone/.rbenv/versions/jruby-9.1.17.0/lib/ruby/gems/shared/gems/rjack-logback-1.9.0-java/lib/rjack-logback.rb:200:in `<module:AppenderUtil>'
/Users/stone/.rbenv/versions/jruby-9.1.17.0/lib/ruby/gems/shared/gems/rjack-logback-1.9.0-java/lib/rjack-logback.rb:199:in `<module:Logback>'
/Users/stone/.rbenv/versions/jruby-9.1.17.0/lib/ruby/gems/shared/gems/rjack-logback-1.9.0-java/lib/rjack-logback.rb:79:in `<module:RJack>'
/Users/stone/.rbenv/versions/jruby-9.1.17.0/lib/ruby/gems/shared/gems/rjack-logback-1.9.0-java/lib/rjack-logback.rb:20:in `<main>'
org/jruby/RubyKernel.java:956:in `require'
/Users/stone/.rbenv/versions/jruby-9.1.17.0/lib/ruby/gems/shared/gems/bundler-1.16.2/lib/bundler/runtime.rb:1:in `block in (root)'
org/jruby/RubyArray.java:1735:in `each'
/Users/stone/.rbenv/versions/jruby-9.1.17.0/lib/ruby/gems/shared/gems/bundler-1.16.2/lib/bundler/runtime.rb:81:in `block in require'
org/jruby/RubyArray.java:1735:in `each'
/Users/stone/.rbenv/versions/jruby-9.1.17.0/lib/ruby/gems/shared/gems/bundler-1.16.2/lib/bundler/runtime.rb:76:in `require'
/Users/stone/.rbenv/versions/jruby-9.1.17.0/lib/ruby/gems/shared/gems/bundler-1.16.2/lib/bundler/runtime.rb:65:in `require'
/Users/stone/.rbenv/versions/jruby-9.1.17.0/lib/ruby/gems/shared/gems/bundler-1.16.2/lib/bundler.rb:114:in `block in require'
org/jruby/RubyBasicObject.java:1691:in `instance_eval'
/Users/stone/RubymineProjects/AutoReimbursement/mas/config.ru:8:in `new_from_string'
/Users/stone/.rbenv/versions/jruby-9.1.17.0/lib/ruby/gems/shared/gems/rack-2.0.5/lib/rack/builder.rb:55:in `<eval>'
org/jruby/RubyKernel.java:995:in `eval'
/Users/stone/RubymineProjects/AutoReimbursement/mas/config.ru:1:in `new_from_string'
/Users/stone/.rbenv/versions/jruby-9.1.17.0/lib/ruby/gems/shared/gems/rack-2.0.5/lib/rack/builder.rb:49:in `new_from_string'
/Users/stone/.rbenv/versions/jruby-9.1.17.0/lib/ruby/gems/shared/gems/rack-2.0.5/lib/rack/builder.rb:40:in `parse_file'
/Users/stone/.rbenv/versions/jruby-9.1.17.0/lib/ruby/gems/shared/gems/rack-2.0.5/lib/rack/server.rb:319:in `build_app_and_options_from_config'
/Users/stone/.rbenv/versions/jruby-9.1.17.0/lib/ruby/gems/shared/gems/rack-2.0.5/lib/rack/server.rb:219:in `app'
/Users/stone/.rbenv/versions/jruby-9.1.17.0/lib/ruby/gems/shared/gems/rack-2.0.5/lib/rack/server.rb:354:in `wrapped_app'
/Users/stone/.rbenv/versions/jruby-9.1.17.0/lib/ruby/gems/shared/gems/rack-2.0.5/lib/rack/server.rb:283:in `start'
/Users/stone/.rbenv/versions/jruby-9.1.17.0/lib/ruby/gems/shared/gems/rack-2.0.5/lib/rack/server.rb:148:in `<main>'
org/jruby/RubyKernel.java:974:in `load'
/usr/local/bin/rackup:23:in `<main>'
Bundler Error Backtrace:

                   block in require at /Users/stone/.rbenv/versions/jruby-9.1.17.0/lib/ruby/gems/shared/gems/bundler-1.16.2/lib/bundler/runtime.rb:84
                               each at org/jruby/RubyArray.java:1735
                   block in require at /Users/stone/.rbenv/versions/jruby-9.1.17.0/lib/ruby/gems/shared/gems/bundler-1.16.2/lib/bundler/runtime.rb:76
                               each at org/jruby/RubyArray.java:1735
                            require at /Users/stone/.rbenv/versions/jruby-9.1.17.0/lib/ruby/gems/shared/gems/bundler-1.16.2/lib/bundler/runtime.rb:65
                            require at /Users/stone/.rbenv/versions/jruby-9.1.17.0/lib/ruby/gems/shared/gems/bundler-1.16.2/lib/bundler.rb:114
           block in new_from_string at /Users/stone/RubymineProjects/AutoReimbursement/mas/config.ru:8
                      instance_eval at org/jruby/RubyBasicObject.java:1691
                         initialize at /Users/stone/.rbenv/versions/jruby-9.1.17.0/lib/ruby/gems/shared/gems/rack-2.0.5/lib/rack/builder.rb:55
                             <eval> at /Users/stone/RubymineProjects/AutoReimbursement/mas/config.ru:1
                               eval at org/jruby/RubyKernel.java:995
                    new_from_string at /Users/stone/.rbenv/versions/jruby-9.1.17.0/lib/ruby/gems/shared/gems/rack-2.0.5/lib/rack/builder.rb:49
                         parse_file at /Users/stone/.rbenv/versions/jruby-9.1.17.0/lib/ruby/gems/shared/gems/rack-2.0.5/lib/rack/builder.rb:40
  build_app_and_options_from_config at /Users/stone/.rbenv/versions/jruby-9.1.17.0/lib/ruby/gems/shared/gems/rack-2.0.5/lib/rack/server.rb:319
                                app at /Users/stone/.rbenv/versions/jruby-9.1.17.0/lib/ruby/gems/shared/gems/rack-2.0.5/lib/rack/server.rb:219
                        wrapped_app at /Users/stone/.rbenv/versions/jruby-9.1.17.0/lib/ruby/gems/shared/gems/rack-2.0.5/lib/rack/server.rb:354
                              start at /Users/stone/.rbenv/versions/jruby-9.1.17.0/lib/ruby/gems/shared/gems/rack-2.0.5/lib/rack/server.rb:283
                              start at /Users/stone/.rbenv/versions/jruby-9.1.17.0/lib/ruby/gems/shared/gems/rack-2.0.5/lib/rack/server.rb:148
                             <main> at /Users/stone/.rbenv/versions/jruby-9.1.17.0/lib/ruby/gems/shared/gems/rack-2.0.5/bin/rackup:4
                               load at org/jruby/RubyKernel.java:974
                             <main> at /usr/local/bin/rackup:23

While simple run fishwife, the app starts with rack default handler WEBrick:

stone$ fishwife
307  [main] INFO  org.eclipse.jetty.util.log - Logging initialized @4406ms to org.eclipse.jetty.util.log.Slf4jLog 
[2018-07-15 10:33:00] INFO  WEBrick 1.3.1
[2018-07-15 10:33:00] INFO  ruby 2.3.3 (2018-04-20) [java]
[2018-07-15 10:33:00] INFO  WEBrick::HTTPServer#start: pid=91462 port=3001

jruby 9.1.7.0 @ macos 10.12.6

stone$ java -version
java version "1.8.0_131"
Java(TM) SE Runtime Environment (build 1.8.0_131-b11)
Java HotSpot(TM) 64-Bit Server VM (build 25.131-b11, mixed mode)

config.ru:

#\ -p 3001
# encoding: utf-8

APP_ROOTDIR = File.expand_path(File.dirname(__FILE__))
$: << File.join(APP_ROOTDIR, 'lib')

require 'bundler/setup'
Bundler.require(:default)

require 'common/app_const'

class AppConst
  AppName = 'mas'
end

if defined? Fishwife
  RJack::Logback.config_console( :stderr => true, :thread => true )
end

AppConfig.setup(AppConst::AppName, APP_ROOTDIR, File.join(APP_ROOTDIR, 'config'))
MAIN_CONFIG = AppConfig.get_config
COMMON_CONFIG = AppConfig.get_config 'common'

DB = Sequel::connect(COMMON_CONFIG['db.conn'])

require 'app'

$stdout.sync = true unless $stdout.isatty
$stderr.sync = true unless $stderr.isatty

begin
  run Cuba
ensure
  DB.disconnect
end

Gemfile:

source 'https://rubygems.org'

gem 'appconf'
gem 'cuba'
# gem 'cuba-sendfile' # this gem does not work any more
gem 'rack-protection', :require => 'rack/protection'
gem 'cuba-sugar', :require => false
gem 'faraday'
gem 'faraday_middleware'
gem 'sequel'

gem 'jruby-jars', '9.1.17.0', :require => false # newest 9.2.0.0 has a bug that .war does not load for error: 'no such file to load -- bundler/shared_helpers'
gem 'jruby-openssl', :platforms => :jruby
gem 'jdbc-sqlite3', :require => false, :platforms => :jruby
gem 'fishwife', :platforms => :jruby
gem 'rjack-logback', :platforms => :jruby

install_if -> { not defined? JRUBY_VERSION } do
  gem 'sqlite3'
  gem 'openssl'
  gem 'thin'
end

Gemfile.lock:

GEM
  remote: https://rubygems.org/
  specs:
    appconf (0.1.0)
    cuba (3.9.2)
      rack (>= 1.6.0)
    cuba-sugar (0.3.1)
      cuba (~> 3.3)
      json (~> 1.7)
      rack_csrf (~> 2.4)
    daemons (1.2.6)
    eventmachine (1.2.7)
    eventmachine (1.2.7-java)
    faraday (0.15.2)
      multipart-post (>= 1.2, < 3)
    faraday_middleware (0.12.2)
      faraday (>= 0.7.4, < 1.0)
    fishwife (1.10.0-java)
      rack (>= 1.6.4, < 2.1)
      rjack-jetty (>= 9.2.11, < 9.5)
      rjack-slf4j (~> 1.7.2)
    jdbc-sqlite3 (3.20.1)
    jruby-jars (9.1.17.0)
    jruby-openssl (0.10.1-java)
    json (1.8.6)
    json (1.8.6-java)
    multipart-post (2.0.0)
    openssl (2.1.0)
    rack (2.0.5)
    rack-protection (2.0.3)
      rack
    rack_csrf (2.6.0)
      rack (>= 1.1.0)
    rjack-jetty (9.4.6.0-java)
    rjack-logback (1.9.0-java)
      rjack-slf4j (~> 1.7.16)
    rjack-slf4j (1.7.25.0-java)
    sequel (5.9.0)
    sqlite3 (1.3.13)
    thin (1.7.2)
      daemons (~> 1.0, >= 1.0.9)
      eventmachine (~> 1.0, >= 1.0.4)
      rack (>= 1, < 3)

PLATFORMS
  java
  ruby

DEPENDENCIES
  appconf
  cuba
  cuba-sugar
  faraday
  faraday_middleware
  fishwife
  jdbc-sqlite3
  jruby-jars (= 9.1.17.0)
  jruby-openssl
  openssl
  rack-protection
  rjack-logback
  sequel
  sqlite3
  thin

BUNDLED WITH
   1.16.2

If I remove 'gem rjack-logback' from Gemfile, and remove RJack::Logback.config_console( :stderr => true, :thread => true ) call from config.ru, then rackup command will freeze on loading.

stone$ rackup -s Fishwife
SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder".
SLF4J: Defaulting to no-operation (NOP) logger implementation
SLF4J: See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details.

---> loading process freezed here

In this case, use fishwife instead, app runs with rack handler fallback to WEBrick, simply the same case with gem rjack-logback included with Gemfile.

fishwife and sinatra 1.4.x mangled content

I have a simple bit of code that serves up index.html in our application.

require 'sinatra'

class StaticContentController < Sinatra::Base
get '/' do
send_file '/Users/jilles/git/localstream/www/localstream-web/foo.html'
end
end

This worked fine up to sinatra 1.3.6. After upgrading to 1.4.2, fishwife mangles the content by prepending and appending some ramdom characters. I've been manually installing and uninstalling gems with specific versions until I narrowed it down to just the sinatra gem and the way it interacts with fishwife,. Using gem list, I can see that sinatra is the only gem that is different. I've verified it is broken for 1.4.0 and 1.4.1 as well. I've tried with a simple foo.html file that contains nothing but the word hello and it returns '6 hello 0' in the browser.

to break: gem uninstall sinatra; gem install --version '1.4.2' sinatra
and to fix: gem uninstall sinatra; gem install --version '1.3.6' sinatra

So, what is wrong here? Using either mizuno or rackup, things are fine. So obviously it is a problem with fishwife. On the other hand that works fine with 1.3.6. So that makes me wonder what changed between that version and 1.4.x that breaks things here.

Any help here would be greatly appreciated since I really like the work you've been doing with Jetty 9 integration.

These are all the gems I have installed:

backports (3.3.0)
bundler (1.3.5)
eventmachine (1.0.3 java)
faraday (0.8.7)
fishwife (1.5.0 java)
hashie (2.0.4)
httpauth (0.2.0)
jsonj-integration (1.2)
jwt (0.1.8)
multi_json (1.7.3)
multipart-post (1.2.0)
oauth (0.4.7)
oauth2 (0.8.1)
omniauth (1.1.4)
omniauth-facebook (1.4.1)
omniauth-foursquare (0.0.8)
omniauth-oauth (1.0.1)
omniauth-oauth2 (1.1.1)
omniauth-openid (1.0.1)
omniauth-twitter (0.0.16)
rack (1.5.2)
rack-openid (1.3.1)
rack-protection (1.5.0)
rack-test (0.6.2)
rjack-jetty (9.0.2.0 java)
rjack-slf4j (1.7.5.0 java)
ruby-openid (2.2.3)
sinatra (1.3.6)
sinatra-docdsl (0.3.0)
tilt (1.4.0)

rack.input does not rewind

This issue was first raised in matadon/mizuno#15 and 5b22977 suggests a fix. However my review and testing finds that RewindableInputStream.to_io (from jruby-rack, kirk, et al) also will not yield a functioning rewind. The kirk original also includes ReweindableInputStream to IO adapter (see its input_stream.rb.) So either that needs to be co-opted here, or a better performing JRuby java extension for InputStream to IO implemented.

Also I would prefer to not use temp files for input caching except where absolutely necessary for giant uploads. An in memory implementation with configurable rewind limit might resolve the issue for 99% of use cases without the performance and complexity impact.

JRUBY-5891 is related. However JRUBY is not going to fix this: InputStream.to_io is not going to support rewind without major changes and assumptions.

Configuration of jetty?

I want to configure Jetty to use their own built in gzip compression instead of Rack Deflater.
How do I do that?

logging configuration, defaults & documentation

I want to use a custom logback.xml and have some java dependencies that log as well so I want to use the same config everywhere. Normally you configure logback by either passing in a -D property or by making sure logback.xml is on the classpath. Neither approach works with fishwife because it imposes a default configuration. This is true with both the slf4j and logback option.

The way to fix this is to write your own start script and making sure to require 'rjack-slf4j/nop' instead of rjack-slf4j/simple. After that, if you have the logback jar on the classpath, it will initialize with the correct configuration. In my custom start script, I actually load a couple of jar files (including slf4j and logback) before fishwife starts.

Probably just documenting this would help a lot (it took me a bit of time to figure this out). Also, it would be nice if the fishwife script did the right thing if valid log4j or logback configuration is on the classpath already or would have an option to take a logback configuration file as a parameter.

java.lang.NoSuchMethodError on Jruby 9.3.3.0 nightly build

While testing our product on the most recent Jruby 9.3.3.0 nightly build, I have noticed an issue with Fishwife's IOUtil class.

This call (https://github.com/dekellum/fishwife/blob/fishwife-dev/src/main/java/fishwife/IOUtil.java#L116) blows up like so:

java.lang.NoSuchMethodError: 'org.jruby.runtime.Block org.jruby.runtime.CallBlock.newCallClosure(org.jruby.runtime.builtin.IRubyObject, org.jruby.RubyModule, org.jruby.runtime.Arity, org.jruby.runtime.BlockCallback, org.jruby.runtime.ThreadContext)'
	at fishwife.IOUtil.writeBody(IOUtil.java:116)
	at fishwife.IOUtil$INVOKER$s$2$0$writeBody_DBG.call(IOUtil$INVOKER$s$2$0$writeBody_DBG.gen)
	at org.jruby.dist/org.jruby.runtime.callsite.CachingCallSite.call(CachingCallSite.java:204)
	at org.jruby.dist/org.jruby.ir.interpreter.InterpreterEngine.processCall(InterpreterEngine.java:325)
	at org.jruby.dist/org.jruby.ir.interpreter.StartupInterpreterEngine.interpret(StartupInterpreterEngine.java:72)
	at org.jruby.dist/org.jruby.internal.runtime.methods.InterpretedIRMethod.INTERPRET_METHOD(InterpretedIRMethod.java:131)
	at org.jruby.dist/org.jruby.internal.runtime.methods.InterpretedIRMethod.call(InterpretedIRMethod.java:109)
	at org.jruby.dist/org.jruby.runtime.callsite.CachingCallSite.call(CachingCallSite.java:85)
	at org.jruby.dist/org.jruby.ir.instructions.CallBase.interpret(CallBase.java:549)
	at org.jruby.dist/org.jruby.ir.interpreter.InterpreterEngine.processCall(InterpreterEngine.java:361)
	at org.jruby.dist/org.jruby.ir.interpreter.StartupInterpreterEngine.interpret(StartupInterpreterEngine.java:72)
	at org.jruby.dist/org.jruby.internal.runtime.methods.InterpretedIRMethod.INTERPRET_METHOD(InterpretedIRMethod.java:131)
	at org.jruby.dist/org.jruby.internal.runtime.methods.InterpretedIRMethod.call(InterpretedIRMethod.java:118)
	at org.jruby.dist/org.jruby.RubyClass.finvoke(RubyClass.java:780)
	at org.jruby.dist/org.jruby.runtime.Helpers.invoke(Helpers.java:661)
	at org.jruby.dist/org.jruby.RubyBasicObject.callMethod(RubyBasicObject.java:370)
	at rubyobj.Fishwife.RackServlet.service(/Users/kovyrin-elastic/work/elastic/ent-search/vendor/fishwife-servlet/lib/fishwife/rack_servlet.rb:71)
	at org.eclipse.jetty.servlet.ServletHolder.handle(ServletHolder.java:799)
	at org.eclipse.jetty.servlet.ServletHandler$ChainEnd.doFilter(ServletHandler.java:1626)
	at org.eclipse.jetty.servlets.QoSFilter.doFilter(QoSFilter.java:202)
	at org.eclipse.jetty.servlet.FilterHolder.doFilter(FilterHolder.java:193)
	at org.eclipse.jetty.servlet.ServletHandler$Chain.doFilter(ServletHandler.java:1601)
	at org.eclipse.jetty.servlet.ServletHandler.doHandle(ServletHandler.java:548)
	at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:143)
	at org.eclipse.jetty.server.handler.gzip.GzipHandler.handle(GzipHandler.java:763)
	at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:127)
	at org.eclipse.jetty.server.handler.ScopedHandler.nextHandle(ScopedHandler.java:235)
	at org.eclipse.jetty.server.handler.ContextHandler.doHandle(ContextHandler.java:1434)
	at org.eclipse.jetty.server.handler.ScopedHandler.nextScope(ScopedHandler.java:188)
	at org.eclipse.jetty.servlet.ServletHandler.doScope(ServletHandler.java:501)
	at org.eclipse.jetty.server.handler.ScopedHandler.nextScope(ScopedHandler.java:186)
	at org.eclipse.jetty.server.handler.ContextHandler.doScope(ContextHandler.java:1349)
	at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:141)
	at org.eclipse.jetty.server.handler.HandlerCollection.handle(HandlerCollection.java:146)
	at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:127)
	at org.eclipse.jetty.server.Server.handle(Server.java:516)
	at org.eclipse.jetty.server.HttpChannel.lambda$handle$1(HttpChannel.java:388)
	at org.eclipse.jetty.server.HttpChannel.dispatch(HttpChannel.java:633)
	at org.eclipse.jetty.server.HttpChannel.handle(HttpChannel.java:380)
	at org.eclipse.jetty.server.HttpConnection.onFillable(HttpConnection.java:277)
	at org.eclipse.jetty.io.AbstractConnection$ReadCallback.succeeded(AbstractConnection.java:311)
	at org.eclipse.jetty.io.FillInterest.fillable(FillInterest.java:105)
	at org.eclipse.jetty.io.ChannelEndPoint$1.run(ChannelEndPoint.java:104)
	at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.runTask(EatWhatYouKill.java:338)
	at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.doProduce(EatWhatYouKill.java:315)
	at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.tryProduce(EatWhatYouKill.java:173)
	at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.run(EatWhatYouKill.java:131)
	at org.eclipse.jetty.util.thread.ReservedThreadExecutor$ReservedThread.run(ReservedThreadExecutor.java:386)
	at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:883)
	at org.eclipse.jetty.util.thread.QueuedThreadPool$Runner.run(QueuedThreadPool.java:1034)
	at java.base/java.lang.Thread.run(Thread.java:829)

(Please ignore line numbers in the stack trace since the error was detected on our internal fork of fishwife, which has some parts of the code reformatted, etc)

Is async supported?

It looks like async response handling is supported, but it doesn't seem to work, or I'm misunderstanding how it is supposed to work.

Looking at these lines

# Close the body if we're supposed to.
body.close if body.respond_to?(:close)
# All done.
output.close
false
I don't see how it could work – the response is closed the first time the async callback is called, no matter what, so subsequent calls will get an EOF.

Is it supposed to work? Am I missing something? Would you like help making it work?

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.