PromiseA+规范的实现
promise A+规范
PromiseA+规范从零实现,包括最新的 allSettled 方法
# promise A+规范的要求
- 术语
1.1 ‘promise’ 是一个有符合此标准的 then 方法的 object 或 function
1.2 ‘thenable’ 是 then 方法定义的 object 或 function
1.3 ‘value’ 是一个 JavaScript 合法值(包括 undefined,thenable,promise)
1.4 ‘exception’ 是一个 throw 语句抛出错误的值
1.5 ‘reason’ 是一个表明 promise 失败的原因的值
- 要求
# 2.1 Promise 状态
一个 promise 有且只有一个状态(pending,fulfilled,rejected 其中之一)
- 2.1.1 pending 状态时:
- 2.1.1.1 可能会转变为 fulfilled 或 rejected 状态
- 2.1.2 fulfilled 状态时:
- 2.1.2.1 不能再状态为任何其他状态
- 2.1.2.2 必须有一个 value,且不可改变
- 2.1.3 rejected 状态时:
- 2.1.3.1 不能再状态为任何其他状态
- 2.1.3.2 必须有一个 reason,且不可改变 注:这里 ‘不可改变’ 意思是不可变恒等(同理 === ),但不意味永远不可变
# 2.2 then 方法
一个 promise 必须提供一个 then 方法,用来获取当前或最终的 value 或 reason 一个 promise 的 then 方法接受两个参数: promise.then(onFulfilled, onRejected)
- 2.2.1 onFulfilled 和 onRejected 都是可选参数:
- 2.2.1.1 如果 onFulfilled 不是函数,它会被忽略
- 2.2.1.2 如果 onRejected 不是函数,它会被忽略
- 2.2.2 如果 onFulfilled 是一个函数:
- 2.2.2.1 它一定是在 promise 是 fulfilled 状态后调用,并且接受一个参数 value
- 2.2.2.2 它一定是在 promise 是 fulfilled 状态后调用
- 2.2.2.3 它最多被调用一次
- 2.2.3 如果 onRejected 是一个函数:
- 2.2.3.1 它一定在 promise 是 rejected 状态后调用,并且接受一个参数 reason
- 2.2.3.2 它一定在 promise 是 rejected 状态后调用
- 2.2.3.3 它最多被调用一次
- 2.2.4 onFulfilled 或 onRejected 只在执行环境堆栈只包含平台代码之后调用 [3.1]
- 2.2.5 onFulfilled 和 onRejected 会作为函数形式调用 (也就是说,默认 this 指向 global,严格模式 undefined) [3.2]
- 2.2.6 promise 的 then 可以链式调用多次
- 2.2.6.1 如果或当 promise 转态是 fulfilled 时,所有的 onFulfilled 回调回以他们注册时的顺序依次执行
- 2.2.6.2 如果或当 promise 转态是 rejected 时,所有的 onRejected 回调回以他们注册时的顺序依次执行
- 2.2.7 then 方法一定返回一个 promise .promise2 = promise1.then(onFulfilled, onRejected);
- 2.2.7.1 如果 onFulfilled 或 onRejected 返回的是一个 x,那么它会以[[Resolve]](promise2, x) 处理解析
- 2.2.7.2 如果 onFulfilled 或 onRejected 里抛出了一个异常,那么 promise2 必须捕获这个错误(接受一个 reason 参数)
- 2.2.7.3 如果 onFulfilled 不是一个函数,并且 promise1 状态是 fulfilled,那么 promise2 一定会接受到与 promse1 一样的值 value
- 2.2.7.4 如果 onRejected 不是一个函数,并且 promise1 状态是 rejected,promise2 一定会接受到与 promise1 一样的值 reason
# 2.3 Promise 处理程序
promise 处理程序是一个表现形式为 [[Resolve]](promise, x) 的抽象处理操作。如果 x 是 thenable 类型,它会尝试生成一个 promise 处理 x,否则它将直接 resolve x
只要 then 方法符合 Promises/A+ 规则,那么对 thenables 处理就允许实现可互操作(链式调用,层层传递下去)。它也允许对那些不符合 Promises/A+ 的 then 方法进行 “吸收”
[[Resolve]](promise, x) 的执行表现形式如下步骤:
- 2.3.1 如果返回的 promise1 和 x 是指向同一个引用(循环引用),则抛出错误
- 2.3.2 如果 x 是一个 promise 实例,则采用它的状态:
- 2.3.2.1 如果 x 是 pending 状态,那么保留它(递归执行这个 promise 处理程序),直到 pending 状态转为 fulfilled 或 rejected 状态
- 2.3.2.2 如果或当 x 状态是 fulfilled,resolve 它,并且传入和 promise1 一样的值 value
- 2.3.2.3 如果或当 x 状态是 rejected,reject 它,并且传入和 promise1 一样的值 reason
- 2.3.3 此外,如果 x 是个对象或函数类型
- 2.3.3.1 把 x.then 赋值给 then 变量
- 2.3.3.2 如果捕获(try,catch)到 x.then 抛出的错误的话,需要 reject 这个 promise
- 2.3.3.3 如果 then 是函数类型,那个用 x 调用它(将 then 的 this 指向 x),第一个参数传 resolvePromise ,第二个参数传 rejectPromise:
- 2.3.3.3.1 如果或当 resolvePromise 被调用并接受一个参数 y 时,执行[[Resolve]](promise, y)
- 2.3.3.3.2 如果或当 rejectPromise 被调用并接受一个参数 r 时,执行 reject(r)
- 2.3.3.3.3 如果 resolvePromise 和 rejectPromise 已经被调用或以相同的参数多次调用的话吗,优先第一次的调用,并且之后的调用全部被忽略(避免多次调用)
- 2.3.3.4 如果 then 执行过程中抛出了异常,
- 2.3.3.3.4.1 如果 resolvePromise 或 rejectPromise 已经被调用,那么忽略异常
- 2.3.3.3.4.2 否则,则 reject 这个异常
- 2.3.3.4 如果 then 不是函数类型,直接 resolve x(resolve(x))
- 2.3.4 如果 x 即不是函数类型也不是对象类型,直接 resolve x(resolve(x))
如果被 resolve 的 promise 参与了 thenable 的循环链中,那么可能会导致无限递归。我们鼓励实现检测这种无限递归的方法并且返回一个错误信息,但并不是必须的 [3.6] 3. 备注 3.1 这里的 “平台代码”是指引擎,环境,和 promise 实现代码。实际上,这个要求确保 onFulfilled 和 onRejected 都在下一轮的事件循环中(一个新的栈)被异步调用。可以用宏任务,例如:setTimeout,setImmediate 或者微任务,例如:MutationObsever 或 process.nextTick 实现。 由于 promise 的实现被当做平台代码,所以它本身可能包含一个任务队列或 “trampoline” 的处理程序
- 3.2 这个 this 在严格模式下是 undefined,在宽松模式,指向 global 对象
- 3.3 具体的实现可以允许 promise2 和 promise1 绝对相等,要满足所有要求。每一个处理 promise2 和 promise1 绝对相等的实现都要写上文档标注
- 3.4 通常,只有它来自当前实现才可以判断 x 是一个真正的 promise。 此条款允许采取已知符合 promise 标准实现的状态
- 3.5 把 x.then 存起来,然后测试、调用这个引用,避免多次访问 x.then 属性。这么做的原因是防止每次获取 x.then 时,返回不同的情况(ES5 的 getter 特性可能会产生副作用)
- 3.6 实现不应该武断地限制 thenable 链的深度,假设超出限制的无限递归。只有真正的循环引用才会导致一个 TypeError 错误,如果遇到一个不同的无限递归 thenable 链,一直递归永远是正确的行为
# 手写 Promise
首先,先将 promise 的基础状态和大致需要写出来
const PENDING = "pending";
const RESOLVE = "resolve";
const REJECT = "reject";
class PromiseClone {
constructor(_handler) {
// 初始化,外部传入一个函数,value用来存储resolve时的值,reason用来存储失败时的原因
this.status = PENDING;
this.value = undefined;
this.reason = undefined;
const resolve = (value) => {
if (this.status !== PENDING) return;
this.value = value;
this.status = RESOLVE;
};
const reject = (reason) => {
if (this.status !== PENDING) return;
this.reason = reason;
this.status = REJECT;
};
// 在构造函数初始化中同步执行handler
_handler(resolve, reject);
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
我们可以通过 console 发现当同步代码中的 handler 执行的时候,promise 内部的状态并没有发生改变,且有的代码会在_handler 内部执行一段异步代码或仍然是一个 promise, 例如
new Promise((resolve) => {
setTimeout(() => {
resolve(123);
}, 1000);
});
new Promise((resolve) => {
resolve(new Promise.resolve(123));
});
2
3
4
5
6
7
8
所以,为了保证链式调用的 then.catch 内的方法异步执行,同时 resolve、reject 能在此之前获得被改变了的状态,我们需要对代码进行进一步的扩充
class PromiseClone {
constructor(_handler) {
this.status = PENDING;
this.value = undefined;
this.reason = undefined;
// 设置两个接收所属的then、catch方法的数组,让他们在resolve、reject异步完成之后执行,确保状态和值产生了改变
this.asyncResolveCallback = [];
this.asyncRejectCallback = [];
const resolve = (value) => {
setTimeout(() => {
if (this.status !== PENDING) return;
this.value = value;
this.status = RESOLVE;
//当 promise 转态是 fulfilled 时,所有的 onFulfilled 回调回以他们注册时的顺序依次执行
this.asyncResolveCallback.forEach((callback) => callback(value));
this.asyncResolveCallback = [];
}, 0);
};
const reject = (reason) => {
setTimeout(() => {
if (this.status !== PENDING) return;
this.reason = reason;
this.status = REJECT;
// 当 promise 转态是 rejected 时,所有的 onRejected 回调回以他们注册时的顺序依次执行
this.asyncRejectCallback.forEach((callback) => callback(reason));
this.asyncRejectCallback = [];
}, 0);
};
// handler在执行过程中可能会报错,我们需要将其放入try/catch中
try {
_handler(resolve, reject);
} catch (error) {
reject(error);
}
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
接下来我们就要开始参照规范书写 then 方法(2.2)
# then 方法
then(nextResolve, nextReject) {
// then方法可以多次链式调用:Promise(resolve(2)).then().then().then(res=>console.log(res)): 2
// 首先判断传入的是否为函数,若不为函数,则为其定义一个将结果继续传递的函数,并返回一个新的promise以满足链式调用
if (typeof nextResolve !== 'function') {
// 2.2.7.3
nextResolve = (v) => v
}
if (typeof nextReject !== 'function') {
// 2.2.7.4
nextReject = (err) => {
throw Error(err)
}
}
return new PromiseClone((resolve, reject) => {
function resolvePromise(x) {
// 2.2.7, 2.3.3
if ((typeof x === 'object' && x !== null) || typeof x === 'function') {
try {
// 有then且为function,则认为它是一个promise
const then = x.then
if (typeof then === 'function') {
x.then(resolve, reject)
} else {
resolve(x)
}
} catch (error) {
reject(error)
}
} else {
resolve(x) // 2.2.7.1
}
}
// 判断状态,将处于不同状态下的promise进行处理
// 2.2.7.2,如果抛出异常,必须捕获错误,抛出原因,返回一个reject状态的新promise
if (this.status === PENDING) {
// PENDING状态,分别将处理函数传入数组中,这里的结果用this.value保证得到的是异步后在所属promise改动的value
this.asyncResolveCallback.push(() => {
try {
const x = nextResolve(this.value)
resolvePromise(x)
} catch (error) {
reject(error)
}
})
this.asyncRejectCallback.push(() => {
try {
const x = nextReject(this.reason)
resolvePromise(x)
} catch (error) {
reject(error)
}
})
}
if (this.status === RESOLVE) {
try {
const x = nextResolve(this.value)
resolvePromise(x)
} catch (error) {
reject(error)
}
}
if (this.status === REJECT) {
try {
const x = nextReject(this.reason)
resolvePromise(x)
} catch (error) {
reject(error)
}
}
})
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
我们按照规范在每次处理 then 之后传入一个新的并且已不属于 PENDING 状态的 promise,并且在 resolvePromise 里通过判断是否返回一个新的 promise,若是的话返回新 promise 的结果,但现在的代码还是有些问题:
- 我们会发现有可能出现新的 promise 里再镶嵌 promise 的情况,这样的话就没办法处理了,接下来我们将 resolvePromise 处理函数提到外面,来循环处理这样的情况。
- 在已拥有状态的情况下 then 方法里的代码找不到 promise 函数,需要将他们异步处理
下面列出带上 then 之后的完整源码:
const PENDING = "pending";
const RESOLVE = "resolve";
const REJECT = "reject";
function resolvePromise(promise, x, resolve, reject) {
// 2.3.1 如果返回的 promise1 和 x 是指向同一个引用(循环引用),则抛出错误
if (promise === x) {
return reject(new TypeError("循环引用相同promise"));
}
// 定一个锁,保证onFulfilled 、onRejected 最多被调用一次
let clock;
// 2.2.7
if ((typeof x === "object" && x !== null) || typeof x === "function") {
try {
// 有then且为function,则认为它是一个promise
const then = x.then;
if (typeof then === "function") {
then.call(
x,
(i) => {
if (clock) return;
clock = true;
// 继续resolve解析直到它是一个普通值为止
resolvePromise(promise, i, resolve, reject);
},
(e) => {
if (clock) return;
clock = true;
reject(e);
}
);
} else {
resolve(x);
}
} catch (error) {
if (clock) return;
clock = true;
reject(error);
}
} else {
resolve(x); // 2.2.7.1
}
}
class PromiseClone {
constructor(_handler) {
// 初始化,外部传入一个函数,value用来存储resolve时的值,reason用来存储失败时的原因
this.status = PENDING;
this.value = undefined;
this.reason = undefined;
// 异步回调数组
this.asyncResolveCallback = [];
this.asyncRejectCallback = [];
const _resolve = (value) => {
setTimeout(() => {
if (this.status !== PENDING) return;
this.value = value;
this.status = RESOLVE;
this.asyncResolveCallback.forEach((callback) => callback(value));
this.asyncResolveCallback = [];
}, 0);
};
const _reject = (reason) => {
setTimeout(() => {
if (this.status !== PENDING) return;
this.reason = reason;
this.status = REJECT;
this.asyncRejectCallback.forEach((callback) => callback(reason));
this.asyncRejectCallback = [];
}, 0);
};
// 在构造函数初始化中同步执行handler
try {
_handler(_resolve, _reject);
} catch (error) {
reject(error);
}
}
then(nextResolve, nextReject) {
// then方法可以多次链式调用:Promise(resolve(2)).then().then().then(res=>console.log(res)): 2
// 首先判断传入的是否为函数,若不为函数,则为其定义一个将结果继续传递的函数,并返回一个新的promise以满足链式调用
if (typeof nextResolve !== "function") {
// 2.2.7.3
nextResolve = (v) => v;
}
if (typeof nextReject !== "function") {
// 2.2.7.4
nextReject = (err) => {
throw err;
};
}
const promise = new PromiseClone((resolve, reject) => {
// 判断状态,将处于不同状态下的promise进行处理
// 2.2.7.2,如果抛出异常,必须捕获错误,抛出原因,返回一个reject状态的新promise
if (this.status === PENDING) {
// PENDING状态,分别将处理函数传入数组中,这里的结果用this.value保证得到的是异步后在所属promise改动的value
this.asyncResolveCallback.push(() => {
try {
const x = nextResolve(this.value);
resolvePromise(promise, x, resolve, reject);
} catch (error) {
reject(error);
}
});
this.asyncRejectCallback.push(() => {
try {
const x = nextReject(this.reason);
resolvePromise(promise, x, resolve, reject);
} catch (error) {
reject(error);
}
});
}
if (this.status === RESOLVE) {
setTimeout(() => {
try {
const x = nextResolve(this.value);
resolvePromise(promise, x, resolve, reject);
} catch (error) {
reject(error);
}
}, 0);
}
if (this.status === REJECT) {
setTimeout(() => {
try {
const x = nextReject(this.reason);
resolvePromise(promise, x, resolve, reject);
} catch (error) {
reject(error);
}
}, 0);
}
});
return promise;
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
# catch 方法
catch 方法其实就是利用 then 方法里的第二个参数
catch(_catchHandler) {
return this.then(null, _catchHandler)
}
2
3
# resolve 方法
static resolve(value) {
return new PromiseClone(resolve=>resolve(value))
}
2
3
# reject 方法
static reject(reason) {
return new PromiseClone((resolve,reject)=>reject(reason))
}
2
3
# all 方法
promise.all 传入一个数组,这个数组内可能时一个常量,也可能是一个 promsie 对象, 我们需要将其包裹到 promsie.resolve 中将他们都转换成一个 promise 对象进行处理
static all(list) {
return new PromiseClone((resolve, reject) => {
if (!Array.isArray(list)) reject(new Error('arguments must be array type'))
const result = [], len = list.length;
let count = 0;
for(let i = 0; i < len; i++) {
PromiseClone.resolve(list[i]).then(res => {
result[i] = res;
count++;
if (count === len)resolve(results)
}, err=> {
reject(err)
})
}
})
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# race 方法
返回最快改变状态的 Promise 的结果
static race(list) {
return new PromiseClone((resolve,reject) => {
list.forEach(promiseHandler=> {
if (!(promiseHandler instanceof PromiseClone)) return
promiseHandler.then((value)=> {
resolve(value)
},error=>{
reject(error)
})
})
})
}
2
3
4
5
6
7
8
9
10
11
12
# done 方法
处于回掉链的尾端,保证抛出任何可能出现的错误
done(resolve, reject) {
this.then(resolve, reject).catch(reason=> {
setTimeout(()=>{
throw reason
}, 0)
})
}
2
3
4
5
6
7
# finally 方法
不管运行成功与否,都会执行的方法
finally(fn) {
return this.then(
value=> PromiseClone.resolve(fn()).then(value),
reason => PromiseClone.resolve(fn()).then(()=>{throw reason})
)
}
2
3
4
5
6
# 最终代码实现
const PENDING = "PENDING"; // 等待
const FULFILLED = "FULFILLED"; // 成功
const REJECT = "REJECT"; // 失败
function resolvePromise(promise, res, resolve, reject) {
if (promise === res) {
// 如果 promise 和 x 指向同⼀对象,以 TypeError为据因拒绝执⾏ promise
return reject(new TypeError("error same promise"));
}
let clock;
// 若是返回值res仍是一个promise
if ((typeof res === "object" && res !== null) || typeof res === "function") {
// then要是一个不能被外界改变使用的方法
try {
const then = res.then;
if (typeof then === "function") {
then.call(
res,
(i) => {
if (clock) return;
clock = true;
// 当前promise解析出来的结果可能还是一个promise, 继续resolve解析直到它是一个普通值为止
resolvePromise(promise, i, resolve, reject);
},
(e) => {
if (clock) return;
clock = true;
reject(e);
}
);
} else {
resolve(res);
}
} catch (e) {
if (clock) return;
clock = true;
reject(e); // 取值失败错误信息抛出去
}
} else {
resolve(res);
}
}
class PromiseClone {
constructor(_handler) {
this.status = PENDING;
this.value = undefined;
this.reason = undefined;
// 异步回调数组
this.asyncResolveCallback = [];
this.asyncRejectCallback = [];
const _resolve = (value) => {
setTimeout(() => {
if (this.status !== PENDING) return;
this.status = FULFILLED;
this.value = value;
this.asyncResolveCallback.forEach((item) => item(value));
this.asyncResolveCallback = [];
}, 0);
};
const _reject = (reason) => {
setTimeout(() => {
if (this.status !== PENDING) return;
this.status = REJECT;
this.reason = reason;
this.asyncRejectCallback.forEach((item) => item(reason));
this.asyncRejectCallback = [];
}, 0);
};
try {
_handler(_resolve, _reject);
} catch (error) {
_reject(error);
}
}
then(_resolve, _reject) {
_resolve = typeof _resolve == "function" ? _resolve : (v) => v;
_reject =
typeof _reject == "function"
? _reject
: (err) => {
throw err;
};
const promise = new PromiseClone((resolve, reject) => {
const { value, status, reason } = this;
if (status === PENDING) {
this.asyncResolveCallback.push(() => {
try {
const x = _resolve(this.value);
resolvePromise(promise, x, resolve, reject);
} catch (error) {
reject(error);
}
});
this.asyncRejectCallback.push(() => {
try {
const x = _reject(this.reason);
resolvePromise(promise, x, resolve, reject);
} catch (error) {
reject(error);
}
});
}
if (status === FULFILLED) {
setTimeout(() => {
try {
let x = _resolve(value);
resolvePromise(promise, x, resolve, reject);
} catch (error) {
reject(error);
}
}, 0);
}
if (status === REJECT) {
setTimeout(() => {
try {
let x = _reject(reason);
resolvePromise(promise, x, resolve, reject);
} catch (error) {
reject(error);
}
}, 0);
}
});
return promise;
}
catch(_rejectFunc) {
return this.then(null, _rejectFunc);
}
// 处于回掉链的尾端,保证抛出任何可能出现的错误
done(resolve, reject) {
this.then(resolve, reject).catch((reason) => {
setTimeout(() => {
throw reason;
}, 0);
});
}
finally(fn) {
return this.then(
(value) => PromiseClone.resolve(fn()).then(value),
(reason) =>
PromiseClone.resolve(fn()).then(() => {
throw reason;
})
);
}
static resolve(ret) {
return new PromiseClone((resolve) => resolve(ret));
}
static reject(ret) {
return new PromiseClone((resolve, reject) => reject(ret));
}
static all(list) {
return new PromiseClone((resolve, reject) => {
let count = 0;
const results = [];
for (const [index, promiseCallback] of list.entries()) {
if (!(promiseHandler instanceof PromiseClone)) break;
promiseCallback.then(
(res) => {
results[index] = res;
count++;
if (count === list.length) resolve(results);
},
(err) => {
reject(err);
}
);
}
});
}
static allSettled(list) {
return new PromiseClone((resolve, reject) => {
let count = 0;
const results = [];
for (const [index, promiseCallback] of list.entries()) {
if (!(promiseHandler instanceof PromiseClone)) break;
promiseCallback.then(
(res) => {
results[index] = res;
count++;
if (count === list.length) resolve(results);
},
(err) => {
results[index] = {
reason: err,
};
count++;
if (count === list.length) resolve(results);
}
);
}
});
}
// 返回最快改变状态的Promise的结果
static race(list) {
return new PromiseClone((resolve, reject) => {
list.forEach((item) => {
if (!(item instanceof PromiseClone)) return;
item
.then((result) => {
resolve(result);
})
.catch((err) => {
reject(err);
});
});
});
}
}
// promise Chain
const promiseChain = [].reduce((memo, current) => {
return memo.then(current);
}, Promise.resolve());
PromiseClone.defer = PromiseClone.deferred = function() {
let dfd = {};
dfd.promise = new PromiseClone((resolve, reject) => {
dfd.resolve = resolve;
dfd.reject = reject;
});
return dfd;
};
module.exports = PromiseClone;
// promise变成已拒绝的状态,不会被trycatch捕获
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238