Bobbyy.org Everything about me. 2019-04-06T10:23:28-07:00 http://bobbyy.org Bobby Yan http://bobbyy.org tmux Cheatsheet and Shortcuts Bobby Yan http://bobbyy.org http://bobbyy.org/tmux-cheatsheeet-and-shortcuts 2018-09-12T00:00:00-07:00 Basics
• Start an unnamed session: tmux
• Start a named session: tmux new -s <name>
• Attach: tmux a #
• Attach to named session: tmux a -t <name>
• Detch from session: Ctrl + b (or your custom <prefix>), then d
• List all sessions: tmux ls
• Kill a named session: tmux kill-ses -t <name>
• Kill the server: tmux kill-server

Shortcuts

Shortcuts for sessions:
<prefix>, d # detach from session
<prefix>, s # select from sessions

Other Good Resources

• List of good tweaks compatible with iOS 11.3.1 here.
]]>
Sorting Bobby Yan http://bobbyy.org http://bobbyy.org/cs61b-sorting 2018-03-31T09:00:00-07:00 Overview
• The Sorting Problem
• Selection Sort, Heapsort
• Mergesort
• Insertion Sort
• Quicksort
• Shell’s Sort (Extra)

Sorting – Definitions

A sort is a permutation (re-arrangement) of a sequence of elements that bring them into order according to some total order. A total order $\preceq$ is

• Total: $x \preceq y$ or $y \preceq x$ for all $x, y$.
• Reflexive: $x \preceq x$
• Antisymmetric: $x \preceq y$ AND $y \preceq x$ $\Longleftrightarrow$ $x = y$.
• Transitive: $x \preceq y$ and $y \preceq z$ implies $x \preceq z$.

Unequal items may be “equivalent” under these definitions. e.g. given strings sorted by length, either may be put first. Strings of equal length are equivalent under this sorting, but not equal.

Sorting: An Alternate Viewpoint

An inversion is a pair of elements that are out of order.

Example: 0 1 1 2 3 4 8 6 9 5 7 has 6 inversions out 66 possible ones. The inversions are: 8-6, 8-5, 8-7, 6-5, 9-5, 9-7.

So, goal of sorting is: Given a sequence of elements with Z inversions, perform a sequence of operations that reduces inversions to 0.

Performance Definitions

Characterizations of the runtime efficiency are sometimes called time complexity of an algorithm. e.g. DFS has time complexity $\Theta(V+E)$.

Chracterizations of the “extra” memory usage of an algorithm is sometimes called the space complexity of an algorithm. e.g. DFS has space complexity of $\Theta(V)$. Note that the graph tiself takes up $\Theta(V+E)$ space, but we don’t count this as a part of DFS’s runtime.

Selection Sort

• Find the smallest item of the unsorted portion.
• Move this item to the front (but end of the sorted portion of the array) and “fix” it.
• Repeat for unfixed items until all items are fixed.

Time complexity: $\Theta(N^2)$ time if we use an array (or similar data structures). This is inefficient because we keep looking at almost the whole array again and again each time we find the min.

Space complexity: $\Theta(1)$ since we don’t need extra space.

Heapsort

Idea: Make getting the minimum fast by using a heap.

Note: for reasons that’ll become clear later, we’ll use a MaxHeap instead of a MinHeap.

Naive heapsorting N items:

• Insert all items into a MaxHeap, and discard the input array. $\Theta(N\log N)$ time.
• Create output array. $\Theta(N)$ time.
• Repeat N times:
• Delete largest item from the MaxHeap $O(\log N)$ time.
• Put it at the end of the unused part of the output array.

What’s the total runtime of Heapsort?

$\Theta(N\log N + N + N \log N) = \Theta(N\log N)$. Much better than Selection sort!

Why MaxHeap?

Because we can’t fluidly swap to the end.

In-place Heapsort

• Rather than inserting into a new array of length N + 1, we can use a process known as “bottom-up heapification” to convert the array into a heap (without using any extra memory).
• This avoids the need for an extra copy of all the data.

Bottom-up Heapify

1. Sink nodes in reverse level order (go through array in reverse order).
2. After sinking, guaranteed that tree rooted at position k is a heap.

But after we bottom-up heapify the input array, the array is still not sorted. But, here’s the magic:

We removeMax of the heap and add to the half-end of the array.

In-place Heapsort Runtime

Breakdown:

• Bottom-up Heapification: $O(N\log N)$ time. (For expert, prove that this is actually $\Theta(N)$ in the worst case.)
• Selecting largest item: $\Theta(1)$ time.
• Removing largest item: $O(\log N)$ for each removal.

Time complexity: $O(N\log N)$.

Memory complexity: $\Theta(1)$. (Note: if done recursively, actually $\Theta(\log N)$ to track recursive calls.)

Mergesort

Idea:

• Split items into two roughly even pieces
• Mergesort each half
• Merge the two sorted halves

Time complexity: $\Theta(N\log N)$.

Memory complexity: $\Theta(N)$.

Faster than Heapsort? How? Because faster in tilde notation, and for reasons to be known in 61C. (Hint: Heapsort has bad cache performance.)

Insertion Sort

Idea:

• Add each item from input, inserting into output at right point.

Naive approach: If output sequence contains k items, worst cost to insert a single item is k because we need to move everything over.

Efficient method: Do everything in space using swapping.

In-place Insertion Sort

Strategy:

• Repeat for i=0 to N-1:
• Designate item i as the traveling item.
• Swap item backwards until traveller is in the right place among all previously examined items.

Flavor: Some travellers move very little, some move far.

Insertion Sort Runtime

$\Omega(N)$, $O(N^2)$.

Picking the Best Sort

Suppose some evil entity give you a list that is sorted for all but one element, which sorting algorithm should you use?

Use Insertion Sort. Insertion sort works very well for almost sorted arrays because if an array has $J$ inversions, the work needed for Insertion sort is $\Theta(N+K)$.

• Define an almost sorted array as one in which the number of inversions $\leq cN$ for some $c$.
• Less obious observation: For small arrays ($% $ or so), empirical fact is that insertion sort is fastest.

Q: For an array that is sorted, I pick a random element and change it, then which algorithm is the best?

A: Insertion Sort. Because worst case is linear time, but merge sort is always $N \log N$.

Insertion Sort has a special property: its runtime is proportional to the number of inversions. $\Longrightarrow \Theta(N+K)$ runtime, where $K$ is the number of inversions.

As a result, even though its worst case is $O(N^2)$, it can be really good in certain cases.

Less obvious thing: For small arrays (N < 15 or so), insertion sort is fastest. Rough idea is that: Heapsort and Mergesort are divide and conquer algorithms with too much overhead, whereas insertion sort goes straight to the conquest.

Quicksort

Much stranger core idea: Partitioning

Invented by Tony Hoare, a novice programmer at the time.

Partitioning

To partition an array a[] on element x=a[i] is to rearrange a[] so that:

• x moves to position j (which may be same as i)
• All entires to the left of x are less than or equal to x
• All entires to the right of x are greater than or equal to x

Interview Question (Partitioning)

Given an array of colors where the 0th element is white, and the remaining elements are either red or blue. How can you rearrange the array so that all red squares are to the left, and all blue are to the right of the white square? The algorithm must take $\Theta(N)$ time with no space restriction.

Approach #1: Red pointer, blue pointer approach

