Friday, November 30, 2018

To determine Vue current development mode

In main.js:

windows['VueMode'] = process.env.NODE_ENV;

Note: If you would like to use process.env.NODE_ENV in a sub component, put it inside one of the lifecycle hooks. For example, created, or mounted.

Friday, November 16, 2018

mtail - extract whitebox monitoring data from application logs for collection in a timeseries database

mtail - extract whitebox monitoring data from application logs for collection in a timeseries database

$ curl -L https://github.com/google/mtail/releases/download/v3.0.0-rc16/mtail_v3.0.0-rc16_linux_amd64 -o mtail

$ vim linecounter.mtail

# simple line counter
counter line_count
/$/ {
  line_count++
}

$ mtail --progs linecounter.mtail --logs debug.log

$ echo hi1 >> debug.log
$ echo hi2 >> debug.log

$ curl http://localhost:3903/metrics

Reference:

https://groob.io/posts/prometheus-intro/

https://github.com/google/mtail

Monday, October 29, 2018

Running php-fpm in Docker based on CentOS 7

Running php-fpm in Docker based on CentOS 7

Dockerfile:

FROM centos:centos7

RUN curl 'https://setup.ius.io/' -o setup-ius.sh \
 && bash setup-ius.sh \
 && rm -f setup-ius.sh \
 && yum -y update \
 && yum -y install \
  php71u-common \
  php71u-cli \
  php71u-fpm \
  php71u-opcache \
  php71u-xml \
  php71u-json \
  php71u-pdo \
  php71u-mysqlnd \
  php71u-intl \
  php71u-mbstring \
  php71u-mcrypt \
  php71u-gd \
  php71u-soap \
  php71u-process \
  php71u-pecl-redis \
  php71u-pecl-xdebug \
  php71u-fpm-httpd

EXPOSE 9000

CMD ["php-fpm", "-F"]

Build the docker image:

# docker build -t junhsieh/php7.1-fpm:0.0.0 .

Some important settings to be changed:

# vim /etc/php-fpm.d/www.conf

; Change ownership:

user = php-fpm
group = php-fpm

; Note: Ubuntu uses www-data user. Add php-fpm user to www-data group if the other container used it.
; # groupadd -g 33 www-data
; # useradd www-data -m -c 'web user' -u 33 -g 33
; # usermod -a -G www-data php-fpm
; # id php-fpm
; Now, restart this container to ensure php-fpm user is in www-data group.

; Bind port 9000 to the all interfaces:

listen = 9000
;listen = [::]:9000

; Note: PHP-FPM has a listen.client_allowed setting which allows you to set a list of IPs that can connect, or leave blank for any IP to connect. However, even with it being left blank, the issue still persisted. Digging into the official PHP-FPM repo, I discovered that you also need to set  listen = [::]:9000 which then began to allow any IP to connect.
; Note: https://stackoverflow.com/questions/19806945/docker-and-connections-between-containers

; Comment out the following line:

;listen.allowed_clients = 127.0.0.1

; Note: "listen.allowed_clients = any" will not work.
; Note: "listen.allowed_clients = other-container-name" will not work. IP address only.


; Uncomment the following line to debug the issue:

catch_workers_output = yes

; Note: Comment it out on production.


xdebug setting:

### xdebug setting
###
; Enable xdebug extension module
zend_extension=xdebug.so
;zend_extension=/usr/lib64/php/modules/xdebug.so

xdebug.default_enable=1
xdebug.remote_enable=1
xdebug.remote_handler=dbgp
xdebug.remote_host=localhost
xdebug.remote_port=9009
; Note: php-fpm uses port 9000 as well.
xdebug.remote_log=/tmp/xdebug.log
xdebug.remote_connect_back=0
xdebug.remote_autostart=0
xdebug.remote_mode=req

xdebug.max_nesting_level=1000

Reference:

https://developers.redhat.com/blog/2014/12/29/running-php-fpm-in-docker/

Sunday, October 14, 2018

usermod and groupmod not found in Alpine Linux Docker Image

usermod and groupmod not found in Alpine Linux Docker Image

$ vim Dockerfile

FROM alpine:latest

RUN apk --no-cache add shadow \
  && usermod -u 2500 elasticsearch \
  && groupmod -g 2500 elasticsearch

Monday, October 8, 2018

Caused by: javax.net.ssl.SSLHandshakeException: java.security.cert.CertificateException: No subject alternative names matching IP address XXXXX found

Caused by: javax.net.ssl.SSLHandshakeException: java.security.cert.CertificateException: No subject alternative names matching IP address XXXXX found 
at sun.security.ssl.Alerts.getSSLException(Unknown Source) ~[na:1.8.0_51] 
at sun.security.ssl.SSLSocketImpl.fatal(Unknown Source) ~[na:1.8.0_51] 

# vim LDAPConnTest.java

Hashtable<String, Object> objEnvironment;
    objEnvironment = new Hashtable<String, Object>(11);
    objEnvironment.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
    objEnvironment.put(Context.PROVIDER_URL,  "LDAPS://domain:636");
    objEnvironment.put(Context.SECURITY_AUTHENTICATION, "simple");
    objEnvironment.put(Context.SECURITY_PRINCIPAL, <username>);
    objEnvironment.put(Context.SECURITY_CREDENTIALS, <Password>);
    objEnvironment.put("java.naming.ldap.attributes.binary", <attributes>);
    System.setProperty("javax.net.ssl.trustStore", "certificates".concat(File.separator).concat("cacerts"));
    this.objLDAPContext = new InitialLdapContext(objEnvironment, null);

# java main -Dcom.sun.jndi.ldap.object.disableEndpointIdentification=true

Note: Do not use the -Dcom.sun.jndi.ldap.object.disableEndpointIdentification=true option on production server.

Improve LDAP support Endpoint identification has been enabled on LDAPS connections.

To improve the robustness of LDAPS (secure LDAP over TLS ) connections, endpoint identification algorithms have been enabled by default.

Note that there may be situations where some applications that were previously able to successfully connect to an LDAPS server may no longer be able to do so. Such applications may, if they deem appropriate, disable endpoint identification using a new system property: com.sun.jndi.ldap.object.disableEndpointIdentification.

Define this system property (or set it to true) to disable endpoint identification algorithms.

Reference:

https://stackoverflow.com/questions/51622117/issue-with-dns-naming-and-certificates-ldap-context

https://www.oracle.com/technetwork/java/javase/8u181-relnotes-4479407.html

fail to run in alpine docker with error "no such file or directory"

fail to run in alpine docker with error "no such file or directory"

