So Long For Now, Our Original Goal Buddy

Chris and I are late to the party, bidding our fond farewells to Stuart McLean.  But it wouldn’t be right to not pay our respects to the person who motivated us through many a chore.

Long before Saturday Morning Productions or Goal Buddy were even conceived, we were spending our Saturday mornings building a cold storage room under the stairs in our then-new house.  We can honestly say it is the opening riff of the theme music and the sound of the storyteller’s voice that encouraged us to get sawing and painting.  We even emailed him back then to let him know the impact he had on our routine.  Years later, during jam-making and harvest seasons, we have his show to thank for the completed room.

Years later, the excitement of home ownership hadn’t faded, but the thrill of housework had lost its shine, especially with our small family and the company to run during the week.  Saturday mornings became the time for  tedious tasks like cleaning bathrooms and filing.  It was Stuart’s voice that made those mornings less unpleasant – that spoonful of sugar, if you will.

We’re thankful we can still listen to old favourites on the podcast.  Not only does it get us through whatever Saturday mornings mean to us now, it serves as a reminder of what can be accomplished with a little push.

Posted in Fun, Goal App | Comments Off on So Long For Now, Our Original Goal Buddy

Stack Overflow Developer Survey 2017

Stack Overflow Developer Survey Results 2017

The results of the Stack Overflow Developer Survey 2017 are live.  Some surprising highlights for me:

  • Most developers surveyed are white male web developers.  Just kidding, this was not surprising at all.
  • More than 50% of developers’ parents had a university degree of some type.  I wonder what the parent’s education level is like for other occupations?
  •  SQL is the 2nd most popular programming language.  Surprising to me because I don’t think of SQL as a programming language. Not sure why.  Maybe because you don’t run a SQL application but an application that uses SQL.  Guess I have to change my thinking.
  • Most dreaded language is VB6 which is what I started my professional career with.  Not sure why people dislike it so much.  Maybe it has more to do with the fact most VB6 projects are old and it’s hard to get a VB6 development environment setup.
  • The most dreaded platform is Sharepoint, which is something I’ve never liked and actively avoid.  Glad it’s not just me.
  • Visual Studio is a very popular IDE but the second most popular was Notepad++.  I assume that everyone has Notepad++ installed on their workstation.  Unless you are a sysadmin then you like Vim.  Don’t forget to quit Vim it’s Esc-q or Esc-wq if you want to save and quit.
  • Most developers outside of the United States are underpaid when you translate their salary to USD.  I wonder if this is because of the currently strong US dollar and if the difference wouldn’t have been so high 5 years ago.
  • Git won the version control war over Mercurial despite me personally liking Mercurial better.  Surprisingly Subversion is used more than Mercurial.

Save

Posted in Software Development, Uncategorized | Tagged , , | Comments Off on Stack Overflow Developer Survey 2017

Success at last!

Update: My last blog post was about my unsuccessful attempt at the APREP, which is the physical assessment part of the Edmonton Police Service’s hiring process. I passed on my second attempt, which was on February 13! It went so much better the second time, and not just because I didn’t wipe out (although not wiping out did help).

Here’s what was really different: my attitude. The first time I attempted the APREP, I was thinking about all the people I was afraid to let down. Fear was the underlying emotion, and that’s not good. Ultimately, I was afraid of letting myself down, and not just all the people who were supporting me. It was the worst possible attitude I could have approached the situation with, because if you tell yourself “don’t screw up” then chances are, you are going to screw up.

I was determined to pass the second time, and I knew my attitude would make or break me. A friend lent me a book on sports psychology (“Mind Gym” by Gary Mack. I highly recommend it.), and I powered through it. Major league and Olympic athletes go through the same thing, I found, even though you don’t see what’s going on in their heads when you watch a hockey game or the Olympics on TV. The author of the book stated that most successful athletes have a pre-game ritual that they go through every time they have a game, and it is often a form of visualization. In other words, if you visualize yourself succeeding, chances are much better that you will. The author said it should be like “your own highlights reel” that you play in your head before something important.

So I gave it a try. I visualized being completely at peace, yet with razor focus. I thought of the time I went skiing and didn’t fall down on a big hill (don’t you dare laugh!) and when I wrote my EPS entrance exams and set a high score record for one of them. I remembered how excited and happy and proud I felt, and how I couldn’t wait to feel that again when I ran the APREP. And all those people I didn’t want to let down? I thought of how I couldn’t wait to tell them how well I did, and how much gratitude I felt towards them.

