Simple life, Complicated mind

Monday, August 22, 2016

CentOS and RHEL 7: Install Linux, Apache MPM, MariaDB, PHP (LAMP) Stack

CentOS and RHEL 7: Install Linux, Apache MPM, MariaDB, PHP (LAMP) Stack

Check CentOS version:

# cat /etc/redhat-release

CentOS Linux release 7.1.1503 (Core)

Set up Network:

# ip addr

2: eno16777736: <broadcast> mtu 1500 qdisc pfifo_fast state UP qlen 1000

# vi /etc/sysconfig/network-scripts/ifcfg-eno16777736

BOOTPROTO=none

IPADDR=192.168.6.9
PREFIX=24
GATEWAY=192.168.6.1
DNS1=8.8.8.8
DNS2=8.8.4.4

PEERDNS=yes
ONBOOT=yes
USERCTL=no

Note: USERCTL=no // Non-root users are not allowed to control this device.

# systemctl restart network

# ip addr

# /bin/ipcalc --netmask 192.168.6.9/24

NETMASK=255.255.255.0

# cat /etc/resolv.conf

Change hostname:

# hostnamectl status

# hostnamectl set-hostname cent-dev.local

# hostnamectl status

# cat /etc/hostname

If you are using Amazon's AWS EC2 instance, append the following string at the bottom of the file to ensure that the hostname is preserved between restarts/reboots:

# vim /etc/cloud/cloud.cfg

preserve_hostname: true

More info: https://aws.amazon.com/premiumsupport/knowledge-center/linux-static-hostname-rhel7-centos7/

Set up timezone:

# timedatectl
# timedatectl list-timezones
# timedatectl set-timezone America/Vancouver
# timedatectl

Set up date and time:

# date +%Y%m%d -s "20081128"
# date +%T -s "10:13:13"

To sync date and time automatically:

# yum -y update

# yum -y install ntp

# ntpdate 0.us.pool.ntp.org

Note: ntpdate is deprecated as of September 2012

You can change which ntp server to use:

# vi /etc/ntp.conf

Set ntpd to start up on boot time:

# systemctl enable ntpd.service
# systemctl restart ntpd.service

# ps auxww|grep -i ntpd
# ntpstat
# timedatectl

Set the Hardware Clock to the current System Time:

# hwclock --systohc

Note: hwclock is a utility for accessing the hardware clock. Hardware clock is independent of the operation system you use and works even when the machine is shut down. This program is used to find out the time from the hardware clock and set the system time at boot time.

Update the ~/.bashrc configuration:

# vi ~/.bashrc

### alias
alias rm='rm -i'
alias cp='cp -i'
alias mv='mv -i'

alias gs='git status'
alias gc='git commit -a -m "up"'
alias gp='git push'
alias gpp='git pull'

alias ls='ls --color=auto'
alias ll='ls -la'
alias h='history'

### ls with color (try "ls --color=auto").
#export CLICOLOR=1 # Use colors (if possible)
#export LSCOLORS="ExGxFxdxCxDxDxBxBxExEx"

### set up a clean UTF-8 environment
### run: locale command
export LC_ALL=en_US.UTF-8
export LANG=en_US.UTF-8
export LANGUAGE=en_US.UTF-8

### display history command with date and time
export HISTTIMEFORMAT="%m/%d/%y %T "

### Prompt
PS1='\[\e[0;32m\]\u@\h \w \$\[\e[0m\] '

#######
# Note: on Ubuntu, xterm-256color may be in different place, try this:
# find /lib/terminfo /usr/share/terminfo -name "*256*"
# Note: tmux respects screen-256color
#######
if [ -e /usr/share/terminfo/x/xterm-256color ]; then
  export TERM='xterm-256color'
else
  export TERM='xterm-color'
fi

### Make bash check its window size after a process completes
shopt -s checkwinsize

# Source global definitions
if [ -f /etc/bashrc ]; then
  . /etc/bashrc
fi

# source ~/.bashrc

Update the ~/.inputrc configuration:

# vi ~/.inputrc

### enable filename tab auto-completion
set show-all-if-ambiguous on
set show-all-if-unmodified on

### if you don't want case-sensitivity
#set completion-ignore-case on

### bash history completion to complete what's already on the line
### arrow up
"\e[A": history-search-backward
### arrow down
"\e[B": history-search-forward

Make sure there is a swap space on your system:

# cat /proc/meminfo | grep -i swap

SwapCached:           36 kB
SwapTotal:       2097148 kB
SwapFree:        2095160 kB

Note: if your system does not have the swap space, please refer to http://blog.ijun.org/2015/04/add-swap-to-amazon-ec2-instance-ebs.html for more information.

Install EPEL and additional repositories on CentOS and Red Hat:

# yum -y install wget
# yum -y install epel-release

http://blog.ijun.org/2014/11/install-epel-and-additional.html
https://fedoraproject.org/wiki/EPEL

Subscribing to the IUS Community Project Repository:

# curl 'https://setup.ius.io/' -o setup-ius.sh
# bash setup-ius.sh

# ls -l /etc/yum.repos.d/ius*

-rw-r--r--. 1 root root 1150 Apr 16  2015 /etc/yum.repos.d/ius-archive.repo
-rw-r--r--. 1 root root 1131 Apr 16  2015 /etc/yum.repos.d/ius-dev.repo
-rw-r--r--. 1 root root 1073 Apr 16  2015 /etc/yum.repos.d/ius.repo
-rw-r--r--. 1 root root 1150 Apr 16  2015 /etc/yum.repos.d/ius-testing.repo

To find which package provides the ifconfig command:

# yum provides ifconfig

To get the ifconfig command into our system:

# yum -y install net-tools

# ifconfig | awk '/inet /{print $2}'

Install tmux:
# yum -y install tmux

# vi ~/.tmux.conf

# tmux
or
# tmux a -d

Install vim-enhanced:

# vim --version
-syntax
-python

# yum -y install vim-enhanced

# vim --version
+syntax
+python

# yum list installed | grep -i vim
# yum info vim-enhanced

Install tree:

# yum -y install tree

Install fortune game:

# yum -y install fortune-mod.x86_64

Install Glances:

# yum -y install glances

Install Git:

# yum -y install git

Install NetCat:

# yum -y install nmap-ncat
# nc localhost 8080

Install firewalld:

# yum -y install firewalld

(optional)
# yum install firewall-config

Note: If you don't mind using a GUI you could use firewall-config instead. If you need something for the console you will have to use firewall-cmd instead.

# systemctl enable firewalld

# systemctl restart firewalld

Install MariaDB:

# yum install mariadb-server

Setting UTF8 defaults for MySQL:

We recommend against MySQL's utf8 character set, since it does not support 4-byte unicode characters, and strings containing them will be truncated. This is fixed by the newer utf8mb4 character set.

# vim /etc/my.cnf

[mysqld]
# Version 5.5.3 introduced "utf8mb4", which is recommended
collation-server = utf8mb4_general_ci # Replaces utf8_general_ci
character-set-server = utf8mb4 # Replaces utf8

default-storage-engine = InnoDB

max_allowed_packet = 16M

# This option makes InnoDB to store each created table into its own .ibd file.
innodb_file_per_table

# Don't resolve hostnames. All hostnames are IP's or 'localhost'.
skip-name-resolve

#The number of simultaneous clients allowed.
max_connections = 200

# uncomment to disable the InnoDB storage engine
#skip-innodb

innodb_buffer_pool_size = 4G
innodb_additional_mem_pool_size = 16M
innodb_log_file_size = 256M
innodb_log_buffer_size = 8M

# systemctl enable mariadb.service

# systemctl restart mariadb.service

# systemctl is-active mariadb.service

# /usr/bin/mysql_secure_installation

# mysql -u root -p

mysql> GRANT ALL PRIVILEGES ON *.* TO 'test'@'192.168.0.%' IDENTIFIED BY '123456';
mysql> FLUSH PRIVILEGES;

mysql> CREATE DATABASE mydb DEFAULT CHARACTER SET utf8 DEFAULT COLLATE utf8_general_ci;

Set up .my.cnf configuration file:

# touch ~/.my.cnf
# chmod 600 ~/.my.cnf
# vim ~/.my.cnf

[client]
host = localhost
port = 3306
user = root
password = MyPassword

Add New Rule to firewalld to allow access to MySQL:

# firewall-cmd --permanent --zone=trusted --add-source=192.168.0.1/32
# firewall-cmd --permanent --zone=trusted --add-port=3306/tcp
# firewall-cmd --reload
# firewall-cmd --zone=trusted --list-all

or

# systemctl restart firewalld.service

Check out the zone file to inspect the XML configuration:

# cat /etc/firewalld/zones/public.xml
# cat /etc/firewalld/zones/trusted.xml

Install Apache:

# yum install httpd mod_ssl

# systemctl status httpd

● httpd.service - The Apache HTTP Server
   Loaded: loaded (/usr/lib/systemd/system/httpd.service; disabled; vendor preset: disabled)

Note: it will tell you if the service starts on boot.

# systemctl enable httpd.service

# systemctl restart httpd.service

# systemctl reload httpd.service

# systemctl -l status httpd.service

# journalctl -xn

# systemctl is-active httpd.service

# apachectl configtest

# httpd -V

# apachectl graceful

httpd service default configuration files:

  • Default config file: /etc/httpd/conf/httpd.conf
  • Configuration files which load modules : /etc/httpd/conf.modules.d/ directory (e.g. PHP)
  • Select MPMs (Processing Model) as loadable modules [worker, prefork (default)] and event: /etc/httpd/conf.modules.d/00-mpm.conf
  • Default ports: 80 and 443 (SSL)
  • Default log files: /var/log/httpd/{access_log,error_log}

Set up a symbolic link:

# cd / ; ln -s var/www/html www

Install PHP:

# yum install php php-mysqlnd php-fpm php-gd php-mbstring php-pdo php-xml php-soap
# yum install php-pear php-devel pcre-devel gcc gcc-c++ make

# systemctl restart httpd.service

Note: you need php-devel pcre-devel gcc make for PHP APC. Try to add httpd-devel if failed.

You need the php-mcrypt to run Magento:

# yum install php-mcrypt

http://blog.ijun.org/2014/11/how-to-install-php-mcrypt-on-centos-7.html

Open port 80 firewall access:

# firewall-cmd --zone=public --add-port=http/tcp
# firewall-cmd --zone=public --add-port=https/tcp

# firewall-cmd --permanent --zone=public --add-port=http/tcp
# firewall-cmd --permanent --zone=public --add-port=https/tcp

# firewall-cmd --reload
or
# systemctl restart firewalld.service

# firewall-cmd --zone=public --list-all

Allow a IP address with a specific port:

# firewall-cmd --zone=public --add-rich-rule='rule family="ipv4" source address="1.2.3.4" port protocol="tcp" port="3306" accept'

To remove the rule:

# firewall-cmd --zone=public --remove-rich-rule='rule family="ipv4" source address="1.2.3.4" port protocol="tcp" port="3306" accept'

Block a IP address:

# firewall-cmd --zone=public --add-rich-rule='rule family="ipv4" source address="1.2.3.4" reject'

To remove the rule:

# firewall-cmd --zone=public --remove-rich-rule='rule family="ipv4" source address="1.2.3.4" reject'

If you get 403 forbidden error, then you probably have problem with SELinux, to deal with Security-Enhanced Linux (SELinux):

# namei -l /var/www/html/magento19

# ls -dZ /var/www/html
drwxr-xr-x. root root system_u:object_r:httpd_sys_content_t:s0 /var/www/html

# chcon -R --reference=/var/www/html /var/www/html/magento19
Or
# chcon -R --type=httpd_sys_content_t /var/www/html/magento19
Or for read and write permission:
# chcon -R -t httpd_sys_rw_content_t /var/www/html/magento19/app/etc

# ps auxwwZ | grep httpd
# ls -dZ /var/www/html/magento19/app/etc
# tail /var/log/audit/audit.log
# tail /var/log/messages

To turn off Security-Enhanced Linux (SELinux):

# setenforce 0

To turn on Security-Enhanced Linux (SELinux):

# setenforce 1

To get the status of a system running SELinux:

# sestatus

Set up Apache MPM and PHP-FPM:

With Apache 2.4, the official module to use is mod_proxy_fcgi instead of the ancient mod_fastcgi. That module, as well as mod_fcgid, were third party modules.

Note: mod_proxy_fcgi now supports network sockets since Apache 2.4.9 ( Unix socket support for mod_proxy_fcgi )

List built-in or shared modules:

# httpd -M | grep -iE 'proxy_module|proxy_fcgi_module|rewrite_module|mpm_event_module|deflate_module|vhost_alias_module|ssl_module'

 deflate_module (shared)
 rewrite_module (shared)
 vhost_alias_module (shared)
 mpm_event_module (shared)
 proxy_module (shared)
 proxy_fcgi_module (shared)
 ssl_module (shared)

List loaded modules:

# httpd -t -D DUMP_MODULES | grep -iE 'proxy_module|proxy_fcgi_module|rewrite_module|mpm_event_module|deflate_module|vhost_alias_module|ssl_module'

 deflate_module (shared)
 rewrite_module (shared)
 vhost_alias_module (shared)
 mpm_event_module (shared)
 proxy_module (shared)
 proxy_fcgi_module (shared)
 ssl_module (shared)

