2018年8月27日 星期一

[轉載都市日報 20180824] 轉按律師費最平幾錢?

轉按律師費最平幾錢?
關於物業轉按的好處,本欄曾經多次提及,今次希望談談轉按唯一開支──律師費。
由於牽涉合約條款轉變,業主申請轉按時需赴律師樓簽訂按揭契約,現時市場最便宜律師費僅約5,000元。坊間有些律師樓稱律師費僅4,000餘元,但未必是「全包價」。除了律師費,全包價還包括政府登記費、查冊費和雜費。如轉按需要甩名,筆者格價後發現最平6,000多元全包。
值得注意的是,有些項目即使是「全包價」亦不包括在內,例如「補契費」。比如如業主將樓契放在牀下底,遺失了當中幾份文件,律師樓便要從土地註冊處「補契」,每份約數百元。如果樓契是由銀行持有,理論上不會遺失,但若果物業因應維修令、欠管理費而被「起釘」,將會註入新文書,屆時律師樓亦要補回這些文件,按數量收費。新樓入伙後的轉按也經常要補契。
如果按揭有擔保人,律師樓需要準備額外文件,會牽涉數百元附加費。如果要經按揭保險、註租約等,每項操作都要額外費用,一般也是幾百元。有業主轉按套現為找卡數,希望將年息30厘息債務,轉化成年息僅2厘多按揭息,不過由於銀行擔心貸款人套現後不願還卡數,故此這項貸款需由律師樓代為繳支,手續費一般是每張信用卡幾百元。
總結而言,若果不需要補契、擔保、按揭保險、找卡數,其實轉按手續費只需約5,000元。這項手續費相比數萬元銀行現金回贈,實在是微不足道。
最後想談談律師樓流程。業主簽署貸款信後,便可聯絡律師樓辦手續;業主再簽授權信後,代表律師便可向原銀行取回樓契,一般需時一個月。如果業主在這個月想查詢進度,最有效方法是直接致電原銀行放契部門查詢。當律師樓收到銀行發送樓契,便可處理文件完成轉按手續;律師樓收到樓契後,業主約兩周就可以提取貸款(Drawdown)。
至於如何選擇律師樓?當然是收費愈平愈好,原因是轉按程序公式化,文件都是根據標準樣本,所以找間既便宜、銀行又認可的律師樓便可以。
子非魚
(逢周五見報)
星之谷按揭轉介榮獲《都市日報》2017傑出轉按顧問大獎,以及2018卓越品牌大獎,並出版「按揭達人」一書
公司網址:https://starpagency.com

2018年8月24日 星期五

[ServiceNow] Email Notification > Send to Event Creator

I think that it is misleading.

The Notification will not be sent to the User who caused the Notification to be triggered unless Send to event creator is checked.

Send to event creator doesn't add that person to the list of recipients. It simply doesn't omit him if he IS in the list...



2018年8月17日 星期五

[ServiceNow] Simple UI Page using Jelly

<?xml version="1.0" encoding="utf-8" ?>

<j:jelly trim="false" xmlns:j="jelly:core" xmlns:g="glide" xmlns:j2="null" xmlns:g2="null">
<!-- query -- >
<g:evaluate var="jvar_gr" object="true">

 var gr = new GlideRecord("u_email_lookup");

 gr.addEncodedQuery("u_emailINchantaiman@yahoo.com.hk,chantaiman@gmail.com");

 gr.orderBy('u_email_lookup');

 gr.setLimit(1);

 gr.query();

 gr;

</g:evaluate>

 
<!-- iterate gliderecord -- >
<table border="1"> <j:while test="${jvar_gr.next()}"> <tr> <td style="padding:5px"><a href="incident.do?sys_id=${jvar_gr.getValue('u_email')}">${jvar_gr.getValue('u_email')}</a></td> <td style="padding:5px">${jvar_gr.getValue('u_category')}</td> <td style="padding:5px"> ${jvar_gr.getValue('u_subcategory')}</td> </tr> </j:while> </table> </j:jelly>

2018年8月9日 星期四

[JAVA] Google Authenticator 2FA Implementation / TOTP

Library / file required:

Apache Commons Codec

https://commons.apache.org/proper/commons-codec/download_codec.cgi


Download TOTP.java

https://tools.ietf.org/html/rfc6238


Put TOTP.java and Test.java together and run.

Good luck.



import org.apache.commons.codec.binary.Base32;
import org.apache.commons.codec.binary.Hex;

public class Test {
 public static void main(String[] args) {
  String seed = "JBSWY3DPEHPK3PXP";
  System.out.println(getTOTPCode(seed));
 }

 public static String getTOTPCode(String secretKey) {
  String normalizedBase32Key = secretKey.replace(" ", "").toUpperCase();
  Base32 base32 = new Base32();
  byte[] bytes = base32.decode(normalizedBase32Key);
  String hexKey = Hex.encodeHexString(bytes);
  long time = (System.currentTimeMillis() / 1000) / 30;
  String hexTime = Long.toHexString(time);
  return TOTP.generateTOTP(hexKey, hexTime, "6");
 }

}