As Yoda famously said, “Do or do not. There is no try.” I did, and I passed with flying colours. It doesn’t matter how big or small your goal is. If you believe you can do it, you can.

Afternote: I wanted to draw a cartoon to fit this post, but instead drew one about budget-friendly working out. I was putting stuff away in the pantry, and it suddenly dawned on my that I could use a large can of tomatoes to roll out my quads!

budgetfriendly

Posted in Fun, Goal App | Comments Off on Success at last!

Today I Learned How To Create Xamarin iOS and Android Unit Tests

I’m currently working on a notification plugin for Xamarin Forms and wanted to setup some unit tests.  The problem is my code accesses the device-specific notification systems in iOS and Android.  This means I can’t just run my unit tests on Windows.  Instead I need to run the unit tests in a iOS or Android environment.  In my case this means an emulator.

How to do that?  Use the NUnit 3 Xamarin Runners.  It was not clear how to correctly create the test projects but the way that worked for me was this.

Create a Shared Project For the Tests

What is a shared project?  I don’t remember the exact problem I had but I first tried creating a portable project.  That failed for some reason I can’t remember so I switched to a shared library.

Create Shared Project

This will be the project your tests will reside in once you write them.  For example in the XPlugins Notifications project I have the following tests.

Shared Project with Tests

You won’t have any tests but should create one now just for testing.  Create a test that simply passes or fails.  Something like the below.

[TestFixture]
class ExampleTests
{
    [Test]
    public void SmokeTest()
    {
        Assert.That(true);
    }
}

Since this is a shared project we can’t actually run it.  The shared project needs to be included in an Android or iOS project.

Create Droid Test Project

First the Droid project.  It’s just a standard Android application.

Create Droid Test Project

In the new Android project add a reference to your test’s project.

Reference Shared Test Project From Droid Project

Then you need to add the following code to the MainActivity classe’s OnCreate method:

// This will load all tests within the current project
// and run them.
 var nunit = new NUnit.Runner.App {AutoRun = true};

The full OnCreate method will look something like this:

protected override void OnCreate(Bundle savedInstanceState)
{
    base.OnCreate(savedInstanceState);

    Xamarin.Forms.Forms.Init(this, savedInstanceState);

    // This will load all tests within the current project
    var nunit = new NUnit.Runner.App {AutoRun = true};

    LoadApplication(nunit);
 }

Now you should be able to run your test.  Set the droid project as your startup project and run it either on your device or your favourite emulator.  You should get the below output if everything is working.

Droid Overall Test Results

Droid Test Results

Create iOS Test Project

Creating the iOS test project is similar to the Android.  First add a basic iOS project.  In our case we add a universal iOS project.

Create iOS Test Project

Add a reference to your test project.

Reference Shared Test Project From iOS Project

Then add the code snippet to run the tests to the FinishedLaunching method in the AppDelegate class.

// This will load all tests within the current project
var nunit = new NUnit.Runner.App {AutoRun = true};

The full FinishedLaunching method will look something like this:

public override bool FinishedLaunching(UIApplication app, NSDictionary options)
{
    Forms.Init();

    // This will load all tests within the current project
    var nunit = new NUnit.Runner.App {AutoRun = true};

    LoadApplication(nunit);

    return base.FinishedLaunching(app, options);
 }

Now the tests should run on an iOS device.

iOS Overall Test Results

iOSTest Results

Writing a Test for a Specific Platform

Your tests might require a reference to a specific platform.  If that is the case then you can use a compiler directive.

#if __ANDROID__
    _schedulerToTest = new Notifications.Droid.NotificationScheduler();
#elif __IOS__
    _schedulerToTest = new Notifications.iOS.NotificationScheduler();
#else
    throw new Exception("Invalid envrionment.")
#endif

An example of a test file looks like this:

/// <summary>
/// Tests to make sure notifications can be found.
/// </summary>
[TestFixture]
internal class FindTests
{
    /// <summary>
    /// The schedule to test.
    /// </summary>
    private INotificationScheduler _schedulerToTest;