• Create an empty array of size N. Set red pointer at 0 and blue pointer at N - 1.
• Go through the array, if red, add at red pointer and increment red pointer, if blue, add at blue pointer and decrement blue pointer.

Approach #2: Two array solution.

• One array for red, one array for blue. At the end, merge the two array wiht the white in the middle.

Partition Sort (a.k.a Quicksort) • Notice that 5 is already in the right place when we first partition pivoted on 5.
• Also note that the left half and right half are somewhat sorted since they have to be to the left or right of 5.
• That means we can just sort the two halves separately, using the leftmost item of each half as the pivot.

Quicksort Algorithm

• Partition on leftmost item
• Quicksort left half
• Quicksort right half

Quicksort Runtime

Theoretical analysis:

• Partitioning cost $\Theta(K)$ time, where $K$ is the # of elements being partitioned.
• Interesting twist: overall runtime is non-deterministic, and it’ll depend on where the pivot lands.

Best case: Pivot always lands in the middle. Then the runtime is $\Theta(N\log N)$.

Worst case: Pivot always lands at beginning of array. Then the runtime is $\Theta(N^2)$.

Now compare this to Mergesort, it seems that Quicksort isn’t really fast. Really?

Argument #1: 10% Case (In General)

Suppose pivot always ends up somewhere at least 10% away from either edge.

Then runtime is $O(NH)$ where $H \approx \log_{\frac {10} 9} N = O(\log N)$. So overall $O(N\log N)$.

Argument #2: Quicksort is really just Insertion into a BST

It turnsout Quicksort is just BST Sort. This idea might take a while to sink in …

• Couldn’t we just check the inversion and see if it’s better to use Insertion Sort or Quicksort?
• It turns out checking for inversion takes $N\log N$ too.

Quicksort Performance

The performance of Quicksort depends critically on:

• choice of pivot
• how you partition around the pivot
• other optimizations you might add

Now, here comes the question:

Do we need to worry about the worst case of giving Quicksort an already sorted array?

• No? We can check if it’s already sorted before doing Quicksort.
• Yes? If everything except one element is sorted, Quicksort is still slow.
• So, using Quicksort is fast but kinda risky…

Avoiding the Worst Case

If pivot always lands somewhere “good”, then Quicksort is $\Theta(N\log N)$. So what can we do?

Hint: Recall that the fundamental issue is that the leftmost item is always chosen as pivot, and after partitioning, items on each side of pivot appear in the same relative order.

• Don’t pick the leftmost item.
• Pick a random item as pivot.
• Scramble the array before starting.
• Pick a smarter pivot, maybe pick 3 items from array and pick the middle value. Maybe use the median.

• Randomness: Pick a random pivot or shuffle before sorting.
• Smarter pivot selection: Calculate or approximate the median.
• Introspection: Switch to a safer sort if recursion goes too deep.
• Try to Cheat: If the array if already sorted, don’t use Quicksort.

Philosophy 1: Randomness (Preferred Approach)

We know that very rarely $\Theta(N^2)$ cases do happen in practice. e.g:

• Bad elements: Array with all duplicates

Two strategies to deal with bad ordering:

1. Pick pivots randomly
2. Shuffle before you sort

Strategy 2 requires care in partitioning code to avoid $\Theta(N^2)$ behavior on arrays of duplicates. (This is a common bug in textbooks. See A Level Problems)

Philosophy 2: Smarter Pivot Selection (Linear time pivot pick)

The best possible pivot to pick is the median, because it splits the problem into two problems of size $N\over 2$.

Raises interesting question of How do you compute the median of an array?

• How do you compute the median of an array?

Is it possible to find the median in $\Theta(N)$ time? Yes! Use “BFPRT”, which is called PICK in the original paper. In practice, this algorithm is rarely used.

Philosophy 2b: Approximate the Median

The bad thing is that for any pivot selection strategy that is deterministic, constant time, the resulting Quicksort has a family of dangerous inputs that an adversary could easily generate.

See Mcllroy’s A Killer Adversary for Quicksort.

Philosophy 3: Introspection

Take a look at the recursion depth, if it goes too deep, change to merge sort.

Tony Hoare’s In-place Partitioning Scheme

• Best case: $\Theta(N\log N)$.
• Worst case if always leftmost pivot: $\Theta(N^2)$.
• Random pivot or Shuffle before sorting: $\Theta(N\log N)$
• Non-random quicksort with a constant-time deterministic pivot selection all have a “dangerous” input.
• Space usage: $\Theta(N)$.

We can actually imporve both the space complexity and make algorithm faster by a constant factor by using in-place partitioning.

This approach’s Main Idea:

• Left pointer loves small items, hates large or equal items (as compared to a pivot).
• Right pointer loves large items, hates small or equal items (as compared to the same pivot).
• The two pointer walks towards each other, stopping on a hated item. When both pointers have stopped, swap and move pointers by one.
• Swap pivot with G.

Using this parititoning scheme alone will not make things fast, we still need to pick pivots intelligently. Shuffling and leftmost is pretty good.

Quick Select

Remember that we can avoid the worst case of $\Theta(N^2)$ if we can find the median really fast, but so far no one has found an algorithm to compute median that’s fast enough to be worth it.

The Selection Problem

Given an array of N items, find the k^th^ smallest item for an arbitrary k.

How would we do this?

• For $k=1$, find the smallest item.
• For $k=2$, either sort the array and get 2nd smallest, or keep 2 variables, one smallest one 2nd smallest.
• For $k = \frac N 2$ (the median)? Many approaches take $\Theta(N\log N)$, but can we do it in $\Theta(N)$ time somehow?

Quick Selection

Goal: Find the median.

Worst-case performance? Give an array that causes worst-case performance.

• If our array is already sorted, like [1, 2, 3, ..., N]. Then, if each time we use the leftmost item, it goes from 1, 2, …, all the way to N/2.
• So, runtime is $\Theta(N^2)$ assuming we are not doing the Tony Hoare way.

Expected performance? $\Theta(N)$ time. Why? Because “on average”, we first do ~̴N compares, ~̴N/2 compares, ~̴N/4 compares and so on.

Stability

Definition: A sort is stable if order of equivalent items is preserved.

Is Insertion sort stable? Yes, when equivalent items in the later (more rightward) part of the array gets picked as traveller and move left, they never move left past their equivalent brethren.

Is Quick sort stable? Maybe. Depends on the partitioning strategy.

Is Merge sort stable? Yes.

Arrays.sort

In Java, Arrays.sort uses:

• Merge sort (TimSort actually), when sorting Objects.
• Quick sort, when sorting primitives.

Why? Obviously it has to do with stability, but it’s good to look at the A Level problems to come up with a ELI5 explanation.

Optimizing Sorts

There are additional tracks we can play:

• Switch to insertion sort with array size < 15
• Make sort adaptive: Exploit existing order in awway (Insertion Sort, SmoothSort, TimSort (the sort in Python and Java)).

Shuffling

There are many ways to shuffle.

Easiest way: Associate each item to a random number, and sort the items by their associated random numbers.

]]>
Data Structures Bobby Yan http://bobbyy.org http://bobbyy.org/cs61b-data-structures 2018-03-05T08:00:00-08:00 Dynamic Connectivity

Goal: Given a series of pairwise connectedness declarations, determine if two items are connected.

Two operations:

• connect(p, q): Connect items p and q
• isConnected(p, q): return if p and q are connected

public interface DisjointSets {
/** Connects two items P and Q. */
void connect(int p, int q);

/** Checks to see if two items are connected. */
boolean isConnected(int p, int q);
}