Edit main.go:

# vim main.go

package main

import (
        "fmt"
        "log"
        "net/http"
)

func handler(w http.ResponseWriter, r *http.Request) {
        fmt.Printf("Hello World\n")
        fmt.Fprintf(w, "Hi there, I love %s!", r.URL.Path[1:])
}

func main() {
        http.HandleFunc("/", handler)
        log.Fatal(http.ListenAndServe(":8080", nil))
}

Build main.go:

# CGO_ENABLED=0 go build main.go

Note: Static build: GOOS=linux GOARCH=amd64 go build main.go

Dockerfile:

#
FROM alpine:latest
RUN apk --no-cache add ca-certificates

COPY main /usr/local/bin

CMD /usr/local/bin/main

Build Docker image:

# docker build -t exp/main:0.0.0 .

Sunday, September 23, 2018

Golang, mysql: Error 1040: Too many connections too many open files

Golang, mysql: Error 1040: Too many connections too many open files

  • Opening and closing databases can cause exhaustion of resources.
  • Failing to read all rows or use rows.Close() reserves connections from the pool.
  • Using Query() for a statement that doesn’t return rows will reserve a connection from the pool.
  • Failing to be aware of how prepared statements work can lead to a lot of extra database activity.

Check MySQL connections:

mysql> SHOW PROCESSLIST;

mysql> SHOW STATUS LIKE '%connections%';

mysql> SHOW STATUS LIKE '%threads%';

Check network connection files:

# lsof -i

Set some connection limits in Go code:

db.SetMaxOpenConns(1000)
db.SetMaxIdleConns(300)
db.SetConnMaxLifetime(0)

Release the resource after used:

rows, err := db.Query("select name from beehives")

if err != nil {
    panic(err)
}   
    
defer rows.Close()

Reference:

https://stackoverflow.com/questions/28135580/golang-mysql-error-1040-too-many-connections

http://go-database-sql.org/surprises.html

http://go-database-sql.org/prepared.html

https://access.redhat.com/solutions/1160343

Saturday, September 22, 2018

Add Swap to a Amazon EC2 instance with an EBS (Elastic Block Store) volume

The Amazon EC2 instance does not come with the swap partition by default. You will need to add the swap or paging space manually.

Swap space are useful for systems having less memory (RAM). If your system facing problem of lack of memory continuously and you don’t want to increase memory on server, Then it can be helpful to enable swap in your system. Swap is comparatively much slower than physical memory but operating system uses swap space in case system goes out of memory. To know more about working of swap visit here.

Creating a swap file in current file system:

# dd if=/dev/zero of=/myswap bs=1M count=4096

Note: if - input file.
Note: of - output file.
Note: bs - block size.

# mkswap /myswap
# chown root:root /myswap
# chmod 0600 /myswap

# swapon /myswap

# free -h

              total        used        free      shared  buff/cache   available
Mem:           3.8G        940M        115M        5.6M        2.8G        2.6G
Swap:          4.0G          0B        4.0G

# swapon -s

Filename                                Type            Size    Used    Priority
/myswap                                 file    4194300 0       -1

To make the swap enable on system boot, run the following command:

# sh -c "echo /myswap swap swap defaults 0 0 >> /etc/fstab"

Or edit the /etc/fstab:

# vim /etc/fstab

/myswap   swap   swap   defaults  0 0

To verify the swap:

# cat /etc/fstab | grep -i swap

/myswap swap swap defaults 0 0

# cat /proc/meminfo | grep -i swap

SwapCached:            0 kB
SwapTotal:       4194300 kB
SwapFree:        4194300 kB

To check the current system's swappiness:

Swappiness is a ratio of how often the system will write to the swapfile: if set to zero, the system will only swap to avoid running out of memory (the error above); if set to 100, the system will attempt to swap all the time. The default is set at 60. Since we want to utilize the swap only when necessary.

The Linux kernel provides a tweakable setting that controls how often the swap file is used, called swappiness.

A swappiness setting of zero means that the disk will be avoided unless absolutely necessary (you run out of memory), while a swappiness setting of 100 means that programs will be swapped to disk almost instantly.

Ubuntu system comes with a default of 60, meaning that the swap file will be used fairly often if the memory usage is around half of my RAM.

# cat /proc/sys/vm/swappiness

30

To configure swappiness:

# sh -c "echo vm.swappiness = 0 >> /etc/sysctl.conf && sysctl -p"

Add the swap space to a second disk instead of the current disk:

If you would like to add the swap space to a second disk, first we need to add extra disk in our system first. In my case new disk mounted as /dev/xvdd (It may change in your case). Then, run the following commands:

# mkswap -f /dev/xvdd
# swapon /dev/xvdd

# vim /etc/fstab

dev/xvdd   swap   swap   defaults  0 0

If at all possible, I'd advise not to use swap on EC2 unless you're 99% certain you won't have to use it (I.E. it's only there for emergency). When we disabled swap on some of our EC2 instances our monthly EBS IO costs probably halved.

You are right, the Ubuntu EC2 EBS images don't come with swap space configured (for 11.04 at least). The "regular" instance-type images do have a swap partition, albeit only 896 MB on the one I tested.

If some process blows up and you don't have swap space, your server could come to a crawling halt for a good while before the OOM killer kicks in, whereas with swap, it merely gets slow. For that reason, I always like to have swap space around, even with enough RAM. Here's your options:

Create an EBS volume (2-4 times the size of your RAM), attach it to your instance (I like calling it /dev/xvdm for "memory"), sudo mkswap /dev/xvdm, add it to fstab, sudo swapon -a, and you're good to go. I have done this before and it works fine, and it is probably a bit faster than using a swap file, but for a server that doesn't normally depend on swap performance, I personally think the minor performance improvement is not worth the added complexity of having to attach a volume. (Update: It's probably not faster than a swap file on instance storage, since EBS has become known for lousy and unpredictable performance.)

Or you might be able to repartition your disk to add a swap partition, though this might require creating a new AMI. I have not been able to do this in a running instance, because I cannot unmount the root file system, and I do not even have access to the disk device (/dev/xvda), only the partition (xvda1).

Or you can create a swap file. This is my preferred solution right now.

# dd if=/dev/zero of=/var/swapfile bs=1M count=2048 &&
# chmod 600 /var/swapfile &&
# mkswap /var/swapfile &&
# echo /var/swapfile none swap defaults 0 0 | tee -a /etc/fstab &&
# swapon -a

Done. :) I know a lot of people feel icky about using files instead of partitions, but it certainly works well enough as emergency swap space.

Reference:

http://tecadmin.net/add-swap-partition-on-ec2-linux-instance/
http://stackoverflow.com/questions/17173972/how-do-you-add-swap-to-an-ec2-instance
http://askubuntu.com/questions/103915/how-do-i-configure-swappiness
http://serverfault.com/questions/218750/why-dont-ec2-ubuntu-images-have-swap
http://danielgriff.in/2014/add-swap-space-to-ec2-to-increase-performance-and-mitigate-failure/

How to extract deb package

How to extract deb package

$ dpkg -x mysql-cluster-community-server_7.6.7-1ubuntu16.04_amd64.deb ~/tmp/out

or

$ ar -xv mysql-cluster-community-server_7.6.7-1ubuntu16.04_amd64.deb

Increase MySQL maximum connection limit

Increase MySQL maximum connection limit

2018-09-22T15:00:42.130042Z 0 [Warning] Changed limits: max_open_files: 1024 (requested 5000)
2018-09-22T15:00:42.130087Z 0 [Warning] Changed limits: max_connections: 214 (requested 500)
2018-09-22T15:00:42.130091Z 0 [Warning] Changed limits: table_open_cache: 400 (requested 2000)

Note: Ubuntu has moved from Upstart to Systemd in version 15.04 and no longer respects the limits in /etc/security/limits.conf for system services. These limits now apply only to user sessions.

# mkdir /etc/systemd/system/mysql.service.d
# vim /etc/systemd/system/mysql.service.d/override.conf

[Service]
LimitNOFILE=infinity
LimitMEMLOCK=infinity

# systemctl daemon-reload
# systemctl restart mysql

Reference:

https://stackoverflow.com/questions/30901041/can-not-increase-max-open-files-for-mysql-max-connections-in-ubuntu-15

Sunday, September 16, 2018

To let other different users login to Amazon's EC2 instance

Solution 1:

On the local machine, get public key for later use:

$ test -f ~/.ssh/id_rsa.pub && cat ~/.ssh/id_rsa.pub || ssh-keygen -t rsa -C "me@example.com" && cat ~/.ssh/id_rsa.pub

On the remote EC2 instance, create a new user and add the new user to sudo group:

# useradd USER_NAME -m -s /bin/bash -c 'admin user' && usermod -aG sudo USER_NAME

# visudo

%sudo ALL=(ALL:ALL) NOPASSWD: ALL
or
USER_NAME ALL=(ALL) NOPASSWD: ALL

# sudo su - USER_NAME

$ mkdir ~/.ssh \
&& chmod 700 ~/.ssh \
&& touch ~/.ssh/authorized_keys \
&& chmod 600 ~/.ssh/authorized_keys \
&& vim ~/.ssh/authorized_keys

On the local machine:

$ ssh -i ~/.ssh/id_rsa -p 22 USER_NAME@1.2.3.4
or
$ mosh --ssh="ssh -i ~/.ssh/id_rsa -p 22" USER_NAME@1.2.3.4

Solution 2:

# vim /etc/ssh/sshd_config

PasswordAuthentication = yes

# systemctl restart sshd.service

Solution 3:

Add a new user:

# useradd testuser -m -c 'test user'

Switch to the new account so that newly created files have the proper ownership:

# sudo su - testuser

$ mkdir ~/.ssh

$ chmod 700 ~/.ssh

Note: this step is very important; without these exact file permissions, you will not be able to log into this account using SSH.

$ touch ~/.ssh/authorized_keys

$ chmod 600 ~/.ssh/authorized_keys

Login to Amazon Web Services console. Then, go to EC2 and create a new key pair: machineName_userName.

It will generate a machineName_userName.pem file for you to download.

Upload machineName_userName.pem to your Linux instance.

Change the permission of the machineName_userName.pem:

# chmod 400 machineName_userName.pem

Retrieving the Public Key for Your Key Pair on Linux:

# ssh-keygen -y

When prompted to enter the file in which the key is, specify the path to your .pem file; for example:

/path_to_key_pair/machineName_userName.pem

The command returns the public key:

ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQClKsfkNkuSevGj3eYhCe53pcjqP3maAhDFcvBS7O6V
hz2ItxCih+PnDSUaw+WNQn/mZphTk/a/gU8jEzoOWbkM4yxyb/wB96xbiFveSFJuOp/d6RJhJOI0iBXr
lsLnBItntckiJ7FbtxJMXLvvwJryDUilBMTjYtwB+QhYXUMOzce5Pjz5/i8SeJtjnV3iAoG/cQk+0FzZ
qaeJAAHco+CY/5WrUBkrHmFJr6HcXkvJdWPkYQS3xqC0+FmUZofz221CBt5IMucxXPkX4rWi+z7wB3Rb
BQoQzd8v7yeb7OzlPnWOyN0qFU0XA246RA8QFYiCNYwI3f05p6KLxEXAMPLE

Edit the authorized_keys file with your favorite text editor and paste the public key for your key pair into the file:

# sudo su - testuser

$ vim ~/.ssh/authorized_keys

ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQClKsfkNkuSevGj3eYhCe53pcjqP3maAhDFcvBS7O6V
hz2ItxCih+PnDSUaw+WNQn/mZphTk/a/gU8jEzoOWbkM4yxyb/wB96xbiFveSFJuOp/d6RJhJOI0iBXr
lsLnBItntckiJ7FbtxJMXLvvwJryDUilBMTjYtwB+QhYXUMOzce5Pjz5/i8SeJtjnV3iAoG/cQk+0FzZ
qaeJAAHco+CY/5WrUBkrHmFJr6HcXkvJdWPkYQS3xqC0+FmUZofz221CBt5IMucxXPkX4rWi+z7wB3Rb
BQoQzd8v7yeb7OzlPnWOyN0qFU0XA246RA8QFYiCNYwI3f05p6KLxEXAMPLE

Remove the private key from the server if you do not need it anymore:

# rm /path_to_key_pair/machineName_userName.pem

Reference:

http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/managing-users.html
http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-key-pairs.html#how-to-generate-your-own-key-and-import-it-to-aws

Saturday, September 15, 2018

Building MySQL from Source Code

Building MySQL from Source Code

# apt-get update && apt-get install build-essential cmake bison -y

# cd /usr/local/src \
&& git clone https://github.com/mysql/mysql-server.git --depth 1 \
&& mkdir bld \
&& cd bld \
&& cmake ../mysql-server \
-DDOWNLOAD_BOOST=1 \
-DWITH_BOOST=/usr/local/src/bld \
&& make

Persistent key-value database written in Go

Persistent key-value database written in Go

