We changed our name! After 14 years of creating award-winning digital products & services, it’s time for a new identity that better reflects the human insights-driven, digital customer experiences we create.
We changed our name! After 14 years of creating award-winning digital products & services, it’s time for a new identity that better reflects the human insights-driven, digital customer experiences we create.

AIAIO: Our Blog

AIAIO: Our Blog

The pulse and reviews of Alexander Interactive

Author Archive

New Manager Tools

This article leans slightly towards Technology Management but is applicable across disciplines

You've been a great senior resource, you've lead a team or a project, and you've made the decision, along with your manager to transition to some kind of management role. If you are still thinking about it, or wondering what it will be like, start here: This 90-Day Plan Turns Engineers into Remarkable Managers. This article will give you all of the thought starters your need to decide if management is something you want to pursue.

Below are some required reading to add to your utility belt. Start taking a read through these, and make sure you block off the appropriate amount of time each week to continue your learning! This list is meant to be a starting point for new managers, not an all inclusive list of manager resources


  • Managing Right for the First Time – This book is intended as a field guide for first time managers, or for managers who want to begin doing a better job. David Baker worked closely with 600+ companies and interviewed more than 10,000 employees, then summarized the findings in an interesting and eminently readable form. Read this book and you're likely to understand management and leadership like you never have before, but also learn very practical steps toward becoming a better manager and leader.
  • Getting Things Done: The Art of Stress-Free ProductivityNote: I'm not advocating for using the GTD system. Use what works for you. However, the first half of this book is a gold mine for how to think about planning, resources, and managing your own and other's tasks. I personally do use GTD, but the lessons, and the way of thinking that this book opens up is transferable to any system. It got me thinking about planning and delegating in different and exciting ways. Read the introduction and I guarantee that you'll see scenarios you recognize and want to scream YES, YES I DEAL WITH THIS. I HATE IT! HOW DO I FIX IT?
  • The Personal MBA: Master the Art of Business – This book is, but isn't about MBA. It's a toolkit of how to handle various situations and grow your skill set. It's not meant to be read cover to cover, but peruse the table of contents you'll see things you want to read.
  • Emotional Intelligence for Project Managers: The People Skills You Need to Achieve Outstanding Results – Great book on emotional intelligence

Articles to read

Websites to subscribe to


  • Manager Tools Podcast – A huge library of how to deal with any situation. Skim the list, there will be something in there you want to learn about. Don't forget to subscribe!

If you have anything that should be on this starter list, let me know!

You can follow Tim on twitter.


How to Sync Basecamp Todos to Omnifocus or Todoist

Basecamp is a large part of our process at Ai. It tracks most of our communication (a lot of this has been moving to Slack). Basecamp serves as our system of record for signs-offs and deliverables. We also use it’s “todo” function pretty heavily in the planning stages and tracking client tasks. Once we get into implementation, we transition to Jira, as it’s more powerful. Clients do not have access to Jira.

I don’t have an issue tracking Basecamp tasks. It’s really good at emailing you when something is due. But, as I’ve said before, I’d be even BETTER at it, if the tasks were in my world. My world is Omnifocus, but there is a VERY large contingent of Todoist users at Ai. I am the outlier in this. In the past, my reasons for not using Todoist were I didn’t want Ai tasks and personal project tasks in the same app, the hotkeys weren’t up to snuff, and I didn’t want to pay for premium to get notifications. I’ve since ignored these rules with Omnifocus; It runs everything in my life, it DOES have great hotkeys, and I dropped the $$$ for premium Omnifocus which was more expensive than Todoist premium in the long run. But, this is a topic for another post.

Back on track. How to get Basecamp todos into my system? Again, Zapier to the rescue. Zapier can connect to Basecamp, do some basic filtering to make sure I only get tasks that I care about, and drop them into my Omnifocus inbox. Most of the following steps hold true for both Omnifocus and Todoist

  1. Create a new Zap that triggers when a new Basecamp todo is created. Have it create a new task in your system
  2. Select the appropriate Basecamp account and test it
  3. Select and test your Todoist/Omnifocus account
  4. Choose your Basecamp Account, Project, and Todo list. If you want to filter even more by only items assigned to you, add a custom filter. Do this by either Assignee ID or Name
  5. Match up the Basecamp data to your tool of choice. First is how I send it to Omnifocus. Note, I do need to populate the due date by hand. In both options, I add the url back to the task in Basecamp so I can easy mark it off or comment in it when I’m done. Todoist lets you be a LOT more granular and handles all of the fields so you have no manual intervetntion
  6. My tasks are now in my world. Profit.


