Tuesday, 28 December 2021

Django framework

route request

When routes a request, it is doing a url mapping. It uses path function. This function accepts three parameters. The first is url, the second is the function to call in the view module. The third one is the name for this path. It will be used when we want to add a link in other pages. We use the name to refer to the page.

from django.urls import path
from . import views

app_name = 'learning_logs'

urlpatterns = [
    # home page
    path('', views.index, name='index'),
    path('topics/', views.topics, name='topics')
]

Access django sqlite3 db

If get this error message: CommandError: You appear not to have the 'sqlite3' program installed or on your path, install sqlite3 in machine first

sudo apt-get install sqlite3
# need to do it in virtual env (source ..bin/activate)
python manage.py dbshell
# also can do this
sqlite3 filename

# list tables
.tables

# see all table schema
.schema

# show table content. use normal sql select

Start server

# 9000 is port number. If port number is not provided, will use 8000 as default port
python manage.py runserver 9000

Sunday, 12 December 2021

Go cheating sheet

Find package

pkg.go.dev

Handle dependency

Create a go.mod

go mod init some_name

Install package

go mod tidy

Change default path to search for a module

go mod edit -replace example.com/greetings=../greetings

Run program

//run directly
go run sample.go

//compile and then run
go build sample.go
./sample

Format codes

go has declared a standard format to avoid pointless debate about trivial format details. Run command below to format codes.

go fmt mysample.go

Some syntax

Loop

//go does not have while loop. use for loop
for condition {
....
}

If statement

//The if expression may be preceded by a simple statement, 
//which executes before the expression is evaluated.
if x := f(); x < y {
    return x
}

Math

It does not have built in max or min function

// get 4
9/2

string

here is a discuss about string and the corresponding char array

Useful built-in strin function

var jewels = "abcd"
var jArr = []rune(jewels)

//convert array rune back to string
mystr :=string(jArr)

//loop through string. Here r is type of rune. However,
//str := "hello" str[0] is of type byte
for _, r := range "hello" {
	fmt.Println(r)
}

//cast a byte to string
var s = string(jwels[0])

//convert a string to int[26]
var arr1 [26]int
for _, r := range word1 {
	arr1[int(r)-97]++
}

//number to string
x=123
t :=strconv.Itoa(x)

//string to int
i, _ := strconv.Atoi("98")

//substring. result is "bc"
s := "abcdef"
fmt.Println(s[1:3])

//build big string. similiar to java string build approach
var ans bytes.Buffer
ans.WriteString("hello")

//back to string
return ans.String()

//split string by spaces to array
sample := "one    two   three four "
words := strings.Fields(sample) //["one", "two", "three", "four"]

//split by string
parts := strings.Split(path, "/")

//join back to sample
strings.Join(words, " ")

//convert int to binary string and convert back
bn := strconv.FormatInt(int64(num), 2)
k, _ :=strconv.ParseInt(string(result), 2, 64)
ans := int(k)

//use bytes package bytes.Buffer to build string
func comma(s string) string {
    var buf bytes.Buffer

    if len(s) <= 3 {
        return s
    }

    for i := 0; i < len(s); i++ {
    	//to write strind, do buf.WriteString("hi")
        buf.WriteByte(s[i])
        if (len(s)-1-i) > 0 && (len(s)-i-1)%3 == 0 {
            buf.WriteByte(',')
        }
    }

    return buf.String()

}

//remove all no alphnumeric chars from string
s := "A man, a plan, a canal: Panama"
reg, _ := regexp.Compile("[^a-zA-Z0-9]+")
   
processedString := reg.ReplaceAllString(s, "")
fmt.Println(processedString) // AmanaplanacanalPanama

//to lower case    
leo:= strings.ToLower(processedString)
fmt.Println(leo) //amanaplanacanalpanama

//convert byte to string. Also repeat a string
 var mb byte
 mb='n'
 mystr := strings.Repeat(string(mb),5)
 fmt.Println(mystr) //nnnnn
 
 //convert hex to int64  "0xde0b6b3a7640000" 1*10^18 wei = 1 
 //ETH "0x" means it is hex
 result, _ := strconv.ParseInt("de0b6b3a7640000", 16, 64)
 fmt.Println(result)
 
//create array of lower case letters
digits :=[]byte("abcdefghijklmnopqrstuvwxyz")

//substring s[start:end] end is exclusive
s := "Hello World"
fmt.Println(s[1:4])   // ell

//build int array. Here s is string of 26 lower case
var pool [26]int
for _, r := range s {
    pool[int(r)-97]++
}

//leetcode 2399
func checkDistances(s string, distance []int) bool {
    var myMap = make(map[rune]int)
    
    //loop through string and we get rune
    for _, r := range s {
        myMap[r] =1
    }
  
    for c, _ := range myMap {
        //rune convert to string
        var subs = string(c)
        
        //rune is int. Therefore, c-97 get index. Also use Index, LastIndex functions
        if strings.LastIndex(s, subs) - strings.Index(s, subs)-1 != distance[c-97] {
            return false;
        }
    }
   
    return true
}

//strings package has lots of useful functions
func maximumOddBinaryNumber(s string) string {
    one := strings.Count(s, "1");
    return strings.Repeat("1", one-1) + strings.Repeat("0", len(s)-one) + "1"; 
}

map

// int to int
 var myMap = make(map[int]int)

//key is rune and value is another map
 var myMap = make( map[rune]map[rune]int)
 
 //loop through map
 for key, val := range myMap {
 .....
 }
 
 //check if 2 is key is myMap. If it is, ok will be true
 j, ok := myMap[2]
 
 //also make(map[int]int) seems to  be default value to be 0.
 //The codes below prints out 0
 var myMap = make(map[int]int)
 fmt.Println(myMap[10])
 
 //default to be false. Print out false
 var myMap = make(map[int]bool)
 fmt.Println(myMap[10])
 
 //there is no clear map function. Therefore, just clear a new one
 myMap = make(map[int]int)
 
 //map as set
var mySet = make(map[int]bool)
mySet[1] = true
if mySet[1] {
    fmt.Println("have 1")
}

if mySet[2] {
    fmt.Println("have 2")
} else {
    fmt.Println("not have 2")
}

Array and Slices

//initiate an array. Type is array of [4]int
//To check type, can do fmt.Println(reflect.TypeOf(myArr))
var myArr [4]int

//if length is decided in runtime, have to use make
//type is []rune
myArr := make([]rune, len(indices))

//make a empty slice. type is []int
ans := make([]string, 0)

//another way. type is []int
ans := []int{}
        
//define slice. type is []int
var ans = []int{9, 6}

//two dimension
var trust = [][]int{{1,2},{2,8}}

//... the array length is determined by number of initializers
var ans = [...]int{9, 6} //type of int[2]

//loop through
for _, v := range ans {
}


//sort. all are in house sort
strs := []string{"c", "a", "b"}
sort.Strings(strs)
   
ints := []int{7, 2, 4}
sort.Ints(ints)

//sort array [26]int
var arr1 [26]int
sort.Ints(arr1[:])

//reverse sort. ints become 7, 4, 2
sort.Sort(sort.Reverse(sort.IntSlice(ints)))

//sort slices by lambdaish
//we want to sort [[4,5],[2,4],[4,6],[3,4],[0,0],[1,1],[3,5],[2,2]]
sort.Slice(intervals, func(i, j int) bool {
	return intervals[i][0] < intervals[j][0]
})  //intervals become [[0 0] [1 1] [2 4] [2 2] [3 5] [3 4] [4 6] [4 5]]

//append. can append multiple element
 var ans[] int
 ans = append(ans, 1, 2) //now ans = [1,2]
 
//join string array to a string
strings.Join(ans, " ")

//pop the first. Actually using sub array
arr := []int{1, 2, 3, 4, 5}
arr = arr[1:]
//get [2,3,4,5]
fmt.Println(arr)

//clone array array. First make an empty array. Then do append
temp := make([]int, 0)
temp = append(temp, score...)

//custom sort. can sort in desc
 var odd = []int {1,3,7}
 sort.Slice(odd, func(i, j int) bool {
     return odd[i] > odd[j]
 })
fmt.Println(odd) //7,3,1

//remove last element from array
stack = stack[:len(stack)-1]

Type convert

//convert byte to int. here n is 97
var a = 'a'
n := int(a)

type keyword

type keyword is there to create a new type

//create a new type Vertex which is type of struct
type Vertex struct {
  X int
  Y int
}

func main() {
  v := Vertex{1, 2}
  v.X = 4
  fmt.Println(v.X)
}

//another example
type Currency int

We can add a method to struct. Noted the syntax is different from normal function definition

package main

import (
    "fmt"
)

type Vertex struct {
    x int
    y int
}

//add a method to struct Vertex. Pay attention to syntax
func (v Vertex) distance() int {
    return v.x*v.x + v.y*v.y
}

func main() {
    v := Vertex{1, 2}
    fmt.Println(v.x)
    fmt.Println(v.distance())
}

enums and iota

Use to define a sequence of constants. For the below example, start USD to be 0

const (
    USD int = iota
    CAD
    RMB
)

func main() {
    fmt.Println(CAD) // 1
}

The below is example to use enum. Create a custom type and define backend raw type. Then use const to define enum

type combineType string

const (
    SAME combineType = "same"
    DIFF = "diff"
)

func makeS(a int, b int) string {
    var c combineType = SAME
    if a != b {
        c=DIFF
    }
    if c=="same" {
        return strconv.Itoa(a)
    } else {
        return strconv.Itoa(a) + "->" + strconv.Itoa(b)
    }
}

Some Leetcode solutions

Leetcode 1290

func getDecimalValue(head *ListNode) int {
    var ans bytes.Buffer
    
    for head.Next != nil {
        ans.WriteString(strconv.Itoa(head.Val))
        head = head.Next
    }
    ans.WriteString(strconv.Itoa(head.Val))
    
    
    result, _ := strconv.ParseInt(ans.String(), 2 , 64)
    return int(result)
}

A fake class

Below is a solution for Leetcode 2671

type FrequencyTracker struct {
    mapN map[int]int
    mapF map[int]int
    
}


func Constructor() FrequencyTracker {
    var m1 = make(map[int]int)
    var m2 = make(map[int]int)
    return FrequencyTracker{m1, m2}
}


func (this *FrequencyTracker) Add(number int)  {
    j, ok := this.mapN[number]
    if ok {
        this.mapN[number] = j+1
        this.decreaseF(j)
        this.increaseF(j+1)
    } else {
        this.mapN[number] =1
        this.increaseF(1)
    }
    
}


