GithubHelp home page GithubHelp logo

lithdew / quickjs Goto Github PK

View Code? Open in Web Editor NEW
146.0 7.0 37.0 532 KB

Go bindings to QuickJS: a fast, small, and embeddable ES2020 JavaScript interpreter.

License: MIT License

C 98.94% C++ 0.41% Go 0.65%
golang quickjs javascript es2020

quickjs's Introduction

quickjs

MIT License go.dev reference Discord Chat

Go bindings to QuickJS: a fast, small, and embeddable ES2020 JavaScript interpreter.

These bindings are a WIP and do not match full parity with QuickJS' API, though expose just enough features to be usable. The version of QuickJS that these bindings bind to may be located here.

These bindings have been tested to cross-compile and run successfully on Linux, Windows, and Mac using gcc-7 and mingw32 without any addtional compiler or linker flags.

Usage

$ go get github.com/lithdew/quickjs

Guidelines

  1. Free quickjs.Runtime and quickjs.Context once you are done using them.
  2. Free quickjs.Value's returned by Eval() and EvalFile(). All other values do not need to be freed, as they get garbage-collected.
  3. You may access the stacktrace of an error returned by Eval() or EvalFile() by casting it to a *quickjs.Error.
  4. Make new copies of arguments should you want to return them in functions you created.
  5. Make sure to call runtime.LockOSThread() to ensure that QuickJS always operates in the exact same thread.

Example

The full example code below may be found by clicking here. Find more API examples here.

package main

import (
	"errors"
	"flag"
	"fmt"
	"github.com/lithdew/quickjs"
	"strings"
)

func check(err error) {
	if err != nil {
		var evalErr *quickjs.Error
		if errors.As(err, &evalErr) {
			fmt.Println(evalErr.Cause)
			fmt.Println(evalErr.Stack)
		}
		panic(err)
	}
}

func main() {
	runtime := quickjs.NewRuntime()
	defer runtime.Free()

	context := runtime.NewContext()
	defer context.Free()

	globals := context.Globals()

	// Test evaluating template strings.

	result, err := context.Eval("`Hello world! 2 ** 8 = ${2 ** 8}.`")
	check(err)
	defer result.Free()

	fmt.Println(result.String())
	fmt.Println()

	// Test evaluating numeric expressions.

	result, err = context.Eval(`1 + 2 * 100 - 3 + Math.sin(10)`)
	check(err)
	defer result.Free()

	fmt.Println(result.Int64())
	fmt.Println()

	// Test evaluating big integer expressions.

	result, err = context.Eval(`128n ** 16n`)
	check(err)
	defer result.Free()

	fmt.Println(result.BigInt())
	fmt.Println()

	// Test evaluating big decimal expressions.

	result, err = context.Eval(`128l ** 12l`)
	check(err)
	defer result.Free()

	fmt.Println(result.BigFloat())
	fmt.Println()

	// Test evaluating boolean expressions.

	result, err = context.Eval(`false && true`)
	check(err)
	defer result.Free()

	fmt.Println(result.Bool())
	fmt.Println()

	// Test setting and calling functions.

	A := func(ctx *quickjs.Context, this quickjs.Value, args []quickjs.Value) quickjs.Value {
		fmt.Println("A got called!")
		return ctx.Null()
	}

	B := func(ctx *quickjs.Context, this quickjs.Value, args []quickjs.Value) quickjs.Value {
		fmt.Println("B got called!")
		return ctx.Null()
	}

	globals.Set("A", context.Function(A))
	globals.Set("B", context.Function(B))

	_, err = context.Eval(`for (let i = 0; i < 10; i++) { if (i % 2 === 0) A(); else B(); }`)
	check(err)

	fmt.Println()

	// Test setting global variables.

	_, err = context.Eval(`HELLO = "world"; TEST = false;`)
	check(err)

	names, err := globals.PropertyNames()
	check(err)

	fmt.Println("Globals:")
	for _, name := range names {
		val := globals.GetByAtom(name.Atom)
		defer val.Free()

		fmt.Printf("'%s': %s\n", name, val)
	}
	fmt.Println()

	// Test evaluating arbitrary expressions from flag arguments.

	flag.Parse()
	if flag.NArg() == 0 {
		return
	}

	result, err = context.Eval(strings.Join(flag.Args(), " "))
	check(err)
	defer result.Free()

	if result.IsObject() {
		names, err := result.PropertyNames()
		check(err)

		fmt.Println("Object:")
		for _, name := range names {
			val := result.GetByAtom(name.Atom)
			defer val.Free()

			fmt.Printf("'%s': %s\n", name, val)
		}
	} else {
		fmt.Println(result.String())
	}
}
$ go run examples/main.go '(() => ({hello: "world", test: 2 ** 3}))()'
Hello world! 2 ** 8 = 256.

