Anil Madhavapeddy, Jason Hickey, Yaron Minsky: Real World OCaml



book cover white Around a month ago I’ve started playing around Reason and for understanding it better I decided to read something about OCaml and chose Real World OCaml by Anil Madhavapeddy, Jason Hickey, and Yaron Minsky. The book explains OCaml syntax, core library, different aspects of language and how to write FP and OOP code in OCaml. The book has a lot of examples and easy to read, not that much repetitive as a lot of books about programming languages.

Although before reading the book I thought that OCaml isn’t that much over-bloated and is a better language, especially it’s syntax. It helped me to better understand concepts and ideas behind Reason.

Don Norman: The Design of Everyday Things



book cover Recently I wanted to read something about UI and UX and I was recommended to read The Design of Everyday Things by Don Norman. Even I’m not a UI/UX specialist at all, it’s one of the most interesting books I’ve read lately. It contains a lot of real-life examples with deep explanations why something is done wrongly and poorly, and it has points and ideas how to make it better.

Although the book is a bit repetitive.

James Turnbull: The Logstash Book



book cover white As I have an interest in monitoring and logging, I decided to read The Logstash Book by James Turnbull. And it’s kind of a nice book, with examples and explanations about working with Logstash and ELK stack. Also, it contains information about the ways to extend Logstash with plugins, even a few pages about writing plugins on your own.

From the other side, the book is a bit too basic and a lot of it is primitive information about deploying Logstash and related stack.

Jason Dixon: Monitoring with Graphite



book cover white Recently I wanted to read something about Graphite and monitoring in general, as I sometimes need to interact with it. And I’ve found Monitoring with Graphite by Jason Dixon and read it. It’s kind of a nice book with history, explanation of the architecture and use cases of Graphite. It’s not that long and easy to read.

Can contain a bit less information of Graphite’s ugly interface though.

Tom White: Hadoop: The Definitive Guide



book cover Around a month ago I’ve started working with Hadoop, so I decided that I need to read something about it, and chose Hadoop: The Definitive Guide by Tom White that I already had from the Humble Book Bundle. The book contains a lot of information about Hadoop internals and related stack with use cases and examples. And I guess there are too much huge code samples with all boilerplate. And too many pages are like some option – description, there’s already the documentation for things like that.

But overall the book is good. After reading it I feel way more confident with Hadoop.

Christmas lights on MacBook TouchBar



MacBook TouchBar is almost useless, so I decided to put Christmas lights on it. And apparently it was very easy. Electron has very simple API for TouchBar.

As Christmas lights should have distinctive colors, I hardcoded just seven of them:

const colors = [
    '#ff0000',
    '#00ff00',
    '#0000ff',
    '#ffff00',
    '#ff00ff',
    '#00ffff',
    '#ffffff',
];

And as only one colorable element in electron API is TouchBarButton, and there’s space for only eight buttons on the TouchBar, I generated them with defined colors:

const count = 8;

const lights = [];
for (let i = 0; i < count; i++) {
    lights.push(
        new TouchBarButton({
            backgroundColor: colors[i * 3 % colors.length],
        })
    );
}

Centered them with an ugly hack with TouchBarLabel:

const touchBar = new TouchBar([
    new TouchBarLabel({label: "      "}),
    ...lights,
]);

Assigned TouchBar to a dummy electron app:

app.once('ready', () => {
  window = new BrowserWindow({
    frame: false,
    titleBarStyle: 'hiddenInset',
    width: 300,
    height: 100,
  });
  window.loadURL('javascript:document.write("<br><h1>Christmas lights!!!</h1>")');
  window.setTouchBar(touchBar);
});

The last part is the logic of the lights. I made it very simple, every five milliseconds I’m increasing tick and updating colors of buttons with number have the same modulo of three as the tick:

const interval = 500;

let tick = 0;
setInterval(() => {
    for (let i = 0; i < count; i++) {
        if (i % 3 === tick % 3) {
            let index = colors.indexOf(lights[i].backgroundColor);
            index += 1;
            if (index >= colors.length) {
                index = 0;
            }

            lights[i].backgroundColor = colors[index];
        }
    }

    tick++;
}, interval);