You can also follow Tim on twitter


Basecamp 3 is Coming

Basecamp 3 is coming and I’m exited. Below are excerpts from Basecamp’s preview post on what I’m looking forward to most

Basecamp won’€™t send you any emails, push notifications, or in-app notifications if it’s outside your specified work hours. Live a little! Work Can Wait until you’re back at work.

group chat room for quick discussions

This is cool but it came a little too late. We’ve been using slack for project based and individual chat. It has a dedicated app that is easy to cmd+tab to. I see campfire in the browser sitting in an unchecked tab and not being useful

Show someone you care by clicking the Applause button on any message, comment, document, or answer on any automatic question. They’ll get a discrete notification letting them know you appreciated what they said. This is a great way to show your support for someone’s suggestion, idea, or point of view without also sending a notification to everyone else on the project.

e.g. What did you work on today€ or Are you blocked on anything?)

Hmm, I wonder if this could be used for virtual scrum?

@mentions: Psst!


They’ll instantly get a notification letting them know they’ve been mentioned, along with a direct link right back to where you mentioned them

If you’re not in the desktop app

Buhhh wait what? Ok maybe what I said about the tabs and apps above might not apply

You can bookmark just about anything in Basecamp 3 so you can jump right back to it from anywhere else

This will be handy. Here are always a few key threads I end up digging for. Usually long running threads about key deliverables

At the bottom of every project is a timeline of all activity going back to the moment you started the project

I like this if search hadn’t been improved. This has a lot easier than scrolling through all the lists looking for something around a certain time

So you can make a folder and put a photoshop file, a Google doc


Now you can assign to-dos to multiple people. Now you can set date ranges, not just single due dates. Now you can bulk assign multiple to-dos with a single click. Now you can select multiple to-dos and move them as a group.


Now you can save any new message or document as a draft before you publish it

Basecamp 3 allows you to see all the work you’ve assigned to other people

You can sign up for an early invite here


PHP7 Vagrant Box

We’re keeping a close eye on PHP7 and what it means for the future of the language. We know it’s coming and will eventually effect the way we work and how we write PHP. The earlier we can get eyes on the new paradigm, the better.

Installing in your local dev machine is risky, especially if you have ongoing work. As usual, Vagrant comes to the rescue!

Rasmus Lerdorf has put together a Vagrant box to ease in the setup and isolate your testing. 

If you use Atlas, check out the box here. Otherwise, the readme is available on Github


Mongular, a Content Delivery System

Mongular is something to keep a close eye on. We’ve had a number of projects here at Ai where we might want something… other than a CMS. Where content is king and that content is decoupled from the system using or displaying it.  Other solutions that we’re excited about are Prismic and Contentful.

Systems like this would let us do whatever we wanted with the site. Not being tied to the confines of a particular CMS’ way of doing things could be freeing. These systems offer much more powerful ways to relate content or parts of content to each other. Going far beyond just weighted tags.

What is Mongular?

Mongular is a Content Delivery System (Framework?… not really) built to take advantage of all the tools available to speed up the delivery of your content to users, and reduce server load.

Content Delivery System?

Mongular wasn’t built to be a Content Management System, even though with enough development it could probably be built to do just that.

Mongular was built to deliver content in an easy, efficient and extendable manner. Where developers take it, is up to them.

Related reading:


Holiday site raises over $10K for New York Animals

Arf! Meow. Oink? Woof! Yay!
Our holiday site raised over $10,000 for Bideawee


Our holiday site has always been a chance to do what we do best – be creative, laugh and have some fun. But this year we gave ourselves three goals. We wanted to feature the human beings that make Ai a company like no other, challenge ourselves to try new things, and use our collective energy to do some good.

