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"

//show annotated tags with their message
git tag -n

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

Create a PR for develop to master in github console

  1. go to github repository
  2. click pull request
  3. click new pull request button
  4. choose base: master, compare:develop
  5. create "Create pull request"
  6. title Rcv1.2.0

Create a release branch which source from master on github console

  1. go to github repository
  2. go to branch selector and click View all brances
  3. create New Branch button
  4. give Branch name: release/v1.3.0 and Branch source: master

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

The root cause is that both volume names are the same. After use docker_mysql for Mysql 5 and use mysql84 from Mysql 8 container, I can switch between two containers.

  • #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/ (map current directory to /var/src inside container) Working directory is /var/src inside container. Then run commnand: vendor/bin/browscap-php browscap:fetch. After it is done, automatically remove the container and its associated anonymous volumes when it exits

docker run --rm -v `pwd`:/var/src/ -w /var/src/ php:8.3-cli-alpine  php ./bin/yamlToJson.php
  1. use image php:8.3-cli-alpine to create a container
  2. mount current directory to /var/src of the container
  3. inside container, use /var/src as work directory and run this command
    php ./bin/yamlToJson.php

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

Tuesday, 14 September 2021

Python cheat sheet

String


# loop through
for c in "abc":
	print(c)

# string replace with return the end result. It does not change original result
date = datePart.replace("th", "")

# string split to list. X will be [welcome, to, jungle]
txt = "welcome to jungle"
x = txt.split()

# substring. will print 20
datePart = "20th"
print(datePart[0:2])

#substring to the end. will print 0th
datePart = "20th"
print(datePart[1:])

# generate an array for all lower case letters (a...z)
letters = list(string.ascii_lowercase)

#convert a decimal integer to binary string. get "111"
s1 = bin(7).replace("0b", "")

#zero left fill. The length is the length of the result string
s= "123"
# get "00123"
s=s.zfill(5)

#The count() method returns the number of times a specified value appears in the string.
print ("foobar".count("o")) # print 2

# get a char's ascii value. 'a' is 97. For code below, will return 98
print(ord('b'))

#ascii value to char. here print 'a'
print(chr(97))

#find and rfind. return 0 and 4
"abcda".find("a")
"abcda".rfind("a")

# str to int. get 9 for the code below
int("09")

hash


#create hash
hash1 = {}

#initiate hash with default data. use get to set a default value. will print out 0
print (hash1.get('a', 0))

#assigin value
hash1['a'] = 10

# access hash. print out 10
count = hash1['a']
print(count)

# check if key exist in hash. should get false
if 'c' not in hash1:
    print ("not have")
        
# loop through
for k in hash1:
    print(hash1[k])

# clear or empty a hash
hash1.clear()

# get hash keys
hash1.keys()

#decouple with hash
keys = list(pointHash.keys())

array

# append. arr becomes 1,2,4
arr = [1,2]
arr.append(4)

# create two dimension array
		dp = []
        for i in range(n):
            dp.append([10000]*n)

# find index of a element
nums = [2,3,49,1]

try:
	i = nums.index(49)
except ValueError:
	pass
#length
print(len(nums))

# join array into string
" ".join(nums)

# sort. This is in house sort
nums.sort()

# sort two dimention array by x[0], then x[1]
intervals.sort(key=lambda x:[x[0], x[1]])

# sort by x[0]
stockPrices.sort(key=lambda x:x[0])

# reverse in house sort
inventory.sort(reverse=True)

# pop at index
nums.pop(0)

# remove from the begin
nums.pop(0)

# remove from the end
nums.pop()

#initial array with 0
ans = [0] * 100

# initiate array with 0 (another way). The below will get [0,0,0,0,0]
arr=[]
arr = [0 for i in range(5)]

#reverse range
reversed(range(100))

#initialize two dimension array
dp = [[0 for x in range(m)] for y in range(m)] 

# list comprehension
 starts = [a for a, b in flowers]
 ends = [b for a, b in flowers]

Set

# create a empty set
s = set()

# add an element to set
s.add(1)

# check length of set
print(len(s))

# check contains
if 2 in s:

Binary search built in functions

bisect.bisect_left(a, x, lo=0, hi=len(a)) : Returns leftmost insertion
point of x in a sorted list. Last two parameters are optional, 
they are used to search in sublist.

