├── .DS_Store ├── .gitignore ├── 2-egg-Puzzle.md ├── 239-Sliding-Window-Maximum.md ├── A-Way-to-Make-an-Efficient-React-Timer.md ├── Authetication-JWT-vs-Session.md ├── Binary-Search-variations.md ├── CSS-element-positioning.md ├── Coding-Problem-find-the-1st-Bad-Version.md ├── Common-Algorithm-Problems-JS.md ├── Common-DOM-Manipulations.md ├── Create-a-Calculator-React.md ├── Create-a-Calculator-Vanilla-JS.md ├── Design-Pattern-JS.md ├── ES6.md ├── Event-Emitter.md ├── Express-Framework.md ├── Facebook-Custom-Search.md ├── Facebook-Custom-Search ├── .FB.png.icloud └── FB.png ├── Facebook-Interview-Preparation.md ├── Flux-Redux.md ├── How-to-Flatten-an-Array.md ├── How-to-Make-Animation-using-JS.md ├── How-to-implement-auto-complete.md ├── MERN-Stack-Online-Exam-System.md ├── MERN-Stack-Online-Exam-System ├── NAF.png └── NAFlogin.png ├── Memory-Game.md ├── Memory-Game ├── IMG_4519.JPG └── memory_game.png ├── Negative-Margin-in-Layout.md ├── News-Recommendation-using-Wed-Mining.md ├── News-Recommendation-using-Wed-Mining ├── .loginPage.png.icloud ├── .newsPage.png.icloud ├── loginPage.png └── newsPage.png ├── Node-MySQL.md ├── Node-js.md ├── Note-of-Eloquent-JavaScript-JS-and-Browser.md ├── Note-of-Eloquent-JavaScript.md ├── README.md ├── React-Expense-Tracking-app.md ├── React-Expense-Tracking-app ├── create.gif ├── delete.gif └── update.gif ├── React-Learning.md ├── React-Router-v4.md ├── Reposition-an-Array.md ├── Search-for-a-Symmetric-Node.md ├── Sorting-Algorithms-in-JS.md ├── Specifio-Work-Summary.md ├── Stack-Queue-Implementation-using-JS.md ├── Tiny-URL.md ├── Tiny-URL ├── .tinyURL.png.icloud └── tinyURL.png ├── Trie-Tree-Implementation-using-JS.md ├── Trie.md ├── Union-Find-to-achieve-max-tasks.md ├── Ways-of-Creating-Objects-in-JS.md ├── Web-Template-Engine.md ├── Web-Worker-no-interfer-with-UI-thread.md ├── Write-Our-Own-Promise.md ├── setTimeout-vs-setInterval.md └── this-arrow-function.md /.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/caomingkai/Front-End-Common-Problems/0e19e3d19a033853eefddce80a68cbfac3e3baa6/.DS_Store -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/ignore-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | !folder/ 5 | folder/* 6 | 7 | 8 | File-System* 9 | How-Does-Kernel-Handl* 10 | How-does-OS-load-File* 11 | RAM-File-* 12 | TEST-File* 13 | Tasks-assignment-Kernel-Vir* 14 | VFS-system-ca* 15 | VM* 16 | Virtual-Memory-Allocation-* 17 | Vnode-Special-* 18 | Weather-Chat* 19 | eCommerce-Websit* 20 | page-frame* 21 | 22 | 23 | # misc 24 | .idea 25 | .DS_Store 26 | .env.local 27 | .env.development.local 28 | .env.test.local 29 | .env.production.local 30 | 31 | npm-debug.log* 32 | yarn-debug.log* 33 | yarn-error.log* 34 | -------------------------------------------------------------------------------- /2-egg-Puzzle.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: The Joy of Egg-Dropping(2-egg Puzzle) 3 | comments: true 4 | date: 2018-05-17 22:03:40 5 | type: categories 6 | categories: Algorithm 7 | tags: 8 | - binary search 9 | - DP 10 | --- 11 | 12 | ### I. Problem statement 13 | 14 | **1. Easy version** 15 | > Given infinite number of same eggs, try with minimun trials to find out the highest floor where tossing the egg won't result in egg crash. The building has 200 floors. 16 | 17 | - 变量:N=200 18 | - 目标:试验次数最小 19 | - 约束:none 20 | 21 | **2. Hard version** 22 | > Only 2 eggs were given, try with minimun trials to find the highest floor where tossing the egg won't result in egg crash. The building has 200 floors. (The egg can be reused as long as it is intact) 23 | 24 | - 变量:F=200, E=2 25 | - 目标:试验次数最小 26 | - 约束: 27 | 28 | 29 | 30 | ### II. Solution for easy version 31 | 32 | Since the number of eggs we can use is unlimited, we can use the **fastest approach in the universe** to find the unknown target in a list: `binary search` 33 | 34 | ``` 35 | - left direction: break 36 | - right direction:intact 37 | 38 | 0 100 200 39 | / \ 40 | 50 150 41 | / \ / \ 42 | 25 75 125 175 43 | / \ 44 | ... 45 | 46 | Toss an egg on floor 100: 47 | 1. if egg break, toss another on floor 50; 48 | 1.1 if egg break, toss another on floor 25; 49 | 1.1.1 ... 50 | 1.1.2 ... 51 | 1.2 if doesn't break, toss another on floor 75; 52 | 1.2.1 ... 53 | 1.2.2 ... 54 | 2. if doesn't break, toss another on floor 150; 55 | 2.1 if egg break, toss another on floor 125; 56 | 2.1.1 ... 57 | 2.1.2 ... 58 | 2.2 if doesn't break, toss another on floor 175; 59 | 2.2.1 ... 60 | 2.2.2 ... 61 | 62 | ``` 63 | 64 | 65 | ### III. Solution for hard version 66 | 67 | Since it is not so intuitive at first glance, we will take a few trials to get a deeper understanding of this problem. 68 | 69 | General idea: 70 | 71 | >egg-1 used to narrow down possible range 72 | >egg-2 used to sequentially find the target floor 73 | 74 | 1. **[egg-1 with step=10]** egg-1 tossed on floor 20,40,60,80,100,120,... with a step=20 75 | - worst-case: 29 trials 76 | + egg-1 tossed on 200 and break: 10 trials 77 | + egg-2 tossed on 199 (from 181), break: 19 trials 78 | - best-case: 2 trials 79 | + egg-1 tossed on 20 and break: 1 trials 80 | + egg-2 tossed on 1: 1 trials 81 | - for this method, what is the min trials can we say? 82 | + 29 trials(the worst case), no worse than it 83 | + we cannot guarantee it is the best case 84 | 85 | 2. **[edge case: BS]** egg-1 tossed on floor 100, 200 86 | - worst-case: 201 trials 87 | + egg-1 tossed on 200 and break: 2 trials 88 | + egg-2 tossed on 199 (from 101), break: 199 trials 89 | - best-case: 2 trials 90 | + egg-1 tossed on 100 and break: 1 trials 91 | + egg-2 tossed on 1: 1 trials 92 | - for this method, what is the min trials can we say? 93 | + 201 trials(the worst case), no worse than it 94 | 95 | 3. **[Solution 1]** 96 | - https://www.zhihu.com/question/19690210/answer/22937826 97 | - the 'step' affect min-trial 98 | - we want control 'step' to make the trials of worst case and best case as close as possible; This way it will divvy up the trial between worst and best cases 99 | - Goal: worst case trials = best case trials 100 | - egg-1 tossed on floor x, 2x-1, 3x-2, .. 1 101 | - 蛋一第一次扔在X层,第二次扔在比原来高 X-1层,... 高2, 高1,使得X+(X-1)+...+2+1=200 102 | - 最坏情况(=最好情况)总的次数就是: 103 | + 如果在第X层就碎,那么蛋二最坏情况要扔X-1,所以总数是 1+X-1=X 104 | + 如果在X+(X-1)碎,那么蛋二最坏情况要扔 X-2,所以2+X-2=X 105 | - x = 20 106 | 107 | ``` 108 | |_|__ 109 | |_| x-2 110 | |_|__ 111 | |_| x-1 112 | |_|___ 113 | |_| x 114 | |_| 115 | |_|___ 116 | ``` 117 | - 假设蛋一第一次扔在X层,第二次扔在比原来高 X-1层,... 高2, 高1,使得X+(X-1)+...+2+1=100,那么最坏情况总的次数就是:如果在第X层就碎,那么蛋二最坏情况要扔X-1,所以总数是 1+X-1=X如果在X+(X-1)碎,那么蛋二最坏情况要扔 X-2,所以2+X-2=X 118 | 119 | 120 | 4. **[Solution 2]** 121 | - 链接:https://www.zhihu.com/question/19690210/answer/125713075 122 | 123 | - 子问题F[i, j]: H的可行范围为[0, i],手上还有j个鸡蛋的时候,最坏情况下的最小试验次数是多少。我们的目标函数就是F[N, K]。 124 | - 这个能够设立是基于这样一种想法,如果H的可能范围目前是[L, R],那么其状态与[0, R-L]是完全一致的,所以我们仅仅记录有可行范围的宽度就可以了。 125 | - `F[i, j]=min{max{F[k-1, j-1], F[i-k, j]}}+1,` 126 | + 其中1<=k<=i。k表示这一次实验是从k楼把鸡蛋扔下去,扔下去有两种结果。 127 | + 一种是鸡蛋碎了,那么剩余的鸡蛋个数是j-1,H的可行范围变为[0, k-1],那么需要的最少实验次数为F[k-1, j-1]。 128 | + 另一种是鸡蛋没碎,那么剩余的鸡蛋个数是j,H的可行范围是[k, i],那么需要的最少实验次数是F[k-i, j]。 129 | - 由于题目所求的是最坏情况下的最优策略,所以对每种k情况内取max,再对所有k取min。 130 | - 边界条件为`F[0, j]=0,F[i, 1]=i`。 131 | - 时间复杂度为O(NK^2)。 132 | -------------------------------------------------------------------------------- /239-Sliding-Window-Maximum.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: 239.Sliding Window Maximum 3 | comments: true 4 | date: 2018-04-07 16:30:20 5 | type: categories 6 | categories: LeetCode 7 | tags: sliding window 8 | --- 9 | 10 | ## 方法一:Priority Queue 11 | 12 | 0. O(nlogn) 13 | 1. 前后两个窗口差别只有两个数,尽量用到上一个窗口的信息 14 | 2. 上一个窗口的头部元素从窗口元素集剔出,加入下一个窗口的尾部元素;形成新的窗口元素集 15 | 3. 想办法从“窗口元素集”中找最大值==> priority queue 最合适 16 | 17 | 18 | ```java 19 | class Solution { 20 | public int[] maxSlidingWindow(int[] nums, int k) { 21 | 22 | if( nums == null || nums.length == 0 ) 23 | return new int[0]; 24 | 25 | int len = nums.length; 26 | int[] ret = new int[len-k+1]; 27 | PriorityQueue pq = new PriorityQueue<>(k, Collections.reverseOrder()); 28 | 29 | for( int i = 0; i < len; i++ ){ 30 | if( i >= k ){ 31 | ret[i-k] = pq.peek(); 32 | pq.remove(nums[i-k]); 33 | } 34 | pq.add(nums[i]); 35 | } 36 | ret[len-k] = pq.peek(); 37 | 38 | return ret; 39 | } 40 | } 41 | ``` 42 | 43 | 44 | 45 | ## 方法二:单调队列 / Monotonic Queue / Deque 46 | 47 | 0. O(n) - 每个元素顶多 add to/remove from queue,共2次 48 | 1. 上一个方法在从窗口元素集找最大 O(logn),继续优化只能为 O(1) 49 | 2. 想办法维护一个与窗口区对应的“有序数据结构” 50 | 3. 进入下一个窗口前,上一个窗口对应的 potential\_max queue 是有序的 51 | 4. 进入下一个窗口后, 52 | - 如果第一个 potential\_max 仍然在新窗口范围内; 53 | 该peotential\_max不需要从 queue中删除,仍然有可能是后边窗口的max 54 | - 如果第一个 potential\_max 不在新窗口范围内; 55 | 该value就不是potential max了,而是 definitely\_not\_possible\_max for later windows 56 | 5. 窗口末尾新加入的元素: 57 | - 如果值比 potential\_max\_queue 中的最后一个 potential\_max\_value 小, 58 | 那么该值与之前的值都有可能是后边窗口的max 59 | - 如果值比后边的“某一段”potential\_max values 都大, 60 | 表明“那一段”potential values 因为更大新元素的加入,由 potential 变为 never\_possible\_max 61 | - 直接删除“那一段” potential values,并将该值插入到 queue之后 62 | 63 | 6. 【小结】:potential\_max\_queue 的维护有4点: 64 | - 维护这么一个“单调队列”目的:某个window的max,就是其对应 petential\_max\_queue 中的第一个元素 65 | - 头部 potential\_max\_value 在当前window下是否valid,是否需要删除; 66 | - 头部 potential\_max\_value 是否valid,实际是根据其 index来判断的,因此在queue中维护的实际是 index 67 | - 新加入的元素是否应该加入potential max queue,加入到哪里 68 | 69 | 70 | ```java 71 | class Solution { 72 | public int[] maxSlidingWindow(int[] nums, int k) { 73 | 74 | if( nums == null || nums.length == 0 ) 75 | return new int[0]; 76 | 77 | int len = nums.length; 78 | int[] ret = new int[len-k+1]; 79 | Deque dq = new LinkedList<>(); 80 | 81 | for( int i = 0; i < len; i++ ){ 82 | // check head items of the potential_max_queue 83 | if( !dq.isEmpty() && dq.peekFirst() < i-k+1 ) 84 | dq.removeFirst(); 85 | 86 | // handle new item 87 | while( !dq.isEmpty() && nums[dq.peekLast()] < nums[i] ){ 88 | dq.removeLast(); 89 | } 90 | dq.addLast(i); 91 | 92 | // update ret values 93 | if(i-k+1 >= 0) 94 | ret[i-k+1] = nums[dq.peekFirst()]; 95 | } 96 | return ret; 97 | } 98 | } 99 | ``` 100 | -------------------------------------------------------------------------------- /A-Way-to-Make-an-Efficient-React-Timer.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: A Way to Make an Efficient React Timer 3 | comments: true 4 | date: 2018-10-05 15:38:28 5 | type: categories 6 | categories: Full stack 7 | tags: 8 | - ReactJS 9 | - efficient state management 10 | --- 11 | 12 | 13 | 14 | ## I. The Problem 15 | 16 | It is very common we need to implement a **Timer** in our daily projects. Of course, there are several ways to make one. 17 | 18 | Most online resource only introduces how to make a Timer as the only one component itself, while in reality we want our Timer to be an sub-component of some parent component 19 | 20 | We don't want to put the `time_elapsed` state in the `state` of its parent component. That way, every one seconds, the parent component will rerender over and over, even though all other state field stay the same. 21 | 22 | 23 | 24 | ## II. We Want Efficiency 25 | 26 | Here, the basic idea is: 27 | 28 | 1. we put the `time_elapsed` state in a single component with no other state field in it. 29 | - start `hanler = setInterval()` to update the `time_elapsed` , in `componentDidMount()` stage 30 | - pass out the `handler` to its parent component 31 | 2. we also want the parent component can `startTimer` and `stopTimer` 32 | - we need to get the handler of the `setInterval()`, in order to stop it in outside 33 | - BUT, how to get the handler??? ==> we pass in an object as `props` to timer component 34 | 35 | ## III. Implementation 36 | 37 | 1. ```js 38 | 39 | 40 | 41 | Hello World 42 | 43 | 44 | 45 | 46 | 47 |
48 | 111 | 112 | 113 | ``` 114 | -------------------------------------------------------------------------------- /Authetication-JWT-vs-Session.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: 'Authetication: JWT vs Session' 3 | comments: true 4 | date: 2018-05-21 21:59:55 5 | type: categories 6 | categories: Full stack 7 | tags: 8 | - Authetication 9 | - JWT 10 | - Session 11 | --- 12 | 13 | 14 | ## I. Why do we need Authetication? 15 | 16 | **Scenario: bank accout transaction** 17 | 18 | > Authetication: an approach to know "Alice" from client side is the real "Alice" in the bank database 19 | 20 | The bank web server needs a way to identify its customers' true identity, knowing 'Alice' is the real 'Alice' as she claims. 21 | 22 | 23 | ## II. `session&cookie` authetication 24 | 25 | **1. Solution A** 26 | 27 | An approach is checking her account&password. If matches, she can access Alice's bank account; Otherwise, no way to Alice's bank account. 28 | 29 | 30 | **2. Problem of Solution A** 31 | 32 | HTTP is stateless. After Alice log into the server, next time when Alice make another request to draw ¥100 from her account (*subtract ¥100 from her accout*). Now she still needs to prove she is Alice. But asking her accout&password again and again is rediculous! 33 | 34 | **3. Solution B:`session` & `cookie`** 35 | 36 | + First time, the Alice log into her account on bank server; 37 | + Bank server maintains a session for her, and issues `sessionID` to her `cookie`. 38 | + Later, each time Alice want to make a transaction, she makes HTTP requests with that `sessionID`(all HTTP requests carry `cookie` ) 39 | + Until a certain period of time, the `session` for Alice become invalid if no activities from Alice 40 | + After a inactive period, if Alice wants to make transaction again, she has to log into system to set up a new `session` in bank server 41 | + `Server`is the safe guard**, preventing evil from accessing sensitive bank account information. Using `session`and`cookie`, customers finally don't have to input their account&password again and again! 42 | 43 | **4. New problem in "distributed" serivce system** 44 | 45 | + **`Distributed`** means: after Alice log into her account on server#1, next time she might be directed by `load balancer` to server#2, if at that time server#1 is already serving extremely large amount of people. 46 | 47 | + **New problem is:** `session & cookie` approach doesn't work in this case. Server#1 has Alice's necessary`context` for following transaction after she logs into it. But server#2 doesn't even know who she is! So, Alice is asked for her account and password again! Bad user experience!!! 48 | 49 | **5. Soutions for "distributed" serivce system** 50 | >【好文】https://www.cnblogs.com/study-everyday/p/7853145.html 51 | 52 | + **version 1: session dupication (多机同步)** 53 | + 思路:多个web-server之间相互同步session,这样每个web-server之间都包含全部的session 54 | + 优点:web-server支持的功能,应用程序不需要修改代码 55 | + 不足: 56 | - session的同步需要数据传输,占内网带宽,有时延 57 | - 所有web-server都包含所有session数据,数据量受内存限制,无法水平扩展 58 | - 有更多web-server时要歇菜 59 | + **version 2: Session Storage at brower (客户端存储法)** 60 | + 思路:服务端存储所有用户的session,内存占用较大,可以将session存储到浏览器cookie中,每个端只要存储一个用户的数据了 61 | + 优点:服务端不需要存储 62 | + 缺点: 63 | - 每次http请求都携带session,占外网带宽 64 | - 数据存储在端上,并在网络传输,存在泄漏、篡改、窃取等安全隐患 65 | - session存储的数据大小受cookie限制 66 | 67 | 68 | + **version 3: Nginx reverse proxy hash: (反向代理hash一致性)** 69 | + 思路:反向代理层使用用户ip来做hash,以保证同一个ip的请求落在同一个web-server上 70 | + 优点: 71 | - 只需要改nginx配置,不需要修改应用代码 72 | - 负载均衡,只要hash属性是均匀的,多台web-server的负载是均衡的 73 | - 可以支持web-server水平扩展(session同步法是不行的,受内存限制) 74 | 75 | + 不足: 76 | - 如果web-server重启,一部分session会丢失,产生业务影响,例如部分用户重新登录 77 | - 如果web-server水平扩展,rehash后session重新分布,也会有一部分用户路由不到正确的session 78 | + **version 4: Database layer for whole session(后端统一集中存储)** 79 | + 思路:将session存储在web-server后端的存储层,数据库或者缓存 80 | + 优点: 81 | - 没有安全隐患 82 | - 可以水平扩展,数据库/缓存水平切分即可 83 | - web-server重启或者扩容都不会有session丢失 84 | 85 | + 不足: 86 | - 增加了一次网络调用,并且需要修改应用代码 87 | 88 | session读取的频率会很高,数据库压力会比较大。如果有session高可用需求,cache可以做高可用,但大部分情况下session可以丢失,一般也不需要考虑高可用。 89 | 90 | + **Summary: for improved `session&cookie` approach** 91 | 92 | 对于方案3和方案4,推荐后者: 93 | - web层、service层无状态是大规模分布式系统设计原则之一,session属于状态,不宜放在web层 94 | - 让专业的软件做专业的事情,web-server存session?还是让cache去做这样的事情吧。 95 | 96 | 97 | ## III. JWT authetication 98 | 99 | >好文: https://www.ctolib.com/flylib-fly-auth.html 100 | 101 | > 1. server不再作为`敏感数据库`的关卡,为client服务; 102 | > 2. brower自己`每次`都携带`authentication token`进行request 103 | 104 | **0.【JWT本质:】** 105 | 106 | - **相当于每次browser request,都要求用户输入`account & password`** 107 | - **即:第一次用户登陆成功后,server根据其“用户名密码”生成唯一“令牌token”,往后该用户只要带上该token进行访问就可以** 108 | - **相同点:`session`方法类似,`cookie`中的`sessionID`也相当于“令牌token”,每次请求都携带上** 109 | - **不同点:** 110 | + **`JWT `方法的token生成依赖于`用户名密码`与`SHA256`,不受server环境影响** 111 | + **`session`方法的`sessionID`生成依赖于`server session context`,每个server生成的`sessionID`不一致,无法适用于distributed system** 112 | 113 | 114 | 115 | 116 | **1. Problems with `session` approach** 117 | 118 | + memcache或者redis的**稳定性**会影响业务系统的可用性 119 | + **微服务的并发能力**受限于memcache或者redis的并发能力 120 | + 由此可见,集中的session管理也不是最优的选择。 121 | + 我们不再关注session本 ,把session的问题抛开,让我们的服务都是无状态的。 122 | + 于是我们把目光转向WEB TOKEN: JWT(Json web token ) 123 | 124 | 125 | **2. Benefits using JWT** 126 | >【好文】https://www.ctolib.com/topics-113075.html 127 | 128 | - 解决跨域问题:这种基于Token的访问策略可以克服cookies的跨域问题。 129 | - 服务端无状态可以横向扩展,Token可完成认证,无需存储Session。 130 | - 系统解耦,Token携带所有的用户信息,无需绑定一个特定的认证方案,只需要知道加密的方法和密钥就可以进行加密解密,有利于解耦。 131 | - 防止跨站点脚本攻击,没有cookie技术,无需考虑跨站请求的安全问题。 132 | 133 | **3. Principle of JWT 原理简介** 134 | 135 | JSON Web Tokens的格式组成,jwt是一段被base64编码过的字符序列,用点号分隔,一共由三部分组成,头部`header`,消息体`playload`和签名`sign` 136 | 137 | - 头部`Header`是json格式: 138 | 139 | ```javascript 140 | { 141 | "typ":"JWT", // 该类型是JWT类型 142 | "alg":"HS256", // 加密方式声明是HS256 143 | "exp":1491066992916 // expire 代表过期时间 144 | } 145 | ``` 146 | - 消息体`Playload`json格式: 147 | 148 | 消息体的具体字段可根据业务需要自行定义和添加,只需在解密的时候注意拿字段的key值获取value。 149 | 150 | ```javascript 151 | { 152 | "userid":"123456", 153 | "iss":"companyName" 154 | } 155 | ``` 156 | 157 | - 签名`sign`的生成 158 | 159 | - 签名的生成是把header和playload分别使用base64url编码,接着用’.‘把两个编码后的字符串连接起来 160 | - 再把这拼接起来的字符串配合密钥进行HMAC SHA-256算法加密 161 | - 然后再次使用base64url编码,这就拿到了签名sign. 162 | - 最后把header和playload和sign用’.‘ 连接起来就生成了整个JWT。 163 | 164 | 165 | **4. Principle of JWT Checking 校验简介** 166 | 167 | >JWT不能保护数据,只能验证数据是否是原始数据,是否被篡改过 168 | 169 | JWT是由`header.playload.sign`连接组成,只有sign是用密钥加密的,而所有的信息都在header和playload中可以直接获取,sign的作用只是校验header和playload的信息是否被篡改过 170 | 171 | 1. 加密:比如要加密验证的是userid字段: 172 | - 首先按前面的格式组装json消息头header和消息体playload,按header.playload组成字符串; 173 | - 再根据密钥和HS256加密header.playload得到sign签名; 174 | - 最后得到jwtToken为header.playload.sign,在http请求中的url带上参数想后端服务请求认证 175 | 176 | 2. 解密:后端服务校验jwtToken是否有权访问接口服务,进行解密认证,如校验访问者的userid: 177 | - 用将字符串按`.`切分三段字符串,分别得到header和playload和sign。 178 | - 然后将header.playload拼装用密钥和SHA-256算法进行加密然后得到新的字符串和sign进行比对, 179 | - 如果一样就代表数据没有被篡改,然后从头部取出exp对存活期进行判断 180 | - 如果超过了存活期就返回空字符串,如果在存活期内返回userid的值 181 | -------------------------------------------------------------------------------- /Binary-Search-variations.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Binary Search variations 3 | date: 2018-03-27 09:12:32 4 | type: "categories" 5 | comments: true 6 | categories: Algorithm 7 | tags: binary search 8 | --- 9 | 10 | 11 | ***Credit to : http://izualzhy.cn/algorithm/2014/04/18/binary-search-analysis*** 12 | 13 | ## I. 二分法及变种的注意点: 14 | 15 | #### 1. 如何得到循环不变式 16 | 17 | 【定义】就是在每次循环里,我们都可以保证要找的index在我们新构造 的区间里。 18 | 【例子】如正常二分法,循环不变式表述如下: 19 | 20 | 21 | if array[mid] > key: 22 | right = mid - 1 23 | else if array[mid] < key: 24 | left = mid + 1 25 | else 26 | return mid 27 | 28 | 29 | 考虑中间值与key的关系: 30 | 31 | - 如果中间值比key大,那么[mid, right]的值我们都可以忽略掉了,这些值都比key要大。只要在[left, mid-1]里查找就是了。 32 | - 如果中间值比key小,那么[left, mid]的值可以 忽略掉,这些值都比key要小,只要在[mid+1, right]里查找就可以了。 33 | - 如果相等,表示找到了,可以直接返回。如果最后这个区间没有,那么就确实是没有 。所以说循环不变式,就是在每次循环里,我们都可以保证要找的index在我们新构造的区间里 34 | 35 | 36 | #### 2. 数组是非递增还是非递减 37 | 38 | 39 | #### 3. 结束条件,即while (condition) 应当是<还是<= 40 | 41 | 42 | “< ” 表明可选区间长度 2~n ; OR 43 | “<= ” 表明可选区间长度 1~n 44 | 45 | 46 | 47 | #### 4. 求mid应当是向上取整还是向下取整 48 | 49 | 50 | mid = (left + right) >>1 OR 51 | mid = (left + right + 1) >>1 52 | 53 | #### 5. while 结束后是否需要判断一次条件 54 | 55 | 56 | 对应可选区间为2~n情况,将所有元素check完毕; 57 | 同时,调整mid取整方式,使该判断优雅 58 | 59 | 60 | --- 61 | 62 | ## II. 常见问题: 63 | 64 | #### 1. 查找值key的下标,如果不存在返回-1. 65 | 66 | ```java 67 | int BS(const Vec Int& vec, int key) 68 | { 69 | int left = 0, right = vec.size() - 1; 70 | while (left <= right) 71 | { 72 | int mid = (left + right) >> 1; 73 | if (vec[mid] > key) 74 | right = mid - 1; 75 | else if (vec[mid] < key) 76 | left = mid + 1; 77 | else 78 | return mid; 79 | } 80 | 81 | return -1; 82 | } 83 | ``` 84 | 85 | - 如果中间值比key大,那么[mid, right]的值我们都可以忽略掉了,这些值都比key要大。只要在[left, mid-1]里查找就是了。 86 | - 如果中间值比key小,那么[left, mid]的值可以 忽略掉,这些值都比key要小,只要在[mid+1, right]里查找就可以了。 87 | - 如果相等,表示找到了, 可以直接返回。 88 | 89 | 因此,循环不变式就是在每次循环里,我们都可以保证要找的index在我们新构造 的区间里。如果最后这个区间没有,那么就确实是没有。 90 | **注意mid的求法**,可能会int越界,但我们先不用考虑这个问题,要记住的是这点:mid是偏向left的,即如果left=1,right=2,则mid=1。 91 | 92 | #### 2. 查找值key第一次出现的下标x,如果不存在返回-1. 93 | 94 | ```java 95 | int BS_First(const VecInt& vec, int key) 96 | { 97 | int left = 0, right = vec.size() - 1; 98 | while (left < right) //问题1,left < right时继续,相等就break. 99 | { 100 | int mid = (left + right) >> 1; 101 | if (vec[mid] < key) 102 | left = mid + 1; 103 | else 104 | right = mid; 105 | } 106 | 107 | if (vec[left] == key) //问题2,再判断一次。 108 | return left; 109 | 110 | return -1; 111 | } 112 | ``` 113 | 114 | 我们仍然考虑中间值与key的关系: 115 | 116 | - 如果array[mid]key,那么x一定在[left, mid-1]区间里。 118 | - 如果array[mid]≤key,那么不能推断任何关系。比如对key=1,数组{0,1,1,2,3},{0,0,0,1,2},array[mid] = array[2] ≤ 1,但一个在左半区间,一个在右半区间。 119 | - 如果array[mid]≥key,那么x一定在[left, mid]区间里。 120 | - 综合上面的结果,我们可以采用1,4即<和≥的组合判断来实现我们的循环不变式,即循环过程中一直满足key在我们的区间里。 121 | 122 | **注意问题:** 123 | 124 | - 循环能否退出,我们注意到4的区间改变里是令right = mid,如果left=right=mid时,循环是无法退出的。换句话说,第一个问题我们始终在减小着区间,而在这个问题里,某种情况下区间是不会减小的! ----- 见代码 125 | - 循环退出后的判断问题,再看下我们的条件1,4组合,只是使得我们最后的区间满足了≥key,是否=key,还需要再判断一次。 ----- 见代码 126 | 127 | #### 3. 查找值key最后一次出现的下标x,如果不存在返回-1. 128 | 129 | ```java 130 | int BS_Last(const VecInt& vec, int key) 131 | { 132 | int left = 0, right = vec.size() - 1; 133 | while (left < right) 134 | { 135 | int mid = (left + right + 1) >> 1; 136 | if (vec[mid] > key) 137 | right = mid - 1; 138 | else 139 | left = mid; 140 | } 141 | 142 | if (vec[left] == key) 143 | return left; 144 | 145 | return -1; 146 | } 147 | ``` 148 | 149 | 循环不变式(省去分析的过程,同上): 150 | 151 | - 如果array[mid]>key,那么x一定在[left, mid-1]区间里。 152 | - 如果array[mid]≤key, 那么x一定在[mid, right]区间里。 153 | 154 | **注意问题:** 155 | 156 | - 在条件2里,实际上我们是令left=mid,但是如前面提到的,如果left=1,right=2,那么mid=left=1,同时又进入到条件2,left=mid=1,即使我们在while设定了left < right仍然无法退出循环, 157 | - 解决的办法很简单:mid = (left + right + 1) >> 1, 向上取整就可以了。 158 | 159 | #### 4. 查找刚好小于key的元素下标x,如果不存在返回-1. 160 | 161 | ```java 162 | int BS_Last_Less(const VecInt& vec, int key) 163 | { 164 | int left = 0, right = vec.size() - 1; 165 | while (left < right) 166 | { 167 | int mid = (left + right + 1) >> 1; 168 | if (vec[mid] < key) 169 | left = mid; 170 | else 171 | right = mid - 1; 172 | } 173 | 174 | if (vec[left] < key) 175 | return left; 176 | 177 | return -1; 178 | } 179 | ``` 180 | 181 | 循环不变式(省去分析的过程,同上): 182 | 183 | - 如果array[mid]> 1; 195 | if (vec[mid] > key) 196 | right = mid; 197 | else 198 | left = mid + 1; 199 | } 200 | 201 | if (vec[left] > key) 202 | return left; 203 | 204 | return -1; 205 | } 206 | ``` 207 | 208 | 循环不变式(省去分析的过程,同上): 209 | 210 | - 如果array[mid]>key,那么x在区间[left, mid] 211 | - 如果array[mid]≤key,那么x在区间[mid + 1, right] 212 | 213 | #### 6. 查找第一个>=key的下标,如果不存在返回-1,等价于std::lower_bound. 214 | 215 | ```java 216 | 217 | int BS_First_Greater_Or_Equal(const VecInt& vec, int key) 218 | { 219 | int left = 0, right = vec.size() - 1; 220 | while (left < right) 221 | { 222 | int mid = (left + right) >> 1; 223 | if (vec[mid] < key) 224 | left = mid +1; 225 | else 226 | right = mid; 227 | } 228 | 229 | if (vec[left] >= key) 230 | return left; 231 | 232 | return -1; 233 | } 234 | ``` 235 | 236 | 循环不变式(省去分析的过程,同上): 237 | 238 | - 如果array[mid] fn(params[0], params[1]) 25 | ) 26 | } 27 | } 28 | 29 | let animalFetcher = function(msg, callback){ 30 | callback( this) 31 | callback( arguments.callee.name + " " + msg) 32 | } 33 | 34 | let fruitFetcher = function(msg, callback){ 35 | callback( arguments.callee.name + " " + msg) 36 | } 37 | 38 | let treeFetcher = function(msg, callback){ 39 | callback( arguments.callee.name + " " + msg) 40 | } 41 | 42 | fetchAll = combineFetchers([animalFetcher, fruitFetcher, treeFetcher]) 43 | fetchAll("message", function(results) {console.log(results)} ) 44 | 45 | // 2.1 Correct version: callback 46 | function combineFetchers(arr) { 47 | return function(input, callback) { 48 | const list = []; 49 | let count = 0; 50 | 51 | arr.forEach(fn => fn(input, res => { 52 | list.push(res); 53 | 54 | if (++count === arr.length) { 55 | callback(list); 56 | } 57 | })); 58 | }; 59 | } 60 | 61 | function animalFetcher (userInput, callback) { 62 | setTimeout(() => callback(userInput + 1), 0); 63 | } 64 | 65 | function fruitFetcher (userInput, callback) { 66 | setTimeout(() => callback(userInput + 2), 0); 67 | } 68 | 69 | function mineralFetcher (userInput, callback) { 70 | setTimeout(() => callback(userInput + 3), 0); 71 | } 72 | 73 | const fetchAll = combineFetchers([animalFetcher, fruitFetcher, mineralFetcher]); 74 | fetchAll(4, function (res) {console.log(res);}); 75 | 76 | 77 | // 2.2 Correct version: promise.all() 78 | function combineFetchers(arr) { 79 | return function(input, callback) { 80 | Promise.all(arr.map(fn => new Promise( 81 | function(resolve){fn(input, resolve)}))) 82 | .then(res => callback(res)); 83 | }; 84 | } 85 | 86 | function animalFetcher (userInput, callback) { 87 | setTimeout(() => callback(userInput + 1), 0); 88 | } 89 | 90 | function fruitFetcher (userInput, callback) { 91 | setTimeout(() => callback(userInput + 2), 0); 92 | } 93 | 94 | function mineralFetcher (userInput, callback) { 95 | setTimeout(() => callback(userInput + 3), 0); 96 | } 97 | 98 | const fetchAll = combineFetchers([animalFetcher, fruitFetcher, mineralFetcher]); 99 | fetchAll(4, function (res) {console.log(res);}); 100 | ``` 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | retry n times 109 | 110 | ```js 111 | function scb(v){ console.log("sucess: ", v) } 112 | function ecb(v){ console.log("error : ", v) } 113 | 114 | function callAPI(data, scb, ecb){ 115 | setTimeout(()=>{ecb(data)}, 2000 ) 116 | } 117 | 118 | // 1. elegant version 119 | function retry(n, data, scb, ecb) { 120 | ecb1 = n == 0 ? ecb : function (){retry(n-1,data,scb,ecb) } 121 | 122 | callAPI(data,scb,ecb1) 123 | } 124 | 125 | // 2. verbose version 126 | function retry(n, period, data, scb, ecb){ 127 | let count = n 128 | let startTime = Date.now() 129 | let customErrorHanlder = function(){ 130 | let timeElapsed = Date.now()-startTime 131 | if( n > 0 && timeElapsed < period ) { 132 | console.log(n + "times trial left! And " + (Date.now()-startTime) + "second elapsed." ) 133 | callAPI(data, scb, customErrorHanlder) 134 | n -= 1 135 | }else{ 136 | console.log(n + "times trial left! And " + (Date.now()-startTime) + "second elapsed." ) 137 | callAPI(data, scb, ecb) 138 | } 139 | } 140 | callAPI(data, scb, customErrorHanlder) 141 | } 142 | 143 | 144 | retry(4, 5000, 3, scb, ecb) 145 | ``` 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 考察JS事件循环,要求写一个mySetInterval(callback, interval),要求callback能够每隔一段时间执行一次,或者如果单次执行事件太长的话则预约到下一次可执行的时间点执行。 154 | 155 | ```js 156 | function mySetInterval(callback, interval){ 157 | setInterval(function(){ 158 | let startFlag = true 159 | setTimeout(function(){ 160 | if(startFlag) 161 | }, interval) 162 | callback() 163 | startFlag = false 164 | 165 | }, interval) 166 | } 167 | 168 | 169 | 170 | 171 | var counter = 0; 172 | 173 | var interval = setInterval(function() { 174 | setTimeout( function(){ console.log(counter)}, 2001 ) 175 | counter++; 176 | }, 2000); 177 | 178 | 179 | ``` 180 | 181 | ​ 182 | 183 | 184 | 185 | generator 186 | 187 | ```js 188 | function *generator(){ 189 | let a = 1 190 | yield a 191 | 192 | a += 1 193 | yield 194 | 195 | yield "the third output" 196 | return 4 197 | } 198 | 199 | let g = generator() 200 | g.next() 201 | g.next() 202 | g.next() 203 | g.next() 204 | g.next() 205 | ``` 206 | 207 | -------------------------------------------------------------------------------- /Coding-Problem-find-the-1st-Bad-Version.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: 'Coding Problem: Find 1st Bad Version' 3 | comments: true 4 | date: 2018-09-10 22:19:23 5 | type: categories 6 | categories: Algorithm 7 | tags: 8 | - Algorithm 9 | - binary search 10 | 11 | --- 12 | 13 | 14 | 15 | 16 | 17 | ## I. problem 18 | 19 | given 500 revisions of programs, write a program that will find and return the FIRST bad revision given a `isBad(revision i)` function. 20 | 21 | 22 | 23 | ## II. Code 24 | 25 | ```js 26 | function isBad( version ){ return version === 0 } 27 | 28 | function firstBadVersion( versions ){ 29 | if( typeof versions === 'undefined' || versions.length === 0 ) 30 | return -1; 31 | 32 | let left = 0, right = versions.length-1; 33 | while( left < right ){ 34 | let mid = (left + right) / 2 35 | if( isBad(mid) ){ 36 | right = mid 37 | }else{ 38 | left = mid+1 39 | } 40 | return versions[left]===0 ? left : -1 41 | } 42 | 43 | } 44 | 45 | // Testing 0 1 2 3 4 5 6 should return index: 4 46 | let versions = [1,1,1,1,0,0,0] 47 | console.log(firstBadVersion(versions)) // 4 48 | 49 | versions = [1,1,1,1,1,0] 50 | console.log(firstBadVersion(versions)) // 6 51 | 52 | versions = [0, 0, 0] 53 | console.log(firstBadVersion(versions)) // 0 54 | 55 | versions = [0] 56 | console.log(firstBadVersion(versions)) // 0 57 | 58 | versions = [1] 59 | console.log(firstBadVersion(versions)) // -1 60 | 61 | versions = [1, 1, 1] 62 | console.log(firstBadVersion(versions)) // -1 63 | 64 | versions = [] 65 | console.log(firstBadVersion(versions)) // -1 66 | 67 | console.log(firstBadVersion()) // -1 68 | ``` 69 | 70 | -------------------------------------------------------------------------------- /Common-DOM-Manipulations.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Common DOM Manipulations 3 | comments: true 4 | date: 2018-10-15 17:40:29 5 | type: categories 6 | categories: Full stack 7 | tags: 8 | - DOM 9 | - Vanilla JS 10 | --- 11 | 12 | ## `Window` VS `document` 13 | 14 | 1. `window`: a global object, and everything runs under it, including `document` 15 | - global variables, 16 | - global functions, 17 | - `location` 18 | - `history` 19 | - `setTimeout` 20 | - ajax call (XMLHttpRequest), 21 | - `console` 22 | - `localStorage` 23 | 2. `documnet`: represents the DOM and DOM is the object oriented representation of the html markup you have written; 24 | - All the nodes are part of document. Hence you can use getElementById or addEventListener on document. 25 | 26 | ## `window.onload` vs `document.onload` 27 | 28 | 1. `window.onload`: When **EVERYTHING** is loaded. DOM is ready and all the contents including images, css, scripts, sub-frames, etc. finished loaded. 29 | 2. `document.onload`: once the **DOM** is loaded, regardless of the css, scripts,... 30 | 31 | ## `attribute` vs `property` 32 | 33 | 1. `attribute`: belongs to HTML tag, is **static** after being initialized 34 | 35 | 2. `property`: belongs to DOM node, is **dynamic** while interact with its element 36 | 37 | 3. ```html 38 | 39 | 44 | ``` 45 | 46 | 47 | 48 | ## Add `class` to element: `classList` 49 | 50 | ```js 51 | function addClass(selector, className){ 52 | var elm = document.querySelector(selector); 53 | if (elm){ 54 | elm.classList.add(className); 55 | } 56 | } 57 | ``` 58 | 59 | ## Check Descendant 60 | 61 | ```js 62 | function isDescendant(parent, child){ 63 | while(child.parentNode ){ 64 | if(child.parentNode == parent) 65 | return true; 66 | else 67 | child = child.parentNode; 68 | } 69 | return false; 70 | } 71 | ``` 72 | 73 | ## Create DOM element: `innerHTML` vs `appendChild` 74 | 75 | 1. `innerHTML`: browser removes all the current children of the elements. Parse the string and assign the parsed string to the element as children. So, **Slow!** 76 | 77 | 1. ```js 78 | var ul = document.getElementById('myList'); 79 | 80 | el.innerHTML = '
  • Only one item
  • '; 81 | ``` 82 | 83 | 2. `appendChild`: you create a new Element. Since you are creating it, browser doesnt have to parse string and there is no invalid html. so, **Fast**! 84 | 85 | 1. ```js 86 | var li = document.createElement("li"); 87 | var text = document.createTextNode('Only one Item'); 88 | 89 | li.appendChild(text); 90 | ul.appendChild(li); 91 | ``` 92 | 93 | 94 | ## `CrateDocumentFragment`: improve performance 95 | 96 | 1. `documentFragment` a lightweight or minimal part of a DOM or a subtree of a DOM tree. 97 | 98 | 2. It is very helpful when you are manipulating a part of DOM for multiple times. 99 | 100 | 3. It becomes expensive to hit a certain portion of DOM for hundreds time. You might cause reflow for hundred times. Stay tuned for reflow. 101 | 102 | - BAD practice: 103 | 104 | - ```js 105 | //bad practice. you are hitting the DOM every single time 106 | var list = ['foo', 'bar', 'baz', ... ], 107 | el, text; 108 | for (var i = 0; i < list.length; i++) { 109 | el = document.createElement('li'); 110 | text = document.createTextNode(list[i]); 111 | el.appendChild(text); 112 | document.body.appendChild(el); 113 | } 114 | ``` 115 | 116 | - GOOD practice: 117 | 118 | - ```js 119 | 120 | //good practice. you causing reflow one time 121 | var fragment = document.createDocumentFragment(), 122 | list = ['foo', 'bar', 'baz', ...], 123 | el, text; 124 | for (var i = 0; i < list.length; i++) { 125 | el = document.createElement('li'); 126 | text = document.createTextNode(list[i]); 127 | el.appendChild(text); 128 | fragment.appendChild(el); 129 | } 130 | document.body.appendChild(fragment); 131 | 132 | ``` 133 | 134 | 135 | 136 | 137 | ## reflow 138 | 139 | 1. **[reflow] :** flow of the elements in the page is changed due to **change size or position** 140 | - When you change size or position of an element in the page, all the elements after it has to change their position according to the changes you made. 141 | - For example, if you change height on an element, all the elements under it has to move down in the page to accomodate a change in height. 142 | 2. Reasons: 143 | - change layout (geometry of the page) 144 | - resize the window 145 | - change height/width of any element 146 | - changing font, or font size 147 | - move DOM element (animation) 148 | - adding or removing stylesheet 149 | - calculating offset height or offset width 150 | - `display: none;` 151 | 152 | ## repaint 153 | 154 | 1. It happens when you change the **look of an element** without changing the size and shape. This doesn't cause reflow as geometry of the element didn't changed. 155 | 2. Reasons: 156 | - change background color 157 | - change text color 158 | - visibility hidden 159 | 160 | ## destroy button 161 | 162 | Create a button that is destroyed by clicking on it but two new buttons are created in it's place. 163 | 164 | ​ 165 | 166 | ```html 167 | 168 |
    169 | 170 |
    171 | 186 | 187 | ``` 188 | 189 | 190 | 191 | ## Get text of a Node: `innerHTML` `textContent` `innerText` 192 | 193 | 1. **innerHTML** parses content as HTML and takes longer. Also vulnerable to [XSS attacks](https://developer.mozilla.org/en-US/docs/Glossary/Cross-site_scripting) 194 | 195 | 2. **textContent** uses straight text, does not parse HTML, and is faster. 196 | 197 | 1. ```js 198 | // Given the following HTML fragment: 199 | //
    This is some text
    200 | 201 | // Get the text content: 202 | var text = document.getElementById("divA").textContent; 203 | // |text| is set to "This is some text". 204 | 205 | // Set the text content: 206 | document.getElementById("divA").textContent = "This is some text"; 207 | // The HTML for divA is now: 208 | //
    This is some text
    209 | Polyfill 210 | ``` 211 | 212 | 3. **innerText** Takes styles into consideration. It won't get hidden text for instance.: Bad, causing **reflow** ! 213 | 214 | 215 | 216 | ## defer vs async 217 | 218 | 1. `defer` & `async` are only effective in ` 210 | 211 | 212 | ``` 213 | 214 | -------------------------------------------------------------------------------- /Event-Emitter.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Event Emitter 3 | comments: true 4 | date: 2018-10-01 20:21:44 5 | type: categories 6 | categories: Full stack 7 | tags: ES6 8 | --- 9 | 10 | 11 | 12 | 13 | #### I. What is an Event Emitter? 14 | 15 | An `event emitter` is a **utility object**, which can be used to emit event, which can be subscribed by as many functions as we can. 16 | 17 | 1. It is an event manager, manages differents event and its subscribers. 18 | 19 | 2. Also, we can see it as the `Redux`, which also dispatches(emits) actions, and handled by its reducers. 20 | 3. It widely used at Node.js ( asynchronous event-driven architecture) 21 | - certain kind of objects call emitters periodically to emit events that cause listener objects to be called. 22 | - when a request comes requesting some resource, Node.js will register the subscriber: `responseToThisRequest()` on event: `thisTypeDataDone`. When data is obtained, will call `emitter.emit( thisTypeDataDone )`, to call the `responseToThisRequest()` corresponding all the requests. 23 | 24 | #### II. Why and when do we need it? 25 | 26 | > Whenever it makes sense for code to SUBSCRIBE to something rather than get a callback from something 27 | > 28 | > https://stackoverflow.com/questions/38881170/when-should-i-use-eventemitter 29 | 30 | If when a certain event happens, we have to deal many type of manipulation for that event's result, then it is better to use the event emitter pattern. 31 | 32 | Instead put all functions inside an event callback, we subscribe all the function to that event, when the event happens, we emit the event! 33 | 34 | #### III. How to use it? 35 | 36 | **[Good Link]:** https://netbasal.com/javascript-the-magic-behind-event-emitter-cce3abcbcef9 37 | 38 | **[Note]: when pass in the callback function, we use arrow function, which already bind 'this' to the function, so that when the function be called, it knows what value it will update** 39 | 40 | ```js 41 | 42 | let input = document.querySelector('input[type="text"]'); 43 | let button = document.querySelector('button'); 44 | let h1 = document.querySelector('h1'); 45 | 46 | button.addEventListener('click', () => { 47 | emitter.emit('event:name-changed', {name: input.value}); 48 | }); 49 | 50 | let emitter = new EventEmitter(); 51 | emitter.subscribe('event:name-changed', data => { 52 | h1.innerHTML = `Your name is: ${data.name}`; 53 | }); 54 | ``` 55 | 56 | 1. create an emitter util object 57 | 58 | 2. subscribe the desired callback function, using `emitter.subscribe(event, function.bind(this))` 59 | 60 | 3. call `emitter.emit()` when the event happen 61 | 62 | 63 | #### IV. Write one! 64 | 65 | 1. **object:** we need an object (utility object) 66 | 2. **data structure:** inside it, we need a data structure to store the `event` and its `subscribers`(callbacks) 67 | 3. **methods:** all the methods 68 | - `subscribe(event, callback)`: we need the return value to be an `unsubscribe()`, so we won't result in the memory leak! 69 | - `emit()` 70 | 71 | ```js 72 | class EventEmitter { 73 | constructor() { 74 | this.events = {}; 75 | } 76 | 77 | on(event, listener) { 78 | if (typeof this.events[event] !== 'object') { 79 | this.events[event] = []; 80 | } 81 | this.events[event].push(listener); 82 | return () => this.removeListener(event, listener); 83 | } 84 | 85 | removeListener(event, listener) { 86 | if (typeof this.events[event] === 'object') { 87 | const idx = this.events[event].indexOf(listener); 88 | if (idx > -1) { 89 | this.events[event].splice(idx, 1); 90 | } 91 | } 92 | } 93 | 94 | emit(event, ...args) { 95 | if (typeof this.events[event] === 'object') { 96 | this.events[event].forEach( 97 | listener => {if(typeof listener === 'function') listener.apply(null, args)} 98 | ); 99 | } 100 | } 101 | 102 | // register a wrapper function containing the listener on this event, 103 | // when get executed, 104 | // - first remove it on this event; 105 | // - then execute real listener 106 | once(event, listener) { 107 | const remove = this.on(event, (...args) => { 108 | remove(); 109 | listener.apply(null, args); 110 | }); 111 | } 112 | }; 113 | 114 | 115 | let emitter = new EventEmitter() 116 | // Test 1: invalid callback function 117 | console.log("Test 1: Nothing should be print out") 118 | emitter.on("a", 1); 119 | emitter.emit("a"); 120 | console.log() 121 | 122 | // Test 2: add mutilple callback function to an event 123 | console.log("Test 2: callback 1, 2, 3") 124 | emitter.on("b", ()=>{console.log("event b callback 1")}); 125 | emitter.on("b", ()=>{console.log("event b callback 2")}); 126 | let off1 = emitter.on("b", ()=>{console.log("event b callback 3")}); 127 | emitter.emit("b"); 128 | console.log() 129 | 130 | 131 | // Test 3: unsubscribe one callback from an event queue 132 | console.log("Test 3: callback 1, 2") 133 | off1(); 134 | emitter.emit("b"); 135 | console.log() 136 | 137 | 138 | // Test 4: subscribe other event & callbacks at the same time 139 | let data = {digit: 1} 140 | console.log("Test 4: digit should be 11 & 14 ") 141 | emitter.on("c", function(data){ data.digit+=1 }); 142 | emitter.on("c", function(data){ data.digit+=2 }); 143 | emitter.on("d", function(data){ data.digit+=3 });; 144 | let off2 = emitter.on("d", function(data){ data.digit+=4 }); 145 | 146 | emitter.emit("c", data); 147 | emitter.emit("d", data); 148 | console.log(data.digit) 149 | 150 | off2() 151 | emitter.emit("d", data); 152 | console.log(data.digit) 153 | console.log() 154 | 155 | 156 | 157 | // Test 5: subscribe other event & callbacks 158 | let data2 = {digit: 5} 159 | console.log("Test 5: digit should be 11") 160 | emitter.emit("d", data2 ); 161 | emitter.emit("c", data2 ); 162 | console.log(data2.digit) 163 | console.log() 164 | 165 | // Test 6: test once 166 | console.log("Test 6: should only print once") 167 | emitter.once("test 6", ()=>{console.log("should only print once")} ); 168 | emitter.emit("test 6" ); 169 | emitter.emit("test 6" ); 170 | emitter.emit("test 6" ); 171 | console.log() 172 | ``` 173 | 174 | ***FaceBook interview version*** 175 | https://gist.github.com/kutyel/7d8f204a347840a6ee7220743957e504 176 | 177 | ```js 178 | /* 179 | * Create an event emitter that goes like this 180 | * emitter = new Emitter(); 181 | * 182 | * Allows you to subscribe to some event 183 | * sub1 = emitter.subscribe('function_name', callback1); 184 | * (you can have multiple callbacks to the same event) 185 | * sub2 = emitter.subscribe('function_name', callback2); 186 | * 187 | * You can emit the event you want with this api 188 | * (you can receive 'n' number of arguments) 189 | * sub1.emit('function_name', foo, bar); 190 | * 191 | * And allows you to release the subscription like this 192 | * (but you should be able to still emit from sub2) 193 | * sub1.release(); 194 | */ 195 | 196 | // facebook.js 197 | 198 | class Emitter { 199 | constructor(events = {}) { 200 | this.events = events 201 | } 202 | 203 | subscribe(name, cb) { 204 | (this.events[name] || (this.events[name] = [])).push(cb) 205 | 206 | return { 207 | release: () => this.events[name] && 208 | this.events[name].splice(this.events[name].indexOf(cb) >>> 0, 1) 209 | } 210 | } 211 | 212 | emit(name, ...args) { 213 | return (this.events[name] || []).map(fn => fn(...args)) 214 | } 215 | } 216 | 217 | export default Emitter 218 | 219 | 220 | 221 | 222 | 223 | // test.js 224 | 225 | const expect = require('expect') 226 | 227 | const Emitter = require('./facebook') 228 | 229 | // Step 1 230 | 231 | let test = 0 232 | 233 | const emitter = new Emitter() 234 | 235 | emitter.emit('sum', 1) 236 | 237 | expect(test).toBe(0) // should trigger nothing 238 | 239 | const sub1 = emitter.subscribe('sum', num => (test = test + num)) 240 | 241 | emitter.emit('sum', 1) 242 | 243 | expect(test).toBe(1) // should trigger 1 callback 244 | 245 | const sub2 = emitter.subscribe('sum', num => (test = test * num)) 246 | 247 | emitter.emit('sum', 2) 248 | 249 | expect(test).toBe(6) // should trigger 2 callbacks 250 | 251 | // Step 2 252 | 253 | sub1.release() 254 | 255 | emitter.emit('sum', 3) 256 | 257 | expect(test).toBe(18) // should trigger 1 callback 258 | 259 | // Step 3 260 | 261 | const myEvent1 = emitter.subscribe('myEvent', () => 1) 262 | const myEvent2 = emitter.subscribe('myEvent', () => 2) 263 | const myEvent3 = emitter.subscribe('myEvent', () => true) 264 | const result = emitter.emit('myEvent') 265 | 266 | expect(result).toEqual([1, 2, true]) 267 | 268 | console.info('You passed the test!!! 👏🏼 👏🏼 👏🏼') 269 | 270 | ``` 271 | -------------------------------------------------------------------------------- /Facebook-Custom-Search.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Facebook Custom Search 3 | date: 2018-03-27 12:32:37 4 | type: "categories" 5 | comments: true 6 | categories: 7 | - Portfolios 8 | tags: 9 | - AngularJS 10 | - PHP 11 | - Swift 12 | --- 13 | 14 | ## I. Introduction 15 | An application for both web-version and IOS-version, supported by PHP-based server on AWS EC2, allows searching, displaying and posting information on Facebook. 16 | 17 | Tech stacks: **AngularJS, Bootstrp, PHP, AWS EC2, Swift, Cocoa** 18 | 19 | **Github web**: https://github.com/caomingkai/FaceBook-custom-Search-Web-App 20 | 21 | **Github IOS**: https://github.com/caomingkai/FaceBook-custom-Search-Web-App 22 | 23 | 24 | {% asset_img FB.png This is an image %} 25 | 26 | -------------------------------------------------------------------------------- /Facebook-Custom-Search/.FB.png.icloud: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/caomingkai/Front-End-Common-Problems/0e19e3d19a033853eefddce80a68cbfac3e3baa6/Facebook-Custom-Search/.FB.png.icloud -------------------------------------------------------------------------------- /Facebook-Custom-Search/FB.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/caomingkai/Front-End-Common-Problems/0e19e3d19a033853eefddce80a68cbfac3e3baa6/Facebook-Custom-Search/FB.png -------------------------------------------------------------------------------- /Flux-Redux.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Flux & Redux 3 | comments: true 4 | date: 2018-10-04 21:04:19 5 | type: categories 6 | categories: Full stack 7 | tags: 8 | - Flux 9 | - Redux 10 | - ReactJS 11 | --- 12 | 13 | ## I. Flux 14 | 15 | 1. **4 parts of Flux architecture:** 16 | - View 17 | - Actions 18 | - Dispatcher 19 | - Store 20 | 21 | 2. **Relationship** 22 | 23 | - **Store:** model object managing all data; has updating methods as well 24 | - provide data to View 25 | - provide updating methods to Actions 26 | - **Dispatcher: **extends `Event Emitter object` 27 | - used by component to register event & callbacks 28 | - used by component to emit actions to call store updating methods 29 | - **View:** receive data from store 30 | - **Actions: **used by *component* to let *dispather* emit actions 31 | - Great article: http://www.ruanyifeng.com/blog/2016/01/flux.html 32 | 33 | 34 | ## II. Redux 35 | 36 | 1. **`store`** 37 | 38 | 1. `getState()`: source of data 39 | 2. `dispath()`: emit actions, execute reducer to update state 40 | 3. `subscribe()`: component subscribe to receive updated state 41 | 42 | 2. **reducer** 43 | 44 | - like`emitter.on`, used to register all the updating functions for related actions 45 | - pure function 46 | - `combineReducers()`: used to make logic clean 47 | 48 | 3. **Store implementation** 49 | 50 | 1. How to use the `store` object 51 | 52 | 2. ```js 53 | import { createStore } from 'redux'; 54 | let { subscribe, dispatch, getState } = createStore(reducer); 55 | // or 56 | let store = createStore(todoApp, window.STATE_FROM_SERVER) 57 | store.getState() 58 | store.dispatch() 59 | store.subscribe() 60 | ``` 61 | 62 | 3. redux provide an interface `createStore()` to create the `store` object 63 | 64 | 4. ```js 65 | const createStore = (reducer) => { 66 | let state; 67 | let listeners = []; 68 | 69 | const getState = () => state; 70 | 71 | const dispatch = (action) => { 72 | state = reducer(state, action); 73 | listeners.forEach(listener => listener()); 74 | }; 75 | 76 | const subscribe = (listener) => { 77 | listeners.push(listener); 78 | return () => { 79 | listeners = listeners.filter(l => l !== listener); 80 | } 81 | }; 82 | 83 | dispatch({}); 84 | 85 | return { getState, dispatch, subscribe }; 86 | }; 87 | ``` 88 | 89 | 4. **An example using Redux** 90 | 91 | 5. ```js 92 | const Counter = ({ value, onIncrement, onDecrement }) => ( 93 |
    94 |

    {value}

    95 | 96 | 97 |
    98 | ); 99 | 100 | const reducer = (state = 0, action) => { 101 | switch (action.type) { 102 | case 'INCREMENT': return state + 1; 103 | case 'DECREMENT': return state - 1; 104 | default: return state; 105 | } 106 | }; 107 | 108 | const store = createStore(reducer); 109 | 110 | const render = () => { 111 | ReactDOM.render( 112 | store.dispatch({type: 'INCREMENT'})} 115 | onDecrement={() => store.dispatch({type: 'DECREMENT'})} 116 | />, 117 | document.getElementById('root') 118 | ); 119 | }; 120 | 121 | render(); 122 | store.subscribe(render); 123 | ``` 124 | 125 | 126 | ## III. React-Redux package 127 | 128 | 1. `connect()`: 129 | - connect UI component with it outer Controller component 130 | - usage: `const Contrainer = connect(mapStateToprops, mapDispatchToProps)(UIComponent)` 131 | 2. `mapStateToProps()` 132 | - map `state` in Redux store to UI 133 | - like `eventEmitter.subscribe()`, will always get the updated state from Redux 134 | 3. `mapDispatchToProps` 135 | - map `actions dispatch()` in Redux to UI 136 | - like `eventEmitter.emit()`, will trigger actions when UI event is fired, to execute reducer to update the state 137 | 138 | 4. `` component 139 | - an outer container, used to pass the `state` to inner components 140 | - using `context` attribute 141 | 142 | -------------------------------------------------------------------------------- /How-to-Flatten-an-Array.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: How to Flatten an Array 3 | comments: true 4 | date: 2018-10-14 19:54:39 5 | type: categories 6 | categories: Algorithm 7 | tags: 8 | - Algorithm 9 | - Stack 10 | - recursion 11 | --- 12 | 13 | ## Problem 14 | 15 | Given an nested array, flatten it to 1-dimension array. 16 | 17 | For example: 18 | 19 | ``` 20 | [1, [2, [ [3, 4], 5], 6], [7, 8], 9] 21 | => 22 | [1, 2, 3, 4, 5, 6, 7, 8, 9] 23 | ``` 24 | 25 | 26 | 27 | ## Solution 1: iterative version 28 | 29 | ```js 30 | // 1. iterative [stack] 31 | function flatten1( arr ){ 32 | let res = [] 33 | let stack = [] 34 | stack.push(arr) 35 | while( stack.length > 0 ){ 36 | let item = stack.pop() 37 | if( !Array.isArray(item) ){ 38 | res.push(item) 39 | }else{ 40 | for( let i = item.length-1; i >=0; i-- ){ 41 | stack.push(item[i]) 42 | } 43 | } 44 | } 45 | return res 46 | } 47 | 48 | 49 | ``` 50 | 51 | 52 | 53 | ## Solution 2: recursive version 54 | 55 | ```js 56 | function flatten2(arr){ 57 | if( !Array.isArray(arr) ){ 58 | return [arr] 59 | } 60 | return [].concat(...arr.map(flatten2)) 61 | } 62 | ``` 63 | 64 | 65 | 66 | ## Solution 3: recursive version [shorter] 67 | 68 | ```js 69 | function flatten(a) { 70 | return Array.isArray(a) ? [].concat(...a.map(flatten)) : a; 71 | } 72 | 73 | 74 | ``` 75 | 76 | 77 | 78 | ## Testing 79 | 80 | ```js 81 | let test1 = [1, [2, 3, [4, 5]], 6, [7, [8, 9], 10], 11] 82 | let test2 = [] 83 | let test3 = [1] 84 | let test4 = 1 85 | let test5 = [[[1,2,3]]] 86 | let test6 = [[[]],[],[],[],[[[]]]] 87 | 88 | 89 | // let arrayFlattened1 = flatten1(test1).toString() 90 | // let arrayFlattened2 = flatten1(test2).toString() 91 | // let arrayFlattened3 = flatten1(test3).toString() 92 | // let arrayFlattened4 = flatten1(test4).toString() 93 | // let arrayFlattened5 = flatten1(test5).toString() 94 | // let arrayFlattened6 = flatten1(test6).toString() 95 | let arrayFlattened1 = flatten2(test1).toString() 96 | let arrayFlattened2 = flatten2(test2).toString() 97 | let arrayFlattened3 = flatten2(test3).toString() 98 | let arrayFlattened4 = flatten2(test4).toString() 99 | let arrayFlattened5 = flatten2(test5).toString() 100 | let arrayFlattened6 = flatten2(test6).toString() 101 | console.log(arrayFlattened1) 102 | console.log(arrayFlattened2) 103 | console.log(arrayFlattened3) 104 | console.log(arrayFlattened4) 105 | console.log(arrayFlattened5) 106 | console.log(arrayFlattened6) 107 | 108 | 109 | ``` 110 | 111 | -------------------------------------------------------------------------------- /How-to-Make-Animation-using-JS.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: How to Make Animation using JS 3 | comments: true 4 | date: 2018-08-11 22:56:29 5 | type: categories 6 | categories: Full stack 7 | tags: 8 | - animation 9 | - vanilla JS 10 | 11 | --- 12 | 13 | 14 | 15 | ## I. problem 16 | 17 | We want a function to move an `element` to its right by `distance` in specified `time` 18 | 19 | - API: `function moveToRight(ele, dis, time) {}` 20 | 21 | ## II. Implementation 22 | 23 | 1. must not be `position: static`: using `ele.style.left` + `ele.offsetLeft` 24 | 2. no restrict on `position`: using ` 25 | 26 | ```html 27 | 28 | 29 | 30 | 38 | 39 | 40 |
    41 |
    42 | 43 | 87 | 88 | 89 | 90 | 91 | ``` 92 | 93 | -------------------------------------------------------------------------------- /How-to-implement-auto-complete.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: How to implement auto-complete? 3 | comments: true 4 | date: 2018-10-08 20:13:10 5 | type: categories 6 | categories: Full stack 7 | tags: 8 | - auto-complete 9 | - event delegation 10 | - debounce 11 | - cache 12 | --- 13 | 14 | ## I. Logic 15 | 16 | 1. For each `input`, wait 500ms to make API call, to load 40 items 17 | 2. `scroll` down close to bottom ( less than 20px left ), make API call to load another 40 items 18 | 3. could add local `cache`, to speed up response 19 | 20 | ## II. code 21 | 22 | 1. ```html 23 | 24 | 25 | 26 | 45 | 46 | 47 |
    48 |
    49 | 50 | 51 |
    52 |
    53 | 54 | 164 | 165 | 166 | 167 | 168 | ``` 169 | -------------------------------------------------------------------------------- /MERN-Stack-Online-Exam-System.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: 'MERN Stack: Online Exam System' 3 | comments: true 4 | date: 2018-05-29 15:38:28 5 | type: categories 6 | categories: Portfolios 7 | tags: 8 | - MERN 9 | - MongoDB 10 | - Mongoose 11 | - Express 12 | - Node.js 13 | - ReactJS 14 | - Redux 15 | - React Router 16 | - JWT 17 | - Passport 18 | --- 19 | 20 | 21 | 22 | ## I. About 23 | 24 | - A **MERN stack** online examination application, providing features like 25 | - *JWT authentication* 26 | - *random questions generation*, 27 | - *timer* 28 | - *automatic grading* 29 | 30 | 31 | ## II. Github 32 | 33 | https://github.com/caomingkai/Online-Exam-System.git 34 | 35 | - MongoDB, Mongoose 36 | - Node.js, Express 37 | - ReactJS, Redux, React Router 38 | - JWT, Passport 39 | 40 | 41 | ## III. How to run it? 42 | 43 | 1. `git clone` it 44 | - `cd` into frontend folder and backend folder, and run `npm install` respectively 45 | - run `npm start` from frontend folder 46 | - run `nodemon app.js`from backend folder 47 | 48 | 49 | ## IV. Charts 50 | 51 | - **Chart1: Login Page** 52 | 53 | {% asset_img NAFlogin.png %} 54 | 55 | - **Chart2: Main Page ( todo: css )** 56 | 57 | {% asset_img NAF.png %} 58 | 59 | 60 | 61 | -------------------------------------------------------------------------------- /MERN-Stack-Online-Exam-System/NAF.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/caomingkai/Front-End-Common-Problems/0e19e3d19a033853eefddce80a68cbfac3e3baa6/MERN-Stack-Online-Exam-System/NAF.png -------------------------------------------------------------------------------- /MERN-Stack-Online-Exam-System/NAFlogin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/caomingkai/Front-End-Common-Problems/0e19e3d19a033853eefddce80a68cbfac3e3baa6/MERN-Stack-Online-Exam-System/NAFlogin.png -------------------------------------------------------------------------------- /Memory-Game.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Memory Game 3 | comments: true 4 | date: 2018-10-02 09:47:18 5 | type: categories 6 | categories: Portfolios 7 | tags: 8 | - ReactJS 9 | - webpack 10 | - Ant Design UI 11 | - CSS grid 12 | --- 13 | 14 | # Memory-Game 15 | 16 | ## What? 17 | 18 | This is a memory game, developed using React, Ant Design, webpack, and CSS grid, etc. 19 | 20 | memory_game.png 21 | 22 | ## How to run? 23 | 24 | 1. git clone 25 | 2. npm install 26 | 3. npm start 27 | 28 | ## Features 29 | 30 | - Notify the user if they win or lose 31 | - Hints assistance 32 | - Allow the user to reset at any time 33 | - Randomize the ‘cards’ layout every game 34 | - Multi Player mode 35 | - Tracking Scores 36 | - Tracking Best Score 37 | - Tracking time 38 | - Adjustable number of cards in the game (difficulty levels) 39 | 40 | ## To-do 41 | 42 | - Options & Start UI substitute the game board UI at the beginning 43 | - Hint feature: add keyboard press event 44 | 45 | ## Layout & Logic 46 | workflow.png 47 | 48 | 49 | 50 | -------------------------------------------------------------------------------- /Memory-Game/IMG_4519.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/caomingkai/Front-End-Common-Problems/0e19e3d19a033853eefddce80a68cbfac3e3baa6/Memory-Game/IMG_4519.JPG -------------------------------------------------------------------------------- /Memory-Game/memory_game.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/caomingkai/Front-End-Common-Problems/0e19e3d19a033853eefddce80a68cbfac3e3baa6/Memory-Game/memory_game.png -------------------------------------------------------------------------------- /Negative-Margin-in-Layout.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Negative Margin in Layout 3 | comments: true 4 | date: 2018-10-30 17:41:46 5 | type: categories 6 | categories: Full stack 7 | tags: 8 | - margin 9 | - layout 10 | - CSS 11 | --- 12 | 13 | 14 | 15 | ## Credits to: 16 | 17 | 1. http://icewind-blog.com/2014/05/27/css-negative-margin/ 18 | 2. https://blog.csdn.net/zhoulei1995/article/details/80161240 19 | 3. https://github.com/rccoder/blog/issues/6 20 | 4. https://www.jianshu.com/p/487d131537b4 21 | 5. https://alistapart.com/article/holygrail 22 | 23 | ## Document flow 24 | 25 | All block elements like boxes (block/inline) flowing on water; The water push them to left, and to top 26 | 27 | 1. inline elements are only push to left; When there is no space in a row, it will automatically switch to next line **without new line generated** 28 | 2. `float` will make element escape from normal document flow 29 | 3. inline element `float` will make it to be block element 30 | 4. `position: absolute` & `position: fixed` will also make escape 31 | 32 | ## Margin Used in Domcument FLow 33 | 34 | - **`margin`** determine the hidden outer border (not `border`) for all elements. 35 | 36 | - All elements have a hidden outer border used by browser to arrange elements. 37 | 38 | ## Positive Margin 39 | 40 | 1. block element: will make margins on 4 directions have a gap between its parents or its siblings 41 | 2. inline element: will only respect `left-margin` and `right-margin` 42 | 43 | ## Negative Margin 44 | 45 | 1. normal document flow 46 | 47 | - **positive**: margin will separate boxes by a gap 48 | - **negative**: 49 | - `margin-left` 和 `margin-top`:affect itself, move to its left/top by value 50 | - `margin-right` 和 `margin-bottom`:affect adjacent elements, pull them to its right/bottom by value 51 | 52 | 2. escape document flow: **absolute position** 53 | 54 | - `margin-left` 和 `margin-top`:can affect itself, move to its left/top by value 55 | - `margin-right` 和 `margin-bottom`:won't affect adjacent, since it out of normal document flow 56 | 57 | 3. escape document flow: **float** 58 | 59 | determined by `float` direction (like normal doc flow) 60 | 61 | - when `float: left`: 62 | 63 | - `margin-left: -5px` will move itself to left by 5px 64 | - `margin-right: -5px` will move adjacent element to its right by 5px 65 | - `margin-top`:can affect itself, move to its top by value 66 | - `margin-bottom`:will move adjacent element to its bottom by value 67 | 68 | - when `float: right`: 69 | 70 | - `margin-right: -5px` will move adjacent element to its right by 5px 71 | - `margin-left: -5px` will move itself to left by 5px 72 | - `margin-top`:can affect itself, move to its top by value 73 | - `margin-bottom`:will move adjacent element to its bottom by value 74 | 75 | - **[NOTE]:** `margin-left:-100%` in `float` document flow 76 | 77 | - since `float` flow is like inline elements, no new line between lines, even though they are in different lines 78 | 79 | - For example below: even though at first `left` is on bottom of `main`, does not mean it break off from `main`, it still adjacent to `main` 80 | 81 | - `margin-left: -100%; ` moves itself to its left by 100% width of its parent 82 | 83 | - Example 84 | 85 | - ```html 86 |
    main
    87 |
    left
    88 |
    right
    89 | 90 | 111 | ``` 112 | 113 | 114 | ## Use case of negative margin 115 | 116 | 1. **Layout Difference: Holy Grail vs Double wings** 117 | 118 | - Holy Grail: background won't affect two sides, even it's higher than two sides 119 | - Double wings: background affects parts below two sides, when it's higher than two sides 120 | 121 | 2. **Layout of Holy Grail (圣杯布局) ** 122 | 123 | - https://blog.csdn.net/zhoulei1995/article/details/80161240 124 | 125 | - container set aside `left/right padding` padding for left/right section 126 | 127 | - move left/right section onto main using `negative margin` 128 | 129 | - move left/right section to padding place using `position:relative` 130 | 131 | - ```html 132 | 133 | 134 | 160 | 161 | 162 | 163 |
    164 |
    165 | 中间内容区域 中间内容区域 中间内容区域 166 | 中间内容区域 中间内容区域 中间内容区域 167 | 中间内容区域 中间内容区域 中间内容区域 168 |
    169 |
    左侧边栏区域
    170 |
    右侧边栏区域
    171 |
    172 | 173 | 174 | ``` 175 | 176 | 3. **Double Wings layout (双飞翼布局)** 177 | 178 | - https://blog.csdn.net/zhoulei1995/article/details/80161240 179 | 180 | - move left/right section onto wrapper using `negative margin` 181 | 182 | - set `margin left/right` to main, to make it won't hidden by two sides 183 | 184 | - ```html 185 | 186 | 187 | 210 | 211 | 212 | 213 |
    214 |
    215 | 中间内容区域 中间内容区域 中间内容区域 216 | 中间内容区域 中间内容区域 中间内容区域 217 | 中间内容区域 中间内容区域 中间内容区域
    218 |
    219 |
    左侧边栏区域
    220 |
    右侧边栏区域
    221 | 222 | 223 | ``` 224 | 225 | 4. Horizontal & Vertical Center 226 | 227 | - For `position: absolute`, even thought it out of the normal document flow, the negative left/top still affect itself, moving to its left/top by value 228 | 229 | - ```html 230 | 231 | 232 | 233 | 234 | Center 235 | 248 | 249 | 250 |
    251 | 252 | 253 | ``` -------------------------------------------------------------------------------- /News-Recommendation-using-Wed-Mining.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: News Recommendation using Wed Mining 3 | date: 2018-03-27 15:02:08 4 | type: "categories" 5 | comments: true 6 | categories: 7 | - Portfolios 8 | tags: 9 | - Python 10 | - ReactJS 11 | - Node.js 12 | - MongoDB 13 | - RPC 14 | - RabbitMQ 15 | - TensorFlow 16 | - Shell 17 | --- 18 | 19 | 20 | ## I. Introduction 21 | An internet-based news aggregator, providing hot news scraping on popular news sources, with recommendation feature based on users' preference with the help of Machine Learning. 22 | 23 | **#Github**: https://github.com/caomingkai/News_Recommendation_System 24 | 25 | **Pull it and run it with Shell script!** 26 | 27 | - **Firstly, run `./launcher.sh`:** 28 | + run redis 29 | + run mongoDB locally 30 | + start recommendation service(python) 31 | + start backend service(phython) 32 | + start web-server service(Node.js + ReactJS) 33 | - **Secondly, run `./news_pipeline_launcher.sh`:** 34 | + run redis 35 | + run mongoDB locally 36 | + install python requirements 37 | + start news_topic_modeling_service (python Machine Learning) 38 | + start news collecting service(data pipeline + web scraping) 39 | 40 | ## II. Tech stack: 41 | - __Front end: React, Express, Node.js, OAuth__ 42 | + Built a responsive single-page web application for users to browse news (React, Node.js, RPC, SOA, JWT) 43 | 44 | 45 | - __Back end: Python RPC, MongoDB, Redis, RabbitMQ__ 46 | + Service Oriented, multiple backends serving via JSON RPC 47 | + Implemented a data pipeline which monitors, scrapes and deduplicates news 48 | 49 | 50 | - __News recommendation system: Tensorflow, DNN, NLP__ 51 | + Designed and built an offline training pipeline for news topic modeling 52 | + Deployed an online classifying service for news topic modeling using trained model 53 | 54 | 55 | - __News topic classifying system: TF-IDF, NLP, RabbitMQ__ 56 | + Implemented a click event log processor which collects users' click logs, updated a news model for each user 57 | 58 | 59 | **Chart1: Login Page with Authentication** 60 | {% asset_img loginPage.png This is an image %} 61 | 62 | **Chart2: News feed page** 63 | {% asset_img newsPage.png This is an image %} 64 | 65 | 66 | 67 | ## III. System structure: 68 | 1. **Front end tier**: React & Node.js 69 | 2. **Back end tier**: providing RPC API for communication among different tiers 70 | 3. **News recommendation system**: time decay algorithm 71 | 4. **News topic classifying system**: Tensorflow with 2-layer CNN model for classification 72 | 5. **data pipeline**: get news sources 73 | - News monitor: gets news from News.API 74 | - News scraper: web scraper 75 | - News deduper: news TF-IDF deduplication 76 | 77 | 78 | 79 | **Chart 3: System with Machine Learning module** 80 | ![chart](https://github.com/caomingkai/News_Recommendation_System/raw/master/with%20ML%20topic%20classification1.png) 81 | 82 | **Chart 4: System with Recommendation module** 83 | ![chart](https://github.com/caomingkai/News_Recommendation_System/raw/master/with%20Recommendation%20module.png) 84 | 85 | **Chart 5: Service dependency** 86 | ![chart](https://github.com/caomingkai/News_Recommendation_System/raw/master/chart.jpg) 87 | -------------------------------------------------------------------------------- /News-Recommendation-using-Wed-Mining/.loginPage.png.icloud: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/caomingkai/Front-End-Common-Problems/0e19e3d19a033853eefddce80a68cbfac3e3baa6/News-Recommendation-using-Wed-Mining/.loginPage.png.icloud -------------------------------------------------------------------------------- /News-Recommendation-using-Wed-Mining/.newsPage.png.icloud: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/caomingkai/Front-End-Common-Problems/0e19e3d19a033853eefddce80a68cbfac3e3baa6/News-Recommendation-using-Wed-Mining/.newsPage.png.icloud -------------------------------------------------------------------------------- /News-Recommendation-using-Wed-Mining/loginPage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/caomingkai/Front-End-Common-Problems/0e19e3d19a033853eefddce80a68cbfac3e3baa6/News-Recommendation-using-Wed-Mining/loginPage.png -------------------------------------------------------------------------------- /News-Recommendation-using-Wed-Mining/newsPage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/caomingkai/Front-End-Common-Problems/0e19e3d19a033853eefddce80a68cbfac3e3baa6/News-Recommendation-using-Wed-Mining/newsPage.png -------------------------------------------------------------------------------- /Node-MySQL.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Node+MySQL 3 | comments: true 4 | date: 2018-05-14 21:30:13 5 | type: categories 6 | categories: Full stack 7 | tags: 8 | - Node.js 9 | - MySQL 10 | --- 11 | 12 | ### Install 13 | This is a Node.js module, install: 14 | `npm install mysql --save` 15 | 16 | 17 | ### Connect 18 | Before connecting to databases, make sure MySQL database is turned on. 19 | 20 | 【注意】: 21 | 22 | - 先执行 `connect()`,让connection object与数据库建立连接。 23 | - 然后,在对该connection执行`.query(MySQL_Command, callback_func)` 24 | 25 | ```javascript 26 | var mysql = require('mysql'); 27 | var connection = mysql.createConnection({ 28 | host : 'example.org', 29 | user : 'bob', 30 | password : 'secret' 31 | }); 32 | 33 | connection.query('SELECT 1', function (error, results, fields) { 34 | if (error) throw error; 35 | // connected! 36 | }); 37 | ``` 38 | 39 | ### Disconnect 40 | 41 | ```javascript 42 | connection.end(function(err) { 43 | // Callback function 44 | }); 45 | ``` 46 | 47 | 48 | ### Escaping query values 49 | 50 | Three ways to avoid **SQL injection** 51 | 52 | - mysql.escape() 53 | - connection.escape() 54 | - pool.escape() 55 | - `?`placeholder 56 | 57 | 58 | ```javascript 59 | // 1 -connection.escape() 60 | var userId = 'some user provided value'; 61 | var sql = 'SELECT * FROM users WHERE id = ' + connection.escape(userId); 62 | connection.query(sql, function (error, results, fields) { 63 | if (error) throw error; 64 | // ... 65 | }); 66 | 67 | // 2 - ? placeholder 68 | var adr = 'Mountain 21'; 69 | var sql = 'SELECT * FROM customers WHERE address = ?'; 70 | con.query(sql, [adr], function (err, result) { 71 | if (err) throw err; 72 | console.log(result); 73 | }); 74 | ``` 75 | 76 | ### Creating a Database 77 | 78 | ```javascript 79 | connection.query("CREATE DATABASE mydb", function (err, result) { 80 | if (err) throw err; 81 | console.log("Database created"); 82 | }); 83 | ``` 84 | ### Creating a Table 85 | Two ways: 86 | 87 | - create database and table simultenously 88 | - first create database, and connect it; then create table with the connection 89 | 90 | ```javascript 91 | // approach 1 92 | 93 | connection.query("CREATE DATABASE db", function (error, rows, fields) { 94 | if (error) throw error; 95 | }); 96 | 97 | connection.query("USE db", function (error, rows, fields) { 98 | if (error) throw error; 99 | }); 100 | 101 | connection.query("CREATE TABLE tb(id INT, name VARCHAR(50))", function (error, rows, fields) { 102 | if (error) throw error; 103 | }); 104 | 105 | 106 | //----------------------- 107 | // approach 2 108 | 109 | var con = mysql.createConnection({ 110 | host: "localhost", 111 | user: "yourusername", 112 | password: "yourpassword", 113 | database: "mydb" 114 | }); 115 | 116 | con.connect(function(err) {}); 117 | 118 | var sql = "CREATE TABLE customers (name VARCHAR(255), address VARCHAR(255))"; 119 | 120 | con.query(sql, function (err, result) { 121 | if (err) throw err; 122 | console.log("Table created"); 123 | }); 124 | ``` 125 | 126 | ### Selecting From a Table 127 | 128 | To select data from a table in MySQL, use the `SELECT` statement. 129 | 130 | ```javascript 131 | var sql = "SELECT * FROM customers WHERE address = 'Park Lane 38'"; 132 | 133 | con.query(sql, function (err, result) { 134 | if (err) throw err; 135 | console.log(result); 136 | }); 137 | ``` 138 | 139 | **Wildcard Characters**`%`: represent zero, one or multiple characters: 140 | 141 | ```javascript 142 | var sql = "SELECT * FROM customers WHERE address LIKE 'S%'" 143 | ``` 144 | 145 | 146 | ### Insert Into Table 147 | 148 | To fill a table in MySQL, use the `INSERT INTO` statement. 149 | 150 | ```javascript 151 | var sql = "INSERT INTO customers (name, address) VALUES ('Company Inc', 'Highway 37')"; 152 | 153 | con.query(sql, function (err, result) { 154 | if (err) throw err; 155 | console.log("1 record inserted"); 156 | }); 157 | ``` 158 | 159 | ### Update Table 160 | 161 | You can update existing records in a table by using the `UPDATE` statement: 162 | 163 | ```javascript 164 | var sql = "UPDATE customers SET address = 'Canyon 123' WHERE address = 'Valley 345'"; 165 | 166 | con.query(sql, function (err, result) { 167 | if (err) throw err; 168 | console.log(result.affectedRows + " record(s) updated"); 169 | }); 170 | ``` 171 | 172 | ### Sort the Result 173 | Use the `ORDER BY` statement to sort the result in ascending or descending order. 174 | 175 | The `ORDER BY` keyword sorts the result ascending by default. To sort the result in descending order, use the `DESC` keyword. 176 | 177 | ```javascript 178 | var sql = "SELECT * FROM customers ORDER BY name DESC"; 179 | 180 | con.query(sql, function (err, result) { 181 | if (err) throw err; 182 | console.log(result); 183 | }); 184 | ``` 185 | 186 | ### Delete Record 187 | 188 | You can delete records from an existing table by using the `DELETE FROM` statement: 189 | 190 | ```javascript 191 | var sql = "DELETE FROM customers WHERE address = 'Mountain 21'"; 192 | 193 | con.query(sql, function (err, result) { 194 | if (err) throw err; 195 | console.log("Number of records deleted: " + result.affectedRows); 196 | ``` 197 | 198 | 199 | ### Limit the Result 200 | 201 | You can limit the number of records returned from the query, by using the `LIMIT` statement: 202 | 203 | ```javascript 204 | var sql = "SELECT * FROM customers LIMIT 5"; 205 | 206 | con.query(sql, function (err, result) { 207 | if (err) throw err; 208 | console.log(result); 209 | }); 210 | ``` 211 | 212 | ### Join Two or More Tables 213 | 214 | Combine rows from two or more tables, based on a related column between them, by using a `JOIN` statement. 215 | 216 | ``` 217 | //users 218 | 219 | [ 220 | { id: 1, name: 'John', favorite_product: 154}, 221 | { id: 2, name: 'Peter', favorite_product: 154}, 222 | { id: 3, name: 'Amy', favorite_product: 155}, 223 | { id: 4, name: 'Hannah', favorite_product:}, 224 | { id: 5, name: 'Michael', favorite_product:} 225 | ] 226 | ``` 227 | 228 | ``` 229 | // products 230 | [ 231 | { id: 154, name: 'Chocolate Heaven' }, 232 | { id: 155, name: 'Tasty Lemons' }, 233 | { id: 156, name: 'Vanilla Dreams' } 234 | ] 235 | ``` 236 | 237 | **1. Inner join** 238 | 239 | These two tables can be combined by using users' favorite_product field and products' id field. 240 | 241 | ```javascript 242 | var sql = "SELECT users.name AS user, products.name AS favorite FROM users JOIN products ON users.favorite_product = products.id"; 243 | 244 | con.query(sql, function (err, result) { 245 | if (err) throw err; 246 | console.log(result); 247 | }); 248 | ``` 249 | 250 | **2. Left Join** 251 | If you want to return all users, no matter if they have a favorite product or not, use the LEFT JOIN statement: 252 | 253 | ```javascript 254 | SELECT users.name AS user, 255 | products.name AS favorite 256 | FROM users 257 | LEFT JOIN products ON users.favorite_product = products.id 258 | ``` 259 | 260 | 261 | **3. Right Join** 262 | If you want to return **all products**, and the users who have them as their favorite, even if no user have them as their favorite, use the RIGHT JOIN statement: 263 | ```javascript 264 | SELECT users.name AS user, 265 | products.name AS favorite 266 | FROM users 267 | RIGHT JOIN products ON users.favorite_product = products.id 268 | ``` 269 | 270 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Front End Common Problems 2 | 3 | Notes for common front-end / full-stack problems in interviews, covering: 4 | - Common algorithms implementation in JavaScript, 5 | - Design patterns, JavaScript basics, 6 | - Node.js/Express basics, 7 | - React/Redux/Flux basics, 8 | - ES6 new features, 9 | - Common code snippets in front end development 10 | 11 | 🏄Check out my personal blog for a better experience: https://caomingkai.github.io/ 12 | 13 | 14 | 15 | ## I. Front End Concepts 16 | 1. [HTML/CSS/JavaScript interview preparation](https://github.com/caomingkai/Front-End-Common-Problems/blob/master/Facebook-Interview-Preparation.md) 17 | 2. [JS basics](https://github.com/caomingkai/Front-End-Common-Problems/blob/master/Note-of-Eloquent-JavaScript.md) 18 | 3. [DOM basics](https://github.com/caomingkai/Front-End-Common-Problems/blob/master/Common-DOM-Manipulations.md) 19 | 4. [Browser basics](https://github.com/caomingkai/Front-End-Common-Problems/blob/master/Note-of-Eloquent-JavaScript-JS-and-Browser.md) 20 | 5. [Negative Margin in Layout](https://github.com/caomingkai/Front-End-Common-Problems/blob/master/Negative-Margin-in-Layout.md) 21 | 7. [Write a Promise](https://github.com/caomingkai/Front-End-Common-Problems/blob/master/Write-Our-Own-Promise.md) 22 | 8. [setTimeout vs setInterval](https://github.com/caomingkai/Front-End-Common-Problems/blob/master/setTimeout-vs-setInterval.md) 23 | 9. [Event Emitter](https://github.com/caomingkai/Front-End-Common-Problems/blob/master/Event-Emitter.md) 24 | 10. [React basics](https://github.com/caomingkai/Front-End-Common-Problems/blob/master/React-Learning.md) 25 | 10. [React Router v4](https://github.com/caomingkai/Front-End-Common-Problems/blob/master/React-Router-v4.md) 26 | 10. [Redux & Flux](https://github.com/caomingkai/Front-End-Common-Problems/blob/master/Flux-Redux.md) 27 | 11. [ES6](https://github.com/caomingkai/Front-End-Common-Problems/blob/master/ES6.md) 28 | 12. [Node.js basics](https://github.com/caomingkai/Front-End-Common-Problems/blob/master/Node-js.md) 29 | 12. [Node & MySQL](https://github.com/caomingkai/Front-End-Common-Problems/blob/master/Node-MySQL.md) 30 | 13. [Express basics](https://github.com/caomingkai/Front-End-Common-Problems/blob/master/Express-Framework.md) 31 | 13. [this & arrow function](https://github.com/caomingkai/Front-End-Common-Problems/blob/master/this-arrow-function.md) 32 | 14. [A way to Make an Efficient React Timer](https://github.com/caomingkai/Front-End-Common-Problems/blob/master/A-Way-to-Make-an-Efficient-React-Timer.md) 33 | 15. [Authenication: JWT vs Session](https://github.com/caomingkai/Front-End-Common-Problems/blob/master/Authetication-JWT-vs-Session.md) 34 | 16. [Create a Calculator- React](https://github.com/caomingkai/Front-End-Common-Problems/blob/master/Create-a-Calculator-React.md) 35 | 17. [Create a Calculator- Vanilla JS](https://github.com/caomingkai/Front-End-Common-Problems/blob/master/Create-a-Calculator-Vanilla-JS.md) 36 | 18. [Animation using JS](https://github.com/caomingkai/Front-End-Common-Problems/blob/master/How-to-Make-Animation-using-JS.md) 37 | 19. [Ways of Creating Object in JS](https://github.com/caomingkai/Front-End-Common-Problems/blob/master/Ways-of-Creating-Objects-in-JS.md) 38 | 20. [Auto-complete Implementation](https://github.com/caomingkai/Front-End-Common-Problems/blob/master/How-to-implement-auto-complete.md) 39 | 40 | ## II. Algorithms & Data Structures 41 | 0. [Common Algorithm Problems in JS](https://github.com/caomingkai/Front-End-Common-Problems/blob/master/Common-Algorithm-Problems-JS.md) 42 | 1. [Sorting Algorithms in JS](https://github.com/caomingkai/Front-End-Common-Problems/blob/master/Sorting-Algorithms-in-JS.md) 43 | 1. [Stack & Queue Implementation in JS](https://github.com/caomingkai/Front-End-Common-Problems/blob/master/Stack-Queue-Implementation-using-JS.md) 44 | 1. [Trie/Prefix Tree Implementation in JS](https://github.com/caomingkai/Front-End-Common-Problems/blob/master/Trie-Tree-Implementation-using-JS.md) 45 | 1. [Trie/Prefix Tree Implementation in Java](https://github.com/caomingkai/Front-End-Common-Problems/blob/master/Trie.md) 46 | 1. [Design Pattern - JS](https://github.com/caomingkai/Front-End-Common-Problems/blob/master/Design-Pattern-JS.md) 47 | 1. [Binaray Search Variation](https://github.com/caomingkai/Front-End-Common-Problems/blob/master/Binary-Search-variations.md) 48 | 2. [Find 1st Bad Version](https://github.com/caomingkai/Front-End-Common-Problems/blob/master/Coding-Problem-find-the-1st-Bad-Version.md) 49 | 3. [Flatten an Nested Array](https://github.com/caomingkai/Front-End-Common-Problems/blob/master/How-to-Flatten-an-Array.md) 50 | 4. [Reposition Elements in an Array](https://github.com/caomingkai/Front-End-Common-Problems/blob/master/Reposition-an-Array.md) 51 | 5. [Search for a Symmetric Node](https://github.com/caomingkai/Front-End-Common-Problems/blob/master/Search-for-a-Symmetric-Node.md) 52 | 6. [Union Find to Achieve Max Tasks](https://github.com/caomingkai/Front-End-Common-Problems/blob/master/Union-Find-to-achieve-max-tasks.md) 53 | 7. [2-Egg Pazzle](https://github.com/caomingkai/Front-End-Common-Problems/blob/master/2-egg-Puzzle.md) 54 | 55 | ## III. Portfolios 56 | 1. [UI/UX Internship Projects at Specifio, Inc.](https://github.com/caomingkai/Front-End-Common-Problems/blob/master/Specifio-Work-Summary.md) 57 | 1. [Full-stack: New Recommendation Using Web Mining](https://github.com/caomingkai/Front-End-Common-Problems/blob/master/News-Recommendation-using-Wed-Mining.md) 58 | 1. [Full-stack: URL Shortening Service](https://github.com/caomingkai/Front-End-Common-Problems/blob/master/Tiny-URL.md) 59 | 1. [Full-stack: Facebook Custom Search](https://github.com/caomingkai/Front-End-Common-Problems/blob/master/Facebook-Custom-Search.md) 60 | 1. [Full-stack: Online Exam System](https://github.com/caomingkai/Front-End-Common-Problems/blob/master/MERN-Stack-Online-Exam-System.md) 61 | 1. [Front-end: Memory Game](https://github.com/caomingkai/Front-End-Common-Problems/blob/master/Memory-Game.md) 62 | 1. [Front-end: Expense Tracking Application](https://github.com/caomingkai/Front-End-Common-Problems/blob/master/Memory-Game.md) 63 | 1. [Web Template Engine](https://github.com/caomingkai/Front-End-Common-Problems/blob/master/Web-Template-Engine.md) 64 | 65 | -------------------------------------------------------------------------------- /React-Expense-Tracking-app.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: 'React: Expense Tracking app' 3 | comments: true 4 | date: 2018-04-23 11:47:10 5 | type: categories 6 | categories: Portfolios 7 | tags: ReactJS 8 | --- 9 | 10 | ## I. About 11 | 12 | - An expense tracking application proving CRUD using React. 13 | - Github: 14 | + https://github.com/caomingkai/Expense-Tracking.git 15 | - **Chart1: Create** 16 | 17 | {% asset_img create.gif %} 18 | 19 | - **Chart2: Update 20 | 21 | {% asset_img update.gif %} 22 | 23 | - **Chart3: Delete** 24 | 25 | {% asset_img delete.gif %} 26 | 27 | ## II. Structure 28 | 29 | ### 1. Components Structure 30 | 31 | ``` 32 | App 33 | |___ Summary 34 | |___ Form _ _ _ _ RecordsAPI 35 | | | 36 | |___ Table | 37 | |_______ TableRow 38 | |____ TableDisplay 39 | |____ TableEdit 40 | 41 | ``` 42 | 43 | - **App Component:** is the data hub 44 | - state: `records` for entries in Table component 45 | - state: `isLoaded` show loading info, before showing Table 46 | - state: `error` 47 | - method: `componentDidMount()` get data from database 48 | - method: `addRecord()` passed to Form 49 | - method: `deleteRecord()` passed to Table and TableRow 50 | - method: `updateRecord()` passed to Table and TableRow 51 | - method: `credits()` passed to Summary 52 | - method: `debits()` passed to Summary 53 | - method: `balance()` passed to Summary 54 | - **Summary Component:** displays negative/ positive summation for the `records` 55 | - **Form Component:** add `record` into `records`, updating Table 56 | - **Table Component:** just pass `records` to **TableRow** 57 | - **TableRow Component:** display each `record` in `records` 58 | - **RecordsAPI:** utility providing interface to make RESTful API call 59 | 60 | ### 2. File Structure 61 | 62 | ``` 63 | |__node_modules 64 | | 65 | |__public 66 | | |___ index.html 67 | | 68 | |__ src 69 | |___ utils: RecordsAPI.js 70 | | 71 | |___ components: 72 | |___ App.js 73 | |___ Form.js 74 | |___ Summary.js 75 | |___ Table.js 76 | |___ TableRow.js 77 | 78 | ``` 79 | 80 | 81 | ## III. Ajax request 82 | 83 | ### Several Ways: 84 | 85 | 1. Ajax Libraries 86 | + Axios 87 | - axios.get(url[, config]) 88 | - axios.delete(url[, config]) 89 | - axios.head(url[, config]) 90 | - axios.options(url[, config]) 91 | - axios.post(url[, data[, config]]) 92 | - axios.put(url[, data[, config]]) 93 | + jQuery AJAX 94 | 2. Browser built-in `window.fetch` 95 | 96 | No need to prepend "window" before `fetch()`: default obj 97 | 98 | ```javascript 99 | ## No need to prepend "window" before fetch, this is the default obj 100 | 101 | fetch('http://example.com/movies.json') 102 | .then(function(response) { 103 | return response.json(); 104 | }) 105 | .then(function(myJson) { 106 | console.log(myJson); 107 | }); 108 | 109 | ``` 110 | 111 | ### When and where to initiate Ajax call? 112 | 113 | Do it in `componentDidMount` lifecycle method. So you can use setState to update your component when the data is retrieved. 114 | 115 | ```javascript 116 | componentDidMount() { 117 | fetch("https://api.example.com/items") 118 | .then(res => res.json()) 119 | .then( 120 | (result) => { 121 | this.setState({ 122 | isLoaded: true, 123 | items: result.items 124 | }); 125 | }, 126 | // Note: it's important to handle errors here 127 | // instead of a catch() block so that we don't swallow 128 | // exceptions from actual bugs in components. 129 | (error) => { 130 | this.setState({ 131 | isLoaded: true, 132 | error 133 | }); 134 | } 135 | ) 136 | } 137 | ``` 138 | 139 | ## IV. Concept 140 | 141 | ### 1. 组件数据流: Model -> View 142 | - 父组件M -> 子组件V 143 | + 父组件prop 之间传给 子组件 prop 144 | 145 | - 子组件M -> 父组件V 146 | + 回调函数 147 |   + 父组件向子组件传递回调函数 148 |   + JS中,function是一等公民,因此传入的值会作为自身field保存起来;与C/Java不同。 149 | - sibling 组件间传值 M->V 150 | + 必须依靠二者共同父组件来传递 151 | + 但等组件之间的关系越来越复杂时候,这种依靠父组件作为中间人传值方式 would be a mess! 152 | + Redux comes into picture 153 | 154 | ### 2. 双向绑定: Model <-> View 155 | - 通过绑定``的 `onChange()` 监视 View的变换 156 | - 在 onChange Handler中更新组件的值,完成 View => Model 的数据流。 157 | 158 | ### 3. React 生命周期 159 | - **Mount** 160 | + constructor() 161 | + componentWillMount() 162 | + render() 163 | + componentDidMount() 164 | - **Update** 165 | + componentWillReceiveProps(): 将接收新的props 166 | + shouldComponentUpdate(): 是否应该被更新? 167 | + componentWillUpdate(): 组件即将更新 168 | + render(): 组件被渲染 169 | + componentDidUpdate(): 组件完成更新 170 | - **Unmount** 171 | + componentWillUnmount(): 组件被卸载前做一些数据清除 172 | 173 | -------------------------------------------------------------------------------- /React-Expense-Tracking-app/create.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/caomingkai/Front-End-Common-Problems/0e19e3d19a033853eefddce80a68cbfac3e3baa6/React-Expense-Tracking-app/create.gif -------------------------------------------------------------------------------- /React-Expense-Tracking-app/delete.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/caomingkai/Front-End-Common-Problems/0e19e3d19a033853eefddce80a68cbfac3e3baa6/React-Expense-Tracking-app/delete.gif -------------------------------------------------------------------------------- /React-Expense-Tracking-app/update.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/caomingkai/Front-End-Common-Problems/0e19e3d19a033853eefddce80a68cbfac3e3baa6/React-Expense-Tracking-app/update.gif -------------------------------------------------------------------------------- /React-Router-v4.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: React Router v4 3 | comments: true 4 | date: 2018-05-15 21:21:05 5 | type: categories 6 | categories: Full stack 7 | tags: React-Router 8 | --- 9 | 10 | 11 | ### I. Three types of Components: 12 | **1. router components** 13 | >create a history object, 提供“前进”、“后退” 14 | 15 | - **``**: for server that responds to requests 16 | - **``**: for a static file server. 17 | 18 | **2. route matching components** 19 | >comparing a 's path prop with the current location’s pathname 20 | >只要路由匹配,Route所在位置就会render相应的Component 21 | 22 | - **`` :包容性路由** 23 | - 3个props: 24 | - path:匹配路径 25 | - component:对应的组件 26 | - render:没有可用组件时,直接render 27 | - 1个state: 28 | - match 29 | - match包含4个field:`isExact`,`params`,`path`,`url` 30 | - 1个context: 31 | - router obj 32 | - router 包含 `history`,`routes` 33 | 34 | - **``:排他性路由** 35 | 36 | ```javascript 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | // when none of the above match, will be rendered 45 | ``` 46 | 47 | - How ? 48 | iterate over all of its children elements and only render the first one that matches the current location. 49 | - Props: `component`, `render`, and `children` 50 | 51 | **3. navigation components** 52 | 53 | - **` `** 54 | - **` `** :a special type of that can style itself as “active” when its ‘to’ prop matches the current location. 55 | - **` `**: navigate using its ‘to’ prop 56 | - 注意:不是 “函数”,而是“组件”,需要放在render中return 57 | - 没有路由解析时候,可以直接使用redirect,重定向到默认页面 58 | 59 | ### II. 3种方式renders Component 60 | 61 | - `` 62 | - `` 63 | - `` 64 | 65 | ### III. Route在render component同时,传入3个量,作为component的props(不论3中方式的哪一种) 66 | - match 67 | - history 68 | - location 69 | 70 | 比如render:func( )方式render conponent 71 | 72 | ```javascript 73 | // eg1: 74 |
    Home
    }/> 75 | 76 | // eg2: wrapping/composing 77 | const FadingRoute = ({ component: Component, ...rest }) => ( 78 | ( 79 | 80 | 81 | 82 | )}/> 83 | ) 84 | 85 | " 86 | - render props: path、children/render/component、 87 | - render state:match 88 | - component props(route所render): history、location、match 89 | "不论是哪种方式render,都会拿到这三个props" 90 | - 因此,eg2中render:func方式,直接将props作为function component的参数传入 91 | "render={ props => ( 92 | 93 | 94 | 95 | )}" 96 | ``` 97 | 98 | ### IV. Route vs Component如何关联 99 | - Router 将路径 match上之后,会调用相应的 Route, 由Route 将相关的参数:match、location、history等传入到 Component中 100 | - Route 的 state: match、location 传入到 Component的 props: match、location 101 | - The Route will render , where props are some router specific things that look like { match, location, history }. 102 | - If the user is not at /dashboard then the Route will render null. That’s pretty much all there is to it. 103 | 104 | ### V. `match.url` vs `match.path` 105 | >A match object contains information about how a matched the URL. 106 | 107 | - match:是 `route`的`state`;是`component`的`props` 108 | - Eg: consider the route `/users/:userId` 109 | - `match.path` - (string) 用于匹配路径模式。用于构建嵌套的 ; `match.path` would be `/users/:userId` 110 | - `match.url` - (string) URL 匹配的部分。 用于构建嵌套的 ; `match.url` would have the :userId value filled in, e.g. "users/5"." 111 | 112 | ### VI. `match.params` 表示 url 匹配上的变量值 113 | 114 | ```javascript 115 | 116 | 117 | {match.params.id} 118 | 119 | ``` 120 | 121 | URL 后半部分由变量 id 兜住,如果进来的url为`/abc`,那么 `match.params.id = abc` 122 | 123 | ### VII. Eg: Custom Link 124 | >Route实际上是 Component 的买办,为Component办事! 125 | >Route放在哪个位置,那里就有可能render出它携带的component(只要url match) 126 | 127 | ```javascript 128 | 129 | 130 | 131 | ``` 132 | 133 | ### VIII. ``:防止中途跳转 134 | >适用情况:用户在填表过程中,点击了“后退”或“跳转链接”,需弹窗询问 135 | >``是保留tag,跟``一样 136 | 137 | - 创建一个wrapper,包含`
    `, `` 138 | - wrapper中设置`state.inMiddle`,来决定是否render`` 139 | - 改变`state.inMiddle`的根源:`form`中的`input`输入框; 140 | + 只要有任何输入值,就将`state.inMiddle`置为`true` 141 | + 提交form后,将form reset()之后,需要将`state.inMiddle`置为`false` 142 | - `Prompt`的props: 143 | + `when`:检查`state.inMiddle` 144 | + `message `: 决定弹窗的显示信息 145 | 146 | ```javascript 147 | class Form extends React.Component { 148 | state = { 149 | isBlocking: false 150 | }; 151 | 152 | render() { 153 | const { isBlocking } = this.state; 154 | 155 | return ( 156 | { 158 | event.preventDefault(); 159 | event.target.reset(); 160 | this.setState({ 161 | isBlocking: false 162 | }); 163 | }} 164 | > 165 | 166 | 169 | `Are you sure you want to go to ${location.pathname}` 170 | } 171 | /> 172 | 173 | { 176 | this.setState({ 177 | isBlocking: event.target.value.length > 0 178 | }); 179 | }} 180 | /> 181 | 182 | 183 | 184 | 185 | 186 | ); 187 | } 188 | } 189 | ``` 190 | 191 | 192 | ### Reference 193 | 194 | - Official API: [https://reacttraining.com/react-router/web/guides/philosophy](https://reacttraining.com/react-router/web/guides/philosophy) 195 | - 中文版API:[https://www.jianshu.com/p/e3adc9b5f75c](https://www.jianshu.com/p/e3adc9b5f75c) 196 | -------------------------------------------------------------------------------- /Reposition-an-Array.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Reposition an Array 3 | comments: true 4 | date: 2018-10-14 19:59:57 5 | type: categories 6 | categories: Algorithm 7 | tags: 8 | - Algorithm 9 | - in-place 10 | --- 11 | 12 | 13 | 14 | ## Problem 15 | 16 | Given an original array, and it new position to be. Reposition it according the given indices array. For example: 17 | 18 | ```js 19 | let arr = ["a", "b", "c", "d", "e", "f"] 20 | let indices = [ 1, 2, 3, 5, 0, 4 ] 21 | 22 | // the new array should be ["e", "a", "b", "c", "f", "d"] 23 | ``` 24 | 25 | ## Follow Up 26 | 27 | Try to do it **in-place**, i.e. : Space Complexity `O(1)` 28 | 29 | 30 | 31 | ## Solution 1: Space complexity `O(n)` 32 | 33 | ```js 34 | function rePosition(arr, indices){ 35 | if( arr.length !== indices.length ) 36 | throw new Error("they are not the same length") 37 | 38 | let newArr = indices.map((item, index)=>{ 39 | return arr[indices.indexOf(index)] 40 | }) 41 | return newArr 42 | } 43 | 44 | // Tests 45 | let newArr = [] 46 | let arr = ["a", "b", "c", "d", "e", "f"] 47 | 48 | // test 1 49 | let indices1 = [ 1, 2, 3, 5, 0, 4 ] 50 | newArr = rePosition(arr, indices1) 51 | console.log(newArr) // ["e", "a", "b", "c", "f", "d"] 52 | 53 | // test 2 54 | let indices2 = [ 0, 1, 2, 3, 4, 5 ] 55 | newArr = rePosition(arr, indices2) 56 | console.log(newArr) // ["a", "b", "c", "d", "e", "f"] 57 | 58 | // test 3 59 | let indices3 = [ 2, 1, 0, 4, 3, 5 ] 60 | newArr = rePosition(arr, indices3) 61 | console.log(newArr) // ["c", "b", "a", "e", "d", "f"] 62 | ``` 63 | 64 | 65 | 66 | ## Solution 2: Space complexity `O(1)` 67 | 68 | We need two variables: `kickedItem` and `kickedIndex`, to denote the kicked item in `arr` and kicked index in `indices` 69 | 70 | 1. Every time we update an item in its new position, we put item in its new position, and swap the kicked item and index to their counterpart in `arr` & `indices` 71 | 72 | 2. Since the kicked item & its new position are just swapped to previous position, we can keep staring the same position to deal with the chaining update, until there is an end to the chain 73 | 74 | 3. NOTE: there are also cases (*test case 3*) that the new indices are not depended upon one another, but instead they are partially dependent. That's why we need to maintain two variable for both `arr` & `indices`, rather than just for `arr` 75 | 76 | 77 | ```js 78 | 79 | function rePosition(arr, indices){ 80 | if( arr.length !== indices.length ) 81 | throw new Error("they are not the same length") 82 | 83 | for( let i = 0; i < arr.length; i++ ){ 84 | while( i !== indices[i] ){ 85 | let kickedItem = arr[indices[i]] 86 | let kickedIndex = indices[indices[i]] 87 | arr[indices[i]] = arr[i] 88 | indices[indices[i]] = indices[i] 89 | arr[i] = kickedItem 90 | indices[i] = kickedIndex 91 | } 92 | } 93 | } 94 | 95 | // Tests 96 | 97 | // test 1 98 | let arr = ["a", "b", "c", "d", "e", "f"] 99 | let indices1 = [ 1, 2, 3, 5, 0, 4 ] 100 | rePosition(arr, indices1) 101 | console.log(arr) // ["e", "a", "b", "c", "f", "d"] 102 | 103 | // test 2 104 | arr = ["a", "b", "c", "d", "e", "f"] 105 | let indices2 = [ 0, 1, 2, 3, 4, 5 ] 106 | rePosition(arr, indices2) 107 | console.log(arr) // ["a", "b", "c", "d", "e", "f"] 108 | 109 | // test 3 110 | arr = ["a", "b", "c", "d", "e", "f"] 111 | let indices3 = [ 2, 1, 0, 4, 3, 5 ] 112 | rePosition(arr, indices3) 113 | console.log(arr) // ["c", "b", "a", "e", "d", "f"] 114 | ``` 115 | 116 | -------------------------------------------------------------------------------- /Search-for-a-Symmetric-Node.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Search for a Symmetric Node 3 | comments: true 4 | date: 2018-10-07 20:34:30 5 | type: categories 6 | categories: Full stack 7 | tags: 8 | - DOM 9 | - parentNode 10 | - Algorithm 11 | --- 12 | 13 | 14 | 15 | ## Problem 16 | 17 | Given two DOM trees with the same structure, and one node in tree1, try to find its symmetric node in tree2 18 | 19 | 20 | 21 | ## Solution 1 22 | 23 | If we are not so familiar with DOM API, we might forget there is an attribute for each DOM element: `parentNode`. Then we might just traverse both trees at the same time, when we encounter the node in tree1, the node in tree2 is what we want. 24 | 25 | ```js 26 | function getSymmetricNode(target, root1, root2){ 27 | if( target === root1 ) return root2 28 | 29 | for( let i = 0; i < root1.childNodes.length; i++ ){ 30 | let node1 = root1.childNodes[i] 31 | let node2 = root2.childNodes[i] 32 | if( node1 === target ) return node2 33 | getSymmetricNode(target, node1, node2 ) 34 | } 35 | return null 36 | } 37 | ``` 38 | 39 | 1. Time Complexity: **O(b^d) [d: depth, b: branches]**, which is BAD! 40 | 41 | ## Solution 2 [Improved ] 42 | 43 | Actually there is an convenient attribute we could utilize, that is `parentNode` 44 | 45 | 1. First, we could go up to find that **path** from root1 to target 46 | - The path is consist of indices of node on that path 47 | 2. Using that path of indices, we could go downwards from root2 to find the desired node 48 | 49 | ```js 50 | let getSymmetricNode = (target, root1, root2) => { 51 | let path = getIndexPath( target, root1 ) 52 | return getNode( path, root2 ) 53 | } 54 | 55 | let getIndexPath = (target, root1)=>{ 56 | let path = [] 57 | let curNode = target 58 | while( curNode && curNode.parentNode ){ 59 | let index = curNode.parentNode.indexOf(curNode) 60 | path.push(index) 61 | curNode = curNode.parentNode 62 | } 63 | return path 64 | } 65 | 66 | let getNode =(path, root)=>{ 67 | let node 68 | while( path.length > 0 ){ 69 | node = root.childNodes[path.pop()] 70 | } 71 | return node 72 | } 73 | 74 | ``` 75 | 76 | 77 | 78 | ## Testing 79 | 80 | ```html 81 | // Testing 82 | 83 | 84 | 85 | 86 | 87 | Hello World 88 | 89 | 90 |
    91 |
    92 |
    93 |
    94 |
    95 |
    96 |
    97 |
    98 |
    99 | 100 |
    101 |
    102 |
    103 |
    104 |
    105 |
    106 |
    107 |
    108 |
    109 | 168 | 169 | 170 | 171 | ``` 172 | 173 | -------------------------------------------------------------------------------- /Sorting-Algorithms-in-JS.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Sorting Algorithms in JS 3 | comments: true 4 | date: 2018-11-01 15:25:34 5 | type: categories 6 | categories: Algorithm 7 | tags: 8 | - insertion sort 9 | - selection sort 10 | - bubble sort 11 | - merge sort 12 | - quick sort 13 | --- 14 | 15 | 16 | 17 | ## I. Selection Sort 18 | 19 | - totally unsorted: O(n^2) 20 | 21 | - partially sorted: O(n^2) 22 | 23 | - ```js 24 | /* 25 | select min element from rest of unsorted elements, put into front 26 | - totally unsorted: O(n^2) 27 | - partially sorted: O(n^2) 28 | */ 29 | 30 | function slectionSort( list ){ 31 | if( list === null || list.length <= 1 ) return 32 | 33 | for( let i = 0; i < list.length; i++ ){ 34 | let curMinId = i 35 | for( let j = i+1; j < list.length; j++ ){ 36 | list[curMinId] > list[j] && (curMinId = j) 37 | } 38 | [ list[i], list[curMinId] ] = [ list[curMinId], list[i] ] 39 | } 40 | } 41 | 42 | // Test 43 | let list = [ 2, 1, 3, 4, 5, 6, 3, 5, 1 ] 44 | console.log("Original list: " + list) 45 | slectionSort(list) 46 | console.log("Selection sort: " + list) 47 | ``` 48 | 49 | 50 | ## II. Insertion Sort 51 | 52 | - totally unsorted: O(n^2) 53 | 54 | - partially sorted: O(n) 55 | 56 | ```js 57 | /* 58 | for each element, insert it into the sorted part exactly before its position 59 | - totally unsorted: O(n^2) 60 | - partially sorted: O(n) 61 | */ 62 | 63 | function insertionSort(list){ 64 | if( list === null || list.length <= 1 ) return 65 | 66 | for( let i = 1; i < list.length; i++ ){ 67 | let idToBe = i 68 | while( idToBe-1 >= 0 && list[idToBe] < list[idToBe-1] ){ 69 | [ list[idToBe-1], list[idToBe] ] = [ list[idToBe], list[idToBe-1] ] 70 | idToBe -= 1 71 | } 72 | } 73 | } 74 | 75 | // Test 76 | let list = [ 2, 1, 3, 4, 5, 6, 3, 5, 1 ] 77 | console.log("Original list: " + list) 78 | insertionSort(list) 79 | console.log("Insertion sort: " + list) 80 | ``` 81 | 82 | 83 | 84 | 85 | ## III. Bubble Sort 86 | 87 | - **BAD version:** 88 | 89 | - totally unsorted: O(n^2) 90 | 91 | - partially sorted: O(n^2) 92 | 93 | - ```js 94 | /* 95 | for each element, compare with its right element, swap if it's larger; 96 | keep doing util (n-1)th, (n-2)th,, (n-3)th ... 1st position 97 | - totally unsorted: O(n^2) 98 | - partially sorted: O(n^2) 99 | */ 100 | 101 | function bubbleSort(list){ 102 | if( list === null || list.length <= 1 ) return 103 | for( let i = list.length-1; i > 0; i-- ){ 104 | for( let k = 0; k < i; k++ ){ 105 | if( list[k] > list[k+1] ){ 106 | [ list[k], list[k+1] ] = [ list[k+1], list[k] ] 107 | } 108 | } 109 | } 110 | } 111 | 112 | 113 | // Test 114 | let list = [ 2, 1, 3, 4, 5, 6, 3, 5, 1 ] 115 | console.log("Original list: " + list) 116 | bubbleSort(list) 117 | console.log("Bubble sort: " + list) 118 | ``` 119 | 120 | - **Good Version** 121 | 122 | - totally unsorted: O(n^2) 123 | 124 | - partially sorted: O(n) **if no swap for a iteration, then every element is in its place, terminate** 125 | 126 | 127 | 128 | ```js 129 | /* 130 | for each element, compare with its right element, swap if it's larger; 131 | keep doing util (n-1)th, (n-2)th,, (n-3)th ... 1st position 132 | - totally unsorted: O(n^2) 133 | - partially sorted: O(n) 134 | - if no swap for a iteration, then every element is in its place, terminate 135 | */ 136 | 137 | function bubbleSort(list){ 138 | if( list === null || list.length <= 1 ) return 139 | let swapped = true 140 | for( let i = list.length-1; i > 0; i-- ){ 141 | if(swapped === false) return 142 | swapped = false 143 | for( let k = 0; k < i; k++ ){ 144 | if( list[k] > list[k+1] ){ 145 | [ list[k], list[k+1] ] = [ list[k+1], list[k] ] 146 | swapped = true 147 | } 148 | } 149 | } 150 | } 151 | 152 | // Test 153 | let list = [ 2, 1, 3, 4, 5, 6, 3, 5, 1 ] 154 | console.log("Original list: " + list) 155 | bubbleSort(list) 156 | console.log("Bubble sort: " + list) 157 | ``` 158 | 159 | 160 | ## VI. Merge Sort 161 | 162 | - Time Complexity 163 | 164 | - totally unsorted: O(n^2) 165 | - partially sorted: O(n) 166 | 167 | - Space Complexity: **cannot sort in-place** 168 | 169 | - O(n^2) 170 | 171 | - ```js 172 | /* 173 | recursively divide list into two half, till each half have one or two elements 174 | recursively merge two half into one, till achieve original size 175 | 176 | Time Complexity 177 | - totally unsorted: O(n^2) 178 | - partially sorted: O(n^2) 179 | Space Complexity: 180 | - O(n^2) 181 | */ 182 | 183 | function mergeSort(list){ 184 | if( list === null || list.length <= 1 ) return 185 | return divideAndMerge(list) 186 | } 187 | 188 | function divideAndMerge(list){ 189 | let l1 = list.slice(0, list.length/2) 190 | if( l1.length > 1 ) l1 = divideAndMerge(l1) 191 | 192 | let l2 = list.slice(list.length/2, list.length) 193 | if( l2.length > 1 ) l2 = divideAndMerge(l2) 194 | 195 | return merge(l1, l2) 196 | } 197 | 198 | function merge(l1, l2){ 199 | let list = [] 200 | let i = 0, j = 0, k = 0 201 | while(i < l1.length && j < l2.length){ 202 | if( l1[i] > l2[j] ) 203 | list[k++] = l2[j++] 204 | else 205 | list[k++] = l1[i++] 206 | } 207 | while( i < l1.length ) list[k++] = l1[i++] 208 | while( j < l2.length ) list[k++] = l2[j++] 209 | 210 | return list 211 | } 212 | 213 | // Test 214 | let list = [ 2, 1, 3, 4, 5, 6, 3, 5, 1 ] 215 | console.log("Original list: " + list) 216 | mergeSort(list) 217 | console.log("Merge sort: " + mergeSort(list)) 218 | ``` 219 | 220 | 221 | 222 | 223 | ## V. Quick Sort 224 | 225 | - **Time Complexity:** 226 | 227 | - totally unsorted: O(n^2) 228 | - partially sorted: O(n) 229 | 230 | - **Space Complexity:** O(n) **in-place** 231 | 232 | - **Approach:** 233 | 234 | - randomly choose a pivot, here we use the first element in the question list 235 | - loop from both ends, compare value with pivot, and swap their value 236 | - how to swap: **front & back two pointers** 237 | - "LeetCode: sort color": https://leetcode.com/problems/sort-colors/description/ 238 | 239 | - ```js 240 | /* 241 | 1. randomly choose a pivot, here we use the first element in the question list 242 | 2. loop from both ends, compare value with pivot, and swap their value 243 | 3. how to swap: "LeetCode: sort color" ==> "front & back two ponters" 244 | https://leetcode.com/problems/sort-colors/description/ 245 | 246 | 247 | 0......0 1......1 x1 x2 .... xm 2.....2 248 | ^ ^ ^ 249 | zero i two 250 | smallerToBe largerToBe 251 | 252 | 区间一:0 | 区间二:1 | 区间三:未知 | 区间四:2 253 | */ 254 | 255 | function quickSort(list, left, right){ 256 | if( list === null || left >= right ) return 257 | 258 | let pivot = list[left], 259 | smallerToBe = left, 260 | largerToBe = right, 261 | i = left 262 | 263 | while( i <= largerToBe ){ 264 | if( list[i] === pivot ){ 265 | i++ 266 | }else if( list[i] < pivot ){ 267 | swap(list, i++, smallerToBe++) 268 | }else{ 269 | swap(list, i, largerToBe--) 270 | } 271 | } 272 | quickSort(list, left, smallerToBe-1) 273 | quickSort(list, largerToBe+1, right) 274 | } 275 | 276 | function swap(list, p1, p2){ [ list[p1], list[p2] ] = [ list[p2], list[p1] ] } 277 | 278 | // Test 279 | let list = [ 3, 1, 3, 4, 5, 1, 3, 2, 5, 1 ] 280 | console.log("Original list: " + list) 281 | quickSort(list, 0, list.length-1) 282 | console.log("Quick sort: " + list) 283 | ``` 284 | -------------------------------------------------------------------------------- /Specifio-Work-Summary.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Specifio Work Summary 3 | comments: true 4 | date: 2018-08-23 20:04:05 5 | type: "categories" 6 | categories: 7 | - Portfolios 8 | tags: 9 | - ReactJS 10 | - Redux 11 | - Docker 12 | - PHP 13 | - Jenkins 14 | - Node.js 15 | - MongoDB 16 | - Express 17 | --- 18 | 19 | 20 | 21 | ## I. PHP legacy website to React 22 | 23 | #### 1. Current website (PHP) 24 | The company website in use is the old one at [https://specif.io/](https://specif.io/). 25 | Hopefully, Our new website will be put into use by October, 2018. 26 | 27 | #### 2. New website (React, Gatsby, Sass) 28 | The new website is currently on staging, but you can still visit it through this link: [https://publicdocker.specif.io/](https://publicdocker.specif.io/) 29 | 30 | **New features:** 31 | 32 | * Static webpage auto generating from Markdown file **(Gatsby.js)** 33 | * better layout & color scheme **(React)** 34 | * more user friendly 35 | * more intuitive 36 | * convey more information 37 | 38 | 39 | 40 | ## II. Admin Panel 41 | 42 | Developped Admin Panel for both internal and external use, with 3-level privileged access. 43 | 44 | ![Admin Panel](https://github.com/caomingkai/specifio_projects/raw/master/Admin%20Panel/docPlan.png) 45 | 46 | #### 1. Introduction: 47 | 1. With Specifio’s Doc Plans feature, practitioners can control how Specifio creates draft applications so they consistently meet the preferences and requirements of clients and reviewers. 48 | 49 | 2. A practitioner’s “active” Doc Plan controls the appearance, content, and structure of the auto-drafts created by Specifio. 50 | 51 | 3. Practitioners can design a collection of different Doc Plans for different clients, technologies, or reviewers. 52 | 53 | 4. Doc Plans can be shared among registered users within your firm. 54 | #### 2. Snapshots for key features 55 | 56 | - **Video: Live demo page for setting like layout, format and content of their Doc Plans** 57 | 58 | Doc Editor 60 | 61 | - **Dashboard** 62 | 63 | auth0 64 |
    65 | auth0 66 | 67 | - **Auth0 integration** 68 | 69 | auth0 70 | 71 | - **Manage doc plans** 72 | 73 | docPlan.png 74 | 75 | - **Manage profile** 76 | 77 | profile.png 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | -------------------------------------------------------------------------------- /Stack-Queue-Implementation-using-JS.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Stack & Queue Implementation using JS 3 | comments: true 4 | date: 2018-10-08 22:08:58 5 | type: categories 6 | categories: Algorithm 7 | tags: 8 | - Stack 9 | - Queue 10 | - ES6 Class 11 | - Data Structure 12 | --- 13 | 14 | 15 | 16 | ## Stack 17 | 18 | 1. interfaces: 19 | 20 | - `stack.size` 21 | - `stack.peek()` 22 | - `stack.push` 23 | - `stack.pop()` 24 | - `stack.isEmpty()` 25 | - `stack.clear()` 26 | 27 | 2. implementation: 28 | 29 | 1. ```js 30 | /* 31 | * Note: this version use `null` as Error symbol, 32 | * so you cannot push null into the stack 33 | */ 34 | class Stack{ 35 | constructor(){ this.data = [] } 36 | 37 | get size(){ return this.data.length } 38 | 39 | isEmpty(){ return this.data.length === 0 } 40 | 41 | peek(){ return this.data[this.data.length-1] } 42 | 43 | push(item){ 44 | if( typeof item ==="undefined" || item === null ) return false 45 | this.data.push(item) 46 | return true 47 | } 48 | 49 | pop(item){ 50 | if(this.data.length === 0) return null 51 | return this.data.pop(); 52 | } 53 | 54 | clear(){ this.data = [] } 55 | } 56 | 57 | /* ---- Testing ---- */ 58 | let s = new Stack() 59 | console.log("size: ",s.size) // 0 60 | console.log(s.pop()) // null 61 | console.log(s.push()) // false 62 | console.log(s.push(null)) // false 63 | console.log(s.push(1)) // true 64 | console.log(s.push(1)) // true 65 | console.log("size: ",s.size) // 2 66 | console.log(s.push(2)) // true 67 | console.log("size: ",s.size) // 3 68 | console.log(s.pop()) // 2 69 | console.log("size: ", s.size) // 2 70 | console.log(s.pop()) // 1 71 | console.log(s.pop()) // 1 72 | console.log("size: ", s.size) // 0 73 | console.log(s.pop()) // null 74 | console.log("size: ", s.size) // 0 75 | console.log(s.isEmpty()) // true 76 | ``` 77 | 78 | 79 | ## Queue 80 | 81 | 1. interfaces: 82 | 83 | - `queue.size` 84 | - `queue.peek()` 85 | - `queue.push` 86 | - `queue.pop()` 87 | - `queue.isEmpty()` 88 | - `queue.clear()` 89 | 90 | 2. implementation: 91 | 92 | 1. ```js 93 | /* 94 | * Note: this version can add any object into Queue 95 | * But need to call `isEmpty()` when necessary 96 | */ 97 | class Queue{ 98 | constructor(){ this.items = [] } 99 | 100 | get size(){ return this.items.length; } 101 | 102 | isEmpty(){ return this.items.length === 0 } 103 | 104 | offer(item){ this.items.push(item) } 105 | 106 | poll(){ return this.items.shift() } 107 | 108 | peek(){ return this.items[0] } 109 | 110 | clear(){ this.items = [] } 111 | } 112 | 113 | /* ---- Testing ---- */ 114 | let q = new Queue() 115 | console.log("size: ", q.size)// 0 116 | console.log(q.offer(null)) 117 | console.log(q.offer(null)) 118 | console.log(q.items) // [null, null] 119 | console.log(q.offer(1)) 120 | console.log(q.items) // [null, null, 1] 121 | console.log(q.poll()) // null 122 | console.log(q.offer(2)) // [null, 1, 2] 123 | console.log("size: ",q.size)// 3 124 | console.log(q.poll()) 125 | console.log(q.items) // [1, 2] 126 | console.log(q.poll()) // 1 127 | console.log(q.items) // [2] 128 | console.log("size: ", q.size)// 1 129 | console.log(q.poll()) // 2 130 | console.log("size: ", q.size)// 0 131 | console.log(q.isEmpty()) // true 132 | ``` 133 | -------------------------------------------------------------------------------- /Tiny-URL.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Tiny URL 3 | date: 2018-03-28 11:14:49 4 | type: "categories" 5 | comments: true 6 | categories: 7 | - Portfolios 8 | tags: 9 | - AngularJS 10 | - Node.js 11 | - MongoDB 12 | - Express 13 | --- 14 | 15 | ## I. Introduction 16 | A MEAN stack Single Page Application, providing: 17 | 18 | 1. URL shortening service 19 | 2. Traffic statistics collecting service 20 | 21 | Tech stacks: **AngularJS, Node.js, Express, MongoDB, Redis, Nginx, Docker** 22 | 23 | Github: https://github.com/caomingkai/URL-shortening-service 24 | 25 | 26 | {% asset_img tinyURL.png This is an image %} 27 | 28 | 29 | 30 | ## II. Work flow 31 | #### 1. Users come to the app webpage 32 | 33 | - Browser send GET request with original URL to server 34 | - Server sends index.html to clients 35 | - Browser get the index.html with script in the head tag. 36 | `