Mark Godwin

Posts

January 10, 05:51 PM
If you have found yourself in the (un)fortunate position of having to use LinkedIn's shareArticle API to share a URL, you may notice that there is around zero articles detailing exactly how to utilize the API correctly.  Even LinkedIn doesn't have an official developer support page which details exactly how to use their shareArticle API.

Too Long, Didn't Read:
Use proper meta tags and image combinations and just give LinkedIn the url parameter to their shareArticle API

Lucky for you I recently had to deal with this horribly under-documented share functionality at work and am going to outline exactly what to do to get it working!

Theoretically the shareArticle API should work like this, and actually this is how you want to use it:

www.linkedin.com/shareArticle?mini=true&url=http://www.mycoolwebpage.com

You may notice that if you try this with your webpage, LinkedIn doesn't gather all the correct information about your page, or possibly it doesn't gather any information about your page except for its title and url.  Where is the thumbnail?  And where is the description?  Lucky for you there's no documentation describing how you can get LinkedIn to pull that information save for a couple forum postings...that have no helpful information.  But the shareArticle API also allows you to pass some GET params to the shareArticle API - to trick you, you see, into doing it the wrong way.  For example, you can specify title, description, source and a couple other things (ooh this looks like it solves our problem!):


www.linkedin.com/shareArticle?mini=true&url=http://www.mycoolwebpage.com&title=mycoolTitle&source=dummysource.com&desc=blah%20blah%20blah...


Except...that if you try sending that URL to LinkedIn and your url-encoded URL is longer than approx. 700 characters, the LinkedIn script throws a Javascript error on IE6&7 on Windows XP, only!  Because this is a Javascript error on the LinkedIn side, you have zero control over how it can be fixed, and if you are dealing with a dynamic length description or title, or source url, constructing this URL can be extremely problematic.

Solution


Ignore LinkedIn's red-herring extra GET parameters, and just specify the url GET parameter.  This will cause LinkedIn to ping back on your URL and look for these tags (title, meta description, img...):


<html>
  <head>
    <title>The Title!</title>
    <meta name="description" content="This is the description of your linkedIn Article!">
  </head>
  <body>
    <img src="/my/img/path.jpg">
    <img src="/my/img/path2.jpg">
  </body>
</html>


If you're having trouble getting the images to work because your page is so cluttered, you can setup your page to skim the browser user-agent and look for 'LinkedInBot', and display an altered form of the webpage for LinkedIn specifically.
May 25, 11:51 AM
Sequel Pro is the SQL editor you've always wanted but didn't know existed

I've spent far too many hours searching for a good SQL editor.  Having used a wide variety ranging from MSSQL Server, MySQL Workbench, PhpMyAdmin and just rolling everything from the command line, I had practically given up on finding something that I thought would make me more efficient.  The good news is that Sequel Pro just about the best piece of database management software I've ever found on any platform, and it's free!  The UI is spectacular and everything is just so easy...  I can now throw together a database, edit, add keys delete tables and do just about everything in a few seconds/minutes.  Seriously, if you have a Mac and you do any sort of database work, this is the software you want to be using.

One other great thing is that if you're working in an environment where you need to take all your queries and save them as you make them, Sequel Pro keeps a detailed log of all queries that its running so you can add it to your migration file if you're keeping one.  Seriously awesome!

I was saddened that I didn't know about this software sooner, so that's why I'm sharing with you right now (apparently it's been around for years)!  Do you know of any other hidden gems for development purposes hiding away on the Mac?
August 08, 12:57 PM

Apple is much expected to make an announcement next month that they're releasing a cloud based music service a la Amazon Cloud Drive and Google Music.  Much of what I've heard from others is speculation that they're going to release a competitor to those serices directly, a "music locker"  where you uplaod music that you already own to their servers are are able to stream it directly to your device.  While possible, I think they are going to release something of the same vein but drastically different.

If you look at the headlines, one thing is immediately obvious, record labels are unhappy with Google and Amazon.  They want in on the cloud based music streaming business as much as anyone, making absurd claims that streaming your own song from someone elses computer consitutes a public performance among other things.  Google and Amazon launched their services anyways, not worrying about any potential repercussions with the record labels (a good decision if you ask me).  Apple on the other hand is stil in talks with 2 of the record companies, but why?  Surely if they were announcing a cloud based locker service there's no reason to really get the approval of the record labels...

We speculate that Google's negotiations with the recording industry fell apart when trying to negotiate a deal to stream music purchased through Google Music to users from a single copy of the song hosted on Google's servers. Therefore with a little bit of extrapolation, it's not hard to imagine thats where Apple is held up as well.  So... if Apple is making that a core part of their business model then my prediction is that Apple is trying to make a cloud based service where they host only one version of the song....and everyone streams that one version that they've purchased through iTunes, foregoing the music locker concept altogether.

So a few people I've mentioned this to said they wouldn't use the service if Apple did this but if you think about it, Apple has every reason to only offer this service. No huge bandwidth requirements for people uploading 200 days of music, way less space required on the server side and perhaps most importantly Apple gives you yet another reason to buy things through iTunes. With tight integration into iOS and iTunes, Apple could make this offering seem pretty lucrative albeit restrictive.

What do you think?

January 16, 10:01 PM
(Oh iPod... Why does your bluetooth suck so much?)
One of the better features in iPhone OS 3.0 was that it enabled you to use the Bluetooth module hidden within second generation iPods (and of course third gen now). Although I was initially excited at this prospect, I realized quickly that I had basically no reason to use the Bluetooth - after all I don't have a Bluetooth headset and its not like Apple would ever let you sync it wirelessly to your computer... So, while the functionality was cool, I never really had a need for it until recently when I got a bluetooth enabled car stereo.