badger - https://github.com/dgraph-io/badger/

Note: https://blog.dgraph.io/post/badger/

bbolt - https://github.com/etcd-io/bbolt

MySQL backup and replication tools

MySQL backup and replication tools

mydumper

https://github.com/maxbube/mydumper

Percona XtraBackup

https://www.percona.com/software/mysql-database/percona-xtrabackup

Percona MySQL-AutoXtraBackup

https://github.com/Percona-Lab/MySQL-AutoXtraBackup

https://www.percona.com/blog/2017/11/27/perconalab-autoxtrabackup-v1-5-0-release/

mysqlbinlog

# mysqlbinlog --result-file=test.log /var/log/mysql/mysql-bin.000001

Note: You may edit the result file and delete any statements you don't want to execut. Then, do mysql -u root -p < test.log

# mysqlbinlog --result-file=test.log --base64-output=DECODE-ROWS /var/log/mysql/mysql-bin.000001
# mysqlbinlog --result-file=test.log -v /var/log/mysql/mysql-bin.000001
# mysqlbinlog --result-file=test.log -vv /var/log/mysql/mysql-bin.000001

Note: Do more research on global transaction identifier (GTID) vs binary log position

Get binary log from the remote server:

# mysqlbinlog --read-from-remote-server --host=192.168.101.2 -p mysqld-bin.000001

Note: https://www.percona.com/blog/2012/01/18/backing-up-binary-log-files-with-mysqlbinlog/

The output of mysqlbinlog can be used as the input of the mysql client to redo the statements contained in the binary log:

# cd /var/log/mysql
# mysqlbinlog mysql-bin.000001 | mysql -u root -p

canal

https://github.com/alibaba/canal

Pingcap syncer:

https://github.com/pingcap/docs/blob/master/tools/syncer.md

To Embed Static Assets in Go

To Embed Static Assets in Go

Requirements:

Compression
Optional decompression
Loading from the local file system
Reproducible builds
Config file
http.FileSystem Interface

vfsgen - https://github.com/shurcooL/vfsgen
fileb0x - https://github.com/UnnoTed/fileb0x
go-assets - https://github.com/jessevdk/go-assets

Reference:

https://tech.townsourced.com/post/embedding-static-files-in-go/

Saturday, September 8, 2018

Convert string to hexadecimal on command line

Convert string to hexadecimal on command line

$ echo -n "Hello" | od -A n -t x1

48 65 6c 6c 6f

Thursday, September 6, 2018

How to avoid Go gotchas

a gotcha is a valid construct in a system, program or programming language that works as documented but is counter-intuitive and almost invites mistakes because it is both easy to invoke and unexpected or unreasonable in its outcome (source: wikipedia)

How to avoid Go gotchas
https://divan.github.io/posts/avoid_gotchas/

Understand Go pointers in less than 800 words or your money back
https://dave.cheney.net/2017/04/26/understand-go-pointers-in-less-than-800-words-or-your-money-back

There is no pass-by-reference in Go
https://dave.cheney.net/2017/04/29/there-is-no-pass-by-reference-in-go

Pointers in Go
https://dave.cheney.net/2014/03/17/pointers-in-go

Should methods be declared on T or *T
https://dave.cheney.net/2016/03/19/should-methods-be-declared-on-t-or-t

HOW EVERYTHING IN GO IS PASSED BY VALUE ?
https://techgita.com/2018/08/25/how-everything-in-go-is-passed-by-value/

50 Shades of Go: Traps, Gotchas, and Common Mistakes for New Golang Devs
http://devs.cloudimmunity.com/gotchas-and-common-mistakes-in-go-golang/

Go traps
https://go-traps.appspot.com/

Go Data Structures
http://research.swtch.com/godata

Go Data Structures: Interfaces
http://research.swtch.com/interfaces

Go Slices: usage and internals
https://blog.golang.org/go-slices-usage-and-internals

Gopher Puzzlers
http://talks.godoc.org/github.com/davecheney/presentations/gopher-puzzlers.slide

Don't use Go's default HTTP client (in production)
https://medium.com/@nate510/don-t-use-go-s-default-http-client-4804cb19f779

The complete guide to Go net/http timeouts
https://blog.cloudflare.com/the-complete-guide-to-golang-net-http-timeouts/

How to organize the go struct, in order to save memory
https://medium.com/@felipedutratine/how-to-organize-the-go-struct-in-order-to-save-memory-c78afcf59ec2

Wheresoever you Go, Go with all your heart

That's the whole reason why Confucius said "Wheresoever you Go, Go with all your heart"

Save the matched values into variables in golang regular expression

Save the matched values into variables in golang regular expression

package main

import (
 "fmt"
 "regexp"
)

func mapSubexpNames(m, n []string) map[string]string {
 m, n = m[1:], n[1:]
 r := make(map[string]string, len(m))
 for i, _ := range n {
  r[n[i]] = m[i]
 }
 return r
}

func main() {
 r := regexp.MustCompile(`(?P<Year>\d{4})-(?P<Month>\d{2})-(?P<Day>\d{2})`)
 m := r.FindStringSubmatch(`2015-05-27`)
 n := r.SubexpNames()
 fmt.Println(mapSubexpNames(m, n))
}

Reference:

https://stackoverflow.com/questions/30483652/how-to-get-capturing-group-functionality-in-golang-regular-expressions

Wednesday, August 22, 2018

Nessus - a vulnerability scanner

Nessus is a proprietary vulnerability scanner developed by Tenable Network Security. It is free of charge for personal use in a non-enterprise environment.

Reference:

https://en.wikipedia.org/wiki/Nessus_(software)

Saturday, August 11, 2018

WireGuard - a VPN runs as a module inside the Linux kernel

WireGuard is an open-source software application and protocol that implements virtual private network (VPN) techniques to create secure point-to-point connections in routed or bridged configurations. It is run as a module inside the Linux kernel and aims for better performance than the IPsec and OpenVPN tunneling protocols.

Reference:

https://en.wikipedia.org/wiki/WireGuard

Saturday, August 4, 2018

Execute sudo without Password?

Execute sudo without Password?

At the bottom of the file:

$ sudo visudo

username ALL=(ALL) NOPASSWD: ALL

Reference:

https://askubuntu.com/questions/147241/execute-sudo-without-password

Sunday, July 29, 2018

Passing data through arguments parameters in Vue

Passing data through arguments parameters in Vue

HTML:

<script src="https://unpkg.com/vue/dist/vue.js"></script>

