Cookie Notice

As far as I know, and as far as I remember, nothing in this page does anything with Cookies.

2014/10/10

The Frustration of Dealing with Users

This woman -- in honor of anonymity and cryptographic protocols, we'll call her Alice -- working on a startup has a problem. She has changes she wants to make in her website and she has no developer. She had contracted with a international developer, but that had fallen through.

I'm a developer, and I'm looking to expand beyond my primary work, so I offered to help.

Turns out, it's in Django, the Python web framework, although she wants to move it to something else. I'm not a Python guy and I'm not a CMS guy, but I'm willing to give it a shot.

Soon after she gives me access to her GitHub repo, she tells me that the international developer had taken care of the first thing, changing the logo, but those changes were a branch on someone's fork of her code. 

"OK," I thought. "This one's easy. First, she has to have the branch merged into the third-party's code. Then, that person needs to set her code as a pull request for Alice's code, and Alice then needs to merge that pull request. Last, she needs to ssh into her server, use git to fetch the changes and restart." The common thing with all of this? I can do none of it. I have no access to Alice's account. I have no access to the other user's account or repo. I have no access to the server. 

So, I draft an email, explaining the situation and the steps needed to get that code into position. Granted, on my end, I have allowed myself to become overburdened by time constraints. This becomes an issue with the relationship between Alice and myself, and and I own it. My primary goal for this is to justify the addition of the word "Django" to my resume, and anything else was gravy. But I was sure that a set of changes were coming, and it seemed a poor idea to work on the code until at least the changes were merged into Alice's main.

But, after some pushing (and repeated git pulls showed no change in master), I decided to try to get things running. I run a Windows laptop, because it's more about entertainment and ssh than real development, so I try to get Vagrant going and find that VirtualBox is corrupt. This takes some time to handle, time that I can't really call Alice's time, because it isn't her fault my laptop sucks.

And, as a personal failing, if I have nothing good to report -- I'm hitting issues and not getting it, or there are days after days where I'm unable to throw time or mental energy on a project -- I feel really bad about communicating no-good-news, so I go radio silence. Again, my bad. It's an issue I need to work on, and I own it and am trying to work through it. I don't want to tar others with a brush and claim I'm spotless.

Eventually, I get VirtualBox and Vagrant running, install Django and get the repo down, and I go to the "run this" file. I try to run it and it errors because a config file is missing.

So, at this point, this pseudocode is a simplification of my position.
# purpose of this program is to add two numbers

my $x = read_X_from_config_file() ;
my $y = read_Y_from_database() ;
my $output = handle_addition( $x , $y ) ;

sub handle_addition {
    # lots of complexity here.
    }

I'm expected to work on handle_addition(), but I have no idea what $x looks like because I don't have the config file, I have no idea what $y might be because I am denied access to the database and schema, and I really have no idea what changes might occur for handle_addition(). So, I explain my position, saying I'm in position where I'm technically able to proceed, but to really do anything, I need things from her.

The response is, since you don't have much time to contribute, I think it's best if I find someone else to participate in this project.

As I have said, it is not unreasonable for her to drop me from this, but I think she is really missing the boat as to what the issues are with her project. At no point was there any indication that there was any attempt to integrate the other developer's code, despite my suggestions, and at no point was I requested to ignore those coming changes and proceed. I say "You need to do this and tell me when you're done so I can go", and she acts like she's entirely waiting on me.

And, as this was one more side project than I can really spend time on, I don't feel I can, nor do I really want to, really get her to understand the situation.

So, I blog it. 

2014/09/12

Leveraging the Forecast.io API

A while ago, I got an API key for Forecast.io, with the intention of writing something that takes a look at the day to say whether I could bike to work without getting weathered on. I have not written that, and I certainly haven't started biking to work on a regular basis.

But now, I have written something that uses that data and presents it via notify-send and Pushover. I use notify-send a lot, but as the sources change, I have to change my scripts.


I've tried to cut things down to just the things that are necessary, but I could do more for that. Carp, for example, is Perl's way of sending errors to STDERR and exiting and such, but I really don't use it. There is a verbose flag that uses Data::Dumper. I'm turning epoch timestamps to times and dates, so I need DateTime (Thank you Dave Rolsky). The API uses JSON to send the weather data, and I use YAML to hold configuration data, so those modules are given. I want to get something from the web, so I use LWP.

So, download, use, adapt, learn, and stay dry!

2014/08/04

I get why I was wrong. Re: Database WTF

In a line, date_time NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP. Specifically, ON UPDATE CURRENT_TIMESTAMP. I did not want that. I wanted to default to current timestamp, but I didn't want it to change. Well, in one case, I think. Not here.

 D'oh!

A Database WTF

Database table exists, and has three columns worth mentioning:

  • run_id - the key to the table
  • date_time - timestamp created on row creation
  • ack_error - a boolean set to determine if errors are silenced.
This is my test code. It includes some functions I import.
  • db_do - Given SQL statements, does them. Used for INSERT, UPDATE, REPLACE, DELETE.
  • db_arrayref - Given SQL statements, does then and returns the result. Used for SELECT.
  • confirm_error_run - Given a run_id, gives current state of ack_error.
  • ack_run_error - Given a run_id, sets ack_error to true.
  • clear_run_error - Given a run_id, sets ack_error to false. 
    sub check_date {
        my $run_id     = shift ;
        my $check_date = q{
        SELECT date_time date
        FROM sequence_run
        WHERE run_id = ?
        } ;
        my $date = db_arrayref( $check_date, $run_id ) ;
        return $date->[ 0 ]->[ 0 ] ;
        }

    my $SQL = 'UPDATE sequence_run SET ack_error = ? where run_id = ? ' ;

    $DB::Database = 'genomicsdb' ;
    my $run_id = 318 ;
    my $date ;
    my $error ;

    say $run_id ;

    $date = check_date( $run_id ) ;  say $date ;
    $error = confirm_error_run( $run_id ) ; say $error ;

    my $do = db_do( $SQL , '1' , $run_id ) ;
    say $do ;

    say '-' x 40 ;
    $date = check_date( $run_id ) ;  say $date ;
    $error  = confirm_error_run( $run_id ) ; say $error ;

    ack_run_error( $run_id ) ;

    say '-' x 40 ;
    $date = check_date( $run_id ) ;  say $date ;
    $error  = confirm_error_run( $run_id ) ; say $error ;

    clear_run_error( $run_id ) ;

    say '-' x 40 ;
    $date = check_date( $run_id ) ;  say $date ;
    $error  = confirm_error_run( $run_id ) ; say $error ;