The prospect of having no wires running everywhere in my car to get my iPod to play over the stereo has long been a dream of mine, and now that I have it working, it's pretty amazing. Until recently however; I was stuck with choppy playback and a spotty bluetooth connection on my iPod - which after doing some Googling for 'iPod touch 2G bluetooth sucks' returned some interesting results. According to some users, the iPod was given a really horrible bluetooth module, so I was left feeling ripped off by Apple for putting in terrible hardware - after all I knew it wasn't my stereo since it would play music from my phone with no choppiness. I considered switching all my music over to my phone, but I kept reminding myself that, "No, I bought this damn iPod to play my music, and I'm going to use it."

So after doing some more reading, I discovered that bluetooth operates on the already crowded 2.4 GHz frequency, and as it turns out something else on the device runs in the same frequency - WiFi. So after reading some postings by people on a forum, I decided to turn off the WiFi and give the bluetooth some time to try on its own. Guess what! My music streams to my stereo almost completely uninterrupted and the connection almost never drops!

So the solution is surprisingly simple, just turn off WiFi when using bluetooth (unless you're already connected to a network).

I think the reason behind the choppiness is not due to the fact that the WiFi is being used but instead that the iPod scans for WiFi networks. If you notice, the iPod is periodically scanning for wireless networks in the background to connect to, and when it does so - the entire iPod lags up (not just the Bluetooth). Now imagine all the networks the iPod is encountering as you're driving down a residential street... And I think you might just see why the audio starts getting choppy :)

January 10, 05:31 PM

Recently working with some code, I came across an interesting concept - references to pointers. What does that even mean? Why would you need a reference to a pointer - ever?

After spending some time with my friend Google, I found out the answer. Suppose we have these two function definitions, and a main function:
void function_a(int *& a) {
*a += 5;
int * c = new int(7);
a = c;
}
void function_b(int * a) {
*a += 5;
int * c = new int(7);
a = c;
}
int main() {
int * myInt = new int(5);
int * myInt2 = new int(5);

function_a(myInt);
// what is the value of myInt?

function_b(myInt2);
// what is the value of myInt2?

return 0;
}

Analysis

Above, in 'function_a' we're actually passing in 'int *& a', which is a 'reference to a pointer' - a better way to think of this as passing in a 'pointer by reference'. Now, I admit, when I first saw this I thought it was called a 'pointer to a reference' but I'm not really sure what that actually would mean. So for now, just take my word for it that it's called a reference to a pointer. :)

Ok, well if you look at 'function_b', it's passing in it's paramter by pointer only ('int * a'). Both functions do the same operations within their bodies, so whats with the ampersand in function_a? Lets assume that you compiled this application and ran it. Using the int main above, you would expect the value of myInt to be 7 after function_a, right? How about for myInt2? Again, you'd expect it to be 7 after function_b. That's where you're wrong though. After running the main function above you'll get this output:

  • myInt = 7
  • myInt2 = 10

Hooray for unexpected results! The reasoning behind this actually makes sense when you realize this rule for C++:


All parameters are passed by value, unless the ampersand is specified.


Yes, even pointers are passed by value, meaning that a local copy is made for that function. This gets confusing because a pointer simply stores a memory address - and you can change the value at that memory address. The key though, is that if you make a local copy of that memory address in another variable, you can still modify the area in memory that memory address refers to, but now since it's a copy of that, if you try to change the address, it only changes for the scope the variable lives in. Confused? Lets see an example:

int * outside - points to memory at 0xFF9999, and lets say the value at that address is the integer '27'.

suppose we write

int * outside = new int(27);
function_b(outside);  // Using function_b from above
  1. Inside function_b, our local int pointer 'a' now has a copy of that memory address 0xFF9999.
  2. We first add 5 to the value at that address the way we normally would... So, 27+5 = 32. Now 'a' has a value of 32. And so does 'outside', since they both point to the same location. This is what we expected!
  3. Now we initialize int * c = new int(7) - so 'c' has a value of 7 and lets say it has an address of 0x22CCCC.
  4. Then we set the address of 'a' to 'c'. Well 'a' now has the address 0x22CCCC, and consequently the value 7, but we're no longer changing the 'outside' pointer value, since 'a' was a copy of 0xFF9999. So 'outside' still is pointing to 0xFF9999, and 'a' is pointing to '0x22CCCC'.
  5. The function returns, 'outside' now has a value of 32, and the memory at address 0x22CCCC has been leaked since nothing is pointing to it any longer!

How Passing a Pointer by Reference Solves this Problem

When we pass the pointer by reference, as in function_a, the local variable 'a' is no longer a copy of the memory address that 'outside' points to, it literally is the variable 'outside'. Therefore setting the address of 'a' to 'c', will actually change the value of 'outside' to 7, as it changes the address of 'outside'. (You may have noticed that function_a also leaks memory as it never deletes the memory that 'a' pointed to before switching to 'c' as well!)

Hopefully this explanation ends up helping someone out there that may encounter this problem, which seems to be some what not well documented and untaught in basic programming classes in school!

Feel free to post about your experiences with references to pointers below.
Thanks!


August 20, 03:16 AM

I recently read an article on the New York Times which talked about a new device Ford is coming out with that alerts you to a car being present in your blind spot by lighting up a light on the respective side of your rear view mirror. Initially I thought, "This is genius!" but after reading on a little bit further I found that you can position your car mirrors in a certain position so as to completely remove blind spots from your car for free.


From the New York Times article:

"The driver leans his head against the driver’s window and sets the mirror so that the side of the vehicle is just visible. Then, the driver leans to the middle of the vehicle (between the front seats) and does the same thing with the passenger-side mirror."

I set out to test out this theory - after work, I placed my head against the driver's side window, adjusted until the side of the car was just along the side of the mirror at this angle...kind of how I would normally have it in my driver side mirror. Then I moved my head to the middle of the car and adjusted the right side mirror in the same manner as the other one from this perspective. OK! All set to go.

When I started driving, it was weird. I could see my surroundings moving quickly around me, something I guess I just never noticed before, maybe because my car was a static portion of the image in the mirror? Anyways, it was a little strange, but after I got on the highway, it was beautiful! I felt like I could see everything around me at all times! It was a little hard to adjust to at first, because I'm SO used to checking my blind spot but now I just need to do a little glance at the mirror and I'm good to go!

I suggest just giving it a shot if you're skeptical, after all - you can just change them back! Let me know of your experiences with this little trick in the comments below!

DISCLAIMER: I'm not held responsible for any damage to your car or you or anyone else because you adjusted your mirrors differently! I found this works for me, and you try it at your own risk!


March 16, 05:39 PM
The simple english Wikipedia makes it easy for everyone to learn!
So the image above kinda looks like a joke but I guarantee you it's completely legitimate.  The Simple English Wikipedia offers 'dumbed down' versions of standard Wikipedia articles.  
It's great if you're just looking for a short summary of a potentially confusing topic like quantum mechanics (or any math article really), check out the simple version for a very easy to understand introduction/outline.  When you feel like you've got a good grasp on the basics, then you can delve into the real Wikipedia article.
You can visit any wikipedia page in simple form by changing the url from http://en.wikipedia.org/wiki/Database to http://simple.wikipedia.org/wiki/Database.
If you know any other cool things like this post them in the comments!
March 11, 02:44 PM
The Cocos2d Icon
Cocos2d is a 2d game library/framework, originally written in python, that was ported over to use Objective-C, and therefore can be used on the iPhone/iPod Touch.  It greatly simplifies some of the more difficult things with standard iPhone development and uses OpenGLES, which means it can take full advantage of the hardware.  Because it effectively serves as a wrapper around OpenGL, you can have a game up and running in a few hours, if you know what you're doing!  
I'll be posting some more tips about iPhone development in the next few days as well as additional information about cocos2d when I come across it in my code!  Have you seen anything better for iPhone development?
Grab Cocos2d for the iPod/iPhone here.
February 27, 05:14 PM
Great for testing your webpage in past versions of IE.
IE6 is still one of the more mainstream browsers according to W3 Counter. It has about a 25% market share, only trumped by IE7 at 31% at the time of this posting. So...how do you test these older browsers when Microsoft will only let you have the latest version of IE installed? Well I came across this awesome product called IE Tester (picture above), which lets you choose which IE rendering engine to use, and simply opens up that browser in a tab. It is definitely very useful for web development, so if you have windows you can grab it here (Oh it's free of course).
February 24, 03:28 PM
Probably the best thing since sliced bread...Or just really useful :)
As a semi-frequent user of the Windows command prompt, I find it frustrating that it always opens in the same folder, in my case "C:\Users\Mark". I had previously discovered a power toy for Windows XP that enabled you to open a command prompt window in the current directory by right clicking on a folder in explorer, and clicking 'Open Command Window Here'. Luckily, Microsoft decided that this was really sweet and actually integrated the functionality straight into Windows Vista/7, you just have to know how to get to it. To have it appear in the right click menu, all you have to do is press and hold shift and then right click on the folder you want to open the command prompt window at. You'll get it to appear in the right click menu, like the picture above :) Pretty Nifty!
February 24, 03:24 PM
A little bit of writing that was done on my $350 Acer Laptop.
A Tablet PC is a PC that you can take notes on, annotate pdf's, emails etc.  Also known as the best thing ever for a college student.  However, they tend to cost around $800 even for the cheapest ones, and that is just too far out of the price range for a poor college student like me.  So instead I found a way to turn my $350 Acer laptop into one!  It doesn't look completely ridiculous either...Minimizing ridicule is always a good thing :)
The DUO
The product I found is called the DUO. The company refers to it as a 'Pen Mouse' because it serves both mouse and pen functionalities. It looked legitimate enough after I found a couple videos on youtube such as this one, below:
Notice that the size of the device at the top of the monitor is small and sexy.
No ridiculing to be had here! :)
So, how does it work?  The pen sends out an ultrasonic sound (you can barely hear it if there's no background noise) and a reciever measures the time for the sound to travel to it - so by physics 101, you can derive the distance...because distance = velocity * time.  When you want to draw, lightly press the pen against the screen - this'll push the tip of the pen inward slightly and essentially click a switch in the pen, changing the signal, which tells the reciever to 'draw'.  Neat!
Purchase it - $80-100
So if you're getting excited like I was, you're probably saying, "Sign me up!" but where can you purchase it, and how much does it cost?  A google search for 'Pen DUO' basically results in the company webpage (http://www.penandfree.com) and that's about it.  The only place to actually purchase it is on Ebay, and all vendors are based out of Korea, because that's where the product is made.  So..this started to sound pretty sketchy, and in all honesty if I had not seen the video above I probably wouldn't have actually purchased it, but the vendor offered a full refund if the product didn't work as advertised, and paypal had buyer protection, so I felt pretty safe.  
The overall cost for me was $98, and considering I spent $350 on my laptop I was still getting the tablet functionality for a good $300 less than the cheapest tablets on the market.  I found the same vendor selling it a week later for $78, so look around first!
A Review of the DUO
I recieved the item in a record 3 days from Korea, and with free shipping!  Most excellent.  It came in a pretty box that looked like an Apple product.
Its as professional as I could get with a cellphone camera!  Pretty box though :)
Inside was the unit and the pen, both of which were much smaller than I expected.
It also came with a nice little carrying bag, replacement pen tips, a slew of manuals, a nice CD, and some batteries.
Please note, the CD does exist, I just couldn't find it for this picture...but it comes with one :)
Here's my awesome $350 Acer laptop, just to give an idea of what it will be attaching to.
She's oldish but gets me through all the development work I need to do :)
The reciever attaches to the laptop via a pretty strong magnet.  Make sure you keep the reciever away from magnetically sensitive things (i.e. credit cards)!  The magnet is attached to the laptop with a very sticky adhesive.  You can place the reciever on the top, left side, or right side of the laptop.  I chose the top.
You'll want to be careful to place the magnet exactly where you want it - 
because I'm not exactly sure you can reposition it very many times.
Here's what it looks like when it is attached.
Pretty low profile :)
Here's another angle.
When you first plug it in, and insert the CD, all you need to do is install the calibration software.  I'm running the Windows 7 beta and it automatically detected that I had an input device that lets me write on the screen.  After a quick calibration like so...
Just gotta make sure it knows where the edges of your monitor are...
I was able to write just as if I had a real Tablet PC!
There really isn't any lag, and it feels like you're writing!
But wait, there's more!
So the other really cool thing about this device is that you can remove it from the top of your laptop, place it on your desk, clip a piece of paper into it and write on the paper and have it transcribe it directly onto your monitor as well!  There are replacement ball-point pen tips that enable you to take notes on notebook paper and retain a digital copy for those of you that might find writing on the screen vertically a bit awkward.
Concerns
  1. Is it good to write on my LCD screen that wasn't designed to be a tablet?      - I don't think it is really good to do it directly with the pen...it has a felt tip, which is pretty gentle on the screen, but I think you should definitely invest in a screen protector if you're going to get one of these.  They go for about $10 on Ebay.
  2. The pen freaks out in some rooms, and not in others?     - This has to do with the fact that some light conditions, such as those offered by flourescent lights, for example, can output a very deep humming sound that can interfere with the sound emitted from the pen.  This causes the pen to act 'broken' even though it isn't.  I've found that this is rarely ever an issue although I do have one classroom where this is the case - luckily I don't really ever take notes in that class, so just something to keep in mind.
  3. Writing on the screen vertically looks really awkward.     - Honestly, this was the thing I was most concerned about.  Standard Tablet PC's allow the monitor to rotate around and lie flat over your keyboard so it's like you're writing on a piece of paper.  I do wish that my laptop was capable of such a feat, but in all truthfulness you do get pretty used to it after a while.  Yes... you probably won't have perfect accuracy or your finest handwriting, but you can definitely take notes, and it's not horribly awkward.  Truthfully it'd be the one thing that I would change...but it really has nothing to to with the product.  You could always just put the reciever on a flat surface and just write on that, as it doesn't know what is your monitor and what isn't :)