bisect.bisect_right(a, x, lo=0, hi=len(a)) Returns rightmost insertion 
point of x in a sorted list a. Last two parameters are optional,
they are used to search in sublist.

index = bisect_right(arr, val)

Permutation

for p in permutations([1,2,3], 3): 
	print (p)
#output
(1, 2, 3)
(1, 3, 2)
(2, 1, 3)
(2, 3, 1)
(3, 1, 2)
(3, 2, 1)

Rest API

Send a post

import requests
import json

url = 'http://localhost:5000'
myobj = {'somekey': 'somevalue'}
headers = {'content-type':'application/json'}

x = requests.post(url, data =json.dumps( myobj), headers=headers)

print(x.text)

Math

#integer div.It will return 4
9//2

# find gcd of two integers
gcd = math.gcd(d, price)

# val is 8
val = max(3, 8)

#power. mod is optional. But if need mod, use it. It is 
#much faster than ans=pow(x,y) ans = ans%mod
pow(x, y, mod)
ans = ans + pow(2, r-i, 1000000007)

Inner Function


def countDaysTogether(self, arriveAlice: str, leaveAlice: str, arriveBob: str, leaveBob: str) -> int:
    months = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
    def getDayOfYear(dayStr:str)->int:
        arrMonth = int(dayStr[0:2])
        arrDay = int(dayStr[3:5])

Hard questions

1799. Maximize Score After N Operations

class Solution:
    myMap = {}
    def maxScore(self, nums: List[int]) -> int:
        def getM(k, nums):
            # build cache key
            cacheK = ' '.join(str(x) for x in nums)+ "k:" + str(k)
            if cacheK in self.myMap:
                return self.myMap[cacheK]

            if len(nums)==2:
                ans = k*math.gcd(nums[0], nums[1])
                self.myMap[cacheK] = ans
                return ans
            
            ans =0
            l = len(nums)
            for i in range(l-1):
                for j in range(i+1, l):
                    n1 = k*math.gcd(nums[i], nums[j])
                    left = []
                    for h in range(l):
                        if h!=i and h!=j:
                            left.append(nums[h])
                    n2 = getM(k+1, left)

                    if (n1+n2) > ans:
                        ans = n1 + n2
            self.myMap[cacheK] = ans
            return ans

        nums.sort()
        return getM(1, nums)

heap

#Leetcode 2542
class Solution:
    def maxScore(self, nums1: List[int], nums2: List[int], k: int) -> int:
        l = len(nums1)
        nums = []
        for i in range(l):
            nums.append([nums1[i], nums2[i]])
        
        #sort by the second element
        nums.sort(key=lambda x:x[1])
        nums.reverse()

        ans, curSum = 0, 0

        myHeap = []
        for i in range(k):
            curSum += nums[i][0]
            heapq.heappush(myHeap, nums[i][0])
        ans = curSum * nums[k-1][1]

        for i in range(k, l):
            out = heapq.heappop(myHeap)
            curSum = curSum-out + nums[i][0]
            heapq.heappush(myHeap, nums[i][0])
            ans = max(ans, curSum * nums[i][1])

        return ans
#Leetcode 1464
import heapq
class Solution:
    def maxProduct(self, nums: List[int]) -> int:
        for i in range(len(nums)):
            nums[i] = nums[i]*-1
        
        heapq.heapify(nums)
        # return smallest
        a = heapq.heappop(nums)
        b = heapq.heappop(nums)
       
        return (a*-1 -1) * (b*-1-1)

Run codes

