Lodash Performance Sucks!

To continue my Functional Programming Sucks series of posts I will have a closer look at reduce().

I complained with Lodash (and Underscore) for different reasons. One complaint was performance, but I just read the code and presumed it was going to be slow without measuring. Then I complained with the performance of Functional Programming in general.

I thought it would be interesting to “improve” the Functional code with Lodash functions, and to my surprise (I admit I was both wrong and surprised) I found Lodash made it faster! After reading a little more about it I discovered this is a well known fact.

So, here are four different implementations of a function that checks if the elements (numbers) in an array are ordered (cnt is incremented if the array is sorted, such was the original problem).

// Standard reduce()
    this.test = function(p) {
        if ( false !== p.reduce(function(acc,val) {
            if ( false === acc || val < acc ) return false;
            return val;
        }, -1)) cnt++;
    };

// Lodash reduce(), and some other Lodash waste
    this.test = function(p) {
        if ( false !== LO.reduce(p,function(acc,val) {
            if ( false === acc || val < acc ) return false;
    //      if ( !LO.isNumber(acc) || val < acc ) return false;
            return val;
        }, -1)) cnt++;
    };

// My own 4 minute to implement simpleReduce(), see below
    this.test = function(p) {
        if ( false !== simpleReduce(p,function(acc,val) {
            if ( false === acc || val < acc ) return false;
            return val;
        }, -1)) cnt++;
    };

// A simple imperative version
    this.test = function(p) {
        var i;
        for ( i=1 ; i < p.length ; i++ ) {
            if ( p[i] < p[i-1] ) return;
        }
        cnt++;
    };

// my own implementation reduce()
    function simpleReduce(array, func, initval) {
         var i;
         var v = initval;
         for ( i=0 ; i<array.length ; i++ ) {
             v = func(v, array[i]);
         }
         return v;
    }

The interesting thing here is that the standard library reduce() is the slowest.
However, my simpleReduce is faster than Lodash reduce().

(seconds) reduce()
Std Lib Lodash Simple Imperative
Raspberry Pi v1 (ARMv6 @ 700) 21 13 9.3 4.8
MacBook Air (Core i5 @ 1400) 0.46 0.23 0.19 0.16

Conclusion
The conclusion is that from a performance perspective Functional Programming sucks. Lodash sucks too, but a little bit less so than the standard library (however, if you decorate all your code with isEmpty, isString, isNumber and that crap it will get worse).

That said, the generic nature of Lodash comes at a cost. The most simpleReduce() imaginable outperforms Lodash. As I see it, this leaves Lodash in a pretty bad (or small) place:

  • Compared to the standard library it is an extra dependency with limited performance benefits
  • The generic nature of Lodash comes at both a performance cost and it allows for sloppy coding
  • A hand written reduce() outperforms Lodash and is a good excercise for anyone to write. I expect this is quite true also for other functions like take or takeRight.
  • For best performance, avoid Functional Programming (and in this case the imperative version is arguably more readable than the FP reduce() versions)

Whats up with the Standard Library???
JavaScript is a scripted language (interpreted with a JIT compiler) that has a standard library written in C++. How can anything written in JavaScript execute faster than anything in the standard library that does the same thing?

First, kudos to the JIT designers! Amazing job! Perhaps the standard library people can learn from you?

I can imagine the standard library functions are doing some tests or validations that are somehow required by the standard, and that a faster and less strict version of reduce() would possibly break existing code (although this sounds far fetched).

I can (almost not) imagine that there is a cost of going from JS to Native and back to JS: that function calls to native code comes with overhead. Like going from user space to kernel space. It sounds strange.

I have read that there are optimizations techniques applied to Lodash (like lazy evaluation), but I certainly didn’t do anything like that in my simpleReduce().

For Node.js optimizing the standard library truly would make sense. In the standard library native code of a single-threaded server application every cycle counts.

UPDATE: I tried replacing parts of the above code: 1) the lambda function that is passed to reduce(), 2) the imperative version, with native code. That is, I wrote C++ code for V8 and used it instead of JavaScript code. In both cases this was slower! Obviously there is some overhead in going between native and JavaScript JIT, and for rather small functions this overhead makes C++ “slower” than JavaScript. My idea was to write a C++ reduce() function but I think the two functions I wrote are enough to show what is happening here. Conclusion: don’t write small native C++ functions for performance, and for maximum performance it can be worth to rewrite the standard library in JavaScript (although this is insane to do)!

All FP-sucks related articles
Functional Programming Sucks)
Underscore.js sucks! Lodash sucks!
Functional Programming Sucks! (it is slow)
Lodash Performance Sucks! (this one)

Functional Programming Sucks! (it is slow)

Update 2017-07-17: Below i present numbers showing that functional code is slower than imperative code. It seems this has changed with newer versions of Node.js: functional code has not turned faster but imperative code has become slower. You can read a little more about it in the comments. I will look more into this. Keep in mind that the below findings may be more accurate for Node.js v4-6 than for v8.

Functional programming is very popular with contemporary JavaScript programmers. As I have written before, Functional programming sucks and functional libraries for JavaScript also suck.

In this post I will explain more why Functional Programming sucks. I will start with the conclusion. Read on as long as you want more details.

Functional Programming practices are bad for performance
It is very popular to feed lamda-functions to map(), reduce(), filter() and others. If you do this carelessly the performance loss is significant.

It is also popular to work with immutable data. That is, you avoid functions that change (mutate) current state (side effects) and instead you produce a new state (a pure function). This puts a lot of pressure on the garbage collector and it can destroy performance.

The Benchmark Problem
Sometimes I entertain myself solving problems on Hackerrank.com. I particularly like the mathematical challenges in the Project Euler section (the Project Euler is also an independent organisation – HackerRank uses the challenges in Project Euler to create programming challenges).

This article refers to Project Euler 32. I will not go into details, but the solution is basically:

  1. Generate all permutations of the numbers 1,2,3,4,5,6,7,8,9 (there are 9! of them)
  2. For each permutation, check if it is “good” (very few are)
  3. Print the sum of the good instances

The first two steps give good benchmark problems. I have made different implementations of (1) and (2) and then compared the results.

Benchmark Results
I have three different permutation generators (all recursive functions):

  1. Pure function, immutable data (it may not be strictly pure)
  2. Function that mutates its own internal state, but not its input
  3. Function that mutates shared data (no allocation/garbace collection)

I also have three different test functions:

  1. Tests the orginal Project Euler problem
  2. Simplified test using reduce() and lamda function
  3. Simplified test implemented a standard loop

I benchmarked on two different systems using Node.js version 6. I have written elsewhere that Node.js performance on Raspberry Pi sucks.

(seconds) Project Euler Test Simplified Test
Test Function: Functional Imperative
Permutation Gen: Pure Semi Shared Shared Shared Pure
Raspberry Pi v1 (ARMv6 @ 700) 69 23 7.4 21 3.7 62
MacBook Air (Core i5 @ 1400) 0.77 0.29 0.13 0.40 0.11 0.74

Comparing columns 1-2-3 shows the performance of different generators (for Project Euler test)
Comparing columns 4-5 shows the performance of two different test functions (using fast generator)
Comparing columns 5-6 shows the performance of two different generators (for fast simple test)

This shows that the benefit of using shared/mutable data (not running the garbage collector) instead of immutable data is 5x performance on the Intel CPU and even more on the ARM. Also, the cost of using reduce() with a lamda function is more than 3x overall performance on the Intel CPU, and even more on the ARM.

For both the test function and permutation generation, making any of them functional-slow significantly slows down the entire program.

The conclusion of this is that unless you are quite sure your code will never be performance critical you should avoid functional programming practices. It is a lot easier to write imperative code than to later scale out your architecture when your code does not perform.

However, the pure immutable implementation of the permutation generator is arguably much simpler than the iterative (faster) counterpart. When you look at the code you may decide that the performance penalty is acceptable to you. When it comes to the reduce() with a lamda function, I think the imperative version is easier to read (and much faster).

Please notice that if your code consists of nice testable, replaceble parts without side effects you can optimize later on. The functional principles are more valuable at a higher level. If you define your functions in a way that they behave like nice FP functions it does not matter if they are implemented using imperative principles (for performance).

Generating Permutations
I used the following simple method for generating permutations. I start with two arrays and I send them to my permute-function:

  head = [];
  tail = [1,2,3,4];

  permute(head,tail);

My permute-function checks if tail is empty, and then: test/evalute head.
Otherwise it generates 4 (one for each element in tail) new sets of head and tail:

  permute( [1] , [2,3,4] )
  permute( [2] , [1,3,4] )
  permute( [3] , [1,2,4] )
  permute( [4] , [1,2,3] )

The difference in implementation is:

  • Pure version generates all the above 8 arrays as new arrays using standard array functions
  • Semi pure version generates its own 2 arrays (head and tail) and then uses a standard loop to change the values of the arrays between the (recursive) calls to permute.
  • Shared version simply creates a single head-array and 9 tail-arrays (one for each recursion step) up front. It then reuses these arrays throughout the 9! iterations. (It is not global variables, they are hidden and private to the permutation generator)

The simplified test
The simplified test checks if the array is sorted: [1,2,3,4]. Of all permutations, there is always exactly one that is sorted. It is a simple test to implement (especially with a loop).