func (this *FrequencyTracker) DeleteOne(number int)  {
    j, ok := this.mapN[number]
    if (ok) {
        if j==1 {
            delete(this.mapN, number)
        } else {
            this.mapN[number] = j -1
        }

        this.decreaseF(j)
        this.increaseF(j-1)
    }
    
}

func (this *FrequencyTracker) decreaseF(f int)  {
    if f>0 {
        j, _ := this.mapF[f]
        if j==1 {
            delete(this.mapF, f)
        } else {
            this.mapF[f] = j-1
        }
    }
}

func (this *FrequencyTracker) increaseF(f int)  {
    if f>0 {
        j, ok := this.mapF[f]
        if ok {
            this.mapF[f] = j+1
        } else {
            this.mapF[f] = 1
        }
    }
}


func (this *FrequencyTracker) HasFrequency(frequency int) bool {
    _, ok := this.mapF[frequency]

    
    return ok
}


/**
 * Your FrequencyTracker object will be instantiated and called as such:
 * obj := Constructor();
 * obj.Add(number);
 * obj.DeleteOne(number);
 * param_3 := obj.HasFrequency(frequency);
 */

Linked List

/**
 * Definition for singly-linked list.
 * type ListNode struct {
 *     Val int
 *     Next *ListNode
 * }
 */
 
 //create a linked list [9, 8]
    node := ListNode{}
    node.Val = 9
    
    //add another node
    node2 :=ListNode{}
    node2.Val = 8
    node.Next = &node2
    
    head := &node
   
   //Another example to create [1, 2, 3] if we return head
   //create a head node and let head point to its address
    node := ListNode{1, nil}
    head := &node
    
    //use cur as an tempary bridge to add more node
    cur := &node
   
    //create node and assign it to cur's next.
    //Then move cur to the next
    cur.Next = &ListNode{2, nil}
    cur = cur.Next
    
    //repeat the above step
    cur.Next = &ListNode{3, nil}
    cur = cur.Next

Run function

//to run test.go go run test.go
package main

import "fmt"

func main() {
	res := tribonacci(25)
	fmt.Println(res)
}

func tribonacci(n int) int {
	if n == 0 {
		return 0
	}

	if n <= 2 {
		return 1
	}

	dp := make([]int, n+1)
	dp[0] = 0
	dp[1] = 1
	dp[2] = 1

	for i := 3; i <= n; i++ {
		dp[i] = dp[i-1] + dp[i-2] + dp[i-3]
	}

	return dp[n]
}

Sunday, 5 December 2021

Java cheating sheet

Syntax and tricks

Array

//initial
var arr = new int[10];

int[] myIntArray = {1, 2, 3};

int[][] move = { { r - 1, c }, { r + 1, c }, { r, c - 1 } };

//add another array list into list.
List<List<String>> ans = new ArrayList<>();

//use List.of to build a list
List<String> arr = List.of("a", "b");
System.out.println(arr.size());
System.out.println(arr.get(0));

//length
var l = arr.length;

//sort
Arrays.sort(arr);

String and Char

//String length. call function
s.length();

//check if char is lower case or upper case
Character.isUpperCase(c)
Character.isLowerCase(c)

//loop through string by chars
for (int i=0; i<s.length(); i++) {
     var c = s.charAt(i);
}

//char to string
Character.toString(c);

//string to int
Integer.parseInt("09")

//int to string
var s = Integer.toString(98);

number char '9' to int

int v = '9' - '0';

map

//To get default value. assume key is int 6 and default value is 0
var val = map.getOrDefault(6, 0);

//can use ArrayList as map key
var map1 = new HashMap<List<Integer>, String>();

//can use array as map value
var map = new HashMap<Integer, int[]>();

//see if hash has key
if (map.containsKey(n)) continue;

//loop through
for (int k: map.keySet()) System.out.println(map.get(k));

//create a reverse order tree map
var map = new TreeMap<Integer, Integer>(Collections.reverseOrder());
 
 //empty map
 map.clear();

set

//add element
set.add(n);

//set size;
return set.size();

//contains key
set.contains(key)

//find intersection of two set
var set1 = new HashSet<Integer>();
var set2 = new HashSet<Integer>();
//copy elements.  So, elements in set1 and set2 will not change
var intersection = new HashSet<Integer>(set1);
intersection.retainAll(set2);

Stack

//pop or push
stack.pop()
stack.peek()
stack.push(c)

//stack can hold array
var stack = new Stack<int[]>();
int[] point = {1,2};
stack.push(point);

StringBuilder

var builder = new StringBuilder();
 for (char c: stack) builder.append(c);
        
return builder.toString();

Noted in code snippets below, some <type> is missing because of shortcoming of code highlight

var keyword in Java

The var keyword was introduced in Java 10. It does not make Java dynamically typed. Compiler will figure out type using information from the variable's initializer.

  • var is used to declaring local variables and an initializer is required on the right-hand side
  • var can not be used as fields, method parameters and method return type
  • can not initiate with null

The below is a code snippet to use var. This is a solution for Leet code 2094


class Solution {
    public int[] findEvenNumbers(int[] digits) {
        var d =new int[10];
        for (var i: digits) d[i]=d[i]+1;
        
        var number= 100;
        
        
        var ans = new ArrayList<Integer>();
        
        while (number<999) {
            // find three digit to build this number
            var d1 = number/100;
            var d2 = (number-d1*100)/10;
            var d3 = number-d1*100-d2*10;
            
            //check if we get enough digits
            var check = Arrays.copyOf(d, 10);
         
            check[d1] = check[d1]-1;
            check[d2] = check[d2]-1;
            check[d3] = check[d3]-1;
           
            if (check[d1]>=0 && check[d2]>=0 && check[d3]>=0) ans.add(number);
               
            number=number+2;
        }
        
        var result = new int[ans.size()];
        for (var i=0; i<ans.size(); i++) result[i]=ans.get(i);
        
        return result;
        
    }
}

Can not find symbol var problem

Test.java:15: error: cannot find symbol var 
java -version
openjdk version "11.0.11" 2021-04-20

javap -verbose Test | grep "major"
 major version: 52
 //okay, not good. 52 =>JVM 8
 
 //install jdk-11 (before used sudo apt-get install default-java)
 sudo apt-get install openjdk-11-jdk

 //check. It is good now
 javap -verbose Test | grep "major"
  major version: 55

Lambda expression


import java.util.*;

class test3 {
	public static void main(String[] args) {
		List<String> names = Arrays.asList("leo", "winkey", "scott", "jeniffer");
		Collections.sort(names, (String a, String b) -> {
				return a.compareTo(b);
			}

		);

	}
}

The below is lambda expression

Lambda was introduced in Java 8

(String a, String b) -> {
	return a.compareTo(b);
}

For one line expression, can skip both return and curly brace

(String a, String b) ->  a.compareTo(b)

Java will figure out type here. Therefore the expression can be

(a,b)->a.compareTo(b)
//sort list of list
pairs.sort((l1, l2) -> l1.get(0).compareTo(l2.get(0)));

//sort arrayList
Collections.sort(list);

//sort array
Arrays.sort(need);

//use Lamda to sort array. Result is "yy", "ddd", "oldyy"
//if want to sort int array by lambda, array needs to be: var arr = new Integer(10)
 String[] hb = {"ddd", "yy", "oldyy"};
 Arrays.sort(hb, (a,b) ->a.length()-b.length());
 
 //sort that two dimension array
 Arrays.sort(nums, (a, b) -> b[1]-a[1]);
 
 //sort by two cols
 Arrays.sort(
      res,
      Comparator.<int[]>comparingInt(arr -> arr[0]).thenComparing(arr -> arr[1])
    );
 
 

Stream

local variable in the lambda function need to be final or effectively final. For object, if we do not change reference, it is effectively final. Then we can use StringBuilder object defined outside in the example below.


List<String> myList =
    Arrays.asList("ab", "cd", "cf", "ed");

myList
    .stream()
    .filter(s -> s.startsWith("c"))
    .map(String::toUpperCase)
    .sorted()
    .forEach(System.out::println);
    
//another example. chars return a int stream for string
StringBuilder sb = new StringBuilder("");
        
s.chars().forEach(i->sb.append(Character.toLowerCase((char)i)));

HashMap

//key reversed (big to small) treemap
var map = new TreeMap<Integer, Integer>(Collections.reverseOrder());

//leetcode 2190
class Solution {
    public int mostFrequent(int[] nums, int key) {
        var hashmap = new HashMap<Integer, Integer>();
        
        for (int i=1; i<nums.length; i++) {
            if (nums[i-1]==key) {
                hashmap.put(nums[i], 1 + hashmap.getOrDefault(nums[i], 0));
            }
        }
        
        int maxC = 0;
        int ans = 0;
        
        
        for(Integer k : hashmap.keySet()) {
            if (hashmap.get(k)>maxC) {
                maxC = hashmap.get(k);
                ans = k;
            }
        }
        return ans;
    }
}

//create ArrayList of arr
var list = new ArrayList<String[]>();

cast between char, string and integer

//int to string
var s = String.valueOf(x);

//solution for leetcode 2194
class Solution {
    public List<String> cellsInRange(String s) {
        
        var row = new int[2];
        
        //cast string "2" to integer
        row[0]  = Integer.parseInt(s.substring(1,2));
        
        row[1]  = Integer.parseInt(s.substring(4,5));
        
        //cast char 'A' to integer
        var col = new int[2];
        col[0] = (int)s.charAt(0);
        col[1] = (int)s.charAt(3);
       
        var ans = new ArrayList<String>();
        
        for (int c= col[0]; c<=col[1]; c++) {
            
            for (int r=row[0]; r<=row[1]; r++) {
            	//int to char; char to string
                var cell = Character.toString((char)c) + r;
                ans.add(cell);
            }
        }
        
        return ans;
   
    }
}

bit operation

bitwise and. & AND Sets each bit to 1 if both bits are 1


int a = 4&3;
System.out.println(a); //0 because 100 &011

Bit shift


    // 2 bit left shift operation
    int number = 2;
    int result = number << 2;
    System.out.println(result); // prints 8

    // 1 bit left shift operation
    int number2 = 2;
    int result2 = number2 << 1;
    System.out.println(result2); // prints 4

The fastest way to check if a number is a prime


private int isPrime(int n) {
    if (n <= 1) return 0;
    if (n == 2 || n == 3) return 1;
    if (n % 2 == 0 || n % 3 == 0) return 0;
    for (int i = 5; i * i <= n; i = i + 6) {
      if (n % i == 0 || n % (i + 2) == 0) return 0;
    }
    return 1;
  }