Edit mpm.conf:

# vim /etc/httpd/conf.modules.d/00-mpm.conf

Comment out the following line:

LoadModule mpm_prefork_module modules/mod_mpm_prefork.so

Uncomment the following line:

LoadModule mpm_event_module modules/mod_mpm_event.so

Make sure the following two lines exist:

# grep -E 'mod_proxy.so|mod_proxy_fcgi' /etc/httpd/conf.modules.d/00-proxy.conf

LoadModule proxy_module modules/mod_proxy.so
LoadModule proxy_fcgi_module modules/mod_proxy_fcgi.so

Add the "if checking" surround the following three lines:

# vim /etc/httpd/conf.d/php.conf

<IfModule mod_php5.c>
  <FilesMatch \.php$>
    SetHandler application/x-httpd-php
  </FilesMatch>
</IfModule>

Add the "if checking" surround the following two lines:

# vim /etc/httpd/conf.d/php.conf

<IfModule mod_php5.c>
  php_value session.save_handler "files"
  php_value session.save_path    "/var/lib/php/session"
</IfModule>

Change the following line:

# vim /etc/httpd/conf/httpd.conf

<Directory "/var/www/html">
  AllowOverride All

  # New directive needed in Apache 2.4.3: 
  Require all granted
</Directory>

Create and Edit the vhosts file:

# vim /etc/httpd/conf.d/httpd-vhosts.conf

#
# Use name-based virtual hosting.
#
NameVirtualHost *:80

#
# VirtualHost example:
# Almost any Apache directive may go into a VirtualHost container.
# The first VirtualHost section is used for all requests that do not
# match a ServerName or ServerAlias in any <VirtualHost> block.
#
<VirtualHost *:80>
    ServerAdmin webmaster@dummy-host.example.com
    DocumentRoot "/var/www/html/host_not_found"
    ErrorLog "/var/log/httpd/host_not_found-error_log"
    CustomLog "/var/log/httpd/host_not_found-access_log" common
</VirtualHost>

<VirtualHost *:80>
    ServerAdmin webmaster@dummy-host.example.com
    DocumentRoot "/var/www/html/magento1.9.1"
    ServerName us.centos.local

    ### Disable PHP script execution for this directory. We don't want to reverse-proxy this subdirectory.
    <Location "/var">
      ProxyPass !
    </Location>

    ### Disable PHP script execution for this directory. We don't want to reverse-proxy this subdirectory.
    <Location "/media">
      ProxyPass !
    </Location>

    ProxyPassMatch ^/(.*\.php(/.*)?)$ fcgi://127.0.0.1:9000/var/www/html/magento1.9.1/$1

    SetEnv MAGE_RUN_CODE "us_centos_local"
    SetEnv MAGE_RUN_TYPE "website"

    ### a request for / will need to be mapped to a resource on the fcgi backend. Failure to address this may cause a blank response, commonly known as a WSOD (White Screen of Death), especially if only a request URI containing the php extension is proxied, such as this example. The processing chain will first map a request for / to /index.php, then proxy to the PHP-FPM backend correctly.
    DirectoryIndex /index.php index.php index.html index.htm

    ErrorLog "/var/log/httpd/us.centos.local-error_log"
    CustomLog "/var/log/httpd/us.centos.local-access_log" common
</VirtualHost>

Setting up an SSL secured Web server:

<VirtualHost *:443>
    SSLEngine on
    SSLCertificateFile /etc/pki/tls/certs/mydomain.com.crt
    SSLCertificateKeyFile /etc/pki/tls/private/mydomain.com.key
    SSLCertificateChainFile /etc/pki/tls/certs/gd_bundle-mydomain.com.crt

    ServerAdmin webmaster@dummy-host.example.com
    DocumentRoot "/var/www/html/magento1.9.1"
    ServerName us.centos.local

    ### we don't want to reverse-proxy this subdirectory.
    <Location "/var">
      ProxyPass !
    </Location>

    ### we don't want to reverse-proxy this subdirectory.
    <Location "/media">
      ProxyPass !
    </Location>

    ProxyPassMatch ^/(.*\.php(/.*)?)$ fcgi://127.0.0.1:9000/var/www/html/magento1.9.1/$1

    SetEnv MAGE_RUN_CODE "us_centos_local"
    SetEnv MAGE_RUN_TYPE "website"

    ErrorLog "/var/log/httpd/us.centos.local443-error_log"
    CustomLog "/var/log/httpd/us.centos.local443-access_log" common
</VirtualHost>

Make sure the security context of the certification files are cert_t:

# cd /etc/pki/tls/certs/mydomain.com
# chcon -t cert_t *

If you do not see the correct security context, you will see the following message when restarting Apache:

Mar 16 23:58:00 ip-172-31-21-55 httpd[22680]: AH00526: Syntax error on line 19 of /etc/httpd/conf.d/httpd-vhosts.conf:
Mar 16 23:58:00 ip-172-31-21-55 httpd[22680]: SSLCertificateFile: file '/etc/pki/tls/certs/mydomain.com/b1210d10x4d812c5.crt' does not exist or is empty
Mar 16 23:58:00 ip-172-31-21-55 systemd[1]: httpd.service: main process exited, code=exited, status=1/FAILURE
Mar 16 23:58:00 ip-172-31-21-55 systemd[1]: Failed to start The Apache HTTP Server.
Mar 16 23:58:00 ip-172-31-21-55 systemd[1]: Unit httpd.service entered failed state.
Mar 16 23:58:00 ip-172-31-21-55 systemd[1]: httpd.service failed.

Restart Apache:

# systemctl reload httpd.service

# httpd -t -D DUMP_VHOSTS

To enable gzip compression:

# egrep 'deflate|header' /etc/httpd/conf.modules.d/00-base.conf

LoadModule deflate_module modules/mod_deflate.so
LoadModule headers_module modules/mod_headers.so

# httpd -t -D DUMP_MODULES | grep deflate

deflate_module (shared)

# vim /etc/httpd/conf.d/mod_deflate.conf

<IfModule mod_deflate.c>
  AddOutputFilterByType DEFLATE text/html text/plain text/xml text/css text/js application/javascript application/x-javascript application/x-httpd-php
</IfModule>

# systemctl restart httpd.service

Install Xdebug for debugging PHP:

# pecl install Xdebug

# vim /etc/php.d/xdebug.ini

zend_extension="/usr/lib64/php/modules/xdebug.so"

