Saturday, April 4, 2026

Migrating from Renpy to Godot

 Due to the limitation of renpy in rendering dynamic screen , 
due the the black border it gives in different UI scale resolution , finally choosed to migrate to Godot.

Starting point, is to understand anchor and offset to recreate the different screen in renpy. 

===============
Best setting in tscn if need to set width/height in .gd dynamically

expand_mode = 0

stretch_mode = 0 


===========================
Test log from adb
adb logcat -s godot

Thursday, December 18, 2025

Next year SF migration plan : moving out customer account to AWS , and call SF data with service account

 👀 The most challenging part is about those function with user verification.

My service cloud with MIAW chat , nearly redo due to the user verification function of UV channel.

Learnt legacy chat migration to MIAW 2025 ,

Customize the MIAW with AWS 2026.


Understood why people are moving out from SF , not just price , is they don't put focus on their core cloud core technology anymore.


The debug of LWC still like a mess ( the syntax is super ugly ).

Not to mention still not able to make change of it in the platform , still rely on IDE deployment which super annoying. Oh the Flow is much not user friendly in compare to workflow rules and process builder. Super heavy as well .

The NEW things to replace the old are worse than those old things. 
Lightning loading slower than classic , MIAW worse than legacy-chat which is very hard to persuade customer to "upgrade" .

Will I still recommend people to use SF ? yes for core cloud ONLY to be honest.
The rest new clouds are "horrible" , not to mention the Agentforce which looks like a semi-product . 
 

Tuesday, June 24, 2025

Something about Renpy For loop error : expected statement.

 It takes me over hour to debug.
The simple fact is that under label, we cannot use For loop.
One while is valid to be used under label.
To use For loop, must go with python:

Another Finding is about call screen and show screen.
In past, it seems the second one is more appropriate for my case .
With Screen A and button A, to open Screen B.



Thursday, May 8, 2025

Colab naifu , AI read model error

Change 
 File "/content/naifu/hydra_node/models.py", line 215, in __init__

from ckpt=torch.load(self.config.vae_path, map_location="cpu")

to ckpt=torch.load(self.config.vae_path, map_location="cpu" , weights_only=False)


Saturday, April 26, 2025

The JWK file specification , something about the public exponent : AQAB 

I need to configure Salesforce JWT (JSON Web Token) user verification recently.

And there is a file JWK (JSON Web Key) required .The sample document from Salesforce shown as below : 
Salesforce Reference


{
    "kid":"123456",
    "alg":"RS256",
    "use":"sig",
    "kty":"RSA",
    "x5c":["<Your public certificate>"],
    "y":"y",
    "n":"<Base64-encoded modulus>",
    "e":"<Base64-encoded public exponent>",
    "crv":"crv",
    "d":"d",
    "k":"k"
}

In order to know more about the values , I do another search online do know more about each parameters.
Detail RFC specification 
And to know more about the Salesforce sample document, I get a search about the Salesforce specific file format as well. 
Medium Reference

The public exponent now become a fix value "AQAB".

{
"kid": "{A unique value that identifies the end user}",
"alg": "RS256",
"use": "sig",
"kty": "RSA",
"x5c": [
"{Paste the public certificate value here}"
],
"y": "y",
"n": "{modulus of the public key in Base64 format}",
"e": "AQAB",
"crv": "crv",
"d": "d",
"k": "k"
}

Isn't it a variable, why it can be fixed ?


The answer is related to the kty (Key Type) parameter.

When "RSA" is used as key type, then the public exponent of it is 65537.


Convert 65537 to hexadecimal , we got 0x01000. Then we encode the 0x01000 to Base64 , we got "AQAB". 


In short, the base64 format public exponent of RSA is "AQAB".  
And this value is came from conversion of public exponent of RSA key type.

Quoted from Wiki

"65537 is commonly used as a public exponent in the RSA cryptosystem".


Sunday, January 26, 2025

Salesforce Tricks : Add line break to Tool tips or field-level help in Lightning Experience.

 A tool tip of a field can be difficult to read when there is no line break.

In formula , we can use "BR()" , but in tool tip, there is no formal method
The idea is still in Idea Exchange .

And a user posted a workaround here , using the "Japanese full width space" (\u3000).

Copy this :   [          ]

And put above bracket into the Help text where you need the line break. 


For example:
My line 1 
[          ] My line 2


Magic is done.


