ติดตั้ง OpenJDK 21 และ Gradle บน macOS ด้วย Homebrew

การติดตั้ง OpenJDK บน macOS สามารถทำได้ง่าย ๆ ผ่าน Homebrew โดยในบทความนี้ เราจะติดตั้ง OpenJDK 21 และ Gradle พร้อมตั้งค่า JAVA_HOME และ PATH ให้ใช้งานได้อย่างถูกต้อง

1. ตรวจสอบ Homebrew

สำหรับบทความนี้จะถือว่าเพื่อนๆ มี homebrew ติดตั้งไว้ในเครื่องอยู่แล้วนะครับ โดยตรวจสอบว่า Homebrew ทำงานปกติไหมด้วยคำสั่ง

brew --version

2. ติดตั้ง OpenJDK 21

ใช้คำสั่งต่อไปนี้เพื่อติดตั้ง OpenJDK 21 ผ่าน Homebrew:

brew install openjdk@21

เพื่อนๆอาจสงสัยว่าความจำเป็นใด ที่จะต้องติดตั้งแบบระบุ Version เนื่องมาจากว่าการใช้ JDK กับ Gradle นั้นจะมี Spec ความต้องการที่มีความสัมพันธ์ด้าน Version กันอยู่นะครับ หากใช้ Version เก่าเกินไป หรือใหม่เกินไป ไม่สัมพันธ์กัน อาจจะเกิด Error ได้

หลังจากติดตั้งเสร็จแล้ว เราต้องเพิ่มพาธของ OpenJDK ลงในตัวแปรสภาพแวดล้อม (Environment Variables) เพื่อให้ระบบรู้จัก Java

3. ตั้งค่า JAVA_HOME และ PATH

เพิ่มตัวแปร JAVA_HOME และปรับ PATH ให้ชี้ไปยัง OpenJDK ที่เพิ่งติดตั้ง โดยใช้คำสั่งนี้:

echo 'export JAVA_HOME="/usr/local/opt/openjdk@21"' >> ~/.zshrc
echo 'export PATH="$JAVA_HOME/bin:$PATH"' >> ~/.zshrc
source ~/.zshrc

หากใช้ bash แทน zsh (เช่น บน macOS รุ่นเก่า) ให้แก้เป็นไฟล์ ~/.bashrc หรือ ~/.bash_profile

หากเราต้องการจะค้นหาว่า openjdk ที่ติดตั้งผ่าน homebrew สามารถใช้คำสั่งดังนี้เพื่อดูรายละเอียดได้ ซึ้ง brew จะแสดง path ให้เห็นในส่วนท้ายๆ นะครับ เพื่อนๆ ลองทำกันได้

brew info openjdk@21

ระบบจะแสดงข้อความให้เราเห็น Path ลักษณะนี้

For the system Java wrappers to find this JDK, symlink it with
  sudo ln -sfn /usr/local/opt/openjdk@21/libexec/openjdk.jdk /Library/Java/JavaVirtualMachines/openjdk-21.jdk

openjdk@21 is keg-only, which means it was not symlinked into /usr/local,
because this is an alternate version of another formula.

If you need to have openjdk@21 first in your PATH, run:
  echo 'export PATH="/usr/local/opt/openjdk@21/bin:$PATH"' >> ~/.zshrc

For compilers to find openjdk@21 you may need to set:
  export CPPFLAGS="-I/usr/local/opt/openjdk@21/include"

4. ตรวจสอบเวอร์ชันของ Java

หลังจากตั้งค่าเสร็จแล้ว ลองตรวจสอบว่า Java พร้อมใช้งานและเป็นเวอร์ชันที่ถูกต้อง:

java -version

ตัวอย่างผลลัพธ์ที่ควรได้:

openjdk version "21.0.1" 2023-10-17
OpenJDK Runtime Environment (build 21.0.1+12)
OpenJDK 64-Bit Server VM (build 21.0.1+12, mixed mode)

5. ติดตั้ง Gradle

เมื่อติดตั้ง Java เสร็จแล้ว เราสามารถติดตั้ง Gradle ต่อได้โดยใช้คำสั่ง:

brew install gradle

6. ตรวจสอบเวอร์ชันของ Gradle