#Leetcode 1992
from typing import List
class Solution:
    def findFarmland(self, land: List[List[int]]) -> List[List[int]]:
        def getFarm(f: List[int], a:int, b:int):
            
            if a<f[0] or b<f[1]:
                f[0]=a
                f[1]=b
            if a>f[2] or b>f[3]:
                f[2] = a
                f[3] = b
            return f
            
        rows = len(land)
        cols = len(land[0])

        ones = []

        # find all ones
        for i in range(rows):
            for j in range(cols):
                if land[i][j] == 1:
                    ones.append([i, j])
        
        #put ans
        ans = []
        for one in ones:
            #some one has been grouped
            if land[one[0]][one[1]] != 1:
                continue
            
            # one itself is a farmland
            x, y = one[0], one[1]
            queue = [[x,y]]
            myLand = [x, y, x, y]

            while len(queue)>0:
                size = len(queue)
                for i in range(size):
                    point = queue.pop(0)
                    a, b = point[0], point[1]

                    #left
                    if b!=0 and land[a][b-1] == 1:
                        myLand = getFarm(myLand, a, b-1)
                        land[a][b-1] = 0
                        queue.append([a, b-1])

                    #right
                    if b!=cols-1 and land[a][b+1] == 1:
                        myLand = getFarm(myLand, a, b+1)
                        land[a][b+1] = 0
                        queue.append([a, b+1])

                    #up
                    if a!=0 and land[a-1][b]==1:
                        myLand = getFarm(myLand, a-1, b)
                        land[a-1][b] = 0
                        queue.append([a-1, b])

                    #down
                    if a!=rows-1 and land[a+1][b]==1:
                        myLand = getFarm(myLand, a+1, b)
                        land[a+1][b] = 0
                        queue.append([a+1, b])
            ans.append(myLand)
        
        return ans
        
obj = Solution()
land = [[1,0,0],[0,1,1],[0,1,1]]
res = obj.findFarmland(land)
print(res)

django

commands

django-admin startproject project-name

python manage.py startapp app-name

python manage.py runserver

# open a shell to run some db query
python manage.py shell

Handle Form

# get post data
post_id = request.POST.get("post_id")

Use env variables

# create .env file in the project directory
api_key=mysecfretetemmsmsm

# in settings.py
from dotenv import load_dotenv
load_dotenv()

# to access env variable
import os
os.getenv("api_key")

var dump

from pprint import pprint
pprint(request.POST)

Versions

#find version
python -V
pip -V
python3.7 -m pip list

#show version used to store library
pip show openai

Install Python OpenAi Module

python3.7 -m pip install --upgrade pip
python3.7 -m pip install openai

Sunday, 12 September 2021

Modules in Node.js

Node.js uses CommonJS module format. It uses require to include a module. It uses module.exports to expose a modules. The npm ecosystem also uses this format.

Use require to include a module. The below we include express module.


const express = require('express')
const app = express()

app.get('/', (req, res) => {
  res.send('Hello World!')
})

const port = 2000
app.listen(port, () => {
  console.log(`listen to port 2000...`)
})

Use exports to let other codes to use this module. For example, AWS Lambda function can be written in Node.js

exports.myFunction = (event, context, callback) => {
        //do something
}

The below is a hello world module and how to use it

//in hello-world.js create a module
module.exports = name => console.log("hello to " + name)

//in main.js
var hw = require('./hello-world')
hw("kei")

//run it
node main.js //output: hello to kei
//another example
//in config.js
module.exports = {
  dbPort : 8080,
  dbHost : "etc",
  dbName : "nom",
}

//in main.js
var config = require("./config")
console.log("config:", config);
//more example
//in config
module.exports = {
  dbPort : 8080,
  dbHost : "etc",
  dbName : "nom",
  hello: (name)=> "hello to " + name
}

//in main
var leo = require("./config")

console.log(leo)

console.log(leo.hello("smith"))

//output node main.js
{
  dbPort: 8080,
  dbHost: 'etc',
  dbName: 'nom',
  hello: [Function: hello]
}
hello to smith

However, for ES6, it uses another format. It uses export and import to export and include a module. Here is post about default values in ES6 module

Monday, 6 September 2021

Java Queue

Both PriorityQueue and LinkedList implement Java Queue interface.

There are these methods. Every is a pair. The first one will throw error on failure. The second will return special value instead of throwing error.

  • add(e) offer(e)
  • remove() poll()
  • element() peek()

For LinkedList, we can call removeFirst()

Java PriorityQueue

java PriorityQueue implements java.util.AbstractQueue class which extends java.util.Collection

The head of the queue is the least element with respect to the specified ordering. However, can provide Collections.reverseOrder() in the constructor to create a max heap.

useful methods:

  • peek()
  • poll()

methods from java.util.Collection

  • size()
  • add()
  • isEmpty()

Here is a Leetcode problem leetcode 1046 which can be solved by max heap


import java.util.*;
class Solution {
    public int lastStoneWeight(int[] stones) {
        //create a max heap. The head has the max value
        var q = new PriorityQueue<Integer>(Collections.reverseOrder());

        //add element into heap
        for (int s: stones) {
            q.add(s);
        }

        while(q.size()>1) {
            int x = q.poll();
            int y = q.poll();

            if (x != y) {
            	//put result stone back into queue
                q.add(Math.abs(x-y));
            }
		}

        //check q.size
        if (q.size()==1) {
            return q.poll();
        } else {
            return 0;
        }
    }
}

