Category Archives: Uncategorized

Wonderdraft – first impressions

As a D&D Dungeon Master I occationally need to create maps, and I discovered Wonderdraft. I have tried it a bit and I will make notes in this post (and update as I learn) hoping it could be useful for other people thinking about getting Wonderdraft.

Initial productivity

I spent a few hours the first evening I got Wonderdraft and I produced two real maps for my D&D campaign. One is a town, and I think I need to learn more to make good town maps, but it is ok. The other one is a more black and white map with towns, paths, mountains, rivers and a few named places.

One feature that surprised me was that I can import a picture (a PNG scan of a map) and it makes a map of it. It does not get good, but at least you get the basics. If you have a map with coasts and forests and towns and you just want the proportions right this is useful.

I learnt a little later that you can rotate a symbol using they keys: . and , before placing it.

Performance

The Wonderdraft web page is quite clear that a powerful computer with a decent GPU is needed or recommended. I have tried a few different computers and reasonably small maps (1920×1280).

  • Painfully slow
    • Mac Book Pro Mid 2010
    • NUC 54250WYKH (4th generation i5), 2013 (Ubuntu)
  • Working fine
    • MacBook Air 2014
    • MacBook Air 2015
  • Working perfectly
    • NUC Hades Canyon NUC8i7HVK (8th gen i7), 2018 (Windows)

What I am saying here is that for my initial, not so large or complex maps, I am satisfied with the performance of 2014 computers and newer, running macOS and Windows: Wonderdraft was snappy and immediate. With the painfully slow machines there is a 1s latency on everything. But it works.

Map size matters much though! I tried some assets on the MacBook from 2010 and used 800×600 maps. Then performance was acceptable (although I had occational crashes).

Extra Assets

There is a community for extra free assets with Wonderdraft. I did things backwards, but I recommend you make it easy for yourself.

  • Click “community links” in the menu
  • Click “Mythkeeper”
  • Install Mythkeeper (macOS and Windows only)
  • Run Mythkeeper

I started working with manual downloads, manual unzip, manual placement of folders in my asset-folder, and Mythkeeper simplifies it all very much.

Making sense of Forgotten Realms

A little while ago I wrote DM lost in Forgotten Realms. I have been thinking a bit more, and I even talked to my players (who thankfully are not into Forgotten Realms lore).

There are some problems with Forgotten Realms (or Faerûn, the continent where most things happen):

  1. It is very much a mix of everything (Kitchen Sink Setting), which makes it a place of little character (although, there are nice spots in Faerûn the big picture is confusing and/or makes little sense).
  2. There is very much magic, and many magic-users.
  3. There are very many deities, and they are rather active.
  4. Faerûn feels overloaded.
  5. The extreme events of Time of Troubles, Spellplague and Second Sundering are all very recent.
  6. Some people complain there are too many high-level NPCs.
  7. It is confusing with different source material for 2e/3e, 4e, 5e when things dramatically change.
  8. Do I want half-orcs to be common, and dragonborns and tieflings?

The good thing is that if you want some type of place to run your campaign, it is very likely that such a place exists in Faerûn. The bad thing is that when you start looking around (or just back a little in time) it probably gets very twisted compared to your expectations, like:

  • city of undead run by 60 liches
  • island is run by a vampire
  • another island is populated by lycantropes

This is not far away in Mordor. You find it most everywhere. You may argue that Forgotten Realms is big, and I can change what I don’t like… and that is what I intend to do.

The Dark Ages

This is just my idea of turning Forgotten Realms into something we like better in my group. I am just drawing out the primary ideas.

After Time of Troubles, Spellplague and Second Sundering things did not calm down. Instead both Good and Evil tried to dominate and the deities kept being active.

16th century was a century of war, death, fire and destruction throughout Faerûn, and in the end of it some major players were beginning to get enough of it, among them Lord Ao (the overgod). Lord Ao established some new principles and managed to have them enforced.

  1. The people(s) and beast(s) of Faerûn shall have Faerûn as their world, just as the deities have their worlds (planes).
  2. Silvanus (Oak Father – neutral god of nature), who did not participate in the century of war while much of Faerûn was burnt, is alone set to guard Faerûn, being neutral.
  3. Faerûn shall be dominated by wilderness.

The other deities mostly accepted. They were wounded, tired of war, imprisoned or not achieving their goals on Faerûn or elsewhere.

17th century, was a century of unusually little magic in Faerûn as many spellcasters were dead after the wars and the deites (including Mystra, deity of magic) were quite absent. Instead hard working mortals formed city states or smaller countries than had been seen before. Rangers started roaming the growing wilderness in the name of Silvanus, and druids settled around the lands.

18th century was the end of the Dark Ages of Faerûn. The newly born Faerûn is a beautiful wild mysterious place with scattered villages and towns inhabited by hardy, brave people.

Magic

Spellcasters are found across the lands. The old deities are rediscovered, as is arcane magic. Attitudes to magic vary, from hostile to friendly, and often curious.

Good and Evil

Lawful ambitious mortals are aspiring to form new empires in the present power vacuum, both good and evil, but the lands remain mostly wild and chaotic. Among the good there is some appreciation for the beauty, the wilderness and the relative peace under neutral Silvanus. The evil on the other hand see much potential and quite little resistance.

Recovery of civilization

The (low magic, nature oriented, somewhat) Moonshae Isles fell less into chaos than other lands. You find the isles not too different from what they were bofore Time of Troubles. Lycantropes, vampires have faded and Kazgoroth has not been seen in long, remaining the symbol of evil on the isles.

The heartlands (the Sword Coast to Cormanthor) saw great destruction and devastating wars during 16th century. However the cities of the heartlands were not all completely destroyed, some remained and some has been rebuilt. The heartlands is where hard working mortals have gathered to build new nations.

In the northwest, the coastal areas were not so damaged by the wars, and some settlements of good people remain.

The rest of Faerûn, the north, the east and the south, are very wild lands. There are of course settlements of good people, but nature dominates and evil is more common.

The truly far away lands (east of the deserts, south of Shaar) can be an enirely different story.

Using Resources

I shall be able to use most maps, and all lore is valid, just history. I shall also be able to cherry pick stuff (places, NPCs, adventures) from 2e-5e and just import it into my setting (without my group of players having any reason to complain).

The year is 1772 DR, and I think it will be great fun!

Everything should be simple…

Einstein said: “everything should be made as simple as possible, but not simpler”. I guess that could apply to my campaign world as well. Why would I not want a simple story and feeling that captures my campaign?

On the other hand I understand that for WotC, Forgotten Realms is complicated because they have very many different requirements on it (not the least to fit all current and past adventures and novels).

So maybe Forgotten Realms is good for WotC, but I can actually do better for myself.

Much ado about Nothing?

You may be well read about Forgotten Realms and think: “But that is how forgotten realms already is: mostly wilderness, mostly citystates, no dominant nations. You just got rid of interesting places and lore because you didn’t understand it, and you may regret that down the road when Tethyr och Calimshan would have been ideal for your ideas.”

And you may actually be right about that!

Adobe CS4 and macOS 10.14 Mojave

How about using an old unsupported CS application on current macOS?

Today I had a reason to try it out. The short version is that it seems to work with Photoshop and Illustrator, but not with Indesign.

Background

Adobe used to sell “perpetual licenses” with their Creative Suite software. Years ago they stopped doing that and changed to a subscription model with Creative Cloud. People with perpetual licenses could still use them, but support in mac OS is getting more troublesome with every upgrade. A perpetual license could be used on two computers, and there was an activation/deactivation feature.

My Case

I have a friend who use CS4 on two older Macs running unspported version of macOS. My friend now got a brand new MacMini (with macOS 10.14 Mojave) and ideally we wanted to deactivate CS4 on the old MacMini, and activate it on the new. That was obviously a gamble.

Activation Servers Down

It appears the Adobe Activation servers are down. Deactivation on the old MacMini was not possible. Thus proper Activation should also not be possible.

Trying an old workaround

There used to be an old workaround (clearly used for software piracy) described here. We tried installing CS4 on Mojave and that worked fine. We then did the hack in the article, and that worked too. It seems Photoshop and Illustrator worked correctly, but Indesign did not. Indesign ran into a perhaps well known problem about “empty toolbox”. Also, when choosing “New”, an empty dialog window opens. This can perhaps be fixed, but we did not bother.

Restoring CS4 using Time Machine gave the same result for practical purposes: Photoshop worked but Indesign appeared broken and could not even be started.

CS5, CS6

Obviously, I can’t say anything definite about CS5 and CS6. I guess the workaround does not work. And I believe after reading some forums that the activation servers are down as well.

Conclusion

You may be able to install and use CS4 Illustrator and Photoshop on macOS 10.14 Mojave. Rumours indicate that it will not work at all in 10.15 when 32-bit support is finally dropped from macOS.

Doublethink 2019

Doublethink is: the acceptance of contrary opinions or beliefs at the same time, especially as a result of political indoctrination

As I listen to politicians and influencers in 2019 there are very many contradictory things that they seem to believe, and that I am expected to also believe.

I publish the list below not to have a discussion about every single item. Perhaps you agree about some and think I got others wrong (which is of course possible). I publish this list to show that it is common that politicians and other influencers hold and express contradictory opinions at the same time, and that we are supposed to accept and follow this.

I am convinced that each and every one of us should ideally hold zero contradictory beliefs at any given time. So even if you only agree about some of my items, we should be able to agree that we have a systemic problem with doublethink.

Much of this doublethink happens in the name of Political Correctness. Welcome to 1984.

We are supposed to believe…

that Nazism is worse than Communism despite the number of dead tell a very different story

that taxation is useful to restrict things like tobacco, alcohol and emissions, but not causing any harm to real businesses and employment

that they care about reducing CO2-emissions, despite they don’t want any nuclear power

that nuclear power is very dangerous, despite coal cause more deaths monthly on the planet than nuclear accidents ever caused

that the unequal distribution of power and money under capitalism will disappear when even more power is centralized with politicians to control not only government, but also companies under socialism

that Israel is a terrible apartheid state, despite there is a significant minority of arabs and muslims in Israel, enjoying a good living standard and having more democracy and human rights than arabs and muslims anywhere else in the middle east

that they stand up against all racism – nazism most of all, except when it comes to antisemitism among people from the middle east

that the hijab (or variants of same purpose) is a symbol of womens freedom when many women in and from the middle east tell a very different story

that the white European man brought slavery and slave trade to the world, when the arab slave trade had been going on for 1000 years (both from Africa and Europe) and the market and infrastructure was already there in Africa when Europeans for a few hundred years did slave trade (a horrible thing)

that capitalism is the worst threat to the environment, when the atrocities when it comes to destroying the environment in the Soviet Union are unprecedented

that Europeans brought all cruelty and misery to the american continent, despite human sacrifice and very authoritarian societies were massively widespread among the natives before the continent was discovered (the Europeans also did horrible things)

that socialism is in strong opposition to nazism, when clearly nazism is a form of socialism, and Marx coined the term “the jewish question” himself

that the left is against hatred and violence, when their own rhetoric against capitalists, white men and other opponents is very aggressive

that all criminals deserve another chance and can be good citizens and humans, despite the fact that psychopathy exists there is no known working treatment

that anti-fascism is a democratic mindset, however the Berlin Wall was stated to be an anti-fascist measurement and it had very little to do with fascism and everything to do with oppressing people in a socialist state

that capitalism is bad to people, despite it is practically unheard of people leaving free market nations for socialist nations, while millions of people have fled socialism

that Islam is a religion like others, and a religion of peace, despite it has been at war with itself, at war with its own people, at war with its women, and at war with its neighbors since the days of Mohammed

that the free market is to blame for lack of housing, when the housing market is one of the few markets that are heavily regulated, and while most free markets show no lack of options for relatively poor people: cheap clothes, food, fast food, entertainment, air travel, furniture are provided by global brands like HM, MacDonalds, Lidl, Netflix, Ryanair and IKEA (how about letting those companies work with lack of housing?)

that ISIS is not representative of Islam despite they just follow the footsteps of Mohammed which is clearly a virtue in Islam

that Islamism is a separate thing from Islam, despite the Koran considers the law, Sharia, central to the life of a muslim, and despite Erdogan has said that the separation of Islam and Islamism is an ugly western construction

that Islam is not a threat to freedom, democracy and human rights, despite there are virtually no muslim majority countries that are free, democratic and respect human rights

that Mohammed is a respectable prophet, despite he was one of the most cruel humans in history

that the environmentalists care about science when it comes to human caused climate change, but when it comes to GMO and studies finding disadvantages with organic farming they ignore scientific results

that later muslim aggressions have been a reasonable response to the crusades, when the crusades are minor isolated events compared to the many centuries of war, imperialism and slavery that muslims had brought upon the Middle East, Europe and Africa before the crusades

that women are structurally and systematically oppressed by men in the west, despite women live 5 years longer, spend less than 20% time in prison, commit far fewer suicides, experience far few workplace accidents, and generally have better mental health and more friends than men do

that feminists care about women who have a hard time, despite they don’t listen at all to what prostitutes say or want

that very few women go into tech jobs because of discrimination and sexist attitudes, despite women a century ago were restricted from most careers and (very impressively) managed to make it into medicine, teaching, law, economics, politics, and so on (feminists today are implying that tech men are worse than other men which is speculative, and also injury-on-insult since women tend to reject nerds in the first place)

that democratic socialism has anything to do with democracy, despite all socialist states have ended up seriously authoritarian, many of them with the word democratic in their names

that the west, USA and modern Europe, are the only evil empires, despite the history of the world is the history of empires (chineese, persian, roman, muslim, aztec, ottoman, russian, and so on) that conquered nations and enslaved people.

that we are very certain about the catastrophic effects of climate change, despite previous threats: peek oil, HIV, the ozone layer, nuclear power, nuclear weapons, world wars, new ice age, turned out to be exaggerated (in fact humans have always thought they live just before the end of time)

that men and women are practically the same, when the biological differences (both physical, psychological, and when it comes to abilities and talents) are clearly significant (and this is also proven scientifically in numerous studies)

that equality of outcome is desirable, when the way to achieve it necessarily is very authoritarian and restrictive to individual freedom and choice

that anxiety of climate change is a virtue, while anxiety of terrorism and criminality is a sin

that nationalism is inherently evil, despite no welfare state has ever existed beyond the scope of a nation

that women are for all purposes equal to men, except when they do horrible things like joining ISIS, then they are to be understood as passive victims and they can play the woman-card

that the anti-racist left are anti racist at all, when they often hold and spread very antisemitic attitudes and support antisemitic (muslim) organisations

