Jeff Cutsinger

  1. 10 Reasons I Use Adblock

    1. Privacy.

    If an advertiser can display an ad, they can use it for tracking. And they do, all the time, in egregious and persistent ways. There is no decent way of opting out of this; the train-wreck that the do not track proposal has become shows that advertisers have extremely inventive ways of interpreting “not tracking”.

    2. Security.

    It turns out that ads are increasingly becoming a vector for malware delivery.

    3. Advertisements are inefficient, part 1.

    In order to be sustainable, ads need to produce more profit than they cost the companies employing them. So, while ads are commonly thought of as free, they in fact must be costing consumers more than companies pay to content creators. Thus, it would be more efficient to pay content creators directly.

    4. Advertisements are inefficient, part 2.

    The efficiency of markets depends on how well informed consumers are. Any advertiser doing their job makes ads that highlight the strengths of a product while downplaying its weaknesses. That is, effective ads are fundamentally misinformation. Thus, ads make the markets they exist in less efficient.

    5. Advertisements fuel greed.

    The point of ads is to make people want things they otherwise wouldn’t. And they are surprisingly effective.

    6. Advertisements are annoying.

    Without adblock, the web becomes a constant assault on the senses.

    7. It works.

    The bottom line is that adblock works. Content creators are giving away their product for free, whether they want to or not. In a sense, ads are to adblock as DRM is to copyright infringement. They punish legitimate customers; meanwhile there is a free and superior alternative available. The difference is that copyright infringement is illegal and adblock is not.

    8-10. I lied.

    I’m only listing 7 reasons, not 10.

    Why it’s terrible that I use adblock.

    Despite all the reasons ads are awful, the web has settled on them as the primary source of revenue for content creators. Usually the only way to support content creators is to view ads. I do want to support content creators, I just don’t want ads more. And that’s kind of selfish.

  2. “Encryption” is not enough

    As I’ve become slightly less ignorant about information security and encryption, I’ve noticed a disturbing trend: vagueness. Okay, so maybe that should be unsurprising, but it’s a serious problem in this context. As an example, here’s something Sony said about the recent attack on the PSN:

    The entire credit card table was encrypted and we have no evidence that credit card data was taken.

    My questions are: what does it even mean for the “entire table” to be “encrypted”? What algorithm did they use? Was it strong? And if so, where was the key? What steps were taken to protect this key? They may have used AES or RSA with a key stored securely on a server located elsewhere from the credit card table. But then again, they may not have. They may have stuffed it in a table next to the credit card table where anyone with read access to the DB could grab it. This is like having a door which is locked, with the key hanging on a chain next to the lock. The point is, we don’t know which one these they did; we just know it was “encrypted”.

    Sony’s not the only one guilty of this. Microsoft just recently announced a new wireless keyboard and mouse which “features Advanced Encryption Standard (AES), which can help protect your personal and business information by encrypting what you type”. Hey! They at least told us the algorithm they used; and they used a good one at that! But this is still not enough. Again there is no mention of the key; how it is exchanged or stored. They could perhaps pair the device and its receiver at manufacture-time, which would be secure. Or they could send the keys across in the clear. Or they could all share a global key. Even if they get that right, if they don’t append a salt to the scan code before sending it, they’re basically using a substitution cipher. Maybe they do this, maybe they don’t. But in the end, we don’t know what it does, we just know it’s “encrypted”.

    It doesn’t have to be like this. Tarsnap is an exceedingly excellent counter-example, with thorough descriptions of both the overall security design and the cryptography. KeePass is another good example of proper security documentation. Both programs are also open source, which is a bonus. It’s good to know that if I place my data in the care of these programs, it will be encrypted, not just “encrypted”.

  3. Statically-typed Heterogeneous Lists in C♯

    I typically don’t write C♯ for fun, but what I’ve been doing at work has gotten the juices flowing and I thought I’d share a taste with you. Read on to taste my delicious mind juices.

    public static class Examples {
      public static void SingleMember() {
        var list = HList.Create(15);
        Debug.Assert(list.Peek == 15);
    
        // Compiler error
        // var wat = list.Pop()
      }
    
      public static void TwoMembers() {
        var list = HList.Create(20).Push("Puppy");
    
        // Compiler error
        // var sickAndTwisted = list.Peek / 2;
    
        var twenty = list.Pop().Peek;
    
        Debug.Assert(twenty == 20);
    
        // Compiler error
        // var huh = list.Pop().Pop();
      }
    
      public static void AndSoOn() {
        var list =
          HList
          .Create(1)
          .Push("2")
          .Push(new DateTimeOffset(3, TimeSpan.FromHours(4)))
          .Push(5.0d);
    
        Debug.Assert(list.Pop().Pop().Pop().Peek == 1);
      }
    }
    

    I’ll start with examples to give you an idea of what I mean by “statically-typed heterogeneous list”. Since I’m using a stack-style API, I’ll go backwards through the term. You should know what “list” means, so I’ll use this opportunity to point out that the HList type doesn’t allow for non-empty lists. Due to the static nature of the list, it just wouldn’t make any sense for one to be empty. “Heterogeneous” means that the list can contain values of multiple types. IList<T> is a statically-typed homogeneous list since it only allows values of type T. Finally, “statically-typed” means that the compiler knows the types of the list’s members. The second example demonstrates this well; uncommenting the “sickAndTwisted” line will cause a compiler error, saving the precious puppy within from being cut in half by demented dynamic typing advocates. ArrayList is a dynamically-typed heterogeneous list; you can put values of multiple types in, but the compiler is unaware of their types.

    HList shares the most similarity with the built-in (to .NET 4) Tuple type. However, HList can store an arbitrary number of values, at least until the compiler decides it has had enough of nesting generic types. I don’t know when that happens.

    Without further ado:

    public static class HList {
      public static HList<T> Create<T>(T member) {
        return new HList<T>(member);
      }
    }
    
    public class HList<TValue> {
      private readonly TValue _member;
    
      public HList(TValue member) {
        _member = member;
      }
    
      public TValue Peek {
        get { return _member; }
      }
    
      public HList<T, HList<TValue>> Push<T>(T member) {
        // Second type argument doesn't matter, but is necessary.
        return HList<T, StackOverflowException>.Create<T>(member, this);
      }
    }
    
    public class HList<TValue, TRest> where TRest : class {
      private readonly TValue _member;
      private readonly TRest _rest;
    
      private HList(TValue member, TRest rest) {
        if(rest == null) {
          throw new ArgumentNullException("rest");
        }
    
        _member = member;
        _rest = rest;
      }
    
      internal static HList<TValue, HList<T>> Create<T>(TValue newMember, HList<T> rest) {
        return new HList<TValue, HList<T>>(newMember, rest);
      }
    
      public HList<T, HList<TValue, TRest>> Push<T>(T member) {
        return new HList<T, HList<TValue, TRest>>(member, this);
      }
    
      public TRest Pop() {
        return _rest;
      }
    
      public TValue Peek {
        get { return _member; }
      }
    }
    

    As you can see there is no great magic here; it’s basically the first datatype one learns in any functional language, but encoded in the type system. It’s not terribly practical, but it is pretty fun. My hope is that it’ll inspire you to play more with C♯’s type system and static type systems in general. Enjoy!

  4. Revenge of the Titans Workaround

    If you haven’t already, you should check out the Humble Indie Bundle #2. If you have, and are running a Debian-based Linux, you may have run into the following problem:

    jeff@metzger ~/Downloads> sudo dpkg -i RevengeOfTheTitans-HIB-i386.deb 
    Selecting previously deselected package revenge-of-the-titans.
    (Reading database ... 207859 files and directories currently installed.)
    Unpacking revenge-of-the-titans (from RevengeOfTheTitans-HIB-i386.deb) ...
    dpkg: error processing RevengeOfTheTitans-HIB-i386.deb (--install):
     unable to create `/opt/revengeofthetitans/full_length_music/einleitung.mp3.dpkg-new' (while processing `/opt/revengeofthetitans/full_length_music/einleitung.mp3'): No such file or directory
    dpkg-deb: subprocess paste killed by signal (Broken pipe)
    Processing triggers for bamfdaemon ...
    Rebuilding /usr/share/applications/bamf.index...
    Processing triggers for python-gmenu ...
    Rebuilding /usr/share/applications/desktop.en_US.utf8.cache...
    Processing triggers for desktop-file-utils ...
    Processing triggers for python-support ...
    Errors were encountered while processing:
     RevengeOfTheTitans-HIB-i386.deb
    

    If so, I have found this workaround helpful:

    ar x RevengeOfTheTitans-HIB-i386.deb
    tar xf data.tar.gz
    rm data.tar.gz
    tar cfz data.tar.gz usr/ opt/
    cp RevengeOfTheTitans-HIB-i386.deb RevengeOfTheTitans-HIB-i386-fixed.deb
    ar r RevengeOfTheTitans-HIB-i386-fixed.deb data.tar.gz
    

    It should go without saying that this workaround is not thoroughly tested and may eat your computer.

  5. Google Interview Answers, part 0

    This is the first in a series of posts where I will attempt to answer some of the interesting interview questions which are given to programming candidates at Google. Unless otherwise noted, I answered these questions of my own accord and did not look them up.

    This post is literate haskell, so you can copy/paste it into a file with the extension .lhs and it will compile in ghc.

    > {-# LANGUAGE NoMonomorphismRestriction #-}
    > import Data.List
    > import Data.Maybe
    > import Control.Monad
    > import System.Random
    

    Question: Given a function which produces a random integer in the range 1 to 5, write a function which produces a random integer in the range 1 to 7.

    I’m going to slightly modify the question. First, I want to deal with integers starting with 0, so the ranges will be 0 to 4 and 0 to 6. Second, random numbers are a little tricky in Haskell, since they violate referential integrity. My answers could be written monadically to handle this, but instead I will write functions that take an infinite list (or lists) of integers, assumed to be uniformly random and in the range of 0 to 4. Here’s my first answer:

    > random_0_to_6_take_0 = head
    

    head is the haskell function that returns the first member of a list. Since the first member is given as a random integer in the range 0 to 4, it is also a random number in the range 0 to 6. But that’s not the intent of this question. Let’s get a little closer to meeting that intent.

    > random_0_to_6_take_1 ns = (sum $ take 6 ns) `div` 4
    

    take returns the first n (in this case 6) members of a list. sum adds them up. So, this function sums up 6 random numbers to get 0-24, and integer divides the result by 4 to get a number from 0 to 6.

    Again, this answer matches the specification of the question, but likely not the intent. This will produce a random integer between 0 and 6, with 5 and 6 as possible outputs, but the distribution of the outputs won’t be uniform. They’ll be biased towards the middle, just as two 6-sided dice are most likely to add up to 7 when rolled. Additionally, this function will produce 6 only once in 15625 calls (on average). Let’s fix that:

    > random_0_to_6_take_2 ns0 ns1 =
    >   let n = fromJust $
    >            find (< 21) $
    >            zipWith (\x y -> x + (5 * y)) ns0 ns1
    >   in
    >     n `div` 3
    

    zipWith traverses two lists memberwise, mapping each pair of members using the given function. Since x and y are uniformly distributed between 0 and 4, x + (5 * y) is uniformly distributed between 0 and 24. find returns the first member satisfying the given predicate, which nets us an integer, uniformly distributed between 0 and 20. Dividing by 3 and truncating gives an integer, uniformly distributed between 0 and 6. Mission accomplished! Now to make it work.

    > skip1 [] = []
    > skip1 (hd:tl) = hd:(skip2 tl)
    
    > skip2 [] = []
    > skip2 (hd:tl) = skip1 tl 
    
    > take_2 lst = random_0_to_6_take_2 (skip1 lst) (skip2 lst)
    
    > aggregate = map (\g -> (head g, length g)) . group . sort
    
    > create_many ls f = zipWith ($) (replicate 1000000 f) ls
    
    > random_list :: RandomGen g => g -> [Int]
    > random_list = randomRs (0, 4)
    
    > run ls f = putStrLn . show . aggregate $ create_many ls f
    
    > functions = [random_0_to_6_take_0, random_0_to_6_take_1, take_2]
    
    > main = do
    >   gen <- getStdGen
    >   let lists = map random_list $ map mkStdGen $ randoms gen
    >   mapM_ (run lists) functions
    

    And here’s an output I got. Notice that in 1,000,000 iterations, the second function produced 6 only 63 times.

    [(0,200092),(1,200329),(2,199494),(3,199689),(4,200396)]
    [(0,5456),(1,94158),(2,344817),(3,395923),(4,146038),(5,13545),(6,63)]
    [(0,142393),(1,142973),(2,142851),(3,143253),(4,142905),(5,142912),(6,142713)]

    Overall, this was great fun. What an excellent question! I hope my answer is enlightening.