diff --git a/.DS_Store b/.DS_Store
new file mode 100644
index 000000000..eeebc5f3f
Binary files /dev/null and b/.DS_Store differ
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 000000000..40b878db5
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1 @@
+node_modules/
\ No newline at end of file
diff --git a/Lesson3/README.md b/Lesson3/README.md
new file mode 100644
index 000000000..ba26ced65
--- /dev/null
+++ b/Lesson3/README.md
@@ -0,0 +1,16 @@
+## 硅谷live以太坊智能合约频道官方地址
+
+### 第三课《智能合约后端优化和产品化》
+
+目录结构
+
|
+
|--orgin 课程初始代码
+
|
+
|--assignment 课程作业提交代码
+
+### 本节知识点
+第3课:智能合约后端优化和产品化
+- 如何通过数据结构优化降低合约执行成本
+- 合约的继承
+- 巧用modifier
+- 以太坊函数库的使用和基本介绍
diff --git a/Lesson3/assignment/README.md b/Lesson3/assignment/README.md
new file mode 100644
index 000000000..01011eb46
--- /dev/null
+++ b/Lesson3/assignment/README.md
@@ -0,0 +1,14 @@
+## 硅谷live以太坊智能合约 第三课作业
+这里是同学提交作业的目录
+
+### 第三课:课后作业
+- 第一题:完成今天所开发的合约产品化内容,使用Remix调用每一个函数,提交函数调用截图
+- 第二题:增加 changePaymentAddress 函数,更改员工的薪水支付地址,思考一下能否使用modifier整合某个功能
+- 第三题(加分题):自学C3 Linearization, 求以下 contract Z 的继承线
+- contract O
+- contract A is O
+- contract B is O
+- contract C is O
+- contract K1 is A, B
+- contract K2 is A, C
+- contract Z is K1, K2
diff --git a/Lesson3/assignment/addEmployee.png b/Lesson3/assignment/addEmployee.png
new file mode 100644
index 000000000..c20caec68
Binary files /dev/null and b/Lesson3/assignment/addEmployee.png differ
diff --git a/Lesson3/assignment/addFund.png b/Lesson3/assignment/addFund.png
new file mode 100644
index 000000000..9077d5395
Binary files /dev/null and b/Lesson3/assignment/addFund.png differ
diff --git a/Lesson3/assignment/c3_sol.txt b/Lesson3/assignment/c3_sol.txt
new file mode 100644
index 000000000..5fe914211
--- /dev/null
+++ b/Lesson3/assignment/c3_sol.txt
@@ -0,0 +1,37 @@
+- 第三题(加分题):自学C3 Linearization, 求以下 contract Z 的继承线
+- contract O
+- contract A is O
+- contract B is O
+- contract C is O
+- contract K1 is A, B
+- contract K2 is A, C
+- contract Z is K1, K2
+
+L(0) := [0]
+
+L(A) := [A, 0]
+
+L(B) := [B, 0]
+
+L(C) := [C, 0]
+
+L(K1) := [K1] + merge(L(B), L(A), [B, A])
+ = [K1] + merge([B, 0], [A, 0], [B, A])
+ = [K1, B] + merge([0], [A, 0], [A])
+ = [K1, B, A] + merge([0], [0])
+ = [K1, B, A, 0]
+
+L(K2) := [K2] + merge(L(C), L(A), [C, A])
+ = [K2] + merge([C, 0], [A, 0], [C, A])
+ = [K2, C] + merge([0], [A, 0], [A])
+ = [K2, C, A] + merge([0], [0])
+ = [K2, C, A, 0]
+
+L(Z) := [Z] + merge(L(K2), L(K1), [K2, K1])
+ = [Z] + merge([K2, C, A, 0], [K1, B, A, 0], [K2, K1])
+ = [Z, K2] + merge([C, A, 0], [K1, B, A, 0], [k1])
+ = [Z, K2, K1] + merge([C, A, 0], [B, A, 0])
+ = [Z, K2, K1, C] + merge([A, 0], [B, 0])
+ = [Z, K1, K2, C, A] + merge([0], [B, 0])
+ = [Z, K1, K2, C, A, B] + merge([0], [0])
+ = [Z, K1, K2, C, A, B, 0]
\ No newline at end of file
diff --git a/Lesson3/assignment/calculateRunway.png b/Lesson3/assignment/calculateRunway.png
new file mode 100644
index 000000000..cea52579d
Binary files /dev/null and b/Lesson3/assignment/calculateRunway.png differ
diff --git a/Lesson3/assignment/changePaymentAddress.png b/Lesson3/assignment/changePaymentAddress.png
new file mode 100644
index 000000000..67b919bb2
Binary files /dev/null and b/Lesson3/assignment/changePaymentAddress.png differ
diff --git a/Lesson3/assignment/checkEmployee.png b/Lesson3/assignment/checkEmployee.png
new file mode 100644
index 000000000..b54aee92c
Binary files /dev/null and b/Lesson3/assignment/checkEmployee.png differ
diff --git a/Lesson3/assignment/create.png b/Lesson3/assignment/create.png
new file mode 100644
index 000000000..44900fcd9
Binary files /dev/null and b/Lesson3/assignment/create.png differ
diff --git a/Lesson3/assignment/getPaid.png b/Lesson3/assignment/getPaid.png
new file mode 100644
index 000000000..bf19d9034
Binary files /dev/null and b/Lesson3/assignment/getPaid.png differ
diff --git a/Lesson3/assignment/hasEnoughFund.png b/Lesson3/assignment/hasEnoughFund.png
new file mode 100644
index 000000000..4bf3c7802
Binary files /dev/null and b/Lesson3/assignment/hasEnoughFund.png differ
diff --git a/Lesson3/assignment/removeEmployee.png b/Lesson3/assignment/removeEmployee.png
new file mode 100644
index 000000000..ecd10d60a
Binary files /dev/null and b/Lesson3/assignment/removeEmployee.png differ
diff --git a/Lesson3/assignment/updateEmployee.png b/Lesson3/assignment/updateEmployee.png
new file mode 100644
index 000000000..c699f9aff
Binary files /dev/null and b/Lesson3/assignment/updateEmployee.png differ
diff --git a/Lesson3/assignment/yours.sol b/Lesson3/assignment/yours.sol
new file mode 100644
index 000000000..6a105d356
--- /dev/null
+++ b/Lesson3/assignment/yours.sol
@@ -0,0 +1,104 @@
+pragma solidity ^0.4.14;
+
+contract Payroll is Ownable{
+ struct Employee {
+ address id;
+ uint salary;
+ uint lastPayday;
+ }
+
+ uint constant payDuration = 10 seconds;
+
+ uint totalSalary;
+ address owner;
+ mapping(address=>Employee) employees;
+
+ function Payroll() public {
+ owner = msg.sender;
+ }
+
+ modifier onlyOwner {
+ require(msg.sender == owner);
+ _;
+ }
+
+ modifier employeeExist(address employeeId) {
+ var employee = employees[employeeId];
+ assert(employee.id != 0x0);
+ _;
+ }
+
+ modifier employeeNotExist(address employeeId) {
+ var employee = employees[employeeId];
+ assert(employee.id == 0x0);
+ _;
+ }
+
+
+
+ function _partialPaid(Employee employee) private {
+ uint payment = employee.salary * (now - employee.lastPayday) / payDuration;
+ employee.id.transfer(payment);
+ }
+
+ function addEmployee(address employeeId, uint salary) public onlyOwner employeeNotExist(employeeId){
+ employees[employeeId] = Employee(employeeId, salary * 1 ether, now);
+ totalSalary += salary * 1 ether;
+ }
+
+ function removeEmployee(address employeeId) public onlyOwner employeeExist(employeeId) {
+ var employee = employees[employeeId];
+
+ _partialPaid(employee);
+
+ totalSalary -= employee.salary;
+ delete employees[employeeId];
+
+ }
+
+ function updateEmployee(address employeeId, uint salary) public onlyOwner employeeExist(employeeId) {
+ var employee = employees[employeeId];
+ _partialPaid(employee);
+ totalSalary -= employees[employeeId].salary;
+ employees[employeeId].salary = salary * 1 ether;
+ totalSalary += employees[employeeId].salary;
+ employees[employeeId].lastPayday = now;
+ }
+
+ function changePaymentAddress(address newEmployeeId) public employeeExist(msg.sender) employeeNotExist(newEmployeeId){
+ //Only the employee can modify it's own address
+ var employee = employees[msg.sender];
+ uint oldlastPayday = employee.lastPayday;
+ uint oldSalary = employee.salary;
+ delete employees[msg.sender];
+
+ //create new employee
+ employees[newEmployeeId] = Employee(newEmployeeId, oldSalary, oldlastPayday);
+ }
+
+ function checkEmployee(address employeeId) public employeeExist(employeeId) returns (uint salary, uint lastPayday) {
+ var employee = employees[employeeId];
+ salary = employee.salary;
+ lastPayday =employee.lastPayday;
+ }
+
+ function addFund() payable public returns (uint) {
+ }
+
+ function calculateRunway() public returns (uint) {
+ return this.balance / totalSalary;
+ }
+
+ function hasEnoughFund() public returns (bool) {
+ return calculateRunway()>0;
+ }
+
+ function getPaid() public employeeExist(msg.sender){
+ var employee = employees[msg.sender];
+
+ uint nextPayday = employee.lastPayday + payDuration;
+ assert(nextPayday < now);
+ employees[msg.sender].lastPayday = nextPayday;
+ employee.id.transfer(employee.salary);
+ }
+}
diff --git a/Lesson3/orgin/README.md b/Lesson3/orgin/README.md
new file mode 100644
index 000000000..6106ea195
--- /dev/null
+++ b/Lesson3/orgin/README.md
@@ -0,0 +1,3 @@
+## 硅谷live以太坊智能合约 第三课
+
+这里是每一课的初始代码,有需要的同学可以参考
diff --git a/Lesson3/orgin/payroll.sol b/Lesson3/orgin/payroll.sol
new file mode 100644
index 000000000..e69de29bb
diff --git a/Lesson4/.DS_Store b/Lesson4/.DS_Store
new file mode 100644
index 000000000..ed6954bf8
Binary files /dev/null and b/Lesson4/.DS_Store differ
diff --git a/Lesson4/README.md b/Lesson4/README.md
new file mode 100644
index 000000000..34bf0bb82
--- /dev/null
+++ b/Lesson4/README.md
@@ -0,0 +1,16 @@
+## 硅谷live以太坊智能合约频道官方地址
+
+### 第四课《使用Truffle架构进行前后端交互,测试,部署》
+
+目录结构
+
|
+
|--orgin 课程初始代码
+
|
+
|--assignment 课程作业提交代码
+
+### 本节知识点
+第4课:使用Truffle架构进行前后端交互,测试,部署
+- 为什么要用Truffle,Truffle的基本概念
+- Truffle 的command line 功能
+- 初始化项目与Truffle项目目录结构
+- 编译部署合约到testrpc
diff --git a/Lesson4/assignment/README.md b/Lesson4/assignment/README.md
new file mode 100644
index 000000000..871e6be04
--- /dev/null
+++ b/Lesson4/assignment/README.md
@@ -0,0 +1,12 @@
+## 硅谷live以太坊智能合约 第四课作业
+这里是同学提交作业的目录
+
+### 第四课:课后作业
+- 将第三课完成的payroll.sol程序导入truffle工程
+- 在test文件夹中,写出对如下两个函数的单元测试:
+- function addEmployee(address employeeId, uint salary) onlyOwner
+- function removeEmployee(address employeeId) onlyOwner employeeExist(employeeId)
+- 思考一下我们如何能覆盖所有的测试路径,包括函数异常的捕捉
+- (加分题,选作)
+- 写出对以下函数的基于solidity或javascript的单元测试 function getPaid() employeeExist(msg.sender)
+- Hint:思考如何对timestamp进行修改,是否需要对所测试的合约进行修改来达到测试的目的?
diff --git a/Lesson4/assignment/box-img-lg.png b/Lesson4/assignment/box-img-lg.png
new file mode 100644
index 000000000..60c19962a
Binary files /dev/null and b/Lesson4/assignment/box-img-lg.png differ
diff --git a/Lesson4/assignment/box-img-sm.png b/Lesson4/assignment/box-img-sm.png
new file mode 100644
index 000000000..466e7097e
Binary files /dev/null and b/Lesson4/assignment/box-img-sm.png differ
diff --git a/Lesson4/assignment/build/contracts/Migrations.json b/Lesson4/assignment/build/contracts/Migrations.json
new file mode 100644
index 000000000..7b021099f
--- /dev/null
+++ b/Lesson4/assignment/build/contracts/Migrations.json
@@ -0,0 +1,79 @@
+{
+ "contract_name": "Migrations",
+ "abi": [
+ {
+ "constant": false,
+ "inputs": [
+ {
+ "name": "new_address",
+ "type": "address"
+ }
+ ],
+ "name": "upgrade",
+ "outputs": [],
+ "payable": false,
+ "type": "function"
+ },
+ {
+ "constant": true,
+ "inputs": [],
+ "name": "last_completed_migration",
+ "outputs": [
+ {
+ "name": "",
+ "type": "uint256"
+ }
+ ],
+ "payable": false,
+ "type": "function"
+ },
+ {
+ "constant": true,
+ "inputs": [],
+ "name": "owner",
+ "outputs": [
+ {
+ "name": "",
+ "type": "address"
+ }
+ ],
+ "payable": false,
+ "type": "function"
+ },
+ {
+ "constant": false,
+ "inputs": [
+ {
+ "name": "completed",
+ "type": "uint256"
+ }
+ ],
+ "name": "setCompleted",
+ "outputs": [],
+ "payable": false,
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "payable": false,
+ "type": "constructor"
+ }
+ ],
+ "unlinked_binary": "0x6060604052341561000f57600080fd5b5b60008054600160a060020a03191633600160a060020a03161790555b5b6101e58061003c6000396000f300606060405263ffffffff7c01000000000000000000000000000000000000000000000000000000006000350416630900f010811461005e578063445df0ac1461007f5780638da5cb5b146100a4578063fdacd576146100d3575b600080fd5b341561006957600080fd5b61007d600160a060020a03600435166100eb565b005b341561008a57600080fd5b610092610182565b60405190815260200160405180910390f35b34156100af57600080fd5b6100b7610188565b604051600160a060020a03909116815260200160405180910390f35b34156100de57600080fd5b61007d600435610197565b005b6000805433600160a060020a039081169116141561017c5781905080600160a060020a031663fdacd5766001546040517c010000000000000000000000000000000000000000000000000000000063ffffffff84160281526004810191909152602401600060405180830381600087803b151561016757600080fd5b6102c65a03f1151561017857600080fd5b5050505b5b5b5050565b60015481565b600054600160a060020a031681565b60005433600160a060020a03908116911614156101b45760018190555b5b5b505600a165627a7a72305820374a88e40b1a420f950c108b1f20a730496e9356f88fbe85169b500a1ae4e2f00029",
+ "networks": {
+ "1516414008735": {
+ "events": {},
+ "links": {},
+ "address": "0x02296ac68137b01fe647749758a6e5a78c1ce818",
+ "updated_at": 1516415853338
+ },
+ "1516418804860": {
+ "events": {},
+ "links": {},
+ "address": "0xabe8f6841727fe4403930be6e4df812334b687e2",
+ "updated_at": 1516420561621
+ }
+ },
+ "schema_version": "0.0.5",
+ "updated_at": 1516420561621
+}
\ No newline at end of file
diff --git a/Lesson4/assignment/build/contracts/Payroll.json b/Lesson4/assignment/build/contracts/Payroll.json
new file mode 100644
index 000000000..1bc55f8e8
--- /dev/null
+++ b/Lesson4/assignment/build/contracts/Payroll.json
@@ -0,0 +1,143 @@
+{
+ "contract_name": "Payroll",
+ "abi": [
+ {
+ "constant": false,
+ "inputs": [],
+ "name": "hasEnoughFund",
+ "outputs": [
+ {
+ "name": "",
+ "type": "bool"
+ }
+ ],
+ "payable": false,
+ "type": "function"
+ },
+ {
+ "constant": false,
+ "inputs": [],
+ "name": "calculateRunway",
+ "outputs": [
+ {
+ "name": "",
+ "type": "uint256"
+ }
+ ],
+ "payable": false,
+ "type": "function"
+ },
+ {
+ "constant": false,
+ "inputs": [
+ {
+ "name": "employeeId",
+ "type": "address"
+ },
+ {
+ "name": "salary",
+ "type": "uint256"
+ }
+ ],
+ "name": "updateEmployee",
+ "outputs": [],
+ "payable": false,
+ "type": "function"
+ },
+ {
+ "constant": false,
+ "inputs": [
+ {
+ "name": "newEmployeeId",
+ "type": "address"
+ }
+ ],
+ "name": "changePaymentAddress",
+ "outputs": [],
+ "payable": false,
+ "type": "function"
+ },
+ {
+ "constant": false,
+ "inputs": [
+ {
+ "name": "employeeId",
+ "type": "address"
+ }
+ ],
+ "name": "checkEmployee",
+ "outputs": [
+ {
+ "name": "salary",
+ "type": "uint256"
+ },
+ {
+ "name": "lastPayday",
+ "type": "uint256"
+ }
+ ],
+ "payable": false,
+ "type": "function"
+ },
+ {
+ "constant": false,
+ "inputs": [],
+ "name": "addFund",
+ "outputs": [
+ {
+ "name": "",
+ "type": "uint256"
+ }
+ ],
+ "payable": true,
+ "type": "function"
+ },
+ {
+ "constant": false,
+ "inputs": [],
+ "name": "getPaid",
+ "outputs": [],
+ "payable": false,
+ "type": "function"
+ },
+ {
+ "constant": false,
+ "inputs": [
+ {
+ "name": "employeeId",
+ "type": "address"
+ }
+ ],
+ "name": "removeEmployee",
+ "outputs": [],
+ "payable": false,
+ "type": "function"
+ },
+ {
+ "constant": false,
+ "inputs": [
+ {
+ "name": "employeeId",
+ "type": "address"
+ },
+ {
+ "name": "salary",
+ "type": "uint256"
+ }
+ ],
+ "name": "addEmployee",
+ "outputs": [],
+ "payable": false,
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "payable": false,
+ "type": "constructor"
+ }
+ ],
+ "unlinked_binary": "0x6060604052341561000f57600080fd5b5b60018054600160a060020a03191633600160a060020a03161790555b5b61073b8061003c6000396000f300606060405236156100965763ffffffff7c010000000000000000000000000000000000000000000000000000000060003504166323fed09e811461009b5780634ec19512146100c25780635e91d8ec146100e75780637124d6131461010b5780637cf562b71461012c578063a2f09dfa14610163578063cf41d6f81461017d578063d108177a14610192578063e7fd9a13146101b3575b600080fd5b34156100a657600080fd5b6100ae6101d7565b604051901515815260200160405180910390f35b34156100cd57600080fd5b6100d56101e9565b60405190815260200160405180910390f35b34156100f257600080fd5b610109600160a060020a0360043516602435610208565b005b341561011657600080fd5b610109600160a060020a03600435166102eb565b005b341561013757600080fd5b61014b600160a060020a036004351661040e565b60405191825260208201526040908101905180910390f35b6100d561043a565b60405190815260200160405180910390f35b341561018857600080fd5b610109610440565b005b341561019d57600080fd5b610109600160a060020a03600435166104f2565b005b34156101be57600080fd5b610109600160a060020a03600435166024356105e3565b005b6000806101e26101e9565b1190505b90565b6000805430600160a060020a03163181151561020157fe5b0490505b90565b60015460009033600160a060020a0390811691161461022657600080fd5b600160a060020a0380841660009081526002602052604090208054859216151561024c57fe5b600160a060020a0385166000908152600260205260409081902093506102a39084906060905190810160409081528254600160a060020a0316825260018301546020830152600290920154918101919091526106bb565b600160a060020a038516600090815260026020819052604082206001810180548454038455670de0b6b3a7640000880290819055835401909255429101555b5b50505b505050565b600160a060020a03338181166000908152600260205260408120805491938493849390929116151561031957fe5b600160a060020a03808716600090815260026020526040902080548892161561033e57fe5b600160a060020a03331660009081526002602081905260408083209182018054600184018054855473ffffffffffffffffffffffffffffffffffffffff191686559086905594909155919950909750909550606090519081016040908152600160a060020a038a1680835260208084018990528284018a9052600091825260029052208151815473ffffffffffffffffffffffffffffffffffffffff1916600160a060020a0391909116178155602082015181600101556040820151600290910155505b5b50505b505050505050565b600160a060020a0381166000908152600260208190526040909120600181015491810154905b50915091565b60005b90565b600160a060020a033381811660009081526002602052604081208054919384939216151561046a57fe5b600160a060020a033316600090815260026020819052604090912090810154909450600a01925042831061049a57fe5b600160a060020a03338116600090815260026020819052604091829020018590558554600187015492169180156108fc029151600060405180830381858888f1935050505015156104ea57600080fd5b5b5b50505050565b60015460009033600160a060020a0390811691161461051057600080fd5b600160a060020a0380831660009081526002602052604090208054849216151561053657fe5b600160a060020a03841660009081526002602052604090819020935061058d9084906060905190810160409081528254600160a060020a0316825260018301546020830152600290920154918101919091526106bb565b60018084015460008054919091038155600160a060020a03861681526002602081905260408220805473ffffffffffffffffffffffffffffffffffffffff1916815592830182905591909101555b5b50505b5050565b60015433600160a060020a039081169116146105fe57600080fd5b600160a060020a03808316600090815260026020526040902080548492161561062357fe5b60606040519081016040908152600160a060020a038616808352670de0b6b3a764000086026020808501919091524283850152600091825260029052208151815473ffffffffffffffffffffffffffffffffffffffff1916600160a060020a03919091161781556020820151816001015560408201516002909101555060008054670de0b6b3a764000085020190555b5b50505b5050565b6000600a826040015142038360200151028115156106d557fe5b0490508151600160a060020a031681156108fc0282604051600060405180830381858888f1935050505015156105df57600080fd5b5b50505600a165627a7a72305820d21cc2996e0c4b58dc159b94e8cb3fb92880073cebfe0134e2370b9729e7c5ae0029",
+ "networks": {},
+ "schema_version": "0.0.5",
+ "updated_at": 1516420561360
+}
\ No newline at end of file
diff --git a/Lesson4/assignment/build/contracts/SimpleStorage.json b/Lesson4/assignment/build/contracts/SimpleStorage.json
new file mode 100644
index 000000000..7c20041ed
--- /dev/null
+++ b/Lesson4/assignment/build/contracts/SimpleStorage.json
@@ -0,0 +1,48 @@
+{
+ "contract_name": "SimpleStorage",
+ "abi": [
+ {
+ "constant": false,
+ "inputs": [
+ {
+ "name": "x",
+ "type": "uint256"
+ }
+ ],
+ "name": "set",
+ "outputs": [],
+ "payable": false,
+ "type": "function"
+ },
+ {
+ "constant": false,
+ "inputs": [],
+ "name": "get",
+ "outputs": [
+ {
+ "name": "",
+ "type": "uint256"
+ }
+ ],
+ "payable": false,
+ "type": "function"
+ }
+ ],
+ "unlinked_binary": "0x6060604052341561000f57600080fd5b5b60b98061001e6000396000f300606060405263ffffffff7c010000000000000000000000000000000000000000000000000000000060003504166360fe47b1811460465780636d4ce63c14605b575b600080fd5b3415605057600080fd5b6059600435607d565b005b3415606557600080fd5b606b6086565b60405190815260200160405180910390f35b60008190555b50565b6000545b905600a165627a7a723058209375bf274b4e0bc28fc406ebb50490f62724d439830c51862fda935bcd7d5f360029",
+ "networks": {
+ "1516414008735": {
+ "events": {},
+ "links": {},
+ "address": "0x90109e8976752e748d962f8c262c2966702ebab2",
+ "updated_at": 1516415853338
+ },
+ "1516418804860": {
+ "events": {},
+ "links": {},
+ "address": "0xe26aba13ac77a885283400f35c411a876d8b6bdd",
+ "updated_at": 1516420561620
+ }
+ },
+ "schema_version": "0.0.5",
+ "updated_at": 1516420561620
+}
\ No newline at end of file
diff --git a/Lesson4/assignment/config/env.js b/Lesson4/assignment/config/env.js
new file mode 100644
index 000000000..5d0ab7b79
--- /dev/null
+++ b/Lesson4/assignment/config/env.js
@@ -0,0 +1,28 @@
+// Grab NODE_ENV and REACT_APP_* environment variables and prepare them to be
+// injected into the application via DefinePlugin in Webpack configuration.
+
+var REACT_APP = /^REACT_APP_/i;
+
+function getClientEnvironment(publicUrl) {
+ var processEnv = Object
+ .keys(process.env)
+ .filter(key => REACT_APP.test(key))
+ .reduce((env, key) => {
+ env[key] = JSON.stringify(process.env[key]);
+ return env;
+ }, {
+ // Useful for determining whether we’re running in production mode.
+ // Most importantly, it switches React into the correct mode.
+ 'NODE_ENV': JSON.stringify(
+ process.env.NODE_ENV || 'development'
+ ),
+ // Useful for resolving the correct path to static assets in `public`.
+ // For example, .
+ // This should only be used as an escape hatch. Normally you would put
+ // images into the `src` and `import` them in code to get their paths.
+ 'PUBLIC_URL': JSON.stringify(publicUrl)
+ });
+ return {'process.env': processEnv};
+}
+
+module.exports = getClientEnvironment;
diff --git a/Lesson4/assignment/config/jest/cssTransform.js b/Lesson4/assignment/config/jest/cssTransform.js
new file mode 100644
index 000000000..aa17d127a
--- /dev/null
+++ b/Lesson4/assignment/config/jest/cssTransform.js
@@ -0,0 +1,12 @@
+// This is a custom Jest transformer turning style imports into empty objects.
+// http://facebook.github.io/jest/docs/tutorial-webpack.html
+
+module.exports = {
+ process() {
+ return 'module.exports = {};';
+ },
+ getCacheKey(fileData, filename) {
+ // The output is always the same.
+ return 'cssTransform';
+ },
+};
diff --git a/Lesson4/assignment/config/jest/fileTransform.js b/Lesson4/assignment/config/jest/fileTransform.js
new file mode 100644
index 000000000..927eb305a
--- /dev/null
+++ b/Lesson4/assignment/config/jest/fileTransform.js
@@ -0,0 +1,10 @@
+const path = require('path');
+
+// This is a custom Jest transformer turning file imports into filenames.
+// http://facebook.github.io/jest/docs/tutorial-webpack.html
+
+module.exports = {
+ process(src, filename) {
+ return 'module.exports = ' + JSON.stringify(path.basename(filename)) + ';';
+ },
+};
diff --git a/Lesson4/assignment/config/paths.js b/Lesson4/assignment/config/paths.js
new file mode 100644
index 000000000..96c3dfb11
--- /dev/null
+++ b/Lesson4/assignment/config/paths.js
@@ -0,0 +1,46 @@
+var path = require('path');
+var fs = require('fs');
+
+// Make sure any symlinks in the project folder are resolved:
+// https://github.com/facebookincubator/create-react-app/issues/637
+var appDirectory = fs.realpathSync(process.cwd());
+function resolveApp(relativePath) {
+ return path.resolve(appDirectory, relativePath);
+}
+
+// We support resolving modules according to `NODE_PATH`.
+// This lets you use absolute paths in imports inside large monorepos:
+// https://github.com/facebookincubator/create-react-app/issues/253.
+
+// It works similar to `NODE_PATH` in Node itself:
+// https://nodejs.org/api/modules.html#modules_loading_from_the_global_folders
+
+// We will export `nodePaths` as an array of absolute paths.
+// It will then be used by Webpack configs.
+// Jest doesn’t need this because it already handles `NODE_PATH` out of the box.
+
+// Note that unlike in Node, only *relative* paths from `NODE_PATH` are honored.
+// Otherwise, we risk importing Node.js core modules into an app instead of Webpack shims.
+// https://github.com/facebookincubator/create-react-app/issues/1023#issuecomment-265344421
+
+var nodePaths = (process.env.NODE_PATH || '')
+ .split(process.platform === 'win32' ? ';' : ':')
+ .filter(Boolean)
+ .filter(folder => !path.isAbsolute(folder))
+ .map(resolveApp);
+
+// config after eject: we're in ./config/
+module.exports = {
+ // Changed from build to build_webpack so smart contract compilations are not overwritten.
+ appBuild: resolveApp('build_webpack'),
+ appPublic: resolveApp('public'),
+ appHtml: resolveApp('public/index.html'),
+ appIndexJs: resolveApp('src/index.js'),
+ appPackageJson: resolveApp('package.json'),
+ appSrc: resolveApp('src'),
+ yarnLockFile: resolveApp('yarn.lock'),
+ testsSetup: resolveApp('src/setupTests.js'),
+ appNodeModules: resolveApp('node_modules'),
+ ownNodeModules: resolveApp('node_modules'),
+ nodePaths: nodePaths
+};
diff --git a/Lesson4/assignment/config/polyfills.js b/Lesson4/assignment/config/polyfills.js
new file mode 100644
index 000000000..7e601502b
--- /dev/null
+++ b/Lesson4/assignment/config/polyfills.js
@@ -0,0 +1,14 @@
+if (typeof Promise === 'undefined') {
+ // Rejection tracking prevents a common issue where React gets into an
+ // inconsistent state due to an error, but it gets swallowed by a Promise,
+ // and the user has no idea what causes React's erratic future behavior.
+ require('promise/lib/rejection-tracking').enable();
+ window.Promise = require('promise/lib/es6-extensions.js');
+}
+
+// fetch() polyfill for making API calls.
+require('whatwg-fetch');
+
+// Object.assign() is commonly used with React.
+// It will use the native implementation if it's present and isn't buggy.
+Object.assign = require('object-assign');
diff --git a/Lesson4/assignment/config/webpack.config.dev.js b/Lesson4/assignment/config/webpack.config.dev.js
new file mode 100644
index 000000000..821743a2e
--- /dev/null
+++ b/Lesson4/assignment/config/webpack.config.dev.js
@@ -0,0 +1,242 @@
+var autoprefixer = require('autoprefixer');
+var webpack = require('webpack');
+var HtmlWebpackPlugin = require('html-webpack-plugin');
+var CaseSensitivePathsPlugin = require('case-sensitive-paths-webpack-plugin');
+var InterpolateHtmlPlugin = require('react-dev-utils/InterpolateHtmlPlugin');
+var WatchMissingNodeModulesPlugin = require('react-dev-utils/WatchMissingNodeModulesPlugin');
+var getClientEnvironment = require('./env');
+var paths = require('./paths');
+
+
+
+// Webpack uses `publicPath` to determine where the app is being served from.
+// In development, we always serve from the root. This makes config easier.
+var publicPath = '/';
+// `publicUrl` is just like `publicPath`, but we will provide it to our app
+// as %PUBLIC_URL% in `index.html` and `process.env.PUBLIC_URL` in JavaScript.
+// Omit trailing slash as %PUBLIC_PATH%/xyz looks better than %PUBLIC_PATH%xyz.
+var publicUrl = '';
+// Get environment variables to inject into our app.
+var env = getClientEnvironment(publicUrl);
+
+// This is the development configuration.
+// It is focused on developer experience and fast rebuilds.
+// The production configuration is different and lives in a separate file.
+module.exports = {
+ // You may want 'eval' instead if you prefer to see the compiled output in DevTools.
+ // See the discussion in https://github.com/facebookincubator/create-react-app/issues/343.
+ devtool: 'cheap-module-source-map',
+ // These are the "entry points" to our application.
+ // This means they will be the "root" imports that are included in JS bundle.
+ // The first two entry points enable "hot" CSS and auto-refreshes for JS.
+ entry: [
+ // Include an alternative client for WebpackDevServer. A client's job is to
+ // connect to WebpackDevServer by a socket and get notified about changes.
+ // When you save a file, the client will either apply hot updates (in case
+ // of CSS changes), or refresh the page (in case of JS changes). When you
+ // make a syntax error, this client will display a syntax error overlay.
+ // Note: instead of the default WebpackDevServer client, we use a custom one
+ // to bring better experience for Create React App users. You can replace
+ // the line below with these two lines if you prefer the stock client:
+ // require.resolve('webpack-dev-server/client') + '?/',
+ // require.resolve('webpack/hot/dev-server'),
+ require.resolve('react-dev-utils/webpackHotDevClient'),
+ // We ship a few polyfills by default:
+ require.resolve('./polyfills'),
+ // Finally, this is your app's code:
+ paths.appIndexJs
+ // We include the app code last so that if there is a runtime error during
+ // initialization, it doesn't blow up the WebpackDevServer client, and
+ // changing JS code would still trigger a refresh.
+ ],
+ output: {
+ // Next line is not used in dev but WebpackDevServer crashes without it:
+ path: paths.appBuild,
+ // Add /* filename */ comments to generated require()s in the output.
+ pathinfo: true,
+ // This does not produce a real file. It's just the virtual path that is
+ // served by WebpackDevServer in development. This is the JS bundle
+ // containing code from all our entry points, and the Webpack runtime.
+ filename: 'static/js/bundle.js',
+ // This is the URL that app is served from. We use "/" in development.
+ publicPath: publicPath
+ },
+ resolve: {
+ // This allows you to set a fallback for where Webpack should look for modules.
+ // We read `NODE_PATH` environment variable in `paths.js` and pass paths here.
+ // We use `fallback` instead of `root` because we want `node_modules` to "win"
+ // if there any conflicts. This matches Node resolution mechanism.
+ // https://github.com/facebookincubator/create-react-app/issues/253
+ fallback: paths.nodePaths,
+ // These are the reasonable defaults supported by the Node ecosystem.
+ // We also include JSX as a common component filename extension to support
+ // some tools, although we do not recommend using it, see:
+ // https://github.com/facebookincubator/create-react-app/issues/290
+ extensions: ['.js', '.json', '.jsx', ''],
+ alias: {
+ // Support React Native Web
+ // https://www.smashingmagazine.com/2016/08/a-glimpse-into-the-future-with-react-native-for-web/
+ 'react-native': 'react-native-web'
+ }
+ },
+
+ module: {
+ // First, run the linter.
+ // It's important to do this before Babel processes the JS.
+ preLoaders: [
+ {
+ test: /\.(js|jsx)$/,
+ loader: 'eslint',
+ include: paths.appSrc,
+ }
+ ],
+ loaders: [
+ // Default loader: load all assets that are not handled
+ // by other loaders with the url loader.
+ // Note: This list needs to be updated with every change of extensions
+ // the other loaders match.
+ // E.g., when adding a loader for a new supported file extension,
+ // we need to add the supported extension to this loader too.
+ // Add one new line in `exclude` for each loader.
+ //
+ // "file" loader makes sure those assets get served by WebpackDevServer.
+ // When you `import` an asset, you get its (virtual) filename.
+ // In production, they would get copied to the `build` folder.
+ // "url" loader works like "file" loader except that it embeds assets
+ // smaller than specified limit in bytes as data URLs to avoid requests.
+ // A missing `test` is equivalent to a match.
+ {
+ exclude: [
+ /\.html$/,
+ /\.(js|jsx)$/,
+ /\.css$/,
+ /\.json$/,
+ /\.woff$/,
+ /\.woff2$/,
+ /\.(ttf|svg|eot)$/
+ ],
+ loader: 'url',
+ query: {
+ limit: 10000,
+ name: 'static/media/[name].[hash:8].[ext]'
+ }
+ },
+ // Process JS with Babel.
+ {
+ test: /\.(js|jsx)$/,
+ include: paths.appSrc,
+ loader: 'babel',
+ query: {
+
+ // This is a feature of `babel-loader` for webpack (not Babel itself).
+ // It enables caching results in ./node_modules/.cache/babel-loader/
+ // directory for faster rebuilds.
+ cacheDirectory: true
+ }
+ },
+ // "postcss" loader applies autoprefixer to our CSS.
+ // "css" loader resolves paths in CSS and adds assets as dependencies.
+ // "style" loader turns CSS into JS modules that inject