that feminism is about fighting the patriarchy, when it is mostly indifferent to outright oppression of women in/from non-western cultures

that feminists have valid reasons to embrace people like Linda Sarsour (an advocate of Sharia in USA), when they reject people like Ayaan Hirsi Ali (an ex-muslim standing up for human rights)

that political correctness is more important (when it comes to respect of minorities and other cultures) than the words of Martin Luther King: History will have to record that the greatest tragedy of this period of social transition was not the strident clamor of the bad people, but the appalling silence of the good people.

that cows, chicken and pigs will be happily liberated by vegetarians, when the animals will instead be practically extinguished

that christianity and islam are mostly the same, despite christianity have been reformed on several occasions and christians mostly accept and respect different interpretations of their religion, while Islam is inherently resilient to reformation, has failed to reform but rather tend to fall back into fundamentalism, and muslims mostly don’t accept the interpretation of other muslims.

that socialism is a fine idea, which it perhaps was just like Thalidomide (Neurosedyn in Swedish), but after seeing the catastrophic effects of applying it, it is nothing less than heartless, cruel and evil to make another attempt (but socialism has, unlike capitalism, science and most other activities, absolutely no feedback loop so it is applied over and over again with the same horrible result – only the propaganda is refined)

intolerant extremists to the right (fascists and nationalists) are considered an absolute evil and threat and they must not even be talked to, but the returning murderers and rapists of ISIS are supposed to be respectfully integrated (getting more support than any other refugee or ISIS victim could dream of)

that the idea of socialism, which ultimately is to reward those who do wrong and punish those who do right, can ever lead to a good society despite any workplace, relationship, raising of children or keeping pets would fail horribly following the same inferior idea (I dare you to start encouraging bad behavior and punishing good behavior with people or pets around you)

that the problem is that some people are very rich, when in fact poverty globally is being effectively pushed back (except mostly in a few unfortunate authoritarian and/or socialist countries); caring about improving the situation for the poor is emphatic, caring about taking from the rich is only jealousy (and shows ignorance of basic economics)

that gender theory and political correctness are good things, when they are just the racial biology and racial hygiene of our time (the purpose is to classify and group people based on origin and physical attributes, and then to create a conforming population for the utopia, not to respect human rights or diversity)

that women have absolute right to their own bodies (abortion now legal up to day of birth in some places), unless they want to make profit on sex or sexuality

that there is anything reasonable about transgender women competing with other women in elite sports, despite the obvious fact that they have a massive unfair advantage

that gender is a social construction, although we are born with a sexual orientation

that Che Guevara is a fighter of freedom and equality for the left, when he was a homophopic, rasist, chauvinistic murderer

that while abortion is an absolute right (my body my choice), surrogacy is unacceptable

that criticism of Islam is Islamophobic, while criticism of Israel is not antisemitic

In Sweden, we are supposed to believe…

that it will reduce emissions to build high speed railroads to the north to replace a few daily flights (emissions from construction will exceed flights for foreseeable future)

that criminality can not be reduced by longer prison sentences, despite criminals answer that they did not even recognize they got a punishment at all for their crime

that there is evidence longer prison sentences don’t work to reduce crime, when it has never been tried in modern time in Sweden (references are usually to studies from the US where already draconian prison sentences were made even longer, which obviously says very little about what happens if criminals start being punished at all, or from a very low level)

that socialism made Sweden rich, when in fact the foundation of wealth in Sweden was built before the second world war by a low-tax, laissez-faire economy (that later came to slow down as taxes rises under socialism)

that socialism brought social security to the working class in Sweden, despite the workers organized it themselves as private insurances (that the socialist government later nationalized and took credit for)

that we have world class healthcare, despite people who have been living abroad are often shocked with Swedish health care

that they care about the well-being of animals, when they want wolves to hunt freely causing massive cruelty to wild and domestic animals wherever they come

that they care about vulnerable people, when they are mostly unwilling to protect ordinary people – even abused women – from criminals with a long record of offences

that the left (Swedish V) is inherently against racism, when they were the only party who did not oppose Hitler at the time Nazi Germany conquered Norway and Denmark.

that the left (Swedish V) is democratic and against imperialism, when they were the only party not support the Polish Solidarity movement at the time

that restricting access to weapons to honest citizens and hunters even more will make the country any safer, despite these legal weapons are virtually unheard of in crime cases (except rare self defense cases)

that they care about ethnic diversity and indigenous people, when Sweden blatantly ignores UN Declaration of the Rights of Indigenous People when it comes to the samis.

About Venezuela, we are supposed to believe…

that USA is to blame for the catastrophe in Venezuela, despite Russia and China has much more dealings with the socialist regime

that it is about USA wanting the oil, when USA is rather self sustained

that Russia has some moral ground when they object to interfering in the internal affairs of other nations, like Venezuela, given their recent history in Georgia, Ukraine and Chechnya, and a longer tradition of occupying neighbour states

that they care about potential climate refugees in a distant futures, despite they don’t give a shit about refugees of socialistic Venezuela