Changes to ack_error should be immaterial to date_time, right? Yet...

djacoby@genomics 12:00:44 ~ $ ./test.pl 
318
2014-07-31 14:36:43
1
1
----------------------------------------
2014-07-31 14:36:43
1
----------------------------------------
2014-07-31 14:36:43
1
----------------------------------------
2014-08-04 12:22:09
0

I just don't get it. ack_run_error() and clear_run_error() are essentially like the db_do( $SQL , ... ), and it's somewhat nondeterministic whether my db_do() and ack_run_error() reset the time. Confusing.

2014/07/27

2014 Body Goals - Status Report

Just because I haven't been writing about my goals doesn't mean I've forgotten them. In fact, a week ago, I participated in Zoo Run Run, a 5K around Columbian Park to benefit the Columbian Park Zoo, and my time was 34:12, which put me well past my goal for Endurance. My next goal is to come in less than 30 minutes, but I think I'll leave that for next year, rather than sign up for more races this year.

I have started working with the cable setup at the Co-Rec to move toward my goal of one pull-up. I was able to pull about 60 lbs, which is good. I don't really know the next step, but I'm happy with that and will work on a plan for pull-ups.

For the longest time, my personal record on the FitBit was the Independence Day Celebration where I was a volunteer and on my feet all day, exhausting myself but hitting 18K or so steps. Related but separate, I had identified when running that my legs weren't tired, my feet weren't bad, but I was huffing and puffing like a big bad wolf. I've since started to focus on breathing, and I put in a 20K step day on June 20th with the main difference being deep diaphramatic breathing. I haven't hit that PR since, but I have been more consistently hitting the 10K goal. I'm still not hitting it every day -- I wimp out on weekends -- but I've hit 10K at least one day a week every week except one I took as a vacation week. 

I've been trying to put HIIT into my runs. Dale Asberry suggested it in my goal-planning post and it is valid. I guess I see it as a level thing, in that if a person can't jog for 10 minutes, that person would be unwilling and unable to alternate sprints and rests for 4 minutes. I, as my okay-ish 5K time shows, am at a point where I should start doing something like Tabata sprints, which I have tried to start. It went well a few times before the 5K, but since, I haven't been able to really engage. Well, last time, I walked and breathed through 2 of 8 20-second sprint times, which 1) is more than I had the time before, and 2) is less than I wanted. 

For weight, I hit 202 lbs recently, but was 206 when I weighed this morning. I'm a little discouraged by the recent jump up, and I think this means I have other habits to engage, but I'm liking this neighborhood and feeling good about it.

I plan to generate a plan to engage my remaining fitness goals 

2014/07/23

Name Things Like You, or "Do you ever feel like an idiot?"

I was preparing a talk on developing against the FitBit API yesterday, which lead me to look at the FitBit website, and I found something called "Alertness Checker", which I didn't recognize. The others, like TicTrac and FaceBook and IFTTT, I did, but not "Alertness Checker".

So I revoked access.

And I found that "Alertness Tracker" is the name I put for my "app", by which I mean the connected series of programs I collect as fitbit_tools, which is the topic of the talk I'll be giving in a week and a half.

Of course, I felt like an idiot, once I realized the FitBit tools I had built my life around had stopped working. The key one is called fitbit.today.py, and it checks once an hour to see if I've made more than 100 steps in that hour, and chides me if I haven't. It's lots of small things, but when you realize you broke lots of small things, you feel like an idiot.

The first thing is, anybody could name a thing "Alertness Tracker". The specific thing that caused me to develop fitbit_tools is a point where I wore my FitBit Ultra every day for several weeks without noticing I hadn't charged it recently and it was a dead dead thing. Once I had enough to tell me if it hasn't synced in a few days, I knew enough to have it tell me if the battery level was anything but high. I wrote it in Python because I couldn't find any code (besides the Net::Twitter module) that really handled oAuth in Perl, but I did find the code in Python. After that, I decided that I'd like to know more about my trends than the FitBit dashboard can tell me, then put it out on GitHub, but since I had the App registered with FitBit, I stayed with it.

This is the main thing I want to hit. The secondary point is "Don't wallop things without checking", but the main point is that you have a style, and you should go with that style. Stay within the conventions of your project and team, of course, but you should be able to recognize yours as yours. In the lab, Rick and I are both Perl programmers, but our styles are very different, so we can open up libraries and look at subroutines and say "Hey, I don't know when I wrote that, or why I wrote that, or what stupid thing I was thinking when I wrote that, but I certainly know that I wrote that."

I recall, I faked the registration using FitBit's tools rather than writing a "get client tokens" oAuth script. I think I put that in the "I really should do that" category and forgot it there. Now, as I'm going to talk through it, and as I just re-experienced the issue, I have explained it in the README and have received a "round tuit", and so will have to write something up.

2014/07/09

Question about versioning with Perl modules

My main two languages are Perl and Javascript, and I've been coding them here for several years. This means that I have a body of code I'm perpetually updating and maintaining old code. And, while I am shamed to admit this, I test in production, I dev in production, and until we change our infrastructure, I don't see that changing any time soon.

In Javascript, there is a capability that I've found I like.

