Tuesday, October 18, 2016

Hide that cluttered desktop on your Mac

A silly hidden feature allows to disable the rendering of desktop icons on Mac OS X (and macOS Sierra). Just put it in a shell file and make it executable. This script basically toggles the hidden boolean setting. For more detailed information on why one would want to hide desktop icons, please see http://osxdaily.com/2009/09/23/hide-all-desktop-icons-in-mac-os-x/.

#!/bin/bash
# Toggles the "rendering" of items on the MacOS X desktop (keep a clean look).
# For more info, see http://osxdaily.com/2009/09/23/hide-all-desktop-icons-in-mac-os-x/
set -u

CMD_READ_V="defaults read com.apple.finder CreateDesktop"
CMD_WRITE_V="defaults write com.apple.finder CreateDesktop -bool "

RET=$(${CMD_READ_V} 2> /dev/null)
[ $? = 1 ] && ENABLED=1 || ENABLED=${RET}
if [ ${ENABLED} = 1 ]; then
  ${CMD_WRITE_V} false
else
  ${CMD_WRITE_V} true
fi
killall Finder

Wednesday, June 11, 2014

Telenet modem-only met werkende DLNA op de digiboxen

TL;DR; Deze post legt uit hoe DLNA op de Digibox werkende te krijgen in een modem-only installatie van Telenet met een Mikrotik router. Zie deel 3 als de blah blah u geen moer interesseert.


1. Telenet HGW of modem-only?

Telenet, de snelste internet provider van ons landje (België). No sarcasm intended :)

Sinds een paar jaar krijgen klanten standaard de zogenaamde HGW 3.0 modem geïnstalleerd. De HGW, wat staat voor Home Gateway Wireless (of whatever), is typisch een DOCSIS 3 kabelmodem van Compal Broadband Networks (CBN, type CH6643E). Op zich een degelijk toestel wat de functionaliteiten betreft. De HGW heeft het grote voordeel dat deze, IPv4 NAT routing, IPv6 routing en Wifi (2.4 en 5 Ghz) in één toestel aanbiedt. Dit is voor de meeste mensen, die gewoon op het internet willen surfen, perfect. Anderzijds, betekent dit ook dat het externe IP adres van de klant wordt toegekend aan de HGW en dat er intern een privaat subnet (192.168.x.0/24), instelbaar via Mijn Telenet, wordt gebruikt.

Totaal irrelevant: Motorola heeft in 2010 hun EMEA DOCSIS divisie verkocht aan CBN (link). Daarom bestaat er soms verwarring tussen kabelmodem types en het merk Motorola vs CBN. It's all the same (shit) now.

Sommige mensen vinden het blijkbaar een obstakel dat ze geen rechtstreeks extern IP adres meer te verkrijgen. Waarom? Geen (echt) idee. Ik heb ook twijfels gehad bij de recentste installatie thuis. Bijvoorbeeld: Dubbele NAT heeft geen invloed op de snelheid van het netwerk of de connecties, VPN zou geen enkel probleem mogen zijn, etc. Ik kan zelf eigenlijk maar heel moeilijk een situatie vinden waarbij er iets absoluut niet werkt met een HGW opstelling.

Mijn persoonlijke redenen om toch een modem-only te vragen waren:
  1. De onmogelijkheid om de interne DHCP van de HGW uit te schakelen. Dit is de enige echte reden om een modem-only te vragen. Waarom? Ik gebruik PXE booting en de opties worden via mijn DHCP meegegeven, wat niet mogelijk is met de HGW DHCP.
  2. Dynamic DNS updating wordt bemoeilijkt. Maar, met behulp van IGD (Interior Gateway Device Protocol) is het mogelijk om het externe IP adres van de HGW op te vragen. Dit heb ik getest en werkt.)
  3. Mogelijkheid tot eigen firewalling. Niet dat ik ze niet vertrouw, maar via de HGW is het voor Telenet technisch heel gemakkelijk om op een LAN segment van een klant te geraken. Bij een HGW + eigen router kan je de wifi van de HGW niet filteren. Telenet kan bijvoorbeeld nagaan hoeveel devices er in de LAN zitten (again, who actually cares?).
  4. Elke configuratie gebeurt via Mijn Telenet. Best wel in orde, als alles werkt.
  5. De ingebouwde Wifi is dikwijls niet bruikbaar omdat de HGW in de garage, de kelder of het waskot hangt. Daardoor is er vaak toch nog nood aan een eigen access point.
  6. En zageventen die mopperen over de HomeSpot/HotSpot moeten zwijgen. Uw wifi staat daar toch te draaien, en verbruikt niet (veel) meer stroom door die extra service.
Enfin, modem-only heeft dan weer enkele nadelen:
  1. Je moet alles zelf regelen, wat in mijn geval deel van de fun is.
  2. Digiboxen moeten afzonderlijk behandeld worden (via VLANs of aparte bekabeling).
  3. De, op papier mooie, DLNA functie van de Digiboxen wordt niet ondersteund.