Goal: Design an efficient DisjointSets implementation.

• Number of elements N can be huge.
• Number of method calls M can be huge.
• Calls to methods may be interspersed.

The Naive Approach

• Connect two things: Record every single connecting line in some data structure.
• Cheking connectedness: do some sort of iteration over the lines to see if one thing can be reached from another.

It turns out this approach is more complex than it needs to me.

Better Approach – Connected Components

Rather an writing down every single line, we can probably just record down which “club” each item belongs to. We don’t have to explicitly state that 1, 3 are connected, we can have a way to denote that they belong to the same set.

For example, {0, 1, 3, 5}, {2, 4}, {6}, {7}, {8}

Downside: We can’t disconnect, but that’s not something we’re trying to do here.

Quick Find

Question: What data structure should we pick to support the tracking of sets?

Solution: Using an array, each index represent an item, and the value of the index represent the group in which it is in.

• Use int[] id where the i^th^ entry is the set number of the item i
• connect(p, q): Change entries that equal id[p] to id[q]

Downside: Connecting two items takes linear time, which is too slow.

Quick Union

Idea: Assign each node a parent (instead of an id). Suppose we want to connect(5, 2), what is the array going to end up being?

We could change the boss of 5 to 2. However, this makes the tree more spindly. So, we should change the boss of 5 to the boss of 2 instead, like this: And this is the Quick Union approach.

Downsides:

• Finding the boss is expensive, especially for more spindly trees.
• For N items, the worst case runtime for connect(p, q) is $\Theta(N)$.
• The worst case runtime for isConnected(p, q) is $\Theta(N)$.

Is there any way we can avoid getting tall, spindly trees? Yes there is!

Weighted Quick Union

Idea:

• Track tree size (number of elements)
• When connecting, link root of smaller tree to larger tree.

One question to ponder: You might be thinking, why not link the root of the shorter tree to the taller tree (Heighted Quick Union)? It turns out, both works, and both give the same performance, but weighing by size is easier to implement.

Implementing Weighted Quick Union

Very few changes need to be made based on Quick Union. We only need another int[] array called size, and change connect(p, q) to update size[] every time we connect.

public void connect(int p, int q) {
int i = find(p);
int j = find(q);
if (i == j) return;
if (size[i] < size[j]) { parent[i] = j; size[j] += size[i]; }
else { parent[j] = i; size[i] += size[j]; }
}


This new approach still requires time that is proportional to the depth of the tree.

However, what’s amazing is that with this approach, the maximum depth of any item is always $\log N$.

Implementation Constructor connect isConnected
QuickFindDS $\Theta(N)$ $\Theta(N)$ $\Theta(1)$
QuickUnionDS $\Theta(N)$ $\Theta(N)$ $\Theta(N)$
WeightedQuickUnionDS $\Theta(N)$ $\Theta(\log N)$ $\Theta(\log N)$

Performing M operations on a DisojointSet object with N elements:

• Runtime ranges from $O(MN)$ to $O(N + M log N)$.

Path Compression: A Clever Idea

Idea: Whenever we do isConnected(p, q), as we go, we tie all the nodes we’ve seen to the root.

In other words, when doing any kind of query involving a node, set that node’s parent to the root.

This results in a union/connected operation that is very very close to amortized constant time.

• M operations on N nodes is $O(N + M \log^* N)$ ($\log^*$ is the Iterative Logarithm)
• $\log^*$ is less than 5 for any realistic input.
• A tighter bound: $O(N + M \alpha(N))$

The end result of our iterative design process is the standard

]]>
Probability Bobby Yan http://bobbyy.org http://bobbyy.org/cs70-probability 2018-02-28T16:00:00-08:00 Basics
• Counting

Counting

Trees

• How many 3-bit strings? $2^3 = 8$
1. How would you make one sequence?
2. How many different sequences of 3 bits from {0, 1}?
         0                 1
/       \         /       \
00       01       10       11
/  \     /  \     /  \     /  \
000  001 010  011 100  101 110  111


First Rule of Counting: Product Rule

Objects made by chosing from $n_1$, then $n_2$, …, then $n_k$. Then number of objects if $n_1 \times n_2 \times ... \times n_k$

First Rule Example

• How many outcomes possible for $k$ coin tosses? –> $2^k$
• How many 10 digit numbers? –> $10^{10}$
• How many $n$ digit base $m$ numbers? –> $m^n$, actually $(m - 1)m^{n - 1}$

Functions, Polynomials

How many functions $f$ mapping $S$ to $T$?

$\|T\|$ ways to choose for $f(s_1)$, $\|T\|$ ways to choose for $f(s_2)$

So, $\| T \| ^{ \| S \|}$ such functions

How many polynomials of degree $d$ modulo $p$?

• $p$ ways to choose $d + 1$ coefficients, so $p^{d + 1}$

Permutations

How many 10 digits numbers without repeating a digit? Answer: $10!$

The number of possible choices for the second number is dependent on the first.

How many different samples of size $k$ from $n$ numbers without displacement? $n \cdot (n - 1) \cdot ... \cdot (n - k + 1) = \dfrac{n!}{(n-k)!}$

Permutation of $n$ objects = $n!$

One-to-one Functions

How many one-to-one functions from $|S|$ to $|S|$?

Counting Without Order

How many poker hands? $52 \times 51 \times 50 \times 49 \times 48 \times 47$?? Not really, because A, K, Q, 10, J of spades are the “same” as 10, J, Q, K, A of spades.

Second Rule of Counting

Second Rule of Counting: If order doesn’t matter, count ordered objects and then divide by number of orderings.

Number of ordering for a poker hand = $5!$

So, correct answer is $\frac{52!}{5!\times47!}$

To choose $k$ out of $n$: $\dfrac{n!}{(n - k)! \times k!}$

Notation: $\displaystyle {n \choose k}$

Examples

How many orderings of “ANAGRAM”?

• Ordered set: $7!$, except for “A”
• A’s are the same. There’re 3 “A”s, so number of such repeated ones = $3!$
• Answer = $\dfrac{7!}{3!}$

How many orderings of “MISSISSIPPI”?

• Ordered set: $11!$
• 4 S’s, 4 I’s, 2 P’s, so $4! \times 4! \times 2!$ ordered objects per unordered object

Sampling

Sample $k$ items out of $n$.

Without replacement:

• If order matters, $\dfrac{n!}{(n - k)!}$
• If order doesn’t matter, $\dfrac{n!}{(n - k)!\times k!} =$ $\displaystyle {n \choose k}$

With replacement:

• If order matters, $n^k$
• If order doesn’t matter: not so easy … depends on how many of each item we choose.
• Different number of unordered elts map to each unordered elt.

Example: Splitting up some money …

How many ways can Bob and Alice split 5 dollars?

Attempt #1:

For each of the 5 dollars pick Bob or Alice, so $2^5$ and divide out order. Does this work??

• Nope, doesn’t work. Second rule of counting isn’t the best here.

Let’s make the question harder… How many ways can Bob, Alice, and Eve split 5 dollars?

Attempt #2:

* * * * * –––– 5 stars are the 5 dollars

| | * * * * *
| * | * * * *
| * * | * * *
...


How many different 5 star and 2 bar diagrams? 7 positions in which to place the 2 bars. Answer: ${7 \choose 2} = {7 \choose 5}$

Stars and Bars

