Never Use This Font Aaron Parecki is the co-founder of Geoloqi.com, and specializes in backend systems development. 2011-07-11T22:50:38Z http://neverusethisfont.com/blog/feed/atom/ WordPress aaron http://www.aaronparecki.com <![CDATA[How to Let Google Power OpenSearch on Your Website]]> http://neverusethisfont.com/blog/?p=526 2011-07-11T22:50:38Z 2011-07-11T22:50:38Z

OpenSearch is a collection of simple formats for the sharing of search results. One of the formats allows your browser to add your site to its list of search engines, which Firefox displays in the top right corner, and Chrome uses in the address bar. Adding a small link and XML document allows your site to be added to a browser.

Many CMSs such as MediaWiki already support this natively so you might already have it on your site. To check in Chrome, in your search bar, enter your domain name followed by a space and see if it looks like the below screenshot.

If not, you’ll have to add a small link and XML file.

The HTML code to reference the XML file is this:

<link href="/opensearch.xml" rel="search" title="aaronpk" type="application/opensearchdescription+xml">

The XML file should look something like the following:

<?xml version="1.0" encoding="UTF-8"?>
<OpenSearchDescription xmlns:moz="http://www.mozilla.org/2006/browser/search/" 
      xmlns="http://a9.com/-/spec/opensearch/1.1/">
  <ShortName>aaron.pk</ShortName>
  <Description>Search aaron.pk</Description>
  <InputEncoding>UTF-8</InputEncoding>
  <Url method="get" type="text/html" 
      template="http://aaron.pk/search?q={searchTerms}"/>
</OpenSearchDescription>

But what if you want to add this to one of your sites that doesn’t have search capability? Turns out there is no restriction on the domains that you can use for the search URL. This means we can delegate the search to google!

Using Google’s “site:example.com” feature, we can restrict the Google search to our domain.

<?xml version="1.0" encoding="UTF-8"?>
<OpenSearchDescription xmlns:moz="http://www.mozilla.org/2006/browser/search/" 
      xmlns="http://a9.com/-/spec/opensearch/1.1/">
  <ShortName>aaron.pk</ShortName>
  <Description>Search aaron.pk</Description>
  <InputEncoding>UTF-8</InputEncoding>
  <Url method="get" type="text/html" 
      template="http://www.google.com/search?q={searchTerms}+site%3Aaaron.pk&amp;hl=en"/>
</OpenSearchDescription>

Then, if someone uses your site’s search, they get taken to a Google search results page with results from your site!

]]>
1
aaron http://www.aaronparecki.com <![CDATA[Enabling SSH on the Seagate BlackArmor NAS 220]]> http://neverusethisfont.com/blog/?p=514 2011-07-11T01:54:47Z 2011-07-11T01:54:47Z I recently acquired a 6 TB Seagate NAS drive which I am using for nightly backups of my servers, as well as snapshots of several Dropbox accounts.

While the web interface on the device isn’t too bad, I wanted a little more control over it, as well as the ability to monitor the device’s health with some custom munin graphs.