Puntjes 1 en 2 zijn eenvoudig. Puntje 3 is de reden voor deze post. Aanvankelijk hoopte ik op een oplossing te vinden op één van de Telenet-gebruikers forums. Maar, na wat vruchteloos zoeken naar een oplossing om DLNA op de Digiboxen werkende te krijgen in combinatie met een eigen router en een modem-only installatie, heb ik besloten om er zelf aan te beginnen. Ook peer-pressure van vrienden helpt soms als motivator.

Elke Digibox krijgt via DHCP een intern IPv4 adres van Telenet toegewezen (ergens in een 10.0.0.0/8 blok) voor de interactiviteit en streaming diensten. Daarnaast zal de Digibox ook zelf zoeken naar een 192.168.x.1/24 adres in het netwerk (meer details vind je in de forum post van NuKeM -- waarvoor dank en credits), en vervolgens ook automatisch een In Home IPv4 adres instellen bij het opstarten (zonder DHCP dus). Het lastige aan dit systeem is dat er maar één MAC adres wordt gebruikt voor de twee IP adressen van de Digibox (anders was het mogelijk om via VLAN's het verkeer te scheiden). Met een In Home IP adres is het mogelijk om de DLNA functies van de box te gebruiken. Dat is wat we willen bereiken met de voorgestelde oplossing.

2. "Transparent bridge with filtering"

Dit deel legt de technische kant uit van een werkende oplossing. Ik beweer niet dat dit de enige methode is, dus als iemand een beter of eenvoudiger alternatief kan geven, dan hoor ik het graag.

De oplossing waar ik voor gekozen heb, werkt met behulp van een bridge (dus layer 2 packet forwarding). Eenvoudig gezegd, stel ik de router volledig in als switch, zodat Digiboxen gewoon met Telenet kunnen communiceren en omgekeerd. De bridge filter scheidt vervolgens het interne LAN verkeer met dat van de buitenwereld.

Ik ben uitgegaan van een block-all principe en zet open wat noodzakelijk is voor een correcte werking van de apparaten op het netwerk. Het functioneel scheiden van enerzijds eigen apparaten en anderzijds de Digiboxen, wordt gedaan met behulp van de MAC adres-vendor-ID, welke voor de Digiboxen 00:03:91:XX:XX:XX en 68:63:59:XX:XX:XX zijn. Alle datapakketten met een passend MAC adres worden in de bridge filter gemarkeerd als "Digibox" (zowel op de Input, Forward als Output chains). De volgende filter regels kunnen deze marker dan gebruiken om concrete beslissingen te nemen. Ethernet poort 1 wordt gereserveerd voor de kabelmodem van Telenet.

De router splitst IPv4 traffiek tussen het klassieke LAN-WAN verkeer en het Digibox-Telenet verkeer. Digibox-Telenet verkeer mag via layer 2 door de bridge, terwijl het klassieke verkeer via layer 3 NAT gaat.

Concreet bestaan dus volgende regels in de bridge filter (in volgorde):
  • Forward (verkeer dat door de router loopt)
    1. Accept: Alles van en naar Digiboxen
    2. Drop: Alles afkomstig van Telenet kant
    3. Drop: Alles naar Telenet kant
    4. Accept: Al het overige verkeer (nodig om tussen interne poorten verkeer toe te laten)
  • Input (verkeer met de router als bestemming)
    1. Drop: DHCP IP aanvragen, afkomstig van Digiboxen (want, deze krijgen IP via DHCP van Telenet zelf)
    2. Drop: DHCP IP aanvragen afkomstig van Telenet kant (dit komt enkel voor als je meerdere apparaten extern hangt, ook hier willen we DHCP van Telenet niet verstoren)
    3. Accept: Alle verkeer dat niet afkomstig is van de Telenet kant (alle protocollen)
    4. Accept: ARP pakketten van Telenet kant
    5. Drop: IPv4 verkeer van Telenet kant met als doel 192.168.0.0/16, 172.16.0.0/16, 10.0.0.0/8 of 169.254.0.0/16
    6. Accept: IPv4 verkeer, naar de router
    7. Drop: alle overige verkeer naar de router
  • Output (verkeer dat de router zelf genereert)
    1. Drop: DHCP IP antwoorden naar Digiboxen
    2. Drop: DHCP IP antwoorden naar Telenet kant
    3. Accept: Alle verkeer dat niet naar de Telenet kant gaat (dus alles naar LAN, ook ARP)
    4. Drop: ARP verkeer naar Telenet kant waar informatie van 192.168.0.0/16 in staat (dit voorkomt lekken naar buiten)
    5. Accept: ARP verkeer naar Telenet kant
    6. Drop: IPv4 verkeer naar Telenet kant met als bron 192.168.0.0/16, 172.16.0.0/16, 10.0.0.0/8 of 169.254.0.0/16
    7. Accept: Alle overige IPv4 verkeer
    8. Drop: Alle overige verkeer van de router
De layer 3 filters voor IPv4 ga ik hier niet expliciet uitleggen. Deze zijn immers identiek aan de standaard IPv4 NAT regels van elke standaard router. Nothing new, dus.

3. Configuratie van de Mikrotik RB2011UiAS-2HnD-IN

De implementatie van de bridge filter regels kan gebeuren met gelijk welk besturingssysteem of embedded router die zoiets ondersteunt. Op Linux kan je hiervoor ebtables gebruiken. Ikzelf heb de praktische uitwerking op een router van Mikrotik gedaan, omdat deze toestellen gewoon extreem veel mogelijkheden aanbieden en zeer betaalbaar zijn.
Hieronder volgt de configuratie, zoals bekomen via het export commando in een terminal. De configuratie bevat enkel de relevante zaken voor deze post (geen wifi of advanced IPv4 firewall dus). Het LAN netwerk zit op 192.168.42.0/24, met een LAN DHCP server die vanaf 128 en hoger leases geeft. De Telenet kabelmodem moet via poort 1 aangesloten worden. De Digiboxen en eigen apparaten kunnen op gelijk welke poort ingestoken worden (zelfs met extra switches ertussen).
/interface bridge
add l2mtu=1598 name=br protocol-mode=none
/interface ethernet
set [ find default-name=ether1 ] name=ether1-gateway
set [ find default-name=ether2 ] name=ether2-master-lan
set [ find default-name=ether3 ] master-port=ether2-master-lan name=\
    ether3-slave-lan
set [ find default-name=ether4 ] master-port=ether2-master-lan name=\
    ether4-slave-lan
set [ find default-name=ether5 ] master-port=ether2-master-lan name=\
    ether5-slave-lan
set [ find default-name=ether6 ] name=ether6-master-dmz
set [ find default-name=ether7 ] master-port=ether6-master-dmz name=\
    ether7-slave-dmz
set [ find default-name=ether8 ] master-port=ether6-master-dmz name=\
    ether8-slave-dmz
set [ find default-name=ether9 ] master-port=ether6-master-dmz name=\
    ether9-slave-dmz
set [ find default-name=ether10 ] master-port=ether6-master-dmz name=\
    ether10-slave-dmz
set [ find default-name=sfp1 ] disabled=yes
/ip neighbor discovery
set ether1-gateway discover=no
set sfp1 discover=no
/ip pool
add name=lan-pool ranges=192.168.42.128-192.168.42.254
/ip dhcp-server
add address-pool=lan-pool disabled=no interface=br name=lan
/port
set 0 name=serial0
/interface bridge filter
add action=mark-packet chain=forward comment=\
    "Tag Advanced Digital Broadcast devices" new-packet-mark=digibox \
    src-mac-address=00:03:91:00:00:00/FF:FF:FF:00:00:00
add action=mark-packet chain=forward comment=\
    "Tag Advanced Digital Broadcast devices" new-packet-mark=digibox \
    src-mac-address=68:63:59:00:00:00/FF:FF:FF:00:00:00
add action=mark-packet chain=forward comment=\
    "Tag Advanced Digital Broadcast devices" dst-mac-address=\
    00:03:91:00:00:00/FF:FF:FF:00:00:00 new-packet-mark=digibox
add action=mark-packet chain=forward comment=\
    "Tag Advanced Digital Broadcast devices" dst-mac-address=\
    68:63:59:00:00:00/FF:FF:FF:00:00:00 new-packet-mark=digibox
add action=mark-packet chain=input comment=\
    "Tag Advanced Digital Broadcast devices" new-packet-mark=digibox \
    src-mac-address=00:03:91:00:00:00/FF:FF:FF:00:00:00
add action=mark-packet chain=input comment=\
    "Tag Advanced Digital Broadcast devices" new-packet-mark=digibox \
    src-mac-address=68:63:59:00:00:00/FF:FF:FF:00:00:00
add action=mark-packet chain=output comment=\
    "Tag Advanced Digital Broadcast devices" dst-mac-address=\
    00:03:91:00:00:00/FF:FF:FF:00:00:00 new-packet-mark=digibox
add action=mark-packet chain=output comment=\
    "Tag Advanced Digital Broadcast devices" dst-mac-address=\
    68:63:59:00:00:00/FF:FF:FF:00:00:00 new-packet-mark=digibox
add chain=forward comment="Forward anything marked as Digibox" packet-\
    mark=digibox
add action=drop chain=forward comment=\
    "Do not forward if originating from Telenet side" in-interface=\
    ether1-gateway
add action=drop chain=forward comment=\
    "Do not forward if destined to Telenet side" out-interface=ether1-\
    gateway
add action=passthrough chain=forward comment=\
    "Bridge everything that gets here" disabled=yes
add action=drop chain=input comment=\
    "Block DHCP client requests from Digiboxes" dst-port=67 ip-protocol=\
    udp mac-protocol=ip packet-mark=digibox src-port=68
add action=drop chain=input comment=\
    "Block DHCP client requests coming from Telenet side" dst-port=67 \
    in-interface=ether1-gateway ip-protocol=udp mac-protocol=ip src-port\
    =68
add chain=input comment=\
    "Accept anything to the router that is NOT originating from Telenet"\
    in-interface=!ether1-gateway
add chain=input comment="Accept ARP from everywhere" in-interface=\
    ether1-gateway mac-protocol=arp
add action=drop chain=input comment=\
    "Block this subnet when originating from Telenet side" dst-address=\
    192.168.0.0/24 in-interface=ether1-gateway mac-protocol=ip
add action=drop chain=input comment=\
    "Block this subnet when originating from Telenet side" dst-address=\
    172.16.0.0/12 in-interface=ether1-gateway mac-protocol=ip
add action=drop chain=input comment=\
    "Block this subnet when originating from Telenet side" dst-address=\
    10.0.0.0/8 in-interface=ether1-gateway mac-protocol=ip
add action=drop chain=input comment=\
    "Block this subnet when originating from Telenet side" dst-address=\
    169.254.0.0/16 in-interface=ether1-gateway mac-protocol=ip
add chain=input comment=\
    "Any IPv4 traffic to the router that gets here is allowed" in-inter\
    face=ether1-gateway mac-protocol=ip
add action=drop chain=input comment=\
    "Drop anything else (other protocols) destined to the router"
add action=drop chain=output comment=\
    "Drop DHCP server answers to Digiboxes" dst-port=68 ip-protocol=\
    udp mac-protocol=ip packet-mark=digibox src-port=67
add action=drop chain=output comment=\
    "Drop DHCP server answers to Telenet side" dst-port=68 ip-protocol=\
    udp mac-protocol=ip out-interface=ether1-gateway src-port=67
add action=drop arp-src-address=!192.168.0.0/16 chain=output comment=\
    "Drop ARP stuff not from 192.168.0.0/16 and internal" mac-protocol=\
    arp out-interface=!ether1-gateway
add chain=output comment=\
    "Allow the router to send anything to non-Telenet side" out-inter\
    face=!ether1-gateway
add action=drop arp-src-address=192.168.0.0/16 chain=output comment=\
    "Drop ARP stuff from 192.168.0.0/16 to Telenet side" mac-protocol=\
    arp out-interface=ether1-gateway
add chain=output comment="Accept ARP to everywhere" mac-protocol=arp \
    out-interface=ether1-gateway
add action=drop chain=output comment=\
    "Block this subnet when destined to Telenet side" mac-protocol=ip \
    out-interface=ether1-gateway src-address=192.168.0.0/16
add action=drop chain=output comment=\
    "Block this subnet when destined to Telenet side" mac-protocol=ip \
    out-interface=ether1-gateway src-address=172.16.0.0/12
add action=drop chain=output comment=\
    "Block this subnet when destined to Telenet side" mac-protocol=ip \
    out-interface=ether1-gateway src-address=10.0.0.0/8
add action=drop chain=output comment=\
    "Block this subnet when destined to Telenet side" mac-protocol=ip \
    out-interface=ether1-gateway src-address=169.254.0.0/16
add chain=output comment=\
    "Any IPv4 traffic from the router that gets here is allowed" \
    mac-protocol=ip out-interface=ether1-gateway
add action=drop chain=output comment=\
    "Drop anything else (other protocols) originating from the router"
/interface bridge port
add bridge=br interface=ether2-master-lan
add bridge=br interface=ether6-master-dmz
add bridge=br interface=wifi
add bridge=br interface=ether1-gateway
/ip address
add address=192.168.42.1/24 interface=br network=192.168.42.0
/ip dhcp-client
add comment="Connection with Telenet Modem" dhcp-options=hostname,\
    clientid disabled=no interface=br
/ip dhcp-server network
add address=192.168.42.0/24 dns-server=192.168.42.1 gateway=\
    192.168.42.1
/ip dns
set allow-remote-requests=yes
/ip dns static
add address=192.168.42.1 name=router
/ip firewall filter
add chain=input connection-state=established
add chain=forward connection-state=established
add chain=input connection-state=related
add chain=forward connection-state=related
add chain=input connection-state=new in-bridge-port=!ether1-gateway
add chain=forward connection-state=new in-bridge-port=!ether1-gateway
add action=drop chain=input
add action=drop chain=forward
/ip firewall nat
add action=masquerade chain=srcnat dst-address=!192.168.0.0/16 out-\
    interface=br src-address=192.168.0.0/16 to-addresses=0.0.0.0
/ip upnp
set allow-disable-external-interface=no
/ipv6 nd
set [ find default=yes ] disabled=yes

Hopelijk heeft iemand iets aan deze post. Dit alles zou eigenlijk niet nodig zijn, als Telenet het zou mogelijk maken om de LAN DHCP server uit te schakelen. Commentaar is welkom :)