// These functions are part of a "test-class" starting like:
function testorder1() {
    var cnt = 0;

// Functional test
    this.test = function(p) {
        if ( false !== p.reduce(function(acc,val) {
            if ( false === acc || val < acc ) return false;
            return val;
        }, -1)) cnt++;
    };

// Iterative test (much faster)
    this.test = function(p) {
        var i;
        for ( i=1 ; i<p.length ; i++ ) {
            if ( p[i] < p[i-1] ) return;
        }
        cnt++;
    };

I tried to optimise the functional reduce() version by breaking out a named function. That did not help. I also tried to let the function always return the same type (now it returns false OR a number) but that also made no difference at all.

All the code
For those who want to run this themselves or compare the permutation functions here is the entire program.

As mentioned above, the slowest (immutable data) permutation function is a lot smaller and easier to understand then the fastest (shared data) implementation.


'use strict';

// UTILITIES

function arrayToNum(p, s, e) {
    var r = 0;
    var m = 1;
    var i;
    for ( i=e-1 ; s<=i ; i-- ) {
        r += m * p[i];
        m *= 10;
    }
    return r;
}

function arrayWithZeros(n) {
    var i;
    var a = new Array(n);
    for ( i=0 ; i<a.length ; i++ ) a[i] = 0;
    return a;
}


// PERMUTATION ENGINES

function permutations0(n, callback) {
}

// IMMUTABLE (SLOWEST)

function permutations1(n, callback) {
    var i;
    var numbers = [];
    for ( i=1 ; i<=n ; i++ ) numbers.push(i);
    permute1([],numbers,callback);
}

function permute1(head, tail, callback) {
    if ( 0 === tail.length ) {
        callback(head);
        return;
    }

    tail.forEach(function(t, i, a) {
        permute1( [t].concat(head),
                  a.slice(0,i).concat(a.slice(i+1)),
                  callback);

    });
}

// MUTATES ITS OWN DATA, BUT NOT ITS ARGUMENTS

function permutations2(n, callback) {
    var i;
    var numbers = [];
    for ( i=1 ; i<=n ; i++ ) numbers.push(i);
    permute2([],numbers,callback);
}

function permute2(head, tail, callback) {
    if ( 0 === tail.length ) {
        callback(head);
        return;
    }
    var h2 = [tail[0]].concat(head);
    var t2 = tail.slice(1);
    var i  = 0;
    var tmp;
    
    while (true) {
        permute2(h2, t2, callback);
        if ( i === t2.length ) return;
        tmp   = h2[0];
        h2[0] = t2[i];
        t2[i] = tmp;
        i++;
    }
}

// MUTATES ALL DATA (INTERNALLY) (FASTEST)

function permutations3(n, callback) {
    var i;
    var head  = arrayWithZeros(n);
    var tails = new Array(n+1);

    for ( i=1 ; i<=n ; i++ ) {
        tails[i] = arrayWithZeros(i);
    }

    for ( i=1 ; i<=n ; i++ ) {
        tails[n][i-1] = i;
    }

    function permute3(x) {
        var j;
        var tail_this;
        var tail_next;
        var tmp;
        if ( 0 === x ) {
            callback(head);
            return;
        }
        tail_this = tails[x];
        tail_next = tails[x-1];

        for ( j=1 ; j<x ; j++ ) {
            tail_next[j-1] = tail_this[j];
        }

        j=0;
        while ( true ) {
            head[x-1] = tail_this[j];
            permute3(x-1);
             
            j++;
            if ( j === x ) return;

            tmp            = head[x-1];
            head[x-1]      = tail_next[j-1];
            tail_next[j-1] = tmp;
        }
    }

    permute3(n);
}

// TEST FUNCTIONS

function testprint() {
    this.test = function(p) {
        console.log(JSON.stringify(p));
    };

    this.done = function() {
        return 'Done';
    };
}

// CHECKS IF PERMUTATION IS ORDERED - FUNCTIONAL (SLOWEST)

function testorder1() {
    var cnt = 0;

    this.test = function(p) {
        if ( false !== p.reduce(function(acc,val) {
            if ( false === acc || val < acc ) return false;
            return val;
        }, -1)) cnt++;
    };

    this.done = function() {
        return cnt;
    };
}

// CHECKS IF PERMUTATION IS ORDERED - IMPERATIVE (FASTEST)

function testorder2() {
    var cnt = 0;

    this.test = function(p) {
        var i;
        for ( i=1 ; i<p.length ; i++ ) {
            if ( p[i] < p[i-1] ) return;
        }
        cnt++;
    };

    this.done = function() {
        return cnt;
    };
}

// TEST FUNCTION FOR PROJECT EULER 32

function testeuler() {
    var sums = {};

    this.test = function(p) {
        var w1, w2, w;
        var m1, m2, mx;
        w =  Math.floor(p.length/2);
        w1 = 1;
        w2 = p.length - w - w1;
    
        while ( w1 <= w2 ) {
            m1 = arrayToNum(p,     0, w1      );
            m2 = arrayToNum(p,    w1, w1+w2   );
            mx = arrayToNum(p, w1+w2, p.length);
        
            if ( m1 < m2 && m1 * m2 === mx ) {
                sums['' + mx] = true;
            }
        
            w1++;
            w2--;
        }
    };

    this.done = function() {
        var i;
        var r = 0;
        for ( i in sums ) {
            r += +i;
        }
        return r;
    };
}

// MAIN PROGRAM BELOW

function processData(input, parg, targ) {
    var r;

    var test = null;
    var perm = null;

    switch ( parg ) {
    case '0':
        perm = permutations0;
        break;
    case '1':
        perm = permutations1;
        break;
    case '2':
        perm = permutations2;
        break;
    case '3':
        perm = permutations3;
        break;
    }

    switch ( targ ) {
    case 'E':
        test = new testeuler;
        break;
    case 'O1':
        test = new testorder1;
        break;
    case 'O2':
        test = new testorder2;
        break;
    case 'P':
        test = new testprint();
        break;
    }


    r = perm(+input, test.test);
    console.log(test.done());
} 

function main() {
    var input = '';
    var parg = '1';
    var targ = 'E';
    var i;

    for ( i=2 ; i<process.argv.length ; i++ ) {
        switch ( process.argv[i] ) {
        case '0':
        case '1':
        case '2':
        case '3':
            parg = process.argv[i];
            break;
        case 'E':
        case 'O1':
        case 'O2':
        case 'P':
            targ = process.argv[i];
            break;
        }
    }
    

    process.stdin.resume();
    process.stdin.setEncoding('ascii');
    process.stdin.on('data', function (s) {
        input += s;
    });

    process.stdin.on('end', function () {
       processData(input, parg, targ);
    });
}

main();

This is how I run the code (use a lower value than 9 to have fewer than 9! permutations)

### Project Euler Test: 3 different permutation generators ###
$ echo 9 | time node projecteuler32.js 3 E
45228
8.95user ...
b$ echo 9 | time node projecteuler32.js 2 E
45228
25.03user ...
$ echo 9 | time node projecteuler32.js 1 E
45228
70.34user ...

### Simple check-order test, two different versions. Fastest permutations.
b$ echo 9 | time node projecteuler32.js 3 O1
1
23.71user ...
$ echo 9 | time node projecteuler32.js 3 O2
1
4.72user ...

(the timings here may not exactly match the above figures)

All FP-sucks related articles
Functional Programming Sucks)
Underscore.js sucks! Lodash sucks!
Functional Programming Sucks! (it is slow) (this one)
Lodash Performance Sucks!

Underscore.js sucks! Lodash sucks!

In a world of functional programming hype there are two very popular JavaScript frameworks: underscore.js and Lodash. Dont use them! It is a horrible idea. They suck just like functional programming sucks!

They make claims like:

  • Lodash: A modern JavaScript utility library delivering […] performance
  • Underscore: JavaScript library that provides a whole mess of useful functional programming helpers.

The road to hell is sided by good intentions. This is how it goes.

1. Sloppy data types
There are many good things about JavaScript. The sloppy dynamic typing is perhaps not one of them. The following are for example true:

  • ’27’ == 27
  • undefined == null
  • 0 == ”
  • ‘object’ === typeof null

Now that I consider myself an experienced programmer I find it quite convenient to not need to be explicit about data types. But I dont mix and change types! If a variable is a number from the beginning it keeps being a number. I carefully pick types: Objects, Arrays, Number, String and stick to that type (for a variable or property). Occationally – mostly for return variables – I break the rule.

Lodash and Underscore is about allowing yourself to be sloppy:

  • Dont know if its an object or an array: use map, foreach, filter, reduce and many more
  • Dont know if it is empty (or what being empty even means): use isEmpty
  • Dont know if it is String Object or a String primitive or something else: use isString

If you dont know what it is is you already have a much bigger problem than how to do something with it.
If you mix String Objects and String primitives AND other things, and you want to know if it is any kind of string you are doing something wrong.

So Step 1 with Lodash and Underscore is that you

  1. Add a depenceny
  2. Allow sloppy and inconsistent typing
  3. No one can now presume anything about your types anymore
  4. Your code is now impossible to maintain or extend without lodash or underscore

2. Performance!
My experience after many years in software development is that when an application is not well received by the users it is very often because of (bad) performance. And bad performance causes weird, hard to reproduce, bugs and instability as well.

An important type of optimization that the JIT can do relies on the runtime generating classes with strict types for your objects (it guesses and learns the types as the program runs). If you allow a property to assume values of different types you are likely to destroy this optimization.

Lets look at the little function isEmpty.

/** Underscore **/
_.isEmpty = function(obj) {
    if (obj == null) return true;
    if (isArrayLike(obj) && (_.isArray(obj) || _.isString(obj) || _.isArguments(obj))) return obj.length === 0;
    return _.keys(obj).length === 0;
};

/** Lodash **/
function isEmpty(value) {
    if (isArrayLike(value) &&
        (isArray(value) || isString(value) ||
         isFunction(value.splice) || isArguments(value))) {
        return !value.length;
    }
    return !nativeKeys(value).length;
}

If you KNOW the datatype you can just do:

/** String **/
if ( 0 === s.length )

/** String that may be null **/
if ( null === s || 0 === s.length )