<script src="/lib/bulldada-0.0.1.js">

This means if I want to play around with rewriting bulldata, I can copy and poke at bulldada-0.0.2.js, and change the script tag to call for 0.0.2 when I'm happy with it. This means I am developing with the production server, but not necessarily with production tools. This makes me happy.

Let's think about Perl. In my programs, I can specify a version:

use BullDada 0.01 ;

In my modules, I can set that version:

package BullDada ;
our $VERSION = 0.01 ;
1;

Question is, how to have multiple modules with the same name in the same directory structure? By testing with Perl 5.18, I know that you can't have BullDada_0.1.pm and BullDada_0.2.pm, both starting with package Bulldada, and expect it to work. It seems that if I wanted to keep programs from using BullDada.pm with $VERSION = 0.01, I could specify BullDada 0.02, but I could also delete the old version and never use versioning at all.

Unless I'm doing it wrong. I'm willing to grant I'm doing it wrong. If there is a way to do it right, what is it?

2014/06/09

Exercise Before Work

Not meaning as a rule. "Exercise takes priority over coding." My goodness that is so not me.

Rather, today, I went to the CoRec and ran this morning, showered and went to work. Normally, I lay in bed watching YouTube videos for the extra hour. I hate to engage the day rushed, having done more than enough waking up barely in time to prepare myself to get there on time. 

As I think I have mentioned, I use jerry-rigged sunrise alarm clocks (one X10 and controlled from Linux via crontab and one a simple vacation timer) to turn lights on in my bedroom, which are set to go off at 5:30 am, and I'm usually awake between 5:50 and 6:20am. This morning, I think I hit close the later limit, watched a video or two, got dressed, and took the bus to campus, then kitted up to run at about 8am. I got an hour in on the upper track, taking a warm-p lap or two, doing four minutes of Tabata Sprints (20 seconds running as fast as I can, 10 seconds slower rest which I did as walking, for 4 minutes) then filling out the hour with laps. I got to 7343 steps before deciding it was time to clean up and get to work.

Exactly 7343 steps, as my FitBit attests

Walking to the office got me to ~9300 (photo not available) and I'm sure that the rest of my day will get me to my FitBit- and AHA-recommended 10,000 steps. I'm thinking I may do pre- and post-work runs on days when my evenings are not already scheduled. I'm liking this.

2014/04/18

The Graphics Interchange Format in Conversation

  • For me, it's a solved issue. When the inventor of a thing says it's pronounced a way, I give that weight.



    Similarly:



  • For me, it's a shibboleth. I have been involved in web development since 1996, and if you pronounce it "Gif" instead of "Jif", that's a sure sign that you're a noob. There's nothing wrong with being a noob, but there's certainly nothing right.
  • For me, it's also not a big thing. If you pronounce it the "wrong" way in a conversation with me, I won't correct you or start an argument about it. Starting an argument over things that don't matter, is dickery.



    Continuing one
    , on the other hand, isn't so bad.
  • The "It's not gramatical" argument cuts no ice with me. Saying the G has to be a hard G will always have me wondering how you'd pronounce "a German Giraffe", and while you say "But it comes from graphical so it must be a hard G", I flash to Police Academy 4: Citizens On Patrol, notice that "Citizens On Patrol" acronyms to COPs, and wonder if you would have me pronounce it "sops".
  • Yeah, I know going back to a Police Lobotomy movie as an argument is not too strong, but my mind has better things to do than develop and parse through a list of acronyms. Believe me, I've tried, and my mind has said "Let's watch YouTube videos. We could browse the web for pictures of smiling dogs. We could consider why your SQL tables are stupid. We could think about Steve Gutenberg movies. Really, anything but the acronym list thing." 

2014/04/11

About Me


I've been working on my resume recently. No reason, really. (If you have questions, ask elsewhere. I'm fairly easy to find.) A recent response to my resume tells me it sucks at telling the story of me. Not too surprised; the form sucked before, and has become the gameboard for competative Reverse Buzzword Bingo, where if you find the right combination, you get the job, which makes it counterproductive to even try to tell your narrative.

So, this is the story of me:


My first degree was a BS in Journalism and Mass Communication. My greatest experience was as copy editor of my student paper, where I did full-page layout of the State-and-Nation wire news section to our paper's style standards, collected the weather forecast (which I cribbed from the regional newspaper's front page by calling a friend who worked in a gas station) and read every dang word in the paper. I got this position by copy-editing a copy of one week's front page, where I not only found the errors they introduced to test me, but also errors that made it into print that week. The biggest lessons I learned were that I was really good at finding miniscule errors in large blocks of text, I was pretty good and making an attractive and readable layout if I knew what sort of look we were shooting for, and if you're really physically and mentally exhausted with more work left to do, fruit juice is better than soda.

Also, I learned that when people say "If everyone from Dan Rather to the guy who writes obit for the local fish-wrap were to die tomorrow, there would not be enough positions opened up to employ all the people who graduate with journalism degrees this year", that's not just a punchline, that's a suggestion that you change majors as soon as this conversation ends.

xkcd
After not finding work in journalism, I went back to school, where I received a BS in Computer Science, and worked for the university as a web developer. As with xkcd, my time with Perl has been much more useful in my post-collegiate career than the courses I took.

Also, the things I learned as a j-school student -- finding small errors in large text blocks, making text blocks readable and attractive, and handling exhaustion -- are incredibly useful for CS students and web geeks, too.

During that time, I found that what I loved to do was converting things to other things. If you sent this email address a message with this string in the subject and a URL in the body, it responded with that URL's web page as the body. If you went to a certain web page, you could send an anonymous email. I fell in love early with RSS and wrote many things that read it and many other things that wrote it. I wrote a thing for my home page that displayed one guitar if I had new mail waiting, and another guitar if I didn't. I once helped write a tool that scrolled RSS headlines across the top of a web page. My goal and hope was to be a developer who turned things into other things, preferably with web technologies on a Unix/Linux platform while contributing to Open Source projects, in an organization whose primary work is creating software.