Here’s how to enable SSH without wiping the drive and installing custom firmware.

  1. Set up a new user account on the device from the web interface, and create a password.
  2. Shut down the device, remove both drives, and connect them to a local computer with SATA cables.
  3. Boot your linux computer with the drives attached, it’s probably safest to boot from some sort of Live CD. I used Fedora.
  4. When you get to a shell, execute the following commands to mount the drives.
    $ mdadm -A /dev/md0 /dev/sda1 /dev/sdb1
    mdadm: /dev/md0 has been started with 2 drives.
    $ mkdir /mnt/md0
    $ mount /dev/md0 /mnt/md0
  5. Add the following line to the file /mnt/md0/etc/inetd.conf:
    ssh stream tcp nowait root /usr/sbin/dropbear dropbear -i
    You can do this in one shell command by executing this:

    echo "ssh stream tcp nowait root /usr/sbin/dropbear dropbear -i" >> /mnt/md0/etc/inetd.conf
  6. Edit /mnt/md0/etc/shadow with a text editor, and replace the hashed password for “root” with the hashed password of the user you created. The hashed password is the characters between the second two colons, and begins with $1$$.
  7. Unmount the drives and shut down the array:
    $ cd
    $ umount /mnt/md0
    $ mdadm -S /dev/md0
    mdadm: stopped /dev/md0
  8. Put the drives back in the NAS device and turn it back on!
  9. After it boots, you’ll be able to ssh in as root with the password you set from the web interface.

]]>
0
aaron http://www.aaronparecki.com <![CDATA[Writing contracts is like programming]]> http://neverusethisfont.com/blog/?p=511 2011-07-01T04:39:50Z 2011-07-01T04:39:50Z Writing contracts feels a little bit like programming. There is an expected syntax and structure, there are certain key words that have special meaning (i.e. functions, keywords), and removing certain clauses make the entire contract invalid (i.e. runtime error). However, contracts are executed over a much longer timeline.

]]>
0
aaron http://www.aaronparecki.com <![CDATA[Analyzing the iPhone Location Log File]]> http://neverusethisfont.com/blog/?p=499 2011-04-21T06:39:25Z 2011-04-21T06:39:25Z Today at Where 2.0, two data scientists announced a discovery that iPhones are recording GPS positions into a hidden file on the device. I’ll save a summary for an update of this post, but go read the original article for now.

I downloaded the logs from Amber Case‘s iPhone, and have been looking through them to see what’s there. Turns out it’s a lot more than just the cell tower positions of the phone. There’s also a list of all wifi access points the device has seen, as well as the best-guess position of each wifi access point!

There also seems to be a table in the database containing a record of all the requests that other programs have made for your location, which includes the app’s bundle ID. Here’s a snippet of the logs:

MCCMNCLACCIRSSIARFCNPSCRSCPECN0OperatorTransmitBundleIdTimestampLatitudeLongitudeHorizontalAccuracyAltitudeVerticalAccuracySpeedCourseConfidence
310410569832067187-19721414967AT&T-1325045574.11904937.39194315-121.97732501666747.421633549763453.273893356323270.28100137579970.0-1.090
310410569832067187-1972141410912AT&T-1com.geoloqi325044683.1898437.3916252333333-121.976906347.421633549763435.274089813232470.28100137579970.0-1.090
310410569832039667-19721276764AT&T-1com.localmind.ios325043720.46491637.4044454-121.9751501162.95795319434228.2493667602539228.3436732562420.0-1.090
310410569832039667-19721276725AT&T-1com.naveenium.foursquare325024994.16863337.4042630166667-121.975922583333162.95795319434228.2504062652588228.3436732562420.0-1.090
310410569832070748-15121809613AT&T-1com.apple.camera324957354.6112937.3848867333333-121.995491966667162.95795319434228.3031120300293228.3436732562420.0-1.090
310410569832068368-197211809914AT&T-1com.alamofire.gowalla324956280.78680537.3848867333333-121.995491966667162.95795319434228.3031120300293228.3436732562420.0-1.090
310410569832052127-197214648912AT&T-1com.google.GoogleLatitude324940590.28854537.4049282-121.976459016667162.95795319434228.2496871948242228.3436732562420.0-1.090
310410569772497652-14385299719AT&T-1com.apple.Maps324879306.75140537.5537628166667-122.30979746666776.356885915378346.2922878265381113.175756567520.0158.090
310410569762757485-19721252899AT&T-1com.yelp.yelpiphone324873997.28152537.7768964333333-122.3948506162.95795319434250.9832305908203228.3436732562420.0-1.090

The Bundle IDs of the apps that requested location are clearly visible, and it also shows where the phone was when the app requested the location. This suggests to me that the purpose for these logs is not malicious on Apple’s part at all.

I also observed that the timestamps of the logs in the CellLocation table were not very granular. There seemed to be batches of 30-50 significantly different locations at a time, with anywhere from 1 to 12 hours between timestamps. My guess after asking Amber about her syncing habits, is that the timestamps correspond to the date the phone was synced with the computer, not necessarily the date the timestamp was recorded. This is speculation at this point, and I will hopefully be able to come to a better conclusion after some more analysis of the data.

