• Share
  • Email
  • Embed
  • Like
  • Save
  • Private Content
Exploring the Sweet Spot: Geolocation, Health, and Gov-data
 

Exploring the Sweet Spot: Geolocation, Health, and Gov-data

on

  • 1,946 views

Location based services are increasingly important, especially when it comes to accessing health information and services. Over the past year and a half, AIDS.gov, a program of the U.S. Department of ...

Location based services are increasingly important, especially when it comes to accessing health information and services. Over the past year and a half, AIDS.gov, a program of the U.S. Department of Health and Human Services, Office of HIV/AIDS Policy, has been collaborating with other Federal agencies (CDC, HUD, SAMHSA, among others) to develop an HIV/AIDS prevention and service locator. This new tool combines key Federal HIV/AIDS programs such as HIV testing, mental health services, health centers, substance abuse clinics, and housing services. Each of these programs is run by a separate agency and pulls information from a wide range of sources. Beyond addressing what it took to get each agency to collaborate and push their data in a consumable format, this presentation will focus on the steps AIDS.gov took to create this locator service. We take a technical approach to discuss the GeoRSS standard, how we built the service using mostly JavaScript, and how we pushed this service to mobile, standard web, and native application platforms. We will also talk about the iterative design and development process, and we tie it all together with the big ticket: the sweet spot of location, mobile, and health. We cover it all, location, Health IT, and Gov 2.0.

Statistics

Views

Total Views
1,946
Views on SlideShare
1,946
Embed Views
0

Actions

Likes
1
Downloads
6
Comments
0

0 Embeds 0

No embeds

Accessibility

Upload Details

Uploaded via as Microsoft PowerPoint

Usage Rights

