Skip to main content

Posts

I'm cancelling JetBrains after 10 years

I've started with PhpStorm only in 2015, then needed PyCharm, DataGrip, and eventually IntelliJ. At some point it just made sense to switch to the All Products Pack. In total, I paid about $975 over 10 years, about $8/month, a pretty good deal. But my workflow has moved. These days it's mostly terminal ( Ghostty ), coding agents (Claude Code, Codex CLI ), and orchestration (Conductor). Code gets written, tested, and validated across preview environments (Railway, Vercel) or fully automated loops (bash, agent-browser ). If I really need an editor, I open VS Code for a quick change. I’ve also been experimenting with a more autonomous SDLC stack, things like gstack from Garry Tan , OpenAI's Symphony , and building ambient intelligence at  https://github.com/scoutqa-dot-ai/thor  on top of  OpenCode . Lots of development without any Integrated Development Environments. Renewal is coming up next month and I don't even have any of their apps installed. Sorry JetBrains, it'...

1k GitHub ⭐

Forgot to take a screenshot when  flutter_widget_from_html  reached 700 stars (the previous milestone, 600 was July last year ). But today  dvhcvn  receives its 300th. So yay!

600 GitHub 🌟

It has been a whole year !

Chiếc nón kì diệu phiên bản 2004 viết bằng Pascal

Nhân dịp sinh nhật Turbo Pascal 40 tuổi, tìm lại trò chơi Chiếc nón kì diệu mình viết năm 2004. Hồi đó không hiểu kết nối như thế nào mà cũng được đăng lên báo. e-CHÍP bắt đầu từ 2003, tới 2016 thì ngưng báo giấy chuyển lên báo điện tử, rồi từ từ chìm dần. Hồi đó ít báo chí, chỉ mong chờ Làm bạn với máy ví tính và e-CHÍP ra để đọc ngấu nghiến. Tới giờ vẫn còn nhớ câu slogan "Tin học như cơm bình dân". Chắc anh chị em 9x làm IT thì ai cũng biết tới báo này, cả một bầu trời tuổi thơ luôn. Xem thêm bài của bác Phạm Hồng Phước về báo e-CHÍP .  Do web sập rồi nên copy nguyên văn lại bài PR cũ ra đây, văn vẻ hồi đó cứ như ChatGPT viết... Giới thiệu về chương trình “CHIẾC NÓN KÌ DIỆU” Ngôn ngữ: Pascal Tác giả: Đào Hoàng Sơn (THCS Đống Đa) 1. Ý tưởng ban đầu Ban đầu, chỉ với sự hứng thú với chương trình chiếc nón kì diệu trên truyền hình, đồng thời do được chơi 1 trò chơi làm bằng Flash giả như là chương trình chiếc nón kì diệu nên tôi đã nảy ra mong muốn làm 1...

Replacing GCP with Railway for faster cold start

TL;DR I switched a Dart API from Cloud Run to Railway for a 300% faster cold start, simplified DevOps, and a straightforward fee structure. Problem I'm working on this project github.com/daohoangson/flutter_widget_from_html . It is a pub.dev package that's super handy for Flutter developers who want to seamlessly render HTML in their apps. Now, when it comes to HTML, it can get pretty dynamic, right? That's why having a playground to showcase features, troubleshoot issues, and tackle bugs is crucial. The Google team has this fantastic tool called dartpad.dev , which is just perfect for this kind of thing. However, there's a little catch - third-party packages like mine usually can't be used there (unless you have thousands of likes, as explained on  Medium ). So I decided to take matters into my own hands, forked it, then deployed try.fwfh.dev with additional package support. Initial idea since 2019 First deployment  in 2021 Cl...

Wow, thanks GitHub!

 

500 GitHub stars 🌟

  It has been ten months ...

Mysterious Android version code = configured value plus 2000

If you are building Flutter app and shows app version in-app for users to see (mostly testers). You may run into a weird issue that the version code is different from the configured value. E.g. if you run ` flutter build --build-number=1234 ` it will show up as ` 3234 `, 123 shows up as ` 2123 `... What the hell is happening? flutter.gradle#L864-L876  is the culprit. Basically ` --split-per-abi ` will increase the version code number by 1000, 2000, 3000, etc. as seen above. If you don't want that behavior, just build one single fat APK.

