You better use your desktop PC to check emails

I always think that on a mobile device you are more vulnerable to become a victim of malicious emails.

Most of the time I check my emails on my desktop or laptop computer. This weekend I was sitting on a chair outside on my patio and used a mobile device to check my emails, using Outlook on Android, to get into the details.

On my email account all incoming email from people I don’t know ends up in my junk folder, but I usually check it quickly to find emails from sender I don’t know (yet) which might not be junk emails. This one caught my attention:


After a first look it did not look suspicious to me: the email address looked authentic, thus I opened the attached pdf file. It contained some letter telling me about a game I had purchased from the Apple store ( a game I never heard of ) and that $ 50 would be paid from my credit card account if I would not cancel that order; a link followed to do so.

I stopped there, left my chair, and checked the very same email on my Windows computer, using Outlook. Here is how that email looked like there:


Very different, I would think: it was obvious right away that this is a suspicious email address not owned by Apple, and Outlook actually did not even allow me to open the attachment while that email was sitting in my junk folder.

I was really surprised to see one and the same app – Microsoft Outlook – behave that different on two different platforms. While it did a quiet good job to protect me on Windows from this suspicious and most likely malicious email it did a lousy job on Android.

On a desktop PC you always have the chance to move your mouse pointer over a link to see how it resolves. On a mobile platform like Android you can’t do that: touching a link will open it.

That said, and this experience having made, I stick to my opinion that it is much safer to do email on a desktop computer than on a mobile device.



Base code to make context menu work with wxPython CustomTreeCtrl

After it took me an hour or two to figure that out, here is some base Python code snippet showing how to make context menues work with wxPython’s CustomTreeCtrl:

class CustomTreeCtrl(CT.CustomTreeCtrl):

    def __init__(self, parent, id=wx.ID_ANY, pos=wx.DefaultPosition,

        CT.CustomTreeCtrl.__init__(self, parent, id, pos, size, style, agwStyle)
        # ...        
        self.item = None
        self.Bind(wx.EVT_CONTEXT_MENU, self.OnContextMenu)
        self.Bind(wx.EVT_RIGHT_DOWN, self.OnRightDown)
    def OnRightDown(self, event):

        pt = event.GetPosition()
        item, flags = self.HitTest(pt)

        if item:
            self.item = item    
    def OnContextMenu(self, event):
        # Setup right-click menu for tree items
        menu = wx.Menu()
        treeMenuItem1 = menu.Append(wx.ID_ANY, "Menu Entry 1")
        treeMenuItem2 = menu.Append(wx.ID_ANY, "Menu Entry 2")
        self.Bind(wx.EVT_MENU, self.OnMenuEntry1, treeMenuItem1)
        self.Bind(wx.EVT_MENU, self.OnMenuEntry2, treeMenuItem2)
    def OnMenuEntry1(self, event):
        print "Method OnMenuEntry1 not implemented yet."
    def OnMenuEntry2(self, event):
        print "Method OnMenuEntry2 not implemented yet."

In essence:

  • we need a method to capture what item has been selected in a tree. This is done by OnRightDown() and the HitTest() method. We store the selected item in an attribute of our CustomTreeCtrl object: self.item
  • we need a method to display the context menu: OnContextMenu()
  • we need one method per context menu entry, yet to be implemented: OnMenuEntry1(), onMenuEntry2(), …
  • we need to ensure the proper bindings so that all these methods working, thus:
    • binding wx.EVT_CONTEXT_MENU to OnContextMenu() in the constructor of our CustomTreeCtrl object
    • binding wx.EVT_RIGHT_DOWN to OnRightDown() in the constructor of our CustomTreeCtrl object
    • binding wx.EVT_MENU to every method used to handle clicking a menu entry, like OnMenuEntry1(), onMenuEntry2(), in OnContextMenu()

There is not such a thing as a stupid question

I hope we all agree on this: “There is not such a thing as a stupid question”. Only stupid answers exist a lot.

imageAnyway, my first reaction when reading that question on was: what a stupid question: “Can you write a program for adding 10 numbers?” !

I am still not sure though what the intension was behind that question, nevertheless it yielded a good and interesting discussion thread

  • with a lot of code samples
  • with a lot of fun, see this answer or this one
  • with some interesting discussion about how to phrase useful requirements for software development ( “what did he mean by ‘adding’ !”, see this answer )
  • with some interesting way to deal with those requirements: instead of firing up your IDE right away, think how else the problem can be soled; see this answer.

Thus, nice evidence that every question makes some sense, no matter how stupid it sounds initially.

image from pexels


How to print ipython notebooks without the source code

This is something I really need to create sort of standard reports based on ipython notebooks which should not contain the source code and input prompts of ipython cells: the capability to print ipython notebooks without the source code.

There are ways to do that as discussed here on stackoverflow but all these methods involve adding some ugly code to your ipython cells or tweaking the way the ipython server is started ( or running nbconvert ) which might be out of your control if you use some cloud offering like Data Science Experience on IBM Cloud and not your own ipython installation.

Here is how I achieve this:

I simply download my notebook as html.

Then I run this python script to convert that html file so that prompts and code cells are gone:

FILE = "/somewhere/myHTMLFile.html"

with open(FILE, 'r') as html_file:
    content =

# Get rid off prompts and source code
content = content.replace("div.input_area {","div.input_area {\n\tdisplay: none;")    
content = content.replace(".prompt {",".prompt {\n\tdisplay: none;")

f = open(FILE, 'w')

That script bascially adds the CSS ‘display: none’ attribute for all divs of class ‘prompt’ or ‘input_area’.

That tweaked html page now easily can be printed into a pdf file for me to get my standard report without any code or input prompt cells.

If you know what you are doing you can add more CSS tweaking, like e.g. this one, to that Python code:

# For dataframe tables use Courier font family with smaller font size
content = content.replace(".dataframe thead","table.dataframe { font-size: 7px; font-family: Courier; }\n.dataframe thead")

To figure out things like that I used Firefox Inspector to determine class names of DOM elements ( like e.g. ‘div.data_frame’ is used to display dataframe tables in ipython ) and some CSS knowledge to achieve the manipulations I find useful, like reducing the font size of tables in order to make them fit on pages printed with portrait orientation.

How I installed Teamviewer 12 on Linux Mint 18.2


Here is how I installed Teamviewer 12 on Linux Mint 18.2 64bit:
1. Downloaded Debian package from here
2. Located file in Downloads folder, right-click, “Open with GDebi Package Installer”
3. Ran into issue about missing dependency: libdbus library
4. Ran this as recommended elsewhere, didn’t help: sudo apt-get install -f
5. Found this useful discussion thread and basically ran the first two commands recommended, then re-attempted install through package manager successfully.

sudo dpkg --add-architecture i386
sudo apt-get update



Yesterday during another boring phone call I googled for “fun python packages” and bumped into this nice article: “20 Python libraries you can’t live without“. While I already knew many of the packages mentioned there one caught my interest: Scrapy. Scrapy seems to be an elegant way not only for parsing web pages but also for travelling web pages, mainly those which have some sort of ‘Next’ or ‘Older posts’ button you wanna click through to e.g. retrieve all pages from a blog.

I installed Scrapy and ran into one import error, thus as mentioned in the FAQ and elsewhere I had to manually install pypiwin32:

pip install pypiwin32

Based on the example on the home page I wrote a little script to retrieve titles and URLs from my German blog “Axel Unterwegs” and enhanced it to write those into a Table-Of-Contents type HTML file, after figuring out how to overwrite the Init and Close method of my spider class.

import scrapy
header = """
<meta content='text/html; charset=UTF-8' http-equiv='Content-Type'/>
footer = """

class BlogSpider(scrapy.Spider):
 name = 'blogspider'
 start_urls = ['']
 def __init__(self, *a, **kw):
   super(BlogSpider, self).__init__(*a, **kw)
   self.file = open('blogspider.html','w')

 def parse(self, response):
   for title in response.css(''):
     t = title.css('a ::text').extract_first()
     url = title.css('a ::attr(href)').extract_first()
     self.file.write("<a target=\"_NEW_\" href=\"%s\">%s</a>\n<br/>" % (url.encode('utf8'),t.encode('utf8')))
     yield {'title': t, 'url': url}

   for next_page in response.css(''):
     yield response.follow(next_page, self.parse)
 def spider_closed(self, spider):

Thus, here is the TOC of my German blog.

I tried to get the same done with my English blog here on WordPress but have been struggling so far. One challenge is that the modern UI of WordPress does not have any ‘Older posts’ type of button anymore; new postings are retrieved as soon as you scroll down. Also the parsing doesn’t seem to work for now, but may be I figure it out some time later.



Victim of some Facebook Phishing

Facebook.jpgToday I became a victim of some Facebook credentials phishing. I received an instant message from one of my Facebook contacts containing a video. When trying to play the video I got prompted to enter my Facebook credentials. After having done this … my credentials went into the wrong hands. And it became obvious that this video was not from my contact.
This happened on my smartphone. I believe on a PC this never would have happened to me because there are many means to cross-check urls and links and other things to detect a phishing. On a mobile device it is much harder. The login screen really looked authentic.
The result was: many dubious videos sent to all my contacts. In the meantime Facebook right away locked my account because they detect suspicious behavior. I also ( too late ) read the warning from my contact in Facebook from whom I had received the malicious message that her account had been compromised.
I unlocked my Facebook account by setting a new password and acknowledging a confirmation code; Facebook did a quiet good job to detect the problem and take me through steps to resolve. I then posted warning on my Facebook page and also sent warning messages to most of my contacts; luckily I have less than 100 Laughing
Interestingly my Chrome browser on one of my laptops later on insisted in downloading a Malicious Software Removal tool from Facebook, which right away was blocked by my virus scanner. This happened while Facebook was working fine in my Firefox browser. I found this very helpful hint here ( see comment # 3 in this lengthy article ) how to overcome this strange means and enable Facebook again in my Chrome browser.