197

5192296858534827628530496329220096

1.9342813113834066795e+25

false

A got called!
B got called!
A got called!
B got called!
A got called!
B got called!
A got called!
B got called!
A got called!
B got called!

Globals:
'Object': function Object() {
    [native code]
}
'Function': function Function() {
    [native code]
}
'Error': function Error() {
    [native code]
}
'EvalError': function EvalError() {
    [native code]
}
'RangeError': function RangeError() {
    [native code]
}
'ReferenceError': function ReferenceError() {
    [native code]
}
'SyntaxError': function SyntaxError() {
    [native code]
}
'TypeError': function TypeError() {
    [native code]
}
'URIError': function URIError() {
    [native code]
}
'InternalError': function InternalError() {
    [native code]
}
'AggregateError': function AggregateError() {
    [native code]
}
'Array': function Array() {
    [native code]
}
'parseInt': function parseInt() {
    [native code]
}
'parseFloat': function parseFloat() {
    [native code]
}
'isNaN': function isNaN() {
    [native code]
}
'isFinite': function isFinite() {
    [native code]
}
'decodeURI': function decodeURI() {
    [native code]
}
'decodeURIComponent': function decodeURIComponent() {
    [native code]
}
'encodeURI': function encodeURI() {
    [native code]
}
'encodeURIComponent': function encodeURIComponent() {
    [native code]
}
'escape': function escape() {
    [native code]
}
'unescape': function unescape() {
    [native code]
}
'Infinity': Infinity
'NaN': NaN
'undefined': undefined
'__date_clock': function __date_clock() {
    [native code]
}
'Number': function Number() {
    [native code]
}
'Boolean': function Boolean() {
    [native code]
}
'String': function String() {
    [native code]
}
'Math': [object Math]
'Reflect': [object Object]
'Symbol': function Symbol() {
    [native code]
}
'eval': function eval() {
    [native code]
}
'globalThis': [object Object]
'Date': function Date() {
    [native code]
}
'RegExp': function RegExp() {
    [native code]
}
'JSON': [object JSON]
'Proxy': function Proxy() {
    [native code]
}
'Map': function Map() {
    [native code]
}
'Set': function Set() {
    [native code]
}
'WeakMap': function WeakMap() {
    [native code]
}
'WeakSet': function WeakSet() {
    [native code]
}
'ArrayBuffer': function ArrayBuffer() {
    [native code]
}
'SharedArrayBuffer': function SharedArrayBuffer() {
    [native code]
}
'Uint8ClampedArray': function Uint8ClampedArray() {
    [native code]
}
'Int8Array': function Int8Array() {
    [native code]
}
'Uint8Array': function Uint8Array() {
    [native code]
}
'Int16Array': function Int16Array() {
    [native code]
}
'Uint16Array': function Uint16Array() {
    [native code]
}
'Int32Array': function Int32Array() {
    [native code]
}
'Uint32Array': function Uint32Array() {
    [native code]
}
'BigInt64Array': function BigInt64Array() {
    [native code]
}
'BigUint64Array': function BigUint64Array() {
    [native code]
}
'Float32Array': function Float32Array() {
    [native code]
}
'Float64Array': function Float64Array() {
    [native code]
}
'DataView': function DataView() {
    [native code]
}
'Atomics': [object Atomics]
'Promise': function Promise() {
    [native code]
}
'BigInt': function BigInt() {
    [native code]
}
'BigFloat': function BigFloat() {
    [native code]
}
'BigFloatEnv': function BigFloatEnv() {
    [native code]
}
'BigDecimal': function BigDecimal() {
    [native code]
}
'Operators': function Operators() {
    [native code]
}
'A': function() { return proxy.call(this, id, ...arguments); }
'B': function() { return proxy.call(this, id, ...arguments); }
'HELLO': world
'TEST': false

