commit
2182a70770
@ -0,0 +1,11 @@
|
||||
root = true
|
||||
|
||||
[*]
|
||||
end_of_line = lf
|
||||
insert_final_newline = true
|
||||
trim_trailing_whitespace = true
|
||||
|
||||
[*.{js,py}]
|
||||
charset = utf-8
|
||||
indent_style = space
|
||||
indent_size = 4
|
@ -0,0 +1,32 @@
|
||||
# Tech Interview Handbook
|
||||
|
||||
Handbook to help you ace your next technical interview, with a focus on algorithms and the front end domain. System design questions are in-progress.
|
||||
|
||||
This handbook is pretty new and help from you in contributing content would be very much appreciated!
|
||||
|
||||
## Motivations
|
||||
|
||||
While there are many awesome books like [Cracking the Coding Interview](http://www.crackingthecodinginterview.com/) and interview-related repositories on Github that contain a lot of algorithm questions, for more domain-specific and non-software engineering questions, there seems to be a lack in resources. This handbook aims to cover questions beyond the algorithm coding questions.
|
||||
|
||||
## Contents
|
||||
|
||||
- **[Algorithms Questions](algorithms)**
|
||||
- Questions categorized by topic.
|
||||
- **[Design Questions](design)**
|
||||
- **[Domain-specific Questions](domain)**
|
||||
- **[Front End Study Notes](front-end)**
|
||||
- Summarized notes on the various aspects of front end.
|
||||
- [Front End Job Interview Questions and Answers](front-end/interview-questions.md) ⭐
|
||||
- **[Non-Technical Tips](non-technical)**
|
||||
- Random non-technical tips that cover behavioral and psychological aspects, interview formats and "Do you have any questions for me?".
|
||||
- [Behavioral Questions](non-technical/behavioral.md)
|
||||
- [Interview Formats](non-technical/format.md)
|
||||
- [Psychological Tricks](non-technical/psychological.md)
|
||||
- [Questions to Ask](non-technical/questions-to-ask.md)
|
||||
- [Negotiation Tips](non-technical/negotiation.md)
|
||||
- **[Utilities](utilities)**
|
||||
- Snippets of algorithms/code that will help in coding questions.
|
||||
|
||||
## Contributing
|
||||
|
||||
There are no hard contributing guidelines at the moment as things are still in flux, might find a better approach to structure content, but we will figure out as we go along! Just contribute whatever that you think will help others. If you would like to contribute content for different domains, feel free to create an issue or submit a pull request and we can discuss further.
|
@ -0,0 +1,27 @@
|
||||
Dynamic Programming
|
||||
==
|
||||
|
||||
- Given a flight itinerary consisting of starting city, destination city, and ticket price (2D list) - find the optimal price flight path to get from start to destination. (A variation of Dynamic Programming Shortest Path)
|
||||
- Given some coin denominations and a target value `M`, return the coins combination with the minimum number of coins.
|
||||
- Time complexity: `O(MN)`, where N is the number of distinct type of coins.
|
||||
- Space complexity: `O(M)`.
|
||||
- Given a set of numbers in an array which represent number of consecutive days of AirBnb reservation requested, as a host, pick the sequence which maximizes the number of days of occupancy, at the same time, leaving at least a 1 day gap in-between bookings for cleaning.
|
||||
- Problem reduces to finding the maximum sum of non-consecutive array elements.
|
||||
- E.g.
|
||||
~~~
|
||||
// [5, 1, 1, 5] => 10
|
||||
The above array would represent an example booking period as follows -
|
||||
// Dec 1 - 5
|
||||
// Dec 5 - 6
|
||||
// Dec 6 - 7
|
||||
// Dec 7 - 12
|
||||
|
||||
The answer would be to pick Dec 1-5 (5 days) and then pick Dec 7-12 for a total of 10 days of occupancy, at the same time, leaving at least 1 day gap for cleaning between reservations.
|
||||
|
||||
Similarly,
|
||||
// [3, 6, 4] => 7
|
||||
// [4, 10, 3, 1, 5] => 15
|
||||
~~~
|
||||
- How many string representations are there for an integer where `a->1, b->2, ... z->26`.
|
||||
- E.g. `26 => 2`. Because `26` can be encoded as `"z"` and `"bf"`.
|
||||
- Given a list of denominations (e.g., `[1, 2, 5]` means you have coins worth $1, $2, and $5) and a target number `k`, find all possible combinations, if any, of coins in the given denominations that add up to `k`. You can use coins of the same denomination more than once.
|
@ -0,0 +1,7 @@
|
||||
Geometry
|
||||
==
|
||||
|
||||
- You have a plane with lots of rectangles on it, find out how many of them intersect.
|
||||
- Which data structure would you use to query the k-nearest points of a set on a 2D plane?
|
||||
- Given many points, find k points that are closest to the origin.
|
||||
- How would you triangulate a polygon?
|
@ -0,0 +1,7 @@
|
||||
Hash Table
|
||||
==
|
||||
|
||||
- Describe an implementation of a least-used cache, and big-O notation of it.
|
||||
- A question involving an API's integration with hash map where the buckets of hash map are made up of linked lists.
|
||||
- Implement data structure `Map` storing pairs of integers (key, value) and define following member functions in O(1) runtime: `void insert(key, value)`, `void delete(key)`, `int get(key)`, `int getRandomKey()`.
|
||||
- [Source](http://blog.gainlo.co/index.php/2016/08/14/uber-interview-question-map-implementation/).
|
@ -0,0 +1,5 @@
|
||||
Heap
|
||||
==
|
||||
|
||||
- Merge `K` sorted lists together into a single list.
|
||||
- Given a stream of integers, write an efficient function that returns the median value of the integers.
|
@ -0,0 +1,28 @@
|
||||
Interval
|
||||
==
|
||||
|
||||
- Given a list of schedules, provide a list of times that are available for a meeting.
|
||||
```
|
||||
[
|
||||
[[4,5], [6,10], [12,14]],
|
||||
[[4,5], [5,9], [13,16]],
|
||||
[[11,14]]
|
||||
]
|
||||
|
||||
Example Output:
|
||||
[[0,4], [11,12], [16,23]]
|
||||
```
|
||||
- You have a number of meetings (with their start and end times). You need to schedule them using the minimum number of rooms. Return the list of meetings in every room.
|
||||
- Interval ranges:
|
||||
- Given 2 interval ranges, create a function to tell me if these ranges intersect. Both start and end are inclusive: `[start, end]`
|
||||
- E.g. `[1, 4]` and `[5, 6]` => `false`
|
||||
- E.g. `[1, 4]` and `[3, 6]` => `true`
|
||||
- Given 2 interval ranges that intersect, now create a function to merge the 2 ranges into a single continuous range.
|
||||
- E.g. `[1, 4]` and `[3, 6]` => `[1, 6]`
|
||||
- Now create a function that takes a group of unsorted, unorganized intervals, merge any intervals that intersect and sort them. The result should be a group of sorted, non-intersecting intervals.
|
||||
- Now create a function to merge a new interval into a group of sorted, non-intersecting intervals. After the merge, all intervals should remain
|
||||
non-intersecting.
|
||||
- Given a list of meeting times, check if any of them overlap. The follow-up question is to return the minimum number of rooms required to accommodate all the meetings.
|
||||
- [Source](http://blog.gainlo.co/index.php/2016/07/12/meeting-room-scheduling-problem/)
|
||||
- If you have a list of intervals, how would you merge them?
|
||||
- E.g. `[1, 3], [8, 11], [2, 6]` => `[1, 6], [8-11]`
|
@ -0,0 +1,13 @@
|
||||
Linked List
|
||||
==
|
||||
|
||||
- Given a linked list, in addition to the next pointer, each node has a child pointer that can point to a separate list. With the head node, flatten the list to a single-level linked list.
|
||||
- [Source](http://blog.gainlo.co/index.php/2016/06/12/flatten-a-linked-list/)
|
||||
- Reverse a singly linked list. Implement it recursively and iteratively.
|
||||
- Convert a binary tree to a doubly circular linked list.
|
||||
- Implement an LRU cache with O(1) runtime for all its operations.
|
||||
- Check distance between values in linked list.
|
||||
- A question involving an API's integration with hash map where the buckets of hash map are made up of linked lists.
|
||||
- Given a singly linked list (a list which can only be traversed in one direction), find the item that is located at 'k' items from the end. So if the list is a, b, c, d and k is 2 then the answer is 'c'. The solution should not search the list twice.
|
||||
- How can you tell if a Linked List is a Palindrome?
|
||||
- Implement a LRU cache with O(1) runtime for all its operations.
|
@ -0,0 +1,20 @@
|
||||
Math
|
||||
==
|
||||
|
||||
- Create a square root function.
|
||||
- Given a string such as "123" or "67", write a function to output the number represented by the string without using casting.
|
||||
- Make a program that can print out the text form of numbers from 1 - 1000 (ex. 20 is "twenty", 105 is "one hundred and five").
|
||||
- Write a function that parses Roman numerals.
|
||||
- E.g. `XIV` returns `14`.
|
||||
- Write in words for a given digit.
|
||||
- E.g. `123` returns `one hundred and twenty three`.
|
||||
- Given a number `N`, find the largest number just smaller than `N` that can be formed using the same digits as `N`.
|
||||
- Compute the square root of `N` without using any existing functions.
|
||||
- Given numbers represented as binary strings, and return the string containing their sum.
|
||||
- E.g. `add('10010', '101')` returns `'10111'`.
|
||||
- Take in an integer and return its english word-format.
|
||||
- E.g. 1 -> "one", -10,203 -> "negative ten thousand two hundred and three".
|
||||
- Write a function that returns values randomly, according to their weight. Suppose we have 3 elements with their weights: A (1), B (1) and C (2). The function should return A with probability 25%, B with 25% and C with 50% based on the weights.
|
||||
- [Source](http://blog.gainlo.co/index.php/2016/11/11/uber-interview-question-weighted-random-numbers/)
|
||||
- Given a number, how can you get the next greater number with the same set of digits?
|
||||
- [Source](http://blog.gainlo.co/index.php/2017/01/20/arrange-given-numbers-to-form-the-biggest-number-possible/)
|
@ -0,0 +1,18 @@
|
||||
Matrix
|
||||
==
|
||||
|
||||
- You're given a 3 x 3 board of a tile puzzle, with 8 tiles numbered 1 to 8, and an empty spot. You can move any tile adjacent to the empty spot, to the empty spot, creating an empty spot where the tile originally was. The goal is to find a series of moves that will solve the board, i.e. get `[[1, 2, 3], [4, 5, 6], [7, 8, - ]]` where - is the empty tile.
|
||||
- Boggle implementation. Given a dictionary, and a matrix of letters, find all the words in the matrix that are in the dictionary. You can go across, down or diagonally.
|
||||
- The values of the matrix will represent numbers of carrots available to the rabbit in each square of the garden. If the garden does not have an exact center, the rabbit should start in the square closest to the center with the highest carrot count. On a given turn, the rabbit will eat the carrots available on the square that it is on, and then move up, down, left, or right, choosing the the square that has the most carrots. If there are no carrots left on any of the adjacent squares, the rabbit will go to sleep. You may assume that the rabbit will never have to choose between two squares with the same number of carrots. Write a function which takes a garden matrix and returns the number of carrots the rabbit eats. You may assume the matrix is rectangular with at least 1 row and 1 column, and that it is populated with non-negative integers. For example,
|
||||
- Example: `[[5, 7, 8, 6, 3], [0, 0, 7, 0, 4], [4, 6, 3, 4, 9], [3, 1, 0, 5, 8]]` should return `27`.
|
||||
- Print a matrix in a spiral fashion.
|
||||
- In the Game of life, calculate how to compute the next state of the board. Follow up was to do it if there were memory constraints (board represented by a 1 TB file).
|
||||
- Grid Illumination: Given an NxN grid with an array of lamp coordinates. Each lamp provides illumination to every square on their x axis, every square on their y axis, and every square that lies in their diagonal (think of a Queen in chess). Given an array of query coordinates, determine whether that point is illuminated or not. The catch is when checking a query all lamps adjacent to, or on, that query get turned off. The ranges for the variables/arrays were about: 10^3 < N < 10^9, 10^3 < lamps < 10^9, 10^3 < queries < 10^9.
|
||||
- You are given a matrix of integers. Modify the matrix such that if a row or column contains a 0, make the values in the entire row or column 0.
|
||||
- Given an N x N matrix filled randomly with different colors (no limit on what the colors are), find the total number of groups of each color - a group consists of adjacent cells of the same color touching each other.
|
||||
- You have a 4 x 4 board with characters. You need to write a function that finds if a certain word exists in the board. You can only jump to neighboring characters (including diagonally adjacent).
|
||||
- Count the number of islands in a binary matrix of 0's and 1's.
|
||||
- Check a 6 x 7 Connect 4 board for a winning condition.
|
||||
- Given a fully-filled Sudoku board, check whether fulfills the Sudoku condition.
|
||||
- Implement a function that checks if a player has won tic-tac-toe.
|
||||
- Given an N x N matrix of 1's and 0's, figure out if all of the 1's are connected.
|
@ -0,0 +1,4 @@
|
||||
Object-Oriented Programming
|
||||
==
|
||||
|
||||
- How would you design a chess game? What classes and objects would you use? What methods would they have?
|
@ -0,0 +1,12 @@
|
||||
Permutation
|
||||
==
|
||||
|
||||
- You are given a 7 digit phone number, and you should find all possible letter combinations based on the digit-to-letter mapping on numeric pad and return only the ones that have valid match against a given dictionary of words.
|
||||
- Give all possible letter combinations from a phone number.
|
||||
- Generate all subsets of a string.
|
||||
- Print all possible `N` pairs of balanced parentheses.
|
||||
- E.g. when `N` is `2`, the function should print `(())` and `()()`.
|
||||
- E.g. when `N` is `3`, we should get `((()))`, `(()())`, `(())()`, `()(())`, `()()()`.
|
||||
- [Source](http://blog.gainlo.co/index.php/2016/12/23/uber-interview-questions-permutations-parentheses/)
|
||||
- Given a list of arrays, return a list of arrays, where each array is a combination of one element in each given array.
|
||||
- E.g. If the input is `[[1, 2, 3], [4], [5, 6]]`, the output should be `[[1, 4, 5], [1, 4, 6], [2, 4, 5], [2, 4, 6], [3, 4, 5], [3, 4, 6]]`.
|
@ -0,0 +1,4 @@
|
||||
Queue
|
||||
==
|
||||
|
||||
- Implement a Queue class from scratch with an existing bug, the bug is that it cannot take more than 5 elements.
|
@ -0,0 +1,18 @@
|
||||
Sorting and Searching
|
||||
==
|
||||
|
||||
- Sorting search results on a page given a certain set of criteria.
|
||||
- Sort a list of numbers in which each number is at a distance `K` from its actual position.
|
||||
- Given an array of integers, sort the array so that all odd indexes are greater than the even indexes.
|
||||
- Given users with locations in a list and a logged-in user with locations, find their travel buddies (people who shared more than half of your locations).
|
||||
- Search for an element in a sorted and rotated array.
|
||||
- [Source](http://blog.gainlo.co/index.php/2017/01/12/rotated-array-binary-search/)
|
||||
- Sort a list where each element is no more than k positions away from its sorted position.
|
||||
- If you have `N` revisions of a program, write a program that will find and return the first bad revision given a `isBad(revision i)` function.
|
||||
- Search for an item in a sorted, but rotated, array.
|
||||
- Merge two sorted lists together.
|
||||
- Given a list of numbers and a function that returns Low, Medium, or High, sort the list by Lows, then Mediums, then Highs.
|
||||
- Give 3 distinct algorithms to find the K largest values in a list of N items.
|
||||
- Find the minimum element in a sorted rotated array in faster than O(n) time.
|
||||
- Write a function that takes a number as input and outputs the biggest number with the same set of digits.
|
||||
- [Source](http://blog.gainlo.co/index.php/2017/01/20/arrange-given-numbers-to-form-the-biggest-number-possible/)
|
@ -0,0 +1,8 @@
|
||||
Stack
|
||||
==
|
||||
|
||||
- Implementation of an interpreter for a small language that does multiplication/addition/etc.
|
||||
- Design a `MinStack` data structure that supports a `min()` operation that returns the minimum value in the stack in O(1) time.
|
||||
- Write an algorithm to determine if all of the delimiters in an expression are matched and closed.
|
||||
- E.g. `{ac[bb]}`, `[dklf(df(kl))d]{}` and `{[[[]]]}` are matched. But `{3234[fd` and `{df][d}` are not.
|
||||
- [Source](http://blog.gainlo.co/index.php/2016/09/30/uber-interview-question-delimiter-matching/)
|
@ -0,0 +1,61 @@
|
||||
String
|
||||
==
|
||||
|
||||
- Output list of strings representing a page of hostings given a list of CSV strings.
|
||||
- Given a list of words, find the word pairs that when concatenated form a palindrome.
|
||||
- Find the most efficient way to identify what character is out of place in a non-palindrome.
|
||||
- Implement a simple regex parser which, given a string and a pattern, returns a boolean indicating whether the input matches the pattern. By simple, we mean that the regex can only contain special character: `*` (star), `.` (dot), `+` (plus). The star means that there will be zero or more of previous character in that place in the pattern. The dot means any character for that position. The plus means one or more of previous character in that place in the pattern.
|
||||
- Find all words from a dictionary that are x edit distance away.
|
||||
- Given a string IP and number n, print all CIDR addresses that cover that range.
|
||||
- Write a function called `eval`, which takes a string and returns a boolean. This string is allowed 6 different characters: `0`, `1`, `&`, `|`, `(`, and `)`. `eval` should evaluate the string as a boolean expression, where `0` is `false`, `1` is `true`, `&` is an `and`, and `|` is an `or`.
|
||||
- E.g `"(0 | (1 | 0)) & (1 & ((1 | 0) & 0))"`
|
||||
- Given a pattern string like `"abba"` and an input string like `"redbluebluered"`, return `true` if and only if there's a one to one mapping of letters in the pattern to substrings of the input.
|
||||
- E.g. `"abba"` and `"redblueredblue"` should return `true`.
|
||||
- E.g. `"aaaa"` and `"asdasdasdasd"` should return `true`.
|
||||
- E.g. `"aabb"` and `"xyzabcxzyabc"` should return `false`.
|
||||
- If you received a file in chunks, calculate when you have the full file. Quite an open-ended question. Can assume chunks come with start and end, or size, etc.
|
||||
- Given a list of names (strings) and the width of a line, design an algorithm to display them using the minimum number of lines.
|
||||
- Design a spell-checking algorithm.
|
||||
- Count and say problem.
|
||||
- Longest substring with `K` unique characters.
|
||||
- [Source](http://blog.gainlo.co/index.php/2016/04/12/find-the-longest-substring-with-k-unique-characters/)
|
||||
- Given a set of random strings, write a function that returns a set that groups all the anagrams together.
|
||||
- [Source](http://blog.gainlo.co/index.php/2016/05/06/group-anagrams/)
|
||||
- Given a string, find the longest substring without repeating characters. For example, for string `'abccdefgh'`, the longest substring is `'cdefgh'`.
|
||||
- [Source](http://blog.gainlo.co/index.php/2016/10/07/facebook-interview-longest-substring-without-repeating-characters/)
|
||||
- Given a string, return the string with duplicate characters removed.
|
||||
- How many string representations are there for an integer where `a->1, b->2, ... z->26`.
|
||||
- E.g. `126` can be `'az'` or `'abf'`.
|
||||
- Write a function that receives a regular expression (allowed chars = from `'a'` to `'z'`, `'*'`, `'.'`) and a string containing lower case english alphabet characters and return `true` or `false` whether the string matches the regex.
|
||||
- E.g. `'ab*a'`, `'abbbbba'` => `true`.
|
||||
- E.g. `'ab*b.'`, `'aba'` => `true`.
|
||||
- E.g. `'abc*'`, `'acccc'` => `false`.
|
||||
- Given a rectangular grid with letters, search if some word is in the grid.
|
||||
- Given two strings representing integer numbers (`'123'` , `'30'`) return a string representing the sum of the two numbers: `'153'`.
|
||||
- Given a really big file with a lots of Facebook posts, find the ten most-used words.
|
||||
- A professor wants to see if two students have cheated when writing a paper. Design a function `hasCheated(String s1, String s2, int N)` that evaluates to `true` if two strings have a common substring of length `N`.
|
||||
- Follow up: Assume you don't have the possibility of using `String.contains()` and `String.substring()`. How would you implement this?
|
||||
- Print all permutations of a given string.
|
||||
- Parse a string containing numbers and `'+'`, `'-'` and parentheses. Evaluate the expression. `-2+(3-5)` should return `-4`.
|
||||
- Output a substring with at most `K` unique characters.
|
||||
- E.g. `'aabc'` and `k` = 2 => `'aab'`.
|
||||
- Ensure that there are a minimum of `N` dashes between any two of the same characters of a string.
|
||||
- E.g. `n = 2, string = 'ab-bcdecca'` => `'ab--bcdec--ca'`.
|
||||
- Find the longest palindrome in a string.
|
||||
- Give the count and the number following in the series.
|
||||
- E.g. `1122344`, next: `21221324`, next: `12112211121214`.
|
||||
- Count and say problem.
|
||||
- Compress a string by grouping consecutive similar questions together:
|
||||
- E.g. `'aaabbbcc' => `'a3b3c2'`.
|
||||
- You have a string consisting of open and closed parentheses, but parentheses may be imbalanced. Make the parentheses balanced and return the new string.
|
||||
- Given a set of strings, return the smallest subset that contains prefixes for every string.
|
||||
- E.g. `['foo', 'foog', 'food', 'asdf']` => `['foo', 'asdf']`.
|
||||
- Write a function that would return all the possible words generated when using a phone (pre-smartphone era) numpad to type.
|
||||
- Given a dictionary and a word, find the minimum number of deletions needed on the word in order to make it a valid word.
|
||||
- [Source](http://blog.gainlo.co/index.php/2016/04/29/minimum-number-of-deletions-of-a-string/)
|
||||
- How to check if a string contains an anagram of another string?
|
||||
- [Source](http://blog.gainlo.co/index.php/2016/04/08/if-a-string-contains-an-anagram-of-another-string/)
|
||||
- Find all k-lettered words from a string.
|
||||
- Given a string of open and close parentheses, find the minimum number of edits needed to balance a string of parentheses.
|
||||
- Run length encoding - Write a string compress function that returns `'R2G1B1'` given `'RRGB'`.
|
||||
- Write a function that finds all the different ways you can split up a word into a concatenation of two other words.
|
@ -0,0 +1,89 @@
|
||||
Topics
|
||||
==
|
||||
|
||||
## Arrays
|
||||
|
||||
## Strings
|
||||
|
||||
- Prefix trees (Tries)
|
||||
- Suffix trees
|
||||
- Suffix arrays
|
||||
- KMP
|
||||
- Rabin-Karp
|
||||
- Boyer-Moore
|
||||
|
||||
## Sorting
|
||||
|
||||
- Bubble sort
|
||||
- Insertion sort
|
||||
- Merge sort
|
||||
- Quick sort
|
||||
- Selection sort
|
||||
- Bucket sort
|
||||
- Radix sort
|
||||
- Counting sort
|
||||
|
||||
## Linked Lists
|
||||
|
||||
## Stacks
|
||||
|
||||
## Queues
|
||||
|
||||
## Hash tables
|
||||
|
||||
- Collision resolution algorithms
|
||||
|
||||
## Trees
|
||||
|
||||
- BFS
|
||||
- DFS (inorder, postorder, preorder)
|
||||
- Height
|
||||
|
||||
## Binary Search Trees
|
||||
|
||||
- Insert node
|
||||
- Delete a node
|
||||
- Find element in BST
|
||||
- Find min, max element in BST
|
||||
- Get successor element in tree
|
||||
- Check if a binary tree is a BST or not
|
||||
|
||||
## Heaps / Priority Queues
|
||||
|
||||
- Insert
|
||||
- Bubble up
|
||||
- Extract max
|
||||
- Remove
|
||||
- Heapify
|
||||
- Heap sort
|
||||
|
||||
## Graphs
|
||||
|
||||
- Various implementations
|
||||
- Adjacency matrix
|
||||
- Adjacency list
|
||||
- Adjacency map
|
||||
- Single-source shortest path
|
||||
- Dijkstra
|
||||
- Bellman-Ford
|
||||
- Topo sort
|
||||
- MST
|
||||
- Prim algorithm
|
||||
- Kruskal's algorithm
|
||||
- Union Find Data Structure
|
||||
- Count connected components in a graph
|
||||
- List strongly connected components in a graph
|
||||
- Check for bipartite graph
|
||||
|
||||
## Dynamic Programming
|
||||
|
||||
- Count Change
|
||||
- 0-1 Knapsack
|
||||
|
||||
## System Design
|
||||
|
||||
- http://www.hiredintech.com/system-design/
|
||||
- https://www.quora.com/How-do-I-prepare-to-answer-design-questions-in-a-technical-interview?redirected_qid=1500023
|
||||
- http://blog.gainlo.co/index.php/2015/10/22/8-things-you-need-to-know-before-system-design-interviews/
|
||||
- https://github.com/donnemartin/system-design-primer
|
||||
- https://github.com/jwasham/coding-interview-university/blob/master/extras/cheat%20sheets/system-design.pdf
|
@ -0,0 +1,37 @@
|
||||
Tree
|
||||
==
|
||||
|
||||
- Find the height of a tree.
|
||||
- Find the longest path from the root to leaf in a tree.
|
||||
- Find the deepest left leaf of a tree.
|
||||
- Print all paths of a binary tree.
|
||||
- [Source](http://blog.gainlo.co/index.php/2016/04/15/print-all-paths-of-a-binary-tree/)
|
||||
- Second largest element of a BST.
|
||||
- [Source](http://blog.gainlo.co/index.php/2016/06/03/second-largest-element-of-a-binary-search-tree/)
|
||||
- Given a binary tree and two nodes, how to find the common ancestor of the two nodes?
|
||||
- [Source](http://blog.gainlo.co/index.php/2016/07/06/lowest-common-ancestor/)
|
||||
- Find the lowest common ancestor of two nodes in a binary search tree.
|
||||
- Print the nodes in an n-ary tree level by level, one printed line per level.
|
||||
- Given a directory of files and folders (and relevant functions), how would you parse through it to find equivalent files?
|
||||
- Write a basic file system and implement the commands ls, pwd, mkdir, create, rm, cd, cat, mv.
|
||||
- Compute the intersection of two binary search trees.
|
||||
- Given a tree, where the parent has any number of nodes and each node has a number, return the average of all the nodes on each level in an array.
|
||||
- Given a binary tree, output all the node to leaf paths of it.
|
||||
- Given a string of characters without spaces, is there a way to break the string into valid words without leftover characters?
|
||||
- Print a binary tree level by level.
|
||||
- Determine if a binary tree is "complete" (i.e, if all leaf nodes were either at the maximum depth or max depth-1, and were 'pressed' along the left side of the tree).
|
||||
- Find the longest path in a binary tree. The path may start and end at any node.
|
||||
- Determine if a binary tree is a BST.
|
||||
- Given a binary tree, serialize it into a string. Then deserialize it.
|
||||
- Print a binary tree by column.
|
||||
- Given a node, find the next element in a BST.
|
||||
- Find the shortest subtree that consist of all the deepest nodes. The tree is not binary.
|
||||
- Print out the sum of each row in a binary tree.
|
||||
- Pretty print a JSON object.
|
||||
- Convert a binary tree to a doubly circular linked list.
|
||||
- Find the second largest number in a binary tree.
|
||||
- Given a tree, find the longest branch.
|
||||
- Convert a tree to a linked list.
|
||||
- Given two trees, write code to find out if tree A is a subtree of tree B.
|
||||
- Deepest node in a tree.
|
||||
- [Source](http://blog.gainlo.co/index.php/2016/04/26/deepest-node-in-a-tree/)
|
@ -0,0 +1,94 @@
|
||||
Design Questions
|
||||
==
|
||||
|
||||
## Guides
|
||||
|
||||
- https://github.com/donnemartin/system-design-primer
|
||||
- https://github.com/checkcheckzz/system-design-interview
|
||||
- https://github.com/shashank88/system_design
|
||||
- https://gist.github.com/vasanthk/485d1c25737e8e72759f
|
||||
- http://www.puncsky.com/blog/2016/02/14/crack-the-system-design-interview/
|
||||
- https://www.palantir.com/2011/10/how-to-rock-a-systems-design-interview/
|
||||
- http://blog.gainlo.co/index.php/2017/04/13/system-design-interviews-part-ii-complete-guide-google-interview-preparation/
|
||||
|
||||
## Flow
|
||||
|
||||
#### A. Understand the problem and scope
|
||||
|
||||
- Define the use cases, with interviewer's help.
|
||||
- Suggest additional features.
|
||||
- Remove items that interviewer deems out of scope.
|
||||
- Assume high availability is required, add as a use case.
|
||||
|
||||
#### B. Think about constraints
|
||||
|
||||
- Ask how many requests per month.
|
||||
- Ask how many requests per second (they may volunteer it or make you do the math).
|
||||
- Estimate reads vs. writes percentage.
|
||||
- Keep 80/20 rule in mind when estimating.
|
||||
- How much data written per second.
|
||||
- Total storage required over 5 years.
|
||||
- How much data reads per second.
|
||||
|
||||
#### C. Abstract design
|
||||
|
||||
- Layers (service, data, caching).
|
||||
- Infrastructure: load balancing, messaging.
|
||||
- Rough overview of any key algorithm that drives the service.
|
||||
- Consider bottlenecks and determine solutions.
|
||||
|
||||
Source: https://github.com/jwasham/coding-interview-university#system-design-scalability-data-handling
|
||||
|
||||
## Grading Rubrics
|
||||
|
||||
- Problem Solving - How systematic is your approach to solving the problem step-by-step? Break down a problem into its core components.
|
||||
- Communication - How well do you explain your idea and communicate it with others?
|
||||
- Evaluation - How do you evaluate your system? Are you aware of the trade-offs made? How can you optimize it?
|
||||
- Estimation - How fast does your system need to be? How much space does it need? How much load will it experience?
|
||||
|
||||
## Specific Topics
|
||||
|
||||
- URL Shortener
|
||||
- http://stackoverflow.com/questions/742013/how-to-code-a-url-shortener
|
||||
- http://blog.gainlo.co/index.php/2016/03/08/system-design-interview-question-create-tinyurl-system/
|
||||
- https://www.interviewcake.com/question/python/url-shortener
|
||||
- Collaborative Editor
|
||||
- http://blog.gainlo.co/index.php/2016/03/22/system-design-interview-question-how-to-design-google-docs/
|
||||
- Photo Sharing App
|
||||
- http://blog.gainlo.co/index.php/2016/03/01/system-design-interview-question-create-a-photo-sharing-app/
|
||||
- Social Network Feed
|
||||
- http://blog.gainlo.co/index.php/2016/02/17/system-design-interview-question-how-to-design-twitter-part-1/
|
||||
- http://blog.gainlo.co/index.php/2016/02/24/system-design-interview-question-how-to-design-twitter-part-2/
|
||||
- http://blog.gainlo.co/index.php/2016/03/29/design-news-feed-system-part-1-system-design-interview-questions/
|
||||
- Trending Algorithm
|
||||
- http://blog.gainlo.co/index.php/2016/05/03/how-to-design-a-trending-algorithm-for-twitter/
|
||||
- Facebook Chat
|
||||
- http://blog.gainlo.co/index.php/2016/04/19/design-facebook-chat-function/
|
||||
- Key Value Store
|
||||
- http://blog.gainlo.co/index.php/2016/06/14/design-a-key-value-store-part-i/
|
||||
- http://blog.gainlo.co/index.php/2016/06/21/design-key-value-store-part-ii/
|
||||
- Recommendation System
|
||||
- http://blog.gainlo.co/index.php/2016/05/24/design-a-recommendation-system/
|
||||
- Cache System
|
||||
- http://blog.gainlo.co/index.php/2016/05/17/design-a-cache-system/
|
||||
- E-commerce Website
|
||||
- http://blog.gainlo.co/index.php/2016/08/22/design-ecommerce-website-part/
|
||||
- http://blog.gainlo.co/index.php/2016/08/28/design-ecommerce-website-part-ii/
|
||||
- Web Crawler
|
||||
- http://blog.gainlo.co/index.php/2016/06/29/build-web-crawler/
|
||||
- http://www.makeuseof.com/tag/how-do-search-engines-work-makeuseof-explains/
|
||||
- https://www.quora.com/How-can-I-build-a-web-crawler-from-scratch/answer/Chris-Heller
|
||||
- YouTube
|
||||
- http://blog.gainlo.co/index.php/2016/10/22/design-youtube-part/
|
||||
- http://blog.gainlo.co/index.php/2016/11/04/design-youtube-part-ii/
|
||||
- Hit Counter
|
||||
- http://blog.gainlo.co/index.php/2016/09/12/dropbox-interview-design-hit-counter/
|
||||
- Facebook Graph Search
|
||||
- Design [Lyft Line](https://www.lyft.com/line).
|
||||
- Design a promo code system (with same promo code, randomly generated promo code, and promo code with conditions).
|
||||
- Model a university.
|
||||
- How would you implement Pacman?
|
||||
- Sketch out an implementation of Asteroids.
|
||||
- Implement a spell checker.
|
||||
- Design the rubik cube.
|
||||
- Design a high-level interface to be used for card games (e.g. poker, blackjack etc).
|
@ -0,0 +1,108 @@
|
||||
Collaborative Document Editor
|
||||
==
|
||||
|
||||
## Variants
|
||||
|
||||
- Design Google docs.
|
||||
- Design a collaborative code editor like Coderpad/Codepile.
|
||||
- Design a collaborative markdown editor.
|
||||
|
||||
## Requirements Gathering
|
||||
|
||||
- What is the intended platform?
|
||||
- Web
|
||||
- What features are required?
|
||||
- Creating a document
|
||||
- Editing a document
|
||||
- Sharing a document
|
||||
- Bonus features
|
||||
- Document revisions and reverting
|
||||
- Searching
|
||||
- Commenting
|
||||
- Chatting
|
||||
- Executing code (in the case of code editor)
|
||||
- What is in a document?
|
||||
- Text
|
||||
- Images
|
||||
- Which metrics should we optimize for?
|
||||
- Loading time
|
||||
- Synchronization
|
||||
- Throughput
|
||||
|
||||
## Core Components
|
||||
|
||||
- Front end
|
||||
- WebSockets/long polling for real-time communication between front end and back end.
|
||||
- Back end services behind a reverse proxy.
|
||||
- Reverse proxy will proxy the requests to the right server.
|
||||
- Split into a few services for different purposes.
|
||||
- The benefit of this is that each service can use different languages that best suits its purpose.
|
||||
- API servers for non-collaborative features and endpoints.
|
||||
- Ruby/Rails/Django for the server that deals with CRUD operations on data models where performance is not that crucial.
|
||||
- WebSocket servers for handling document edits and publishing updates to listeners.
|
||||
- Possibly Node/Golang for WebSocket server which will need high performance as updates are frequent.
|
||||
- Task queue to persist document updates to the database.
|
||||
- ELB in front of back end servers.
|
||||
- MySQL database.
|
||||
- S3 and CDN for images.
|
||||
|
||||
## Data Modeling
|
||||
|
||||
- What kind of database to use?
|
||||
- Data is quite structured. Would go with SQL.
|
||||
- Design the necessary tables, its columns and its relations.
|
||||
- `users`
|
||||
- `id`
|
||||
- `name`
|
||||
- `document`
|
||||
- `id`
|
||||
- `owner_id`
|
||||
- `permissions`
|
||||
- `id`
|
||||
- `name`
|
||||
- `document_permissions`
|
||||
- `id`
|
||||
- `document_id`
|
||||
- `user_id`
|
||||
|
||||
## Collaborative Editing - Client
|
||||
|
||||
- Upon loading of the page and document, the client should connect to the WebSocket server over the WebSocket protocol `ws://`.
|
||||
- Upon connection, perform a time sync with the server, possibly via Network Time Protocol (NTP).
|
||||
- The most straightforward way is to send the whole updated document content to the back end, and all users currently viewing the document will receive the updated document. However, there are a few problems with this approach:
|
||||
- Race condition. If two users editing the document at the same time, the last one to edit will overwrite the changes by the previous user. One workaround is to lock the document when a user is currently editing it, but that will not make it real-time collaborative.
|
||||
- A large payload (the whole document) is being sent to servers and published to users on each change, and the user is likely to already have most of the content. A lot of redundant data being sent.
|
||||
- A feasible approach would be to use operational transforms and send just the action deltas to the back end. The back end publishes the action deltas to the listeners. What is considered an action delta?
|
||||
- (a) Changing a character/word, (b) inserting a character/word/image, (c) deleting a character/word.
|
||||
- With this approach, the payload will contain only small amount of data, such as (a) type of change, (b) character/word, (c) position in document: line/column, (d) timestamp. Why is the timestamp needed? Read on to find out.
|
||||
- Updates can also be throttled and batched, to avoid flooding the web server with requests. For example, if a user inserts a
|
||||
|
||||
## Back End
|
||||
|
||||
The back end is split into a few portions: WebSocket server for receiving and broadcasting document updates, CRUD server for reading and writing non-document-related data, and a task queue for persistence of the document.
|
||||
|
||||
## WebSocket Server
|
||||
|
||||
- Languages and frameworks that support async requests and non-blocking I/O will be suitable for the collaborative editor server. Node and Golang comes to my mind.
|
||||
- However, the WebSocket server is not stateless, so is it not that straightforward to scale horizontally. One approach would be for a Load Balancer to use Redis to maintain a map of the client to the WebSocket server instance IP, such that subsequent requests from the same client will be routed to the same server.
|
||||
- Each document corresponds to a room (more of namespace). Users can subscribe to the events happening within a room.
|
||||
- When a action delta is being received, blast it out to the listeners within the room and add it to the task queue.
|
||||
|
||||
## CRUD Server
|
||||
|
||||
- Provides APIs for reading and writing non-document-related data, such as users, permissions.
|
||||
|
||||
## Task Queue + Worker Service
|
||||
|
||||
- Worker service retrieves messages from the task queue and writes the updated documents to the database in an async fashion.
|
||||
- Batch the actions together and perform one larger write that consists of multiple actions. For example, instead of persisting to the database once per addition of a word, combine these additions and write them into the database at once.
|
||||
- Publish the save completion event to the WebSocket server to be published to the listeners, informing that the latest version of the document is being saved.
|
||||
- Benefit of using a task queue is that as the amount of tasks in the queue goes up, we can scale up the number of worker services to clear the backlog of work faster.
|
||||
|
||||
## Document Persistence
|
||||
|
||||
TODO
|
||||
|
||||
###### References
|
||||
|
||||
- http://blog.gainlo.co/index.php/2016/03/22/system-design-interview-question-how-to-design-google-docs/
|
@ -0,0 +1,6 @@
|
||||
Search Engine
|
||||
==
|
||||
|
||||
###### References
|
||||
|
||||
- [How Do Search Engines Work?](http://www.makeuseof.com/tag/how-do-search-engines-work-makeuseof-explains/)
|
@ -0,0 +1,61 @@
|
||||
<!doctype html>
|
||||
<head>
|
||||
<style>
|
||||
body {
|
||||
font-family: 'Helvetica', sans-serif;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div>
|
||||
<div id="chapters">
|
||||
</div>
|
||||
</div>
|
||||
<script>
|
||||
(() => {
|
||||
const DOM = {
|
||||
$chapters: document.getElementById('chapters'),
|
||||
};
|
||||
const URL = 'https://raw.githubusercontent.com/googlesamples/web-fundamentals/gh-pages/fundamentals/getting-started/primers';
|
||||
|
||||
function getJSON(url) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const req = new XMLHttpRequest();
|
||||
req.open('GET', url);
|
||||
req.onload = () => {
|
||||
if (req.status === 200) {
|
||||
resolve(JSON.parse(req.response));
|
||||
return;
|
||||
}
|
||||
reject(req.responseText);
|
||||
}
|
||||
req.onerror = (err) => {
|
||||
reject(err);
|
||||
}
|
||||
req.send();
|
||||
});
|
||||
}
|
||||
|
||||
function init() {
|
||||
getJSON(`${URL}/story.json`).then(story => {
|
||||
const $heading = document.createRange().createContextualFragment(story.heading);
|
||||
DOM.$chapters.before($heading);
|
||||
return Promise.all(story.chapterUrls.map((url, index) => {
|
||||
return getJSON(`${URL}/${url}`);
|
||||
}));
|
||||
}).then(chapters => {
|
||||
const $chapters = document.createDocumentFragment();
|
||||
chapters.forEach(chapter => {
|
||||
$chapters.appendChild(document.createRange().createContextualFragment(chapter.html));
|
||||
});
|
||||
DOM.$chapters.appendChild($chapters);
|
||||
}).catch(err => {
|
||||
console.warn(err);
|
||||
});
|
||||
}
|
||||
|
||||
document.addEventListener('DOMContentLoaded', init);
|
||||
})();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
@ -0,0 +1,8 @@
|
||||
Databases
|
||||
==
|
||||
|
||||
## General
|
||||
|
||||
- How should you store passwords in a database?
|
||||
- http://www.geeksforgeeks.org/store-password-database/
|
||||
- https://nakedsecurity.sophos.com/2013/11/20/serious-security-how-to-store-your-users-passwords-safely/
|
@ -0,0 +1,6 @@
|
||||
Networking
|
||||
==
|
||||
|
||||
- Given an IPv4 IP address p and an integer n, return a list of CIDR strings that most succinctly represents the range of IP addresses from p to (p + n).
|
||||
- Describe what happens when you enter a url in the web browser.
|
||||
- Define UDP/TCP and give an example of both.
|
@ -0,0 +1,677 @@
|
||||
const data = [
|
||||
{
|
||||
"_id": "591ad7e2d1b6119887420af5",
|
||||
"age": 36,
|
||||
"name": "Salas Mccarthy",
|
||||
"gender": "male",
|
||||
"company": "MAKINGWAY",
|
||||
"email": "salasmccarthy@makingway.com",
|
||||
"phone": "+1 (905) 546-3931"
|
||||
},
|
||||
{
|
||||
"_id": "591ad7e2918b0ba1231b582d",
|
||||
"age": 29,
|
||||
"name": "Jodi Graham",
|
||||
"gender": "female",
|
||||
"company": "BITREX",
|
||||
"email": "jodigraham@bitrex.com",
|
||||
"phone": "+1 (861) 596-2691"
|
||||
},
|
||||
{
|
||||
"_id": "591ad7e2bc19d181dcb64d57",
|
||||
"age": 34,
|
||||
"name": "Hollie Hardin",
|
||||
"gender": "female",
|
||||
"company": "ZENSURE",
|
||||
"email": "holliehardin@zensure.com",
|
||||
"phone": "+1 (822) 410-2433"
|
||||
},
|
||||
{
|
||||
"_id": "591ad7e224d2fa7216132561",
|
||||
"age": 26,
|
||||
"name": "Bullock Cole",
|
||||
"gender": "male",
|
||||
"company": "ZILPHUR",
|
||||
"email": "bullockcole@zilphur.com",
|
||||
"phone": "+1 (839) 563-3350"
|
||||
},
|
||||
{
|
||||
"_id": "591ad7e206c3fb3043ccf8a8",
|
||||
"age": 30,
|
||||
"name": "Peterson Mosley",
|
||||
"gender": "male",
|
||||
"company": "MOBILDATA",
|
||||
"email": "petersonmosley@mobildata.com",
|
||||
"phone": "+1 (974) 547-3461"
|
||||
},
|
||||
{
|
||||
"_id": "591ad7e20a180de908b0960e",
|
||||
"age": 34,
|
||||
"name": "Lucille Jackson",
|
||||
"gender": "female",
|
||||
"company": "KINETICUT",
|
||||
"email": "lucillejackson@kineticut.com",
|
||||
"phone": "+1 (845) 443-3594"
|
||||
},
|
||||
{
|
||||
"_id": "591ad7e2768b0cf4837ecf35",
|
||||
"age": 40,
|
||||
"name": "Cooper Leonard",
|
||||
"gender": "male",
|
||||
"company": "CHORIZON",
|
||||
"email": "cooperleonard@chorizon.com",
|
||||
"phone": "+1 (817) 418-2290"
|
||||
},
|
||||
{
|
||||
"_id": "591ad7e270a640cf8f8a3e44",
|
||||
"age": 27,
|
||||
"name": "Iris Shepherd",
|
||||
"gender": "female",
|
||||
"company": "IDEALIS",
|
||||
"email": "irisshepherd@idealis.com",
|
||||
"phone": "+1 (858) 599-3628"
|
||||
},
|
||||
{
|
||||
"_id": "591ad7e222ddd244aaba0315",
|
||||
"age": 31,
|
||||
"name": "Oneil Head",
|
||||
"gender": "male",
|
||||
"company": "LIMOZEN",
|
||||
"email": "oneilhead@limozen.com",
|
||||
"phone": "+1 (894) 440-3396"
|
||||
},
|
||||
{
|
||||
"_id": "591ad7e2d36847b5e648587b",
|
||||
"age": 28,
|
||||
"name": "Swanson Singleton",
|
||||
"gender": "male",
|
||||
"company": "NSPIRE",
|
||||
"email": "swansonsingleton@nspire.com",
|
||||
"phone": "+1 (817) 510-2480"
|
||||
},
|
||||
{
|
||||
"_id": "591ad7e2b78092f9fb866779",
|
||||
"age": 37,
|
||||
"name": "Sutton Odom",
|
||||
"gender": "male",
|
||||
"company": "GLUKGLUK",
|
||||
"email": "suttonodom@glukgluk.com",
|
||||
"phone": "+1 (961) 424-2812"
|
||||
},
|
||||
{
|
||||
"_id": "591ad7e222736aa66a9b35cc",
|
||||
"age": 31,
|
||||
"name": "Chandler Kirk",
|
||||
"gender": "male",
|
||||
"company": "EWAVES",
|
||||
"email": "chandlerkirk@ewaves.com",
|
||||
"phone": "+1 (902) 524-3712"
|
||||
},
|
||||
{
|
||||
"_id": "591ad7e2ac3f9abecd5175a7",
|
||||
"age": 28,
|
||||
"name": "Gentry Stanley",
|
||||
"gender": "male",
|
||||
"company": "GINK",
|
||||
"email": "gentrystanley@gink.com",
|
||||
"phone": "+1 (878) 592-2331"
|
||||
},
|
||||
{
|
||||
"_id": "591ad7e2f79787dc605d61fb",
|
||||
"age": 28,
|
||||
"name": "Paulette Guthrie",
|
||||
"gender": "female",
|
||||
"company": "SEQUITUR",
|
||||
"email": "pauletteguthrie@sequitur.com",
|
||||
"phone": "+1 (820) 473-2926"
|
||||
},
|
||||
{
|
||||
"_id": "591ad7e2ff61553783737bc0",
|
||||
"age": 37,
|
||||
"name": "Lesley Nash",
|
||||
"gender": "female",
|
||||
"company": "MELBACOR",
|
||||
"email": "lesleynash@melbacor.com",
|
||||
"phone": "+1 (849) 414-2115"
|
||||
},
|
||||
{
|
||||
"_id": "591ad7e26f9c3fc95fa8e6f1",
|
||||
"age": 22,
|
||||
"name": "Frye Oneil",
|
||||
"gender": "male",
|
||||
"company": "OVERPLEX",
|
||||
"email": "fryeoneil@overplex.com",
|
||||
"phone": "+1 (999) 412-2403"
|
||||
},
|
||||
{
|
||||
"_id": "591ad7e2eee8b7cd857a29d0",
|
||||
"age": 40,
|
||||
"name": "Christina Zamora",
|
||||
"gender": "female",
|
||||
"company": "REPETWIRE",
|
||||
"email": "christinazamora@repetwire.com",
|
||||
"phone": "+1 (860) 504-3885"
|
||||
},
|
||||
{
|
||||
"_id": "591ad7e2be93544c81761053",
|
||||
"age": 25,
|
||||
"name": "Earlene Dunn",
|
||||
"gender": "female",
|
||||
"company": "PHARMEX",
|
||||
"email": "earlenedunn@pharmex.com",
|
||||
"phone": "+1 (831) 582-2974"
|
||||
},
|
||||
{
|
||||
"_id": "591ad7e2cb672de927940ef4",
|
||||
"age": 25,
|
||||
"name": "Hoffman Pittman",
|
||||
"gender": "male",
|
||||
"company": "ENOMEN",
|
||||
"email": "hoffmanpittman@enomen.com",
|
||||
"phone": "+1 (882) 420-3186"
|
||||
},
|
||||
{
|
||||
"_id": "591ad7e2aabaae50d75c21a3",
|
||||
"age": 35,
|
||||
"name": "Wilson Tran",
|
||||
"gender": "male",
|
||||
"company": "CAXT",
|
||||
"email": "wilsontran@caxt.com",
|
||||
"phone": "+1 (842) 529-3085"
|
||||
},
|
||||
{
|
||||
"_id": "591ad7e2bdd6104be85bdd87",
|
||||
"age": 22,
|
||||
"name": "Hensley Hawkins",
|
||||
"gender": "male",
|
||||
"company": "LUDAK",
|
||||
"email": "hensleyhawkins@ludak.com",
|
||||
"phone": "+1 (902) 566-3308"
|
||||
},
|
||||
{
|
||||
"_id": "591ad7e24796cbdc0eacb6c0",
|
||||
"age": 36,
|
||||
"name": "Gray Schultz",
|
||||
"gender": "male",
|
||||
"company": "EBIDCO",
|
||||
"email": "grayschultz@ebidco.com",
|
||||
"phone": "+1 (910) 532-2845"
|
||||
},
|
||||
{
|
||||
"_id": "591ad7e204425cc3b121279a",
|
||||
"age": 25,
|
||||
"name": "Odonnell Livingston",
|
||||
"gender": "male",
|
||||
"company": "ANOCHA",
|
||||
"email": "odonnelllivingston@anocha.com",
|
||||
"phone": "+1 (991) 422-2754"
|
||||
},
|
||||
{
|
||||
"_id": "591ad7e2997ac59b446d3a30",
|
||||
"age": 36,
|
||||
"name": "Shelton Lindsay",
|
||||
"gender": "male",
|
||||
"company": "DENTREX",
|
||||
"email": "sheltonlindsay@dentrex.com",
|
||||
"phone": "+1 (899) 567-2928"
|
||||
},
|
||||
{
|
||||
"_id": "591ad7e2646dad2ff456b035",
|
||||
"age": 40,
|
||||
"name": "Mcclain Larson",
|
||||
"gender": "male",
|
||||
"company": "GENMOM",
|
||||
"email": "mcclainlarson@genmom.com",
|
||||
"phone": "+1 (934) 508-3477"
|
||||
},
|
||||
{
|
||||
"_id": "591ad7e21e908e847ee6d3ea",
|
||||
"age": 27,
|
||||
"name": "Miranda Branch",
|
||||
"gender": "female",
|
||||
"company": "ROCKYARD",
|
||||
"email": "mirandabranch@rockyard.com",
|
||||
"phone": "+1 (989) 446-2387"
|
||||
},
|
||||
{
|
||||
"_id": "591ad7e2d7905d2fcaa1ce18",
|
||||
"age": 36,
|
||||
"name": "Valencia Moreno",
|
||||
"gender": "male",
|
||||
"company": "KIOSK",
|
||||
"email": "valenciamoreno@kiosk.com",
|
||||
"phone": "+1 (807) 449-2626"
|
||||
},
|
||||
{
|
||||
"_id": "591ad7e245e3c4ce18a92054",
|
||||
"age": 40,
|
||||
"name": "Witt Leblanc",
|
||||
"gender": "male",
|
||||
"company": "ENERSAVE",
|
||||
"email": "wittleblanc@enersave.com",
|
||||
"phone": "+1 (809) 491-3886"
|
||||
},
|
||||
{
|
||||
"_id": "591ad7e27f2c70583d1cf34f",
|
||||
"age": 32,
|
||||
"name": "Glover Mccoy",
|
||||
"gender": "male",
|
||||
"company": "BYTREX",
|
||||
"email": "glovermccoy@bytrex.com",
|
||||
"phone": "+1 (928) 470-2426"
|
||||
},
|
||||
{
|
||||
"_id": "591ad7e22768012595c933c9",
|
||||
"age": 25,
|
||||
"name": "Billie Dunlap",
|
||||
"gender": "female",
|
||||
"company": "INQUALA",
|
||||
"email": "billiedunlap@inquala.com",
|
||||
"phone": "+1 (903) 415-2136"
|
||||
},
|
||||
{
|
||||
"_id": "591ad7e22df8d07559a29904",
|
||||
"age": 21,
|
||||
"name": "Bridget Hill",
|
||||
"gender": "female",
|
||||
"company": "TRIBALOG",
|
||||
"email": "bridgethill@tribalog.com",
|
||||
"phone": "+1 (954) 461-3390"
|
||||
},
|
||||
{
|
||||
"_id": "591ad7e201b2bddbc81ae05e",
|
||||
"age": 30,
|
||||
"name": "Dawson Clements",
|
||||
"gender": "male",
|
||||
"company": "EURON",
|
||||
"email": "dawsonclements@euron.com",
|
||||
"phone": "+1 (926) 570-3444"
|
||||
},
|
||||
{
|
||||
"_id": "591ad7e2c2aeb820e77c1d9a",
|
||||
"age": 31,
|
||||
"name": "Valdez Johnson",
|
||||
"gender": "male",
|
||||
"company": "RETRACK",
|
||||
"email": "valdezjohnson@retrack.com",
|
||||
"phone": "+1 (841) 506-2428"
|
||||
},
|
||||
{
|
||||
"_id": "591ad7e2370ff047048bd688",
|
||||
"age": 31,
|
||||
"name": "Nichole Dickerson",
|
||||
"gender": "female",
|
||||
"company": "NEOCENT",
|
||||
"email": "nicholedickerson@neocent.com",
|
||||
"phone": "+1 (945) 437-3591"
|
||||
},
|
||||
{
|
||||
"_id": "591ad7e2b77affba5a8f8603",
|
||||
"age": 34,
|
||||
"name": "Madden Weaver",
|
||||
"gender": "male",
|
||||
"company": "VERBUS",
|
||||
"email": "maddenweaver@verbus.com",
|
||||
"phone": "+1 (810) 598-3145"
|
||||
},
|
||||
{
|
||||
"_id": "591ad7e21e692cc8247b1d83",
|
||||
"age": 26,
|
||||
"name": "Larsen Benson",
|
||||
"gender": "male",
|
||||
"company": "ISOSURE",
|
||||
"email": "larsenbenson@isosure.com",
|
||||
"phone": "+1 (890) 435-2219"
|
||||
},
|
||||
{
|
||||
"_id": "591ad7e2de06284f2d2a8d19",
|
||||
"age": 37,
|
||||
"name": "Barnes Gaines",
|
||||
"gender": "male",
|
||||
"company": "RODEOCEAN",
|
||||
"email": "barnesgaines@rodeocean.com",
|
||||
"phone": "+1 (824) 484-2693"
|
||||
},
|
||||
{
|
||||
"_id": "591ad7e20d9d8224dfbd292f",
|
||||
"age": 28,
|
||||
"name": "Pacheco Landry",
|
||||
"gender": "male",
|
||||
"company": "METROZ",
|
||||
"email": "pachecolandry@metroz.com",
|
||||
"phone": "+1 (813) 525-3821"
|
||||
},
|
||||
{
|
||||
"_id": "591ad7e2c5348da6a981a148",
|
||||
"age": 21,
|
||||
"name": "Richard Alexander",
|
||||
"gender": "male",
|
||||
"company": "GADTRON",
|
||||
"email": "richardalexander@gadtron.com",
|
||||
"phone": "+1 (911) 513-3007"
|
||||
},
|
||||
{
|
||||
"_id": "591ad7e2ca9ef31ba3b67d4f",
|
||||
"age": 22,
|
||||
"name": "Stone Campos",
|
||||
"gender": "male",
|
||||
"company": "TETAK",
|
||||
"email": "stonecampos@tetak.com",
|
||||
"phone": "+1 (879) 440-3672"
|
||||
},
|
||||
{
|
||||
"_id": "591ad7e2ff5a9796c8470151",
|
||||
"age": 31,
|
||||
"name": "Walter Randall",
|
||||
"gender": "male",
|
||||
"company": "EQUITAX",
|
||||
"email": "walterrandall@equitax.com",
|
||||
"phone": "+1 (927) 563-3777"
|
||||
},
|
||||
{
|
||||
"_id": "591ad7e272c6b6c1241b3a4a",
|
||||
"age": 27,
|
||||
"name": "Copeland Compton",
|
||||
"gender": "male",
|
||||
"company": "MAXIMIND",
|
||||
"email": "copelandcompton@maximind.com",
|
||||
"phone": "+1 (829) 599-2574"
|
||||
},
|
||||
{
|
||||
"_id": "591ad7e2220c6caa9e2c444d",
|
||||
"age": 30,
|
||||
"name": "Lorie Irwin",
|
||||
"gender": "female",
|
||||
"company": "ELPRO",
|
||||
"email": "lorieirwin@elpro.com",
|
||||
"phone": "+1 (938) 584-2368"
|
||||
},
|
||||
{
|
||||
"_id": "591ad7e2942d603032f1ebda",
|
||||
"age": 35,
|
||||
"name": "Buck Roth",
|
||||
"gender": "male",
|
||||
"company": "COMTRACT",
|
||||
"email": "buckroth@comtract.com",
|
||||
"phone": "+1 (830) 585-3168"
|
||||
},
|
||||
{
|
||||
"_id": "591ad7e2c23efccd2fcd5b2e",
|
||||
"age": 31,
|
||||
"name": "Mamie Robinson",
|
||||
"gender": "female",
|
||||
"company": "ZOMBOID",
|
||||
"email": "mamierobinson@zomboid.com",
|
||||
"phone": "+1 (845) 481-3222"
|
||||
},
|
||||
{
|
||||
"_id": "591ad7e285109fadbf0f9c01",
|
||||
"age": 33,
|
||||
"name": "Bryan Stone",
|
||||
"gender": "male",
|
||||
"company": "PODUNK",
|
||||
"email": "bryanstone@podunk.com",
|
||||
"phone": "+1 (971) 469-3832"
|
||||
},
|
||||
{
|
||||
"_id": "591ad7e25abc328c2cc42283",
|
||||
"age": 37,
|
||||
"name": "Benson Lyons",
|
||||
"gender": "male",
|
||||
"company": "FUTURITY",
|
||||
"email": "bensonlyons@futurity.com",
|
||||
"phone": "+1 (964) 536-3522"
|
||||
},
|
||||
{
|
||||
"_id": "591ad7e28fa81611cdf5066a",
|
||||
"age": 37,
|
||||
"name": "Sally Finley",
|
||||
"gender": "female",
|
||||
"company": "ZYTRAC",
|
||||
"email": "sallyfinley@zytrac.com",
|
||||
"phone": "+1 (953) 506-2428"
|
||||
},
|
||||
{
|
||||
"_id": "591ad7e271c5882aa5452601",
|
||||
"age": 26,
|
||||
"name": "Callahan Mckee",
|
||||
"gender": "male",
|
||||
"company": "ACCUPRINT",
|
||||
"email": "callahanmckee@accuprint.com",
|
||||
"phone": "+1 (842) 400-3570"
|
||||
},
|
||||
{
|
||||
"_id": "591ad7e2275e787c5d9eea26",
|
||||
"age": 25,
|
||||
"name": "Ines Hamilton",
|
||||
"gender": "female",
|
||||
"company": "PROSURE",
|
||||
"email": "ineshamilton@prosure.com",
|
||||
"phone": "+1 (976) 485-2663"
|
||||
},
|
||||
{
|
||||
"_id": "591ad7e2d8790e386b671ec6",
|
||||
"age": 38,
|
||||
"name": "Mcknight Abbott",
|
||||
"gender": "male",
|
||||
"company": "MAXEMIA",
|
||||
"email": "mcknightabbott@maxemia.com",
|
||||
"phone": "+1 (960) 600-3920"
|
||||
},
|
||||
{
|
||||
"_id": "591ad7e2a1cae1e4f17d8db2",
|
||||
"age": 28,
|
||||
"name": "Tanisha Ross",
|
||||
"gender": "female",
|
||||
"company": "SYNKGEN",
|
||||
"email": "tanishaross@synkgen.com",
|
||||
"phone": "+1 (920) 502-3204"
|
||||
},
|
||||
{
|
||||
"_id": "591ad7e2f816fd6848bc03a3",
|
||||
"age": 22,
|
||||
"name": "Pam Webb",
|
||||
"gender": "female",
|
||||
"company": "VALREDA",
|
||||
"email": "pamwebb@valreda.com",
|
||||
"phone": "+1 (926) 442-2683"
|
||||
},
|
||||
{
|
||||
"_id": "591ad7e208585adb332ac653",
|
||||
"age": 29,
|
||||
"name": "Bobbi Mays",
|
||||
"gender": "female",
|
||||
"company": "PARLEYNET",
|
||||
"email": "bobbimays@parleynet.com",
|
||||
"phone": "+1 (940) 577-3487"
|
||||
},
|
||||
{
|
||||
"_id": "591ad7e2f4b29cbd1744b14e",
|
||||
"age": 27,
|
||||
"name": "Snider Sandoval",
|
||||
"gender": "male",
|
||||
"company": "GRONK",
|
||||
"email": "snidersandoval@gronk.com",
|
||||
"phone": "+1 (903) 526-2655"
|
||||
},
|
||||
{
|
||||
"_id": "591ad7e23a3f54209ec9deba",
|
||||
"age": 33,
|
||||
"name": "Fitzpatrick Weiss",
|
||||
"gender": "male",
|
||||
"company": "MICROLUXE",
|
||||
"email": "fitzpatrickweiss@microluxe.com",
|
||||
"phone": "+1 (894) 494-2135"
|
||||
},
|
||||
{
|
||||
"_id": "591ad7e229d21e1b7723c044",
|
||||
"age": 27,
|
||||
"name": "Kimberly Brown",
|
||||
"gender": "female",
|
||||
"company": "SPACEWAX",
|
||||
"email": "kimberlybrown@spacewax.com",
|
||||
"phone": "+1 (832) 481-2926"
|
||||
},
|
||||
{
|
||||
"_id": "591ad7e247e285f0c563ac94",
|
||||
"age": 20,
|
||||
"name": "Fisher Kent",
|
||||
"gender": "male",
|
||||
"company": "ORBIN",
|
||||
"email": "fisherkent@orbin.com",
|
||||
"phone": "+1 (962) 523-3956"
|
||||
},
|
||||
{
|
||||
"_id": "591ad7e274439c6eb52e99df",
|
||||
"age": 26,
|
||||
"name": "Arlene Carroll",
|
||||
"gender": "female",
|
||||
"company": "ELITA",
|
||||
"email": "arlenecarroll@elita.com",
|
||||
"phone": "+1 (998) 497-3751"
|
||||
},
|
||||
{
|
||||
"_id": "591ad7e271852e5766fad809",
|
||||
"age": 22,
|
||||
"name": "Tamra Spence",
|
||||
"gender": "female",
|
||||
"company": "ARTWORLDS",
|
||||
"email": "tamraspence@artworlds.com",
|
||||
"phone": "+1 (963) 516-2492"
|
||||
},
|
||||
{
|
||||
"_id": "591ad7e28c9165c4372744f7",
|
||||
"age": 29,
|
||||
"name": "Alice Goodman",
|
||||
"gender": "female",
|
||||
"company": "ZILLIDIUM",
|
||||
"email": "alicegoodman@zillidium.com",
|
||||
"phone": "+1 (829) 577-2972"
|
||||
},
|
||||
{
|
||||
"_id": "591ad7e2c2a9121f713f15c3",
|
||||
"age": 27,
|
||||
"name": "Clay Washington",
|
||||
"gender": "male",
|
||||
"company": "EXOSTREAM",
|
||||
"email": "claywashington@exostream.com",
|
||||
"phone": "+1 (926) 460-3699"
|
||||
},
|
||||
{
|
||||
"_id": "591ad7e2c99d41ce0347ac8f",
|
||||
"age": 38,
|
||||
"name": "Navarro Walsh",
|
||||
"gender": "male",
|
||||
"company": "ILLUMITY",
|
||||
"email": "navarrowalsh@illumity.com",
|
||||
"phone": "+1 (896) 564-3270"
|
||||
},
|
||||
{
|
||||
"_id": "591ad7e25e7c6ff0785d1337",
|
||||
"age": 22,
|
||||
"name": "Alexandra Hughes",
|
||||
"gender": "female",
|
||||
"company": "TASMANIA",
|
||||
"email": "alexandrahughes@tasmania.com",
|
||||
"phone": "+1 (977) 509-3599"
|
||||
},
|
||||
{
|
||||
"_id": "591ad7e2acb8a5785b6fd512",
|
||||
"age": 40,
|
||||
"name": "Vonda Oliver",
|
||||
"gender": "female",
|
||||
"company": "NEPTIDE",
|
||||
"email": "vondaoliver@neptide.com",
|
||||
"phone": "+1 (836) 595-2260"
|
||||
},
|
||||
{
|
||||
"_id": "591ad7e20543a9fc7bc33515",
|
||||
"age": 36,
|
||||
"name": "Christa Nixon",
|
||||
"gender": "female",
|
||||
"company": "GLASSTEP",
|
||||
"email": "christanixon@glasstep.com",
|
||||
"phone": "+1 (966) 551-2149"
|
||||
},
|
||||
{
|
||||
"_id": "591ad7e21b8e73ba4dbf7c9a",
|
||||
"age": 34,
|
||||
"name": "Weber Hurst",
|
||||
"gender": "male",
|
||||
"company": "SLUMBERIA",
|
||||
"email": "weberhurst@slumberia.com",
|
||||
"phone": "+1 (943) 516-3449"
|
||||
},
|
||||
{
|
||||
"_id": "591ad7e282b9cb56357b42db",
|
||||
"age": 27,
|
||||
"name": "Rasmussen Kramer",
|
||||
"gender": "male",
|
||||
"company": "MUSIX",
|
||||
"email": "rasmussenkramer@musix.com",
|
||||
"phone": "+1 (891) 553-3264"
|
||||
},
|
||||
{
|
||||
"_id": "591ad7e2287c587e3a04e80c",
|
||||
"age": 30,
|
||||
"name": "Mayra Beasley",
|
||||
"gender": "female",
|
||||
"company": "BRAINCLIP",
|
||||
"email": "mayrabeasley@brainclip.com",
|
||||
"phone": "+1 (958) 576-2642"
|
||||
},
|
||||
{
|
||||
"_id": "591ad7e26245135989367fa8",
|
||||
"age": 20,
|
||||
"name": "Nunez Ortiz",
|
||||
"gender": "male",
|
||||
"company": "KYAGURU",
|
||||
"email": "nunezortiz@kyaguru.com",
|
||||
"phone": "+1 (906) 591-3563"
|
||||
},
|
||||
{
|
||||
"_id": "591ad7e23248cee3b84bde40",
|
||||
"age": 39,
|
||||
"name": "Michael Foreman",
|
||||
"gender": "male",
|
||||
"company": "DANCITY",
|
||||
"email": "michaelforeman@dancity.com",
|
||||
"phone": "+1 (848) 400-3539"
|
||||
},
|
||||
{
|
||||
"_id": "591ad7e23ae236a1d59d07ee",
|
||||
"age": 36,
|
||||
"name": "Virgie Wheeler",
|
||||
"gender": "female",
|
||||
"company": "XIIX",
|
||||
"email": "virgiewheeler@xiix.com",
|
||||
"phone": "+1 (831) 400-2814"
|
||||
},
|
||||
{
|
||||
"_id": "591ad7e2d8b9e3c0c31d770d",
|
||||
"age": 31,
|
||||
"name": "Levy Hoover",
|
||||
"gender": "male",
|
||||
"company": "CANDECOR",
|
||||
"email": "levyhoover@candecor.com",
|
||||
"phone": "+1 (843) 428-2780"
|
||||
},
|
||||
{
|
||||
"_id": "591ad7e2badb7200ca06a483",
|
||||
"age": 21,
|
||||
"name": "Battle Stanton",
|
||||
"gender": "male",
|
||||
"company": "CALCULA",
|
||||
"email": "battlestanton@calcula.com",
|
||||
"phone": "+1 (861) 522-3951"
|
||||
},
|
||||
{
|
||||
"_id": "591ad7e27fd1a4455ccf406c",
|
||||
"age": 24,
|
||||
"name": "Church Lynn",
|
||||
"gender": "male",
|
||||
"company": "DAISU",
|
||||
"email": "churchlynn@daisu.com",
|
||||
"phone": "+1 (896) 425-3854"
|
||||
}
|
||||
]
|
@ -0,0 +1,144 @@
|
||||
<!doctype html>
|
||||
<head>
|
||||
<style>
|
||||
body {
|
||||
font-family: 'Helvetica', sans-serif;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h1>People</h1>
|
||||
<table class="js-table">
|
||||
<tr class="js-table-header">
|
||||
<th data-field="name">Name</th>
|
||||
<th data-field="age">Age</th>
|
||||
<th data-field="email">Email</th>
|
||||
</tr>
|
||||
<tbody class="js-table-body">
|
||||
</tbody>
|
||||
</table>
|
||||
<button class="js-page-button button-prev" data-type="prev">Prev</button>
|
||||
Page <span class="js-current-page"></span> / <span class="js-total-page"></span>
|
||||
<button class="js-page-button button-next" data-type="next">Next</button>
|
||||
|
||||
<script type="text/javascript" src="data.js"></script>
|
||||
<script>
|
||||
(() => {
|
||||
function init() {
|
||||
const DOM = {
|
||||
$pageButtons: document.querySelectorAll('.js-page-button'),
|
||||
$prevButton: document.querySelector('.js-page-button.button-prev'),
|
||||
$nextButton: document.querySelector('.js-page-button.button-next'),
|
||||
$tableHeader: document.querySelector('.js-table-header'),
|
||||
$tableBody: document.querySelector('.js-table-body'),
|
||||
$currentPage: document.querySelector('.js-current-page'),
|
||||
$totalPages: document.querySelector('.js-total-page'),
|
||||
};
|
||||
|
||||
const PAGE_SIZE = 10;
|
||||
function initialState() {
|
||||
return {
|
||||
currentPage: 0,
|
||||
totalPages: 0,
|
||||
sortField: 'name',
|
||||
sortOrder: 'asc',
|
||||
data,
|
||||
};
|
||||
}
|
||||
let state = initialState();
|
||||
state.totalPages = Math.ceil(state.data.length / PAGE_SIZE);
|
||||
|
||||
function navigatePages(type) {
|
||||
let newCurrentPage = state.currentPage + (type === 'prev' ? -1 : 1);
|
||||
newCurrentPage = Math.max(0, newCurrentPage);
|
||||
newCurrentPage = Math.min(newCurrentPage, state.totalPages - 1);
|
||||
state.currentPage = newCurrentPage;
|
||||
}
|
||||
|
||||
function setSortField(field) {
|
||||
state.currentPage = 0;
|
||||
if (state.sortField !== field) {
|
||||
state.sortField = field;
|
||||
state.sortOrder = 'asc';
|
||||
} else {
|
||||
state.sortOrder = state.sortOrder === 'asc' ? 'desc' : 'asc';
|
||||
}
|
||||
}
|
||||
|
||||
function attachEventListeners() {
|
||||
// Pagination.
|
||||
DOM.$pageButtons.forEach(el => {
|
||||
el.addEventListener('click', function () {
|
||||
navigatePages(this.getAttribute('data-type'));
|
||||
render();
|
||||
});
|
||||
});
|
||||
|
||||
// Sorting.
|
||||
DOM.$tableHeader.addEventListener('click', function (event) {
|
||||
const el = event.target;
|
||||
const field = el.getAttribute('data-field');
|
||||
if (el.tagName !== 'TH' || !field) {
|
||||
return;
|
||||
}
|
||||
setSortField(field);
|
||||
render();
|
||||
});
|
||||
}
|
||||
|
||||
function render() {
|
||||
DOM.$tableBody.innerHTML = '';
|
||||
|
||||
// Sort data.
|
||||
const sortField = state.sortField;
|
||||
state.data.sort((a, b) => {
|
||||
switch (sortField) {
|
||||
case 'name':
|
||||
case 'email':
|
||||
return a[sortField] > b[sortField] ? 1 : -1;
|
||||
case 'age':
|
||||
return a[sortField] - b[sortField];
|
||||
}
|
||||
});
|
||||
if (state.sortOrder === 'desc') {
|
||||
state.data.reverse();
|
||||
}
|
||||
|
||||
// Create table rows.
|
||||
const pageData = state.data.slice(state.currentPage * PAGE_SIZE, state.currentPage * PAGE_SIZE + PAGE_SIZE);
|
||||
const $tableRowsFragment = document.createDocumentFragment();
|
||||
pageData.forEach(person => {
|
||||
const $tableRow = document.createElement('tr');
|
||||
['name', 'age', 'email'].forEach(field => {
|
||||
const $tableCell = document.createElement('td');
|
||||
$tableCell.textContent = person[field];
|
||||
$tableRow.appendChild($tableCell);
|
||||
});
|
||||
$tableRowsFragment.appendChild($tableRow);
|
||||
});
|
||||
DOM.$tableBody.appendChild($tableRowsFragment);
|
||||
|
||||
// Pagination buttons disabled states.
|
||||
DOM.$currentPage.textContent = state.currentPage + 1;
|
||||
DOM.$totalPages.textContent = state.totalPages;
|
||||
if (state.currentPage === 0) {
|
||||
DOM.$prevButton.setAttribute('disabled', true);
|
||||
} else {
|
||||
DOM.$prevButton.removeAttribute('disabled');
|
||||
}
|
||||
if (state.currentPage === state.totalPages - 1) {
|
||||
DOM.$nextButton.setAttribute('disabled', true);
|
||||
} else {
|
||||
DOM.$nextButton.removeAttribute('disabled');
|
||||
}
|
||||
}
|
||||
|
||||
render();
|
||||
attachEventListeners();
|
||||
}
|
||||
|
||||
document.addEventListener('DOMContentLoaded', init);
|
||||
})();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
@ -0,0 +1,77 @@
|
||||
Snake Game
|
||||
==
|
||||
|
||||
Design a snake game that is to be played in web browser.
|
||||
|
||||
Client: React + Redux
|
||||
|
||||
Rendering:
|
||||
Pixel-based graphics. Depending on the intended resolution, can divide the screen into N * M pixels. Can dynamically calculate the size of each pixel.
|
||||
|
||||
Fruit: One pixel.
|
||||
Snake body: One pixel width made up of connected pixels.
|
||||
|
||||
Model:
|
||||
{
|
||||
fruit: {
|
||||
x, y
|
||||
},
|
||||
snake: {
|
||||
points: [(x, y), ...] # head is at index 0
|
||||
direction: north/south/east/west
|
||||
}
|
||||
speed: 500,
|
||||
points: 0
|
||||
}
|
||||
|
||||
function update() {
|
||||
next_loc = points[0] + (x, y) # Depends on the direction
|
||||
if (snake.points.find(next_loc) > 0) {
|
||||
// die
|
||||
}
|
||||
let pts = snake.points;
|
||||
if (!isEqual(next_loc, fruit)) {
|
||||
pts = points.removeLast();
|
||||
} else {
|
||||
generate_fruit();
|
||||
points++;
|
||||
}
|
||||
snake.points = [next_loc, ...pts];
|
||||
|
||||
// Boundary checking -> die
|
||||
}
|
||||
|
||||
function generate_fruit() {
|
||||
// Cannot generate on my own body.
|
||||
|
||||
// First approach: while on body, generate
|
||||
let next_fruit_location = random_location();
|
||||
while (snake.points.find(next_fruit_location) > 0) {
|
||||
next_fruit_location = random_location();
|
||||
}
|
||||
fruit = next_fruit_location
|
||||
|
||||
// Second approach: brute force
|
||||
for (let i = 0; i < rows; i++) {
|
||||
for (let j = 0; j < cols; j++) {
|
||||
let point = { x: i, y: j }
|
||||
if (snake.points.find(next_fruit_location) === -1) {
|
||||
fruit = point
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Third approach: brute force with random
|
||||
const available_points = []
|
||||
for (let i = 0; i < rows; i++) {
|
||||
for (let j = 0; j < cols; j++) {
|
||||
let point = { x: i, y: j }
|
||||
if (snake.points.find(next_fruit_location) === -1) {
|
||||
available_points.push(point);
|
||||
}
|
||||
}
|
||||
}
|
||||
fruit = _.sample(available_points);
|
||||
}
|
||||
|
||||
setInterval(update, speed);
|
@ -0,0 +1,22 @@
|
||||
Software Engineering
|
||||
==
|
||||
|
||||
## What is the difference between an interface and abstract class?
|
||||
|
||||
**Abstract Class**
|
||||
|
||||
- For an abstract class, a method must be declared as abstract. An abstract method doesn't have an implementation.
|
||||
- The Abstract methods can be declared with Access modifiers like public, internal, protected, etc. When implementing these methods in a subclass, you must define them with the same (or a less restricted) visibility.
|
||||
- Abstract classes can contain variables and concrete methods.
|
||||
- A class can Inherit only one Abstract class. Hence multiple inheritance is not possible for an Abstract class.
|
||||
- Abstract is object-oriented. It offers the basic data an 'object' should have and/or functions it should be able to do. It is concerned with the object's basic characteristics: what it has and what it can do. Hence objects which inherit from the same abstract class share the basic characteristics (generalization).
|
||||
- Abstract class establishes "is a" relation with concrete classes.
|
||||
|
||||
**Interface**
|
||||
|
||||
- For an interface, all the methods are abstract by default. So one cannot declare variables or concrete methods in interfaces.
|
||||
- All methods declared in an interface must be public.
|
||||
- Interfaces cannot contain variables and concrete methods except constants.
|
||||
- A class can implement many interfaces. Hence multiple interface inheritance is possible.
|
||||
- Interface is functionality-oriented. It defines functionalities an object should have. Regardless what object it is, as long as it can do these functionalities, which are defined in the interface, it's fine. It ignores everything else. An object/class can contain several (groups of) functionalities; hence it is possible for a class to implement multiple interfaces.
|
||||
- Interface provides "has a" capability for classes.
|
@ -0,0 +1,178 @@
|
||||
<!doctype html>
|
||||
<head>
|
||||
<style>
|
||||
body {
|
||||
font-family: 'Helvetica', sans-serif;
|
||||
}
|
||||
|
||||
.board-cell {
|
||||
border: 1px solid #666;
|
||||
box-sizing: border-box;
|
||||
display: inline-block;
|
||||
font-size: 32px;
|
||||
height: 100px;
|
||||
line-height: 100px;
|
||||
text-align: center;
|
||||
width: 100px;
|
||||
}
|
||||
|
||||
.board-cell .content {
|
||||
display: inline-block;
|
||||
vertical-align: middle;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Tic Tac Toe</h1>
|
||||
<p>Current player turn: <span class="js-current-player"></span></p>
|
||||
<div class="js-board"></div>
|
||||
<button class="js-reset">Reset</button>
|
||||
<script>
|
||||
// We will spend the next 45 minutes building a single-page web app that implements a Tic-Tac-Toe game. jQuery has been included for you. We'll implement the following features in order:
|
||||
|
||||
// 1. Render a 3x3 board. You can hardcode some X and O values within the cell for starters.
|
||||
// 2. Implement the add symbol functionality that adds a X or O into a cell whenever the player clicks on it.
|
||||
// 3. Rotate between the players whenever a move is made. Update the current player display.
|
||||
// 4. Check for end game conditions after each move and display the winner if any.
|
||||
// horizontally, vertically, diagonally
|
||||
// 5. After a winner has been determined, disable further moves on the board.
|
||||
// 6. Add a button to reset the game state.
|
||||
(() => {
|
||||
function init() {
|
||||
const DOM = {
|
||||
$currentPlayer: document.querySelector('.js-current-player'),
|
||||
$board: document.querySelector('.js-board'),
|
||||
$resetButton: document.querySelector('.js-reset'),
|
||||
};
|
||||
const SIZE = 3;
|
||||
function initialState() {
|
||||
return {
|
||||
boardModel: Array(SIZE).fill(null).map(_ => Array(SIZE).fill(null)),
|
||||
players: ['X', 'O'],
|
||||
currentPlayer: 0,
|
||||
gameEnded: false,
|
||||
turn: 0,
|
||||
};
|
||||
}
|
||||
let state = initialState();
|
||||
|
||||
function renderBoard() {
|
||||
DOM.$currentPlayer.textContent = state.players[state.currentPlayer];
|
||||
// Assuming SIZE > 0.
|
||||
DOM.$board.innerHTML = '';
|
||||
for (let i = 0; i < SIZE; i++) {
|
||||
const $row = document.createElement('div');
|
||||
$row.classList.add('board-row');
|
||||
for (let j = 0; j < SIZE; j++) {
|
||||
const $cell = document.createElement('div');
|
||||
$cell.classList.add('board-cell');
|
||||
$cell.setAttribute('data-i', i);
|
||||
$cell.setAttribute('data-j', j);
|
||||
const $content = document.createElement('span');
|
||||
$content.classList.add('content');
|
||||
$content.textContent = state.boardModel[i][j];
|
||||
$cell.appendChild($content);
|
||||
$row.appendChild($cell);
|
||||
}
|
||||
DOM.$board.appendChild($row);
|
||||
}
|
||||
}
|
||||
|
||||
function checkWinning(board, player) {
|
||||
// Check horizontal.
|
||||
for (let i = 0; i < SIZE; i++) {
|
||||
if (board[i].every(cell => cell === player)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// Check vertical.
|
||||
for (let j = 0; j < SIZE; j++) {
|
||||
let verticalAllPlayer = true;
|
||||
for (let i = 0; i < SIZE; i++) {
|
||||
if (board[i][j] !== player) {
|
||||
verticalAllPlayer = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (verticalAllPlayer) {
|
||||
return verticalAllPlayer;
|
||||
}
|
||||
}
|
||||
|
||||
// Check diagonal South-East.
|
||||
let diagonalAllPlayer = true;
|
||||
for (let i = 0; i < SIZE; i++) {
|
||||
if (board[i][i] !== player) {
|
||||
diagonalAllPlayer = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (diagonalAllPlayer) {
|
||||
return diagonalAllPlayer;
|
||||
}
|
||||
|
||||
// Check diagonal North-East.
|
||||
diagonalAllPlayer = true;
|
||||
for (let i = SIZE - 1, j = 0; i >= 0; i--, j++) {
|
||||
if (board[i][j] !== player) {
|
||||
diagonalAllPlayer = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (diagonalAllPlayer) {
|
||||
return diagonalAllPlayer;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
function attachEventListeners() {
|
||||
DOM.$board.addEventListener('click', (event) => {
|
||||
if (state.gameEnded) {
|
||||
return;
|
||||
}
|
||||
if (!event.target.classList.contains('board-cell')) {
|
||||
return;
|
||||
}
|
||||
const $cell = event.target;
|
||||
const i = parseInt($cell.getAttribute('data-i'), 10);
|
||||
const j = parseInt($cell.getAttribute('data-j'), 10);
|
||||
if (state.boardModel[i][j] !== null) {
|
||||
alert('Cell has already been taken!');
|
||||
return;
|
||||
}
|
||||
const player = state.players[state.currentPlayer];
|
||||
state.boardModel[i][j] = player;
|
||||
const winningMove = checkWinning(state.boardModel, player);
|
||||
state.turn++;
|
||||
if (!winningMove) {
|
||||
state.currentPlayer = (state.currentPlayer + 1) % 2;
|
||||
renderBoard();
|
||||
if (state.turn === SIZE * SIZE) {
|
||||
alert('It\'s a draw!');
|
||||
}
|
||||
} else {
|
||||
renderBoard();
|
||||
state.gameEnded = true;
|
||||
alert(`Player ${player} wins!`);
|
||||
}
|
||||
});
|
||||
|
||||
DOM.$resetButton.addEventListener('click', () => {
|
||||
if (confirm('Start a new game?')) {
|
||||
state = initialState();
|
||||
renderBoard();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
renderBoard();
|
||||
attachEventListeners();
|
||||
}
|
||||
|
||||
document.addEventListener('DOMContentLoaded', init);
|
||||
})();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
@ -0,0 +1,201 @@
|
||||
Accessibility
|
||||
==
|
||||
|
||||
## Glossary
|
||||
|
||||
- **Accessibility** -
|
||||
- **WAI-ARIA** - Web Accessibility Initiative - Accessible Rich Internet Applications. Commonly shortened to ARIA.
|
||||
|
||||
## What is Accessibility?
|
||||
|
||||
Making sure that the content and the websites we create are usable to people with impairments or disabilities.
|
||||
|
||||
## WebAIM Checklist
|
||||
|
||||
The following is a checklist that contains recommendations for implementing HTML-related principles and techniques for those seeking WCAG 2.0 conformance (it is NOT the Web Content Accessibility Guidelines (WCAG) 2.0).
|
||||
|
||||
- **Perceivable** - Web content is made available to the senses - sight, hearing, and/or touch.
|
||||
- Text Alternatives: Provide text alternatives for any non-text content.
|
||||
- Time-based Media: Provide alternatives for time-based media.
|
||||
- Adaptable: Create content that can be presented in different ways (for example simpler layout) without losing information or structure.
|
||||
- Distinguishable: Make it easier for users to see and hear content including separating foreground from background.
|
||||
- **Operable** - Interface forms, controls, and navigation are operable.
|
||||
- Keyboard Accessible: Make all functionality available from a keyboard.
|
||||
- Enough Time: Provide users enough time to read and use content.
|
||||
- Seizures: Do not design content in a way that is known to cause seizures.
|
||||
- Navigable: Provide ways to help users navigate, find content, and determine where they are.
|
||||
- **Understandable** - Content and interface are understandable.
|
||||
- Readable: Make text content readable and understandable.
|
||||
- Predictable: Make Web pages appear and operate in predictable ways.
|
||||
- Input Assistance: Help users avoid and correct mistakes.
|
||||
- **Robust** - Content can be used reliably by a wide variety of user agents, including assistive technologies.
|
||||
- Compatible: Maximize compatibility with current and future user agents, including assistive technologies.
|
||||
|
||||
**Source:** http://webaim.org/standards/wcag/checklist
|
||||
|
||||
## Focus
|
||||
|
||||
- Making sure your application has a sensible tab order is important.
|
||||
- HTML forms and inputs are focusable and handle keyboard events by default.
|
||||
- Focus tab order relies on the DOM order in the HTML.
|
||||
- Be careful when using CSS when changing the order of elements on the screen, it can cause the order to be unintuitive and messy.
|
||||
- `tabindex` attribute:
|
||||
- `-1`: Not in the natural tab order, but programatically focusable using JavaScript with `focus()` method. Useful for off-screen content which later appears on screen. Children elements are **NOT** pulled out of the tab order.
|
||||
- `0`: In the natural tab order and can be programatically focused.
|
||||
- `1` (bigger than 1): In the natural tab order but jumped in front of the tab order regardless of where it is in the DOM. It can be considered an anti-pattern.
|
||||
- Add focus behavior to interactive controls, like buttons, tabs, dropdowns, stuff that users will interactive with.
|
||||
- Use skip links to allow users to skip directly to the main content without having to tab through all the navigation.
|
||||
- `document.activeElement` is useful in tracking the current element that has focus on.
|
||||
|
||||
## Semantics
|
||||
|
||||
- Using proper labeling not only helps accessibility but it makes the element easier to target for all users!
|
||||
- Use `<label>` with `for` attributes for form elements.
|
||||
- Use `alt` attribute for `<img>` elements. Alt text must describe the image.
|
||||
- TODO
|
||||
|
||||
## Navigating Content
|
||||
|
||||
- MacOS comes built-in with VoiceOver. Press <kbd>CMD</kbd> + <kbd>F5</kbd> to activate.
|
||||
- Activate Web Rotor with <kbd>Ctrl</kbd> + <kbd>Option</kbd> + <kbd>U</kbd>. Web Rotor displays landmarks, headings, links and more on the page and allows you to jump to them directly.
|
||||
- Heading weight should be decided by its importance on the page and not how big it should look, as the heading tag chosen affects the order the headings are listed on screen readers.
|
||||
- Use HTML5 semantic tags like `<main>`, `<nav>`, `<header>`, `<aside>`, `<article>`, `<section>`, `<footer>` to indicate landmarks on the page.
|
||||
|
||||
## ARIA
|
||||
|
||||
- Express semantics that HTML can't express on its own.
|
||||
- Accessibility tree = DOM + ARIA.
|
||||
- ARIA attributes
|
||||
- Allow us to modify the accessibility tree before they are exposed to assistive technologies.
|
||||
- DO NOT modify the element apperance.
|
||||
- DO NOT modify element behaviour.
|
||||
- DO NOT add focusability.
|
||||
- DO NOT add keyboard event handling.
|
||||
- E.g. for custom checkboxes, adding ARIA attributes is not sufficient, you will need to write your own JavaScript to emulate the native behaviour to synchronize the ARIA attributes and values with the actual visual state, such as toggling using clicks and hitting spacebar. It's probably not worth it to reinvent the wheel by writing your own custom widgets that already exist in HTML5.
|
||||
- ARIA can add semantics to elements that have no native semantics, such as `<div>`. ARIA can also modify element semantics.
|
||||
- ARIA allows developers to create accessible widgets that do not exist in HTML5, such as a tree widget.
|
||||
- `aria-role` attributes tell assistive technologies that the element should follow that role's accessibility patterns. There are well-defined roles in the HTML spec. Do not define them on your own.
|
||||
- `tabindex="0"` is usually added to it elements that have `role` added so that it can be focused.
|
||||
- Assistive labelling
|
||||
- `aria-label` is useful for labelling buttons where the content is empty or contains only icons.
|
||||
- `aria-labelledby` is similar to `<label>` elements, and can be used on any elements.
|
||||
```html
|
||||
/* Normal label example */
|
||||
<input type="radio" id="coffee-label">
|
||||
<label for="coffee-label">Coffee</label>
|
||||
|
||||
/* aria-labelledby example */
|
||||
<div role="radio" aria-labelledby="coffee-label"></div>
|
||||
<span id="coffee-label">Coffee</span>
|
||||
```
|
||||
- ARIA Relationships
|
||||
- ARIA relationship attributes create semantic relationships between elements on the page. The `aria-labelledby` attribute in the previous example indicates that the `<div>` is labelled by the element with that `id`.
|
||||
- Possible relationship attributes include `aria-activedescendent`, `aria-describedby`, `aria-labelledby`, `aria-owns`, `aria-posinset` and `aria-setsize`.
|
||||
- With ARIA, you can expose only relevant parts of the page to accessibility tree. Elements can be hidden via:
|
||||
- Setting `visibility`: `<button style="visibility: hidden">`.
|
||||
- Setting `display`: `<button style="display: none">`.
|
||||
- HTML5 `hidden` attribute: `<span hidden>`. This makes the element hidden to everyone.
|
||||
- `aria-hidden` attribute: `<div aria-hidden="true">`. This makes the element hidden to screenreaders too. Note that `aria-hidden` attribute requires an explicit value of `true` or `false`.
|
||||
- Technique for screenreader-only text:
|
||||
```
|
||||
.screenreader {
|
||||
position: absolute;
|
||||
left: -1000px;
|
||||
width: 1px;
|
||||
height: 1px;
|
||||
overflow: hidden;
|
||||
}
|
||||
```
|
||||
- `aria-live` attribute can be used to grab the assistive technology's attention to cause it to announce updates to the user. Practically, include `aria-live` attributes in the initial page load. The different `aria-live` values include:
|
||||
- `off` (default) - Updates will not be presented unless the region is currently focused.
|
||||
- `polite` - Assistive technologies should announce updates at the next graceful opportunity, such as at the end of speaking the current sentence on when the user pauses typing. Such as receiving new chat messages.
|
||||
- `assertive` - Highest priority and assistive technologies should notify the user immediately. Examples include server status error alerts.
|
||||
- `aria-atomic` attribute indicates whether the entire region should be presented as a whole when communicating updates. Such as a date widget comprising of multiple `<input>` fields for day/month/year. When the user changes a field, the full contents of the widget will be read out. It takes in a `true` or `false` value.
|
||||
- `aria-relevant` attribute indicates what types of changes should be presented to the user.
|
||||
- `additions` - Element nodes are added to the DOM within the live region.
|
||||
- `removals` - Text or element nodes within the live region are removed from the DOM.
|
||||
- `text` - Text is added to any DOM descendant nodes of the live region.
|
||||
- `all` - Equivalent to the combination of all values, `additions removals text`.
|
||||
- `additions text` (default) - Equivalent to the combination of values, `additions text`.
|
||||
- `aria-busy` attribute indicates the assistive technologies should ignore changes to the element, such as when things are loading, for example after a temporary connectivity loss. It takes in `true` or `false`. It takes in a `true` or `false` value.
|
||||
|
||||
## Style
|
||||
|
||||
#### Introduction
|
||||
|
||||
- Ensure elements are styled to support the existing accessibility work, such as adding styles for `:focus` and the various ARIA states.
|
||||
- Flexible user interface that can handle being zoomed or scaled up, for users who have trouble reading smaller text.
|
||||
- Color choices and the importance of contrast, making sure we are not conveying information just with color alone.
|
||||
|
||||
#### Focus
|
||||
|
||||
- As much as possible, leave the default focus in place. Do not remove the `:focus` styling just because it does not fit into your design or looks odd! - A good technique is to use a similar styling as `:hover` for `:focus`.
|
||||
- Some CSS resets would kill off the focus styling, so it's important to be aware of them and get them back.
|
||||
|
||||
#### Styling with ARIA
|
||||
|
||||
Consider using ARIA attributes in your CSS selectors to reduce some noise in your CSS. For custom toggle buttons, instead of doing this,
|
||||
|
||||
```html
|
||||
<div class="toggle pressed" role="button" tabindex="0" aria-pressed="true"></div> /* On */
|
||||
<div class="toggle" role="button" tabindex="0" aria-pressed="false"></div> /* Off */
|
||||
|
||||
.toggle.pressed {
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
you can do this instead:
|
||||
|
||||
```html
|
||||
<div class="toggle" role="button" tabindex="0" aria-pressed="true"></div> /* On */
|
||||
<div class="toggle" role="button" tabindex="0" aria-pressed="false"></div> /* Off */
|
||||
|
||||
.toggle[aria-pressed="true"] {
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
which removes the need for toggling the `press` class on the element.
|
||||
|
||||
#### Responsive Design
|
||||
|
||||
Responsive design is also beneficial for accessibility when zooming the page transforms the page into the mobile layout instead.
|
||||
|
||||
Use a meta viewport tag:
|
||||
|
||||
```
|
||||
<meta name="viewport" content="width=device-width initial-scale="1">
|
||||
```
|
||||
|
||||
`user-scalable=no` is an anti-pattern for accessibility.
|
||||
|
||||
Use relative units like `%`, `em` and `rem`. The differences are as follows:
|
||||
|
||||
- `%` - Relative to the containing block.
|
||||
- `em` - Relative to the `font-size` of the parent.
|
||||
- `rem` - Relative to the `font-size` of the root, which is the `<html>` element.
|
||||
|
||||
Interactive interface elements such as buttons should be large enough, have enough spacing around itself so that they do not overlap with other interactive elements.
|
||||
|
||||
#### Color and Contrast
|
||||
|
||||
Contrast ratio is the ratio of luminance between the foreground color (such as text) and the background color. For text and images, aim for a large contrast ratio of 7:1 and for larger text (over 18 point or 14 point bold), aim for at least 4.5:1.
|
||||
|
||||
Chrome Devtools has an Accessibility audit feature that can flag the contrast issues on your page.
|
||||
|
||||
Color should not be used as the sole method of conveying content or distinguishing visual elements, such as only changing the `border-color` of `<input>` fields that have error to red. These changes will not be obvious/visible to people with color blindness. An error message below the field will be helpful.
|
||||
|
||||
Some users might be using a High Contrast mode which allows a user to invert the background and foreground colors to read text better. Ensure that your page also looks fine on High Contrast mode which you can simulate with a [Chrome High Contrast extension](https://chrome.google.com/webstore/detail/high-contrast/djcfdncoelnlbldjfhinnjlhdjlikmph?hl=en).
|
||||
|
||||
#### Assessing Impact of Accessibility Issues
|
||||
|
||||
Fixing accessibility issues is like fixing bugs; it is best looked at through the lens of impact. How can you have the most impact on users with the least amount of effort?
|
||||
|
||||
- How frequent is this piece of UI used? Is it part of a critical flow?
|
||||
- How badly does this accessibility issue affect your users?
|
||||
- How expensive is it going to cost to fix?
|
||||
|
||||
###### References
|
||||
|
||||
- https://www.udacity.com/course/web-accessibility--ud891
|
@ -0,0 +1,59 @@
|
||||
Browser
|
||||
==
|
||||
|
||||
## Glossary
|
||||
|
||||
- **BOM** - The Browser Object Model (BOM) is a browser-specific convention referring to all the objects exposed by the web browser. The `window` object is one of them.
|
||||
- **CSSOM** - CSS Object Model.
|
||||
- **DOM** - The Document Object Model (DOM) is a cross-platform and language-independent convention for representing and interacting with objects in HTML, XHTML, and XML documents.
|
||||
- **Reflow** - When the changes affect document contents or structure, or element position, a reflow (or relayout) happens.
|
||||
- **Repaint** - When changing element styles which don't affect the element's position on a page (such as `background-color`, `border-color`, `visibility`), the browser just repaints the element again with the new styles applied (that means a "repaint" or "restyle" is happening).
|
||||
- **Composite** - TODO
|
||||
|
||||
## Rendering
|
||||
|
||||
High level flow of how browsers render a webpage:
|
||||
|
||||
1. DOM
|
||||
- The DOM (Document Object Model) is formed from the HTML that is received from a server.
|
||||
- Characters -> Tokens -> Nodes -> DOM.
|
||||
- DOM construction is incremental.
|
||||
- CSS and JS are requested as the respective `<link>` and `<script>` tags are encountered.
|
||||
1. CSSOM
|
||||
- Styles are loaded and parsed, forming the CSSOM (CSS Object Model).
|
||||
- Characters -> Tokens -> Nodes -> CSSOM.
|
||||
- CSSOM construction is not incremental.
|
||||
- Browser blocks page rendering until it receives and processes all the CSS.
|
||||
- CSS is render blocking.
|
||||
1. Render Tree
|
||||
- On top of DOM and CSSOM, a render tree is created, which is a set of objects to be rendered. Render tree reflects the DOM structure except for invisible elements (like the <head> tag or elements that have `display: none`; set). Each text string is represented in the rendering tree as a separate renderer. Each of the rendering objects contains its corresponding DOM object (or a text block) plus the calculated styles. In other words, the render tree describes the visual representation of a DOM.
|
||||
1. Layout
|
||||
- For each render tree element, its coordinates are calculated, which is called "layout". Browsers use a flow method which only required one pass to layout all the elements (tables require more than one pass).
|
||||
1. Painting
|
||||
- Finally, this gets actually displayed in a browser window, a process called "painting".
|
||||
|
||||
###### References
|
||||
|
||||
- https://www.html5rocks.com/en/tutorials/internals/howbrowserswork/webkitflow.png
|
||||
- https://medium.freecodecamp.org/its-not-dark-magic-pulling-back-the-curtains-from-your-stylesheets-c8d677fa21b2
|
||||
|
||||
## Repaint
|
||||
|
||||
When changing element styles which don't affect the element's position on a page (such as `background-color`, `border-color`, `visibility`), the browser just repaints the element again with the new styles applied (that means a "repaint" or "restyle" is happening).
|
||||
|
||||
## Reflow
|
||||
|
||||
When the changes affect document contents or structure, or element position, a reflow (or relayout) happens. These changes are usually triggered by:
|
||||
- DOM manipulation (element addition, deletion, altering, or changing element order)
|
||||
- Contents changes, including text changes in form fields
|
||||
- Calculation or altering of CSS properties
|
||||
- Adding or removing style sheets
|
||||
- Changing the "class" attribute
|
||||
- Browser window manipulation (resizing, scrolling); Pseudo-class activation (`:hover`)
|
||||
|
||||
#### References
|
||||
|
||||
- [How Browsers Work](https://www.html5rocks.com/en/tutorials/internals/howbrowserswork/)
|
||||
- [What Every Frontend Developer Should Know About Webpage Rendering](http://frontendbabel.info/articles/webpage-rendering-101/)
|
||||
- [Rendering: repaint, reflow/relayout, restyle](http://www.phpied.com/rendering-repaint-reflowrelayout-restyle/)
|
||||
- [Building the DOM faster: speculative parsing, async, defer and preload](https://hacks.mozilla.org/2017/09/building-the-dom-faster-speculative-parsing-async-defer-and-preload/)
|
@ -0,0 +1,12 @@
|
||||
Caching
|
||||
==
|
||||
|
||||
## Glossary
|
||||
|
||||
- **Cookies**
|
||||
|
||||
#### References
|
||||
|
||||
- [A Tale of Four Caches](https://calendar.perfplanet.com/2016/a-tale-of-four-caches/)
|
||||
- [Web Caching Basics: Terminology, HTTP Headers, and Caching Strategies](https://www.digitalocean.com/community/tutorials/web-caching-basics-terminology-http-headers-and-caching-strategies)
|
||||
- [This browser tweak saved 60% of requests to Facebook](https://code.facebook.com/posts/557147474482256/this-browser-tweak-saved-60-of-requests-to-facebook/)
|
@ -0,0 +1,25 @@
|
||||
CSS
|
||||
==
|
||||
|
||||
CSS (Cascading Style Sheets) are rules to describe how your HTML elements look. Writing good CSS is hard. It usually takes many years of experience and frustration of shooting yourself in the foot before one is able to write maintainable and scalable CSS. CSS, having a global namespace, is fundamentally designed for web documents, and not really for web apps that favor a components architecture. Hence, experienced front end developers have designed methodologies to guide people on how to write organized CSS for complex projects, such as using [SMACSS](https://smacss.com/), [BEM](http://getbem.com/), [SUIT CSS](http://suitcss.github.io/), etc.
|
||||
|
||||
However, the encapsulation of styles that these methodologies bring about are artificially enforced by conventions and guidelines. They break the moment developers do not follow them.
|
||||
|
||||
As you might have realized by now, the front end ecosystem is saturated with tools, and unsurprisingly, tools have been invented to [partially solve some of the problems](https://speakerdeck.com/vjeux/react-css-in-js) with writing CSS at scale. "At scale" means that many developers are working on the same large project and touching the same stylesheets. There is no community-agreed approach on writing [CSS in JS](https://github.com/MicheleBertoli/css-in-js) at the moment, and we are hoping that one day a winner would emerge, just like Redux did, among all the Flux implementations. For now, I would recommend [CSS Modules](https://github.com/css-modules/css-modules). CSS modules is an improvement over existing CSS that aims to fix the problem of global namespace in CSS; it enables you to write styles that are local by default and encapsulated to your component. This feature is achieved via tooling. With CSS modules, large teams can write modular and reusable CSS without fear of conflict or overriding other parts of the app. However, at the end of the day, CSS modules are still being compiled into normal globally-namespaced CSS that browsers recognize, and it is still important to learn and understand how raw CSS works.
|
||||
|
||||
If you are a total beginner to CSS, Codecademy's [HTML & CSS course](https://www.codecademy.com/learn/learn-html-css) will be a good introduction to you. Next, read up on the [Sass preprocessor](http://sass-lang.com/), an extension of the CSS language which adds syntactic improvements and encourages style reusability. Study the CSS methodologies mentioned above, and lastly, CSS modules.
|
||||
|
||||
## Glossary
|
||||
|
||||
- **Box Model** - The CSS box model describes the rectangular boxes that are generated for elements in the document tree and laid out according to the visual formatting model. Each box has a content area (e.g. text, an image, etc.) and optional surrounding padding, border, and margin areas.
|
||||
- **Specificity** - TBD
|
||||
- **Positioning** - TBD
|
||||
- **Floats** - TBD
|
||||
|
||||
## Writing CSS without Side Effects
|
||||
|
||||
TODO
|
||||
|
||||
###### References
|
||||
|
||||
- https://philipwalton.com/articles/side-effects-in-css/
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,9 @@
|
||||
Networking
|
||||
==
|
||||
|
||||
## Glossary
|
||||
|
||||
- **JSON**
|
||||
- **RPC**
|
||||
- **HTTP**
|
||||
- **HTTP/2**
|
@ -0,0 +1,64 @@
|
||||
Performance
|
||||
==
|
||||
|
||||
## Glossary
|
||||
|
||||
- **Critical Rendering Path** -
|
||||
- `requestAnimationFrame`
|
||||
|
||||
## General Strategies
|
||||
|
||||
1. Minimize Bytes.
|
||||
1. Reduce critical resources.
|
||||
1. Reduce CRP length. TODO: Explain what CRP length is.
|
||||
|
||||
## Loading
|
||||
|
||||
- Minify, Compress, Cache assets.
|
||||
- Browsers have a [preloader](https://andydavies.me/blog/2013/10/22/how-the-browser-pre-loader-makes-pages-load-faster/) to load assets ahead of time.
|
||||
|
||||
## Rendering
|
||||
|
||||
- Remove whitespace and comments from HTML/CSS/JS file via minification.
|
||||
- CSS
|
||||
- CSS blocks rendering AND JavaScript execution.
|
||||
- Split up CSS for fewer rendering blocking CSS stylesheets by using media attributes.
|
||||
- Download only the necessary CSS before the browser can start to render.
|
||||
- https://developers.google.com/web/fundamentals/design-and-ui/responsive/#css-media-queries
|
||||
- Use Simpler selectors.
|
||||
- JavaScript
|
||||
- JS blocks HTML parsing. If the script is external, it will have to be downloaded first. This incurs latency in network and execution.
|
||||
- Shift `<script>` tags to the bottom.
|
||||
- Async:
|
||||
- Scripts that don't modify the DOM or CSSOM can use the `async` attribute to tell the browser not to block DOM parsing and does not need to wait for the CSSOM to be ready.
|
||||
- Defer JavaScript execution:
|
||||
- There is also a `defer` attribute available. The difference is that with `defer`, the script waits to execute until after the document has been parsed, whereas `async` lets the script run in the background while the document is being parsed.
|
||||
- Use web workers for long running operations to move into a web worker thread.
|
||||
- Use `requestAnimationFrame`
|
||||
|
||||
###### References
|
||||
|
||||
- https://bitsofco.de/understanding-the-critical-rendering-path/
|
||||
|
||||
## Measuring
|
||||
|
||||
- [Navigation Timing API](https://developer.mozilla.org/en/docs/Web/API/Navigation_timing_API) is a JavaScript API for accurately measuring performance on the web. The API provides a simple way to get accurate and detailed timing statistics natively for page navigation and load events.
|
||||
- `performance.timing`: An object with the timestamps of the various events on the page. Some uses:
|
||||
- Network latency: `responseEnd` - `fetchStart`.
|
||||
- The time taken for page load once the page is received from the server: `loadEventEnd` - `responseEnd`.
|
||||
- The whole process of navigation and page load: `loadEventEnd` - `navigationStart`.
|
||||
|
||||
## Tools
|
||||
|
||||
- Yahoo YSlow
|
||||
- Google PageSpeed Insights
|
||||
- WebPageTest
|
||||
- Sitespeed.io
|
||||
- Google Lighthouse
|
||||
|
||||
## Web Performance Rules
|
||||
|
||||
- https://www.html5rocks.com/en/tutorials/webperformance/basics/
|
||||
- http://stevesouders.com/hpws/rules.php
|
||||
- https://developer.yahoo.com/performance/rules.html
|
||||
- https://browserdiet.com/en/
|
@ -0,0 +1,110 @@
|
||||
Security
|
||||
==
|
||||
|
||||
## Glossary
|
||||
|
||||
- **CORS** - Cross-Origin Resource Sharing (CORS).
|
||||
- **CSRF** - Cross-Site request forgery (CSRF) is an attack that forces an end user to execute unwanted actions on a web application in which they're currently authenticated.
|
||||
- **XSS** - Cross-site scripting (XSS).
|
||||
|
||||
## CORS
|
||||
|
||||
The same-origin policy protects users by disallowing websites to retrieve information from other websites of different origins. An origin is the triple {protocol, host, port}. Two resources are considered to be of the same origin if and only if all these values are exactly the same.
|
||||
|
||||
Cross-Origin Resource Sharing allows relaxing of the same-origin policy. CORS defines a way in which a browser and server can interact to determine whether or not it is safe to allow the cross-origin request.
|
||||
|
||||
This standard extends HTTP with a new `Origin` request header and `Access-Control-Allow-Origin` and `Access-Control-Allow-Methods` response headers. It allows servers to use a header to explicitly list origins and HTTP methods that may request a file or to use a wildcard and allow a file to be requested by any site. `XMLHttpRequest`s to a target origin from a different source origin will be blocked if the server did not allow CORS for source origin.
|
||||
|
||||
## CSRF
|
||||
|
||||
XSS vulnerabilities allow attackers to bypass essentially all CSRF preventions.
|
||||
|
||||
#### Protection
|
||||
|
||||
- Verifying Same Origin with Standard Headers
|
||||
- There are two steps to this check:
|
||||
1. Determining the origin the request is coming from (source origin).
|
||||
2. Determining the origin the request is going to (target origin).
|
||||
- Examine the `Origin`, `Referer` and `Host` Header values.
|
||||
- Synchronizer Tokens
|
||||
- The CSRF token is added as a hidden field for forms or within the URL.
|
||||
- Characteristics of a CSRF Token
|
||||
- Unique per user session
|
||||
- Large random value
|
||||
- Generated by a cryptographically secure random number generator
|
||||
- The server rejects the requested action if the CSRF token fails validation.
|
||||
- Double Cookie
|
||||
- When a user visits a site, the site should generate a (cryptographically strong) pseudorandom value and set it as a cookie on the user's machine. The site should require every form submission to include this pseudorandom value as a form value and also as a cookie value. When a POST request is sent to the site, the request should only be considered valid if the form value and the cookie value are the same. When an attacker submits a form on behalf of a user, he can only modify the values of the form. An attacker cannot read any data sent from the server or modify cookie values, per the same-origin policy. This means that while an attacker can send any value he wants with the form, he will be unable to modify or read the value stored in the cookie. Since the cookie value and the form value must be the same, the attacker will be unable to successfully submit a form unless he is able to guess the pseudorandom value.
|
||||
- The advantage of this approach is that it requires no server state; you simply set the cookie value once, then every HTTP POST checks to ensure that one of the submitted <input> values contains the exact same cookie value. Any difference between the two means a possible XSRF attack.
|
||||
- Cookie-to-Header Token
|
||||
- On login, the web application sets a cookie containing a random token that remains the same for the whole user session
|
||||
- `Set-Cookie: Csrf-token=i8XNjC4b8KVok4uw5RftR38Wgp2BFwql; expires=Thu, 23-Jul-2015 10:25:33 GMT; Max-Age=31449600; Path=/`
|
||||
- JavaScript operating on the client side reads its value and copies it into a custom HTTP header sent with each transactional request
|
||||
- `X-Csrf-Token: i8XNjC4b8KVok4uw5RftR38Wgp2BFwql`
|
||||
- The server validates presence and integrity of the token.
|
||||
- Security of this technique is based on the assumption that only JavaScript running within the same origin will be able to read the cookie's value.
|
||||
- JavaScript running from a rogue file or email will not be able to read it and copy into the custom header. Even though the `csrf-token` cookie will be automatically sent with the rogue request, the server will be still expecting a valid `X-Csrf-Token` header.
|
||||
- Use of Custom Request Headers
|
||||
- An alternate defense which is particularly well suited for AJAX endpoints is the use of a custom request header. This defense relies on the same-origin policy (SOP) restriction that only JavaScript can be used to add a custom header, and only within its origin. By default, browsers don't allow JavaScript to make cross origin requests. Such a header can be `X-Requested-With: XMLHttpRequest`.
|
||||
- If this is the case for your system, you can simply verify the presence of this header and value on all your server side AJAX endpoints in order to protect against CSRF attacks. This approach has the double advantage of usually requiring no UI changes and not introducing any server side state, which is particularly attractive to REST services. You can always add your own custom header and value if that is preferred.
|
||||
- Require user interaction
|
||||
- Require a re-authentication, using a one-time token, or requiring users to complete a captcha.
|
||||
|
||||
###### References
|
||||
|
||||
https://www.owasp.org/index.php/Cross-Site_Request_Forgery_(CSRF)
|
||||
|
||||
## HTTPS
|
||||
|
||||
HTTPS is HTTP over SSL/TLS. Servers and clients still speak exactly the same HTTP to each other, but over a secure SSL connection that encrypts and decrypts their requests and responses. The SSL layer has 2 main purposes:
|
||||
|
||||
1. Verifying that you are talking directly to the server that you think you are talking to.
|
||||
1. Ensuring that only the server can read what you send it and only you can read what it sends back.
|
||||
|
||||
#### TLS Handshake
|
||||
|
||||
// TODO. Crosscheck and add in more details.
|
||||
|
||||
1. The client computer sends a `ClientHello` message to the server with its Transport Layer Security (TLS) version, list of cipher algorithms and compression methods available.
|
||||
1. The server replies with a `ServerHello` message to the client with the TLS version, selected cipher, selected compression methods and the server's public certificate signed by a CA (Certificate Authority). The certificate contains a public key that will be used by the client to encrypt the rest of the handshake until a symmetric key can be agreed upon.
|
||||
1. The client verifies the server digital certificate against its list of trusted CAs. If trust can be established based on the CA, the client generates a string of pseudo-random bytes and encrypts this with the server's public key. These random bytes can be used to determine the symmetric key.
|
||||
1. The server decrypts the random bytes using its private key and uses these bytes to generate its own copy of the symmetric master key.
|
||||
1. The client sends a `Finished` message to the server, encrypting a hash of the transmission up to this point with the symmetric key.
|
||||
1. The server generates its own hash, and then decrypts the client-sent hash to verify that it matches. If it does, it sends its own `Finished` message to the client, also encrypted with the symmetric key.
|
||||
1. From now on the TLS session transmits the application (HTTP) data encrypted with the agreed symmetric key.
|
||||
|
||||
#### Downsides of HTTPS
|
||||
|
||||
- TLS handshake computational and latency overhead.
|
||||
- Encryption and decryption requires more computation power and bandwidth.
|
||||
|
||||
###### References
|
||||
|
||||
- https://blog.hartleybrody.com/https-certificates/
|
||||
- https://github.com/alex/what-happens-when#tls-handshake
|
||||
- http://robertheaton.com/2014/03/27/how-does-https-actually-work/
|
||||
|
||||
## XSS
|
||||
|
||||
XSS vulnerabilities allow attackers to bypass essentially all CSRF preventions.
|
||||
|
||||
```js
|
||||
const name = "<img src='x' onerror='alert(1)'>";
|
||||
el.innerHTML = name;
|
||||
```
|
||||
|
||||
http://shebang.brandonmintern.com/foolproof-html-escaping-in-javascript/
|
||||
|
||||
## Session hijacking
|
||||
|
||||
- https://developer.mozilla.org/en-US/docs/Web/HTTP/Cookies
|
||||
- https://www.nczonline.net/blog/2009/05/12/cookies-and-security/
|
||||
|
||||
|
||||
## Framebusting
|
||||
|
||||
https://seclab.stanford.edu/websec/framebusting/framebust.pdf
|
||||
|
||||
## API
|
||||
|
||||
https://github.com/shieldfy/API-Security-Checklist
|
@ -0,0 +1,28 @@
|
||||
Widgets
|
||||
==
|
||||
|
||||
Here are a list of commonly seen widgets/components and the issues/pitfalls with them.
|
||||
|
||||
## Autocomplete
|
||||
|
||||
TODO
|
||||
|
||||
## Carousel
|
||||
|
||||
TODO
|
||||
|
||||
## Dropdown
|
||||
|
||||
TODO
|
||||
|
||||
## Modal
|
||||
|
||||
- When dismissing, if a click handler is attached and you click on the modal content, the backdrop might receive the click be triggered as a result.
|
||||
|
||||
###### References
|
||||
|
||||
- https://css-tricks.com/dangers-stopping-event-propagation/
|
||||
|
||||
## Tooltip
|
||||
|
||||
TODO
|
@ -0,0 +1,130 @@
|
||||
Interview Formats
|
||||
==
|
||||
|
||||
The following interview formats are based on my experience interviewing with Bay Area companies. Formats would differ slightly depending on the roles you are applying to. Many companies like to use [CoderPad](https://coderpad.io/) for collaborative code editing. CoderPad supports running of the program, so you might be asked to fix your code such that it can be run. For front end interviews, many companies like to use [CodePen](https://codepen.io/), and it will be worth your time to familiarize yourself with the user interfaces of such web-based coding environments.
|
||||
|
||||
For on-site interviews at smaller (non-public) companies, most will allow (and prefer) that you use your own laptop. Hence it is important that you prepare your development environment in advance.
|
||||
|
||||
## Companies
|
||||
|
||||
- [Airbnb](#airbnb)
|
||||
- [Asana](#asana)
|
||||
- [Dropbox](#dropbox)
|
||||
- [Facebook](#facebook)
|
||||
- [Google](#google)
|
||||
- [Lyft](#lyft)
|
||||
- [Palantir](#palantir)
|
||||
- [WhatsApp](#whatsapp)
|
||||
|
||||
### Airbnb
|
||||
|
||||
- Recruiter phone screen.
|
||||
- Technical phone interview:
|
||||
- 1 or 2 x Algorithm/front end on CoderPad/CodePen.
|
||||
- On-site (General):
|
||||
- 2 x Algorithm coding on CoderPad.
|
||||
- 1 x System design/architecture.
|
||||
- 1 x Past experience/project.
|
||||
- 2 x Cross functional.
|
||||
- On-site (Front End):
|
||||
- 2 x Front end coding on CodePen. Use any framework/library.
|
||||
- 1 x General coding on your own laptop.
|
||||
- 1 x Past experience/project.
|
||||
- 2 x Cross functional.
|
||||
- Tips:
|
||||
- All sessions involve coding on your own laptop. Prepare your development environment in advance.
|
||||
- You are allowed to look up APIs if you need to.
|
||||
- They seem to place high emphasis on compilable, runnable code in all their coding rounds.
|
||||
- Cross functional interviews will involve getting Airbnb employees from any discipline to speak with you. These interviews are mostly non-technical but are extremely important to Airbnb because they place a high emphasis on cultural fit. Do look up the Airbnb section of the behavioural questions to know what sort of questions to expect.
|
||||
|
||||
### Asana
|
||||
|
||||
- Recruiter phone screen.
|
||||
- Technical phone interview.
|
||||
- On-site (Product Engineer):
|
||||
- 3 x Algorithm and system design on whiteboard within the same session.
|
||||
- 1 x Algorithm on laptop and system design. This session involves writing code on your own laptop to solve 3 well-defined algorithm problems in around 45 minutes after which an engineer will come in and review the code with you. You are not supposed to run the code while working on the problem.
|
||||
- Tips:
|
||||
- No front end questions were asked.
|
||||
- Asana places high emphasis on System Design and makes heavy use of the whiteboard. You do not necessarily have to write code for the algorithm question of the first three interviews.
|
||||
- All 4 sessions involve algorithms and system design. One of the sessions will be conducted by an Engineering Manager.
|
||||
- The last session will involve coding on your own laptop. Prepare your development environment in advance.
|
||||
- Regardless of Product Engineer or Engineering Generalist position, their interview format and questions are similar.
|
||||
|
||||
### Dropbox
|
||||
|
||||
- Recruiter phone screen.
|
||||
- Technical phone interviews:
|
||||
- 2 x Algorithm/front end on CoderPad/CodePen.
|
||||
- On-site (Front End):
|
||||
- 2 x Front end on CodePen. Only Vanilla JS or jQuery allowed.
|
||||
- 1 x General coding on CoderPad.
|
||||
- 1 x All around. Meet with an Engineering Manager and discussing past experiences and working style.
|
||||
- Tips:
|
||||
- You can code on your own laptop and look up APIs.
|
||||
- Dropbox recruiters are very nice and will give you helpful information on what kind of questions to expect for the upcoming sessions.
|
||||
- One of the front end sessions involve coding up a pixel-perfect version of a real page on www.dropbox.com. You'll be given a spec of the desired page and you'll be asked to create a working version during the interview.
|
||||
|
||||
### Facebook
|
||||
|
||||
- Recruiter phone screen.
|
||||
- Technical phone interviews:
|
||||
- 1 or 2 x Algorithm/front end on Skype/CoderPad.
|
||||
- On-site (Front End):
|
||||
- 2 x Technical coding interview on whiteboard (Ninja).
|
||||
- 1 x Behavioural (Jedi). Meet with an Engineering Manager and discussing past experiences and working style.
|
||||
- 1 x Design/architecture on whiteboard (Pirate).
|
||||
- Tips:
|
||||
- You are only allowed to use the whiteboard. No laptops involved.
|
||||
- For the Jedi round, you may be asked a technical question at the end of it. Front end candidates will be given a small HTML/CSS problem nearing the end of the session.
|
||||
- For the Ninja rounds, you may be asked one to two questions depending on how fast you progress through the question.
|
||||
|
||||
### Google
|
||||
|
||||
- Recruiter phone screen.
|
||||
- Technical phone interview:
|
||||
- 1 or 2 x algorithm on Google Doc.
|
||||
- On-site (Front End):
|
||||
- 3 x Front end on whiteboard. Have to use Vanilla JS (or at the most, jQuery).
|
||||
- 2 x Algorithm on whiteboard.
|
||||
- Tips:
|
||||
- You are only allowed to use the whiteboard. No laptops involved.
|
||||
- In rare cases, candidates may even be allowed to skip the phone interview round and advanced to on-site directly.
|
||||
|
||||
### Lyft
|
||||
|
||||
- Recruiter phone screen.
|
||||
- Technical phone interview:
|
||||
- 1 x Algorithm/Front end over JSFiddle.
|
||||
- On-site (Front End):
|
||||
- 4 x Front end on Coderpad/your own laptop. Use any language/framework.
|
||||
- 1 x Behavioural. Meet with an Engineering Manager and go through candidate's resume.
|
||||
- Tips:
|
||||
- Can use whiteboard and/or laptop.
|
||||
- For front end coding, I opted to use React and had to set up the projects on the spot using `create-react-app`.
|
||||
|
||||
### Palantir
|
||||
|
||||
- Recruiter phone screen.
|
||||
- Technical phone interview:
|
||||
- 1 x Algorithm over HackerRank CodePair and Skype.
|
||||
- On-site (General):
|
||||
- 2 x Algorithm on whiteboard.
|
||||
- 1 x Decomposition (system design) on whiteboard.
|
||||
- On-site (Front End):
|
||||
- 1 x Front end on your own laptop. This session lasts about 1.5 hours. Use any library/framework.
|
||||
- 1 x Decomposition (system design) on whiteboard.
|
||||
- Tips:
|
||||
- I opted to use React and had to set up projects on the spot using `create-react-app`.
|
||||
- You may be asked to meet with Engineering Managers after the technical sessions and it's not necessarily a good/bad thing.
|
||||
|
||||
### WhatsApp
|
||||
|
||||
- Recruiter phone screen.
|
||||
- Technical phone interview:
|
||||
- 2 x Algorithm over CoderPad.
|
||||
- On-site (Web Client Developer):
|
||||
- 4 x Algorithm on whiteboard.
|
||||
- Tips:
|
||||
- No front end questions were asked.
|
||||
- 1 of the interviewers is an Engineering Manager.
|
@ -0,0 +1,86 @@
|
||||
Negotiation
|
||||
==
|
||||
|
||||
### Ten Rules of Negotiation
|
||||
|
||||
Key points extracted from "Ten Rules for Negotiating a Job Offer" [Part 1](http://haseebq.com/my-ten-rules-for-negotiating-a-job-offer/) and [Part 2](https://haseebq.com/how-not-to-bomb-your-offer-negotiation/) by Haseeb Qureshi.
|
||||
|
||||
#### Get everything in writing
|
||||
|
||||
Note down EVERYTHING on your phone call with the recruiters as they may be helpful later on. Even if there are things that are not directly monetary, if they relate to the job, write them down. If they tell you "we're working on porting the front-end to Angular," write that down. If they say they have 20 employees, write that down. You want as much information as you can. You'll forget a lot of this stuff, and it's going to be important in informing your final decision.
|
||||
|
||||
#### Always keep the door open
|
||||
|
||||
Never give up your negotiating power until you're absolutely ready to make an informed, deliberate final decision. This means your job is to traverse as many of these decision points as possible without giving up the power to continue negotiating. Very frequently, your interlocutor will try to trick you into making a decision, or tie you to a decision you didn't commit to. You must keep verbally jiu-jitsu-ing out of these antics until you're actually ready to make your final decision.
|
||||
|
||||
#### Information is power
|
||||
|
||||
To protect your power in the negotiation, you must protect information as much as possible. A corollary of this rule is that you should not reveal to companies what you're currently making. So given this offer, don't ask for more money or equity or anything of the sort. Don't comment on any specific details of the offer except to clarify them. Companies will ask about your current compensation at different stages in the process—some before they ever interview you, some after they decide to make you an offer. But be mindful of this, and protect information.
|
||||
|
||||
> "Yeah, [COMPANY_NAME] sounds great! I really thought this was a good fit, and I'm glad that you guys agree. Right now I'm talking with a few other companies so I can't speak to the specific details of the offer until I'm done with the process and get closer to making a decision. But I'm sure we'll be able to find a package that we're both happy with, because I really would love to be a part of the team."
|
||||
|
||||
#### Always be positive
|
||||
|
||||
Even if the offer is bad, it's extremely important to remain positive and excited about the company. This is because your excitement is one of your most valuable assets in a negotiation.
|
||||
|
||||
Despite whatever is happening in the negotiation, give the company the impression that 1) you still like the company, and that 2) you're still excited to work there, even if the numbers or the money or the timing is not working out. Generally the most convincing thing to signal this is to reiterate you love the mission, the team, or the problem they're working on, and really want to see things work out.
|
||||
|
||||
#### Don't be the decision maker
|
||||
|
||||
Even if you don't particularly care what your friends/family/husband/mother thinks, by mentioning them, you're no longer the only person the recruiter needs to win over. There's no point in them trying to bully and intimidate you; the "true decision-maker" is beyond their reach. This is a classic technique in customer support and remediation. It's never the person on the phone's fault, they're just some poor schmuck doing their job. It's not their decision to make. This helps to defuse tension and give them more control of the situation.
|
||||
|
||||
> I'll look over some of these details and discuss it with my [FAMILY/CLOSE_FRIENDS/SIGNIFICANT_OTHER]. I'll reach out to you if I have any questions. Thanks so much for sharing the good news with me, and I'll be in touch!
|
||||
|
||||
It's much harder to pressure someone if they're not the final decision-maker. So take advantage of that.
|
||||
|
||||
#### Have alternatives
|
||||
|
||||
If you're already in the pipeline with other companies (which you should be if you're doing it right), you should proactively reach out and let them know that you've just received an offer. Try to build a sense of urgency. Regardless of whether you know the expiration date, all offers expire at some point, so take advantage of that.
|
||||
|
||||
> Hello [PERSON],
|
||||
>
|
||||
> I just wanted to update you on my own process. I've just received an offer from [COMPANY] which is quite strong. That said, I'm really excited about [YOUR AMAZING COMPANY] and really want to see if we can make it work. Since my timeline is now compressed, is there anything you can do to expedite the process?
|
||||
|
||||
Should you specifically mention the company that gave you an offer? Depends. If it's a well-known company or a competitor, then definitely mention it. If it's a no-name or unsexy company, you should just say you received an offer. If it's expiring soon, you should mention that as well.
|
||||
|
||||
Either way, send out a letter like this to every single company you're talking to. No matter how hopeless or pointless you think your application is, you want to send this signal to everyone who is considering you in the market.
|
||||
|
||||
Companies care that you've received other offers. They care because each company knows that their own process is noisy, and the processes of most other companies are also noisy. But a candidate having multiple offers means that they have multiple weak signals in their favor. Combined, these converge into a much stronger signal than any single interview. It's like knowing that a student has a strong SAT score, and GPA, and won various scholarships. Sure, it's still possible that they're a dunce, but it's much harder for that to be true.
|
||||
|
||||
This is not to say that companies respond proportionally to these signals, or that they don't overvalue credentials and brands. They do. But caring about whether you have other offers and valuing you accordingly is completely rational.
|
||||
|
||||
Tell other companies that you've received offers. Give them more signals so that they know you're a valued and compelling candidate. And understand why this changes their mind about whether to interview you.
|
||||
|
||||
Your goal should be to have as many offers overlapping at the same time as possible. This will maximize your window for negotiating.
|
||||
|
||||
Have a strong BATNA (Best Alternative To a Negotiated Agreement) and communicate it.
|
||||
|
||||
> I 've received another offer from [OTHER CORP] that's very compelling on salary, but I really love the mission of [YOUR COMPANY] and think that it would overall be a better fit for me.
|
||||
|
||||
> I'm also considering going back to grad school and getting a Master's degree in Postmodern Haberdashery. I'm excited about [YOUR COMPANY] though and would love to join the team, but the package has to make sense if I'm going to forego a life of ironic hatmaking.
|
||||
|
||||
#### Proclaim reasons for everything
|
||||
|
||||
It's kind of a brain-hack, both for yourself and for your negotiating partner. Just stating a reason (any reason) makes your request feel human and important. It's not you being greedy, it's you trying to fulfill your goals.
|
||||
|
||||
The more unobjectionable and sympathetic your reason, the better. If it's medical expenses, or paying off student loans, or taking care of family, you'll bring tears to their eyes.
|
||||
|
||||
Just go with it, state a reason for everything, and you'll find recruiters more willing to become your advocate.
|
||||
|
||||
#### Be motivated by more than just money
|
||||
|
||||
You should be motivated by money too of course, but it should be one among many dimensions you're optimizing for. How much training you get, what your first project will be, which team you join, or even who your mentor will be—these are all things you can and should negotiate.
|
||||
|
||||
Of course, to negotiate well you need to understand the other side's preferences. You want to make the deal better for both of you.
|
||||
|
||||
#### Understand what they value
|
||||
|
||||
Remember that you can always get salary raises as you continue to work at the company, but there's only one point at which you can get a signing bonus.
|
||||
|
||||
The easiest thing for a company to give though is stock (if the company offers stock). Companies like giving stock because it invests you in the company and aligns interests. It also shifts some of the risk from the company over to you and burns less cash.
|
||||
|
||||
#### Be winnable
|
||||
|
||||
This is more than just giving the company the impression that you like them (which you continually should). But more so that you must give any company you're talking to a clear path on how to win you. Don't bullshit them or play stupid games. Be clear and unequivocal with your preferences and timeline.
|
||||
|
||||
Don't waste their time or play games for your own purposes. Even if the company isn't your dream company, you must be able to imagine at least some package they could offer you that would make you sign. If not, politely turn them down.
|
@ -0,0 +1,10 @@
|
||||
Self Introduction
|
||||
==
|
||||
|
||||
You can rephrase the question like this:
|
||||
|
||||
"Tell me about your journey into tech. How did you get interested in coding, and why was web development a good fit for you? How is that applicable to our _____ role or company goals?"
|
||||
|
||||
###### References
|
||||
|
||||
- [8 Secrets to Software Engineer Self Introduction](http://blog.gainlo.co/index.php/2016/10/14/8-secretes-software-engineer-self-introduction)
|
@ -0,0 +1,26 @@
|
||||
function binarySearch(arr, target) {
|
||||
let left = 0;
|
||||
let right = arr.length - 1;
|
||||
while (left < right) {
|
||||
let mid = left + Math.floor((right - left) / 2);
|
||||
if (arr[mid] === target) {
|
||||
return mid;
|
||||
}
|
||||
if (arr[mid] < target) {
|
||||
left = mid + 1;
|
||||
} else {
|
||||
right = mid - 1;
|
||||
}
|
||||
}
|
||||
return left;
|
||||
}
|
||||
|
||||
console.log(binarySearch([1, 2, 3, 10], 1) === 0)
|
||||
console.log(binarySearch([1, 2, 3, 10], 2) === 1)
|
||||
console.log(binarySearch([1, 2, 3, 10], 3) === 2)
|
||||
console.log(binarySearch([1, 2, 3, 10], 10) === 3)
|
||||
console.log(binarySearch([1, 2, 3, 10], 9) === 3)
|
||||
console.log(binarySearch([1, 2, 3, 10], 4) === 3)
|
||||
console.log(binarySearch([1, 2, 3, 10], 0) === 0)
|
||||
console.log(binarySearch([1, 2, 3, 10], 11) === 3)
|
||||
console.log(binarySearch([5, 7, 8, 10], 3) === 0)
|
@ -0,0 +1,22 @@
|
||||
def binary_search(arr, target):
|
||||
left = 0;
|
||||
right = len(arr) - 1
|
||||
while left < right:
|
||||
mid = left + (right - left) / 2;
|
||||
if arr[mid] == target:
|
||||
return mid
|
||||
elif arr[mid] < target:
|
||||
left = mid + 1
|
||||
else:
|
||||
right = mid - 1
|
||||
return left
|
||||
|
||||
print(binary_search([1, 2, 3, 10], 1) == 0)
|
||||
print(binary_search([1, 2, 3, 10], 2) == 1)
|
||||
print(binary_search([1, 2, 3, 10], 3) == 2)
|
||||
print(binary_search([1, 2, 3, 10], 10) == 3)
|
||||
print(binary_search([1, 2, 3, 10], 9) == 3)
|
||||
print(binary_search([1, 2, 3, 10], 4) == 3)
|
||||
print(binary_search([1, 2, 3, 10], 0) == 0)
|
||||
print(binary_search([1, 2, 3, 10], 11) == 3)
|
||||
print(binary_search([5, 7, 8, 10], 3) == 0)
|
@ -0,0 +1,19 @@
|
||||
# For mapping a lowercase character to a prime number.
|
||||
# Useful for checking whether two strings are anagram or permutations of each other.
|
||||
primes = {
|
||||
'a': 2, 'b': 3, 'c': 5, 'd': 7, 'e': 11, 'f': 13,
|
||||
'g': 17, 'h': 19, 'i': 23, 'j': 29, 'k': 31, 'l': 37,
|
||||
'm': 41, 'n': 43, 'o': 47, 'p': 53, 'q': 59, 'r': 61,
|
||||
's': 67, 't': 71, 'u': 73, 'v': 79, 'w': 83, 'x': 89,
|
||||
'y': 97, 'z': 101, ' ': 103,
|
||||
}
|
||||
|
||||
import functools
|
||||
|
||||
def mul(seq):
|
||||
return functools.reduce(lambda a, b: a * b, seq, 1)
|
||||
|
||||
def prime_value_of_string(string):
|
||||
return mul([primes[c] for c in string])
|
||||
|
||||
print(prime_value_of_string('abcde'))
|
@ -0,0 +1,35 @@
|
||||
function graphTopoSort(numberNodes, edges) {
|
||||
const nodes = new Map();
|
||||
const order = [];
|
||||
const queue = [];
|
||||
for (let i = 0; i < numberNodes; i++) {
|
||||
nodes.set(i, { in: 0, out: new Set() });
|
||||
}
|
||||
|
||||
edges.forEach(edge => {
|
||||
const [node_id, pre_id] = edge;
|
||||
nodes.get(node_id).in += 1;
|
||||
nodes.get(pre_id).out.add(node_id);
|
||||
});
|
||||
|
||||
for (let [node_id, value] of nodes.entries()) {
|
||||
if (value.in === 0) {
|
||||
queue.push(node_id);
|
||||
}
|
||||
}
|
||||
|
||||
while (queue.length) {
|
||||
const node_id = queue.shift();
|
||||
for (let outgoing_id of nodes.get(node_id).out) {
|
||||
nodes.get(outgoing_id).in -= 1;
|
||||
if (nodes.get(outgoing_id).in === 0) {
|
||||
queue.push(outgoing_id);
|
||||
}
|
||||
}
|
||||
order.push(node_id);
|
||||
}
|
||||
|
||||
return order.length == numberNodes ? order : [];
|
||||
}
|
||||
|
||||
console.log(graphTopoSort(3, [[0, 1], [0, 2]]))
|
@ -0,0 +1,24 @@
|
||||
def graph_dfs(matrix):
|
||||
rows, cols = len(matrix), len(matrix[0])
|
||||
visited = set()
|
||||
directions = ((0, 1), (0, -1), (1, 0), (-1, 0))
|
||||
def dfs(i, j):
|
||||
if (i, j) in visited:
|
||||
return
|
||||
visited.add((i, j))
|
||||
# Traverse neighbors.
|
||||
for direction in directions:
|
||||
next_i, next_j = i + direction[0], j + direction[1]
|
||||
if 0 <= next_i < rows and 0 <= next_j < cols: # Check boundary.
|
||||
# Add any other checking here ^
|
||||
dfs(next_i, next_j)
|
||||
|
||||
for i in range(rows):
|
||||
for j in range(cols):
|
||||
dfs(i, j)
|
||||
|
||||
graph_dfs([
|
||||
[1, 2, 3, 4],
|
||||
[5, 6, 7, 8],
|
||||
[9, 10, 11, 12],
|
||||
])
|
@ -0,0 +1 @@
|
||||
# TODO
|
@ -0,0 +1,21 @@
|
||||
def graph_topo_sort(num_nodes, edges):
|
||||
from collections import deque
|
||||
nodes, order, queue = {}, [], deque()
|
||||
for node_id in range(num_nodes):
|
||||
nodes[node_id] = { 'in': 0, 'out': set() }
|
||||
for node_id, pre_id in edges:
|
||||
nodes[node_id]['in'] += 1
|
||||
nodes[pre_id]['out'].add(node_id)
|
||||
for node_id in nodes.keys():
|
||||
if nodes[node_id]['in'] == 0:
|
||||
queue.append(node_id)
|
||||
while len(queue):
|
||||
node_id = queue.pop()
|
||||
for outgoing_id in nodes[node_id]['out']:
|
||||
nodes[outgoing_id]['in'] -= 1
|
||||
if nodes[outgoing_id]['in'] == 0:
|
||||
queue.append(outgoing_id)
|
||||
order.append(node_id)
|
||||
return order if len(order) == num_nodes else []
|
||||
|
||||
print(graph_topo_sort(3, [[0, 1], [0, 2]]))
|
@ -0,0 +1,19 @@
|
||||
function isSubsequence(s, t) {
|
||||
if (s.length > t.length) {
|
||||
return false;
|
||||
}
|
||||
let matchedLength = 0;
|
||||
for (let i = 0; i < t.length; i++) {
|
||||
if (matchedLength < s.length && s[matchedLength] === t[i]) {
|
||||
matchedLength += 1;
|
||||
}
|
||||
}
|
||||
return matchedLength === s.length;
|
||||
}
|
||||
|
||||
console.log(isSubsequence('abc', 'abcde') === true);
|
||||
console.log(isSubsequence('abd', 'abcde') === true);
|
||||
console.log(isSubsequence('abf', 'abcde') === false);
|
||||
console.log(isSubsequence('abef', 'abcde') === false);
|
||||
console.log(isSubsequence('abcdef', 'abcde') === false);
|
||||
console.log(isSubsequence('a', 'abcde') === true);
|
@ -0,0 +1,13 @@
|
||||
def is_subsequence(s, t):
|
||||
"""
|
||||
:type s: str
|
||||
:type t: str
|
||||
:rtype: bool
|
||||
"""
|
||||
if len(s) > len(t):
|
||||
return False
|
||||
matched_s = 0
|
||||
for char in t:
|
||||
if matched_s < len(s) and s[matched_s] == char:
|
||||
matched_s += 1
|
||||
return matched_s == len(s)
|
@ -0,0 +1 @@
|
||||
# TODO
|
@ -0,0 +1,11 @@
|
||||
function treeEqual(node1, node2) {
|
||||
if (!node1 && !node2) {
|
||||
return true;
|
||||
}
|
||||
if (!node1 || !node2) {
|
||||
return false;
|
||||
}
|
||||
return node1.val == node2.val &&
|
||||
treeEqual(node1.left, node2.left) &&
|
||||
treeEqual(node1.right, node2.right);
|
||||
}
|
@ -0,0 +1,10 @@
|
||||
function treeMirror(node) {
|
||||
if (!node) {
|
||||
return;
|
||||
}
|
||||
let temp = node.left;
|
||||
node.left = node.right;
|
||||
node.right = temp;
|
||||
treeMirror(node.left);
|
||||
treeMirror(node.right);
|
||||
}
|
@ -0,0 +1,8 @@
|
||||
def tree_equal(node1, node2):
|
||||
if not node1 and not node2:
|
||||
return True
|
||||
if not node1 or not node2:
|
||||
return False
|
||||
return node1.val == node2.val and \
|
||||
tree_equal(node1.left, node2.left) and \
|
||||
tree_equal(node1.right, node2.right)
|
@ -0,0 +1,6 @@
|
||||
def tree_mirror(node):
|
||||
if not node:
|
||||
return
|
||||
node.left, node.right = node.right, node.left
|
||||
tree_mirror(node.left)
|
||||
tree_mirror(node.right)
|
@ -0,0 +1,62 @@
|
||||
# Various iterative ways of traversing a tree.
|
||||
def inorder_traversal(root):
|
||||
"""
|
||||
:type root: TreeNode
|
||||
:rtype: List[int]
|
||||
"""
|
||||
if not root:
|
||||
return []
|
||||
result = []
|
||||
stack = [root]
|
||||
while len(stack) > 0:
|
||||
curr_node = stack.pop()
|
||||
if curr_node.left:
|
||||
stack.append(curr_node)
|
||||
stack.append(curr_node.left)
|
||||
curr_node.left = None
|
||||
else:
|
||||
result.append(curr_node.val)
|
||||
if curr_node.right:
|
||||
stack.append(curr_node.right)
|
||||
return result
|
||||
|
||||
def preorder_traversal(root):
|
||||
"""
|
||||
:type root: TreeNode
|
||||
:rtype: List[int]
|
||||
"""
|
||||
if not root:
|
||||
return []
|
||||
result = []
|
||||
stack = [root]
|
||||
while len(stack) > 0:
|
||||
curr_node = stack.pop()
|
||||
result.append(curr_node.val)
|
||||
if curr_node.right:
|
||||
stack.append(curr_node.right)
|
||||
if curr_node.left:
|
||||
stack.append(curr_node.left)
|
||||
return result
|
||||
|
||||
def postorder_traversal(root):
|
||||
"""
|
||||
:type root: TreeNode
|
||||
:rtype: List[int]
|
||||
"""
|
||||
if not root:
|
||||
return []
|
||||
result = []
|
||||
stack = [root]
|
||||
while len(stack) > 0:
|
||||
curr_node = stack.pop()
|
||||
if curr_node.left:
|
||||
stack.append(curr_node)
|
||||
stack.append(curr_node.left)
|
||||
curr_node.left = None
|
||||
elif curr_node.right:
|
||||
stack.append(curr_node)
|
||||
stack.append(curr_node.right)
|
||||
curr_node.right = None
|
||||
else:
|
||||
result.append(curr_node.val)
|
||||
return result
|
@ -0,0 +1,80 @@
|
||||
class Trie(object):
|
||||
def __init__(self):
|
||||
"""
|
||||
Initialize your data structure here.
|
||||
"""
|
||||
self.d = {}
|
||||
|
||||
def insert(self, word):
|
||||
"""
|
||||
Inserts a word into the trie.
|
||||
:type word: str
|
||||
:rtype: void
|
||||
"""
|
||||
curr = self.d
|
||||
for char in word:
|
||||
if char not in curr:
|
||||
curr[char] = {}
|
||||
curr = curr[char]
|
||||
curr['#'] = {} # Using an empty dict rather than a boolean value makes recursive traversal easier.
|
||||
|
||||
def search(self, word):
|
||||
"""
|
||||
Returns if the word is in the trie.
|
||||
:type word: str
|
||||
:rtype: bool
|
||||
"""
|
||||
curr = self.d
|
||||
for char in word:
|
||||
if char in curr:
|
||||
curr = curr[char]
|
||||
else:
|
||||
return False
|
||||
return '#' in curr
|
||||
|
||||
def startsWith(self, prefix):
|
||||
"""
|
||||
Returns if there is any word in the trie that starts with the given prefix.
|
||||
:type prefix: str
|
||||
:rtype: bool
|
||||
"""
|
||||
curr = self.d
|
||||
for char in prefix:
|
||||
if char in curr:
|
||||
curr = curr[char]
|
||||
else:
|
||||
return False
|
||||
return True
|
||||
|
||||
def searchRegex(self, word):
|
||||
"""
|
||||
Returns if the word is in the data structure. A word could contain the dot character '.' to represent any one letter.
|
||||
:type word: str
|
||||
:rtype: bool
|
||||
"""
|
||||
def traverse(node, index):
|
||||
if len(word) == index:
|
||||
return '#' in node
|
||||
char = word[index]
|
||||
if char == '.':
|
||||
for key in node.keys():
|
||||
if traverse(node[key], index+1):
|
||||
return True
|
||||
return False
|
||||
else:
|
||||
if char not in node:
|
||||
return False
|
||||
return traverse(node[char], index + 1)
|
||||
return traverse(self.d, 0)
|
||||
|
||||
# Example
|
||||
trie = Trie()
|
||||
trie.insert('hello')
|
||||
print(trie.search('hello') == True)
|
||||
print(trie.startsWith('hello') == True)
|
||||
print(trie.startsWith('hel') == True)
|
||||
print(trie.search('world') == False)
|
||||
print(trie.startsWith('wor') == False)
|
||||
print(trie.searchRegex('..llo') == True)
|
||||
print(trie.searchRegex('..llx') == False)
|
||||
print(trie.searchRegex('..') == False)
|
Loading…
Reference in new issue