If it in in fact the timestamp of the sync, this would seem to further contradict the notion that Apple is covertly tracking your every move, since location data is far more useful when it contains a timestamp associated with it. This data says something more like “Here are all the cell towers the phone has seen since it was last synced.” I’m not sure exactly what purpose this would serve.

Some of the other database tables that piqued my interest included:

WifiLocation – a database of all wifi hotspots seen, their mac addresses and latitude/longitudes

Fences – my guess is this corresponds to Apple’s CLRegion API, which allows iOS developers to define fences which trigger a method when the user crosses the boundary.

*Harvest – All tables ending in Harvest correlate with the different location tracking types, Cell, CDMA, Wifi, etc. These tables track requests made to the various location providers.

So far it’s been a lot of fun to look through this data, and I’m looking forward to continuing to play with the data. Many thanks to Pete Warden and Alasdair Allan for pointing out this log!


Aaron Parecki is the co-founder of Geoloqi.com, a private, real-time location sharing platform. Geoloqi allows you to securely track your location and you always have complete control over who can see your location. You can leave yourself a Geonote at a place which will be sent to you next time you’re there. Geoloqi has an API which lets you download all of your location history, as well as build fun apps on top of the platform!

]]>
5
aaron http://www.aaronparecki.com <![CDATA[Soft Signup: Lower the barrier to entry]]> http://neverusethisfont.com/blog/?p=475 2011-04-12T17:42:37Z 2011-04-12T17:42:37Z Nobody wants to be presented with a signup form when trying out a new web service. Even though in recent years many websites have trimmed down their signup forms to make them easier to complete, I think we can do better.

A typical signup form these days consists of asking for your email address and creating a password. Some will also request you create a username, or ask for your real name.

People will probably fill out your signup form on your website if it doesn’t look too daunting, but mobile apps are a whole different story. With mobile apps, people expect to be able to use your app immediately after downloading it. Adding a signup form will do nothing but make people frustrated. It is important to think about whether you actually need their email address or phone number in order for them to at least start using your app.

Incrementally collect information from your users as it becomes necessary to provide a feature.

Example: Geoloqi

Download the app and press “use anonymously”, you’re taken to your map

You can leave yourself a Geonote, and we can deliver the message since we have your push token for the device

When you press “Share Location,” you have multiple options:

Send via SMS or Email

The app opens the phone’s system SMS composer, and your phone sends the SMS. We never need to know your phone number to do so.

Send via Twitter or Facebook

In order to post to your Twitter account, we need to connect your Geoloqi account to Twitter. At this point, we prompt you to log in to your Twitter account which then tells Geoloqi who you are. Similarly to Twitter, posting to Facebook requires you to grant Geoloqi permission to your Facebook account.

At this point, we have now named your previously anonymous user account in Geoloqi, tied to your Twitter or Facebook account. This is a relatively seamless way of “registering,” since you knew exactly why you had to authenticate at that point.

Soft Create: GraphThis.me

Similar to the idea of “soft signup” is the idea of “soft create.” Send an email to “weight@graphthis.me” where the subject line is your weight, and a graph will immediately be created for you. Replace “weight” with other values to create new graphs.

We don’t require signing up beforehand in order to use the service, since you’ll be inputting data from your email address anyway. If you want to expand your input options, such as being able to send a tweet or a DM, then you can connect your Twitter account.

We don’t require that the tag “weight” be set up before starting to graph the values. We could have required you to set up the graph name before hand, but that would have increased the barrier to create new graphs.

Conclusion

Make it as easy as possible for people to start using your service. Think about whether you actually need more than a unique identifier for a user in order to get them started playing around. Collect new information from your users only as it becomes necessary to provide a new service to them.

]]>
0
aaron http://www.aaronparecki.com <![CDATA[Shortlink Design for Syndicating to Twitter]]> http://neverusethisfont.com/blog/?p=448 2011-03-28T20:11:06Z 2011-03-28T20:11:06Z Tantek Çelik has been using his Falcon project to create short-form and long-form content on his site, and syndicate it out to Twitter. Falcon is a personal publishing (tweeting, blogging, realtime syndicating) web application created in the true spirit of the Indie Web.