/** Array **/
if ( 0 === a.length )

/** Object **/
function objectIsEmpty(o) {
    for ( x in o ) return false;
    return true;
}

(you may want to check o.hasOwnProperty(x) depending on what you actually want – but if you dont know what you want using Lodash or Underscore will produce equally unexpected results as my code)

The worst thing with the Underscore and Loadash implementations are the last lines:

    return _.keys(obj).length === 0;
    return !nativeKeys(value).length;

Unless the JIT compiler and runtime is very smart those two will produce an entire array of strings on the heap – just to check if the array length is 0! Even though this in most practical cases will have an acceptable overhead it can get very expensive.

This IS the beauty of FP generic programming. Focus on WHAT, not HOW, and any little innocent check (like isEmpty) can turn horribly expensive.

However, to be honest, I took some plain functional code and replaced plain JavaScript with Lodash functions (forEach, reduce, isNumber, isEmpty and a few more) and the code actually got faster! Still much slower than imperative code, but slightly faster than not using Lodash.

3. Complexity and Optimization
Now that you have added an extra dependency, made your data objects sloppy, made your application harder for the JIT to optimize, perhaps your application is not as quick as you need it to be. If you are writing a front end you are probably quite fine. But if you are coding a Node.js backend, performance matters a lot more and waste is more unacceptable. If you are really unlucky these sloppy types give you hard to find bugs and your backend is not completely stable and reliable.

What do you do? Common practices in the business could be things like:

  • Minification/uglification
  • Scale out service architecture
  • Failover technology
  • Spend time optimizing code and modules

This is how little sloppyness, laziness and convenience when making initial decisions about your architecture later can cause you huge problems and costs.

Of course, just including lodash and using isEmpty() in a few places is not going to do much (if any) harm.
But finding lodash or underscore generally preferable to not using them is one kind of low quality thinking that causes software to be bad.

Conclusion
Be explicit, careful, consistent and smart about the data types you use.
Be restrictive with libraries and frameworks that introduce overhead and hide relevant details.

Use the standard library. However, you can find that for example the Array functions of Lodash outperform the standard library equivalents. That may not be true in the future (and I really wonder how it can happen at all).

All FP-sucks related articles
Functional Programming Sucks)
Underscore.js sucks! Lodash sucks! (this one)
Functional Programming Sucks! (it is slow)
Lodash Performance Sucks!

Functional Programming Sucks*

(*like everything else that is mindlessly applied the wrong way to solve the wrong problems)

Functional Programming Rocks!
You can do amazing things with Haskell. The historical importance of Lisp is huge. Math, computer science, algorithms and engineering can come together beautifully with functional programming. Writing small reusable, testable functions with no side effects is a great thing to do in any language – but more than anywhere else those virtues are emphasized in functional programming. I love first class functions!

But…

The unfortunate JavaScript Hype
As JavaScript made map, filter and reduce part of the standard those have become the foremost frontier of functional programming. Being quite serious, many people argue that if you replace your for-loops with map, filter, reduce and forEach you have achieved something significant when it comes to readability. What do you think?

// non-functional smelly loop
redFruits = [];
for ( f in fruits ) {
  if ( 'red' === fruits[f].color ) redFruits.push(fruits[f]);
}

// fantastic functional alternative
greenFruits = fruits.filter(function(f) {
  return 'green' === f.color;
});

As a bonus with functional, you can use lamda-functions… that is functions, with no name, that can not be reused. You can even use arrow-functions if you think this is too easy a concept and you think the code gets more readable by omitting the confusing word function.

While there are a lot of balanced articles about using functional ideas in JavaScript, for a lot of people eliminating for-loops at any cost seems to be functional enough.

The argument here is that your code should be declarative, it should express intention rather than instructions. In the case above with the fruit-filter it does make some sense. But if that argument should make any sense, it requires that the programmer does not abuse map, filter, forEach or reduce to eliminate a for-loop just for the sake of it. I have seen things like:

// functional
applePrice = Object.keys(fruits).filter(function(f) {
  return 'apple' === f.name;
})[0].price;

// when this would work
for ( f in fruits ) {
  if ( 'apple' === fruits[f].name ) {
    applePrice = fruits[f].price;
    break;
  }
}

I have several objections with the functional version. The Object.keys thing is hardly pleasant to the eye. It is false marketing to use filter: the intention is find or search, not filter. So you still need to read the details (just as with the for-loop), you are just first fooled into thinking its a filter (and chaining is very popular, so then you have no function names and no variable names). But perhaps the worst problem is the lack of error handling. Functional code is not meant to have side effects, and error handling is exactly that. If ‘apple’ is not found you get an ugly Error. You can of course try/catch, or make temporary array variable apples and check that its length is one, but people who prefer functional style usually dont do it.

I understand your objection: people can write crappy code with any language an paradigm and just becuase I have seen bad applications of filter does not mean there is anything wrong with filter or FP. Of course. The bad thing is recommending people to use it like a silver bullet. The bad thing is that good FP is actually difficult and junior programmers will get it wrong trying to be fashionable.

Here is another example to show I am not inventing this rant.

Functional is preferable-Hype
Another favorite example of this functional hype is from rosettacode. Look at this amazing collection of implementations of a simple algorithm: the Luhn Algorithm. I suggest:

  1. Read the introduction so you get some idea
  2. Look at the C-implementation: imperative and simple. Testable and no side effects.
  3. Look at the functional implementations: C++11, Common Lisp, Haskell, JavaScript (ES5.1 version), PicoLisp, Python, Rust, Scheme

Look at Scala: there are two versions, a Functional Style (recommended) and an Imperative style. The people att IOCCC would be jealous with this shit!

I can only come to one conclusion: the emperor is naked.

I mean, if you code in PicoLisp, for fun or for a good reason, and you have to implement the Luhn algorith, please do so! But to say “recommended” about the functional Scala code or to think that the C++11 code is in anyway more reasonable than the original C-code… it makes no sense. No real systems programmers will choose Rust over C based on this. And Python – a language known for its clarity… such a sad example.

Trendy fashionable “functional programmers” suck
So, the problem here is not primarily with Function Programming itself or the code that guru coders write with Functional Programming. The problem is that people with far too little theoretical background, training and experience follow the hype and the result is ugly.

Functional Programming Sucks (at)
There are some things that Functional Programming is not very good at: State and Side Effects. This is by design. From a FP perspective (and a general perspective as well) State and Side Effects are nasty and problematic: they should be avoided and when they cant be avoided they need special attention (like Monads).

The problem here is that JavaScript is mostly a programming language for the web. A simple (modern, single page) web application:

  1. Loads data from a server
  2. Presents data to the user
  3. Lets the user update the data
  4. Sends the data back to the server

This is (almost) all about state and side effects! You may have some functions for validation, filtering, sorting and calculations on the client, and those benefit from Functional Programming ideas. But your core enterprise is about state, side effects and error handling! Functional Programming is so unsuitable for this that a simple web page just can’t be written functionally, unless you start breaking rules. And this is of course what programmers end up doing because in the end of the day they have a real application to build for real users.

The difficult thing is to break the right rules in the right way at the right place for the right reason. This is architecture – mixing concepts, and designing how your application lives, its breaths and heartbeats. Architecture is difficult, and it is not made easier relying on unsuitable silver bullets.

Functional Reactive Programming
There is one thing that is even more hyped and even more theoretic than Functional Programming, and that is Functional Reactive Programming.

But it makes sense (as I understand it). It is not about taking Functional Programming one step further but about putting it in context. You have data that changes (signals, events, behaviours, whatever). That data can be pipelined with high quality through FP logic to produce the content of your GUI or the requests to the server.

Keep the functional parts functional, and let other parts of your application just deal with I/O, GUI and state. Dividing your code into separate modules with clear responsibilites and clear interactions have always been a good idea.

Performance
My experience is that when a real world application is not well received by the users a lot of the time its because performance sucks. When performance is bad usability is also bad, and stability gets bad (especially on the server side).

Functional programming is typically bad for performance.

  • anonymous functions can often not be JIT compiled and will never be optimized
  • recursion is nice, but rarely faster than a loop
  • the chaining concept creates arrays and arrays and arrays just for throwing away, which is fun for the garbage collector, but it is not fast
  • the immutable object concept is about generating new RO copies of object instead of changing objects, which is expensive and wasteful

Perhaps worse, since functional programming and proper use of and map(), filter(), reduce() and friends is hard (easy things get difficult) not so experienced programmers end up writing implementations with unnecessary computational complexity ( O(n) turns into O(n^2) ). It is not funny – you cant afford that for most anything that goes to production.

Agile, refactoring and generic code
It is HARD to design code properly from the beginning! Good objects, classes, functions, modules, packages, namings, dependency trees and architecture dont come for free! Agile and Refactoring are about accepting that the design will not be optimal the first time, thus we should not bother too much about it, but rather fix the code when we have learnt more about the problem and our code starts getting (too) ugly.

A strong argument for FP is that it is highly generic – which is true. But until a programmer has spent much time with her domain and problem she will not know what things can and should be made generic. Making things too generic is called overengineering, and it is perhaps the worst sickness in our industry.

I usually:

  • start with one source file rather than many
  • allow myself some copy-paste until I see what code really gets repeated
  • make my code as specific as possible, unless I see an obvious generalisation or the actual need for generalisation emerges
  • dont worry too much about global variables in the beginning (after a while there will be a natural place for them or for what the represent)
  • allow quite long functions until I see what parts of them actually do something meaningful on its own
  • code quite defensively with lots of error handling (it usually pays of quite quickly)

This works for getting quick practical results. Later, during refactoring, when the code base has grown, and when I have learnt more about the domain, I can break out pieces of critical code that creates nice generic functions. But thinking FP first – no way!