Object:
'hello': world
'test': 8

License

QuickJS is released under the MIT license.

QuickJS bindings are copyright Kenta Iwasaki, with code copyright Fabrice Bellard and Charlie Gordon.

quickjs's People

Contributors

cemremengu avatar lithdew 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

quickjs's Issues

"At code:1" error message

  1. platform: mac
  2. code
func TestName(t *testing.T) {
	const code = `
var name = "test_hello";

function main() {
}

main();
`
	runtime := quickjs.NewRuntime()

	context := runtime.NewContext()
	defer context.Free()

	for {
		val, err := context.Eval(code)
		if err != nil {
			fmt.Printf("%#v\n", err)
			time.Sleep(time.Second)
			continue
		}

		g:=context.Globals()
		fmt.Println(g.Get("name"),val)
		time.Sleep(time.Millisecond*10)
		val.Free()
	}
}
  1. output
test_hello undefined
test_hello undefined
test_hello undefined
test_hello undefined
test_hello undefined
test_hello undefined
test_hello undefined
test_hello undefined
test_hello undefined
test_hello undefined
test_hello undefined
&quickjs.Error{Cause:"", Stack:"    at code:1\n"}
&quickjs.Error{Cause:"", Stack:"    at code:1\n"}
&quickjs.Error{Cause:"", Stack:"    at code:1\n"}
&quickjs.Error{Cause:"", Stack:"    at code:1\n"}
&quickjs.Error{Cause:"", Stack:"    at code:1\n"}
&quickjs.Error{Cause:"", Stack:"    at code:1\n"}
&quickjs.Error{Cause:"", Stack:"    at code:1\n"}
&quickjs.Error{Cause:"", Stack:"    at code:1\n"}
&quickjs.Error{Cause:"", Stack:"    at code:1\n"}
&quickjs.Error{Cause:"", Stack:"    at code:1\n"}
&quickjs.Error{Cause:"", Stack:"    at code:1\n"}
&quickjs.Error{Cause:"", Stack:"    at code:1\n"}
&quickjs.Error{Cause:"", Stack:"    at code:1\n"}
&quickjs.Error{Cause:"", Stack:"    at code:1\n"}
&quickjs.Error{Cause:"", Stack:"    at code:1\n"}
&quickjs.Error{Cause:"", Stack:"    at code:1\n"}
&quickjs.Error{Cause:"", Stack:"    at code:1\n"}
&quickjs.Error{Cause:"", Stack:"    at code:1\n"}
&quickjs.Error{Cause:"", Stack:"    at code:1\n"}
&quickjs.Error{Cause:"", Stack:"    at code:1\n"}
&quickjs.Error{Cause:"", Stack:"    at code:1\n"}
&quickjs.Error{Cause:"", Stack:"    at code:1\n"}
test_hello undefined

Still alive?

Hey, your project seems really cool! I saw your the last activity was about ~8 months ago, is it still in development?

Freeing quickjs.Runtime after creating a new function causes a segmentation fault.

The suspicion is of possible misuse of JS_NewCFunctionData, which is used over JS_NewCFunction to provide an opaque pointer to proxy() in Go to dispatch Go functions in C.

