Giter Club home page Giter Club logo

go-questions's Introduction

logo

Go 程序员面试笔试宝典

作者: 饶全成, 欧长坤, 楚秦 等编著
ISBN: 978-7-111-70242-9
出版社机械工业出版社

购买链接

关于本站

这个站点包含了纸质版图书中的部分内容、对纸质版图书内容的部分更新以及勘误, 我们推荐读者购买实体书籍配合本站共同使用。

致读者

因为 Go 语言在服务端的开发效率、服务性能有着不俗的表现,最近几年,Go 的热度越来越高。国内外很多大公司都在大规模地使用 Go。Google 就不用说了,它是 Go 语言诞生的地方,其他公司 如 Meta(Facebook)、uber、腾讯、字节跳动、知乎、脉脉等都在拥抱和转向 Go。用 Go 语言开发的著名开源项目也非常多,如 k8s、docker、etcd、consul,每个名字都是如雷贯耳。

随着市场对 Go 语言人才需求的不断增长,很多开发人员都从其他语言,如 PHP、C++、Java 等 转投 Go 语言的怀抱。因为 Go 语言自身的特点和优势,这些转型的开发人员也能写出性能不错的代码。但是,由于没有深入系统地学习 Go 的底层原理,在某些场景下,因为不懂底层原理,无法快速定位问题、无法进行性能优化。

有些人说,语言并不重要,架构、技术选型这些才是根本。笔者觉得这个说法不完全对,架构、技术选型固然重要,但语言其实是开发人员每天都要打交道的东西,会用是远远不够的,只有用好、知其所以然才能更全面地发挥其威力。

近一两年,笔者在中文世界论坛里发表了很多篇与 Go 源码阅读相关的文章,也是在写作本书的过程中做的功课。我通过看源码、做实验、请教大牛,对 Go 的“理解”逐渐加深。再去看很多文章就会感觉非常简单,为什么这些我都能掌握? 因为我研究过,我知道原理是什么,所以也知道你想要说什么。

最后,无论你是面试官,还是求职者,这本书都能让你有所收获。另外,本书内容不仅仅是对面试有帮助,所有写 Go 的程序员都能从本书中有所收获,能让你的 Go 水平真正上升一个台阶。

致谢

在写作本书的过程中,我和本书的二作欧长坤有很多交流讨论,他对 Go 的理解非常深,他同时也是 Go Contributor,我们的交流和讨论让我对很多问题有了更深入的理解, 非常感谢。我从 Go 夜读社区 的分享中学到了很多东西。并且我本人也担任讲师,分享了多期 Go 相关的内容,很多观众都表示很有帮助。教是最好的学,我本人的收获是最多的。感谢 Go 夜读社区的发起者杨文及 SIG 小组成员煎鱼傲飞。另外,我和 “Go 圈” 的很多博客作者也有很多交流,比如曹大Draven 大神收获良多,在此一并感谢。这两年,我在 “码农桃花源” 发表了很多文章,得到了很多读者的肯定,这也是我能不断写作的动力,感谢你们。

交流和勘误

我们在这里维护了一份已出版内容的勘误表,以帮助并消除读者在阅读过程中出现的困惑。 读者还可以本书的 GitHub 仓库 里讨论关于本书内容的问题,或报告并提交本书存在的错误。

我们欢迎你在 GitHub 仓库上发起 Issues 或提交 Pull Request

我们也欢迎你关注 “码农桃花源” 的公众号,和更多的人一起学习:

logo

作者的其他技术分享视频

主题 作者 观看链接
Go defer 和逃逸分析 饶全成 YouTuBe, Bilibili
Go map 源码阅读 饶全成 YouTuBe, Bilibili
Go Scheduler 源码阅读 饶全成 YouTuBe, Bilibili
Go channel & select 源码阅读 欧长坤 YouTuBe, Bilibili
CSP 理解顺序进程间通信 欧长坤 YouTuBe, Bilibili
真实世界中的 Go 程序并发错误 欧长坤 YouTuBe, Bilibili
Go 1.14 time.Timer 源码分析 欧长坤 YouTuBe, Bilibili
Go 2 泛型预览 欧长坤 YouTuBe, Bilibili
对 Go 程序进行可靠的性能测试 欧长坤 YouTuBe, Bilibili
Go 1.18 的泛型 欧长坤 YouTuBe, Bilibili

许可

知识共享许可协议