All FP-sucks related articles
Functional Programming Sucks (this one)
Underscore.js sucks! Lodash sucks!
Functional Programming Sucks! (it is slow)
Lodash Performance Sucks!

Unique T-65 X-wing Titles

DRAFT

There is an ongoing discussion about fixes for the X-wing (in the X-wing Miniatures game). I wrote another post about possible X-wing upgrades.

I now have another idea. The game is called X-wing and the X-wing ship could be a little special. I imagine and think that many of those T-65 were built by Incom, but later during the Galactic civil war (and perhaps even later on) X-wings were built in small shops, small batches, not always with the same original components available. Over the years X-wings were worn, damaged in battles, refitted for special missions, repaired with available parts, subjected to the forces of the Galaxy and adjusted to their pilots preferences.

In the game the concept Title can refer to a ship model (BTL-A4) or a unique individual ship (Millenium Falcon). In this way, there can be many unique X-wing titles, all corresponding to a unique X-wing with its history, flaws and upgrades.

Below I have created (by the X-wing game standards) many X-wing Titles. They are all Unique and they are not to be used with the T-70 X-wing (or any other X-wing that may come). I think it is fine that the X-wing is having many titles in ways no other ships have. The X-wing was the most common starfighter on the Rebel side, yet it has very few upgrade options in the game. The ships could survive many years while I imagine the Empire scrapped TIE fighters that didn’t match specifications to ensure a consistent pilot experience.

I have no information on how the X-wings were identified. I guess they all had some kind of build number, and in the below list they have the format “X-123”. It is not a model, it is a specific ship. If you have information on how the identical ships where named/numbered feel free to let me know!

All the titles are supposed to be good for its points. The X-wing needs a little fix, and these titles should work that way. Most of them have a positive squad cost, and many have a restriction, requirement or drawback. They cannot be thrown in without thought just to make your squad better.

The purpose is to make your X-wings a little better, but perhaps more to personalize them and to make them fit your play style or your current list better. And they should be a little more challenging and interesting to fly.

Some titles have a negative cost, but not for the purpose of being able to fit 5 identical X-wings into a swarm.

Several titles have a Pilot Skill must equal to 4 requirement: they are only for the rarely used 23p Red Squadron Pilot. These Titles may seem a little better, but its because the Red Squadron Pilot (without an Elite upgrade) is in a particularly bad place (I dont think the 4PS B/Y/Z95/X-T70 generics see much play either). These PS4 only upgrades often reflect some more experimental technology that requires much training to use, thus those titles are only available to specially trained (generic) pilots (not to famous named pilots).

X-Wing ID Restriction Cost Description
X-113 1 When attacking with Primary Weapon you may roll 1 extra red die. You cannot attack next round.
X-116 1 When attacking with Primary Weapon you may roll 1 extra red die. If you do so, in Deal Damage Step, ignore all Crits.
X-122 1 When attacking with Primary Weapon, if defender cancelled any Crits with Shield tokens, deal one stress token to defender.
X-17K -1 You can not equip an Astromech. This X-wing has 3 shields.
X-08X PS=4+ 1 This X-wing has a hull value of 2. Once per round when defending you may roll one extra green die.
X-14D Targeting Astromech 1 When you Spend a Target Lock you may keep it (instead of discarding it).
X-14K Targeting Astromech 1 You may acquire Target Lock on any ship in play regardless of range.
X-16F R2 Astromech 1 When executing a 4-K-turn, you may treat it as a speed 3, 4 or 5 K-turn.
X-19A R2 Astromech 1 When executing a 1-bank, you may treat it as a 1-turn the same direction.
X-222 R5 Astromech 0 At the End Phase, you may discard your Astromech to recover 1 shield.
X-291 1 Your action bar gains the Boost action icon. You cannot equip an Astromech.
X-2B7 0 Your action bar gains the Barrel roll icon. You can not equip an Astromech.
X-30P 2 When you equip this card, place 1 ordnance token on a Torpedo Upgrade card. When you are instructed to discard an Upgrade card, you may discard 1 ordnance token on that card instead.
X-370 PS=4+ 1 You must use a T-70 X-Wing maneuver dial
X-379 PS=4+ 1 You must use an A-wing maneuver dial. Your X-wing has 2 hull.
X-414 PS=4 0 Your action bar gains the Cloak Action
X-416 PS=4 1 Your action bar gains the Cloak Action. You may equip one Elite upgrade card.
X-441 PS=4 0 If your maneuver causes you to overlap X-442 and you are touching X-442 you may perform your action as if you did not overlap. You may equip one Elite upgrade card.
X-442 PS=4 0 If your maneuver causes you to overlap X-441 and you are touching X-441 you may perform your action as if you did not overlap. You may equip one Elite upgrade card.
X-460 PS=4 1 You may equip two missile upgrade cards. Get the cheapest one for free. You cannot equip a Torpedo. You may equip one Elite upgrade card.
X-465 PS=4 0 Your pilot skill is 5. You must equip one Elite upgrade card.
X-466 PS=4 1 Your pilot skill is 6. You must equip two different Elite upgrade cards.
X-484 PS=4 0 You may equip one Crew and one Elite upgrade card.
X-491 PS=4 1 Dual Card. You may equip on Elite upgrade card. You may flip this card during the end phase.
A) Your PS=0
B) Your PS=12
X-4X0 PS=4 0 You may equip one Illicit upgrade card and one Elite upgrade card.
X-502 PS=4+ 1 If your maneuver cases you to overlap a ship or an obstacle you may choose to instead execute another slower manuever with the same bearing (including 1-turn).
X-5LX 1 When you attack, the defender does not benefit from obstacles.

Upgrades for T-65 X-wing

In the X-wing game the original X-wing (T-65) is by many considered underpowered. The exception is Biggs Darklighter and to some extent Tarn Mison (with R7 Astromech) who are useful thanks to their Pilot ability. But the rebel aces (thematically) Luke Skywalker and Wedge Antilles are not worth their points.

It is interesting to compare the orginal X-wing (T-65) with the new T-70 X-wing. For 3 extra points you get:

  1. Shield upgrade (4p)
  2. Engine upgrade (4p)
  3. Better maneuver dial with Tallon Roll
  4. A tech upgrade (which can take Primed Thrusters for just 1p)

It is rare to spend 4p on a Shield upgrade, but it is very clear that a T-70 for 24p is much more value than a T-65 for 21p.

In practice the lowest cost for an X-wing is 22p (25p for a T-70) because it always makes sense to add Integrated Astromech and any (1p) Astromech. The thing with Integrated Astromech was that it improved the T-65, but it improved the T-70 as well, so it didn’t make the T-65 more viable.

At 25p it is possible to make a “swarm” of 4. For the T-65 you can still just include 4, possibly in a XXXXZ-squad (but then BBBBZ is usually more effective).

If you read X-wing forums you find that there is “demand” for a “fix” for the X-wing. Such a fix may never come, but arguments are:

  • The game is called X-wing: the title ship should not suck
  • Luke and Wedge should be good pilots (Darth Vader got a powerful fix)

Some complicating factors are:

  • Biggs (and Tarn) are already good, and could be too powerful with a fix
  • Any fix that also makes the T-70 more powerful may cause more problems that it solves
  • The maneuver dial can’t trivially be changed to be on par with the T-70 (so just a title or modification is not quite enough)
  • Integrated Astromech occupies the modification “slot” so a new modification (as well as otherwise potentially useful Guidance Chips or Vectored Thrusters) wont do
  • Since the two ship types are called “X-wing” and “T-70 X-wing” it requires some ugliness to address only the old T-65
  • From the very beginning, Wave 1, the X-wing was under powered compare to the Tie Fighter

So, we are looking for an Astromech, a Title or possibly a Torpedo, that wont be unbalanced with Y-wing, ARC-170, E-wing, T-70 or Biggs. It should make both the generic and named pilots viable. It would also be fun with something that promotes a swarm/squad of (just) X-wings.

The generics
For the generics I would like a fix that allows a swarm with 5 of them. That would ideally be a negative cost Title or Astromech, or possibly a Torpedo just like Chardaan Refit. This would increase the difference between T-65 and T-70, positioning the T-65 between the Z95 and the T-70. Thematically this could be “refurbished”, “old”, “ill maintained”, “original”, “refit” or something else.

The named pilots
The named pilots suffer more from lack of repositioning (Boost or Barrel Roll). They are hardly helped by Push the Limit since they have few actions. Engine Upgrade or Vectored Thrusters are modfications and compete with Integrated Astromech. Luke Skywalker could need Veterans Instincts so then not even the Elite slot is available.

What should it be (good at)
There are two ideas about what the X-wing is (good at). The first is that it should be Jack of all Trades. The other is that it should be a jouster (because it is all it can do).

Jousting is about two (groups of) ships approching each other, firing and evading. As they pass each other they both U-turn and keep shooting. This continues until one (side) is dead. It is possible to make mathematical models or simultions (and people have) to decide jousting efficiency. It turns out Z-95 headhunter is best value, the B-wing sligtly less, and the X-wing falls behind.

As the B-wing has more other options (barrel roll, cannon, two torpedoes) it leaves the X-wing in a very bad place.

Fixes to the X-wing tend to fall in different categories:

  1. Lowering the cost to make it a better Jouster
  2. Making it more like the T-70 (boost)
  3. Adding defensive capabilities: evade or cloak
  4. Give it some other (unique) capability

While there are creative suggestions to improve the X-wing I hesitate about something that would be a more or less mandatory and exotic upgrade. I mean, if ALL X-wings played suddenly have Cloak, and they are played much, that changes the entire game. If X-wings more often than not would carry Proton Torpedoes that would not change the game much.

