diff --git a/chapter-37-Context/chapter_37.md b/chapter-37-Context/chapter_37.md
new file mode 100644
index 0000000000000000000000000000000000000000..5bfc86bf95eed211cfd1f5f7da6414bff5190632
--- /dev/null
+++ b/chapter-37-Context/chapter_37.md
@@ -0,0 +1,1169 @@
+# Chapter 37: Context
+
+![Context](imgs/context.92f43817.jpg)
+
+## 1. 你将在本章学到什么
+
+* 什么是 context (上下文)?
+* 什么是链表 ?
+* 如何使用 context (上下文)包 。
+
+## 2. 涵盖的技术概念
+
+* 上下文推导
+* 链表列表
+* Context key-value pair (上下文键值对)
+* 取消
+* 超时
+* 最后期限
+
+## 3. 简介
+
+这一章专门讨论上下文包。在本章的第一部分,我们将发现什么是 "上下文 "以及它的目的是什么。在第二部分,我们将看到如何在真实的程序中使用上下文包
+
+## 4. 什么是面向上下文的编程 ?
+
+### 4.1 定义
+
+上下文来自拉丁词“contexo”。 它意味着将某物与一组其他事物联合、连接、链接。 我们在这里有这样的想法,即事物的上下文是一组与其他事物的链接和联系。 在日常语言中,我们使用如下表达式:
+
+* Take something out of context.
+
+* 在某事的上下文中。
+
+事物、动作、词语都有上下文,与其他事物有联系。 如果我们从它的上下文中剔除某些东西,我们就会把它简化为我们可能会误解的东西。 上下文是改进决策的信息的集合。 什么是上下文的一部分? 这是部分列表:
+
+* 地点
+
+* 日期
+
+* 历史
+
+* 人
+
+
+为了更好地理解为什么 context(上下文)对我们很重要,让我们举一些例子。
+
+### 4.2 上下文增加对事件的理解
+想象一下,在散步时,您听到两个人之间的对话:
+
+Alice
+你看过上周的比赛吗?
+
+Bob
+是的!
+
+Alice
+在此之后,我相信他们会赢得下一个!
+
+Bob
+当然,我会赌一千
+
+他们谈论“比赛”。一支球队上周赢得了一场比赛,并且有很多机会在下周赢得另一场比赛。我们不知道它是哪支球队和哪种运动。
+
+对话的上下文可以帮助我们理解它。如果谈话发生在纽约,我们可以猜测它与棒球或篮球有关,因为这些运动在那里很受欢迎。如果这次谈话发生在巴黎,那么他们谈论足球的可能性就很高。
+
+我们在这里所做的是添加上下文来理解某些东西。在这里,我们谈到了这个地方。我们还可以在对话的上下文中添加时间因素。如果我们知道它发生的时间,我们将能够浏览本周的运动成绩以更好地了解。
+
+### 4.3 上下文改变行为
+
+对事件上下文的分析将改变参与者的行为。 试着回答其中的一些问题:
+
+* 你在自己的国家比在其他国家是否更有礼貌?
+* 你们在办公室和家人使用相同的语言水平吗?
+* 你每天去面试的时候都穿得像这样吗?
+
+对这三个问题的回答可能是“否”。那是因为上下文。我们根据上下文采取不同的行动。背景正在影响我们的行为。环境会影响我们的行为和反应。
+
+### 4.4 计算机科学背景
+
+通常情况下,我们设计计算机程序是为了执行一个预定义的任务。我们实现的指定程序总是以同样的方式执行。程序不因使用它的用户而改变。当环境改变时,它的行为也不会改变。
+
+面向上下文编程的理念是在程序中引入受情境影响的变化。Abowd在1999年给出了一个有趣的上下文定义:"上下文是我们可以用来描述一个实体的情况的任何信息。一个实体是指被认为与用户和应用程序之间的交互有关的人、地方或物体,包括用户和应用程序本身"。
+
+隐式和显式信息是上下文的构建建块。程序员应该考虑上下文来构建可以在运行时调整其行为的应用程序。
+
+智能是什么意思?"智能 "这个词来自拉丁词根 "intellego",意思是辨别、理解、注意、意识。如果一个东西能够辨别和理解,它就是智能的。在应用程序中引入上下文并不能使它们变得智能,但它们往往能使它们意识到它们的环境和它们的用户。
+
+## 5. "Context " 包:历史和使用案例
+
+### 5.1 软件包历史
+
+该软件包最初由 Google 开发人员在内部开发。它已在 Go 的标准库中引入。在此之前,它在 Go 子存储库中可用。
+
+### 5.2 用途
+
+上下文包有两个主要用法:
+
+#### 5.2.0.1 取消传播
+
+为了理解这种用法,让我们以一家名为FooBar的虚构建筑公司为例。
+
+巴黎市的使命是建立一个巨大的游泳池。巴黎市长在民众代表中捍卫了自己的想法,该项目已获得批准。公司开始从事该项目;项目经理已经订购了建造游泳池所需的所有原材料。四个月过去了,但市长换了,项目被取消了!
+
+FooBar的项目经理很生气;该公司必须取消156个订单。他开始通过电话一个接一个地加入他们。他们中的一些人还从其他建筑公司订购了原材料。每个人都在遭受这种快速情况演变的困扰。
+
+现在让我们假设项目经理不会取消分包商的订单。其他公司将生产所需的商品,但不会得到报酬。这是对资源的严重浪费。
+
+正如您在图 [1](#fig:Cancellation-propagation) 中所想象的那样,项目的取消正在传播给间接参与的所有工作人员。市议会取消该项目;FooBar公司也取消了对承包商的订单。
+
+在建筑和其他人类活动中,我们总有办法取消工作。我们可以将取消政策引入我们的程序和上下文包。当向Web服务器发出请求时,如果客户端已断开连接,我们可以取消所有工作链!
+
+![Cancellation propagation[fig:Cancellation-propagation]](imgs/cancellation_propagation.7f4e0613.png)
+
+
+
+#### 5.2.0.2 传输请求作用域的数据以及调用堆栈
+
+当向网络服务器发出请求时,负责处理请求的网络服务器函数不会单独完成这项工作。该请求将通过一连串的函数和方法,然后再发送响应。在微服务架构中,一个单一的请求可以产生对其他微服务的新请求!这就是微服务。这个函数调用链就是 "调用栈"。我们将在本节中看到,为什么与调用栈一起传输数据会很有用。
+
+我们将举另一个例子:为一个购物应用程序开发一个网络服务器。我们有一个与我们的应用程序互动的用户。
+
+* 用户将用其网络浏览器进入登录页面
+* 填写它的登录信息
+* 网络浏览器将向服务器发送一个认证请求,服务器将把请求转发给认证服务。
+* 服务器将建立 "我的账户 "页面(例如通过一个模板),并发送用户的响应。
+* 如果用户请求 "最后的订单 "页面,那么服务器将需要调用订单服务来检索它们。
+
+![](imgs/request_context.77c1b04c.png)
+
+我们可以将哪些数据添加到我们的上下文中?
+
+* 我们可以将发送请求的设备类型保留在上下文中。
+ * 如果设备是手机,我们可以选择加载一个轻量级的模板来改善用户体验。
+ * 订单服务也可以只加载最后五个订单,以减少页面的渲染时间。
+* 我们可以将经过身份验证的用户的 id 保存到上下文中。
+* 我们也可以保留传入请求的IP。
+ * 身份验证层可以使用它来阻止可疑活动(引入阻止列表、检测错误、多次登录尝试)
+* 另一个非常常见的用例是生成单个请求 ID。 requestId 被传递到应用程序的每一层。 使用该 ID,负责维护的团队将能够在日志中跟踪请求。
+
+#### 5.2.0.3 设置截止日期和超时
+
+截止日期是任务应该完成的时间。 超时是一个非常相似的概念。 我们不考虑日历中的精确日期和时间,而是考虑最大允许持续时间。 我们可以使用上下文来定义长时间运行的进程的时间限制。 这是一个例子:
+
+* 你开发了一个服务器,而你的客户端有一个指定的超时时间为1秒。
+* 你可以为一个上下文设置1秒的超时;在这个时间段之后,你知道客户端将放弃连接。
+* 在这种情况下,我们同样希望避免浪费资源。
+
+### 5.3 Context(上下文)接口
+
+上下文包暴露了一个由四个方法组成的接口。
+
+```go
+type Context interface {
+ Deadline() (deadline time.Time, ok bool)
+ Done() <-chan struct{}
+ Err() error
+ Value(key interface{}) interface{}
+}
+```
+
+在下一节,我们将看到如何使用软件包
+
+## 6 链接列表
+
+上下文包是用一个标准的数据结构构建的:链表。为了充分了解上下文的工作原理,我们首先需要了解链表。
+
+链接列表是一个数据元素的集合。存储在列表中的数据类型不受限制;它可以是整数、字符串、结构体、浮点数......等等。列表中的每个元素都是一个节点。每个节点包含两个东西。
+
+* 数据值
+* 列表中下一个元素在内存中的地址。换句话说,这是一个指向下一个值的指针。
+
+你可以在图3中看到一个链接列表的直观表示。
+
+列表是 "链接的",列表中的节点有一个子(列表中的下一个元素)和一个父(列表中的最后一个元素)。请注意,这个说法并不正确;列表中的第一个节点没有父节点。它是根,是原点,是列表的头。还有一个值得注意的例外,最后一个节点没有任何子节点。
+
+![Linked List[fig:Linked-List]](imgs/linked_list.2f868379.png)
+
+ Linked List[fig:Linked-List]
+
+![Linked List : pointers and values[fig:Linkedl-pointers-and-values]](imgs/linked_list_pointers.3614379a.png)
+
+ Linked List : pointers and values[fig:Linkedl-pointers-and-values]
+
+## 7 root context: Background
+
+在大多数程序中,我们在程序的根部创建一个Background概念。例如,在将启动我们的应用程序的主函数中。要创建根上下文,你可以使用以下语法。
+
+```go
+ctx := context.Background()
+```
+
+对Background()函数的调用将返回一个指向空上下文的指针。在内部,对Background()的调用将创建一个新的context.emptyCtx。
+
+这种类型没有对外暴露出来:
+
+```go
+type emptyCtx int
+```
+
+emptyCtx的基本类型是int。这个类型实现了Context接口所要求的四个方法。
+
+```go
+func (*emptyCtx) Deadline() (deadline time.Time, ok bool) {
+ return
+}
+
+func (*emptyCtx) Done() <-chan struct{} {
+ return nil
+}
+
+func (*emptyCtx) Err() error {
+ return nil
+}
+
+func (*emptyCtx) Value(key interface{}) interface{} {
+ return nil
+}
+```
+
+注意 emptyCtx 类型也实现了 fmt.Stringer 接口。这使得我们可以做一个 fmt.Println(ctx)。
+
+```go
+fmt.Println(reflect.TypeOf(ctx))
+// *context.emptyCtx
+fmt.Println(ctx)
+// context.Background
+```
+
+
+
+## 8 为你的函数/方法添加 Context
+
+当你的 root context 被创建后,我们可以把它传递给函数或方法。
+
+但在这之前,我们必须在我们的函数中添加一个上下文参数。
+
+```go
+func foo1(ctx context.Context, a int) {
+ //...
+}
+```
+
+在前面的列表中,你注意到两个在go项目中被广泛使用的Go习语。
+
+1. context 是一个函数的第一个参数
+2. context 的参数被命名为 `ctx`
+
+## 9 衍生出来的 Context
+
+我们已经在上一节中创建了我们的根上下文。这个上下文是空的;它什么也不做。我们可以做的是,从我们的空上下文衍生出另一个子上下文:
+
+![Deriving Contexts[fig:Deriving-Contexts]](imgs/deriving_context.ad1f8dc6.png)
+
+ Deriving Contexts[fig:Deriving-Contexts]
+
+为了推导出一个 context,你可以使用以下函数。
+
+* WithCancel
+* WithTimeout
+* WithDeadline
+* WithValue
+
+## 10 取消
+
+函数`WithCancel`只接受一个名为`parent`的参数。这个参数代表我们要派生的上下文。我们将创建一个新的上下文,而父上下文将保持对这个新的子上下文的引用。
+
+让我们看一下WithCancel函数的签名:
+
+```go
+func WithCancel(parent Context) (ctx Context, cancel CancelFunc)
+```
+
+此函数返回下一个子上下文和一个 CancelFunc。 CancelFunc 是上下文包的自定义类型:
+
+```go
+type CancelFunc func()
+```
+
+`CancelFunc` 是一个命名类型,它的底层类型是 `func()`。 这个函数“告诉操作放弃它的工作”(Golang 来源)。 调用 `WithCancel` 将为我们提供一种取消操作的方法。 以下是如何创建派生上下文:
+
+```go
+ctx, cancel := context.WithCancel(context.Background())
+```
+
+要取消操作,您需要调用 cancel :
+
+```
+cancel()
+```
+
+## 11 WithTimeout / WithDeadline (超时 / 截止时间)
+
+超时是归因于进程正常完成的最长时间。 对于需要可变时间执行的任何进程,我们可以添加超时,即允许等待的固定时间。 如果没有超时,我们的应用程序可以无限期地等待进程完成。
+
+```go
+ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
+```
+
+截止日期是指定的时间点。 当你设置一个截止日期时,你指定一个进程不会超过它。
+
+```go
+deadline := time.Date(2021, 12, 12, 3, 30, 30, 30, time.UTC)
+ctx, cancel := context.WithDeadline(context.Background(), deadline)
+```
+
+## 12 用法示例
+
+### 12.1 Without context
+
+举个例子:我们将设计一个应用程序,它必须向 Web 服务器发出 HTTP 请求以获取数据,然后将其显示给用户。 我们将首先考虑没有 context (上下文)的应用程序,然后我们将为其添加上下文。
+
+#### 12.1.1 Client
+
+```go
+package main
+
+import (
+ "log"
+ "net/http"
+)
+
+func main() {
+ req, err := http.NewRequest("GET", "http://127.0.0.1:8989", nil)
+ if err != nil {
+ panic(err)
+ }
+ resp, err := http.DefaultClient.Do(req)
+ if err != nil {
+ panic(err)
+ }
+ log.Println("resp received", resp)
+}
+```
+
+我们这里有一个简单的 http 客户端。 我们创建一个调用“http://127.0.0.1:8989”的 GET 请求。 如果我们无法创建请求,我们会让我们的程序恐慌。 然后我们使用默认的 HTTP 客户端 (`http.DefaultClient`) 将请求发送到服务器(使用方法 `Do`).
+
+然后将收到的响应打印给用户。
+
+#### 12.1.2 Server
+
+我们已经设置了我们的客户端。我们现在必须建立我们的假服务器。
+
+```go
+package main
+
+import (
+ "fmt"
+ "log"
+ "net/http"
+ "time"
+)
+
+func main() {
+ http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
+ log.Println("request received")
+ time.Sleep(time.Second * 3)
+ fmt.Fprintf(w, "Response") // 向客户端发送数据
+ log.Println("response sent")
+
+ })
+ err := http.ListenAndServe("127.0.0.1:8989", nil) // 设置监听端口
+ if err != nil {
+ panic(err)
+ }
+}
+```
+
+代码很简单。我们首先用函数.`http.HandleFunc`来设置我们的http处理器。这个函数需要两个参数,路径和响应请求的函数。
+
+我们用指令`time.Sleep(time.Second * 3)`等待3秒,然后我们写出响应。这个睡眠在这里是为了伪造服务器回答所需的时间。在这种情况下,响应就是简单的 `"Response"`。
+
+然后我们启动我们的服务器来监听 `127.0.0.1:8989` (localhost, port 8989).
+
+#### 12.1.3 First test
+
+首先,我们启动服务器; 然后,我们启动客户端。 3 秒后,客户端收到响应。
+
+```shell
+$ go run server.go
+2019/04/22 12:17:11 request received
+2019/04/22 12:17:14 response sent
+
+$ go run client.go
+2019/04/22 12:17:14 resp received &{200 OK 200 HTTP/1.1 1 1 map[Content-Length:[8] Content-Type:[text/plain; charset=utf-8] Date:[Mon, 22 Apr 2019 10:17:14 GMT]] 0xc000132180 8 [] false false map[] 0xc00011c000 }
+```
+
+正如你所看到的,我们的客户端必须处理3秒的延迟。让我们在服务器的代码中增加这一点;假设我们现在睡眠时间为1分钟。我们的客户端将等待1分钟;它将阻止我们的应用程序1分钟。
+
+我们可以在这里注意到,我们的客户端应用程序注定要等待服务器,即使它需要无限长的时间。 这不是一个很好的设计。 用户不会乐于无限期地等待应用程序回答。 在我看来,与其让他无限期地等待,不如对用户说发生了错误。
+
+### 12.2 客户端上下文
+
+我们将保留我们之前创建的代码的基础。 我们将从创建 root context (根上下文) 开始:
+
+```go
+rootCtx := context.Background()
+```
+
+然后,我们将把这个 context 衍生为一个新的上下文,称为ctx。
+
+``` go
+ctx, cancel := context.WithTimeout(rootCtx, 50*time.Millisecond)
+```
+
+* `WithTimeout` 函数有两个参数,一个是 context,一个是 time.Duration.
+* 第二个参数是超时时间.
+* 在这里,我们将其设置为 50 毫秒.
+* 我建议您在实际应用程序中创建一个配置变量来保存超时持续时间。 通过这样做,您无需重新编译程序来更改超时.
+
+`context.WithTimeout`将返回:
+
+1. 衍生的 context
+2. 一个取消函数
+
+可以调用取消函数来警告子进程它应该放弃它正在做的事情。 调用取消将释放与上下文关联的资源。 为了确保在程序结束时调用取消函数,我们将使用 defer 语句:
+
+```go
+defer cancel()
+```
+
+下一步包括创建请求并将我们的全新 context 附加到它:
+
+```go
+req, err := http.NewRequest("GET", "http://127.0.0.1:8989", nil)
+if err != nil {
+ panic(err)
+}
+// 为我们的请求添加context
+req = req.WithContext(ctx)
+```
+
+其他地方与没有 context 的版本相同。
+
+这是完整的客户端代码:
+
+```go
+// context/client-side/main.go
+package main
+
+import (
+ "context"
+ "fmt"
+ "net/http"
+ "time"
+)
+
+func main() {
+ rootCtx := context.Background()
+ req, err := http.NewRequest("GET", "http://127.0.0.1:8989", nil)
+ if err != nil {
+ panic(err)
+ }
+ // 创建 context
+ ctx, cancel := context.WithTimeout(rootCtx, 50*time.Millisecond)
+ defer cancel()
+ // 将 context 附加到我们的请求
+ req = req.WithContext(ctx)
+ resp, err := http.DefaultClient.Do(req)
+ if err != nil {
+ panic(err)
+ }
+ fmt.Println("resp received", resp)
+}
+```
+
+现在让我们测试我们的新客户端。 以下是服务器的日志:
+
+```tex
+2019/04/24 00:52:08 request received
+2019/04/24 00:52:11 response sent
+```
+
+我们看到我们收到了一个请求,并在 3 秒后发送了响应。 以下是我们客户的日志:
+
+```go
+panic: Get http://127.0.0.1:8989: context deadline exceeded
+```
+
+我们看到 `http.DefaultClient.Do` 返回了一个 `error`。
+
+* 文本说超过了最后期限。
+* 我们的请求已被取消,因为我们的服务器需要 3 秒来完成它的工作。 即使客户端已经取消了请求,服务器也会继续做这项工作。 我们必须找到一种在客户端和服务器之间共享该上下文的方法。
+
+### 12.3 服务端上下文
+
+#### 12.3.1 Headers
+
+HTTP 请求包括一组标头、一个正文和一个查询字符串。 当我们发送请求时,Go 不会传输任何有关请求上下文的信息。
+
+如果要可视化请求的标头,可以在服务器代码中添加以下行:
+
+```go
+fmt.Println("headers :")
+for name, headers := range r.Header {
+ for _, h := range headers {
+ fmt.Printf("%s: %s\n", name, h)
+ }
+}
+```
+
+我们使用循环遍历请求的标头并打印它们。 以下是与我们的客户端一起传输的标头:
+
+```tex
+headers :
+User-Agent: Go-http-client/1.1
+Accept-Encoding: gzip
+```
+
+我们只有两个标头。 第一个提供有关所用客户端的更多信息。 第二个通知服务器客户端可以接受压缩数据。 没有关于最终超时的事情。
+
+但是如果我们看一下 `http.Requestobject`,我们可以注意到有一个名为 `Context()` 的方法。 此方法将检索请求的上下文。 如果尚未定义,它将返回一个空上下文:
+
+```go
+func (r *Request) Context() context.Context {
+ if r.ctx != nil {
+ return r.ctx
+ }
+ return context.Background()
+}
+```
+
+文档中说,"当客户端的连接关闭时,上下文被取消"。这意味着在go服务器的实现中,当客户端连接关闭时,取消函数被调用。
+
+这意味着在我们的服务器内部,我们必须监听由ctx.Done()返回的通道。当我们在该通道上收到一个消息时,我们必须停止目前正在做的事情。
+
+#### 12.3.2 doWork 函数
+
+让我们看看如何将它引入我们的服务器.
+
+例如,我们将引入一个新函数 `doWork`。 它将代表我们的服务器处理的计算密集型任务。 这个 `doWork` 是 CPU 密集型操作的占位符。
+
+![5](imgs/serverWithTimeout.78b3d9c5.png)
+
+ 带有上下文活动图的 Http 服务器处理程序
+
+我们将在一个单独的 goroutine 中启动 `doWork` 函数。 该函数将上下文和将写入其结果的通道作为参数。 我们来看看这个函数的代码:
+
+```go
+// context/server-side/main.go
+//...
+
+func doWork(ctx context.Context, resChan chan int) {
+ log.Println("[doWork] launch the doWork")
+ sum := 0
+ for {
+ log.Println("[doWork] one iteration")
+ time.Sleep(time.Millisecond)
+ select {
+ case <-ctx.Done():
+ log.Println("[doWork] ctx Done is received inside doWork")
+ return
+ default:
+ sum++
+ if sum > 1000 {
+ log.Println("[doWork] sum has reached 1000")
+ resChan <- sum
+ return
+ }
+ }
+ }
+}
+```
+
+在图 [5](#5) 中,您可以看到 doWork 函数的活动图。
+
+在这个函数中,我们将使用一个通道与调用者进行通信。 我们创建了一个 for 循环,在该循环中,我们将放置一个 select 语句。 在这个 select 语句中,我们有两种情况:
+
+* `ctx.Done()` 返回的通道已关闭。 这意味着我们收到了完成工作的命令
+ * 在这种情况下,我们将中断循环,记录一条消息并返回。
+* 默认情况(如果没有执行任何先前的情况,则执行)
+ * 在这种默认情况下,我们将递增总和.
+ * 如果变量总和严格来说大于1.000,我们将把结果发送到结果通道(``resChan'`)。
+
+![Activity diagram of the doWork function[fig:doWork-fct]](imgs/doWorkFunction.15397b29.png)
+
+doWork函数的活动图 [fig:doWork-fct]
+
+#### 12.3.3 The server handler
+
+让我们看看我们将如何在我们的服务器处理程序中使用 `doWork` 函数:
+
+```go
+// context/server-side/main.go
+//...
+
+func main() {
+ http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
+ log.Println("[Handler] request received")
+ // 检索请求的上下文 context
+ rCtx := r.Context()
+ // 创建结果通道
+ resChan := make(chan int)
+ // 在goroutine中启动函数doWork
+ go doWork(rCtx, resChan)
+ // 等待
+ // 1. 客户端断开连接
+ // 2. 函数doWork完成它的工作
+ select {
+ case <-rCtx.Done():
+ log.Println("[Handler] context canceled in main handler, client has diconnected")
+ return
+ case result := <-resChan:
+ log.Println("[Handler] Received 1000")
+ log.Println("[Handler] Send response")
+ fmt.Fprintf(w, "Response %d", result) // 向客户端发送数据
+ return
+ }
+ })
+ err := http.ListenAndServe("127.0.0.1:8989", nil) // 设置听端口
+ if err != nil {
+ panic(err)
+ }
+}
+```
+
+我们已更改处理程序的代码以使用请求 Context。 这里要做的第一件事是检索请求的 Context:
+
+```go
+rCtx := r.Context()
+```
+
+然后我们设置一个整数通道(`resChan`),它允许你与`doWork`函数进行通信。 我们将在单独的 goroutine 中启动 `doWork` 函数。
+
+```go
+resChan := make(chan int)
+// 在goroutine中启动函数doWork
+go doWork(rCtx, resChan)
+```
+
+然后,我们将使用select语句等待两个可能的事件:
+
+1. 客户端关闭连接;因此,取消通道将被关闭。
+2. 函数`doWork`已经完成了它的工作。(我们从 `resChan` 通道接收一个整数)
+
+在选项1中,我们记录一条消息,然后返回。当选项2发生时,我们使用来自 `resChan` 通道的结果,并将其写入响应写入器。我们的客户端将收到doWork函数计算的结果。
+
+让我们运行服务器和客户机. 在图 [6](#fig:Execution-logs-client-server-context) 中 您可以看到客户机和服务器程序的执行日志。
+
+您可以看到处理程序接收到请求,然后启动 `doWork` 函数。 然后处理程序接收取消信号。 然后将该信号传播到“doWork”函数。
+
+![Execution logs for the client and the server[fig:Execution-logs-client-server-context]](imgs/server_client_timeout.4e32a6a4.png)
+
+Execution logs for the client and the server[fig:Execution-logs-client-server-context]
+
+## 13 截止日期
+
+### 13.1 定义
+
+`WithDeadline` 和 `WithTimeout` 非常相似。 如果我们查看 `context` 包的源代码,我们可以看到函数 `WithTimeout` 只是 `WithDeadline` 的一个包装器:
+
+```go
+// source : context.go (in the standard library)
+func WithTimeout(parent Context, timeout time.Duration) (Context, CancelFunc) {
+ return WithDeadline(parent, time.Now().Add(timeout))
+}
+```
+
+如果您查看前面的代码片段,您可以看到超时持续时间已添加到当前时间。 让我们看看 WithDeadline 函数的签名:
+
+```go
+func WithDeadline(parent Context, d time.Time) (Context, CancelFunc)
+
+```
+
+这个函数有两个参数 :
+
+1. 一个父 Context
+2. 一个特定的时间
+
+### 13.2 用法
+
+正如我们在上一节中所说,deadline 和 timeout 是相似的概念。 超时表示为持续时间,但最后期限表示为特定时间点(参见图 7)
+
+![Timeout vs Deadline[fig:Timeout-vs-Deadline]](imgs/timeout_deadline.b1d54bad.png)
+
+超时与截止日期[fig:Timeout-vs-Deadline]
+
+WithDeadline 可以用在你使用 WithTimeout 的地方。 这是标准库的示例:
+
+```go
+// golang standard library
+// src/net/dnsclient_unix.go
+// line 133
+
+// Exchange发送一个关于连接的查询并希望得到响应。
+func (r *Resolver) exchange(ctx context.Context, server string, q dnsmessage.Question, timeout time.Duration) (dnsmessage.Parser, dnsmessage.Header, error) {
+ //....
+ for _, network := range []string{"udp", "tcp"} {
+ ctx, cancel := context.WithDeadline(ctx, time.Now().Add(timeout))
+ defer cancel()
+
+ c, err := r.dial(ctx, network, server)
+ if err != nil {
+ return dnsmessage.Parser{}, dnsmessage.Header{}, err
+ }
+ //...
+ }
+ return dnsmessage.Parser{}, dnsmessage.Header{}, errNoAnswerFromDNSServer
+}
+
+```
+
+* 这里的函数 `exchange` 将上下文作为第一个参数。
+* 对于每个网络(UDP 或 TCP),它衍生作为参数传递的Context。
+* 输入 Context 是通过调用 `context.WithDeadline` 衍生的。 截止时间是通过将超时持续时间添加到当前时间来创建的:`time.Now().Add(timeout)`
+* 请注意,在创建衍生上下文后**immediately**,会延迟调用由`context.WithDeadline` 返回的取消函数。 这意味着当函数交换将返回时,取消函数将被调用。
+* 例如,如果拨号函数由于某种原因返回错误,交换函数将返回,取消函数将被调用,并且取消信号将被传播到子 Context。
+
+## 14 取消传播
+
+本节将深入探讨取消传播的机制。让我们举一个例子:
+
+```go
+func main(){
+ ctx1 := context.Background()
+ ctx2, c := context.WithCancel(ctx1)
+ defer c()
+}
+```
+
+在这个小程序中,我们首先定义一个 root Context:`ctx1`。 然后我们通过调用 `context.WithCancel` 衍生这个Context。
+
+Go将创建一个新的结构。 被调用的函数如下所示:
+
+```go
+// src/context/context.go
+
+// newCancelCtx返回一个初始化的cancelCtx
+func newCancelCtx(parent Context) cancelCtx {
+ return cancelCtx{Context: parent}
+}
+```
+
+一个 `cancelCtx` 结构被创建,我们的root Context 被嵌入其中。 这里的类型 struct `cancelCtx` :
+
+```go
+// src/context/context.go
+
+type cancelCtx struct {
+ Context
+
+ mu sync.Mutex // 一把锁,保护以下字段
+ done chan struct{} // 惰性创建,由第一次取消调用关闭
+ children map[canceler]struct{} // 在第一次取消呼叫时设置为nil
+ err error // 在第一次取消呼叫时设置为非空
+}
+```
+
+我们有五个字段:
+
+* `Context`(父级)是一个嵌入的字段(它没有明确的字段名称)
+* 互斥锁(名为 `mu`)
+* 一个名为`done`的通道
+* 一个名为`children`的字段,它是一个地图。 键是 `canceller` 类型,值是 `struct{}` 类型
+* 还有一个名为 `err` 的错误
+
+Canceller 是一个接口:
+
+```go
+// 取消器是可以直接取消的 Context 类型
+// 实现是 *cancelCtx 和 *timerCtx。
+type canceler interface {
+ cancel(removeFromParent bool, err error)
+ Done() <-chan struct{}
+}
+```
+
+实现接口取消器的类型必须实现到函数:cancel 函数和`done`函数。
+
+![WithCancel create a derived context and a cancel function[fig:WithCancel-create-a]](imgs/withCancel.150ca94b.png)
+
+使用WithCancel创建一个衍生Context和一个取消函数 [fig:WithCancel-create-a]
+
+当我们执行取消函数时会发生什么? **ctx2** 会发生什么?
+
+* 互斥体 (`mu`) 将被锁定。 因此,没有其他 goroutine 能够修改这个上下文。
+* 通道 (`done`) 将被关闭
+* `ctx2` 的所有 children 也将被取消(在这种情况下,我们没有children ......)
+* 互斥锁将被解锁。
+
+### 14.0.0.1 二次推导
+
+让我们扩展我们的示例并导出 ctx2:
+
+![Derive a derived context[fig:3-contexts]](imgs/withCancel3Derivatin.c23d2f44.png)
+
+获得一个衍生的 context[fig:3-contexts]
+
+```go
+func main() {
+ ctx1 := context.Background()
+ ctx2, c2 := context.WithCancel(ctx1)
+ ctx3, c3 := context.WithCancel(ctx2)
+ //...
+}
+```
+
+这里我们创建了`ctx3`**,**一个`cancelCtx`类型的新对象。 子 Context `ctx3` 将被添加到父 Context (`ctx2`)。 父 Context `ctx2` 将保留其子 Context 的内存。 目前,它只有一个子 `ctx3`(参见 [9](https://www.practical-go-lessons.com/chap-37-context#fig:3-contexts))。
+
+现在我们来看看当我们调用取消函数c2时会发生什么。
+
+* 互斥体 (`mu`) 将被锁定。 因此,没有其他 goroutine 能够修改这个上下文。
+
+* 通道 (`done`) 将被关闭
+
+* `ctx2` 的所有 children 也将被取消(在这种情况下,我们没有children ......)
+
+ `ctx3` 将以相同的进程被取消
+
+* 这里 `ctx1`(`ctx2` 的父级)是 `emptyCtx`,因此 `ctx2` 不会从 `ctx1` 中删除。
+* 互斥锁将被解锁。
+
+### 14.0.0.2 三阶推导
+
+现在让我们创建另一个衍生上下文。
+
+```go
+func main() {
+ ctx1 := context.Background()
+ ctx2, c2 := context.WithCancel(ctx1)
+ ctx3, c3 := context.WithCancel(ctx2)
+ ctx4, c4 := context.WithCancel(ctx3)
+}
+```
+
+![3 derived contexts[fig:3-derived-contexts]](imgs/ctx_4_levels.f46f9ff9.png)
+
+3 derived contexts[fig:3-derived-contexts]
+
+* 正如您在图 [10](https://www.practical-go-lessons.com/chap-37-context#fig:3-derived-contexts) 中看到的,我们有一个 root Context 和三个后代。
+* 最后一个是`ctx4`。
+* 当我们调用 `c2` 时,它会取消 `ctx2` 以及它的子项(`ctx3`)。
+* 当 `ctx3` 将被取消时,它也将取消其所有子项,并且 `ctx4` 将被取消。
+
+![Cancellation propagation[fig:Cancellation-propagation-1]](imgs/cancellation_propagation_2.51cb103e.png)
+
+取消传播[fig:Cancellation-propagation-1]
+
+本节的关键信息是“当您取消上下文时,取消操作将从父级传播到子级”。
+
+## 15 一个重要的习惯用法:defer cancel()
+
+以下两行代码很常见:
+
+```go
+ctx, cancel = context.WithCancel(ctx)
+defer cancel()
+```
+
+您可以在标准库中遇到这些行,也可以在许多库中遇到这些行。 一旦我们衍生出现有的Context,就会在 defer 语句中调用取消函数。
+
+正如我们之前所看到的,取消指令会从父代传播到子代;为什么我们需要明确地调用取消呢?当构建一个库时,你不确定有人会在父级 Context 中有效地执行取消函数。通过在延迟语句中加入对cancel的调用,你可以确保cancel会被调用:
+
+* 当函数返回(或到达其主体的末尾)
+
+* 或者当运行函数的 goroutine 发生恐慌时。
+
+### 15.1 Goroutine 泄露
+
+为了理解这种现象,我们举个例子。
+
+首先,我们定义了两个函数:`doSth` 和 `doSth2`。 这两个功能是虚拟的。 他们将 Context 作为第一个参数。 然后他们无限期地等待 `ctx.Done()` close 返回的通道:
+
+```go
+// context/goroutine-leak/main.go
+// ...
+
+func doSth2(ctx context.Context) {
+ select {
+ case <-ctx.Done():
+ log.Println("second goroutine return")
+ return
+ }
+}
+
+func doSth(ctx context.Context) {
+ select {
+ case <-ctx.Done():
+ log.Println("first goroutine return")
+ return
+ }
+}
+```
+
+我们现在将在名为`launch`的第三个函数中使用这两个函数:
+
+```go
+// context/goroutine-leak/main.go
+// ...
+
+func launch() {
+ ctx := context.Background()
+ ctx, _ = context.WithCancel(ctx)
+ log.Println("launch first goroutine")
+ go doSth(ctx)
+ log.Println("launch second goroutine")
+ go doSth2(ctx)
+}
+```
+
+在这个函数中,我们首先创建一个 root Context(由`context.Background`返回)。 然后我们推导出这个 root Context。 我们调用方法 `WithCancel()` 来获取可以取消的上下文。
+
+然后我们启动我们的两个 goroutine。 现在让我们看看我们的主要功能:
+
+```go
+// context/goroutine-leak/main.go
+// ...
+
+func main() {
+ log.Println("begin program")
+ go launch()
+ time.Sleep(time.Millisecond)
+ log.Printf("Gouroutine count: %d\n", runtime.NumGoroutine())
+ for {
+ }
+}
+```
+
+我们在 goroutine 中启动函数 `launch`。 然后我们稍作停顿(1 毫秒),然后计算 goroutine 的数量。 在运行时包中定义了一个非常方便的函数:
+
+```go
+runtime.NumGoroutine()
+```
+
+这里的goroutine的数量应该是3个:1个主goroutine + 1个执行doSth的goroutine + 1个执行`doSth2'的goroutine。如果我们不调用cancel,最后两个goroutine将无限期地运行。请注意,我们在程序中创建了另一个goroutine:启动`launch`**.**这个goroutine不会被计算在内,因为它几乎会瞬间返回。
+
+当我们取消上下文时,我们的两个goroutines正在返回。因此,goroutines的数量将减少到1(main)。但在这里,我们根本没有调用取消函数。
+
+下面是标准输出。
+
+```shell
+2019/05/04 19:01:16 begin program
+2019/05/04 19:01:16 launch first goroutine
+2019/05/04 19:01:16 launch second goroutine
+2019/05/04 19:01:16 Gouroutine count: 3
+```
+
+在主函数中,我们无法取消 Context(因为它是在启动函数中定义的)。 我们有 2 个泄露的 goroutine! 为了解决这个问题,我们可以修改函数启动并添加一个延迟语句:
+
+```go
+// context/goroutine-leak-fixed/main.go
+// ...
+
+func launch() {
+ ctx := context.Background()
+ ctx, cancel := context.WithCancel(ctx)
+ defer cancel()
+ log.Println("launch first goroutine")
+ go doSth(ctx)
+ log.Println("launch second goroutine")
+ go doSth2(ctx)
+}
+```
+
+现在让我们看看通过运行我们的程序的这个修改版本获得的日志:
+
+```shell
+2019/05/04 19:15:09 begin program
+2019/05/04 19:15:09 launch first goroutine
+2019/05/04 19:15:09 launch second goroutine
+2019/05/04 19:15:09 first goroutine return
+2019/05/04 19:15:09 second goroutine return
+2019/05/04 19:15:09 Gouroutine count: 1
+```
+
+在这里,我们杀死了两个泄露的 goroutine!
+
+## 16 WithValue
+
+context 可以**携带数据**。 此功能旨在与 **request-scoped** 数据一起使用,例如:
+
+* 凭据(例如 JSON Web 令牌)
+* 请求 id(跟踪系统中的请求)
+* 请求的 IP
+* 一些标头(例如:用户代理)
+
+### 16.1 示例
+
+```go
+// context/with-value/main.go
+package main
+
+import (
+ "context"
+ "fmt"
+ "log"
+ "net/http"
+
+ uuid "github.com/satori/go.uuid"
+)
+
+func main() {
+ http.HandleFunc("/status", status)
+ err := http.ListenAndServe(":8091", nil)
+ if err != nil {
+ log.Fatal(err)
+ }
+}
+
+type key int
+
+const (
+ requestID key = iota
+ jwt
+)
+
+func status(w http.ResponseWriter, req *http.Request) {
+ // 将请求 ID 添加到 context
+ ctx := context.WithValue(req.Context(), requestID, uuid.NewV4().String())
+ // 将凭据添加到 context
+ ctx = context.WithValue(ctx, jwt, req.Header.Get("Authorization"))
+
+
+ upDB, err := isDatabaseUp(ctx)
+ if err != nil {
+ http.Error(w, "Internal server error", http.StatusInternalServerError)
+ return
+ }
+ upAuth, err := isMonitoringUp(ctx)
+ if err != nil {
+ http.Error(w, "Internal server error", http.StatusInternalServerError)
+ return
+ }
+ fmt.Fprintf(w, "DB up: %t | Monitoring up: %t\n", upDB, upAuth)
+}
+
+
+func isDatabaseUp(ctx context.Context) (bool, error) {
+ // 检索请求ID值
+ reqID, ok := ctx.Value(requestID).(string)
+ if !ok {
+ return false, fmt.Errorf("requestID in context does not have the expected type")
+ }
+ log.Printf("req %s - checking db status", reqID)
+ return true, nil
+}
+
+func isMonitoringUp(ctx context.Context) (bool, error) {
+ // 检索请求ID值
+ reqID, ok := ctx.Value(requestID).(string)
+ if !ok {
+ return false, fmt.Errorf("requestID in context does not have the expected type")
+ }
+ log.Printf("req %s - checking monitoring status", reqID)
+ return true, nil
+}
+```
+
+* 我们创建了一个正在监听 localhost:8091 的服务器
+* 此服务器有一个路由:`"/status"`
+* 我们使用 `ctx := context.WithValue(req.Context(), requestID, uuid.NewV4().String())` 导出请求上下文 (`req.Context()`)
+ * 我们在 context 中添加一个键值对:requestID
+* 然后我们更新操作。 我们添加一个新的密钥对来保存请求凭据:`ctx = context.WithValue(ctx, jwt, req.Header.Get("Authorization"))`
+
+然后,context 的值可以进入`isMonitoringUp`和`isMonitoringUp`。
+
+```go
+reqID, ok := ctx.Value(requestID).(string)
+if !ok {
+ return false, fmt.Errorf("requestID in context does not have the expected type")
+}
+```
+
+### 16.2 Key type (密匙类型)
+
+这是 WithValue 方法的标头:
+
+```go
+func WithValue(parent Context, key, val interface{}) Context
+```
+
+参数 `key` 和 `val` 的类型是 `interface{}`。 换句话说,它们可以有任何类型。 只应遵守一个限制,`key` 的类型应该是 **comparable**。
+
+* 我们可以跨多个包共享一个 context.
+* 您可能希望限制对添加值的包之外的 context 值的访问.
+* 为此,您可以创建一个未导出的类型
+* 所有键都属于这种类型.
+* 我们将在包内全局定义键 :
+
+```go
+type key int
+
+const (
+ requestID key = iota
+ jwt
+)
+```
+
+在前面的示例中,我们创建了一个底层类型为 int(可比较)的类型键。 然后我们定义了两个未导出的全局常量。 然后使用这些常量添加一个值并从上下文中检索一个值:
+
+```go
+// 添加一个值
+ctx := context.WithValue(req.Context(), requestID, uuid.NewV4().String())
+
+// 获取一个值
+reqID, ok := ctx.Value(requestID).(string)
+```
+
+#### 16.2.0.1 缺少的值和预期类型与实际类型不同
+
+* 当在上下文中找不到键值对时,`ctx.Value` 将返回 `nil`。
+* 这就是我们制作**类型断言**的原因:保护我们免受缺失值或没有所需类型的值的影响。
+
+### 16.3 问题
+
+1. 截止日期和超时有什么区别?
+2. 填空。 链表的每个节点都包含一个____值和一个____。
+3. 如何创建一个空的 context?
+4. 您可以使用哪些方法导出 context?
+5. 当 context 中没有找到键值对时,`ctx.Value(key)` 返回什么?
+
+### 16.4 答案
+
+1. 截止日期和超时有什么区别?
+ 1. 截止日期是一个精确的时间点。 例如:2027年12月12日
+ 2. 超时:持续时间。 例如:12 秒
+2. 填空。 链表的每个节点都包含一个____值和一个____。
+ 1. 链表的每个节点都包含一个数据值和下一个元素在内存中的地址
+ 2. 最终节点除外。 它没有设置地址。
+3. 如何创建一个空的 context?
+ 1. ctx := context.Background()
+4. 您可以使用哪些方法导出 context?
+ 1. WithCancel
+ 2. WithTimeout
+ 3. WithDeadline
+ 4. WithValue
+5. 当 context 中没有找到键值对时,`ctx.Value(key)` 返回什么?
+ 1. nil
+
+## 17 主要收获
+
+* Context 是标准库中的一个包
+
+* 我们可以使用 context 来:
+
+ * 取消传播(例如:如果 API 使用者断开连接,则取消所有工作链)
+ * 与调用堆栈一起传输请求范围的数据。
+ * 设置最后期限和超时。
+
+* 截止日期=一个精确的时间点
+
+* 超时 = 持续时间
+
+* 在内部,包 context 是使用链表构建的。
+
+* 链表是数据的集合。 链表的每个节点都包含一个数据值和下一个元素在内存中的地址。
+
+* 要创建一个空 context,请使用:
+
+ ```go
+ ctx := context.Background()
+ ```
+
+* 我们可以使用以下方法导出每个 context:
+ * WithCancel : `ctx, cancel := context.WithCancel(context.Background())`
+ * WithTimeout : `ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)`
+ * WithDeadline : `ctx, cancel := context.WithDeadline(context.Background(), deadline)`
+ * WithValue : `ctx := context.WithValue(context.Background(),"key","value")`
+* 通过衍生 context,您可以在上下文链接列表中创建一个节点.
+* 当您取消上下文时,取消操作将从父上下文传播到子上下文。
+* context 可以携带请求范围的值。
+* 要**添加**一个值,请像这样导出上下文:`ctx := context.WithValue(req.Context(), requestID, uuid.NewV4().String())`
+* 要从上下文中**检索**一个值,请使用以下语法:`reqID, ok := ctx.Value(requestID).(string)`
+* 当没有使用给定键 `ctx.Value` 检索到值时,将返回 `nil`
+* 通常,未导出类型的全局未导出变量/常量用作键。
+
+## Bibliography
+
+* [abowd1999towards] Abowd, Gregory D, Anind K Dey, Peter J Brown, Nigel Davies, Mark Smith, and Pete Steggles. 1999. “Towards a Better Understanding of Context and Context-Awareness.” In International Symposium on Handheld and Ubiquitous Computing, 304–7. Springer.
diff --git a/chapter-37-Context/imgs/cancellation_propagation.7f4e0613.png b/chapter-37-Context/imgs/cancellation_propagation.7f4e0613.png
new file mode 100644
index 0000000000000000000000000000000000000000..ee609efcaeb5e44a7ffe35bcdd95ebb2eb48da88
Binary files /dev/null and b/chapter-37-Context/imgs/cancellation_propagation.7f4e0613.png differ
diff --git a/chapter-37-Context/imgs/cancellation_propagation_2.51cb103e.png b/chapter-37-Context/imgs/cancellation_propagation_2.51cb103e.png
new file mode 100644
index 0000000000000000000000000000000000000000..af67ee1ee55469a1f2caf5f16ec592252fe20be6
Binary files /dev/null and b/chapter-37-Context/imgs/cancellation_propagation_2.51cb103e.png differ
diff --git a/chapter-37-Context/imgs/context.92f43817.jpg b/chapter-37-Context/imgs/context.92f43817.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..56b5bad1bd1e8b53a7c7bdaa45988624bc540c06
Binary files /dev/null and b/chapter-37-Context/imgs/context.92f43817.jpg differ
diff --git a/chapter-37-Context/imgs/ctx_4_levels.f46f9ff9.png b/chapter-37-Context/imgs/ctx_4_levels.f46f9ff9.png
new file mode 100644
index 0000000000000000000000000000000000000000..930dd665686f0001c71f9f9ad02b2d6732aa7642
Binary files /dev/null and b/chapter-37-Context/imgs/ctx_4_levels.f46f9ff9.png differ
diff --git a/chapter-37-Context/imgs/deriving_context.ad1f8dc6.png b/chapter-37-Context/imgs/deriving_context.ad1f8dc6.png
new file mode 100644
index 0000000000000000000000000000000000000000..b6c48eb7a7b8e3757221fcc1cd6033239ec7e635
Binary files /dev/null and b/chapter-37-Context/imgs/deriving_context.ad1f8dc6.png differ
diff --git a/chapter-37-Context/imgs/doWorkFunction.15397b29.png b/chapter-37-Context/imgs/doWorkFunction.15397b29.png
new file mode 100644
index 0000000000000000000000000000000000000000..64551ea8912063bcd81c76211b398660f79abc49
Binary files /dev/null and b/chapter-37-Context/imgs/doWorkFunction.15397b29.png differ
diff --git a/chapter-37-Context/imgs/linked_list.2f868379.png b/chapter-37-Context/imgs/linked_list.2f868379.png
new file mode 100644
index 0000000000000000000000000000000000000000..a8ce468c398202c500db775f98c28f27c81c2815
Binary files /dev/null and b/chapter-37-Context/imgs/linked_list.2f868379.png differ
diff --git a/chapter-37-Context/imgs/linked_list_pointers.3614379a.png b/chapter-37-Context/imgs/linked_list_pointers.3614379a.png
new file mode 100644
index 0000000000000000000000000000000000000000..50cb63bf3b579b35c994975db9b39c4b143385aa
Binary files /dev/null and b/chapter-37-Context/imgs/linked_list_pointers.3614379a.png differ
diff --git a/chapter-37-Context/imgs/request_context.77c1b04c.png b/chapter-37-Context/imgs/request_context.77c1b04c.png
new file mode 100644
index 0000000000000000000000000000000000000000..521a014aad3136f569fa6b81edcd54e7d1c69048
Binary files /dev/null and b/chapter-37-Context/imgs/request_context.77c1b04c.png differ
diff --git a/chapter-37-Context/imgs/serverWithTimeout.78b3d9c5.png b/chapter-37-Context/imgs/serverWithTimeout.78b3d9c5.png
new file mode 100644
index 0000000000000000000000000000000000000000..084bb5c781a273124a39a3a388f737d38ce7023b
Binary files /dev/null and b/chapter-37-Context/imgs/serverWithTimeout.78b3d9c5.png differ
diff --git a/chapter-37-Context/imgs/server_client_timeout.4e32a6a4.png b/chapter-37-Context/imgs/server_client_timeout.4e32a6a4.png
new file mode 100644
index 0000000000000000000000000000000000000000..f0405131ec5cfc2f2e9a67faa9840dfc76114c54
Binary files /dev/null and b/chapter-37-Context/imgs/server_client_timeout.4e32a6a4.png differ
diff --git a/chapter-37-Context/imgs/timeout_deadline.b1d54bad.png b/chapter-37-Context/imgs/timeout_deadline.b1d54bad.png
new file mode 100644
index 0000000000000000000000000000000000000000..25f178e5561556946ecd2e1f2bce8e72116bc5d0
Binary files /dev/null and b/chapter-37-Context/imgs/timeout_deadline.b1d54bad.png differ
diff --git a/chapter-37-Context/imgs/withCancel.150ca94b.png b/chapter-37-Context/imgs/withCancel.150ca94b.png
new file mode 100644
index 0000000000000000000000000000000000000000..d9678fbddb9d6a7af179381c3fe9b3fd9aac6e6d
Binary files /dev/null and b/chapter-37-Context/imgs/withCancel.150ca94b.png differ
diff --git a/chapter-37-Context/imgs/withCancel3Derivatin.c23d2f44.png b/chapter-37-Context/imgs/withCancel3Derivatin.c23d2f44.png
new file mode 100644
index 0000000000000000000000000000000000000000..97047d13699f8ad2606f6c96f7d76e028f2a3dce
Binary files /dev/null and b/chapter-37-Context/imgs/withCancel3Derivatin.c23d2f44.png differ