-->

Thursday, May 26, 2016

Rochester, MN - Destination Project Center



Home of the Mayo Clinic, our former hometown is referred to as "Destination Medical Center". But during our visit the last few weeks, Rochester became more fondly referred to as "Destination Project Center", as Chris' personal RV fix-it man (me, Doug ... not so skilled and woefully underpaid) worked hard to repair some of the Wildebeest's ills.


While Chris was busy visiting friends and working at Mayo to earn enough diesel to satisfy the Wildebeest's huge appetite, it became my "job" was to tackle the many RV repair projects that had accumulated over the last several months.

Job number 1 - get the electric side of our water heater working.
The electric portion of the water heater hasn't worked for almost a year, and Chris finally put her foot down and insisted that this needed to be fixed. After all, we were back in the north, and it can get REALLY COLD some mornings.


I knew this would be a significant job, since people that design and build RVs hate the people that have to maintain them. For the water heater, this means that you place a high failure rate item in a location which is totally inaccessible unless you remove the entire water heater. So, I had to remove the water heater and disconnect the plumbing to get it out in order to access the heating elements. 
As expected, numerous plumbing issues resulted when trying to get everything back together without leaks ... I got to know the local plumbing store REALLY WELL! After three days of RVenturous repairs, the job got done, and now we have hot water via the electric element ANY TIME THAT CHRIS WANTS IT rather than solely when we turn on the propane to temporarily heat up the water. Some pictures of the "great water heater repair job" are below.

Back of the water heater exposed so that I can get to the electric element. Fortunately, the engine coolant hoses were long enough so that I didn't have to remove them.

The water heater hanging exposed out of the Wildebeest.

Another view of the water heater.

Doug working on the water heater.

The failing parts. I think it was just burnt wiring that was the problem, but since I took the trouble to remove the water heater to get to this stuff, I replaced it all - thermostat, emergency cutoff, wiring, and heating element.

Burnt wiring.

The electric water heater element. I think it's still good, but it gets replaced anyway.
I think I had to take the water heater out and put it back in about seven times during the process of getting this little problem resolved. At least I know that I'm all caught up on the task of flushing my water heater!

Job number 2 - Find and repair the leaking roof
We had been getting some water in the RV around the area of the window over the front door. Fixing this problem actually started in Pensacola, FL where I decided that the problem may be the condition of the caulking of the unused satellite dish on the roof. I decided to remove it and seal the holes in order to fix the problem.

Satellite dish is gone!

Here it is ... I ended up selling it on Craigslist.
Well, the next hard rain showed that this did not fix the problem. So, when we got to Rochester, I took apart a bunch of stuff inside the RV so I could have a better view of where the problem might be.

The Wildebeest with a lot of panels removed.
I also decided to remove two old CB antennas and seal the holes in order to eliminate those as potential problems, although it didn't appear that they were a problem. But, with the new streamlined Wildebeest I'm sure that I'll get a great increase in diesel mileage! I'll also no longer hear them wack into tree branches as I am coming into campsites.


When re-caulking the front caps, I removed some downspouts and found some pretty suspicious looking screw holes. So, after re-caulking those, I had high hopes. Alas, the next large rain proved that I still had a problem to solve.


The next suspicion was the awning over the front door. I definitely did not like the looks of the rivet holes that were holding that awning in place. Why, oh why do they attach awnings with rivets! It must again be the hatred of the RV manufacturer against the RV owner/repairer. So, off with the awning and proceed to patch the holes ... I still need to locate paint which will match the existing "Wild Berry" color scheme of the Wildebeest. Some of the nail holes did not look very good, so I had high confidence going into the next rain the I would no longer see any water. Alas, I was proven wrong again.

So, I am running out of possible culprits at this point. The two most likely remaining possibilities were the TV antenna and the window itself. I decided that the window was the most likely, so I removed the window and reinstalled it with some new butyl tape caulk. I make this sound easy, but it was not. I had a couple of screws which were rusted in place, and I broke the heads off trying to get them removed. There was also a screw which needed a special low profile screwdriver in order to access. So, a few trips to local hardware stores were required to get some new tools (including a dremel) and screws, in order to get this job done. In the end, I got the window out, re-taped, and re-installed ... and got some COOL NEW TOOLS in the process! SCORE!!