Ways to add up $n$ numbers to sum to $k$, or “$k$ from $n$ with replacement where order doesn’t matter”.

In general, if we have $k$ stars and $n$ bars, there are $n+k$ positions from which to choose $n$ bar positions. i.e. $\displaystyle {n+k-1 \choose n-1}$

Summary

First rule: $k$ sampls with replacement from $n$ items: $n^k$ Samples without replacement: $\dfrac{n!}{(n-k)!}$

Second rule: when order doesn’t matter

Balls in bins

$k$ balls in $n$ bins” $\equiv$$k$ samples from $n$ possibilities”. “indistinguishable balls” $\equiv$ “order doesn’t matter” “only one ball in each bin” $\equiv$ “without replacement”

Sum Rule

Sum rule: Can sum over disjoint sets

Example 1: Two indistinguishable jokers in 54-card deck. How many 5 card poker hands? No jokers: $52 \choose 5$ One joker: $52 \choose 4$ Two jokers: $52 \choose 3$ So, answer: $52 \choose 5$ + $52 \choose 4$ + $52 \choose 3$

Example 2: Two distingiushable jokers in 54-card deck. No jokers: $52 \choose 5$. One black/white joker: $2 \times {52 \choose 4}$ Both jokers: $52 \choose 3$ Answer is actually same as $54 \choose 5$

Combinatorial Proofs

Theorem 1

Theorem: $\displaystyle {n \choose k} = {n \choose n - k}$

Proof: Choosing what we choose is the same as choosing what we leave out.

Theorem 2 – Pascal’s Triangle

Pascal’s rule: ${n + 1 \choose k} = {n \choose k} + { n \choose k-1}$

Proof: How many size $k$ subsets of $n+1$? $n+1 \choose k$ Disjoint sets:

• Contains first element: then $n \choose k - 1$
• Doesn’t contain first element: then $n \choose k$
    0
1 1
1 2 1
1 3 3 1
1 4 6 4 1


Row $n$: coefficients of $(1 + x)^n$

Foil (4 terms) on steroids: $2^n$ terms: choose $1$ or $x$ from each factor of $(1+x)$

Simplify: collect all terms corresponding to $x^k$. Coefficient of $x^k$ is $n \choose k$: choose $k$ factors where $x$ is in product.

Theorem 3

Theorem: $\displaystyle { {n \choose k} = {n-1 \choose k-1} + ... + {k-1 \choose k-1} }$

Proof: Consider size $k$ subset where $i$ is the first element chosen:

• Must choose $k-1$ elements from the remaining $n-i$ elements. => $n-i \choose k-1$ such subsets.
• Add the up to get the total number of subsets

Theorem 4 – Binomial Theorem: x = 1

Theorem: $\displaystyle { 2^n = {n \choose n} + {n \choose n - 1} + {n \choose 0} }$

Proof: How many subsets of {1, …, $n$}? Construct a subset with sequence of $n$ choices.

First rule of counting: $2^n$ subsets.

Sum over $i$ to get

Simple Inclusion/Exclusion

Sum Rule: For disjoint sets $S$ and $T$, $\| S \cup T \| = \|S\| + \|T\|$

Inclusion/Exclusion Rule: For any $S$ and $T$, $\|S \cup T \| = \|S\| + \|T\| - \|S \cap T\|$

Example: How many 10-digit phone numbers have 7 as their first or second digit?

$S$ = phone numbers with 7 as first digit. $\|S\| = 10^9$

$T$ = phone numbers with 7 as first digit. $\|S\| = 10^9$

Key Points

• Uncertainty doesn’t mean “nothing is known”

Conditional Probability

Definition:

For events $A$ , $B$ in the same probability space, such that ${\mathbb{P}}[B]>0$ , the conditional probability of $A$ given $B$ is:

${\mathbb{P}}[A\mid B] = \dfrac{\mathbb{P}[A\cap B]}{\mathbb{P}[B]}$.

Total Probability Rule

For disjoint sets $A_1, A_2, …, A_N$, $Pr(B) = Pr(A_1 \cap B) + Pr(A_2 \cap B) + … + Pr(A_N \cap B)$

]]>
Asymptotics Bobby Yan http://bobbyy.org http://bobbyy.org/cs61b-asymptotics 2018-02-25T16:00:00-08:00 Writing Efficient Programs

An engineer will do for a dime what any fool will do for a dollar.

– Paul Hilfinger

• Efficiency comes in two flavors, programming cost and execution cost. Today we’ll deal with the latter:
• How much time does your program take to execute?
• How much memory does your program require?

Example Problem 1

Objective: Given a sorted array A, determine if it contains any duplicates.

• A silly algorithm is to consider every possible pair and return true if there’s any match.
• A better algorithm is: for each number A[i], compare with A[i + 1]. Return true if see a match, false otherwise.

Our Goal Today: Introduce a formal technique to compare algorithmic efficiency.

Intuitive Runtime Characterizations

Runtime Characterizations

Characterizations should:

• be simple and mathemtically rigorous
• demonstrate superiority of one algorithm over another

From the example problem 1, how can we characterize runtime to show that dup2 is better than dup1?

public static boolean dup1(int[] A) {
for (int i = 0; i < A.length; i += 1) {
for (int j = i + 1; j < A.length; j += 1) {
if (A[i] == A[j]) {
return true;
}
}
}
return false;
}

public static boolean dup2(int[] A) {
for (int i = 0; i < A.length - 1; i += 1) {
if (A[i] == A[i + 1]) {
return true;
}
}
return false;
}


Techniques for Measuring Computational Cost

• Technique 1: Measure execution time
• Unix has a built in time command to measure execution time. e.g. time java Dup1 20000
• Princeton StdLib has a Stopwatch class
• Physical timewatch
• Technique 2A: Count possible operations for an array of size N = 10,000 (what we’ll use often)
• Consider worst case and best case scenarios
• Pros: Machine independent. Input dependence is captured in model.
• Cons: Tedious to compute. Array size is arbitrary, so doesn’t tell actual time (nope, really can’t tell actual time).
• Technique 2B: Count possible operations in terms of input array size N
• Pros:
• Cons: Even more tedious to compute. Doesn’t tell actual time.

Counting Operations

For dup1:

Operation Count for N = 10000
i = 0 1
j = i + 1 1 ~ 10,000
less than (<)
increment (+= 1)

For dup2:

Operation Systematic Count Count for N = 10000
i = 0 1
less than < 0 ~ N
increment += 1 0 ~ N - 1
equals == 1 ~ N - 1 1
array accesses 2 ~ 2N - 2

Comparing Algorithms

A better algorithm scales better in the worse case.

So, suppose we have two algorithms that zerpify a collection of N items, and zerp1 takes 2N^2 operations while zerp2 takes 500N operations. While zerp1 may be faster for smaller inputs, it doesn’t scale well, so zerp2 is a better algorithm.

Asymptotic Behavior

In most cases, we only care about asymptotic behavior, i.e. what happens for very large N. How this is important in real life? Think about bitcoins, NASA, etc.

Worse Case Order of Growth

Duplicate Finding

Our goal is to charactertize the runtime of dup1 and dup2. What we’ve been doing so far indeed demonstrates the superiority of dup2, but is it simple? Not at all.

Simplifications

1. Only consider the worst case.
2. Pick one representation operation as a proxy for overall runtime.
3. Ignore lower order terms.
4. Ignore multiplicative constant.

With these simplifications, for dup2, we can pick “array accesses” as our cost model, and derive that the order of growth is just N.