that the crimes the socialist regime in Venezuela commit against human rights and its own population (censorship, torture, oppression, socialistic market regulation and currency regulations resulting in lack of everything, blocking humanitarian aid, ignoring the constitution, establishing collectivos to harass and brutalize people, and so on) are somehow reasonable given a narrative that USA is working against the chavism and socialist movement

that the socialist regime had inherently good intentions towards its own population when it ran welfare programs in the past, despite the same regime now is completely indifferent to the suffering of its own people, even rejecting international emergency humanitarian aid (the regime only cares about its loyal supporters, everyone else who don’t support the socialistic cause can suffer)

that things are mostly fine in Venezuela despite UNHCR tells that more than 3 million people have fled the country in a few years (3 million people had left GDR before the Berlin Wall was built to prevent it)

Trainz Log

I decided to try Trainz (now that 2019 is out) and I think it is useful to keep track of my progress, so I will do it here.

Gamepad

I prefer to drive my train with a gamepad. I found a little free software called AntiMicro which allowed me to map my Xbox gamepad to relevant Trainz keys. It was easy and I recommend it.

Graphics

My computer is a NUC Hades Canyon. It has an Intel Core i7 CPU, AMD Radeon RX Vega M GPU, 16GB or RAM and 512GB SSD. This computer can not at all play Trainz 2019 in “Ultra”, instead I have to tune down the performance settings quite much. I have found (and I may change opinion when I have experimented more) that I want to run Trainz in full resolution (1920×1080) and I think the lowest anti aliasing (2x) makes most sense. I allow myself to use “Clutter + Turf FX” and High details. Different routes are supposed to be demanding on the GPU.

Cornish Mainline and Branches

A trip to Falmouth: Completed with 2 stars.
Freight Delivery: This session is tricky and I started a thread on the Trainz forum. I dont think the 2MT is capable of pulling 23 wagons all the way, I got completely stuck after 7 miles in a 2%+ grade. I modified the session and used a 4200 tank locomotive instead but I got two new problems: 1) AI trains going in the other direction all stand still, 2) When I have finally arrived the session never ends (or continues). Perhaps I broke something when I modified it.
Helston freight run: Completed with 5 stars.
Helston passenger run: Completed with 4 stars.
Mainline passenger service: Completed with 1 star (!), on time, gorgeous!
St Ives passenger run: Completed with 5 stars.

ECML Edinburgh – Dundee

09-10 Dundee – Kings Cross: Completed with 5 starts (but can’t drive in realistic CAB mode)

Sebino Lake

Maintenance Service: Completed with 5 stars (in DCC, can’t get the train rolling in Cab mode)

Lambda Functions considered Harmful

Decades ago engineers wrote computer programs in ways that modern programmers scorn at. We learn that functions were long, global variables were used frequently and changed everywhere, variable naming was poor and gotos jumped across the program in ways that were impossible to understand. It was all harmful.

Elsewhere matematicians were improving on Lisp and functional programming was developed: pure, stateless, provable code focusing on what to do rather than how to do it. Functions became first class citizens and they could even be anonymous lambda functions.

Despite the apparent conflict between object oriented, functional and imperative programming there are some universally good things:

  • Functions that are not too long
  • Functions that do one thing well
  • Functions that have no side effects
  • Functions that can be tested, and that also are tested
  • Functions that can be reused, perhaps even being general
  • Functions and variables that are clearly named

So, how are we doing?

Comparing different styles
I read code and I talk to people who have different opinions about what is good and bad code. I decided to implement the same thing following different principles and discuss the different options. I particularly want to explore different ways to do functional programming.

My language of choice is JavaScript because it allows different styles, it requires quite little code to be written, and many people should be able to read it.

My artificial problem is that I have two arrays of N numbers. One number from each array can be added in NxN different ways. How many of these are prime? That is, for N=2, if I have [10,15] and [2,5] i get [12,15,17,20] of which one number (17) is prime. In all code below I decide if a number is prime in the same simple way.

Old imperative style (imperative)
The old imperative style would use variables and loops. If I had goto in JavaScript I would use goto instead of setting a variable (p) before I break out of the inner loop. This code allows for nothing to be tested nor reused, although the function itself is testable, reusable and pure (for practical purposes and correct input, just as all the other examples).

  const primecount = (a1,a2) => {
    let i, j;
    let d, n, p;
    let retval = 0;


    for ( i=0 ; i<a1.length ; i++ ) {
      for ( j=0 ; j<a2.length ; j++ ) {
        n = a1[i] + a2[j];
        p = 1;
        for ( d=2 ; d*d<=n ; d++ ) {
          if ( 0 === n % d ) {
            p = 0;
            break;
          }
        }
        retval += p;
      }
    }
    return retval;
  }