Everyone chose one thing to make or do to raise money for Bideawee, a leading animal welfare organization in New York. And in true Ai form, people came up with some pretty unique and ambitious ideas. Put on a magic show, let someone shave your beard, create custom bedazzled artwork–the list gets longer and weirder. These contributions were featured for sale on our site and the purchase price of each item sold would be donated to Bideawee in an effort to raise a total of $10,000 by the holidays.

In the end we met our goal, but the success of the project went beyond that. It was an opportunity to try new ways of designing collaboratively, new technology to test drive, new photographers to partner with in attempt to shoot our entire office in 1 day. “The site also became an expression of us as individuals and as a company. Scrolling down the page and seeing the talent and energy our people committed to, it tells the story of who we are.” – Josh Levine, Chief Experience Officer

On the day we launched the site, Bideawee volunteers and some of their cats and dogs paid a visit. While the thrill of birthing our babies never gets old, this launch day was special. It was a celebration of the live site, but it was also a celebration of animals and their ability to bring out the best in humans.

Having lost our beloved Mayor Jack  this year, our French bulldog and VP of Security & Integrity, it felt good to have some four-legged friends in the office. And when one of Bideawee’s pups peed on the office floor, we knew Jack was looking down from heaven–smiling, drooling and sending us his love.

“All of us here at Bideawee are so incredibly appreciative of the AI staff and management for their compassion and generosity in helping Bideawee provide shelter and medical care for the hundreds of dogs and cats waiting for their forever homes this holiday season!” – Nancy Taylor, President and CEO


Shout out to Bel, Nick, Katie, Chris, Judy and Josh for getting the site designed and built, Stephen Landau for photographing our entire company, all of our amazing employees for contributing their talents and passion, and our friends at Bideawee, for helping make this such a rewarding project.
Lastly, a special thank you from all us at Ai, and from the animals at Bideawee to everyone who helped us meet our goal of raising $10,000.


Apple Pay and Magento

The Business of Apple Pay (Alec Simonson)

On the outset, Apple Pay is very cool and could very well be the wave of the future. A lot of this hinges on “what’s under the hood” in terms of Apple’s contract with the leading credit card companies who helped with the development. If everything is open, and companies like Samsung can let their customers pay with NFC technology as well, I could see this as something that will be successful, adopted, and an example of Apple leading the way. However, if Apple goes all proprietary (as they love to do) and contractually forces these major credit cards to only use their devices, or charges other companies like Samsung to license their payment platform, or otherwise mandate that all touch-to-pay via smartphone methods are hereby known as “Apple Pay,” I could see adoption problems happening. Open standards have frequently been key to paving the way to adoption, and this has never really been Apple’s model in the past. For example, AirPlay is really cool and loved but does not work outside the environs of iOS, and can therefore never reach greater than 14.8% penetration as of this writing. So Chromecast was born, and while not nearly as simple or feature rich, it’s open to both Android and iOS and therefore has a much higher potential of adoption. Feature expansion will follow.

One of the aspects of Apple Pay that I think is great is that merchants aren’t really troubled with much of everything, since most of this is really on the backend. A new reader with NFC capabilities, and they’re off and running. Low cost or no cost adoption. Or is it? Nobody has mentioned what Apple’s commission is on this latest development. An article on Forbes suggested it may be around 0.2%, giving Apple $0.20 for every $100 spent. That’s not much, but when you consider what percentage that is of the credit card companies’ net (perhaps around 14%), it starts to look more substantial. Credit card companies like their investors, so it’s hard to imagine them not wanting to pass that extra cost onto merchants, who will be all-too-willing to share that with consumers.

All of that aside, it’s very smart and forward thinking, and early adopters will likely be looked upon with jealousy by others. From an implementation perspective, adding Apple Pay will likely be as easy as it was to add Google+, and merchants will do it. But the long-term prospects will rely highly on what sort of deal Apple made….the devil is always in the details.

The Technology of Apple Pay (Tim Broder)

Out of the gate, Pay is native app only. This leaves Magento sites at a disadvantage. In the future I’d like to see Apple open up this functionality to Safari on both mobile and desktop. Pay already has one-time number generation. This could be implemented in the browser similar to how 1Password can inject a credit card number into a form. Until something like this happens, only sites with a native app siting in front of Magento’s API will be able to take advantage.  If you are looking to investigate this space,, an unofficial Magento SDK, is a great starting point.