    /// <summary>
    /// Load the correct scheduler based on the environment we are in.
    /// </summary>
    [OneTimeSetUp]
    public void OneTimeSetUp()
    {
#if __ANDROID__
        _schedulerToTest = new Notifications.Droid.NotificationScheduler();
#elif __IOS__
        _schedulerToTest = new Notifications.iOS.NotificationScheduler();
#else
        throw new Exception("Invalid envrionment.")
#endif
 }
    /// <summary>
    /// Should find a created notification.
    /// </summary>
    [Test]
    public void NotificationExists()
    {
        // Create the notifiaction to find.
        const string expectedNotificationTitle = "Test Notification";
        const string expectedNotificationMessage = "This is a test notification.";

        var expectedNotificationId = _schedulerToTest.Create(expectedNotificationTitle, expectedNotificationMessage, DateTime.Now.AddHours(1));

        // Try to find it.
        var resultNotification = _schedulerToTest.Find(expectedNotificationId);

        Assert.That(resultNotification, Is.Not.Null);
        Assert.That(resultNotification.Title, Is.EqualTo(expectedNotificationTitle));
        Assert.That(resultNotification.Message, Is.EqualTo(expectedNotificationMessage));
    }
 }

Remember these tests require items specific to the iOS or Android environment.  In this case notifications.  If you are just testing business logic that does not require a feature on a specific device then just add a standard Class Library project to hold your tests.

Save

Save

Posted in Goal App, Today I Learned | Tagged , , , , | Comments Off on Today I Learned How To Create Xamarin iOS and Android Unit Tests

The Vinyl Cafe – So Long For Now

A couple of weeks ago, we at Saturday Morning Productions learned that Stuart Maclean, of CBC’s The Vinyl Cafe, passed away of melanoma. It was a loss felt keenly by all of us (Liv, Ada and Chris). When I (Liv) started working at Saturday MP, I was happy to discover that I wasn’t the only Vinyl Cafe listener on the team. Stuart’s Dave and Morley stories cracked me up on a regular basis, and some of the musicians he had as guests over the years had become regulars on my playlists (especially Owen Pallett and Harmony Trowbridge).

I was lucky to see his show live twice, both times in Ontario. He came to Peterborough in October 2005, and told the story of how Dave and Morley prepared for parenthood when they were expecting their first child, Stephanie. Dave was worried that he might not have key parental instincts, like not rolling over and squishing your baby when you were lying next to her. He practiced by filling a ziplock bag with peanut butter and laying it next to him in bed. When he woke up the next morning – you guessed it – Dave had rolled over on it and there was peanut butter everywhere. “I killed her!” Dave screamed in anguish. The audience howled.

A few months later, I got to see his Christmas show in Toronto. It was the day before I was supposed to fly home to Saskatchewan for the holidays. The show was at the University of Toronto’s Convocation Hall. The building was ancient and stately. The acoustics were incredible. The hall was packed. I was two rows from the front. Stuart told “Dave Cooks the Turkey,” of course. He was touring with a talented young man named Owen Pallett. Owen Pallett is a violinist, who records himself as he plays, and then builds layers of melodies consecutively as the song wears on. It sounds like a whole orchestra, but it’s just him. I remember him playing a tune called “Song Song Song.” Have a listen. The layers of melody circled higher and higher, weaving like a sinuous cat around the pillars and rafters, higher and higher into the winter night before evaporating like snowflakes. It was so beautiful that I was almost in tears by the time the last notes played.

I found out after I started working with Chris and Ada that The Vinyl Cafe was a fixture in their lives too – often, it played on the radio in their kitchen. It’s the kind of show that had no fixed demographic. It didn’t seem to matter who you were or where you came from. Everyone could relate.

I had always planned to go and see another show, but it wasn’t to be. I moved. Life happened. I suspect there are a great many who will mourn the loss of Stuart and The Vinyl Cafe. He was all of us, in a way. The stories were about small things. Relatable things. I’m not sure what show I’ll tune into now as I putter around on Sundays.

And yet, I know it’s not good-bye. It’s just so long for now.

Posted in Uncategorized | Comments Off on The Vinyl Cafe – So Long For Now

Making Lemonade…

On January 16th I took a flying spill when I tried to drag a huge dude-sized dummy for 50 feet. There I was, lying on the gym floor, elbows bloodied and pants torn, with an astounded audience looking just as horrified as I was. How did I get there?

*sound of a record needle being ripped off the record*

