2018年12月19日 星期三

[ServiceNow] Search scripts among workflow activities

1) In the Navigator filter box, type sys_variable_value.list <-- This takes you to the table to search


2) Click on the Filter wizard icon to create a custom filter
--- Table (document) is wf_activity AND
--- Variable.Column Name contains script' OR
------ Variable.Type.Name contains 'script' AND
--- Value contains [whatever you are searching for]

2018年12月11日 星期二

Javascript: html encode and decode

            function htmlencode(s) {
                var div = document.createElement('div');
                div.appendChild(document.createTextNode(s));
                return div.innerHTML;
            }
            function htmldecode(s) {
                var div = document.createElement('div');
                div.innerHTML = s;
                return div.innerText || div.textContent;
            }


Enjoy!!!

2018年11月23日 星期五

[C#] How to convert Active Directory pwdLastSet to Date/Time

From https://stackoverflow.com/questions/18614810/how-to-convert-active-directory-pwdlastset-to-date-time

According to the MSDN documentation:
This value is stored as a large integer that represents the number of 100 nanosecond intervals since January 1, 1601 (UTC).
This aligns perfectly with DateTime.FromFileTimeUtcas described here.
And I'm not sure why you feel the need to do the low level manipulation of the integer. I think you could just cast it.
So just do:
long value = (long)objResult.Properties["pwdLastSet"][0];
DateTime pwdLastSet = DateTime.FromFileTimeUtc(value);

2018年9月27日 星期四

[Active Directory] Full name vs Display name

Reference: https://www.zubairalexander.com/blog/the-strange-way-in-which-active-directory-implements-the-full-name-attribute/


The Strange Way in Which Active Directory Implements the Full Name Attribute

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天內跑去任何港鐵客務中心辦理取消手續。

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

2018年7月30日 星期一

2018 香港人生日優惠

最後更新︰2018年7月28日

免費的只剩下海洋公園和杜麗莎夫人蠟像館

海洋公園


生日當天出示身份證可免費入場

杜麗莎夫人蠟像館


由生日前一星期至生日後一星期期間,出示身份證可免費入場一次。

天際100


生日當天携同最少有一名朋友購票進場,壽星仔可免費進場。

2018年7月18日 星期三

[C# MVC] Force Web Application using HTTPS

Step 1:)

Select your web application > then go to "Properties" windows > set "SSL Enabled" to True

Pay attention to the SSL port




Step 2:)

Open Globa.asax.cs > type the following code

Make sure the SSL port here is equal to the one in web application properties.


Step 3:)

You may add [RequireHttps] to Controllers.



Press Ctrl F5 to test, good luck

2018年7月17日 星期二

Create Linked Servers (SQL Server Database Engine)

最近公司的DATABASE更新為SQL SERVER 2017。可是ORACLE IM的java runtime是1.6,嘗試CONNECT到SQL SERVER 2017時發生EXCEPTION︰

The driver could not establish a secure connection to SQL Server by using Secure Sockets Layer (SSL) encryption.

Microsoft提供了一些解決方法


不過現在公司的方向是LINKED SERVER,研究中……


source: https://docs.microsoft.com/en-us/sql/relational-databases/linked-servers/create-linked-servers-sql-server-database-engine?view=sql-server-2017

Create Linked Servers (SQL Server Database Engine)

THIS TOPIC APPLIES TO: yesSQL ServernoAzure SQL DatabasenoAzure SQL Data Warehouse noParallel Data Warehouse
For content related to previous versions of SQL Server, see Create Linked Servers (SQL Server Database Engine).
This topic shows how to create a linked server and access data from another SQL Server by using SQL Server Management Studio or Transact-SQL. By creating a linked server, you can work with data from multiple sources. The linked server does not have to be another instance of SQL Server, but that is a common scenario.

Background

A linked server allows for access to distributed, heterogeneous queries against OLE DB data sources. After a linked server is created, distributed queries can be run against this server, and queries can join tables from more than one data source. If the linked server is defined as an instance of SQL Server, remote stored procedures can be executed.
The capabilities and required arguments of the linked server can vary significantly. The examples in this topic provide a typical example but all options are not described. For more information, see sp_addlinkedserver (Transact-SQL).

Security

Permissions

When using Transact-SQL statements, requires ALTER ANY LINKED SERVER permission on the server or membership in the setupadmin fixed server role. When using Management Studio requires CONTROL SERVER permission or membership in the sysadmin fixed server role.

How to Create a Linked Server

You can use any of the following:

Using SQL Server Management Studio