Functional style with lambda-functions (lambda)
The functional programming equivalent would look like the below code. I have focused on avoiding declaring variables (which would lead to a mutable state) and rather using the higher order function reduce to iterate over the two lists. This code also allows for no parts to be tested or reused. In a few lines of code there are three unnamed functions, none of them trivial.

  const primecount = (a1,a2) => {
    return a1.reduce((sum1,a1val) => {
      return sum1 + a2.reduce((sum2,a2val) => {
        return sum2 + ((n) => {
          for ( let d=2 ; d*d<=n ; d++ ) if ( 0 === n % d ) return 0;
          return 1;
        })(a1val+a2val);
      }, 0);
    }, 0);
  };

Imperative style with separate test function (imperative_alt)
The imperative code can be improved by breaking out the prime test function. The advantage is clearly that the prime function can be modified in a more clean way, and it can be tested and reused. Also note that the usefulness of goto disappeared because return fulfills the same task.

  const is_prime = (n) => {
    for ( let d=2 ; d*d<=n ; d++ ) if ( 0 === n % d ) return 0;
    return 1;
  };

  const primecount = (a1,a2) => {
    let retval = 0;
    for ( let i=0 ; i<a1.length ; i++ )
      for ( let j=0 ; j<a2.length ; j++ )
        retval += is_prime(a1[i] + a2[j]);
    return retval;
  };

  const test = () => {
    if ( 1 !== is_prime(19) ) throw new Error('is_prime(19) failed');
  };

Functional style with lambda and separate test function (lambda_alt)
In the same way, the reduce+lambda-code can be improved by breaking out the prime test function. That function, but nothing else, is now testable and reausable.

  const is_prime = (n) => {
    for ( let d=2 ; d*d<=n ; d++ ) if ( 0 === n % d ) return 0;
    return 1;
  };

  const primecount = (a1,a2) => {
    return a1.reduce((sum1,a1val) => {
      return sum1 + a2.reduce((sum2,a2val) => {
        return sum2 + is_prime(a1val+a2val);
      }, 0);
    }, 0);
  };

  const test = () => {
    if ( 1 !== is_prime(19) ) throw new Error('is_prime(19) failed');
  };

I think I can do better than any of the four above examples.

Functional style with reduce and named functions (reducer)
I don’t need to feed anonymous functions to reduce: I can give it named, testable and reusable functions instead. Now a challenge with reduce is that it is not very intuitive. filter can be used with any has* or is* function that you may already have. map can be used with any x_to_y function or some get_x_from_y getter or reader function that are also often useful. sort requires a cmpAB function. But reduce? I decided to name the below functions that are used with reduce reducer_*. It works quite nice. The first one reducer_count_primes simply counts primes in a list. That is (re)useful, testable all in itself. The next function reducer_count_primes_for_offset is less likely to be generally reused (with offset=1 it considers 12+1 to be prime, but 17+1 is not), but it makes sense and it can be tested. Doing the same trick one more time with reducer_count_primes_for_offset_array and we are done. These functions may not be reused. But they can be tested and that is often a great advantage during development. You can build up your program part by part and every step is a little more potent but still completely pure and testable (I remember this from my Haskell course long ago). This is how to solve hard problems using test driven development and to have all tests in place when you are done.

  const is_prime = (n) => {
    for ( let d=2 ; d*d<=n ; d++ ) if ( 0 === n % d ) return 0;
    return 1;
  };

  const reducer_count_primes = (s,n) => {
    return s + is_prime(n);
  };

  const reducer_count_primes_for_offset = (o) => {
    return (s,n) => { return reducer_count_primes(s,o+n); };
  };

  const reducer_count_primes_for_offset_array = (a) => {
    return (s,b) => { return s + a.reduce(reducer_count_primes_for_offset(b), 0); };
  };

  const primecount = (a1,a2) => {
    return a1.reduce(reducer_count_primes_for_offset_array(a2), 0);
  };

  const test = () => {
    if ( 1 !== [12,13,14].reduce(reducer_count_primes, 0) )
      throw new Error('reducer_count_primes failed');
    if ( 1 !== [9,10,11].reduce(reducer_count_primes_for_offset(3), 0) )
      throw new Error('reducer_count_primes_for_offset failed');
    if ( 2 !== [2,5].reduce(reducer_count_primes_for_offset_array([8,15]),0) )
      throw new Error('reducer_count_primes_for_offset_array failed');
  };

Using recursion (recursive)
Personally I like recursion. I think it is easier to use than reduce, and it is great for acync code. The bad thing with recursion is that your stack will eventually get full (if you dont know what I mean, try my code – available below) for recursion depths that are far from unrealistic.  My problem can be solved in the same step by step test driven way using recursion.

  const is_prime = (n) => {
    for ( let d=2 ; d*d<=n ; d++ ) if ( 0 === n % d ) return 0;
    return 1;
  };

  const primes_for_offset = (a,o,i=0) => {
    if ( i === a.length )
      return 0;
    else
      return is_prime(a[i]+o) + primes_for_offset(a,o,i+1);
  }

  const primes_for_offsets = (a,oa,i=0) => {
    if ( i === oa.length )
      return 0;
    else
      return primes_for_offset(a,oa[i]) + primes_for_offsets(a,oa,i+1);
  }

  const primecount = (a1,a2) => {
    return primes_for_offsets(a1,a2);
  };

  const test = () => {
    if ( 2 !== primes_for_offset([15,16,17],2) )
      throw new Error('primes_with_offset failed');
  };

