Sunday, January 31, 2016

Follow technology dream, slightly un-break the world , accept some regret

Over 15 years , I made a few sacrifices to follow my tech dream to make the world slightly better place. After 4 years of reflection, I have some satisfaction and some selfish regrets. Click bait but true, the selfish regrets probably aren't what you'd think.

DISCLAIMER: There are at least 20 people I don't acknowledge here. Without you accepting the legal responsibility of board membership, making generous, sometimes sacrificial contributions of resources or providing the political and fund-raisin advice I needed to keep our nose above water, this work wouldn't have happened. You deserve acknowledgement. However, I took 3 years to write what is here. Any more delay and this note will never be finished. I hope you know who you are and know that that I am grateful for your help.

Confirmation bias is a thing. If you repeat, over and over: "At least I tried", you can tell yourself: "yes, it was worth it."

If you believe:

 "Do not store up for yourselves treasures on earth, where moth
  and rust destroy, and where thieves break in and steal. But 
  store up for yourselves treasures in heaven, where neither 
  moth nor rust destroys, and where thieves do not break in 
  or steal; for where your  treasure is, there your heart 
  will be also.

...Earning about $7,000 per year for 15 years of tech support, system administration, cat herding, tutoring and software engineering is just fine.

So that's me with a spouse that paid the rent so I could be holier-than-thou for 15 years. Compared to the quiet guy who has run a good after school program in the same notorious low income neighbourhood for 40 years, I have few, legitimate self-righteous points.

Not maximizing my income was a means to the end of my dream of using technology to make a better world at the Community Software Lab (RIP). However, being (somewhat) low income had interesting side benefits. For example, these last 4 years at market rate, our income more than doubled. However, it ***feels*** like we've only been living only slightly large. Dinner and drinks a few times a week vs just coffee at the local shop. Running outside in the winter vs Yoga 5 days a week. Perhaps, the feeling of living large these past 4 years is muted by paying debts and starting to save toward old age.

Again, confirmation bias, but past an income floor of < some number of $ >, limiting desires is probably a better strategy for material happiness than increasing income. We still have credit card debt, but instead of paying to attend funerals on the other side of the country, we're paying off a winter beach vacation.

In my limited experience, subjective perception is better predictor of satisfaction than empirical measurement. Surrounded by middle income family, acquaintances and in-laws the expectations of our peers was always a greater pressure than the cost of adequate housing, food or medical care.

When I was a practising Catholic, I did informal tech support for the Oblates of Mary Immaculate. If lunch-time came in the middle of work, we had lunch together. I have a sense for how these guys live. Everyone has health care, an allowance for new uniforms, meals, a computer a bed room and a bathroom to themselves and a spot in the retirement home when the time comes.

The rooms were a little smaller than your average Motel 6, but a little less shabby. I think they got $20 per week in spending money. If they needed a car for work they submitted a budget. Oblates working over seas live even simpler, closer to the people they serve.

The Oblates have infrastructure and a supporting culture. It didn't seem like honouring the Oblate vow of poverty was a significant struggle. My spouse and I struggled in our unstructured time of relatively simple living. I think our struggle was more about being embedded in the culture of money than it was being able to pay our bills.

Considering only the money issues, for at least me, autonomy and the chance to make a difference, were worth not maximizing our income. However, for different selfish reasons, given a do over, I would do things differently.

The last 8 of 15 years, my focus was using novice programmers to build useful software for low income people in a organization I started called the Community Software Lab. Three lab alumni work at Google, Amazon and Microsoft. More significantly, three different people explicitly credit the Community Software Lab for significantly better opportunities and lives than they would have had otherwise.

Despite occasional flashes of student brilliance and the many personal indulgences granted me by teachers and educational bureaucrats, I've long considered the industrial/educational complex ineffective and unjust. The lecture system was created in medieval times because it is quicker to read a book aloud to 50 people than it is to hand-write 50 copies. Adjunct professors do almost all the revenue producing teaching but those without independent means are eligible for public assistance. (about 25% of them)