Tree Level Traversal

The below is a solution for LeetCode 104

public int maxDepth(TreeNode root) {
        if (root ==null) return 0;
        
        var myq = new LinkedList<TreeNode>();
        myq.add(root);
        var ans = 0;
        
        while(!myq.isEmpty()) {
            //queue only holde nodes of current level
            var size = myq.size();
            
            //every iteration is one level because of size
            for(int i=0; i<size; i++) {
                TreeNode cur = myq.poll();
                if (cur.left!=null) myq.add(cur.left);
                if (cur.right!=null) myq.add(cur.right);
             }
            
            ans++;
        }
        
        return ans;
        
    }

Use Paire as queue element

2462

Priority Queue using custom comparator

Leetcode 2099

class Solution {

  public int[] maxSubsequence(int[] nums, int k) {
    var pq = new PriorityQueue<int[]>((a, b) -> a[1] - b[1]);

    for (int i = 0; i < nums.length; i++) {
      int[] t = { i, nums[i] };
      if (pq.size() < k) {
        pq.add(t);
      } else {
        var e = pq.peek();
        if (e[1] < nums[i]) {
          pq.poll();
          pq.add(t);
        }
      }
    }

    int[] index = new int[k];
    int j = 0;
    while (pq.size() > 0) {
      var e = pq.poll();

      index[j] = e[0];
      j++;
    }

    Arrays.sort(index);

    int[] ans = new int[k];
    j = 0;
    for (int i : index) {
      ans[j] = nums[i];
      j++;
    }

    return ans;
  }
}

array as queue element

//See Leetcode 373
PriorityQueue<int[]> minHeap = new PriorityQueue<> ((a, b) -> (a[0] + a[1]) - (b[0] + b[1]));
       
//init. the last two elements are index for two array
minHeap.add(new int[]{nums1[0], nums2[0], 0 ,0});

How to inject codes into blogger

Basically you need to add highlight.js into your blogger template. Then wrapper your code. See highlight.js usage

Here is a good tutorial about that: https://www.youtube.com/watch?v=APNWCe56cQA

Create REST API by AWS API Gateway and AWS Lambda

 We can create a REST API using AWS API Gateway and AWS Lambda by Proxy integration.

For Proxy integration, when API Gateway receives the request, it sends proxy resources such as path information and request body to Lambda function. Lambda function generates a responses based on information sent by API gateway. This response is sent back to API Gateway which send this response back to API user. In Lambda function, you can call other aws services such as store data in s3 bucket and send message to sqs before send back the response.

Step 1: Create a AWS Lamda function

Use Python as example. After create function, need to edit lambda_hander

 
import json

def lambda_handler(event, context):
    # event has info of request passed by API Gateway
    userId = event['queryStringParameters']['userId']

    # build response body
    body = {"user_id": userId, "message": "processed by Lambda"}

    # build response
    response = {'statusCode': 200, 'headers': {}}

    # let API caller know that our body is in json format
    response['headers']['content-type'] = 'application/json'
    response['body'] = json.dumps(body)

    return response

Note for node.js. In node.js, you can do

 
exports.myhandler = {event, context, callback) => {
        //get path parameters
        event.pathParamters...

        //get body
        event.body

        //get query string
        event.queryStringParameters ...

}

Note for debug:

For Python, use print something

For node.js, console.log something

Then we can see these debug info in cloudwatch


Step 2: Create a API Gateway

1. Pick Rest type

2. Create resource. Give it a name

3. Create method. We choose GET for this example.

4. In Get set up. Choose Integration type: Lambda Function. Also check "Use Lambda Proxy integration". Link the lambda function just created.


Step 3: deplay this API Gateway

Step 4: try it

find the api url and append a user id such as ?user_id=1

Step 5: add custom domain

You may want to add custom domain for this api.

Here is a good youtube video about setting up custom domain for API gateway

Here is a good youtube video about Gateway API and lamda function.

Friday, 27 August 2021

Put component, app, store together in React Redux

Redux store like a React state database. To display a component, we need retrieve states from store. When we take some actions on component, some states will be updated and we need to save these states in store. How do we connect all these pieces together? We will use Redux connect API!