Upgrades I would like to see
Disclaimer: Star Wars lore is not my speciality.

** T-65 Standard Torpedo: 1p Torpedo. X-wing (Rebel Alliance) only. As Proton Torpedo.
At 1p it is not an autoinclude (like Chardaan Refit). It also requires a choice between offensive Guidance Chips and defensive Integrated Astromech. Finally, it does not help Biggs, but it does help generics as well as named pilots.

** T-65 Standard R2: -1p Astromech. X-wing (Rebel Alliance) only.
This would allow swarm of 5 T-65 X-wings.

** S-Foils: 0p, Title, Dual Card. X-wing (Rebel Alliance) only.
Side A: Cruise Position): When executing a maneuver you may treat it as +1-speed maneuver with the same bearing. Immediately after rolling attack dice, change one (if any) Crit to a Hit.
Side B: Attack Position): Immediately after rolling attack dice, if you rolled no Crits you may change one Hit to a Crit. 3 turns and 4 straight are red maneuvers.
You may flip this card before revealing your maneuver dial.
This would make the X-wing a little bit more interesting and challenging to fly. It would slightly compensate for lack of boost and repositioning capability, but at a cost. It would give it a slight edge compared to B/Y/Z95.

I like that S-foils always are both good and bad. I don’t want the cruise mode to essentially give it a boost and I don’t want the attack mode to be significantly more powerful than B-wing or T-70. Also, I want the change in attack efficiency to be effective regardless of range, focus and target lock.

** Overdrive: Torpedo, Dual Card. X-wing only.
Side A: Overdrive Compressor): 4p
Side B: Overdrive Pack): 1p (discard after use)
Both sides: Action: Perform a free Boost Action. Then receive one Focus token and one Stress token.

I would much like to see this for the Z95 Headhunter as well (as a Modification or Missile).

I have made the above cards available as a printable PDF File.

References
Below is a collection of links to fix suggestions elsewhere.

** T-65 X-wing starfighter: Add one shield, -3p, title (I presume)
My guess is that this is way too powerful.

** T-68 Prototype: If your pilot skill is 6 or higher and you are not stressed when you reveal a white 3 turn, you may perform a 3 tallon roll in the same direction, 2 or 3 points.
To me, this just makes it a worse T-70 and it does not help the generics.

** StealthX: Your action bar gains the [cloak] action icon. ? points
This would widen the use of the X-wing and it is a nice idea. It would be very good with Biggs though, completely unbalanced.

** Rogue One: When you perform a focus action any friendly x wing at range 1-2 may perform a free target lock action. Add EPT if you don’t have one. Unique 3p title, PS6 or better
I doubt anyone would pay 3p for it, otherwise it is a good idea.

** Rogue Squadron: Reduce cost of Astromechs and Torpedoes by 1p (min 0), Title 0p
Well, if it was 2 points it would be possible to fly 5 of them.

** Two unnamed titles: (Rebel Alliance / T-65 only)
1) When attacking, you may spend a target lock you have on an enemy ship at range 1 to perform an attack against that ship even if it is outside your firing arc.
2) At the start of the combat phase, if you have a target lock on an enemy ship, you may assign it one stress token.
While useful, I think it is weird to add a new capability to T-65 that T-70 cant have. The first one is thematically odd, and the second one would be very powerful, esp if not unique.

** XJ-5 Title: Add boost to the upgrade bar, add Tech slot, lose Astromech slot. Treat 3 forward and 2 banks as greens.
Since Integrated Astromech exist I think the loss of Astromech is too bad. I am also sceptical about adding the Tech slot. Green maneuvers are not that useful since it only has one red maneuver. Otherwise, adding maneuverability and removing something else makes sense.

** Engine Refit: Add the (Boost) and (Evade) actions to your action bar. Torpedo 2p.
The author intended it to be available also to the T-70 (which would add only Evade). The Rebels/Resistance are not having too many ships with evade actions so I could welcome that. However if all X-wings always add an Evade Action that could change quite much. Also this would be very good with Biggs.

** T-65b: Player may choose to take the (Boost) action. If this is done, subtract (X) from your attack skill for this turn. Title (I suppose)
This could work. It could also be an Astormech. (Should not be T-65b though, se below)

** Refurbished Astromech: -2 points. Your upgrade bar loses all upgrade icons besides [Astromech slot].
This would reduce the generic cost to 19 which is quite fine.

** Corran Horn and giving it Boost+Shield.
The first option does not help any current pilots, and the second option is still just worse than the T-70, but now for the same price.

** Free Proton Torpedo
Not such a bad idea?

** No name title: Title that when a R2 is equipped all 1,2 & 3 maneuvers are green.

** S-Foil: Take a weapons disabled token and evade token to make all moves white. Modification or Title.
Maybe a good idea!

** Some title: Enemy ships in arc at range 2-3 cannot perform boost or barrel roll actions.
I think a title that will be added to several ships, almost as a default/fix should do something with the ship itself, not with plenty of other ships at the board.

** Astromech: If an enemy ship within 1-2 and inside your arc performs a barrel roll or boost action you may perform a free barrel roll action.
Well, that is interesting. Perhaps better as a title.

** Lightened Payload: Torpedo, -1p.
This would obviously be useful.

** T-65C-A4: Your range 1 combat bonus extends to range 1-2, but at range 3 you roll one less red die. You may treat the 3 bank as a red segnors loop of the same direction. Title 1p

** T-65D: Replace your astromech slot with a system slot, title 1p.
Very expensive since Integrated Astromech is lost.

** S-Foils: Dual Card:
S-foils in cruise position: reduce your Primary attack value to 2. During the end step, you must perform a free boost action.
S-foils in attack position: When you declare an attack on a target you have locked, you may turn an eye into a hit.

Not sure how it would exactly work, but I can see it being useful and interesting.

** A -1p Astromech that does nothing

** Give it 4 attack dice

**** A fine post with several suggestions. ****

T-65B Model: Lore wise this was the sturdiest X-Wing. Due to its heavy armor, and early design, it was still slower than the Tie Fighters. It was very easy to learn and fly. T-65B Title Card increases Hull Value, and Shield Value by 1. Decreases cost by 1. Your 4 Straight becomes a red maneuver.

T-65D-A1 Model: This was an attempt to remove the Astromech from the X-Wing. They were trying to use computer in place of the Astromech to help the pilot. T-65D-A1 Title Card removes the Astromech Slot. Grants 1 Focus when in range 1 of an enemy ship.

T-65AC4 Model: This was perhaps the last T-65 Model. It was the superior model as it had increased engine power, increased Torpedo capacity, and armor. T-65AC4 Model Title Card decreases Torpedo or Missile Cost by 2. Grants the Boost Icon.

T-65 Missile Conversion Card: There is reference in the books and in the internet that T-65’s used Torpedoes as their standard mission load out. They could be equipped with Missiles, if a mechanic spent enough time to do so. T-65 Missile Conversion Modification changes the Torpedo slot to Missiles. If using the T-65AC4 Title Card, this card costs 0

X-Wing Stutter Fire Card (X-Wing, and T-70 X Wing): Discard this card, to lower the Agility Value of your Target by 2 (no damage)

X-Wing Quad Fire Card (X-Wing, and T-70 X Wing): Discard this card to increase your attack value by 1 for this turn

Elite Pilot Talent called “Red Squadron” (X-Wing and T-70 X-Wing). If you have a Target Lock on your enemy, your other Ships may treat that Target Lock as their own (IE One Target Lock for all of your ships)

Those are all interesting ideas.

3 Astromechs that I came up with myself a little while ago. I dont like them much anymore.

10x Horton Salm

I will post ten different squads with Horton Salm. Work in progress.

Links Other Squads , X-Wing Wiki , My Pilot Browser

** Horton, Tycho and Jake ** (100)
1x Y-Wing Horton Salm (25), Twin Laser Turret (6), R5 Astromech (1), Shield Upgrade (4)
1x A-wing Tycho Celchu (26), A-wing test pilot (0),
 1x Push the Limit (3), Proton Rockets (3), Guidance Chip (0), Veteran Instincts (1)
1x A-wing Jake Farrel (24), A-wing test pilot (0),
 1x Push the Limit (3), Proton Rockets (3), Guidance Chip (0), Veteran Instincts (1)

My opponent, flying four different TIE fighters, did everything to kill Horton Salm right away and he went down the second round of combat firing only the round before. But that gave the A-wings a smooth start and I won in the end. R2-D2 could have been a better option than Shield Upgrade, but in my case I would hardly have been able to use it. R2-D6 + Veteran Instincts would be another option. You could also replace the A-wing Veteran instincts with Outmaneuver or Predator, and use less points on Horton Salm (I think that would generally be better, but the A-wings much benefit from highest skill). The Proton Rockets effectively cost 5p (since you use them instead of Chardaan refit), but they turned out to be very good on Jake and Tycho. The A-wings usually last a few rounds, frequently gets within range 1, and with Push The Limit you can easily roll 5 dice, reroll with target lock and then apply Guidance Chip + Focus.

** 3 old veterans ** (99)
1x Y-Wing Horton Salm (25), Twin Laser Turret (6), BTL-A4 (0)
1x X-Wing Wedge Antilles (29), BB-8 (2), Stay on Target (2), Integrated Astromech (0)
1x ARC-170 Norra Wexley (29), Weapons Engineer (3), Push the Limit (3)

These are three pilots with stronger than normal 3 dice attack capabilites. With high skills you can deal damage fast and all ships can sustain significant damage. Wedge with Stay on target, BB-8 and skill 9 typically has quite a few options if he makes a green straight 2 maneuver. Norra can use the two target locks defensively. There are of course options. An R2 droid on Horton can be useful… if he survives to use it. There are plenty of elite skills that can be useful for Wedge (you are never going wrong with Predator). It is also possible to replace the ARC-170 with a low skill B-wing and Heavy Laser Cannon, and equip Horton with R2-D6 and Swarm Tactics.