CC Attribution-NonCommercial-ShareAlike LicenseCC Attribution-NonCommercial-ShareAlike LicenseCC Attribution-NonCommercial-ShareAlike License

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Processing…
Post Comment
Edit your comment
  • IntroConfessions (SXSW, no mobile, didn’t follow any advice from SpeakerUp)
  • So, a wee bit about me. I used to live here,
  • And work over here.
  • Now I live here,
  • And still work over there. Well, virtually, anyway.
  • One of the projects I work on is the AIDS.gov web site
  • As part of that project, we created a location based search tool to help people living with HIV/AIDS or their caretakers to find service providers near them.Been a tripMight have something useful to share
  • Whether you’re pulling data from many different sources, or…
  • Building widgets people can use on any website.Specific anecdotes throughoutLet’s get started
  • So, first, let’s look at the problem we wanted to solve.
  • Gov agencies offer tools to find service providers
  • These are extremely useful
  • but are difficult to find (the Goog is not with them)
  • Some are many layers deep in the agency’s hierarchy
  • -all only one type of service provider-wanted to help people find all different types of service providers using one search.-wanted to leave the data where it was-people who were already collecting and maintaining it could continue taking care of that, and we wouldn’t have to.
  • Instead of bringing all the data together into one central database, we wanted to aggregate it dynamically.asked each agency to provide a REST APIreturn a GeoRSS feedAccept two parameters, ZIP Code and distance. We settled on those after looking at the existing search engines, but In hindsight, latitude and longitude would be nice, and we’ve started working with some of the data providers to accomplish that as well.
  • Here is an example URL for the CDC HIV Testing data feed API. It takes a ZIP Code and a distance in miles, and returns…
  • An RSS (Atom, actually) feed with all of the locations within that distance of that ZIP Code.
  • The crucial bit that makes this GeoRSS is each element brings along a latitude and longitude with it.
  • So they can be plopped on the map like so. The Google Maps API actually offers a GeoRSS parser, but I found it rather finicky so ended up rolling my own.[anecdote]-issues while implementing-wrote our initial how-to on GeoRSS-made point data, the latitude and longitude, optional. -Bad idea.We were afraid making it mandatory would be a barrier to entry for some agenciesWe thought it would be simple enough to geocode the addresses on our end.Most of agencies already had geocoded data, or were pretty quick to do so, even though we’d made it optional.one data provider called our bluffDelays between us trying to dynamically geocode and giving up and them adding lat and long on their end.
  • Not only did we want to give people one place to search, we wanted to make that tool available anywhere.
  • This is a pure JavaScript widget, which can be placed in a page with a single line of HTML.
  • There’s the one liner, we include a tag for times when JavaScript might be turned off for some reason. It makes for more for people to copy and paste, but I think it’s the right thing to do in the long run.
  • This widget is styleable and somewhat modular. We’ve created a few different versions, one for the CDC,
  • A vertical version,
  • We’re also working on a version that can be attached to an already existing form field.
  • search without leaving the page their on. This overlay is actually an iframe, which is loading http://locator.aids.gov/. Amazingly, we were able to get it to look decent in most browsers. In IE6, it simply opens a new window.[anecdote]After implementing the overlay, we realized that if any Flash elements were on the page, they appeared above the overlay. After some serious debugging, we came up with a way to keep this from happening.
  • -Flash toobey z-index rules-‘wmode’ param set to ‘transparent’.-attribute must be present before the element is loaded in the DOM.-So… what we’re doing here is manually removing every element, setting it’s wmode parameter, and then sticking it back where it was-not the cleanest code, and I’m sure there are probably a lot of edge cases where this would blow up.-I’ve run across at least one, where if a movie is set to autoplay (please never do that), it will restart when this code runs.
  • One of the fun things about the widget is that you can grab the embed snippet directly from it to place on your own site.
  • Analytics are a great way to make sure what you’re working on is actually reaching the people it should. Analytics are a bit more complicated with a widget, since you’re tracking loads of something on someone else’s page.
  • We tried using Clearspring for awhile until they canned the bit of their API we were using earlier this year. You might be able to find another use for them, though.
  • We now are using Omniture through an arrangement with CDC in order to get metrics on the widget. This is more or less out of convenience, it wouldn’t be my preference, also it takes major bank. Also, we’re using Google Analytics on locator.aids.gov itself.
  • National HIV Testing Daywe created a special look for the locator widgetsAsked partners to place the widget on their web sites.loaded ~1.6 million timesMeaninglessDoesn’t even mean eyeballs (below the fold)
  • of those 1.6 million loads2000 real searches.Measured by interactions on the widget and GA on locator.aids.gov
  • Embedded on 70 different websitesmany of those including the widget on several, or all, pages.
  • General case
  • Unique name, and a local alias
  • Replace the
  • Add the init function to the window.onload event
  • This is a technique we hope to implement in the future, pioneered by the guys who work on the Meebo Bar. Check the video of their Velocity conf presentation.
  • The Meebo guys do a much better job of explaining this, but effectively they’ve come up with a way to achieve truly non-blocking JavaScript by tacking their code onto an iframe.
  • Some of the issues we’ve had with the widget: it does block, CSS isn’t totally sandboxed, and it’s not able to be inserted on a MySpace or Facebook page because JS isn’t allowed there.
  • Currently, if our servers are unavailable for whatever reason, a page will stop rendering at the point the widget is loaded. Fortunately, this hasn’t been a big issue yet because our servers have been doing fine, but obviously that’s not something we should bank on. We need to protect any site which lets our widget loose on their pages.deferasync
  • Kent Brewster actually provides a technique that we use to add style to our widget. However, it’s problematic to ensure that any given styles from the parent page aren’t overriding our CSS. So, it’d be nice if our widget’s DOM was totally sandboxed from the parent page’s CSS. Cleanslate is part of Sqwidget, a JS widget toolkit that I’m hoping to use in future versions of the locator widget.
  • Many social networking sites and free blog sites disallow pasting JavaScript onto your pages, as a preventative measure against misbehaving scripts. We need to come up with a way to allow people using those services to use our widget.
  • -page load time contributes to Google algorithm-better user experience-some tools to help you on your way
  • LABjs, a JavaScript library by Kyle SimpsonHelps pages load more quickly by loading the scripts in parallel, but still giving you control over execution order
  • Yahoo! has an excellent resource on how to speed up page load time.far-future expires on static contentDownside: changes don’t get loaded if url doesn’t change
  • Auto version static files based on modification dateApache directivesPHP – read this article to get the full story
  • Atomic release easy rollback, scripts