Verdict
This is probably the cheapest solution to obtaining tablet functionality without spending huge amounts of money on a tablet.  It works really well and install was a breeze, plus it looks really slim and sexy.  It has a few drawbacks, although they're certainly able to be worked around or just overlooked if you're desiring tablet functionality.  For me, it's been a great investment and a great study tool.  I didn't see any reviews for this product out there on the internet, so hopefully it helps you decide whether or not it's worth the money.
If you have any questions, comments or advice, please leave a comment below!
Thanks!
February 24, 03:27 PM
It's been a couple months, but a user has posted an awesome link to another solution for getting RTM to display on your desktop.  It's a combination of Adobe Air and Snippage, and seems to be a little more graceful than the minibrowser approach.  (Incidentally, this should also work for XP users!)  The process of what to do can be found here (it's in French but you can google 'translate webpage' and find a website translator): 
http://www.spawnrider.net/blogs/2008/12/04/rtm-todolist-sur-votre-bureau-via-adobe-air/
Rtm on my desktop via Adobe Air + Snippage
Which one do you prefer?  Weigh in on the comments below!  Happy holidays!
August 26, 06:49 PM
Remember the Milk is one of the best websites out there. If you aren't familiar with it, you should definitely go check it out! One of my biggest gripes with it however is that you can't do task list management from your desktop... I'm really lazy and so forgetful that I often forget a task as I am opening the browser and navigating to rememberthemilk.com to put it in the task list! (If that sounds pathetic, just go try it yourself like 50 times...you'll get tired of it too =) )