A thing I didn't really learn is that, in the last year of your college career, your primary goal is finding something to do with your life after graduation. Preferably, something where you are paid. Successfully completing your courses and graduating is necessary but secondary. So, I found myself as a VMS admin and occasional Microsoft-focused web developer for a medical clinic. I often made things out of other things: I recall parsing the four-digit long-distance records by long-distance code and sending a list of calls to the user of record for each code. It was okay, but not in line with my desired workplace as above.

After that, I came to work at the university again, for a research lab. We do gene sequencing; I do full-stack web development. I did some of the stuff I like to do: I turned web forms into database updates. I turned database tables into web tables. I turned CSV into plots with R. I used Perl and Linux and Unix and eventually R. I coded  daily.

For a while, I worked through a temp service with a defense contractor. Mostly I maintained a lab. On occasion, I set up specialty PCs. I used a visual pre-processor that eventually made C code, which wasn't fun. The pay was somewhat better, but of the things in the goals-and-hopes bit above, I did nothing.

So, I came back to the lab again. I gained more responsibility, and continue to make things from other things. I turn database dumps into XML-filled ZIP files that our instruments use to handle the sequences we give them. I used Sikuli and Jython to script a Windows application to turn a bunch of XML files that held UUencoded BLOBs into searchable XML files. I turned database dumps into JSON, and turned JSON into web page tables and Javascript-created plots. I write libraries that make it easy turn things on various machines into messages on my Linux box, on my Windows box, on my phone.

My one-true-language is Perl. Most everything I write, I first try in Perl, and only go away from it if I can't make it work there. I code in JavaScript: Perl doesn't run on the web browser, so I have to. I'm trying Node.js, and am slowly finding my way toward usefulness. I'm writing more and more R, because it's the shortcut for making plots.

I dislike Python. On first hearing about it, I thought, "What's the point? It sits in the same niche as Perl, but isn't Perl. Why use it?" My first experience with it was some code which displayed available machines in an on-campus computer lab. It has been handed to me as "this works", but it was indented with tabs, and somewhere along the line, a space had been inserted before a tab, so it didn't work. I get readable code, and my journalism degree forced me to appreciate whitespace for readability, but here something I couldn't see ruined my day. My Sikuli project was written with Jython, the Java implementation of Python, because that's the only choice, and my FitBit Tools are in Python because I couldn't easily get OAuth working with Perl. I could see using it more, but I write Perl in a Perl shop right now.

The Greyjoys of the Iron Islands Do Not Sow; I Do Not Make Web Pages. I make tools. I make things that turn things into other things. This can be web, but it will be dynamic, either at the server side or the client side. If you want a web page -- something static, a billboard for the web -- you will be happier and I will be happier if someone not me made this page. For design, I can get you 50-75% of the way to an attractive and useful web tool, and probably more if given a standard to align to, but design is not where my strengths lie and are not where my interests lie.

This is me. This is the tools I like to use, the tasks I like to complete, the environment I like to be in. Right now, I am a developer, working with web technologies in a Unix/Linux environment, doing more but not enough to contribute to Open Source projects. I'm part of an organization that's (writ large) education and/or (smaller) assisting biological research. This means I'm not quite where I want to be, but better than I was for many years. So, I'm looking, but not looking too hard.

2014/03/14

My Body Plans For 2014: March and April, plus Status Report

First, my status report:

Caffeine:

The darker, the more cups recorded. I drank coffee on weekends. I often had more than 1 cup. I sometimes had more than two cups. I didn't drink it late, but I drank more of it. I consider this sort of a fail.

Weights: In February, I participated in a month-long triathlon. I rode lots of bike. I swam miles like it ain't no thang. I did not lift much. So, right now, I'm struggling to throw around the 20lb dumbbells, much less throw more reps of the 25lb dumbbells. But I did get the t-shirt.

Feet: I've started to wear my inserts again. I haven't developed a the series of range-of-motion exercises, much less committed to doing them daily. I have been walking a lot, which means I've been getting the activity without so much the stomping on my ankles.
Blue: max/week. Green: min/week. Orange: avg/week. Yellow: AHA goal of 10,000 steps.  Purple: Personal goal of 6000 steps.

Tools: I wrote a tool, more working against MongoDB than anything else, that checks and stores my steps per day from FitBit, and tell me if I haven't been taking more than 100 steps per hour.

Weight: I have made a new all-time-low weight, 208 lbs, but that was when I was out sick. Otherwise, I'm seeing a winter-month plateau. So, while I am not where I want to be, and see more jiggle than I want to see, I am not depressed about my progress.

Endurance: By the rules of the month-long triathlon, all steps counted and I knew that, by my normal walking, I could easily handle the distance. I have been doing other endurance exercises, but I haven't been doing anything to push myself in walking into running.

I think I have been consistent with my goals but not so much my plans. I think I haven't been doing it as good as I could, but I've been OK.

In part, I think I don't push myself nearly enough when I'm walking, so I'm starting back to the treadmill, and while the action will continue to be "walk on the treadmill until I hit my 10,000 steps" when I show up, I'll start trying to push the speed and elevation to keep my heart rate raised.

I have a pointer to a weather API to make the "Bike Today, Dag-nabbit!" tool.

That's enough for now.

2014/03/06

It started out with wanting to take in mass quantities of "ruin my day". I wrote a program that would traverse a directory tree and run Perl::Critic on everything with pl and pm suffixes. This would bring out all the depression in all the code I've written in the last five years.

It got to ~/bin/TESTING and crashed. This the program it crashed on:


Slight, isn't it. You wouldn't figure it out at first.

. This code works; you can have Unicode characters in variable names in Perl.

What you can't do is have Unicode characters in variable names in PPI, which means you can't have Perl::Critic analyze Perl programs with Unicode characters in variable names.