By the end I just run the script with electron and got semi-nice Christmas lights and kind of Christmas spirit:

electron macbook_touchbar_christmas_lights.js

Gist with sources.

Make KissCartoon usable with Chromecast



KissCartoon is a nice place to watch cartoons, but it’s not usable with Chromecast at all. It doesn’t play next episode automatically. But it’s very easy to fix with a small Chrome extension. TLDR: Castable KissCartoon.

So how it works?

When you open a page with a player, it’s starting to listen for an ended event:

const enableAutoplay = (player) => player.addEventListener('ended', () => {
  window.localStorage.setItem('autoPlayingBefore', location.href);
  document.getElementById('btnNext').click();
}, false);

When the event emits, it puts current URL in localStorage and clicks next button. After the next page is loaded, it ensures that the previous page is the page with the previous episode:

const isContinuingPlaying = () => {
  const previous = window.localStorage.getItem('autoPlayingBefore');
  window.localStorage.removeItem('autoPlayingBefore');

  const [previousBtn] = document.getElementsByClassName('preev');

  return previousBtn.href === previous;
};

If the extension is sure that we on the page with the next episode, it toggles fullscreen. But we can’t actually toggle fullscreen, it’s not possible to call requestFullscreen because it can be called only from a callback initiated by a user event. So the extension uses a little hack. It dims other elements on the page and expands the player by setting position: fixed. And it works well with Chromecast, the player fills the whole TV.

const enableFullscreen = (player) => {
  const offlight = document.getElementById('offlight');
  player.style.setProperty('position', 'fixed');
  offlight.click();

  let isExited = false;
  document.addEventListener('keyup', ({keyCode}) => {
    if (keyCode === 27 && !isExited) {
      player.style.setProperty('position', '');
      offlight.click();
      isExited = true;
    }
  });
};

And that’s all! Source code, Chrome extension.

Loading/progress indicator for shell with aging emojis



Recently, while waiting for a long-running script to finish, I thought that it would be nice to have some sort of loader with aging emojis. TLDR: we-are-waiting.

The “life” of an emoji is simple:

👶🏿 → 👧🏿 → 👩🏿 → 👱🏿‍♀️ → 👩🏿‍⚕️ → 👵🏿

It contains aging from a baby to grown-up person, one profession, and oldness.

And as we have four colors, two genders, five ages, and 22 professions. We can have a great variety of lives. So as the first thing to do I decided to generate all those variants. Initially, I was planning to implement everything in Go, but it’s not possible to use emojis in Go code, only codepoints. Because of that, I decided to write a little Python script, that will generate Go code with all variants with codepoints instead of emojis.

For that I just copied lines with emojis from getemoji.com and put them in lists:

ages = [
    "👶 👦 👧 👨 👩 👱‍♀️ 👱 👴 👵",
    "👶🏻 👦🏻 👧🏻 👨🏻 👩🏻 👱🏻‍♀️ 👱🏻 👴🏻 👵🏻",
    "👶🏼 👦🏼 👧🏼 👨🏼 👩🏼 👱🏼‍♀️ 👱🏼 👴🏼 👵🏼",
    "👶🏽 👦🏽 👧🏽 👨🏽 👩🏽 👱🏽‍♀️ 👱🏽 👴🏽 👵🏽",
    "👶🏾 👦🏾 👧🏾 👨🏾 👩🏾 👱🏾‍♀️ 👱🏾 👴🏾 👵🏾",
    "👶🏿 👦🏿 👧🏿 👨🏿 👩🏿 👱🏿‍♀️ 👱🏿 👴🏿 👵🏿",
]
ages = [x.split(' ') for x in ages]