Wait. Let me back up a bit. That Monday I took a run at the EPS physical assessment. The APREP. It stands for “Alberta something something something.” Maybe one of the P’s stands for policing. Probably. I should look that up. It’s a two part test, with the first part being a timed obstacle course that includes walls, stairs, nefarious equipment and – yep, right at the end when you’re tired – dragging a dummy. You have to finish in under 2 minutes and 10 seconds.

I’d been training hard for this course since last March. I was well-rested, cautiously optimistic, and ready. So what went wrong? I screamed through the stairs, walls and equipment, but when I went to drag the dummy, things did not go as expected.

You’re supposed to grab him by a rope around his ankles (because all people who require rescuing have an ankle rope, right?) and drag him 25 feet to a pylon and then back across the line. I grabbed the ankle rope and lunged. Big mistake. The dummy outweighs me, and then good old physics kicked in. I went flying across the gym floor. You could almost hear this gasp of horror from everyone in the room. I knew it was game over when I hit the floor, but I had to get up and complete the task. But my heart was in my shoes. I was the only unsuccessful candidate in my group.

After the dust settled, I found myself sitting in the car in the parking lot, staring out the window at the pervasive grey that dominated both sky and ground. How was I going to tell everyone that had wished me well that I had failed. On the long drive home, it occurred to me that this setback had an unexpected bonus. I now had a few extra weeks to study for my interviews, since I was rebooked to rerun the course in February. The more I thought about it, the better I felt. The friction burns on my arms are still scabby, and I have yet to sew the rip in my pants, but my epic pile of lemons has made some very useful lemonade.

P.S. I tried really hard to think of good illustrations for this post, but I drew a blank. Literally!

Posted in Fun, Goal App | Comments Off on Making Lemonade…

Why I’m not a fan of New Year’s Resolutions

Wow, we are already one week into 2017. The Christmas decorations are put away, the leftovers are eaten, and I have to get used to writing the correct year. So far it’s going well, although my brain had a glitch last week where I kept writing “2012.”It’s also the time where I keep getting asked what my New Year’s resolutions are. My standard answer has been “get more sleep and eat more food.” It’s not really a serious answer, because I am not a fan of New Year’s resolutions.

Here’s why. It’s pretty easy to get caught up in the idea that a new year magically brings a clean slate where all past indiscretions are deleted and all the food you’ve eaten suddenly doesn’t have calories. I get that the start of a new year, symbolically, means a whole year ahead to make better choices. However, our past choices tend to follow us. Change is tough, and it is so easy to become disillusioned by the second week of January once it sinks in how difficult our resolutions are. Get hired by EPS? (I thought last new year) Yeah right! That’s going to be like climbing a sheer cliff. I don’t even know where to begin.

Instead, I think it’s more realistic to make very small changes. They don’t have to be on New Year’s Day to be effective or meaningful either. Maybe just one small change (like going for a ten minute walk every other day) at a time. That way, it isn’t overwhelming or discouraging. That is what we are hoping the Goal Buddy app will accomplish: help establish a pattern of small, positive choices that are cumulative towards a grander goal.

As for me, I am going to try skiing once per week. I went this morning and I already know I’ll need a paint roller covered in Rub-A535 tomorrow…

paintroller

Save

Posted in Fun, Goal App | Comments Off on Why I’m not a fan of New Year’s Resolutions

Merry Christmas from Saturday Morning Productions

Merry Christmas everyone! We can hardly believe how quickly 2016 has gone by and that the new year is almost here.

xmas3So many things have happened that it’s going to be a challenge to summarize them all here without making you read for the next hour. But hey, challenges are fun! This year Ada got a brand-new full time job that she will start in the new year. She and her family also traveled to Hong Kong and China, and saw tons of interesting things including the Great Wall and the Forbidden City. Chris worked hard on xmas2developing Goal Buddy (as did Ada!), as well as his other computer projects. He said that his big goal is to become a better communicator.

I (Liv, that is) had one heck of a year too. I started the huge goal of joining EPS, and that meant an overhaul of  my entire life, including fitness, discipline, going to bed at a reasonable hour, and as I write this I am proud to say that I have cleared the first hurdles and have my xmas1physical assessment (the APREP) coming up in January. When I started working out seriously in March, I could barely deadlift 60 pounds and couldn’t do a chin-up to save my life. I’m now proud to say I can deadlift nearly 200 pounds and do wide-grip pull-ups as well as chip-ups.

