Press enter after choosing selection

The AADL Developer's Blog. Technical info about what new features we're working on, releasing, and playing with.

AADL Developer Blog

Welcome to the AADL Developer Blog! Software Development is a big part of what we do here at AADL, and this section of is the place to keep up with our new features, see what our developers are working on, and find out what kind of tools we're playing with.

We also have open-source software that we've developed available for download, and you can find that [:services/devblog/downloads|here]. Please feel free to comment on our posts or [:contactus] if you have any other questions, and thanks for your interest!

Graphic for events post

Blog Post

PreK Bits - "D" is for DOG

Wed, 03/01/2017 - 1:54pm by LibraryRachel

Ms. Rachel and Ms. Betsy brought all dog songs and stories to Storytime.
Stuffed dogs acted-out the story and the audience barked along with the dogs in DOGGIES by Sandra Boynton.
We sang “B-I-N-G-O” ... which can be found on youth CDs SONGS & STORIES For KIDS, BABY BOOST: 48 Interactive Sing-a-longs For Your Little One and LITTLE PEOPLE: Songs From The Farm.
In the story KATIE LOVES the KITTENS ... it is hard to stop bouncing and barking and the kittens keep running away.

For more famous DOG stories try the following favorites:
RAGWEED’S FARM DOG HANDBOOK by Anne Vittur Kennedy ... Learn From The Best!
HARRY The DIRTY DOG and NO ROSES For HARRY ... old dog classics by Gene Zion.
BUDDY And EARL and BUDDY And Earl And The GREAT BIG BABY ... new dog classics by Maureen Fergus.
MISS MOON: Wise Words From A Dog Governess by Janet Hill ... wise words for All with beautiful illustrations!
ZORRO GETS AN OUTFIT and MR BUD WEARS The CONE by Carter Goodrich ... a pitch-perfect dog point-of-view.
BARK GEORGE by Jules Feiffer... a dog fantasy.
The DOGHOUSE ... critters go in but they don't come out. Surprise?
For screen-time try the DVD BARK GEORGE And More Doggie Tails by Weston Woods Studios.
WOOF! ... snooff snurff ... doggie treat, Please.
... pant ... pant ...

Graphic for events post

Public Event

Biking Northern Michigan

Saturday April 23, 2016: 3:00pm to 4:30pm
Downtown Library: 4th Floor Meeting Room
Grade 6 - Adult

Graphic for events post

Blog Post

Stuff We Like: Code School

Mon, 03/16/2015 - 12:24pm by ejk

Trying to learn more about a new programming language? Want to quickly try out writing some code without having to set up a complete environment? Check out Code School.

They offer multiple free courses on Ruby, Javascript, HTML/CSS, iOS and more. And the great thing is that each lesson is presented in small, incremental exercises where you write the code and see your result right within your browser window. No need to install anything on your local system. Immediate feedback on your code and helpful hints.

I just completed their free course on Angular.js for an upcoming project idea and I was able to get through the five lessons in a couple of hours. Lots of the courses are free, so give it a shot!

Code School:
Shaping Up with AngularJS:

Graphic for events post

Blog Post

Watching Drupal 8

Mon, 02/23/2015 - 11:48am by ejk

The AADL website is approaching its 10 year anniversary of running on the Drupal platform. Since then it has allowed us to create a powerful web presence and products like our catalog, Old News, and the Summer Game.

Drupal is readying a new major release, Drupal 8. Features have been frozen, and the work is concentrating on eliminating the remaining critical issues. At the beginning of 2015, there were 84 critical issues. Currently there are 55 remaining. Once that number reaches zero, Drupal will release their first Release Candidate of Drupal 8.

The best way to track the progress is on the "Get Involved" page on There you can see a interactive graph of the critical issue progress as well as more information about how to contribute to the project.

We anxiously await the new release and working on leveraging its new features for the future of

Graphic for events post

Blog Post

Git Tip: Commit part of a file

Mon, 02/09/2015 - 11:45am by ejk

I recently found myself in the position of having edited a single file of code for two different projects at the same time (I know, I know, I should have branched first before editing) and not wanting to commit both of them at the same time. Well git has an awesome feature for staging code changes based on section, rather than the entire file. Just stage the file with

git add --patch filename.code

and it will present you with an interactive prompt for each section of changed lines within the file, allowing you to include that section or not in the new commit.

I was able to easily commit the changes that were ready and roll them out while holding off on the changes that weren't ready. Oh, and I immediately moved those changes to a new branch so as not to run into this problem again.

Source and further info: commit-only-part-of-a-file-in-git

Graphic for events post

Blog Post

Git Alias for Log and Status

Mon, 09/08/2014 - 11:05am by ejk

I found that I often was doing a "git log" plus a "git status" when visiting a repository I hadn't touched in a while, just to get a lay of the land. Here's a quick alias I whipped up for git that combines the two, giving you a peek at how recently the repository has commits and also if there are any uncommitted changes lurking around.

Here's an example of the output:

$ git logstat == LOG =========== d5e8186 ejk 2014-08-31 Add badge check for all players function 9c3d1e5 ejk 2014-08-04 Correct default end date on game code form if left blank 1f48884 ejk 2014-07-20 Add curly brackets to badge formula description == STATUS ======== # On branch master # Untracked files: # (use "git add ..." to include in what will be committed) # # ._.DS_Store # pdf/._adult_game.pdf # pdf/._adult_game_1.pdf # pdf/._adult_game_2.pdf # pdf/._sg2014_adult.pdf nothing added to commit but untracked files present (use "git add" to track)

Create the alias from a shell prompt:

$ git config --global alias.logstat 'echo "== LOG ===========" && git log --date=short --pretty=format:"%h %an %ad %s" -n 3 && echo "== STATUS ========" && git status'

Or create the alias in your .gitconfig:

[alias] logstat = "!echo \"== LOG ===========\" && git log --date=short --pretty=format:\"%h %an %ad %s\" -n 3 && echo \"== STATUS ========\" && git status"

More about git aliases: Aliases

Graphic for events post

Blog Post

Paying with Points: Creating a Custom Payment Type in Ubercart

Mon, 07/28/2014 - 10:30am by ejk

Our players have kept the Summer Game Shop busy this summer; as of this writing, we have received and processed 1599 orders, with an additional 190 orders waiting to be filled this week, with a total of 14,841,000 Summer Game points spent. We use the Drupal module Ubercart to run our shop. It keeps track of item inventory, allows for customer cart & checkout, and keeps track of orders. Normally, Ubercart expects payment to be in US dollars via check or credit card, but it provides a nice set of API hooks to allow us to pay with points instead of dollars. Here's the code we use to talk to Ubercart:

First thing we need to do is to tell Ubercart that we have a new payment method to allow the user to choose at checkout, using hook_payment_method. Ours has a little wrinkle in that we need to allow payment any of your players if you have multiple players attached to your website account. So we load all of your players and list them all as separate payment methods. For each player, we grab your total points to display in the payment method text.

function uc_summergame_payment_method() { global $user; $methods = array(); foreach (summergame_player_load_all($user->uid) as $player) { $balance = 0; $tokens = 0; $uc_game_term = variable_get('uc_summergame_game_term', ''); $uc_token_term = variable_get('uc_summergame_token_term', ''); $player_points = summergame_get_player_points($player['pid']); foreach ($player_points as $game_term => $game_details) { if (strpos($game_term, $uc_game_term) !== FALSE) { $balance += $game_details['balance']; } else if (strpos($game_term, $uc_token_term) !== FALSE) { $tokens += $game_details['balance']; } } $playername = ($player['nickname'] ? $player['nickname'] : $player['name']); $methods[] = array( 'id' => 'sgpoints' . $player['pid'], 'name' => $playername . ' SG Points', 'title' => "$playername's Summer Game points (current balance: $balance points" . ($tokens ? "+ $tokens Tokens" : '') . ')', 'desc' => t('Pay with points earned by playing the Summer Game.'), 'callback' => 'uc_summergame_method_sgpoints', 'weight' => ++$weight, 'checkout' => TRUE, ); } return $methods; }

Next we need to tell Ubercart how to validate an order when it's processed. The main thing we need to check is that the player has enough points to pay for the order. The function named in the 'callback' element of the $methods array in the previous section of code will do this validation for us:

function uc_summergame_method_sgpoints($op, &$order) { if ($op == 'cart-process' && strpos($order->payment_method, 'sgpoints') === 0) { $valid = FALSE; $pid = str_replace('sgpoints', '', $order->payment_method); if ($player = summergame_player_load(array('pid' => $pid))) { $balance = 0; $tokens = 0; $uc_game_term = variable_get('uc_summergame_game_term', ''); $uc_token_term = variable_get('uc_summergame_token_term', ''); $player_points = summergame_get_player_points($player['pid']); foreach ($player_points as $game_term => $game_details) { if (strpos($game_term, $uc_game_term) !== FALSE) { $balance += $game_details['balance']; } else if (strpos($game_term, $uc_token_term) !== FALSE) { $tokens += $game_details['balance']; } } // Get token total (using the "weight" field of the products) $order->token_total = 0; foreach ($order->products as $product) { $order->token_total += $product->weight; } if ($balance < $order->order_total || $tokens < $order->token_total) { drupal_set_message("Your balance of $balance Summer Game points" . ($order->token_total ? " and $tokens Tokens" : '') . " is not enough to complete this purchase.", 'error'); } else { $valid = TRUE; } } else { drupal_set_message('You need to sign up for the Summer Game to earn points to make this purchase', 'error'); } return $valid; } }

Finally, we need to hook into the various order states to do the actual points transactions, using hook_order. If the order is being submitted, we deduct points on the player's ledger. If the order is canceled or deleted, we need to add a refund to their ledger.

function uc_summergame_order($op, &$order, $arg2) { // Get token total (using the "weight" field of the products) $order->token_total = 0; foreach ($order->products as $product) { $order->token_total += $product->weight; } switch ($op) { case 'submit': // fires when the order is submitted and adds/subtracts thier points if (strpos($order->payment_method, 'sgpoints') === 0) { $pid = str_replace('sgpoints', '', $order->payment_method); $player = summergame_player_load(array('pid' => $pid)); $order_link = l('Created Order #' . $order->order_id, 'user/' . $order->uid . '/order/' . $order->order_id); summergame_player_points($player['pid'], -$order->order_total, 'Shop Order', $order_link, "delete:no leaderboard:no"); if ($order->token_total) { summergame_player_points($player['pid'], -$order->token_total, 'Shop Order', $order_link, "delete:no leaderboard:no", variable_get('uc_summergame_token_term', 'SecretShopTokens')); } } // send label to printer if ($label_email = variable_get('uc_summergame_label_email', '')) { uc_summergame_print_premium_label($order, $label_email); } break; case 'update': // if the order is canceled we need to refund thier points if ($arg2 == 'canceled') { if (strpos($order->payment_method, 'sgpoints') === 0) { $pid = str_replace('sgpoints', '', $order->payment_method); $player = summergame_player_load(array('pid' => $pid)); $order_link = l('Refund for Order #' . $order->order_id, 'user/' . $order->uid . '/order/' . $order->order_id); summergame_player_points($player['pid'], $order->order_total, 'Shop Refund', $order_link, "delete:no leaderboard:no"); if ($order->token_total) { summergame_player_points($player['pid'], $order->token_total, 'Shop Refund', $order_link, "delete:no leaderboard:no", variable_get('uc_summergame_token_term', 'SecretShopTokens')); } } } if ($arg2 == 'completed') { // Send a message to the player uc_summergame_send_pickup_notice($order); } break; case 'delete': if (strpos($order->payment_method, 'sgpoints') === 0) { // Refund the points $pid = str_replace('sgpoints', '', $order->payment_method); $player = summergame_player_load(array('pid' => $pid)); $order_link = l('Refund for Order #' . $order->order_id, 'user/' . $order->uid . '/order/' . $order->order_id); summergame_player_points($player['pid'], $order->order_total, 'Shop Refund', $order_link, "delete:no leaderboard:no"); if ($order->token_total) { summergame_player_points($player['pid'], $order->token_total, 'Shop Refund', $order_link, "delete:no leaderboard:no", variable_get('uc_summergame_token_term', 'SecretShopTokens')); } } break; case 'can_delete'; return FALSE; break; } }

Keep those orders coming!

Ubercart API:
Summer Game:

Graphic for events post

Blog Post

Summer Game Tech: QR Code Generator

Mon, 07/21/2014 - 2:09pm by ejk

The Summer Game is a really busy time for us at the library; many of us are involved with producing special events, writing up Game Codes & Badges, and processing and filling your orders for prizes. The Summer Game season each summer gives us an opportunity to develop improvements to the game from year to year. One of the new features for our fourth season of the Summer Game is QR Codes on the Game Code posters around the branches and displayed at events. The QR Code has a link embedded that goes directly to the code submission form with the code in the text field, ready to submit and receive points.

Finding a QR code reader for your device is usually a pretty easy affair (I use Red Laser), but getting one generated can be a hassle, especially if you're trying to integrate it with a script. After looking at some hefty looking libraries to integrate with our sign PDF generation script, I found the QR Code API from You can pass in your QR code parameters via a URL with GET or POST variables, and it will return a QR Code image in your desired format. It was a very simple matter at that point to embed the image in our PDF generation script, no additional libraries required.

For example:

Generates the following image:
Image removed.

The service is currently provided free of charge, with no limit. They do request you contact them if you will use more than 10,000 requests per day.

Enjoy the Summer Game, and keep entering those Game Codes!

QR code API:
Red Laser:
AADL Summer Game:">

Graphic for events post

Blog Post

Dev Tools: Modern IE

Tue, 05/27/2014 - 11:11am by ejk

[img_assist|nid=263711|title=|desc=|link=none|align=left|width=100|height=80]One of the most challenging aspects of web development is making sure your site works on multiple platforms. Firefox and Chrome are available for most every system where you develop, but tracking down one of the different versions of Internet Explorer to try to reproduce a bug can be an exercise in frustration. Luckily, Microsoft has generously created Virtual Machines containing versions of Internet Explorer from the current IE 11 all the way back to IE 6, and made them freely available. These can run in another piece of freely available software, VirtualBox, which will run on your development system.

modern.IE currently provides the following Virtual Machines:

  • IE 11 on Windows 8.1
  • IE 10 on Windows 8
  • IE 11 on Windows 7
  • IE 10 on Windows 7
  • IE 9 on Windows 7
  • IE 8 on Windows 7
  • IE 7 on Windows Vista
  • IE 8 on Windows XP
  • IE 6 on Windows XP

Image removed.

Getting all these Virtual Machines downloaded and installed properly can be difficult, but luckily there is a terminal script which will do the downloading and initial config for you. Running the bash script from the IEVMS repository on Github will automatically download all or just selected versions of the modern.IE VMs and get them installed in your VirtualBox. Just run the following command in a terminal:

curl -s | bash

If you've got VirtualBox up and running you can even see your new VMs being created and booted up by the script. Look at the IEVMS page for more information and options.

modern.IE Virtual Machines []
VirtualBox []