Thoughts on One Trick Ponies

When your company is a one trick pony (Apple), that pony (the iPhone) better be a compelling trick.  ZDNet’s Ed Bott just wrote an article that shows where Apple, Google, and Microsoft gain their income from.  While Google predictably gets most of the money from advertising and Microsoft has pivoted from the Windows company to the Services company, Apple remains as the company that sells the iPhone with other things.

With 68% of Apple’s income coming from the iPhone, protecting that product line is a big deal for Apple.  With the relative maturity of the Android platform, it’s incumbent on Apple to keep the iPhone as the premium device.  It has to be different and it has to be better in order for Apple to keep that revenue stream high.

There’s an argument that I have had with a few other developers about mobile development tools that let you write once, deploy everywhere.  Tools like Cordova, where the screens are defined in HTML and the code in JavaScript.  I’ve been told that I should be using that instead of tools that let me write to the native platform.  Xamarin tools in my case.  The Cordova (and other web like development tools) are a threat to Apple.  If you can write an app with Cordova and it runs the same way on Android as it does on the iPhone, what is the point in paying a premium for Apple hardware?

That’s why Apple continues to add functionality and services that doesn’t exist on other platforms.  Features like 3D Touch or FaceTime.  Remember when FaceTime was announced?  Steven Jobs said it would be an open industry standard.  That was in 2010.  Six years later Facetime is still a closed platform.  If FaceTime ran on Android, customized Androids would be the rage at schools, not the iPhone.  Apple is never going to open up FaceTime.  But they will continue on enhancing that one trick.

Get AMPed for faster page loading on mobile

I just updated this blog to use the Accelerated Mobile Pages (AMP) plugin for WordPress.  AMP is an open source project designed to optimize page content for mobile pages.  It uses a subset of HTML and some JavaScript to trim down the content of a web page.  Early testing has shown that AMP pages load four times faster and use eight times less data than a traditional web page.

AMP filters out 3rd party JavaScript code (aside from the AMP code), which basically takes out every analytics package.  Iframe and object tags are stripped out.  The HTML5 multimedia tags (img, video, audio) are replaced with custom elements (amp-img, amp-video, amp-audio).  On a page that uses the AMP runtime, a hidden link is added that provides the URL to AMP optimized version of the web page.  With the WordPress plugin, the AMP page is the original URL with “/amp” appended to it.  This will work on any hosted WordPress site.  Self hosted sites would need to add the plugin.

For this blog post, if you want to see the AMP version, click here.  It will load much faster, but without any special styling.  The banner image will be gone.  I like to use images from the Getty collection and as part of the terms of use, you have to embed the image with their custom template and that template puts the image in an iframe.  And since iframes are forbidden in AMP HTML, good bye image.

The AMP runtime manages the amp-* HTML tags and can manage the loading and unloading of the resources. CSS is also limited for performance reasons.  That trade off gives you the performance boost on mobile.  AMP is already being used by sites like Pinterest, Twitter, New York Times, The Verge.

AMP is not for everyone.  It is basically serving up a subset of your experience and you will lose custom animations, analytics, etc.  So where is it useful?  When you want a page to load as fast as it can.  Like a status page for service.  Google is already indexing AMP pages.  While it’s not currently giving preference to AMP pages, it does rank pages by page load.  AMP is open source and you can view the code on GitHub in the ampproject repository.

Generating new row numbers in SQL based on a starting value

One of our support people came to me with an interesting task.  He needed to add rows from a SQL Server table to another table and populate a row number type of field.  That field needed to be generated by his SQL statements and start with the next number after the highest value already in the table.  And he couldn’t use an autoincrement field.

My first thought was to read the new values into a table variable with an column for that row number field.  Then iterate over that table with a cursor and populate that column.  That was a very bad thing and was quickly banished.  So I thought about it a bit and sent him the following example.

-- The following temporary tables represent the 
-- the data to be worked with.  They are temp
-- tables only to illustrate the code
create table #BaseTable
    ID int,
    Name varchar(64)

create table #NewData
    Name varchar(64)

-- Lets throw some sample data into the base
-- table.
insert #BaseTable(ID, Name) values (1, 'Joe')
insert #BaseTable(ID, Name) values (2, 'Jim')
insert #BaseTable(ID, Name) values (3, 'Jay')
insert #BaseTable(ID, Name) values (4, 'John')

