Sunday, 27 December 2015

BeforeClass in Parameterized JUnit Test

Recently I was faced with an old problem again: JUnit does not run the @BeforeClass method before the @Parameters method. So I had to apply a workaround – to call the initialisation method within the parameters method.
@RunWith(Parameterized.class)
public class TestAddress2 {
 static Address addr, addr2, addr3;
 ...
 // for parameterized tests
 private Boolean equalResult, identicalResult;
 private Address a1, a2;

 //@BeforeClass
 public static  void init() {
  // set up addr, addr2, addr3
 }
 public TestAddress2(Boolean eqResult, Boolean idResult, Address a1, Address a2) {
  this.equalResult=eqResult;
  this.identicalResult=idResult;
  this.a1=a1;
  this.a2=a2;
 }
 @Parameters
 public static Collection parameters() {
  init();
  // equalResult, identicalResult, address 1, address 2
  return Arrays.asList(new Object[][] {
   { false, true, addr, addr3 },
   { false, false, addr, addr2 },
   { false, true, addr3, addr },
   { false, false, addr2, addr3 },
   { false, false, addr3, addr2 },
  });
 }
 @Test
 public void testEquals() {
  assertEquals(equalResult, a1.equals(a2));
 }
 @Test
 public void testIdentical() {
  assertEquals(identicalResult, a1.identical(a2));
 }
}

Friday, 6 November 2015

Checking VPN with Javascript

The problem: When working outside the office, there are two ways to access the company’s services (e.g. email, time sheets, …)
  1. access the company URLs directly using company VPN: e.g. https://email.company.com
  2. access the company URLs via company’s web portal, where the portal acts as a proxy. The company URLs are replaced like this: https://webportal.company.com/prx/000/https/email.company.com
So to access company service, I would have to type different URLs in the browser depending on whether I am on VPN or not. This can be tedious. So I wrote a little cheat sheet as my home page to automate this for me. The following Javascript goes in the head section of the HTML file.

    var webgatePrefix="https://webportal.company.com/prx/000/";
    
    var addrText='{ "links" : ['+
        '{"name": "Web Mail", "url":"https://mail.company.com/owa"},'+
        '{"name":"Travel", "url":"https://ecc.company.com/irj/portal"},'+
        '{"name":"Expense", "url":"http://iler.company.com:8007/OA_HTML/OA.jsp?OAFunc=OAHOMEPAGE&SSO_RESP=FN"},'+
        '{"name":"Wiki", "url":"http://creativity/SpaceDirectory/Sites/wiki/default.aspx"}'+
    ']}';
    
    
    var addrDb ;
    

    function checkVpn() {
        if (window.XMLHttpRequest) xmlhttp = new XMLHttpRequest();
        else xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
        xmlhttp.open("HEAD","http://wh/wh");
        
        xmlhttp.onreadystatechange=function() {
            // IE reports 12007 if no network
            if(200 == this.status) {
                document.getElementById("vpn").innerHTML="Got VPN!";
                addrDb = JSON.parse(addrText);
            } else {
                document.getElementById("vpn").innerHTML="No VPN! "+this.status;
                addrDb = JSON.parse(addrText, function(key, value) {
                    if (key === 'url' && typeof value === 'string') {
                        return webgatePrefix+value.replace(":/", "")
                    } else
                        return value
                })
            }
            var ul=document.getElementById("ox");
            ul.innerHTML="";
            
            for (i in addrDb.links) {
                var link=addrDb.links[i];
                var li = document.createElement("li");
                var a=document.createElement("a");
                a.setAttribute("href", link.url);
                a.innerHTML=link.name;
                li.appendChild(a);
                ul.appendChild(li);
            };
        }
        
        xmlhttp.send();
    }
    window.onload = function() {
        checkVpn();
        
    }

The body section of the HTML is then quite simple:

   
<!DOCTYPE html>
<html>
<head>
<script type="text/javascript"><!-- the javascript code goes here --></script>
</head>
<body>
    <div id="vpn">Checking VPN...</div>
<h1>Company Links</h1>
<ul id="ox"></ul>
</body>
</html>


The approach is very simple: try to access a URL that is only available in VPN. If it is accessible, then we are on VPN; otherwise, we are not.
Notes:
  1. this only works on IE using the ActiveX object (I have only tested on IE8, which is required by company’s web mail). It does not work on Chrome because Chrome does not bubble the XmlHttpRequest.send() error to the Javascript to handle - the XHR spec simply does not distinguish between network error and CORS denial.
  2. the first line '&lt!DOCTYPE html&gt' is very important in IE, otherwise, IE will complain JSON undefined.

Friday, 30 October 2015

He’s a pirate!

Saturday, 24 October 2015

Exodus

Tuesday, 6 October 2015

Killing ‘Ads by La Superba’ Virus

My laptop (with Symantec Endpoint Protection installed) was infected by a variation of Shopperz a few days ago. Google search shows many web postings claiming to show instructions to remove the virus. However, most of them are rubbish and simply trying to peddle their so called cleaners…

The blog post from Malwarebytes is the only comprehensive article explaining the inner working of the virus and how to remove it. My experience is a bit different from what has been described in the blog post:

  1. There are no shopperz (or similar) add-on or extensions in my web browser – I don’t see any additional add-on/extension in my browsers.
  2. I did not see any unrecognisable scheduled tasks, nor any rouge RunOnce entries in the Windows Registry.
  3. It certainly does not show up in the Programs list (Control Panel – Programs …)

I used Malwarebytes free version to scan and clean. However, it did not find any suspicious executables or dlls related to this virus. It did find the fake hosts file though – in my case it’s called ‘cug\teu\jabak.dat’. I promptly removed this file. I also deleted all the browser data (cookies, temp files, etc.).