** BBB-Horton ** (99)
1x Y-Wing Horton Salm (25), Twin Laser Turret (6), BTL-A4 (0), R3 Astromech (2)
3x B-Wing Blue Squadron Pilot (22)

A squad design to make your opponent at least consider not targetting Horton first. Anyway, the R3 Astromech is a decent combo with Hortons special ability and BTL-A4.

** The Force is with Horton ** (99)
1x Y-Wing Horton Salm (25), Twin Laser Turret (6)
1x X-Wing Luke Skywalker (28), R7-T1 (3), Opportunist (4), Integrated Astromech (0)
1x X-Wing Wes Janson (29), Targeting Astromech (2), Stay on Target (2), Integrated Astromech (0)

I wanted to make something useful with old Rebel Alliance X-wings and came up with this squad. Horton usually attracts enough hatred anyway, so he gets no upgrade besides the turret. Both Luke and Wes have some repositioning ability with R7-T1 and Stay on Target to make them competetive against more modern ships. Stay on Target works nicely with Targeting Astromech. What turned out to be surprisingly useful was Opportunist – actually quite worth its 4 points. Wes Janson attacks first and even if he would not produce much damage he should leave the enemy quite vulnerable to Horton and Luke. I would probably replace R7-T1 with BB-8 (which is good with Opportunist) if I use this list again.

** Veteran Alpha Strike ** (99)
1x Y-wing Horton Salm (25)
 Proton Torpedoes (4), Extra Munitions (2), Guidance Chip (0), R2 Astromech (1)
1x X-wing Wes Janson (29)
 Veteran Instinct (1), BB-8 (2), Integrated Astromech (0)
1x X-wing Wedge Antilles (29)
 Proton Torpedoes (4), Guidance Chip (0), Crack Shot (1), R2 Stromech (1)

Wes Janson fires first and should strip your target of defensive tokens. Then Wedge and Horton unleashes Proton Torpedoes. It is quite possible you can take out a hi profile enemy ship before it has shot a single shot this way and you should have an upper hand after the first round of fire.

** Horton, Wedge and Nera ** (100)
1x Y-Wing Horton Salm (25), Twin Laser Turret (6)
1x X-Wing Wedge Antilles (29),
 BB-8 (2), Guidance Chip (0), Proton Torpedoes (4), Trick Shot (0)
1x B-Wing Nera Dantels (26)
 Proton Torpedoes (4), Extra Munitions (2), Guidance Chip (0), Fire Control System (2)

The only way to make Horton survive is the make the rest of the list more intimidating. Nera usually saves the torpedoes for occations when the primary weapon can not be used. Wedge is very dangerous with Proton Torpedoes and Guidance chip.

** Horton and Chewbacca **
1x Y-Wing Horton Salm (25), Twin Laser Turret (6)
1x Y-wing Gold Squadron Pilot (18), Ion Cannon Turret (5)
1x YT-1300 Chewbacca (42) (HOR), Push The Limit (3), Millenium Falcon (1) (original)

This is in a way a variant of the classical YYYY-squad (with TLTs). When the Y-wings die early they at least dont die in vain since Chewbacca gets another shot.

Wookie Commandoes is an alternative to Push The Limit, giving you two points. I tried it and upgraded to a second Twin Laser Turret and gave Chewbacca Crack Shot.

** Horton & Horn ** (98)
1x Y-Wing Horton Salm (25), Twin Laser Turret (6)
1x E-Wing Corran Horn (35), Advanced Sensors (3), Push the Limit (3), R2-D2 (4)
1x B-Wing Blue Squadron Pilot (22), Collision Detector (0)

First, understand how to use Advanced Sensors (the idea is not to stress yourself with Push the Limit and start every round stressed). Corran Horn is supposed to (I have read) be best in the end game so the B-wing is there to carry a big “shoot at me” label.

…2 to go…

X-wing squads

Links: Horton Salm Squads , X-Wing Wiki , My Pilot Browser

I will post (rebel/resistance) X-wing squads I have played here.

** Big Nien Numb Squad ** (100)
1x T70 X-Wing Nien Numb (29), Push the Limit (3), R3-A2 (2)
2x A-Wing Prototype Pilot (17), Chardaan Refit (-2)
3x Z-95 Bandit Squadron Pilot (12)

This worked very well. Nien Numb is good at handling out stress. I tried to replace Nien Numb with Wedge Antilles but was less lucky. The idea is to have a large squad with some edge. For 34p there are many options to replace Nien Numb.

** Angry Chewbacca ** (100)
1x YT-1300 Chewbacca (42), Recon Specialist (3), Jan Ors (2), Millenium Falcon (1), Push the Limit (3)
2x B-Wing Blue Squadron Pilot (22), Fire Control System (2)

This is the new (Hereos of the Resistance) Chewbacca, but the old Millenium Falcon. The idea is that Chewbacca can make green maneuvers, Push the Limit and get 2xFocus + 1xEvade, or 1xFocus + 2xEvade every round. When the B-wings die Chewbacca gets a bonus shot. First time I used this squad I had 4xZ95 instead of B-wings, but they were not enough of a threat to keep the fire away from Chewbacca (and you do want Millenium Falcon left in the end).

** Very Aggressive B-wings ** (99)
1x B-wing Keyan Farlander (29), Fire Control System (2), Expose (4), Experimental Interface (3)
1x B-wing Nera Dantels (26)
 Fire Control System (2), Proton Torpedo (4), Extra Munitions (2), Guidance Chip (0), Trick Shot (0)
1x X-wing Biggs Darklighter (25), Integrated Astromech (0), R3 Astromech (2)

Keyan Farlander can use Experimental Interface to be stressed and Exposed, and then use his stress as a focus. Thanks to Biggs, enemy can’t fire at Keyan. Nera is a royal pain (save your torpedoes until you have nobody in your primary firing arc). Admittedly I flew this squad with the R4-D6 astromech, which sucked, because it does not cancel criticals, and did not help Biggs at all.

** Wedge and his crack team ** (100)
1x X-wing Wedge Antilles (29), Integrated Astromech (0), BB-8 (2), Adaptability (0)
1x A-wing Tycho Celchu (26), Chardaan Refit (-2), A-Wing Test Pilot (0), Push the Limit (3), Wired (1)
1x A-wing Jake Farrell (24), Chardaan Refit (-2), A-Wing Test Pilot (0), Adaptability (0), Trick Shot (0)
1x Z95 Airen Cracken (19)

I got this squad from my oppenent who wanted me to fly a good Wedge squad. The core idea is that 4 ships with 8 skill is very powerful in itself. And Airen helping Wedge to get two actions make Wedge a very hard hitter. While I like the idea, Wedge is not that good for the price and I would have wanted Push the Limit on Jake also.

** An odd squad ** (97+)
1x ARC-170 Braylen Stramm (25), Alliance Overhaul (0), Tactician (2), R3-A2 (2)
1x T70 X-Wing Jess Pava (25), Integrated Astromech (0), R2 Astromech (1), Pattern Analyzer (2)
2x A-wing Green Squadron (19)
 Chardaan Refit (-2), A-Wing Test Pilot (0), Push the Limit (3), Trick Shot (0)

Four competent ships, all with the same skill (3) allowing them to move and shoot in any order. Jess leads the way, the others staying within range 1, maximizing his special ability. At 97 points, there is room to replace Jess’s R2 and/or Trick Shot with something else. Braylen can deliver 1-2 stress which is a powerful and flexible weapon.

** Another Odd Squad ** (100)
1x ARC-170 Braylen Stramm (25), Alliance Overhaul (0), Tactician (2), R3-A2 (2)
1x X-wing T70 Jess Pava (25), Integrated Astromech (0), Targeting Astromech (2), Pattern Analyzer (2)
1x X-wing Tarn Mison (23), Integrated Astromech (0), R7 Astromech (2)
1x Tie Fighter Zeb Orrelios (13), Sabine’s Masterpiece (1), Hot Shot Blaster (3)

Another squad of four ships with skill 3. Tarn Mison with R7 is not bad and Jess Pava needs wingmen.

** Acrobatic X-wings ** (100)
1x T70 X-wing Ello Asty (30)
 Integrated Astromech (0), R2 Astromech (1), Push the Limit (3), Primed Thrusters (1)
1x T70 X-wing Snap Wexley (28), Integrated Astromech (0), Targeting Astromech (2),
 Pattern Analyzer (2), Proton Torpedoes (4), Adaptability (0)
1x T70 X-wing Blue Ace (27), Integrated Astromech (0), BB-8 (2)

These three X-wings are all capable of moving in very acrobatic ways, and still come out with focus and/or target lock.

** Alpha Strike ** (100)
1x A-wing Tycho Celchu (26), A-wing test pilot (0),
 Concussion Missiles (4), Push the Limit (3), Swarm Tactics (2), Guidance Chip (0)
1x Z-95 Airen Cracken (19), Concussion Missiles (4), Push The Limit (3), Guidance Chip (0)
1x Z-95 Lieutenant Blount (17), Assault Missiles (5), Guidance Chip (0), Veteran Instincts (2)
1x Z-95 Bandit Squadron Pilot (12), Concussion Missiles (4), Guidance Chip (0)

Tycho, Airen and Bandit should all shot with Target Lock+Focus at skill 8. Blount has no focus, but he cant miss. I lost with this squad but it was a funny game. In hindsight I would have been better off with Ion Pulse Missiles on Lieutenant Blount.