Step one: define mapStateToProps function in component

To display a component, we need props. These props comes from states. We need a mapping between component's props and store's states. This function take state as parameter and return a mapping object.

const mapStateToProps = (state) => {
    return {
        user: state.app.user,
        name: getName(state),
        ....
    }
};

Noted we can do a direct mapping. Also we can call a function in reducer to do mapping.

These props can be used in function component directly

function myfuncComponent({user, name}) {
...
}

Also can access prop using the syntax below

 this.props.user

Also noted we can access props generated by step two in the same way.

There is another pattern to do mapStateToProps. Map some props to states by modify states. Then copy all left states as props. See below

const mapStateToProps = (state) => {
    const values = {
     user: state.app.user,
        name: getName(state),
        ....
    };
    //the first parameter is target. Here merge values 
    //with state. Then copy to the target and return target
    return Object.assign({}, state, values);
    
    //may do. only overwrite counut property and leave other properties intact
    return {...state, count:state.count+1}
};

Step two: define mapDispatchToProps function in component

This function uses dispatch as a paramter. It defines mapping between user action and redux action by dispatch user action. Reduct action will pass the action event to reducer. Reducer will change states. States will map props, and component display will be changed.

const mapDispatchToProps = (disptach, ownProps) => {
    return {
    	//when use handleSubmit, we can pass values
        handleSubmit: values => dispatch(saveValues(values))
        ...
    }
}

Example to use ownProps of mapDispatchToProps

const mapDispatchToProps = (dispatch, ownProps) => {
  return {
    toggleTodo: () => dispatch(toggleTodo(ownProps.todoId))
  }
}

Step 3: use connect api to create a container and export it

export default connect(
    mapStateToProps,
    mapDispatchToProps
)(ComponentName)

connect is a high order component. After call connect, it returns a new function. This new function will accept a component as argument and return an enchanced component. To understand this, we can do this in two step.

const newfunction = connect(mapStateToProps, mapDispatchToProps)
export default newfunction(ComponentName)

When write a component, we need some props and some event handlers. This is why we need to do state mapping and dispatch mapping.

Step 4: connect app, store and component. It is done in index.js of app

Use provider to provide store and put our container into provider. Our app will render provider in root element. By far, things are put together.

import {Provider} from 'react-redux'

import store from './redux/store'

//we export container as default in myComponent
import container from './myComponent'

//create a store. To create a store, you should 
//have written a reducer
import reducers from 'yourReducer'
import {createStore} from 'redux'

const store = createStore(reducers)

const root = document.getElementById('root')

ReactDOM.render(
        <Provider store={store}>
                <container />
        </Provider>, root
    );

Some nice explanation from stackoverflow

To see states of store

store.subscribe(() => console.log("state", store.getState()))

shouldComponentUpdate

Once I find that state is updated, but component is not updated. Eventually, I figured out that was caused by shouldComponentUpdate. The following prograph comes from React documentation.

Use shouldComponentUpdate() to let React know if a component’s output is not affected by the current change in state or props. The default behavior is to re-render on every state change, and in the vast majority of cases you should rely on the default behavior. shouldComponentUpdate() is invoked before rendering when new props or state are being received. Defaults to true. This method is not called for the initial render or when forceUpdate() is used.

Redux form

To create a redux form

//create a normal react component. 
//It can be a function component or class component
let myComponent = (props) => {
 return <form onSubmit={props.handleSubmit}> .... </form>
}

//convert to a redux-form component. 
//Noted that reduxFormCreator is a function
let reduxFormCreator = reduxForm({form: 'my-form'})
myComponent = reduxFormCreator(myComponent)

//we can combine the above two lines into one line
myComponent = reduxForm({form: 'my-form'})(myComponent)

//redux form provide a Field component. 
//Form elements like input or select needs to be replaced by Field
//this field component to make input to connect to redux store
<Field name="my_input_name" component="input" type="text" 
onChange={some function}/>
//another Field example
<Field name="group_by_session" onChange={this.updateAndFetch.bind(this, "group_by_session")}
 id="group_by_session" component="input" type="checkbox" />

The value from component prop of Field can be a stateless or stateful component. It can access these props

How to set intial values in Fields of Redux Form

submit form

