Giter Site home page Giter Site logo

ws-qvh's Introduction

ws qvh

Web Socket server for streaming the screen of iOS devices.

How it works?

  1. danielpaulus/quicktime_video_hack - video streaming
  2. appium/WebDriverAgent - device control
  3. NetrisTV/ws-scrcpy - user interface
  4. NetrisTV/ws-qvh - forwards the video stream over Web Socket

Steps to set up

  1. Get macOS (streaming only should also work on GNU/Linux)
  2. Connect a device, accept "Trust This Computer".
  3. Verify that you can record your device screen with QuickTime
  4. Install danielpaulus/quicktime_video_hack and verify that you can record your device screen with it
  5. Build sources: go build. This command will produce ws-qvh binary.
  6. Make sure your ws-qvh binary is available via the PATH environment variable.
  7. Setup and run ws-scrcpy. Follow the instructions here.
  8. Open link provided by ws-scrcpy in your browser.

Notes

  • Only video stream is transmitted (no audio).
  • WebDriverAgent can be started only after the start of video transmission (i.e. quicktime interface activation).
  • WebDriverAgent can take a long time to start.
  • Control capabilities are very limited (compared to scrcpy/ws-scrcpy):
    • single tap
    • home button click
    • swipe (this command will be sent only after the gesture is complete)
  • No way to customize stream parameters (bitrate, fps, video size, etc.)

ws-qvh's People

Contributors

drauggres 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

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar

ws-qvh's Issues

Unable to get screen frames on ios 16

I forked this project, and change qvh module to code version of externalizeGST branch fixing gstream issue. While I'm using ws-qvh with ws-scrcpy with USE_QVH_SERVER enabled. I found it can get datas from ios 14 and ios 15, but not ios 16.

Versions:

Here are versions I'm using:

Steps to reproduce

  1. Clone and build ws-qvh using command go build, then got ws-qvh binary file.
  2. Add ws-qvh file to environment variable PATH
  3. Connect ios device to mac.
  4. Start ws-scrcpy using code version https://github.com/chenhengjie123/ws-scrcpy/tree/feat-20230302-testOnWsscrcpy using command npm install && npm start
  5. Open http://127.0.0.1:8000/ , select the ios device and open its remote control module:
    image

On ios 14, 15, the screen content can appear normally like below:
image

But on ios 16.0, 16.1.1, the screen content did not appear:
image

From ws messages in screenshot, it seems no data came from server side.

Logs from server side

On iOS 14 or 15, I can get screen frames successfully and quickly, here are logs(most of them are logs from ws-qvh):

logs-on-ios-15.log

While on ios 16, it stuck while reading lengthBuffer like below:

logs-on-ios-16.1.1.log

Can't control the device from the UI

Hi,

Thanks for the great effort you've put. I can successfully connect and reach my device from "http://127.0.0.1:8080/" port and everything works perfectly.

However, I can't control the device from the UI, its not responding to my mouse clicks and swipes at all. I hope you can help me to figure out this problem.

I have this error popping out in every 2 seconds
handle_events: error: libusb: interrupted [code -10]

Thanks in advance!

WS-QVH buffer format and help

Hi Can you help me, how ws-qvh works and what format, it is buffering its raw data. so i can use AVFOUNDATION ios library to mimic same.

xcodebuild failed with code 65

Im getting this error after de qvh starts:
Im running appium test with no problem, but with ws-qvh im getting this error.
I have already check the possible fixes witht the setting the team to the WebDriverAgent and nothing.