Wednesday, January 8, 2014

Telenet CI+ Module on a Samsung UE40C7700WSXXN

Another little post that seems worthwhile sharing with the world (at least for Telenet customers in Belgium/Flanders region). 

TL;DR;

The Telenet CI+ card works on the Samsung UE40C7700WSXXN (using firmware T-VALDEUC-3018.1).

Long version

Imagine that LED flat screen TV in the bedroom, mounted to the wall, with only a power plug and a coax connection hidden behind. Then Digital TV becomes available and there is no room for a power hungry STB (cable setup box).

Luckily, Telenet allows (since a few months at the time of writing) its customers to buy a CI+ card that plugs into the TV (see TV met een kaartje) at the price of 69 euro (one time buy). However, apparently a lot of (typically pre-2010) televisions with a CI+ slot do not work with the Telenet CI+ cards. So, to prevent complaints, Telenet provides a list with 'certified' televisions that were tested to work. The Samsung UE40C7700 was not on this list.

At the risk of wasting 69 euro, I bought the card and it works fine. I did perform a firmware upgrade first (before even trying anything) to version 3018. Subsequently, it's just a matter of following the provided steps and waiting. It basically comes down to tuning in all the available channels (via DVB-C) and only then inserting the CI+ card. It took about 20 minutes before the encrypted channels became view-able.