** Big Bad Boys ** (100)
1x YT-1300 Chewbacca (42), Millenium Falcon (1), Jan Ors (2), Kyle Katarn (3), Push the Limit (3)
1x YT-2400 Leebo (34), Outrider (5), Heavy Laser Cannon (7), Recon Specialist (3), Trick Shot (0)

This is the old Chewbacca and the old Millenium Falcon. You can typically get focus+evade on both ships every round. Chewbacca can even get 2 evade plus focus or target lock. My idea is to fly defensively, constantly making green maneuvers with Chewbacca, and you will make damage anyway. Your problem can be that your enemy will do everything to kill Leebo first and stay close enough to him to avoid his laser. It could be better to replace Heavy Laser Cannon with Mangler Cannon and add Stealth Device or a 3p Elite.

** X-wing swarm ** (100)
1x T70 X-wing Jess Pava (25), Targeting Astromech (2), Primed Thrusters (1)
1x T70 X-wing Blue Squadron Novice (24), R2 Astromech (1)
1x X-wing Tarn Mison (23), R7 Astromech (2)
1x X-wing Rookie Pilot (21), R2 Astromech (1)
 + Integrated Astromech (0) on all

You just can’t squeeze 5 X-wings into a 100p squad. 4 X-wings can be done, but the options are quite limited. This squads takes full advantage of Jess’s pilot ability. Tarn Mison with R7 is surprisingly good. You may prefer Pattern Analyzer (and a 1p Astromech) on Jess. The Rookie Pilot can use another Astromech as well (R5 comes to mind). It is not the easiest swarm to fly as you have two different skills and two different (although similar) maneuver dials: all 4 pilots different.

** The A-wing Aces Squad ** (99)
1x A-wing Tycho Celchu (26), Trick Shot (0)
1x A-wing Jake Farrell (24), Adaptability (0)
1x A-wing Arvel Crynyd (23)
1x A-wing Gemmer Sojan (22)
 + Chardaan Refit (-2), A-Wing Test Pilot (0), Push the Limit (3) on all

You can argue about a lot of things but this is the definite A-wing Aces Squad. You can of course put Veteran Instincts on Jake and Adaptability on Tycho for 100 points.

** AAAA-Etahn ** (99)
1x E-wing Etahn A’baht (32), R2-D2 (4), Push The Limit (3), Collision Detector (0)
4x A-wing Prototype Pilot (17), Chardaan Refit (-2)

After the BBB-Etahn below I thought I would make a better Etahn supporting a little A-wing swarm. Big mistake. Etahn is not worth the upgrades and pushing/stressing him is not pretty. This squad requires more than minor fixes to be good.

** BBB-Etahn ** (98)
1x E-wing Etahn A’baht (32)
3x B-wing Blue Squadron Pilot (22)

The idea here is simply to make good use of Etahns’ special ability. Also, with Barrel Roll, Etahn is quite capable of staying in formation with (or just behind) the slow B-wings. Possible upgrades for Etahn: Swarm Tactics, Elusiveness, Veteran Instincts, Wingman, Calculation, Crack Shot, Juke, Snap Shot, Trick Shot) R2-D6 (allows Trick Shot + 1p Elite), Collision Detector (free). When I played this squad I used Fire Control System but that is not good: Etahn fires first, gets Target Lock, then 3 B-wings fire and typically they want to fire at the same enemy until destroyed – Target Lock wasted. For the same reason I would not equip R3-A2.

** XXX-Etahn ** (100)
1x E-wing Etahn A’baht (32), R2 Astromech (1), Collision Detector (1), Crack Shot (1)
3x X-wing Rookie Pilot (21), R2 Astromech (1), Integrated Astromech (0)

This is simple and old fashined, but quite balanced. The R2 Astromechs make it easy to fly the E-wing together with the X-wing (and the price of occational K-turns is not so bad). Etahns’ special ability comes to good use. Four ships with 3 attack dice is always a threat.

** Basic T70s ** (100)
3x T70 X-wing Blue Squadron Pilot (24)
 Integrated Astromech (0), Targeting Astromech (2), Primed Thrusters (1)
1x Z95 Airen Cracken (19), Trick Shot (0)
 or
1x A-wing Green Squadron (19)
 Chardaan Refit (-2), A-Wing Test Pilot (0), Adaptability (0), Intimidation (2)

The A-wing could use Elusiveness, Expert Handling or Juke instead depending on your preference. Adaptability gives it the same skill as the X-wings for easy maneuvering. The squad does not require much presentation. However, compared to the naked 24p Blue Squadron Pilot, the 3-card-3-p upgrades makes a lot of difference.

** K-wing support ** (100)
1x K-wing Warden Squadron Pilot (23), Sabine Wren (2), Advanced SLAM (2)
 Ion Bombs (2), Conner Net (4), Extra Munitions (2)
1x E-wing Etahn A’bath (32), Fire Control System (2), R2 Astromech (1), Push The Limit (3)
1x X-wing Garven Dreis (26), R2 Astromech (1), Integrated Astromech (0)

This one lost big time. I need more practice with the K-wing wanted to try out pilots I never used before.

** 6-6-6 ** (100)
1x ARC-170 Shara Bay (28), Weapons Engineer (3), Alliance Overhaul (0), Trick Shot (0)
1x B-wing Ibtisam (28), Advanced Sensors (3), Cool Hand (1)
1x K-wing Esege Tuketu (28), Twin Laser Turret (6), Recon Specialist (3)

Another squad that lost. The 6-6-6 PS is a gamble and turned out a bit unlucky twice. The idea here is very simply to have 3 aggressive ships that can take a lot of damage, and share Focus and Target Locks. Ibtisam with Advanced Sensors is quite unpredictable and Twin Laser Turret is usually good. Perhaps I need more practice with the K-wing or with this squad, or perhaps everything is a little too expensive and none of the ships reach their full potential.

** Mixed swarm ** (100)
1x Tie Fighter Sabine Wren (15), Crack Shot (1)
4x A-wing Prototype Pilot (17), Chardaan Refit (-2)
2x Z-95 Bandit Squadron Pilot (12)

If you want a swarm of 6-7 ships you don’t have so many options. Also, you may not own 8 Headhunters or 6 A-wings. I think the extra cost for the A-wings are worth it, but if you want to make it to 7 ships you need to add Headhunters. I was not happy with Sabines performance; she ended up first blocking and then being blocked by my own ships all the time. Fly the A-wings (same dial and skill) in one swarm and the Headhunters in their own little swarm. If you use Sabine, have a plan so she stays behind the others. If you have another A-wing you can use it instead of Sabine. If you have another Z95 you get 4p for upgrades: vectored thrusters for 2 Headhunters come to mind but there are other options (a missile, a shield upgrade, 2x autothrusters).

** Poe Power X-wings ** (98)
1x T70 X-wing Poe Dameron (33),
 Autothrusters (2), Push the Limit (3), R5-P9 (3), Black One (1), Pattern Analyzer (2)
1x X-wing Garven Dreis (26), M9-G8 (3), Integrated Astromech (0)
1x X-wing Tarn Mison (23), R7 Astromech (2), Integrated Astromech (0)

I have seen that many people fly very powerful Poe (or Corran Horn) and my thought has always been that its a very sensitive squad with so many points on one pilot. In this squad Poe is 44 points so you can basically replace him with two X-wings or two B-wings. I have to admit that Poe did not disappoint. With Push the Limit Poe can almost always Focus, and with Poes special ability he can often keep that Focus and exchange it for a shield in the end of the turn. With Boost (and a green 3 straight maneuver) you can often stay quite far away from your enemy and with Autothrusters you are hard to hit at range 3. However, at least I can’t Push the Limit and fly green maneuvers all the time, and I did find use for Pattern Analyzer (which I typically don’t see in such Poe configurations). It does make sense to include Autothrusters (rather than Integrated Astromech) as they help to protect Poe when he needs to regenerate shields. Tarn Mison with R7 is very good on his own. Garven Dreis is there to give Poe extra focus if/when he needs it, and Garven is arguably the weakest link in this squad.

** Suicide Squad ** (100)
1x ARC-170 Braylen Stramm (25), Alliance Overhaul (0), Tactician (2), R3-A2 (2)
1x X-wing Tarn Mison (23), Integrated Astromech (0), R7 Astromech (2)
2x X-wing Rookie Pilot (21), Integrated Astromech (0), Targeting Astromech (2)

My idea was to have 4 rather similar ships with 3 attack dice and to have firepower and hull on my side. It was a royal catastrophy. The X-wing does need a fix. I commanded the squad badly. And Braylen Stramm is too much of an obvious target and too easy to take out.

** Regenerator Aces ** (100)
1x E-wing Corran Horn (35), Push the Limit (3), Advanced Sensors (3), R2-D2 (4)
1x T70 X-wing Poe Dameron (31), Pattern Analyzer (2), R5-P9 (3), Autothrusters (2), Lone Wolf (2)
1x A-wing Prototype Pilot (17), Chardaan Refit (-2)

There are numerous Dameron/Horn lists to be found online, mine is probably not the best one. Most importantly, understand how to use Advanced Sensors (the idea is not to stress yourself with Push the Limit and start every round stressed). The idea with Lone Wolf is that it will make Poe very nasty in the end game. There may be better options.

** Sluggers ** (100)
1x B-wing Nera Dantels (26),
 Plasma Torpedoes (3), Extra Munitions (2), Trick Shot (0), Fire-Control System (2)
1x YT-2400 Wild Space Fringer (30), Mercenary Copilot (2), Outrider (5), Heavy Laser Cannon (7)
1x Y-wing Gold Squadron Pilot (18), Ion Cannon Turret (5)

