jonwear.com

jon wear's personal website

Mastodon

19 April 2018

I signed up for most of big the social media service. LinkedIn, Twitter, Ello, Google +, Instagram. Prolly some others I forgot about.

I knew it was just a matter of time until the ads ruined it all. Even after they showed up I thought, "it's not so bad." But it was. The algoritms, the modified time lines, the suggestions for MORE things you should follow. And the weird "A friend of friend liked a post..." I left a few times and always went back. But I gave up FB for Lent this year and then not so long ago we had the Cambridge Analytica fiasco. Mr. Zuckerburg is in front of the Senate. I think I'm done. I think for good this time.

I like a lot of things about social media, but ad-based capitalism is really starting to bother me. Has for a while.

Mastodon. What is it?

There are lots of articles you can read about it but I'll do my best to summarize it in my own words. Mastodon is social media that runs on many different servers that are all linked together by a protocol called Activity Pub.

A protocol is tech speak for an agreement between software installations. You'll also described as federated and distritubed. Email is an example of a federated protocol. You might have your email service on Gmail. A friend might be on Yahoo! Mail or AOL mail. All of you can send messages to each other even though your email is hosted by different companies on different servers in different parts of the world. Your copper wire telephone is distrubed as well. You might be on AT&T and someone else on Southwestern Bell but you can still talk to each other. Or you can call around the world going through all sorts of connections to ring phones just about anywhere in the world.

No Ads. No tracking. Free

A Mastodon server (or instance) is the same thing for social media. You can make an account on one server choose to follow (or not) other users on that server. But you can also follow any user on any other maston server. All you need is the address or handle of the person and you're good. Mine is jon@route66.social. I'm the admin on that server and you're welcome to join up. You could sign up on any Mastodon server you wanted and follow me and I could follow you back. Messages and pictures that you post to your account will show up for everyone who follows you, no matter what server they happen to have an account on.

You can have your account be wide open to whoever wants to follow you, or you can lock it and manually approve followers if you're more comfortable with that. You can block individual accounts from following/interacting with you if you want. Admins can block users as well or entire instances if a community is contually toxic. That's what I find most interesting. If a community(or user) on a server is abusive to others they will find themselves banned from most communities to the point where they can't interact with anyone. On the other hand, if a community/user is offended by nearly everything anyone says, they can block as well until they effectively block themselves from everyone else.

Is it perfect? No. It's a little clunky. Kind of like Twitter when it first got big after SXSW way back in...2007. The main thing the Mastodon fediverse is lacking is people that you want to interact with. There's lots on there, but for it to really take off you gotta get some people on there. Facebook did a barn storming tour of college campusus back before it was open to the public. Worked out great because when those college students graduated, they brought the social network with them.

Anyway, it's not Twitter and it's not Facebook. There's no Mastodon coporation running the whole thing. It's just people deciding to setup servers and inviting their friends. Hopefully that will be enough to get it going.

By Jon Wear

Your own Go blog(Update)

15 April 2018

This post is update for my Go Blog Go post Go Blog Go.

What a difference 2 and 1/2 years makes. Not only has the blog setup changed a bit, but when I tried to use my previous post to help me setup my blog on a new Scaleway server, I realized that there were several errors and ommisions. I'll try to correct them here.

Get a server

I continue to use www.scaleway.com. Same low price. Perfect baremetal server for my low traffic blog.

But! When you select the server image (wherever you do it) be sure to select an LTS version. Mistakenly I chose a non-LTS image (Ubuntu Vivid) when I initially setup my blog and guess what? EOL happened sooner than I would have liked.

If you are setting up a Scaleway server for the first time, you'll need to add your SSH public key to the Credentials section of your account. That way when your server boots up you'll be able to ssh root@IP_ADDRESS and you're good to go.

Once you are in, be sure to run:

apt-get update
apt-get upgrade

Now you have an up to date server.

Install Go

Scaleway.com servers use ARM processors so I found it easiest to just install Go on the server and do my builds there. You could install Go locally, target your build and copy it up to your server however you wish. But that's not how I did it.

apt-get install golang

As of now that installs version 1.6.1:

go version go1.6.1 linux/arm

Be sure to set your GOPATH

Get the code

Make sure Git is installed on your server.

Download the code from here:

I recommend that you make your own git repo with the release code. Be sure to keep the BSD license in place.

From inside the directory where you downloaded the blog code run:

go get

Build the binary

go build *.go

Now you could launch the freshly built binary, but you don't have a way to get to it from the outside yet.

Install nginx

apt-get install nginx
service nginx start

Make sure you see the nginx startup page by navigating to the public IP address of your server.

Configure nginx

Our blog binary is going to be listening on port 8080. We want to serve requests/responses on port 80. We need to tell nginx to proxy between 80 and 8080.

Put this inside the http { } section of nginx.conf file.