My Solution

So I run Windows Vista...  and I wanted a sidebar gadget to interact with my task list from my desktop. What's more convienent for updating your task list than your desktop? The folks at rememberthemilk.com put together an awesome blog post detailing alternative ways to interact with your task list in a bunch of different operating systems, but none of them either: were for Vista, or did what I wanted.

So...just when I was about to give up (two months of searching, and potentially developing one on my own), I found this article that detailed how to use the 'Active Desktop' feature of Windows XP with Remember the Milk! If you check out the article you'll see its exactly the thing I was looking for...except on XP. So I searched for the 'Active Desktop' feature on Vista and soon found out that they stripped this functionality out of Vista for some reason or another... Basically all it does though is just display a webpage on your desktop.

So I have kinda made a sidebar gadget in the past and knew they're made up of HTML, javascript and XML (I think?)...so I figured it wasn't a stretch for there to be a browser gadget for the sidebar. I searched the sidebar gadget gallery at Microsoft.com and found a sweet gadget called Minibrowser!! A couple tweaks and I got RTM on my desktop, just like the active desktop feature in XP! Needless to say I'm pretty happy now, and if you'd like to do this in Vista, check out the step by step instructions below:

  1. Get the gadget
    So you're looking for a gadget called 'Minibrowser' which can be found at this link.  Click download, install..install, and you're good to go!  Add the gadget to your sidebar.
  2. Login to Remember the Milk
    Fire up Internet Explorer (this is because Minibrowser uses IE for page rendering), and go to http://www.rememberthemilk.com and login.  Make sure to check the 'remember me on this computer' checkbox!
  3. Point the gadget to the URL
    In the gadget's address bar, set the url to:  http://rememberthemilk.com/services/modules/googleig/
  4. Customize the gadget
    Assuming nothing's gone wrong, you should have your remember the milk task list on your Vista desktop now!  You'll notice that you have a somewhat ugly address bar and some buttons...and status bar, but if you click on the settings icon for the gadget, you can turn all those pesky things off.  Also, there's a tab called 'size' which enables you to resize the gadget so you can get the optimum viewing of your RTM task list.