When syndicating content to other sites, a good practice is to include a link back to the original content. This has the effect of letting people know that this copy is not the original, and lets them find the original if they want to cite or link to it.

Unfortunately, Twitter has no mechanism for including this “citation” link anywhere except in the text of the tweet itself. This means if you’re syndicating content to Twitter and want to include a link back, the link will become part of the tweet. This ends up looking something like this:

Now I don’t know about you, but when I see a link in an interesting tweet, I am inclined to click it. The problem with these links is that they often link back to tantek.com which has an exact copy of the tweet text and no additional content. I often find myself disappointed after clicking, because I was expecting to see more. Sometimes, @t’s tweets are in fact cut short and do link to more content, such as in this example.

After hearing this feedback from a couple people, Tantek realized he needed a solution to indicate whether there is additional content available when following the link. He proposed this format:

So far this has been working great. Now, tweets with no additional content look like this:

while tweets with additional content include the “http://” prefix.

I think another great convention would be to use a colon to indicate additional content. It’s a natural indicator of “more” and generally draws interest to the thing following the colon.

Would you be more likely to click this link http://aaron.pk/2DS or this link: http://aaron.pk/2DS.

Tantek has already used this convention, possibly without realizing it, as observed in this tweet:

So what do you think? Should this be the convention for syndicating content?

No content other than this text (ttk.me/t4B12)

There is some more content available here: http://ttk.me/t4B13


If you are interested in this topic, you might also be interested in attending IndieWebCamp in Portland, Oregon in June, 2011.

]]>
2
aaron http://www.aaronparecki.com <![CDATA[URL Shortener as a Search Interface]]> http://neverusethisfont.com/blog/?p=431 2011-03-28T19:23:17Z 2011-03-25T18:41:44Z cyborganthropology.com is quickly becoming the default online resource for everything relating to Cyborg Anthropology. With over 800 articles and growing daily, it’s possible to find nearly anything you can think of.

We recently registered the domain “anth.ro” to use as a URL shortener to articles on cyborganthropology.com. I suggested creating a business card such as this, which would allow Amber to write in arbitrary text following the URL after having a conversation with someone and giving them the card.

Since she would obviously be offline while handing out cards, there would be no way to know for sure if a certain URL existed. The goal is to be able to write down any topic on the card and have the recipient be taken to the corresponding content when they get back to their computer.

Site search

If you didn’t already know, you can add “site:cyborganthropology.com” to the end of any search in Google to restrict your search to a specific website. Try it here: google.com/search?q=Second+self+site:cyborganthropology.com. This is a great start, because this lets us search the wiki for anything using Google’s excellent search algorithms and spelling correction.

I’m Feeling Lucky

Since we’ve restricted the search to this site, we can be reasonably confident that the first match is the one we intended. If we were to press Google’s “I’m feeling lucky” button, we’d probably get a good result. A quick Google search revealed that I can craft a URL which will automatically redirect to the first result, just like what happens when you press the button!

Adding “btnI=I’m+Feeling+Lucky” to the query string will automatically redirect the visitor.

Now our full search URL looks like this. Clicking this link will redirect you to the first page on the wiki matching “Second self”.

http://www.google.com/search?q=Second+self+site:cyborganthropology.com&btnI=I’m+Feeling+Lucky

Short Domain

Now let’s put that together with the short domain, anth.ro. We can easily set up a small script to redirect “http://anth.ro/second+self” to the full google search query. However, we’d ideally like to get some better Google analytics on how many times this URL shortener was used, so we’ll need to add some tracking parameters to the URL. Since we lose control of the visitor if we send them straight to Google, instead, we can query Google ourselves first to get the destination URL.

Here is a short PHP script which will do the following:

  • Query Google with the “I’m feeling lucky” option to find the best match on our site
  • Add our additional tracking parameters
  • Redirect the browser to the page on the wiki with the tracking code
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, 'http://www.google.com/search?btnI=I\'m+Feeling+Lucky&q=' . urlencode($_GET['code']) . '+site%3Acyborganthropology.com');
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, FALSE);    // Don't follow redirects, we want the first Location header
curl_setopt($ch, CURLOPT_HEADER, TRUE);             // Return the headers in the output	curl_setopt($ch, CURLOPT_USERAGENT, "Mozilla");     // Set the user agent to Mozilla so Google doesn't block the query
curl_setopt($ch, CURLOPT_NOBODY, TRUE);             // Don't include the response body in the output
curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);     // Return the response in a variable instead of printing it out
$response = curl_exec($ch);
 