Picking the representative operation (a.k.a the cost model)

• Good choice: increment
• Bad choice: i = 0
• We call our choice the “cost model

Big-Theta

Formal Definition:

$R(N) \in \Theta(f(N))$ if $\exists k_1, k_2 \in \mathbb{Z}^+$ such that $k_1 \cdot f(N) \leq R(N) \leq k_2 \cdot f(N)$

Formalizing Order of Growth

$N^3 + 3N^4 \in \Theta(N^4)$

$Ne^N + N \in \Theta(Ne^N)$

Now that we’re familiar with Big O, we’ll revisit the dup1 and realize it is $\Theta(N^2)$ time.

Tricky For Loop Example

public static void printParty(int n) {
for (int i = 0; i < n; i *= 2) {
for (int j = 0; j < n; j++) {
System.out.println("Party time!")
}
}
}


This actually has $\Theta(N)$ not $\Theta(N \log N)$ runtime.

Sums that’re Good to Know

• $1 + 2 + 3 + 4 + ... + N = \frac{N(N + 1)}{2} \in \Theta(N^2)$
• $1 + 2 + 4 + 8 + ... + N = 2N - 1 \in \Theta(N)$
• $1 + 2 + 4 + 8 + ... + 2^{N - 1} = 2\times(2^{N - 1}) - 1 = 2^{N} - 1 \in \Theta(N)$

Recursion Example

public static int f3(int n) {
if (n <= 1) {
return 1;
}
return f3(n - 1) + f3(n - 1);
}


Answer: $\Theta(2^N)$

Interesting fact: bug in Java’s implementation of binary search found in 2006.

static int binarySearch(String[] sorts, String x, int lo, int hi) {
if (lo > hi) return -1;
int m = (lo + hi) / 2;
int cmp = x.compareTo(sorted[m]);
if (cmp < 0) return binarySearch(sorted, x, lo, m - 1);
else if (cmp > 0) return binarySearch(sorted, x, m + 1, hi);
else return m;
}


Runtime: $\Theta(\log_2 N)$

For exact solution, see this video.

Mergesort

We have talked about Selection Sort:

• Find the smallest unfixed item, move it to the front and “fix” it.
• Sort the remaining unfixed items using selection sort.
• Runtime: $\Theta(N^2)$

Merge Sort Basic:

• Selection sort the left half: $\Theta(N^2)$
• Selection sort the right half: $\Theta(N^2)$
• Merge the two arrays: $\Theta(N)$

Overall, it’s still $\Theta(N^2)$. ($N + 2 \cdot (\dfrac N 2)^2$ to be exact).

Merge Sort:

• If array is of size 1, return.
• Mergesort the left half.
• Mergesort the right half.
• Merge the results: $\Theta(N)$

Overall runtime: $\Theta(N \log N)$

Big O Notation

While we can think of Big Theta as “equals”, Big O is something like “less than or equal”.

Formal Definition

$R(N) \in O(f(N))$ means there exists some positive constant $k$ such that $R(N) \leq k \cdot f(N)$.

Big O vs Big Theta

$\Theta(f(N))$ means the order of growth is $f(N)$.

$O(f(N))$ means the order of growth is less than or equal to $f(N)$.

Limitations of Big Theta

Consider this question:

public boolean dup4(int[] a) {
int N = a.length;
for (int i = 0; i < N; i += 1) {
for (int j = i + 1; j < N; j += 1) {
if (a[i] == a[j]) {
return true;
}
}
}
return false;
}


In this example, using Big Theta requires us to qualify what we’re talking about exactly:

• The best case runtime of dup4 is $\Theta(1)$.
• The worst case runtime of dup4 is $\Theta(N^2)$.

A big theta is a strong statement, because it implies “equals”. This means that if runtime depends on more factors than just N, then we may need different Big Theta notation for every interesting condition.

In these case, we can just use Big O and avoid qualifying our statment. e.g. the runtime of dup4 is $O(N^2)$.

A Subtle Distinction

1. The worst case runtime is $\Theta(N^2)$.
2. The runtime is $O(N^2)$.

Usefulness of Big O

Although Big O doesn’t provide a tight bound, it is still useful:

• Allows us to make simple blanket statements. e.g. we can just say “binary search is O(log N)” instead of “binary search is Θ(log N) in the worst case”.

Big Omega $\Omega$

Big Omega is “greater than or equal”.

Formal Definition

$R(N) \in O(f(N))$ means there exists some positive constant $k$ such that $R(N) \geq k \cdot f(N)$.

Usefulness of Big Omega

Two common uses of Big Omega:

• Very careful proofs of Big Theta runtime
• Providing lower bounds for the hardness of a problem
• e.g. The time to find wheather an array has duplicates is $\Omega(N)$ in the worse case or any algorithm.

Geometric Array Resizing

For ArrayLists, most add additions are constant time, but some operations are very expensive.

Amortized Analysis (Rigorous)

• Pick a cost model
• Compute the amortized (a.k.a average) cost of the ith insertion.

Cost Model: Array Accesses

Consider the cost for the 5th insert into an ArrayList.

We have 4 array reads + 4 array writes + 1 array write for new value = 9 array accesses in total.

Potentials and Amortized Cost Bounds

For operation $i$, choose an arbitrary “amortized cost” $a_i$. This cost may be more or less than the “actual cost” $c_i$ of that operation.

• Let $\Phi_i$ be the potential at time $i$. THe potential represents the cumulative difference between arbitrary amortized costs and actual costs over time.
• $\Phi_{i+1} = \Phi_i + (a_i - C_i)$
• If we select $a_i$ such that potential $\Phi_i$ is never negative, then amortized cost is an upper bound on the actual cost.

Side Note: Take CS 170 for full rigor.

]]>
Lecture 4 – Higher Order Functions Bobby Yan http://bobbyy.org http://bobbyy.org/lecture-4-higher-order-functions 2017-08-29T18:00:00-07:00 Iteration

while Statements

Execution rule:

2. If it’s a true value, execute the (whole) suite, then return to step 1.

Iteration Demo - The Fibonacci Sequence




Designing Functions

Three characteristics of functions that are really important:

• A function’s domain is the set of all inputs it might possibly take as arguments.
• A function’s range is the set of output values it might possible return.
• A pure function’s behavior is the relationship it creates between input and output.

A Guide to Designing Functions

• Give each function eactly one job, but make it apply to many related situations
• Don’t repeat yourself. Implement a process just once.
>>> round(1, 23)
1
>>> round(1.23, 1) # round to 1 decimal place
1.2
>>> round(1.23, 0) # roudn to integer
1


The area example

Higher Order Functions

Generalizing over Computational Processes

A higher order function is a function that takes in another function as an argument.

Example, summation and make_adder

Locally Defined Functions

Functions defined within other function bodies are bound to names in a local frame.

An operator is any expression that evaluates to a function. So, in

make_adder(1)(2)


make_adder(1) is the operator.

]]>
Lecture 3 – Controls Bobby Yan http://bobbyy.org http://bobbyy.org/cs61a-lecture-3-control 2017-08-29T17:00:00-07:00 Print and None
>>> 'Go Bears'
'Go Bears'
>>> print('Go Bears')
Go Bears

>>> None
>>> print(None)
None


None is special in Python, it represents nothing. A function that does not explicitly return a value will return None.

Note: None is not displayed by the interpreter as the value of an expression