RTM on my desktop!
That's it!  Feel free to comment/post suggestions if you have any!  Thanks!

-Mark

Profile

Software Engineer - Specializing in Web
Computer Software | Greater Denver Area, US

Experience

  • May 2011 - Present
    Software Engineer / ReadyTalk
  • Jan 2010 - Present
    Web Developer / QualVu
    PHP, MySQL, and Javascript work leveraging the QCodo framework to develop web applications. Worked with Apache Solr to implement a site wide search engine Developed an Android application to allow users to record videos and upload them via a RESTful API
  • Aug 2009 - Present
    Teaching Assistant - Operating Systems / Colorado School of Mines
    Help out students with the Operating Systems senior level course at School of Mines.
  • Aug 2009 - Present
    Teaching Assistant - Intro to C++ / Colorado School of Mines
    Help out students with the introductory C++ course at School of Mines.
  • Jul 2009 - Present
    Testing Intern / LGS Innovations
    Developed a series of unit tests for GSM/CDMA cellular protocols using SIP. Built the tests in C++ using the Google Test unit test framework.
  • Sept 2008 - Present
    Ambassador / Colorado School of Mines
    Give tours around campus for prospective students
  • May 2009 - Present
    Intern / Sun Microsystems
    Part of a team of students working at Sun Microsystems to develop a Text-based installer for OpenSolaris
  • Dec 2008 - Present
    Website Developer / Ron Hazelton Productions
    Created a content management system to manage all house improvement material delivered through ronhazelton.com. Used XSL, XML, PHP, Javascript (jquery), and HTML
  • Aug 2008 - Present
    Teaching Assistant - C++ / Colorado School of Mines
    Mentored and assisted students in the intro to C++ class at Mines.
  • May 2005 - Present
    IT Intern / IHS
    Developed business solutions using data mining, OLAP technologies, reporting solutions and MS SharePoint 2007 presenting management information to facilitate decisions using KPI’s and analytics. − Delivered a live demo/presentation, “How to Create a Market Basket Analysis on Your Data”, to the Microsoft Business Intelligence User Group showcasing SQL Server Analysis Services. − Created a solution using optical character recognition to scan Adobe PDF files and extract useful information for the Human Resources Department. − Developed a .NET application that automated the use of Internet Explorer to fill in thousands of records online.

Education

  • 2006 - 2009
    Colorado School of Mines
    BS in Mathematics and Computer Science

Additional Information

Websites:
Interests:
Dancing, Rock Climbing, Hiking, Skiing

Posts

May 11, 11:51 PM

I'm trying to essentially replicate the functionality of the latest YouTube app in the Android marketplace. When watching a video there's two separate layouts, one in portrait which provides additional info, and one in landscape which provides a full screen view of the video.


YouTupe app in portrait mode


YouTube app in landscape mode

(Sorry for the randomness of the photos, but they were the first pics I could find of the actual layout)

This is pretty easy to do normally - just specify an alternate layout in layout-land and all will be good. The thing that the YouTube app does really well (and what I'm trying to replicate) is that on orientation change, the video continues playing and doesn't have to re-buffer from the beginning.

I've figured out that overriding onConfigurationChange() and setting new LayoutParameters will allow me to resize the video without forcing a rebuffer - however the video will randomly scale to different widths/heights when rotating the screen multiple times. I've tried doing all sorts of invalidate() calls on the VideoView, tried calling RequestLayout() on the parent RelativeLayout container and just trying as many different things as I can, but I can't seem to get it to work properly. Any advice would be greatly appreciated!

Here's my code:

@Override
public void onConfigurationChanged(Configuration newConfig) {
    super.onConfigurationChanged(newConfig);
    if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE) {
        questionText.setVisibility(View.GONE);
        respond.setVisibility(View.GONE);
        questionVideo.setLayoutParams(new RelativeLayout.LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT));
    } else {
        questionText.setVisibility(View.VISIBLE);
        respond.setVisibility(View.VISIBLE);
        Resources r = getResources();
        int height = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 150.0f, r.getDisplayMetrics());
        questionVideo.setLayoutParams(new RelativeLayout.LayoutParams(LayoutParams.FILL_PARENT, height));
    }
}

EDIT: I've discovered in logcat some interesting output that comes up when my video is rotated which seems to be the culprit - although I have no idea how to fix it:

Logcat output when resizing properly (takes up entire window)

notice the h=726