300 stars and 100 forks 🎉

  It only takes eight months  😅

A faster Docker for Mac experience

Docker for Mac is freaking slow, this is known issue for years. I'm switching to docker-machine running within Parallels for now... Image from unsplash.com Install the tools I use brew to quickly install these: brew install docker-machine brew install docker-machine-parallels Create the virtual machine The --driver param and vm name is required. The others are all optional, the default values are quite low so I bumped the specs a bit. docker-machine create --driver=parallels \   --parallels-cpu-count=2 \   --parallels-disk-size=100000 \   --parallels-memory=4096 \   parallels Usage Set up the shell environment: eval $(docker-machine env parallels) Then use the cli as normal: docker ls docker-compose up -d To get the vm IP address: docker-machine ip parallels

Setting up a new laptop

This is mostly a self note for the next time I'm doing a fresh install of my laptop. Which I do about once a year to catch up with the latest macOS version. I feel like a new install has better performance then an in place upgrade. System Preferences The first thing that I do on any laptop is to make sure tap to click is enabled 🤣 Also related to the trackpad, three finger drag is also needed... macOS has tons of Apple icons in the default Dock. I get rid of most of them and also make it a bit smaller, align left, disable magnification / minimizing / animation. Some what related to the animations, I often reduce motion / increase contrast these days. It feels easier on the eyes. While I'm still in there, I also disable autocorrect and most of Spotlight indeces. Applications App Store I usually pre-download the installation packages before installing to save time but there are a few apps that need to be downloaded from the store. Xcode is the most important one, and it is huge....

GME? WSB? Short squeeze là cái quái gì vậy?

Trong khi các nhà đầu tư trên Facebook đau khổ vì VN-Index giảm điểm thì bên Mẽo dồn dập những cái tên như GameStop, WallStreetBets rồi các khái niệm short squeeze, options, etc. Sau khi đọc tá lả các nguồn thì mình tổng hợp lại cho các bạn đọc giải trí (đổi khẩu vị đi chứ nhiều tin bệnh dịch quá). Các nguồn tham khảo để ở cuối nhé. 1 GameStop là công ty chuyên bán băng đĩa, máy chơi game thành lập từ 1984 và lên sàn New York năm 2002 với mã GME. Ngày trước ăn nên làm ra, được mua đi bán lại nhiều lần nhưng gần đây thì bết bát do gamer mua online cho nhanh, cả năm vừa rồi cũng giãn cách nên không ai đi trung tâm thương mại / tiệm game làm gì… GME đã rẻ bèo rồi lại còn bị đánh giá là sẽ còn giảm nữa nên bị các nhà đầu cơ bán khống 71.2m cổ phiếu trong khi chỉ có 69.7m cổ phiếu lưu hành. 2 Bán khống ( short ) cổ phiếu thường sẽ làm như thế này: nhà đầu tư A dự đoán cố phiếu X có giá $10 và sẽ còn giảm nên quyết định cọc tiền (collateral) để mượn cổ phiếu bán ra thị trường, chờ X tụt giá...

200 stars!

Yay! flutter_widget_from_html .

Flutter: Fixing Firebase header not found with Notification Service Extension

If you follow the FCM tutorial Send an image in the notification payload and encountered this error message: 'FirebaseMessaging/FirebaseMessaging.h' file not found You are on the right place, I'm going to show you how to fix it. My app was working fine but one day it stopped compiling. Apparently Flutter 1.20 changed the way it uses CocoaPod so the service extension no longer has the proper library configured. After some tinkering, I came up with this pod config, it has to be added to ios/Podfile below the main Runner target. target 'FcmImage' do use_frameworks! use_modular_headers! require File.expand_path('../.symlinks/plugins/firebase_core/ios/firebase_sdk_version.rb', __FILE__) firebase_sdk_version = firebase_sdk_version! pod 'Firebase/Messaging', "~> #{firebase_sdk_version}" end FcmImage is my extension name, replace it with yours We can use a hardcoded version for Firebase/Messaging pod but doing so m...

Making GIF of iOS Simulator without additional apps