// If there was a Location header found, use it, otherwise, Google couldn't find a match
if(preg_match('/Location: (.+)/', $response, $match)) {
  $url = parse_url(trim($match[1]));
 
  if($url && is_array($url)) {
    $query = array();
    // If the search result included query string parameters, parse those out
    if(array_key_exists('query', $url)) {
      parse_str($url['query'], $query);
    }
    // Add the search term as the "q" parameter. This is so Google Analytics will treat this as a "site search" query
    // and include it in the search analytics. You'll also need to add "q" to the "include site search" section in Google Analytics
    $query['q'] = $_GET['code'];
    // Add "anth.ro" as the utm_source
    $query['utm_source'] = 'anth.ro';
    // Add "ShortURL" as the medium. These end up appearing in the "Traffic Sources" list as "anth.ro / ShortURL"
    $query['utm_medium'] = 'ShortURL';
    $q = http_build_query($query);
 
    // Redirect the user to the page specified by google with our additional parameters included
    $location = 'http://cyborganthropology.com' . $url['path'] . '?' . $q;
    header('HTTP/1.1 302 Moved Temporarily');
    header('Location: ' . $location);
    die();
  }
}
 
// If there were no results returned from Google's I'm feeling lucky button, redirect to a Google search page
// This most likely happens on a typo
header('HTTP/1.1 302 Moved Temporarily');
header('Location: http://www.google.com/search?q=' . urlencode($_GET['code']) . '+site%3Acyborganthropology.com');

Search

With this in place, you can now use the anth.ro domain as a search interface to the wiki! You can type in anything after anth.ro and you’ll either be taken to a page on the wiki or to a page of search results! We didn’t have to write any search code, we just let Google take care of that since that’s what they do best!

]]>
5
aaron http://www.aaronparecki.com <![CDATA[Tools for Co-Working Spaces]]> http://neverusethisfont.com/blog/?p=406 2011-03-19T00:06:38Z 2011-03-19T00:06:38Z
Souk Co-Working Space

Souk Co-Working Space

I recently spent some time at Souk, a co-working space in Portland. It’s a great space with lots of room and lots of light, which is important when you’re going to spend hours on end somewhere. Over the course of a couple days, it became apparent that there are several tools that can help facilitate the coming and going of people in spaces like these.

CloudKnock is an application built using Tropo to facilitate letting people in to co-working spaces. When you need to get in, you can text “knock knock” to the application’s phone number. The application will then forward your message on to anyone who has checked in to the space. Since it uses Tropo it works not only by SMS but also by AIM, MSN, Yahoo IM, or Jabber! This means your “knock knock” SMS can be seamlessly forwarded on to people sitting at their desks using Gmail chat or AIM. While this app won’t actually open the door for you, that also means there is no physical hardware to install making it feasible to start using it today! Download the source code on Github, and sign up with Tropo to get started.

Have you ever wondered where someone in your group ran off to at lunch? Wouldn’t it be great if you could find out where they are without having to call them or text them and wait for their reply? Using Tropo, you can just send a quick IM to a bot which can find out where they are if they’re using Geoloqi.

Every person who you want to track should download the Geoloqi app for iPhone or Android.

From your map page, create a new shared link which never expires.

Copy the token at the end of the URL that is created, and paste it into the users array in the script.

Copy the sample code into a new Tropo scripting application, and add the Geoloqi shared link tokens for everyone in your group you want to track. You can give people nicknames so they can be identified by multiple names.

Then, you can send a message (via SMS or IM) like “Where is Aaron?” and you’ll get a quick reply with your friend’s location if they’re tracking themselves using Geoloqi!

]]>
8
aaron http://www.aaronparecki.com <![CDATA[How to Distribute your iOS Apps Over the Air]]> http://neverusethisfont.com/blog/?p=351 2011-01-21T18:33:20Z 2011-01-21T18:33:20Z We’ve been using Apple’s Wireless distribution method for sending out beta invites of Geoloqi. It’s a much easier process for our beta testers than syncing with iTunes to install the app! They just click on a link from their phones, and they can download the app immediately!