Writing software that people use, following a modern process is a better way to learn to program than listening to lectures or copying your roommate's homework. Requiring 100% test coverage for new code, creating detailed engineering documentation, tools , standards and processes and (most important) re-re-doing line by line code review, allowed people starting with only the ability to write a FOREACH loop to contribute production code and gain real skill. By unanimous testimonial, working with me was hugely more educational than undergraduate computer science education.

This is all anecdotal, but I challenge any CS dept to provide better outcomes with their standard program than I could locked in a room with five CS 101 grads and their tuition for 4 years.

The problem is that most people don't have the drive to write software. They want a paycheck or the entitlements accorded to the coder caste. They don't want to stay up until 3:00am, failing again and again, debugging for joy or compulsion. I helped hundreds of people confirm that they really didn't want to be engineers. The educational industrial complex has the advantage of not investing much emotional energy helping people accept their failure.

Over 8 years, of the approximately 200 people who I setup development environments for, 10 people created more value (useful code) than I could have created by spending the setup/ tutoring/ code review time just writing code myself. More people personally benefited from the experience, than contributed more than they took, but wasn't the greatest good for the greatest number.

Given only 1 chance to repeat the last 8 years of volunteer experience, (previous 7 are another matter) I'd ignore everyone else and lock myself in a room to code. Crappy as it was, our software did refer tens of thousands of people to the social services they needed. Not-crappy software would have been a far greater good for a far greater number. Certainly more the (at best ) 25 people who got to be better coders from their work with the Lab.

Compounding the uncertainty is my suspicion that most of our "successful" alumni would have made it anyway. The MIT dropout, yes. The guy with 10 years industry experience waiting out a recession, yes. The driven, angry, smart kid who'd lived half his life in foster care, probably.

Despite our best efforts, most of the people we gave practical experience to weren't especially dis-advantaged. Our usual admissions test was "Use Javascript to prompt the user for a positive integer, print the numbers between 1 and that integer". In theory this bar is low enough for anyone pass, in practice only 2 of the 10 productive people came from a low income background or with a label like "at risk youth" We probably accepted a good number of people without advantages, but subjectively, the big service we provided most of them was helping them accept that they didn't like coding.

Selfishly, given 8 years of effort, I wouldn't be the mediocre programmer I am today. If instead of explaining the same things over and over, I'd written and re-written code, I'd be pretty good, or at least better. It felt horrible to blow the recruiter level phone screen at Facebook. It felt worse to be completely oblivious to the sql INNER JOIN syntax on a web dev interview for a spot on a team full of people as smart or smarter than me. (FWIW, I am still reasonably employable at a few levels below elite. )

In both interviews, I missed things because I'd been focused on explaining existing code and making it hard for people to screw up new code instead of writing new code or updating code myself. Building skill is a different than helping other people learn. Also, usually being the most knowledgeable person in the room is not a recipe for personal growth.

For example in 2006, it was an acceptable practice to connect database tables in the SELECT clause. By my interview in 2013, modern databases supported JOINs and modern programmers used them.

This strong regret was obvious only in hind-sight, after I'd been away from the lab for a few years. In the moment, it was mostly great. I like Yoga a lot partly because the instructor usually feels compelled to thank the class for the privilege of sharing the skill. It feels very, very good to contribute to other people's ah-ha moments.

People talk about engineering education a lot like they talk about baseball. At the little league level there is lots of fun, but eventually the grind sets in. Maybe the grind is the price of greatness. Maybe the grind is yet another black mark for the educational/industrial complex. Having 3 people get jobs at famous companies, was OK. More satisfying than alumni success was watching a women, a serious A+ student, pound her heels, shake her fists and giggle after fixing a complicated bug.

Overall, these moments of joy didn't add up to what might have been with a more selfish approach.

--- or maybe a more effective approach ?

It's kinda obvious, but the reason only about 10 people gave more than they took and (guessing) only about 25 people benefited from the practical experience was that not many people put the needed time in.

Without exception, people who dabbled, trying to fit our work in between school or other jobs or being a mom, were a net loss. Some of those people were quite talented but just couldn't find the time.