>>> x = -2
>>> x
-2
>>> x = print(-2)
-2
>>> x
>>> print(x)
None


An interesting example:

>>> print(print(1), print(2))
1
1
None None


Pure Functions & Non-Pure Functions

• Pure functions just return values
• Non-pure functions have side effects

print is an example of a non-pure function, because it has side effects. A side effect isn’t value, but anything that happens as a consequence of calling a function.

Multiple Environments

With a def statement:

1. A new function is created
2. Name is bound to that funciton in the current frame

With a Call expression:

1. The operator & operand(s) are evaluated
2. The function (value of operator) is called on the arguments (value of operands)

Note: A name evaluates to the value bound to that name in the earlist frame of the current environment in which that name is found.

Miscellaneous Python Features

Operator What it does
/ True Division
// Floor Division

Something interesting:

>>> from operator import *
>>> mod(3, 2)
1
>>> mod(3.0, 2)
1.0
>>> mod(3.1, 2)
1.1
>>> mod(3.2, 2)
1.2000000000000002


Statements

A statement is executed by the interpreter to perform an action.

A compound statement consists of one or more clauses, each of which has a header and a suite. def is a compound statement.

• The first header of the compound statement determines the statement type
• The subsequent header of each clause controls the suite that follows

Boolean Contexts

Falsey values in Python:

False, 0, '', None, [] # There are more!!


Iteration

>>> i, total = 0, 0
>>> while i < 3:
...     i += 1
...     total += i
...
>>> i
3
>>> total
6


Execution Rule for while Statements

2. If it is truthy, execute the suite, then return to step 1.

Short-Circuting

• and returns the first falsey value, if any.
• or returns the first truthy value, if any.
• If and and or do not short-circuit, they return the last value.

Things to Take Note

Here’s something for you to ponder:

>>> 0 == False
True
>>> 1 == True
True
>>> 2 == True
False
>>> 2 == False
False


More to ponder: Why does the boolean value get casted to an integer first, and not the integer casted to a boolean first?

Python Operator Precedence

Common ones in descending precedence (most binding to least binding):

Operators
**
*, @, /, //, %
+, -
in, not in, is, is not, <, <=, >, >=, !=, ==
if – else
not
and
or
lambda

Here is the official Python Operator Precedence Chart in case you’re interested.

]]>
How to Switch to App Store of a Different Country Bobby Yan http://bobbyy.org http://bobbyy.org/switch-app-store-country 2017-07-27T00:00:00-07:00 Note: If you are trying to actually download anything from the App Store of a different region, you’ll have to change the country of your Apple ID.

Accidentally figured this out some time ago when I was trying to look at the top charts of the Singapore App Store.

See, https://itunes.apple.com/us/app/spanish-word/id1123591991 takes you to the Spanish Vocab Builder, in the App Store of your country. Now if you change it to https://itunes.apple.com/sg/app/spanish-word/id1123591991, it still takes you to the same page, because this app is available in all territories where the App Store is available.

Apple finds the app by its id, and it happens that if you give it an invalid app id, it’ll actually bring you to the app store of that country. For example:

https://itunes.apple.com/us/app/spanish-word/id1234567890 takes you to the US App Store.

https://itunes.apple.com/sg/app/spanish-word/id1234567890 takes you to the Singapore App Store.

https://itunes.apple.com/ca/app/spanish-word/id1234567890 takes you to the Canada App Store.

https://itunes.apple.com/cn/app/spanish-word/id1234567890 takes you to the China App Store.

https://itunes.apple.com/de/app/spanish-word/id1234567890 takes you to the Germany App Store.

https://itunes.apple.com/jp/app/spanish-word/id1234567890 takes you to the Japan App Store.

]]>
Easiest Way to Set Up a Shadowsocks Server Bobby Yan http://bobbyy.org http://bobbyy.org/setting-up-shadowsocks 2017-06-04T00:00:00-07:00 VPS

You could use any service. Here I’m using Vultr’s Los Angeles server since that’s what works for me. Another really good hosting provider is Linode, but just for the purpose of what we’re doing today, Vultr saves us the trouble of upgrading the kernal.

Your operating system could be any Linux flavor. I’m going with Ubuntu 16.04 LTS x64.

TeddySun wrote a very nice script for setting up the four major flavors of Shadowsocks, and we are just going to use that:

wget --no-check-certificate -O shadowsocks-all.sh https://raw.githubusercontent.com/teddysun/shadowsocks_install/master/shadowsocks-all.sh


It’s going to ask you which of the four Shadowsocks server (Python, R, Go, libev) you’d like to set up:

Which Shadowsocks server you'd select:
Please enter a number (default 1):


Next, you have to enter the password, and then the port you would like:

You choose = Shadowsocks-Go

(default port: 8989):

port = 8989

Press any key to start...or Press Ctrl+C to cancel


Here, for demo purpose, I pressed Enter and used the default settings. It doesn’t really matter what you put here as you can always come back and change the settings in /etc/shadowsocks-go/config.json later on.

Anyways, once that’s done, you’ll get a summary of your configuration, like this:

Congratulations, Shadowsocks-Go server install completed!


Multiple Users

Edit the config.jsonfile, following this template:

{
"server":"0.0.0.0",
"local_port":1080,
},
"timeout":300,
"method":"aes-256-gcm",
"fast_open":true
}


TCP BBR

What’s BBR, you might ask. Well, it’s

Bottleneck Bandwidth and Round-trip Time

To put it simply, it’s something extremely good for juicing the best speed out of your server that Google has made open-source. Sweet right?

Hey Linode users! Now it’s a good time to go and upgrade your kernal before moving on with the rest of the tutorial. Check out the last section of this post if you are not sure how to do that.

Ok, with the right kernal, you should now login using root user, and run the following commands:

wget --no-check-certificate https://github.com/teddysun/across/raw/master/bbr.sh
chmod +x bbr.sh
./bbr.sh


After that, you will be prompted to reboot your server. Do that with y+Enter.

Then, check if BBR is working normal:

sysctl net.ipv4.tcp_available_congestion_control


should return

net.ipv4.tcp_available_congestion_control = bbr cubic reno

sysctl net.ipv4.tcp_congestion_control


should return

net.ipv4.tcp_congestion_control = bbr

sysctl net.core.default_qdisc


should return

net.core.default_qdisc = fq

lsmod | grep bbr


should return something containing tcp_bbr in return. If not, run the following:

echo "net.core.default_qdisc = fq" >> /etc/sysctl.conf
echo "net.ipv4.tcp_congestion_control = bbr" >> /etc/sysctl.conf


Automatic restarts

This step is entirely optional, and unlike TCP BBR, it won’t dramatically increase your connection speed. Nevertheless, what I’m trying to do in this step is to set up a cron job that restarts the server every day at midnight to prevent it from getting sluggish.

First, create a bash script. I put it under /root/restart-ss.sh.

date


In the demo above, I was using Shadowsocks-Go. If you’ve gone with one of the other options, you would get an error with line 2, and you might have to just look around to find the right command for restarting your version of the shadowsocks server. For example, for Shadowsocks Python the command should be /etc/init.d/shadowsocks-python restart.

After that, just enter:

crontab -e


and add the following to the last line:

0 0 * * * bash /root/restart-ss.sh >> /root/cron.log


Perfect! Now run this to make sure our cron job is correctly set up and we’re good to go!

service cron restart


First, check your kernal information with:

uname -r