Thanks for joining us on this journey, and we look forward to achieving goals with you in 2017! Merry Christmas to all and to all a good night.

Posted in Fun | Comments Off on Merry Christmas from Saturday Morning Productions

Today I Learned How to Create a Local Notification in Xamarin Android

In Android you can schedule a notification that shows immediately using the NotificationManager.  However, if you are like me, awesome, and want to schedule a notification for a future date you need to use the Android AlarmManager.  The alarm manager lets you schedule an Intent to occur at a later date.

Quick aside, do you know what an Intent is in Android?  I kind of understand them but not as in-depth as I would like.  Please forgive any errors I make when I setup the alarm intent below.

Without any further hesitation here is the code to schedule a local notification stolen from the SaturdayMP.XPlugins.Notifications:

public Guid Create(string title, string message, DateTime scheduleDate, Dictionary<string, string> extraInfo)
{
  // Create the unique identifier for this notifications.
  var notificationId = Guid.NewGuid();

  // Create the intent to be called when the alarm triggers. Make sure
  // to add the id so we can find it later if the user wants to update or
  // cancel.
  var alarmIntent = new Intent(Application.Context, typeof(NotificationAlarmHandler));
  alarmIntent.SetAction($"{notificationId:N}");
  alarmIntent.PutExtra("title", title);
  alarmIntent.PutExtra("message", message);

  var pendingIntent = PendingIntent.GetBroadcast(Application.Context, 0, alarmIntent, PendingIntentFlags.UpdateCurrent);

  // Figure out the alaram in milliseconds.
  var utcTime = TimeZoneInfo.ConvertTimeToUtc(scheduleDate);
  var epochDif = (new DateTime(1970, 1, 1) - DateTime.MinValue).TotalSeconds;
  var notifyTimeInInMilliseconds = utcTime.AddSeconds(-epochDif).Ticks/10000;
  
  // Set the notification.
  var alarmManager = Application.Context.GetSystemService(Context.AlarmService) as AlarmManager;
  alarmManager?.Set(AlarmType.RtcWakeup, notifyTimeInInMilliseconds, pendingIntent);

  // All done.
  return notificationId;
}

First thing to notice is the GUID. This is not required when scheduling a notification but can be useful later when you need to find and cancel it.

// Create the unique identifier for this notifications.
var notificationId = Guid.NewGuid();

Next you need to create the intent you want to occur.  This is the notification as well as what happens when the user clicks on the notification when it appears.  When creating the intent set the class you want to be executed.  In this case it’s the NotificationAlarmHandler.

var alarmIntent = new Intent(Application.Context, typeof(NotificationAlarmHandler));

The title and message are displayed when the notification is displayed.  The action is set to the GUID so we can find the notification at a later and cancel it.

alarmIntent.SetAction($"{notificationId:N}");
alarmIntent.PutExtra("title", title);
alarmIntent.PutExtra("message", message);

Then you need to wrap the intent in a pending intent.  What is the different between an Intent and PendingIntent?  Well a pending intent is an intent that will occur sometime in the future.  Just like it sounds.  Actually a PendingIntent is a reference to the actual Intent so if your application is shut down your scheduled intent is not destroyed.  Remember I don’t really understand Intents very well.

var pendingIntent = PendingIntent.GetBroadcast(Application.Context, 0, alarmIntent, PendingIntentFlags.UpdateCurrent);

Next we need to translate C# dates to Android dates.  Don’t ask me for the details.  I found this code in edsnider/Xamarin.Plugins project.  Something to do with the Unix epoch.

// Figure out the alaram in milliseconds. var utcTime = TimeZoneInfo.ConvertTimeToUtc(scheduleDate);
var epochDif = (new DateTime(1970, 1, 1) - DateTime.MinValue).TotalSeconds;
var notifyTimeInInMilliseconds = utcTime.AddSeconds(-epochDif).Ticks/10000;

Finally we are at the moment we can actually schedule the notification.  Man that took longer than it should have.  Let me catch my breath.  I think I suffer from Panda Asthma.

Now that I have my breath back let’s schedule the notification.  This part is straight forward. Just get an instance of the AlarmManager and then schedule our pending intent. Ask the alarm to  wake up our application, if it’s asleep, at our scheduled time.