Custom Higher Order Function (custom_higher_order)
Clearly reduce is not a perfect fit for my problem since I need to nest it. What if I had a reduce-like function that produced the sum of all NxN possible pairs from two arrays, given a custom value function? Well that would be quite great and it is not particularly hard either. In my opinion this is a very functional approach (despite its implemented with for-loops). All the functions written are independently reusable in a way not seen in the other examples. The problem with higher order functions is that they are pretty abstract, so they are hard to name, and they need to be general enough to ever be reused for practical purposes. Nevertheless, if I see it right away, I can do it. But I don’t spend time inventing generic stuff instead of solving the actual problem at hand.

  const is_prime = (n) => {
    for ( let d=2 ; d*d<=n ; d++ ) if ( 0 === n % d ) return 0;
    return 1;
  };

  const combination_is_prime = (a,b) => {
    return is_prime(a+b);
  };

  const sum_of_combinations = (a1,a2,f) => {
    let retval = 0;
    for ( let i=0 ; i<a1.length ; i++ )
      for ( let j=0 ; j<a2.length ; j++ )
        retval += f(a1[i],a2[j]);
    return retval;
  };

  const primecount = (a1,a2) => {
    return sum_of_combinations(a1,a2,combination_is_prime);
  };

  const test = () => {
    if ( 1 !== is_prime(19) )
      throw new Error('is_prime(19) failed');
    if ( 0 !== combination_is_prime(5,7) )
       throw new Error('combination_is_prime(5,7) failed');
    if ( 1 !== sum_of_combinations([5,7],[7,9],(a,b)=> { return a===b; }) )
       throw new Error('sum_of_combinations failed');
  };

Lambda Functions considered harmful?
Just as there are many bad and some good applications for goto, there are both good and bad uses for lambdas.

I actually dont know if you – the reader – agrees with me that the second example (lambda) offers no real improvement to the first example (imperative). On the contrary, it is arguably a more complex thing conceptually to nest anonymous functions than to nest for loops. I may have done the lambda-example wrong, but there is much code out there, written in that style.

I think the beauty of functional programming is the testable and reusable aspects, among other things. Long, or even nested, lambda functions offer no improvement over old spaghetti code there.

All the code and performance
You can download my code and run it using any recent version of Node.js:

$ node functional-styles-1.js 1000

The argument (1000) is N, and if you double N execution time shall quadruple. I did some benchmarks and your results my vary depending on plenty of things. The below figures are just one run for N=3000, but nesting reduce clearly comes at a cost. As always, if what you do inside reduce is quite expensive the overhead is negligable. But using reduce (or any of the built in higher order functions) for the innermost and tightest loop is wasteful.

 834 ms  : imperative
874 ms  : custom_higher_order
890 ms  : recursive
896 ms  : imperative_alt
1015 ms  : reducer
1018 ms  : lambda_alt
1109 ms  : lambda

Other findings on this topic
Functional Programming Sucks


Fix broken Marshall Stanmore

First I want to be clear, this post is about fixing a broken Marshall Stanmore speaker by turning it into an active loudspeaker. It is not about repairing it to its original functionality.

My Marshall Stanmore died after about two years of little use. One day it simply did not turn on. Completely dead. It seems to be a common fate of those loudspeakers and there seems to be no easy fix. I opened up the loudspeaker and quite quickly decided that I would not be able to repair it.

I felt very certain that the loudspeaker elements themselves were not broken. The loudspeaker looks and sounds quite good and it is against my nature to just throw such a thing away. So I started looking for ways to make a working active loudspeaker of it (allowing to use it with an iPhone or as a computer speaker). Since I thought this was a fun project I was willing to put some time and effort into it. But a brand new Marshall Stanmore is 200 Euros so the fix had to be significantly cheaper than that.

2.1
The Stanmore is a 2.1-loudspeaker. It has two tweeters and one woofer. The cutoff frequency is 2500Hz meaning that the tweeters are responsible for higher than 2500Hz frequencies and the woofer for the lower frequencies. There are different ways to properly produce 2.1 audio from a 2.0 signal. If I remember correctly the tweeters are rated at 2x20W and the woofer at 40W. I don’t know the impendance (Ohm).

The thing not to do
It is not a good idea to just simply connect L+R and connect it to the woofer. Regardless whether you do this before or after the amplifier you will drive current into components that are only supposed to produce a signal and this can destroy your equipment (your smartphone or computer pre-amp, or your amplifier).

Cutoff filters
There are special cutoff filters to split a signal into a lower and a higher part. I looked into this first, but it seemed a bit to advanced (expensive and complicated) for my project, and the problem with mixing L+R remains.