<div id="app">
  <p>Expected output: <code>{{ JSON.stringify(expected) }}</code></p>
  <component @emission="hearEmission">complete data, without extras</component>
  <component @emission="hearEmission('extra', ...arguments)">with extras, incomplete data</component>
  <component @emission="function (a, b, c) { hearEmission('extra', a, b, c) }">expected, overly explicit</component>
  
  <ol class="log">
    <li v-for="line in logs"><code>{{ JSON.stringify(line) }}</code></li>
  </ol>
</div>

Script:

Vue.component('component', {
 template: '<button @click="emitEvent"><slot></slot></button>',
  methods: {
   emitEvent: function() {
     this.$emit('emission', 1, 2, 3);
    }
  }
});

new Vue({
  el: '#app',
  data: {
   logs: [],
    expected: ['extra', 1, 2, 3]
  },
  methods: {
   hearEmission: function(extra, a, b, c) {
     this.logs.push([extra, a, b, c]);
      if (this.logs.length === 11) {
       this.logs.splice(0, 1);
      }
    }
  }
})

Reference:

https://jsfiddle.net/50wL7mdz/30115

Sunday, July 15, 2018

Create SVG dynamically with JavaScript and save export download SVG file

Create SVG dynamically with JavaScript and save export download SVG file

function saveSvg(svgEl, name) {
    svgEl.setAttribute("xmlns", "http://www.w3.org/2000/svg");
    var svgData = svgEl.outerHTML;
    var preface = '<?xml version="1.0" standalone="no"?>\r\n';
    var svgBlob = new Blob([preface, svgData], {type:"image/svg+xml;charset=utf-8"});
    var svgUrl = URL.createObjectURL(svgBlob);
    var downloadLink = document.createElement("a");
    downloadLink.href = svgUrl;
    downloadLink.download = name;
    document.body.appendChild(downloadLink);
    downloadLink.click();
    document.body.removeChild(downloadLink);
}

saveSvg(svg, 'test.svg');

Reference:

https://stackoverflow.com/questions/23218174/how-do-i-save-export-an-svg-file-after-creating-an-svg-with-d3-js-ie-safari-an

Sunday, June 17, 2018

troubleshot network connection unstable issue

$ mtr -n -c 200 --report -P 53 8.8.8.8

$ traceroute -T -p 53 8.8.8.8

$ hping3 -S -c 50 -V 8.8.8.8 -p 53

$ tcpdump port 53

Thursday, May 31, 2018

Terminal display messed up when using tmux vim and docker container

Terminal display messed up when using tmux vim and docker container

Solution 1:

$ echo $TERM $LINES $COLUMNS

screen-256color 41 146

$ docker exec -it -e TERM=$TERM -e LINES=$LINES -e COLUMNS=$COLUMNS YOUR_CONTAINER_NAME bash

Solution 2:

$ reset

Solution 3:

$ stty size

41 146

$ stty rows 41 cols 146

Sunday, May 13, 2018

AutoHotkey

example.ahk:

; reload the autohotkey script.
^!r::Reload

; input date and time
#d::
  FormatTime, mydatetime,, M/d/yyyy HH:mm:ss
  SendInput, %mydatetime%
return

; input date
#f::
  FormatTime, mydate,, M/d/yyyy
  SendInput, %mydate%
return

; input date
#y::
  FormatTime, mydate,, yyyy-MM-dd
  SendInput, %mydate%
return

; press ctrl-alt 1
^!1::
SendInput, Hello World
return

; In command prompt window, press shift + insert to paste from clipboard
#IfWinActive ahk_class ConsoleWindowClass
<+Insert::
  SendInput, {Raw}%clipboard%
return
#IfWinActive

grep number

grep number

$ go version | grep -Eo '[0-9.]+'

String length in bytes in JavaScript

String length in bytes in JavaScript

(new TextEncoder('utf-8').encode('foo')).length

Reference:

https://stackoverflow.com/questions/5515869/string-length-in-bytes-in-javascript

Photoshop alternative tool

Photoshop alternative tool

GIMP (GNU Image Manipulation Program) is a free and open-source raster graphics editor[6] used for image retouching and editing, free-form drawing, converting between different image formats, and more specialized tasks.

https://en.wikipedia.org/wiki/GIMP

Sketch is a proprietary vector graphics editor for Apple's macOS, developed by the Dutch company Bohemian Coding.

https://en.wikipedia.org/wiki/Sketch_(application)

Sunday, May 6, 2018

To connect to a remote MySQL Server via an SSH Tunnel

A SSH tunnel is a exactly as the name suggests, a tunnel over SSH on which we'll forward a specific port. The port will be accessible on your local machine, but will be automatically forwarded to the remote machine so it appears as if you're remote service (MySQL in this case) is actually local.

To connect to a remote MySQL Server via an SSH Tunnel:

$ ssh -i ubun-exp.pem -p 22 -L 127.0.0.1:3308:127.0.0.1:3306 username@example.com
$ mysql -u root -p -P 3308 -h 127.0.0.1

Note: The command above will open a pseudo terminal.

Note: You have to specify host with -h and put 127.0.0.1 instead of localhost since mysql will try to connect to the local MySQL socket on your computer instead of the TCP connection via port 3306.

If you only want to create a tunnel you can use the -NnT option:

$ ssh -i ubun-exp.pem -p 22 -NnT -L 127.0.0.1:3308:127.0.0.1:3306 username@example.com

Note: -N wich will disable the ability to execute a remote command.
Note: -n will prevent reading from stdin.
Note: -T will disable the pseudo-terminal allocation.

Reference: https://hostpresto.com/community/tutorials/how-to-connect-to-a-remote-mysql-server-via-an-ssh-tunnel/

Tuesday, February 27, 2018

Kali Linux is a Debian-derived Linux distribution designed for digital forensics and penetration testing.

Kali Linux is a Debian-derived Linux distribution designed for digital forensics and penetration testing.

Reference:

https://en.wikipedia.org/wiki/Kali_Linux

Dynamic allowed values list

Dynamic allowed values list

Set allowed_values_callback in database

Reference:

https://drupal.stackexchange.com/questions/200693/dynamic-allowed-values-list

To SSH login to the remote server without entering password (by using SSH keys)

To SSH login to the remote server without entering password (by using SSH keys)

# cat ~/.ssh/id_rsa.pub | ssh USER@HOST "mkdir -p ~/.ssh && cat >> ~/.ssh/authorized_keys"

Reference:

https://askubuntu.com/questions/46424/adding-ssh-keys-to-authorized-keys

Thursday, February 22, 2018

Ace Text Editor Bookmarklet