; When this setting is set to on, the tracing of function calls will be enabled just before the script is run. This makes it possible to trace code in the auto_prepend_file.
xdebug.auto_trace = 1
xdebug.trace_output_dir = "/tmp"
xdebug.collect_params = 4

; Enables Xdebug's profiler which creates files in the profile output directory. Those files can be read by KCacheGrind to visualize your data.
xdebug.profiler_enable = 1
xdebug.profiler_output_dir = "/tmp"

; Controls the protection mechanism for infinite recursion protection. The value of this setting is the maximum level of nested functions that are allowed before the script will be aborted.
xdebug.max_nesting_level = 100

; shows a human readable / computer readable trace file.
xdebug.trace_format = 0

; This setting tells Xdebug to gather information about which variables are used in a certain scope. This analysis can be quite slow as Xdebug has to reverse engineer PHP's opcode arrays. This setting will not record which values the different variables have, for that use xdebug.collect_params. This setting needs to be enabled only if you wish to use xdebug_get_declared_vars().
xdebug.collect_vars = 0

; When set to '1' the trace files will be appended to, instead of being overwritten in subsequent requests.
; Note: this option can be useful if you could not find your function calls anywhere.
xdebug.trace_options = 1

To search all other php modules:

# yum search php

Edit php.ini:

# vim /etc/php.ini

cgi.fix_pathinfo = 0

The default value is 1, which is an extremely insecure setting because it tells PHP to attempt to execute the closest file it can find if a PHP file does not match exactly. This basically would allow users to craft PHP requests in a way that would allow them to execute scripts that they shouldn't be allowed to execute.

Note: if I set it to "cgi.fix_pathinfo = 0", I would get "Access denied (403)" (see security.limit_extensions) or no input file specified error when setting up Magento. You can either:

1. commented out the cgi.fix_pathinfo = 0 line.
2. set cgi.fix_pathinfo = 1
3. try to set "security.limit_extensions = " in the /etc/php-fpm.d/www.conf file.

http://stackoverflow.com/questions/23390531/access-denied-403-for-php-files-with-nginx-php-fpm
http://serverfault.com/questions/627903/is-the-php-option-cgi-fix-pathinfo-really-dangerous-with-nginx-php-fpm

display_errors = On
log_errors = On
error_log = /var/log/php_errors.log

Note: make sure you do:

# touch /var/log/php_errors.log
# chmod 660 /var/log/php_errors.log
# chown root:apache /var/log/php_errors.log

# chcon -t httpd_log_t /var/log/php_errors.log
Or
# chcon -u system_u -t httpd_log_t /var/log/php_errors.log

Install XCache:

XCache is a fast, stable ​PHP opcode cacher that has been proven and is now running on production servers under high load. It is tested (on linux) and supported on all of the latest ​PHP release branches such as PHP_5_1 PHP_5_2 PHP_5_3 PHP_5_4 PHP_5_5. It is more stable than APC.

Warning: APC would cause segfault segmentation fault. Use XCache instead.

# yum install php-xcache xcache-admin

# systemctl restart httpd
# systemctl restart php-fpm
# php -v

PHP 5.4.16 (cli) (built: Oct 31 2014 12:59:36)
Copyright (c) 1997-2013 The PHP Group
Zend Engine v2.4.0, Copyright (c) 1998-2013 Zend Technologies
    with XCache v3.1.1, Copyright (c) 2005-2014, by mOo
    with XCache Optimizer v3.1.1, Copyright (c) 2005-2014, by mOo
    with XCache Cacher v3.1.1, Copyright (c) 2005-2014, by mOo
    with XCache Coverager v3.1.1, Copyright (c) 2005-2014, by mOo

# echo -n "Your Password" | md5sum

5afd8756ebeda48acf7eb645503dae60

# vim /etc/php.d/xcache.ini

[xcache]

xcache.admin.user = "admin name"
xcache.admin.pass = "5afd8756ebeda48acf7eb645503dae60"

xcache.size = 60M

; This number divides total cache size into threads in order to increase the efficiency. If you have 128M xcache.size and you set the count as 4, that means each thread will manage 32M size of cache.
xcache.count = 1

xcache.cacher = On
xcache.stat = On
xcache.optimizer = On

# cp -r /usr/share/xcache/ /var/www/html/

# systemctl restart php-fpm

http://localhost/xcache/

Install APC:

Warning: APC would cause segfault segmentation fault. Use XCache instead.

# pecl install apc

# vim /etc/php.d/apc.ini

; Enable APC for PHP
extension=apc.so
apc.enabled=1

; The number of seconds a cache entry is allowed to idle in a slot before APC dumps the cache
apc.ttl=72000
apc.user_ttl=72000
apc.gc_ttl=3600

; Size of memory for apc ( 1024 M)
apc.shm_size=1024M

; Enable apc stats.
apc.stat=1

; Enable APC for command line php operations.
apc.enable_cli=1

; Allow 2 seconds after a file is created before it is cached. This will prevent premature PHP pages to get cached.
apc.file_update_protection=2

; Maximum size of single file that apc can store.
apc.max_file_size=1M

; Maximum number of files APC can store ( rotation).
apc.num_files_hint=200000

; Maximum number of users data entries that APC can store.
apc.user_entries_hint=20000

Copy the apc.php file:

# cp /usr/share/pear/apc.php /var/www/html

Set up php-fpm:

Apach 2.4.8 mod_proxy: Added support for unix domain sockets as the backend server endpoint.

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

If you are using Apach 2.4.8 or above, please change the following line from:

listen = 127.0.0.1:9000

To:

listen = /var/run/php-fpm/php-fpm.sock

Now, there are different ways to actually forward requests for .php files to this module, ranging from everything (using ProxyPass) to very specific or rewritten files or patterns (using mod_rewrite with the [P] flag).

The method I chose (using ProxyPassMatch) lies somewhere in between these in complexity and flexibility, since it allows you to set one rule for all PHP content of a specific vhost, but will only proxy .php files (or URLs that contain the text .php somewhere in the request).

TCP socket (IP and port) approach

Edit the configuration for a vhost of your choice, and add the following line to it:

# vim /etc/httpd/conf.d/httpd-vhosts.conf

ProxyPassMatch ^/(.*\.php(/.*)?)$ fcgi://127.0.0.1:9000/path/to/your/documentroot/$1

### a request for / will need to be mapped to a resource on the fcgi backend. Failure to address this may cause a blank response, commonly known as a WSOD (White Screen of Death), especially if only a request URI containing the php extension is proxied, such as this example. The processing chain will first map a request for / to /index.php, then proxy to the PHP-FPM backend correctly.
    DirectoryIndex /index.php index.php index.html index.htm

Note: please do change /path/to/your/documentroot to for example /var/www/html/drupal8