This is how I did it: open Terminal and execute this command: ``` xcrun simctl io booted recordVideo \   --code=h264 \   --force "$( date +%Y%m%d%H%M%S ).mov" ``` Running this will record the Simulator screen until you press ` Control+C `. The filename will be something like ` 20200730095757.mov `. The next step is to convert this video into GIF, FFMPEG is required for this. You can either install it via Homebrew but I prefer running it in a Docker container, something like this: ``` docker run --rm -it -v $PWD:/data -w /data --entrypoint /bin/bash jrottenberg/ffmpeg ``` Once you have FFMPEG installed or are inside the container, execute this command: ``` ffmpeg -i 20200730095757.mov \   -vf "fps=fps=5,split[s0][s1];[s0]palettegen[p];[s1][p]paletteuse" \   20200730095757.gif ``` I have played around with the command line arguments and came up with those. Basically it will create a decent GIF to use in issue report etc. Bec...

Running phpinfo to test Kubernetes ingress and Let's Encrypt certificate

For new cluster, I usually deploy a simple phpinfo app to test that the happy-path works as expected. The PHP service and deployment is pretty simple: The Docker image is basically a php:apache image with a single index.php file . Next, setup the ingress and issuer (I'm using ingress-nginx and cert-manager FYI): And voila.

Amazon SES notes

Amazon IAM policy to restrict sending email from a single address {   "Version": "2012-10-17",   "Statement": [     {            "Effect": "Allow",        "Action": "ses:SendRawEmail",        "Resource": "*",        "Condition": {          "StringLike": {            "ses:FromAddress": "username@domain.com"          }        }      }   ] } Replace ` username@domain.com ` with ` *@domain.com ` to allow sending from any addresses. Generate SMTP password from the secret access key Official document is available at  docs.aws.amazon.com . Usage is like this: ./ses.py --secret DmxxxOY --region us-west-2 Test SMTP credentials I use the swaks script (source:  wiert.me ): brew insta...

Configure XenForo 2 to use FTP adapter for external and internal data storage

XenForo 1 needs an add-on to use remote storage for data (useful in container environments) but XenForo 2 supports FTP out of the box. Just put something like these in config.php : $config [ 'fsAdapters' ][ 'data' ] = function () { return new \League\Flysystem\Adapter\Ftp ([ 'host' => 'ftp.domain.com' , 'password' => 'password' , 'username' => 'data' , ]); }; $config [ 'externalDataUrl' ] = function ( $externalPath , $canonical ) { return 'https://data.domain.com/' . $externalPath ; }; $config [ 'fsAdapters' ][ 'internal-data' ] = function () { return new \League\Flysystem\Adapter\Ftp ([ 'host' => 'ftp.domain.com' , 'password' => 'password' , 'username' => 'internal_data' , ]); };

Cord cutting là gì và vì sao mình chọn không dùng truyền hình cáp

Ngày xửa ngày xưa, mua tivi xong chỉ cần cắm  ăngten râu vào cái lỗ tròn tròn là xem được Tây du ký. Sau đấy sờ râu với cắm lại đủ kiểu mà xem Cảnh sát hình sự vẫn nhiễu nên từ đó mặc định có tivi là lắp luôn truyền hình cáp (hồi đầu là 45k/tivi/tháng, toàn trả tiền một cái nhưng cho thêm anh lắp đặt ít tiền để ảnh làm giùm bộ tách, xem thêm ở hai ba tivi nữa). Ngày nảy ngày nay, cáp rồi nhưng còn quẩy thêm bộ giải mã để xem các kênh  hát đê  (cái cục thì có thể tặng nhưng tiền gói thì thêm 50k/tivi/tháng). Đến khổ, càng hiện đại thì càng ăn tiền 😭 Năm ngoái, đứng trước quyết định vô cùng lớn lao khi... lắp tivi, vợ chồng mình đã dấn thân vào con đường khá mới mẻ và (có lẽ) trở thành một trong những cord cutters tiên phong ở Sài Gòn! Hiểu theo nghĩa đen thì cord cutting là việc cầm kéo cắt cái dây truyền hình cáp cái bụp. Sở dĩ không xài truyền hình cáp vì bọn mình thấy bỏ ra một khoản tiền vài trăm ngàn một tháng cho cáp là không hề cần thiết. Mang tiếng là có ...