Go 程序员面试笔试宝典 由 饶全成, 欧长坤, 楚秦等 采用署名-非商业性使用-禁止演绎 4.0 国际许可协议许可
严禁任何商业行为使用或引用该文档的全部或部分内容,特授权 golang.design/go-questions 发布

go-questions's People

Contributors

alilestera avatar banbo avatar changkun avatar chanyang97 avatar crazywr avatar cuishuang avatar dagsi avatar decade613 avatar felixseptem avatar fennay avatar hawken94 avatar latavin243 avatar minoic avatar oiar avatar qcrao avatar shenbinzai avatar simonwei97 avatar yangchen97 avatar yangwenmai 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  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

go-questions's Issues

Page 32 annotation typo

实际描述

  • 原文页码:32
  • 原文段落:第 2 个代码块
// 初始化 hamp

预期描述

// 初始化 hmap

第三章:数据容器3.1.2-Page22

实际描述

  • 原文页码:P22
  • 原文段落:从上至下第三段
再次向S2追加元素200:
`s2 = append(s2, 100)`

预期描述

再次向S2追加元素200:
`s2 = append(s2, 200)`这里应该是200不是100

附图

必要时,请附上相关页面的照片或者截图

关于Yuasa屏障的疑问

欧神好, 按照yuasa写屏障的图示, 当C作为黑色对象去引用白色对象B, Yuasa屏障将C变为灰色, B颜色不变. 这不是避免满足了条件1吗. 不允许黑色对象去引用白色对象..

切片作为函数参数这一章节,倒数第三段描述应该不准确

问题描述

请在此描述你的问题,提问前请参考提问的智慧

原文是这么说的:

myAppend 函数里,虽然改变了 s,但它只是一个值传递,并不会影响外层的 s,因此第一行打印出来的结果仍然是 [1 1 1]。

这个地方我在第一次看到的时候有点歧义,虽说slice是一个值传递,但是slice中是包含是指向数组的指针的。按理说,值传递的也是数组的指针。

经过验证,不影响的准确原因应该是append触发了slice的扩容,扩容会导致copy,也就是说slice结构体中指向数组的指针发生了变化。因此外层的s不会发生变化。
如果是直接修改slice元素,内外层都会改变

func myAppend(s []int) []int {
	//s = append(s, 100)
	s[0] = 100
	fmt.Printf("s point out func: %p, %p\n", s, &s)
	return s
}

我个人的理解,如有不对,欢迎讨论~

Page 288 (并发标记清除法的难点是什么)

Page 288 (并发标记清除法的难点是什么)

  • 原文页码:288
  • 原文段落:
A.ref1 = nil:移除灰色对象 A 对白色对象 B 的引用(ref2)

预期描述

A.ref1 = nil:移除灰色对象 A 对白色对象 B 的引用(ref1)

错误处理的As 和 Is 函数有误

实际描述

As 应该是判断是否为同一个类型,Is 是判断是否为同一个值

  • 原文页码:132
  • 原文段落:As 从 err 错误链里找到第一个和 target 相等的值并且设置为 target 。。。
复制原文段落

预期描述

修改后的段落

附图

必要时,请附上相关页面的照片或者截图

调度时机章节有误

实际描述

https://golang.design/go-questions/sched/when/

  • 原文页码:
  • 原文段落:
复制原文段落

image

预期描述

还包括 “函数调用”的时候,每个函数头都有一行栈检查代码。会有一个背景程序(来达到抢占式调度的目的)定时污染这个栈limit,导致程序进入runtime,
触发调度

参考 https://www.youtube.com/watch?v=-K11rY57K7k
52:24 function prologue
image

52:41 spoof stack limit

或者也可以参考 https://golangbyexample.com/goroutines-golang/
image

修改后的段落

附图

必要时,请附上相关页面的照片或者截图

垃圾回收机制图片错误

实际描述

  • 原文页码:
  • p290 p291
  • 原文段落:
    图14-16和图14-7
    图14-16的Dijxxxx(C.ref3, C.ref2,ref1)的逗号应该变成点Dijxxxx(C.ref3, C.ref2.ref1)
    图14-7的Yuasaxx(A.ref3,B)应该变成Yuasaxx(C.ref3,B)
    还有这两幅图和你博客上的出入非常大,你可以仔细对比下,希望尽快纠正

图片

图片

哈希表的遍历顺序是否有问题?

原文中提到

这样,遍历结果集变成:
遍历结果

按照文中描述,从3号桶的2号cell开始往后顺序遍历。但我翻看了一下文中所使用的1.9.2的源码以及最新的go1.17.5的源码,发现不管哪个Go版本,桶的遍历顺序是3->0->1->2,但每个桶内都要从offset处开始遍历,而不是前后首尾相接的遍历。所以最终的遍历顺序应该是egfcbhda,而不是efgbchad