We've had some rain over the last couple of days, and I am no longer getting any drips. But I haven't quite declared victory until we survive a multi-day soaker.

Job 3 - Cleaning the Wildebeest's roof
The roof of the Wildebeest was really dirty, and for some reason I thought it should be cleaned. This would also give me a chance to do a good inspection of the roof of the Wildebeest since I intended to do the cleaning by hand. It was not easy to get the job done in between the rain and wind storms, but it eventually did get completed, and I think it looks really nice. Of course, it's very hard to see how nice it looks unless you are up on the roof ... but, you never know ... it may become Chris' new favorite hangout spot!


Why does the roof of RVs need to be cleaned?? Not really sure, but maybe I'll get some better diesel mileage with the smoother surface! Not likely, but at least I can get satisfaction in knowing that it looks nice. My cleaning method: squirt some Clorox cleanup down, wipe with magic eraser (scrubbing a bit where there are stains or gunk stuck to the roof), wipe up with shop towels, squirt some Windex where I just wiped, and then wipe that up with some fresh shop towels. I should probably wax it before it gets dirty again. It took a number of hours of labor, but it sure does look nice! Tours are available if you want to check it out in person, but if not, here are some pictures:

8 feet done

Closer look at the 8 feet where the satellite dish used to be.

More done!

All done!
Job 4 - Bike maintenance.
I spent some time tuning the gears on both of our bikes. My bike was no longer getting into seventh gear since a stick bent the derailleur while mountain biking in Florida. Chris' bike also had problems getting to all the gears, plus her brakes needed adjusting ... badly. It also turned out that both of our chains were at the end of life. So, I spent a couple of days getting everything working again and also replacing the chains. They both run much better now, and we were able to enjoy some longer rides on the beautiful bike paths ... and a few gravel roads of Rochester.



Jobs 5 and 6 - Check battery water levels and run the generator. 
These tasks should be done monthly in order to ensure that you have no issues. However, if I get these done every few months it will be a miracle. I did manage to accomplish each of these tasks while I was in Rochester, and set up a system where my phone task list will remind me to do this every month. We'll see if that helps.

Then there is the never ending "Honey-Do" Jobs ...
Clean the carpet ...
Biking with friends ... 
And taking Chris out for our favorite caramel pecan french toast
So, my task list has all been accomplished by the end of our Rochester stay, and I'm feeling that things are really working well now. I'm pretty sure that this state will not hold for very long ... but in the meantime, I will reward myself with a cold one on the patio with my sweetie!


I (Chris) am continually amazed and grateful for the knowledge, patience and and skills that Doug has in order to keep our "house on wheels" a comfortable and well functioning "home". 

Until next time ... Keep everything in the state of repair ... and enjoy the adventures in your life!

Saturday, May 14, 2016

Developing a Google App Engine Web Service

We interrupt this travel blog to bring you some important nerdly information.  A couple of months ago, I completed a web service to handle photo rotations and resizing as part of my personal photo processing work flow. I thought I would document this here for two reasons:


  1. It may be useful to someone else.
  2. It will definitely be useful for me to remember how this stuff works if I ever need to work on it again.

To bring yourself up to speed on my photo processing process, you can refer to my previous blog entry.

I wanted to eliminate the requirement to process all my photos with my Android Photoroto application prior to uploading the photos to google drive. In order to do that, I decided that I would process the rotations as part of my Google Drive script which moves the photos to a new location, and then creates a resized version in a mirror directory structure. Specifically, I created a web service using google app engine which allows a photo to be rotated and resized at the same time. This is a bit different than my old process, where the rotation was done on the original images and then only resized when copied to the mirror. I think this is acceptable for my use at this point, since it is primarily the resized versions which I had difficulty with being rotated incorrectly when using to Google public domain resizing web service. Here is how I created the web service.

Install the Eclipse SDK using this documentation: https://developers.google.com/eclipse/docs/getting_started#running