Exploring the Sweet Spot: Geolocation, Health, and Gov-data Exploring the Sweet Spot: Geolocation, Health, and Gov-data Presentation Transcript

  • Exploring the Sweet Spot
    Geolocation, Health, and Gov-data
    Lance Roggendorff | @lroggendorff | lroggendorff@gmail.com
  • aggregators
    “Pipe Dream” by RishiMenon - http://www.flickr.com/photos/rxmflickr/4102530508/
  • Widget builders
    Frank Scherschel - http://images.google.com/hosted/life/l?imgurl=a00c346a37821dc5
  • The Problem
  • aggregators
    Data aggregation
    “Pipe Dream” by RishiMenon - http://www.flickr.com/photos/rxmflickr/4102530508/
  • http://cdcnpin.org/hivTestLocatorFeed/feed.aspx?zip=37206&radius=5
  • <?xml version="1.0" encoding="utf-8"?>
    <feed xmlns="http://www.w3.org/2005/Atom" xmlns:georss="http://www.georss.org/georss">
    <title>Search Results from CDC - Locate HIV/AIDS Testing Sites</title>
    <link href="http://cdcnpin.org/hivTestLocatorFeed.aspx?zip=37206&amp;radius=5" rel="self" />
    <link href="http://hivtest.org" rel="alternate" />
    <author>
    <name>CDC NPIN</name>
    </author>
    <id>tag:cdcnpin.org,2009-09-15:/npinwebservices/NPINDataWebservices</id>
    <updated>2009-09-15T00:00:00-05:00</updated>
    <entry>
    <title>Cayce Family Health Center</title>
    <link href="http://www.hivtest.org/search/OrgResult.cfm?OrgNbr=21952" />
    <id>tag:hivtest.org,2000-03-20:/search/OrgResult.cfm?OrgNbr=21952</id>
    <summary type="xhtml">
    <div xmlns="http://www.w3.org/1999/xhtml">
    <div class="vcard">
    <div class="fn org">Cayce Family Health Center</div>
    <div class="adr">
    <div class="street-address">617 S 8th St</div>
    <span class="locality">Nashville</span>, <span class="region">TN</span>, <span class="postal-code">37206</span></div>
    <div class="tel">615-226-1695</div>
    </div>
    </div>
    </summary>
    <georss:point>36.168533 -86.755339</georss:point>
    <updated>2010-10-14T18:17:31.0000000-04:00</updated>
    </entry>
    </feed>
  • <?xml version="1.0" encoding="utf-8"?>
    <feed xmlns="http://www.w3.org/2005/Atom" xmlns:georss="http://www.georss.org/georss">
    <title>Search Results from CDC - Locate HIV/AIDS Testing Sites</title>
    <link href="http://cdcnpin.org/hivTestLocatorFeed.aspx?zip=37206&amp;radius=5" rel="self" />
    <link href="http://hivtest.org" rel="alternate" />
    <author>
    <name>CDC NPIN</name>
    </author>
    <id>tag:cdcnpin.org,2009-09-15:/npinwebservices/NPINDataWebservices</id>
    <updated>2009-09-15T00:00:00-05:00</updated>
    <entry>
    <title>Cayce Family Health Center</title>
    <link href="http://www.hivtest.org/search/OrgResult.cfm?OrgNbr=21952" />
    <id>tag:hivtest.org,2000-03-20:/search/OrgResult.cfm?OrgNbr=21952</id>
    <summary type="xhtml">
    <div xmlns="http://www.w3.org/1999/xhtml">
    <div class="vcard">
    <div class="fn org">Cayce Family Health Center</div>
    <div class="adr">
    <div class="street-address">617 S 8th St</div>
    <span class="locality">Nashville</span>, <span class="region">TN</span>, <span class="postal-code">37206</span></div>
    <div class="tel">615-226-1695</div>
    </div>
    </div>
    </summary>
    <georss:point>36.168533 -86.755339</georss:point>
    <updated>2010-10-14T18:17:31.0000000-04:00</updated>
    </entry>
    </feed>
  • Widget builders
    Search decentralization
    Frank Scherschel - http://images.google.com/hosted/life/l?imgurl=a00c346a37821dc5
  • <noscript><div style="height:115px;position:relative;width:314px;background:url(http://locator.aids.gov/images/bg_widget-8bit.png) no-repeat;padding-left:19px;"><strong style="padding-top:6px;color:#fff;display:block;font-family:Trebuchet MS;font-size:14px;line-height:16px;">Find HIV/AIDS Prevention & Service Providers</strong><p style="font-size:9px;margin: 3px 0 4px;color:#fff;">Enter your address, city and state, or ZIP Code:</p><form action="http://locator.aids.gov/index.php" style="margin:0;"><label style="margin-left:22px;"><input type="text" name="location" style="border:0;font-size:11px;width:230px;"/></label><button type="submit" style="background:none;border:none;cursor:pointer;height:40px;margin-top:5px;padding:0;text-indent:-999em;overflow:hidden;vertical-align:middle;width:40px;">GO</button><input type="hidden" name="text_only" value="true" /></form><p style="font-size:9px;margin: 10px 0 0;color:#fff;">For more information on this widget, please visit <a href="http://aids.gov/locator" style="color:#fff;">AIDS.gov</a>.</p></div></noscript><script type="text/javascript" src="http://locator.aids.gov/widget.js"></script>
  • var objects = $.d.getElementsByTagName('object');
    if ( objects.length > 0 ) {
    for (vari = 0, ol = objects.length; i < ol; i++) {
    varobj = objects[i].cloneNode(true);
    varobj_parent = objects[i].parentNode;
    var placeholder = $.f.createNode('div', {id:trueName+'obj'+i+'savedspot'});
    obj_parent.insertBefore(placeholder, objects[i].nextSibling);
    obj_parent.removeChild(objects[i]);
    varparam = $.f.createNode('param', {name:'wmode',value:'transparent'});
    obj.appendChild(param);
    obj_parent.insertBefore(obj, placeholder.nextSibling);
    obj_parent.removeChild(placeholder);
    }
    }
    // repeat for <embed> elements for IE
  • Shareable
  • Analytics
  • 1,600,000 loads
    (meaningless)
  • ~2000 actual searches
  • Widget on ~70 websites
  • Widget Techniques
    Get on your coding shoes
  • Case-hardened JS
    http://kentbrewster.com/badges/
  • (function() {
    vartrueName = '';
    for (vari = 0; i < 16; i++) {
    trueName += String.fromCharCode(Math.floor(Math.random() * 26) + 97);
    }
    window[trueName] = {};
    var $ = window[trueName];
    $.f = function() {
    return {
    init : function(target) {
    vartheScripts = document.getElementsByTagName('SCRIPT');
    for (vari = 0; i < theScripts.length; i++) {
    if (theScripts[i].src.match(target)) {
    $.w = document.createElement('DIV');
    $.w.innerHTML = 'Hello, world. My name is ' + trueName + '.';
    theScripts[i].parentNode.insertBefore($.w, theScripts[i]);
    theScripts[i].parentNode.removeChild(theScripts[i]);
    break;
    }
    }
    }
    };
    }();
    varthisScript = /behavior.js/;
    if (typeofwindow.addEventListener !== 'undefined') {
    window.addEventListener('load', function() { $.f.init(thisScript); }, false);
    } else if (typeofwindow.attachEvent !== 'undefined') {
    window.attachEvent('onload', function() { $.f.init(thisScript); });
    }
    })();
  • (function() {
    vartrueName = '';
    for (vari = 0; i < 16; i++) {
    trueName += String.fromCharCode(Math.floor(Math.random() * 26) + 97);
    }
    window[trueName] = {};
    var $ = window[trueName];
    $.f = function() {
    return {
    init : function(target) {
    vartheScripts = document.getElementsByTagName('SCRIPT');
    for (vari = 0; i < theScripts.length; i++) {
    if (theScripts[i].src.match(target)) {
    $.w = document.createElement('DIV');
    $.w.innerHTML = 'Hello, world. My name is ' + trueName + '.';
    theScripts[i].parentNode.insertBefore($.w, theScripts[i]);
    theScripts[i].parentNode.removeChild(theScripts[i]);
    break;
    }
    }
    }
    };
    }();
    varthisScript = /behavior.js/;
    if (typeofwindow.addEventListener !== 'undefined') {
    window.addEventListener('load', function() { $.f.init(thisScript); }, false);
    } else if (typeofwindow.attachEvent !== 'undefined') {
    window.attachEvent('onload', function() { $.f.init(thisScript); });
    }
    })();
  • (function() {
    vartrueName = '';
    for (vari = 0; i < 16; i++) {
    trueName += String.fromCharCode(Math.floor(Math.random() * 26) + 97);
    }
    window[trueName] = {};
    var $ = window[trueName];
    $.f = function() {
    return {
    init : function(target) {
    vartheScripts = document.getElementsByTagName('SCRIPT');
    for (vari = 0; i < theScripts.length; i++) {
    if (theScripts[i].src.match(target)) {
    $.w = document.createElement('DIV');
    $.w.innerHTML = 'Hello, world. My name is ' + trueName + '.';
    theScripts[i].parentNode.insertBefore($.w, theScripts[i]);
    theScripts[i].parentNode.removeChild(theScripts[i]);
    break;
    }
    }
    }
    };
    }();
    varthisScript = /behavior.js/;
    if (typeofwindow.addEventListener !== 'undefined') {
    window.addEventListener('load', function() { $.f.init(thisScript); }, false);
    } else if (typeofwindow.attachEvent !== 'undefined') {
    window.attachEvent('onload', function() { $.f.init(thisScript); });
    }
    })();
  • (function() {
    vartrueName = '';
    for (vari = 0; i < 16; i++) {
    trueName += String.fromCharCode(Math.floor(Math.random() * 26) + 97);
    }
    window[trueName] = {};
    var $ = window[trueName];
    $.f = function() {
    return {
    init : function(target) {
    vartheScripts = document.getElementsByTagName('SCRIPT');
    for (vari = 0; i < theScripts.length; i++) {
    if (theScripts[i].src.match(target)) {
    $.w = document.createElement('DIV');
    $.w.innerHTML = 'Hello, world. My name is ' + trueName + '.';
    theScripts[i].parentNode.insertBefore($.w, theScripts[i]);
    theScripts[i].parentNode.removeChild(theScripts[i]);
    break;
    }
    }
    }
    };
    }();
    varthisScript = /behavior.js/;
    if (typeofwindow.addEventListener !== 'undefined') {
    window.addEventListener('load', function() { $.f.init(thisScript); }, false);
    } else if (typeofwindow.attachEvent !== 'undefined') {
    window.attachEvent('onload', function() { $.f.init(thisScript); });
    }
    })();
  • Meebo Bar
    http://en.oreilly.com/velocity2010/public/schedule/detail/13070
  • http://en.oreilly.com/velocity2010/public/schedule/detail/13070
  • Issues
  • JavaScript Blocks
    Solution: Meebo Bar technique
  • CSS Sandbox
    http://github.com/premasagar/cleanslate
  • JavaScript Prohibited
    MySpace, Wordpress.com, FB, others, disallow JS
  • Performance
  • <script>
    $LAB
    .script("http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js")
    .script("/scripts/config.1284731050.js")
    .wait()
    .script("/scripts/locator.1284731052.js")
    .script("http://www.google.com/jsapi")
    .wait(function () {
    google.load("maps", "3", {"callback": "Locator.initialize", "other_params": "sensor=false" });
    });
    </script>
    @getify http://labjs.com
  • Client cache
    http://developer.yahoo.com/performance/rules.html#expires
    #Far Future Expires Header
    <FilesMatch ".(gif|png|jpg|js|css|swf)$">
    ExpiresActive On
    ExpiresDefault "access plus 10 years"
    </FilesMatch>
  • File versioning
    http://particletree.com/notebook/automatically-version-your-css-and-javascript-files/
    #Rules for Versioned Static Files
    #filename.123456789.js -> filename.js
    RewriteRule^(scripts|css|images)/(.+).(.+).(js|css|jpg|gif|png)$ $1/$2.$4 [L]
  • One last tip…
    Build
    Iterate
  • Thanks!
    Please rate me: http://spkr8.com/t/4825
    Or, give feedback:
    @lroggendorff
    lroggendorff@gmail.com