I’ll be curious if a developer comes up with a browser dedicated to this functionality. Tap into the Pay API and generate credit card numbers ad hoc, and bridge between Pay and e-commerce sites. Or, take it a step further and develop a custom keyboard for iOS 8. If allowed, it would be more seamless than a whole seperate browser. I say “if allowed” because there are some restrictions on what 3rd party keyboard can do. For example, they cannot touch passwords. The stock keyboard reasserts itself when tapping on a password field.


Generating an InlineAdmin Form on the fly in Django

I’m adding drag/drop uploading to the django admin for one of our open source projects called Stager. A blog post about that will follow, it’s not screen-shot ready yet. While doing this I knew we needed a pretty seamless transition after the upload finished, and that we would have to refresh the inline. I didn’t want a full page refresh, so let’s ajax it in.

For these examples just assume that we have a parent CompAdmin which has an model of Comp and an inline called CompSlideInline. We store the instance of the Comp in comp.

from django.template import loader, Context
from django.contrib.admin import helpers
from django.db import transaction
from django.contrib import admin

comp = Comp.objects.get(id=comp_id)
#get the current site
admin_site =
compAdmin = CompAdmin(Comp, admin_site)

#get all possible inlines for the parent Admin
inline_instances = compAdmin.get_inline_instances(request)
prefixes = {}

for FormSet, inline in zip(compAdmin.get_formsets(request, comp), inline_instances):
    #get the inline of interest and generate it's formset
    if isinstance(inline, CompSlideInline):
        prefix = FormSet.get_default_prefix()
        prefixes[prefix] = prefixes.get(prefix, 0) + 1
        if prefixes[prefix] != 1 or not prefix:
            prefix = "%s-%s" % (prefix, prefixes[prefix])
        formset = FormSet(instance=comp, prefix=prefix, queryset=inline.queryset(request))

#get possible fieldsets, readonly, and prepopulated information for the parent Admin
fieldsets = list(inline.get_fieldsets(request, comp))
readonly = list(inline.get_readonly_fields(request, comp))
prepopulated = dict(inline.get_prepopulated_fields(request, comp))

#generate the inline formset
inline_admin_formset = helpers.InlineAdminFormSet(inline, formset,
            fieldsets, prepopulated, readonly, model_admin=compAdmin)

#render the template
t = loader.get_template('admin/staging/edit_inline/_comp_slide_drag_upload_ajax.html')
c = Context({ 'inline_admin_formset': inline_admin_formset })
rendered = t.render(c)

Getting Started with Solr and Django

Solr is a very powerful search tool and it is pretty easy to get the basics, such as full text search, facets, and related assets up and running pretty quickly. We will be using haystack to do the communication between Django and Solr. All code for this can be viewed on github.


Assuming you already have Django up and running, the first thing we need to do is install Solr.

curl -O
cd apache-solr-4.0.0-BETA
cd example
java -jar start.jar

Next install pysolr and haystack. (At the time of this writing the git checkout of haystack works better with the Solr 4.0 beta then the 1.2.7 that’s in pip.)

pip install pysolr
pip install -e