I have reported this bug to Perl::Critic. I don't expect them to be able to fix it, because it isn't in their code.

I have also reported this bug to PPI. Making everything Unicode-safe will be difficult, but considering how so many billions of people don't use languages based on the Roman alphabet, allowing them to write code in as much of their language as possible is a good thing. I can also imagine mathematicians liking $π instead of $pi, $θ instead of $theta, and so on, but the world population of mathematician programmers is smaller than the world population of non-western-european-language-speaking programmers, to be sure.

ETA: It is being fixed.

I don't really know how to make Perl code Unicode-safe, but I might pull down the source to PPI::Token::Word and figure it out.

2014/02/22

You Don't Want Another Computer! On Dash-Top PCs, Set-Top PCs and Pocket Supercomputers

A decade ago, I started to get obsessed with the idea of hooking a computer to my car. I thought about storing and displaying diagnostic and status information, about storing music and podcasts, about having it handle navigation and all sorts of stuff. I hit the point where I considered the trade-off between storage media — solid state would be more survivable, but I could get literally hundreds of much bigger spinning hard drives for the cost of an SSD — and decided to keep it a mental exercise.

I'm certainly not the only one who considered putting computers in cars. And, eventually it became easy, because the iPhone came around, phones all had data and GPS, so the media and navigation parts of the equation were solved, and with Bluetooth and even 1/8" jacks, cars became stereos with four wheels. The only parts remaining are diagnostics and auto behavior modification. You can get the Garmin ecoRoute for $100 or a Bluetooth-talking ELM327 OBDII dongle for much less, plus many free apps for your phone. To my knowledge, chipping isn't dynamic yet — you can't remap your engine control unit's behavior on-the-fly — but I'm sure it's coming. Andy Greenberg wrote in Forbes about all the things two security researchers could do to pwn a Toyota Prius, and they were looking at capabilities, not attack vectors.

Point I'm trying to make is, for all my dreaming of putting a car into my computer, I now have one every time I sit down in my car, and even better, it comes back out every time I get out, so I don't have to worry about it when I go to the office, and it isn't locked in there if I have an accident. Things like Ford's Sync work best when they realize they're just an interface between your phone and your car.