To create a linked server to another instance of SQL Server Using SQL Server Management Studio

  1. In SQL Server Management Studio, open Object Explorer, expand Server Objects, right-click Linked Servers, and then click New Linked Server.
  2. On the General page, in the Linked server box, type the name of the instance of SQL Server that you area linking to.
    SQL Server
    Identify the linked server as an instance of Microsoft SQL Server. If you use this method of defining a SQL Server linked server, the name specified in Linked server must be the network name of the server. Also, any tables retrieved from the server are from the default database defined for the login on the linked server.
    Other data source
    Specify an OLE DB server type other than SQL Server. Clicking this option activates the options below it.
    Provider
    Select an OLE DB data source from the list box. The OLE DB provider is registered with the given PROGID in the registry.
    Product name
    Type the product name of the OLE DB data source to add as a linked server.
    Data source
    Type the name of the data source as interpreted by the OLE DB provider. If you are connecting to an instance of SQL Server, provide the instance name.
    Provider string
    Type the unique programmatic identifier (PROGID) of the OLE DB provider that corresponds to the data source. For examples of valid provider strings, see sp_addlinkedserver (Transact-SQL).
    Location
    Type the location of the database as interpreted by the OLE DB provider.
    Catalog
    Type the name of the catalog to use when making a connection to the OLE DB provider.
    To test the ability to connect to a linked server, in Object Explorer, right-click the linked server and then click Test Connection.
    Note
    If the instance of SQL Server is the default instance, enter the name of the computer that hosts the instance of SQL Server. If the SQL Server is a named instance, enter the name of the computer and the name of the instance, such as Accounting\SQLExpress.
  3. In the Server type area, select SQL Server to indicate that that the linked server is another instance of SQL Server.
  4. On the Security page, specify the security context that will be used when the original SQL Server connects to the linked server. In a domain environment where users are connecting by using their domain logins, selecting Be made using the login’s current security context is often the best choice. When users connect to the original SQL Server by using a SQL Server login, the best choice is often to select By using this security context, and then providing the necessary credentials to authenticate at the linked server.
    Local login
    Specify the local login that can connect to the linked server. The local login can be either a login using SQL Server Authentication or a Windows Authentication login. Use this list to restrict the connection to specific logins, or to allow some logins to connect as a different login.
    Impersonate
    Pass the username and password from the local login to the linked server. For SQL Server Authentication, a login with the exact same name and password must exist on the remote server. For Windows logins, the login must be a valid login on the linked server.
    To use impersonation, the configuration must meet the requirement for delegation.
    Remote User
    Use the remote user to map users not defined in Local login. The Remote User must be a SQL Server Authentication login on the remote server.
    Remote Password
    Specify the password of the Remote User.
    Add
    Add a new local login.
    Remove
    Remove an existing local login.
    Not be made
    Specify that a connection will not be made for logins not defined in the list.
    Be made without using a security context
    Specify that a connection will be made without using a security context for logins not defined in the list.
    Be made using the login's current security context
    Specify that a connection will be made using the current security context of the login for logins not defined in the list. If connected to the local server using Windows Authentication, your windows credentials will be used to connect to the remote server. If connected to the local server using SQL Server Authentication, login name and password will be used to connect to the remote server. In this case a login with the exact same name and password must exist on the remote server.
    Be made using this security context
    Specify that a connection will be made using the login and password specified in the Remote login and With password boxes for logins not defined in the list. The remote login must be a SQL Server Authentication login on the remote server.
  5. Optionally, to view or specify server options, click the Server Options page.
    Collation Compatible
    Affects Distributed Query execution against linked servers. If this option is set to true, SQL Server assumes that all characters in the linked server are compatible with the local server, with regard to character set and collation sequence (or sort order). This enables SQL Server to send comparisons on character columns to the provider. If this option is not set, SQL Server always evaluates comparisons on character columns locally.
    This option should be set only if it is certain that the data source corresponding to the linked server has the same character set and sort order as the local server.
    Data Access
    Enables and disables a linked server for distributed query access.
    RPC
    Enables RPC from the specified server.
    RPC Out
    Enables RPC to the specified server.
    Use Remote Collation
    Determines whether the collation of a remote column or of a local server will be used.
    If true, the collation of remote columns is used for SQL Server data sources, and the collation specified in collation name is used for non- SQL Server data sources.
    If false, distributed queries will always use the default collation of the local server, while collation name and the collation of remote columns are ignored. The default is false.
    Collation Name
    Specifies the name of the collation used by the remote data source if use remote collation is true and the data source is not a SQL Server data source. The name must be one of the collations supported by SQL Server.
    Use this option when accessing an OLE DB data source other than SQL Server, but whose collation matches one of the SQL Server collations.
    The linked server must support a single collation to be used for all columns in that server. Do not set this option if the linked server supports multiple collations within a single data source, or if the linked server's collation cannot be determined to match one of the SQL Server collations.
    Connection Timeout
    Time-out value in seconds for connecting to a linked server.
    If 0, use the sp_configure default remote login timeout option value.
    Query Timeout
    Time-out value in seconds for queries against a linked server.
    If 0, use the sp_configure default remote query timeout option value.
    Enable Promotion of Distributed Transactions
    Use this option to protect the actions of a server-to-server procedure through a Microsoft Distributed Transaction Coordinator (MS DTC) transaction. When this option is TRUE, calling a remote stored procedure starts a distributed transaction and enlists the transaction with MS DTC. For more information, see sp_serveroption (Transact-SQL).
  6. Click OK.