เมื่อติดตั้งเสร็จแล้ว ลองเช็กว่า Gradle ทำงานได้ปกติด้วยคำสั่ง:

gradle --version

ตัวอย่างผลลัพธ์ที่ควรได้:

------------------------------------------------------------
Gradle 8.13
------------------------------------------------------------

Build time:    2025-02-25 09:22:14 UTC
Revision:      073314332697ba45c16c0a0ce1891fa6794179ff

Kotlin:        2.0.21
Groovy:        3.0.22
Ant:           Apache Ant(TM) version 1.10.15 compiled on August 25 2024
Launcher JVM:  21.0.6 (Homebrew 21.0.6)
Daemon JVM:    /usr/local/Cellar/openjdk@21/21.0.6/libexec/openjdk.jdk/Contents/Home (no JDK specified, using current Java home)
OS:            Mac OS X 11.7.10 x86_64

สรุป

ในบทความนี้ เราได้ติดตั้ง OpenJDK 21 และ Gradle บน macOS ผ่าน Homebrew พร้อมทั้งตั้งค่าตัวแปรสภาพแวดล้อมให้ระบบรู้จัก Java และ Gradle สามารถเริ่มใช้งานได้ทันที 🎯

📌 หากต้องการเปลี่ยนไปใช้เวอร์ชันอื่นในอนาคต สามารถติดตั้ง OpenJDK เวอร์ชันใหม่ ๆ ผ่าน Homebrew และอัปเดตค่า JAVA_HOME ตามเวอร์ชันที่ต้องการ

🔹 ตัวอย่างเวอร์ชันอื่น:

brew install openjdk@17 → สำหรับ Java 17
brew install openjdk@11 → สำหรับ Java 11

ลองดูกันได้นะครับเพื่อนๆ

ความแตกต่างระหว่างคำสั่ง docker run กับ docker exec


docker run

$ docker run #{image} sh
จะมีการสร้าง temporary container ขึ้นมาเพื่อรัน command เมื่อรันเสร็จจะหยุด container แต่ไม่ terminate
ดังนั้นจะมี container id ค้างอยู่ในระบบ

docker exec

$ docker exec #{container} sh
จะใช้ container ที่มีอยู่แล้วในการรัน

Process Manufacturing Vs Discrete Manufacturing

Basic Manufacturing Differences

 ความแตกต่างระหว่างกระบวนการผลิต แบบ Process และ Discrete

ProcessDiscrete


    รูปแบบส่วนผสมเป็นแบบ
  • วัตถุดิบสามารถเปลี่ยนแปลงได้

  • การเลือกวัตถุดิบจากคุณสมบัติของวัตถุดิบ

  • หน่วยนับ(UOM) มีความเป็นเอกลักษณ์ของแต่ละวัตถุดิบ (กิโลกรัม, %Active)

  • มีสูตร BOM แตกต่างกันหลายสูตร ตามความผันแปรของวัตถุดิบ

  • ต้องการ Lot,Grades,Potency,อายุ(Shelf-life)

  • การผลิตเป็นลักษณะการผสม, ปั่น, เปลี่ยนแปลงรูป, การเติมวัตถุดิบระหว่างผลิต

  • Makes “STUFF”




    รูปแบบส่วนผสมเป็นแบบ
  • ชิ้นส่วน, อะไหล่

  • การเลือกวัตถุดิบใช้ลักษณะ Part number

  • หน่วยนับ(UOM) เป็นชิ้น

  • BOM มีความซับซ้อน เป็น Multi-level BOMs

  • ต้องการ Serial Numbers, ECN’s

  • การผลิตเป็นลักษณะการประกอบ, สร้าง, ประดิษฐ์, แยกชิ้นส่วน

  • Makes “THINGS”


เช่น อาหารและยา, สี, Beveragesเช่น รถยนต์, Hitech, Automotive

PHP array Group and Sum ด้วย array_reduce

