Skip to main content

Navigating Strikes While Living In Greece

This post is part of the Into The Past series. A list of posts written long after they happened as part of an attempt to look back at some earlier creations and thoughts I had along the way. This post was written April 2024.

Απεργίες (Apergíes) #

Sometimes it's the public transportation, sometimes it's the public office. Even othertimes it can be waste collection. Strikes in the public sector in Greece was widespread at the time I was living there, and navigating this kind of environment can be unpredictable. At least when you have low chances of knowing about a strike in advance.

There existed already at the time a Greek service called Strike, https://apergia.gr, which would act as a one point stop for information about upcoming strikes as well as an actively maintained calendar for future events. But this was all Greek to me. Quite literally since they had no English translation.

Greek Strikes - Strikes in Athens #

Hanging around waiting for a bus that would never arrive, or standing in line for a train that would at best depart on a very delayed scheduled was not at all uncommon. So what else can one do, other than take it upon themselves to make things more accessible and stay updated.

Greek Strikes app loading page Greek Strikes app no strikes found Greek Strikes app strike details not translated

Built using NativeScript, this was a fairly simple Android app which at the time was released on Google Play store. But as one would notice, the app no longer lives and the store page no longer exists.

While the original APK can no longer be downloaded, APKCombo.com (web.archive.org alternative) has archived the app store page which gives a small glimpse in the past that once was. Even rebuilding from source no longer works - the endpoint used to scrape data has been shut down and the Microsoft Cognitive API has been rebranded with their more AI focused line of products.

Fetching strikes from Apergia was a fairly straight forward matter

function GetStrikes () {
	this.fetch = function(){
        let strike_arr = [];
        let url = "http://apergia.gr/q/";

        return fetch(url, {
            headers: {
                "Accept":"text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8",
                "Cache-Control":"max-age=0"
            }
        })
        .then(/* handle http errors */)
        .then(function(response) {
            return response.text();
        })
        .then(function(text) {

            // Replace all line breaks with whitespace
            let str = text.replace(/\r?\n|\r/g, "");

            let days = str.match(/<h2>(.*?)<\/h2>/g);
            let strikes = str.match(/<ul>(.*?)<\/ul>/g);

            // strip out html h2 and add days
            for (var i = 0; i < days.length; i++) {
                strike_arr.push([days[i].substring(days[i].indexOf(',')+2, days[i].length-5), []]);

                let single_d = strikes[i].match(/<li>(.*?)<\/li>/g);

                // Add all registered strikes after day
                for (var j = 0; j < single_d.length; j++) {
                    strike_arr[i][1].push(single_d[j].substring(4, single_d[j].length-5));
                }
            }

            return strike_arr;
        })
        .catch((e) => {
            // Error handling
        });
    }
	
	return this;
}

Commented for your convenience, this method would return a multidimensional array with dates and strike details for two days.

Translating texts on request was done by using the free tier of Microsoft Cognitive Service. Meaning, first come first serve as it had an upper limit to how many translations were allowed per month. I never expected this app to be used widespread and I trust my beliefs about unscalable solutions that I share with Paul Graham, so I figured this was quite enough to start off with.

const host = 'https://api.cognitive.microsofttranslator.com';
const path = '/translate?api-version=3.0';
const SUBSCRIPTION_KEY = '...';

function Translate () {
    this.getTranslation = function (from, to, text) {
        let params = '&from=' + from + '&to=' + to;
        let content = JSON.stringify ([{'Text' : text}]);
        let url = host + path + params;

        return fetch(url, {
            method: 'POST',
            headers: {
                'Content-Type' : 'application/json',
                'Ocp-Apim-Subscription-Key' : SUBSCRIPTION_KEY,
            },
            body: content
        })
        .then(/* handle http errors */)
        .then(function(response) {
            return response.json();
        })
        .catch((e) => {
            // Error handling
        });
    }
    return this;
}

The above snippet was built directly into the app. Yes, that does indeed leave room for some heavy abuse, but I'll let you figure that one out on your own. For me the keywords here were still unscalability, convenience and release first, think later.