<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/atom10full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><feed xmlns="http://www.w3.org/2005/Atom" xmlns:openSearch="http://a9.com/-/spec/opensearch/1.1/" xmlns:georss="http://www.georss.org/georss" xmlns:gd="http://schemas.google.com/g/2005" xmlns:thr="http://purl.org/syndication/thread/1.0" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" gd:etag="W/&quot;AkYEQ3Y-fCp7ImA9WhRUFk0.&quot;"><id>tag:blogger.com,1999:blog-1377183911445147227</id><updated>2012-01-26T12:01:42.854-08:00</updated><category term="Mobile" /><category term="Apps Script" /><category term="mpstaffpick" /><category term="Chrome OS" /><category term="Resellers" /><category term="Google Prediction API" /><category term="webinar" /><category term="Google Sites API" /><category term="Freemium" /><category term="Gadgets" /><category term="Auth" /><category term="Google Docs API" /><category term="analytics" /><category term="Google Data Protocol" /><category term="Gmail APIs" /><category term="Groups" /><category term="OpenID" /><category term="App Engine" /><category term="PHP" /><category term="ISVs" /><category term="billing" /><category term="googlenew" /><category term="AdSense" /><category term="Developers" /><category term="SaaS" /><category term="Community" /><category term="Charts" /><category term="Staff Picks" /><category term="Google Talk" /><category term="Ruby" /><category term="python" /><category term="Google Calendar API" /><category term="Cloud Storage API" /><category term="Google Profiles API" /><category term="Administrative APIs" /><category term="Marketplace" /><category term="Google Tasks API" /><category term="Guest Post" /><category term="marketing" /><category term="oauth" /><category term="Google Spreadsheets API" /><category term="Fusion Tables" /><category term="JavaScript" /><category term="Android" /><category term="Google Contacts API" /><category term="Google I/O" /><category term="Marketplace ISV Guest" /><category term=".NET" /><title>Google Apps Developer Blog</title><subtitle type="html" /><link rel="http://schemas.google.com/g/2005#feed" type="application/atom+xml" href="http://googleappsdeveloper.blogspot.com/feeds/posts/default" /><link rel="alternate" type="text/html" href="http://googleappsdeveloper.blogspot.com/" /><link rel="next" type="application/atom+xml" href="http://www.blogger.com/feeds/1377183911445147227/posts/default?start-index=26&amp;max-results=25&amp;redirect=false&amp;v=2" /><author><name>Jordan N.</name><uri>http://www.blogger.com/profile/16901237984070230091</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><generator version="7.00" uri="http://www.blogger.com">Blogger</generator><openSearch:totalResults>176</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/atom+xml" href="http://feeds.feedburner.com/GoogleAppsDeveloperBlog" /><feedburner:info uri="googleappsdeveloperblog" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><feedburner:emailServiceId>GoogleAppsDeveloperBlog</feedburner:emailServiceId><feedburner:feedburnerHostname>http://feedburner.google.com</feedburner:feedburnerHostname><entry gd:etag="W/&quot;AkYEQ3c7cCp7ImA9WhRUFk0.&quot;"><id>tag:blogger.com,1999:blog-1377183911445147227.post-8376078335796651701</id><published>2012-01-26T12:01:00.000-08:00</published><updated>2012-01-26T12:01:42.908-08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2012-01-26T12:01:42.908-08:00</app:edited><title>Reading Query Results from Calendar in Pages</title><content type="html">&lt;p&gt;What’s the difference between reality and theory?  In theory, there is no difference.  But reality often imposes unanticipated constraints on developers.  These may come in the form of bandwidth restrictions, memory limits, timeouts, or other requirements of the systems that interact with your application.&lt;/p&gt;

&lt;p&gt;My team recently built an application that helps us analyze the scheduling and usage of conference rooms at Google.  We use the new &lt;a href="http://code.google.com/apis/calendar/v3/getting_started.html"&gt;Calendar API v3&lt;/a&gt; on &lt;a href="http://code.google.com/appengine/"&gt;Google App Engine&lt;/a&gt; to read the rooms’ schedules, which we combine with actual occupancy data to calculate utilization and other metrics.&lt;/p&gt;

&lt;p&gt;As you might imagine, Google has a lot of conference rooms (I believe the last official count was “more than twelve.”)  And many of the rooms seem to be booked fairly solid.  That means we need to read a lot of data from Calendar.  So much, in fact, that our queries time out if we try to read an entire calendar at once.  But the API team anticipated “Google scale” use and designed a mechanism that allows us to retrieve data in batches.&lt;/p&gt;

&lt;p&gt;The idea is simple.  When you create a request, you specify the page size: the maximum number of results you’d like Calendar to return in one batch.  Calendar returns the data you requested, along with an opaque page token, which you can think of as a bookmark.  To retrieve the next batch of data, you ask the API for the next page token and include the new token in your next request.  The page token keeps track of the results you’ve already seen, so Calendar can send the next batch each time.  You repeat this process until you’ve exhausted all the results.&lt;/p&gt;

&lt;p&gt;Here’s how we did this in Java:&lt;/p&gt;
&lt;pre class="prettyprint"&gt;
public void getRoomEvents(String roomEmail) throws IOException {
    // Create a request to list this room’s events (see code, below)
    Calendar.Events.List listRequest = getListRequest(roomEmail);
    do {
      // Retrieve one page of events
      Events events = executeListRequest(listRequest);
      List&lt;Event&gt; eventList = events.getItems();

      // Process each event
      for (Event event : eventList) {
        processEvent(event);
      }

      // Update the page token
      listRequest.setPageToken(events.getNextPageToken());

    // Stop when all results have been retrieved
    } while (listRequest.getPageToken() != null);
  }

  // Create a request to list the events for a room
  private Calendar.Events.List getListRequest(String roomEmail)
        throws IOException {
    return calendarClient.events().list(roomEmail)
        .setMaxResults(1000) // Limit each response to 1000 events
        .setPageToken(null)  // Start with the first page of results
        // Return an individual event for each instance occurrence of a
        // recurring event
        .setSingleEvents(true); 
  }
&lt;/pre&gt;

&lt;p&gt;We call &lt;code&gt;getRoomEvents()&lt;/code&gt; for each room, using the room’s email address to identify it to Calendar.  (You can retrieve events from your own calendar by substituting your own email address.)  Then &lt;code&gt;getListRequest()&lt;/code&gt; creates a request that we will send to Calendar.  The request asks for a list of up to 1000 events from the room’s calendar.&lt;/p&gt;

&lt;p&gt;The remainder of &lt;code&gt;getRoomEvents()&lt;/code&gt; is a loop that executes the request, processes the results, and updates the page token in preparation for the next request.  The loop continues, retrieving and processing each subsequent page of results, until the entire list has been returned.  The call to &lt;code&gt;getNextPageToken()&lt;/code&gt; indicates the end of the results by returning a null value.&lt;/p&gt;

&lt;p&gt;By paginating our requests we avoid timeouts and reduce memory requirements.  As an added benefit, each request completes fairly quickly, which means it’s also quick to retry if an error should occur.  And finally, a multithreaded application may be able to process one or more pages of results while it retrieves the next, speeding execution.  These advantages have led developers at Google to adopt pagination as a best practice.  Look for it in our APIs when you need to exchange large amounts of data, and consider adding it to your own services.&lt;/p&gt;

&lt;p&gt;If you have questions about our services or APIs, or if you want to see what other developers are doing with Google Calendar, check the discussions and documentation in the &lt;a href="http://code.google.com/apis/calendar/community/forum.html"&gt;Google Apps Calendar API forum&lt;/a&gt;.&lt;/p&gt;

&lt;br /&gt;&lt;table cellpadding="5" cellspacing="0"&gt;&lt;tbody&gt;&lt;tr style="background-color: #f2f2f2;"&gt;&lt;td&gt;&lt;img class="profile" width="76px" style="width:76px;" src="http://4.bp.blogspot.com/-7KcjLbsjxrg/TyGvWYqnXqI/AAAAAAAAAZc/ecLG4cD4wxU/s200/adamliss.png" /&gt;&lt;/td&gt;&lt;td valign="top"&gt;&lt;span class="largefont"&gt;Adam Liss&lt;/span&gt;   &lt;a class="alt" href="https://plus.google.com/u/0/116984609600395690760/about" rel="me" target="_blank"&gt;profile&lt;/a&gt;
&lt;br /&gt;&lt;div class="bio"&gt;
&lt;br /&gt;Adam is an engineer who believes that "technical" shouldn't necessarily mean "difficult."  He enjoys building infrastructure and tools that make Googlers more productive.  Before joining Google in 2010, he built network-security appliances and one of the first wireless application delivery platforms.&lt;/div&gt;
&lt;br /&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1377183911445147227-8376078335796651701?l=googleappsdeveloper.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/GoogleAppsDeveloperBlog/~4/rA7MbtTZ7Ac" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://googleappsdeveloper.blogspot.com/feeds/8376078335796651701/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=1377183911445147227&amp;postID=8376078335796651701&amp;isPopup=true" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/1377183911445147227/posts/default/8376078335796651701?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/1377183911445147227/posts/default/8376078335796651701?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/GoogleAppsDeveloperBlog/~3/rA7MbtTZ7Ac/reading-query-results-from-calendar-in.html" title="Reading Query Results from Calendar in Pages" /><author><name>Google Apps Developer Blog Editor</name><uri>http://www.blogger.com/profile/07808045840831274565</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://4.bp.blogspot.com/-7KcjLbsjxrg/TyGvWYqnXqI/AAAAAAAAAZc/ecLG4cD4wxU/s72-c/adamliss.png" height="72" width="72" /><thr:total>0</thr:total><feedburner:origLink>http://googleappsdeveloper.blogspot.com/2012/01/reading-query-results-from-calendar-in.html</feedburner:origLink></entry><entry gd:etag="W/&quot;A0cFRX46eyp7ImA9WhRUFE4.&quot;"><id>tag:blogger.com,1999:blog-1377183911445147227.post-4033892497175955537</id><published>2012-01-24T13:03:00.000-08:00</published><updated>2012-01-24T13:03:34.013-08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2012-01-24T13:03:34.013-08:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Developers" /><title>Tips on using the APIs Discovery Service</title><content type="html">&lt;p&gt;Our newest set of APIs - &lt;a href="http://code.google.com/apis/tasks/v1/getting_started.html"&gt;Tasks&lt;/a&gt;, &lt;a href="http://code.google.com/apis/calendar/v3/getting_started.html"&gt;Calendar v3&lt;/a&gt;, &lt;a href="https://developers.google.com/+/api/"&gt;Google+&lt;/a&gt; to name a few - are supported by the &lt;a href="http://code.google.com/apis/discovery/"&gt;Google APIs Discovery Service&lt;/a&gt;. The Google APIs Discovery service offers an interface that allows developers to programmatically get API metadata such as:&lt;/p&gt;
&lt;ul&gt;
 &lt;li&gt;A directory of supported APIs.&lt;/li&gt;
 &lt;li&gt;A list of API resource schemas based on JSON Schema.&lt;/li&gt;
 &lt;li&gt;A list of API methods and parameters for each method and their inline documentation.&lt;/li&gt;
 &lt;li&gt;A list of available OAuth 2.0 scopes.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The APIs Discovery Service is especially useful when building developer tools, as you can use it to automatically generate certain features. For instance we are using the APIs Discovery Service in &lt;a href="http://code.google.com/apis/discovery/libraries.html"&gt;our client libraries&lt;/a&gt; and in our &lt;a href="https://code.google.com/apis/explorer/"&gt;APIs Explorer&lt;/a&gt; but also to generate some of our &lt;a href="https://code.google.com/apis/tasks/v1/reference.html"&gt;online API reference&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Because the APIs Discovery Service is itself an API, you can use features such as &lt;a href="http://googlecode.blogspot.com/2010/03/making-apis-faster-introducing-partial.html"&gt;partial response&lt;/a&gt; which is a way to get only the information you need. Let’s look at some of the useful information that is available using the APIs Discovery Service and the partial response feature.&lt;/p&gt;

&lt;h3&gt;List the supported APIs&lt;/h3&gt;
&lt;p/&gt;
&lt;p&gt;You can get the list of all the APIs that are supported by the discovery service by sending a &lt;code&gt;GET&lt;/code&gt; request to the following endpoint:&lt;/p&gt;

&lt;pre class="prettyprint"&gt;
https://www.googleapis.com/discovery/v1/apis?fields=items(title,discoveryLink)
&lt;/pre&gt;

&lt;p&gt;Which will return a JSON feed that looks like this:&lt;/p&gt;
&lt;pre class="prettyprint"&gt;
{
    "items": [
        …
        {
            "title": "Google+ API",
            "discoveryLink": "./apis/plus/v1/rest"
        },
        {
            "title": "Tasks API",
            "discoveryLink": "./apis/tasks/v1/rest"
        },
        {
            "title": "Calendar API",
            "discoveryLink": "./apis/calendar/v3/rest"
        },
        …
    ]
}
&lt;/pre&gt;
&lt;p&gt;Using the &lt;code&gt;discoveryLink&lt;/code&gt; attribute in the resources part of the feed above you can access the discovery document of each API. This is where a lot of useful information about the API can be accessed.&lt;/p&gt;

&lt;h3&gt;Get the OAuth 2.0 scopes of an API&lt;/h3&gt;
&lt;p/&gt;

&lt;p&gt;Using the API-specific endpoint you can easily get the OAuth 2.0 scopes available for that API. For example, here is how to get the scopes of the Google Tasks API:&lt;/p&gt;

&lt;pre class="prettyprint"&gt;
https://www.googleapis.com/discovery/v1/apis/tasks/v1/rest?fields=auth(oauth2(scopes))
&lt;/pre&gt;

&lt;p&gt;This method returns the JSON output shown below, which indicates that &lt;code&gt;https://www.googleapis.com/auth/tasks&lt;/code&gt; and &lt;code&gt;https://www.googleapis.com/auth/tasks.readonly&lt;/code&gt; are the two scopes associated with the Tasks API.&lt;/p&gt;

&lt;pre class="prettyprint"&gt;
{
    "auth": {
        "oauth2": {
            "scopes": {
                "https://www.googleapis.com/auth/tasks": {
                    "description": "Manage your tasks"
                },
                "https://www.googleapis.com/auth/tasks.readonly": {
                    "description": "View your tasks"
                }
            }
        }
    }
}
&lt;/pre&gt;

&lt;p&gt;Using requests of this type you could detect which APIs do not support OAuth 2.0. For example, the Translate API does not support OAuth 2.0, as it does not provide access to OAuth protected resources such as user data.  Because of this, a &lt;code&gt;GET&lt;/code&gt; request to the following endpoint:&lt;/p&gt;

&lt;pre class="prettyprint"&gt;
https://www.googleapis.com/discovery/v1/apis/translate/v2/rest?fields=auth(oauth2(scopes))
&lt;/pre&gt;

&lt;p&gt;Returns:&lt;/p&gt;

&lt;pre class="prettyprint"&gt;
{}
&lt;/pre&gt;

&lt;h3&gt;Getting scopes required for an API’s endpoints and methods&lt;/h3&gt;
&lt;p/&gt;
&lt;p&gt;Using the API-specific endpoints again, you can get the lists of operations and API endpoints, along with the scopes required to perform those operations. Here is an example querying that information for the Google Tasks API:&lt;/p&gt;

&lt;pre class="prettyprint"&gt;
https://www.googleapis.com/discovery/v1/apis/tasks/v1/rest?fields=resources/*/methods(*(path,scopes,httpMethod))
&lt;/pre&gt;

&lt;p&gt;Which returns:&lt;/p&gt;
&lt;pre class="prettyprint"&gt;
{
    "resources": {
        "tasklists": {
            "methods": {
                "get": {
                    "path": "users/@me/lists/{tasklist}",                         
                    "httpMethod": "GET",
                    "scopes": [
                        "https://www.googleapis.com/auth/tasks",
                        "https://www.googleapis.com/auth/tasks.readonly"
                    ]
                },
                "insert": {
                    "path": "users/@me/lists",
                    "httpMethod": "POST",
                    "scopes": [
                        "https://www.googleapis.com/auth/tasks"
                    ]
                },
                …
            }
        },
        "tasks": {
            …
        }
    }
}
&lt;/pre&gt;

&lt;p&gt;This tells you that to perform a &lt;code&gt;POST&lt;/code&gt; request to the &lt;code&gt;users/@me/lists&lt;/code&gt; endpoint (to insert a new task) you need to have been authorized with the scope &lt;code&gt;https://www.googleapis.com/auth/tasks&lt;/code&gt; and that to be able to do a &lt;code&gt;GET&lt;/code&gt; request to the &lt;code&gt;users/@me/lists/{tasklist}&lt;/code&gt; endpoint you need to have been authorized with either of the two Google Tasks scopes.&lt;/p&gt;

&lt;p&gt;You could use this to do some automatic discovery of the scopes you need to authorize to perform all the operations that your applications does.&lt;/p&gt;

&lt;p&gt;You could also use this information to detect which operations and which endpoints you can access given a specific authorization token ( OAuth 2.0, OAuth 1.0 or Authsub token).  First, use either the Authsub Token Info service or the OAuth 2.0 Token Info Service to determine which scopes your token has access to (see below); and then deduct from the feed above which endpoints and operations requires access to these scopes.&lt;/p&gt;

&lt;pre&gt;                        
&lt;b&gt;[Access Token]&lt;/b&gt; -----(Token Info)----&gt; &lt;b&gt;[Scopes]&lt;/b&gt; -----(APIs Discovery)----&gt; &lt;b&gt;[Operations/API Endpoints]&lt;/b&gt;
&lt;/pre&gt;

&lt;p&gt;Example of using the OAuth 2.0 Token Info service:&lt;p&gt;

&lt;p&gt;Request:&lt;/p&gt;

&lt;pre class="prettyprint"&gt;
GET /oauth2/v1/tokeninfo?access_token=&lt;OAuth 2.0 Access Token&gt; HTTP/1.1
Host: www.googleapis.com
&lt;/pre&gt;

&lt;p&gt;Response:&lt;/p&gt;

&lt;pre class="prettyprint"&gt;
HTTP/1.1 200 OK
Content-Type: application/json; charset=UTF-8
…

{
    "issued_to": "1234567890.apps.googleusercontent.com",
    "audience": "1234567890.apps.googleusercontent.com",
    "scope": "https://www.google.com/m8/feeds/ 
              https://www.google.com/calendar/feeds/",
    "expires_in": 1038
}
&lt;/pre&gt;

&lt;p&gt;There is a lot more you can do with the APIs Discovery Service so I invite you to have a deeper look at the documentation to find out more.&lt;/p&gt;

&lt;br /&gt;&lt;table cellpadding="5" cellspacing="0"&gt;&lt;tbody&gt;&lt;tr style="background-color: #f2f2f2;"&gt;&lt;td&gt;&lt;img class="profile" src="http://sites.google.com/site/developeradvocates/image/nicolas_garnier.png" /&gt;&lt;/td&gt;&lt;td valign="top"&gt;&lt;span class="largefont"&gt;Nicolas Garnier&lt;/span&gt;   &lt;a class="alt" href="http://www.google.com/profiles/Nivco.las" rel="me" target="_blank"&gt;profile&lt;/a&gt; | &lt;a class="alt" href="http://twitter.com/nivco" rel="me" target="_blank"&gt;twitter&lt;/a&gt; | &lt;a class="alt" href="http://code.google.com/events/#&amp;amp;speaker=nivco"&gt;events&lt;/a&gt;
&lt;br /&gt;&lt;div class="bio"&gt;
&lt;br /&gt;Nicolas joined Google’s Developer Relations in 2008. Since then he's worked on commerce oriented products such as Google Checkout and Google Base.  Currently, he is working on Google Apps with a focus on the Google Calendar API, the Google Contacts API, and the Tasks API. Before joining Google, Nicolas worked at Airbus and at the French Space Agency where he built web applications for scientific researchers.&lt;/div&gt;
&lt;br /&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1377183911445147227-4033892497175955537?l=googleappsdeveloper.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/GoogleAppsDeveloperBlog/~4/Wt2eB4o4Qms" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://googleappsdeveloper.blogspot.com/feeds/4033892497175955537/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=1377183911445147227&amp;postID=4033892497175955537&amp;isPopup=true" title="1 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/1377183911445147227/posts/default/4033892497175955537?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/1377183911445147227/posts/default/4033892497175955537?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/GoogleAppsDeveloperBlog/~3/Wt2eB4o4Qms/tips-on-using-apis-discovery-service.html" title="Tips on using the APIs Discovery Service" /><author><name>Google Apps Developer Blog Editor</name><uri>http://www.blogger.com/profile/07808045840831274565</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>1</thr:total><feedburner:origLink>http://googleappsdeveloper.blogspot.com/2012/01/tips-on-using-apis-discovery-service.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CkcFQnk8fCp7ImA9WhRVGUs.&quot;"><id>tag:blogger.com,1999:blog-1377183911445147227.post-8042533873388026453</id><published>2012-01-19T00:00:00.000-08:00</published><updated>2012-01-19T00:00:13.774-08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2012-01-19T00:00:13.774-08:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Apps Script" /><title>Google Apps EMEA Developer Tour (continued)</title><content type="html">&lt;p&gt;Two months ago &lt;a href="http://googlecode.blogspot.com/2011/11/google-apps-emea-developer-tour.html"&gt;we announced&lt;/a&gt; that a few of us from the Google Apps Developer Relations team would be going around EMEA to meet with developers and talk about Google Apps technologies. We have met great developers from Germany, France, Russia, Czech Republic, Egypt, Switzerland, Israel, and Spain during Google Developer Days, hackathons, developer conferences and GTUG meetings.&lt;/p&gt;

&lt;p&gt;This year we are continuing the tour with a series of Google Apps Script hackathons taking place in &lt;a href="http://apps-dev-tour.appspot.com/agenda.html#Vienna"&gt;Vienna&lt;/a&gt;, &lt;a href="http://apps-dev-tour.appspot.com/agenda.html#Milan"&gt;Milan&lt;/a&gt;, &lt;a href="http://apps-dev-tour.appspot.com/agenda.html#Madrid"&gt;Madrid&lt;/a&gt;, &lt;a href="http://apps-dev-tour.appspot.com/agenda.html#Munich"&gt;Munich&lt;/a&gt; and &lt;a href="http://apps-dev-tour.appspot.com/agenda.html#Dublin"&gt;Dublin&lt;/a&gt; over the next few months. These hackathons provide a fun and hands-on way to learn about Google Apps Script and a good opportunity to give us your feedback on this technology.&lt;/p&gt;

&lt;p&gt;For more information about the tour and to register for these events, please visit the &lt;a href="http://apps-dev-tour.appspot.com/"&gt;Google Apps EMEA Developer Tour&lt;/a&gt; website.&lt;/p&gt;

&lt;iframe width="530" height="350" frameborder="0" scrolling="no" marginheight="0" marginwidth="0" style="margin-top: 20px;border-radius:5px;" src="http://maps.google.com/maps/ms?z=4&amp;amp;t=t&amp;amp;vpsrc=5&amp;amp;msa=0&amp;amp;msid=212740107356106824507.0004b09b4f5a62b1c5bfb&amp;amp;ie=UTF8&amp;amp;ll=48.516604,8.369141&amp;amp;spn=17.888665,46.538086&amp;amp;output=embed"&gt;&lt;/iframe&gt;

&lt;p&gt;We plan to organize many other Google Apps events close to you in the near future. Look for updates on the &lt;a href="http://apps-dev-tour.appspot.com/"&gt;Google Apps EMEA Developer Tour&lt;/a&gt; website or keep an eye out for further announcements on this blog.&lt;/p&gt;

&lt;br /&gt;&lt;table cellpadding="5" cellspacing="0"&gt;&lt;tbody&gt;&lt;tr style="background-color: #f2f2f2;"&gt;&lt;td&gt;&lt;img class="profile" src="http://sites.google.com/site/developeradvocates/image/nicolas_garnier.png" /&gt;&lt;/td&gt;&lt;td valign="top"&gt;&lt;span class="largefont"&gt;Nicolas Garnier&lt;/span&gt;   &lt;a class="alt" href="http://www.google.com/profiles/Nivco.las" rel="me" target="_blank"&gt;profile&lt;/a&gt; | &lt;a class="alt" href="http://twitter.com/nivco" rel="me" target="_blank"&gt;twitter&lt;/a&gt; | &lt;a class="alt" href="http://code.google.com/events/#&amp;amp;speaker=nivco"&gt;events&lt;/a&gt;
&lt;br /&gt;&lt;div class="bio"&gt;
&lt;br /&gt;Nicolas joined Google’s Developer Relations in 2008. Since then he's worked on commerce oriented products such as Google Checkout and Google Base.  Currently, he is working on Google Apps with a focus on the Google Calendar API, the Google Contacts API, and the Tasks API. Before joining Google, Nicolas worked at Airbus and at the French Space Agency where he built web applications for scientific researchers.&lt;/div&gt;
&lt;br /&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1377183911445147227-8042533873388026453?l=googleappsdeveloper.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/GoogleAppsDeveloperBlog/~4/_8okS-KNb7c" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://googleappsdeveloper.blogspot.com/feeds/8042533873388026453/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=1377183911445147227&amp;postID=8042533873388026453&amp;isPopup=true" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/1377183911445147227/posts/default/8042533873388026453?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/1377183911445147227/posts/default/8042533873388026453?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/GoogleAppsDeveloperBlog/~3/_8okS-KNb7c/google-apps-emea-developer-tour.html" title="Google Apps EMEA Developer Tour (continued)" /><author><name>Google Apps Developer Blog Editor</name><uri>http://www.blogger.com/profile/07808045840831274565</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>0</thr:total><feedburner:origLink>http://googleappsdeveloper.blogspot.com/2012/01/google-apps-emea-developer-tour.html</feedburner:origLink></entry><entry gd:etag="W/&quot;C0cFQ3Y7fyp7ImA9WhRVGU4.&quot;"><id>tag:blogger.com,1999:blog-1377183911445147227.post-645475526053634190</id><published>2012-01-18T13:55:00.000-08:00</published><updated>2012-01-18T15:56:52.807-08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2012-01-18T15:56:52.807-08:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Google Calendar API" /><title>Calendar API v3 Best Practices: Reminders</title><content type="html">&lt;p&gt;We recently posted some best practices for working with recurring events in Google Calendar API v3. In this blog post we’ll highlight another improved area in the v3 API: event reminders.&lt;/p&gt;

&lt;h2&gt;Reminders&lt;/h2&gt;

&lt;p&gt;Google Calendar API v3 offers developers flexible control over event reminders, including per-calendar default settings and custom overrides for individual events.&lt;/p&gt;

&lt;p&gt;The user’s default reminders for events on a given calendar can be found in the corresponding entry in the Calendar List collection. The Calendar List collection acts a bit like a list of bookmarks, containing entries for the calendars that the user owns or has looked at in the past (it corresponds to the content of the "My Calendars" and "Other Calendars" list on the bottom left in the Web version of Google Calendar). Each entry is annotated with user-specific settings for the individual calendar, such as the preferred color in the UI and the default reminders.&lt;/p&gt;

&lt;p&gt;Google Calendar currently supports three ways of reminding its users of events: "popup", prompting a message directly in the browser, mobile phone or desktop client, as well as "email" and "sms" for messages sent through the respective channels. To change the defaults, update the Calendar List entry and include the reminder method and how many minutes in advance the user should be alerted. In the following example, we set an email reminder to be sent 60 minutes before an event, and a popup reminder 10 minutes before.&lt;/p&gt;

&lt;pre class="prettyprint lang-js"&gt;{
 "summary": "Work Calendar",
 ...
 "defaultReminders": [
   {
     "method": "email",
     "minutes": 60
   },
   {
     "method": "popup",
     "minutes": 10
   }
 ]
}&lt;/pre&gt;

&lt;center&gt;&lt;i&gt;A Calendar List entry with title and default reminders.&lt;/i&gt;&lt;/center&gt;

&lt;p&gt;The default reminders will be applied to all existing and future events on this calendar, provided they don’t have custom reminders set already. In contrast to earlier versions of the API, newly created events will also have reminders set by default.&lt;/p&gt;

&lt;p&gt;Sometimes, there are events that we want a special reminder for, or none at all. To override the defaults for a specific event, switch the &lt;code&gt;useDefault&lt;/code&gt; flag in the &lt;code&gt;reminders&lt;/code&gt; section to &lt;code&gt;false&lt;/code&gt;, and include a set of custom reminders, or leave the list empty. When you define a set of override reminders for a recurring series, they are automatically applied to each of its occurrences, unless they have been overridden explicitly. Like the default reminders on the calendar, these are personal reminders for the user that is logged in, and will not influence the settings others might have for the same calendar or event.  Here is an example that overrides the default reminders with a 15 minute SMS reminder for that specific event.&lt;/p&gt;

&lt;pre class="prettyprint lang-js"&gt;{
 "summary": "API Office Hours",
 ...
 "reminders": {
   "useDefault": false,
   "overrides": [
     {
       "method": "sms",
       "minutes": 15
     }
   ]
 }
}&lt;/pre&gt;

&lt;center&gt;&lt;i&gt;An event representation with title and reminder overrides.&lt;/i&gt;&lt;/center&gt;

&lt;p&gt;The defaults for the given calendar are included at the top of any event listing result. This way, reminder settings for all events in the result can be determined by the client without having to make the additional API call to the corresponding entry in the Calendar List collection.&lt;/p&gt;

&lt;p&gt;In this post and an &lt;link&gt;earlier post about best practices with recurring events&lt;/link&gt;, we have covered some improved areas of the latest version of the Google Calendar API. Have a look at the &lt;a href="http://code.google.com/apis/calendar/v3/migration_guide.html"&gt;migration guide&lt;/a&gt; for a more complete view of other changes we made in the new version, and let us know what you think.&lt;/p&gt;

&lt;p&gt;If you have any questions about handling reminders or other features of the new Calendar API, post them on the &lt;a href="http://code.google.com/apis/calendar/community/forum.html"&gt;Calendar API forum&lt;/a&gt;.&lt;/p&gt;

&lt;br /&gt;&lt;table cellpadding="5" cellspacing="0"&gt;&lt;tbody&gt;&lt;tr style="background-color: #f2f2f2;"&gt;&lt;td&gt;&lt;img class="profile" src="http://1.bp.blogspot.com/-_FQ5XomCjpw/TuI5FxjR9-I/AAAAAAAAAV4/UKg5HiFmTcs/s400/image01.jpg" /&gt;&lt;/td&gt;&lt;td valign="top"&gt;&lt;span class="largefont"&gt;Peter Lundblad&lt;/span&gt; &amp;nbsp;  &lt;a class="alt" href="http://plus.google.com/104780772893555468975" rel="me" target="_blank"&gt;profile&lt;/a&gt; 
&lt;br /&gt;&lt;div class="bio"&gt;
&lt;br /&gt;Peter joined Google in 2006.  He's been leading the Calendar API team for the last 2 years. He's previously worked on video uploads for YouTube.&lt;/div&gt;
&lt;br /&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;

&lt;br /&gt;&lt;table cellpadding="5" cellspacing="0"&gt;&lt;tbody&gt;&lt;tr style="background-color: #f2f2f2;"&gt;&lt;td&gt;&lt;img class="profile" src="http://2.bp.blogspot.com/-_Khy5lbHDWA/TuI5d7WabOI/AAAAAAAAAWE/i5QKiVnk2YU/s400/image00.png" /&gt;&lt;/td&gt;&lt;td valign="top"&gt;&lt;span class="largefont"&gt;Fabian Schlup&lt;/span&gt; &amp;nbsp;  &lt;a class="alt" href="http://www.google.com/profiles/fschlup" rel="me" target="_blank"&gt;profile&lt;/a&gt; 
&lt;br /&gt;&lt;div class="bio"&gt;
&lt;br /&gt;Fabian is a Software Engineer at Google in Zürich, working on Calendar and Tasks, with a focus on APIs.&lt;/div&gt;
&lt;br /&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1377183911445147227-645475526053634190?l=googleappsdeveloper.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/GoogleAppsDeveloperBlog/~4/ImYB_9ragz8" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://googleappsdeveloper.blogspot.com/feeds/645475526053634190/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=1377183911445147227&amp;postID=645475526053634190&amp;isPopup=true" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/1377183911445147227/posts/default/645475526053634190?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/1377183911445147227/posts/default/645475526053634190?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/GoogleAppsDeveloperBlog/~3/ImYB_9ragz8/calendar-api-v3-best-practices.html" title="Calendar API v3 Best Practices: Reminders" /><author><name>Google Apps Developer Blog Editor</name><uri>http://www.blogger.com/profile/07808045840831274565</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://1.bp.blogspot.com/-_FQ5XomCjpw/TuI5FxjR9-I/AAAAAAAAAV4/UKg5HiFmTcs/s72-c/image01.jpg" height="72" width="72" /><thr:total>0</thr:total><feedburner:origLink>http://googleappsdeveloper.blogspot.com/2012/01/calendar-api-v3-best-practices.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CEcDQn44fCp7ImA9WhRWF0w.&quot;"><id>tag:blogger.com,1999:blog-1377183911445147227.post-3690778472751207005</id><published>2012-01-04T11:05:00.000-08:00</published><updated>2012-01-04T13:21:13.034-08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2012-01-04T13:21:13.034-08:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Apps Script" /><category scheme="http://www.blogger.com/atom/ns#" term="Guest Post" /><title>Fun with Apps Script at the Google Apps Developer Hackathon in NYC</title><content type="html">&lt;p&gt;&lt;b&gt;Editor’s Note:&lt;/b&gt;&lt;i&gt;This is a guest post from John Watkinson.  John is a developer and the co-founder of &lt;a href="http://docracy.com"&gt;Docracy&lt;/a&gt;, a start-up company that hosts crowd-sourced legal documents and provides free e-signing services. He recently attended, and won first place, at the Google Apps Hackathon in NYC.  Here's John's story about the event.&lt;/i&gt;&lt;/p&gt;

&lt;p&gt;Our company is focused on documents in the cloud, so we attended the Google Apps Developer Hackathon on December 1st in New York City to learn more about the various Google Apps APIs, and how we can best integrate with them. During the initial presentations from Ryan Boyd and Saurabh Gupta of the Google Apps team, we were delighted to learn about &lt;a href="http://code.google.com/googleapps/appsscript/"&gt;Apps Script&lt;/a&gt;. It provides a powerful JavaScript interface into Google Apps, including &lt;a href="http://code.google.com/googleapps/appsscript/service_document.html"&gt;Docs&lt;/a&gt;, &lt;a href="http://code.google.com/googleapps/appsscript/service_calendar.html"&gt;Calendar&lt;/a&gt;, &lt;a href="http://code.google.com/googleapps/appsscript/service_gmail.html"&gt;Gmail&lt;/a&gt;, &lt;a href="http://code.google.com/googleapps/appsscript/service_maps.html"&gt;Maps&lt;/a&gt; and many others.&lt;/p&gt;
&lt;p/&gt;
&lt;h3&gt;Hack #1: “The Wolf”&lt;/h3&gt;
&lt;p&gt;After the tech presentations, we formed teams and started hacking with the technology. I joined a team with Matt Hall (also from Docracy), Nick Siderakis, Jeff Hsin and Scott Thompson. We struck upon the idea of creating a function that would make calls to &lt;a href="http://www.wolframalpha.com/"&gt;Wolfram Alpha&lt;/a&gt; via their &lt;a href="http://products.wolframalpha.com/api/"&gt;developer API&lt;/a&gt;. It took all five of us hacking away for a few hours to parse the Alpha results properly, but eventually we had an Apps Script custom function for Spreadsheet called “wolf”. It had a kind of magic feeling about it, as you could pass simple English-language queries into the function and get back exact numeric results in your Google Spreadsheet. Some example working queries:&lt;/p&gt;
&lt;ul style="list-style: none;"&gt;
  &lt;li&gt;&lt;code&gt;=wolf("distance from the earth to the moon in km")&lt;/code&gt; &lt;em&gt;Answer: 403,778km&lt;/em&gt;&lt;/li&gt;
  &lt;li&gt;&lt;code&gt;=wolf("population of canada in 1960")&lt;/code&gt; &lt;em&gt;Answer: 17.9 million&lt;/em&gt;&lt;/li&gt;
  &lt;li&gt;&lt;code&gt;=wolf("average january temperature in buenos aires")&lt;/code&gt; &lt;em&gt;Answer: 64F&lt;/em&gt;&lt;/li&gt;
  &lt;li&gt;&lt;code&gt;=wolf("9th digit of pi")&lt;/code&gt; &lt;em&gt;Answer: 5&lt;/em&gt;&lt;/li&gt;
  &lt;li&gt;&lt;code&gt;=wolf("count of olympic medals won by japan in 2008")&lt;/code&gt; &lt;em&gt;Answer: 25&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Any function in Apps Script can be used as a spreadsheet function directly, so our main &lt;code&gt;wolf&lt;/code&gt; function is the entry point to our script. We use Apps Script’s &lt;code&gt;UrlFetch&lt;/code&gt; service to make our API call to Wolfram Alpha (note, the full URL is truncated for brevity):&lt;/p&gt;
&lt;pre class="prettyprint"&gt;
var response = UrlFetchApp.fetch("http://api.wolframalpha.com/..." +
  encodeURIComponent(input));
&lt;/pre&gt;
&lt;p&gt;The response from Alpha is an XML file that includes a lot of metadata we don’t need. So, we used a recursive function and the XML manipulation tools in Apps Script to track down the element of interest to us (below is a simplified version):&lt;/p&gt;
&lt;pre class="prettyprint"&gt;
function findText(e) {
  if (e.getName().getLocalName() == 'plaintext') {
    return e.getText();
  } else {
    var children = e.getElements();
    for (var i = 0; i &lt; children.length; i++) {
      var result = findText(children[i]);
      if (result) return result;
    }
    return null;
  }
}
&lt;/pre&gt;
&lt;p&gt;A little bit more work is required to parse the result, as sometimes Alpha will report numbers in words (i.e. “40.7 million”), but otherwise that’s it!&lt;p&gt;
&lt;p&gt;For a small script, it definitely feels pretty powerful! Our little invention earned us a first place finish at the hackathon, and the prizes were little indoor RC-controlled helicopters. I managed to irreparably damage mine in a gruesome crash into my refrigerator already, but I hear that many of the others are still serviceable and flying missions daily.&lt;/p&gt;
&lt;p/&gt;
&lt;h3&gt;Hack #2: Sheet Sweeper&lt;/h3&gt;
&lt;p&gt;Once we were comfortable with the &lt;a href="http://code.google.com/googleapps/appsscript/defaultservices.html"&gt;Apps Script Services&lt;/a&gt; (and aware of its capabilities with spreadsheets in particular), a side project emerged that used some of the other integration features available. Apps Script functions can listen for events that are triggered by the editing of a spreadsheet cell (if the user grants the appropriate permissions). Using these onEdit &lt;a href="http://code.google.com/googleapps/appsscript/guide_events.html"&gt;Event Handlers&lt;/a&gt;, we wrote an implementation of the classic game Mine Sweeper that is playable right in the spreadsheet!&lt;/p&gt;
&lt;p/&gt;
&lt;div class="separator" style="text-align: center;"&gt;
&lt;a href="http://3.bp.blogspot.com/-Yo90FgfFcD4/TwSgzwiV3_I/AAAAAAAAAZQ/gtouyS7WOzw/s1600/image00.png" imageanchor="1" style="margin-left:1em; margin-right:1em"&gt;&lt;img border="0" width="400" src="http://3.bp.blogspot.com/-Yo90FgfFcD4/TwSgzwiV3_I/AAAAAAAAAZQ/gtouyS7WOzw/s500/image00.png" /&gt;&lt;/a&gt;
&lt;div&gt;&lt;a href="http://www.youtube.com/watch?v=4Y4mfD-Jog0"&gt;Watch on YouTube&lt;/a&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;You can play the game by making a copy of &lt;a href="https://docs.google.com/a/google.com/spreadsheet/ccc?key=0Ap2tXBYlw7QmdEg3SVUwSXFXVDNKcGloY0JLcERlZ0E#gid=0"&gt;this spreadsheet&lt;/a&gt; and then clicking the menu item SheetSweeper &amp;gt; New Game. When you play the game, the script responds to onEdit events that are dispatched from the spreadsheet.&lt;/p&gt;
&lt;pre class="prettyprint"&gt;
function onOpen() {
  var ss = SpreadsheetApp.getActiveSpreadsheet();
  var menuEntries = [{name: "New Game", functionName: "startGame"}];
  ss.addMenu("SheetSweeper", menuEntries);
}
&lt;/pre&gt;

&lt;p&gt;Then when the user edits a cell, the script responds and implements the mine sweeper logic:&lt;/p&gt;

&lt;pre class="prettyprint"&gt;
function onEdit(event) {
  var ss = event.source.getActiveSheet();
  var cell = ss.getActiveCell();
  if (cell.getValue() == 'x') {
    // Flagging a mine
    flagCell(cell);
  } else {
    // Clearing a cell
    clearCell(cell);
  }  
}
&lt;/pre&gt;

&lt;p&gt;We had a great time at the hackathon, and are happy to have been introduced to Apps Script. We believe it has an exciting future ahead of it.&lt;p&gt;


&lt;p /&gt;&lt;table cellpadding="5" cellspacing="0"&gt;&lt;tbody&gt;&lt;tr style="background-color: #f2f2f2;"&gt;&lt;td&gt;&lt;img style="width:90px;" width="90px" class="profile" src="https://lh3.googleusercontent.com/-t3OszVpHgzw/AAAAAAAAAAI/AAAAAAAABD4/G89QRX-Wpqw/s200-c-k/photo.jpg" /&gt;&lt;/td&gt;&lt;td valign="top"&gt;&lt;span class="largefont"&gt;John Watkinson&lt;/span&gt; &amp;nbsp;   &lt;a class="alt" href="https://plus.google.com/u/0/103808128853828210342/" rel="me" target="_blank"&gt;profile&lt;/a&gt;
&lt;br /&gt;&lt;div class="bio"&gt;
&lt;br /&gt;John is a developer and the co-founder of &lt;a href="http://docracy.com"&gt;Docracy&lt;/a&gt;, a start-up company that hosts crowd-sourced legal documents and provides free e-signing services. He previously co-founded the mobile development shop &lt;a href="http://larvalabs.com"&gt;Larva Labs&lt;/a&gt;, which developed the popular &lt;a href="http://androidify.com"&gt;Androidify&lt;/a&gt; app with the Google Creative Lab.
&lt;/div&gt;
&lt;br /&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1377183911445147227-3690778472751207005?l=googleappsdeveloper.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/GoogleAppsDeveloperBlog/~4/faMc9HzGlQA" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://googleappsdeveloper.blogspot.com/feeds/3690778472751207005/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=1377183911445147227&amp;postID=3690778472751207005&amp;isPopup=true" title="4 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/1377183911445147227/posts/default/3690778472751207005?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/1377183911445147227/posts/default/3690778472751207005?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/GoogleAppsDeveloperBlog/~3/faMc9HzGlQA/fun-with-apps-script-at-google-apps.html" title="Fun with Apps Script at the Google Apps Developer Hackathon in NYC" /><author><name>Google Apps Developer Blog Editor</name><uri>http://www.blogger.com/profile/07808045840831274565</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://3.bp.blogspot.com/-Yo90FgfFcD4/TwSgzwiV3_I/AAAAAAAAAZQ/gtouyS7WOzw/s72-c/image00.png" height="72" width="72" /><thr:total>4</thr:total><feedburner:origLink>http://googleappsdeveloper.blogspot.com/2012/01/fun-with-apps-script-at-google-apps.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DEANQ3c6fCp7ImA9WhRWFkw.&quot;"><id>tag:blogger.com,1999:blog-1377183911445147227.post-1192278272237522131</id><published>2012-01-03T10:37:00.000-08:00</published><updated>2012-01-03T10:53:12.914-08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2012-01-03T10:53:12.914-08:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Administrative APIs" /><category scheme="http://www.blogger.com/atom/ns#" term="Google Calendar API" /><title>Automatically setting a vacation responder from a calendar event</title><content type="html">&lt;p&gt;Are you ever at an airport with no internet access, and realize that you forgot to set your "Out of Office" (OOO) message?" I forget regularly, but always remember to block off my calendar. Why not have the calendar automatically update my OOO message? We can! With the Calendar API, we can retrieve calendar events and set a vacation responder for the event duration for any user in the domain using the Email Settings API.&lt;p&gt;

&lt;p&gt;The first step is to authorize the Calendar and Email Settings client to make any call to the APIs respectively. The new Calendar API requires &lt;a href="http://code.google.com/p/google-api-python-client/source/checkout"&gt;google-api-client&lt;/a&gt; library while the Email settings API still works with the &lt;a href="http://code.google.com/p/gdata-python-client/source/checkout"&gt;gdata-client&lt;/a&gt; library in Python. These libraries use different underlying protocols and handle authorization differently.&lt;p&gt;

&lt;p&gt;Fortunately we can use the same code to get an OAuth 2.0 token for both the &lt;a href="http://code.google.com/apis/calendar/v3/using.html"&gt;Calendar API&lt;/a&gt; and the &lt;a href="http://code.google.com/googleapps/domain/email_settings/developers_guide_protocol.html"&gt;Email Settings API&lt;/a&gt;.&lt;/p&gt;

&lt;pre class="prettyprint"&gt;
from oauth2client.file import Storage
from oauth2client.client import AccessTokenRefreshError
from oauth2client.client import OAuth2WebServerFlow
from oauth2client.tools import run

SCOPES = ('https://www.googleapis.com/auth/calendar '
     'https://apps-apis.google.com/a/feeds/emailsettings/2.0/')

FLOW = flow_from_clientsecrets('client_secrets.json', scope=SCOPES)

storage = Storage('vacation.dat')
credentials = storage.get()
if credentials is None or credentials.invalid:
    credentials = run(FLOW, storage)
&lt;/pre&gt;

&lt;p&gt;Now that we have obtained the OAuth 2.0 token from OAuth2WebServerFlow, we can use it in either library. To authorize the Calendar service:&lt;/p&gt;

&lt;pre class="prettyprint"&gt;
# Create an httplib2.Http object to handle the HTTP 
# requests and authorize it with our good Credentials.

http = httplib2.Http()
http = credentials.authorize(http)

# Build authorized service for Calendar API
service = build('calendar', 'v3', http=http)
&lt;/pre&gt;

&lt;p&gt;Authorizing the Email Settings client requires adapting the credentials:&lt;/p&gt;

&lt;pre class="prettyprint"&gt;
auth2token = gdata.gauth.OAuth2Token(client_id=client_id,
  client_secret=client_secret,
  scope=SCOPE,
  access_token=credentials.access_token,
  refresh_token=credentials.refresh_token,
  user_agent='vacation-responder-sample/1.0')

email_client = auth2token.authorize(
  gdata.apps.emailsettings.client.EmailSettingsClient(
    domain=domain))
&lt;/pre&gt;

&lt;p&gt;Now its time to update the vacation responder based on calendar event using the authorized client. Lets query for events containing the string ‘vacation’ from the Calendar API. The following code snippet shows the retrieval of events.&lt;/p&gt;

&lt;pre class="prettyprint"&gt;
# Convert the date to the RFC 3339 timestamp format
# for Calendar API.
cur_datetime = datetime.datetime.now()
cur_date = cur_datetime.strftime('%Y-%m-%dT%H:%M:%SZ')

events = service.events().list(calendarId=username,
      q='vacation', timeMin=cur_date, singleEvents=True,
      orderBy='startTime').execute()
&lt;/pre&gt;

&lt;p&gt;By specifying a user’s email address as the calendarID, we can query against any primary calendars in our domain that are shared and readable by the administrator.  If the user opts to hide their calendar, we won’t find any of their events.  For additional details about the query on calendar events, refer to  the ca&lt;a href="http://code.google.com/apis/calendar/v3/using.html#api_params"&gt;lendar query parameters&lt;/a&gt; from the reference guide.&lt;/p&gt;

&lt;p&gt;Next we can obtain the start and end time of the event and &lt;a href="http://code.google.com/googleapps/domain/email_settings/developers_guide_protocol.html#GA_email_vacation_main"&gt;update the vacation responder&lt;/a&gt; using the Email Settings client if the event’s duration is day long or more.&lt;/p&gt;

&lt;pre class="prettyprint"&gt;
if 'items' in events:
  for event in events['items']:
    startDate = event['start']
    endDate = event['end']
    # If event is set for the day not just for a time slot.
    if 'date' in startDate:
      email_client.UpdateVacation(username=username,
            enable=True,
            subject='Out of office', 
            message='If urgent call me.',
            domain_only=True, 
            start_date=startDate['date'],
            end_date=endDate['date'])
      print '\nVacation responder set for the days between %s to %s'  % 
            (startDate['date'], endDate['date'])
      break
&lt;/pre&gt;

&lt;p&gt;You can &lt;a href="http://code.google.com/p/google-vacation-responder-demo/source/browse/vacation_responder.py"&gt;download the sample&lt;/a&gt; and build your own application on top of it. We hope that this sample makes it easier to get started, particularly for apps that need to combine APIs from the two API clients. Please feel free to reach us in the &lt;a href="http://code.google.com/googleapps/support/domain_info_and_management_forum.html"&gt;Google Domain Info and Management Forum&lt;/a&gt; with any questions you have or write us feedback on this post.&lt;/p&gt;

&lt;p /&gt;&lt;table cellpadding="5" cellspacing="0"&gt;&lt;tbody&gt;&lt;tr style="background-color: #f2f2f2;"&gt;&lt;td&gt;&lt;img class="profile" src="http://sites.google.com/site/developeradvocates/image/shraddha_gupta.png" /&gt;&lt;/td&gt;&lt;td valign="top"&gt;&lt;span class="largefont"&gt;Shraddha Gupta&lt;/span&gt; &amp;nbsp;   &lt;a class="alt" href="https://plus.google.com/114165026575240989729/about" rel="me" target="_blank"&gt;profile&lt;/a&gt;
&lt;br /&gt;&lt;div class="bio"&gt;
&lt;br /&gt;Shraddha is a Developer Programs Engineer for Google Apps. She has her MTech in Computer Science and Engineering from IIT Delhi, India.
&lt;/div&gt;
&lt;br /&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1377183911445147227-1192278272237522131?l=googleappsdeveloper.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/GoogleAppsDeveloperBlog/~4/EHuZ4IP3be4" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://googleappsdeveloper.blogspot.com/feeds/1192278272237522131/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=1377183911445147227&amp;postID=1192278272237522131&amp;isPopup=true" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/1377183911445147227/posts/default/1192278272237522131?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/1377183911445147227/posts/default/1192278272237522131?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/GoogleAppsDeveloperBlog/~3/EHuZ4IP3be4/automatically-setting-vacation.html" title="Automatically setting a vacation responder from a calendar event" /><author><name>Google Apps Developer Blog Editor</name><uri>http://www.blogger.com/profile/07808045840831274565</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>0</thr:total><feedburner:origLink>http://googleappsdeveloper.blogspot.com/2012/01/automatically-setting-vacation.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CU8CQ3gzcSp7ImA9WhRWEUU.&quot;"><id>tag:blogger.com,1999:blog-1377183911445147227.post-1600058305066268242</id><published>2011-12-28T13:43:00.000-08:00</published><updated>2011-12-29T10:37:42.689-08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-12-29T10:37:42.689-08:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Marketplace" /><title>Improved Customer Engagement &amp; Discovery in the Google Apps Marketplace</title><content type="html">&lt;p&gt;We recently updated the &lt;a href="http://www.google.com/enterprise/marketplace"&gt;Google Apps Marketplace&lt;/a&gt; with several new features to help developers better engage with their customers and improve discoverability of apps in the marketplace.&lt;/p&gt;
&lt;p/&gt;
&lt;h3&gt;Reply to Comments &amp; Reviews&lt;/h3&gt;
&lt;p&gt;It’s no secret that &lt;a href="http://googleappsdeveloper.blogspot.com/2011/09/finding-success-on-google-apps.html"&gt;engaging your customers&lt;/a&gt; and responding to their feedback is critical to success.  It’s now possible to engage in conversations with customers based on comments &amp; reviews for your app in the marketplace.&lt;/p&gt;
&lt;p style="text-align: center;"&gt;
&lt;a href="http://2.bp.blogspot.com/-n8inMM0-waI/TvuM8-6R1aI/AAAAAAAAAYs/_Fgx0tqwvDs/s1600/image00.jpg" imageanchor="1" style="margin-left:1em; margin-right:1em"&gt;&lt;img border="0" width="500" src="http://2.bp.blogspot.com/-n8inMM0-waI/TvuM8-6R1aI/AAAAAAAAAYs/_Fgx0tqwvDs/s540/image00.jpg" /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p/&gt;
&lt;h3&gt;Rich Application Snippets in Google Search&lt;/h3&gt;
&lt;p&gt;Google Search recently introduced &lt;a href="http://googlewebmastercentral.blogspot.com/2011/09/introducing-application-rich-snippets.html"&gt;rich snippets for applications&lt;/a&gt; several months ago with 
enhanced search results for applications from marketplaces like &lt;a href="http://market.android.com"&gt;Android Market&lt;/a&gt; and others.  Marketplace apps will soon be appearing as rich snippets with ratings and pricing details.&lt;/p&gt;
&lt;p style="text-align: center;"&gt;
&lt;a href="http://1.bp.blogspot.com/-NohT_qV2JIQ/TvuNBEXnDkI/AAAAAAAAAY4/OYFsHCcHG5k/s1600/image01.jpg" imageanchor="1" style="margin-left:1em; margin-right:1em"&gt;&lt;img border="0" width="500" src="http://1.bp.blogspot.com/-NohT_qV2JIQ/TvuNBEXnDkI/AAAAAAAAAY4/OYFsHCcHG5k/s540/image01.jpg" /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p/&gt;
&lt;h3&gt;New Category Home Pages&lt;/h3&gt;
&lt;p&gt;Lastly, we introduced new home pages for each category in the Marketplace to feature the top installed and newest apps for that category.&lt;/p&gt;

&lt;p style="text-align: center;"&gt;
&lt;a href="http://1.bp.blogspot.com/-mmezUHpkUeA/TvuNEpwJccI/AAAAAAAAAZE/ojgPcF7MPJk/s1600/image02.jpg" imageanchor="1" style="margin-left:1em; margin-right:1em"&gt;&lt;img border="0" width="500" src="http://1.bp.blogspot.com/-mmezUHpkUeA/TvuNEpwJccI/AAAAAAAAAZE/ojgPcF7MPJk/s540/image02.jpg" /&gt;&lt;/a&gt;&lt;/p&gt;


&lt;p&gt;We hope that you find value in these changes and wish everyone a happy new year!&lt;/p&gt;

&lt;table cellpadding="5" cellspacing="0"&gt;&lt;tbody&gt;&lt;br /&gt;&lt;tr style="background-color: #f2f2f2;"&gt;&lt;td&gt;&lt;img class="profile" src="http://sites.google.com/site/developeradvocates/image/steve_bazyl.png" /&gt;&lt;/td&gt;&lt;td valign="top"&gt;&lt;span class="largefont"&gt;Steven Bazyl&lt;/span&gt;  &amp;nbsp; &lt;a class="alt" href="https://plus.google.com/103354693083460731603/" rel="me" target="_blank"&gt;profile&lt;/a&gt; | &lt;a class="alt" href="http://twitter.com/stevenbazyl" rel="me" target="_blank"&gt;twitter&lt;/a&gt; | &lt;a class="alt" href="http://code.google.com/events/#&amp;speaker=sbazyl"&gt;events&lt;/a&gt;&lt;br /&gt;&lt;div class="bio"&gt;&lt;br /&gt;Steve is a Developer Advocate for Google Apps and the Google Apps Marketplace.  He enjoys helping developers find ways to integrate their apps and bring added value to users.&lt;/div&gt;&lt;br /&gt;&lt;/td&gt;&lt;/tr&gt;&lt;br /&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1377183911445147227-1600058305066268242?l=googleappsdeveloper.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/GoogleAppsDeveloperBlog/~4/jGks2IFXPJk" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://googleappsdeveloper.blogspot.com/feeds/1600058305066268242/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=1377183911445147227&amp;postID=1600058305066268242&amp;isPopup=true" title="3 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/1377183911445147227/posts/default/1600058305066268242?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/1377183911445147227/posts/default/1600058305066268242?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/GoogleAppsDeveloperBlog/~3/jGks2IFXPJk/improved-customer-engagement-discovery.html" title="Improved Customer Engagement &amp; Discovery in the Google Apps Marketplace" /><author><name>Google Apps Developer Blog Editor</name><uri>http://www.blogger.com/profile/07808045840831274565</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://2.bp.blogspot.com/-n8inMM0-waI/TvuM8-6R1aI/AAAAAAAAAYs/_Fgx0tqwvDs/s72-c/image00.jpg" height="72" width="72" /><thr:total>3</thr:total><feedburner:origLink>http://googleappsdeveloper.blogspot.com/2011/12/improved-customer-engagement-discovery.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DEYGQno8eSp7ImA9WhRWEU0.&quot;"><id>tag:blogger.com,1999:blog-1377183911445147227.post-1606921859123168882</id><published>2011-12-28T11:00:00.000-08:00</published><updated>2011-12-28T13:02:03.471-08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-12-28T13:02:03.471-08:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Apps Script" /><title>2011 - A year of features, use cases and developers of Apps Script</title><content type="html">&lt;p&gt;2011 was the year of momentum for &lt;a href="http://code.google.com/googleapps/appsscript/"&gt;Google Apps Script&lt;/a&gt;. As 2012 dawns upon us, let us take a moment to reflect on the past year.&lt;/p&gt;

&lt;p&gt;We started 2011 with a bang! In January we released &lt;a href="http://googleappsscript.blogspot.com/2011/02/apps-scripts-new-debugger-improved.html"&gt;a cloud-based Debugger into&lt;/a&gt; Apps Script’s IDE that proved to be very useful for developers. The Script Editor was upgraded bringing about many features and bug fixes. In March we implemented a very powerful feature of embedding &lt;a href="http://googleappsscript.blogspot.com/2011/03/build-applications-in-sites-using-apps.html"&gt;Apps Script in Google Sites pages as Gadgets&lt;/a&gt;, making it easy to enhance Sites in amazing ways. We also improved Contacts Services, making it more stable with an improved API.&lt;/p&gt;

&lt;p&gt;At &lt;a href="http://www.google.com/events/io/2011/index-live.html"&gt;Google I/O&lt;/a&gt; in May we launched &lt;a href="http://googleappsdeveloper.blogspot.com/2011/06/gmail-and-document-services-now.html"&gt;Document Services, Gmail Services&lt;/a&gt; and the drag ‘n’ drop &lt;a href="http://googleappsdeveloper.blogspot.com/2011/06/building-ui-in-apps-script-just-got.html"&gt;GUI Builder&lt;/a&gt;. These were major steps forward in making sure that Apps Script provides a full set of APIs to allow developers to build rich workflow and automation solutions.&lt;/p&gt;

&lt;p&gt;We were very busy during the summer months preparing for a series of launch for later part of 2011. In September, we launched &lt;a href="http://googleappsdeveloper.blogspot.com/2011/09/visualize-your-data-charts-in-google.html"&gt;Charts Services&lt;/a&gt;.  It allows users to dynamically create Charts and embed them in emails, UiApp or export as images. We also released three Google API services for &lt;a href="http://googlecode.blogspot.com/2011/09/three-new-apis-for-google-apps-script.html"&gt;Prediction, UrlShortener and Tasks APIs&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="http://googleappsdeveloper.blogspot.com/2011/10/concurrency-and-google-apps-script.html"&gt;Lock&lt;/a&gt; and &lt;a href="http://googleappsdeveloper.blogspot.com/2011/11/caching-in-cloud-with-google-script.html"&gt;Cache&lt;/a&gt; Services launched in October. These services are important for building performant and scalable applications. We also improved the Script Editor by adding Project Support and made other UI improvements. November brought about the launch of &lt;a href="http://googleappsdeveloper.blogspot.com/2011/11/creating-more-responsive-applications.html"&gt;Client Handlers and Validators&lt;/a&gt;. This is only the beginning of our commitment to allow developers to build more advanced UI using Apps Script.&lt;/p&gt; 

&lt;p&gt;In December we continued to improve the reliability and stability of Apps Script runtime. We capped the year by releasing &lt;a href="http://googleappsdeveloper.blogspot.com/2011/12/google-groups-and-google-apps-script.html"&gt;Groups&lt;/a&gt; and &lt;a href="http://googleappsdeveloper.blogspot.com/2011/12/domain-user-management-with-apps-script.html"&gt;Domain&lt;/a&gt; Services. And who can forget the very useful &lt;a href="http://googleappsdeveloper.blogspot.com/2011/12/introducing-adsense-management-services.html"&gt;AdSense Services&lt;/a&gt; for AdSense advertisers!&lt;/p&gt;

&lt;p&gt;Throughout the year we expanded our outreach channels. There were Apps Script sessions at Google I/O and Bootcamp, and several attendees got their last minute tickets through the &lt;a href="http://googleappsscript.blogspot.com/2011/03/last-call-for-google-io-google-apps.html"&gt;Apps Script I/O challenge&lt;/a&gt;. We were at &lt;a href="http://www.google.com/events/developerday/2011/"&gt;Google Developer Day&lt;/a&gt; and &lt;a href="http://code.google.com/events/devfests/2011/index.html"&gt;DevFest&lt;/a&gt; events, met with GTUGs, and hosted &lt;a href="http://apps-dev-tour.appspot.com/"&gt;hackathons&lt;/a&gt; throughout the world. Our blog also featured scripts like Revevol’s &lt;a href="http://googleenterprise.blogspot.com/2011/03/improving-revevols-productivity-with.html"&gt;Trainer Finder&lt;/a&gt;, Corey’s &lt;a href="http://googleappsdeveloper.blogspot.com/2011/07/gmail-snooze-with-apps-script.html"&gt;Gmail Snooze&lt;/a&gt;, Dave’s Flubaroo, Top Contributor’s &lt;a href="http://googleappsdeveloper.blogspot.com/2011/10/4-ways-to-do-mail-merge-using-google.html"&gt;Mail Merge&lt;/a&gt;, Saqib’s &lt;a href="http://googleappsdeveloper.blogspot.com/2011/09/building-idea-bank-using-google-apps.html"&gt;Idea Bank&lt;/a&gt;, and Drew’s &lt;a href="http://googleappsdeveloper.blogspot.com/2011/10/calorie-counting-with-google-apps.html"&gt;Calorie Counting&lt;/a&gt; that showed the power of Apps Script.&lt;/p&gt;

&lt;p&gt;Recently we started Office Hours in G+ hangout. These hangouts proved to be very popular, personal and effective means to share ideas with Apps Script community.  Join us some day!&lt;/p&gt;

&lt;p&gt;In our efforts to help educators, we worked with &lt;a href="http://gothamschools.org/2011/12/21/a-queens-school-finds-opportunity-in-googles-education-apps/"&gt;a New York city school&lt;/a&gt; to help them make most out of Google Apps. We also hosted many EDU focused webinars and workshops.  In great Google tradition, Apps Script team participated in &lt;a href="http://www.google.com/edu/cape/"&gt;CAPE&lt;/a&gt; and &lt;a href="http://googleblog.blogspot.com/2011/06/googleserve-2011-giving-back-around.html"&gt;Google Serve&lt;/a&gt;.&lt;/p&gt; 

&lt;p&gt;2012 is going to be an even more exciting and promising year. Tighten your seat belts because we intend to keep firing on all cylinders!&lt;/p&gt;
&lt;table cellpadding="5" cellspacing="0"&gt;&lt;tbody&gt;&lt;br /&gt;&lt;tr style="background-color: #f2f2f2;"&gt;&lt;td&gt;&lt;img class="profile" src="http://3.bp.blogspot.com/-AfmuFkbdBJQ/TjHzJVAWTXI/AAAAAAAAAMo/xVhok61rw7I/s400/Google%2BChromeScreenSnapz157.png"" /&gt;&lt;/td&gt;&lt;td valign="top"&gt;&lt;span class="largefont"&gt;Saurabh Gupta&lt;/span&gt;   &lt;a class="alt" href="https://profiles.google.com/sg1705" rel="me" target="_blank"&gt;profile&lt;/a&gt; | &lt;a class="alt" href="http://twitter.com/#gluemesh" rel="me" target="_blank"&gt;twitter&lt;/a&gt; | &lt;a class="alt" href="http://www.gluemesh.com/" rel="me" target="_blank"&gt;blog&lt;/a&gt;&lt;br /&gt;&lt;div class="bio"&gt;&lt;br /&gt;Saurabh is a Developer Programs Engineer at Google. He works closely with Google Apps Script developers to help them extend Google Apps. Over the last 10 years, he has worked in the financial services industry in different roles. His current mission is to bring automation and collaboration to Google Apps users.&lt;/div&gt;&lt;br /&gt;&lt;/td&gt;&lt;/tr&gt;&lt;br /&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1377183911445147227-1606921859123168882?l=googleappsdeveloper.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/GoogleAppsDeveloperBlog/~4/wuueUNHaVY0" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://googleappsdeveloper.blogspot.com/feeds/1606921859123168882/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=1377183911445147227&amp;postID=1606921859123168882&amp;isPopup=true" title="3 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/1377183911445147227/posts/default/1606921859123168882?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/1377183911445147227/posts/default/1606921859123168882?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/GoogleAppsDeveloperBlog/~3/wuueUNHaVY0/2011-year-of-features-use-cases-and.html" title="2011 - A year of features, use cases and developers of Apps Script" /><author><name>Google Apps Developer Blog Editor</name><uri>http://www.blogger.com/profile/07808045840831274565</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://3.bp.blogspot.com/-AfmuFkbdBJQ/TjHzJVAWTXI/AAAAAAAAAMo/xVhok61rw7I/s72-c/Google%2BChromeScreenSnapz157.png" height="72" width="72" /><thr:total>3</thr:total><feedburner:origLink>http://googleappsdeveloper.blogspot.com/2011/12/2011-year-of-features-use-cases-and.html</feedburner:origLink></entry><entry gd:etag="W/&quot;A0ECQno5eyp7ImA9WhRXFUQ.&quot;"><id>tag:blogger.com,1999:blog-1377183911445147227.post-4997241781148605682</id><published>2011-12-22T16:21:00.000-08:00</published><updated>2011-12-22T16:21:03.423-08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-12-22T16:21:03.423-08:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Groups" /><category scheme="http://www.blogger.com/atom/ns#" term="Administrative APIs" /><title>Managing groups using the new Groups Settings API</title><content type="html">&lt;p&gt;The recently launched &lt;a href="http://code.google.com/googleapps/domain/group_settings/v1/using_api.html"&gt;Groups Settings API&lt;/a&gt; allows Google Apps domain administrators to write client applications for managing groups in their domain. Once you have created the groups and added members using the &lt;a href="http://code.google.com/googleapps/domain/gdata_provisioning_api_v2.0_developers_protocol.html"&gt;Provisioning API&lt;/a&gt;, you can use the Groups Settings API to perform actions like:&lt;/p&gt;

&lt;ul&gt;&lt;li&gt;manage access to the group&lt;/li&gt;
&lt;li&gt;configure discussion archiving &lt;/li&gt;
&lt;li&gt;configure message moderation&lt;/li&gt;
&lt;li&gt;edit a group's description, display format and custom fields&lt;/li&gt;&lt;/ul&gt;

&lt;p&gt;Let’s have a look at how you can make authorized calls to the Groups Settings API from your client application.&lt;/p&gt;

&lt;h2&gt;Getting Started&lt;/h2&gt;

&lt;p&gt;You must enable the Provisioning API to make requests to the Groups Settings API.
You can do so by enabling the &lt;i&gt;Provisioning API&lt;/i&gt; checkbox in the &lt;i&gt;Domain settings&lt;/i&gt; tab of your Google Apps control panel. &lt;/p&gt;&lt;br /&gt;

&lt;img border="0" height="287" width="500" src="http://2.bp.blogspot.com/-isgrM8Ikaq0/TvPFqRWvw-I/AAAAAAAAAYU/H3Fzt96Fwdk/s500/PreviewScreenSnapz004.png" style="border: 0px;"/&gt;

&lt;p&gt;Next, ensure that the &lt;i&gt;Google Groups for Business&lt;/i&gt; and &lt;i&gt;Email&lt;/i&gt; services are added to your domain by going to the Dashboard. If these services are not listed, add them by going to &lt;i&gt;Add more services&lt;/i&gt; link next to the &lt;i&gt;Service settings&lt;/i&gt; heading.&lt;/p&gt;&lt;br /&gt;

&lt;img border="0" height="304" width="500" src="http://3.bp.blogspot.com/-yz6IVkjujlw/TvPFqm5LKCI/AAAAAAAAAYg/wj054z_89gE/s500/PreviewScreenSnapz005.png" style="border: 0px;" /&gt;

&lt;p&gt;Now you are set to write client applications. Let's discuss the steps to write an application using the Python client library. You need to install the &lt;a href="http://code.google.com/p/google-api-python-client/"&gt;google-api-python-client library&lt;/a&gt; first.  &lt;/p&gt;

&lt;p&gt;You can register a new project or use an existing one from the &lt;a href="http://code.google.com/apis/console#access"&gt;APIs console&lt;/a&gt; to obtain credentials to use in your application. The credentials (&lt;code&gt;client_id&lt;/code&gt;, &lt;code&gt;client_secret&lt;/code&gt;) are used to obtain OAuth tokens for authorization of the API requests. &lt;/p&gt;

&lt;h2&gt;Authorization using OAuth 2.0&lt;/h2&gt;

&lt;p&gt;The &lt;a href="http://code.google.com/googleapps/domain/group_settings/"&gt;Groups Settings API&lt;/a&gt; supports various authorization mechanisms, including &lt;a href="http://code.google.com/apis/accounts/docs/OAuth2.html"&gt;OAuth 2.0&lt;/a&gt;.  Please see the &lt;a href="http://code.google.com/p/google-api-python-client/wiki/OAuth2"&gt;wiki&lt;/a&gt; for more information on using the library’s support for OAuth 2.0 to create a &lt;code&gt;httplib2.Http&lt;/code&gt; object.  This object is used by the Groups Settings service to make authorized requests.&lt;/p&gt;

&lt;h2&gt;Make API requests with GroupSettings service&lt;/h2&gt;

&lt;p&gt;The Python client library uses the &lt;a href="http://code.google.com/apis/discovery/"&gt;Discovery API&lt;/a&gt; to build the Groups Settings service from &lt;a href="https://www.googleapis.com/discovery/v1/apis/groupssettings/v1/rest"&gt;discovery&lt;/a&gt;. The method &lt;code&gt;build&lt;/code&gt; is defined in the library and can be imported to build the service. The service can then access resources (‘groups’ in this case) and perform actions on them using methods defined in the discovery metadata.&lt;/p&gt;

&lt;p&gt;The following example shows how to retrieve the properties for the group &lt;code&gt;staff@example.com&lt;/code&gt;. &lt;/p&gt;

&lt;pre class="prettyprint lang-python"&gt;service = build(“groups”, “v1”, http=http) 
group = service.groups()
g = group.get(groupUniqueId=”staff@example.com”).execute()&lt;/pre&gt;

&lt;p&gt;This method returns a dictionary of property pairs (name/value):&lt;/p&gt;

&lt;pre class="prettyprint lang-python"&gt;group_name = g['name']
group_isArchived = g['isArchived']
group_whoCanViewGroup = g['whoCanViewGroup']&lt;/pre&gt;

&lt;p&gt;The &lt;code&gt;update&lt;/code&gt; method can be used to set the properties of a group. Let’s have a look at how you can set the access permissions for a group:&lt;/p&gt;

&lt;pre class="prettyprint lang-python"&gt;body = {'whoCanInvite': ALL_MANAGERS_CAN_INVITE,
        'whoCanJoin': ‘INVITED_CAN_JOIN’,
        'whoCanPostMessage': ‘ALL_MEMBERS_CAN_POST’,
        'whoCanViewGroup': ‘ALL_IN_DOMAIN_CAN_VIEW’
       }

 # Update the properties of group
 g1 = group.update(groupUniqueId=groupId, body=body).execute()&lt;/pre&gt;

&lt;p&gt;Additional valid values for these properties, as well as the complete list of properties, are documented in the  &lt;a href="http://code.google.com/googleapps/domain/group_settings/v1/reference.html"&gt;reference guide&lt;/a&gt;. We have recently added a &lt;a href="http://code.google.com/p/google-api-python-client/source/browse/#hg%2Fsamples%2Fgroupssettings"&gt;sample&lt;/a&gt; in the Python client library that you can refer to when developing your own application. We would be glad to hear your feedback or any queries you have on the &lt;a href="http://code.google.com/googleapps/support/domain_info_and_management_forum.html"&gt;forum&lt;/a&gt;.&lt;/p&gt;

&lt;p /&gt;&lt;table cellpadding="5" cellspacing="0"&gt;&lt;tbody&gt;&lt;tr style="background-color: #f2f2f2;"&gt;&lt;td&gt;&lt;img class="profile" src="http://sites.google.com/site/developeradvocates/image/shraddha_gupta.png" /&gt;&lt;/td&gt;&lt;td valign="top"&gt;&lt;span class="largefont"&gt;Shraddha Gupta&lt;/span&gt; &amp;nbsp;   &lt;a class="alt" href="https://plus.google.com/114165026575240989729/about" rel="me" target="_blank"&gt;profile&lt;/a&gt;
&lt;br /&gt;&lt;div class="bio"&gt;
&lt;br /&gt;Shraddha is a Developer Programs Engineer for Google Apps. She has her MTech in Computer Science and Engineering from IIT Delhi, India.
&lt;/div&gt;
&lt;br /&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1377183911445147227-4997241781148605682?l=googleappsdeveloper.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/GoogleAppsDeveloperBlog/~4/iXV1mHeQNqg" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://googleappsdeveloper.blogspot.com/feeds/4997241781148605682/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=1377183911445147227&amp;postID=4997241781148605682&amp;isPopup=true" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/1377183911445147227/posts/default/4997241781148605682?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/1377183911445147227/posts/default/4997241781148605682?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/GoogleAppsDeveloperBlog/~3/iXV1mHeQNqg/managing-groups-using-new-groups.html" title="Managing groups using the new Groups Settings API" /><author><name>Google Apps Developer Blog Editor</name><uri>http://www.blogger.com/profile/07808045840831274565</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://2.bp.blogspot.com/-isgrM8Ikaq0/TvPFqRWvw-I/AAAAAAAAAYU/H3Fzt96Fwdk/s72-c/PreviewScreenSnapz004.png" height="72" width="72" /><thr:total>0</thr:total><feedburner:origLink>http://googleappsdeveloper.blogspot.com/2011/12/managing-groups-using-new-groups.html</feedburner:origLink></entry><entry gd:etag="W/&quot;Dk4CQXgyeSp7ImA9WhRXFEQ.&quot;"><id>tag:blogger.com,1999:blog-1377183911445147227.post-1856670498654552628</id><published>2011-12-21T11:16:00.000-08:00</published><updated>2011-12-21T11:16:00.691-08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-12-21T11:16:00.691-08:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Android" /><category scheme="http://www.blogger.com/atom/ns#" term="Google Calendar API" /><title>Building a Meeting Scheduler for Android using the new Calendar API</title><content type="html">&lt;p&gt;Though developers are quite comfortable thinking in abstractions, we still find a lot of value in code examples and fully developed sample applications. Judging by the volume of comments, tweets, and git checkouts of the &lt;a href="http://googleappsdeveloper.blogspot.com/2011/11/au-to-do-sample-application-using.html"&gt;Au-to-do&lt;/a&gt; sample code we released a few weeks ago, our readers agree.&lt;/p&gt;

&lt;p&gt;For Google Apps API developers who want to get started writing mobile apps, here’s a great new resource: a sample application that integrates &lt;a href="http://code.google.com/apis/calendar/v3/getting_started.html"&gt;Google Calendar API v3&lt;/a&gt; with Android and illustrates best practices for OAuth 2.0.  This meeting scheduler app built by &lt;a href="https://plus.google.com/110487324451850883514/about"&gt;Alain Vongsouvanh&lt;/a&gt; gets the user’s contact list, lets users select attendees, and matches free/busy times to suggest available meeting times.  It provides a simple Android UI for user actions such as attendee selection:&lt;/p&gt;
&lt;br /&gt;
&lt;center&gt;&lt;img border="0" height="400" width="210" src="http://3.bp.blogspot.com/-g180hkmW--o/TvIshqTQzAI/AAAAAAAAAYI/cSEVyod_gZo/s400/KeynoteScreenSnapz010.png" style="border: 0px;" /&gt;&lt;/center&gt;

&lt;p&gt;The sample code for Meeting Scheduler demonstrates many key aspects of developing with Google Apps APIs.  After authorizing all required access using OAuth 2.0, the Meeting Scheduler makes requests to the Calendar API.  For example, the class &lt;code&gt;&lt;a href="http://code.google.com/p/google-meeting-scheduler/source/browse/src/com/google/samples/meetingscheduler/util/FreeBusyTimesRetriever.java"&gt;FreeBusyTimesRetriever&lt;/a&gt;&lt;/code&gt; queries the free/busy endpoint to find available meeting times:&lt;/p&gt;

&lt;pre class="prettyprint lang-java"&gt;
FreeBusyRequest request = new FreeBusyRequest();

request.setTimeMin(getDateTime(startDate, 0));
request.setTimeMax(getDateTime(startDate, timeSpan));

for (String attendee : attendees) {
  requestItems.add(new FreeBusyRequestItem().setId(attendee));
}
request.setItems(requestItems);

FreeBusyResponse busyTimes;
try {
  Freebusy.Query query = service.freebusy().query(request);
  // Use partial GET to retrieve only needed fields.
  query.setFields("calendars");
  busyTimes = query.execute();
      // ...
} catch (IOException e) {
  // ...
}
&lt;/pre&gt;

&lt;p&gt;In this snippet above, note the use of a partial GET request.   Calendar API v3, along with many other new Google APIs, provides &lt;a href="http://code.google.com/apis/calendar/v3/performance.html#partial"&gt;partial response&lt;/a&gt; with GET and PATCH to retrieve or update only the data fields you need for a given request.  Using these methods can help you streamline your code and conserve system resources.&lt;/p&gt;

&lt;p&gt;For the full context of all calls that Meeting Scheduler makes, including OAuth 2.0 flow and the handling of expired access tokens, see &lt;a href="http://code.google.com/apis/calendar/articles/meeting_scheduler.html"&gt;Getting Started with the Calendar API v3 and OAuth 2.0 on Android&lt;/a&gt;.  The &lt;a href="https://code.google.com/p/google-meeting-scheduler/"&gt;project site&lt;/a&gt; provides all the source code and other resources, and there’s a related &lt;a href="https://code.google.com/p/google-meeting-scheduler/wiki/GettingStarted"&gt;wiki page&lt;/a&gt; with important configuration details.   &lt;/p&gt;

&lt;p&gt;We hope you’ll have a look at the sample and let us know what you think in the &lt;a href="http://code.google.com/apis/calendar/community/forum.html"&gt;Google Apps Calendar API forum&lt;/a&gt;.  You’re welcome to create a clone of the source code and do some Meeting Scheduler development of your own.  If you find a bug or have an idea for a feature, don’t hesitate to file it for evaluation.&lt;/p&gt;

&lt;br /&gt;&lt;table cellpadding="5" cellspacing="0"&gt;&lt;tbody&gt;&lt;tr style="background-color: #f2f2f2;"&gt;&lt;td&gt;&lt;img class="profile" src="http://2.bp.blogspot.com/-H9M9OEwDXf4/Tt1N9yG3X2I/AAAAAAAAAVs/hsd0Q5LU4PI/s400/Google%2BChromeScreenSnapz071.png" /&gt;&lt;/td&gt;&lt;td valign="top"&gt;&lt;span class="largefont"&gt;Eric Gilmore&lt;/span&gt; &amp;nbsp; 
&lt;br /&gt;&lt;div class="bio"&gt;
&lt;br /&gt;Eric is a technical writer working with the Developer Relations group.  Previously dedicated to Google Enterprise documentation, he is now busy writing about various Google Apps APIs, including Contacts, Calendar, and Provisioning.&lt;/div&gt;
&lt;br /&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1377183911445147227-1856670498654552628?l=googleappsdeveloper.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/GoogleAppsDeveloperBlog/~4/PWvR-inQpRU" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://googleappsdeveloper.blogspot.com/feeds/1856670498654552628/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=1377183911445147227&amp;postID=1856670498654552628&amp;isPopup=true" title="3 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/1377183911445147227/posts/default/1856670498654552628?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/1377183911445147227/posts/default/1856670498654552628?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/GoogleAppsDeveloperBlog/~3/PWvR-inQpRU/building-meeting-scheduler-for-android.html" title="Building a Meeting Scheduler for Android using the new Calendar API" /><author><name>Google Apps Developer Blog Editor</name><uri>http://www.blogger.com/profile/07808045840831274565</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://3.bp.blogspot.com/-g180hkmW--o/TvIshqTQzAI/AAAAAAAAAYI/cSEVyod_gZo/s72-c/KeynoteScreenSnapz010.png" height="72" width="72" /><thr:total>3</thr:total><feedburner:origLink>http://googleappsdeveloper.blogspot.com/2011/12/building-meeting-scheduler-for-android.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CkEBRncyeyp7ImA9WhRXFE8.&quot;"><id>tag:blogger.com,1999:blog-1377183911445147227.post-2243751674519178546</id><published>2011-12-20T14:37:00.000-08:00</published><updated>2011-12-20T14:37:37.993-08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-12-20T14:37:37.993-08:00</app:edited><title>Optimizing bandwidth usage with gzip compression</title><content type="html">&lt;p&gt;All developers agree that saving bandwidth is a critical factor for the success of a mobile application. Less data usage means faster response times and also lower costs for the users as the vast majority of mobile data plans are limited or billed on a per-usage basis.&lt;/p&gt;

&lt;p&gt;When using any of the &lt;a href="http://code.google.com/apis/gdata/"&gt;Google Data APIs&lt;/a&gt; in your application, you can reduce the amount of data to be transferred by requesting &lt;a href="http://en.wikipedia.org/wiki/Gzip"&gt;gzip-encoded&lt;/a&gt; responses. On average, the size of a page of users returned by the &lt;a href="http://code.google.com/googleapps/domain/gdata_provisioning_api_v2.0_developers_protocol.html"&gt;Provisioning API&lt;/a&gt; (100 accounts) is about 100 Kb, while the same data, gzip-encoded, is about 5 Kb -- 20 times smaller!  When you can reduce data sizes at this dramatic scale, the benefits of compression will often outweigh any costs in client-side processing for decompression.&lt;/p&gt;

&lt;p&gt;Enabling gzip-encoding in your application requires two steps.  You have to edit the &lt;a href="http://en.wikipedia.org/wiki/User_agent"&gt;&lt;code&gt;User-Agent&lt;/code&gt;&lt;/a&gt; string to contain the value &lt;code&gt;gzip&lt;/code&gt; and you must also include an &lt;a href="http://en.wikipedia.org/wiki/List_of_HTTP_header_fields"&gt;&lt;code&gt;Accept-Encoding&lt;/code&gt;&lt;/a&gt; header with the same value. For example:&lt;/p&gt;

&lt;pre&gt;User-Agent: my application - gzip
Accept-Encoding: gzip&lt;/pre&gt;

&lt;p&gt;&lt;a href="http://code.google.com/apis/gdata/docs/client-libraries.html"&gt;Client libraries&lt;/a&gt; for the various supported programming languages make enabling gzip-encoded responses even easier. For instance, in the &lt;a href="http://code.google.com/p/google-gdata/"&gt;.NET client library&lt;/a&gt; it is as easy as setting the boolean UseGZip flag of the RequestFactory object:&lt;/p&gt;

&lt;pre class="prettyprint"&gt;service.RequestFactory.UseGZip = true;&lt;/pre&gt;

&lt;p&gt;For any questions, please get in touch with us in the &lt;a href="http://code.google.com/googleapps/support/"&gt;respective forum&lt;/a&gt; for the API you’re using.&lt;/p&gt;

&lt;p /&gt;&lt;table cellpadding="5" cellspacing="0"&gt;&lt;tbody&gt;&lt;tr style="background-color: #f2f2f2;"&gt;&lt;td&gt;&lt;img class="profile" src="http://4.bp.blogspot.com/-dlrMe7xZ-to/TlaWF9TImaI/AAAAAAAAAM4/ih9HtRk8AMY/s1600/Google%2BChromeScreenSnapz248.png" /&gt;&lt;/td&gt;&lt;td valign="top"&gt;&lt;span class="largefont"&gt;Claudio Cherubino&lt;/span&gt; &amp;nbsp;   &lt;a class="alt" href="https://profiles.google.com/claudiocherubino" rel="me" target="_blank"&gt;profile&lt;/a&gt; | &lt;a class="alt" href="http://twitter.com/#ccherubino" rel="me" target="_blank"&gt;twitter&lt;/a&gt; | &lt;a class="alt" href="http://www.claudiocherubino.it/" rel="me" target="_blank"&gt;blog&lt;/a&gt;
&lt;br /&gt;&lt;div class="bio"&gt;
&lt;br /&gt;Claudio is a Developer Programs Engineer working on Google Apps APIs and the Google Apps Marketplace. Prior to Google, he worked as software developer, technology evangelist, community manager, consultant, technical translator and has contributed to many open-source projects, including MySQL, PHP, Wordpress, Songbird and Project Voldemort.&lt;/div&gt;
&lt;br /&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1377183911445147227-2243751674519178546?l=googleappsdeveloper.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/GoogleAppsDeveloperBlog/~4/3OnA4lA_m-Y" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://googleappsdeveloper.blogspot.com/feeds/2243751674519178546/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=1377183911445147227&amp;postID=2243751674519178546&amp;isPopup=true" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/1377183911445147227/posts/default/2243751674519178546?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/1377183911445147227/posts/default/2243751674519178546?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/GoogleAppsDeveloperBlog/~3/3OnA4lA_m-Y/optimizing-bandwidth-usage-with-gzip.html" title="Optimizing bandwidth usage with gzip compression" /><author><name>Google Apps Developer Blog Editor</name><uri>http://www.blogger.com/profile/07808045840831274565</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://4.bp.blogspot.com/-dlrMe7xZ-to/TlaWF9TImaI/AAAAAAAAAM4/ih9HtRk8AMY/s72-c/Google%2BChromeScreenSnapz248.png" height="72" width="72" /><thr:total>0</thr:total><feedburner:origLink>http://googleappsdeveloper.blogspot.com/2011/12/optimizing-bandwidth-usage-with-gzip.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CkMFR3o5fSp7ImA9WhRXE0k.&quot;"><id>tag:blogger.com,1999:blog-1377183911445147227.post-2840502086666176585</id><published>2011-12-19T16:20:00.000-08:00</published><updated>2011-12-19T16:20:16.425-08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-12-19T16:20:16.425-08:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Google Docs API" /><title>Announcing the Archive Feed of the Documents List API</title><content type="html">&lt;p&gt;Users of the &lt;a href="http://code.google.com/apis/documents/docs/developers_guide.html"&gt;Google Documents List API&lt;/a&gt; have traditionally had to perform individual export operations in order to export their documents.  This is quite inefficient, both in terms of time and bandwidth for these operations.&lt;/p&gt;

&lt;p&gt;To improve latency for these operations, we have added the &lt;a href="http://code.google.com/apis/documents/docs/3.0/developers_guide_protocol.html#Archives"&gt;Archive Feed&lt;/a&gt; to the API.  Archives allow users to export a large number of items at once, in single ZIP archives.  This feature provides a useful optimization for users, greatly increasing the efficiency of export operations.  Additionally, users can receive emails about archives, and choose to download them from a link provided in the email.&lt;/p&gt;

&lt;p&gt;This feature had a &lt;a href="http://code.google.com/apis/documents/changelog.html"&gt;soft release&lt;/a&gt; earlier this year, and we think it’s now ready for prime time.  For more information, please see the &lt;a href="http://code.google.com/apis/documents/docs/3.0/developers_guide_protocol.html#Archives"&gt;Archive Feed documentation&lt;/a&gt;.&lt;/p&gt;

&lt;p /&gt;&lt;table cellpadding="5" cellspacing="0"&gt;&lt;tbody&gt;&lt;tr style="background-color: #f2f2f2;"&gt;&lt;td&gt;&lt;img class="profile" src="http://1.bp.blogspot.com/-V5mFET2kKmo/ToDvvlZMA1I/AAAAAAAAAQ8/FRtONEkaUOo/s400/vicfryzel_headshot.png" /&gt;&lt;/td&gt;&lt;td valign="top"&gt;&lt;span class="largefont"&gt;Vic Fryzel&lt;/span&gt;     &lt;a class="alt" href="https://www.google.com/profiles/vicfryzel" rel="me" target="_blank"&gt;profile&lt;/a&gt; | &lt;a class="alt" href="http://twitter.com/vicfryzel" rel="me" target="_blank"&gt;twitter&lt;/a&gt; | &lt;a class="alt" href="http://www.vicfryzel.com/" rel="me" target="_blank"&gt;blog&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;div class="bio"&gt;Vic is a Google engineer and open source software developer in the United States. His interests are generally in the artificial intelligence domain, specifically regarding neural networks and machine learning. He's an amateur robotics and embedded systems engineer, and also maintains a significant interest in the security of software systems and engineering processes behind large software projects.&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1377183911445147227-2840502086666176585?l=googleappsdeveloper.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/GoogleAppsDeveloperBlog/~4/X6Vi18N-K2s" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://googleappsdeveloper.blogspot.com/feeds/2840502086666176585/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=1377183911445147227&amp;postID=2840502086666176585&amp;isPopup=true" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/1377183911445147227/posts/default/2840502086666176585?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/1377183911445147227/posts/default/2840502086666176585?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/GoogleAppsDeveloperBlog/~3/X6Vi18N-K2s/announcing-archive-feed-of-documents.html" title="Announcing the Archive Feed of the Documents List API" /><author><name>Google Apps Developer Blog Editor</name><uri>http://www.blogger.com/profile/07808045840831274565</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://1.bp.blogspot.com/-V5mFET2kKmo/ToDvvlZMA1I/AAAAAAAAAQ8/FRtONEkaUOo/s72-c/vicfryzel_headshot.png" height="72" width="72" /><thr:total>0</thr:total><feedburner:origLink>http://googleappsdeveloper.blogspot.com/2011/12/announcing-archive-feed-of-documents.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DUUCRH45cCp7ImA9WhRXE08.&quot;"><id>tag:blogger.com,1999:blog-1377183911445147227.post-7937646213519339748</id><published>2011-12-19T11:18:00.000-08:00</published><updated>2011-12-19T12:41:05.028-08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-12-19T12:41:05.028-08:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Administrative APIs" /><title>Doodles for your Google Apps domain</title><content type="html">&lt;p&gt;Since 1998, when &lt;a href="http://www.google.com/logos/googleburn.jpg"&gt;the first doodle&lt;/a&gt; was released, they have been one of the most loved features of the Google home page. There have been doodles to celebrate all kinds of events, including national holidays, birthdays of artists and scientists, sports competitions, scientific discoveries and even video games! Also, doodles have evolved from simple static images to complex applications, such as the i&lt;a href="http://www.google.com/logos/2011/lespaul.html"&gt;nteractive electric guitar&lt;/a&gt; used to celebrate the birthday of Les Paul.&lt;/p&gt;

&lt;p&gt;Want your company logo to change for selected events or holidays, just like doodles? The &lt;a href="http://code.google.com/googleapps/domain/admin_settings/docs/1.0/admin_settings_developers_guide_protocol.html"&gt;Admin Settings API&lt;/a&gt; allows domain administrators to write scripts to programmatically change the logo of their Google Apps domain, and &lt;a href="http://code.google.com/appengine/"&gt;Google App Engine&lt;/a&gt; offers the ability to configure regularly scheduled tasks, so that those scripts can run automatically every day.&lt;/p&gt;

&lt;p&gt;With these two pieces combined, it is pretty easy to implement a complete solution to change the domain logo on a daily basis (assuming the graphic designers have prepared a doodle for each day), as in the following screenshot:&lt;/p&gt;
&lt;p /&gt;
&lt;img border="0" height="214" width="279" src="http://1.bp.blogspot.com/-miPLgHdkyPA/Tu-hJTLCJxI/AAAAAAAAAX8/sekjdVMxj_w/s400/image00.png" style="border: 0px;" /&gt;

&lt;p&gt;Let’s start with a Python App Engine script called &lt;code&gt;doodleapps.py&lt;/code&gt;:&lt;/p&gt;

&lt;pre class="prettyprint lang-python"&gt;import gdata.apps.adminsettings.service
from google.appengine.ext import webapp
from google.appengine.ext.webapp import util
from datetime import date

class DoodleHandler(webapp.RequestHandler):
  # list of available doodles
  DOODLES = {    
    '1-1': 'images/newyearsday.jpg',
    '2-14': 'images/valentinesday.jpg',
    '10-31': 'images/halloween.jpg',
    '12-25': 'images/christmas.jpg'
  }
  
  # returns the path to the doodle corresponding to the date
  # or None if no doodle is available
  def getHolidayDoodle(self, date):
    key = '%s-%s' % (date.month, date.day)
    if key not in self.DOODLES:
      return None
      
    return self.DOODLES[key]
  
  # handles HTTP requests by setting today’s doodle
  def get(self):
    doodle = self.getHolidayDoodle(date.today())
    self.response.out.write(doodle)
    
    if doodle:
      service = gdata.apps.adminsettings.service.AdminSettingsService()
      // replace domain, email and password with your credentials
      // or change the authorization mechanism to use OAuth
      service.domain = 'MYDOMAIN.COM'
      service.email = 'ADMIN@MYDOMAIN.COM'
      service.password = 'MYPASSWORD'
      service.source = 'DoodleApps'
      service.ProgrammaticLogin()
      
      # reads the doodle image and update the domain logo
      doodle_bytes = open(doodle, "rb").read()
      service.UpdateDomainLogo(doodle_bytes)

# webapp initialization
def main():
    application = webapp.WSGIApplication([('/', DoodleHandler)],
                                         debug=True)
    util.run_wsgi_app(application)


if __name__ == '__main__':
    main()&lt;/pre&gt;

&lt;p&gt;The script uses a set of predefined doodles which can be edited to match your list of images or replaced with more sophisticated logic, such as using the &lt;a href="http://code.google.com/apis/calendar/v3/getting_started.html"&gt;Google Calendar API&lt;/a&gt; to get the list of holidays in your country.&lt;/p&gt;

&lt;p&gt;Every time the script is triggered by an incoming HTTP request, it will check whether a doodle for the date is available and, if there is one, update the domain logo using the Admin Settings API.&lt;/p&gt;

&lt;p&gt;In order for this script to be deployed on App Engine, you need to to configure the application by defining a &lt;code&gt;app.yaml&lt;/code&gt; file with the following content:&lt;/p&gt;

&lt;pre class="prettyprint lang-python"&gt;application: doodleapps
version: 1
runtime: python
api_version: 1

handlers:
- url: .*
  script: doodleapps.py&lt;/pre&gt;

&lt;p&gt;We want the script to run automatically every 24 hours, without the need for the administrator to send a request, so we also have to define another configuration file called &lt;code&gt;cron.yaml&lt;/code&gt;:&lt;/p&gt;

&lt;pre class="prettyprint lang-python"&gt;cron:
- description: daily doodle update
  url: /
  schedule: every 24 hours&lt;/pre&gt;

&lt;p&gt;Once the application is deployed on App Engine, it will run the script on a daily basis and update the logo.&lt;/p&gt;

&lt;p&gt;The holiday season is upon us. Could there be a better time for your company to start using doodles?&lt;/p&gt;
&lt;p&gt;Happy Holidays!&lt;/p&gt;


&lt;p /&gt;&lt;table cellpadding="5" cellspacing="0"&gt;&lt;tbody&gt;&lt;tr style="background-color: #f2f2f2;"&gt;&lt;td&gt;&lt;img class="profile" src="http://4.bp.blogspot.com/-dlrMe7xZ-to/TlaWF9TImaI/AAAAAAAAAM4/ih9HtRk8AMY/s1600/Google%2BChromeScreenSnapz248.png" /&gt;&lt;/td&gt;&lt;td valign="top"&gt;&lt;span class="largefont"&gt;Claudio Cherubino&lt;/span&gt; &amp;nbsp;   &lt;a class="alt" href="https://profiles.google.com/claudiocherubino" rel="me" target="_blank"&gt;profile&lt;/a&gt; | &lt;a class="alt" href="http://twitter.com/#ccherubino" rel="me" target="_blank"&gt;twitter&lt;/a&gt; | &lt;a class="alt" href="http://www.claudiocherubino.it/" rel="me" target="_blank"&gt;blog&lt;/a&gt;
&lt;br /&gt;&lt;div class="bio"&gt;
&lt;br /&gt;Claudio is a Developer Programs Engineer working on Google Apps APIs and the Google Apps Marketplace. Prior to Google, he worked as software developer, technology evangelist, community manager, consultant, technical translator and has contributed to many open-source projects, including MySQL, PHP, Wordpress, Songbird and Project Voldemort.&lt;/div&gt;
&lt;br /&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1377183911445147227-7937646213519339748?l=googleappsdeveloper.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/GoogleAppsDeveloperBlog/~4/m1eD4456TVA" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://googleappsdeveloper.blogspot.com/feeds/7937646213519339748/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=1377183911445147227&amp;postID=7937646213519339748&amp;isPopup=true" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/1377183911445147227/posts/default/7937646213519339748?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/1377183911445147227/posts/default/7937646213519339748?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/GoogleAppsDeveloperBlog/~3/m1eD4456TVA/doodles-for-your-google-apps-domain.html" title="Doodles for your Google Apps domain" /><author><name>Google Apps Developer Blog Editor</name><uri>http://www.blogger.com/profile/07808045840831274565</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://1.bp.blogspot.com/-miPLgHdkyPA/Tu-hJTLCJxI/AAAAAAAAAX8/sekjdVMxj_w/s72-c/image00.png" height="72" width="72" /><thr:total>0</thr:total><feedburner:origLink>http://googleappsdeveloper.blogspot.com/2011/12/doodles-for-your-google-apps-domain.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DEYMRHc4fyp7ImA9WhRXE0w.&quot;"><id>tag:blogger.com,1999:blog-1377183911445147227.post-5207353979459728811</id><published>2011-12-19T09:36:00.000-08:00</published><updated>2011-12-19T09:36:25.937-08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-12-19T09:36:25.937-08:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Apps Script" /><category scheme="http://www.blogger.com/atom/ns#" term="Administrative APIs" /><title>Domain user management with Apps Script</title><content type="html">&lt;p&gt;Managing the user accounts in a Google Apps domain can be a daunting task when you have hundreds or thousands of them and you have no tools to automate the process. The Google Apps &lt;a href="http://code.google.com/googleapps/domain/provisioning_API_v2_developers_guide.html"&gt;Provisioning API&lt;/a&gt; allows developers to write user management applications in the programming language of their choice, but many system administrators prefer a script-based solution instead. The recently launched &lt;a href="http://code.google.com/googleapps/appsscript/class_usermanager.html"&gt;UserManager Apps Script service&lt;/a&gt; fills the gap, providing Google Apps domain administrators an easy way to automate tasks such as batch user creation or update.&lt;/p&gt;

&lt;p&gt;With the new Apps Script service, creating a user will be as easy as writing a single line of code:&lt;/p&gt;

&lt;pre class="prettyprint lang-js"&gt;var user = UserManager.createUser("newuser", "John", "Smith", "mypassword");&lt;/pre&gt;

&lt;p&gt;The UserManager service also makes it easy to perform the same task on each account in the domain. The following sample shows how you can force all users to change their passwords at the next login:&lt;/p&gt;

&lt;pre class="prettyprint lang-js"&gt;var users = UserManager.getAllUsers();
for (var i in users) {
    users[i].setChangePasswordAtNextLogin(true);
}&lt;/pre&gt;

&lt;p&gt;Calls to the UserManager service can also be scheduled to run hourly or daily, or in response to certain events thanks to Apps Script &lt;a href="http://code.google.com/googleapps/appsscript/guide_events.html"&gt;Triggers&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Interested in what else you can do with the UserManager service? Please &lt;a href="http://code.google.com/googleapps/appsscript/class_usermanager.html"&gt;check the documentation&lt;/a&gt; and get in touch with us on the the &lt;a href="http://www.google.com/support/forum/p/apps-script/"&gt;forum&lt;/a&gt; for any questions about its usage or to share more info about your project with the community.&lt;/p&gt;

&lt;p /&gt;&lt;table cellpadding="5" cellspacing="0"&gt;&lt;tbody&gt;&lt;tr style="background-color: #f2f2f2;"&gt;&lt;td&gt;&lt;img class="profile" src="http://4.bp.blogspot.com/-dlrMe7xZ-to/TlaWF9TImaI/AAAAAAAAAM4/ih9HtRk8AMY/s1600/Google%2BChromeScreenSnapz248.png" /&gt;&lt;/td&gt;&lt;td valign="top"&gt;&lt;span class="largefont"&gt;Claudio Cherubino&lt;/span&gt; &amp;nbsp;   &lt;a class="alt" href="https://profiles.google.com/claudiocherubino" rel="me" target="_blank"&gt;profile&lt;/a&gt; | &lt;a class="alt" href="http://twitter.com/#ccherubino" rel="me" target="_blank"&gt;twitter&lt;/a&gt; | &lt;a class="alt" href="http://www.claudiocherubino.it/" rel="me" target="_blank"&gt;blog&lt;/a&gt;
&lt;br /&gt;&lt;div class="bio"&gt;
&lt;br /&gt;Claudio is a Developer Programs Engineer working on Google Apps APIs and the Google Apps Marketplace. Prior to Google, he worked as software developer, technology evangelist, community manager, consultant, technical translator and has contributed to many open-source projects, including MySQL, PHP, Wordpress, Songbird and Project Voldemort.&lt;/div&gt;
&lt;br /&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1377183911445147227-5207353979459728811?l=googleappsdeveloper.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/GoogleAppsDeveloperBlog/~4/iAH5nQMwJU8" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://googleappsdeveloper.blogspot.com/feeds/5207353979459728811/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=1377183911445147227&amp;postID=5207353979459728811&amp;isPopup=true" title="7 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/1377183911445147227/posts/default/5207353979459728811?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/1377183911445147227/posts/default/5207353979459728811?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/GoogleAppsDeveloperBlog/~3/iAH5nQMwJU8/domain-user-management-with-apps-script.html" title="Domain user management with Apps Script" /><author><name>Google Apps Developer Blog Editor</name><uri>http://www.blogger.com/profile/07808045840831274565</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://4.bp.blogspot.com/-dlrMe7xZ-to/TlaWF9TImaI/AAAAAAAAAM4/ih9HtRk8AMY/s72-c/Google%2BChromeScreenSnapz248.png" height="72" width="72" /><thr:total>7</thr:total><feedburner:origLink>http://googleappsdeveloper.blogspot.com/2011/12/domain-user-management-with-apps-script.html</feedburner:origLink></entry><entry gd:etag="W/&quot;A0EBQXgyeip7ImA9WhRXEEo.&quot;"><id>tag:blogger.com,1999:blog-1377183911445147227.post-7543264669893958770</id><published>2011-12-16T15:08:00.000-08:00</published><updated>2011-12-16T15:54:10.692-08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-12-16T15:54:10.692-08:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Groups" /><category scheme="http://www.blogger.com/atom/ns#" term="Apps Script" /><title>Google Groups and Google Apps Script</title><content type="html">&lt;p&gt;Google Groups is a great way to foster communication over email and on the web, connecting people and allowing them to participate in and read archived discussions. Today, we are introducing the &lt;a href="http://code.google.com/googleapps/appsscript/service_groups.html"&gt;Google Groups Service&lt;/a&gt; in Google Apps Script.  Groups Service will allow a script to check if a user belongs to a certain group, or to enumerate the members of a particular group. The &lt;a href="http://code.google.com/googleapps/appsscript/service_groups.html"&gt;Google Groups Service&lt;/a&gt; works with groups created through the Google Groups web interface as well as groups created by enterprise customers with their own domain using the control panel and the Google Apps Provisioning API.&lt;/p&gt;

&lt;p&gt;This opens a wide range of possibilities, such as allowing a script with &lt;a href="http://code.google.com/googleapps/appsscript/guide_user_interfaces.html"&gt;Ui Services&lt;/a&gt; to show additional buttons to the members of a particular group - for example teachers or managers - and &lt;a href="http://code.google.com/googleapps/appsscript/class_mailapp.html"&gt;sending customized emails&lt;/a&gt; to all the members of a group.&lt;/p&gt;

&lt;p&gt;Here are a few sample scripts to help you get started with the new API. To try out these samples, select &lt;b&gt;Create &amp;gt; New Spreadsheet&lt;/b&gt; and then &lt;b&gt;Tools &amp;gt; Script Editor&lt;/b&gt; from the menu. You can then copy the code into the script editor.  The scripts’ output will appear back in the spreadsheet.&lt;/p&gt;

&lt;h2&gt;List Your Google Groups&lt;/h2&gt;

&lt;p&gt;The Groups Services can be used to fetch a list of the Google Groups of which you’re a member.&lt;/p&gt;

&lt;p&gt;Below is a function which returns all the groups of which you’re a member. Copy and paste it into the script editor and run it. The editor will prompt you to grant READ access to the Google Groups Service before the script can run successfully.&lt;/p&gt;

&lt;p&gt;&lt;i&gt;If you receive a message stating that you’re not a member of any group, open up &lt;a href="https://groups.google.com"&gt;Google Groups&lt;/a&gt; and join any of the thousands of groups there.&lt;/i&gt;&lt;/p&gt;

&lt;pre class="prettyprint lang-js"&gt;function showMyGroups() {
  var groups = GroupsApp.getGroups();
  var s;
  if (groups.length &gt; 0) {
    s = "You belong to " + groups.length + " groups: ";
    for (var i = 0; i &lt; groups.length; i++) {
      var group = groups[i];
      if (i &gt; 0) {
        s += ", ";
      }
      s += group.getEmail();
    }
  } else {
    s = "You are not a member of any group!";
  }
  Browser.msgBox(s);
}&lt;/pre&gt;

&lt;h2&gt;Test Group Membership&lt;/h2&gt;

&lt;p&gt;Brendan plays trumpet in a band. He also runs the band’s website and updates its Google+ page. He’s created a web application with Google Apps Script and now he wants to add to it some additional features for members of the band. Being a model Google user, he’s already subscribed each band member to a Google Group. Although building a complete UI with Google Apps Script is beyond the scope of this article, Brendan could adapt the following function to help make additional features available only to members of that Google Group.&lt;/p&gt;

&lt;p&gt;Of course, this is not just useful for tech-savvy trumpet players: schools may wish to make certain features available just to teachers or others just to students; businesses may need to offer certain functionality to people managers or simply to show on a page or in a UI operations of interest to those in a particular department. Before running this example yourself, replace &lt;code&gt;test@example.com&lt;/code&gt; with the email address of any group of which you’re a member.&lt;/p&gt;

&lt;p&gt;&lt;i&gt;Note: the group’s member list must be visible to the user running the script. Generally, this means you must yourself be a member of a group to successfully test if another user is a member of that same group. Additionally, group owners and managers can restrict member list access to group owners and managers. For such groups, you must be an owner or manager of the group to query membership.&lt;/i&gt;&lt;/p&gt;

&lt;pre class="prettyprint lang-js"&gt;function testGroupMembership() {
  var groupEmail = "test@example.com";
  var group = GroupsApp.getGroupByName(groupEmail);
  if (group.hasUser(Session.getActiveUser().getEmail())) {
    Browser.msgBox("You are a member of " + groupEmail);
  } else {
    Browser.msgBox("You are not a member of " + groupEmail);
  }
}&lt;/pre&gt;

&lt;h2&gt;Get a List of Group Members&lt;/h2&gt;

&lt;p&gt;Sending an email to the group’s email address forwards that message to all the members of the group. Specifically, that message is forwarded to all those members who subscribe by email. Indeed, for many users, discussion over email is the principal feature of Google Groups.&lt;/p&gt;

&lt;p&gt;Suppose, however, that you want to send a customised message to those same people. Provided you have permission to view a group’s member list, the Google Groups Service can be used to fetch the usernames of all the members of a group. The following script demonstrates how to fetch this list and then send an email to each member.&lt;/p&gt;

&lt;p&gt;&lt;i&gt;Before running this script, consider if you actually want to send a very silly message to all the members of the group. It may be advisable just to examine how the script works!&lt;/i&gt;&lt;/p&gt;

&lt;pre class="prettyprint lang-js"&gt;function sendCustomizedEmail() {
  var groupEmail = "test@example.com";
  var group = GroupsApp.getGroupByEmail(groupEmail);
  var users = group.getUsers();
  for (var i = 0; i &lt; users.length; i++) {
    var user = users[i];
    MailApp.sendEmail(user.getEmail(), "Thank you!",
        "Hello " + user.getEmail() + ", thank you for joining this group!");
  }
}&lt;/pre&gt;

&lt;h2&gt;Find Group Managers&lt;/h2&gt;

&lt;p&gt;The Google Groups Service lets you query a user’s role within a group. One possible role is MANAGER (the other roles are described in detail in the Google Groups Service’s documentation): these users can perform administrative tasks on the group, such as renaming the group and accepting membership requests. Any user’s Role can be queried with the help of the Group class’ getRole() method.&lt;/p&gt;

&lt;p&gt;This sample function may be used to fetch a list of a group’s managers. Once again, you must have access to the group’s member list for this function to run successfully:&lt;/p&gt;

&lt;pre class="prettyprint lang-js"&gt;function getGroupOwners(group) {
  var users = group.getUsers();
  var managers = [];
  for (var i = 0; i &lt; users.length; i++) {
    var user = users[i];
    if (group.getRole(user) == GroupsApp.Role.MANAGER) {
      managers.push(user);
    }
  }
  return managers;
}&lt;/pre&gt;


&lt;p&gt;Let us know what you end up building, or if you have any questions about this new functionality, by posting in the &lt;a href="http://code.google.com/googleapps/appsscript/forum.html"&gt;Apps Script forum&lt;/a&gt;.&lt;/p&gt;

&lt;p /&gt;&lt;table cellpadding="5" cellspacing="0"&gt;&lt;tbody&gt;&lt;tr style="background-color: #f2f2f2;"&gt;&lt;td&gt;&lt;img class="profile" src="http://2.bp.blogspot.com/-y2FSdZaV21Q/TuvX4oUqqEI/AAAAAAAAAXw/JPhJN5jWLd8/s90/Google%2BChromeScreenSnapz079.png" /&gt;&lt;/td&gt;&lt;td valign="top"&gt;&lt;span class="largefont"&gt;Trevor Johnston&lt;/span&gt; &amp;nbsp;  
&lt;br /&gt;&lt;div class="bio"&gt;
&lt;br /&gt;Trevor is a software engineer at Google. Before joining the Google Apps Script team in New York, he developed travel products in Switzerland and supported Google’s help centers in Dublin. Prior to joining Google, he worked on Lotus branded products at IBM’s Dublin Software Lab.&lt;/div&gt;
&lt;br /&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1377183911445147227-7543264669893958770?l=googleappsdeveloper.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/GoogleAppsDeveloperBlog/~4/AINTKtwsrgo" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://googleappsdeveloper.blogspot.com/feeds/7543264669893958770/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=1377183911445147227&amp;postID=7543264669893958770&amp;isPopup=true" title="3 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/1377183911445147227/posts/default/7543264669893958770?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/1377183911445147227/posts/default/7543264669893958770?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/GoogleAppsDeveloperBlog/~3/AINTKtwsrgo/google-groups-and-google-apps-script.html" title="Google Groups and Google Apps Script" /><author><name>Google Apps Developer Blog Editor</name><uri>http://www.blogger.com/profile/07808045840831274565</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://2.bp.blogspot.com/-y2FSdZaV21Q/TuvX4oUqqEI/AAAAAAAAAXw/JPhJN5jWLd8/s72-c/Google%2BChromeScreenSnapz079.png" height="72" width="72" /><thr:total>3</thr:total><feedburner:origLink>http://googleappsdeveloper.blogspot.com/2011/12/google-groups-and-google-apps-script.html</feedburner:origLink></entry><entry gd:etag="W/&quot;Dk8ERXk5cSp7ImA9WhRXEEg.&quot;"><id>tag:blogger.com,1999:blog-1377183911445147227.post-8869475803371065173</id><published>2011-12-16T08:51:00.001-08:00</published><updated>2011-12-16T09:00:04.729-08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-12-16T09:00:04.729-08:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Apps Script" /><category scheme="http://www.blogger.com/atom/ns#" term="AdSense" /><title>Introducing AdSense Management Services in Apps Script</title><content type="html">&lt;p&gt;&lt;i&gt;Editor's note: this announcement is cross-posted from the &lt;a href="http://googleadsdeveloper.blogspot.com/2011/12/introducing-adsense-management-services.html"&gt;Google Ads Developer Blog&lt;/a&gt;, which caters to AdWords, AdSense, DoubleClick and AdMob developers.  We hope you enjoy this latest addition to Google Apps Script &amp;mdash; Ryan Boyd&lt;/i&gt;&lt;/p&gt;

&lt;p&gt;Starting today, the AdSense Management API is available as part of &lt;a href="http://code.google.com/googleapps/appsscript/service_adsense.html"&gt;AdSense Services&lt;/a&gt; in &lt;a href="http://code.google.com/googleapps/appsscript/"&gt;Google Apps Script&lt;/a&gt;. This means that you&amp;#8217;ll be able to do things like:
&lt;ul&gt;
&lt;li&gt;Create AdSense &lt;a href="http://code.google.com/googleapps/appsscript/articles/adsense_tutorial.html#section3"&gt;performance reports&lt;/a&gt; for your AdSense accounts in a Google spreadsheet&lt;/li&gt;
&lt;li&gt;Create a &lt;a href="http://code.google.com/googleapps/appsscript/articles/adsense_tutorial.html#section4"&gt;chart based on your AdSense reporting data&lt;/a&gt; and display it in a Google Spreadsheet&lt;/li&gt;
&lt;li&gt;&lt;a href="http://code.google.com/googleapps/appsscript/articles/getting-started-with-sites.html"&gt;Embed&lt;/a&gt; your scripts in a Google Sites page, for instance to import a chart&lt;/li&gt;
&lt;li&gt;Use &lt;a href="http://code.google.com/googleapps/appsscript/guide_events.html#TimeTriggers"&gt;triggers&lt;/a&gt; to schedule the execution of your scripts, for instance to periodically update the chart imported in the Google Sites page&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;Accessing the API from Google Apps Scripts is very easy.  The following snippet of code shows how to generate a report and populate columns of a spreadsheet with the data retrieved:&lt;/p&gt;

&lt;pre class="prettyprint"&gt;function generateReport() {
  var ss = SpreadsheetApp.getActiveSpreadsheet();
  var sheet = ss.getSheetByName('Reports');
  var startDate = Browser.inputBox(
      "Enter a start date (format: 'yyyy-mm-dd')");
  var endDate = Browser.inputBox(
      "Enter an end date (format: 'yyyy-mm-dd')");
  var args = {
    'metric': ['PAGE_VIEWS', 'AD_REQUESTS', 'MATCHED_AD_REQUESTS',
               'INDIVIDUAL_AD_IMPRESSIONS'],
    'dimension': ['MONTH']};
  var report = AdSense.Reports.generate(startDate, endDate, args).getRows();
  for (var i=0; i&amp;lt;report.length; i++) {
    var row = report[i];
    sheet.getRange('A' + String(i+2)).setValue(row[0]);
    sheet.getRange('B' + String(i+2)).setValue(row[1]);
    sheet.getRange('C' + String(i+2)).setValue(row[2]);
    sheet.getRange('D' + String(i+2)).setValue(row[3]);
    sheet.getRange('E' + String(i+2)).setValue(row[4]);
  }    
}
&lt;/pre&gt;

If you want to generate a chart from your data instead of populating the spreadsheet, that&amp;#8217;s very easy as well:

&lt;br /&gt;
&lt;pre class="prettyprint"&gt;function generateLineChart() {
  var doc = SpreadsheetApp.getActiveSpreadsheet();
  var startDate = Browser.inputBox(
      "Enter a start date (format: 'yyyy-mm-dd')");
  var endDate = Browser.inputBox(
      "Enter an end date (format: 'yyyy-mm-dd')");
  var adClientId = Browser.inputBox("Enter an ad client id");
  var args = {
    'filter': ['AD_CLIENT_ID==' + adClientId],
    'metric': ['PAGE_VIEWS', 'AD_REQUESTS', 'MATCHED_AD_REQUESTS',
               'INDIVIDUAL_AD_IMPRESSIONS'],
    'dimension': ['MONTH']};
  var report = AdSense.Reports.generate(startDate, endDate, args).getRows();
  var data = Charts.newDataTable()
      .addColumn(Charts.ColumnType.STRING, "Month")
      .addColumn(Charts.ColumnType.NUMBER, "Page views")
      .addColumn(Charts.ColumnType.NUMBER, "Ad requests")
      .addColumn(Charts.ColumnType.NUMBER, "Matched ad requests")
      .addColumn(Charts.ColumnType.NUMBER, "Individual ad impressions");
  
  // Convert the metrics to numeric values.
  for (var i=0; i&amp;lt;report.length; i++) {
    var row = report[i];
    data.addRow([row[0],parseInt(row[1]),parseInt(row[2]),
        parseInt(row[3]),parseInt(row[4])]);  
  }
  data.build();
  
  var chart = Charts.newLineChart()
      .setDataTable(data)
      .setTitle("Performances per Month")
      .build();
  
  var app = UiApp.createApplication().setTitle("Performances");
  var panel = app.createVerticalPanel()
      .setHeight('350')
      .setWidth('700');
  panel.add(chart);
  app.add(panel);
  doc.show(app); 
}
&lt;/pre&gt;
A shiny line chart will be displayed in your spreadsheet, as shown in the following picture:&lt;br /&gt;&lt;br /&gt;

&lt;div class="separator" text-align: center;"&gt;
&lt;a href="http://2.bp.blogspot.com/-1bAkSvzAZ_g/TutzFbGfLlI/AAAAAAAAAFI/Xs76JKlLt2I/s1600/spread_chart_small.png" imageanchor="1" style="margin-left:1em; margin-right:1em"&gt;&lt;img border="0" height="185" width="320" src="http://2.bp.blogspot.com/-1bAkSvzAZ_g/TutzFbGfLlI/AAAAAAAAAFI/Xs76JKlLt2I/s320/spread_chart_small.png" /&gt;&lt;/a&gt;&lt;/div&gt;

&lt;br /&gt;
You can start using the service by checking out the &lt;a href="http://code.google.com/googleapps/appsscript/service_adsense.html"&gt;reference documentation&lt;/a&gt;, that contains also some sample scripts, and &lt;a href="http://code.google.com/googleapps/appsscript/articles/adsense_tutorial.html"&gt;this tutorial&lt;/a&gt; that implements the use cases mentioned above.&lt;br /&gt;&lt;br /&gt;

Happy Google Apps Scripting with the AdSense Management API!&lt;br /&gt;

&lt;p /&gt;&lt;table cellpadding="5" cellspacing="0"&gt;&lt;tbody&gt;&lt;tr style="background-color: #f2f2f2;"&gt;&lt;td&gt;&lt;img class="profile" src="http://1.bp.blogspot.com/-OdUhq4rwd_0/Tut4Tp-96JI/AAAAAAAAAXk/uXBuTueo3kQ/s400/Google%2BChromeScreenSnapz078.png" /&gt;&lt;/td&gt;&lt;td valign="top"&gt;&lt;span class="largefont"&gt;Silvano Luciani&lt;/span&gt; &amp;nbsp;   &lt;a class="alt" href="https://plus.google.com/u/0/118276561380249048216/about" rel="me" target="_blank"&gt;profile&lt;/a&gt; 
&lt;br /&gt;&lt;div class="bio"&gt;
&lt;br /&gt;Silvano Luciani joined Google's London office in 2011 to make the AdSense API developers happier people. Before that, he has worked in Finland, Italy, Spain and the UK, writing web based configuration management tools for ISPs, social networks, web based training materials, e-commerce apps and more. He has recently discovered that he loves charts, and has finally started to play the drums in the London’s office music room. If you can call what he does "playing the drums".&lt;/div&gt;
&lt;br /&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1377183911445147227-8869475803371065173?l=googleappsdeveloper.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/GoogleAppsDeveloperBlog/~4/iJNRbh3dTUA" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://googleappsdeveloper.blogspot.com/feeds/8869475803371065173/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=1377183911445147227&amp;postID=8869475803371065173&amp;isPopup=true" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/1377183911445147227/posts/default/8869475803371065173?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/1377183911445147227/posts/default/8869475803371065173?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/GoogleAppsDeveloperBlog/~3/iJNRbh3dTUA/introducing-adsense-management-services.html" title="Introducing AdSense Management Services in Apps Script" /><author><name>Google Apps Developer Blog Editor</name><uri>http://www.blogger.com/profile/07808045840831274565</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://2.bp.blogspot.com/-1bAkSvzAZ_g/TutzFbGfLlI/AAAAAAAAAFI/Xs76JKlLt2I/s72-c/spread_chart_small.png" height="72" width="72" /><thr:total>0</thr:total><feedburner:origLink>http://googleappsdeveloper.blogspot.com/2011/12/introducing-adsense-management-services.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DkQCRH4-eSp7ImA9WhRXEE0.&quot;"><id>tag:blogger.com,1999:blog-1377183911445147227.post-5888857883938922826</id><published>2011-12-15T18:01:00.000-08:00</published><updated>2011-12-15T18:59:25.051-08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-12-15T18:59:25.051-08:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Administrative APIs" /><title>More administrative APIs now available to all Google Apps editions</title><content type="html">&lt;p&gt;Google Apps domain administrators have access to a number of &lt;a href="http://code.google.com/googleapps/docs/"&gt;APIs&lt;/a&gt; to automate their management activities or to integrate with third-party applications, including the &lt;a href="http://code.google.com/googleapps/domain/gdata_provisioning_api_v2.0_developers_protocol.html"&gt;Provisioning API&lt;/a&gt; to manage user accounts and groups, the &lt;a href="http://code.google.com/googleapps/domain/audit_admin/v1/getting_started.html"&gt;Admin Audit API&lt;/a&gt;, &lt;a href="http://code.google.com/googleapps/domain/admin_settings/docs/1.0/admin_settings_developers_guide_protocol.html"&gt;Admin Settings API&lt;/a&gt;, and the &lt;a href="http://code.google.com/googleapps/domain/reporting/google_apps_reporting_api.html"&gt;Reporting API&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;These APIs were only available in Google Apps for Business, Education and ISP editions but many administrators of the free version of Google Apps also requested access to them.  I’m glad to say that we listened to your feedback and, starting today, we made the these APIs available to all Google Apps editions.&lt;/p&gt;

&lt;p&gt;Please check the &lt;a href="http://code.google.com/googleapps/docs/"&gt;documentation&lt;/a&gt; as the starting point to explore the possibilities of the APIs and post on our &lt;a href="http://code.google.com/googleapps/support/domain_info_and_management_forum.html"&gt;forum&lt;/a&gt; if you have questions or comments.&lt;/p&gt;

&lt;p /&gt;&lt;table cellpadding="5" cellspacing="0"&gt;&lt;tbody&gt;&lt;tr style="background-color: #f2f2f2;"&gt;&lt;td&gt;&lt;img class="profile" src="http://4.bp.blogspot.com/-dlrMe7xZ-to/TlaWF9TImaI/AAAAAAAAAM4/ih9HtRk8AMY/s1600/Google%2BChromeScreenSnapz248.png" /&gt;&lt;/td&gt;&lt;td valign="top"&gt;&lt;span class="largefont"&gt;Claudio Cherubino&lt;/span&gt; &amp;nbsp;   &lt;a class="alt" href="https://profiles.google.com/claudiocherubino" rel="me" target="_blank"&gt;profile&lt;/a&gt; | &lt;a class="alt" href="http://twitter.com/#ccherubino" rel="me" target="_blank"&gt;twitter&lt;/a&gt; | &lt;a class="alt" href="http://www.claudiocherubino.it/" rel="me" target="_blank"&gt;blog&lt;/a&gt;
&lt;br /&gt;&lt;div class="bio"&gt;
&lt;br /&gt;Claudio is a Developer Programs Engineer working on Google Apps APIs and the Google Apps Marketplace. Prior to Google, he worked as software developer, technology evangelist, community manager, consultant, technical translator and has contributed to many open-source projects, including MySQL, PHP, Wordpress, Songbird and Project Voldemort.&lt;/div&gt;
&lt;br /&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1377183911445147227-5888857883938922826?l=googleappsdeveloper.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/GoogleAppsDeveloperBlog/~4/mOj5z2oPfgk" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://googleappsdeveloper.blogspot.com/feeds/5888857883938922826/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=1377183911445147227&amp;postID=5888857883938922826&amp;isPopup=true" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/1377183911445147227/posts/default/5888857883938922826?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/1377183911445147227/posts/default/5888857883938922826?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/GoogleAppsDeveloperBlog/~3/mOj5z2oPfgk/more-administrative-apis-now-available.html" title="More administrative APIs now available to all Google Apps editions" /><author><name>Google Apps Developer Blog Editor</name><uri>http://www.blogger.com/profile/07808045840831274565</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://4.bp.blogspot.com/-dlrMe7xZ-to/TlaWF9TImaI/AAAAAAAAAM4/ih9HtRk8AMY/s72-c/Google%2BChromeScreenSnapz248.png" height="72" width="72" /><thr:total>0</thr:total><feedburner:origLink>http://googleappsdeveloper.blogspot.com/2011/12/more-administrative-apis-now-available.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CUcHSH84fyp7ImA9WhRQGUQ.&quot;"><id>tag:blogger.com,1999:blog-1377183911445147227.post-3819483630153293631</id><published>2011-12-15T11:32:00.000-08:00</published><updated>2011-12-15T15:50:39.137-08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-12-15T15:50:39.137-08:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Marketplace" /><title>Important Changes to Google Apps Marketplace Billing Policies</title><content type="html">&lt;p&gt;When we launched the Google Apps Marketplace in March last year, one of our goals was to make it easy for developers to build, integrate, and sell their apps to Google Apps users.  Since then, each vendor in the Google Apps Marketplace has handled their own billing and keeps the revenue they generate. Today, we are making that the official Marketplace &lt;a href="http://www.google.com/enterprise/marketplace/devtos"&gt;policy&lt;/a&gt; moving forward: Google will not require vendors to adopt a Google billing API or share any portion of their revenue with us. This will keep more revenue in developers’ pockets, and brings the Google Apps Marketplace policy in line with the Chrome Web Store.&lt;/p&gt;  

&lt;p&gt;So it’s business as usual -- developers can continue to “bring their own billing” to the Marketplace. Developers retain full control over application pricing and billing, and continue to keep all revenue from Google Apps Marketplace customers.&lt;/p&gt;

&lt;p&gt;If you’re in need of a billing solution, we encourage you to try &lt;a href="https://checkout.google.com/sell"&gt;Google Checkout&lt;/a&gt; and &lt;a href="https://checkout.google.com/inapppayments/"&gt;In-App Payments&lt;/a&gt;.  Or use one of the many other commercial billing and subscription services available online.&lt;/p&gt;

&lt;p&gt;Please join us at our next &lt;a href="https://developers.google.com/events/ahNzfmdvb2dsZS1kZXZlbG9wZXJzcg0LEgVFdmVudBigmBIM/"&gt;Google Apps Developer Office Hours&lt;/a&gt; on Google+ Hangouts on December 19th at 12 PM PST time to discuss the Google Apps Marketplace and any questions you may have about these changes.&lt;/p&gt;

&lt;br /&gt;&lt;table cellpadding="5" cellspacing="0"&gt;&lt;tbody&gt;&lt;tr style="background-color: #f2f2f2;"&gt;&lt;td&gt;&lt;img width="72" style="width: 72px;" class="profile" src="http://www.scottmcmullan.com/.a/6a00d8342026ce53ef00e54ffe761d8833-150wi" /&gt;&lt;/td&gt;&lt;td valign="top"&gt;&lt;span class="largefont"&gt;Scott McMullan&lt;/span&gt; &amp;nbsp;  &lt;a class="alt" href="https://plus.google.com/u/0/107950851093654625603" rel="me" target="_blank"&gt;profile&lt;/a&gt; | &lt;a class="alt" href="http://twitter.com/#!/scottmcmullan" rel="me" target="_blank"&gt;twitter&lt;/a&gt;
&lt;br /&gt;&lt;div class="bio"&gt;
&lt;br /&gt;Scott is a Product Manager at Google, where he runs the Apps Marketplace and is extremely lucky to be able to work with amazing developers and companies revolutionizing the way businesses use the web.&lt;/div&gt;
&lt;br /&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1377183911445147227-3819483630153293631?l=googleappsdeveloper.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/GoogleAppsDeveloperBlog/~4/KMm8y-IlCpk" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://googleappsdeveloper.blogspot.com/feeds/3819483630153293631/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=1377183911445147227&amp;postID=3819483630153293631&amp;isPopup=true" title="3 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/1377183911445147227/posts/default/3819483630153293631?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/1377183911445147227/posts/default/3819483630153293631?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/GoogleAppsDeveloperBlog/~3/KMm8y-IlCpk/important-changes-to-google-apps.html" title="Important Changes to Google Apps Marketplace Billing Policies" /><author><name>Google Apps Developer Blog Editor</name><uri>http://www.blogger.com/profile/07808045840831274565</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>3</thr:total><feedburner:origLink>http://googleappsdeveloper.blogspot.com/2011/12/important-changes-to-google-apps.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CUUHRXs9cCp7ImA9WhRQGUw.&quot;"><id>tag:blogger.com,1999:blog-1377183911445147227.post-8780961806867301558</id><published>2011-12-14T17:21:00.000-08:00</published><updated>2011-12-14T17:40:34.568-08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-12-14T17:40:34.568-08:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Google Calendar API" /><category scheme="http://www.blogger.com/atom/ns#" term="Marketplace" /><title>Calendar API v3, 2-legged OAuth &amp; Java</title><content type="html">&lt;p&gt;&lt;a href="http://code.google.com/apis/accounts/docs/OAuth.html#GoogleAppsOAuth"&gt;2-Legged OAuth&lt;/a&gt; is a useful authorization mechanism for apps that need to manipulate calendars on behalf of users in an organization.  Both developers building apps for the &lt;a href="http://www.google.com/enterprise/marketplace"&gt;Google Apps Marketplace&lt;/a&gt; and domain administrators writing tools for their own domains can benefit.  Let’s take a look at how to do this with the new &lt;a href="http://code.google.com/apis/calendar/v3"&gt;Calendar API v3&lt;/a&gt;  and &lt;a href="http://code.google.com/p/google-api-java-client/downloads/detail?name=google-api-java-client-1.6.0-beta.zip&amp;can=2&amp;q="&gt;Java client library 1.6.0 beta&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;To get started as a domain administrator, you need to explicitly enable the new Google Calendar API scopes under &lt;b&gt;Google Apps cPanel &gt; Advanced tools &gt; Manage your OAuth access &gt; Manage third party OAuth Client access&lt;/b&gt;:&lt;/p&gt;

&lt;a href="http://1.bp.blogspot.com/-qLLvOb3l2Vs/Tuf4NRDWajI/AAAAAAAAAWQ/oZUXjdbi4_Q/s1600/image00.png" imageanchor="1" style=""&gt;&lt;img border="0" width="530" src="http://1.bp.blogspot.com/-qLLvOb3l2Vs/Tuf4NRDWajI/AAAAAAAAAWQ/oZUXjdbi4_Q/s540/image00.png" /&gt;&lt;/a&gt;

&lt;p&gt;The scope to include is:&lt;/p&gt;
&lt;pre class="prettyprint"&gt;
    https://www.googleapis.com/auth/calendar
&lt;/pre&gt;

&lt;p&gt;To do the same for a Marketplace app, include the scope in your &lt;a href="http://code.google.com/googleapps/marketplace/listing_manifest.html"&gt;application's manifest&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Calendar API v3 also needs an API access key that can be retrieved in the &lt;a href="http://code.google.com/apis/console-help/#generatingdevkeys"&gt;APIs Console&lt;/a&gt;. Once these requirements are taken care of, a new Calendar service object can be initialized:&lt;/p&gt;

&lt;pre class="prettyprint"&gt;
  public Calendar buildService() {
    HttpTransport transport = AndroidHttp.newCompatibleTransport();
    JacksonFactory jsonFactory = new JacksonFactory();

    // The 2-LO authorization section
    OAuthHmacSigner signer = new OAuthHmacSigner();
    signer.clientSharedSecret = "&amp;lt;CONSUMER_SECRET&amp;gt;";

    final OAuthParameters oauthParameters = new OAuthParameters();
    oauthParameters.version = "1";
    oauthParameters.consumerKey = "&amp;lt;CONSUMER_KEY&amp;gt;";
    oauthParameters.signer = signer;

    Calendar service = Calendar.builder(transport, jsonFactory)
      .setApplicationName("&amp;lt;YOUR_APPLICATION_NAME&amp;gt;")
      .setJsonHttpRequestInitializer(new JsonHttpRequestInitializer() {
        @Override
        public void initialize(JsonHttpRequest request) {
          CalendarRequest calendarRequest = (CalendarRequest) request;
          calendarRequest.setKey("&amp;lt;YOUR_API_KEY&amp;gt;");
        }
      }).setHttpRequestInitializer(oauthParameters).build();
    return service;
  }
&lt;/pre&gt;

&lt;p&gt;Once the Calendar service object is properly initialized, it can be used to send authorized requests to the API.  To access calendar data for a particular user, set the query parameter &lt;code&gt;xoauth_requestor_id&lt;/code&gt; to a user’s email address:&lt;/p&gt;

&lt;pre class="prettyprint"&gt;
  public void printEvents() {
    Calendar service = buildService();
    
    // Add the xoauth_requestor_id query parameter to let the API know
    // on behalf of which user the request is being made.
    ArrayMap&lt;String, Object&gt; customKeys = new ArrayMap&lt;String, Object&gt;();
    customKeys.add("xoauth_requestor_id", "&amp;lt;USER_EMAIL_ADDRESS&amp;gt;");

    List listEventsOperation = service.events().list("primary");
    listEventsOperation.setUnknownKeys(customKeys);
    Events events = listEventsOperation.execute();

    for (Event event : events.getItems()) {
      System.out.println("Event: " + event.getSummary());
    }
  }
&lt;/pre&gt;

&lt;p&gt;Additionally, if the same service will be used to send requests on behalf of the same user, the &lt;code&gt;xoauth_requestor_id&lt;/code&gt; query parameter can be set in the initializer:&lt;/p&gt;

&lt;pre class="prettyprint"&gt;
  // …
  Calendar service = Calendar.builder(transport, jsonFactory)
    .setApplicationName("&amp;lt;YOUR_APPLICATION_NAME&amp;gt;")
    .setJsonHttpRequestInitializer(new JsonHttpRequestInitializer() {
       @Override
       public void initialize(JsonHttpRequest request) {
         ArrayMap&lt;String, Object&gt; customKeys = new ArrayMap&lt;String, Object&gt;();
         customKeys.add("xoauth_requestor_id", "&amp;lt;USER_EMAIL_ADDRESS&amp;gt;");
         calendarRequest.setKey("&amp;lt;YOUR_API_KEY&amp;gt;");
         calendarRequest.setUnknownKeys(customKeys);
       }
    }).setHttpRequestInitializer(oauthParameters).build();
  // ...
&lt;/pre&gt;

&lt;p&gt;We hope you’ll try out 2-Legged OAuth and let us know what you think in the &lt;a href="http://code.google.com/apis/calendar/community/forum.html"&gt;Google Calendar API forum&lt;/a&gt;.&lt;/p&gt;

&lt;br /&gt;&lt;table cellpadding="5" cellspacing="0"&gt;&lt;tbody&gt;&lt;tr style="background-color: #f2f2f2;"&gt;&lt;td&gt;&lt;img class="profile" src="http://sites.google.com/site/developeradvocates/image/alain_vongsouvanh.png" /&gt;&lt;/td&gt;&lt;td valign="top"&gt;&lt;span class="largefont"&gt;Alain Vongsouvanh&lt;/span&gt; &amp;nbsp;  &lt;a class="alt" href="https://plus.google.com/110487324451850883514" rel="me" target="_blank"&gt;profile&lt;/a&gt;
&lt;br /&gt;&lt;div class="bio"&gt;
&lt;br /&gt;Alain is a Developer Programs Engineer for Google Apps with a focus on Google Calendar and Google Contacts. Before Google, he graduated with his Masters in Computer Science from EPITA, France.&lt;/div&gt;
&lt;br /&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1377183911445147227-8780961806867301558?l=googleappsdeveloper.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/GoogleAppsDeveloperBlog/~4/cuR3Z6hmou0" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://googleappsdeveloper.blogspot.com/feeds/8780961806867301558/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=1377183911445147227&amp;postID=8780961806867301558&amp;isPopup=true" title="2 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/1377183911445147227/posts/default/8780961806867301558?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/1377183911445147227/posts/default/8780961806867301558?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/GoogleAppsDeveloperBlog/~3/cuR3Z6hmou0/calendar-api-v3-2-legged-oauth-java.html" title="Calendar API v3, 2-legged OAuth &amp; Java" /><author><name>Google Apps Developer Blog Editor</name><uri>http://www.blogger.com/profile/07808045840831274565</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://1.bp.blogspot.com/-qLLvOb3l2Vs/Tuf4NRDWajI/AAAAAAAAAWQ/oZUXjdbi4_Q/s72-c/image00.png" height="72" width="72" /><thr:total>2</thr:total><feedburner:origLink>http://googleappsdeveloper.blogspot.com/2011/12/calendar-api-v3-2-legged-oauth-java.html</feedburner:origLink></entry><entry gd:etag="W/&quot;C0AGQHkyeCp7ImA9WhRQGEU.&quot;"><id>tag:blogger.com,1999:blog-1377183911445147227.post-6782809161404931864</id><published>2011-12-14T08:55:00.000-08:00</published><updated>2011-12-14T08:55:21.790-08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-12-14T08:55:21.790-08:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Google Docs API" /><title>Documents List API Best Practices: Typed and untyped resource IDs</title><content type="html">&lt;p&gt;With the &lt;a href="code.google.com/apis/documents/"&gt;Google Documents List API&lt;/a&gt;, there are two ways to identify resources:  typed and untyped resource identifiers.  Typed resource identifiers prefix a string of characters with the resource type.  Untyped resource identifiers are similar, but do not have a type prefix.  For example:&lt;/p&gt;
&lt;ul&gt;&lt;li&gt;a typed resource identifier is &lt;code&gt;drawing:0Aj01z0xcb9&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;an untyped resource identifier is &lt;code&gt;0Aj01z0xcb9&lt;/code&gt;.&lt;/li&gt;&lt;/ul&gt;

&lt;p&gt;Client applications often need one type of identifier or the other.  For instance, some applications use untyped resource IDs to access spreadsheets using the Google Spreadsheets API.  Automatically generated API URLs in the Documents List API use typed or untyped resource IDs in certain situations.&lt;/p&gt;

&lt;p&gt;Having two types of resource IDs is something that we will resolve in a future version of the API.  Meanwhile, we strongly recommend that instead of using resource identifiers, clients always use URLs provided in feeds and entries of the Google Documents List API.  The only time that manual URL modification is required is to add special parameters to a URL given by the API, for instance to search for a resource by title.&lt;/p&gt;

&lt;p&gt;For example, the API issues self links along with each entry.  To request an entry again, simply GET the self link of the entry.  We recommend against constructing the link manually, by inserting the entry’s resource ID into the link.&lt;/p&gt;

&lt;p&gt;Common links on entries include:&lt;/p&gt;
&lt;ul&gt;&lt;li&gt;&lt;i&gt;self&lt;/i&gt;: Link at which to fetch a resource again.&lt;/li&gt;
&lt;li&gt;&lt;i&gt;edit&lt;/i&gt;: Link at which to PUT metadata changes for a resource.&lt;/li&gt;
&lt;li&gt;&lt;i&gt;parent&lt;/i&gt;: Links to the set of collections that may contain a given resource.&lt;/li&gt;
&lt;li&gt;&lt;i&gt;next&lt;/i&gt;: Link to the next page of results from the API.&lt;/li&gt;
&lt;li&gt;&lt;i&gt;batch&lt;/i&gt;: Link to POST batch operations.&lt;/li&gt;
&lt;li&gt;&lt;i&gt;resumable-create-media&lt;/i&gt;: Link at which to upload resources to the API or straight into a collection.&lt;/li&gt;
&lt;li&gt;&lt;i&gt;resumable-edit-media&lt;/i&gt;: Link at which to perform resumable upload to modify a resource’s metadata and content.&lt;/li&gt;
&lt;li&gt;&lt;i&gt;thumbnail&lt;/i&gt;: Link at which to get a thumbnail of a resource.&lt;/li&gt;
&lt;li&gt;&lt;i&gt;content&lt;/i&gt;: Link at which to download (export) a resource.&lt;/li&gt;
&lt;li&gt;&lt;i&gt;alternate&lt;/i&gt;: Link to which to redirect a user in a web browser to view a resource in Google Docs.&lt;/li&gt;
&lt;li&gt;&lt;i&gt;accessControlList&lt;/i&gt;: Link to a resource’s ACL feed.&lt;/li&gt;
&lt;li&gt;&lt;i&gt;revisions&lt;/i&gt;: Link to a resource’s revisions feed.&lt;/li&gt;&lt;/ul&gt;

&lt;p&gt;Accessing these links from a client library is simple.  For instance, to retrieve the alternate link in Python, one uses:&lt;/p&gt;

&lt;pre class="prettyprint lang-python"&gt;resource = client.GetAllResources()[0]
print resource.GetHtmlLink()&lt;/pre&gt;

&lt;p&gt;More information on these links is available in the &lt;a href="http://code.google.com/apis/documents/docs/3.0/developers_guide_protocol.html#GettingDocsAndFiles"&gt;documentation&lt;/a&gt;.  For any questions, please post in the &lt;a href="http://code.google.com/apis/documents/forum.html"&gt;forum&lt;/a&gt;.&lt;/p&gt;

&lt;br /&gt;
&lt;table cellpadding="5" cellspacing="0"&gt;&lt;tbody&gt;
&lt;tr style="background-color: #f2f2f2;"&gt;&lt;td&gt;&lt;img class="profile" src="http://1.bp.blogspot.com/-V5mFET2kKmo/ToDvvlZMA1I/AAAAAAAAAQ8/FRtONEkaUOo/s400/vicfryzel_headshot.png" /&gt;&lt;/td&gt;&lt;td valign="top"&gt;&lt;span class="largefont"&gt;Vic Fryzel&lt;/span&gt; &amp;nbsp;   &lt;a class="alt" href="https://www.google.com/profiles/vicfryzel" rel="me" target="_blank"&gt;profile&lt;/a&gt; | &lt;a class="alt" href="http://twitter.com/vicfryzel" rel="me" target="_blank"&gt;twitter&lt;/a&gt; | &lt;a class="alt" href="http://www.vicfryzel.com/" rel="me" target="_blank"&gt;blog&lt;/a&gt; &lt;br /&gt;
&lt;br /&gt;
&lt;div class="bio"&gt;Vic is a Google engineer and open source software developer in the United States. His interests are generally in the artificial intelligence domain, specifically regarding neural networks and machine learning. He's an amateur robotics and embedded systems engineer, and also maintains a significant interest in the security of software systems and engineering processes behind large software projects.&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1377183911445147227-6782809161404931864?l=googleappsdeveloper.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/GoogleAppsDeveloperBlog/~4/sVK4otMQj_0" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://googleappsdeveloper.blogspot.com/feeds/6782809161404931864/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=1377183911445147227&amp;postID=6782809161404931864&amp;isPopup=true" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/1377183911445147227/posts/default/6782809161404931864?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/1377183911445147227/posts/default/6782809161404931864?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/GoogleAppsDeveloperBlog/~3/sVK4otMQj_0/documents-list-api-best-practices-typed.html" title="Documents List API Best Practices: Typed and untyped resource IDs" /><author><name>Google Apps Developer Blog Editor</name><uri>http://www.blogger.com/profile/07808045840831274565</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://1.bp.blogspot.com/-V5mFET2kKmo/ToDvvlZMA1I/AAAAAAAAAQ8/FRtONEkaUOo/s72-c/vicfryzel_headshot.png" height="72" width="72" /><thr:total>0</thr:total><feedburner:origLink>http://googleappsdeveloper.blogspot.com/2011/12/documents-list-api-best-practices-typed.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DUIERnYzfip7ImA9WhRQGEU.&quot;"><id>tag:blogger.com,1999:blog-1377183911445147227.post-6744462649306315727</id><published>2011-12-13T16:24:00.000-08:00</published><updated>2011-12-14T10:31:47.886-08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-12-14T10:31:47.886-08:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="PHP" /><category scheme="http://www.blogger.com/atom/ns#" term="Google Tasks API" /><category scheme="http://www.blogger.com/atom/ns#" term="Ruby" /><category scheme="http://www.blogger.com/atom/ns#" term="Google Calendar API" /><title>Enhanced object properties in the PHP and Ruby libraries</title><content type="html">The newest versions of the &lt;a href="http://code.google.com/apis/calendar/v3/getting_started.html"&gt;Google Calendar API&lt;/a&gt; and &lt;a href="http://code.google.com/apis/tasks/v1/getting_started.html"&gt;Google Tasks API&lt;/a&gt; use JSON as their data format. In languages like PHP and Ruby, it’s simple to turn a JSON object into something that can be easily read and modified, like an associative array or hash.&lt;br /&gt;
&lt;br /&gt;
While creating and modifying hashes is straightforward, sometimes you want a true object and the benefits that come with using one, such as type checking or introspection. To enable this, the &lt;a href="http://code.google.com/p/google-api-php-client/"&gt;PHP&lt;/a&gt; and &lt;a href="http://code.google.com/p/google-api-ruby-client/"&gt;Ruby&lt;/a&gt; client libraries can now provide objects as the results of API calls, in addition to supporting hash responses.&lt;br /&gt;
&lt;br /&gt;
Ruby gets this for free with the latest version of the gem. For PHP, you have to enable support in the client instance:&lt;pre class="prettyprint lang-php"&gt;$apiClient = new apiClient();
$apiClient-&gt;setUseObjects(true);&lt;/pre&gt;The following examples for PHP and Ruby retrieve an event via the Calendar API, and use data from the new resulting object:&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;PHP:&lt;/b&gt;&lt;pre class="prettyprint lang-php"&gt;$event = $service-&gt;events-&gt;get("primary", "eventId");
echo $event-&gt;getSummary();&lt;/pre&gt;&lt;b&gt;Ruby:&lt;/b&gt;&lt;pre class="prettyprint lang-ruby"&gt;result = client.execute(
:api_method =&gt; service.events.get,
:parameters =&gt; {'calendarId' =&gt; 'primary',
'eventId' =&gt; 'eventId'})
print result.data.summary&lt;/pre&gt;If you have general questions about the client libraries, be sure to check out the client library forums (&lt;a href="http://groups.google.com/group/google-api-php-client"&gt;PHP&lt;/a&gt; and &lt;a href="http://groups.google.com/group/google-api-ruby-client"&gt;Ruby&lt;/a&gt;). For questions on specific Apps APIs come find us in the &lt;a href="http://code.google.com/googleapps/support/"&gt;respective Apps API forum&lt;/a&gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;table cellpadding="5" cellspacing="0"&gt;&lt;tbody&gt;
&lt;tr style="background-color: #f2f2f2;"&gt;&lt;td&gt;&lt;img class="profile" src="http://sites.google.com/site/developeradvocates/image/dan_holevoet.png" /&gt;&lt;/td&gt;&lt;td valign="top"&gt;&lt;span class="largefont"&gt;Dan Holevoet&lt;/span&gt; &amp;nbsp;  &lt;a class="alt" href="https://plus.google.com/112953471808394921173" rel="me" target="_blank"&gt;profile&lt;/a&gt;  &lt;br /&gt;
&lt;div class="bio"&gt;&lt;br /&gt;
Dan joined the Google Developer Relations team in 2007. When not playing Starcraft, he works on Google Apps, with a focus on the Calendar and Contacts APIs. He's previously worked on iGoogle, OpenSocial, Gmail contextual gadgets, and the Google Apps Marketplace.&lt;/div&gt;&lt;br /&gt;
&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1377183911445147227-6744462649306315727?l=googleappsdeveloper.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/GoogleAppsDeveloperBlog/~4/u7RuGG8hQFU" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://googleappsdeveloper.blogspot.com/feeds/6744462649306315727/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=1377183911445147227&amp;postID=6744462649306315727&amp;isPopup=true" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/1377183911445147227/posts/default/6744462649306315727?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/1377183911445147227/posts/default/6744462649306315727?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/GoogleAppsDeveloperBlog/~3/u7RuGG8hQFU/enhanced-object-properties-in-php-and.html" title="Enhanced object properties in the PHP and Ruby libraries" /><author><name>Google Apps Developer Blog Editor</name><uri>http://www.blogger.com/profile/07808045840831274565</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>0</thr:total><feedburner:origLink>http://googleappsdeveloper.blogspot.com/2011/12/enhanced-object-properties-in-php-and.html</feedburner:origLink></entry><entry gd:etag="W/&quot;A0UEQ3Y7cSp7ImA9WhRXEEw.&quot;"><id>tag:blogger.com,1999:blog-1377183911445147227.post-3581831833861288685</id><published>2011-12-12T10:00:00.000-08:00</published><updated>2011-12-15T23:06:42.809-08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-12-15T23:06:42.809-08:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Google Docs API" /><title>Documents List API Best Practices: Handling errors and exponential backoff</title><content type="html">We have recently added a new section to the Google Documents List API documentation, titled &lt;a href="http://code.google.com/apis/documents/docs/3.0/developers_guide_protocol.html#HandlingErrors"&gt;Handling API errors&lt;/a&gt;.  A number of developers in the forum have asked what to do when certain requests cause errors, and this documentation responds to their general need for better information.&lt;br /&gt;&lt;br /&gt;This new documentation details all errors and the scenarios that cause them.  We strongly recommend that both new and advanced Google Documents List API developers read the section thoroughly.&lt;br /&gt;&lt;br /&gt;An important technique described in the new docs is &lt;a href="http://code.google.com/apis/documents/docs/3.0/developers_guide_protocol.html#ExponentialBackoff"&gt;exponential backoff&lt;/a&gt;.  Exponential backoff helps clients to automatically retry requests that fail for intermittent reasons.  For example, an application might make too many requests to the API in a short period of time, resulting in HTTP 503 responses.  In cases like this, it makes sense for API clients to automatically retry the requests until they succeed.&lt;br /&gt;&lt;br /&gt;Exponential backoff can be implemented in all of the Google Data API client libraries.  An example in Python follows:&lt;br /&gt;&lt;pre class="prettyprint lang-python"&gt;import random&lt;br /&gt;import time&lt;br /&gt;&lt;br /&gt;def GetResourcesWithExponentialBackoff(client):&lt;br /&gt;  """Gets all of the resources for the authorized user&lt;br /&gt;&lt;br /&gt;  Args:&lt;br /&gt;    client: gdata.docs.client.DocsClient authorized for a user.&lt;br /&gt;  Returns:&lt;br /&gt;    gdata.docs.data.ResourceFeed representing Resources found in request.&lt;br /&gt;  """&lt;br /&gt;  for n in range(0, 5):&lt;br /&gt;    try:&lt;br /&gt;      response = client.GetResources()&lt;br /&gt;      return response&lt;br /&gt;    except:&lt;br /&gt;      time.sleep((2 ** n) + (random.randint(0, 1000) / 1000))&lt;br /&gt;  print "There has been an error, the request never succeeded."&lt;br /&gt;  return None&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;We strongly recommend developers take about 30 minutes and update applications to use exponential backoff.  For help doing this, please read the &lt;a href="http://code.google.com/apis/documents/docs/3.0/developers_guide_protocol.html#HandlingErrors"&gt;documentation&lt;/a&gt; and post in the &lt;a href="http://code.google.com/apis/documents/forum.html"&gt;forum&lt;/a&gt; if you have any questions.&lt;br /&gt;&lt;br /&gt;&lt;table cellpadding="5" cellspacing="0"&gt;&lt;tbody&gt;&lt;tr style="background-color: #f2f2f2;"&gt;&lt;td&gt;&lt;img class="profile" src="http://1.bp.blogspot.com/-V5mFET2kKmo/ToDvvlZMA1I/AAAAAAAAAQ8/FRtONEkaUOo/s400/vicfryzel_headshot.png" /&gt;&lt;/td&gt;&lt;td valign="top"&gt;&lt;span class="largefont"&gt;Vic Fryzel&lt;/span&gt;     &lt;a class="alt" href="https://www.google.com/profiles/vicfryzel" rel="me" target="_blank"&gt;profile&lt;/a&gt; | &lt;a class="alt" href="http://twitter.com/vicfryzel" rel="me" target="_blank"&gt;twitter&lt;/a&gt; | &lt;a class="alt" href="http://www.vicfryzel.com/" rel="me" target="_blank"&gt;blog&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;div class="bio"&gt;Vic is a Google engineer and open source software developer in the United States. His interests are generally in the artificial intelligence domain, specifically regarding neural networks and machine learning. He's an amateur robotics and embedded systems engineer, and also maintains a significant interest in the security of software systems and engineering processes behind large software projects.&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1377183911445147227-3581831833861288685?l=googleappsdeveloper.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/GoogleAppsDeveloperBlog/~4/kwkhwmX2ZXs" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://googleappsdeveloper.blogspot.com/feeds/3581831833861288685/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=1377183911445147227&amp;postID=3581831833861288685&amp;isPopup=true" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/1377183911445147227/posts/default/3581831833861288685?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/1377183911445147227/posts/default/3581831833861288685?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/GoogleAppsDeveloperBlog/~3/kwkhwmX2ZXs/documents-list-api-best-practices.html" title="Documents List API Best Practices: Handling errors and exponential backoff" /><author><name>Google Apps Developer Blog Editor</name><uri>http://www.blogger.com/profile/07808045840831274565</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://1.bp.blogspot.com/-V5mFET2kKmo/ToDvvlZMA1I/AAAAAAAAAQ8/FRtONEkaUOo/s72-c/vicfryzel_headshot.png" height="72" width="72" /><thr:total>0</thr:total><feedburner:origLink>http://googleappsdeveloper.blogspot.com/2011/12/documents-list-api-best-practices.html</feedburner:origLink></entry><entry gd:etag="W/&quot;Dk4DRH05fSp7ImA9WhRQFkg.&quot;"><id>tag:blogger.com,1999:blog-1377183911445147227.post-2970707263316947068</id><published>2011-12-11T17:56:00.000-08:00</published><updated>2011-12-11T17:56:15.325-08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-12-11T17:56:15.325-08:00</app:edited><title>Stay informed of important announcements and downtimes</title><content type="html">&lt;p&gt;Developers using the Google Apps APIs owe it to themselves to stay informed.  To make it as easy as possible, we’ve adopted a standard process for making important announcements about the APIs.&lt;/p&gt;&lt;p&gt;All major outages or issues, although infrequent, are announced on the &lt;a href="http://code.google.com/googleapps/support/downtime/"&gt;Google Apps APIs Downtime Notify&lt;/a&gt; list as quickly as possible.  We also post updates and resolutions.  All developers using the Google Apps APIs should subscribe.&lt;/p&gt;&lt;p&gt;Announcements about new APIs and features as well as best practices about the Google Apps APIs occur on the this blog.   You can subscribe via e-mail (see right sidebar), using the &lt;a href="http://googleappsdeveloper.blogspot.com/atom.xml"&gt;feed&lt;/a&gt;, by following &lt;a href="http://www.twitter.com/GoogleAppsDev"&gt;@GoogleAppsDev&lt;/a&gt; on Twitter, or by following &lt;a href="http://code.google.com/team/index.html?product=googleapps"&gt;members of the team&lt;/a&gt; on Google+.&lt;/p&gt;&lt;p&gt;If you want to hear about just the most important announcements, follow the &lt;a href="http://code.google.com/googleapps/support/announcements/"&gt;Google Apps APIs Announcements forum&lt;/a&gt;.  This is a low-volume list and you can subscribe via e-mail.&lt;/p&gt;&lt;p&gt;Lastly, you should subscribe to the &lt;a href="http://code.google.com/googleapps/support/"&gt;individual forums&lt;/a&gt; for the Google Apps APIs you care about the most.  A lot of technical discussion occurs in the forums and many advanced API users participate in the conversation along with Google engineers.&lt;/p&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;table cellpadding="5" cellspacing="0"&gt;&lt;tbody&gt;
&lt;tr style="background-color: #f2f2f2;"&gt;&lt;td&gt;&lt;img class="profile" src="http://1.bp.blogspot.com/-V5mFET2kKmo/ToDvvlZMA1I/AAAAAAAAAQ8/FRtONEkaUOo/s400/vicfryzel_headshot.png" /&gt;&lt;/td&gt;&lt;td valign="top"&gt;&lt;span class="largefont"&gt;Vic Fryzel&lt;/span&gt; &amp;nbsp;   &lt;a class="alt" href="https://www.google.com/profiles/vicfryzel" rel="me" target="_blank"&gt;profile&lt;/a&gt; | &lt;a class="alt" href="http://twitter.com/vicfryzel" rel="me" target="_blank"&gt;twitter&lt;/a&gt; | &lt;a class="alt" href="http://www.vicfryzel.com/" rel="me" target="_blank"&gt;blog&lt;/a&gt; &lt;br /&gt;
&lt;div class="bio"&gt;&lt;br /&gt;
Vic is a Google engineer and open source software developer in the United States. His interests are generally in the artificial intelligence domain, specifically regarding neural networks and machine learning. He's an amateur robotics and embedded systems engineer, and also maintains a significant interest in the security of software systems and engineering processes behind large software projects.&lt;/div&gt;&lt;br /&gt;
&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1377183911445147227-2970707263316947068?l=googleappsdeveloper.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/GoogleAppsDeveloperBlog/~4/Bj9ANwgwZAM" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://googleappsdeveloper.blogspot.com/feeds/2970707263316947068/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=1377183911445147227&amp;postID=2970707263316947068&amp;isPopup=true" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/1377183911445147227/posts/default/2970707263316947068?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/1377183911445147227/posts/default/2970707263316947068?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/GoogleAppsDeveloperBlog/~3/Bj9ANwgwZAM/stay-informed-of-important.html" title="Stay informed of important announcements and downtimes" /><author><name>Google Apps Developer Blog Editor</name><uri>http://www.blogger.com/profile/07808045840831274565</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://1.bp.blogspot.com/-V5mFET2kKmo/ToDvvlZMA1I/AAAAAAAAAQ8/FRtONEkaUOo/s72-c/vicfryzel_headshot.png" height="72" width="72" /><thr:total>0</thr:total><feedburner:origLink>http://googleappsdeveloper.blogspot.com/2011/12/stay-informed-of-important.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CEENQXwzfSp7ImA9WhRQFEU.&quot;"><id>tag:blogger.com,1999:blog-1377183911445147227.post-7614765782959663697</id><published>2011-12-09T08:19:00.001-08:00</published><updated>2011-12-09T18:04:50.285-08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-12-09T18:04:50.285-08:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Google Calendar API" /><title>Calendar API v3 Best Practices: Recurring Events</title><content type="html">&lt;p&gt;We recently launched a &lt;a href="http://googleappsdeveloper.blogspot.com/2011/11/introducing-next-version-of-google.html"&gt;new version of the Google Calendar API&lt;/a&gt;. In addition to the advantages it gains from Google's new infrastructure for APIs, Google Calendar API v3 has a number of improvements that are specific to Google Calendar. In this blog post we’ll highlight a topic that often causes confusion for developers using the Google Calendar API: recurring events.  &lt;/p&gt;

&lt;p&gt;A recurring event is a 'template' for a series of events that usually happen with some regularity, for example daily or bi-weekly.  To create a recurring event, the client specifies the first instance of the event and includes one or more rules that describe when future events should occur. Google Calendar will then 'expand' the event into the specified occurrences. Individual events in a series may be changed, or even deleted.  Such events become exceptions: they are still part of the series, but changes are preserved even if the recurring event itself is updated.&lt;/p&gt;

&lt;p&gt;Let's create a daily recurring event that will occur every weekday of the current week (as specified by the recurrence rule on the last line):&lt;/p&gt;

&lt;pre&gt;POST https://www.googleapis.com/calendar/v3/calendars/primary/events

{
  "summary": "Daily project sync",
  "start": {
    "dateTime": "2011-12-12T10:00:00",
    "timeZone": "Europe/Zurich"
  },
  "end": {
    "dateTime": "2011-12-12T10:15:00",
    "timeZone": "Europe/Zurich"
  },
  "recurrence": [
    "RRULE:FREQ=DAILY;COUNT=5"
  ]
}&lt;/pre&gt;

&lt;p&gt;When added to a calendar, this will turn into five different events. The recurrence rule is specified according to the iCalendar format (see &lt;a href="http://tools.ietf.org/html/rfc5545"&gt;RFC 5545&lt;/a&gt;). Note, however, that, in contrast to the previous versions of the Google Calendar API, the start and end times are specified the same way as for single instance events, and not with iCalendar syntax.  Further, note that a
timezone identifier for both the start and end time is always required for recurring events, so that expansion happens correctly if part of a series occurs during daylight savings time.&lt;/p&gt;

&lt;p&gt;By default, when listing events on a calendar, recurring events and all exceptions (including canceled events) are returned.  To avoid having to expand recurring events, a client can set the singleEvents query parameter to true, like in the previous versions of the API.  Doing so excludes the recurring events, but includes all expanded instances.&lt;/p&gt;

&lt;p&gt;Another way to get instances of a recurring event is to use the 'instances' collection, which is a new feature of this API version. To list all instances of the daily event that we just created, we can use a query like this:&lt;/p&gt;

&lt;pre&gt;GET https://www.googleapis.com/calendar/v3/calendars/primary/events/7n6f7a9g8a483r95t8en23rfs4/instances&lt;/pre&gt;

&lt;p&gt;which returns something like this:&lt;/p&gt;

&lt;pre&gt;{
  ...
  "items": [
  {
    "kind": "calendar#event",
    "id": "7n6f7a9g8a483r95t8en23rfs4_20111212T090000Z",
    "summary": "Daily project sync",
    "start": {
      "dateTime": "2011-12-12T10:00:00+01:00"
    },
    "end": {
      "dateTime": "2011-12-12T10:15:00+01:00"
    },
    "recurringEventId": "7n6f7a9g8a483r95t8en23rfs4",
    "originalStartTime": {
      "dateTime": "2011-12-12T10:00:00+01:00",
      "timeZone": "Europe/Zurich"
    },
    ...
  },
  … (4 more instances) ...&lt;/pre&gt;

&lt;p&gt;Now, we could turn one instance into an exception by &lt;a href="https://code.google.com/apis/calendar/v3/using.html#updating_events"&gt;updating that event&lt;/a&gt; on the server. For example, we could move one meeting in the series to one hour later as usual and change the title. The original start date in the event is kept, and serves as an identifier of the instance within the series.&lt;/p&gt;

&lt;p&gt;If you have a client that does its own recurrence rule expansion and knows the original start date of an instance that you want to change, the best way to get the instance is to use the &lt;code&gt;originalStart&lt;/code&gt; parameter like so:&lt;/p&gt;

&lt;pre&gt;GET https://www.googleapis.com/calendar/v3/calendars/primary/events/7n6f7a9g8a483r95t8en23rfs4/instances?originalStart=2011-12-16T10:00:00%2B01:00&lt;/pre&gt;

&lt;p&gt;This would return a collection with either zero or one item, depending on whether the instance with the exact original start date exists.  If it does, just update or delete the event as above.&lt;/p&gt;

&lt;p&gt;Lastly, in Google Calendar API v3, we have added the ability to revert the changes made to an individual instance, so it is no longer an exception. One way of doing something similar with the previous versions of the API would be to just copy all fields from the underlying recurring event into the instance and perform an update.  That is an incomplete solution, however, because fields that were once updated in the exception would not be updated when the recurring event changes. The proper way to do this now is to use the reset method on the event. To undo the changes we did to our Friday meeting, we would issue a request like this:&lt;/p&gt;

&lt;pre&gt;POST https://www.googleapis.com/calendar/v3/calendars/primary/events/7n6f7a9g8a483r95t8en23rfs4_20111216T090000Z/reset&lt;/pre&gt;

&lt;p&gt;We hope you’ll find value in these changes to recurring events.  Keep in mind, too, that these are not the only improvements in Google Calendar API v3.  Look for an upcoming post describing best practices for another key area of improvement: reminders.&lt;/p&gt;

&lt;p&gt;If you have any questions about handling recurring events or other features of the new Calendar API, post them on the &lt;a href="http://code.google.com/apis/calendar/community/forum.html"&gt;Calendar API forum&lt;/a&gt;.&lt;/p&gt;

&lt;br /&gt;&lt;table cellpadding="5" cellspacing="0"&gt;&lt;tbody&gt;&lt;tr style="background-color: #f2f2f2;"&gt;&lt;td&gt;&lt;img class="profile" src="http://1.bp.blogspot.com/-_FQ5XomCjpw/TuI5FxjR9-I/AAAAAAAAAV4/UKg5HiFmTcs/s400/image01.jpg" /&gt;&lt;/td&gt;&lt;td valign="top"&gt;&lt;span class="largefont"&gt;Peter Lundblad&lt;/span&gt; &amp;nbsp;  &lt;a class="alt" href="http://plus.google.com/104780772893555468975" rel="me" target="_blank"&gt;profile&lt;/a&gt; 
&lt;br /&gt;&lt;div class="bio"&gt;
&lt;br /&gt;Peter joined Google in 2006.  He's been leading the Calendar API team for the last 2 years. He's previously worked on video uploads for YouTube.&lt;/div&gt;
&lt;br /&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;

&lt;br /&gt;&lt;table cellpadding="5" cellspacing="0"&gt;&lt;tbody&gt;&lt;tr style="background-color: #f2f2f2;"&gt;&lt;td&gt;&lt;img class="profile" src="http://2.bp.blogspot.com/-_Khy5lbHDWA/TuI5d7WabOI/AAAAAAAAAWE/i5QKiVnk2YU/s400/image00.png" /&gt;&lt;/td&gt;&lt;td valign="top"&gt;&lt;span class="largefont"&gt;Fabian Schlup&lt;/span&gt; &amp;nbsp;  &lt;a class="alt" href="http://www.google.com/profiles/fschlup" rel="me" target="_blank"&gt;profile&lt;/a&gt; 
&lt;br /&gt;&lt;div class="bio"&gt;
&lt;br /&gt;Fabian is a Software Engineer at Google in Zürich, working on Calendar and Tasks, with a focus on APIs.&lt;/div&gt;
&lt;br /&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1377183911445147227-7614765782959663697?l=googleappsdeveloper.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/GoogleAppsDeveloperBlog/~4/1_Qlsy6lGi8" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://googleappsdeveloper.blogspot.com/feeds/7614765782959663697/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=1377183911445147227&amp;postID=7614765782959663697&amp;isPopup=true" title="2 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/1377183911445147227/posts/default/7614765782959663697?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/1377183911445147227/posts/default/7614765782959663697?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/GoogleAppsDeveloperBlog/~3/1_Qlsy6lGi8/calendar-v3-best-practices-recurring.html" title="Calendar API v3 Best Practices: Recurring Events" /><author><name>Google Apps Developer Blog Editor</name><uri>http://www.blogger.com/profile/07808045840831274565</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://1.bp.blogspot.com/-_FQ5XomCjpw/TuI5FxjR9-I/AAAAAAAAAV4/UKg5HiFmTcs/s72-c/image01.jpg" height="72" width="72" /><thr:total>2</thr:total><feedburner:origLink>http://googleappsdeveloper.blogspot.com/2011/12/calendar-v3-best-practices-recurring.html</feedburner:origLink></entry><entry gd:etag="W/&quot;Ck4NRns5cSp7ImA9WhRQE0s.&quot;"><id>tag:blogger.com,1999:blog-1377183911445147227.post-4374190268604172487</id><published>2011-12-08T07:48:00.001-08:00</published><updated>2011-12-08T08:16:37.529-08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-12-08T08:16:37.529-08:00</app:edited><title>More opportunities to Hangout with the Google Apps developer team in 2011</title><content type="html">&lt;p&gt;We've held many Office Hours on Google+ Hangouts over the last two months, bringing together Google Apps developers from around the world along with Googlers to discuss the Apps APIs.  We've heard great feedback about these Office Hours from participants, so we've scheduled a few more in 2011.&lt;/p&gt;

&lt;p&gt;General office hours (covering all Google Apps APIs):&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://developers.google.com/events/ahNzfmdvb2dsZS1kZXZlbG9wZXJzcg0LEgVFdmVudBixvRAM/"&gt;&lt;b&gt;TODAY: December 8 @ 10:00am PST&lt;/b&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developers.google.com/events/ahNzfmdvb2dsZS1kZXZlbG9wZXJzcg0LEgVFdmVudBiZxRAM/"&gt;December 14 @ 1:30pm PST&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developers.google.com/events/ahNzfmdvb2dsZS1kZXZlbG9wZXJzcg0LEgVFdmVudBiBzRAM/"&gt;December 20 @ 12:00pm PST&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Product-specific office hours:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://developers.google.com/events/ahNzfmdvb2dsZS1kZXZlbG9wZXJzcg0LEgVFdmVudBiJ-g4M/"&gt;Google Apps Marketplace - December 12 @ 12:00pm PST&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;As we add more Office Hours in the new year, we'll post them on the &lt;a href="https://developers.google.com/events/"&gt;events calendar&lt;/a&gt;, and announce them on &lt;a href="http://twitter.com/GoogleAppsDev"&gt;@GoogleAppsDev&lt;/a&gt; and our &lt;a href="http://code.google.com/team/index.html?product=googleapps"&gt;personal Google+ profiles&lt;/a&gt;.  &lt;/p&gt;

&lt;p&gt;Hope you’ll hang out with us soon!&lt;/p&gt;

&lt;br /&gt;&lt;table cellpadding="5" cellspacing="0"&gt;&lt;tbody&gt;&lt;br /&gt;&lt;tr style="background-color: #f2f2f2;"&gt;&lt;td&gt;&lt;img class="profile" src="http://sites.google.com/site/developeradvocates/image/ryan_boyd.png" /&gt;&lt;/td&gt;&lt;td valign="top"&gt;&lt;span class="largefont"&gt;Ryan Boyd&lt;/span&gt;  &amp;nbsp; &lt;a class="alt" href="http://www.google.com/profiles/ryan.boyd" rel="me" target="_blank"&gt;profile&lt;/a&gt; | &lt;a class="alt" href="http://twitter.com/ryguyrg" rel="me" target="_blank"&gt;twitter&lt;/a&gt; | &lt;a class="alt" href="http://code.google.com/events/#&amp;speaker=ryanboyd"&gt;events&lt;/a&gt;&lt;br /&gt;&lt;div class="bio"&gt;&lt;br /&gt;Ryan is a Developer Advocate on the Google Apps team, helping businesses build applications integrated with Google Apps.  Wearing both engineering and business development hats, you'll find Ryan writing code and helping businesses get to market with integrated features.  &lt;/div&gt;&lt;br /&gt;&lt;/td&gt;&lt;/tr&gt;&lt;br /&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1377183911445147227-4374190268604172487?l=googleappsdeveloper.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/GoogleAppsDeveloperBlog/~4/Jzjq8UVCfVQ" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://googleappsdeveloper.blogspot.com/feeds/4374190268604172487/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=1377183911445147227&amp;postID=4374190268604172487&amp;isPopup=true" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/1377183911445147227/posts/default/4374190268604172487?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/1377183911445147227/posts/default/4374190268604172487?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/GoogleAppsDeveloperBlog/~3/Jzjq8UVCfVQ/more-opportunities-to-hangout-with.html" title="More opportunities to Hangout with the Google Apps developer team in 2011" /><author><name>Google Apps Developer Blog Editor</name><uri>http://www.blogger.com/profile/07808045840831274565</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>0</thr:total><feedburner:origLink>http://googleappsdeveloper.blogspot.com/2011/12/more-opportunities-to-hangout-with.html</feedburner:origLink></entry></feed>