server {
 listen         80;

 server_name    IP_Address_or_URL;

 access_log   /var/log/nginx/blog/access.log ;
 error_log    /var/log/nginx/blog/error.log info ;

 location / {
    proxy_pass  http://127.0.0.1:8080;
    }
 }

Make sure that the path to your access_log and error_log files exist.

Daemonize our blog binary

Simple right? We're almost there. We could start our go binary right now by just invoking it from the command line, but if it crashes for some reason we want it to start back up. If we reboot our server, we want the blog server to start up again without us having to do it. So let's daemonize.

We're on a newer version of Ubuntu now (16.04) so we have to daemonize using SystemD. Make a file called blog.service in the path /etc/sysmted/system/. Be sure that the following values are set to the correct path on your server:

  • ConditionPathExists
  • WorkingDirectory
  • ExecStart
[Unit]
Description=Blog
ConditionPathExists=/root/go/src/jwblog/blog
After=network.target

[Service]
User=root
LimitNOFILE=1024

Restart=on-failure
RestartSec=10

WorkingDirectory=/root/go/src/jwblog
ExecStart=/root/go/src/jwblog/blog

# make sure log directory exists and owned by syslog
PermissionsStartOnly=true
ExecStartPre=/bin/mkdir -p /var/log/blogservice
ExecStartPre=/bin/chown syslog:adm /var/log/blogservice
ExecStartPre=/bin/chmod 755 /var/log/blogservice
StandardOutput=syslog
StandardError=syslog
SyslogIdentifier=blogservice

[Install]
WantedBy=multi-user.target

Start the service!

We're almost there!

Now, at the terminal prompt on your server type:

systemctl start blog

Your blog server should be running. Check your IP address http://YOUR_IP and you should see the sample content. Set your domain via DNS to your IP and you're all done.

Comment on my subreddit.

By Jon Wear

New direction for my blog

10 July 2017

Hey all, my job changed a while back. I'm no longer a full time developer(another post for another time), although I still code on occasion.

My wife and I started fostering two brothers in September of 2016. So we went from 1 kid to 3 kids. Fostering is without a doubt one of the best things I've ever done with my life (this too warrants its on post, probably posts).

Since I don't go out as much these days, I found myself getting interested in something equally nerdy, card magic...

So...future posts will probably have more to do with that than with various tech related things. I still find tech interesting (especially golang), but I'll be consuming that content as opposed to (very occasionally) creating it.

Here's the outtakes from me trying to make a card trick tutorial video back in December. The finished product isn't that good, but I thought the outtakes were funny.

Comment on my subreddit.

By Jon Wear

Your own Go blog

19 September 2015

This post is based on a talk I gave at the Philly Go Meetup on September 8th .

Now that I have my blog running using the same blog engine that http://blog.golang.org uses, I thought I'd write up a post to explain how I did it.

Get a server

You gotta host it somewhere. I used www.scaleway.com. I got a Linux server with enough power to run my lowly blog:

  • 4 Cores @1.3GHz
  • 2GB memory
  • 50 GB SSD
  • 1 public IP
  • Costs €2.99/month which is currently $3.34

Turn it on and ssh in. Be sure to run:

apt-get update
apt-get upgrade

Now you have an up to date server.

Install Go

Scaleway.com servers use ARM processors so I found it easiest to just install Go on the server and do my builds there. You could install Go 1.5 locally, target your build and copy it up to your server however you wish. But that's not how I did it.

apt-get install golang

As of now that installs version 1.3.3:

go version go1.3.3 linux/arm

Be sure to set your GOPATH

Get the code

Download the code from here:

I recommend that you make your own git repo with the release code. Be sure to keep the BSD license in place.

From inside the directory run:

go get

Build the binary

go build blog.go local.go rewrite.go

Now you could launch the freshly built binary, but you don't have a way to get to it from the outside yet.

Install nginx

apt-get install nginx
service nginx start

Make sure you see the nginx startup page by navigating to the public IP address of your server.

Configure nginx

Our blog binary is going to be listening on port 8080. We want to serve requests/responses on port 80. We need to tell nginx to proxy between 80 and 8080.

Put this inside the html { } section of nginx.conf file.

server {
 listen         80;

 server_name    IP_Address_or_URL;

 access_log   /var/log/nginx/blog/access.log ;
 error_log    /var/log/nginx/blog/error.log info ;

 location / {
    proxy_pass  http://127.0.0.1:8080;
    }
 }

Daemonize our blog binary

Simple right? We're almost there. We could start our go binary right now by just invoking it from the command line, but if it crashes for some reason we want it to start back up. If we reboot our server, we want the blog server to start up again without us having to do it. So let's daemonize.

If you've never seen a System V script before, this may make you a little glassy eyed, but don't worry, it's mostly boiler plate. There's only one thing to change, the dir= part. Put in the path to the directory that contains the blog binary there. Keep the enclosing double quotes.