Ace is a standalone code editor written in JavaScript. Our goal is to create a browser based editor that matches and extends the features, usability and performance of existing native editors such as TextMate, Vim or Eclipse.

Ace Bookmarklet http://ajaxorg.github.io/ace/build/demo/bookmarklet/index.html

javascript:(function inject(options, callback) { var load = function(path, callback) { var head = document.getElementsByTagName('head')[0]; var s = document.createElement('script'); s.src = options.baseUrl + "/" + path; head.appendChild(s); s.onload = s.onreadystatechange = function(_, isAbort) { if (isAbort || !s.readyState || s.readyState == "loaded" || s.readyState == "complete") { s = s.onload = s.onreadystatechange = null; if (!isAbort) callback(); } }; }; var pending = []; var transform = function(el) { pending.push(el) }; load("ace.js", function() { ace.config.loadModule("ace/ext/textarea", function(m) { transform = function(el) { if (!el.ace) el.ace = m.transformTextarea(el, options.ace); }; pending = pending.forEach(transform); callback && setTimeout(callback); }); }); if (options.target) return transform(options.target); window.addEventListener("click", function(e) { if (e.detail == 3 && e.target.localName == "textarea") transform(e.target); });})({"selectionStyle":"line","highlightActiveLine":true,"highlightSelectedWord":true,"readOnly":false,"copyWithEmptySelection":false,"cursorStyle":"ace","mergeUndoDeltas":true,"behavioursEnabled":true,"wrapBehavioursEnabled":true,"keyboardHandler":"ace/keyboard/vim","hScrollBarAlwaysVisible":false,"vScrollBarAlwaysVisible":false,"highlightGutterLine":true,"animatedScroll":false,"showInvisibles":false,"showPrintMargin":false,"printMarginColumn":80,"printMargin":false,"fadeFoldWidgets":false,"showFoldWidgets":true,"showLineNumbers":true,"showGutter":true,"displayIndentGuides":true,"fontSize":"12px","scrollPastEnd":0,"theme":"textmate","scrollSpeed":2,"dragDelay":0,"dragEnabled":true,"focusTimeout":0,"tooltipFollowsMouse":true,"firstLineNumber":1,"overwrite":false,"newLineMode":"auto","useWorker":true,"useSoftTabs":true,"navigateWithinSoftTabs":false,"tabSize":4,"wrap":"off","indentedSoftWrap":true,"foldStyle":"markbegin","mode":"javascript","enableMultiselect":true,"enableBlockSelect":true,"baseUrl":"https://ajaxorg.github.io/ace-builds/src-noconflict"})

Reference:

https://github.com/ajaxorg/ace/

Sunday, February 11, 2018

How do you get struct value on unknown interface{}

How do you get struct value on unknown interface{}


func getProp(d interface{}, label string) (interface{}, bool) {
    switch reflect.TypeOf(d).Kind() {
    case reflect.Struct:
        v := reflect.ValueOf(d).FieldByName(label)
             return v.Interface(), true
    }
   return nil, false
}

Reference:

https://stackoverflow.com/questions/13856539/how-do-you-get-struct-value-on-unknown-interface

Saturday, February 10, 2018

Convert uint64 number to string

Convert uint32 string to uint64 number:

strconv.ParseUint("123", 10, 32)

Convert uint64 number to string:

strconv.FormatUint(uint64(123), 10)

ajax global default setting

(function($) {
    $(document).ready(function(){
        // ajax global default setting
        $.ajaxSetup({
            contentType: 'Content-Type: application/json',
            method: 'POST',
            dateType: 'json',
        });

        //
        let obj = {Asdf: 'asdf'};

        $.ajax({
            url: '/admin/region/request',
            data: JSON.stringify(obj),
        }).done(function(data) {
            console.log(data);
        }).fail(function(jqXHR, textStatus) {
            console.log(jqXHR.responseJSON);
        }).always(function(data) {
        });
    });
})(jQuery);

How can I get form data with JavaScript/jQuery?

How can I get form data with JavaScript/jQuery?

JQuery:

let formData = new FormData($('#RegionForm')[0]);

for (let [key, val] of formData.entries()) {
  console.log(key + ': ' + val);
}

JavaScript:

document.querySelector('form').addEventListener('submit', (e) => {
  const formData = new FormData(e.target);

  // Now you can use formData.get('foo'), for example.

  for (let pair of formData.entries()) {
    console.log(pair[0] + ', ' + pair[1]); 
  }

  // Don't forget e.preventDefault() if you want to stop normal form .submission
});

Reference:

https://stackoverflow.com/questions/2276463/how-can-i-get-form-data-with-javascript-jquery

Sunday, January 28, 2018

How to export PUTTY Sessions list?

How to export PUTTY Sessions list?

# vim backupPuttySession.bat

cmd /c "regedit /e "%USERPROFILE%\Desktop\putty-sessions.reg" HKEY_CURRENT_USER\Software\SimonTatham\PuTTY\Sessions"

Reference:

https://stackoverflow.com/questions/13023920/how-to-export-putty-sessions-list

https://stackoverflow.com/questions/16727941/how-do-i-execute-cmd-commands-through-a-batch-file

Run multiple PHP-FPM versions on the same Ubuntu server

Run multiple PHP-FPM versions on the same Ubuntu server

# vim /etc/apache2/sites-enabled/symfony.local.conf

<VirtualHost *:80>
    ServerName symfony.local

    Include "conf-available/php7.2-fpm.conf"

    ServerAdmin webmaster@localhost
    DocumentRoot /var/www/symfony.local/curr/public

    <Directory /var/www/symfony.local/curr/web>
        AllowOverride All
    </Directory>
</VirtualHost>

Saturday, January 27, 2018

Switch php versions on commandline ubuntu 16.04

Switch php versions on commandline ubuntu 16.04

# update-alternatives --set php /usr/bin/php7.1
# update-alternatives --set phar /usr/bin/phar7.1
# update-alternatives --set phar.phar /usr/bin/phar.phar7.1

Reference:

https://stackoverflow.com/questions/42619312/switch-php-versions-on-commandline-ubuntu-16-04

To increase the number in Vim

To increase the number in Vim


$arr = [
    'test 0' => 'test 0',
    'test 0' => 'test 0',
    'test 0' => 'test 0',
    'test 0' => 'test 0',
    'test 0' => 'test 0',
    'test 0' => 'test 0',
];

ctrl-v jjjjjj g ctrl-a a

Fastest way to flatten / un-flatten nested JSON objects

Fastest way to flatten / un-flatten nested JSON objects

Solution 1:

// Reference:
// https://github.com/henrytseng/dataobject-parser

/**
 * Dependencies
 */

// True if Object
function _isObject(value) {
  return typeof(value) === 'object' && value !== null;
}

// True if Array
function _isArray(value) {
  return Array.isArray(value);
}

/// True if type is string
function _isString(value) {
  return typeof(value) === 'string';
}

// True if undefined
function _isUndefined(value) {
  return typeof(value) === 'undefined';
}

// True if Number
function _isNumber(value) {
  return typeof(value) === 'number';
}

// True if Boolean
function _isBoolean(value) {
  return typeof(value) === 'boolean';
}

// True if Date object
function _isDate(value) {
  return value instanceof Date;
}

function DataObjectParser($data){
  this._data = $data || {};
}

/**
 * Given a dot deliminated string set will create an object
 * based on the structure of the string with the desired value
 *
 * @param {[String} $path  path indicating where value should be placed
 * @param {Mixed} $value   the value desired to be set at the location determined by path
 */
DataObjectParser.prototype.set = function($path, $value) {
  if(!$path || $path==='') return void 0;

  var _self = this;
  var re = /[\$\w-|]+|\[\]|([^\[[\w]\]]|["'](.*?)['"])/g;
  // parse $path on dots, and brackets
  var pathList = $path.match(re);
  var parent = this._data;
  var parentKey;
  var grandParent = null;
  var grandParentKey = null;

  var addObj = function($obj, $key, $data) {
    if($key === '[]') {
      $obj.push($data);
    } else {
      $obj[$key] = $data;
    }
  };

  while(pathList.length > 0) {
    parentKey = pathList.shift().replace(/["']/g, '');

    // Number, treat it as an array
    if (!isNaN(+parentKey) || parentKey === "[]") {
      if(!_isArray(parent)  /* prevent overwritting */ ) {
        parent = [];
        addObj(grandParent, grandParentKey, parent);
      }

    // String, treat it as a key
    } else if (_isString(parentKey)) {
      if(!_isObject(parent)) {
        parent = {};
        addObj(grandParent, grandParentKey, parent);
      }
    }
    // Next
    grandParent = parent;
    grandParentKey = parentKey;
    parent = parent[parentKey];
  }

  addObj(grandParent, grandParentKey, $value);
  return this;
};

/**
 * Returns the value defined by the path passed in
 *
 * @param  {String} $path string leading to a desired value
 * @return {Mixed}        a value in an object
 */
DataObjectParser.prototype.get = function($path) {
  var data = this._data;
  var regex = /[\$\w-|]+|\[\]|([^\[[\w]\]]|["'](.*?)['"])/g;
  //check if $path is truthy
  if (!$path) return void 0;
  //parse $path on dots and brackets
  var paths = $path.match(regex);
  //step through data object until all keys in path have been processed
  while (data !== null && paths.length > 0) {
    if(data.propertyIsEnumerable(paths[0].replace(/"/g, ''))){
      data = data[paths.shift().replace(/"/g, '')];
    }
    else{
      return undefined;
    }
  }
  return data;
};

DataObjectParser.prototype.data = function($data) {
  if(!_isUndefined($data)) {
    this._data = $data;
    return this;
  }
  return this._data;
};

/**
 * "Transposes" data; receives flat data and returns structured
 *
 * @param  {Object}           $data Structured object
 * @return {DataObjectParser} An instance of a DataObjectParser
 */
DataObjectParser.transpose = function($flat) {
  var parser = (new DataObjectParser());
  for(var n in $flat) {
    if($flat[n]!==undefined) {
      parser.set(n, $flat[n]);
    }
  }
  return parser;
};

/**
 * "Untransposes" data object; opposite of transpose
 *
 * @param  {Mixed}  $structured A Object or a DataObjectParser
 * @return {Object}             Flat object
 */
DataObjectParser.untranspose = function($structured) {
  //check to see if $structured is passed
  $structured = $structured || {};
  //handles if an object or a dataObjectParser is passed in
  var structuredData = $structured._data || $structured;

  var traverse = function($data, $isIndex) {
    var result = [];

    var createMapHandler = function($name, $data) {
      return function($item, $i) {
        var name = $name;
        //check if $name is a key of form "hello.world"
        if((/\./).test($name)) name = '["'+name+'"]';
        //add name to $item.key
        $item.key.unshift(name+".");
        //return $item.key with updated key
        return {
          key: $item.key,
          data: $item.data
        };
      };
    };

    for(var name in $data) {
      var modifiedName;
      // check if current name is an arrays index
      if($isIndex) modifiedName = "["+name+"]";
      else modifiedName = name;

      // check if current name is linked to a value
      if(_isString($data[name]) || _isNumber($data[name]) || $data[name]===null || _isBoolean($data[name]) || _isDate($data[name])) {
        if((/\./).test(name)) modifiedName = '["'+name+'"]';
        result.push({
          key: [modifiedName],
          data: $data[name]
        });
      }

      // check if current name is an array
      else if(_isArray($data[name])) {
        // tell traverse next name is an array's index
        var subArray = traverse($data[name],true);
        result = result.concat(subArray.map(createMapHandler(modifiedName, $data)));
      }

      //check if current name is an object
      else if(_isObject($data[name])) {
        var subObject = traverse($data[name],false);
        result = result.concat(subObject.map(createMapHandler(modifiedName, $data)));
      }
    }
    return result;
  };

  var flatArray = traverse(structuredData,false);
  var flatObj = {};

  flatArray.every(function($item) {
    //check for any dots followed by brackets and remove the dots
    for(var i = 0;i<$item.key.length-1;i++){
      var name = $item.key[i];
      var nextName = $item.key[i+1];
      if((/^\[/).test(nextName)){
        $item.key[i] = name.replace(/\.$/,"");
      }
    }
    //join all the keys in flatArray to form one key
    flatObj[$item.key.join("")] = $item.data;
    return true;
  });
  return flatObj;
};

var d = new DataObjectParser();

d.set("User.caravan.personel.leader","Travis");
d.set("User.caravan.personel.cook","Brent");
d.set("User.location.rooms[0]", "kitchen");
d.set("User.location.rooms[1]", "bathroom");
d.set("User.location.rowArr[0][0].Name", "Jun 00");
d.set("User.location.rowArr[0][0].Age", 19);
d.set("User.location.rowArr[0][1].Name", "Jun 01");
d.set("User.location.rowArr[0][1].Age", 20);
d.set("User.location.rowArr[1][0].Name", "Jun 10");
d.set("User.location.rowArr[1][0].Age", 21);
d.set("User.location.rowArr[1][1].Name", "Jun 11");
d.set("User.location.rowArr[1][1].Age", 22);
var obj1 = d.data();
console.log(obj1);

var flat = DataObjectParser.untranspose(obj1);
var obj2 = DataObjectParser.transpose(flat).data();

console.log(flat);
console.log(obj2);

Solution 2:

// Reference:
// https://stackoverflow.com/questions/19098797/fastest-way-to-flatten-un-flatten-nested-json-objects
// https://stackoverflow.com/questions/24833379/why-and-when-do-we-need-to-flatten-json-objects
// https://stackoverflow.com/questions/7793811/convert-javascript-dot-notation-object-to-nested-object
// https://github.com/henrytseng/dataobject-parser

function unflatten(table) {
    var result = {};

    for (var path in table) {
        var cursor = result, length = path.length, property = "", index = 0;

        while (index < length) {
            var char = path.charAt(index);

            if (char === "[") {
                var start = index + 1,
                    end = path.indexOf("]", start),
                    cursor = cursor[property] = cursor[property] || [],
                    property = path.slice(start, end),
                    index = end + 1;
            } else {
                var cursor = cursor[property] = cursor[property] || {},
                    start = char === "." ? index + 1 : index,
                    bracket = path.indexOf("[", start),
                    dot = path.indexOf(".", start);

                if (bracket < 0 && dot < 0) var end = index = length;
                else if (bracket < 0) var end = index = dot;
                else if (dot < 0) var end = index = bracket;
                else var end = index = bracket < dot ? bracket : dot;

                var property = path.slice(start, end);
            }
        }

        cursor[property] = table[path];
    }

    return result[""];
}

var flatten = (function (isArray, wrapped) {
    return function (table) {
        return reduce("", {}, table);
    };

    function reduce(path, accumulator, table) {
        if (isArray(table)) {
            var length = table.length;

            if (length) {
                var index = 0;

                while (index < length) {
                    var property = path + "[" + index + "]", item = table[index++];
                    if (wrapped(item) !== item) accumulator[property] = item;
                    else reduce(property, accumulator, item);
                }
            } else accumulator[path] = table;
        } else {
            var empty = true;

            if (path) {
                for (var property in table) {
                    var item = table[property], property = path + "." + property, empty = false;
                    if (wrapped(item) !== item) accumulator[property] = item;
                    else reduce(property, accumulator, item);
                }
            } else {
                for (var property in table) {
                    var item = table[property], empty = false;
                    if (wrapped(item) !== item) accumulator[property] = item;
                    else reduce(property, accumulator, item);
                }
            }

            if (empty) accumulator[path] = table;
        }

        return accumulator;
    }
}(Array.isArray, Object));

let obj1 = {
  "User": {
   "UserID": 999,
    "Username": "Jun",
    "IsEnabled": true,
    "PermissionArr": {
     "52": ["VIEW", "UPDATE"],
      "53": ["VIEW", "UPDATE"],
      "54": [{"Name": "View", "Status": true}, {"Name": "Create", "Status": false}],
    },
    "CreditCardArr": [
      {"Num": "12345"},
      {"Num": "6789"},
    ],
    "RowArr": [
     [{"Name": "Jun 00"}, {"Name": "Jun 01"}],
      [{"Name": "Jun 10"}, {"Name": "Jun 11"}],
    ],
  }
};

let data1 = flatten(obj1);
let obj2 = unflatten(data1);
//console.log(data1);
console.log(obj2);

Reference:

https://stackoverflow.com/questions/19098797/fastest-way-to-flatten-un-flatten-nested-json-objects

https://stackoverflow.com/questions/7793811/convert-javascript-dot-notation-object-to-nested-object

To decode a json string to an object other than stdClass

To decode a json string to an object other than stdClass

$ composer require symfony/serializer
$ composer require symfony/property-access
$ composer require symfony/property-info

<?php
require 'vendor/autoload.php';

use Symfony\Component\Serializer\Serializer;
use Symfony\Component\Serializer\Encoder\JsonEncoder;
use Symfony\Component\Serializer\Normalizer\ObjectNormalizer;
use Symfony\Component\Serializer\Normalizer\DateTimeNormalizer;
use Symfony\Component\PropertyInfo\Extractor\ReflectionExtractor;

$encoders = array(new JsonEncoder());

$normalizers = [
    new ObjectNormalizer(null, null, null, new ReflectionExtractor()),
    new DateTimeNormalizer(),
];

$serializer = new Serializer($normalizers, $encoders);

$person = new Person();
$person->setName('foo');
$person->setAge(99);
$person->setSportsman(false);

$jsonContent = $serializer->serialize($person, 'json');

$person2 = $serializer->deserialize($jsonContent, Person::class, 'json');

echo $jsonContent . PHP_EOL;

echo $person2->getName() . PHP_EOL;

// $jsonContent contains {"name":"foo","age":99,"sportsman":false}
//
// echo $jsonContent; // or return it in a Response

class Person
{
    private $age;
    private $name;
    private $sportsman;

    // Getters
    public function getName()
    {
        return $this->name;
    }

    public function getAge()
    {
        return $this->age;
    }

    // Issers
    public function isSportsman()
    {
        return $this->sportsman;
    }

    // Setters
    public function setName($name)
    {
        $this->name = $name;
    }

    public function setAge($age)
    {
        $this->age = $age;
    }

    public function setSportsman($sportsman)
    {
        $this->sportsman = $sportsman;
    }
}

Reference:

https://stackoverflow.com/questions/5397758/json-decode-to-custom-class

https://symfony.com/doc/current/components/serializer.html

In vim, how do I highlight TODO: and FIXME:?

In vim, how do I highlight TODO: and FIXME:?

$ ~/.vimrc

syntax on

augroup vimrc_jun_todo
        au!
        au Syntax * syn match JunTodo /\v<(FIXME|NOTE|TODO|OPTIMIZE):/ containedin=.*Comment,vimCommentTitle
augroup END
hi def link JunTodo Todo

Reference:

https://stackoverflow.com/questions/4097259/in-vim-how-do-i-highlight-todo-and-fixme

Github changes repository to wrong language

Github changes repository to wrong language

# vim .gitattributes

*.php linguist-vendored

Reference:

https://stackoverflow.com/questions/34713765/github-changes-repository-to-wrong-language/34715182

how to exclude css files from eslint parser

how to exclude css files from eslint parser

# vim .eslintignore

*.css

Reference:

https://stackoverflow.com/questions/43626296/how-to-exclude-css-files-from-eslint-parser-in-react