Except during live demos.
Tag: geek
Wow… just… wow.
Once in a while, I try and clean up the crap that’s been accumulating in my website. I just realized that I built my first website some time in 1998, if not before, and some traces of it still linger on the filesystem today – and also on the Wayback Machine.
The original homepage – circa 1998 – greeted you like this:
Welcome gentle reader.
A bit of background on this website:
In case you’re wondering what Karoshi means, let me inform you that it is a japanese expression meaning “death by overwork”. It’s fairly representative of the last few years of my life, moreso since I’ve started working towards my master’s degree. An interesting article on Karoshi can be found here
This web was setup primarily to showcase my the ever growing amount of pictures in my portfolio. In other parts of my web, you’ll also have a look at my bio and resume.
As a side note, the original title of the website was The Karoshi Archives – which I know now is in bad taste, but I was young and stupid at the time, and still used BLINK and MARQUEE tags and had ALT descriptions as “COOL SEPARATOR BAR”. Oy.
My DNA results are in…
… and I can confirm that I’m 100% human!
And given my French-Canadian lineage, I’m really not surprised about my genetic heritage being predominantly Northwestern-European (French, British, Irish, etc…)
Katy says that “this might explain the forehead”. Thank you, my love.
The good news is that there are no major health gremlins hiding in my DNA (with the usual caveats that they don’t check for everything), so that’s good. Some of the train reports that they provide also indicate that the findings need to be taken with a grain of salt:
Bald Spot – Likely no bald spot
Cilantro Taste Aversion – Slightly higher odds of disliking cilantro
Early Hair Loss – Likely no hair loss
Fear of Heights – Less likely than average to be afraid of heights
Finger Length Ratio – Likely ring finger longer
Hair Texture – Likely straight or wavy
Hair Thickness – Less likely to have thick hair
Light or Dark Hair – Likely light
Wake-Up Time – Likely to wake up around 7:46 am
The errors seem to be mainly centered around hair, weird. I also really like coriander.
Sequence me!
Optimized solution for periodic words
The previous solution I coded for the problem of finding words written in periodic element symbols didn’t sit well with me. It worked, but it was sub-optimal and was too rigid in how it tried to find matches. A more complete and elegant solution is below and will discover *all* possible variants of elements for a given word. At each position in the word, it uses both 1- and 2-letter elements and branches out. The initial recursion will generate many more incomplete/partial matches, but then the finalizing pass will recompose and flatten all paths through the graph and then cleanup after itself. This makes me happy.
When running this code, the results are:
Number of words found: 9092 // a 22% increase
Longest word: Internationalisation
I, N, Te, Rn, At, I, O, N, Al, I, S, At, I, O, N
In, Te, Rn, At, I, O, N, Al, I, S, At, I, O, N
I, N, Te, Rn, At, I, O, Na, Li, S, At, I, O, N
Longest word with unique variants: Bureaucratisation
B, U, Re, Au, Cr, At, I, S, At, I, O, N
B, U, Re, Au, C, Ra, Ti, S, At, I, O, N
Longest word with most variants: Consciousnesses
C, O, N, S, C, I, O, U, S, Ne, S, Se, S
C, O, N, S, C, I, O, U, S, Ne, S, S, Es
C, O, N, S, C, I, O, U, S, N, Es, Se, S
C, O, N, S, C, I, O, U, S, N, Es, S, Es
C, O, N, Sc, I, O, U, S, Ne, S, Se, S
C, O, N, Sc, I, O, U, S, Ne, S, S, Es
C, O, N, Sc, I, O, U, S, N, Es, Se, S
C, O, N, Sc, I, O, U, S, N, Es, S, Es
C, O, N, S, C, I, O, U, SN, Es, Se, S
C, O, N, S, C, I, O, U, SN, Es, S, Es
Co, N, S, C, I, O, U, S, Ne, S, Se, S
Co, N, S, C, I, O, U, S, Ne, S, S, Es
Co, N, S, C, I, O, U, S, N, Es, Se, S
Co, N, S, C, I, O, U, S, N, Es, S, Es
Longest word with most unique variants: Carbines
C, Ar, B, I, Ne, S
C, Ar, B, I, N, Es
Ca, Rb, I, Ne, S
Ca, Rb, I, N, Es
C, Ar, Bi, Ne, S
C, Ar, Bi, N, Es
C, Ar, B, In, Es
Elements that were never used in any word:
Bk, Cd, Cf, Cm, Fm, Gd, Hg, Md, Mg, Sg, Sr, Zn, Zr
import java.io.*; import java.util.*; public class PeriodicWordFinder { private TreeSet<String> words; private TreeSet<String> elements; private ArrayList<PeriodicWord> periodicWords; public PeriodicWordFinder() { try { words = read("wordlist.txt"); elements = new TreeSet<>((s1, s2) -> { int lenthComparison = Integer.compare(s1.length(), s2.length()); if (lenthComparison == 0) return s1.compareTo(s2); else return lenthComparison; }); elements.addAll(read("elements.txt")); periodicWords = new ArrayList<>(); System.out.println("words.size() = " + words.size()); System.out.println("elements.size() = " + elements.size()); } catch (Exception e) { e.printStackTrace(); } } private TreeSet<String> read(String fileName) throws Exception { TreeSet<String> retval = new TreeSet<>(); InputStream stream = getClass().getClassLoader().getResourceAsStream(fileName); BufferedReader in = new BufferedReader(new InputStreamReader(stream)); String line; while ((line = in.readLine()) != null) { line = line.toUpperCase().trim(); //no elements contain Q or J if (line.contains("Q") || line.contains("J")) { continue; } retval.add(line); } in.close(); return retval; } private void findWords() { for (String word : words) { PeriodicWord pWord = new PeriodicWord(word); if (periodicWord(1, pWord)) { periodicWords.add(pWord); } } //the new variant searcher algo will find partial/incomplete matches //this needs to be filtered out by the finalizeVariants method finalizeVariants(); for (PeriodicWord pWord : periodicWords) { System.out.println("found: " + pWord.getInitialWord()); } } private boolean periodicWord(long variantId, PeriodicWord word) { if (word.getWord(variantId).length() == 0) return true; /*COSEU -- 11 C -- 111 O -- 1111 S -- 11111 Eu -- 111 O -- 1112 Se -- 11121 U -- 112 Os -- 1121 Eu -- 12 Co -- 121 S -- 1211 Eu -- 122 Se -- 1221 U */ long ndx = 1; boolean matchFound = false; for (String element : elements) { if (word.getWord(variantId).startsWith(element)) { matchFound = true; long newVariantId = variantId * 10 + ndx++; String alreadyPresent = word.setElement(newVariantId, element); //if (alreadyPresent != null) { // System.err.println("Should not already be element " + alreadyPresent + // " at newVariantId " + variantId + " for word" + word.getInitialWord()); //} word.setWord(newVariantId, word.getWord(variantId).substring(element.length())); if (!periodicWord(newVariantId, word)) { //we found a partial match //it will be dealt with in finalize } } } return matchFound; } private void finalizeVariants() { for (Iterator<PeriodicWord> it = periodicWords.iterator(); it.hasNext(); ) { PeriodicWord pWord = it.next(); TreeMap<Long, String> elementVariants = pWord.getElementVariants(); boolean allFound = false; while (!allFound && !elementVariants.isEmpty()) { //start from the end of the collection and work your way backwards, //collapsing the paths in the graph String lastElement = elementVariants.lastEntry().getValue().toUpperCase(); if (pWord.getInitialWord().toUpperCase().endsWith(lastElement)) { //build a word List<String> elementVariant = buildVariant(elementVariants); //add last sanity check, check that you don't return a partial word String elVarStr = String.join("", elementVariant).toUpperCase(); if (pWord.getInitialWord().equals(elVarStr)) { pWord.addElementWordVariant(elementVariant); } //remove tail of collection and continue elementVariants.remove(elementVariants.lastKey()); } else { //all words found, stop loop allFound = true; } } //if only partial words were mapped - no full words - remove as invalid if (pWord.elementWordVariants.isEmpty()) { it.remove(); } } } private List<String> buildVariant(TreeMap<Long, String> elementVariants) { /*COSEU -- 11 C -- 111 O -- 1111 S -- 11111 Eu -- 111 O -- 1112 Se -- 11121 U -- 112 Os -- 1121 Eu -- 12 Co -- 121 S -- 1211 Eu -- 122 Se -- 1221 U */ List<String> retval = new ArrayList<>(); boolean done = false; long key = elementVariants.lastKey(); while (!done) { String val = elementVariants.get(key); if (val != null) { retval.add(0, val); } else { done = true; } key = key / 10; } return retval; } public List<PeriodicWord> getPeriodicWords() { return periodicWords; } public Set<String> getElements() { return elements; } public static void main(String[] args) { PeriodicWordFinder ew = new PeriodicWordFinder(); ew.findWords(); //now we have fun List<PeriodicWord> pWords = ew.getPeriodicWords(); System.out.println("Number of words found: " + pWords.size()); //longest word pWords.sort((o1, o2) -> Integer.compare(o1.getInitialWord().length(), o2.getInitialWord().length())); System.out.println("Longest word: " + pWords.get(pWords.size() - 1)); //longest word with only unique elements pWords.sort((o1, o2) -> { String s1 = String.join("", o1.getVariantWithMostElements(true)); String s2 = String.join("", o2.getVariantWithMostElements(true)); int lenthComparison = Integer.compare(s1.length(), s2.length()); if (lenthComparison == 0) return s1.compareTo(s2); else return lenthComparison; }); System.out.println("Longest word with unique variants: " + pWords.get(pWords.size() - 1)); //longest word with with most variants pWords.sort((o1, o2) -> { int numberComparison = Integer.compare(o1.getNumberOfVariants(false), o2.getNumberOfVariants(false)); if (numberComparison == 0) { int lenthComparison = Integer.compare(o1.getInitialWord().length(), o2.getInitialWord().length()); if (lenthComparison == 0) return o1.getInitialWord().compareTo(o2.getInitialWord()); else return lenthComparison; } else { return numberComparison; } }); System.out.println("Longest word with most variants: " + pWords.get(pWords.size() - 1)); //longest word with most unique variants pWords.sort((o1, o2) -> { int numberComparison = Integer.compare(o1.getNumberOfVariants(true), o2.getNumberOfVariants(true)); if (numberComparison == 0) { int lenthComparison = Integer.compare(o1.getInitialWord().length(), o2.getInitialWord().length()); if (lenthComparison == 0) return o1.getInitialWord().compareTo(o2.getInitialWord()); else return lenthComparison; } else { return numberComparison; } }); System.out.println("Longest word with most unique variants: " + pWords.get(pWords.size() - 1)); //is there any element that was not used? TreeSet<String> elements = new TreeSet<>(ew.getElements()); for(PeriodicWord pWord : pWords){ for (List<String> variantElements : pWord.elementWordVariants ){ elements.removeAll(variantElements); if (elements.isEmpty()){ break; } } } System.out.println("Elements not used: " + elements); } private class PeriodicWord { private TreeMap<Long, String> wordVariants; //will get mangled during recursion private String initialWord; //keep track of initial word private TreeMap<Long, String> elementVariants; //will get updated during recursion private List<List<String>> elementWordVariants; public int getNumberOfVariants(boolean onlyUnique) { List<List<String>> sorted = new ArrayList<>(); sorted.addAll(elementWordVariants); if (onlyUnique) { sorted.removeIf(this::containsDuplicateElements); } return sorted.size(); } public List<String> getVariantWithMostElements(boolean onlyUnique) { if (elementWordVariants.size() == 1) { return elementWordVariants.get(0); } else { List<List<String>> sorted = new ArrayList<>(); sorted.addAll(elementWordVariants); if (onlyUnique) { sorted.removeIf(this::containsDuplicateElements); } sorted.sort((o1, o2) -> Integer.compare(o1.size(), o2.size())); if (sorted.size() > 0) { return sorted.get(sorted.size() - 1); } else { return new ArrayList<>(); } } } private boolean containsDuplicateElements(List<String> elementVariant) { return new HashSet<>(elementVariant).size() != elementVariant.size(); } public PeriodicWord(String word) { initialWord = word; elementVariants = new TreeMap<>(); wordVariants = new TreeMap<>(); wordVariants.put(1l, word); elementWordVariants = new ArrayList<>(); } public void setWord(long variantId, String word) { wordVariants.put(variantId, word); } public TreeMap<Long, String> getElementVariants() { return elementVariants; } public String getWord(long variantId) { return wordVariants.get(variantId); } public String setElement(long variantId, String element) { return elementVariants.put(variantId, element); } public String getInitialWord() { return initialWord; } public void addElementWordVariant(List<String> elementWordVariant) { elementWordVariants.add(elementWordVariant); } @Override public String toString() { return "PeriodicWord{" + "initialWord='" + initialWord + '\'' + ", elementWordVariants=" + elementWordVariants + '}'; } } }
Words written in Periodic Table elements
This is how my brain works.
This morning, on my way to work, I remembered a t-shirt from a TV show we’re currently binging on with the word “sarcasm” written using element symbols from the periodic table:
I then started to wondered about how I would go about finding all the words that would be written using element symbols. So when I got into work, I quickly hacked this together. Out of a starting word set of 58109 words, I find 7417 “periodic” words. The longest word, and one of several with the most component elements (13) is:
Internationalisation, elements=In,Te,Rn,At,I,O,Na,Li,S,At,I,O,N
Other amusing ones are:
Inarticulateness, elements=In,Ar,Ti,Cu,La,Te,Ne,S,S
Supersaturation, elements=S,U,P,Er,S,At,U,Ra,Ti,O,N
Consciousnesses, elements=CO,N,Sc,I,O,U,Sn,Es,Se,S
Procrastination, elements=Pr,O,Cr,As,Ti,Na,Ti,O,N
Hyperinflation, elements=H,Y,P,Er,In,F,La,Ti,O,N
Falsification, elements=F,Al,Si,F,I,Ca,Ti,O,N,S
Perniciousness, elements=P,Er,Ni,C,I,O,U,Sn,Es,S
Perambulations, elements=P,Er,Am,B,U,La,Ti,O,N,S
Pontifications, elements=Po,N,Ti,F,I,Ca,Ti,O,N,S
Hallucinations, elements=H,Al,Lu,C,In,At,I,O,N,S
Voluptuousness, elements=V,O,Lu,Pt,U,O,U,Sn,Es,S
Sensationalism, elements=Se,N,S,At,I,O,Na,Li,Sm
And many, many more.
I then added a little tweak to filter out words that use repetitions of elements, and that brings down the number of “periodic” words to 5483. In that case, the longest word, and one of several with the most component elements (10) is:
Reclassification, elements=Re,Cl,As,Si,F,I,Ca,Ti,O,N
package wordlist; import java.io.*; import java.util.*; public class PeriodicWordFinder { private TreeSet<String> words; private TreeSet<String> elements; private ArrayList<PeriodicWord> periodicWords; public PeriodicWordFinder() { init(); } private void init(){ try{ words = read("wordlist.txt"); elements = new TreeSet<>(new AlphaLengthComparaator()); elements.addAll(read("elements.txt")); periodicWords = new ArrayList<>(); System.out.println("words.size() = " + words.size()); System.out.println("elements.size() = " + elements.size()); } catch (Exception e) { e.printStackTrace(); } } private TreeSet<String> read(String fileName) throws Exception{ TreeSet<String> retval = new TreeSet<>(); InputStream stream = getClass().getClassLoader().getResourceAsStream(fileName); BufferedReader in = new BufferedReader(new InputStreamReader(stream)); String line; while ((line = in.readLine()) != null){ line = line.toUpperCase().trim(); //no elements contain Q or J if (line.contains("Q") || line.contains("J")){ continue; } retval.add(line); } in.close(); return retval; } private void findWords(boolean onlyUniqueElements) { for(String word : words){ PeriodicWord pWord = new PeriodicWord(word); if ( periodicWord(pWord) ){ //if the word only contains unique instances of elements, or we don't care if (checkUniqueElements(pWord) || !onlyUniqueElements) { System.out.println("found: " + pWord); periodicWords.add(pWord); } } } } private boolean periodicWord(PeriodicWord word) { if (word.getWord().length() == 0) return true; for (String element : elements){ if (word.getWord().startsWith(element)){ word.getElements().add(element); word.setWord(word.getWord().substring(element.length())); return periodicWord(word); } } return false; } private boolean checkUniqueElements(PeriodicWord pWord) { //if elements are duplicated, size of hashset will be different than size of original list return (pWord.getElements().size() == new HashSet<>(pWord.getElements()).size()); } public static void main(String[] args){ PeriodicWordFinder ew = new PeriodicWordFinder(); ew.findWords(true); } private class AlphaLengthComparaator implements Comparator<String>{ @Override public int compare(String o1, String o2) { Integer l1 = o1.length(); Integer l2 = o2.length(); int lengthComparison = l1.compareTo(l2); if (lengthComparison == 0){ return o1.compareTo(o2); } else { return l1.compareTo(l2)*-1; } } } private class PeriodicWord { private String word; //will get mangled during recursion private String initialWord; //keep track of initial word private ArrayList<String> elements; //will get updated during recursion public PeriodicWord(String word) { this.initialWord = word; this.word = word; } public void setWord(String word) { this.word = word; } public String getWord() { return word; } public ArrayList<String> getElements() { if (elements == null) elements = new ArrayList<>(); return elements; } @Override public String toString() { return initialWord +", elements=" + String.join(",", elements); } } }
Katy will tell you I have smartphone syndrome
The struggle is real
I foresee unforeseen problems
Browsing a website on your phone in 2018
Okay, I’ll accept cookies.
Yeah, okay, I’ll disable my adblocker.
No, I don’t want to sign up for your newsletter.
No, I don’t want to sign in with Facebook.
No, I don’t want push notifications.
No, I don’t want to bookmark your site.
No, don’t allow location services.
OMG why is my phone buzzing constantly.
Franticly mute sound for autoplay videos.
Close popup ad tab.
Read 3 paragraph article split over 15-page slideshow.
Close tab.
Close previously missed popunder ad tab.