Wednesday, January 15, 2025

Great free tools for System Integration : Inspecting the HTTP-based request for API testing 免費好用的API測試工具

In order to setup a  HTTP-based API successfully, it is necessary to check request and response.

Postman is a great tool to check the response, how about the request ?

It can be trouble that if we cannot access a 3rd party system's request log while we have to send request to them . How can we verify the request we made is valid ? If the request will be altered by some middleware we may not able to touch ?

Here is one of the solution , make a mock server to capture the final request to the endpoint.
In past , it may takes time to setup a mock server , now , it becomes super easy. 

The great tool here is beeceptor !!! No registration needed , no installation needed.
Just need one browser tab ~

Steps as simple as below :

  1. Create an endpoint at https://beeceptor.com/ and leave this browser tab open.
    The endpoint will be like : 
    https://{your_input_name}.free.beeceptor.com 



  2. Change the endpoint used in code to the endpoint you just created .
  3. Execute the request in code from your IDE or other place , just execute your callout code.
  4. Refresh your https://beeceptor.com/ browser tab .
  5. Now you can check the request and header you just send, and you may create any response in the mock server .


Is is simple and easy , recommended by many platform like Salesforce.
Reference : 
https://help.salesforce.com/s/articleView?id=000384720&type=1

Thanks for reading.





Tuesday, October 15, 2024

Salesforce flow or Process deployment : Setting of active and test flow coverage

When deploy a new flow, it is default to be inactive.

But there is a setting to make it active in PROD org called "Process Automation Settings". 


We need to ensure coverage of the automation . It can be check by SOQL to FlowTestCoverage:

To calculate your flow test coverage, determine the number of all active flow versions with or without test coverage.
Single SOQL with + symbol.

SELECT count_distinct(Id) 
FROM Flow 
WHERE Status = 'Active' AND Id NOT IN ( 
SELECT FlowVersionId 
FROM FlowTestCoverage 
)
+
SELECT count_distinct(FlowVersionId) 
FROM FlowTestCoverage

 

Ref :https://help.salesforce.com/articleView?id=sf.flow_distribute_deploy_active.htm&type=5

Sunday, July 7, 2024

Python Error (Renpy) : TypeError: 'str' object is not callable

Met an error in renpy when writing the action function of an image button like below :
 action Function( '\u2192', pygame.K_RIGHT)

Error shown as below : 
File "renpy/common/00action_other.rpy", line 583, in __call__

    rv = self.callable(*self.args, **self.kwargs)

TypeError: 'str' object is not callable

Forgot to add the function name 
Corrected the syntax to below (also added the parameter name to before value):
action Function(simulate_keypress, unicode_key='\u2192', pygame_key=pygame.K_RIGHT)


Friday, June 28, 2024

Window Command line : Super easy command to search file in whole PC quickly

 1: cd "therootpath" 

2: dir "filename.extension" /s

For example search tje entire C drive : 
C:\>dir "myFile.jar" /s

Save me a day when searching for a jar file ...

Friday, March 22, 2024

安而後能慮。Think and plan , implement later . All about Patient .

成長可以很早,可以很晚。最近一年的感覺是,這件事,好像終於到我身上來了。
深深體會沒耐心的壞處,凡事等一等,是今年的大課題。


知止而後有定,定而後能靜;

靜而後能安,安而後能慮,慮而後能得。


太急進,急於求成,是很大的性格缺憾。管理人或事,都成很大的絆腳石。

Thursday, December 28, 2023

上架Play Store 之路 : Java Keytool 的亂碼字符 還有 存取被拒 使用的簽署憑證即將過期 的解決方法

第一次做react native App , 因電腦配備低只用React Native Cli. 

需要 Keytool做keystore. 

然後遇上第一個難關:
Run 以下command ,出現了亂碼 :
keytool -genkey -v -keystore my_key_name.keystore -alias my_key_alias -keyalg RSA -keysize 2048 -validity 10000 

原因是中文Window OS (也可能只有Win 10 這樣?) 

解決方法是輸入 : chcp 936 
將encoding 轉utf-8 . 

接著是第二個難關
密碼都打完了,卻發生存取被拒,無法生成keystore. 
解決方法是用管理員身份執行 Command line ... 😅

第三個難關
上載至Play Console 後,出現 
你上載的 APK 或 Android App Bundle 使用的簽署憑證即將過期,請使用有效期至較遠時間的憑證簽署 APK 或 Android App Bundle。

