Above, Below, and Beyond Tech Talk

by Rahel Lüthy

May 3, 2018

GitHub Pages Custom Domains Via HTTPS

Two days ago, GitHub announced the support of HTTPS for custom domains. In addition to this blog, I maintain a few websites for friends and family, all configured through A records – time for migration!

Officially, the migration is a simple matter of toggling the “Enforce HTTPS” button, but the button was disabled for all of my sites. The explanation wasn’t particularly encouraging: Unavailable for your site because your domain is not properly configured to support HTTPS.

Well, time for RTFM (not my favorite hobby).

These are the steps that finally worked for me:

HTTPS Migration Steps

Step 0: Mixed Content Prevention

First things first: Prepare your site’s content. Ensure that all your assets (links to CSS, JS, etc.) are loaded via HTTPS. Otherwise browsers might block your “Mixed Content”.

Step 1: DNS A-Record Migration

On your provider’s website, change all A records to point to the following four new IPs:
 

192.30.252.153

192.30.252.154

185.199.108.153

185.199.109.153

185.199.110.153

185.199.111.153
 

This change might take a few hours to become effective (depending on the TTL). Use dig to check whether the new DNS configuration is ready:

dig netzwerg.ch +noall +answer

It should look like this:

; <<>> DiG 9.10.6 <<>> netzwerg.ch +noall +answer
;; global options: +cmd
netzwerg.ch.		10800	IN	A	185.199.110.153
netzwerg.ch.		10800	IN	A	185.199.111.153
netzwerg.ch.		10800	IN	A	185.199.108.153
netzwerg.ch.		10800	IN	A	185.199.109.153

Step 2: Trigger Certificate Generation

In order for GitHub to detect that your site is now ready for migration, you apparently need to trigger a detection script. Any change to your repository’s CNAME file will do, so e.g. make a minor change and revert it, or make a harmless whitespace edit. As a result, GitHub will now generate the certificates necessary for HTTPS.

Step 3: Wait For Certificate Availability

Now the “Enforce HTTPS” button will still be disabled, but the explanation will be much more encouraging: Not yet available for your site because the certificate has not finished being issued. More patience required, we’re getting there…

Step 4: Enforce HTTPS

It might take a few hours, but as soon as this message is gone, you can access your site via HTTPS. Check that everything still works (particularly your new HTTPS asset links). Once you’re happy, toggle the “Enforce HTTPS” switch – Voilà!


April 24, 2018

Position animations across SVG groups

Animated transitions between UI states can greatly enhance the usability of applications because they reduce the likelihood of change blindness.

In a typical web application, UI state is represented by the DOM. Instead of switching from one DOM state to the next instantaneously, animations smoothly transition DOM element properties over time.

On a technical level, a multitude of libraries provide abstractions to create animated transitions with minimal effort.

This is how an animation of an SVG circle would look like with D3.js (notice the “Rerun” button which appears once you hover the right pane):
 

See the Pen D3.js Animation by Rahel Lüthy (@netzwerg) on CodePen.


 

D3.js is interpolating the circle’s cx attribute from 10 to 190 pixels over the course of a second.

Well, this is a simple example because the SVG scene graph is simple – it just contains one circle. Unfortunately, SVG scene graphs tend to get very complex in real applications. One way to tame this complexity, is by breaking applications into components, each responsible for rendering a sub-graph of the final SVG.

Components FTW

Component-based libraries like React come in handy here: Each component is responsible for rendering a small, human-digestible SVG chunk.

Here’s a React component which renders a box with a circle at its center:

const Box = ({width, height}: BoxProps) => {
    return (
        <g>
            <rect width={width} height={height}/>
            <circle cx={width / 2} cy={height / 2}/>
        </g>
    );
};

Using simple composition, we can then stack two boxes on top of each other:

<g>
    <Box width={width} height={height / 2} />
</g>
<g transform={`translate(0,${height / 2})`}>
    <Box width={width} height={height / 2} />
</g>

Note how the second box gets moved to the bottom by translating its container group by height/2.

To make things a bit more interesting, let’s make the circle alternate between boxes at a fixed interval:

type State = {
    readonly box: 'UPPER' | 'LOWER';
};

class App extends React.Component<object, State> {

    private readonly circleId = 'circleId';
    private timer: Timer;

    constructor(props: object) {
        super(props);
        this.state = {box: 'UPPER'};
    }

    componentDidMount() {
        this.timer = setInterval(() => this.switchBox(), 1000);
    }

    switchBox() {
        this.setState(prevState => ({box: prevState.box === 'UPPER' ? 'LOWER' : 'UPPER'}));
    }

    render() {

        const viewBox = {width: 100, height: 100};
        const margin = {top: 10, right: 10, bottom: 10, left: 10};
        const width = viewBox.width - margin.left - margin.right;
        const height = viewBox.height - margin.top - margin.bottom;

        return (
            <div className="App">
                <svg viewBox={`0 0 ${viewBox.width} ${viewBox.height}`}>
                    <g transform={`translate(${margin.left}, ${margin.top})`}>
                        <g>
                            <Box
                                circleId={this.circleId}
                                showCircle={this.state.box === 'UPPER'}
                                width={width}
                                height={height / 2}
                            />
                        </g>
                        <g transform={`translate(0,${height / 2})`}>
                            <Box
                                circleId={this.circleId}
                                showCircle={this.state.box === 'LOWER'}
                                width={width}
                                height={height / 2}
                            />
                        </g>
                    </g>
                </svg>
            </div>
        );
    }

    componentWillUnmount() {
        clearInterval(this.timer);
    }

}

Complete code on GitHub

Smoothly Moving Circles