If it returns anything 4.9 and above, you are good to go. But for this instance 4.11+ actually works slightly better with BBR, so I’m still going to show you how kernal upgrade is done with Linode.

Install the Latest Kernal

Go to http://kernel.ubuntu.com/~kernel-ppa/mainline/ to locate the latest linux image. Hint: look for the one that has linux-image and generic in it.

wget http://kernel.ubuntu.com/~kernel-ppa/mainline/v4.11.5/linux-image-4.11.5-041105-generic_4.11.5-041105.201706141137_amd64.deb


2) Install kernal:

dpkg -i linux-image-4.11.5*.deb


3) Checking if installation is complete:

ls /boot/vmlinuz*


Incidentally, I didn’t purge the old kernal for safety concerns…

Configure GRUB

If you don’t have GRUB installed yet:

apt-get install linux-image-virtual grub2


1) Edit /etc/default/grub and change the parameters to the following:

GRUB_TIMEOUT = 10
GRUB_CMDLINE_LINUX =“console = ttyS0,19200n8”
GRUB_DISABLE_LINUX_UUID = true
GRUB_SERIAL_COMMAND =“serial --speed = 19200 --unit = 0 --word = 8 --parity = no --stop = 1”
GRUB_TERMINAL = serial


Keep everything else as it is.

2) Update GRUB

update-grub


3) Under the “Boot Settings” of your linode, change Kernal to “Grub 2”

reboot

]]>
How to prevent your Mac from sleeping, a Different way Bobby Yan http://bobbyy.org http://bobbyy.org/how-to-prevent-mac-from-sleeping 2017-05-01T00:00:00-07:00 By default, your Mac computers go to sleep automatically after some period of inactivity which is rather appropriate given how short most battery life is. However, this becomes annoying when you’re downloading much larger files. We’re talking about those that take hours.

If you aren’t careful, what might happen is this: you start the download, go for a walk, hit the gym, or take a power nap before coming back to the office to see if your download’s finished, only to realize your Mac’s sleeping too. Normally, on days that you’re careful, what you do is go to “Settings” > “Energy Saver” and drag the “Computer sleep” slider all the way to “Never”. This solution is simple enough, but you risk forgetting to set the energy saver back to where it was after you’re done with all the downloads. So, I set out to look for another solution.

Do you know that when media players, like iTunes, are running, as long as something is playing, your Mac won’t go to sleep. Let’s have a look at what has happened. pmset is an in-built command line utility for power management in macOS. Now it is clear to us that before iTunes started playing, sleep was working fine, but sleep was prevented by iTunes, coreaudiod once we’ve begun playing a song.

Now that we’ve found the key, some Google searches would show us this command called caffeinate that basically keep your Mac from sleeping. Here’s the man page of caffeinate. With everything we need, there are just two more things to do:

1. Get the PID of the process we want to monitor.
2. Use “caffeinate” to prevent idle sleep when this process/program is running.

Since we’ve only got two things at hand, a script should do. I named the script prevent_sleep and put it under /usr/local/bin.

#!/bin/sh
if [[ -n "$1" ]]; then pid=$(ps rax | awk '{print $1,$5}' | grep -i "$1" | cut -d ' ' -f 1) if [[ -n$pid ]]; then
caffeinate -s -w "$pid" & echo "System sleep prevented by$1."
else
echo "Sorry, $1 could not be found." fi else echo "Enter the name of the process: " echo "Example:" echo " prevent_sleep wget" fi  This script first checks for processes with the given name, and looks for its PID if the process exists, before passing the PID to caffeinate. As long as the monitored process is running, caffeinate keeps running, and your computer won’t go to sleep. Ok, it’s time for some coffee. ]]> Lecture 2 – Names Bobby Yan http://bobbyy.org http://bobbyy.org/cs61a-lecture-2-names 2017-04-27T17:00:00-07:00 Names from operator import add, mul from operator import *  Though you can import everything from math, or operator, it’s more common to specify. Thus, from math import pi, sin, cos  Binding two names at once area, circ = pi * radius * radius, 2 * pi * radius  We can bind the build-in function names to values >>> max(3, 4) 4 >>> max = 7 >>> max(4, 5) Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: 'int' object is not callable  How to get “max” back? __builtins__.max(3, 4) max = __builtins__.max  OR del max  f is max, g id min, max is min Types of Expressions Primitive expressions Expression Type 2 number/numeral 'hello' string add name Call expressions Environment Diagrams Frames • Within a frame, a name CANNOT be repeated • Everytime a user-defined function is called, a local frame is created. Looking up Names in Environments The current environment is either: • the global frame alone, or • a local frame, followed by the global frame Defining Functions Assignment is a simple means of abstraction, by binding names to values Function definition is a more powerful means of abstraction, by binding names to expressions def <name>(<formal parameters>): return <return expression>  Function signature indicates how many arguments a function takes. Function body defines the computation performed when the function is applied. ]]> An Introduction to Markdown Bobby Yan http://bobbyy.org http://bobbyy.org/markdown-guide 2016-12-15T00:00:00-08:00 Getting to know Markdown Markdown is a lightweight markup language with many advantages, and it’s growing in popularity among writers, editors, etc. Now, don’t be fooled by “markup” and “language” – Markdown has a very straightforward syntax. Compared to the long, laborious HTML tags, Markdown is truly lightweight and has a shallow learning curve. Once you’re familiar with its syntax, Here’s a quick example of Markdown in action: The *quick* brown fox, jumped **over** the lazy [dog](https://en.wikipedia.org/wiki/Dog). becomes The quick brown fox, jumped over the lazy dog. Markdown = Awesome • You can concentrate on writing instead of formatting. • When it finally comes to formatting, Markdown allows you to keep your fingers planted on the keyboard as you apply formatting. • You can easily convert your .md document to HTML, PDF, ePub … • Markdown deals with plain text, which means it’s compatible with all editors. • Straightforward, super readable, shallow learning curve. Basic Markdown Formatting Ok! You are sold. Now let’s dive in: Headings This is perhaps the most common element you’ll use, and in most modern text editors, this is what has to be done: enter the text, select the text, change the style to heading. That’s rather complicated. In Markdown, just add # in front! The number of hashes indicate the level of the heading. \# Heading 1 \## Heading 2 \### Heading 3  Lists Lists are incredibly easy to manage in Markdown. To create an unordered list, just add a * or a - or a + as a prefix. For example: * Markdown is cool * I love Markdown * This list is awesome  becomes: • Markdown is cool • I love Markdown • This list is awesome To create an ordered list, add the numbers 1. 2. 3. and you’re good to go. For example: 1. Lists 2. Are 3. Fun  becomes: 1. Lists 2. Are 3. Fun In Markdown, you don’t need any buttons to create inline links. [This is a link to Google](http://google.com "Google")  This is a link to Google If you fancy making reference links, you could do this: This line has [a link] and [another link] : http://bobbyy.org : http://google.com  to get something like this: This line has a link and another link Images Images are really similar to links, except that you need to add a ! before the links. The syntax goes like this: ![Alt](/images/social_icons/email.svg "Title")  and becomes: Quotes We often need quotes as a proof or example whenever we are writing, and that’s when this element comes in handy. In Markdown, all you’ve got to do is add > before the text you’re about to quote, like this: > To be or not to be, that is the question.  which would turn out like this: To be or not to be, that is the question. Bold and Italic So easy with Markdown. **Some bold text here** => Some bold text here *Some italic text here* => Some italic text here Code blocks Did you know Markdown comes with syntax highlighting? Well, just put  (3 backticks) before and after your code! How simple is that? // # Notifications API // RESTful API for creating notifications var Promise = require('bluebird'), _ = require('lodash'), canThis = require('../permissions').canThis, errors = require('../errors'), utils = require('./utils'), // Holds the persistent notifications notificationsStore = [], // Holds the last used id notificationCounter = 0, notifications;  What next? Why not write something with Markdown right now?! If there’s anything else you are not sure, or if you want to learn other more advanced Markdown syntax, check out this Markdown Quick Reference by Wordpress. ]]> 12 Regular Expressions that are Good to Know Bobby Yan http://bobbyy.org http://bobbyy.org/regular-expressions 2016-12-06T00:00:00-08:00 A regular expression, abbreviated regex or regexp, is a very old and powerful way to describe search patterns by using a concise text string to define complex searching algorithms. As a programmer, if you can master regular expressions, you can save yourself a whole lot of time and effort. One regular expression can often accomplish what would otherwise take tens or hundreds of code. Regular expressions are frequently used to check for the validity of text strings of any sequence of characters. Here is what a typical regex to validate date format looks like in Javascript: function validateDate(testdate) { var date_regex = /^(0[1-9]|1[0-2])\/(0[1-9]|1\d|2\d|3)\/(19|20)\d{2}$/ ;
return date_regex.test(testdate);
}