It may be that this is not the intended use of JS_NewCFunctionData, and that calling JS_FreeRuntime frees unintended memory as a result.

func main() {
	runtime := quickjs.NewRuntime()
	defer runtime.Free()

	ctx := runtime.NewContext()
	defer ctx.Free()

	globals := ctx.Globals()
	defer globals.Free()

	httpFunc := ctx.Function(func(ctx quickjs.Context, this quickjs.Value, args []quickjs.Value) quickjs.Value {
		if len(args) != 1 || !args[0].IsString() {
			return ctx.ThrowTypeError("http(request: string)")
		}

		request := args[0]
		fmt.Println(request.String())

		return request
	})
	defer httpFunc.Free()

	globals.Set("http", httpFunc)

	result, err := ctx.Eval(`http('test')`)
	check(err)
	defer result.Free()

	fmt.Println(result)
}
$ CGO_CFLAGS="-DDUMP_LEAKS" go run main.go
# command-line-arguments
/tmp/go-link-072279044/000024.o: In function `_cgo_26061493d47f_C2func_getaddrinfo':
cgo_unix.cgo2.c:(.text+0x81): warning: Using 'getaddrinfo' in statically linked applications requires at runtime the shared libraries from the glibc version used for linking
test
test
main: quickjs.c:5625: gc_decref_child: Assertion `p->ref_count > 0' failed.
SIGABRT: abort
PC=0x782978 m=0 sigcode=18446744073709551610

goroutine 0 [idle]:
runtime: unknown pc 0x782978
stack: frame={sp:0x7ffd922906b8, fp:0x0} stack=[0x7ffd91a91ae8,0x7ffd92290b10)
00007ffd922905b8:  000000000092db5c  0000000000000000 
00007ffd922905c8:  0000000000798780  00000000fbad8000 
00007ffd922905d8:  00000000022c1a00  00000000022c1a00 
00007ffd922905e8:  00000000022c1a00  00000000022c1a00 
00007ffd922905f8:  00000000022c1a4c  00000000022c1a64 
00007ffd92290608:  00000000022c1a00  00000000022c1a64 
00007ffd92290618:  0000000000000000  0000000000000000 
00007ffd92290628:  0000000000000000  0000000000000000 
00007ffd92290638:  0000000000000000  0000000092290660 
00007ffd92290648:  0000000000688a26  00000000022c0000 
00007ffd92290658:  0000000000000000  00007ffd92290690 
00007ffd92290668:  0000000000688aae  ffffffffffffffff 
00007ffd92290678:  0000000000000000  00000000022b70c8 
00007ffd92290688:  00007f356e578000  00000000009b2420 
00007ffd92290698:  000000000092d5c4  00000000000015f9 
00007ffd922906a8:  000000000092db5c  0000000000000000 
00007ffd922906b8: <0000000000782d0a  0000000000000020 
00007ffd922906c8:  0000000000000000  0000000000000000 
00007ffd922906d8:  0000000000000000  0000000000000000 
00007ffd922906e8:  0000000000000000  0000000000000000 
00007ffd922906f8:  0000000000000000  0000000000000000 
00007ffd92290708:  0000000000000000  0000000000000000 
00007ffd92290718:  0000000000000000  0000000000000000 
00007ffd92290728:  0000000000000000  0000000000000000 
00007ffd92290738:  0000000000000000  0000000000000004 
00007ffd92290748:  00000000022b7ab0  00007ffd92290720 
00007ffd92290758:  00000016022c9230  0000000000000000 
00007ffd92290768:  00007f356e578000  00000000009b2420 
00007ffd92290778:  000000000092d5c4  00000000000015f9 
00007ffd92290788:  000000000092db5c  0000000000000000 
00007ffd92290798:  00000000007a5377  00000000022c3bf0 
00007ffd922907a8:  fffffffffffffff9  00000000009c9e9c 
runtime: unknown pc 0x782978
stack: frame={sp:0x7ffd922906b8, fp:0x0} stack=[0x7ffd91a91ae8,0x7ffd92290b10)
00007ffd922905b8:  000000000092db5c  0000000000000000 
00007ffd922905c8:  0000000000798780  00000000fbad8000 
00007ffd922905d8:  00000000022c1a00  00000000022c1a00 
00007ffd922905e8:  00000000022c1a00  00000000022c1a00 
00007ffd922905f8:  00000000022c1a4c  00000000022c1a64 
00007ffd92290608:  00000000022c1a00  00000000022c1a64 
00007ffd92290618:  0000000000000000  0000000000000000 
00007ffd92290628:  0000000000000000  0000000000000000 
00007ffd92290638:  0000000000000000  0000000092290660 
00007ffd92290648:  0000000000688a26  00000000022c0000 
00007ffd92290658:  0000000000000000  00007ffd92290690 
00007ffd92290668:  0000000000688aae  ffffffffffffffff 
00007ffd92290678:  0000000000000000  00000000022b70c8 
00007ffd92290688:  00007f356e578000  00000000009b2420 
00007ffd92290698:  000000000092d5c4  00000000000015f9 
00007ffd922906a8:  000000000092db5c  0000000000000000 
00007ffd922906b8: <0000000000782d0a  0000000000000020 
00007ffd922906c8:  0000000000000000  0000000000000000 
00007ffd922906d8:  0000000000000000  0000000000000000 
00007ffd922906e8:  0000000000000000  0000000000000000 
00007ffd922906f8:  0000000000000000  0000000000000000 
00007ffd92290708:  0000000000000000  0000000000000000 
00007ffd92290718:  0000000000000000  0000000000000000 
00007ffd92290728:  0000000000000000  0000000000000000 
00007ffd92290738:  0000000000000000  0000000000000004 
00007ffd92290748:  00000000022b7ab0  00007ffd92290720 
00007ffd92290758:  00000016022c9230  0000000000000000 
00007ffd92290768:  00007f356e578000  00000000009b2420 
00007ffd92290778:  000000000092d5c4  00000000000015f9 
00007ffd92290788:  000000000092db5c  0000000000000000 
00007ffd92290798:  00000000007a5377  00000000022c3bf0 
00007ffd922907a8:  fffffffffffffff9  00000000009c9e9c 