[C#] Google Authenticator 2FA Implementation / TOTP

Here you go!

Create a "Window Console Application" and paste the following code to Program.cs, then press Ctrl F5.

Good Luck!

For Java implementation of Totp, please visit https://tools.ietf.org/html/rfc6238


namespace ConsoleApp1
{
    class Program
    {
        static void Main(string[] args)
        {
            string secret = "JBSWY3DPEHPK3PXP";
            var bytes = Base32Encoding.ToBytes(secret);

            var totp = new Totp(bytes);

            var result = totp.ComputeTotp();
            var remainingTime = totp.RemainingSeconds();
            Console.WriteLine(result);
        }
    }

    public class Totp
    {
        const long unixEpochTicks = 621355968000000000L;

        const long ticksToSeconds = 10000000L;

        private const int step = 30;

        private const int totpSize = 6;

        private byte[] key;

        public Totp(byte[] secretKey)
        {
            key = secretKey;
        }

        public string ComputeTotp()
        {
            var window = CalculateTimeStepFromTimestamp(DateTime.UtcNow);

            var data = GetBigEndianBytes(window);

            var hmac = new HMACSHA1();
            hmac.Key = key;
            var hmacComputedHash = hmac.ComputeHash(data);

            int offset = hmacComputedHash[hmacComputedHash.Length - 1] & 0x0F;
            var otp = (hmacComputedHash[offset] & 0x7f) << 24
                   | (hmacComputedHash[offset + 1] & 0xff) << 16
                   | (hmacComputedHash[offset + 2] & 0xff) << 8
                   | (hmacComputedHash[offset + 3] & 0xff) % 1000000;

            var result = Digits(otp, totpSize);

            return result;
        }

        public int RemainingSeconds()
        {
            return step - (int)(((DateTime.UtcNow.Ticks - unixEpochTicks) / ticksToSeconds) % step);
        }

        private byte[] GetBigEndianBytes(long input)
        {
            // Since .net uses little endian numbers, we need to reverse the byte order to get big endian.
            var data = BitConverter.GetBytes(input);
            Array.Reverse(data);
            return data;
        }

        private long CalculateTimeStepFromTimestamp(DateTime timestamp)
        {
            var unixTimestamp = (timestamp.Ticks - unixEpochTicks) / ticksToSeconds;
            var window = unixTimestamp / (long)step;
            return window;
        }

        private string Digits(long input, int digitCount)
        {
            var truncatedValue = ((int)input % (int)Math.Pow(10, digitCount));
            return truncatedValue.ToString().PadLeft(digitCount, '0');
        }

    }

    public static class Base32Encoding
    {
        public static byte[] ToBytes(string input)
        {
            if (string.IsNullOrEmpty(input))
            {
                throw new ArgumentNullException("input");
            }

            input = input.TrimEnd('='); //remove padding characters
            int byteCount = input.Length * 5 / 8; //this must be TRUNCATED
            byte[] returnArray = new byte[byteCount];

            byte curByte = 0, bitsRemaining = 8;
            int mask = 0, arrayIndex = 0;

            foreach (char c in input)
            {
                int cValue = CharToValue(c);

                if (bitsRemaining > 5)
                {
                    mask = cValue << (bitsRemaining - 5);
                    curByte = (byte)(curByte | mask);
                    bitsRemaining -= 5;
                }
                else
                {
                    mask = cValue >> (5 - bitsRemaining);
                    curByte = (byte)(curByte | mask);
                    returnArray[arrayIndex++] = curByte;
                    curByte = (byte)(cValue << (3 + bitsRemaining));
                    bitsRemaining += 3;
                }
            }

            //if we didn't end with a full byte
            if (arrayIndex != byteCount)
            {
                returnArray[arrayIndex] = curByte;
            }

            return returnArray;
        }

        public static string ToString(byte[] input)
        {
            if (input == null || input.Length == 0)
            {
                throw new ArgumentNullException("input");
            }

            int charCount = (int)Math.Ceiling(input.Length / 5d) * 8;
            char[] returnArray = new char[charCount];

            byte nextChar = 0, bitsRemaining = 5;
            int arrayIndex = 0;

            foreach (byte b in input)
            {
                nextChar = (byte)(nextChar | (b >> (8 - bitsRemaining)));
                returnArray[arrayIndex++] = ValueToChar(nextChar);

                if (bitsRemaining < 4)
                {
                    nextChar = (byte)((b >> (3 - bitsRemaining)) & 31);
                    returnArray[arrayIndex++] = ValueToChar(nextChar);
                    bitsRemaining += 5;
                }

                bitsRemaining -= 3;
                nextChar = (byte)((b << bitsRemaining) & 31);
            }

            //if we didn't end with a full char
            if (arrayIndex != charCount)
            {
                returnArray[arrayIndex++] = ValueToChar(nextChar);
                while (arrayIndex != charCount) returnArray[arrayIndex++] = '='; //padding
            }

            return new string(returnArray);
        }

        private static int CharToValue(char c)
        {
            int value = (int)c;

            //65-90 == uppercase letters
            if (value < 91 && value > 64)
            {
                return value - 65;
            }
            //50-55 == numbers 2-7
            if (value < 56 && value > 49)
            {
                return value - 24;
            }
            //97-122 == lowercase letters
            if (value < 123 && value > 96)
            {
                return value - 97;
            }

            throw new ArgumentException("Character is not a Base32 character.", "c");
        }

        private static char ValueToChar(byte b)
        {
            if (b < 26)
            {
                return (char)(b + 65);
            }

            if (b < 32)
            {
                return (char)(b + 24);
            }

            throw new ArgumentException("Byte is not a value Base32 value.", "b");
        }

    }
}

2018年8月6日 星期一

取消八達通自動增值服務

取消八達通自動增值服務
  1. 致電八達通顧客服務熱線2266 2222
  2. 按 1 選廣東話
  3. 按 3 > 1 > 1 > 5
  4. 輸入 [八達通卡號碼] > # > 身份證頭6位數字 > 按 1 確認


之後八達通公司會發一封確認取消自動增值服務的信給你。

信件發出日期起計10天內跑去任何港鐵客務中心辦理取消手續。

完成手續後,自動增值服務會被即時取消,而八達通的付款功能仍可繼續使用。