<?php
$array = [
['tax'=>'1','val'=>10],
['tax'=>'1','val'=>20],
['tax'=>'2','val'=>10]
];
$result = array_reduce($array,function($carry,$item){
if(!isset($carry[$item['tax']])){
$carry[$item['tax']] = ['tax'=>$item['tax'],'val'=>$item['val']];
} else {
$carry[$item['tax']]['val'] += $item['val'];
}
return $carry;
});
echo "RESULT*****".PHP_EOL;
echo var_dump($result);
/**
RESULT*****
array(2) {
[1]=>
array(2) {
["tax"]=>
string(1) "1"
["val"]=>
int(30)
}
[2]=>
array(2) {
["tax"]=>
string(1) "2"
["val"]=>
int(10)
}
}
**/

เมื่อฉันซื้อหนังจาก iTunes ครั้งแรก

เนื่องจากเป็นคนที่ติดตามตลาด iTunes Store อยู่ตลอด (เปิดดูเล่นสนุกดี). วันก่อนได้ไปสะดุดตากับหนังในดวงใจหนึ่งเรื่อง. นั่นคือ Gladiator จ้าา. แถมยังเป็น Gladiator (Extended Cut) โดยราคา เช่า 25 บาท และถ้า ซื้อ 99 บาท.

Screen Shot 2560-04-30 at 2.50.50 PM

ก็เลยจัดมาลองสะหน่อย ซื้อมาเลย.

Gladiator เป็นหนังที่ออกโรงฉายเมื่อปี 2000. กำกับโดย ผู้กำกับ Ridley Scott. นำแสดงโดย Russell Crowe หนังเล่าเรื่องราวของนายพลผู้ถูกทรยศผู้กลายมาเป็น Gladiator ที่ดูกี่ครั้ง ยืนดูตามร้านขายทีวี เวลาที่เดินผ่าน ก็ยังสนุก

ซื้อเสร็จลองดูเลย เนื่องจากใช้ Macbook จอ 13 นิ้ว ก็เลยเสียบสายต่อ ออกจอ LG 24 นิ้ว ปรากฎว่า.

ดูไม่ได้ !!

IMG_5114

“The selected movie won’t play on your display.”

“This movie can be played only on displays that support HDCP (High-bandwidth Digital Content Protection).”

ภาพยนตร์เรื่องนี้ไม่สามารถเล่นบนจอภาพนี้ได้. ภาพยนตร์สามารถเล่นได้บนหน้าจอที่สนับสนุน HDCP เท่านั้นนะจ๊ะ.

HDCP เป็นกระบวนการที่สร้างขึ้นมาเพื่อปกป้อง Content ไม่ให้ถูกคัดลอกระหว่างที่เดินทางผ่านการเชื่อมต่อ (DVI,HDMI,DisplayPort) นั่นเอง.

แล้วจะรู้ได้อย่างไรว่าจอเรามันใช้ HDCP ได้หรือไม่อ่ะ?.

ก็เลยต้องปิดไปแบบ งงๆ เปลี่ยนไปดูหน้าจอ Macbook 13″ แทน.

เฮ้อ เศร้าโศก.

ความน่าหลงไหลของ Python : Dictionaries, Tuple key

ความน่าหลงไหลของภาษา Python ที่น่าสนใจคือ Dictionaries ซึ่งเป็นการเก็บข้อมูลแบบ (key,value) ที่สามารถใช้ tuple เป็น key ได้
ตัวอย่างของ tuple เฃ่น (1,2,3) (‘ไทย’,’กรุงเทพ’,’สีลม’) อธิบายง่ายๆก็คือใน 1 key ประกอบไปด้วยคียร์ย่อย ข้างในนั่นเอง
โดยไม่ต้องแปลง key เป็น string หรือแปลงกลับจาก string เป็น key ให้ยุ่งยากวุ่นวาย

ประโยชน์ที่เห็นว่าสามารถนำมาใช้งานได้อย่างดีก็คือ เรื่องการจัดกลุ่มชุดข้อมูล
เราสามารถ ทำ group ข้อมูลโดยใช้ tuple เข้ามาช่วยเป็น key ได้อย่างสะดวก

ตัวอย่างเช่นเรา query ข้อมูลจาก Database มาเป็น row และต้องการ group ตาม column
และเข้าถึงข้อมูลตาม column ได้โดยไม่ต้อง query ข้อมูลจาก database ใหม่
ซึ่งจะดำเนินการใน memory เท่านั้น

มาดูตัวอย่างกันเลยดีกว่า

Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
view raw dict.ipynb hosted with ❤ by GitHub