Blinking UIs are almost never a good idea, so back to animations! Smoothly moving the circle between boxes looks way better:

We already know how to animate a circle’s position with D3.js, so this should be simple, right?

Well… the circle’s y-coordinate in the upper box is height/2, and its coordinate in the lower box is height/2, too! So how are we supposed to animate between these identical states?!

I vividly remember my own confusion when I first encountered this problem in one of our research projects.

The complexity is caused by the fact that our components all use their own, 0-based coordinate system. But that’s exactly what made the components simple in the first place, so we don’t want to give this up!

Animations Across Component Boundaries

Situation recap:

What we have (and want to keep): Simple components with 0-based coordinate systems

What we want: Animations across component boundaries

There’s no easy fix, but we know that animations are simple as long as they are happening on a common coordinate system. Thus the idea is straightforward: We keep using 0-based components, but switch to a common coordinate system while performing an animation. One very suitable common coordinate system is the view port coordinate system of our SVG’s root node.

Here’s the rough recipe:

And in code (remember, the complete project is on GitHub):

const circle = this.svgRoot.getElementById(this.circleId) as SVGCircleElement;

if (circle) {

    // (0) Calculate current coordinates relative to global view port
    const currentCoordinates = this.getCoordinates(this.svgRoot, circle);

    const previousCoordinates = this.coordinateCache || currentCoordinates;

    this.coordinateCache = currentCoordinates;

    const easingFunction = currentCoordinates.cy > previousCoordinates.cy ? easeBounceOut : easeCubicInOut;

    // (1) This clone will be used for the animation
    const animatedCircle = circle.cloneNode(true) as SVGCircleElement;

    // (2) Attach to root element (animated x/y coordinates are in the system of the global view port)
    this.svgRoot.appendChild(animatedCircle);

    // (3) The DOM already contains the circle at the new position -> hide it until the animation is over
    select(circle)
        .attr('visibility', 'hidden');

    // (4) The actual animation
    select(animatedCircle)
        .attr('visibility', 'visible')
        .attr('cx', previousCoordinates.cx)
        .attr('cy', previousCoordinates.cy)
        .transition()
        .duration(1000)
        .ease(easingFunction)
        .attr('cx', currentCoordinates.cx)
        .attr('cy', currentCoordinates.cy)
        .remove() // (5) Detach the animated circle once we're done
        .on('end', () => { // (6) Un-hide new state (already properly placed in the DOM)
            select(circle)
                .attr('visibility', 'visible');
        });

}

Phew, some things are harder than they should be – let me know if there’s a simpler way!


June 22, 2016

Covariance in Java and Scala

While there are tons of articles explaining the concept of covariance in Java, this post attempts to highlight how and why Java and Scala differ when it comes to collection type safety.

Java Arrays

Let’s start with Java arrays. They are covariant, meaning that an array of type S[] is a subtype of an array of type T[] if S is a subtype of T:

Cat[] cats = { new Cat("Gizmo"), new Cat("Bella") };
Animal[] animals = cats;

Things are simple and life is good. The fact that arrays are covariant makes code re-use possible. Utility methods inside java.util.Arrays are perfect examples, e.g.:

public static int binarySearch(Object[] a, Object key) {
  // ...
}
binarySearch(new Integer[]{1, 2, 3}, 2); // VALID

As usual, everything falls apart because of mutability. Java arrays are mutable, making it possible to store the wrong type of object into an array without the compiler being able to tell:

Cat[] cats = { new Cat("Gizmo"), new Cat("Bella") };
Animal[] animals = cats;
animals[0] = new Dog("Max"); // FAILS AT RUNTIME

Ouch, heap pollution – an ArrayStoreException is thrown at runtime! People obsessed with types tend to call this unsound.

Java Generics

With Java 5 came generics, which allow “a type or method to operate on objects of various types while providing compile-time type safety.” (Oracle Java 1.5 Docs). Let me repeat that: Generics were introduced to improve type safety. It was thus not an option to accept the same unsound array behavior. Because Java collections are mutable, the only option was to make a List<T> invariant:

List<Cat> cats = Arrays.asList(new Cat("Gizmo"), new Cat("Bella"));
List<Animal> animals = cats; // DOES NOT COMPILE

Even though Cat is a subtype of Animal, List<Cat> is not a subtype of List<Animal>. This is not very intuitive, but it is necessary to prevent heap pollution at runtime.

Obviously, we still want to write re-usable utility code. Wildcards are making that possible. Methods inside java.util.Collections are good examples, e.g.:

public static <T> int binarySearch(List<? extends Comparable<? super T>> list, T key) {
  // ...
}

In Java, you thus get better compile-time safety when using generified collections than when using raw arrays.

Scala Arrays

In Scala, things are a lot different. Array[T] is Scala’s representation for Java’s T[]. Like in Java, a Scala Array is mutable. But in contrast to Java, Scala cares a lot more about compile-time type safety. The only way to prevent unsound heap pollution is to make Array[T] invariant:

val cats: Array[Cat] = Array(Cat("Gizmo"), Cat("Bella"))
val animals: Array[Animal] = cats // DOES NOT COMPILE

Scala arrays are thus safer to use than Java arrays.

Scala List

Things are even better for Scala List, which is immutable. It is thus perfectly safe to make List[+T] covariant (notice the little +). There’s just no way to ever sneak in an object, let alone sneaking in an object with the wrong type:

val cats: List[Cat] = List(Cat("Gizmo"), Cat("Bella"))
val animals: List[Animal] = cats // VALID

In other words: In Scala, List[S] is a subtype of List[T] if S is a subtype of T.


Older Posts » Archive