-- Lets populate the data table that we want
-- to get the data from
insert #NewData(Name) values ('Ken')
insert #NewData(Name) values ('Keith')
insert #NewData(Name) values ('Kevin')

-- Declare a variable to hold the maximum
-- value of our row number field
declare @LastRow int

-- Assign the max value to our variable
set @LastRow = (select MAX(ID) from #BaseTable)

-- Add the rows into the destination tabkle
insert into #BaseTable(id, name)
-- Use the rank() function to generate row
-- numbers for the rows that we are adding
-- and add the @LastRow to get the next highest
-- values
select rank() over (order by n.Name) + @LastRow as rank, n.Name
from #NewData n
order by rank

-- Show our merged results
select * from #BaseTable

-- Example over, cleanup
drop table #NewData
drop table #BaseTable

To generate the row numbers from the merge table, we use the rank() function.  Rank() returns the rank of each row within the partition of the result set.  We specify the partition with the “over (order by” clause.  If you have multiple fields to make a row unique, you would need to specify each field in the over clause.

FBI vs Apple vs the Consequences

iPhone 5C, FBI Edition

There has been a lot of conversations about the court order that the FBI has filed on Apple.  If you are following this story and have not yet read the court order, you should read it now.

The FBI is asking for Apple to disable the code that slows down and locks access to the device when too many incorrect pass codes are entered. They are not asking for Apple to decrypt anything and have stated that Apple could keep possession of the device.  The Trail of Bits blog has a very write up of how Apple could comply with this request.

My initial thought was that this was a reasonable request.   What tipped me over to Apple’s view was what will happen afterwards.  Once this becomes a precedent, other countries could make the same request of Apple.  Countries with a less than stellar record of civil rights. The 800 lb gorilla in that room would be China. The same people who brought us the Golden Shield Project (aka the Great Firewall of China) would now have the opportunity to add new laws requiring backdoors into all mobile devices sold in their country. You may have seen the tweet from Snowden on this subject:

There are other ways that the FBI can get some of information that would be on the phone.  I would assume that they have already subpoenaed the mobile carrier to get the phone records.  That would tell the FBI who was talking to Farook and Malik.  According to the court order, the phone was on the Verizon network.  If Farook and/or Malik were sending SMS text messages, then Verizon has those messages on file and can supply them in response to a court order.  If they were using iMessage and were backing the phone up to iCloud, Apple could hand over that information via court order.  There’s a good article on that goes over the multiple ways information can be accessed from an iPhone.

Hard cases make bad law.  While I sympathize with the reasons that the FBI is making this request, the long term consequences would be worse.  We  face the real risk of having weaker security in mobile devices.  At the end of the day, Apple is making the right choice in opposing the court order.  It sets a bad legal precedence and they should fight it all the way to the Supreme Court.

Use Powershell to batch rename files from digital cameras

If your household is like my household, then you’ll have more than one digital camera laying around.  My wife and I have similar Sony cameras (NEX-6 and an a5000).  For easy of management and the sake of my own sanity, I back up the images from both cameras together.

I store my images in a chronological order.  A folder for each year, then sub folders for each month.  It’s simple to manage and it’s easy to find pictures.  When daughter(0) asks where the pictures are from last year’s lake vacation, I can tell her it’s in “2015\7”.   There are times where I create folders for special purposes, but by and large the collection is in chronological order.

Since Sony prefixes every image with the letters DSC, I wanted a way differentiate between my images and my wife’s images.  I also wanted to eliminate any chance of two images having the same name.  There many ways of doing batch file renaming.  I wanted something simple.

That brings us to Powershell.  There’s very little that you can’t do with Powershell and a lot resources for it.  In this case, a batch rename is trivial:

# Pipe the contents of the DIR command
# to the Rename-Item command and do text
# replacement
Dir *.jpg, *.arw | 
  Rename-Item –NewName { $ –replace “DSC“,”ABM” }

That command will take all of the files in the current folder with the .JPG and .ARW (Sony’s RAW file) extension and rename any of them that have “DSC” in the name to use “ABM”. This will replace the “DSC” in any part of the filename. If you want to just match files that start with “DSC”, then you could RegEx pattern matching. Since I didn’t need that level of pattern matching, I chose not to dive down that rabbit hole.