Find all primes less than n


  //find all primes LESS THAN n
  //if want to primes less or equals, set argument to 
  //be n+1 when call this function.
  public ArrayList<Integer> countPrimes(int n) {
    ArrayList<Integer> arr = new ArrayList<>();
    boolean[] notPrime = new boolean[n];

    for (int i = 2; i < n; i++) {
      if (notPrime[i] == false) {
        arr.add(i);

        for (int j = 2; i * j < n; j++) {
          notPrime[i * j] = true;
        }
      }
    }

    return arr;
  }

TreeSet floor and ceiling

It will find a value for the set. floor: greast value less or equals the given value. ceiling: smalles value greater or equals to the given value.

//solution for Leetcode 2817
class Solution {
    public int minAbsoluteDifference(List<Integer> nums, int x) {
        int ans = Integer.MAX_VALUE;
        TreeSet<Integer> set = new TreeSet<>();

        for (int i=x; i<nums.size(); i++) {
            set.add(nums.get(i-x));
            
            Integer val = set.floor(nums.get(i));
            if (val!=null) ans = Math.min(ans, Math.abs(val - nums.get(i)));

            val = set.ceiling(nums.get(i));
            if (val!=null) ans = Math.min(ans, Math.abs(val - nums.get(i)));
        }

        return ans;
        
    }
}

Run codes

//javac Solution.java | java Solution
class Solution {

  public boolean canMakeSquare(char[][] grid) {
    if (isGood(grid, 0, 0)) return true;
    if (isGood(grid, 1, 0)) return true;
    if (isGood(grid, 0, 1)) return true;
    if (isGood(grid, 1, 1)) return true;

    return false;
  }

  private boolean isGood(char[][] grid, int row, int col) {
    int b = 0;
    int w = 0;

    for (int i = row; i <= row + 1; i++) {
      for (int j = col; j <= col + 1; j++) {
        if (grid[i][j] == 'B') {
          b++;
        } else {
          w++;
        }
      }
    }

    return b >= 3 || w >= 3;
  }

  public static void main(String[] args) {
    Solution obj = new Solution();
    char[][] test = { { 'B', 'W', 'B' }, { 'B', 'W', 'W' }, { 'B', 'W', 'B' } };

    var ans = obj.canMakeSquare(test);
    System.out.println(ans);
  }
}

Java Queue

Java Queue

Sunday, 21 November 2021

Run Jenkins pipeline for local git repository

Step one: global tool config to add git excutable

  • Go to Dashboard
  • Click Manage Jenkins
  • Click Global Tool Configuration
  • In Git Section add git executable path. For me: /usr/bin/git
  • Click apply

Step two: Create a new item

  • Go to Dashboard
  • Click New Item
  • Give name
  • Click Pipeline
  • Click OK
  • In Pipeline Section, select Pipeline Script from SCM from drop down for Definition field
  • Choose Git from dropdown for SCM
  • Pu file:///home/leo2019/play_jenkins in repository Url field
  • Click apply

Step three: Create a Jenkinsfile

In the root directory of git repository, create a file called Jenkinsfile. For this example, the file is put in /home/leo2019/play_jenkins/

The following is the content of my test Jenkinsfile

#!/usr/bin/env groovy
pipeline {
  agent any
  stages {
    stage('Stage 1') {
      steps {
        echo 'Hello world!'
        println "Great!"
        sleep(30)
      }
    }
  }
}

Step four: build

Some console output