To view the provider options

  • To view the options that the provider makes available, click the Providers Options page.
    All providers do not have the same options available. For example, some types of data have indexes available and some might not. Use this dialog box to help SQL Server understand the capabilities of the provider. SQL Server installs some common data providers, however when the product providing the data changes, the provider installed by SQL Server might not support all the newest features. The best source of information about the capabilities of the product providing the data is the documentation for that product.
    Dynamic parameter
    Indicates that the provider allows '?' parameter marker syntax for parameterized queries. Set this option only if the provider supports the ICommandWithParameters interface and supports a '?' as the parameter marker. Setting this option allows SQL Server to execute parameterized queries against the provider. The ability to execute parameterized queries against the provider can result in better performance for certain queries.
    Nested queries
    Indicates that the provider allows nested SELECT statements in the FROM clause. Setting this option allows SQL Server to delegate certain queries to the provider that require nesting SELECT statements in the FROM clause.
    Level zero only
    Only level 0 OLE DB interfaces are invoked against the provider.
    Allow inprocess
    SQL Server allows the provider to be instantiated as an in-process server. When this option is not set, the default behavior is to instantiate the provider outside the SQL Server process. Instantiating the provider outside the SQL Server process protects the SQL Server process from errors in the provider. When the provider is instantiated outside the SQL Server process, updates or inserts referencing long columns (textntext, or image) are not allowed.
    Non transacted updates
    SQL Server allows updates, even if ITransactionLocal is not available. If this option is enabled, updates against the provider are not recoverable, because the provider does not support transactions.
    Index as access path
    SQL Server attempts to use indexes of the provider to fetch data. By default, indexes are used only for metadata and are never opened
    Disallow ad hoc access
    SQL Server does not allow ad hoc access through the OPENROWSET and OPENDATASOURCE functions against the OLE DB provider. When this option is not set, SQL Server also does not allow ad hoc access.
    Supports 'Like' operator
    Indicates that the provider supports queries using the LIKE key word.

Using Transact-SQL

To create a linked server by using Transact-SQL, use the sp_addlinkedserver (Transact-SQL)CREATE LOGIN (Transact-SQL) and sp_addlinkedsrvlogin (Transact-SQL) statements.

To create a linked server to another instance of SQL Server using Transact-SQL

  1. In Query Editor, enter the following Transact-SQL command to link to an instance of SQL Server named SRVR002\ACCTG:
    SQL
    USE [master]  
    GO  
    EXEC master.dbo.sp_addlinkedserver   
        @server = N'SRVR002\ACCTG',   
        @srvproduct=N'SQL Server' ;  
    GO  
    
  2. Execute the following code to configure the linked server to use the domain credentials of the login that is using the linked server.
    SQL
    EXEC master.dbo.sp_addlinkedsrvlogin   
        @rmtsrvname = N'SRVR002\ACCTG',   
        @locallogin = NULL ,   
        @useself = N'True' ;  
    GO  
    

Follow Up: Steps to take after you create a linked server

To test the linked server

  • Execute the following code to test the connection to the linked server. This example the returns the names of the databases on the linked server.
    SQL
    SELECT name FROM [SRVR002\ACCTG].master.sys.databases ;  
    GO  
    

Writing a query that joins tables from a linked server

  • Use four-part names to refer to an object on a linked server. Execute the following code to return a list of all logins on the local server and their matching logins on the linked server.
    SQL
    SELECT local.name AS LocalLogins, linked.name AS LinkedLogins  
    FROM master.sys.server_principals AS local  
    LEFT JOIN [SRVR002\ACCTG].master.sys.server_principals AS linked  
        ON local.name = linked.name ;  
    GO  
    
    When NULL is returned for the linked server login it indicates that the login does not exist on the linked server. These logins will not be able to use the linked server unless the linked server is configured to pass a different security context or the linked server accepts anonymous connections.