การตั้ง Timezone ใน Docker Ubuntu

1. เข้า bash ของ docker container ก่อน

docker exec -it mysql_container bin/bash

2. ตั้ง Timezone

echo Asia/Bangkok > /etc/timezone && dpkg-reconfigure -f noninteractive tzdata

ผลลัพธ์

Current default time zone: 'Asia/Bangkok'
Local time is now:      Fri Sep 16 10:19:55 ICT 2016.
Universal Time is now:  Fri Sep 16 03:19:55 UTC 2016.

ERPNext new app with embeded js/css

environment structure
$home = /dev/frappe-bench/

1. Create new app

bench new-app myapp1

and key in App Description and other information.
App wil appear in

$home/apps/myapp1

App structure

myapp1
├── MANIFEST.in
├── README.md
├── license.txt
├── myapp1
│   ├── __init__.py
│   ├── config
│   │   ├── __init__.py
│   │   ├── desktop.py
│   │   └── docs.py
│   ├── hooks.py
│   ├── modules.txt
│   ├── myapp1
│   │   └── __init__.py
│   ├── patches.txt
│   ├── templates
│   │   ├── __init__.py
│   │   ├── generators
│   │   │   └── __init__.py
│   │   ├── includes
│   │   └── pages
│   │   └── __init__.py
│   └── www
├── myapp1.egg-info
│   ├── PKG-INFO
│   ├── SOURCES.txt
│   ├── dependency_links.txt
│   ├── not-zip-safe
│   ├── requires.txt
│   └── top_level.txt
├── requirements.txt
└── setup.py

2. Create webview and page controller
create html in folder www/myapp1_index.html

<p class="intro">Car</p>
<p>Brand: {{car.brand}}</p>
<p>Color: {{car.color}}</p>

create py in folder www/myapp1_index.py for page context data

import frappe

def get_context(context):
context.car = dict(brand="Toyota",color="Red")

3. Create js and css
create folder public/js and public/css in ../myapp1/myapp1/
for public/css create myapp-demo.css

.intro {
background-color:yello;
}

for public/js create myapp-demo.js

alert("Hello from myapp-demo.js");

Create build.json at public/build.json to config the js/css file

{
   "myapp1/css/myapp1.css": [
     "public/css/myapp-demo.css"
   ],
   "myapp1/js/myapp1.js": [
     "public/js/myapp-demo.js"
   ]
}

4. From hooks.py file add configuration

# include js, css files in header of web template
web_include_css = "/assets/myapp1/css/myapp1.css"
web_include_js = "/assets/myapp1/js/myapp1.js"

5. Final app tree

myapp1
├── __init__.py
├── config
│   ├── __init__.py
│   ├── desktop.py
│   └── docs.py
├── hooks.py
├── hooks.pyc
├── modules.txt
├── myapp1
│   ├── __init__.py
├── patches.txt
├── public
│   ├── build.json
│   ├── css
│   │   ├── myapp-demo.css
│   │   └── myapp1.css
│   └── js
│       ├── myapp-demo.js
│       └── myapp1.js
├── templates
│   ├── __init__.py
│   ├── generators
│   │   └── __init__.py
│   ├── includes
│   └── pages
│       └── __init__.py
└── www
    ├── myapp1_index.html
    ├── myapp1_index.py

6. Install app with command

bench --site site1.local install-app myapp1
bench --site site1.local sync-www

7. Run app

http://localhost:8000/myapp1_index

Source code
https://github.com/wisaruthk/myapp1.git

Xcode: Unit test, Test long duration on background thread

การเขียน Unit test สำหรับ Method ที่มีการรันนาน หรือ รันที่ Thread อื่นและต้องมีการรอผล เช่น การเรียก HTTP Request เป็นต้น

@interface AppTests : XCTestCase

@end

@implementation AppTests

- (void)testWS
{
    XCTestExpectation *completionExpectation = [self expectationWithDescription:@"Long method"];
    
    // start thread
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0), ^{
      // do something on another thread long duration
      [completionExpectation fulfill];
    }
   
    [self waitForExpectationsWithTimeout:5.0 handler:nil];
    
}

@end
Design a site like this with WordPress.com
Get started