Look confusing ? Let's run through it:

ProxyPassMatch

only proxy content that matches the specified regex pattern; in this case:

^/(.*\.php(/.*)?)$

from the documentroot onwards, match everything ending in .php (with the dot escaped), optionally followed by a slash and any continued path you like (some applications use this so-called PathInfo to pass arguments to the php script.)

The ^ (caret) and $ (dollar) signs are used to anchor both the absolute start and end of the URL, to make sure no characters from the request escape our pattern match.

The nested parentheses enable us to refer to the entire request-URI (minus the leading slash) as $1, while still keeping the trailing pathinfo optional.

fcgi://127.0.0.1:9000

forward via mod_proxy_fcgi, using the fastCGI protocol, to the port our php-fpm daemon is listening on.

This determines which fastcgi pool will serve requests proxied by this rule.

/path/to/your/documentroot/

IMPORTANT! This must exactly match the real filesystem location of your php files, because that is where the php-fpm daemon will look for them.

php-fpm just interprets the php files passed to it; it is not a web server, nor does it understand your web servers' namespace, virtualhost layout, or aliases.

IMPORTANT! Read the above again

$1

expands to the entire request-URI from the original request, minus the leading slash (because we already added that above.)

DirectoryIndex /index.php index.php index.html index.htm

Note: a request for / will need to be mapped to a resource on the fcgi backend. Failure to address this may cause a blank response, commonly known as a WSOD (White Screen of Death), especially if only a request URI containing the php extension is proxied, such as this example. The processing chain will first map a request for / to /index.php, then proxy to the PHP-FPM backend correctly.

unix domain socket (UDS) approach

Edit the configuration for a vhost of your choice, and add the following line to it:

# vim /etc/httpd/conf.d/httpd-vhosts.conf

ProxyPassMatch ^/(.*\.php(/.*)?)$ unix:/path/to/socket.sock|fcgi://127.0.0.1:9000/path/to/your/documentroot/

unix:/path/to/socket.sock

the path to your fpm socket

Note that with this approach, the captured request URI ($1) is not passed after the path

Enable php-fpm to start on boot:

# systemctl enable php-fpm.service

Start our PHP processor:

# systemctl restart php-fpm.service
# systemctl restart httpd.service

Test PHP:

# php -r "echo 'hi';";

Check the PHP-FPM setting:

<?php
echo phpinfo();
?>

You should see the message: Server API: FPM/FastCGI

# httpd -V

Server MPM:     event

To create a locked user account:

# useradd dev -m -c 'git user'

Unlock the account by issuing the passwd command to assign a password and set password aging guidelines:

# passwd dev

Add a new group called web:

# groupadd web

Add the dev user to the web group:

# usermod -a -G web dev

Show The Groups a User Is In:

# groups dev
# id -Gn dev

Find out the primary group of a user:

# getent group dev

To allow Apache to connect network and sendmail send email:

# setsebool -P httpd_can_network_connect 1
# setsebool -P httpd_can_sendmail 1

Note: -P in the above command means Persistent (across reboots)

# getsebool -a | grep -i httpd_can

httpd_can_network_connect --> on
httpd_can_sendmail --> on

# sestatus -b | grep httpd_can

httpd_can_network_connect                   on
httpd_can_sendmail                          on

Install Memcached:

# yum install memcached
# yum install php-pecl-memcached

# systemctl enable memcached.service
# systemctl restart memcached.service

# memcached-tool localhost:11211 display
# memcached-tool localhost:11211 stats
# memcached-tool localhost:11211 dump

Install redis server:

# yum install redis
# yum install php-pecl-redis

Two important redis server configuration files:

# less /etc/redis.conf
# less /etc/redis-sentinel.conf

Start the Redis server:

# systemctl start redis.service

Check the running status of Redis server:

# systemctl status redis.service

To test the installation of Redis:

# redis-cli ping

PONG

To enable Redis server at system's booting time:

# systemctl enable redis.service

To get the listening port 6379 of Redis server:

# ss -nlp | grep redis

To install Redis PHP extension:

# pecl install redis

Add the following line to /etc/php.d/redis.ini:

# echo 'extension=redis.so' >> /etc/php.d/redis.ini

Check to see if Redis PHP extension is installed:

# pecl list | grep redis

redis   2.2.7   stable

Restart Apache and PHP-FPM:

# systemctl restart httpd.service
# systemctl restart php-fpm.service

To see if Redis extension is being loaded by PHP:

# php -m | grep redis

To allow Apache to connect to the Redis server:

# setsebool -P httpd_can_network_connect 1

Note: If you have turned on Security-Enhanced Linux (SELinux), httpd scripts by default are not allowed to connect out to the network.

To list all Redis Databases:

# redis-cli info keyspace

To clear remove delete all data from a particular Redis database:

# redis-cli

127.0.0.1:6379> info keyspace
127.0.0.1:6379> select 0
127.0.0.1:6379> keys *
127.0.0.1:6379> flushdb
127.0.0.1:6379> keys *

To clear remove delete all data from all Redis database:

# redis-cli flushall

Dumping all key/value pairs in a Redis db:

# redis-cli -n 0 keys \*

# redis-cli -n 0 keys \* | xargs -n 1 redis-cli dump

Note: the 0 is the database number.

To store PHP sessions in Redis:

Storing PHP session files in RAM can be much more efficient than storing on disk and can also save some IO. To configure this, you should modify the main php.ini file and change session.save_handler to redis.

# vim /etc/php.ini

session.save_handler = redis

session.save_path = "tcp://127.0.0.1:6379"

# systemctl restart php-fpm

# php -r 'echo phpinfo();' | grep redis

Registered save handlers => files user redis
session.save_handler => redis => redis

# vim test.php

<?php
session_start();

$_SESSION['favcolor'] = 'green';

echo '<pre>' . print_r($_SESSION, TRUE) . '</pre>';
?>

# php test.php

# redis-cli info keyspace
# Keyspace
db0:keys=68,expires=39,avg_ttl=2977110
db2:keys=427,expires=427,avg_ttl=1856886

# redis-cli -n 0 keys \*| grep -i session

PHPREDIS_SESSION:vhauaf8qpdj146kirsbivrh4i7

Note: the 0 is the database number.

Redis setup hints

  • We suggest deploying Redis using the Linux operating system. Redis is also tested heavily on osx, and tested from time to time on FreeBSD and OpenBSD systems. However Linux is where we do all the major stress testing, and where most production deployments are working.
  • Make sure to set the Linux kernel overcommit memory setting to 1. Add vm.overcommit_memory = 1 to /etc/sysctl.conf and then reboot or run the command sysctl vm.overcommit_memory=1 for this to take effect immediately.
  • Make sure to disable Linux kernel feature transparent huge pages, it will affect greatly both memory usage and latency in a negative way. This is accomplished with the following command: echo never > sys/kernel/mm/transparent_hugepage/enabled.
  • Make sure to setup some swap in your system (we suggest as much as swap as memory). If Linux does not have swap and your Redis instance accidentally consumes too much memory, either Redis will crash for out of memory or the Linux kernel OOM killer will kill the Redis process.
  • Set an explicit maxmemory option limit in your instance in order to make sure that the instance will report errors instead of failing when the system memory limit is near to be reached.
  • If you are using Redis in a very write-heavy application, while saving an RDB file on disk or rewriting the AOF log Redis may use up to 2 times the memory normally used. The additional memory used is proportional to the number of memory pages modified by writes during the saving process, so it is often proportional to the number of keys (or aggregate types items) touched during this time. Make sure to size your memory accordingly.
  • Use daemonize no when run under daemontools.
  • Even if you have persistence disabled, Redis will need to perform RDB saves if you use replication, unless you use the new diskless replication feature, which is currently experimental.
  • If you are using replication, make sure that either your master has persistence enabled, or that it does not automatically restarts on crashes: slaves will try to be an exact copy of the master, so if a master restarts with an empty data set, slaves will be wiped as well.

Running Redis on EC2

  • Use HVM based instances, not PV based instances.
  • Don't use old instances families, for example: use m3.medium with HVM instead of m1.medium with PV.
  • The use of Redis persistence with EC2 EBS volumes needs to be handled with care since sometimes EBS volumes have high latency characteristics.
  • You may want to try the new diskless replication (currently experimetnal) if you have issues when slaves are synchronizing with the master.

Reference:

http://blog.ijun.org/2014_04_01_archive.html
http://blog.ijun.org/2014/11/configuring-magento-to-use-redis.html
http://blog.ijun.org/2014/12/install-apache-24-php-56-and-mysql-56.html
http://redis.io/topics/admin
http://www.cyberciti.biz/faq/howto-install-linux-apache-mariadb-php-lamp-stack-on-centos7-rhel7/
http://serverfault.com/questions/629937/centos-7-apache2-httpd-mod-fastcgi-installation-impossible
http://blog.famillecollet.com/post/2014/08/01/Apache-httpd-server-2.4.10-and-PHP-FPM-5.6-in-Fedora-21
https://wiki.apache.org/httpd/PHP-FPM
http://sharadchhetri.com/2014/10/04/install-redis-server-centos-7-rhel-7/
https://access.redhat.com/documentation/en-US/Red_Hat_Enterprise_Linux/6/html/Deployment_Guide/s1-networkscripts-interfaces.html
http://technovergence-en.blogspot.ca/2012/03/mysql-from-utf8-to-utf8mb4.html

How to prevent or disable favicon.ico requests?

How to prevent or disable favicon.ico requests?

The following uses data URI and can be used to avoid fake favicon requests:

<link rel="shortcut icon" href="data:image/x-icon;," type="image/x-icon"> 

Reference:

http://stackoverflow.com/questions/1321878/how-to-prevent-favicon-ico-requests

Friday, August 12, 2016

C# .Net monitor directory file changed created

What does Dropbox use to monitor file changes in the Dropbox folder?

Native Windows applications track directory changes by using the FindFirstChangeNotification / FindNextChangeNotification functions.

https://www.quora.com/What-does-Dropbox-use-to-monitor-file-changes-in-the-Dropbox-folder

As name suggests FileSystemWatcher watches the Directory or Files for any modification. FileSystemWatcher is a class in .Net derived fromSystem.IO namespace that continuously monitors a specified Directory for file system changes. As soon as the change occurs it automatically raises a corresponding event. These events include Created, Renamed, Changed, Deleted and an Error event. Of course, there are several reasons why one needs File System Watcher in his application. As mentioned above there might be a requirement in application to log a File creation time or deletion time, etc. In short this acts as Directory watcher or File Watcher service. 

The file system watcher in C# monitors a specified directory along with files and subdirectories. The FileSystemWatcher has a property called "Filter" by which you can filter the files with specific extensions i.e. with the help of wild-card; even you can monitor File attributes like Last Access, Security, Last Write and Size of a file. 

Look at the below table for all events that gets raised byFileSystemWatcher while monitoring a specified Directory or file. 

Sr. No.
Event Name
Description
1
Created
When a new File or Folder gets created.
2
Renamed
When an existing file or folder gets renamed.
3
Deleted
When an existing file or folder gets deleted.
4
Changed
When an existing file or folder gets modified.
5
Error
When an error occurs.
Now let's look at the actual implementation of simple FileSystemWatcher. In this example, we will create a new Windows Forms on which user can be able to Select a Folder path to monitor. Please refer below screenshot, this would be our filesystemwatecher application. 

Please note that, We are using Visual Studio 2010 – Windows Form application to demonstrate the FileSystemWatcher that will monitor a folder for changes. In fact it monitors Directory, subdirectories along with files in it.

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO;
using System.Threading;

namespace a1ashiishFileSystemWatcher
{
    public partial class MainForm : Form
    {
        public ListBox listBox;
        public const String startMonitoring = "Start Minitoring...";
        public const String stopMonitoring = "Stop Minitoring...";

        public MainForm()
        {
            InitializeComponent();

            //Create a listBox to show activities of all Events.
            listBox = new ListBox();
            listBox.FormattingEnabled = true;
            listBox.Location = new System.Drawing.Point(23, 121);
            listBox.Name = "listBox";
            listBox.Size = new System.Drawing.Size(571, 238);
            listBox.TabIndex = 2;
            this.Controls.Add(listBox);
        }

        private void button1_Click(object sender, EventArgs e)
        {
            // Create FolderBrowserDialog object.
            FolderBrowserDialog folderBrowserDialog = new FolderBrowserDialog();
            // Show a button to create a new folder.
            folderBrowserDialog.ShowNewFolderButton = true;

            DialogResult dialogResult = folderBrowserDialog.ShowDialog();

            // Get selected path from FolderBrowserDialog control.
            if (dialogResult == DialogResult.OK)
            {
                textBox1.Text = folderBrowserDialog.SelectedPath;
                Environment.SpecialFolder root = folderBrowserDialog.RootFolder;
            }
        }

        private void button2_Click(object sender, EventArgs e)
        {
            // Create a new FileSystemWatcher object.
            FileSystemWatcher fsWatcher = new FileSystemWatcher();

            switch (button2.Text)
            {
                // Start Monitoring...
                case startMonitoring:
                    if (!textBox1.Text.Equals(String.Empty))
                    {
                        listBox.Items.Add("Started FileSystemWatcher Service...");
                        fsWatcher.Path = textBox1.Text;

                        // Set Filter.
                        fsWatcher.Filter = (textBox2.Text.Equals(String.Empty)) ? "*.*" : textBox2.Text;

                        // Monitor files and subdirectories.
                        fsWatcher.IncludeSubdirectories = true;

                        // Monitor all changes specified in the NotifyFilters.
                        fsWatcher.NotifyFilter = NotifyFilters.Attributes |
                                                 NotifyFilters.CreationTime |
                                                 NotifyFilters.DirectoryName |
                                                 NotifyFilters.FileName |
                                                 NotifyFilters.LastAccess |
                                                 NotifyFilters.LastWrite |
                                                 NotifyFilters.Security |
                                                 NotifyFilters.Size;

                        fsWatcher.EnableRaisingEvents = true;

                        // Raise Event handlers.
                        fsWatcher.Changed += new FileSystemEventHandler(OnChanged);
                        fsWatcher.Created += new FileSystemEventHandler(OnCreated);
                        fsWatcher.Deleted += new FileSystemEventHandler(OnDeleted);
                        fsWatcher.Renamed += new RenamedEventHandler(OnRenamed);
                        fsWatcher.Error += new ErrorEventHandler(OnError);

                        button2.Text = stopMonitoring;
                        textBox1.Enabled = false;
                        textBox2.Enabled = false;
                    }
                    else
                    {
                        listBox.Items.Add("Please select folder to monitor....");
                    }
                    break;

                // Stop Monitoring...
                case stopMonitoring:
                default:

                    fsWatcher.EnableRaisingEvents = false;
                    fsWatcher = null;
                    button2.Text = startMonitoring;
                    textBox1.Enabled = true;
                    textBox2.Enabled = true;

                    listBox.Items.Add("Stopped FileSystemWatcher Service...");
                    break;
            }

        }

        // FileSystemWatcher - OnCreated Event Handler
        public void OnCreated(object sender, FileSystemEventArgs e)
        {
            // Add event details in listbox.
            this.Invoke((MethodInvoker)delegate { listBox.Items.Add(String.Format("Path : \"{0}\"   || Action : {1}", e.FullPath, e.ChangeType)); });
        }

        // FileSystemWatcher - OnChanged Event Handler
        public void OnChanged(object sender, FileSystemEventArgs e)
        {
            // Add event details in listbox.
            this.Invoke((MethodInvoker)delegate { listBox.Items.Add(String.Format("Path : \"{0}\"   || Action : {1}", e.FullPath, e.ChangeType)); });
        }

        // FileSystemWatcher - OnRenamed Event Handler
        public void OnRenamed(object sender, RenamedEventArgs e)
        {
            // Add event details in listbox.
            this.Invoke((MethodInvoker)delegate { listBox.Items.Add(String.Format("Path : \"{0}\"   || Action : {1} to \"{2}\"", e.FullPath, e.ChangeType, e.Name)); });
        }

        // FileSystemWatcher - OnDeleted Event Handler
        public void OnDeleted(object sender, FileSystemEventArgs e)
        {
            // Add event details in listbox.
            this.Invoke((MethodInvoker)delegate { listBox.Items.Add(String.Format("Path : \"{0}\"   || Action : {1}", e.FullPath, e.ChangeType)); });
        }

        // FileSystemWatcher - OnError Event Handler
        public void OnError(object sender, ErrorEventArgs e)
        {
            // Add event details in listbox.
            this.Invoke((MethodInvoker)delegate { listBox.Items.Add(String.Format("Error : {0}", e.GetException().Message)); });
        }

    }
}

Reference:

http://www.csharptutorial.in/2013/04/Csharp.Net-How-To-Monitor-Directory-and-files-using-Csharp-FileSyestemWatcher.html#.U16l0vn3V4A

Wednesday, August 3, 2016

sum up group by criteria in Google Sheets


=sum(sumif(indirect(C4&"!$A$2:A"), A4, indirect(C4&"!$F$2:F"))*24)

Friday, July 29, 2016

對自己狠一點!成功的人,一定留給自己

「斬斷一切纏繞在自己身上的鎖鏈,
唯獨忠於自我」── 金鎮愛
「狠心」在韓文裡用「毒」字來表示,

「狠心」的意思,就是「遵守對自己的承諾」。

說得仔細一點,

就是

「斬斷一切纏繞在自己身上的鎖鏈,

唯獨忠於自我」,

首先你要學習的就是

「嘗試離開眾人獨處」。

──金鎮愛

獨處時間、獨處空間的力量
人要有獨處的時間,才會成長。
守護自己最簡單的方式,就是「獨處」。

獨處,和睡覺是同一個道理。

只能獨自入睡的睡眠時間裡,

人會將當天所學、所體驗過的事情,

在腦子裡接二連三銘記下來,

並啟動潛意識,做夢的同時,

也將新的刺激和新的能量填補進去。

睡眠對人的成長與生存不可或缺;

獨處對成長和生存,

也同樣是絕對需要的。



「脫離分內之事」的狀態 才是獨處
所謂獨處,

基本上就是「離群而出的狀態」。

對一個人來說,

人可以是最美好的天國,

也可以是最可怕的地獄;

可以給我們帶來無限的喜悅,

卻也可能拖住我們的腳步。

另外,

真正的獨處,

是指「脫離分內之事的狀態」。

當我們

從每天不斷重複的

各種分內之事中脫離的時候,

才能感受到生活操之在我。

任何人都需要,別說你例外
然而,

想要一個人獨處,

就非得去旅行嗎?

搞不好比起出發去旅行,

我們更需要的,

是在日常生活的枷鎖裡

擁有「自己的樂園」。

那就是「獨處的時間、獨處的空間」。

任何人都需要自己的時間、自己的空間。

不管是學生、教師、受雇者、

雇主、上班族、自由工作者、

妻子、丈夫、少男、少女,

更別說是兒童,甚至是嬰兒,

全都一樣。



人們想盡辦法 不讓自己獨處,
同時也不想讓 別人獨處?!


有趣的是,

人們卻傾向想盡辦法不讓自己獨處,

同時也不想讓別人獨處。

因為這個社會裡,

大家都害怕遭人「排擠」的關係嗎?

還是怕被人貼上不合群、沒人情味的標籤?

也可能是

因為我們文化中特有的「拉幫結派」社會特性,

或者是因為,

有太多人混雜在一起、太多資訊在空中交流,

形成了這時代的「群癮症」。



必須「狠下心」來才能擁有 獨處的時間
因此,

我們更迫切需要「獨處」的時間。

在無人妨礙,