12-13 15:37:35.468  1262  1270 I ActivityManager: Config changed: { scale=1.0 imsi=310/4 loc=en_US touch=3 keys=1/1/2 nav=1/1 orien=2 layout=34 uiMode=17 seq=210}
12-13 15:37:35.561  1262  1268 I TIOverlay: Position/X0/Y76/W480/H225
12-13 15:37:35.561  1262  1268 I TIOverlay: Adjusted Position/X1/Y0/W403/H225
12-13 15:37:35.561  1262  1268 I TIOverlay: Rotation/90
12-13 15:37:35.561  1262  1268 I Overlay : v4l2_overlay_set_position:: w=480 h=224
12-13 15:37:35.561  1262  1268 I Overlay : v4l2_overlay_set_position:: w=402 h=726
12-13 15:37:35.561  1262  1268 I Overlay : dumping driver state:
12-13 15:37:35.561  1262  1268 I Overlay : output pixfmt:
12-13 15:37:35.561  1262  1268 I Overlay : w: 432
12-13 15:37:35.561  1262  1268 I Overlay : h: 240
12-13 15:37:35.561  1262  1268 I Overlay : color: 7
12-13 15:37:35.561  1262  1268 I Overlay : UYVY
12-13 15:37:35.561  1262  1268 I Overlay : v4l2_overlay window:
12-13 15:37:35.561  1262  1268 I Overlay : window l: 1 
12-13 15:37:35.561  1262  1268 I Overlay : window t: 0 
12-13 15:37:35.561  1262  1268 I Overlay : window w: 402 
12-13 15:37:35.561  1262  1268 I Overlay : window h: 726

Logcat output when resizing incorrectly (takes up tiny portion of full screen)

notice the h=480

12-13 15:43:00.085  1262  1270 I ActivityManager: Config changed: { scale=1.0 imsi=310/4 loc=en_US touch=3 keys=1/1/2 nav=1/1 orien=2 layout=34 uiMode=17 seq=216}
12-13 15:43:00.171  1262  1268 I TIOverlay: Position/X0/Y76/W480/H225
12-13 15:43:00.171  1262  1268 I TIOverlay: Adjusted Position/X138/Y0/W266/H225
12-13 15:43:00.171  1262  1268 I TIOverlay: Rotation/90
12-13 15:43:00.179  1262  1268 I Overlay : v4l2_overlay_set_position:: w=480 h=224
12-13 15:43:00.179  1262  1268 I Overlay : v4l2_overlay_set_position:: w=266 h=480
12-13 15:43:00.179  1262  1268 I Overlay : dumping driver state:
12-13 15:43:00.179  1262  1268 I Overlay : output pixfmt:
12-13 15:43:00.179  1262  1268 I Overlay : w: 432
12-13 15:43:00.179  1262  1268 I Overlay : h: 240
12-13 15:43:00.179  1262  1268 I Overlay : color: 7
12-13 15:43:00.179  1262  1268 I Overlay : UYVY
12-13 15:43:00.179  1262  1268 I Overlay : v4l2_overlay window:
12-13 15:43:00.179  1262  1268 I Overlay : window l: 138 
12-13 15:43:00.179  1262  1268 I Overlay : window t: 0 
12-13 15:43:00.179  1262  1268 I Overlay : window w: 266 
12-13 15:43:00.179  1262  1268 I Overlay : window h: 480

Maybe someone knows what 'Overlay' is and why it's not getting the correct height value?

November 13, 02:24 PM

I had this problem, and I found that it was because in Rails 3 files in the lib/ directory aren't autoloaded. To diagnose, I added:

# application.rb
Delayed::Worker.destroy_failed_jobs = false

as mentioned by Ben W. This told me what was going on, as I could inspect the last_error.

So to solve the autoloading problem, I found a couple answers on SO, but the gist is adding this:

# application.rb

# Custom directories with classes and modules you want to be autoloadable.
# config.autoload_paths += %W(#{config.root}/extras)
config.autoload_paths += %W(#{config.root}/lib)
config.autoload_paths += Dir["#{config.root}/lib/**/"]

Which was kindly provided by http://hemju.com/2010/09/22/rails-3-quicktip-autoload-lib-directory-including-all-subdirectories/.

I'd be interested to see how you could solve this without turning on autoloading for the lib directory. Any thoughts?

February 09, 10:12 AM

I upgraded to Android SDK Tools r8 today and I can't seem to run the draw9patch tool. I'm getting the following error:

Exception in thread "AWT-EventQueue-0" java.lang.NoClassDefFoundError: org/jdesktop/swingworker/SwingWorker
at com.android.draw9patch.Application$1.run(Application.java:48)
at java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:209)
at java.awt.EventQueue.dispatchEvent(EventQueue.java:633)
at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:296)
at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:211)
at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:201)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:196)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:188)
at java.awt.EventDispatchThread.run(EventDispatchThread.java:122)
Caused by: java.lang.ClassNotFoundException: org.jdesktop.swingworker.SwingWorker
at java.net.URLClassLoader$1.run(URLClassLoader.java:202)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(URLClassLoader.java:190)
at sun.misc.Launcher$ExtClassLoader.findClass(Launcher.java:229)
at java.lang.ClassLoader.loadClass(ClassLoader.java:307)
at java.lang.ClassLoader.loadClass(ClassLoader.java:248)
... 9 more

I'm running snow leopard and have jre (or jdk?) 1.6.

Any ideas how to get this working? Thanks!

January 17, 11:50 AM

Rob,

The problem is that setBackgroundColor() is looking for a color object. So you would need to use something like the line below

ll.setBackgroundColor(Color.WHITE);

or

ll.setBackgroundColor(Color.parseColor("#ffffff"));

whereas setBackgroundResource is looking for a resource to use as the background, i.e. something in your res folder. You could use that to set the background to a drawable or something of that nature.

ll.setBackgroundResource(R.something.mydrawable);
January 04, 02:56 PM

I encountered this same problem. Turns out the android MediaPlayer won't handle redirects, so you have to find where the php script is redirecting you and give it the rtsp URL as Jeorgesys explained.