The people that succeeded put in at least 20 hours a week and most of those people got paid a small stipend, --Often below minimum wage, but something.

Most of the people who succeeded, were Americorps/VISTAs, The government paid them 16K per year and basic health benefits. The program was created by President Kennedy to fight poverty through (almost) voluntarism and required a full time commitment. Other people got funded through Google Summer of Code. We got some contracts. I was able to fund-raise to pay other people. I did other completely unrelated contract programming work that paid relatively well.

This is an insight for other groups trying to skill-up low income or disadvantaged people. "Work for free" is not perceived as a survival skill by low income people or entitled feeling middle class people. There is an almost infite distance between "almost nothing" and "free" for both producers and consumers. Many people needed the stipend to pay their rent. Other people just felt exploited working for free ---Even if the "work" was mostly training that they'd otherwise have to pay for.

The ideal would have been to have a summer camp with computers , Internet access, showers, a silo of rice and a silo of beans. Given that I spent about half my time trying to fund-raise as a charity and barely kept the doors open with an annual budget of around 20K , this was probably not a reachable ideal.

Given more than (1) chance for a do-over, I might just have worked as a market rate programmer, banked the money for 8 years and retired early to spend the banked money on stipends. ( Assuming my wants didn't expand to match my earnings )

The biggest sacrifice wasn't money, but personal growth. The biggest barrier to most people's personal growth was a little money. There is a difference between something and nothing. So there it is. Money isn't important, except when it is.

I've covered the major regret ( lack of personal growth). A minor regret is lack of measurement. If I'd taken the time to better define success in advance, I might have changed course earlier and I might have fewer doubts now

Disclaimer: The first version of our (MVHub) software was written by DS and EA in about 8 months working by themselves. During their work I was mostly focused on system administration. ---providing email, web hosting and databases to non-profit organizations.

Sunday, September 7, 2014

POP3 gets academic / university / office 365 into gmail

I use Gmail.[*] Part of the cost of a night course at the local Uni is agreeing to use their email, which uses Microsoft's  Fortunately, Gmail can be configured to pull email from other systems.

The winning search term is POP3 academic office 365.  If you know what POP3 is, all you need is that  POP3 server info:

Incoming POP3 server:, port 995, encryption SSL

If you don't know what POP3 is, proceed as follows. You will need:

  1. Your student email username
  2. Your student email password
  3. Confidence that your university is using Academic Office 365  or
  4. a gmail account. 
Given the above:

Login to Gmail and access settings:



Choose accounts

Add POP3 account you own



Add your email address

Set username (probably your email address) , password, POP3 server ( , port (995) and encryption

Finish (no to send outgoing mail as your student account)

Possible Problems / sources of errors

  1. Don't include any invalid letters like a comma  in the POP3 server name 
  2. Do get your username correct. (probably your email address)

Bigger issues

Why do many students have to deal with this multiple account hassle instead of 1 person at the university provide good service in compiling a directory of existing emails  ?

[*] albeit with Icedove

Sunday, August 3, 2014

HOWTO backup mediawiki for easy restore on debian wheezy/squeeze

Creating a useful backup for a a web app like MediaWIki is somewhat more complicated process than backing up somebody's home directory.

While there is no warranty, I have tested this script on the Debian GNU/LINUX Wheezy release. Tonight I used it for reals to move a MedaiWiki on dead Wheezy server to a living Squeeze server.

Assuming you have a working, somewhat standard MediaWiki setup on Debian Wheezy (and probably squeeze), the script below creates a complete tarball backup of your Debian Wheezy MediaWiki install, including:
  1. Database 
  2. MediaWiki configuration
  3. PHP configuration
  4. Apache configuraiton
  5. README.restore , containing complete instructions on restoring your MediaWiki
By default, the script deletes backups older than 90 days, Edit the script and change the variable: delete_after_days if you don't like this. 

  To install / test install:
  1. copy the script below to /etc/cron.daily/backup_media
  2. edit the script to change the config variables (probably just mysqlopt to set mysql root password)
  3. make the script executable
  4. make the script readable only by root
  5. run the script.
  6. untar the tarball in /var/backups/mediawiki/
  7. examine the tarball contents, in particular README.restore


# based on

########### start configuration variables#########

# You need to change this:
mysqlopt="--user=root --password=your-mysql-db-root-password"     #  user/password to run mysql dump as

# you might want to change this:
delete_after_days=90                                              # how long to keep the backups

# you probably don't need to change these:
now=`date +%Y-%m-%d-%H_%M-%a`                                     # used to give you timestamped backup files, 
backupdir=/var/backups/mediawiki                                  # the directory to write the backup tar file to
dump_dir="$backupdir/mediawiki_backup.d/"                         # directory to hold backed up files
db_dumpfile="$dump_dir/mediawiki-restore.sql"                     # database dump to this file

########### no more configuration variables below #########

mkdir -p $dump_dir || exit $?

# dump the database
mysqldump  $mysqlopt wikidb  | gzip > "$db_dumpfile.gz" || exit $?

cp -ar /etc/mediawiki $dump_dir/etc-mediawiki                       || exit $? 
cp -ar /var/www/mediawiki_images $dump_dir/var-www-mediawiki_images || exit $?
cp -ar /etc/cron.daily/backup_mediawiki $dump_dir/                  || exit $?

cat << 'EOF' > "$dump_dir/mediawiki-setup.sql"

 -- #################         start HEREDOC for mediawiki-setup.sql" #################

  USE wikidb;
  CREATE USER 'wiki'@'localhost';
  GRANT DELETE ON wikidb.* TO wiki;
  GRANT SELECT ON wikidb.* TO wiki;
  GRANT UPDATE ON wikidb.* TO wiki;
  GRANT INSERT ON wikidb.* TO wiki;

  -- CHANGE mysql 'password'  (below) to password you configured 
  --  Mediawiki to connect to database with see: 
  --      grep wgDBpassword  etc-mediawiki/LocalSettings.php

  SET PASSWORD FOR  wiki  = password('password');

  -- #################         end HEREDOC for mediawiki-setup.sql"  ################# 

cat << 'EOF' > "$dump_dir/README.restore"

#################         start HEREDOC for README.restore  #################

# To restore on Debian wheezy  run commands below

# Assumptions are that you:
 #   use mysql / apache 
 #   will handle Dns on your own.
 #   know what the root mysql password  is on your system

sudo apt-get install php5-mysql mysql-server mediawiki mediawiki-extensions-base  mediawiki-math
sudo apt-get install mediawiki-extensions-confirmedit mediawiki-extensions-openid 

 # follow comment about changing password
 # re-discover password configured mediawiki to connect to mysql with
       grep wgDBpassword  etc-mediawiki/LocalSettings.php

 # change script to use that password for the mysql user 'wiki'
 sudo $EDITOR mediawiki-setup.sql

 # unzip the database backup
 gunzip mediawiki-restore.sql.gz

# create the  dataase and database user
 mysql -u root --password=the-password-for-wikiuser       < mediawiki-setup.sql

 # restore the database
 mysql -u root --password=your-mysql-root-password  wikidb < mediawiki-restore.sql

 # copy the files
 sudo mv /etc/mediawiki            /etc/mediawiki.original
 sudo mv etc-mediawiki             /etc/mediawiki
 sudo mv var-www-mediawiki_images  /var/www/mediawiki_images
 sudo mv backup_mediawiki          /etc/cron.daily/

 # replace the default apache conf file  for mediawiki with yours
 sudo rm /etc/apache2/conf.d/mediawiki.conf
 sudo ln -s /etc/mediawiki/apache.conf /etc/apache2/sites-enabled/wiki.conf

 # set the mysql root password  and other parameters you care to change
 sudo $EDITOR /etc/cro.daily/backup_mediawiki

 #################         Stop HEREDOC for README.restore  #################


cd $backupdir
tar -zcf $tarfile mediawiki_backup.d/ || exit $?
rm  -rf mediawiki_backup.d/ || exit $?

/usr/bin/find $backupdir   -type f -mtime +$delete_after_days -exec rm {} \;

############   END  of  backup script ###############


Saturday, February 15, 2014

I am a delegate to the 2014 Massachusetts state convention.

So I, Alex , Marlene Faulkner-Hussein , Patty Coffey and Stacie Ann Hargis are democratic delegates to the state convention representing Lowell Massachusetts second ward. Alicia Page, Fatima (sp?) and Marie-tou (sp?) are alternates.

Our vote decides who represents the Democratic party in the state-wide November elections. My big take aways were:

1. 90% of success is showing up.
2. It is a big advantage to be male.

I arrived late in tatty jeans and a tee-shirt but I still got in. There are (2) spots reserved for each gender and (1) open gender spot. There were only 2 men running.

Alex demonstrated the political acumen to show up on time, shave, wear a shirt with buttons, pants without holes. Probably most important, he was careful to stand next to Stacie. He crushed me 5 to 3 on the ballet for the first spot 5-3. (Thanks to Alicia and my mystery friend for voting for me.)

In the vote for the 2nd male delegate, I ran against nobody and beat him 8 - 0. I doubt I could have beat Marlene, Patty or Stacie, who all demonstrated much more than the minimum commitment.

I guess the gender quota was created some time in the distant past to get women in the game. Now that female political participation exceeds male participation, we might be dealing with un-intended consequences.

The alternative hypothesis is less creditable. I don't think women have more political power than men or that middle aged men need endangered species status.

An interesting bit about the female voting was Patty voted for somebody else the first round. She had only one vote and since it was me, I know she didn't vote for herself.

Wednesday, January 1, 2014

Download Microsoft Virtual Machines for testing IE

This page should rank higher in the search results: Download Free Windows Virtual Machines . It is Microsoft, it is official. There are VirtualBox, VMware, Virtual PC and Hyper-V images.

Sunday, September 29, 2013

HOWTO easy wrapper for php code beautifier / formatter

I wanted a tool that formatted php from the command line. phpstylist does what I want, but it is tedious to supply the options each time you run it. Below is a wrapper so you can set default options.

To install:

  1. Save phpstylist as /usr/local/bin/phpStylist.php
  2. Save the script below as /usr/local/bin/pstyle
  3. Edit /usr/local/bin/pstyle
    1. set MAKE_BACKUP='yes' , if you want to keep the original unformulated files
    2. set MAKE_HTML to a lower case 'yes or 'no' make an html copy of the formatted file
    3. un-comment the # STYLIST_OPTIONS+= lines that contain the php formatting options you want
  4. Be sure /usr/local/bin/ is in your $PATH

To run:

       pstyle phpFile.php
       pstyle phpFile1.php phpFile2.php phpFile3.php 

# wrapper for
# by

  set -u # halt on undefined BASH variables
  set -e # halt if command doesn't return 'no error' aka 0


MAKE_BACKUP='yes'  # lower case 'yes' or 'no', backup the php file before formatting it
MAKE_HTML='yes'    # lower case 'yes or 'no'   make an html copy of the formatted file


# uncomment/edit options you want
# see php -f phpStylist.php for more options
# --------------------

# Indentation and General Formatting:

#   STYLIST_OPTIONS+=" --indent_size 4  "      # 4 characters per indentation level
#   STYLIST_OPTIONS+="--indent_with_tabs          "      # Indent with tabs instead of spaces
#   STYLIST_OPTIONS+="--keep_redundant_lines      "      # Keep redundant lines
#   STYLIST_OPTIONS+="--space_inside_parentheses  "      # Space inside parentheses
#   STYLIST_OPTIONS+="--space_outside_parentheses "      # Space outside parentheses
#   STYLIST_OPTIONS+="--space_after_comma         "      # Space after comma

# Operators:
#   STYLIST_OPTIONS+="--space_around_assignment     "    # Space around = .= += -= *= /= <<<
#   STYLIST_OPTIONS+="--align_var_assignment        "    # Align block +3 assigned variables
#   STYLIST_OPTIONS+="--space_around_comparison     "    # Space around == === != !== > >= < <=
#   STYLIST_OPTIONS+="--space_around_arithmetic     "    # Space around - + * / %
#   STYLIST_OPTIONS+="--space_around_logical        "    # Space around && || AND OR XOR << >>
#   STYLIST_OPTIONS+="--space_around_colon_question "    # Space around ? :
#Functions, Classes and Objects:                        
#   STYLIST_OPTIONS+="--line_before_function         "   # Blank line before keyword
#   STYLIST_OPTIONS+="--line_before_curly_function   "   # Opening bracket on next line
#   STYLIST_OPTIONS+="--line_after_curly_function    "   # Blank line below opening bracket
#   STYLIST_OPTIONS+="--space_around_obj_operator    "   # Space around ->
#   STYLIST_OPTIONS+="--space_around_double_colon    "   # Space around ::

# Control Structures:
#   STYLIST_OPTIONS+="--space_after_if               "    # Space between keyword and opening parentheses
#   STYLIST_OPTIONS+="--else_along_curly             "    # Keep else/elseif along with bracket
#   STYLIST_OPTIONS+="--line_before_curly            "    # Opening bracket on next line
#   STYLIST_OPTIONS+="--add_missing_braces           "    # Add missing brackets to single line structs
#   STYLIST_OPTIONS+="--line_after_break             "    # Blank line after case "break"
#   STYLIST_OPTIONS+="--space_inside_for             "    # Space between "for" elements
#   STYLIST_OPTIONS+="--indent_case                  "    # Extra indent for "Case" and "Default"

#Arrays and Concatenation:
#   STYLIST_OPTIONS+="--line_before_array            "    # Opening array parentheses on next line
#   STYLIST_OPTIONS+="--vertical_array               "    # Non-empty arrays as vertical block
#   STYLIST_OPTIONS+="--align_array_assignment       "    # Align block +3 assigned array elements
#   STYLIST_OPTIONS+="--space_around_double_arrow    "    # Space around double arrow
#   STYLIST_OPTIONS+="--vertical_concat              "    # Concatenation as vertical block
#   STYLIST_OPTIONS+="--space_around_concat          "    # Space around concat elements

# Comments:
#   STYLIST_OPTIONS+="--line_before_comment_multi    "    # Blank line before multi-line comment (/*)
#   STYLIST_OPTIONS+="--line_after_comment_multi     "    # Blank line after multi-line comment (/*)
#   STYLIST_OPTIONS+="--line_before_comment          "    # Blank line before single line comments (//)
#   STYLIST_OPTIONS+="--line_after_comment           "    # Blank line after single line comments (//)

# provide help for bad args 
if [[ $# -eq 0  ]]; then
  echo '  Syntax is: pstyle <php file to style> [php file to style ] [..] '
  exit 1 

# did we copy phpStylist.php to right place
if [[ ! -r $STYLIST_CMD  ]]; then
  echo "$STYLIST_CMD is missing or unreadable"
  exit 1


for file_to_style in "$@"
    MAKE_BACKUP=${MAKE_BACKUP,,}       # make it lower case
    if [[ $MAKE_BACKUP=='yes' ]]; then
        cp "$1" "$1.bak" 

    CMD="php  -f $STYLIST_CMD $file_to_style $STYLIST_OPTIONS"
    $CMD > "$OUT_FILE"

    mv "$OUT_FILE" "$file_to_style"
    if [[ $MAKE_HTML=='yes' ]]; then
      php -s "$file_to_style" > "$file_to_style.html"

Thursday, May 30, 2013

What:: link to mood, running & pain

The Moodscope site is a very useful tool for monitoring the quality of your mood. Awareness is a good step toward improvement. If you sign up for the free site, you can elect to have daily email reminding you to measure your mood. As a bonus, the email contains a short reflection designed to help you manage your mood.

Today my volunteer submission Life As Accomplished Marathon Runner was the emailed reflection. If you are into running or mental health, you might give it a look