// Set the notification.
var alarmManager = Application.Context.GetSystemService(Context.AlarmService) as AlarmManager;
alarmManager?.Set(AlarmType.RtcWakeup, notifyTimeInInMilliseconds, pendingIntent);

That’s it.  The shows over.  Go home.

P.S. – Today’s programming song is about communication.  Make sure you communicate with those important to you.  Also yelling “Say something, I’m giving up on you” at your phone when your notification code is not working is therapeutic.

Posted in Goal App, Today I Learned | Comments Off on Today I Learned How to Create a Local Notification in Xamarin Android

Operation Add Author Profile Pictures (OAAPP)

You may have noticed that our smiling faces now accompany our posts. This is to prevent confusion among our long time readers who may think that Chris is joining the Edmonton Police (he’s not, Liv is) or that Liv has a behemoth garden (she doesn’t, I do). Also, so you can see our smiling faces.

If you are looking to do the same for your blog, you can follow the steps I took.

Step 0 – Research (and know what you’re looking for)

The real issue we were facing was not being able to add a profile picture unless we had Gravatar accounts.  We wanted to use pictures uploaded to our media library.  I researched how to add a profile photo from our media library to our WordPress blog.  I read technical stuff I didn’t really understand.  You might too.  It’s important to note which ones you looked at but won’t work, and why, if that’s important to you.  Note which ones you want to try out.

Step 1 – Try it out and choose your plugin

Try your solution(s) on a Staging server. Find this under WPEngine –> Staging.

staging

Life does not have an undo button, but luckily your blog does.

I originally chose User Photo but after installing the plugin, WordPress alerted me that it was outdated and pointed me to User Profile Picture.  Good thing I tried this all in Staging first.  Once you’re satisfied with the results, bring it into Production.

Step 2 – Back up your blog

Go to WP Engine User Portal and back up.

backup

 

Step 3 – Follow the installation instructions

This may be easier said than done since I really didn’t understand the technical stuff that I read.

instructions
I understood 1. Download the plug-in file, upload the folder to the directory and 2. Activate the plugin (hint: there are buttons that say “Add New” and “Upload Plugin” and “Install Now”).  From there I was admittedly lost.

It said “3. Place code-y stuff in your templates and 4. Use the “Override Avatar” function to change your default avatar.”

Knowing what I know now and having done this once in staging, I would advise reversing the two steps:

3. Use the “Override Avatar” function to change your default avatar and
4. Place code-y stuff in your templates.

This is so we could get our smiling faces in a row, add them to our profiles, and then plug in those proverbial Christmas lights.  It’s your choice.

On your side menu, go to Appearance –> Editor. On the right Templates menu, click on Theme Functions (footnote functions.php)

functions

I scrolled down to the bottom of the code-y part and added

 add_filter( 'mpp_avatar_override', '__return_true' );

so the “Override Avatar” checkbox would be checked by default.  You may not want this, but we did.

4. is still gibberish to me, but after some playing around, and with the help of a code-cracking genius husband/business partner, we deciphered this to mean “make changes to loop.php, which is the code for what to display for each of the blog posts (loop, you get it?)”

We opened loop.php.

On your side menu, go to Appearance –> Editor. On the right Templates menu, click on loop.php)

loop

We played around a bit, not really knowing how to go about this.  Admittedly, Chris is rusty in php land.

We scrolled around on the blog and thought out loud “well, we’d want our smiling faces to be near where it says our usernames. i.e. Posted on by…” We searched for the words “Posted on” and found it was a variable called

twentyten_posted_on()

We put this block/chunk of code before the 3rd instance of it.

<?php
if (function_exists ( 'mt_profile_img' ) ) {
    $author_id=get_the_author_meta( 'ID' );
    mt_profile_img( $author_id, array(
        'size' => array(32,32),
        'attr' => array( 'alt' => 'Author Image' ),
        'echo' => true)
    );
}
?>

We also wanted our faces to be smaller than the default “thumbnail” size, so I learned a bit about php arrays from here and chose 32 pixels by 32 pixels. We also changed the Alternative Text to read “Author Image”. That’s it!

Armed with this, you too can run your own OAAPP.

Save

Save

Save

Save

Save

Save

Save

Save

Save

Save

Save

Save

Save

Save

Posted in Fun | Tagged , | Comments Off on Operation Add Author Profile Pictures (OAAPP)