//Redux-Form decorates your component with handleSubmit prop
let MyForm = ({
    handleSubmit, handleCloseRequestChangeModal, error, handleCloseRequestChangeModalError, formErrors
}) => {
    return (<>
        <Field
            name="storeName"
            label = "Store Name"
            component="input"
            validate={[formFieldValidator.required, formFieldValidator.notEmpty]}
        />
        <button className={"btn btn-success margin-right-3"} onClick={handleSubmit}>Save</button>
        </>)
}

When use this redux form, we need to pass a function for onSubmit

<MyForm  onSubmit={saveIntegration}/>

Add a hidden field in redux form and fill the hidden field dynamically

 <Field
name="recaptchaToken"
component="input"
type="hidden"
/>
handleRemoteSubmit: (token) => {
           dispatch(change('checkoutForm', 'recaptchaToken', token));
           dispatch(submit('checkoutForm'))
}

React function component

If a component only needs render function and props, we can write it in function component.

//create one
function Square(props) {
  return (
    <button className="square" onClick={props.onClick}>
      {props.value}
    </button>
  );
}

//to use it, we do NOT do a function call. Use it as normal component.
//pass two props. one is called value and the other is called onClick
 <Square
    value={this.state.squares[i]}
    onClick={() => this.handleClick(i)}
 />

Disptach

The Redux store has a method called dispatch. The only way to update the state is to call store.dispatch() and pass in an action object. The store will run its reducer function and save the new state value inside.

//here is how to apply this tech

//in the action.js, create a action creator
export const CHANGE_RESULTS_VIEW = 'CHANGE_RESULTS_VIEW';
export function changeResultsView(view) {
    return { type: CHANGE_RESULTS_VIEW, view: view}
}

//in container, import that action creator. When do mapDispatchToProps,
//use action creator to create a action, and this action is passed into
//dispatch. dispatch will change state of store using logic defined
//in reducer.
const mapDispatchToProps = (dispatch, ownProps) => {
    return {
       
        changeResultsView: view => dispatch(changeResultsView(view)),
        ...
        }
    }

in line conditional render

can use js logical && to add a element based on some condition

{books.length > 0 &&
	<h2>
		You have {books.length} books.
	</h2>
} 

Use update from immutability helpers

Update Library

Use update to keep the original object unchanged. Then create a upated new object. Here we use $set to set new value. Update has other commands such as $push

var update = require('immutability-helper');
 const obj = {a:5, b:3}
 const newObj = update(obj, {b: {$set:10}})
 console.log("new obj:", newObj)
 //newObj is {a:5, b:10}
 
 //the below is example for $merge. use to update multiple values
 update(state, {$merge:{details: '', showModal: false}})

Add inline css in jsx

properties with two names, like background-color, must be written with camel case syntax

<h1 style={{backgroundColor: "white"}}>Hello World!</h1>

//this css will keep spaces.jsx will remove space as default
<div style={{ whiteSpace: 'pre-wrap' }}>some text  <div>

Workflow to add event handler in react component using redux

step one: define a function in mapDispatchToProp

const mapDispatchToProps = (dispatch, ownProps) => {
    return {
        handleCloseDetailsModal: () => dispatch({ type: CLOSE_DETAILS_MODAL })
    }
};

step two: in render function, use object spread to get the function from props

step three: use that function in component. Note we put a function name. NOT call the function.

render() {
        const {handleCloseDetailsModal } = this.props;
        return (
            <div><DetailsModal
                isOpen={showModal}
                closeDetailsModal={handleCloseDetailsModal}
                details={details}
            /></div>
        );
    }

React hook and context

Good Explain

7 Hooks to know

Good tutorial

Create a context
//create a context object. Then create a function to return provider
const MyContext = createContext();
const GlobalContext = ({ children }) => {
	//define some state here
    var states = {...}
    
    //if it is class component, use this.props.children
    return (<MyContext.Provider values={...states}> {children} 
    </MyContext.Provider>)
}
To consume context

There are several different ways. By now the most popular is to use useContext

//here useGlobalContext has values and we can put this 
//line in any component. Therefore, this is just another way to share
//states between different components. Now useGlobalContext has values
//defined in the provider
  const useGlobalContext = useContext(Context)
import {useState} from 'react';

function TestB() {
    const [state, setState] = useState(0)

    return (
        <div>
            <p>{state}</p>
            <button onClick={() => setState(state + 1)}>More</button>
        </div>
    )
}

setState function in React.Component