Piece of cake :)


Friday, April 19, 2013

JAVA_HOME annoyances on Linux (Ubuntu)

Just a quick writeup about an annoyance I come across every time I need to use Java on a Linux server. In my case I use the Ubuntu (12.04) server distro, so I'm unsure as to how this behaves on the other distro's. However, setting up the correct JAVA_HOME environment variable for a user never seems automatically done by the system or the package installers.

Tired of manually keeping track of the correct JAVA_HOME environment, I wrote this little script that is called in profile.d at logon time. It simply checks the /etc/alternatives/java symlink and resolves it. Then cuts of the /bin/java and optionally the /jre to construct the JAVA_HOME path. I know for sure that on some systems or in some situations this will not suffice, but on my system it does.

Put the following code in a file in /etc/profile.d (e.g. /etc/profile.d/java.sh):
JAVA_SEARCH="/etc/alternatives/java";

# Resolve link
INSTALLED_JAVA_ALTERNATIVES=`readlink -f ${JAVA_SEARCH}`

# Test if it is set
if [[ $INSTALLED_JAVA_ALTERNATIVES != $JAVA_SEARCH ]]; then
  # Test if the full path to java binary ends with /bin/java
  if [[ $INSTALLED_JAVA_ALTERNATIVES =~ .*/bin/java ]]; then
    JAVA_HOME_CANDIDATE=${INSTALLED_JAVA_ALTERNATIVES:0:-9}
    if [[ $JAVA_HOME_CANDIDATE =~ .*/jre ]]; then
      JAVA_HOME_CANDIDATE=${JAVA_HOME_CANDIDATE:0:-4}
    fi

    # Verify JVM
    if [[ -x ${JAVA_HOME_CANDIDATE}/bin/java ]]; then
      # Set the candidate as HOME
      export JAVA_HOME=${JAVA_HOME_CANDIDATE}
    fi
  fi