(I now have an OBDII-to-USB cable and a Raspberry Pi, so I will have a computer in my car, but I'm going to explore the API and try to do more of the controlling-the-car things than a phone app would do. Certainly I'll still listen to podcasts while driving with my phone, not my Pi. I'll be sure to blog about it later.)

But I am not here to talk about car PCs.

I'm here to talk about home theater PCs.

I have one. It's an old HP that was handed down to me because it had connection issues I have never been able to replicate. The CMOS battery had died and corroded, too. Now it runs Windows 8.1 — will the indignities never end? — and I have it in my bedroom connected to the VGA port of my TV. I don't often use it, because when I start throwing pixels through the video card, the fan starts up and I have to turn it up to hear anything. I use it when I want to play with Windows 8, so not a lot.

When I want to consume media these days, I pull out my phone or tablet and point it at the Chromecast. More and more apps are coming — Google's opened the ChromeCast API — so the sweet spot between "essentially a wireless HDMI cable" and "smart thing that holds on to your credentials and streams you stuff" is being filled with more and more things.

I have a BluRay player. It comes with a wired ethernet jack in the back, and I have on occasion had it set up so I could use the networking portions, but when you're searching for YouTube videos or trying to type in passwords, the remote is a poor interface. Updates to YouTube's TV interface and others now bring up a URL you browse to that sets up the connection between your box and your account, but that's an update nobody ever pushed to my BluRay player; basically, once they make the next device, they don't care about the old one, so nothing cool is ever going to come back to my several-year-old player. This is what I fear is the fate of proprietary smart TV interfaces: the next cool thing in streaming apps will come next year, while I'll hold on to any TV I buy for several years, which means I'd have an ugly interface I hate for a decade after the company doesn't care.

We just got a Roku; I haven't even used it yet, and have only touched the remote once. It makes sense for the living room TV, which is old enough that it doesn't have an HDMI port. There is a Roku app for Android, so I'm sure I'll use it in a similar way to how I use the ChromeCast.

I saw a presentation recently that showed the older Google TV interface next to the Apple TV remote, arguing that every button in the full-keyboard-rethought-as-an-XBox-controller is a delayed design decision, and that the sparseness of the Apple TV is a selling point; I haven't used the Apple ecosystem, and I understand it's really slick, but trying to handle deep, full and varied content through such a limited interface. (Sophie Wong has a fuller discussion with photos of both remotes in a blog post.) The Roku's remote adds to that by having a hardware button to go directly to Blockbuster's app; Blockbuster is defunct and now there's a button always pointing to a dead thing. Software remotes like the Roku app should be easily updated to the sweet spot of usability.

When some people I know have tried the ChromeCast, they've objected, because they want a computer they control, not a second screen for their phone. I recognize that thinking, because really, that's what I was looking for in a car PC, before I realized that it isn't what I really want. Nothing built-in, as little smarts as I need to talk to it, and as much controllable from my phone as possible.

Do you have an argument for set-top boxes I haven't talked through? The only one I can think of is that content providers sometimes allow their content to be viewed in one forum and not others; the video to the left of Marina Shifrin telling her boss she quits through the art of interpretative dance is one of many that is cleared to be shown through TV only. As the use of phones for connectivity dwarfs the use of desktops and laptops, I'm sure that'll fall. If there's another argument, I'm game to engage it.

2014/02/21

Using Fitbit to keep me moving

I have a FitBit Ultra (which I have discussed before) that I use to keep track of my daily activity, trying to force myself into higher and higher numbers, toward the AHA-suggested 10,000 steps per day.

In all honesty, I have dropped my personal goal from 10,000 steps to 6000, because 6000 is an amount that I can adjust my day to get, while I have to spend hours of my evening walking around to get myself up to 10,000. With 6000, I have a lower barrier, so I don't beat myself up with disappointment as easily. I still do, because I still have <3000-step days, but with 6000, I feel I have a fighting chance.

I have a FitBit but I don't pay for the upgraded API, but I can check every hour. And now I do. 

#!/usr/bin/env python

from oauth import oauth
import datetime 
import httplib
import os
import pymongo
import simplejson as json
import time

import fitbit
import locked
import pushover as p

def main():
    checker = locked.locked()   # determines if screen is locked
    if not checker.is_locked():
        from pymongo import MongoClient # connect to mongodb
        client = MongoClient()          # connect to mongodb
        db = client.fitbit              # connect to fitbit DB 
        reads = db.daily_reads          # connect to collection 
        now = datetime.datetime.now()       # what time is now?
        datestr = now.strftime("%Y-%m-%d")  # now in date format
        isostr  = now.isoformat()           # now in ISO format
        fb = fitbit.make_class()                    # connect 
        fbr = fb.activities_date_json( datestr )    # get updates
        summary         = fbr['summary']            # get summary
        steps  = summary['steps']                   # pull out steps 
        new_read = {}               # create new read
        new_read["date"] = datestr     # date == datestr
        new_read["time"] = isostr      # time == ISO
        new_read["steps"] = steps      # steps is steps to date
        
        if 0 == reads.find( { "date" : datestr } ).count(): # if nada 
            for read in reads.find():       # clear out 
                id = read["_id"]
                reads.remove( { "_id" : id } )
            reads.insert( new_read )        # insert 
        else:
            old_read = reads.find_one()
            delta_steps = new_read["steps"] - old_read["steps"]
            if delta_steps < 100:
                msg = "You took " + str(delta_steps) 
                msg = msg + " steps in the last hour. "
                msg = msg + "Go take a walk."
                pu = p.pushover()
                pu.send_message( msg )
            id = old_read["_id"]
            reads.update( { '_id' : id } , new_read )

if __name__ == '__main__':
    main()

There are three modules that are mine: the fitbit module which comes from my fitbit_tools repository; locked module which uses xscreensaver-command to determine if the screen is locked (if I'm not at my desk, my step counter isn't being updates; and pushover, which uses the Pushover service to keep me informed. I could and maybe should have it do speech with Festival or pop to my screens with Notify or Snarl, which also are desktop-centered tools, but this is what I have.

Similarly, perhaps this task is better suited to a key-value store like Redis than MongoDB's document store. At most I'm having one entry per day and the first entry of a day clears out all previous entries.

But, notwithstanding all the perhaps-suboptimal design decisions, this is an example of how coding and quantifying yourself can help you improve your life.

2014/02/15

If ( starting_over() ) { start( this ) } # 'this' undefined

I listened to FLOSS Weekly's podcast on nginx today, and it hit a cap on something that I've been considering for a while. Basically, I have worked in a few technology stacks over the years, but if I was to say what I've spent most of my development time with, I'd have to say Linux machines, Apache web servers, MySQL databases and programs written in Perl. 

This is not exclusive: For a while, I did work with Windows on whatever their default server was, doing Active Server Pages with VBScript connecting to an Oracle DB, while being admin for a VMS system. I've written Python, Bash, R and JavaScript. I've tied hashes to Berkeley DB and used flat-file databases before I learned the next steps. Not that I ever got it into production, but I've written Visual Basic for Embedded to build an app on an iPaq in the days before .NET. And I'm sure there's more that I've forgotten. But the things I write for myself tend to be hosted on Linux, distributed over the web, served by Apache, storing to MySQL and generally written in Perl.

We'll call that my comfort zone.

The comfort zone is a good place. You have a job that works in the comfort zone, you know where to start. You likely have a "framework" in place that you can adapt to what the new thing is. The world can turn quite a lot while you sit in your comfort zone.

Aside: I generally don't use frameworks, because I know my comfort zone well enough that I can make separate things fast enough by adapting existing things that I'd rather do that than spend time trying to learn a framework. With Catalyst, I timed out twice before getting to the point I could do something with it. I'm better with Dancer, which is closer to the level of web programming I'm comfortable with, but the individual-pieces-of-CGI I work with doesn't lend itself to the web-applications world. Our lab still does puppies, not cattle. Consider that part of the comfort zone.

The first thing I missed was Python and Django. I was the last remaining Perl guy when most everyone I knew went to Python in the late 1990s and early 2000s. Then there was Ruby and Rails. I could probably get to iterative and recursive Fibonacci on both without looking too much at the documentation, but I've not spent quality time with either. 

There are two problems with staying in a comfort zone. First is, the world goes on, and eventually nobody values your comfort zone. There are still places where they want Perl people, but other languages are higher in the desired skills list. The other is that it's a good way to burn out. Everything looks like X and you get tired of looking at X

I think the hot spot for web development, the place I'd be if I was starting out right now, is still Linux, still Web, but nginx, MongoDB and Node.js. I like what I've seen of Redis and have used it in a personal project (and really, I've spent enough time with it to REALLY like MySQL; I still think in tables), but I think that MongoDB maps well with JSON (which works well with Perl hashrefs, which is the source of my love for it all, I won't lie) and is my fave so far of all the NoSQL databases I've played with so far.

So, I'm curious: if you were starting over today, knowing the computing environment and your own preferences, what would you start with? Why? Is this stuff you use right now?

2014/02/09

Question about New School Web Authentication and Images

Time was, you authenticated via htaccess, and the server handled the details for you. If you gave the right password, you could access the materials in a directory, and if you didn't, you couldn't.

Now, we're authenticating with OAuth with Google or the like, and the smart stuff you write knows whether you're authenticated or not, but that kinda happens at the client level, and your server doesn't know whether it's authenticated or not.

xkcd
If you're talking to the database to get content, there has to be some code there that says "OK, there's authentication, so we know Alice's content from Bob's, but if there's something saved to file, like an image — You could put your images in a database table, and I've done it, but in practice it's kinda stupid — that means that image is hardcoded, so anyone could browse around your authentication.

So, is the solution to have the images in a non-web-shared directory and have code determine whether it's OK to send the image or not? I've done that, too, but it seems like you stop the server from doing what it's good at. As efficient as you can make a program that takes in a user identifier, determines if it's acceptable, reads in a file and sends either a good image or a "that's not okay" image, that's always going to be slower than letting your server just send that image.

So, do I own that slowness? Is there another way that I just don't know yet? I'd put this on Stack Overflow if I even knew how to pose the question. Any thoughts?

2014/01/31

Trying just MongoDB, and it works!

And it works!

#!/usr/bin/perl

use feature qw{ say state } ;
use strict ;
use warnings ;
use Data::Dumper ;
use MongoDBx::Class ;
use MongoDB ;

my @movies ;
push @movies,
    {
    title           => 'Blade Runner',
    rating          => 'R',
    releaseYear     => '1982',
    hasCreditCookie => 1
    } ;
push @movies,
    {
    title           => 'Thor',
    rating          => 'PG-13',
    releaseYear     => '2011',
    hasCreditCookie => 1
    } ;

{
    my $client     = MongoDB::MongoClient->new( host => 'localhost', port => 27017 ) ;
    my $database   = $client->get_database( 'test' ) ;
    my $collection = $database->get_collection( 'movies' ) ;
    my $movies     = $collection->find( ) ; # READ
    while ( my $movie = $movies->next ) { # would prefer for ( @$movies ) {} but oh well
        my $title = $movie->{ title } ? $movie->{ title } : 'none' ;
        my $releaseYear = $movie->{ releaseYear } ? $movie->{ releaseYear } : 'none' ;
        my $count = $movie->{ count } ? $movie->{ count } : 0 ;
        say qq{$title ($releaseYear) - $count } ;
        my $id = $movie->{ _id } ; # every mongodb record gets an _id
        $collection->remove( { _id => $id } ) if $title eq 'none' ; # DELETE
        $collection->update(
            { title => $title },
            { '$set' => { count => 1 + $count } }
            ) ; # UPDATE
        }
    #LADIES AND GENTLEMEN, WE HAVE CRUD!!!
    }
exit ;
{
    my $client     = MongoDB::MongoClient->new( host => 'localhost', port => 27017 ) ;
    my $database   = $client->get_database( 'test' ) ;
    my $collection = $database->get_collection( 'movies' ) ;
    my $data       = $collection->find( ) ;
    for my $movie ( @movies ) {
        say qq{$movie->{ title } ($movie->{ releaseYear })} ;
        $collection->insert( $movie ) ; # CREATE
        }
    }

The lesson might be Don't Trust ORMs, Do It Yourself, but I hope that there's some reason to use these things.

You Had One Job, MongoDBx::Class Documentation

So, after yesterday, I started back with the command line interface to MongoDB. I found I can do what I want with it, which of course is creating, retrieving, updating and deleting records. So, I try working with Perl, my go-to language, and I install MongoDBx::Class. The following code, especially the $db-&gtlinsert() is closely adapted from the CPAN page.


#!/usr/bin/perl

use feature qw{ say state } ;
use strict ;
use warnings ;
use MongoDBx::Class ;

my $dbx = MongoDBx::Class->new( namespace => 'MyApp::Model::DB' ) ;
my $conn = $dbx->connect(host => 'localhost', port => 27017 , safe => 1 );
my $db = $conn->get_database( 'test' ) ;

my @movies ;
push @movies , {
    title => 'Blade Runner' ,
    rating => 'R' ,
    releaseYear => '1982' ,
    hasCreditCookie => 1
    } ;
push @movies , {
    title => 'Thor' ,
    rating => 'PG-13' ,
    releaseYear => '2011' ,
    hasCreditCookie => 1
    } ;

for my $movie ( @movies ) {
    say qq{$movie->{ title } ($movie->{ releaseYear })};
    $db->insert($movie) ; # How the documentation says it should go
    }


2014/01/30

You Had ONE Job, Mongoose.js Documentation

Source
I'm trying to learn Node.js, MongoDB and Mongoose.js as an ORM connecting the two. I don't know what I'm doing yet, going through the early example code. I come to this as a reasonably experienced hand with Perl and MySQL. The first thing people write is a "Hello World" application, where you give it an input, commonly your name, and it gives you an output. In data, the four actions you want are Create, Read, Update and Delete, often used as CRUD. When trying out a data-storage system, you want to be able to Hello World your data.

The following is code adapted from the front page of Mongoosejs.com and the first link to documentation.

#!/usr/bin/js

/*
 * test_mongo.js
 *  adapted from mongoosejs.com
 *  
 * Getting up to speed with MongoDB, Mongoose as an ORM, ORMs in general,
 * and Node.js. 
*/

// Testing direct from http://mongoosejs.com/

// initiallizing connection to MongoDB 
var mongoose = require('mongoose');
mongoose.connect('mongodb://localhost/cats');
var db = mongoose.connection;
db.on('error', console.error.bind(console, 'connection error:'));
db.once('open', function callback () {
    console.log( "Yay" );
    });

// Schema - what comes from DB
var kittySchema = mongoose.Schema({ name: String }) ; 
kittySchema.methods.speak = function () {
    var greeting = this.name
        ? "Meow name is " + this.name
        : "I don't have a name" ;
    console.log(greeting);
    } ;
kittySchema.methods.save = function ( err , cat ) {
    console.log( cat ) ;
    if ( err ) {
        console.log(err) ;
        }
    cat.speak() ;
    } ;

// Model - what we work with
var Kitten = mongoose.model('Kitten', kittySchema) ;
Kitten.find(function (err, kittens) {
    if (err) // TODO handle err
    console.log(kittens)
    })

// Objects - instances of models
var silence = new Kitten({ name: 'Silence' }) ;
var morris = new Kitten({ name: 'Morris' }) ;
var fluffy = new Kitten({ name: 'Fluffy' });
var blank  = new Kitten({ });

console.log( '------------------------' ) ;
silence.speak() ;
morris.speak() ;
fluffy.speak() ;
blank.speak() ;
console.log( '------------------------' ) ;
silence.save() ;
morris.save() ;
fluffy.save() ;
blank.save() ;
console.log( '------------------------' ) ;

process.exit(0) ;


save() doesn't seem to save, or do anything, really. speak() works, but why shouldn't it? The reason I'm doing this is so that Mongoose can stand between me and MongoDB. Mongoose has one job. The documentation has one job: to show people me how to do just that.

One Job!

2014/01/29

Coming to Terms with Javascript's Not-Quite-Procedural Nature

I'm creating a web application. I've written HTML code on the server before and have decided templates are best, because whatever language, writing code that generates HTML is always worse than making a template that has holes you can fill with your data. This is why I now love Perl's Template Toolkit.

Funny thing is, making the code client-side doesn't make it much better. For now, I'm using Mustache.

There are many things you can easily do in JavasScript, but multi-line variables are not pretty in JavaScript, so it's far better to have external templates and import them. This is my current code to import a list of templates, which so far are div_request.m, div_sample.m and div_final.m.

var accordion_request = {} ;
accordion_request.m_path    = '/dev/dave' ;
accordion_request.templates = {} ;
accordion_request.template_fetch = []
accordion_request.template_fetch.push( 'div_request' ) ;
accordion_request.template_fetch.push( 'div_sample' ) ;
accordion_request.template_fetch.push( 'div_final' ) ;

accordion_request.get_templates = function ( ) {
    for ( var t in accordion_request.template_fetch ) {
        var template = accordion_request.template_fetch[t] ;
        var name = [ template , 'm' ].join( '.' )
        var url = [ accordion_request.m_path , name ].join('/') ;
        console.log( template ) ;
        console.log( name ) ;
        console.log( url ) ;
        $.get( url , function ( data ) {
            console.log( ': ' + url ) ;
            accordion_request.templates[template] = data ;
            }  ) ;
        }
    }

Do you see the problem?

JavaScript does not block. So, we convert div_request to div_request.m to /dev/dave/div_request.m, then we set the jQuery $.get() off to get that url, then we convert div_sample to div_sample.m to /dev/dave/div_sample.m and set that off to $.get(), then jump back to div_final.

By the time $.get() starts working, url is "/dev/dave/div_final.m", so we get a console log that looks like:
div_sample
div_sample.m
/dev/dave/div_sample.m
div_request
div_request.m
/dev/dave/div_request.m
div_final
div_final.m
/dev/dave/div_final.m
: /dev/dave/div_final.m
: /dev/dave/div_final.m
: /dev/dave/div_final.m

I now believe I need to write a function that takes url and gets and writes it, so that it has it's own scoped url rather than using the one in get_templates(). We will see.

2014/01/10

My Body Plans For 2014: January and February

I've covered my 2014 priorities and goals previously. Now, I'm starting to make plans, but I'm not going too far ahead. Just the first quarter. Will make further plans in support of my goals as the years go on.

It is important when planning behavior change to remember that willpower is finite, and so changing too many behaviors will doom a plan to failure. So, the plans will be set by month, not by task.

January

Sticking to strength training and diet at the beginning of the year, because running in snow sucks. 

Caffeine -- I have been trying to cut down of caffeine, and now follow these rules:
  • coffee only when I'm at work 
  • no coffee after work 
  • no more than two cups a day 
 I will be coming off a two-week vacation, so I'll be reset with caffeine. I could either see if I can code without coffee, or I can go down to one cup a day. I believe I'll go to one cup a day. 

Strength -- I have been going to the gym after work when I can, which tended to be Mondays and Thursdays. It's been ill-defined thing, with me picking up things as I figure them out. I know nothing about the gym -- the only thing I learned from gym class in school is to fear my fellow man -- but I've found some sources and now think I have a protocol to start with.

AreaExerciseCurrent Weight
Chest Dumbell Fly 15lbs
Dumbell Bench Press 25lbs
Back Dumbell Row 25lbs
Shoulder Dumbell Press --
Dumbell Shrug 25lbs
Arms Dumbell Curl 25lbs
Dumbell Extensions --
Glutes Dumbell Deadlift --
Quads Body Weight Squats
Core Planks
Sit-Ups


Once I get solid with Body Weight Squats, I might start doing them with weights. I'll work up how the circuit goes with the Quads and Core as I start to work through them. 

The source I read suggested that you do reps and sets such that they add up to 25. I put it to 30 to make all the math right, and came up with this.

Monday Wednesday Friday
  6 sets of 5 reps     3 sets of 10 reps     2 sets of 15 reps  

My plan is to do the circuit following this, going in before work on Monday Wednesday and Friday. That'll help get my body and mind going without coffee those days.

February
 

Feet -- Starting this month, I start to do range of motion exercizes to get my right foot's range of motion to more closely approximate the left. Will get into that later.

Tools --  Will also develop tools to prepare for coming months. Specifically: 
  • check against Forecast.io to see if the day will be dry and warm. If so, have it tell me to run.  
  • additions to weight tools to 1) accept Google+, Facebook and Twitter login 2) allow multiple users 3) show progress on weight goals with sexy plots done with D3.js 
  • additions to FitBit tools 1) add to handled API calls 2) find best/worst days of the week 
  • obWeightTrainingApp work 
March
Endurance -- This month, I start preparing for the 5K, beginning the Couch to 5K. Adding HIIT Tabata sprints. Also, start finding and signing