I was able to solve by performing a HttpGet and NOT following any redirects, then pulling the rtsp url from the 'Location' Http header. If you have multiple redirects, you'll have a little more trouble, but luckily in my case I only have to worry about a single redirect.

public static String resolveRedirect(String url) throws ClientProtocolException, IOException {
    HttpParams httpParameters = new BasicHttpParams();
    HttpClientParams.setRedirecting(httpParameters, false);

    HttpClient httpClient = new DefaultHttpClient(httpParameters);      
    HttpGet httpget = new HttpGet(url);
    HttpContext context = new BasicHttpContext();

    HttpResponse response = httpClient.execute(httpget, context);

    // If we didn't get a '302 Found' we aren't being redirected.
    if (response.getStatusLine().getStatusCode() != HttpStatus.SC_MOVED_TEMPORARILY)
        throw new IOException(response.getStatusLine().toString());

    Header loc[] = response.getHeaders("Location");
    return loc.length > 0 ? loc[0].getValue() : null;
}
December 21, 08:14 PM

I'm trying to post a video file to our server and monitor it's progress. I followed the steps outlined in Can't grab progress on http POST file upload (Android) and that worked great, but with larger files my program will hang while writing to the output socket and subsequently cause my phone to lock the WiFi so I can't turn it on/off and then cause it to crash (after a short period).

So I attempted to write my own HTTPClient and it works, but also with intermittent success, still falling victim to the random crashes of the method outlined above. It seems this only occurs on files > 5MB, but I've had it die around 1.3MB and I've even had it successfully transfer a 13MB file. The fact that it's so random and sporadic is infuriating but I'm convinced there's some reason it's happening.

Here's my connection code:

socket.connect(new InetSocketAddress(host, port));
socket.setSendBufferSize(1024 * 65);

int bytesSent = 0;
PrintStream out = new PrintStream(socket.getOutputStream());
out.print(headersBuffer);
out.print(bodyBuffer);
bytesSent += headersBuffer.length() + headersBuffer.length();
byte[] bytes = new byte[1024 * 65];
int size;
while ((size = fileStream.read(bytes)) > 0) {
    mListener.transferred(bytesSent);
    Log.i(TAG, "bytes sent: " + bytesSent);
    bytesSent += size;
    out.write(bytes, 0, size);       // Random freezes (/blocking?) on this line
    out.flush();
}

Log.i(TAG, "Made it!");
out.print(lastBoundary);
out.flush();

I've used the debugger to see where it's getting to in the stack when the write just seems to block and it's the OSNetworkSystem.writeSocketImpl() function. That function just never returns...

So my next thought was - if the socket will just sit there, perhaps I can interrupt it and force it to close so at least the phone doesn't crash and the user can retry... I read up on force closing sockets in Android here (since it seems there are some problems): http://code.google.com/p/android/issues/detail?can=2&q=7933&colspec=ID%20Type%20Status%20Owner%20Summary%20Stars&id=7933

Basically what I did was create a Listener thread that looks at how many bytes have been transferred every 500ms and if there hasn't been a change, attempt to force close the socket by means of

socket.shutdownOutput();
socket.close();

However the socket returns that it is closed and everything proceeds to fail as outlined above.

Here's the general sequence of events in Logcat:

12-21 14:25:26.802  2234  2340 V UploadService: Bytes transferred: 5959800 of: 13191823
12-21 14:25:26.802  2234  2340 V UploadService: Bytes transferred: 5963896 of: 13191823
12-21 14:25:26.802  2234  2340 V UploadService: Bytes transferred: 5967992 of: 13191823
12-21 14:26:00.693  1262  1270 D WifiService: acquireWifiLockLocked: WifiLock{NetworkLocationProvider type=2 binder=android.os.Binder@45b48958}
12-21 14:26:11.083  1262  1289 D WifiHW  : 'DRIVER LINKSPEED' command timed out.
12-21 14:26:21.130  1262  1500 D WifiHW  : 'AP_SCAN 2' command timed out.
12-21 14:26:31.177  1262  1500 D WifiHW  : 'SCAN' command timed out.

And after a few minutes the really bad stuff starts happening and the phone crashes!

Please help! Thank you.

EDIT: Works great over 3G - I'm going to try at home and see if its some sort of router issue. However - how can I catch this problem and prevent the phone from crashing?

December 15, 11:52 AM

I was able to narrow down the problem to the onMeasure function in the VideoView class. By creating a child class and overriding the onMeasure function, I was able to get the desired functionality.

public class VideoViewCustom extends VideoView {

    private int mForceHeight = 0;
    private int mForceWidth = 0;
    public VideoViewCustom(Context context) {
        super(context);
    }

    public VideoViewCustom(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public VideoViewCustom(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
    }

    public void setDimensions(int w, int h) {
        this.mForceHeight = h;
        this.mForceWidth = w;

    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        Log.i("@@@@", "onMeasure");

        setMeasuredDimension(mForceWidth, mForceHeight);
    }
}

Then inside my Activity I just did the following:

@Override
public void onConfigurationChanged(Configuration newConfig) {
    super.onConfigurationChanged(newConfig);

    if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE) {
        getWindow().clearFlags(WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN);
        getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);

        questionVideo.setDimensions(displayHeight, displayWidth);
        questionVideo.getHolder().setFixedSize(displayHeight, displayWidth);

    } else {
        getWindow().setFlags(WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN, WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN);

        questionVideo.setDimensions(displayWidth, smallHeight);
        questionVideo.getHolder().setFixedSize(displayWidth, smallHeight);

    }
}

The line:

questionVideo.getHolder().setFixedSize(displayWidth, smallHeight);

is key in order to make this work. If you do the setDimensions call without this guy, the video still will not resize.

The only other thing you need to do is ensure that you call setDimensions() inside the onCreate() method as well or your video will not start buffering as the video won't be set to draw on a surface of any size.

// onCreate()
questionVideo.setDimensions(initialWidth, initialHeight); 

One last key part - if you ever find yourself wondering why the VideoView isn't resizing on rotation, you need to ensure the dimensions you're resizing to are either exactly equal to the visible area or less than it. I had a really big problem where I was setting the VideoView's width/height to the entire display size when I still had the notification bar/title bar on the screen and it was not resizing the VideoView at all. Simply removing the notification bar and title bar fixed the problem.

Hopefully this helps someone in the future!

December 03, 03:09 PM

While perhaps not the most elegant solution, I used static data members in my ActivityA class which I can set from ActivityB.

//ActivityA.class

public static boolean refreshData = false;

public void onResume() {
    if (refreshData) {
         mRefreshData();
         refreshData = false;
    }
}

//ActivityB.class

ActivityA.refreshData = true;
Intent myIntent = new Intent(v.getContext(), ActivityT.class);
startActivityForResult(myIntent, 0);

I'm interested to know if there's a better way to do this kind of thing!

December 03, 03:09 PM

I have three activities:

Activity A - Displays a list of data from a website. From this activity you can perform an action which would add something to this list (Activity B).

Activity B - This is the activity that adds data to the website. Upon successful completion this activity will need to tell Activity A to refresh its list.

Activity T - A TabHost which contains Activity A.

My problem is:

Activity B needs to tell Activity A to refresh, but its intent must be Activity T, since I want the TabHost to display Activity A.

//ActivityB.class
Intent myIntent = new Intent(v.getContext(), ActivityT.class);
myIntent.putExtra("target", "ActivityA");
myIntent.putExtra("refreshData", true);
startActivityForResult(myIntent, 0);

I thought I could use the TabHost as an intermediary and just pass the extras through to Activity A if they were set, like so:

//ActivityT.class
Bundle extras = getIntent().getExtras();

// Create an Intent to launch an Activity for the tab (to be reused)
intent = new Intent().setClass(this, ActivityA.class);

// Check to see if we want to pass our bundle through to the activity
if (extras != null && extras.getString("target").equals("activityA")) {
     intent.putExtras(extras);
}

// Initialize a TabSpec for each tab and add it to the TabHost
spec = tabHost.newTabSpec("Tab1").setIndicator("Tab1",
            res.getDrawable(R.drawable.ic_tab_tab1)).setContent(intent);
tabHost.addTab(spec);

This works great, except that when I change tabs to a different tab and change back, the extras are passed through yet again, and again - which causes my tab to refresh its data every time, even though I'm no longer coming from Activity B. This is because the TabActivity doesn't get recreated on tab change and therefore the extras are always passed through to the child intents.

So, how I can tell Activity A to refresh ONLY from Activity B, but still get the TabHost to show up?

September 09, 07:27 PM

I'm working on developing a native android application to retrieve data for a user from my company's website.

Because the data is specific to the user, I need to authenticate with our web server, but I'm unsure of the best way to go about this. I've been reading about REST/SOAP/HTML form auth, but I can't really find any definite 'this is how its done' anywhere. I know mobile apps do this kind of thing all the time - just look at facebook/skype/any email app - you have to login before you can do anything.

My question is - how should I architect the server side code (php) to easily allow me to authenticate a user from my android device?

I'm fairly new to the 'web service' arena - does this fall into that category? Are there any tutorials you guys would recommend looking at?

Thanks!

September 09, 12:01 PM

I'm having almost the exact same problem, did you find a solution?

August 31, 01:49 PM

I wonder if this has changed since I posted my solution what version did you write this for, > 2.2?

July 18, 04:48 PM

Doesn't get much better than that, wish I could give more points!

January 06, 02:38 PM

Its a bummer that at the moment there is only QUALITY_HIGH and QUALITY_LOW

December 22, 02:44 PM

Any ideas how I could possibly check whether its reading all the data from the server side? I've got apache/php running on my server.

December 22, 03:37 AM

Ok so I just confirmed that it is indeed the Wifi connection at my office causing the problems - the upload works fine from my home network... but I still need to figure out how to catch the error that's happening up above.

December 22, 12:18 AM

@Dan Breslau - Sorry for not being more clear - The youtube app when uploading a file will also error out on upload and cause the Wifi adapter to throw the same "WifiHW : 'DRIVER LINKSPEED' command timed out." error on Logcat. The difference is that youtube is able to catch the error and stop the upload whereas my app will just hang. I'm going to check the server and see if its pulling the information from the socket and try some of your suggestions.

December 21, 08:16 PM

Uploading a video to youtube makes the same thing happen so it's gotta be something on my side - but the youtube app is able to catch the error before anything bad happens and forces the phone to shutdown. I'm almost convinced this has to do with the WifiHW errors in Logcat shown above.

December 08, 03:23 PM

This is a fantastic solution! Thanks so much for posting

December 07, 11:30 AM

Works on OSX (Snow Leopard) as well! Thanks!

December 03, 12:14 PM

Isn't broadcast a little heavy duty for a small task like this? Aren't they typically used to listen for events/intents broadcast by other apps/services?

September 13, 11:38 AM

Thanks a bunch! This is a great place for me to start. I hear JSON is pretty easy to parse on the android side of things as well.

Web Design/Development

Software developer, web designer, swing dancer, and technology enthusiast.

abcdefghijklmnopqrstuvwxyz abcdefghijklmnopqrstuvwxyz