fi
When I happen to change the default Java JVM through the provided Ubuntu commands, this piece of scripting will make sure that the JAVA_HOME is correctly updated as well (after the next login). The script is very defensive, so if something isn't returned as expected then it will simply stop and not set a JAVA_HOME at all. Also, a user can still manually override the JAVA_HOME in his private profile.

As always, feel free to throw in a comment. The script is provided as-is and if your head explodes because of it, then don't blame me :)

Wednesday, January 2, 2013

32-bit division on an old school 8086 processor

During a 8086 assembler course, a student asked me how he could divide a 32-bit unsigned integer by a 16-bit unsigned integer. I knew that the answer was not to simply use the DIV instruction once, because of potential range limitations. Let me explain.

On the 8086 CPU the DIV instruction takes as input a 32-bit numerator in DX::AX and divides it by a denominator given as the operand of the instruction (a register or a memory address). After the division, AX holds the quotient, while DX contains the remainder of the division. More formal:


DIV   Unsigned divide
Syntax:  DIV    op8 (8-bit register or memory)
        DIV    op16 (16-bit register or memory)
Action:  If operand is op8, unsigned AL = AX / op8  and  AH = AX % op8
         If operand is op16, unsigned AX = DX::AX / op16  and  DX = DX::AX % op16
Flags:   OF=?, SF=?, ZF=?, AF=?, PF=?, CF=?