#!/bin/sh
### BEGIN INIT INFO
# Provides: blog
# Required-Start:    $remote_fs $syslog
# Required-Stop:     $remote_fs $syslog
# Default-Start:     2 3 4 5
# Default-Stop:      0 1 6
# Short-Description: Start daemon at boot time
# Description:       Enable service provided by daemon.
### END INIT INFO

dir="PATH_TO_DIRECTORY_THAT_CONTAINS_BINARY"
cmd="./blog"
user="root"

name=`basename $0`
pid_file="/var/run/$name.pid"
stdout_log="/var/log/$name.log"
stderr_log="/var/log/$name.err"

get_pid() {
cat "$pid_file"
}

is_running() {
[ -f "$pid_file" ] && ps `get_pid` > /dev/null 2>&1
}

case "$1" in
start)
if is_running; then
    echo "Already started"
else
    echo "Starting $name"
    cd "$dir"
    if [ -z "$user" ]; then
        sudo $cmd >> "$stdout_log" 2>> "$stderr_log" &
    else
        sudo -u "$user" $cmd >> "$stdout_log" 2>> "$stderr_log" &
    fi
    echo $! > "$pid_file"
    if ! is_running; then
        echo "Unable to start, see $stdout_log and $stderr_log"
        exit 1
    fi
fi
;;
stop)
if is_running; then
    echo -n "Stopping $name.."
    kill `get_pid`
    for i in {1..10}
    do
        if ! is_running; then
            break
        fi

        echo -n "."
        sleep 1
    done
    echo

    if is_running; then
        echo "Not stopped; may still be shutting down or shutdown may have failed"
        exit 1
    else
        echo "Stopped"
        if [ -f "$pid_file" ]; then
            rm "$pid_file"
        fi
    fi
else
    echo "Not running"
fi
;;
restart)
$0 stop
if is_running; then
    echo "Unable to stop, will not attempt to start"
    exit 1
fi
$0 start
;;
status)
if is_running; then
    echo "Running"
else
    echo "Stopped"
    exit 1
fi
;;
*)
echo "Usage: $0 {start|stop|restart|status}"
exit 1
;;
esac

exit 0

Start the service!

We're almost there!

Now, at the terminal prompt on your server type:

service blog start

Your blog server should be running. Check your IP address http://YOUR_IP and you should see the sample content. Set your domain via DNS to your IP and you're all done.

Comment on my subreddit.

By Jon Wear

Self Description - Text

9 February 2015

One of the xkcd.com comics that has really stuck with me over the years is this one:

The part that inspired me to write some Go code wasn't the image itself, but the hover text which reads as follows:

"The contents of any one panel are dependent on the contents of every panel including itself. The graph of panel dependencies is complete and bidirectional, and each node has a loop. The mouseover text has two hundred and forty-two characters ."

That was clever. A bit of text that includes the length of the the text within the text itself. So, I wrote some program that does it for any text up to 1,000 characters. It ignores trailing spaces, but other than that, you type and it will append the length of the text (including the length of the text).

I went about it this way:

Calculate the text for a given integer ("one" for 1, "twelve" for 12, "thirty-seven" for 37) & store the length of that text representation. You can find the loop for this here and the actual functions that convert number representations to text representations in this file.

Next, I call up my old buddy brute force. For every text length between 1 and 1,000, I take the text submitted (for example, "Hello World!") and I add the text representation of the current loop integer. Then I check to see if the actual length of those two bits of text concatenated together equal the length (number wise) of the text form of the number. If they are equal, great! I have a match and return it. In this case:

Hello World! This text is fifty-nine characters in length.

It all happens here:

func ProcessText(text string, items []TextLengthItem) string {
    firstParts := []string{"This text is %v characters in length.", "Text is %v characters long.", "Text is %v characters in length."}
    result_template := "%v  %v"
    textLength := len(text) + 2
    for _, firstPart := range firstParts {
        for _, item := range items {
            length_sentence := fmt.Sprintf(firstPart, item.Text)
            if textLength+len(length_sentence) == item.Value {
                return fmt.Sprintf(result_template, text, length_sentence)
            }

        }
    }
    return "No match found."
}

Make a simple bit of formatting text "%v %v". That's two place holders separated by 2 spaces (thus the + 2 on line 4). Add the text to position one, add the text of the number to position two, and then see if the total length matches the numeric value of the number you put in position two.

There are more elegant ways, I'm sure. Even for brute force, you could decide to start your brute loop with the length of the submitted text instead of 1.

That's almost all there is to it. One thing I discovered is that sometimes, certain lengths of text just won't match up. You can check everything and nothing will give you that nice recursive bit of text. I got around that by giving more than one boiler plate phrase. Instead of just using, "This text is %v characters in length."

I use two more phrases that say the same thing but have different over all lengths.

firstParts := []string{"This text is %v characters in length.", "Text is %v characters long.",
"Text is %v characters in length."}

So far one of these three phrases has caught every possible length between 1 & 1000. You can tweak the code to go higher if you want.

Code & installation instructions can be found here:

By Jon Wear

See the index for more articles.