info WebDriverAgent Using WDA path: '/Users/fulviocarvalhido/Projects/Worten/farmer/ws-scrcpy/node_modules/appium-webdriveragent'
info WebDriverAgent Using WDA agent: '/Users/fulviocarvalhido/Projects/Worten/farmer/ws-scrcpy/node_modules/appium-webdriveragent/WebDriverAgent.xcodeproj'
info XCUITest Setting up real device
info DevCon Factory Requesting connection for device 00008030-001550A4029A402E on local port 8004, device port 8004
info DevCon Factory Successfully requested the connection for 00008030-001550A4029A402E:8004
info WD Proxy socket hang up
info WebDriverAgent Launching WebDriverAgent on the device
info WebDriverAgent WebDriverAgent does not need a cleanup. The sources are up to date (1626192173947 >= 1626192173947)
info WD Proxy socket hang up
info WD Proxy socket hang up
ERR! WebDriverAgent xcodebuild exited with code '65' and signal 'null'
info WebDriverAgent Launching WebDriverAgent on the device
info WebDriverAgent WebDriverAgent does not need a cleanup. The sources are up to date (1626192173947 >= 1626192173947)
info WD Proxy socket hang up
info WD Proxy socket hang up
info WD Proxy socket hang up
info WD Proxy socket hang up
ERR! WebDriverAgent xcodebuild exited with code '65' and signal 'null'
WARN XCUITest Quitting and uninstalling WebDriverAgent
info WebDriverAgent Shutting down sub-processes
ERR! XCUITest {}
info DevCon Factory Releasing connections for 00008030-001550A4029A402E device on any port number
info DevCon Factory Found cached connections to release: ["00008030-001550A4029A402E:8004"]
info DevCon Factory Releasing the listener for '00008030-001550A4029A402E:8004'
info iProxy@00008030:8004 The connection has been closed
(node:3841) UnhandledPromiseRejectionWarning: Error: Unable to launch WebDriverAgent because of xcodebuild failure: xcodebuild failed with code 65
xcodebuild error message:
. Make sure you follow the tutorial at https://github.com/appium/appium-xcuitest-driver/blob/master/docs/real-device-config.md. Try to remove the WebDriverAgentRunner application from the device if it is installed and reboot the device.
    at quitAndUninstall (/Users/fulviocarvalhido/Projects/Worten/farmer/ws-scrcpy/node_modules/appium-xcuitest-driver/lib/driver.js:544:15)
    at /Users/fulviocarvalhido/Projects/Worten/farmer/ws-scrcpy/node_modules/appium-xcuitest-driver/lib/driver.js:579:11
    at wrapped (/Users/fulviocarvalhido/Projects/Worten/farmer/ws-scrcpy/node_modules/asyncbox/lib/asyncbox.js:60:13)
    at retry (/Users/fulviocarvalhido/Projects/Worten/farmer/ws-scrcpy/node_modules/asyncbox/lib/asyncbox.js:43:13)
    at retryInterval (/Users/fulviocarvalhido/Projects/Worten/farmer/ws-scrcpy/node_modules/asyncbox/lib/asyncbox.js:70:10)
    at /Users/fulviocarvalhido/Projects/Worten/farmer/ws-scrcpy/node_modules/appium-xcuitest-driver/lib/driver.js:559:7