goroutine 1 [syscall]:
runtime.cgocall(0x6578e2, 0xc000059db0, 0x1f9)
        /snap/go/current/src/runtime/cgocall.go:133 +0x5b fp=0xc000059d80 sp=0xc000059d48 pc=0x403fab
github.com/lithdew/quickjs._Cfunc_JS_FreeRuntime(0x22b7030)
        _cgo_gotypes.go:260 +0x41 fp=0xc000059db0 sp=0xc000059d80 pc=0x504551
github.com/lithdew/quickjs.Runtime.Free.func1(0x22b7030)
        /home/kenta/lithdew/quickjs/quickjs.go:33 +0x4d fp=0xc000059de0 sp=0xc000059db0 pc=0x50691d
github.com/lithdew/quickjs.Runtime.Free(0x22b7030)
        /home/kenta/lithdew/quickjs/quickjs.go:33 +0x2b fp=0xc000059df8 sp=0xc000059de0 pc=0x50556b
main.main()
        /home/kenta/lithdew/ghost/main.go:109 +0x40e fp=0xc000059f88 sp=0xc000059df8 pc=0x656d2e
runtime.main()
        /snap/go/current/src/runtime/proc.go:203 +0x1fa fp=0xc000059fe0 sp=0xc000059f88 pc=0x4359fa
runtime.goexit()
        /snap/go/current/src/runtime/asm_amd64.s:1373 +0x1 fp=0xc000059fe8 sp=0xc000059fe0 pc=0x4620d1