Add ‘haystack’ to INSTALLED_APPS in and add the following haystack connection:

    'default': {
        'ENGINE': 'haystack.backends.solr_backend.SolrEngine',
        'URL': ''

Full Text Search

For the example, we’re going to create a simple job database that a recruiter might use. Here is the model:

from django.db import models
from import models as us_models

    ('pt', 'Part Time'),
    ('ft', 'Full Time'),
    ('ct', 'Contract')

class Company(models.Model):
    name = models.CharField(max_length=64)
    address = models.TextField(blank=True, null=True)
    contact_email = models.EmailField()

    def __unicode__(self):

class Location(models.Model):
    city = models.CharField(max_length=64)
    state = us_models.USStateField()

    def __unicode__(self):
        return "%s, %s" % (, self.state)

class Job(models.Model):
    name = models.CharField(max_length=64)
    description = models.TextField()
    salary = models.CharField(max_length=64, blank=True, null=True)
    type = models.CharField(max_length=2, choices=JOB_TYPES)
    company = models.ForeignKey(Company, related_name='jobs')
    location = models.ForeignKey(Location, related_name='location_jobs')
    contact_email = models.EmailField(blank=True, null=True)
    added_at = models.DateTimeField(auto_now=True)

    def __unicode__(self):

    def get_contact_email(self):
        if self.contact_email:
            return self.contact_email

The next step is to create the SearchIndex object that will be used to transpose to data to Solr. save this as in the same folder as your The text field with its template will be used for full text search on Solr. The other two fields will be used to faceted (drill down) navigation. For more details on this file, check out the haystack tutorial.

class JobIndex(indexes.SearchIndex, indexes.Indexable):
    text = indexes.CharField(document=True, use_template=True)
    type = indexes.CharField(model_attr='type', faceted=True)
    location = indexes.CharField(model_attr='location', faceted=True)

    def get_model(self):
        return Job

    def index_queryset(self):
        return self.get_model().objects.all()

Create the search index template in your template folder with the following naming convention: search/indexes/[app]/[model]_text.txt
For us, this is templates/search/indexes/jobs/job_text.txt

{{ }}
{{ object.description }}
{{ object.salary }}
{{ object.type }}
{{ object.added_at }}

Now, lets get our data into Solr. Run ./ build_solr_schema to generate a schema.xml file. Move this into example\solr\conf in your Solr install. Note: if using Solr 4, edit this file and replace stopwords_en.txt with lang/stopwords_en.txt in all locations. To test everything and load your data, run: rebuild_index Subsequent updates can be made with: update_index.

If that all worked we can start working on the front-end to see the data in Django. Add this to your

(r'^$', include('haystack.urls')),

At this point there are at least two templates we’ll need. One for the search results page, and a sub-template to represent each item we are pulling back. My example uses twitter bootstrap for some layout help and styling, see my base.html here if interested.

Create templates/search/search.html
This gives you a basic search form, the results, and pagination for a number of results

{% extends 'base.html' %}

{% block hero_text %}Search{% endblock %}
{% block header %}
Click around!

{% endblock %}

{% block content %}</pre>
<div class="span12">
<form class=".form-search" action="." method="get">{{ form.as_table }}
 <input type="submit" value="Search" /></form></div>
{% if query %}</pre>
<div class="span8">
<div id="accordion2" class="accordion">{% for result in page.object_list %}
 {% include 'search/_result_object.html' %}
 {% empty %}

No results found.

 {% endfor %}</div>
 {% if page.has_previous or page.has_next %}
<div>{% if page.has_previous %}<a href="?q={{ query }}&page={{ page.previous_page_number }}">{% endif %}« Previous{% if page.has_previous %}</a>{% endif %}
 {% if page.has_next %}<a href="?q={{ query }}&page={{ page.next_page_number }}">{% endif %}Next »{% if page.has_next %}</a>{% endif %}</div>
 {% endif %}</div>
{% else %}

{% endif %}
{% endblock %}

And the templates/search/_result_object.html

{% with obj=result.object %}</pre>
<div class="accordion-group">
<div class="accordion-heading"><a class="accordion-toggle" href="#collapse_{{ }}" data-toggle="collapse" data-parent="#accordion2">
 {{ }}
<div style="padding: 8px 15px;">
Company: {{ }}

Type: {{ obj.type }}

 {% if obj.salary %}
Salary: {{ obj.salary }}

{% endif %}

Location: {{ obj.location }}</div>
<div id="collapse_{{ }}" class="accordion-body collapse in">
<div class="accordion-inner">
Contact: <a href="mailto:{{ obj.get_contact_email }}">{{ obj.get_contact_email }}</a>

 {{ obj.description }}</div>
{% endwith %}

Start up your dev server for search!

Related Items

Adding Related Items is as simple as using the related_content tag in the haystack more_like_this tag library and tweaking out Solr config. Open up solrconfig.xml and add a MoreLikeThisHandler within the tag:

<requestHandler name="/mlt" class="solr.MoreLikeThisHandler" />

Our full _result_object.html now looks like this:

{% load more_like_this %}

{% with obj=result.object %}
<div class="accordion-group">
    <div class="accordion-heading">
        <a class="accordion-toggle" data-toggle="collapse" data-parent="#accordion2" href="#collapse_{{ }}">
            {{ }}
        <div style="padding: 8px 15px;">
            <p>Company: {{ }}</p>
            <p>Type: {{ obj.type }}</p>
            {% if obj.salary %}<p>Salary: {{ obj.salary }}</p>{% endif %}
            <p>Location: {{ obj.location }}</p>
    <div id="collapse_{{ }}" class="accordion-body collapse in">
        <div class="accordion-inner">
            <p>Contact: <a href="mailto:{{ obj.get_contact_email }}">{{ obj.get_contact_email }}</a></p>
            {{ obj.description }}
            {% more_like_this obj as related_content limit 5  %}
            {% if related_content %}
                        {% for related in related_content %}
                            <li><a>{{ }}</a></li>
                        {% endfor %}
            {% endif %}
{% endwith %}


To get our type and location facets, we’ll have to add them to a queryset and pass this to a FacetedSearchView instead of the default one. now looks like this:

from django.conf.urls import patterns, include, url
from haystack.forms import FacetedSearchForm
from haystack.query import SearchQuerySet
from haystack.views import FacetedSearchView

sqs = SearchQuerySet().facet('type').facet('location')

urlpatterns = patterns('haystack.views',
    url(r'^$', FacetedSearchView(form_class=FacetedSearchForm, searchqueryset=sqs), name='haystack_search'),

Then, we can use the generated facets in the search template in the facets variable

{% extends 'base.html' %}

{% block hero_text %}Search{% endblock %}
{% block header %}<p>Click around!</p>{% endblock %}

{% block content %}
<div class="span12">
    <form method="get" action="." class=".form-search">
            {{ form.as_table }}
        <input type="submit" value="Search">
        {% if query %}
            <div class="span2">
                {% if facets.fields.type %}
                        {% for type in facets.fields.type %}
                            <li><a href="{{ request.get_full_path }}&amp;selected_facets=type_exact:{{ type.0|urlencode }}">{{ type.0 }}</a> ({{ type.1 }})</li>
                        {% endfor %}
                {% endif %}
                {% if facets.fields.location %}
                        {% for location in facets.fields.location %}
                            <li><a href="{{ request.get_full_path }}&amp;selected_facets=location_exact:{{ location.0|urlencode }}">{{ location.0 }}</a> ({{ location.1 }})</li>
                        {% endfor %}
                {% endif %}
            <div class="span6">
                <div class="accordion" id="accordion2">
                    {% for result in page.object_list %}
                        {% include 'search/_result_object.html' %}
                    {% empty %}
                        <p>No results found.</p>
                    {% endfor %}

                {% if page.has_previous or page.has_next %}
                        {% if page.has_previous %}<a href="?q={{ query }}&amp;page={{ page.previous_page_number }}">{% endif %}&laquo; Previous{% if page.has_previous %}</a>{% endif %}
                        {% if page.has_next %}<a href="?q={{ query }}&amp;page={{ page.next_page_number }}">{% endif %}Next &raquo;{% if page.has_next %}</a>{% endif %}
                {% endif %}
        {% else %}
            <div class="span6">
                {# Show some example queries to run, maybe query syntax, something else? #}
        {% endif %}
{% endblock %}

And we’re done! As I said, check out the haystack documentation for more information. Leave any questions in the comments and I’ll be sure to answer them. Spelling suggestions to come in the next post.


Magento Security Update: Zend Vulnerability

While doing routine sanity checks, one of our QA Engineers, Sammy Shaar, was alerted about an important Magento security update. The vulnerability potentially allows an attacker to read any file on the web server where the Zend XMLRPC functionality is enabled. This might include password files, configuration files, and possibly even databases if they are stored on the same machine as the Magento web server.

To see if you site has been affected, please see this page.

Luckily, Magento has released patches for all supported versions:

  • Magento Enterprise Edition and Professional Edition merchants:
    You may access the Zend Security Upgrade patch from Patches & Support for your product in the Downloads section of your Magento account. Account log-in is required.

To install the patch, place the patch file in the root of your Magento site and run the following command:

patch -p0 < zendxml_fix.patch

If you don’t have ssh access or patch installed on your machine, please see this stack overflow post for alternative methods.

Please Note: All current Ai and Canopy sites have been patched