You’re probably wondering why you couldn’t just, say, use Date.Parse() in Javascript. That works well until you try to mess around with the UK date format (dd/mm/yyyy).

Now that we know how useful regular expressions are, I want to just list a few handy ones.

/^(?=.*[A-Z].*[A-Z])(?=.*[!@#$&*])(?=.*[0-9].*[0-9])(?=.*[a-z].*[a-z].\*[a-z]).{8}$/


Breakdown:

 / Delimiter ^ Start anchor (?=.*[A-Z].*[A-Z]) Ensure string has two uppercase letters (?=.\*[!@#$&\*]) Ensure string has one special case letter (?=.*[0-9].*[0-9]) Ensure string has two digits (?=.*[a-z].*[a-z].\*[a-z]) Ensure string has three lowercase letters .{8} Ensure string is of length 8 $ End anchor

/^-?\d+$/  3. Validate an email address /^([a-z0-9\_\.-]+)@([\da-z\.-]+)\.([a-z\.]{2,6})$/


/^(?!0)(?!.\*\.$)((1?\d?\d|25[0-5]|2[0-4]\d)(\.|$)){4}$/  5. Validate IPv6 addresses /^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$|^(([a-zA-Z]|[a-zA-Z][a-zA-Z0-9\-]*[a-zA-Z0-9])\.)*([A-Za-z]|[A-Za-z][A-Za-z0-9\-]*[A-Za-z0-9])$|^\s*((([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))|(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|((:[0-9A-Fa-f]{1,4})?:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})|((:[0-9A-Fa-f]{1,4}){0,2}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-Fa-f]{1,4}){1,5})|((:[0-9A-Fa-f]{1,4}){0,3}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){1,6})|((:[0-9A-Fa-f]{1,4}){0,4}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(:(((:[0-9A-Fa-f]{1,4}){1,7})|((:[0-9A-Fa-f]{1,4}){0,5}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:)))(%.+)?\s\*$/


/^#?([a-f0-9]{6}|[a-f0-9]{3})$/  7. Check a URL /^(https?:\/\/)?([\da-z\.-]+)\.([a-z\.]{2,6})([\/\w \.-]*)*\/?$/


8. Check if a string is currency

This regex works like isDecimal, except that only zero or two digits are allowed after the decimal points.

/^\s*(\+|-)?((\d+(\.\d\d)?)|(\.\d\d))\s*$/  9. Check a Username Checks a username to see if it has at least 4 characters. /^[\w\d\_.]{4,}$/


10. Check IE version

Though obsolete, Internet Explorer hasn’t been completely replaced yet, so many sites may still consider fixing their compatibility issues with IE. Here’s a regex to check for IE version.

/^.*MSIE [5-8]?(?!.*Trident\\/[5-9]\\.0).\*$/  11. Check the URL Prefix There’re plenty of times in web development when you need to check the URL prefix, whether it’s http:// or https://, and you can do that with this regex: if ( !s.match( /^[a-zA-Z]+:\\/\\// ) ) { s = 'http://' + s; }  12. Check a Domain This checks if a domain name is valid. /^[a-z0-9]+[a-z0-9-.]\*[a-z0-9]+.[a-z.]{2,6}$/


I found a really awesome quick reference guide for regular expressions, and a pretty good cheat sheet for Javascript regular expressions here: Also, Regex101 is an excellent regular expressions tester that highlights pattern and matches online.

]]>

So, let’s get started.

For instance, you are looking for one of the good old books like 7 habits of Highly Effective People, but somehow you are trying to see if there are any powerpoint slides to give you a sum up of what you’ve already read quite a few times.

So, you find yourself searching for 7 habits of highly effective file-type:ppt in Google, and let’s use the first link: www.bumc.bu.edu/clinepi/files/2009/07/Seven-Habits.ppt.

Make the tweak

In short, you just need to add the string docs.google.com/viewer?url= in front of the link you just copied, and off you go!

Hope this tip helps to save some trouble downloading the file every time you just wanna preview it.

]]>
How to Get High-Quality Album Cover (Artwork) for Any Album Bobby Yan http://bobbyy.org http://bobbyy.org/how-to-get-high-quality-album-cover-(artwork)-for-any-albums 2015-12-30T01:10:55-08:00 Why do I want Album Cover?

Have you ever encountered this problem: you have a bunch of music files and you want to import them to iTunes library.

Ok, done! Now you have all your favorite songs in iTunes. And … “Wait a minute, this is really ugly!” If you think that way, you’re very very likely one of those that just can’t stand the white placeholders for your album cover. Having artworks can be really aesthetically appealing and seems to somehow make your songs nicer.

Before we jump to the point, I want you to know that this works for all albums that are available on iTunes, but not necesarilly any album. May the title was kinda a clickbait?Anyway, let’s get to it!

Yo! Tutorial Starts Here!

So here is an example of the format of the URL you could use to search for your desired artwork:

and term=V+Maroon+5 is the part of the URL you want to change.

In the above example, I’m trying to look for Maroon 5’s album “V”, and I simply used + for the “space bar” that you would usually put for all your Google searches.

Personally, I recommend that you do term=<album name>+<artist name>.

Then, you should see something like this:

Just do a Command (Control for Windows) + F search in the browser to whittle down the results. Usually, like the example I’m giving you right now, the first result should be the one you are looking for if you are using the structure I’ve just suggested above.

So, now you might consider looking for the string artworkUrl100, which should be pretty easy to find. And you’ll see this link right after that string:

http://is5.mzstatic.com/image/thumb/Music7/v4/b3/fb/cc/b3fbcca9-85a0-c25d-cb20-feee4900bdb2/source/100x100bb.jpg

You should copy that URL and change the ending from 100x100bb.jpg to 10000x10000bb.jpg`. What this does is essentially getting a link for the .jpg with a much higher dimension.

Now you’ve got the final link you need here:

http://is5.mzstatic.com/image/thumb/Music7/v4/b3/fb/cc/b3fbcca9-85a0-c25d-cb20-feee4900bdb2/source/10000x10000bb.jpg

]]>