rax    0x0
rbx    0x7f356e578000
rcx    0x782978
rdx    0x6
rdi    0x6960
rsi    0x6960
rbp    0x9b2420
rsp    0x7ffd922906b8
r8     0x22c1a00
r9     0x0
r10    0x8
r11    0x206
r12    0x92d5c4
r13    0x15f9
r14    0x92db5c
r15    0x0
rip    0x782978
rflags 0x206
cs     0x33
fs     0x0
gs     0x0
exit status 2
func main() {
	runtime := quickjs.NewRuntime()
	defer runtime.Free()

	ctx := runtime.NewContext()
	defer ctx.Free()

	globals := ctx.Globals()
	defer globals.Free()

	httpFunc := ctx.Function(func(ctx quickjs.Context, this quickjs.Value, args []quickjs.Value) quickjs.Value {
		if len(args) != 1 || !args[0].IsString() {
			return ctx.ThrowTypeError("http(request: string)")
		}

		request := args[0]
		fmt.Println(request.String())

		return request
	})
	//defer httpFunc.Free()

	globals.Set("http", httpFunc)

	result, err := ctx.Eval(`http('test')`)
	check(err)
	//defer result.Free()

	fmt.Println(result)
}
$ CGO_CFLAGS="-DDUMP_LEAKS" go run main.go
# command-line-arguments
/tmp/go-link-896294616/000024.o: In function `_cgo_26061493d47f_C2func_getaddrinfo':
cgo_unix.cgo2.c:(.text+0x81): warning: Using 'getaddrinfo' in statically linked applications requires at runtime the shared libraries from the glibc version used for linking
test
test
fatal error: unexpected signal during runtime execution
[signal SIGSEGV: segmentation violation code=0x2 addr=0x1e4c030 pc=0x1e4c030]

runtime stack:
runtime.throw(0x8bd124, 0x2a)
        /snap/go/current/src/runtime/panic.go:1116 +0x72
runtime.sigpanic()
        /snap/go/current/src/runtime/signal_unix.go:679 +0x46a

goroutine 1 [syscall]:
runtime.cgocall(0x6577e2, 0xc000059e08, 0x1f9)
        /snap/go/current/src/runtime/cgocall.go:133 +0x5b fp=0xc000059dd8 sp=0xc000059da0 pc=0x403fab
github.com/lithdew/quickjs._Cfunc_JS_FreeRuntime(0x1e38010)
        _cgo_gotypes.go:260 +0x41 fp=0xc000059e08 sp=0xc000059dd8 pc=0x504551
github.com/lithdew/quickjs.Runtime.Free.func1(0x1e38010)
        /home/kenta/lithdew/quickjs/quickjs.go:33 +0x4d fp=0xc000059e38 sp=0xc000059e08 pc=0x50691d
github.com/lithdew/quickjs.Runtime.Free(0x1e38010)
        /home/kenta/lithdew/quickjs/quickjs.go:33 +0x2b fp=0xc000059e50 sp=0xc000059e38 pc=0x50556b
main.main()
        /home/kenta/lithdew/ghost/main.go:109 +0x329 fp=0xc000059f88 sp=0xc000059e50 pc=0x656c49
runtime.main()
        /snap/go/current/src/runtime/proc.go:203 +0x1fa fp=0xc000059fe0 sp=0xc000059f88 pc=0x4359fa
runtime.goexit()
        /snap/go/current/src/runtime/asm_amd64.s:1373 +0x1 fp=0xc000059fe8 sp=0xc000059fe0 pc=0x4620d1
exit status 2

Possible to use inside an http.Handler?

Thanks for putting this package together! It works great out of the box without any additional installation scripts.

I was wondering about Guideline 5.

Make sure to call runtime.LockOSThread() to ensure that QuickJS always operates in the exact same thread.

Does this make QuickJS unsuitable to run inside http.Handlers where you can have many goroutines servicing requests at the same time? The use-case in mind is server-side rendering.

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.