解決方法是修改validity 至更長時間
插曲 : 最後發現copy 至commandline時出錯,少copy 了validity..😭 

keytool -genkey -v -keystore my_key_name.keystore -alias my_key_alias -keyalg RSA -keysize 2048 -validity 20000 

第四個難關
是修改證書時間後再上載,然後出現的..
由於 Google Play 中已存在「com.xxx」,你需要改用其他套件名稱

解決方法是修改build.gradle中的applicationId...

第5個難關

都上載完成了,但是測試員無法下載...
A testing version of this app hasn't been published yet or isn't available for this account.

後來終於找到類似的解答 : Alpha test (Closed test封閉測試) 要等Google Review完成,才可以讓測試員下載。

Quoted : "
Every new app version that you release on Closed testing track are religiously reviewed by Google before they are made available to the testers. During this time, the release will show up as “in review” in the PlayStore console."

Ref : 這一篇關於Google Play Store Alpha Testing

根據文章資料,一般Google Review需要數小時至4天...

為了上架,撞得頭破血流了,希望快點Review完成,一切順利。

Sunday, November 12, 2023

Batch Script : The mystery of setting variable inside for loop

 Spend whole day to figure out how to get a random terms inside for loop.


Tried %%list[!index!]%% , %list[!index!]% , !list[%index%]! many many combination. 

Finally, a "call" made the magic.


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
@echo off

setlocal enabledelayedexpansion



REM Define the list

set "list[0]=a"

set "list[1]=b"

set "list[2]=c"



REM Enable delayed expansion within the loop

for /l %%i in (1,1,3) do (

    REM Generate a random index within the range of the list

    set /a "index=!random! %% 3"

    

    REM without that call, cannot get the string

    call set "randomString=%%list[!index!]%%"

    

    REM Print the iteration number and the corresponding random string

    echo Random string for iteration %%i: !randomString!

)



endlocal

Tuesday, August 22, 2023

Colab Python web service : Cannot get expected return with json passing to REST API

Another silly mistake I made due carelessness .
I spent certain hours to just figure out the root-cause : Missing json.dumps when I pass the data.
Originally, I think put json content in header is OK...


#Call Rest API with json data
import requests
import json
import os

baseUrl = 'endpointAddr/api-link'

#Parameters
data = {
   "id":"1234568",
   "currency":"HKD",
   "amount":"1000"
}




#function to call
def callAPI():
    response = requests.post(baseUrl,headers={"Content-Type": "application/json","Authorization": "Bearer xxxxxxxxxxxxxxx"}, data=json.dumps(data))

    if response.status_code == 200:
       print('Access token test :' , response.json())
       authToken = response.json()['access_token']
       print('Access token:', authToken)
       return (authToken)
    else:
        print('Login failed with status code:', response.status_code , response.text)
        return (0)


#Main
response1 = callAPI()
print ('response 1 ' + response1)

Wednesday, August 2, 2023

Python Coding : Call Salesforce API using OAuth 2.0 JWT Bearer token Flow 以 Python 代碼實現Salesforce JWT 伺服器簽名驗證

Prequisites : Setup Connected App with  X509 Certification.

預設需要先在Salesforce 上載X509證書。詳細設定連接。(可接受自行簽署版本證書)

Details Set up in Salesforce side : link



#POC of JWT call to API#Colab install library with >> !pip install pyJWT[crypto]

import jwt
from cryptography.hazmat.primitives import serialization
from cryptography.hazmat.primitives.asymmetric import rsa
import time
import requests
import json

expTime = int(time.time()) + 900  #Unix Epoch Timestamp Expire time. 15mins buffer
jwt_algorithm = 'RS256'
jwt_private_key_file = '/myPath/server.key'
jwt_payload = {
  "iss": "clientid",
  "sub": "salesforce_username_email",
  "aud": "https://test.salesforce.com",
  "exp": expTime
}

jwt_header = {
  "alg": "RS256",
  "typ": "JWT"
}
salesforceEndpoint = 'https://test.salesforce.com/services/oauth2/token'
api_endpoint = 'https://instance_domain.my.salesforce.com/services/data/v57.0/sobjects/myObject__c'

test_data={
    "description": "PythonSent",
    "language": "en",
    "remarks": "xxx",
    "expiry_time": expTime+900,
    "created_time": expTime
}