We can use setState() to change the state of the component directly as well as through an arrow function.

//change directly by passing an object
setState({ stateName : updatedStateValue })

//use function to change state
setState((prevState) => ({ 
   stateName: prevState.stateName + 1 
}))

React Context

Introduction to React Context

React Hook Form

Good Tutorial

JS Cheating Sheet

Sheet

Class Component Benefit

export default class GooglePay extends React.Component {
    constructor(props) {
        super(props);

        //Google payment client
        this.paymentsClient = new google.payments.api.PaymentsClient({
            environment: props.cardInfo.googlePayEnv // 'TEST' Or 'PRODUCTION'
        });

        //request sent to Google
        this.paymentDataRequest = null;

        //need this method to create payment data request
        this.cardPaymentMethod = null;

        //create Google Pay Button
        this.createGooglePayButton();
    }

    state = {
        isLoading: false
    }
......

If parent component render multiple time and the child component is class component, the child component renders only once. However, if child component is function component, it will render the same time as parent component.

React and Bootsrap

import { Container, Row, Col } from "react-bootstrap";
return (
      <div className="App">
        <Container>
          <Row>
            <Col className="bg-primary p-2">1 of 2</Col>
            <Col className="bg-success p-2">2 of 2</Col>
          </Row>
          <Row>
            <Col className="bg-success p-2">1 of 3</Col>
            <Col className="bg-secondary p-2">2 of 3</Col>
            <Col className="bg-danger p-2">3 of 3</Col>
          </Row>
        </Container>
      </div>
    );


need to add bootstrap css

<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.4.1/dist/css/bootstrap.min.css" integrity="sha384-Vkoo8x4CGsO3+Hhxv8T/Q5PaXtkKtu6ug5TOeNV6gBiFeWPGFN9MuhOf23Q9Ifjh" crossorigin="anonymous">

The below should work too. But I found it did not work. Have not figured out.

import 'bootstrap/dist/css/bootstrap.min.css';

React and TypeScript

Create a Project

Documentation

If you have created a folder already, do not put my_app and instead use "."

npx create-react-app . --template typescript

Access element in event hander

function MyButton() {
  function handleClick(event) {
    let button = event.target;
    alert(button.id);
  }
  return (
    <button id="leo" onClick={handleClick} className="my-button">
      Click Me
    </button>
  );
}

function component

//three ways to write function component
function Welcome({name, ...props}) {
    return <h1>Hello, {name}, yau are {props.age} old</h1>
}

function Welcome({name, age}) {
    return <h1>Hello, {name}, yau are {age} old</h1>
}

function Welcome(props) {
    return <h1>Hello, {props.name}, yau are {props.age} old</h1>
}

//use component
<Welcome name="smith" age="51" />

Tuesday, 24 August 2021

docker run or docker container run

They are exactly the same. docker container run is new syntax introduced in Docker 1.13.


Because there are so many docker commands, docker has put these commands in different groups. docker run is put into the group of docker container.


Here is a list of docker container command:


docker container commands


It is encouraged to use the new syntax. Therefore, let us do:


docker container run

Sunday, 1 August 2021

Import and export default values in JS modules

There should be only one default value in a module. There are two ways to export it.


export default function(n, m) {

    return n + m;

}   

another way


function add(n, m) {

    return n + m;

}   

export default add;

Assume the module name is math.js. To import it,


import sum from "./math.js";

Noted that we can give any name for default value when import it. Also do not need curly braces. For not default values, need curly braces.

For no default function export or import, need curly braces

import {mymethod} from '../../utilities/actions'
......
export {foo, awesom, check}

Import multiple functions from a module

import {get, set} as moduleName from 'module-name'
moduleName.get();

//or can do
import * as moduleName from 'module-name';
moduleName.get();

//or can do. But this may cause name collision
import {get,set} from 'module-name';
get()

//real life example
import * as yup from "yup";

username: yup.string().required("Username is required"),

(node:46383) Warning: To load an ES module, set "type": "module" in the package.json or use the .mjs extension.

If get the above error when use node to run the script. The warning message you are encountering indicates that you are trying to load an ES (ECMAScript) module in a Node.js environment, but your current setup is not configured to recognize it as such.

node use commonjs module format

To solve it, one: Use "type": "module" in package.json. The alternative way is: rename your JavaScript files to use the .mjs extension instead of .js.