As shown, the DIV instruction performs a division and modulus operation at once. And, it is clear that one can provide certain values for the numerator when executing the DIV instruction that will result in an error. For example, with DX::AX set to 4000h::0000h, a division by 2 should give 2000h::0000h as the result, but the CPU cannot represent this value in the AX register. The quotient is too big and requires more than 16-bits to be able to represent it. In the worst case when a 32-bit number is divided by 1, then the quotient is that same 32-bit number. Therefore, when the quotient is too large to fit into AX, the CPU will generate a division overflow exception, just as it does with a division by zero.

It is obvious that a solution must exist to tackle this problem. Why else on earth would those Intel engineers in the seventies have designed a DIV instruction that takes 32-bit numerators at the input for 16-bit divisions?

At first, I searched the Internet for a solution. However, it did not take long to realize that either nobody, still working with 8086 assembler, understands or realizes the issue at hand, or that no-one was ever interested in providing a simple solution (I suspect the latter). So, I was forced to think it over myself and I decided to make this blog post about the solution for other people to use.

It appears that those Intel engineers did think about this problem and they provided everything necessary to divide big numbers by a 16-bit divisor. The DIV instruction design allows it to be chained easily with an unspecified amount of subsequent DIV instructions. This basically enables a programmer to use an arbitrary n * 16-bit number as numerator, by splitting the dividend in 32-bit blocks.

So here is a piece of plain old 8086 code (MASM-style). The actual div32 procedure performs a 32-bit unsigned integer division by chaining two DIV instructions. However, larger n * 16-bit numbers could be supported easily. Using LODSW and STOSW, the code becomes very clean and straightforward...

  ...<setup CX, SI, DI, DS, ES and FLAGS>...
  XOR   DX, DX ; set DX := 0
  LODSW        ; load the higher 16-bits into AX
  DIV   CX     ; divide DX::AX by CX
               ; leaves DX with remainder and AX with quotient
  STOSW        ; write out AX to result

  LODSW        ; load the lower 16-bits into AX
  DIV   CX     ; divide DX::AX by CX
               ; leaves DX with remainder and AX with quotient
  STOSW        ; write out AX to result
  ...<cleanup code>...


This LODSW, DIV, STOSW sequence can be repeated as many times as necessary in order to divide n * 16-bit numbers by a 16-bit divident.

I hope this small post will help some people to save some research time. Have fun coding on old-school 8086 :)

Note: The formatting on Google Docs for assembler code is not so great. Indentation is gone, and so is readability. Download the code and view it in a decent text editor to see indentation.

Thursday, May 24, 2012

Diablo III Launcher Lazyness

Like so many others (6 million at least), I bought a copy of Diablo III at the launch date. Finally after years of waiting in agony, we can once again slay the daemons of hell.

However, this post is not about the game itself. For game critiques, there are plenty of whining people on the internet (e.g. the BattleNet Forums). So, you won’t find complaints about gameplay or graphics here. Actually, I like the game very much so far…

Rather, this post discusses a small Blizzard-annoyance for which I created a simple solution. For some obscure reason, Blizzard decided that launching Diablo III pops up the famous Blizzard Launcher. Famous for WoW and SC2 players, not so famous for Diablo II fans. I know that this launcher isn’t just a fancy picture with a play button on it and that is performs some consistency checks and makes sure that the latest patches are installed. In fact, I don’t care what it does do or does not do. The annoyance is that I have to click the Play button.

So starting a session of Diablo III involves 2 clicks, instead of one? Yes, in contrast to actually playing Diablo games with millions of mouse clicks, this single extra click won’t hurt :p. Yet, I find it annoying.

Enough complaints, here’s a solution for those who agree. I created a very simple AutoIt script that launches the launcher and clicks the play button for you. Call me lazy…

Here’s the script:
 ; Script Function:  
 ;  Presses the stupid play button.  
 ;  
 If ProcessExists("Blizzard Launcher.exe") = 0 Then  
   Run("Diablo III Launcher.exe")  
 EndIf  
 If WinWaitActive("[CLASS:QWidget; TITLE:Diablo III]", "", 5) Then  
   Sleep(1500)  
   AutoItSetOption("MouseCoordMode", 0)  
   MouseClick("left", 640, 480)  
 EndIf  
You can compile this as an executable and drop it in the Diablo III install folder. It assumes the launcher is in the same folder as the script.


Note to the autistic readers: This script is far from perfect. I don't know what happens when the play button changes in a "format c:" or if you are touching the mouse while executing this script. So use as is, or improve.


Note to smarter people: I actually hope for someone to point out that it might be possible to add an argument to the Blizzard Launcher that makes the game start automatically... However, I don't know of such an argument to pass.

Wednesday, September 28, 2011

Eindelijk Mobile Vikings

Het volgende moet even van mijn lever :)