roles = [
    "👮‍♀️ 👮 👷‍♀️ 👷 💂‍♀️ 💂 🕵️‍♀️ 🕵️ 👩‍⚕️ 👨‍⚕️ 👩‍🌾 👨‍🌾 👩‍🍳 👨‍🍳 👩‍🎓 👨‍🎓 👩‍🎤 👨‍🎤 👩‍🏫 👨‍🏫 👩‍🏭 👨‍🏭 👩‍💻 👨‍💻 👩‍💼 👨‍💼 👩‍🔧 👨‍🔧 👩‍🔬 👨‍🔬 👩‍🎨 👨‍🎨 👩‍🚒 👨‍🚒 👩‍✈️ 👨‍✈️ 👩‍🚀 👨‍🚀 👩‍⚖️ 👨‍⚖️ 🤶 🎅 👸 🤴",
    "👮🏻‍♀️ 👮🏻 👷🏻‍♀️ 👷🏻 💂🏻‍♀️ 💂🏻 🕵🏻‍♀️ 🕵🏻 👩🏻‍⚕️ 👨🏻‍⚕️ 👩🏻‍🌾 👨🏻‍🌾 👩🏻‍🍳 👨🏻‍🍳 👩🏻‍🎓 👨🏻‍🎓 👩🏻‍🎤 👨🏻‍🎤 👩🏻‍🏫 👨🏻‍🏫 👩🏻‍🏭 👨🏻‍🏭 👩🏻‍💻 👨🏻‍💻 👩🏻‍💼 👨🏻‍💼 👩🏻‍🔧 👨🏻‍🔧 👩🏻‍🔬 👨🏻‍🔬 👩🏻‍🎨 👨🏻‍🎨 👩🏻‍🚒 👨🏻‍🚒 👩🏻‍✈️ 👨🏻‍✈️ 👩🏻‍🚀 👨🏻‍🚀 👩🏻‍⚖️ 👨🏻‍⚖️ 🤶🏻 🎅🏻 👸🏻 🤴🏻",
    "👮🏼‍♀️ 👮🏼 👷🏼‍♀️ 👷🏼 💂🏼‍♀️ 💂🏼 🕵🏼‍♀️ 🕵🏼 👩🏼‍⚕️ 👨🏼‍⚕️ 👩🏼‍🌾 👨🏼‍🌾 👩🏼‍🍳 👨🏼‍🍳 👩🏼‍🎓 👨🏼‍🎓 👩🏼‍🎤 👨🏼‍🎤 👩🏼‍🏫 👨🏼‍🏫 👩🏼‍🏭 👨🏼‍🏭 👩🏼‍💻 👨🏼‍💻 👩🏼‍💼 👨🏼‍💼 👩🏼‍🔧 👨🏼‍🔧 👩🏼‍🔬 👨🏼‍🔬 👩🏼‍🎨 👨🏼‍🎨 👩🏼‍🚒 👨🏼‍🚒 👩🏼‍✈️ 👨🏼‍✈️ 👩🏼‍🚀 👨🏼‍🚀 👩🏼‍⚖️ 👨🏼‍⚖️ 🤶🏼 🎅🏼 👸🏼 🤴🏼",
    "👮🏽‍♀️ 👮🏽 👷🏽‍♀️ 👷🏽 💂🏽‍♀️ 💂🏽 🕵🏽‍♀️ 🕵🏽 👩🏽‍⚕️ 👨🏽‍⚕️ 👩🏽‍🌾 👨🏽‍🌾 👩🏽‍🍳 👨🏽‍🍳 👩🏽‍🎓 👨🏽‍🎓 👩🏽‍🎤 👨🏽‍🎤 👩🏽‍🏫 👨🏽‍🏫 👩🏽‍🏭 👨🏽‍🏭 👩🏽‍💻 👨🏽‍💻 👩🏽‍💼 👨🏽‍💼 👩🏽‍🔧 👨🏽‍🔧 👩🏽‍🔬 👨🏽‍🔬 👩🏽‍🎨 👨🏽‍🎨 👩🏽‍🚒 👨🏽‍🚒 👩🏽‍✈️ 👨🏽‍✈️ 👩🏽‍🚀 👨🏽‍🚀 👩🏽‍⚖️ 👨🏽‍⚖️ 🤶🏽 🎅🏽 👸🏽 🤴🏽",
    "👮🏾‍♀️ 👮🏾 👷🏾‍♀️ 👷🏾 💂🏾‍♀️ 💂🏾 🕵🏾‍♀️ 🕵🏾 👩🏾‍⚕️ 👨🏾‍⚕️ 👩🏾‍🌾 👨🏾‍🌾 👩🏾‍🍳 👨🏾‍🍳 👩🏾‍🎓 👨🏾‍🎓 👩🏾‍🎤 👨🏾‍🎤 👩🏾‍🏫 👨🏾‍🏫 👩🏾‍🏭 👨🏾‍🏭 👩🏾‍💻 👨🏾‍💻 👩🏾‍💼 👨🏾‍💼 👩🏾‍🔧 👨🏾‍🔧 👩🏾‍🔬 👨🏾‍🔬 👩🏾‍🎨 👨🏾‍🎨 👩🏾‍🚒 👨🏾‍🚒 👩🏾‍✈️ 👨🏾‍✈️ 👩🏾‍🚀 👨🏾‍🚀 👩🏾‍⚖️ 👨🏾‍⚖️ 🤶🏾 🎅🏾 👸🏾 🤴🏾",
    "👮🏿‍♀️ 👮🏿 👷🏿‍♀️ 👷🏿 💂🏿‍♀️ 💂🏿 🕵🏿‍♀️ 🕵🏿 👩🏿‍⚕️ 👨🏿‍⚕️ 👩🏿‍🌾 👨🏿‍🌾 👩🏿‍🍳 👨🏿‍🍳 👩🏿‍🎓 👨🏿‍🎓 👩🏿‍🎤 👨🏿‍🎤 👩🏿‍🏫 👨🏿‍🏫 👩🏿‍🏭 👨🏿‍🏭 👩🏿‍💻 👨🏿‍💻 👩🏿‍💼 👨🏿‍💼 👩🏿‍🔧 👨🏿‍🔧 👩🏿‍🔬 👨🏿‍🔬 👩🏿‍🎨 👨🏿‍🎨 👩🏿‍🚒 👨🏿‍🚒 👩🏿‍✈️ 👨🏿‍✈️ 👩🏿‍🚀 👨🏿‍🚀 👩🏿‍⚖️ 👨🏿‍⚖️ 🤶🏿 🎅🏿 👸🏿 🤴🏿",
]
roles = [x.split(' ') for x in roles]