不知道我是否理解错误,欢迎讨论。

"GC 的认识" 文中写屏障部分有误

dijkstra style barrier 需要栈重扫,不是因为文中说的原因,而是因为 Go 中出于性能考虑不对栈上保存的指针加 barrier。这一点在 proposal 17503 中讲的很清楚:“However, it also has disadvantages. In particular, it presents a trade-off for pointers on stacks: either writes to pointers on the stack must have write barriers, which is prohibitively expensive, or stacks must be permagrey. Go chooses the later, which means that many stacks must be re-scanned during STW. ”

对于文中的 case,并不影响 GC 的正确性,只是让 GC 更加保守。即使没有栈重扫,那个被错误染黑的 A 在下次 GC 也会被回收掉。

Page 192 typo

实际描述

  • 原文页码:192
  • 原文段落:第一段
G 变成 _Grunnale 状态之后

预期描述

G 变成 _Grunnable 状态之后

第12章节

实际描述

  • 原文页码:240
  • 原文段落:
    12.14.1
复制原文段落

这时和P绑定的G正在进行系统调用,无法执行其他的G

预期描述

应该是P绑定的M正在进行系统调用?

修改后的段落

附图

必要时,请附上相关页面的照片或者截图

关于 P 的状态流转

问题描述

image

请问这个 P 的状态流转图中:_Prunning -> _Pidle 由 retake 方法触发是否准确呢(图中红色线框)?

我猜测指的是:随着 preempt 发生,G 解绑后,进入新的调度,此时发现该 P 没有可运行的 G 了,然后还是调用的 releasep 方法将 P 的状态由 _Prunning 改为 _Pidle 的?

请问一个关于 m 和主线程绑定的问题。(顺便提个 typo)

问题描述

作者你好,想请问下,关于书中第 201 页以及其他一些函数中会用到一个 get_tls 方法。我能理解汇编可以通过 fs 段找到 m.tls,但是想问下这里为啥不能直接在 m 这个结构体上获取 g 呀?比如在这个 schedinit 函数中,m0 就是和他同一个包的全局变量,直接从它身上把 m0.tls 捞出来再去拿 g,这样会有什么问题么?
另外还想请问下,所谓的把 m 和主线程绑定,我理解本质上就是通过系统调用把 m.tls[1] 的地址存到 fs 段指向的内存,这个的目的除了是可以直接通过汇编的方式以 fs 寄存器找到当前的 m.tls(比如 get_tls)之外,还有其他的什么作用么?
另外有个 typo,在图片中的 “BX 存器里面现在放的是当前 g 结构体对象的地址”中的 BX 后边少了个寄存器的 “寄”。
WechatIMG33

关于`如何实现字符串和byte切片的零拷贝转换` 字符串转切片代码的问题

问题描述

在线文档中看到字符串转切片的代码

//方法一
func string2bytes(s string) []byte {
	return *(*[]byte)(unsafe.Pointer(&s))
}

运行后转出来的切片cap字段值是824634806128,并且append操作会报如下错误

unexpected fault address 0x10a4280
fatal error: fault
[signal SIGBUS: bus error code=0x2 addr=0x10a4280 pc=0x108b0b6]

网上另一种方案,转出来后的切片是可以像正常切片一样append,修改。

//方法二
func string2bytes(s string) []byte {
	stringHeader := (*reflect.StringHeader)(unsafe.Pointer(&s))
	bh := reflect.SliceHeader{
		Data: stringHeader.Data,
		Len:  stringHeader.Len,
		Cap:  stringHeader.Len,
	}
	runtime.KeepAlive(&s)
	return *(*[]byte)(unsafe.Pointer(&bh))
}

StringHeader 比 SliceHeader 缺少cap字段的,方法一这样转是不是存在问题?请您解答一下

步调算法下界描述有误

从 Go 1.14 开始时 $h_t$ 增加了下界 0.6)

  • 原文页码:292
  • 原文段落:
计算 $H_T$ 的最终结论(从 Go 1.10 时开始 $h_t$ 增加了上界 $0.95 \rho$,从 Go 1.14 开始时 $h_t$ 增加了下界 0.6)

从 Go 1.14 开始时 $h_t$ 增加了下界 $0.6 \rho$