How, you ask? Apple has made this possible since iOS 4.0, but not many developers have noticed it’s available. TestFlight has make a great wrapper on top of this functionality, but it’s possible to do it without using TestFlight too!

How to set up Ad Hoc distribution

First, build and archive your application from XCode. Make sure you’ve selected the Developer provisioning profile when building your app. This must pass code-signing verification or people will get an error when trying to install.

Open Organizer if it’s not already open. Select your archived application, then click “Share.” The next step is slightly misleading. Choose “Distribute for Enterprise” here, even if you don’t have an enterprise account! Make sure you select the same provisioning profile you signed the app with!

This is the critical step. At this point, XCode is bundling the provisioning profile into the IPA archive so that your users only have to download one file! No need to have them install the provisioning profile separately, since it will be included in the app archive!

Next you’ll need to fill out the form that appears. XCode uses this info to create a .plist file. If you’re comfortable editing the .plist file directly, you can do that instead. Here’s a sample .plist file that XCode creates from this dialog.

At this point, XCode prompts you to save the files to a folder. You’ll end up with two files, a .plist and an .ipa file. Now comes the easy part!

You just need to create a web page with a link to the .plist file using the special itms-services:// protocol. This might look something like the code below.

1
2
3
<a href="itms-services://?action=download-manifest&url=http://loqi.me/app/Geoloqi.plist">
Download Geoloqi
</a>

When someone clicks the link from their iPhone, they’ll get a prompt that says “loqi.me would like to install Geoloqi.” Clicking “Install” will then immediately download and install the provisioning profile and the app!

Note: This is not going to get you around the 100-device limit that Apple imposes. You’ll still need to get your beta testers’ UDIDs from them and upload them to the Provisioning Portal.

You can pretty up the download page like we have done to make it look like more than just a plaintext link. Here’s some HTML and CSS to get you started making your own mobile installation page.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
<!DOCTYPE html>
<html>
<head>
        <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
        <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" /> 
        <title>Install Geoloqi</title>
        <style type="text/css">
                body {
                        background: url(bkg.png) repeat #c5ccd4;
                        font-family: Helvetica, arial, sans-serif;
                }
                .congrats {
                        font-size: 16pt;
                        padding: 6px;
                        text-align: center;
                }
                .step {
                        background: white;
                        border: 1px #ccc solid;
                        border-radius: 14px;
                        padding: 4px 10px;
                        margin: 10px 0;
                }
                .instructions {
                        font-size: 10pt;
                }
                .arrow {
                        font-size: 15pt;
                }
                table {
                        width: 100%;
                }
        </style>
</head>
<body>
 
<div class="congrats">Congrats! You've been invited to the beta of Geoloqi.</div>
 
<div class="step">
        <table><tr>
                <td class="instructions">Install the<br />Geoloqi app</td>
                <td width="24" class="arrow">&rarr;</td>
                <td width="57" class="imagelink">
                        <a href="itms-services://?action=download-manifest&url=http://loqi.me/app/Geoloqi.plist">
                                <img src="geoloqi-icon.png" height="57" width="57" />
                         </a>
                </td>
        </tr></table>
</div>
 
</body>
</html>

Here is the background graphic I used on the installation web page. Feel free to use it on your own pages.

]]>
4
aaron http://www.aaronparecki.com <![CDATA[I had a dream last night where I was an XCode project]]> http://neverusethisfont.com/blog/?p=343 2011-01-19T20:21:32Z 2011-01-19T20:21:32Z I had a dream last night where I was an XCode project. Every time the alarm went off, that was running “Build and Run.” If I would fail to compile, I’d have to fix the errors and try again. The next time the alarm went off, I’d attempt to “run” again, and I kept failing to compile a few times when I kept hitting “snooze.”

The last thing I did before I actually woke up was fix a missing semicolon which finally allowed me to compile and then I was awake.

]]>
2