Ik was tot op heden 10 jaar een tevreden klant van Proximus. Deze mobiele operator beschikt immers over een zeer goed uitgebouwd netwerk met een hoge dekkingsgraad. Ook mijn persoonlijke ervaring met de klantendienst van Proximus was altijd uiterst positief. Twee goede argumenten om zeker niet te veranderen van operator. Niet veranderen betekent echter ook stilstaan in het turbulente landschap van de telecom waarin alles beweegt. Het tijdperk waarin Base of Mobistar gebruikers geen of slechte ontvangst hebben in bepaalde regio’s van ons land, behoort ondertussen al tot een ver verleden. In dat opzicht zijn de drie Belgische netwerk operatoren dus vrij gelijk. Het verschil wordt echter vooral gemaakt in de kostprijs voor de klant. En kort gezegd: Proximus is veel te duur!

Dit is dé enige reden waarom ik actief op zoek ging naar een alternatief.

Formules, packs en tarieven
In de laatste 10 jaar heb ik meermaals de waslijst aan tariefformules met bijhorende voorwaarden van zowel Proximus, Mobistar als Base bestudeerd. Meestal volgde dan de conclusie dat ik een verouderd abonnement gebruikte en bijgevolg al enkele maanden teveel betaalde. Ook kon ik telkens vaststellen dat de prijzen van Proximus en Mobistar nagenoeg tot op de eurocent hetzelfde zijn. Enkel Base leek steeds net iets goedkoper. Persoonlijk vind ik het onaanvaardbaar dat ik als trouwe klant het reilen en zeilen van mijn provider actief moet volgen om er zeker van te zijn dat ik niet met een abonnement of pre-paid formule blijf zitten welke niet 100% op mijn persoonlijk gebruik is afgestemd. Waarom zijn er ook zoveel verschillende tarieven? Ik begrijp best dat iemand die veel belt en dus meer betaalt, een gunstiger tarief per minuut kan krijgen. Ik begrijp niet waarom je met een “Mobile Comfort 10” van 10 euro per maand in de daluren gratis belt (tot 600 minuten per maand), terwijl met een “Mobile Start 10” van 10 euro per maand de gebruiker gewoon alle gesprekken volledig betaalt. Is dit de zogenaamde transparante tarifering?

Proximus Internet
Om op internet te mogen, kan elke gebruiker gebruik maken van een uiterst voordelig gunsttarief van  0,42 euro per 5 minuten. Los van het belachelijk hoge bedrag, stamt het aanrekenen van internetgebruik per tijdseenheid nog uit de koloniale tijden van de RTT. Temeer dat deze “optie” standaard is voor iedereen. De enige manier om toegang tot het internet te laten blokkeren en zodoende accidentele kosten te vermijden, is per telefoon via de klantendienst. Geen mogelijkheid om dit via de e-Services website te regelen, wat volgens mij aangeeft dat ze bij Proximus deze optie liever niet blokkeren. Indien gewenst kan je echter wel kiezen om te betalen per volume aan een democratische 0,50 euro per 100kB. WTF? 5 euro voor 1MB? Ik ben ervan overtuigd dat iedereen wel iemand kent die onbewust met de nieuwe telefoon op internet heeft gezeten en op het einde van de maand een gepeperde factuur ontvangen heeft. Om zulke situaties te vermijden, hebben de operatoren ondertussen wel een waarschuwingssysteem via SMS geïmplementeerd, zodat accidentele kosten meestal nog net betaalbaar blijven. Het gevolg is dan ook dat weinigen nog een poging ondernemen om in zulke gevallen de hoog opgelopen kosten te laten schrappen.

Omdat Proximus ook wel doorheeft dat de voornoemde tarieven schandalig zijn, bestaan er gelukkig de verschillende varianten van de optie “Internet on GSM”, aan 5 euro (50MB), 10 euro (250MB) of 20 euro (1000MB) per maand. Bij het overschrijden van de maandelijkse data limiet, wordt naargelang de variant aan een uiterst gunstig tarief een meerprijs per MB aangerekend. Voor de 50MB optie bedraagt deze meerprijs 0,10 euro per MB, terwijl dit voor de andere twee slechts 0,03 euro per MB is. Dus even uitrekenen:
  • Met de “Internet on GSM Comfort” formule van 10 euro per maand kost een extra 250MB aan 0.03 euro is 7,50 euro. Dit is dus goedkoper dan de eerste schijf van 250MB? Waarom?
  • Stel dat uw verbruik tussen de 50MB en 150MB per maand zit. Kies je dan best voor de Start (5 euro) of de Comfort (10 euro) optie? Waarom zo ingewikkeld?
De onderstaande grafiek laat beter zien hoe de kosten oplopen per 10MB. Merk op dat de standaard optie van 5 euro per 1MB niet op de grafiek past!
Aangezien ik ongeveer 200MB aan data trafiek verbruik per maand, maakte ik gebruik van de “Internet on GSM Comfort” van 10 euro per maand.