def loginSfdc():
    # Load the private key 
    with open(jwt_private_key_file, 'r') as f:
        jwt_private_key = f.read()

    # Generate the JWT token
    jwt_token = jwt.encode(jwt_payload, jwt_private_key, algorithm=jwt_algorithm,headers=jwt_header)
    print('token : ' + jwt_token);
    salesforceUrlParams = {
        'grant_type' : 'urn:ietf:params:oauth:grant-type:jwt-bearer',
        'assertion' :jwt_token
    }

    response = requests.post(salesforceEndpoint, params=salesforceUrlParams, verify=False)

    if response.status_code == 200:
        authToken = response.json()['access_token']
        print('return token ' + authToken)
        return authToken
    else:
        print('Request failed with status code:', response.status_code)
        print('Request failed with status code:', response.text)
        return(0)

#function to call
def callSfdc_pocApi(authToken):
    session = requests.Session()
    rheaders = {
    'Authorization': 'Bearer ' + authToken,
    'Content-Type': 'application/json'
    }
   
    response = requests.post(api_endpoint,headers=rheaders, data=json.dumps(test_data))
    returnStr = ''
    if response.status_code == 200:
        data = response.json()
        returnStr = data
    else:
        print('Request failed with status code:', response.text)
        returnStr = response.status_code

    return returnStr

#Main
response1 = loginSfdc()
if not response1 == 0:
    response2 = callSfdc_pocApi(response1)
    print ("OK")
    print(response2)
else:
    print ('Failed to Login')

Thursday, June 29, 2023

超老舊軟體PhotoImpact X3走在Window 10 , 停止在 "正在初始化主要視窗及元件"階段 . 錯誤碼0xc0000005解決方法

一直在Window 10 (64bit) 上使用PhotoImpact X3 都好好的,今天突然開不到。
查了很多資料,最後發現是暫存檔的問題。

把以下位置中所有今天才生成的檔案移走,重開就行了。
C:\Users\YOUR_NAME\AppData\Roaming\Ulead Systems\Ulead PhotoImpact\13.0\Ulead.DAT\

從中學開始用了PhotoImpact 系列20年,升學及工作都多用Photoshop,但自用時還是更喜歡輕量易用的PhotoImpact 呢!~

Saturday, April 1, 2023

C# coding : Download Salesforce attachment to local disk using SOAP webservice Enterprise wsdl method (with SOQL selection)

Pre-requisite :

  • Select Target framework to 4.5.2 
  • Install DeveloperForce.Force 2.1.0 (via nuget if VS2015 is used)
  • Import Enterprise wsdl as WebReference (for easy Type Casting , partner wsdl also work but need more code lines.)
  • Update 2 ListViewRecordColumn[][] in Reference.cs to ListViewRecordColumn[].
    Otherwise, error  as below will be shown :
    Cannot convert type 'SaleForceBase.SaleForceRef.ListViewRecordColumn[]' ...

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Salesforce;
using System.IO;
using ConsoleApplication1.SfService;

namespace ConsoleApplication1

{
    class Program
    {
        static void Main(string[] args)
        {

            System.Net.ServicePointManager.SecurityProtocol = System.Net.SecurityProtocolType.Ssl3 | System.Net.SecurityProtocolType.Tls12;//Added to fix he request was aborted could not create ssl/tls secure channel.

            //Get Salesforce credentials
            var username = "your_salesforce_username";
            var password = "your_salesforce_password";
	   //var token = "your_salesforce_security_token";//uncomment this if you have enabled security token function. 

            var authEndpoint = "https://login.salesforce.com/services/Soap/u/50.0";

            // Login to Salesforce using SOAP API

            var binding = new SforceService();

            try {

            var loginResult = binding.login(username, password);
	    //var loginResult = binding.login(username, password + your_salesforce_security_token); //use this instead of above to login if you have enabled security token function. 
            binding.Url = loginResult.serverUrl;
            binding.SessionHeaderValue = new SessionHeader { sessionId = loginResult.sessionId };

            // Query for to get 5 attachments related to Account object

            var attachmentQuery = "SELECT Id, Name, ParentId FROM Attachment WHERE Parent.Type = 'Account' ORDER BY ParentId limit 5";
            var queryResult = binding.query(attachmentQuery);

            // Loop through the results and download each attachment

            foreach (var sObject in queryResult.records)

            {

                var attachment = (Attachment)sObject;//retrieve(string fieldList, string sObjectType, ID ids[]);
                var account = (Account)binding.retrieve("Name", "Account", new string[] { attachment.ParentId })[0];//returned as sObject[] , so need to get [0] 

                // Create a file name for the attachment

                var fileName = $"{account.Name} - {attachment.Name}";

                // Download the attachment

                var attachmentBody = (Attachment)binding.retrieve("Body" ,"Attachment",  new string[] { attachment.Id })[0];
                File.WriteAllBytes(fileName, attachmentBody.Body);
				
            }
            }
            catch(Exception ex)
            {
                System.Diagnostics.Debug.WriteLine("Error : " + ex.InnerException);
                System.Diagnostics.Debug.WriteLine("Error2 : " + ex.StackTrace);
                System.Diagnostics.Debug.WriteLine("Error3 : " + ex.Message);
            }
        }
    }
}

 

Thursday, March 16, 2023

Colab : ImportError cannot import name 'rank_zero_only' from 'pytorch_lightning.utilities.distributed' (Stable Diffusion WebUI related) AI生成圖片Colab偵錯

When I am trying to use Colab for stable diffusion ,
I met error below today :

ImportError cannot import name 'rank_zero_only' from 'pytorch_lightning.utilities.distributed'


After searching , I got the answer finally from here.

Changed From : from pytorch_lightning.utilities.distributed import rank_zero_only 


To : from pytorch_lightning.utilities.rank_zero import rank_zero_only 


Before Run , remember to downgrade !pip install pydantic==1.10.11





So I updated the line 20 in file ddpm.py as indicated in debug log, and the issue is resolved. 




Friday, January 13, 2023

Salesforce concept : Limitation of Rollup Summary and Validation Rule

Question : Rollup summary CANNOT be used in formula field ?
Answer : No .
Rollup Summary can be used to group field values of child record .

Even thought it is formula type field , however ,
grouped field values CANNOT be cross-object formula field.


Question : How to validate the field values changed by Approval process ?
Answer : Validation is NOT a choice . Since field update fired by approval process will NOT initiate validation rule. (More explicit answer from google  , Validation Rules fire before workflow rules, so the record has to meet the validation rule criteria before the workflows get a chance to run. So, the validation rule will not work when you update the workflow field.)

Tigger can be used to validate the field values changed by approval process.

Monday, December 19, 2022

Lyrics about destiny , karma and sin .陳健安 On Chan - 《在錯誤的宇宙尋找愛》

意外聽到一首2019的歌,看了MV和歌詞,就喜歡上了。 
這種帶點宗教宿命色彩的詞總是很吸引我。
超脫得很浪漫。

詞: 黃偉文 曲: 馮穎琪

編/:謝國維 意識一早超脫 情愛這東西 越過了天地 並未眷戀螻蟻 沒有光陰跟遠近 我是叢電波 破天際 但你的召喚 讓我將功德放低 為你呱呱出世 回到這身體 自降四千等 為覓人類一吻 作謝禮 誰話愛戀 苦海濟世 會創造奇蹟 將蒼生撫慰 被你吸引 讓我當初失智慧 這宇宙 這種深情根本虛構 失了足 才會跌落你的地球 目光遠大如我 你有限維度裡 看春秋 很後悔 但愛死方會得救 為了找到真愛 尋遍每粒沙 住進你的家 就為明白這叫 錯誤嗎 求做對簡單的愛侶 與你歷其境 方知多可怕 沒法擺脫 俗套的分手戲碼 這宇宙 這種深情根本虛構 失了足 才會跌落你的地球 上天已難回去 我似被囚在你 那春秋 不恨你 恨我太晚參透 親手作孽 惡果他人怎可解救 貪怨癡 要葬在你的地球 為了擁抱你 換這雙手 一早已 被切去兩翼 禁飛走 這樣勇 試問你可能夠 自絕位列仙班 都不算太內疚 但愛到欠自我 我笑我下流 這宇宙 這種深情根本虛構 失了足 才會跌入你的溫柔 在你的結界 盪過韆鞦 我便無力 再看北斗 不恨你 恨我的反抗不夠 我的愛全被接收 必須再重頭禪修 練到清心寡愛 無懼色誘

Migrating from Renpy to Godot

 Due to the limitation of renpy in rendering dynamic screen ,  due the the black border it gives in different UI scale resolution , finally ...