My usual problems with the YT-2400, Outrider and HCL is that it really draws all fire to it, and the donut. The idea here is to mitigate those problems by making the YT-2400 a little bit less threatening and having something to put in the donut. The Y-wing should fly in the donut, preferably between the YT-2400 and your enemy. Nera can be in the background, but can take different roles and responsibilities depending on your enemy. It is possible to replace Extra Munitions with Flechette Torpedoes.

** Four Cannons ** (100)
2x B-wing Blue Squadron Pilot (22), Collision Detector (0), Ion Cannon (3)
1x B-wing Blue Squadron Pilot (22), Collision Detector (0), Flechette Cannon (2)
1x B-wing Blue Squadron Pilot (22), Collision Detector (0), Mangler Cannon (4)

Four B-wings with Cannons that can deliver Ions, Stress and Crits. Your opponent needs to deal 32 damage. That will be an uphill battle. The weakness of 4 lo-skill-pilots is somewhat compensated for by the ability to deliver Ions and Stress.

** Ten Numb with support ** (100)
1x B-wing Ten Numb (31), Fire Control System (2), Veteran Instinct
3x B-wing Blue Squadron Pilot (22), Collision Detector (0)

Four B-wings, including one ace to deal with other aces.

Sort strings without case sensitivity

In JavaScript, I wanted to sort arrays of strings without caring about case. It was more complicated than I first thought.

The background is that I present lists like this in a GUI:

  • AMD
  • Apple
  • Gigabyte
  • IBM
  • Intel
  • Microsoft
  • MSI
  • Nokia
  • Samsung
  • Sony

I want AMD and MSI (spelled in all caps) to be sorted without respect to case. Standard sort() would put MSI before Microsoft.

Obviously I am not the first one wanting to do this and I found an article on stackoverflow. It suggests the following solution:

Use toLowerCase()
You can make your own string compare function that uses toLowerCase and send it as an argument to sort():

function cmpCaseless(a,b) {
    a = a.toLowerCase();
    b = b.toLowerCase();
    if ( a < b ) return -1;
    if ( a > b ) return  1;
    return 0;
}

myStringArray.sort(cmpCaseless);

This has a number of problems. The article above mentions that it is not stable. That is probably true in some cases but I was of course worried about performance: making two String objects for each compare should make the garbage collector quite busy, not to mention the waste of copying and lowercasing potentially quite long stings when usually the first character is enought. When I started experimenting I found another more critical flaw though: in Swedish we have three extra characters in the alphabet; Å,Ä,Ö, in that order. The above cmpCaseless orders Ä,Å,Ö, which sounds like a little problem, but it is simply unacceptable.

Use localeCompare
There is a more competent (or so I thought, read on) way to compare strings in JavaScript: the localeCompare function. This one simply treats A,Å,Ä and O,Ö as the same character, which is far more unacceptable than the toLowerCase problem.

However, it also has a “locales” option (a second optional argument). If I set it to ‘sv’ I get the sort order that I want, but performance is horrible. And I still have to use toLowerCase as well as localeCompare:

function localeCompare(a,b) {
    return a.toLowerCase().localeCompare(b.toLowerCase());
}

function localeCompare_sv(a,b) {
    return a.toLowerCase().localeCompare(b.toLowerCase(), 'sv');
}

localeCompare() has an extra options argument with a “sensitivity” parameter, but it is no good for our purpuses.

Rolling my own
Of course, I ended up building my own function to do caseless string compare. The strategy is to compare one character at a time, not making any new String objects, and fallback to localeCompare if both characters are above the 127 ASCII characters:

function custom(a,b) {
    var i, al, bl, l;
    var ac, bc;
    al = a.length;
    bl = b.length;
    l = al < bl ? al : bl;
        
    for ( i=0 ; i<l ; i++ ) {
        ac = a.codePointAt(i);  // or charCodeAt() for better compability
        bc = b.codePointAt(i);
        if ( 64 < ac && ac < 91 ) ac += 32;
        if ( 64 < bc && bc < 91 ) bc += 32;
        if ( ac !== bc ) { 
            if ( 127 < ac && 127 < bc ) {
                ac = a.substr(i,1).toLowerCase();
                bc = b.substr(i,1).toLowerCase();
                if ( ac !== bc ) return ac.localeCompare(bc);
            } else {
                return ac-bc;
            }
        }
    }
    return al-bl;
}

One fascinating thing is that here I can use localeCompare() without 'sv'.

Test for yourself
I built a simple webpage where you can test everything yourself.

Conclusion
Defining a string sort order is not trivial, when you dont just have ASCII characters. If you look at the ascii table you see that non alphabetic characters are spread out:

  • SPACE, #, 1-9, and many more come before both A-Z and a-z
  • Underscore: _, and a few other characters come after A-Z but before a-z
  • Pipe: | and a few other characters come after A-Z and a-z

When it comes to characters behind ASCII 127, it just gets more complicated: how do you sort european language latin letters, greek letters and arrows and other symbols?

For this reason, I think it makes sense to define your own sorting function and clearly define the behaviour for the characters you know that you care about. If it really matters in your application.

My function above is significantly faster than the options.

Disclaimer
These results can probably be inconsistent over different web browsers.

Node.js 6 on OpenWrt

I have managed to produce a working Node.js 6 binary for OpenWrt and RPi (brcm2708/brcm2709).

Binaries

15.05.1: brcm2708 6.9.5
15.05.1: brcm2709 6.9.5
15.05.1: mvebu 6.9.5 Please test (on WRT1x00AC router) and get back to me with feedback

Note: all the binaries work with equal performance on RPi v2 (brcm2709). For practical purposes the brcm2708 may be the only binary needed.

How to build 6.9.5 brcm2708/brcm2709
The procudure is:

  1. Set PATH and STAGING_DIR
  2. Set a few compiler flags and run configure with not so few options
  3. Fix nearbyint/nearbyintf
  4. Fix config.gypi
  5. make

1. I have a little script to set my toolchain variables.

# file:  env-15.05.1-brcm2709.sh
# usage: $ source ./env-15.05.1-brcm2709.sh

PATH=/path/to/staging_dir/bin:$PATH
export PATH

STAGING_DIR=/path/to/staging_dir
export STAGING_DIR

Your path should now contain arm-openwrt-linux-uclibcgnueabi-g++ and other binaries.

2. (brcm2709 / mvebu) I have another script to run configure:

#!/bin/sh -e

#Tools
export CSTOOLS="$STAGING_DIR"
export CSTOOLS_INC=${CSTOOLS}/include
export CSTOOLS_LIB=${CSTOOLS}/lib

export CC="arm-openwrt-linux-uclibcgnueabi-gcc"
export CXX="arm-openwrt-linux-uclibcgnueabi-g++"
export LD="arm-openwrt-linux-uclibcgnueabi-ld"

export CFLAGS="-isystem${CSTOOLS_INC} -mfloat-abi=softfp"
export CPPFLAGS="-isystem${CSTOOLS_INC} -mfloat-abi=softfp"

export PATH="${CSTOOLS}/bin:$PATH"

./configure --without-snapshot --dest-cpu=arm --dest-os=linux --without-npm --without-ssl --without-intl --without-inspector

bash --norc

Please not that this script was the first one that worked. It may not be the best. Some things may not be needed. –without-intl and –without-inspector helped me avoid build errors. If you need those features you have more work to do.

2. (brcm2708)

#!/bin/sh -e

#Tools
export CSTOOLS="$STAGING_DIR"
export CSTOOLS_INC=${CSTOOLS}/include
export CSTOOLS_LIB=${CSTOOLS}/lib

export CC="arm-openwrt-linux-uclibcgnueabi-gcc"
export CXX="arm-openwrt-linux-uclibcgnueabi-g++"
export LD="arm-openwrt-linux-uclibcgnueabi-ld"

export CFLAGS="-isystem${CSTOOLS_INC} -march=armv6j -mfloat-abi=softfp"
export CPPFLAGS="-isystem${CSTOOLS_INC} -march=armv6j -mfloat-abi=softfp"

export PATH="${CSTOOLS}/bin:$PATH"

./configure --without-snapshot --dest-cpu=arm --dest-os=linux --without-npm --without-ssl --without-intl --without-inspector

bash --norc

3. Use “grep -nR nearbyint” to find and replace:

  nearbyint => round
  nearbyintf => roundf

This may not be a good idea! However, nearbyint(f) is not supported in OpenWrt, and with the above replacements Node.js builds and it passes the octane benchmark – so it is not that broken. I suppose there is correct way to replace nearbyint(f).

4. Add to config.gypi:

{ 'target_defaults': {
    'cflags': [ '-D__STDC_LIMIT_MACROS' ,'-D__STDC_CONSTANT_MACROS'],
    'ldflags': [ '-Wl,-rpath,/path/to/staging_dir/lib/' ]},

These are just compilation error workarounds.

This works for me.

Dependencies
You need to install dependencies in OpenWrt:

# opkg update
# opkg install librt
# opkg install libstdcpp

Performance
My initial tests indicate that Node.js v6 is a little (~2%) slower than Node.js 4 on ARM v7 (RPi v2).

Other targets
mvebu: I will build a binary, but I need help to test
x86/x86_64: This shall be easy, but I see little need/use. Let me know if you want a binary.
mpc85xx: The chip is quite capable, but the PowerPC port of Node.js will most likely never support it.

Most MIPS architectures lack FPU and are truly unsuitable for running Node.js.

std::snprintf
It seems the OpenWrt C++ std library does not support std::snprintf. You can replace it with just snprintf and add #include <stdio.h> in the file:
deps/v8_inspector/third_party/v8_inspector/platform/inspector_protocol/String16_cpp.template
However, this is not needed when –without-inspector is applied.

Node.js 7
I have failed building Node.js 7 before. But perhaps I will give it a try sometime that Node.js 6 is working.

Older versions of Node.js
I have previously built and distributed Node.js 4 for OpenWrt.