The code to actually implement the web service is pretty simple. I have included it here:

package net.chartrand.doug.photomanip;
import static com.google.appengine.api.urlfetch.FetchOptions.Builder.disallowTruncate;
import java.io.IOException;
import java.net.URL;
import java.util.Enumeration;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.google.appengine.api.images.CompositeTransform;
import com.google.appengine.api.images.Image;
import com.google.appengine.api.images.ImagesService;
import com.google.appengine.api.images.ImagesService.OutputEncoding;
import com.google.appengine.api.images.ImagesServiceFactory;
import com.google.appengine.api.images.OutputSettings;
import com.google.appengine.api.images.Transform;
import com.google.appengine.api.urlfetch.HTTPMethod;
import com.google.appengine.api.urlfetch.HTTPRequest;
import com.google.appengine.api.urlfetch.URLFetchServiceFactory;
@SuppressWarnings("serial")
public class PhotoManipServlet extends HttpServlet {
 public void doGet(HttpServletRequest req,
 HttpServletResponse resp)
 throws IOException {
     Enumeration<String> parameterNames = req.getParameterNames();
     String url = null;
     int rotate = 0;
     int size=0;
     while (parameterNames.hasMoreElements()) {
         String paramName = parameterNames.nextElement();
         if (paramName.equalsIgnoreCase("url"))
         {
        String[] paramValues = req.getParameterValues(paramName);
        for (int i = 0; i < paramValues.length; i++) {
            String paramValue = paramValues[i];
            url=paramValue;
        }
         }
         if (paramName.equalsIgnoreCase("rotate"))
         {
        String[] paramValues = req.getParameterValues(paramName);
        for (int i = 0; i < paramValues.length; i++) {
            String paramValue = paramValues[i];
            rotate=Integer.valueOf(paramValue).intValue();
        }
         }
         if (paramName.equalsIgnoreCase("size"))
         {
        String[] paramValues = req.getParameterValues(paramName);
        for (int i = 0; i < paramValues.length; i++) {
            String paramValue = paramValues[i];
            size=Integer.valueOf(paramValue).intValue();
        }
         }
     }
     if (url != null && (rotate != 0 || size != 0))
     {
    URL urlo = new URL(url);
    byte[] b = URLFetchServiceFactory.getURLFetchService().fetch(
    new HTTPRequest(urlo, HTTPMethod.GET,
    disallowTruncate().setDeadline(30.0))).getContent();
    Image oldImage = ImagesServiceFactory.makeImage(b);
    Image i = processImage(oldImage, rotate, size);
    resp.setContentType("image/jpeg");
    resp.setContentLength(i.getImageData().length);
    resp.getOutputStream().write(i.getImageData());
    resp.getOutputStream().flush();
    resp.getOutputStream().close();
     }
 }

