Bobbyy.org Everything about me. 2022-09-02T14:30:49-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:

• Start with an empty output sequence
• 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 ($$N<15$$ 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 ordering: Array already in sorted order
• 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:

• Start with using the leftmost item as the pivot.

• 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

Note: There’s no way to add items, or unlink items.

## The Disjoint Sets ADT

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^{\text{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

]]>
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

Which of the following statement gives us more information?

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

It turns out, statement 1 gives us more information.

### 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.

]]>
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:

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

## 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


## 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.

]]>
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

1. Evaluate the header’s expression
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 Have you ever wondered what the top charts of the App Store in another country looks like?

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.

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.

]]>
Setting up a Shadowsocks Server on Linux Bobby Yan http://bobbyy.org http://bobbyy.org/setting-up-shadowsocks 2017-06-04T00:00:00-07:00
• Basic Setup
• Other
• If you’ve found this post, you probably don’t need me to tell you what Shadowsocks is or what it is for. You can read all about shadowsocks or shadowsocks-libev here.

Before we get started, make sure you have a Linux server running. I’m using a Vultr LA server. Linode is great too.

## Basic Setup

First, clone the shadowsocks-libev repo:

git clone git@github.com:shadowsocks/shadowsocks-libev.git


Then, install the dependencies depending on your Linux flavor:

# Installation of basic build dependencies
## Debian / Ubuntu
sudo apt-get install --no-install-recommends gettext build-essential autoconf libtool libpcre3-dev asciidoc xmlto libev-dev libc-ares-dev automake libmbedtls-dev libsodium-dev
## CentOS / Fedora / RHEL
sudo yum install gettext gcc autoconf libtool automake make asciidoc xmlto c-ares-devel libev-devel
## Arch
sudo pacman -S gettext gcc autoconf libtool automake make asciidoc xmlto c-ares libev


Finally, install shadowsocks-libev:

# Installation of libsodium
export LIBSODIUM_VER=1.0.16
wget https://download.libsodium.org/libsodium/releases/libsodium-$LIBSODIUM_VER.tar.gz tar xvf libsodium-$LIBSODIUM_VER.tar.gz
pushd libsodium-$LIBSODIUM_VER ./configure --prefix=/usr && make sudo make install popd sudo ldconfig # Installation of MbedTLS export MBEDTLS_VER=2.6.0 wget https://tls.mbed.org/download/mbedtls-$MBEDTLS_VER-gpl.tgz
tar xvf mbedtls-$MBEDTLS_VER-gpl.tgz pushd mbedtls-$MBEDTLS_VER
make SHARED=1 CFLAGS="-O2 -fPIC"
sudo make DESTDIR=/usr install
popd
sudo ldconfig

# Start building
git submodule init && git submodule update
./autogen.sh && ./configure && make
sudo make install


#### Option 2: with Snap

Snap is shipped with most modern OS, so it you are on Debian 9+, CenOS 7.6+, Ubuntu 16.04 LTS or later, just run

sudo snap install shadowsocks-libev


If you’re on older software, follow https://snapcraft.io/core to install snap core first, then run the above.

### Configurations

sudo vim /etc/shadowsocks-libev/config.json
# For Debian:

{
"server": ["[::0]", "0.0.0.0"], # alternatively, use your actual ipv6, ipv4 addresses
"server_port": "<YOUR CUSTOM PORT>",
"mode": "tcp_and_udp",
"timeout": 300,
"method": "aes-256-gcm"
}


### TCP BBR

BBR (Bottleneck Bandwidth and Round-trip propagation Time) is latest and greatest from Google for TCP congestion control.

To put it simply, it’s the magic dust for juicing every last drop of your server network Google made open-source. Sweet, right?

Hey Linode users! Right now would be a good time to go and upgrade your kernel before moving on with the rest of the tutorial. Check out the last section of this post for how to do that.

Make sure you are root and run the following:

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


When you’re done, reboot the server.

Then, check if we’re all set:

sysctl net.ipv4.tcp_available_congestion_control | grep -q 'bbr' && echo '1 Yes'; sysctl net.ipv4.tcp_congestion_control | grep -q 'bbr' && echo '2 Yes'; sysctl net.core.default_qdisc | grep -q 'fq' && echo '3 Yes'; lsmod | grep bbr | grep -q 'tcp_bbr' && echo '4 Yes'


If you don’t see four yes’s, run the following

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