Meestal volstaat de 250MB limiet dus ruimschoots, behalve dan die ene maand waar ik een “factory reset” had gedaan van mijn Android toestel. Onmiddellijk na het instellen van mijn Google account begon Android Market alle apps en instellingen terug te downloaden. Prachtig als de wifi-verbinding al opstaat, minder prachtig als je vaststelt dat alles via HSPA binnenloopt. Tegen de tijd dat ik mijn wifi had ingesteld was er al 70MB verbruikt. Dit was misschien niet de juiste reactie, maar toch: Great start of the month. Ik moet wel toegeven dat HSPA van Proximus enorm snel is, daarover zeker geen klachten. Dit voorval betekende wel dat ik de rest van de maand zwaar moest opletten om niet over mijn limiet te gaan.

Klantenbinding
Trouw wordt soms beloond, en dus kreeg ik af en toe een telefoontje van een vriendelijke verkoper. Ergens in Maart 2010 werd me zo een “offer you cannot refuse” aangeboden. Bij intekenen op een contractverlenging van 15 maanden, kreeg ik twee maanden 20,50 euro belkrediet. Omdat ik op het moment van ons gesprek eigenlijk met andere zaken bezig was, en omdat ik al jaren klant was, leek me dit een goed voorstel. Ik had immers geen flauw idee van de onbeduidende randvoorwaarden van het voorstel en rekende snel uit dat mijn factuur de komende twee maanden dus 20 euro lager zou zijn. Bijgevolg antwoordde ik dat ik wel geïnteresseerd was. Ik wist perfect dat ik bijgevolg nog eens 15 maanden bij Proximus zou moeten blijven. Wat ik niet wist, maar wel had moeten weten, is dat belkrediet niet hetzelfde betekent als korting op een factuur. Mijn maandelijkse kosten voor gesprekken die buiten mijn bundel vielen, lagen slechts rond de 10 euro. En bijgevolg lag de werkelijke korting op mijn facturen voor de komende twee maanden slechts rond de 10 euro. Oh well… lesson learned.

Mobile Vikings
Al kort na het opstarten van Mobile Vikings had ik mezelf een account aangemaakt op hun website. Ik was echter nooit overgegaan tot het daadwerkelijk aanvragen van een SIM kaart, om de eenvoudige reden dat ik niet onmiddellijk het nut zag in het constant online kunnen met mijn Nokia E51. Met de opkomst van de touchscreen smartphones is de situatie grondig veranderd.

Rationeel rekenen
Van Oktober 2010 tot Oktober 2011, betaalde ik gemiddeld 38 euro per maand aan Proximus. Mijn verbruik bedroeg gemiddeld 80 minuten bellen en 80 SMS berichtjes. De data teller stond meestal ergens rond de 200MB bij het afsluiten van de factuur. Ik zat nog 9 maanden vast bij Proximus. Aan gemiddeld 38 euro per maand zou me dit dus rond de 342 euro kosten. Bij een onmiddellijke overstap naar Mobile Vikings zal ik ongeveer 19 euro per maand moeten betalen, wat neerkomt op 172 euro op 9 maanden. De besparing van 170 euro is dus groter dan de afkoopsom van 150 euro die ik verschuldigd ben aan Proximus wegens contractbreuk. Daarbij komt dat ik niet meer moet kijken naar een byte meer of minder, omdat de 2GB limiet normaal gezien ruimschoots voldoende moet zijn. Ook de belachelijk hoge limiet voor SMS berichtjes kan misschien helpen om de gesprekskosten te beperken.

De volgende grafiek laat de besparing per maand zien bij een overstap tussen nu en binnen 9 maanden. Niet overstappen betekent dus dat ik niets bespaar. Overstappen binnen 4 tot 8 maanden zou verlies betekenen. De grafiek laat duidelijk zien dat ik zo snel mogelijk moet overstappen! Eigenlijk ben ik al te laat.
Achteraf bekeken had ik ook gewoon een ander GSM nummer kunnen gebruiken, en mijn 9 maanden aan abonnement bij Proximus braaf uitbetalen. Dit zou me dan slechts 90 euro gekost hebben, i.p.v. 150 euro. Ik voelde er echter weinig voor om een nieuw nummer in gebruik te nemen, en beschouw ik de 60 euro als een soort van “losgeld” om mijn nummer te kunnen behouden.

Overstappen!
Ondertussen ben ik reeds één week Mobile Viking en ik heb er tot nu toe nog geen seconde spijt van. Ondanks het feit dat het vervroegd opzeggen van mijn Proximus abonnement op het eerste zicht zeer nadelig lijkt, blijkt na wat eenvoudig rekenwerk dit niet zo te zijn. Integendeel, één maand langer wachten zou mijn verlies nog groter maken. Het moeten betalen van 150 euro voelt vreemd en fout aan, maar dat neem ik er met een zure glimlach graag bij. Ik zal nooit nog intekenen op contractverlengingen in ruil voor één of andere miezerige korting... Nu nog mijn vrouw overtuigen.