 static Image processImage(Image o, int degrees, int size)
 {
ImagesService imagesService = ImagesServiceFactory.getImagesService();
CompositeTransform composite = ImagesServiceFactory.makeCompositeTransform();
if (degrees != 0)
{
Transform rotate = ImagesServiceFactory.makeRotate(degrees);
composite.concatenate(rotate);
}
if (size != 0)
{
Transform resize = ImagesServiceFactory.makeResize(size, size);
composite.concatenate(resize);
}
OutputSettings enc = new OutputSettings(OutputEncoding.JPEG);
enc.setQuality(90);
     Image newImage = imagesService.applyTransform(composite, o, enc);
   
return newImage;
 }
}
Once this is deployed to google app engine under a certain appid, I can now use the service in my google app script as follows - with the following changes to the original script.
function getDestBlob(sourcePath, sourceFolderId, srcFile, size)
{
  var data = srcFile.getBlob().getBytes();
  var blob;
  var w = 0;
  var h = 0;
  var rotate = 0;
  var comps = 0;
  var len = data.length;
  Logger.log("Start: " + getShortAt(data, 0, true));
  var offset = 2;
  while (offset < len) {
    var marker = getShortAt(data, offset, true);
    Logger.log("Marker: " + marker);
offset += 2;
if (marker == 0xFFC0) {
        Logger.log("Found the marker!");
   h = getShortAt(data, offset + 3, true);
w = getShortAt(data, offset + 5, true);
comps = data[offset + 7];
break;
} else {
        var inc = getShortAt(data, offset, true);
        Logger.log("inc: " + inc);
offset += inc;
}
  }
  Logger.log("h: " + h + " w: " + w);
 
  var bf = new BinaryFile(data, 0, data.length);
  var tags = ImageInfo.readInfoFromData(bf);
  var orientation = 0;
  if (tags["exif"] != undefined)
  {
    var exif = tags["exif"];
    var datetime = null;
    if (exif["Orientation"]) { orientation = exif["Orientation"];}
  }
  if (orientation == 3) {rotate = 180;}
  if (orientation == 5 || orientation == 6) { rotate = 90; }
  if (orientation == 7 || orientation == 8) {rotate = 270; }
 
  Logger.log("h: " + h + " w: " + w + " o: " + orientation + " r: " + rotate);
 
  var uri = sourceFolderId;
  if (sourcePath.match("^/")) {uri = uri + sourcePath;}
  else {uri = uri + "/" + sourcePath;}
  uri = encodeURI(uri);
  /*throw new Error(uri);*/
  /*throw new Error("Done!");*/
  try {
    var resize = 0;
    if ((w > size) || (h > size)) { resize = size; }
    if (rotate != 0 || resize != 0)
    {
      /* https://images1-focus-opensocial.googleusercontent.com/gadgets/proxy?url=http://googledrive.com/host/0B7HZjn1EQgIxcUpEeE5CcGJCdnM/Family/2013/2013-11/CAM00367.jpg&container=focus&resize_w=650&refresh=31536000 */
      var url = "https://myappid.appspot.com/photomanip?url=http://googledrive.com/host/"+
        uri +
        "&size="+resize+"&rotate="+rotate;
      blob = UrlFetchApp.fetch(url).getBlob();
    }
  }
  catch(err)
  {
    Logger.log("Error on resize: " + err.message);
    // blob = null;
  }
  return blob;
}
The primary change above is to retrieve the photo orientation from the exif and then calculate the appropriate rotation. Then, instead of calling google's opensocial.googusercontent.com webapp to perform just a resize, you called my new appengine webapp to perform both a rotate and resize at the same time. The specific call to the webapp is shown in this example:
var url = "https://myappid.appspot.com/photomanip?url=http://googledrive.com/host/"+        uri +         "&size="+resize+"&rotate="+rotate;blob = UrlFetchApp.fetch(url).getBlob();

Note that you can deploy this webapp for free, and do a limited number of photos per day. Because of this, I changed the appid above from the one that I have deployed to myappid. You would use whatever app id that you decide to develop for your application. myappid will not actually work here, since this app is not deployed at this id (as far as I know). You can also pay to be able to process more photos per day than allowed for free.

After implementing this change, I no longer need to route all my photos to an android platform in order to get the rotations correct. This has simplified my photo processing to a great extent.

Good luck, and let me know if you have any questions. I know this description is kind of short and rough, but I wanted to quickly get it out there while I had a chance.

Monday, May 9, 2016

Celebrating "6744"



We are very fortunate to find ourselves residing close to Chris' childhood home this month. Beautifully renovated by her siblings, the house recently sold and is ready to welcome a new family.



We gathered last weekend for one final time to celebrate family memories at "6744".



Through the years, family celebrations included a wonderful spread of food including delicious sandwiches made with the Polish cold cut known as Krakowska. Available at Kramarczuk's in north Minneapolis, its wonderful garlic aroma draws fans from near and far! 



I appreciated the chance to tour my childhood home one last time and take pictures of all the "memories". Although empty, repainted and ready for new owners, each room still resonated with wonderful memories of celebrations past.

The living room is ready for new family gatherings ...




And the dining room awaits many more birthday celebrations ...



And the "rec room" welcomes more New Year's Eve parties ...





The new owners may wonder about a few things ... like the six names, dates and lines in the "toy closet". Our parents recorded the height each of us when we moved into the house in 1969.