只屬於自己的時間、空間裡,

好好品嘗沉浸在自己的時間、空間裡的滋味。

無論如何想辦法享受一下獨處時間和獨處空間吧!

獨處空間,

相較之下比較容易獲得。

但獨處時間,

就必須狠下心來才能擁有。

好好學習獨處空間和獨處時間的力學吧!

與自己對決的黎明時分
我的獨處時間,

只能選在黎明時分。

每天黎明,

是我和自己面對面,

與內在的我相遇的時間。

這一段時光充斥著煩惱與角力,

也讓我回顧各種折磨我的痛苦。

同時,

更是讓我集中精神處理非分內工作、

做我自己想做的事情的時間。

要不是有這段完全屬於我的時間,

我想我大概早就瘋掉,或逃到天涯海角去了。



當萬籟俱寂,
眾人皆睡我獨醒之際
我對黎明的崇拜,

可說如滔滔江水,一瀉千里。

當萬籟俱寂,

眾人皆睡我獨醒之際,

讓我有一種隱隱的喜悅。



沒有人找我,

也沒有討厭的電話,

只要能好好活用黎明的時間,

會覺得一天真的很夠用。

不管怎樣,

傍晚或夜裡的時間,

還是屬於消耗性質的。

邀約遊玩的人很多,

可玩可去的地方也很多,

燈火輝煌,充滿誘惑的地方更多。

悠哉地吃完一頓晚飯後,

想再回頭工作就很難。

想多玩點,是入夜後的心理;

相反地,

想多做點事情,就是黎明時的心理。

孤單,也是有好處的。

醒著的人一個都沒有,

營業的地方也不多。

因此,

黎明可說是一個沒有外界誘惑,

只能沉浸在自己世界的自我誘惑時間。

當然,

不是任何人都能成為「黎明型」,

個人情況上實在無法成為早鳥的話,

請繼續擠出其他的時間。

每個人都需要一段隱密又激烈地面對自己、

與自己對決的時間,

不管是晚上十二點前後,

還是上班前、上班後或下班後的時光。



一天至少兩個小時的時間
無論什麼人,

一天裡至少需要兩個小時這樣的時間。

為什麼是兩個小時,

因為去掉進入狀況的十五分鐘,

從狀況裡出來的十五分鐘,

集中精神大約九十分鐘,

就可以做很多事情,

所以兩個小時的時間差不多。

一天花兩個小時,

一年就有七百到八百個小時,

一個禮拜以

工作四十個小時來計算的話,

就等於至少有四個月的時間

是為了自己在工作,

如此累積下來的力量是很驚人的。



所以,
狠下心來讓自己擁有獨處的時間吧!
以自己幽禁自己的方式,

尋找自己的存在感,

擺脫日常生活的羈絆所導致的消耗感。

那麼,

你就能在人生的

分內之事與想做之事中間,

找到平衡點。

與妨礙獨處的事物對抗
這麼多想奪走我時間的誘惑,
該如何擺脫?
然而,

這個世界不肯放我一人獨處,

總以各種方式干涉我,

想剝奪我的時間。

這麼多想奪走我時間的誘惑,

該如何擺脫?



電話最容易干擾我,我該怎麼做?
就以這個時代算得上妨礙獨處時間

排行榜第一名的「電話」為例吧!

我對於找上門來的電話,

訂下了幾項防禦原則。



(1)請託電話,一律以電子郵件連絡
請託電話,例如邀稿、邀約演講或訪談的,

一律以電子郵件連絡,

如此就能明快地在短時間內

傳遞資訊和掌握內容。



(2)訂好不接電話的時間。
例如當我必須全心投入工作的時候,

乾脆就把電話切斷幾天。

或是一天中有幾個小時不接電話,

就當作自己去旅行了。



(3)主要利用簡訊連絡。


(4)沒有來電顯示的電話,盡可能不接,
當作對方會另傳簡訊來。



(5)手機最好只用來撥出用。


要想堅持這些原則,

我自己也有必須盡力做到的原則,

就是「一定回信」。

不把時間 花在沒意義的事情上
不只是業務方面的電話,

連邀約性質的電話也隨即回覆。

因為從我自己無數次拜託他人,

也無數次被拒絕的經驗來看,

就算是被拒絕也想早點知道,

才能尋求其他管道。

不過,對於一些不著邊際的邀約,

也就沒有非得回覆的必要了。

不久之後我就了解到,

電話接到手軟,

不代表工作也接個不停。

有時反而是「如留言般簡短的電話」,

獲取實質機會的可能性更高。



這裡雖然舉了電話為例,

但對於不時剝奪我們時間的所有事物,
都必須建立起自己的原則。
推特、臉書等通訊軟體也可能使人上癮,

因此要有自己活用這些軟體的原則。

Reference:

http://www.cmoney.tw/notes/note-detail.aspx?nid=58236

Tuesday, July 26, 2016

代碼覆蓋率 (code coverage) 是開發流程蠻重要的一環

代碼覆蓋率 (code coverage) 是開發流程蠻重要的一環,用來評估專案內測試的覆蓋率,也代表了自己寫的程式,至少要測試過一次。在 Github 上面最常用的一套就是 Coveralls 相信大家對於此服務並不陌生,一個好的 Open Source 專案一定會在 Readme 上附上 Coveralls badge,證明自己寫的專案都有經過測試,請安心使用。

Coveralls https://coveralls.io/

codecov https://codecov.io/

Travis https://travis-ci.org/

Reference:

https://blog.wu-boy.com/2016/07/new-coverage-service-codecov-io/

Monday, July 25, 2016

How to create a Symbolic Link on Windows 10?

What's the correct way to make symlinks in Windows 10?

You can use either mklink (cmd built-in) or junction (from Windows SysInternals, which is part of Microsoft) in Windows 10 to create junctions.

Notes:

junction can also list junctions and determine if a file is a junction unlike mklink.

mklink is an internal command only available within a cmd shell.

By default Administrator privileges are required to create symbolic links.

It can also be granted to other users. The security setting "Create symbolic links" can be granted at:

Configuration\Windows Settings\Security Settings\Local Policies\User Rights Assignment\

Using mklink:

F:\test>mklink /j test-junction test

Junction created for test-junction <<===>> test

Using junction:

F:\test>C:\apps\NirSoft\SysinternalsSuite\junction.exe test-junction test

Junction v1.06 - Windows junction creator and reparse point viewer
Copyright (C) 2000-2010 Mark Russinovich
Sysinternals - www.sysinternals.com

Created: F:\test\test-junction
Targetted at: F:\test\test

Reference:

http://superuser.com/questions/1020821/how-to-create-a-symbolic-link-on-windows-10