As emojis have a strange order, generation of all variants is a bit tricky, but it’s easier than rearranging them in code because my editor doesn’t work quite well with emojis:

def get_life(color, gender, role):
    yield ages[color][0]
    yield ages[color][1 + gender]
    yield ages[color][3 + gender]
    yield ages[color][6 - gender]
    yield roles[color][role * 2 + 1 - gender]
    yield ages[color][7 + gender]
>>> list(get_life(0, 0, 0))
['👶', '👦', '👨', '👱', '👮', '👴']
def get_variants():
    for color in range(len(ages)):
        for gender in (0, 1):
            for role in range(len(roles[0]) // 2):
                yield color, gender, role
>>> list(get_life(*list(get_variants())[23]))
['👶', '👧', '👩', '👱\u200d♀️', '👷\u200d♀️', '👵']

And after that it’s very easy to generate Go package with all possible variants:

code = b'package variants\n\nvar All = [][]string{\n'

for variant in get_variants():
    code += b'\t{\n'
    for emoji in get_life(*variant):
        code += b'\t\t"' + emoji.encode('unicode-escape') + b'",\n'
    code += b'\t},\n'

code += b'}\n'

with open('variants/variants.go', 'wb') as f:
    f.write(code)

So we’ll have something like this in variants/variants.go:

package variants

var All = [][]string{
	{
		"\U0001f476",
		"\U0001f466",
		"\U0001f468",
		"\U0001f471",
		"\U0001f46e",
		"\U0001f474",
	},
	...
}

The logic of the loader isn’t that interesting, although I want to highlight some moments. At the high level we just read lines from a pipe, if there’s no new line arrived before tick seconds, we update our emojis:

func main() {
        ...
        go watchApp(lines)
        
        for {
            select {
            case line, isOpen := <-lines:
                ...
                os.Stdout.WriteString(line)
                ...
                printPeople(people)
            case <-time.After(time.Duration(*tick) * time.Second):
                people = updatePeople(people, *count)
                printPeople(people)
            }
        }
}

While updating, we can add new emoji, make one emoji older or “kill” the oldest:

func updatePeople(people []*human, count int) []*human {
	addNew := rand.Intn(5) == 0
	toMakeOlder := canMakeOlder(people)

	if addNew || len(toMakeOlder) == 0 {
		people = append(people, getRandomHuman())
	} else {
		index := toMakeOlder[rand.Intn(len(toMakeOlder))]
		people[index].position += 1
	}

	if len(people) > count {
		oldest := getOldest(people)
		return append(people[:oldest], people[oldest+1:]...)
	} else {
		return people
	}
}

And that’s all. You can find the source code on GitHub.

Mark Jason Dominus: Higher-Order Perl



book cover As I sometimes use Perl, I decided to read something about it. And Higher-Order Perl by Mark Jason Dominus was looking interesting. The book is really nice, it shows that Perl can be kind of a functional programming language and that it’s possible to implement almost every feature from other languages in Perl. Also, after reading the book, I think there’s copious amount of ways to shot yourself in the leg in Perl.

The problems in the book are interesting and a bit challenging, so I think it can be worth reading even for people who don’t work with Perl.

Soundlights with ESP8266 and NeoPixel Strip



About a year ago I made soundlights with Raspberry Pi. But RPI is a bit of an overkill for this simple task and it’s quite big, doesn’t have WiFi out of the box and practically can’t be used without a power adapter.

So I decided to port soundlights to ESP8266. The main idea was to reuse as much as possible from the previous implementation, so the parts with patched audio visualizer and colors generation are the same. In a few words, I’ve patched cava to print numbers instead of showing pretty bars in a terminal. And I’ve generated colors with a code found on Quora.

And in current implementation I decided to make it very simple to use, the only requirement is to have a machine with cava and ESP8266 on the same WiFi network. So I chose UDP broadcasting as a way to send data to ESP8266. And because there’s just 60 LEDs and color of a LED is three values from 0 to 255, colors for all strip is just 180 bytes. So it fits in one UDP packet.

Let’s start with the part with cava:

import sys
import socket
import array


COLORS_COUNT = 256
COLORS_OFFSET = 50


def get_spaced_colors(n):
    max_value = 16581375
    interval = int(max_value / n)
    colors = [hex(i)[2:].zfill(6) for i in range(0, max_value, interval)]

    return [(int(color[:2], 16),
             int(color[2:4], 16),
             int(color[4:6], 16)) for color in colors]


def send(colors):
    line = array.array('B', colors).tostring()
    sock.sendto(line, ('255.255.255.255', 42424))


sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)

colors = get_spaced_colors(COLORS_COUNT)

while True:
    try:
        nums = map(int, sys.stdin.readline()[:-1].split())
        led_colors = [c for num in nums for c in colors[num]]
        send(led_colors)
    except Exception as e:
        print(e)

It can be used like:

unbuffer ./cava -p soundlights/cava_config | python cava/soundlights/esp/client.py

And it just reads numbers from cava output, generates colors, transforms them to bytes and broadcasts them at 42424 port.

The ESP8266 part is even simpler:

import socket
import machine
import neopixel


np = neopixel.NeoPixel(machine.Pin(5), 60)
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.bind(('', 42424))


while True:
    line, _ = sock.recvfrom(180)

    if len(line) < 180:
        continue

    for i in range(60):
        np[i] = (line[i * 3], line[i * 3 + 1], line[i * 3 + 2])

    np.write()

It just receives broadcasts from 42424 port and changes colors of LEDs.

At the end, this version has less code and just works. It’s even some sort of IoT and with some effort can become a wearable device.

Github.