So the only action left for me is to overwrite the infected c:\windows\system32\dnsapi.dll with a clean one. I tried to use ‘sfc /verifyfile=c:\windows\system32\dnsapi.dll’ to fix it. But it did not work. I can’t remember whether I used Administrator rights to execute the shell and command or not. I could not boot the system into Safe Mode because my laptop was a company one and it was probably disabled.

What I did instead was to search for file ‘dnsapi.dll’ in c:\windows directory. Several entries showed up – some of them are from c:\windows\winsxs\x86_microsoft-windows-dns-client_…(a long string) directories and their timestamp looked safe enough (in year 2011). So I just copied them over the dnsapi.dll in windows\system32. Note that because the c:\windows\system32\dnsapi.dll is opened by the system it cannot be overwritten as is; two steps are required:

  1. rename the bad dnsapi.dll into some other name (I used the ‘move’ command in cmd shell, run as Administrator of course)
  2. then copy the clean version into c:\windows\system32

Summary

In summary the actions I have taken were:

  1. remove the fake hosts file
  2. clean browser data for all my browsers
  3. replace dnsapi.dll with clean version

It’s been two days since I did that. My computer seems to have stayed clean so far.

Sunday, 16 August 2015

You Raise Me Up

Butchering through this relatively long piece by Kyle Landry.

Tuesday, 4 August 2015

External Microphone Problem with Realtek HD Audio

One day, my 12-year-old son’s MSI GT70 laptop simply would not detect external microphone (on the headset) any more. I tried to update Realtek audio drivers, looked up any online forums but nothing worked.

I noticed that if I hover my mouse over the microphone jack (the pink one in below diagram (although on mine it shows black)) the text says ‘Center & Subwoofer’ instead of microphone. I thought it might be driver or hardware problem.

But my son thought differently. He reckoned that there must be something wrong at the configuration, and it turned out that it is simply the Speaker Configuration (combo box / drop down list) in the below diagram.

If you choose more than 4 speakers, the microphone jack will be used for audio output for the center speaker instead of for microphone input. So the solution is as simple as changing the Speaker Configuration to quad… or less and that will free up the pink jack for microphone.

After fixing that problem, the mic worked fine on Windows 10’s Voice Recorder, but the volume was too faint on Skype. To fix that, my son unchecked the ‘let application have exclusive control’ option of the sound device from Windows Control Panel.

So now the headset is fully functional. Next time anyone ask me to fix their computer or phone, I will outsource them to my son! Smile

Saturday, 25 July 2015

月亮代表我的心

My first totally self-taught piano upload - 月亮代表我的心.

Friday, 5 June 2015

Blog Renovation

Today I did some renovation work on my blog. For one thing, the Cluster Map server that I used has been defunct for several months, so I have to re-do everything.

More importantly I have changed the title of my blog into ‘eSpace’ and the definition of ‘e’ has been overloaded:

  1. ‘e’ as in ‘e-commerce’. This reflects the original intention of this blog – subjects on IT, computing, technical, nerdy etc. So all my existing blog entries will still fit – making my blog backward compatible so to speak.
  2. ‘e’ which is the pronunciation of the Chinese character ‘艺’or ‘藝’, meaning ‘art’ or ‘skill’. For a while I have been reviving my childhood passion for fine-art and also taught myself piano playing. So I should dedicate some of my blogs on arty stuff.

Although eSpace is anagram of ‘escape’, that is one thing that this blog is not.

Magical Strings

When I read about a text message that can cause iPhones to reboot, I couldn’t wait to try it on my son’s iPhone 5. So I sent this string to his phone through SMS.

Power لُلُصّبُلُلصّبُررً ॣ ॣh ॣ ॣ 冗

However, nothing happened. Maybe I missed a couple of returns, i.e.

Power
 لُلُصّبُلُلصّبُررً ॣ ॣh ॣ ॣ
冗

So I will try again tonight. Winking smile

Talking about magical strings – where can you find the most magical strings? The Magical Kingdom of course! Yesterday was the 26th anniversary of the Beijing TianAnMen Square Crackdown that happened in June 4 1989, known in Chinese communities as the ‘6.4 Event’ or simply ‘6.4’.

In 2012, the ShangHai Composite Index fell 64.89 points on the anniversary of the event and created quite a stir in the country. So this year the government has gone extra miles to make sure that nothing of this sort can happen again.

In addition to increased security measures in the streets, they also blocked anything that can remotely remind people of the event in the cyberspace. For example, if you tried to transfer money over WeChat with certain amounts such as 6.4RMB, 89.64RMB, 89RMB, 0.89RMD, etc. you will be greeted with an error message ‘unusual transaction, please try again later’.

Not only strings are banned, certain imagery are also blocked – for example, candle light pictures, yes, candle lights! Ironically, they had to unban it soon after the ferry capsized in Yangtze River just a few days ago and over 400 people are feared dead.

Thursday, 26 February 2015

Wednesday, 4 February 2015

From Office 2010 to 2013–a step backward

I was forced to upgrade to Office 2013 when answering a RFP. From a user experience perspective, I feel that Office 2013 is a step backward from 2010. In the two days of using it, Excel has wasted me several hours of valuable time due to crashes. So I neurotically saved the file after every row of update… Another obvious draw back is the speed – or lack of it. Word, Powerpoint and Excel are noticeably slower than their 2010 counterparts. Even worse was the installation experience – I thought it might take a few minutes (as said on screen) or even up to an hour, but boy was I wrong! I finally got sick of waiting in front of the computer and started on a watercolour of what’s left of my breakfast and finished the painting, then I still had to wait over an hour before the installation was finally finished! At least it was not a total waste of time – I have a picture to show for it: