<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Google Data &#187; Fred Sauer, Developer Advocate</title>
	<atom:link href="/author/fred-sauer-developer-advocate/feed/" rel="self" type="application/rss+xml" />
	<link>https://googledata.org</link>
	<description>Everything Google: News, Products, Services, Content, Culture</description>
	<lastBuildDate>Thu, 19 Mar 2015 22:49:02 +0000</lastBuildDate>
	<language>en-US</language>
		<sy:updatePeriod>hourly</sy:updatePeriod>
		<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.7.5</generator>
	<item>
		<title>Pushing Updates with the Channel API</title>
		<link>https://googledata.org/google-app-engine/pushing-updates-with-the-channel-api/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=pushing-updates-with-the-channel-api</link>
		<comments>https://googledata.org/google-app-engine/pushing-updates-with-the-channel-api/#comments</comments>
		<pubDate>Wed, 23 Feb 2011 23:48:00 +0000</pubDate>
		<dc:creator><![CDATA[Fred Sauer, Developer Advocate]]></dc:creator>
				<category><![CDATA[Google App Engine]]></category>
		<category><![CDATA[app engine team]]></category>

		<guid isPermaLink="false">https://googledata.org/?guid=eb33a16e34cf4c3ac4189d9986035305</guid>
		<description><![CDATA[If you've been watching Best Buy closely, you already know that Best Buy is constantly trying to come up with new and creative ways to use App Engine to engage with their customers. In this guest blog post, Luke Francl, BBYOpen Developer, was kind enou...]]></description>
				<content:encoded><![CDATA[<p><i>If you've been watching Best Buy closely, you already know that Best Buy is constantly trying to come up with <a href="http://googleappengine.blogspot.com/2009/02/best-buys-giftag-on-app-engine.html">new</a> and <a href="https://developer.bestbuy.com/">creative</a> ways to use App Engine to engage with their customers. In this guest blog post, <a href="http://www.recursion.org">Luke Francl</a>, BBYOpen Developer, was kind enough to share with us Best Buy's latest App Engine project.</i></p>


<br/>

<p>As part of Best Buy's <a href="http://www.bby.com/2010/10/06/best-buy-unveils-new-research-study-on-the-connected-world/">Connected Store</a> initiative, we have placed QR codes on our product information <a href="http://retailgeek.com/retail/best-buy-deploys-qr-codes-to-enhance-shopping-experience/">Fact Tags</a>, in addition to the standard pricing and product descriptions already printed there. When a customer uses the Best Buy app, or any other QR code scanner, they are shown the product details for the product they have scanned, powered by the <a href="https://developer.bestbuy.com/">BBYOpen API</a> or the <a href="http://m.bestbuy.com/">m.bestbuy.com</a> platform.</p>

<p>To track what stores and products are most popular, QR codes are also encoded with the store number. My project at Best Buy has been to analyze these scans and make new landing pages for QR codes easier to create.</p>

<p>Since we have the geo-location of the stores and product details from our API, it is a natural fit to display these scans on a map. We implemented an initial version of this idea, which used polling to visualize recent scans. To take our this a step further, we thought it would be exciting to use the recently launched App Engine <a href="http://code.google.com/appengine/docs/python/channel/overview.html">Channel API</a> to update our map in real-time.</p>


<p>
<iframe width="500" height="500" src="http://www.bbyscan.com/map?embedded=1&zoom=3">
</iframe>
</p>

<p>Our biggest challenge was pushing the updates to multiple browsers, since we'd most certainly have more than one user at a time looking at our map. The Channel API does not currently support <a href="http://code.google.com/appengine/docs/python/channel/overview.html#One_Client_Per_Key">broadcasting a single update to many connected clients</a>. In order to broadcast updates to multiple users, our solution was to keep a list of client IDs and send an update message to each of them.</p>

<p>To implement this, we decided to store the list of active channels in memcache. This solution is not ideal as there are race conditions when we modify the list of client IDs. However, it works well for our demo.</p>

<p>Here’s how we got it working. The code has been slightly simplified for clarity, including removing the rate limiting that we do. To play with a working demo, check out the <a href="https://github.com/BBYOpen/channel-map-demo">channel-map-demo project</a> from GitHub.</p>

<p>As customers in our stores scan QR codes, those scans are recorded by enqueuing a <a href="http://code.google.com/appengine/articles/deferred.html"><code>deferred</code></a>. We defer all writes so we can return a response to the client as quickly as possible.</p>

<p>In the <code>deferred</code>, we call a function to push the message to all the active channels (see <a href="https://github.com/BBYOpen/channel-map-demo/blob/master/main.py#L84">full source</a>).</p>

<pre style="border: 1px solid #eee; padding: 1em; background-color: #fafafa;">
def push_to_channels(scan):
    content = '&lt;div class="infowindowcontent"&gt;(...) &lt;/div&gt;' % {
                  'product_name': scan.product.name,
                  'timestamp' : scan.timestamp.strftime('%I:%M %p'),
                  'store_name': scan.store.name,
                  'state': scan.store.state,
                  'image': scan.product.image }
            
    message = {'lat': scan.store.lat,
               'lon': scan.store.lon,
               'content': content}

    channels = simplejson.loads(memcache.get('channels') or '{}')
    
    for channel_id in channels.iterkeys():
        encoded_message = simplejson.dumps(message)

        channel.send_message(channel_id, encoded_message)
</pre>

<p>The message is a JSON data structure containing the latitude and longitude of the store where the scan occurred, plus a snippet of HTML to display in an <a href="http://code.google.com/apis/maps/documentation/javascript/overlays.html#InfoWindows"><code>InfoWindow</code></a> on the map. The product information (such as name and thumbnail image) comes from our BBYOpen Products API.</p>

<p>Then, when a user opens up the site and requests the map page, we create a channel, add it to the serialized <code>channels</code> Python dictionary, stored in memcache, and pass the token back to the client (see <a href="https://github.com/BBYOpen/channel-map-demo/blob/master/main.py#L55">full source</a>).</p>

<pre style="border: 1px solid #eee; padding: 1em; background-color: #fafafa;">
channel_id = uuid.uuid4().hex
token = channel.create_channel(channel_id)

channels = simplejson.loads(memcache.get('channels') or '{}')
    
channels[channel_id] = str(datetime.now())

memcache.set('channels', simplejson.dumps(channels))
</pre>

<p>On the map page, JavaScript creates a Google Maps map and uses the token to open a channel. When the <a href="http://code.google.com/appengine/docs/python/channel/javascript.html"><code>onMessage</code> callback</a> is called by the Channel API, a new <code>InfoWindow</code> is displayed on the map using the HTML content and latitude and longitude in the message (see <a href="https://github.com/BBYOpen/channel-map-demo/blob/master/javascript/map.js#L7">full source</a>).</p>

<pre style="border: 1px solid #eee; padding: 1em; background-color: #fafafa;">
function onMessage(message) {
  var scan = JSON.parse(message.data);

  var infoWindow = new google.maps.InfoWindow(
    {content: scan.content,
     disableAutoPan: true,
     position: new google.maps.LatLng(scan.lat, scan.lon)});

  infoWindow.open(map);
  setTimeout(function() { infoWindow.close(); }, 10000);
};
</pre>

<p>Finally, since channels can only be open for two hours, we have a cron job that runs once an hour to remove old channels. Before deleting the client ID, a message is sent on the channel which triggers code in the JavaScript <code>onMessage</code> function to reload the page, thus giving it a new channel and client ID (see <a href="https://github.com/BBYOpen/channel-map-demo/blob/master/main.py#L114">full source</a>).</p>

<p>You can see the <a href="http://www.bbyscan.com/map">end result on our map</a>, <a href="http://bbyopen.com/2011/01/bbyscan-mobile-code-scan-map">watch a video about the BBYScan project</a> or checkout the <a href="https://github.com/BBYOpen/channel-map-demo">sample channel-map-demo project</a> and create your own Channel API based application.</p>

<span class="byline-author">Posted by Fred Sauer, App Engine Team</span><div class="blogger-post-footer"><img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8501956666581132164-1638570310478882134?l=googleappengine.blogspot.com' alt='' /></div>]]></content:encoded>
			<wfw:commentRss>https://googledata.org/google-app-engine/pushing-updates-with-the-channel-api/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Practical Report Generation on App Engine</title>
		<link>https://googledata.org/google-app-engine/practical-report-generation-on-app-engine/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=practical-report-generation-on-app-engine</link>
		<comments>https://googledata.org/google-app-engine/practical-report-generation-on-app-engine/#comments</comments>
		<pubDate>Tue, 10 Aug 2010 04:58:00 +0000</pubDate>
		<dc:creator><![CDATA[Fred Sauer, Developer Advocate]]></dc:creator>
				<category><![CDATA[Google App Engine]]></category>
		<category><![CDATA[app engine team]]></category>

		<guid isPermaLink="false"></guid>
		<description><![CDATA[We recently announced the Mapper API, a first step in a broader effort to provide full MapReduce capabilities on App Engine. While we still have some work ahead of us, there’s already a lot that can be done with today’s Mapper API. One area of part...]]></description>
				<content:encoded><![CDATA[<p>We recently <a href="http://googleappengine.blogspot.com/2010/07/introducing-mapper-api.html">announced the Mapper API</a>, a first step in a broader effort to provide full MapReduce capabilities on App Engine. While we still have some work ahead of us, there’s already a lot that can be done with today’s Mapper API. One area of particular interest is report generation.</p>
<br>
<p>Most applications create and maintain large numbers of detail records: entities in data models, transaction history or event logs. In order to glean useful information out of these vast data sets, your application has to iterate over your entities, summarize and breakdown the results. That’s where the Mapper API comes in.</p>
<br>
<p>The Mapper API uses the Task Queue to enable your application to rapidly iterate over its data sets, whether small or very, very large. The API takes care of the tedious bookkeeping involved in efficiently scheduling and keeping track of all those tasks. The Task Queue, in turn, automatically ‘pushes’ the work to your app.</p>
<br>
<p>Christopher O’Donnell (<a href="http://www.twitter.com/markitecht">@markitecht</a>), a technology product designer and developer from Cambridge, Massachusetts, was kind enough to share with us some of the motivations and implementation details behind his own project. In a new guest article, <a href="http://code.google.com/appengine/articles/mr/mapper.html">Modern Funnel Analytics Using Mapper</a>, Christopher makes extensive use of the Mapper API to illustrate the process of generating rollup reports. With his approach, he's able to provide both summarized results and drill down capabilities.</p>
<br>
<p>If you like Christopher’s article, you should also checkout out the many other <a href="http://code.google.com/appengine/articles/">interesting articles</a> on the Google App Engine home page. And, if you have an interesting App Engine article or story you'd like to share, <a href="mailto:fredsa@google.com">let us know</a>. We'd love to hear about it.</p>
<br>
<p>Posted by <span class="byline-author">Fred Sauer</span>, App Engine Team</p><div class="blogger-post-footer"><img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8501956666581132164-3163854127784545970?l=googleappengine.blogspot.com' alt='' /></div>]]></content:encoded>
			<wfw:commentRss>https://googledata.org/google-app-engine/practical-report-generation-on-app-engine/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Open sourcing Thoughtsite &#8211; A discussion forum designed for Google App Engine</title>
		<link>https://googledata.org/google-app-engine/open-sourcing-thoughtsite-a-discussion-forum-designed-for-google-app-engine/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=open-sourcing-thoughtsite-a-discussion-forum-designed-for-google-app-engine</link>
		<comments>https://googledata.org/google-app-engine/open-sourcing-thoughtsite-a-discussion-forum-designed-for-google-app-engine/#comments</comments>
		<pubDate>Tue, 01 Jun 2010 23:33:00 +0000</pubDate>
		<dc:creator><![CDATA[Fred Sauer, Developer Advocate]]></dc:creator>
				<category><![CDATA[Google App Engine]]></category>
		<category><![CDATA[app engine team]]></category>

		<guid isPermaLink="false"></guid>
		<description><![CDATA[Editor's Note: Cross-posted from the Open Source at Google Blog.

Google App Engine is a powerful system, designed to take all the pain of infrastructure management and performance scaling out of web application programming. App Engine applications are...]]></description>
				<content:encoded><![CDATA[<b>Editor's Note:</b> <i><a href="http://google-opensource.blogspot.com/2010/05/open-sourcing-thoughtsite-discussion.html">Cross-posted from the Open Source at Google Blog</a></i>.<br />
<br />
Google App Engine is a powerful system, designed to take all the pain of infrastructure management and performance scaling out of web application programming. App Engine applications are easy to build, easy to maintain, and easy to scale as your traffic and data storage needs grow.<br />
<br />
While there are a lot of <a href="https://groups.google.com/group/google-appengine/web/google-app-engine-open-source-projects?pli=1">open source projects</a> available to learn how to use App Engine, there have been few open sourced, comprehensive web applications built on App Engine to help you learn how best to use the advanced features that App Engine provides.<br />
<br />
Enter... Thoughtsite!<br />
<br />
<a href="http://4.bp.blogspot.com/_U-yOwEkHpTM/TAWPgBvcQWI/AAAAAAAAAX4/Ew2jL-2Lo_U/s1600/index.001.png" onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}"><img alt="" border="0" id="BLOGGER_PHOTO_ID_5477942302152081762" src="http://4.bp.blogspot.com/_U-yOwEkHpTM/TAWPgBvcQWI/AAAAAAAAAX4/Ew2jL-2Lo_U/s320/index.001.png" style="cursor: hand; cursor: pointer; display: block; height: 145px; margin: 0px auto 10px; text-align: center; width: 320px;" /></a><br />
<br />
<a href="http://code.google.com/p/thoughtsite/">Thoughtsite</a> is a discussions/forum web app designed for Google App Engine. The main features of the app are:<br />
<ul>
<li>A flexible system that could be used for any kind of discussion forum.</li>
<li>Voting, tagging, comments and a reputation point system for users.</li>
<li>Full text search on App Engine with Apache Lucene.</li>
<li>Search for threads by tags or by keywords. Threads can also be linked to from user profiles.</li>
<li>Users gain reputation points based on community votes for their contributions.</li>
<li>Full-fledged user profiles with info, points, contributions, user's personal tag cloud, etc.</li>
<li>Basic duplication detection filters to detect similar threads so posters can avoid creating a new thread if one already exists.</li>
<li>Basic spam and gaming filters (self-voting, cross-voting, etc.).</li>
<li>Comprehensive admin section that allows moderation of individual posts and users. Users can flag objectionable content or trolls.</li>
</ul>
<br />
<a href="http://1.bp.blogspot.com/_U-yOwEkHpTM/TAWPvjS3fuI/AAAAAAAAAYI/1eaW052v7G4/s1600/index.002.png" onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}"><img alt="" border="0" id="BLOGGER_PHOTO_ID_5477942568857075426" src="http://1.bp.blogspot.com/_U-yOwEkHpTM/TAWPvjS3fuI/AAAAAAAAAYI/1eaW052v7G4/s320/index.002.png" style="display: block; height: 210px; margin-bottom: 10px; margin-left: auto; margin-right: auto; margin-top: 0px; text-align: center; width: 320px;" /></a><br />
<br />
Best of all, Thoughtsite is completely open source using an Apache 2 license and the code is available for <a href="http://code.google.com/p/thoughtsite/">download</a>.<br />
<br />
We hope you download the source, take it apart and play with it. Thoughtsite will work as a complete app if you want to use it to host a discussion forum on your own domain, but its real value is in taking it apart to understand how it uses App Engine under the hood.<br />
<br />
<span class="byline-author">Posted by Fred Sauer, App Engine Team</span><div class="blogger-post-footer"><img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8501956666581132164-8728599753105315074?l=googleappengine.blogspot.com' alt='' /></div>]]></content:encoded>
			<wfw:commentRss>https://googledata.org/google-app-engine/open-sourcing-thoughtsite-a-discussion-forum-designed-for-google-app-engine/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
<enclosure url="" length="" type="" />
		</item>
	</channel>
</rss>