计算 $H_T$ 的最终结论(从 Go 1.10 时开始 $h_t$ 增加了上界 $0.95 \rho$,从 Go 1.14 时开始 $h_t$ 增加了下界 $0.6 \rho$)

附图

src code

image

14.1.8 节

实际描述

  • 原文页码:288
  • 原文段落:A.ref1 = nil: 移除灰色对象 A 对白色对象 B 的引用 (ref2);
A.ref1 = nil: 移除灰色对象 A 对白色对象 B 的引用 (ref2);

预期描述

根据第389页顶部的图 14-5 来看,A.ref1 = B,所以原句里括号的部分是 ref1 吧

A.ref1 = nil: 移除灰色对象 A 对白色对象 B 的引用 (ref1);

附图

必要时,请附上相关页面的照片或者截图

有关优雅关闭channel的问题

问题描述

尊敬的作者您好, 请问在书中78页提供的“有关优雅关闭channel的样例代码“中,假如sender向中间人(toStop)发起关闭的dataCh的信号时,不会出现dataCh无法被完全消费,从而导致内存泄漏的风险吗?

第4章节

实际描述

  • 原文页码:73
  • 原文段落:
复制原文段落

预期描述

代码示例与讲解中图4-14的不符

修改后的段落

附图

必要时,请附上相关页面的照片或者截图

【数组和切片】关于超过数组的上限赋值给新对象不会panic的讨论

不会Panic的写法

testSlice := [...]int{1, 2}
newTestSlice := testSlice[2:]
for _, v := range newTestSlice {
	log.Print(v)
}

会Panic的写法

testSlice := [...]int{1, 2}
newTestSlice := testSlice[3:]
for _, v := range newTestSlice {
	log.Print(v)
}

output:

invalid slice index 3 (out of bounds for 2-element array)

直接取 testSlice[2] 也会报panic。


以上情况能加到数组和切片中去说明一下吗?

Page 289 关于写屏障

问题描述

原文

“因此我们所说的 Go 中的写屏障、混合写屏障,其实是指赋值器的写屏障,赋值器的写屏障作为一种同步机制,使赋值器在进行指针写操作时,能够“通知”回收器,进而不会破坏弱三色不变性。”

写屏障这样描述似乎有些容易和 memory barrier 混淆呢,gc barrier 只是插入的一些代码片段,而 memory barrier 则是一种并发同步操作。

go-questions/channel/graceful-close 文章内容疑似有误

实际描述

对 “IsClosed函数返回的结果仅代表那个瞬间” 的解释可能有笔下误。“IsClosed函数返回true,但这时有另一个goroutine关闭了channel” 应改为 “IsClosed函数返回false,但这时有另一个goroutine关闭了channel”

其次,IsClosed 函数返回的结果仅代表调用那个瞬间,并不能保证调用之后会不会有其他 goroutine 对它进行了一些操作,改变了它的这种状态。例如,IsClosed 函数返回 true,但这时有另一个 goroutine 关闭了 channel,而你还拿着这个过时的 “channel 未关闭”的信息,向其发送数据,就会导致 panic 的发生。当然,一个 channel 不会被重复关闭两次,如果 IsClosed 函数返回的结果是 true,说明 channel 是真的关闭了。

预期描述

其次,IsClosed 函数返回的结果仅代表调用那个瞬间,并不能保证调用之后会不会有其他 goroutine 对它进行了一些操作,改变了它的这种状态。例如,IsClosed 函数返回 false,但这时有另一个 goroutine 关闭了 channel,而你还拿着这个过时的 “channel 未关闭”的信息,向其发送数据,就会导致 panic 的发生。当然,一个 channel 不会被重复关闭两次,如果 IsClosed 函数返回的结果是 true,说明 channel 是真的关闭了。

Page 64 4-3 recv workflow graph

实际描述

  • 原文页码:64
  • 原文段落:图 4-3
 缓冲区是否有数据?
- 是 ...
- 否 -> (返回true, true) -> 复制缓冲区元素

预期描述

 缓冲区是否有数据?
- 是 -> (返回true, true) -> 复制缓冲区元素
- 否 ...

所以如果没理解错的话,这好像是个比较大的错误了?

零拷贝实现string 和bytes的转换疑问

func string2bytes(s string) []byte {
	stringHeader := (*reflect.StringHeader)(unsafe.Pointer(&s))

	bh := reflect.SliceHeader{
		Data: stringHeader.Data,
		Len:  stringHeader.Len,
		Cap:  stringHeader.Len,
	}

	return *(*[]byte)(unsafe.Pointer(&bh))
}