### simple-obfs

git clone https://github.com/shadowsocks/simple-obfs.git
cd simple-obfs
git submodule update --init --recursive
./autogen.sh && ./configure && make
sudo make install


### Create a systemd service

sudo vim /etc/systemd/system/shadowsocks-libev.service

[Unit]
Description=Shadowsocks-libev Default Server Service
After=network-online.target
StartLimitIntervalSec=0

[Service]
Type=simple
CapabilityBoundingSet=CAP_NET_BIND_SERVICE
AmbientCapabilities=CAP_NET_BIND_SERVICE
DynamicUser=true
LimitNOFILE=32768
Restart=always
RestartSec=1
# ExecStart=/usr/bin/ss-server -c $CONFFILE$DAEMON_ARGS

[Install]
WantedBy=multi-user.target

systemctl daemon-reload


### Cron Job for Periodic Restarts

This is optional. It won’t make nearly as much of a different to speed as BBR would, but setting up a cron job that restarts the server every now and then may just prevent it from getting sluggish.

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

date


After that, let’s set up the cron job.

crontab -e


Append as the last line:

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


Perfect. Let’s restart the cron service and we’re good to go.

service cron restart


### Multiple Users

If you want to have multiple users, use the following template for your config.json.

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


## Other

### Upgrading your Linux kernel (For Linode Users)

First, check your kernel 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 kernel upgrade is done with Linode.

#### Install the Latest kernel

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 kernel:

dpkg -i linux-image-4.11.5*.deb


3) Checking if installation is complete:

ls /boot/vmlinuz*


Incidentally, I didn’t purge the old kernel 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 kernel to “Grub 2”

4) Reboot your Linode

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. ]]> 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  Now that we’ve reassigned our very useful max function to just a number, we could get it back with: __builtins__.max(3, 4) max = __builtins__.max  or, more simply, del max  ### Expressions An expression describes a computation and evaluates to a value. ##### Primitive expressions A primitive expression is a single evaluation step. You either look up the value of a name or take the literal value. Some examples are: Expression Type 2 number/numeral 'hello' string add name ##### Call expressions A call expression makes one or more function calls, for example: max(1, 2)  ## Environment Diagrams ### Frames • Within a frame, a name cannot be repeated • Every time 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>  A function signature indicates how many arguments a function takes. A 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. Don’t be fooled by “markup” and “language” — Markdown is in fact very simple and straightforward. Compared to the long, laborious HTML tags, Markdown is truly lightweight and doesn’t have that much of a learning curve at all. 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 is 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. ]]> A Few Useful Regular Expressions Bobby Yan http://bobbyy.org http://bobbyy.org/regular-expressions 2016-12-06T00:00:00-08:00 • Test password strength • Matching an integer • Validate an email address • Validate IPv4 addresses • Validate IPv6 addresses • Check a Hex Value • Check a URL • Check if a string is currency • Check a Username • Check IE version • Check the URL Prefix • Check a Domain • A regular expression, abbreviated “regex” or “regexp”, is an old and powerful way to describe complex search patterns using a concise string. As a programmer, if you can master regular expressions, you can often save yourself a whole lot of time and effort. One regular expression can often accomplish what would otherwise take tens or hundreds lines 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.

### Test password strength

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


#### Breakdown

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

/^-?\d+$/  ### 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}$/  ### 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})$/  ### Check a URL /^(https?:\/\/)?([\da-z\.-]+)\.([a-z\.]{2,6})([\/\w \.-]*)*\/?$/


### 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*$/  ### Check a Username Checks a username to see if it has at least 4 characters. /^[\w\d\_.]{4,}$/


### 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).\*$/  ### 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; }  ### Check a Domain This checks if a domain name is valid. /^[a-z0-9]+[a-z0-9-.]\*[a-z0-9]+.[a-z.]{2,6}$/


There’s an awesome quick reference guide for regular expressions, and a pretty good cheat sheet for Javascript regular expressions here: And regex101 is an excellent regular expressions tester that has some nice highlighting of patterns and matches.

]]>
An Easy Way to Preview Documents Online without Downloading Them Bobby Yan http://bobbyy.org http://bobbyy.org/how-to-view-documents-without-downloading 2016-06-11T19:08:04-07:00 This is a quick and sleek tutorial on how to view documents in browser without downloading the files to your computer. This comes especially handy for larger files.

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

]]>