(Use `node --trace-warnings ...` to show where the warning was created)
(node:3841) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). To terminate the node process on unhandled promise rejection, use the CLI flag `--unhandled-rejections=strict` (see https://nodejs.org/api/cli.html#cli_unhandled_rejections_mode). (rejection id: 8)
(node:3841) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.

ws-qvh in PATH environment, but not work.

I am stuck in "Steps to set up" steps 6th.

I'm sure ws-qvh config is correctly by "which ws-qvh" in Terminal, but when run ws-qvh in Terminal, ws-qvh crashed with following log:

fatal error: unexpected signal during runtime execution
[signal SIGSEGV: segmentation violation code=0x1 addr=0xb01dfacedebac1e pc=0x7fff2051dcbe]

runtime stack:
runtime: unexpected return pc for runtime.sigpanic called from 0x7fff2051dcbe
stack: frame={sp:0x7ffeefbff148, fp:0x7ffeefbff198} stack=[0x7ffeefb801e8,0x7ffeefbff250)
0x00007ffeefbff048:  0x01007ffeefbff068  0x0000000000000004 
0x00007ffeefbff058:  0x000000000000001f  0x00007fff2051dcbe 
0x00007ffeefbff068:  0x0b01dfacedebac1e  0x0000000000000001 
0x00007ffeefbff078:  0x0000000004036a51 <runtime.throw+0x0000000000000071>  0x00007ffeefbff118 
0x00007ffeefbff088:  0x00000000042cf7b3  0x00007ffeefbff0d0 
0x00007ffeefbff098:  0x0000000004036d08 <runtime.fatalthrow.func1+0x0000000000000048>  0x00000000044fa280 
0x00007ffeefbff0a8:  0x0000000000000001  0x0000000000000001 
0x00007ffeefbff0b8:  0x00007ffeefbff118  0x0000000004036a51 <runtime.throw+0x0000000000000071> 
0x00007ffeefbff0c8:  0x00000000044fa280  0x00007ffeefbff108 
0x00007ffeefbff0d8:  0x0000000004036c90 <runtime.fatalthrow+0x0000000000000050>  0x00007ffeefbff0e8 
0x00007ffeefbff0e8:  0x0000000004036cc0 <runtime.fatalthrow.func1+0x0000000000000000>  0x00000000044fa280 
0x00007ffeefbff0f8:  0x0000000004036a51 <runtime.throw+0x0000000000000071>  0x00007ffeefbff118 
0x00007ffeefbff108:  0x00007ffeefbff138  0x0000000004036a51 <runtime.throw+0x0000000000000071> 
0x00007ffeefbff118:  0x00007ffeefbff120  0x0000000004036a80 <runtime.throw.func1+0x0000000000000000> 
0x00007ffeefbff128:  0x00000000042d4825  0x000000000000002a 
0x00007ffeefbff138:  0x00007ffeefbff188  0x000000000404c276 <runtime.sigpanic+0x0000000000000396> 
0x00007ffeefbff148: <0x00000000042d4825  0x00000000044fa280 
0x00007ffeefbff158:  0x00007ffeefbff1c8  0x00000000040298e6 <runtime.(*mheap).allocSpan+0x0000000000000546> 
0x00007ffeefbff168:  0x000000c00010e000  0x0000000000002000 
0x00007ffeefbff178:  0x0000000000000008  0x0000000004068100 <runtime.walltime_trampoline+0x0000000000000000> 
0x00007ffeefbff188:  0x00007ffeefbff1d0 !0x00007fff2051dcbe 
0x00007ffeefbff198: >0x00007ffeefbff1d0  0x00000000044a4000 
0x00007ffeefbff1a8:  0x0000000000000343  0x0000000004222825 <golang.org/x/sys/unix.libc_ioctl_trampoline+0x0000000000000005> 
0x00007ffeefbff1b8:  0x000000000406873f <runtime.syscall+0x000000000000001f>  0x000000c000058490 
0x00007ffeefbff1c8:  0x00000000040680ac <runtime.nanotime_trampoline+0x000000000000000c>  0x000000c000058460 
0x00007ffeefbff1d8:  0x00000000040665b0 <runtime.asmcgocall+0x0000000000000070>  0x0000000000000001 
0x00007ffeefbff1e8:  0x0000000004010900 <runtime.newarray+0x0000000000000060>  0x0900000000001018 
0x00007ffeefbff1f8:  0x0000000000000010  0x000000000452e1b8 
0x00007ffeefbff208:  0x0000000000000bc8  0x000000c0000001a0 
0x00007ffeefbff218:  0x00000000040646c9 <runtime.systemstack+0x0000000000000049>  0x0000000000000004 
0x00007ffeefbff228:  0x0000000004324228  0x00000000044fa280 
0x00007ffeefbff238:  0x00007ffeefbff280  0x00000000040645c5 <runtime.mstart+0x0000000000000005> 
0x00007ffeefbff248:  0x000000000406457d <runtime.rt0_go+0x000000000000013d> 
runtime.throw({0x42d4825, 0x44fa280})
	/usr/local/go/src/runtime/panic.go:1198 +0x71
runtime: unexpected return pc for runtime.sigpanic called from 0x7fff2051dcbe
stack: frame={sp:0x7ffeefbff148, fp:0x7ffeefbff198} stack=[0x7ffeefb801e8,0x7ffeefbff250)
0x00007ffeefbff048:  0x01007ffeefbff068  0x0000000000000004 
0x00007ffeefbff058:  0x000000000000001f  0x00007fff2051dcbe 
0x00007ffeefbff068:  0x0b01dfacedebac1e  0x0000000000000001 
0x00007ffeefbff078:  0x0000000004036a51 <runtime.throw+0x0000000000000071>  0x00007ffeefbff118 
0x00007ffeefbff088:  0x00000000042cf7b3  0x00007ffeefbff0d0 
0x00007ffeefbff098:  0x0000000004036d08 <runtime.fatalthrow.func1+0x0000000000000048>  0x00000000044fa280 
0x00007ffeefbff0a8:  0x0000000000000001  0x0000000000000001 
0x00007ffeefbff0b8:  0x00007ffeefbff118  0x0000000004036a51 <runtime.throw+0x0000000000000071> 
0x00007ffeefbff0c8:  0x00000000044fa280  0x00007ffeefbff108 
0x00007ffeefbff0d8:  0x0000000004036c90 <runtime.fatalthrow+0x0000000000000050>  0x00007ffeefbff0e8 
0x00007ffeefbff0e8:  0x0000000004036cc0 <runtime.fatalthrow.func1+0x0000000000000000>  0x00000000044fa280 
0x00007ffeefbff0f8:  0x0000000004036a51 <runtime.throw+0x0000000000000071>  0x00007ffeefbff118 
0x00007ffeefbff108:  0x00007ffeefbff138  0x0000000004036a51 <runtime.throw+0x0000000000000071> 
0x00007ffeefbff118:  0x00007ffeefbff120  0x0000000004036a80 <runtime.throw.func1+0x0000000000000000> 
0x00007ffeefbff128:  0x00000000042d4825  0x000000000000002a 
0x00007ffeefbff138:  0x00007ffeefbff188  0x000000000404c276 <runtime.sigpanic+0x0000000000000396> 
0x00007ffeefbff148: <0x00000000042d4825  0x00000000044fa280 
0x00007ffeefbff158:  0x00007ffeefbff1c8  0x00000000040298e6 <runtime.(*mheap).allocSpan+0x0000000000000546> 
0x00007ffeefbff168:  0x000000c00010e000  0x0000000000002000 
0x00007ffeefbff178:  0x0000000000000008  0x0000000004068100 <runtime.walltime_trampoline+0x0000000000000000> 
0x00007ffeefbff188:  0x00007ffeefbff1d0 !0x00007fff2051dcbe 
0x00007ffeefbff198: >0x00007ffeefbff1d0  0x00000000044a4000 
0x00007ffeefbff1a8:  0x0000000000000343  0x0000000004222825 <golang.org/x/sys/unix.libc_ioctl_trampoline+0x0000000000000005> 
0x00007ffeefbff1b8:  0x000000000406873f <runtime.syscall+0x000000000000001f>  0x000000c000058490 
0x00007ffeefbff1c8:  0x00000000040680ac <runtime.nanotime_trampoline+0x000000000000000c>  0x000000c000058460 
0x00007ffeefbff1d8:  0x00000000040665b0 <runtime.asmcgocall+0x0000000000000070>  0x0000000000000001 
0x00007ffeefbff1e8:  0x0000000004010900 <runtime.newarray+0x0000000000000060>  0x0900000000001018 
0x00007ffeefbff1f8:  0x0000000000000010  0x000000000452e1b8 
0x00007ffeefbff208:  0x0000000000000bc8  0x000000c0000001a0 
0x00007ffeefbff218:  0x00000000040646c9 <runtime.systemstack+0x0000000000000049>  0x0000000000000004 
0x00007ffeefbff228:  0x0000000004324228  0x00000000044fa280 
0x00007ffeefbff238:  0x00007ffeefbff280  0x00000000040645c5 <runtime.mstart+0x0000000000000005> 
0x00007ffeefbff248:  0x000000000406457d <runtime.rt0_go+0x000000000000013d> 
runtime.sigpanic()
	/usr/local/go/src/runtime/signal_unix.go:719 +0x396

goroutine 1 [syscall]:
syscall.syscall(0x4222820, 0x2, 0x40487413, 0xc000058520)
	/usr/local/go/src/runtime/sys_darwin.go:22 +0x3b fp=0xc000058490 sp=0xc000058470 pc=0x406327b
syscall.syscall(0x400, 0xc000058548, 0x0, 0xc000058540)
	<autogenerated>:1 +0x26 fp=0xc0000584d8 sp=0xc000058490 pc=0x4068ea6
golang.org/x/sys/unix.ioctl(0xc000058520, 0x539ffff, 0x400)
	/Users/dynamicui/Downloads/3.AMapProj/NetrisTV/ws-qvh/vendor/golang.org/x/sys/unix/zsyscall_darwin_amd64.go:746 +0x39 fp=0xc000058508 sp=0xc0000584d8 pc=0x42224b9
golang.org/x/sys/unix.IoctlGetTermios(...)
	/Users/dynamicui/Downloads/3.AMapProj/NetrisTV/ws-qvh/vendor/golang.org/x/sys/unix/ioctl.go:72
github.com/sirupsen/logrus.isTerminal(0x504c9e0)
	/Users/dynamicui/Downloads/3.AMapProj/NetrisTV/ws-qvh/vendor/github.com/sirupsen/logrus/terminal_check_bsd.go:11 +0x50 fp=0xc000058578 sp=0xc000058508 pc=0x4224cb0
github.com/sirupsen/logrus.checkIfTerminal({0x4328080, 0xc0000b0010})
	/Users/dynamicui/Downloads/3.AMapProj/NetrisTV/ws-qvh/vendor/github.com/sirupsen/logrus/terminal_check_notappengine.go:13 +0x75 fp=0xc000058590 sp=0xc000058578 pc=0x4224d55
github.com/sirupsen/logrus.(*TextFormatter).init(0xc0000b2240, 0x5700800)
	/Users/dynamicui/Downloads/3.AMapProj/NetrisTV/ws-qvh/vendor/github.com/sirupsen/logrus/text_formatter.go:103 +0x34 fp=0xc000058610 sp=0xc000058590 pc=0x4224e34
github.com/sirupsen/logrus.(*TextFormatter).Format.func1()
	/Users/dynamicui/Downloads/3.AMapProj/NetrisTV/ws-qvh/vendor/github.com/sirupsen/logrus/text_formatter.go:193 +0x25 fp=0xc000058630 sp=0xc000058610 pc=0x42264e5
sync.(*Once).doSlow(0x432d298, 0xc0000a6168)
	/usr/local/go/src/sync/once.go:68 +0xd2 fp=0xc000058698 sp=0xc000058630 pc=0x406cfd2
sync.(*Once).Do(...)
	/usr/local/go/src/sync/once.go:59
github.com/sirupsen/logrus.(*TextFormatter).Format(0xc0000b2240, 0xc0000f60e0)
	/Users/dynamicui/Downloads/3.AMapProj/NetrisTV/ws-qvh/vendor/github.com/sirupsen/logrus/text_formatter.go:193 +0xebe fp=0xc000058c08 sp=0xc000058698 pc=0x4225e9e
github.com/sirupsen/logrus.(*Entry).write(0xc0000f60e0)
	/Users/dynamicui/Downloads/3.AMapProj/NetrisTV/ws-qvh/vendor/github.com/sirupsen/logrus/entry.go:275 +0xa5 fp=0xc000058c80 sp=0xc000058c08 pc=0x42233a5
github.com/sirupsen/logrus.Entry.log({0xc0000f6000, 0xc00009b290, {0x0, 0x0, 0x0}, 0x0, 0x0, {0x0, 0x0}, 0x0, ...}, ...)
	/Users/dynamicui/Downloads/3.AMapProj/NetrisTV/ws-qvh/vendor/github.com/sirupsen/logrus/entry.go:251 +0x285 fp=0xc000058d00 sp=0xc000058c80 pc=0x4223045
github.com/sirupsen/logrus.(*Entry).Log(0xc0000f6070, 0x4, {0xc000058e30, 0x422405a, 0xc0000f6040})
	/Users/dynamicui/Downloads/3.AMapProj/NetrisTV/ws-qvh/vendor/github.com/sirupsen/logrus/entry.go:287 +0xa8 fp=0xc000058e08 sp=0xc000058d00 pc=0x42235c8
github.com/sirupsen/logrus.(*Entry).Logln(0xc0000f6070, 0x4, {0xc000058f40, 0x42c4280, 0xc000000101})
	/Users/dynamicui/Downloads/3.AMapProj/NetrisTV/ws-qvh/vendor/github.com/sirupsen/logrus/entry.go:378 +0x85 fp=0xc000058e50 sp=0xc000058e08 pc=0x4223785
github.com/sirupsen/logrus.(*Entry).Infoln(...)
	/Users/dynamicui/Downloads/3.AMapProj/NetrisTV/ws-qvh/vendor/github.com/sirupsen/logrus/entry.go:391
github.com/sirupsen/logrus.(*Entry).Println(...)
	/Users/dynamicui/Downloads/3.AMapProj/NetrisTV/ws-qvh/vendor/github.com/sirupsen/logrus/entry.go:395
github.com/sirupsen/logrus.(*Logger).Println(0xc0000f6000, {0xc000058f40, 0x1, 0x1})
	/Users/dynamicui/Downloads/3.AMapProj/NetrisTV/ws-qvh/vendor/github.com/sirupsen/logrus/logger.go:259 +0x51 fp=0xc000058e90 sp=0xc000058e50 pc=0x4224651
github.com/sirupsen/logrus.Println(...)
	/Users/dynamicui/Downloads/3.AMapProj/NetrisTV/ws-qvh/vendor/github.com/sirupsen/logrus/exported.go:194
main.startWebSocketServer({0x7ffeefbff527, 0x6})
	/Users/dynamicui/Downloads/3.AMapProj/NetrisTV/ws-qvh/main.go:33 +0x7c fp=0xc000058f60 sp=0xc000058e90 pc=0x424b65c
main.main()
	/Users/dynamicui/Downloads/3.AMapProj/NetrisTV/ws-qvh/main.go:29 +0x56 fp=0xc000058f80 sp=0xc000058f60 pc=0x424b5b6
runtime.main()
	/usr/local/go/src/runtime/proc.go:255 +0x227 fp=0xc000058fe0 sp=0xc000058f80 pc=0x40390e7
runtime.goexit()
	/usr/local/go/src/runtime/asm_amd64.s:1581 +0x1 fp=0xc000058fe8 sp=0xc000058fe0 pc=0x40668a1
	

So, did any steps I miss? pls let me know that ,thanks.

ws-qvh not working on Ubuntu

ws-qvh is very cool and is working very well on Mac. I want it to be run on Ubuntu but fail. There is no video data output. I have tried to update to the latest quicktime_video_hack project. The output is the same.

Following is what I have done.

  1. upgrade to latest quicktime_video_hack with 2 patch from ws-qvh
  2. Modify main.go to fit with latest go-ios which must change go-ios/usbmux to go-ios/ios
  3. build ws-qvh-new on ubuntu
    [on linux]
  4. run sudo usbmuxd &
  5. run idevicepair pair
  6. run ws-qvh-new 0.0.0.0:8888
  7. run modified simple web client with h246 renderer connect to ws://:8888
  8. No video output. Find the console output for ws-qvh-new from below
  9. Original ws-qvh is with same result.
  10. I can stream video with ws-qvh & ws-qvh-new on mac.

image
...
image

Device waiting for ping

Hello,

When I click the phone, console log says:

INFO[0000] Starting WebSocket server
INFO[0004] Device '000080xxxx' USB connection ready, waiting for ping..
2021/01/14 13:03:19 handle_events: error: libusb: interrupted [code -10]
2021/01/14 13:03:20 handle_events: error: libusb: interrupted [code -10]
2021/01/14 13:03:22 handle_events: error: libusb: interrupted [code -10]

iPhone: XS Pc: Mac mini Catalina 10.15.3

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.