1,这里的Data 是一个uintptr整型,把stringHeader.Data作为值拷贝,后面gc不会移动或者回收该uintptr指向的内存吗?

2,在官方文档里面的描述是这样的:

// In general, reflect.SliceHeader and reflect.StringHeader should be used
// only as *reflect.SliceHeader and *reflect.StringHeader pointing at actual
// slices or strings, never as plain structs.
// A program should not declare or allocate variables of these struct types.
//	// INVALID: a directly-declared header will not hold Data as a reference.
//	var hdr reflect.StringHeader
//	hdr.Data = uintptr(unsafe.Pointer(p))
//	hdr.Len = n
//	s := *(*string)(unsafe.Pointer(&hdr)) // p possibly already lost

你的转换函数是不是换成下面的更好?

func string2bytes(s string) []byte {
	stringHeader := (*reflect.StringHeader)(unsafe.Pointer(&s))

        var b []byte
        pbytes := (*reflect.SliceHeader)(unsafe.Pointer(&b))
        pbytes.Data = stringHeader.Data
        pbytes.Len = stringHeader.Len
        pbytes.Cap = stringHeader.Cap

	return b
}

关于 Golang 内存分配机制 的延伸问题

问题描述

Golang 的内存分配机制有两大策略
顺序分配 (sequential allocation) 和
自由表分配 (free-list allocation)

其中,顺序分配比较迎合 Go Routine 的执行栈,因为一次可以分配整块内存空间

但是问题来了,Go Routine 的执行栈要扩容,如果用 自由表分配 扩容时,就不需要重新复制整个 Go Routine 的执行栈
所以 Golang 应是以 自由表分配 为主比较合理?

我的观点正确吗?谢谢

纸质版印刷图片展示不友好

纸质版印刷图片展示不友好

  • 原文页码:P278/P306
  • 原文段落:书中的一些图片或图例使用不同颜色划分不同部分,在纸质版书中肉眼较难区分,阅读体验不好

预期描述

图片不同区域使用不同样式的点划线作为背景可以较好地在纸质书上实现区分效果,类似这样
image

9页

实际描述

  • 原文页码:9
  • 原文段落:倒数第二个代码块
func() {
    t = t + 5
}

预期描述

func() {
t = t + 5
}()

修改后的段落

附图

必要时,请附上相关页面的照片或者截图

关于map 的 key类型

原文中这段不准确吧:

k1 == k2 时,可认为 k1 和 k2 是同一个 key。如果是结构体,则需要它们的字段值都相等,才被认为是相同的 key。

应该是hash后的值相等和字面值相等才是同一个key,很多字面值相等的,hash出来的值不一定相等,比如引用

Map 扩容过程描述错误

原文

搬迁的目的就是将老的 buckets 搬迁到新的 buckets。而通过前面的说明我们知道,应对条件 1,新的 buckets 数量是之前的一倍,应对条件 2,新的 buckets 数量和之前相等。

对于条件 1,从老的 buckets 搬迁到新的 buckets,由于 bucktes 数量不变,因此可以按序号来搬,比如原来在 0 号 bucktes,到新的地方后,仍然放在 0 号 buckets。

对于条件 2,就没这么简单了。要重新计算 key 的哈希,才能决定它到底落在哪个 bucket。例如,原来 B = 5,计算出 key 的哈希后,只用看它的低 5 位,就能决定它落在哪个 bucket。扩容后,B 变成了 6,因此需要多看一位,它的低 6 位决定 key 落在哪个 bucket。这称为 rehash。

条件1是buckets数量翻倍,条件2是sizeSameGrow,下面描述错误,与上下文不一致。

目录中文章顺序有误

”调度器“一章中,“描述scheduler的初始化过程”和“主goroutine如何创建“两节顺序颠倒了

1-map B=5时 bucket num 由 hash 的低 5 位决定

实际描述

B=5时 bucket num 由 hash 的低 5 位决定

  • 原文页码:1-map
  • 原文段落:310-313 行
	// 比如 B=5,那 m 就是31,二进制是全 1
	// 求 bucket num 时,将 hash 与 m 相与,
	// 达到 bucket num 由 hash 的低 8 位决定的效果
	m := uintptr(1)<<h.B - 1

预期描述

B为5时 bucket num 由 hash 的低 5 位决定

	// 比如 B=5,那 m 就是31,二进制是全 1
	// 求 bucket num 时,将 hash 与 m 相与,
	// 达到 bucket num 由 hash 的低 5 位决定的效果
	m := uintptr(1)<<h.B - 1

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.