And there is the dent in a door ... a remnant of some innocent "rough-housing" through the years.


While it is always bittersweet to say "goodbye", we embraced our real reason for gathering ... celebrating family, friends and wonderful memories through the years!



Like all the fun times spent in the "playhouse" that our dad built many years ago ... 



and looking forward to new generations to enjoy their own fun space!


Celebrating thoughtful neighbors who delivered scrumptious pies as well as friendship to our family through the years.






And, most importantly, sharing family memories and celebrating the new generation ... how do these kids grow up so fast?









So as we say our goodbyes to "6744", we celebrate the gifts that make up home ...


Love, Memories, Family, Friends, and Laughter!

Until next time ... celebrate the gift of "home" ... and enjoy the adventures in your life!

Tuesday, May 3, 2016

A "Hawkeye" View of Iowa


When living in Minnesota, we had enjoyed a fun rivalry with our neighbor to the south, Iowa. There are many Iowans living in the Gopher state who still maintain their loyalty to the black and gold "Herky the Hawk". So during our three day stay at F.W. Kent County Park in Tiffin, Iowa, we explored the area from a "Hawkeye's" view.


From our quiet campground, Iowa City was only 12 miles to the east of us and home of the University of Iowa. Being a college town, we felt that the odds were good that we would find bike/walking paths and a brewery or two! We scored big on both accounts when we enjoyed handcrafted brews and great food at Backpocket Brewery and walked around the campus on some beautiful pathways.


Backpocket Brewery, located in the recently developed Iowa River Landing, served up delicious pizza and a wide selection of beer. It was a good reward for Doug who had just finished up his longest RV driving day on record with a 302 mile, 7 hour drive from Lake of the Ozarks, Missouri.



After relaxing on their comfortable patio, we took a walk towards campus. We knew we were getting close because of all of the randomly placed "Hawkeyes" that lined our path. 



The Hawkeye most certainly is "King" in these parts!



The next day, we drove 12 miles west of the park to discover what the Amana Colonies is all about. The Amana Colonies is a group of seven villages that was established in 1855 by German immigrants seeking economic and religious freedom. They embraced a communal way of life in which the citizens worked for the benefit of all. They relied on each other for food, clothing, education and other necessities of life. This communal way of life continued until 1932 when the Great Depression forced them to make changes. Today the buildings of this National Historic Landmark that produced the meat, linens, furniture and other needed items, stand tall enticing tourists to explore.



We (ok, mainly Chris) enjoyed walking through the shops and admiring the goods still handcrafted in Amana. Some of the beautiful items that one could be tempted to buy if one lived in a house larger than ours ....


Christmas ornaments galore!
Beautiful Quilts!
Handcrafted furniture!
Dandelion Wine!

OK, I always have room for a bottle of wine, so let's go in!



Meanwhile, Doug found his little piece of heaven at the Chocolate Haus!


We were too early in the tourist season to take a guided tour of the rest of the villages, so we finished up our day the way that we both enjoy ... with a walk on the path around Lily Lake.



The path led us past eagles, hawks, geese, and all sizes of turtles ... including this little guy who had lost his way. We enjoyed this part of Amana Colonies which gave us "hawkeye" view of the natural side of Iowa.



Back at our campsite, we took an evening walk around the beautiful lake in F.W. Kent Park and enjoyed the quiet that comes when you are the only campers in the park.



Always having his "hawkeye" on the weather radar, Doug studied the weather forecast to determine our most opportune move day into Rochester. With rain on its way, we decided to leave a few days early. We are currently at Autumn Woods RV Park for the month of May. While Chris puts in a few hours at work ...


... Doug is spending his time on some RV maintenance projects. The Wildebeest is currently in a state of upheaval as Doug investigates and repairs a leak above our door. I just try to ignore the mess and trust that all will turn out well in the end!


And ... I am sure that he will have a little "down time" and would love to share some of the nerdly RV facts that he has discovered. Let him know that his "fans" want to hear from him!

Until next time ... Ask the RV expert ... and enjoy the adventures in your life!