Started by user unknown or anonymous
Obtained Jenkinsfile from git file:///home/leo2019/play_jenkins
Running in Durability level: MAX_SURVIVABILITY
[Pipeline] Start of Pipeline
[Pipeline] node
Running on Jenkins in /var/lib/jenkins/workspace/My test for blog
[Pipeline] {
[Pipeline] stage
[Pipeline] { (Declarative: Checkout SCM)
[Pipeline] checkout
Selected Git installation does not exist. Using Default
The recommended git tool is: NONE
No credentials specified
Cloning the remote Git repository
Cloning repository file:///home/leo2019/play_jenkins
 > /usr/bin/git init /var/lib/jenkins/workspace/My test for blog # timeout=10
Fetching upstream changes from file:///home/leo2019/play_jenkins
 > /usr/bin/git --version # timeout=10
 > git --version # 'git version 2.17.1'
 > /usr/bin/git fetch --tags --progress -- file:///home/leo2019/play_jenkins +refs/heads/*:refs/remotes/origin/* # timeout=10
 > /usr/bin/git config remote.origin.url file:///home/leo2019/play_jenkins # timeout=10
 > /usr/bin/git config --add remote.origin.fetch +refs/heads/*:refs/remotes/origin/* # timeout=10
Avoid second fetch
 > /usr/bin/git rev-parse refs/remotes/origin/master^{commit} # timeout=10
Checking out Revision 743c558e082f3fe9944db4ecd969f6ffc007aaeb (refs/remotes/origin/master)
 > /usr/bin/git config core.sparsecheckout # timeout=10
 > /usr/bin/git checkout -f 743c558e082f3fe9944db4ecd969f6ffc007aaeb # timeout=10
Commit message: "greate"
First time build. Skipping changelog.
[Pipeline] }
[Pipeline] // stage
[Pipeline] withEnv
[Pipeline] {
[Pipeline] stage
[Pipeline] { (Stage 1)
[Pipeline] echo
Hello world!
[Pipeline] echo
Great!
[Pipeline] sleep
Sleeping for 30 sec
[Pipeline] }
[Pipeline] // stage
[Pipeline] }
[Pipeline] // withEnv
[Pipeline] }
[Pipeline] // node
[Pipeline] End of Pipeline
Finished: SUCCESS

Tuesday, 9 November 2021

Which version of alpine linux package will be installed?

Assume you have this docker file. You may wonder what version of bash will be installed.


FROM alpine:3.14
RUN apk --update add apache2 bash

The pakage version depends on alpine version. We can go to Alpine Linux packages to find out.

Monday, 8 November 2021

MongoDB

Install MongoDB in Ubuntu.

start stop server

1. start
sudo systemctl start mongod

2. check status
sudo systemctl status mongod

3. stop
 sudo systemctl stop mongod

4. restart
sudo systemctl restart mongod

5. use mongosh
mongosh

Find connect uri

mongosh

//should see something like the below
Connecting to:mongodb://127.0.0.1:27017/?directConnection=true&serverSelectionTimeoutMS=2000

Use node.js to connect to MongoDB

Install node.js MongoDB driver

npm install mongodb --save

Connect

//put it in index.js
const { MongoClient } = require("mongodb");

// Connection URI
const uri = "mongodb://127.0.0.1:27017/?directConnection=true&serverSelectionTimeoutMS=2000";

// Create a new MongoClient
const client = new MongoClient(uri);

//database name
const dbName = 'leo_test_db';

async function run() {
  try {
    // Connect the client to the server
    await client.connect();

    // Establish and verify connection
    await client.db("admin").command({ ping: 1 });
    console.log("Connected successfully to server");
    
    const db = client.db(dbName);
    const collection = db.collection('books');

    const insertResult = await collection.insertMany([{'java':2005}, {'PHP':2010}]);
    console.log("insert result", insertResult)

    } finally {
    // Ensures that the client will close when you finish/error
    await client.close();
  }
}
run().catch(console.dir);

//run it
node index.js

//output Connected successfully to server

Basic CRUD operations

//insert one
const insertResult = await collection.insertOne({'go':2021});

//insert multiple items
const insertResult = await collection.insertMany([{'java':2005}, {'PHP':2010}]);

mongo shell reference

//open shell
mongosh
//show databases
show dbs

Create a new database

mongosh

//want to create db called newswatcherdb. This command will work
//even we do not have this db yet
use newswatcherdb

//need to add something into db to create db
db.user.insert({name:"leo"})

//new created db in the list
show dbs

//show collections in db
use leo_test_db
show collections //get books
db.books.find() // will show items in collection

Some useful links

Monday, 25 October 2021

Javascript cheat sheet

Promise

The Promise object represents the eventual completion (or failure) of an asynchronous operation and its resulting value.

Therefore we can let an asynchronous method to return as a synchronous method. We can associate handlers to the promise. These handlers will handle eventaul success values or failure reason.

A promise has three states: pending, fulfilled with a value or rejected with a reason. We use then method of promise object to attach handler.

Consuming promise

promiseObj.then(successCallBackFunc, failureCallbackFunc)

Guarantees for then()

  1. then will never be invoked if promise is in pending state
  2. then will be called event if it is added after promise has exited from pending state
  3. can add multiple then. These thens will be called in the order they are added

promise.catch()

return a promise and deals with rejected case only. It is the same as to call then(undefined, onRejected)

promise.finally()

  • the finally() method is executed when the promise is settled no matter it is successful or failed
  • This handler of finally receives no parameters
  • It will return another promise

Creating Promise

Promise.resolve(value) will return

  1. A promise that is resolved by value passed as argument
  2. If value passed as argument is a promise, will return that promise

Promise.reject(reason) will return A promise object that is rejected with a given reason

Promise.all() The argument of all is an array of promise. It will return one promise. This returned promise fulfills when all of the input's promises fulfill (including when an empty iterable is passed), with an array of the fulfillment values. It rejects when any of the input's promises rejects, with this first rejection reason.

The Promise.race() static method takes an iterable of promises as input and returns a single Promise. This returned promise settles with the eventual state of the first promise

setTimeout(functionRef, delay, param1)  delay unit is millisecond
const promise1 = new Promise((resolve, reject) => {
  setTimeout(resolve, 500, 'tuttle');
});

const promise2 = new Promise((resolve, reject) => {
  setTimeout(resolve, 100, 'rabit');
});

Promise.race([promise1, promise2]).then((value) => {
  console.log(value);
  // Both resolve, but promise2 is faster
});
// Expected output: "rabit"
//Promise in action
//Promise constructor accepts two predefined 
//functions: resolve and reject
let p = new Promise((resolve, reject)=> {
        let good = false
        if (good) {
                resolve(100)
        } else {
                reject("sad. bad")
        }
});

//we will see sad. bad. However, if we set good to be true,
//will see 101. Here then accepts two functions. The first is
//for fulfillment and the second is for rejection
p.then((n)=> console.log(n+1), (msg)=>console.log(msg))

//here is another way
p.then((n)=> {
    console.log("resolved")
    console.log("n", n+1)
}).catch((msg) => {
    console.log("rejected")
    console.log("msg", msg)
})

Put axios in a Promise chain

//sample codes to put axios in a Promise chain
session.onpaymentauthorized =  (event)=> {
    applePayInstance.tokenize({
        token: event.payment.token
    }).then( (payload) => {
        const requestData = {
            url: '/test/do-whatever/',
            method: 'post',
            headers: {'content-type': 'application/x-www-form-urlencoded'},
            data: "amount=111"
        }
         
         //return another promise and it will be put in this chain
         return axios(requestData)
    }).then(response => {
            if (response.data.success){
                console.log("good. will complete sesson to dismiss sheet")
            } else {
               console.log("creating order failed")
            }
    }).catch((tokenizeErr) => {
        console.log('Error tokenizing Apple Pay:', tokenizeErr);
        session.completePayment(ApplePaySession.STATUS_FAILURE);
    });
};
//an example to use axios
//an example to use axios
import axios from "axios";
let postData = {
    name: "john",
    age: 35,
};

const requestData = {
    url: '/myulr/test/?eventName=' + eventName,
    method: 'post',
    headers: {
        'content-type': 'application/json',
        'x-requested-with': 'XMLHttpRequest'
    },
    data: postData
}

axios(requestData)
//server side to invoke by node.js
const axios = require('axios');

//to debug
axios(requestData).catch((err) => {
    console.log(err.response)
})

Use async function to handle promise

An async function is a function declared with the async keyword. It works with await keywords to handle promise in a cleaner style. Await and async will not block javascript main thread. await will wait a result of a promise. Here is an example:

myPromiseGenerator = function() {
  return new Promise(resolve => {
    setTimeout(() => {
      resolve('Hello world');
    }, 2000);
  });
}

async function myFunc() {
  console.log('calling');
  
  //waiting for promise result
  const result = await myPromiseGenerator();
  console.log(result);
}

myFunc()

//output will be the following
//calling
//Hello world

Object.assign

const target = { a: 1, b: 2 };
const source = { b: 4, c: 5 };

const returnedTarget = Object.assign(target, source);

console.log(target);
// Expected output: Object { a: 1, b: 4, c: 5 }

console.log(returnedTarget)
// Expected output: Object { a: 1, b: 4, c: 5 }

console.log(source)
// Expected output: Object { a: 1, b: 2} . no change from origin

for ..of loops

ES6 adds a for ..of loop. It is used to loop of set of values produced by an iterator. Most likely, will be used to loop through array and string


var arr = ['a','b','c']
for (var val of arr) {
    console.log(val)
}
//'a', 'b', 'c'


for (var c of 'hi') {
    console.log(c)
}
//'h', 'i'

//loop array index
for (let i in arr) {
    console.log(i)
}
//0,1,2

use object as hash table

The below is a solution for a LeetCode problem


/**
 * @param {number[]} nums
 * @return {number}
 */
var singleNumber = function(nums) {
	//define a object
    let d = {}
    
    for (let n of nums) {
    	//check if n is a property of object. like check if hash has key
        if (n in d) {
            d[n] = 2
        } else {
            d[n] =1
        }
    }
    
    //loop through object's property
    for (let n in d) {
        if (d[n]==1) {
            return n;
        }
    }
    
    //if want to get all properties of this object
    let keys = Object.keys(d)
    
    // get length
    Object.keys(obj).length
};

Build array of objects

//build offer array
let offerVals = []
for (let offer of data.offers) {
    let obj = {}
    obj[offer.sku] = offer.quantity
    offerVals.push(obj)
}
//build json string with array. noted that build obj in two ways
//output {"category":"developers","persons":[{"name":"leo","age":50},
//{"name":"john","age":40}]}
let obj = [];
obj.push({ name: "leo", age: 50 });

let p2 = {};
p2["name"] = "john";
p2["age"] = 50;
obj.push(p2);

let str = { category: "developers", persons: obj };
console.log(JSON.stringify(str));

ES6 template literals

Use backtick ` as delimiter.

let name="leo"
let welcome = `hi ${name}!`;

console.log(welcome) //hi leo!

//allow split across multiple lines
let name=`hello
world`;

//hello
//world
console.log(name)

Array

//sort number array
nums.sort((a,b)=>a-b)

//initiate array with single values
// arr = Array(arraySize).fill(value)
let ans = Array(5).fill(-1)

//copy array
const animals = ['dog', 'bison', 'camel', 'duck', 'elephant'];

let animalCopy = animals.slice();

//also can do the following to copy
let animalCopy = [].concat(animals)


//array merge
const array1 = ['a', 'b', 'c'];
const array2 = ['d', 'e', 'f'];
const arr3 = ['j','p']
const array4 = array1.concat(array2, arr3);
//array4 is ['a', 'b', 'c','d', 'e', 'f','j','p']

//unshift to add element in the begining of array
const array1 = [1, 2, 3];
array1.unshift(4, 5);
console.log(array1);
// expected output: Array [4, 5, 1, 2, 3]

//map() will create a new array by calling a provided function for every elements
const arr1 = [1, 2, 3]
const arr2 = arr1.map((n)=>n*n)
console.log(arr2) //[1,4,9]

//use filter to move element to the begin of array. Here assume p is in array and it is unique
 arr = arr.filter(item => item !== q);
 arr.unshift(q);
 
 //create a 26 letters array
 const letters = 'abcdefghijklmnopqrstuvwxyz'.split('');
 
 //string to array
 let s ="leetcode"
 const chars = [...s];

Object destructuring

const pet = {name:"weiwei", age:13}

//here is object destructuring
 const {name, age} = pet
 
 console.log("name", name)
 console.log("age", age)
 
 //Destruct and Rename
const person =  {
    name: "leo",
    country: "Canada"
}

const {name:first} = person
console.log("first is:", first) //leo
console.log("name:", name) //undefined

Math


// integer division. will get 4
Math.trunc(32/7)

High order component

A good blog about high order component

Four steps

  1. Create a base component
  2. Create a function which take base component and return a upgraded component
  3. import that function and call it to get a new component
  4. use this new component. This new component normally has new extra props

Redux form is high order component. Here is a good introduction for redux form.

Response.json()

The json() method takes a Response stream and reads it to completion. It returns a promise which resolves with the result of parsing the body text as JSON. Then we can use this data to do some thing. The pattern is showing below which work with fetch.

const remoteEndPoint = "https://someapi";
fetch(remoteEndPoint)
      .then((response) => response.json())
      .then((data) => {
        this.setState({ loading: false, data: data });
      })
      .catch(console.error);

Use Axios

We can send a header config when do API call using Axios. Noted position of config field for get and post are different.

const config = {
    headers: {
        "X-Authorization-JWT": initData.jwt,
        "Content-Type": "application/json"
    }
}

axios.get(url, config)
axios.post(url, data, config)
axios.put(url, data, config)

//to pass csrf and more headers
const config = {
    headers: {
        'Content-Type': 'application/json',
        'X-CSRF-Token': csrf
    }
}

lodash

_.includes( collection, value)

let a=[1,2]
let f = _.includes(a, 3) //false
f = _.includes(a,1) //true 

Some useful built in function

slice() will do a shallow copy of an array. You can pass indexes as argument of the function. If no argument is passed, do a shallow copy of entire array

const animals = ['ant', 'bison', 'elephant', 'dog'];
console.log(animals.slice());
// expected output: Array ["ant", "bison", "elephant", "dog"]

Object.assign() method copies all enumerable own properties from one or more source objects to a target object. It returns the modified target object.

const target = { a: 1, b: 2 };
const source = { b: 4, c: 5 };
const returnedTarget = Object.assign(target, source, {leo:22});
console.log(target);
console.log(returnedTarget);
//output
> Object { a: 1, b: 4, c: 5, leo: 22 }
> Object { a: 1, b: 4, c: 5, leo: 22 }

two ways to copy an object

var player = {score: 1, name: 'Jeff'};
var newPlayer = Object.assign({}, player, {score: 2});
// Now player is unchanged, but newPlayer is {score: 2, name: 'Jeff'}

// Or if you are using object spread syntax proposal, you can write:
// var newPlayer = {...player, score: 2};

Array reduce(). It accept a callback, and will work on every element in order. After done, return the last value. For that callback function, the first argument is the previous value, and the seconde is the current value. When run on the first element, we can pass an initial value

let arr=[1,2,3]
let iniV = 7
let ans = arr.reduce((total,n)=>total*n, 7)
console.log(ans) //42 = 7*1*2*3

If initial value is not provided, the first element will be used as init value and process element starting from the second element.

let arr=[1,2,3]
let ans = arr.reduce((total,n)=>total*n)
console.log(ans)//6=1*2*3

mapping letter to integer. 'A' =>1 A has value 65

columnTitle.charCodeAt(i)-64

cast type

let a="8"
let b = +a
console.log(typeof a) //string
console.log(typeof b) //number

Optional chaining (?.)

In most use case, try to access an property of object. If it does not exist, return undefined instead of giving out error.

const obj = {
  cat: {
    name: 'Dinah'
  }
};

console.log(obj.cat2?.name);
// expected output: undefined

console.log(obj.cat2.name);
//expected error

console.log(obj.cat.name);
//Dinah

Use [key] notation for object

const name = "leo"
const obj = {[name]:"developer"}

console.log(obj.leo)
console.log(obj[name])

//undefined
console.log(obj.name)

char, int, ascii code

//solution for Leetcode 2194
var cellsInRange = function(s) {
    let c1 = s.charCodeAt(0)
    let c2 = s.charCodeAt(3)
    
    //0 ascii code is 48
    let r1 = s.charCodeAt(1) - 48
    let r2 = s.charCodeAt(4) -48
    
    let ans = []
    
    for (let c=c1; c<=c2; c++) {
        for (let r=r1; r<=r2; r++) {
        	//ascii code to char
            let cell = String.fromCharCode(c) + r
            ans.push(cell)
        }
    }
      
    return ans
    
};

Logic or

//The Logical OR operator (||) returns the value of its 
//second operand, if the first one is falsy, otherwise the value
//of the first operand is returned
let a ="foo" || "bar"; // returns "foo"
console.log(a)

a = false || "bar"; // returns "bar"
console.log(a)

window.dataLayer = window.dataLayer || [];

Class

Solution for Leetcode 2622

var TimeLimitedCache = function () {
  this.d = {};
};

/**
 * @param {number} key
 * @param {number} value
 * @param {number} time until expiration in ms
 * @return {boolean} if un-expired key already existed
 */
TimeLimitedCache.prototype.set = function (key, value, duration) {
  let ans = false;
  if (key in this.d) {
    let obj = this.d[key];
    if (obj.expiry >= Date.now()) ans = true;
  }
  this.d[key] = { v: value, expiry: duration + Date.now() };

  return ans;
};

/**
 * @param {number} key
 * @return {number} value associated with key
 */
TimeLimitedCache.prototype.get = function (key) {
  if (key in this.d) {
    let obj = this.d[key];
    return (obj.expiry >= Date.now()) ? obj.v : -1
  }

  return -1;
};

/**
 * @return {number} count of non-expired keys
 */
TimeLimitedCache.prototype.count = function () {
  let ans = 0;
  let keys = Object.keys(this.d);
  for (let k of keys) {
    if (this.d[k].expiry >= Date.now()) ans = ans + 1;
  }
  return ans;
};

/**
 * Your TimeLimitedCache object will be instantiated and called as such:
 * var obj = new TimeLimitedCache()
 * obj.set(1, 42, 1000); // false
 * obj.get(1) // 42
 * obj.count() // 1
 */

Solution for Leetcode 2695

/**
 * @param {number[]} nums
 */
var ArrayWrapper = function(nums) {
    this.nums = nums
};

ArrayWrapper.prototype.valueOf = function() {
    return this.nums.reduce((a, b) => a + b, 0)
}

ArrayWrapper.prototype.toString = function() {
    return `[${this.nums.join()}]`
}

/**
 * const obj1 = new ArrayWrapper([1,2]);
 * const obj2 = new ArrayWrapper([3,4]);
 * obj1 + obj2; // 10
 * String(obj1); // "[1,2]"
 * String(obj2); // "[3,4]"
 */

Some mistakes

The below is solution for Leetcode 2627

Scope problem. use pendingF = [] instead of let pendingF = []. Without let, pendingF becomes a global variable. Because Leetcode will run bunches of test, pendingF is accessed by all tests and it causes a hard fix bug.

/**
 * @param {Function} fn
 * @param {number} t milliseconds
 * @return {Function}
 */
var debounce = function (fn, t) {
  //make sure this variable is not global. Need let
  let pendingF = [];
  return function (...args) {
    let cur = Date.now();
    for (let obj of pendingF) {
      if (obj.start > cur) {
        clearTimeout(obj.timeout);
      }
    }

    myTimeout = setTimeout(() => fn(...args), t);
    pendingF.push({ timeout: myTimeout, start: cur + t });
  };
};

/**
 * const log = debounce(console.log, 100);
 * log('Hello'); // cancelled
 * log('Hello'); // cancelled
 * log('Hello'); // Logged at t=100ms
 */

Sort Array

Sort Array

Play with object

/**
 * @param {Object} obj
 * @return {Object}
 * Leetcode 2822
 */
var invertObject = function (obj) {
  let ans = {};
  for (let k of Object.keys(obj)) {
    let v = obj[k];

    if (Object.hasOwn(ans, v)) {
      let cur = ans[v];

      if (Array.isArray(cur)) {
        cur.push(k);
      } else {
        cur = [cur];
        cur.push(k);
      }

      ans[v] = cur;
    } else {
      ans[v] = k;
    }
  }

  return ans;
};

Set

let set = new Set();
set.add(1);
set.add(1);
set.add(2);
set.add(100);

//size is 3
console.log(set.size);

Debug

Safari

  • right click page. select inspect element to show console
  • click recycle bin in the upper right corner to clear console

Chrome

  • right click page. select inspect to show console
  • type console.clear() to clear console

package.json

//do not install devDependencies
npm install --production

//will install devDependencies
npm install

jQuery

//ajax call to get data
$.get("http://test.com", function(data, status){
    alert("Data: " + data + "\nStatus: " + status);
});
//find first element of a class
$(".myClass").first();
//pass a string containing HTML and create a new element:
let html = "
Hi
"; let myEle = $(html);

let parent = $(".myClass").first();
let html = "<div>Hi</div>";
let myEle = $(html);

parent.append(myEle);

Switch node version by nvm

nvm list

# add the following in .bashrc, so alway use the version 16 when open a terminal
nvm use 16.15.1

not null and not undefined

//the followinig two lines are equasl
a != null;
a !==null && a !== undefined;














Sunday, 24 October 2021

Solve a LeetCode problem with regular expression

Here is the problem LeetCode 2047

Eventually, I figure out a regular express to solve this problem. I will explain how this regular expression works


//Java
import java.util.regex.*;
class Solution {
    public int countValidWords(String sentence) {
        String[] words = sentence.trim().split("\\s+");
        int ans = 0;
        
        Pattern pattern = Pattern.compile("^(([a-z]{0,})|([a-z]+\\-[a-z]+))[!\\.,]?$");
        
        for(String word: words) {
           Matcher matcher = pattern.matcher(word);
            if (matcher.find()) {
                ans++;
            }
        }
        
        return ans;
    }
}

#Python
import re
class Solution:
    def countValidWords(self, sentence: str) -> int:
        arr = sentence.split()
        ans = 0
        for word in arr:
            if re.search("^(([a-z]{0,})|([a-z]+\-[a-z]+))[!\.,]?$", word):
                ans+=1
        return ans

# ruby
# @param {String} sentence
# @return {Integer}
def count_valid_words(sentence)
    words = sentence.split
    ans = 0
    for word in words
        if word.match(/^(([a-z]{0,})|([a-z]+\-[a-z]+))[!\.,]?$/)
            ans = ans +1
        end
    end
    return ans
end

//PHP
class Solution {
    /**
     * @param String $sentence
     * @return Integer
     */
    function countValidWords($sentence) {
        $words = preg_split("/\s+/", trim($sentence));
        $ans = 0;
      
        foreach ($words as $word) {
           if (preg_match("/^(([a-z]{0,})|([a-z]+\-[a-z]+))[!\.,]?$/", $word)) {
                $ans++;
            }
        }
        return $ans;
    }
}

/**
 * Javascript
 * @param {string} sentence
 * @return {number}
 */
var countValidWords = function(sentence) {
    let arr = sentence.trim().split(/\s+/)
    let ans = 0
    arr.forEach((word)=>{
                if (word.match(/^(([a-z]{0,})|([a-z]+\-[a-z]+))[!\.,]?$/)) {
                    
                    ans++
                }
    })
    return ans
    
};

Here is a summary for regular express

How that regulare expression works

  • [!\.,]?$
    one or zero punctuation in the end of word
  • ^(([a-z]{0,})|([a-z]+\-[a-z]+))
    all lower case letters or lower case letters . "-" lower case letters

continue to analyse

^(([a-z]{0,})|([a-z]+\-[a-z]+))
. There are two parts in it

  • ([a-z]{0,})
    string consist of zero or more lower case letters
  • ([a-z]+\-[a-z]+)
    string with hypen which is wrapped with lower case letters

regular expression used here

  • how many time to repreat. ? (0 or once) + (at least once) {0,} (one and more)
  • group (x|y) (x or y). The first part of the expression uses group
  • boundary ^(start) $(end)

If you try to solve it without using regular expression, it will be very tedious.


//PHP
class Solution {

    /**
     * @param String $sentence
     * @return Integer
     */
    function countValidWords($sentence) {
        $words = explode(" ", $sentence);
        $ans = 0;
    
        foreach ($words as $word) {
            $word = trim($word);
            if ($word=="") {
                continue;
            }

            if (self::isValid($word)) {

                $ans++;
            }
        }
        return $ans;
    }
    
    public static function isValid($word) {
        //generate lower case letter array
        $letters = [];
        foreach (range('a', 'z') as $l) {
            $letters[] = $l;
        }
        
        $p = ['!', '.', ','];
            
        $allowedC = array_merge($letters, $p, ['-']);
      
        //count hyphens and index
        $hyC = 0;
        $hi = 0;
        
        //count punctuation and index
        $pc = 0;
        $pi = 0;
        
        for ($i=0; $i1 || $hyC >1) {
            return false;
        }
        
        if ($pc == 1 && $pi != strlen($word)-1) {
            return false;
        }
        
        if ($hyC == 0) {
            return true;
        }
        
        if ($hi-1<0 || $hi+1>= strlen($word)) {
          
            return false;
        }
        
      
        if ((!in_array($word[$hi-1], $letters)) || (!in_array($word[$hi+1], $letters))) {
           
            return false;
        }
        
        return true;
    }
}

Sunday, 17 October 2021

Solve LeetCode design problem with different languages

Here is a LeetCode problem. Now will solve this design problem in different language.

  1. Java
  2. Python
  3. Ruby
  4. PHP
  5. JavaScript ES6
  6. JavaScript

Java


class Bank {

    private long[] balance;
    private int n;
    public Bank(long[] balance) {
        this.balance = balance;
        this.n = balance.length;
        
    }
    
    private boolean goodA(int account) {
        return account >=1 && account<= this.n;
    }
    
    public boolean transfer(int account1, int account2, long money) {
        if (!goodA(account1) || !goodA(account2)) {
            return false;
        }
        
        if (this.balance[account1-1] < money) {
            return false;
        }
        
        this.balance[account1-1] = this.balance[account1-1] - money;
        this.balance[account2-1] = this.balance[account2-1] + money;
        return true;
        
        
    }
    
    public boolean deposit(int account, long money) {
        if (!goodA(account)) {
            return false;
        }
        
        this.balance[account-1] = this.balance[account-1] + money;
        return true;
        
    }
    
    public boolean withdraw(int account, long money) {
        if (!goodA(account)) {
            return false;
        }
        
        if (this.balance[account-1] < money) {
            return false;
        }
        
        this.balance[account-1] = this.balance[account-1] - money;
        return true;
        
    }
}

Python


class Bank:

    def __init__(self, balance: List[int]):
        self.balance = balance
        self.n = len(balance)
    
    def goodA(self, account):
        return account>=1 and account<=self.n
        

    def transfer(self, account1: int, account2: int, money: int) -> bool:
        if not self.goodA(account1) or not self.goodA(account2):
            return False
        if self.balance[account1-1] < money:
            return False
        
        self.balance[account1-1] = self.balance[account1-1] - money
        self.balance[account2-1] = self.balance[account2-1] + money
        return True
        

    def deposit(self, account: int, money: int) -> bool:
        if not self.goodA(account):
            return False
        
        self.balance[account-1] = self.balance[account-1] + money
        return True
        

    def withdraw(self, account: int, money: int) -> bool:
        if not self.goodA(account):
            return False
        
        if self.balance[account-1] < money:
            return False
        
        self.balance[account-1] = self.balance[account-1] - money
        
        return True

Ruby


class Bank

=begin
    :type balance: Integer[]
=end
    def initialize(balance)
        @balance = balance
        @n = balance.length
        
    end


=begin
    :type account1: Integer
    :type account2: Integer
    :type money: Integer
    :rtype: Boolean
=end
    def transfer(account1, account2, money)
        if account1<1 || account1>@n
            return false
        end
        
        if account2<1 || account2>@n
            return false
        end
        
        if @balance[account1-1] < money
            return false
        end
        
        @balance[account1-1] = @balance[account1-1] - money
        @balance[account2-1] = @balance[account2-1] + money
        return true
 
    end
=begin
    :type account: Integer
    :type money: Integer
    :rtype: Boolean
=end
    def deposit(account, money)
        if account<1 || account>@n
            return false
        end
        
        @balance[account-1] = @balance[account-1] + money
        return true
 
    end


=begin
    :type account: Integer
    :type money: Integer
    :rtype: Boolean
=end
    def withdraw(account, money)
        if account<1 || account>@n
            return false
        end
        
        if @balance[account-1] < money
            return false
        end
        
        @balance[account-1] = @balance[account-1] - money
        return true
        
    end

end

PHP


class Bank {
    private $balance;
    private $n;
    /**
     * @param Integer[] $balance
     */
    function __construct($balance) {
        $this->balance = $balance;
        $this->n = count($balance);
        
    }
  
    /**
     * @param Integer $account1
     * @param Integer $account2
     * @param Integer $money
     * @return Boolean
     */
    function transfer($account1, $account2, $money) {
        if ($account1 > $this->n || $account1 <1) {
            return false;
        }
        
        if ($account2 > $this->n || $account2 <1) {
            return false;
        }
        
        if ($this->balance[$account1 -1] < $money) {
            return false;
        }
        
        //do transfer
        $this->balance[$account1 -1] = $this->balance[$account1 -1] - $money;
        $this->balance[$account2 -1] = $this->balance[$account2 -1] + $money;
        
        return true;
        
    }
    
     /**
     * @param Integer $account
     * @param Integer $money
     * @return Boolean
     */
    function deposit($account, $money) {
         if ($account > $this->n || $account <1) {
            return false;
        }
        
        $this->balance[$account -1] = $this->balance[$account -1] + $money;
        return true;
        
    }
  
    /**
     * @param Integer $account
     * @param Integer $money
     * @return Boolean
     */
    function withdraw($account, $money) {
         if ($account > $this->n || $account <1) {
            return false;
        }
        
         if ($this->balance[$account -1] < $money) {
            return false;
        }
        
        $this->balance[$account -1] = $this->balance[$account -1] - $money;
        return true;
    }
}

Javascript ES6


class Bank {
    constructor(balance) {
        this.balance = balance
    }
    
    notValid(account) {
        return account<1 || account > this.balance.length
    }
    
    transfer(account1,account2,money) {
        if (this.notValid(account1) || this.notValid(account2)) {
            return false
        }
        
        if (money > this.balance[account1-1]) {
            return false;
        }
        
        this.balance[account1-1] = this.balance[account1-1] - money
        this.balance[account2-1] = this.balance[account2-1] + money
        return true
    }
    
    deposit(account,money) {
        if (this.notValid(account)) {
            return false;
        }
        this.balance[account-1] = this.balance[account-1] + money
        return true
    }
    
    withdraw(account,money) {
        if (this.notValid(account)) {
            return false;
        }
         
        if (money > this.balance[account-1]) {
            return false;
        }
         
        this.balance[account-1] = this.balance[account-1] - money
        return true
    }
    
}

JavaScript


/**
 * @param {number[]} balance
 */
var Bank = function(balance) {
    this.balance = balance
    
};

Bank.prototype.check = function(account) {
    return account>=1 && account<= this.balance.length
    
};

/** 
 * @param {number} account1 
 * @param {number} account2 
 * @param {number} money
 * @return {boolean}
 */
Bank.prototype.transfer = function(account1, account2, money) {
    if (!this.check(account1) || !this.check(account2)) {
        return false;
    }
    
    if (this.balance[account1-1] < money) {
        return false;
    }
    
    this.balance[account1-1] = this.balance[account1-1] - money;
    
    this.balance[account2-1] = this.balance[account2-1] + money;
    return true;
    
};

/** 
 * @param {number} account 
 * @param {number} money
 * @return {boolean}
 */
Bank.prototype.deposit = function(account, money) {
    if (!this.check(account)) {
        return false
    }
    
    this.balance[account-1] = this.balance[account-1] + money;
    return true;
    
};

/** 
 * @param {number} account 
 * @param {number} money
 * @return {boolean}
 */
Bank.prototype.withdraw = function(account, money) {
    if (!this.check(account)) {
        return false
    }
    
    if (this.balance[account-1] < money) {
        return false;
    }
    
    this.balance[account-1] = this.balance[account-1] - money;
    
    return true;
    
};

Saturday, 16 October 2021

Javascript Array Sort. Surprise!

What is the output for the below


arr = [3,20,17,2,12,15,17,4,15,20]
arr.sort()
console.log(arr)

The out put is:

[12, 15, 15, 17, 17, 2, 20, 20,  3,  4] 

The reason is that for this built in sort function, it will converting the elements into strings before do sorting! This is the only language I find so far to do such a stupid thing

To sort integer in the expected order, do that


//will out put [2,  3,  4, 12, 15, 15, 17, 17, 20, 20]
arr = [3,20,17,2,12,15,17,4,15,20]
arr.sort((a,b) => a-b)
console.log(arr)

Friday, 15 October 2021

Git cheat sheet

See branch

# see remote branch
git branch -r

# find remote branches which has release in name and sorted time desc
git branch -r --sort=-committerdate |grep release

Git rebase

# rebase 5 commit into one
git rebase -i HEAD~5

Patch file

git diff develop feature_br > test.diff
patch -p1 < test.diff

Show details of git server

git remote show origin

Show files changes in commits

git show --name-status

Push branch to remote origin and create a PR

git push -u origin feature/my-ticket
//the same as
git push --set-upstream origin feature/my-ticket

Create tag

//list tag by date
git log --tags --simplify-by-decoration --pretty="format:%ai %d"

//list tag by pattern
git tag -l "release-cron*"

//show tag details including tag message
git show release-cron-v2021v05.1

//create tag 2.0.1 in local
git tag -a 2.0.1 -m "create tag message"

//push tag
git push origin 2.0.1


//checkout tag
 git checkout tags/2.0.1 -b mytag_branch

Remote origin

// find remote origin
git config --get remote.origin.url

// set remote origin. In bitbucket, may need username in url such as 
git remote set-url origin [you repo URL>

git remote set-url origin https://lshen@git.testcompany.dev/scm/smp/looksearch.git

The below is a test to switch between ssh and https repo url. This repo has two url

ssh:  git@github.com:revenuewire/translation.git
https: https://github.com/revenuewire/translation.git
git clone  https://github.com/revenuewire/translation.git
//try find url. output: https://github.com/revenuewire/translation.git
git config --get remote.origin.url

//update url
git remote set-url origin  git@github.com:revenuewire/translation.git

//try find url again. output: git@github.com:revenuewire/translation.git
git config --get remote.origin.url

//see all config including origin
git config --list

Other commands

// see if in git repository. If in repository, get true.
//if not in, get "fatal: not a git repository (or any of the parent directories): .git"
git rev-parse --is-inside-work-tree
//create a code review in bitbucket
git push --set-upstream origin branch_name

You are in 'detached HEAD' state

Good explanation

Will get the detached HEAD state by checking out a commit directly

git checkout acb8a20
git status
HEAD detached at acb8a20
nothing to commit, working tree clean

To go back normal. Assume you are at master branch before

git checkout master

Want to stay here, make changes and keep changes

git branch new_branch_name
git checkout new_branch_name

If HEAD is synonymous with the last commit in the current branch, HEAD is attached to a branch.

Create a pull request in GitHub

//push the feature branch
 git push -u origin feature/JFR-3864
 
//Then shoud see something as
//remote: Create a pull request for 'feature/JFR-3864' on GitHub by visiting:
//remote: https://github.com/myconabsbsbsbs/bar/pull/new/feature/JFR-3864

Use the link to create a pull request. 
You can specify a reviewer when create pull request

Move repository from Bitbucket to GitHub

mkdir my_temp

cd my_temp

git clone --mirror https://git.mybitbucket.dev/scm/pay/my-api.git

cd my-api.git/

git remote set-url --push origin git@github.com:my/my-api.git

git push --mirror

Remove bigfile from Git repository

BFG Repo-Cleaner

git clone --mirror https://git.mybitbucket.dev/scm/pay/my-api.git

java -jar bfg.jar --strip-blobs-bigger-than 100M my-api.git

cd my-api.git

git reflog expire --expire=now --all && git gc --prune=now --aggressive

Show when a branch is created

git checkout your_branch_name
git show --summary

Ruby cheat sheet

Range

Ruby range includes the last index.

str = "helloworld"
#print "hel"
puts str[0..2]

#print 0, 1, 2
(0..2).each do |i|
    puts i
end

# range with step (here get 0, 3, 6)
(0..8).step(3) do |i|
    puts i
end

String


1. find index of char in a string
i = email.index('@')

2. substring
# the first 3 chars
e1 = email[0..2]

# get the last char in string
lastC = email[-1]

# get single char by index. The following will return "b"
s = "ab"
puts s[1]

3. string length
l = email.length

4. split string by space to array
w = "hello world"

# split will remove leadin and trailing spaces. Also it will split by multiple spaces
#return ["hello", "world"]
arr = w.split

5. string to int; int to string
"5".to_i
5.to_s

6. concatenation 
# print "ab"
puts "a" + "b"

7. loop through
"abc".each_char do |c|
puts c
end

8. convert number to different base
255.to_s(36) #=> "73"
255.to_s(16) #=> "ff"
255.to_s(2)  #=> "11111111"

9. array of 26 letters
arr = "abcdefghijklmnopqrstuvwxyz".chars()
# find char from begin or from end. return 0 and 3 respectively
"abca".index('a')
"abca".rindex("a")

10. use range
arr = ('a'..'z').to_a
arr.index('b')

11. string to array
column_title = "ABC"
arr = column_title.chars

12. char to Ascii value. get 97
"a".ord

13. get assii values for chars in string (97, 98)
"ab".each_byte do |c|
    puts c
end

Array

# pre define array with 10 elements of empty string
arr = Array.new(10, "")

# join array into string
# will return "Hello world"
str = ["Hello", "world"].join(" ")

# shift will remove the first element
arr.shift

#unshift will add element in the begin
arr.unshift("hi")

# reverse array
arr = arr.reverse()

# sort array in house
arr = [4,2,6,1,9]
arr.sort!

# to access last element of arr
arr[-1]

# sort array without change original array
arr2 = arr.sort()

# drop. drop the first n element and return result
arr = [1,2,3,4,5]

# result will be [3,4,5]
result = arr.drop(2)

# check if array has value
n=3
if (arr.include?n)

# delete element by value
n =3
nums2.delete_at(nums2.find_index(n))

#loop through array using each_with_index
nums = [1,2,3,4]
nums.each_with_index do |val, index|
    puts val
    puts index
end

#loop through array using each
nums.each {|val| puts val }

nums.each do |val|
    puts val
end

#loop through array using for .. in
for val in nums
    puts val
end

for i in (0..nums.length-1)
    puts nums[i]
end

# loop through array reverse with index
(0..n-1).reverse_each do |i|
...
end

# access last element
arr[-1]

# add last and remove from last
arr = []
arr.apend(1)
arr.pop()

#find index. return 1
arr = "abcdefghijklmnopqrstuvwxyz".chars()
    puts arr.index('b')

# conconcat array to string
arr.join("")

#remove the first element. e is 1 and arr becomes [2, 3, 4]
arr = [1,2, 3,4]
e = arr.shift

Hash


#create hash
hash1 = {}

#initiate hash with default data. Not set default value to be array
# Otherwise, they are pointing to the same array
hash2 = Hash.new(1)

#assigin value
hash1['a'] = 10

# access hash
count = hash1['a']

# get default value. should print out 1 because we set default to be 1
puts hash2['b']

# check if key exist in hash. should get false
puts hash2.key?('b')

# loop through hash
hash1.each do |key, val|
        puts key
        puts val
end

# get hash length
puts hash.length()

# empty a hash
hash.clear()

Set


# create a new set
s = Set.new()

# add element to set. also can do: s.add(1)
s<<1

# get length
s.length

Queue

queue = Queue.new
# add element
queue.push(node)
# remove element
node = queue.pop
# size
size = queue.length

Math

# return 9
(17.to_f/2).round

#return 8
17/2

# find min or max
[a, b].max
[a, b].min

# do math pow
26**3

# convert number to any base. Return string
s = n.to_s(b)

Class

Can add an method to a object directly

obj = Object.new

def obj.event
  "small event"
end

puts obj.event

Can overriding method in the same class

class Ticket
  def event
    "can not really specify yet..."
  end
  def event
    "wht define me again"
  end
end

ticket = Ticket.new
puts ticket.event

Reopen a class to add more methods

class Ticket
  def event
    "can not really specify yet..."
  end
end

class Ticket
  def price
    puts "100 yuan"
  end
end

ticket = Ticket.new
puts ticket.event
ticket.price

equal sign(=) method name

class Ticket
  def price=(price)
    @price = price
  end
 
  def price
    @price
  end
end

ticket = Ticket.new
ticket.price=(10)
puts ticket.price

Modules


#load a file that is relative to the file containing the require_relative statement.
require_relative "stacklike"
class Stack
	# module name
	include Stacklike
end

More..

#skip a loop. ruby version continue
next if ansM.key?(re)

Thursday, 14 October 2021

Docker

run docker image

docker image ls
REPOSITORY      TAG            IMAGE ID       CREATED          SIZE
java            8-jdk-alpine   3fd9dd82815c   4 years ago      145MB

//start a container using image
docker run -i -t 3fd9dd82815c /bin/sh

//find if www-data group exists in alpine:3.14
docker run --rm -it alpine:3.14 cat /etc/group | grep www-data

//find php version of this linux box
docker run --rm -it docker-php7-alpine:1.3.3 php -v

//link another container
docker run --link docker_mysql_1:sql-master.local.buzz.io

//add entry in host file of docker container
docker run --add-host sql-master.sandbox.buzz.io:250.48.4.218


about -p (or --publish) flag

docker run -p [host port]:[container port]

The -p flag in docker run is used to publish a container's port(s) to the host. It allows external access to the container's network ports. For example, if a container is running a web server on port 80 and you want to access it from your host machine on port 8080, you would use the command docker run -p 8080:80 [image name]. This would map port 80 of the container to port 8080 on the host machine.

delete all stopped container

docker container prune

Start a stopped container

//tweb is container name
docker container start tweb

delete docker image

 docker image rm b9032ca8381a

That number is image id. get by run docker image ls

go into docker container

docker exec -it container_name bash | ash 

-i -t flag: "interactively" type commands to the pseudo-tty/terminal created by the -t switch.

Some times need to replace /bin/sh with /bin/bash depending on which program container has

see volumes

docker volume ls
//see docker volumes a contained mounted
docker inspect -f '{{ .Mounts }}' container_id

//sample output
[{bind  /home/leo2019/jenkins_home /var/jenkins_home   true rprivate}]
//$PWD is a built in env variable. It is current directory
volumes:
    - $PWD:/var/src:delegated

see log

docker logs container_name

build image

//build image called web:latest. do not forget dot
//it tells docker to use current directory as build context
docker image build -t web:latest .

//--no-cache will not use cached layers
docker-compose build  --no-cache web

see image layer

docker image inspect my_image_name

//the above will show image maintanter. Therefore, by changing
//maintanter and inspect image
//we can be sure it is using the new docker file

push image to docker hub

Assume there is a image in local called web:latest. Want to push to leo_image in docker hub

//re-tag
docker image tag web:latest leo_image/web:latest

//docker login
docker login

//push to docker hub
docker image push leo_image/web:latest

Docker copy

It is very useful. One use case is that we can pre-built some binary instead of building it directly when build image. Then copy the binary to the right destination.

COPY extra_php_extension/grpc.so /usr/lib/php7/modules/.
COPY extra_php_extension/protobuf.so /usr/lib/php7/modules/.

//from alpine base image. The following will build grpc.so and protobuf.so and it will
//take 20 minutes. Instead we can build once and grab grpc.so and protobuf.so. Then use
//copy command to do the copy. It will save lots of build time.
RUN apk --update add php-pear php7-dev g++ make linux-headers php-phar

RUN apk add --no-cache --virtual .phpize-deps $PHPIZE_DEPS \
       && pecl install grpc \
       && pecl install protobuf \
       && apk del .phpize-deps

Trouble shooting

build always failed. After change Dockerfile to dockerfile, it works. what?

docker-compose build web get error: [output clipped, log limit 1MiB reached]

To solve:

COMPOSE_DOCKER_CLI_BUILD=0 DOCKER_BUILDKIT=0 docker-compose build web 

COMPOSE_DOCKER_CLI_BUILD

Configure whether to use the Compose python client for building images or the native docker cli. By default, Compose uses the docker CLI to perform builds, which allows you to use BuildKit to perform builds. Set COMPOSE_DOCKER_CLI_BUILD=0 to disable native builds, and to use the built-in python client.

docker network

My Post for Docker Network

Copy File from container in EC2 to local machine

//go to EC2 which host the container
ssh -i NOC.pem ec2-user@10.123.6.123

//copy file from container to EC2
docker cp ecs-sandbox-container-c8bdbc01:/var/src/composer.lock /tmp/.

//copy file to local
scp -i NOC.pem ec2-user@10.123.6.123:/tmp/composer.lock .

docker info

Also can see how much data space we have. If data space is too low, some tasks can not be done.

docker info
Client:
 Context:    desktop-linux
 Debug Mode: false
 Plugins:
  buildx: Docker Buildx (Docker Inc.)
    Version:  v0.10.4
    Path:     /Users/leo/.docker/cli-plugins/docker-buildx
  compose: Docker Compose (Docker Inc.)
    Version:  v2.17.3
    Path:     /Users/leo/.docker/cli-plugins/docker-compose
  dev: Docker Dev Environments (Docker Inc.)
    Version:  v0.1.0
    Path:     /Users/leo/.docker/cli-plugins/docker-dev
  extension: Manages Docker extensions (Docker Inc.)
    Version:  v0.2.19
    Path:     /Users/leo/.docker/cli-plugins/docker-extension
....

To free up data space, can delete some unused docker image in the machine.

MySQL container can not start because of no space left on device

One time, I can not start mysql db container because it complained that there was not enough spaces. We can free up spaces by deleted orphaned volumes. Also delete images with <none> to free up spaces. Also consider clear redis cache use flush command below. You may need to restart Docker desktop

//Error
Error response from daemon: mkdir /var/lib/docker/overlay2/d49a2835b41459956e752ceddaaf0671b4e9386fc220e8b9d4697a46ad29a635-init: no space left on device
# see orphaned volumes. These volumes are not 
# referenced by any containers.
docker volume ls -qf dangling=true

#to remove
docker volume rm $(docker volume ls -qf dangling=true)

Can not start redis container

Container started, but exited right away. Before it always worked. But all of sudden, it did not work any more.

root cause is that image is updated. Because we use redis:latest, some how machine downloaded a new version of image and this image does not work for alpine linux. The old image works for alpine linux.

To solve it, we use redis:7-alpine and it works on Alpine linux.

Lesson learned: try not use image with latest tag. If use latest image and suddenly it stops working, it may because of image itself.

Clear a redis cache in Docker

docker exec -it container-name redis-cli FLUSHALL

port is used when start MYSQL container

Error response from daemon: Ports are not available: exposing port TCP 0.0.0.0:3306 -> 0.0.0.0:0: listen tcp 0.0.0.0:3306: bind: address already in use

Soulution

//in mac:  sudo launchctl unload -F /Library/LaunchDaemons/com.oracle.oss.mysql.mysqld.plist 

Download file from AWS Fargate container to local machine

aws ecs execute-command --region us-west-1 --cluster sandbox-ecs-mickdkkdroserv --task  e7b0edkdkdk4ace95052a678b896845    --container sandbox-msdbbdcontanern-1 --command "cat /var/src/utils/test.csv"  --interactive >> ~/leotest.csv

Local MySQL container can not run because of switching between mysl5.7 and mysql8.0 image

  • #stop container
      docker-compose down
  • #find mysql volume
      docker volume ls -qf dangling=true
  • #delete mysql volume. Be careful, all database will be removed.
     #Only do it for local db!!
      docker volume rm docker_mysql
  • #restart container
      docker-compose up -d

Copy file from docker container to host machine

docker cp optimistic_mirzakhani:/var/src/phpunit.xml  ~/Desktop/.

Docker run explained

Usage	docker container run [OPTIONS] IMAGE [COMMAND] [ARG...]
//this command is used in Jenkin. Here pwd means to get the current directory
docker run --rm -v `pwd`:/var/src/ -w /var/src php:8.0.26-cli-alpine3.16  vendor/bin/browscap-php browscap:fetch

flag --rm Automatically remove the container and its associated anonymous volumes when it exits

flag -v Bind mount a volume

-w Working directory inside the container

use image php:8.0.26-cli-alpine3.16 to create a container. Mount volume `pwd`:/var/src/. Working directory is /var/src. run commnand: vendor/bin/browscap-php browscap:fetch. After it is done, automatically remove the container and its associated anonymous volumes when it exits

Can not docker-compose up any container in my mac

Look like it is still because of spaces. The build cache is more than 20 GB

# can see build cache is more than 20 GB
docker system df

#clear builder cache
docker builder prune

After delete builder cache, restart Docker Destop. Everything goes normal!

entrypoint in docker-compose.yml

In a docker-compose.yml file, the entrypoint directive specifies the command that will be executed when a container starts. It overrides the default ENTRYPOINT defined in the Docker image's Dockerfile.

version: '3'
services:
    mysite:
        container_name: webpack-cart
        image: node:16.6.1-alpine3.13
        ports:
            - 8092:8092
        hostname: webpack.mysite.com
        volumes:
            - $PWD:/app:delegated
        working_dir: /app
        entrypoint: ['npm', 'run', 'build']
        stdin_open: true
        tty: true
        network_mode: bridge

The command below wll be executed when the container starts

npm run build

This command build is defined in package.json scripts section

 "scripts": {
    "build": "./node_modules/.bin/webpack serve --config webpack.development.config.js --mode development --env APP_VERSION=dev-server --env APPLICATION_ENV=local",
  },

Tuesday, 12 October 2021

Java integer overflow and binary search

The below is two solutions for Leet code 374

Solution one

public class Solution extends GuessGame {
    public int guessNumber(int n) {
        int high = n;
        int low = 1;
        
        while (low<=high) {
            int mid = (low+high)/2;
            
            if (guess(mid) == 0) {
                return mid;
            }
            
            if (guess(mid) >0) {
                low = mid +1;
            } else {
                high = mid -1;
            }
        
        }
       
        return 0;
            
    }
}

Solution two

public class Solution extends GuessGame {
    public int guessNumber(int n) {
        int high = n;
        int low = 1;
        
        while (low<=high) {
            int mid = low + (high-low)/2;
            
            if (guess(mid) == 0) {
                return mid;
            }
            
            if (guess(mid) >0) {
                low = mid +1;
            } else {
                high = mid -1;
            }
        
        }
       
        return 0;
            
    }
}

These two solutions are almost identical. However, the first solution will not pass all tests. So, what is going on? The only difference is how to calculate mid value.


//solution one
int mid = (low+high)/2;

//solution two
int mid = low + (high-low)/2;

For solution one, it will cause integer overflow for large inputs.

Sunday, 10 October 2021

JavaScript bind() method

  • we invoke the bind() on a functon
  • the argument passed into bind() is an object
  • it will return a new function. This new function becomes method of that object
class NameForm extends React.Component {
  constructor(props) {
    super(props);
    this.handleSubmit = this.handleSubmit.bind(this);
    this.input = React.createRef();
  }
  
   handleSubmit(event) {
    alert('A name was submitted: ' + this.input.current.value);
    event.preventDefault();
  }
  
 .....

 

For the above code, we need bind this. Because when we set this.handleSumit as callback of event handler, this inside that function is lost

onSubmit={this.handleSubmit}

However, we also can use arrow function for event handler. arrow function binds this lexically, so this will point to NameForm

onSubmit={()=>this.handleSubmit()}

For Promise then callback, we also need to write it as arrow function to access this of class instance.

A blog about why we need bind this

Friday, 1 October 2021

Docker networking

Docker and iptables

Docker installs two custom iptables chains named DOCKER-USER and DOCKER, and it ensures that incoming packets are always checked by these two chains first.

Use bridge networks

  • bridge is the default network driver if does not specify other driver
  • a bridge netwok allows containers connected to the same bridge network to commuicate with each other
  • bridge networks only apply to containers running on the same Docker daemon host
  • when start Docker, a default bridge network (also called bridge) is created automatically
  • newly-started containers connect to the default network unless otherwise specified

connect from a container to a service on the host

In Docker Desktop for Mac, host.docker.internal is the special DNS name which resolves to the internal IP used by host.

Therefore, if want to connect to host, use DNS name host.docker.internal if you are using docker desktop for mac.

ports mapping

In Docker file, we can expose container on some port by

EXPOSE 8080

To map to a host port, we can do the below. We assume tomcat container has exposed on port 8080

 //-p is short cut for --publish (host port to container port)
docker run -d --name tweb -p 8090:8080 tomcat
//can check port map. tweb is container name
docker port tweb

Then we can access tomcat at: http://localhost:8090

Tuesday, 28 September 2021

AWS

AWS CloudFormation intrinsic functions

The abbreviation of the intrinsic functions

Fn::Sub is identical to !Sub

Fn::!GetAtt returns the value of an attribute from a resource


Value: !GetAtt 'VM.PublicDnsName' # get VM's Public dns name attribute

Ref returns the value of the specified parameter or resource


VpcId: !Ref VPC

Fn::Sub like string concatenation


TableName: !Sub "${EnvironmentType}-user" # EnvironmentType is a parameter created elsewhere in the CloudFormation template.

Limitation

Lambda

Per region

  • Memory 128M to 10 GB (1MB increments)
  • Max execution time 15 minutes
  • Max size of environment variables 4 KB
  • /tmp 512 MB
  • Max currency 1000
  • Max zip file 50 MB
  • Uncompression file 250 MB

DynamoDB

  • Maximum size of an item is 400 KB

API Gateway

  • Default cache TTL is 300 seconds. Max is 3600 seconds

Saturday, 25 September 2021

Install rails 6.0 in Ubuntu 18

Step 1: remove ruby 2.5 because rails 6 needs ruby 2.6 and up


aptitude purge ruby

Step 2: install ruby

sudo snap install ruby --classic

Step 3: create a symbolic link in /usr/bin

sudo ln -s /snap/bin/ruby /usr/bin/ruby 

Step 4: install rails

sudo gem install rails -v 6.0.2.1 

Step 5: create a symbolic link for rails

sudo ln -s /home/leo2019/.gem/bin/rails /usr/bin/rails 

Step 6: verify

rails -v 

output: Rails 6.0.2.1

Monday, 20 September 2021

npm install and npx

npm install

If it is a new project and does not have package.json, do

npm init

module will be added as dependencies in package.json

npm install express --save 

module will be added as devDependencies in package.json

npm install mocha --save-dev

module will not be added to dependencies list and install it temporarily

npm install express --no-save

If we want to install modules listed in package.json and respect package-lock.json

npm ci 

npx

npx is package runner tool that comes with npm 5.2

  • If module is installed, npx can run command in the bin directory of the module
  • If module is not installed, when you run npx , the module will be installed and then be cleaned

Some examples


npx happy-birthday -u leo
npx create-react-app my-app

For the above examples, we are running happy-birthday and create-react-app runner tools. npx has other functionalities. For details, see Kat Marchán blog for npx

npm upgrade package

install tools to check package

npm install -g npm-check-updates

To check

npx ncu

To fix patches

npx ncu -u -t patch

To fix minor version

npx ncu -u -t minor

To fix main version

npx ncu -u -f react-datepicker 

All these fix command will only change package.json. To instll, run:

 npm install

Small syntax difference ends up different result

Java ArrayList remove function

Assume we have a Integer array list arr


    arr.add(20);
    arr.add(30);
    arr.add(1);
    arr.add(10);
    
    arr.remove(new Integer(1));

    //will return [20, 30, 10]
    System.out.println(arr);
	

    arr.add(20);
    arr.add(30);
    arr.add(1);
    arr.add(10);
    
    arr.remove(1);

    //will return [20, 1, 10]
    System.out.println(arr);
	

In the first case, we are calling remove function from public interface java.util.Collection

public boolean remove(E element)

In the second case, we are calling remove function from public interface java.util.List

public Object remove(int index)

Ruby sort


arr = [3,4,1,0]
arr.sort!
# return [0,1,3,4]
puts arr

arr = [3,4,1,0]
newArr = arr.sort
# return [3,4,1,0]
puts arr

The first case is in house sort. (use sort!). The second case will not change the original list, but return a sorted new list. The only difference is !

Wednesday, 15 September 2021

Amazon DynamoDB

Amazon DynamoDB Indexes

Primary Key

There are two kinds of primary key:

1. Partition key (aslo called hash attribute) only

2. Partition key and sort key. This kind of primary key is also called composite primary key.

The name of partition key comes from the fact that items have the key is mapping to a physical address in storage. For example, in composite primary key case, items which have the same partition key and different sort key are stored together with sorted order by sort key.

Secondary Indexes

1. Global secondary index. Can be created on items which have different partition key. Basically, can use this index to search whole table.

2. Local secondary index. Items need to have the same partition key and different sort key. Most time, this index is useless.

Secondary Index is also a table. You also need to specify primary key(partition key only or composite primary key). Also need to specify projected attributes from the base table. The primary key of the base table will be projected automatically.

Noted: In a DynamoDB table, each key value must be unique. However, the key values in a global secondary index do not need to be unique.

Using Global Secondary Indexes in DynamoDB

Amazon Dynamodb Schema

For attributes used in primary key and indexes, you need to define these attributes. However, you can only define these attributes. In fact, if you define other attributes and try to create a table, you will get error that said attributes do not match. This is because Dynamodb is a schemaless database and you can save attributes you do not define.

This is a good explanation about DynamoDB query how to query DynamoDB

Create Dynamodb table in AWS

One option is to create a cloudformation template for this table. Then deploy template


aws cloudformation deploy --template /path_to_template/my-template.json --stack-name my-new-stack --parameter-overrides Key1=Value1 Key2=Value2 

PHP code snippet to query DynamoDB

//define expression attribute names and expression attribute values. It is a key/value map
//in PHP, we use associate array as a map
//For expression attribute names, need to start with pound sign(#)
//For expression attribute values, need to start with colon(:). Also need to define type.
//Here use marshalValue to add a type. e.g {":agelimit": {"N": 21} }
$attributeNames["#typeAndStatus"] = "typeAndStatus";
$attributeValues[":typeAndStatus"] = self::$marshaller->marshalValue($typeAndStatus);
$attributeValues[":now"] = self::$marshaller->marshalValue(time());

//pass the above expression attribute names and expression attributes values in query
$queryAttributes['ExpressionAttributeNames'] = $attributeNames;
$queryAttributes['ExpressionAttributeValues'] = $attributeValues;

//Therefore, for KeyConditionExpression, we can use expression attribute names and expression attribute values
$queryAttributes['KeyConditionExpression'] = "#typeAndStatus = :typeAndStatus and nextRunTime < :now"

//query the Dynamodb client
$result = self::$client->query($queryAttributes);

DynamoDB

You can set up a DynamoDB local using Dockfile provided by AWS. After set up, you can admin db

Calculation of WCU and RCU

It is speed of size

  • One WCU is 1 KB per second. RCU is 4 KB per second. Also RCU counts on strongly consistent read
  • Item size will be round up
  • For RCU: one strongly consistent read. (== 2 eventaully consistent read)

Global Table

  • Active to Active replication between multiple region
  • Can take up to 2 seconds to do replication
  • aws:rep:updateregion contains the region in which the update was made

See ReplicationLatency Metrics

  • Go to Cloudwatch Service
  • click all metrics tab
  • Choose DynamoDB
  • Choose ReceivingRegion, TableName
  • Find Table and check replicationLatency
  • It will show up in the above chart