node.js TiddlyWiki to Joplin

Migrating from TiddlyWiki to Joplin

I wanted to migrate my data from TiddlyWiki to Joplin. This documents how I got there. You will not like the results if you follow my steps exactly. You may find this document helpful if you use it as a guide in creating your own migration process.

My Setup:

  • I use the “anstosa” plugin for Markdown tiddler markup. (David Alfonso’s conversion uses the official Markdown plugin, not anstosa. They implement Markdown subsets.)
  • Most of my tiddlers are in Markdown.
  • My wikis are all run via node.js on a Linux box. This is named “boxtop3”.
  • My Joplin target will run on a Macbook.
  • I have about 2000 tiddlers.
  • I have lots of wiki links (intra-TiddlyWiki links). David’s conversion does not deal with these, leaving broken links when imported into Joplin. I fixed these with code (see below).
  • I have two TiddlyWikis. One is named PKB and the other DTL.

See this: https://davidalfonso.es/posts/migrating-from-tiddlywiki-to-markdown-files and this: https://gitlab.com/davidalfonso/tiddlywiki-migrator/tree/master

WARNINGS:

  • This process does not convert all legal Markdown. To do that, you’d have to fully parse the source files. The conversion does only string matching, so there are some edge cases where you have to just fix the source tiddlers to avoid.
  • This process does not deal with multiple stories having the same name. e.g. If you import TWO TiddlyWikis and each has a story called My Story, and there are wiki links to My Story, there’s no telling which of the two My Story your links will point to in Joplin. (This is not a problem for TiddlyWiki because wiki links point within the same wiki. It is a problem for Joplin because wiki-links are within Joplin, not within notebook.)
    • After you load Joplin, you can use “DB Browser for SQLite” to run this query to report on your duplicates:
select title,  count(*) from notes group by title having count(*) > 1  
and title != "DefaultTiddlers"
and title != "MarkupPreHead"
and title != "PageTemplate"

Preparing to Convert

  • (Optional:) Using TiddlyWiki in your browser, manually converted any remaining non-Markdown tiddlers to Markdown format.
    • This is a useful filter search to find Markdown tiddlers: [!field:type[text/x-markdown]!prefix[$:]!tag[OkNotMd]]
    • Except (You can tag these as OkNotMd):
      • AdvancedOptions
      • Configure Tiddler Subtitle
      • DefaultTiddlers
      • … and similar tiddlers which contain code or TW options.
    • The manual conversion to Markdown works for one of my TW where most tiddlers are Markdown, but I have an older wiki using TiddlyWiki markup: 4 are type text/vnd.tiddlywiki; 755 are type text/x-tiddlywiki; 90 are text/x-markdown.
    • For the old wiki, I manually convert text/vnd.tiddlywiki to Markdown.
  • I edited my tiddlers to remove all apostrophe and quote marks from tiddler titles. Take my word for it. You want to do this.

Converting

  • Download https://gitlab.com/davidalfonso/tiddlywiki-migrator/tree/master and unzip on your node.js server as ~/tiddlywiki-migrator
  • using the TW save button, save PKB to temp and move it to ~/tiddlywiki-migrator/wiki.html
  • Look in ~/tiddlywiki-migrator/node_modules/tiddlywiki/plugins/tiddlywiki/markdown/files/markdown.js
    • See (around line 395): jsonml.unshift.apply( jsonml, this.processBlock( m[ 1 ], [] ) );
    • That line is fragile about “——” (HR) in your tiddlers without a blank line before. you might want to make the code near there look like this in order to find bad tiddlers so you can manually fix them. See https://github.com/evilstreak/markdown-js/issues/17
      // if there's a leading abutting block, process it
      if ( m[ 1 ] ) {
        console.log('m1');
        console.log(m[1]);
        console.log('block');
        console.log(block);
        jsonml.unshift.apply( jsonml, this.processBlock( m[ 1 ], [] ) );
      }
  • The work-around is to edit any offending tiddlers to ensure ----- has a blank line before and after.
  • I prefer my file names to match the Tiddler titles. Edit scripts/safe-rename.js and make it look like this:
const fs = require('fs');
  
if (process.argv.length != 3) {
    console.log("Wrong parameters. Directory name expected.");
    process.exit(1);
}

const PATHNAME = process.argv[2].endsWith('/') ?
                 process.argv[2] : process.argv[2] + '/';

// List all filenames in dir received as argument
fs.readdir(PATHNAME, (err, files) => {
    if (err) throw err;
    files.forEach((filename) => {
        let newFilename = decodeURIComponent(filename);

        // Clean filename (CUSTOMIZE THIS)
        newFilename = newFilename
        // Remove accents/diacritics
        .normalize('NFD').replace(/[\u0300-\u036f]/g, "")
        // Convert separators to low line
        .replace(/\s+/g, '_')
        // Remove any non-safe character
        .replace(/[^0-9a-zA-Z-._]/g, "");

        fs.rename(PATHNAME + filename, PATHNAME + newFilename, (err) => {
            if (err) throw err;
        });
    });
});
  • The original puts YAML front matter on the .md files, and Joplin cant handle it, so edit the Makefile and remove these lines:

      @echo "---" > "$@"
      @cat "$(^:html=meta)" >> "$@"
      @echo "---" >> "$@"
    
  • Run: make * If it crashes on content, make sure evey Tiddler has valid syntax. (Using regular TW, open each tiddler without a JS crash.)
  • make convert
    • Somebody escaped the brackets in [[Title]]
      • The pandoc output has it.
      • The exported html does not.
      • Ergo pandoc added it.
      • I cant find a way to make pandoc stop.
      • i checked and my tw do not contain \[\ so it is safe to sed the Markdown.
    • Also, Yuck. Tiddlywiki output the html for triple backtick as <code></code>backtick both at the begining and at the end of the code block. Sometimes. I think the standard Markdown plugin cannot deal with single backtick inline code. Screw it. The MD converter plugin handles only Gruber MD, where triple backtick means something screwy. I’m just going to copy the Markdown tiddlers (where they exist) from TW into the output folder.
  • Put the following in ~/tiddlywiki-migrator/kpk-fixup.sh and run it.
# Rename files without the underscore so the names match the TW names
cd markdown_tiddlers
rename -v -e 's/_/ /g' *
cd ..

# For all the files created by the other guy's migration...
for f in markdown_tiddlers/*.md ; do

  # f2 = the node.js Tiddlywiki MARKDOWN file name
  f2="/data/tiddlywiki-sites/tw-node/pkb/tiddlers/`basename \"$f\"`"

  # Some older Tiddlers maybe got converted to Markdown, so they still have a .tid file type
  f3="${f2%%.md}.tid"
  
  # If TW has a .md file then use it.
  if [ -r "$f2" ] ; then
    echo cp "$f2" "$f"
    cp "$f2" "$f"
  else
    # if TW has no .md but it has a .tid, copy that IFF it is markdown format
    if [ -r "$f3" ] ; then
      echo "found $f3"
      if grep "type: text/x-markdown" "$f3" 1>/dev/null ; then
        echo "replace $f with $f3"
        
        # .tid files begin with metadata. The Markdown begins after a blank line.

        # Count how many lines to the first empty line
        var=`sed '/^$/q' "$f3" | wc -l`
        
        # Skip the empty line too
        var=$((var+1))
        tail -n +${var} "$f3" > "$f"
      fi
    fi
  fi
done
  • Get the underscores converted to spaces in the file names, and zip up the files for transfer to Mac:
cd markdown_tiddlers
rename -v -e 's/_/ /g' *
cd ..
tar -czvf markdown_tiddlers.tgz markdown_tiddlers/
  • On mac: scp kevin@boxtop:~/tiddlywiki-migrator/markdown_tiddlers.tgz markdown_tiddlers.tgz
  • This is pretty good except internal links import as [[Title]] but Joplin insists on using [Title](:/b9d7acbfa256439c8e92e018d0ebb1b7) as internal links.

  • Update the database to fix the internal links. You can’t do this until after the import, because the GUID are not assigned until the files are imported.
  • Database is in ~/.config/database.sqlite
  • code is in /Users/kevin/Sync/code/python/joplin
  • I’m using Python 3
  • Run: tw-to-joplin-links.py (code is shown below)

#!/usr/bin/env python
import re
import sqlite3

# Converts TiddlyWiki [[Link]] to Joplin's  [Link](:/GUID]

JOPLINDB = '~/.config/joplin-desktop/database.sqlite'

def no_commas(s):
    return s.replace(',', '')

# Some Titles look like Word%20With%20Spaces.
def decode_title(s):
    s2 = s.replace('%20', ' ')     # string.replace is a global replace-all-occurrences
    return s2

conn = sqlite3.connect(JOPLINDB)
c = conn.cursor()

c.execute("DELETE FROM notes where title = 'favicon.ico' or title = 'DefaultTiddlers' ")
c.execute("DELETE FROM notes where title = 'MarkupPreHead' or title = 'PageTemplate' ")

c.execute('SELECT title, id FROM notes')
rows = c.fetchall()
title_id = dict(rows)

# These may convert poorly. Mabe the [[foo]] is like this and should not be converted:  ```[[foo]]```
c.execute("SELECT id, body, title from notes where body like '%```%[[%```' order by title")
rows = c.fetchall()
for r in rows:
    print("WARNING:", r[2], "has [[ INSIDE ``` and may convert poorly")

# replacing [[AltTitle|Title]] with [AltTitle](:/ID)
c.execute("SELECT id, body, title FROM notes WHERE BODY LIKE '%[[%]]%' ORDER BY title")
rows = c.fetchall()

# Non-backtick, followed by [[blahblah]]
# This will fail to convert if the first 2 characters in the document are [[
reg1 = r"[^`]\[\[(.*?)\]\]"

for r in rows:
    matched1 = False
    body = r[1]
    my_title = r[2]
    print("Current story:", my_title)
    match = re.search(reg1, body)
    while match:
        print("Processing Markdown wiki link:", my_title)
        matched1 = True
        m = match.group(1)
        m2=re.search(r"(.+)\|(.+)",m)  # This one should be greedy because m contains only the content between [ ond ]
        if m2:
            # [alt_title|real_title]
            alt_title = m2.group(1)
            title = decode_title(m2.group(2))
            print("DEBUG processing alternate name wiki link. visible name=", alt_title, "internal name=", title)
        else:
            # [real_title]
            title = m
            alt_title = decode_title(title)

        #print("DEBUG lookup ID for title", title)
        if no_commas(title) in title_id:
            guid = title_id[no_commas(title)]
        else:
            guid = "LINK_TARGET_MISSING"
            print("WARNING:", my_title, "has a wiki link to missing document", title )

        # replace match.group(0) in r with [alt_title](:/GUID-of-title)
        s = match.group(0)[0]  # The 1-character not-backtick before the [
        newstring = s + "[" + alt_title + "](:/" + guid + ")"
        body = body.replace(match.group(0), newstring , 1)
        print("DEBUG replaced", match.group(0), "with", newstring)
        match = re.search(reg1, body)

    if matched1:
        escaped_body = body.replace("'", r"''")
        cmd = "UPDATE notes SET body = '" + escaped_body + "' WHERE id = '" + r[0] + "'"
        c.execute(cmd)

# replacing [Title](#Blah%20Blah) [Title](:/ID)
# You get these when the other guy's code exports tiddlywiki classic wiki links.
c.execute("SELECT id, body, title FROM notes WHERE BODY LIKE '%[%](#%)%' ORDER BY title")
rows = c.fetchall()

# Not backtick, followed by...
# This will fail if the first characters in the document are [
reg1 = r"[^`]\[.+?\]\(#(.+?)\)"

for r in rows:
    matched1 = False
    body = r[1]
    my_title = r[2]
    print("Current story:", my_title)
    match = re.search(reg1, body)
    while match:
        print("Processing TW wiki link:", my_title)
        matched1 = True
        m = match.group(1)

        title = decode_title(m)

        #print("DEBUG lookup ID for title", title)
        if no_commas(title) in title_id:
            guid = title_id[no_commas(title)]
        else:
            guid = ""


        # replace match.group(0) in r with [alt_title](:/GUID-of-title)
        # The other guy's export forces CamelCase wiki links, even if not enabled in TW.
        # That leads to a lot of link-not-found.  Just remove the hyperlink if link-not-found.
        s = match.group(0)[0]  # The 1-character not-backtick before the [
        newstring = s + "[" + title + "](:/" + guid + ")"
        if guid == "":
            body = body.replace(match.group(0), s + title)
            print("DEBUG replaced", match.group(0), "with", s + title)
        else:
            body = body.replace(match.group(0), newstring , 1)
            print("DEBUG replaced", match.group(0), "with", newstring)


        match = re.search(reg1, body)

    if matched1:
        escaped_body = body.replace("'", r"''")
        cmd = "UPDATE notes SET body = '" + escaped_body + "' WHERE id = '" + r[0] + "'"
        c.execute(cmd)


conn.commit()
conn.close()

print("FINISHED")

Done.

Short, Step-by-step - After You Did All the Setup

On Mac:

  1. Save DTL as ~/temp/dtl.html
  2. Save PKB as ~/temp/pkb.html
if [ `uname` = Darwin ] ; then
  cd ~/temp
  scp dtl.html kevin@boxtop3.home:dtl.html
  scp pkb.html kevin@boxtop3.home:pkb.html
fi

On boxtop3, from ~/tiddlywiki-migrator:

First - BOXTOP BOXTOP BOXTOP!

if [ `uname` = Linux ] ; then
  cd ~/tiddlywiki-migrator
  cp ../dtl.html wiki.html
  rm -rf tmp_wiki markdown_tiddlers
  make
  make convert
  ./kpk-fixup.sh
fi

Second

if [ `uname` = Linux ] ; then
  cd markdown_tiddlers
  rename -v -e 's/_/ /g' *
  cd ..
  tar -czf dtl_tiddlers.tgz markdown_tiddlers/
fi

Third

if [ `uname` = Linux ] ; then
  cp ../pkb.html wiki.html
  rm -rf tmp_wiki markdown_tiddlers
  make
  make convert
  ./kpk-fixup.sh
  tar -czf pkb_tiddlers.tgz markdown_tiddlers/
fi

On Mac, from ~/temp:

if [ `uname` = Darwin ] ; then
  rm -rf dtl_tiddlers  pkb_tiddlers dtl_tiddlers.tgz  pkb_tiddlers.tgz
  scp kevin@boxtop3.home:~/tiddlywiki-migrator/dtl_tiddlers.tgz dtl_tiddlers.tgz
  scp kevin@boxtop3.home:~/tiddlywiki-migrator/pkb_tiddlers.tgz pkb_tiddlers.tgz
fi
if [ `uname` = Darwin ] ; then
  tar zxvf dtl_tiddlers.tgz
  mv markdown_tiddlers dtl_tiddlers
  tar zxvf pkb_tiddlers.tgz
  mv markdown_tiddlers pkb_tiddlers
fi
  1. Using Joplin, import dtl_tiddlers
  2. Using Joplin, import pkb_tiddlers
  3. Run on Mac, from /Users/kevin/Sync/code/python/joplin:
    1. . python-chooser
    2. tw-to-joplin-links.py
  • And check your results in Joplin:
    • Check some general page layouts in DTL
    • Check some wiki links in DTL
    • Check some general page layouts in PKB
    • Check some wiki links in PKB

Turn Off Notifications for SMS From One Contact

I wanted to turn off notifications for text messages from some senders. This has changed over the years. Here’s how it works on my phone today. I think I’m on Android 8 (Oreo).

  • Navigate to the list of conversations in Messages
  • Open a thread with the desired sender
  • Click the menu icon (3 dots)
  • Choose Details
  • Choose Notifications
  • Turn off the “Show notifications” switch

Dear Marie Kondo

Dear Marie Kondo,

Clothes do not bring me joy. I simply do not give a damn about socks, shirts, pants, briefs. Following your advice to retain only items which spark joy, I am now nude and unemployed. Of course, since I was the breadwinner for my family, my wife and children have left me. They brought me joy, but discarding my clothing was important to reducing my clutter, and now I’ve certainly reduced my clutter.

Oh, and thank heavens I got rid of those clothes. I saw many pictures of drawers full of folded clothing stored vertically. That really does work well for a drawer full of clothing. But my drawers were full of clothing only immediately after I washed. By mid-week, they were only half full! Of course, whenever I opened a half full drawer of shirts stored vertically, they fell over. It was so much bother to stand them up each time I opened the drawer. I considered using bookends to keep them tidy, but bookends do not bring me joy.

I had many tools which I’ve discarded. I really didn’t get joy from my lawn mower or the table saw and other tools. Now the city mows my lawn for me. They fine me only $2500 each time they mow it, so I’m getting rid of the clutter of cash too! Of course, without the table saw and other tools, there are some home repairs I can’t perform. But that’s OK. My home has been condemned by the city, so it too will be discarded.

Oy! Don’t get me started about eating utensils. Is there really someone who derives joy from a fork or a spoon? But now that I’m losing my home, I won’t really have to bother with utensils. Chez Dump lets one eat with one’s fingers.

Camping used to bring me joy, but it has so many items one must store. There really isn’t any way to store 432 items vertically. I used to store them in stacked containers. Of course they overflowed the available space. When I looked at each individual item, I had to admit that most of them did not bring me joy in and of themselves. Picking up my nifty little camp stove does bring me joy because it is so well designed. Fuel bottles – not so much joy. So now I go camping in the nude with just my stove and no fuel. I’ve certainly reduced my clutter.

I used to enjoy ham radio as a hobby. I really, really love my Elecraft KX3 radio. It is epically well designed. But to be honest, things like batteries to run it, wires to connect it to the batteries, antennas, microphones… not so much. Now that I got rid of all of those critical accessories, I do still love my radio. Do you have any advice on how I can use my radio without power or a microphone? No? Well, I’ll just appreciate what it used to do for me.


Frankly, problems with the whole Kondo method include

  • It assumes that one lives in a managed apartment with all maintenanced attended to by someone else
  • One has no hobbies which come with lots of stuff. (Hobbies bring joy.)
  • One’s drawers are always at a constant level of fullness. (Vertical topples unless supported.)
  • One derives joy from items necessary to meet one’s responsibilities. (There’s a whole lot of shit I have to own in order to maintain my house, my car, my job, my dental health.)

The Kondo method seems well suited to someone with clothing and housewares fetishes, no hobbies, and no responsibilities.

Podcatcher With Sync

I wanted to use a podcast client which would sync across devices. i.e. I could be playing a podcast on my phone while walking, pause it on my phone, resume it on my laptop, pause it on my laptop, and resume it on Alexa.

My other unusual usage pattern is that I sometimes listen while on my daily walk, but I mostly binge-listen while on occasional long trips (e.g. vacations).

I use Android, Mac, Windows, and occasionally Linux.

I’d been using Podcast Addict. It doesn’t work on Alexa or on the desktop.

Features I wanted to carry forward from Podcast Addict:

  • Auto-download of new episodes
  • Auto-archive (hide and delete) played episodes
  • The list of shows should indicate which shows have unplayed episodes (ideally with a count)
  • Limit downloads to Wi-Fi
  • Download of old, unplayed episodes (not just the latest episode)

I started by searching for multi-platform podcatchers, including platforms Android, IOS, and web/HTML5. Alexa is a nice-to-have because I’m willing to use Bluetooth to stream from my phone.

Here’s what I looked at:

  • Pocket Casts- web $9, Android $4, IOS, Alexa.
    • Auto-downloads new episodes
    • Auto-archive of played episodes
    • List of shows indicates unplayed episodes
    • Can limit downloads to Wi-Fi
    • “Alexa, tell Pocket Casts to resume the last podcast”. Slant likes it.
    • Web and desktop apps (Windows, Mac) missing some features present in Android.
  • Stitcher - web, Android, IOS, Alexa.
    • Auto-downloads new episodes
    • No way to hide/delete played episodes.
    • List of shows does not indicate which have unplayed episodes.
    • “Alexa, ask Stitcher to pick up where I left off”
  • Podbean - Android, IOS, HTML5. Alexa skill is reviewed horrible.
  • Castbox - web, Android, IOS. Alexa skill is reviewed horrible.
  • Player.FM - web, Android, IOS. No Alexa.
  • Podcast Addict - Android only
    • Has all the features I want except it is Android only.

I want:

  • Desktop/web, Android. Able to continue a podcast from desktop/Android to Alexa.
  • Auto-download via WiFi.
  • Sync across platforms.
  • hide/delete played episodes.
  • List of shows displays which shows have unplayed episodes
  • Download of old episodes (not just the latest episode)

How to Import Email From an IMAP Server Into Gmail

GMail has a helpful import-from-POP3 function, to bring your old email when you migrate to GMail. But I wanted to import from a server which supports only webmail and IMAP. Here’s how:

Step 1 - Import Messages to a Desktop Email Client

Since we can’t go directly from the old server into GMail, we’ll pass through an intermediate step. We’ll set up a desktop email client to fetch messages from the old server. This will make a copy of the messages on the desktop. Then, in step 2, we’ll push the messages from the desktop into GMail.

Note: If you’re about to lose access to your old server, the step of copying the messages to your desktop is URGENT. Step 2 can be done at your leisure.

I’m going to describe how to do this using the Thunderbird email client. If you already use a different desktop email client, you can probably do something similar using it.

  1. Install Thunderbird from https://www.thunderbird.net/en-US/ .
    • Just click on the default Next/Install/Finish buttons until you get to the “Set up an Existing Email Account” window.
  2. Enter your ordinary, human name next to “Your name”. e.g. Tom Smith.
  3. Enter your email address (from the old server) next to “Email address”. e.g. tom.s@example.com
  4. Enter your email password (from the old server) next to “Password”. e.g. TopSecret1234
  5. If you are lucky, it will auto-detect your settings.
  6. If you are unlucky, you may have to press the “Manual Config” button and enter your information manually:
    • Set Incoming to IMAP
    • Set both host names to the server name for your old email server. e.g. example.com
    • Set the Username Incoming field to your old email server’s user name. e.g. tom.s
    • Set both Port fields to Auto.
    • Set both SSL fields to Autodetect.
    • Set both Authentication fields to Autodetect.
    • Set the Username Outgoing field to your old email server’s user name. e.g. tom.s
    • Press “Re-test”. It should report “The following settings were found by probing the given server”. Then press Done.
  7. You may get passed to a login form for your old email server. If so, complete it.
  8. At the left side of Thunderbird, you should see your old email account. e.g. tom.s@example.com. Underneath the email address, you should see some folders. Explore those folders until you see the emails from your old server.
  9. Once you find the folder/folders with your old messages:
    • Right click the folder.
    • Choose Properties, then Synchronization.
    • Set (put a check mark next to) “Select this folder for offline use”.
    • Press the Download Now button.
    • Be sure to do this for each folder which has old emails.
  10. If you have lots of messages, just let your computer sit, connected to the internet for a little while, while the old messages get downloaded to your computer.

How to Pull-down Refresh on a Kindle Fire

I use Nirvana from nirvanahq.com for my tasks list. On an Android phone, it has a nice Sync icon. On a Kindle Fire Android tablet, there is no Sync icon. Here’s how to make it refresh.

  • At the top of the page, there’s a big blue title bar, showing the name of your selected folder. e.g. “Inbox”
  • Below the title bar is a narrow gray bar which repeats the name of the selected folder. e.g. “Inbox”
  • You must pull-down from the dividing line between these two bars.

I’ve heard this is a general issue with Kindles – that the pull-down area for an app has a very narrow activation area. This is reportedly because Android apps expect you to be able to pull down from the main title bar but Kindle uses the title bar in a non-Android-standard way.

How to Revoke an Alexa Skill Account Link

Many Alexa skills want you to “link accounts.” Often, this involves connecting to your Amazon account via OAuth. Later, you may wish to revoke this access.

Some revocation is at:

  • Visit https://www.amazon.com/gp/css/homepage/
  • Locat “Login with Amazon” under “Other Accounts” and click it.

Other revocation is at:

  • Visit https://www.amazon.com/gp/css/homepage/
  • Locate “Apps and more” in the “Digital content and devices” grouping. Click it.
  • Note that https://www.amazon.com/gp/mas/your-account/myapps/ref=mas_ya_apps may take you there with a single link.

Microsoft Office Apps - Tick, Tick, Tick

For no apparent reason, most of my Office 365 apps started ticking about once per second. Tick, tick, tick. The ticking would stop several seconds to minutes after I exited the app. It happened even when I launched the apps in “safe mode.” It affected Word, Excel, Access, and Powerpoint, but not Outlook. (I didn’t try Publisher or the other, lesser Office apps.)

I went into Control Panel and set the Windows sound scheme to “No Sounds” and the sound went away. So I drilled down to the “Windows Explorer” grouping and discovered that I could just disable the “Start Navigation” sound, and that silenced it.

That led me to run Fiddler to see what the navigation was. It was loading some Microsoft authentication URLs, over and over.

That led me to notice my name on the Office (Word, Excel, Powerpoint, Access) title bar. Office 365 wants you to be logged in to Office. There was an exclamation point next to my name, indicating some sort of error. I logged out of my Office 365 account and back in. The exclamation point was still there, but clicking it gave me a complaint about the status of my account (which disappeared too quickly for me to capture it).

Eventually I clicked on a message about re-authenticating. That displayed a blank dialog, which eventually loaded and told me I was re-logged in. THAT cleared the exclamation point. A few seconds later, the ticking (and URL loading) stopped.

So tick, tick, tick from Office apps is telling you that you’re not successfully logged into Office 365. Microsoft says you have to login to Office 365, even if all you wanted to do was to view a Powerpoint.

Some Modestly Priced Cell Phones in Late 2018

General Notes

  • Tom’s Hardware says the average cell phone has 9:48 battery life, browsing via LTE at 150 nits of brightness. 150 is pretty dim. Gizmodo says, “In most conditions, a 250 nit screen will appear plenty bright.”
  • I’m replacing my current phone because it frequently powers down due to low battery by surprise.
  • I’d almost buy a Pixel 3 or a Pixel 3 XL, despite the high price, but they have sub-average battery life. If I’m buying a $700-$1000 phone (plus accessories), I need it to last at least 3 years and I’m not confident that battery will still be good. And I might break it or lose it, or there could be some new whiz-bang feature I really want before 3 years are up.
  • My existing Moto X2 phone has
    • 5.2 inch screen, 140.8 x 72.4 x 9.9 mm (5.5 x 2.9 x .4 inches), 1920 x 1080, 423 pixels per inch
    • 2 GB RAM
    • 32 GB storage, no SD Card support
    • Water repellent
    • Battery Life = 7:33 (tomshardware)
    • NFC
    • Bluetooth, WiFi, Cell Data
    • When it was new, Anandtech said its battery life was sub-average at 5 hours at 200 nits
    • Quick Charge, 3rd gen
  • Things I’d like my phone to do/have
    • Still fit in my pocket
    • 64 GB storage or more (or 32 + SD Card)
    • Battery last longer
    • Rainproof
    • GSM, LTE
    • NFC (Android Pay)
    • Bluetooth, WiFi, Cell Data
    • Wireless charging
    • Quick charge
    • VoLTE, WiFi calling on AT&T
  • Things I’m indifferent about
    • Fingerprint sensor. Convenient, less secure, and police can compel you to unlock.

Moto E4 Plus, $199

  • 5.5 inch screen, 155 x 77.5 x 9.5 mm (6.1 x 3.1 x 0.4 inches), 1280 x 720, 267 pixels per inch
  • 3 GB RAM
  • 32GB storage (the available model) + SD Card
    • Must select gold color to get the 32GB edition
  • Battery life 14:43 (tomshardware.com)
  • Water repellent, not waterproof
  • No NFC in USA
  • Bluetooth, WiFi, Cell Data
  • Wired charging (only)
  • Not standard quick charge. Not as fast as Quick Charge 2.0
  • No VoLTE, WiFi calling on AT&T. Some people report no LTE cell data
  • Fingerprint sensor
  • Limited to Android Nougat (no Oreo)
  • Conclusion: Great battery, but screen resolution is too low.

Moto G5 Plus, $150-$210

  • 5.2 inch screen, 150.2 x 74 x 7.7 mm (5.9 x 2.9 x 0.3 in), 1920 x 1080, 424 pixels per inch
  • 2 GB RAM
  • 32 GB storage (the available model) + SD Card
    • $150 32GB (not confirmed U.S. model), $210 32GB (confirmed U.S.)
  • Battery life 11:43 (tomshardware.com)
  • Water repellent, not waterproof
  • No NFC in USA
  • Bluetooth, WiFi, Cell Data
  • Wired charging (only)
  • Quick Charge 3.0
  • No VoLTE, WiFi calling on AT&T. Some people report no LTE cell data
  • Fingerprint sensor
  • Upgradable to Oreo
  • Conclusion: If that $150 model is U.S., consider it after the seller gets some reviews.

Moto X4, $180-$300

  • 5.2 inch screen, 148.4 x 73.4 x 8 mm (5.8 x 2.9 x 0.3 in), 1920 x 1080, 424 pixels per inch
  • 3 GB RAM
  • 32 GB storage (the econo model) + SD Card
    • $180 32GB Amazon Ads, $230 32GB, $300 64GB
  • Battery life 11:41 (tomshardware.com, slightly different model)
  • Water repellent, not waterproof
  • NFC
  • Bluetooth, WiFi, Cell Data
  • Wired charging (only)
  • Quick Charge 3.0
  • No VoLTE, WiFi calling on AT&T. Some people report no LTE cell data
  • Fingerprint sensor
  • Upgradable to Oreo
  • Scary: 20% of Amazon users hate it, reporting frequent total failure.
  • Conclusion: This looks pretty good except for the quality control.

Nokia 6.1, $180

  • 5.5 inch screen, 148.8 x 75.8 x 8.2 mm (5.9 x 3.0 x 0.3 in), 1920 x 1080, 403 pixels per inch
  • 3 GB RAM
  • 32 GB storage + SD Card
  • Battery life 10:24 (tomshardware.com)
  • NOT Water repellent
  • NFC
  • Bluetooth, WiFi, Cell Data
  • Wired charging (only)
  • USB-C rapid charging
  • No VoLTE, WiFi calling on AT&T
  • Fingerprint sensor
  • Comes with Oreo and updates through 2019
  • Conclusion: I really can’t buy a non-water repellent phone.

LG G6 Amazon Prime, $360

  • 5.7 inch screen, 1148.9 x 71.9 x 7.9 mm (5.9 x 2.8 x 0.3 in), 2880 x 1440, 564 pixels per inch
  • 4 GB RAM
  • 32 GB storage + SD Card
  • Battery life 8:30 (tomshardware.com)
  • Water resistant, IP68
  • NFC
  • Bluetooth, WiFi, Cell Data
  • Wireless charging
  • USB-C rapid charging and Quick Charge
  • No VoLTE, WiFi calling on AT&T
  • Fingerprint sensor
  • Upgrade to Oreo
  • Conclusion: Unwilling to pay $180 for wireless charging.

Huawei Mate SE, $220

  • 5.9 inch screen, 156.5 x 75.3 x 7.6 mm (6.2 x 3.0 x 0.3 inches), 2160x1080, 407 pixels per inch
  • 4 GB RAM
  • 64 GB storage + SD Card
  • Battery life not reported
  • Water resistant, IP67
  • No NFC
  • Bluetooth, WiFi, Cell Data
  • Wired charging only
  • No Quick Charge
  • No VoLTE, WiFi calling on AT&T
  • Fingerprint sensor
  • Upgrade to Oreo
  • High reviews on Amazon
  • Concern: They use “EMUI” skin to alter the stock Android look and feel
  • Conclusion: ????