เกิดอาการนี้มาเป็นวันที่ 2 แล้ว เมื่อวานสั่ง reboot แล้วหาย แต่วันนี้ reboot แล้วยังคงมีอาการอยู่
ที่เคยเจออาการนี้ คือ harddisk เต็ม ซึ่งปกติจะตรวจพื้นที่เหลือใน harddisk ก่อน ด้วย df -h ผลออกมาว่ายังมีพื้นที่เหลืออีกเพียบ จนในที่สุดก็พบว่าที่เต็มนั้นไม่ใช่พื้นที่ แต่เป็น inode ลองตรวจดูด้วยคำสั่ง df -i พบว่า / เต็ม 100%
สาเหตุของครั้งนี้คือ inode ที่มีไว้สำหรับเก็บตำแหน่ง folder/file เต็ม เท่าที่อ่านดู ยังไม่สามารถขยายเพิ่มได้ (ต้องทำตอน format harddisk) จึงต้องค้นหาว่า folder ไหนที่มีไฟล์เป็นจำนวนมาก แล้วก็ลบ/ย้ายไปไว้ที่อื่นที่ใช้คนละ inode กัน
# df -i
Filesystem Inodes IUsed IFree IUse% Mounted on udev 1275949 357 1275592 1% /dev tmpfs 1278745 553 1278192 1% /run /dev/sda1 1831424 1831424 0 100% / tmpfs 1278745 1 1278744 1% /dev/shm tmpfs 1278745 3 1278742 1% /run/lock tmpfs 1278745 15 1278730 1% /sys/fs/cgroup /dev/sdb1 122093568 8699755 113393813 8% /backup /dev/sda4 119996416 4748787 115247629 4% /home /dev/sda2 122400 337 122063 1% /boot tmpfs 1278745 10 1278735 1% /run/user/1004
คำสั่ง ls เพื่อดูว่าแต่ละ file มี inode หมายเลขอะไร
# ls -lai
คำสั่งสำหรับนับจำนวนไฟล์ในแต่ละ folder
# for i in /*; do echo $i; find $i |wc -l; done
# echo "Detailed Inodes usage for: $(pwd)" ; for d in `find -maxdepth 1 -type d |cut -d/ -f2 |grep -xv . |sort`; do c=$(find $d |wc -l) ; printf "$c - $d " ; done ; printf "Total: $(find $(pwd) | wc -l) "
พบว่า folder usr/local/directadmin/data/tickets มี folder/file จำนวนมาก ซึ่งสะสมมาจาก ticket ที่ระบบอัตโนมัตของ directadmin สร้างขึ้นมา จึงทำการลบไฟล์ทิ้งทั้งหมด
# rm -rm /usr/local/directadmin/data/tickets[code] แล้วย้าย folder tickets ไปไว้ใน /backup (ซึ่งอยู่คนละ harddisk ก็จะไม่มีผลต่อ inode ของ /) [code] # mkdir /backup/usr # mkdir /backup/usr/local # mkdir /backup/usr/local/directadmin # mkdir /backup/usr/local/directadmin/data # mkdir /backup/usr/local/directadmin/data/tickets [code] เปลี่ยน owner/group ให้เป็นของ DirectAdmin [code] # chown diradmin:diradmin /backup/usr/local/directadmin # chown diradmin:diradmin /backup/usr/local/directadmin/data # chown diradmin:diradmin /backup/usr/local/directadmin/data/template # chown diradmin:diradmin /backup/usr/local/directadmin/data/tickets
สร้างลิงก์ tickets ไปที่ใหม่
# cd /usr/local/directadmin/data # mv tickets tickets.old # ln -s /backup/usr/local/directadmin/data/tickets tickets # chown -h diradmin:diradmin tickets
ปล. เขาบอกว่าให้ลบไฟล์ session ทิ้งด้วย
# find . -type f -name sess_\* -delete
ที่มา
ตอนจะติดตั้ง Xcode มัน error "Not enough storage disk space, you can't install the product".
สาเหตุเกิดจาก App Store คำนวณพื้นที่ว่างผิด ได้ไม่เท่ากับพื้นที่ว่างจริง
สำรวจพื้นที่ว่างในฮาร์ดดิสกันก่อน
About this Mac > Storage
Trick คือ ให้ macOS ทำการ clean up APFS โดยสร้าง a huge garbage file หลังจากนั้นก็ลบมันทิ้งไป
สร้างไฟล์โดยคำสั่ง:
dd if=/dev/zero of=/Users/<username>/hugefile bs=100m
ปล่อยให้มันทำงานไปสัก 30 วินาที แล้วก็ kill มันทิ้งด้วย ctrl+c หลังจากนั้นก็ลบไฟล์นั้นทิ้งไป:
rm ~/hugefile
ลบ Snapshots
tmutil thinlocalsnapshots / 21474836480 4
น่าจะถึงเวลาที่ต้องมาเขียน App บน iOS เสียที มีงานรออยู่หลายชิ้นแล้ว ตั้งแต่ iMed@home, Green Smile, 1T1U และน่าจะมีตามมาอีกหลายงาน เช่น iMed@NCD Care
Set App to be a release mode (default is debug mode cannot run directly)
In VS Code Settings:
Tab User => Extensions/Dart & Flutter/Dart: Flutter Run Additional Args
or search "Flutter Run Additional Args"
Dart: Flutter Run Additional Args
Additional args to pass to the flutter run command.
Add Item --release
In command line
You can Run your application in Release Mode easily in your terminal using :
flutter run --release
And it will switch to Release Mode .
But if you don't want to run your app , just want to build your apk or ipa , Use :
flutter build --release
In X-Code
You can specify to build for ios by using flutter build ios
Follow these 3 steps:
cd project open ios/Runner.xcworkspace
- Open your Flutter project in Xcode.
- Top Bar Product > Scheme > Edit Scheme
- Build Configuration - Select Release
Note: Release type flutter app is valid for 7 days on iOS devices.
ที่มา
รอก่อนนะ ค่อยกลับมาทยอยเขียน
Edit Apache config
sudo nano /etc/apache2/httpd.conf
ServerName my.local.:80 <Directory "/"> AllowOverride All Require all denied </Directory> <Directory "/Library/WebServer/Documents"> AllowOverride All </Directory>
Restart Apache
sudo apachectl restart sudo apachectl -k graceful
Edit MariaDB config
nano ~/.my.cnf
Restart MariaDB
Auto start
brew services start mariadb
Manual start
mysql.server restart
Configuration
PHP Config
nano /usr/local/etc/php/8.0/php.ini
... post_max_size = 1024M upload_max_filesize = 1024M ...
ที่มา
แปะไว้ก่อน ค่อยมาเขียนรายละเอียดนะครับ
sudo nano /etc/php/7.4/fpm/php.ini sudo systemctl restart apache2sudo nano /etc/mysql/conf.d/mysqld.cnf sudo systemctl restart mysql
mkdir remotefolder sshfs -p 22 username@example.com:/home/folder/ remotefolder umount remotefolder
sshfs -p 22 username@example.com:/home/user/domains/example.com/public_html/ remotefolder nohup rsync -trv remotefolder/path/ path/ &
sudo apt update<br /> sudo apt upgrade
sudo apt install apache2 -y systemctl status apache2
sudo a2dismod ssl sudo a2enmod ssl<br /> <br /> <br />
apt install php7.4 php7.4-mysql php-common php7.4-cli php7.4-json php7.4-common php7.4-opcache libapache2-mod-php7.4
apt install mariadb-server mariadb-client systemctl status mariadb
mysql> CREATE USER 'newuser'@'localhost' IDENTIFIED BY 'password'; mysql> GRANT ALL PRIVILEGES ON * . * TO 'newuser'@'localhost';<br /> <br /> <br />
sudo systemctl restart apache2<br /> sudo systemctl restart mysql<br /> <br /> <br /> wget -r --ask-password ftp://user:server.com/
- https://upcloud.com/community/tutorials/installing-lamp-stack-ubuntu/?utmterm=&utmcampaign=DSA&utmsource=adwords&utmmedium=ppc&hsaacc=9391663435&hsacam=7185608860&hsagrp=81739862313&hsaad=391197952986&hsasrc=g&hsatgt=dsa-460992423274&hsakw=&hsamt=b&hsanet=adwords&hsaver=3&gclid=CjwKCAiAeb-BRB2EiwAGBnXXuae-7ru2jsgSAiku6bX0k7XucjvKLGBQkSm-DKo92SXjG1odKAeRoCid0QAvD_BwE - https://www.digitalocean.com/community/tutorials/how-to-create-a-new-user-and-grant-permissions-in-mysql - https://stackoverflow.com/questions/113886/how-to-recursively-download-a-folder-via-ftp-on-linux - https://askubuntu.com/questions/709594/how-can-i-disable-and-enable-ssl-in-apache-without-a-command-if-possible
- ต่อโทรศัพท์ Android กับ Mac ก่อน ด้วย USB Cable
- เปิด Termilal แล้ว run
Library/Android/sdk/platform-tools/adb tcpip 5555 Library/Android/sdk/platform-tools/adb connect YOURDEVICEIP:5555
- รอดูผลของการเชื่อมต่อ
- ถอดสาย USB ออก แล้วก็ debug ผ่าน WIFI โลด
ที่มา
Apache Tuning from How To Optimize Apache
Timeout 300 KeepAlive On MaxKeepAliveRequests 100 KeepAliveTimeout 15 MinSpareServers 5 MaxSpareServers 10 StartServers 5 MaxClients 150 MaxRequestsPerChild 0
Create new user how
sudo adduser userName
Make user sudo how
sudo adduser userName sudo
MySQL Configuration
- Increrase memory size for MySQL Server using nano /etc/my.cnf and add/change value ตามรายละเอียด
innodbbufferpoolsize = 2048M innodblogfilesize = 512M maxconnections = 500 keybuffer_size = 512M
PHP Config
Set timezone to Asia/Bangkok
nano /etc/php/7.4/apache2/php.ini
date.timezone = Asia/Bangkok
Add CNAME domain.com to ppi.psu.ac.th
Add new site to Apache
cd /etc/apache2/sites-available nano sites-available/doname.com.conf
<VirtualHost *:80>
ServerName domain.com
ServerAdmin webmaster@localhost
DocumentRoot /var/www/html/domain.com
</VirtualHost>
<VirtualHost *:80>
ServerName www.domain.com
ServerAdmin webmaster@localhost
DocumentRoot /var/www/html/domain.com
</VirtualHost>
<IfModule mod_ssl.c>
<VirtualHost _default_:443>
ServerName domain.com
ServerAdmin webmaster@localhost
DocumentRoot /home/user/domains/domain.com
</VirtualHost>
<VirtualHost _default_:443>
ServerName www.domain.com
ServerAdmin webmaster@localhost
DocumentRoot /home/user/domains/domain.com
</VirtualHost>
</IfModule>
cd /etc/apache2/sites-enabled ln -s ../sites-available/domain.com.conf domain.com.conf
Restart Apache
systemctl restart apache2
Restart MySql
systemctl restart mysql
INSTALL Let's Encrypt
1. ติดตั้งด้วย snap ดูรายละเอียดได้ที่ Certbot instructions
snap install --classic certbot ln -s /snap/bin/certbot /usr/bin/certbot certbot --apache certbot certonly --apache certbot renew --dry-run
2. ติดตั้งด้วย apt-get จาก repo
apt-add-repository -r ppa:certbot/certbot
After that, the following commands do not generate any errors:
apt update apt-get update apt install python3-certbot-apache
certbot --apache -d domain.com -d www.domain.com
You should test your configuration at:
https://www.ssllabs.com/ssltest/analyze.html?d=domain.com
IMPORTANT NOTES:
Congratulations! Your certificate and chain have been saved at:
- /etc/letsencrypt/live/domain.com/fullchain.pem
- Your key file has been saved at:
- /etc/letsencrypt/live/domain.com/privkey.pem
- Your cert will expire on 2021-01-08. To obtain a new or tweaked version of this certificate in the future, simply run certbot again with the "certonly" option. To non-interactively renew all of your certificates, run "certbot renew"
To test the renewal process, you can do a dry run with certbot:
sudo certbot renew --dry-run
Correct way to completely remove issued certificate(s) for a domain
certbot delete --cert-name domain.com
Copy file from another server using SSH
Alternatively, you could mount the myserver's filesystem over SSH with sshfs. This may be too much hassle for a one-off need, but convenient if you do this sort of thing often.
mkdir myserver sshfs -p 22 domain.com:/path/ myserver wget -O ~/myserver/path/to/remote/destination http://www.example.com/whatever rsync -trv myserver/src/path/ dest/path/ umount myserver
rsync in background
nohup rsync -trv myserver/src/path/ dest/path/ &
Dump Database
mysqldump -u [username] -p [database-you-want-to-dump] > [path-to-place-data-dump.sql] /usr/local/mysql/bin/mysqldump -u [username] -p [database-you-want-to-dump] > [path-to-place-data-dump.sql]
Ways to Flush DNS Cache on Mac OSx
sudo killall -HUP mDNSResponder
WhoIs LookUp
nslookup -type=ns softganz.com
Setup Time Sync
ติดตั้ง
apt-get install ntp
แก้ไข config
nano /etc/ntp.conf
เปลี่ยน server เป็น
server 1.th.pool.ntp.org server 0.asia.pool.ntp.org server 2.asia.pool.ntp.org server clock.nectec.or.th
Restart
service ntpd restart
หรือ
service ntp restart
ที่มา
- Certbot instructions
- How To Secure Apache with Let's Encrypt on Ubuntu 18.04
- E: The repository 'http://ppa.launchpad.net/certbot/certbot/ubuntu focal Release' does not have a Release file
- How To Use SSHFS to Mount Remote File Systems Over SSH
- How to wget a file to a remote machine over SSH?
- Correct way to completely remove issued certificate(s) for a domain
- How to increase memory size for MySQL Server
- MySQL Performance Tuning Settings
- HOWTO: Sync เวลาไม่ควรใช้ ntpdate ควรใช้ ntpd แทน
ตอนที่เริ่มสร้าง App ใหม่ โดยใช้ Template Buttom Navigator Activity นั้นจะไม่มีปุ่มเมนูบนด้านขวาของ Action Bar หากเราต้องการใช้ ก็จำเป็นต้องสร้างขึ้นมาเอง
เริ่มด้วยการสร้าง resource file ของ options menu ก่อน
Menu -> New -> Resource File File name : options_menu Resource type : Menu
options_menu.xml
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:id="@+id/searchFragment"
android:icon="@drawable/ic_baseline_search_24"
android:title="@string/action_search"
app:showAsAction="always" />
<item
android:id="@+id/settingsFragment"
android:icon="@drawable/ic_baseline_settings_24"
android:title="@string/action_settings"
app:iconTint="@color/yourcolor"
app:showAsAction="ifRoom" />
<item
android:id="@+id/aboutUsFragment"
android:icon="@drawable/ic_baseline_info_24"
android:title="@string/action_aboutus" />
</menu>
MainActivity.kt
override fun onCreateOptionsMenu(menu: Menu?): Boolean {
val inflater = menuInflater
inflater.inflate(R.menu.options_menu, menu)
if (menu is MenuBuilder) {
menu.setOptionalIconsVisible(true)
}
return super.onCreateOptionsMenu(menu)
}
override fun onOptionsItemSelected(item: MenuItem): Boolean {
when (item.itemId) {
R.id.aboutUsFragment -> {
toast("About Us")
}
}
return super.onOptionsItemSelected(item)
}
เพิ่มรายการในเมนู
menu?.apply {
// ----------------- add a new item to menu ----------------
// add new item to menu
val newItem:MenuItem = menu.add(
Menu.NONE, // group id
2, // item id
1, // order
"New Item" // title
)
// set new item's icon
newItem.setIcon(R.drawable.ic_check_circle)
// set new item show as action flags
newItem.setShowAsActionFlags(
MenuItem.SHOW_AS_ACTION_ALWAYS or
MenuItem.SHOW_AS_ACTION_WITH_TEXT
)
// menu new item click listener
newItem.setOnMenuItemClickListener {
Toast.makeText(this@MainActivity, "New Item Clicked", Toast.LENGTH_SHORT).show()
true
}
// ----------------- remove an item from menu ----------------
menu.removeItem(R.id.cancel)
// ----------------- update an item in menu ----------------
menu.findItem(R.id.settings).apply {
title = "Updated Title"
}
ตรวจสอบว่า menu ได้สร้างหรือยัง?
::actionMenu.isInitialized
ตรวจสอบว่า key ของ Array มีหรือไม่?
options.has("menu")
การเข้าถึง R -> Resource
android.R.attr.actionBarSize
ที่มา
ช่วงนี้กำลังพัฒนา Green Smile App เวอร์ชั่นใหม่ โดยเปลี่ยนแปลงรูปแบบมาใช้ Fragment แทน
หลังจากทำไปพักหนึ่ง ก็มีปัญหาในการสื่อสาร/เข้าถึงข้อมูลระหว่า Activity กับ Fragment
ขอบคุณบทความดี ๆ จาก Akexorcist เรื่อง Let’s Fragment — วิธีการรับส่งข้อมูลของ Fragment แถมในบทความยังมีบทความในซีรีย์เดียวกันอีกหลายเรื่อง เช่น
- มารู้จักกับ Fragment กันเถอะ~
- เริ่มต้นง่ายๆกับ Fragment แบบพื้นฐาน
- ว่าด้วยเรื่องการสร้าง Fragment จาก Constructor ที่ถูกต้อง
- รู้จักกับ FragmentTransaction สำหรับการแสดง Fragment [ตอนที่ 1]
- รู้จักกับ FragmentTransaction สำหรับการแสดง Fragment [ตอนที่ 2]
- Lifecycle ของ Fragment (Fragment Lifecycle)
- วิธีการรับส่งข้อมูลของ Fragment
- มาทำ View Pager กันเถิดพี่น้อง~ [ตอนที่ 1]
- มาทำ View Pager กันเถิดพี่น้อง~ [ตอนที่ 2]
- เพิ่มลูกเล่นให้กับ View Pager ด้วย Page Transformer
ลองตามไปอ่านกันดูนะครับ
fun evaluateJsFromNative(command: String,
webView: WebView, function: (value : Boolean) -> Unit ) {
webView.evaluateJavascript("(function() { return $command; })();") {
s -> function(s.toBoolean())
}
}
override fun onBackPressed() {
var boxCheck = "document.getElementsByClassName('box-page')[0].tagName == 'DIV';"
evaluateJsFromNative(boxCheck, myWebView) {
if (it) {
evaluateJsFromNative("$.colorbox.close()", myWebView){}
} else {
super.onBackPressed()
}
}
}