2.1 Amplifiers
There are 2.1 amplifiers to buy. The problem is that they are designed for use with a subwoofer (very low frequencies), not our 2500Hz woofer. This may or may not be a problem.

Mono
If I had a mono amplifier (that accepts stereo input and produce mono output) I could connect all the three loudspeakers to the same output. Since the distance between the tweeters is less than 25cm I don’t think the lack of stereo-tweeters will matter. However, it was not very easy to find suitable mono amplifiers (or “bridged amplifiers” that can be used as a mono amplifier).

Two-trick-solution
In the end I decided to go for a simple solution based on two parts.

First, pre-amp, it is very easy to convert stereo to mono. The only thing needed is two resistors (470 Ohm, or something close to that).

Second, a 2.0 amplifier can drive the tweeters on one channel and the woofer on the other (that is 40W on each channel).

Cleaning out the Stanmore
I removed (unscrewed) the back of my Stanmore. When I was done with it, the only thing that remained (and in place) was:

  • The box itself (except the back of it).
  • The three loudspeaker elements, and as long cables as possible.
  • The top golden colored control panel (because removing it would not make anything pretty) and the board attached to it (because it was hard to remove).
  • The cable (black+white+red) from the 3.5mm connection on top of the loudspeaker.
  • The 4 red cables from the on/off-switch.

What I also needed
This is a list of other components I used

Assembly
I neatly connected everything in a way that it fits nicely inside the Stanmore.

  • DC-power to two red cables connected to Stanmore power switch
  • The other two red cable to Jtron board (make sure to no reverse!)
  • One Jtron channel connected to yellow+black of woofer
  • One Jtron channel connected to red/blue+black of tweeters
  • Black of 3.5mm connector to Jtron input (middle)
  • Red/white of 3.5mm connector connected via two 470 Ohm resistors
  • From between the resistors, connect to Jtron input (left and right)

This is what I got:

As you can see the Jtron is pretty small.

For now my laptop DC supply is outside the Stanmore and there is just a little hole in the back for the cable.

Operating
The power switch on top is operational and I connect my audio source to the 3.5mm connection on top. The Jtron knobs work as expected (there is no balance).

About the Jtron
The Jtron was very good price and I thought 2x50W was kind of optimal for me. Also, it is a digital amplifier with high power efficiency (little excess heat). There are obviously many other options.

Serial vs Parallell
I connected my tweeters in parallell. I suppose they could have been used in series instead. Perhaps serial would have been more safe: impendence would be 4x higher, which would be less demanding on the Jtron.

Review
Well, I shall not review my own work. To be honest I have not fixed a new back plane yet and I think not having it in place is far from optimal for audio quality. Despite that, the Stanmore sounds very decent. It plays loud enough for me (perhaps louder than before). You probably want to experiment with bass/treble until satisfied. The way I use it (with an iPhone) I will set preset volume to loud, and mostly use the iPhone to control volume.

What I have lost compared to the original Stanmore is RCA-input, bluetooth and volume/treble/bass on top of the unit. I can live with it.




SonarQube 6.5 – Mac OS X – Installation problems

It seems SonarQube 6.5 does not work with JDK 9. Java 8 upgrade 144 works fine.

There is no automated way to uninstall JDK 9 properly, but you can have different Java side by side. This is how to pick Java version.

export JAVA_HOME=/Library/Java/JavaVirtualMachines/jdk1.8.0_144.jdk/Contents/Home

After that you can run

sonar.sh start

as usual.

Can not log in to SonarQube 6.5 on Mac OS X with default password
With JDK 9 authentication with default user/pass admin/admin fails. It turns out the error HTTP code is 500, not 401, which made me suspicious.

Syncthing: breaking upgrades

Syncthing is usually very easy to upgrade: it upgrades itself silently or via apt-get. Problem is, when it changes version (lastly from 0.12 to 0.13) it is not compatible anymore. It is not a big problem since it is easy to upgrade, but you kind of have to upgrade your entire Syncthing cluster at the same time, otherwise you get an undesired fork.

This was the quite confusing error message i got on the newly updated system that failed to connect to non upgraded systems:

[THC2C] 19:17:52 INFO: Failed to exchange Hello messages with <ID> (<ADDRESS>): EOF

So, be mindful when upgrading syncthing so you dont get a non breaking upgrade when you dont have time to upgrade everything.

Syncthing on Android

I installed Syncthing a few weeks ago. Now I found it was time to connect my Android mobile to it. Installing Syncthing via Google Play was easy. Configuring it, not that easy. The amount of useful error messages… close to zero.

I found:

  1. When I manually write the address to my other syncthing unit (like my NAS), only IP address works (with :port after it). Writing a domain name fails.
  2. When sharing a folder, I can not share a folder on the SD card: I get something like “Error (100%)”. To me, this is a pity, because I could put a big SD card (32-64GB) and have synchronised music there… but it seems not possible.

Update 2015-11-14: Upgraded to new syncthing version (0.12.2). Syncthing (for Android) now does not start properly. It just keeps “Loading”. No error message. No way to interact with it.