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

<channel>
	<title>DJ&#039;s Weblog</title>
	<atom:link href="http://www.pipetree.com/qmacro/blog/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.pipetree.com/qmacro/blog</link>
	<description>Reserving the right to be wrong</description>
	<lastBuildDate>Wed, 25 Jan 2012 10:31:32 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.1.3</generator>
		<item>
		<title>SAP ICF course marketing: video!</title>
		<link>http://www.pipetree.com/qmacro/blog/2012/01/sap-icf-course-marketing-video/</link>
		<comments>http://www.pipetree.com/qmacro/blog/2012/01/sap-icf-course-marketing-video/#comments</comments>
		<pubDate>Wed, 25 Jan 2012 10:31:32 +0000</pubDate>
		<dc:creator>dj</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[course]]></category>
		<category><![CDATA[icf]]></category>
		<category><![CDATA[madlab]]></category>
		<category><![CDATA[omniversity]]></category>
		<category><![CDATA[sap]]></category>
		<category><![CDATA[video]]></category>

		<guid isPermaLink="false">http://www.pipetree.com/qmacro/blog/?p=1292</guid>
		<description><![CDATA[I dropped by Madlab and the Omniversity yesterday evening to see Hwayoung and Dave and talk about the upcoming Web Programming with the SAP Internet Communication Framework course in early March. (Sign up!) In preparation for the previous instance of the course last year, we shot a video with yours truly explaining what the course [...]]]></description>
			<content:encoded><![CDATA[<p>I dropped by <a href="http://madlab.org.uk/">Madlab</a> and the <a href="http://omniversity.madlab.org.uk">Omniversity</a> yesterday evening to see <a href="http://twitter.com/hwayoung">Hwayoung </a>and <a href="http://twitter.com/davemee">Dave</a> and talk about the upcoming <a href="https://docs.google.com/document/pub?id=1lX_X95LIaNBxlOsXxO_DFxYZfz4AxGyennxMNKIaaJE">Web Programming with the SAP Internet Communication Framework</a> course in early March. (<a href="http://s.madlab.org.uk/sap2">Sign up!</a>)</p>
<p>In preparation for the previous instance of the course last year, we shot a video with yours truly explaining what the course was about and why you should attend.</p>
<p><iframe src="http://player.vimeo.com/video/27779382?title=0&amp;byline=0&amp;portrait=0" width="400" height="225" frameborder="0" webkitAllowFullScreen mozallowfullscreen allowFullScreen></iframe>
<p><a href="http://vimeo.com/27779382">Omniversity : Web Programming with SAP&#8217;s Internet Communication Framework</a> from <a href="http://vimeo.com/madlabuk">Madlab</a> on <a href="http://vimeo.com">Vimeo</a>.</p>
<p>Madlab have their own semi-resident video expert and in the run up to the next course we&#8217;re going to shoot a new video with lots of exciting content! Well, I guess you might call it exciting if you are into SAP tech and seeing debugging activity in slow motion.</p>
<p>Anyway, watch this space &#8211; next week I&#8217;m over at Madlab again for the shoot. Perhaps I should get a haircut. Or a wig.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.pipetree.com/qmacro/blog/2012/01/sap-icf-course-marketing-video/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>On the Information Diet</title>
		<link>http://www.pipetree.com/qmacro/blog/2012/01/on-the-information-diet/</link>
		<comments>http://www.pipetree.com/qmacro/blog/2012/01/on-the-information-diet/#comments</comments>
		<pubDate>Tue, 03 Jan 2012 06:58:06 +0000</pubDate>
		<dc:creator>dj</dc:creator>
				<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://www.pipetree.com/qmacro/blog/?p=1282</guid>
		<description><![CDATA[There seems to be a movement currently gaining momentum from the flurry of New Year resolutions, a movement on information consumption. Last week, I read about a noble and desirable goal to consume less and produce more. Consume 10%, produce 90% seemed to be the general metric. I aspire to that, but I know it&#8217;s [...]]]></description>
			<content:encoded><![CDATA[<div>
<div>
<div>
<div>
<div>
<div>
<p>There seems to be a movement currently gaining momentum from the flurry of New Year resolutions, a movement on information consumption. Last week, I read about a noble and desirable goal to consume less and produce more. Consume 10%, produce 90% seemed to be the general metric. I aspire to that, but I know it&#8217;s difficult to achieve. This morning, on the train to London, the first thing I read is an article by Clay Johnson called &#8220;<a href="http://www.informationdiet.com/blog/read/how-to-start-your-information-diet">How to Start Your Information Diet</a>&#8220;. There&#8217;s an accompanying <a href="http://shop.oreilly.com/product/0636920019978.do">book</a>, also. Notable 2.0 space luminaries such as Gina Trapani, Tim O&#8217;Reilly and Ev Williams, amongst others, are looking to go on an Information Diet. What is an Information Diet? Slightly worried that I&#8217;m doing exactly what other people are trying to avoid (consuming), and wondering whether it&#8217;s a trap, I read the article.</p>
<div>
<p>Clay Johnson&#8217;s <a href="http://www.informationdiet.com">Information Diet</a> is about reducing your consumption of information, and actively making time to produce. Resonating with the earlier goal, so far so good. The article tells you to cut down on TV viewing, and by use of certain apps and utilities, reduce the number of interruptions and temptations to divert you from producing: turning off notifications from your email system, Google+, Twitter, and the like. This is good stuff. After watching a Peepcode episode on managing your inbox (&#8220;<a href="http://peepcode.com/products/email">Control Your Email Inbox</a>&#8221; &#8211; recommended), I turned off all email notifications at work, and scheduled a thrice-daily email check, rather than have myself driven to doing it by a popup, interrupting my flow. It works well.</p>
<p>But there&#8217;s something about the general term &#8216;Information Diet&#8217; that has me concerned, and has caused me to write this post (and therefore produce &#8211; win!). Yes, reduce your TV viewing (I don&#8217;t watch much anyway, and we don&#8217;t have satellite or cable). Yes, reduce your general browsing, and certainly try to move away from &#8216;<a href="http://en.wikipedia.org/wiki/Continuous_partial_attention">continuous partial attention</a>&#8216; towards &#8216;managed full attention&#8217; (perhaps using <a href="http://www.pomodorotechnique.com/">Pomodoro</a> or similar techniques). But don&#8217;t treat this like a typical diet. Just like your body, your mind needs energy, and what&#8217;s more, it needs feeding. With the right sources. Don&#8217;t think you have to <em>reduce</em> your information intake. Rather, make sure that the information you consume is protein, good carbs, fibre and the like. Last year I started to exercise in earnest again, and am consuming more than before. But I&#8217;m consuming the right foods &#8211; oily fish, fruit, veg, nuts, and so on. And I&#8217;m feeling pretty healthy on it.</p>
<p>Don&#8217;t worry about consuming less. Don&#8217;t worry about <em>dieting</em>. Concern yourself about the <em>quality</em> of what you consume. I have a Kindle, and combined with <a href="http://www.instapaper.com/">Instapaper</a>, consume more excellent, stimulating, educational and thought-provoking articles than ever (here&#8217;s <a href="http://www.sdn.sap.com/irj/scn/weblogs?blog=/pub/wlg/16597">some background</a> that goes some way to explaining my reading appetite). And just as my consumption of the right foodstuffs (with exercise) has increased my health and wellbeing, so my consumption of the right infostuff has increased my knowledge, and exercised my brain. Yes, certainly aim to produce more, but look to <em>what</em> you consume, rather than how much.</p>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
]]></content:encoded>
			<wfw:commentRss>http://www.pipetree.com/qmacro/blog/2012/01/on-the-information-diet/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>The Developer Renaissance</title>
		<link>http://www.pipetree.com/qmacro/blog/2011/11/the-developer-renaissance/</link>
		<comments>http://www.pipetree.com/qmacro/blog/2011/11/the-developer-renaissance/#comments</comments>
		<pubDate>Thu, 10 Nov 2011 16:37:00 +0000</pubDate>
		<dc:creator>dj</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[aiazkazi]]></category>
		<category><![CDATA[interview]]></category>
		<category><![CDATA[sapteched]]></category>
		<category><![CDATA[teched]]></category>
		<category><![CDATA[techedlive]]></category>

		<guid isPermaLink="false">http://www.pipetree.com/qmacro/blog/?p=1271</guid>
		<description><![CDATA[At SAP TechEd in Madrid this year, I had the privilege of interviewing SAP&#8217;s Head of Technology &#38; Innovation Platform (TIP) Marketing,﻿ Aiaz Kazi, on the SAP TechEd Live TV channel. The interview is available here. His team has an enormous scope, covering Mobile, In-Memory, On-Demand, HANA and more. While the word &#8220;Marketing&#8221; might be [...]]]></description>
			<content:encoded><![CDATA[<p>At <a href="http://www.sapteched.com/emea">SAP TechEd in Madrid</a> this year, I had the privilege of interviewing SAP&#8217;s Head of Technology &amp; Innovation Platform (TIP) Marketing,﻿ <a href="http://www.sdn.sap.com/irj/scn/weblogs?blog=/pub/u/251736460">Aiaz Kazi</a>, on the <a href="http://www.sapteched.com/online">SAP TechEd Live</a> TV channel. The interview is available <a href="http://www.sapvirtualevents.com/teched/sessiondetails.aspx?sId=841">here</a>.</p>
<p>His team has an enormous scope, covering Mobile, In-Memory, On-Demand, HANA and more. While the word &#8220;Marketing&#8221; might be auto-filtered by a techie&#8217;s radar-filter, what became clear very quickly is that this group is totally developer focused. His group is already building a brand-new Developer Center (<a href="http://www.pipetree.com/qmacro/blog/2011/11/sap-developer-center/">I wrote about this earlier this week</a>) and is focused on helping the developer help themselves. What&#8217;s more, the group is staffed with developers. I&#8217;ve not managed to find anyone in TIP yet that doesn&#8217;t have a developer background.</p>
<div id="attachment_1273" class="wp-caption alignnone" style="width: 310px"><a href="http://www.sapvirtualevents.com/teched/sessiondetails.aspx?sId=841"><img class="size-medium wp-image-1273 " title="DJ Adams interviews Aiaz Kazi at SAP TechEd Live 2011" src="http://www.pipetree.com/qmacro/blog/wp-content/uploads/2011/11/interview_screengrab-300x171.png" alt="" width="300" height="171" /></a><p class="wp-caption-text">DJ Adams interviews Aiaz Kazi at SAP TechEd Live 2011</p></div>
<p>Hasso is reported to have said &#8220;developers are the key to success&#8221;, and of course, we all know that <a href="http://www.google.co.uk/search?gcx=c&amp;sourceid=chrome&amp;ie=UTF-8&amp;q=%22developers+are+the+new+kingmakers%22">Developers Are The New Kingmakers</a>. What becomes clear in this interview, is that there&#8217;s a re-focus on the developer in the space that spans the distance between mobile and enterprise. This re-focus is long overdue in our industry, so I applaud SAP for having the courage to lead on this. Yes, SAP will benefit because one of the keys to a successful mobile platform is a host of developers in the non traditional-SAP space. But if the message and focus builds, the developer at large will benefit even more.</p>
<p>Perhaps this is a milestone along the way to the upcoming Developer Renaissance?</p>
<p>The interview is here: <a href="http://www.sapvirtualevents.com/teched/sessiondetails.aspx?sId=841">http://www.sapvirtualevents.com/teched/sessiondetails.aspx?sId=841</a></p>
<p>&nbsp;</p>
]]></content:encoded>
			<wfw:commentRss>http://www.pipetree.com/qmacro/blog/2011/11/the-developer-renaissance/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>HTML5 @ SAP</title>
		<link>http://www.pipetree.com/qmacro/blog/2011/11/html5-sap/</link>
		<comments>http://www.pipetree.com/qmacro/blog/2011/11/html5-sap/#comments</comments>
		<pubDate>Wed, 09 Nov 2011 18:04:41 +0000</pubDate>
		<dc:creator>dj</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[gateway]]></category>
		<category><![CDATA[html5]]></category>
		<category><![CDATA[sap]]></category>
		<category><![CDATA[sapteched]]></category>
		<category><![CDATA[tip]]></category>

		<guid isPermaLink="false">http://www.pipetree.com/qmacro/blog/?p=1261</guid>
		<description><![CDATA[Over the years SAP has been slowly but surely turning itself inside out towards the wider, open community. Open as in open source, open protocols and open data. One facet of this long-term tanker maneuver was very evident today; I attended session EXP443 &#8220;HTML5 @ SAP&#8221;. With tens of thousands of developers across the continents, [...]]]></description>
			<content:encoded><![CDATA[<p>Over the years SAP has been slowly but surely turning itself inside out towards the wider, open community. Open as in open source, open protocols and open data. One facet of this long-term tanker maneuver was very evident today; I attended session EXP443 &#8220;HTML5 @ SAP&#8221;. With tens of thousands of developers across the continents, it&#8217;s no surprise to find that some group, somewhere in SAP will be working on the same technology as you are, whatever that is.</p>
<p><a href="http://www.html5rocks.com">HTML5</a> is one of those technologies. While not so much a surprise, what&#8217;s more revealing, and encouraging, is that it&#8217;s being given decent coverage at <a href="http://www.sapteched.com/emea/">SAP TechEd</a> this year. The adoption of HTML5 as the core of a new UI library (originally codenamed &#8220;Phoenix&#8221;) for app front-ends is something that has a voice here. Look at the TechEd sessions available:</p>
<ul>
<li>CD202 HTML5 for Lightweight SAP Applications</li>
<li>MOB264 Building &amp; Customising a Mobile Application Without Writing Code</li>
<li>MM220 How to Customise a Mobile Application with HTML5 and Javascript</li>
<li>EXP443 HTML5 @ SAP</li>
</ul>
<p>That&#8217;s not to say that this is breaking news &#8211; <a href="http://wiki.sdn.sap.com/wiki/display/profile/Thomas+Jung">Thomas Jung</a> (an SAP Mentor from SAP Labs) made reference to Phoenix <a href="http://www.erpexecutive.com/2011/08/next-generation-abap-development-the-erp-executive-interview/">in an interview with Jon Reed</a> a few months ago. Furthermore, in a very useful chat with SAP&#8217;s <a href="http://wiki.sdn.sap.com/wiki/display/profile/Chris+Whealy">Chris Whealy</a> on Monday after InnoJam, I got to understand more about the philosophy and approach of SAP NetWeaver Gateway&#8217;s exposure of data objects and their relationships in a way that would make <a href="http://en.wikipedia.org/wiki/HATEOAS">HATEOAS</a> pay attention. And Chris used an early version of the UI library to present the exposed data. This seems to be a common theme internally in SAP, at least.</p>
<p>So what&#8217;s the deal? In EXP443 I learned that the library is built upon <a href="http://jquery.com">jQuery</a>. So SAP are avoiding the NIH syndrome, that&#8217;s good. But there were other attendees that were questioning SAP&#8217;s decision to build Yet Another Javascript Ui Library. At the very least, the model implementation of the library&#8217;s MVC framework gives the wily Javascript hacker a head-start on using and consuming Gateway services. And in my opinion that&#8217;s the deal. Yes, we have a very nice UI library (and no, it&#8217;s not available until 2Q12, before you ask!) but we also have code that speaks the language of thousands of front-end developers on the one hand, and eases the connection to the proprietary back-end on the other.</p>
<p>SAP&#8217;s future lies with developers, and they&#8217;re embracing those developers in many different ways (the Technology &amp; Innovation Platform team is one group that is making seriously good moves in this direction &#8212; but that&#8217;s a story for another time). HTML5 adoption by SAP was most likely part of a scratching of an internal itch, but it implicitly embraces non-SAP developers in potentially far-reaching ways. Great stuff.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.pipetree.com/qmacro/blog/2011/11/html5-sap/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>SAP Developer Center</title>
		<link>http://www.pipetree.com/qmacro/blog/2011/11/sap-developer-center/</link>
		<comments>http://www.pipetree.com/qmacro/blog/2011/11/sap-developer-center/#comments</comments>
		<pubDate>Tue, 08 Nov 2011 15:52:48 +0000</pubDate>
		<dc:creator>dj</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[developercenter]]></category>
		<category><![CDATA[gateway]]></category>
		<category><![CDATA[hana]]></category>
		<category><![CDATA[sap]]></category>
		<category><![CDATA[sapteched]]></category>
		<category><![CDATA[sup]]></category>

		<guid isPermaLink="false">http://www.pipetree.com/qmacro/blog/?p=1253</guid>
		<description><![CDATA[At SAP TechEd Madrid 2011 I stopped by booth 104 in the Technology Innovation area of Hall 10 after lunch and chatted to David Brutman, from SAP&#8217;s Technology and Innovation Platform Marketing. SAP already have enjoyed tremendous success in terms of takeup and social engagement with their SAP Community Network (which grew from the original [...]]]></description>
			<content:encoded><![CDATA[<p>At <a href="http://www.sapteched.com/emea/">SAP TechEd Madrid 2011</a> I stopped by booth 104 in the Technology Innovation area of Hall 10 after lunch and chatted to David Brutman, from SAP&#8217;s Technology and Innovation Platform Marketing. SAP already have enjoyed tremendous success in terms of takeup and social engagement with their <a href="http://www.scn.sap.com">SAP Community Network</a> (which grew from the original <a href="http://www.sdn.sap.com/">SAP Developer Network</a>) but until now, there hasn&#8217;t been a consistent place for developers to go and enjoy &#8220;Discover, Learn, Build&#8221; activities. In other words, while there has been a huge amount of two-way discussion and sharing of ideas amongst the wider developer community, the next step &#8212; to be fair, a <em>parallel</em> step &#8212; is to offer a resource centre for developers who want to Get On And Do It.</p>
<div class="wp-caption alignnone" style="width: 557px"><a href="https://plus.google.com/u/0/photos/110526626182299357893/albums/5672256376647909457/5672645397795974882"><img class=" " title="David Brutman" src="https://lh3.googleusercontent.com/--rg5nHDoWdY/TrknPWX3YcI/AAAAAAAAGAs/_MFVjCgbivs/s912/IMAG0442.jpg" alt="" width="547" height="328" /></a><p class="wp-caption-text">David Brutman - Technology Platforms Developer Programs</p></div>
<p>Tangible at this year&#8217;s TechEd is the explosion of concepts, tools and technologies all fighting for primary position in the finite developer mindspace. HANA, NetWeaver Gateway, SUP, and the rest. And perhaps I&#8217;m not a typical developer these days, but I&#8217;m looking for guidance: some focused documentation, some tutorials, and perhaps most importantly, a platform to try this stuff out on.</p>
<p>Enter the SAP Developer Center (I&#8217;ll keep to the US spelling of this for consistency!) &#8211; which is pretty much exactly what I&#8217;m looking for. It&#8217;s not live yet, but when it is (we&#8217;re talking 1Q12), it looks to be a killer resource centre. Right now it&#8217;s in beta testing, specifically with HANA. Think <a href="http://code.google.com">code.google.com</a> / <a href="http://developer.google.com">developer.google.com</a> with a cloud-based offering of trial instances on demand. A go-to resource centre for building your skills in the new era of SAP&#8217;s technology platform.</p>
<p>Sounds good? I think it sounds great! Look out for it appearing as part of the SAP Community Network soon.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.pipetree.com/qmacro/blog/2011/11/sap-developer-center/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Movember &#8211; please donate!</title>
		<link>http://www.pipetree.com/qmacro/blog/2011/11/movember-please-donate/</link>
		<comments>http://www.pipetree.com/qmacro/blog/2011/11/movember-please-donate/#comments</comments>
		<pubDate>Tue, 08 Nov 2011 10:02:21 +0000</pubDate>
		<dc:creator>dj</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[charity]]></category>
		<category><![CDATA[movember]]></category>

		<guid isPermaLink="false">http://www.pipetree.com/qmacro/blog/?p=1245</guid>
		<description><![CDATA[I&#8217;m taking part in Movember, a fun and serious movement where moustaches are grown, ridicule is thrown, and hopefully people become more aware of men&#8217;s health in general, and prostate and testicular cancer in particular. The idea is that you start clean-shaven on 1st Nov, and grown your moustache through the month, raising money along the [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://www.pipetree.com/qmacro/blog/wp-content/uploads/2011/11/movember.jpg"><img class="size-medium wp-image-1247 alignleft" title="movember" src="http://www.pipetree.com/qmacro/blog/wp-content/uploads/2011/11/movember-179x300.jpg" alt="" width="179" height="300" /></a></p>
<p>I&#8217;m taking part in <a href="http://uk.movember.com/">Movember</a>, a fun and serious movement where moustaches are grown, ridicule is thrown, and hopefully people become more aware of men&#8217;s health in general, and prostate and testicular cancer in particular.</p>
<p><a href="http://www.pipetree.com/qmacro/blog/wp-content/uploads/2011/11/movember.jpg"></a></p>
<p>The idea is that you start clean-shaven on 1st Nov, and grown your moustache through the month, raising money along the way. I have a Movember page here:</p>
<p><a href="http://mobro.co/qmacro">http://mobro.co/qmacro</a></p>
<p>Please visit and donate what you can &#8211; I&#8217;ll be very grateful, thank you!</p>
<p>&nbsp;</p>
]]></content:encoded>
			<wfw:commentRss>http://www.pipetree.com/qmacro/blog/2011/11/movember-please-donate/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Web Programming with SAP&#8217;s ICF: new course dates</title>
		<link>http://www.pipetree.com/qmacro/blog/2011/11/web-programming-with-icf-course-new-dates/</link>
		<comments>http://www.pipetree.com/qmacro/blog/2011/11/web-programming-with-icf-course-new-dates/#comments</comments>
		<pubDate>Sat, 05 Nov 2011 12:56:47 +0000</pubDate>
		<dc:creator>dj</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[course]]></category>
		<category><![CDATA[http]]></category>
		<category><![CDATA[icf]]></category>
		<category><![CDATA[madlab]]></category>
		<category><![CDATA[omniversity]]></category>
		<category><![CDATA[sap]]></category>

		<guid isPermaLink="false">http://www.pipetree.com/qmacro/blog/?p=1238</guid>
		<description><![CDATA[I&#8217;m pleased to announce that my 2-day Omniversity course Web Programming with SAP&#8217;s Internet Communication Framework is coming up again a couple of times in the first half of next year. SAP&#8217;s Internet Communication Framework (ICF) is the platform that underpins the majority of SAP&#8217;s offerings in this space, even SAP NetWeaver Gateway. This 2-day course [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;m pleased to announce that my 2-day <a href="http://omniversity.madlab.org.uk">Omniversity</a> course <a href="https://docs.google.com/document/pub?id=1lX_X95LIaNBxlOsXxO_DFxYZfz4AxGyennxMNKIaaJE&amp;pli=1">Web Programming with SAP&#8217;s Internet Communication Framework</a> is coming up again a couple of times in the first half of next year.</p>
<p>SAP&#8217;s Internet Communication Framework (ICF) is the platform that underpins the majority of SAP&#8217;s offerings in this space, even SAP NetWeaver Gateway. This 2-day course will help you gain a detailed understanding of the framework, harness its power, and unleash your own resource orientated web service masterpieces!</p>
<p>Dates in March and May are available; follow the links to find out more and to book a place:</p>
<p><a href="http://s.madlab.org.uk/sap2">Sat 03 &#8211; Sun 04 March 2012</a></p>
<p><a href="http://s.madlab.org.uk/sap3">Wed 09 &#8211; Thu 10 May 2012</a></p>
<p><strong>Alternative Dispatcher Layer</strong></p>
<p><a href="https://docs.google.com/document/pub?id=1lX_X95LIaNBxlOsXxO_DFxYZfz4AxGyennxMNKIaaJE&amp;pli=1#h.bz5oteq9itkk">One of the topics covered in Day 2</a> on this course is the Alternative Dispatcher Layer (ADL), a lightweight alternative approach to building web applications, an approach informed and influenced by other libraries and frameworks such as the Python <a href="http://code.google.com/appengine/docs/python/tools/webapp/">webapp framework</a> in Google App Engine. Read more about the origins of ADL in this SAP Developer Network post: <a href="http://www.sdn.sap.com/irj/scn/weblogs?blog=/pub/wlg/15899">A new REST handler / dispatcher for the ICF</a>.</p>
<p>If you&#8217;re after more background, see this post from earlier this year: <a href="http://www.pipetree.com/qmacro/blog/2011/07/stand-steady-on-the-shoulders-of-giants/">Stand Steady on the Shoulders of Giants</a></p>
<p>Looking forward to seeing you on the course!</p>
]]></content:encoded>
			<wfw:commentRss>http://www.pipetree.com/qmacro/blog/2011/11/web-programming-with-icf-course-new-dates/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Moving on &#8230; to Bluefin Solutions</title>
		<link>http://www.pipetree.com/qmacro/blog/2011/11/moving-on-to-bluefin-solutions/</link>
		<comments>http://www.pipetree.com/qmacro/blog/2011/11/moving-on-to-bluefin-solutions/#comments</comments>
		<pubDate>Wed, 02 Nov 2011 11:06:13 +0000</pubDate>
		<dc:creator>dj</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[az]]></category>
		<category><![CDATA[bluefin]]></category>
		<category><![CDATA[work]]></category>

		<guid isPermaLink="false">http://www.pipetree.com/qmacro/blog/?p=1227</guid>
		<description><![CDATA[Since moving back to the North West in 2005 I&#8217;ve been contracting most of the time at AstraZeneca, in Macclesfield, Alderley Edge and Chorlton. I&#8217;ve been involved in a number of great projects, from invoice automation, through HCP honoraria systems, ERP integration (REST-informed, of course) and latterly the first truly global-scale travel &#38; expense system, [...]]]></description>
			<content:encoded><![CDATA[<p>Since moving back to the North West in 2005 I&#8217;ve been contracting most of the time at <a href="http://www.astrazeneca.com/Home">AstraZeneca</a>, in Macclesfield, Alderley Edge and Chorlton. I&#8217;ve been involved in a number of great projects, from invoice automation, through HCP honoraria systems, ERP integration (REST-informed, of course) and latterly the first truly global-scale travel &amp; expense system, which we now have running in 70 countries, with over 60,000 users. The integration hubs I&#8217;ve built pump tens of thousands of transactions daily through the systems, and hundreds of thousands of master data records without a murmur. I&#8217;ve hacked on SAP, Ariba and Infor systems as well as building these custom integration hubs, and I designed and built a credit card feed processing system that&#8217;s become almost self-aware.</p>
<p>Life at AstraZeneca has been great; it&#8217;s one of the friendliest places to work, the people are great, and the location and facilities are second to none. I also met my wife and theoretical childhood sweetheart <a href="www.pipetree.com/michelleadams/">Michelle</a> here. It&#8217;s not all been a bed of roses of course (nowhere is!) at times the work has been frustrating and increasingly there are too many layers between me and the code surface.</p>
<p>At heart I&#8217;m a coder and builder, driven by curiosity and the desire to learn, teach and implement.</p>
<p>So it&#8217;s with great excitement that, in January 2012, I&#8217;m joining <a href="http://www.bluefinsolutions.com/">Bluefin Solutions</a> as a permanent member of the team. I&#8217;ve known many of the gang at Bluefin for a while, and feel as though I already have a lot in common with them. I&#8217;ve spoken at the<a href="http://lanyrd.com/2010/northern-it-directors-round-table-november/"> Northern IT Directors&#8217; Round Table</a> for them, was their first <a href="http://www.bluefinsolutions.com/insights/guest_blog/">guest blogger</a>, and have bumped into many of them during SAP orientated events from <a href="http://lanyrd.com/2009/manchester-sap-evening-november/">SAP Evenings</a> to <a href="http://lanyrd.com/2010/sapteched-berlin/">SAP TechEds</a> and beyond.</p>
<p>My official title will be &#8220;Senior SAP Development Architect&#8221; but there&#8217;s also an &#8220;Evangelist&#8221; flavour to my role, which I&#8217;ll be embracing and making my own. What attracts me to Bluefin in addition to the quality of their people is their drive, their leadership and their embrace of technology, and with that in mind, I&#8217;m really looking forward to helping research, steer and shape innovation in the Enterprise in the near future.</p>
<p>Hooray!</p>
]]></content:encoded>
			<wfw:commentRss>http://www.pipetree.com/qmacro/blog/2011/11/moving-on-to-bluefin-solutions/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Reading List Mark 2 &#8211; Part 5</title>
		<link>http://www.pipetree.com/qmacro/blog/2011/10/reading-list-mark-2-part-5/</link>
		<comments>http://www.pipetree.com/qmacro/blog/2011/10/reading-list-mark-2-part-5/#comments</comments>
		<pubDate>Sun, 16 Oct 2011 20:32:12 +0000</pubDate>
		<dc:creator>dj</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[appsscript]]></category>
		<category><![CDATA[gas]]></category>
		<category><![CDATA[google]]></category>
		<category><![CDATA[googleappsscript]]></category>
		<category><![CDATA[gtug]]></category>
		<category><![CDATA[madlab]]></category>
		<category><![CDATA[mangtug]]></category>
		<category><![CDATA[tasks]]></category>
		<category><![CDATA[ui]]></category>
		<category><![CDATA[urlfetch]]></category>

		<guid isPermaLink="false">http://www.pipetree.com/qmacro/blog/?p=1201</guid>
		<description><![CDATA[This is Part 5, the last part in a series about an example app that I put together to demonstrate and describe the use of various Google Apps Script features. See Part 1 for an introduction. This part is “Putting it all together and using the OnOpen event to insert a new 2-item menu entry on [...]]]></description>
			<content:encoded><![CDATA[<p>This is Part 5, the last part in a series about an example app that I put together to demonstrate and describe the use of various Google Apps Script features. See <a href="http://www.pipetree.com/qmacro/blog/2011/10/reading-list-mark-2-part-1/">Part 1</a> for an introduction. This part is “<strong>Putting it all together and using the OnOpen event to insert a new 2-item menu entry on the spreadsheet’s page</strong>“.</p>
<p><strong>Parts Overview</strong></p>
<ol>
<li><a href="http://www.pipetree.com/qmacro/blog/2011/10/reading-list-mark-2-part-1/">Introduction to the app, and a short screencast showing the features</a></li>
<li><a href="http://www.pipetree.com/qmacro/blog/2011/10/reading-list-mark-2-part-2/">Using the Tasks API to retrieve and insert tasklists, and the Ui Services to build the tasklist chooser component</a></li>
<li><a href="http://www.pipetree.com/qmacro/blog/2011/10/reading-list-mark-2-part-3/">Using the UrlFetch Services to interact with the Google+ API and grab info on articles pointed to by users in their activity stream</a></li>
<li><a href="http://www.pipetree.com/qmacro/blog/2011/10/reading-list-mark-2-part-4/">Synchronising the URL list in the spreadsheet with corresponding tasks in the chosen tasklist</a></li>
<li><a href="http://www.pipetree.com/qmacro/blog/2011/10/reading-list-mark-2-part-5/">Putting it all together and using the OnOpen event to insert a new 2-item menu entry on the spreadsheet’s page</a> <strong>&lt;– You Are Here</strong></li>
</ol>
<p><strong>Putting it all together</strong></p>
<p>So at this stage we&#8217;ve done pretty much everything required for this example app. The final task is to extend the standard Spreadsheet menu to give the user access to the custom features of selecting a tasklist, and kicking off an update (URL pull and synchronisation). It&#8217;s very easy to extend the menu; in a few lines of code we&#8217;re going to end up with something like this:</p>
<div id="attachment_1202" class="wp-caption alignnone" style="width: 320px"><a href="http://www.pipetree.com/qmacro/blog/wp-content/uploads/2011/10/menu.png"><img class="size-full wp-image-1202" title="Menu" src="http://www.pipetree.com/qmacro/blog/wp-content/uploads/2011/10/menu.png" alt="" width="310" height="105" /></a><p class="wp-caption-text">Menu</p></div>
<p>It&#8217;s as simple as this:</p>
<pre name="code" class="javascript">function onOpen() {
  var ss = SpreadsheetApp.getActiveSpreadsheet();
  var menuEntries = [
    {name: "Update", functionName: "update"},
    {name: "Select Task List", functionName: "taskListUi"}
  ];
  ss.addMenu("Articles", menuEntries);
}</pre>
<p>We use the <a href="http://code.google.com/googleapps/appsscript/class_spreadsheet.html#addMenu">addMenu</a>() method of the Spreadsheet class to create a new menu entry with an array of objects representing menu items. And the function name? onOpen() is one of a number of <a href="http://code.google.com/googleapps/appsscript/guide_events.html">built-in simple event handler functions</a>; this one runs automatically when a spreadsheet is opened &#8211; an ideal time to extend the menu.</p>
<p><strong>The complete script</strong></p>
<p>So we&#8217;re done with the final part! Let&#8217;s celebrate with the script in its entirety. And a beer. Cheers!</p>
<pre name="code" class="javascript">
// Constants

APIKEY = "AIz...drBs"; // don't forget to get your own and record it here
ACTIVITYLISTURL = "https://www.googleapis.com/plus/v1/people/{userId}/activities/{collection}";
READINGLISTCELL = "D1";
USERIDCELL = "B1";
USERID = "106413090159067280619"; // Fallback default

// update()
// Pulls in article links into sheet and synchronises with task list

function update() {
  // First, check that we have a tasklist id already; it's stored in
  // the comment section of the 'readinglistcell'
  var sh = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
  var taskListId = sh.getRange(READINGLISTCELL).getComment();
  // If we don't have an id, tell the user to choose a tasklist
  if(taskListId === "") {
    SpreadsheetApp.getActiveSpreadsheet().toast(
      "Use Articles -> Select Task List to choose a task list",
      "No Task List",
      5
    );
  // Otherwise, we know which task list to synchronise with, so
  // go and update the reading list with URLs from the Google+ activity
  // list, and then sync that with the task list items
  } else {
    retrieveActivityUrls_();
    synchronise_(taskListId);
  }
}

// taskListUi()
// Displays a Ui to allow the user to select a tasklist to manage
// the reading tasks. Can select an existing task list or create a new one

function taskListUi() {
  var doc = SpreadsheetApp.getActiveSpreadsheet();
  var app = UiApp.createApplication();
  app.setTitle('Task Lists');

  // We'll have a grid and a button in this
  // vertical panel
  var panel = app.createVerticalPanel();

  // Use a listbox to display a choice of existing tasklists
  var lb = app.createListBox(false);
  lb.setName('existingList');
  var tasklists = getTasklists_();
  for (var tl in tasklists) {
    lb.addItem(tasklists[tl].getTitle());
  }  

  // Use the grid to layout the listbox, a textbox for a new list,
  // and some corresponding labels
  var grid = app.createGrid(2, 2);
  grid.setWidget(0,0, app.createLabel("Existing:"));
  grid.setWidget(0,1, lb);
  grid.setWidget(1,0, app.createLabel("Or new:"));
  grid.setWidget(1,1, app.createTextBox().setName('newList'));

  // The only button; handler will be linked to this button click event
  // Remember to add the grid contents to the callback context
  var button = app.createButton("Choose");
  var chooseHandler = app.createServerClickHandler('handleChooseButton_');
  chooseHandler.addCallbackElement(grid);
  button.addClickHandler(chooseHandler);

  // Put it all together and show it
  panel.add(app.createLabel("Select existing or create new list"));
  panel.add(grid);
  panel.add(button);
  app.add(panel);
  doc.show(app);
}  

// handleChooseButton_(e)
// Handler for 'Choose' button on taskListUi Ui; creates a new task list
// if a new one has been specified; grabs the ID of the chosen task list
// and stores the task list name and id in the TASKLISTCELL

function handleChooseButton_(e) {

  // Assume an existing list was chosen
  var selectedList = e.parameter.existingList;

  // But check for a new list being specified; if it as, create
  // a new task list
  if(e.parameter.newList != '') {
    selectedList = e.parameter.newList;
    var newTaskList = Tasks.newTaskList().setTitle(selectedList);
    Tasks.Tasklists.insert(newTaskList);
  }

  // Grab the list of tasklists, because we'll need the id
  var taskLists = getTasklists_();
  var taskListId = -1;
  for(tl in taskLists){
    if(taskLists[tl].getTitle() === selectedList) {
      taskListId = taskLists[tl].getId();
      break;
    }
  }

  // Record the list name and id
  var sh = SpreadsheetApp.getActiveSheet();
  var cell = sh.getRange(READINGLISTCELL);
  cell.setValue(selectedList);
  cell.setComment(taskListId);

  // Close the Ui popup and display the name of the chosen list
  var app = UiApp.getActiveApplication();
  app.close();
  SpreadsheetApp.getActiveSpreadsheet().toast(selectedList, "Selected List", 3);
  return app;
}

// onOpen()
// Event based function called when the spreadsheet is opened; adds items
// to the menu

function onOpen() {
  var ss = SpreadsheetApp.getActiveSpreadsheet();
  var menuEntries = [
    {name: "Update", functionName: "update"},
    {name: "Select Task List", functionName: "taskListUi"}
  ];
  ss.addMenu("Articles", menuEntries);
}

// getTasklists()
// Retrieve a list of the user's tasklists (uses the APIs Services)
// Note that the Tasks Services docu is not accurate here; we would
// expect to be able to use the TasklistsCollection class.

function getTasklists_() {
  var tasklistsList = Tasks.Tasklists.list();
  return tasklistsList.getItems();
}

// retrieveActivityUrls_()
// Use UrlFetch to retrieve a Google+ API resource: activities for a person
// Use Javascript data structures; restrict the number of API calls

function retrieveActivityUrls_() {

  // Grab existing list of URLs
  var sh = SpreadsheetApp.getActiveSheet();
  var lastRow = sh.getLastRow();
  var urlList = sh.getRange(2, 1, lastRow - 1 || 1) .getValues();
  var list = {'old': {}, 'new': []};
  for (var i in urlList){
    list['old'][urlList[i]] = 1;
  }

  // Use the userid in the sheet, fallback to a favourite
  var userid = sh.getRange(USERIDCELL).getValue() || USERID;

  // Build Google+ API resource and retrieve it; parse JSON content
  var actListUrl = buildActivityListUrl_(userid, 'public', APIKEY);
  var jsonString = UrlFetchApp.fetch(actListUrl).getContentText();
  var activities = Utilities.jsonParse(jsonString);

  // We're looking for the item object attachments, where the
  // attachment's objectType is 'article'. We want the url and displayName
  for (var i in activities.items) {
    var attachments = activities.items[i].object.attachments;
    for (var a in attachments) {
      var attachment = attachments[a];
      // We've got a URL and title; store it as new if it doesn't
      // already exist. Store it as list of lists, ready for
      // a setValues([][]) insert
      if (attachment.objectType == 'article') {
        if (! (attachment.url in list['old'])) {
          list['new'].push([attachment.url, attachment.displayName]);
        }
      }
    }
  }

  // Blammo!
  if (list['new'].length) {
    sh.getRange(lastRow + 1, 1, list['new'].length, 2).setValues(list['new']);
  }

}

// synchronise(taskListId)
// Synchronise the URLs in the spreadsheet with items in the chosen tasklist
// The task list item id for a URL is stored in the comment for that URL cell

function synchronise_(taskListId) {

  // Grab list of all URLs, and associated comments
  var sh = SpreadsheetApp.getActiveSheet();
  var urlRange = sh.getRange(2, 1, sh.getLastRow() - 1, 1);
  var urls = urlRange.getValues();
  var comments = urlRange.getComments();

  // For each URL, check the status of the associated task.
  // If there isn't an associated task, create one.
  for (var i = 0, j = urls.length; i < j; i++) {
    if (comments[i] == "") {
      Logger.log("New task");
      var task = Tasks.newTask();
      task.setTitle(urls[i]);
      var newTask = Tasks.Tasks.insert(task, taskListId);
      sh.getRange(i + 2, 1).setComment(newTask.getId());
    } else {
      Logger.log("Existing task");
      var existingTask = Tasks.Tasks.get(taskListId, comments[i][0]);
      if (existingTask.getStatus() === "completed") {
        sh.getRange(i + 2, 1, 1, 2).setFontLine("line-through");
      }
    }
  }
}

// buildActivityListUrl_(userId, collection, apiKey)
// Creates a specific resource address (URL) for the public activities
// for a given person in Google+
// See https://developers.google.com/+/api/latest/activities/list
// This will be obsolete when there are direct Google+ Services for
// Apps Script

function buildActivityListUrl_(userId, collection, apiKey) {

  var actListUrl = ACTIVITYLISTURL;
  actListUrl = actListUrl.replace(/{userId}/, userId);
  actListUrl = actListUrl.replace(/{collection}/, collection);
  actListUrl = actListUrl + '?key=' + apiKey;

  return actListUrl;
}
</pre>
<p>&nbsp;</p>
]]></content:encoded>
			<wfw:commentRss>http://www.pipetree.com/qmacro/blog/2011/10/reading-list-mark-2-part-5/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Reading List Mark 2 &#8211; Part 4</title>
		<link>http://www.pipetree.com/qmacro/blog/2011/10/reading-list-mark-2-part-4/</link>
		<comments>http://www.pipetree.com/qmacro/blog/2011/10/reading-list-mark-2-part-4/#comments</comments>
		<pubDate>Sat, 15 Oct 2011 15:50:45 +0000</pubDate>
		<dc:creator>dj</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[appsscript]]></category>
		<category><![CDATA[gas]]></category>
		<category><![CDATA[google]]></category>
		<category><![CDATA[googleappsscript]]></category>
		<category><![CDATA[gtug]]></category>
		<category><![CDATA[madlab]]></category>
		<category><![CDATA[mangtug]]></category>
		<category><![CDATA[tasks]]></category>
		<category><![CDATA[ui]]></category>
		<category><![CDATA[urlfetch]]></category>

		<guid isPermaLink="false">http://www.pipetree.com/qmacro/blog/?p=1170</guid>
		<description><![CDATA[This is Part 4 in a series about an example app that I put together to demonstrate and describe the use of various Google Apps Script features. See Part 1 for an introduction. This part is “Synchronising the URL list in the spreadsheet with corresponding tasks in the chosen tasklist“. Parts Overview Introduction to the app, [...]]]></description>
			<content:encoded><![CDATA[<p>This is Part 4 in a series about an example app that I put together to demonstrate and describe the use of various Google Apps Script features. See <a href="http://www.pipetree.com/qmacro/blog/2011/10/reading-list-mark-2-part-1/">Part 1</a> for an introduction. This part is “<strong>Synchronising the URL list in the spreadsheet with corresponding tasks in the chosen tasklist</strong>“.</p>
<p><strong>Parts Overview</strong></p>
<ol>
<li><a href="http://www.pipetree.com/qmacro/blog/2011/10/reading-list-mark-2-part-1/">Introduction to the app, and a short screencast showing the features</a></li>
<li><a href="http://www.pipetree.com/qmacro/blog/2011/10/reading-list-mark-2-part-2/">Using the Tasks API to retrieve and insert tasklists, and the Ui Services to build the tasklist chooser component</a></li>
<li><a href="http://www.pipetree.com/qmacro/blog/2011/10/reading-list-mark-2-part-3/">Using the UrlFetch Services to interact with the Google+ API and grab info on articles pointed to by users in their activity stream</a></li>
<li><a href="http://www.pipetree.com/qmacro/blog/2011/10/reading-list-mark-2-part-4/">Synchronising the URL list in the spreadsheet with corresponding tasks in the chosen tasklist</a> <strong>&lt;– You Are Here</strong></li>
<li><a href="http://www.pipetree.com/qmacro/blog/2011/10/reading-list-mark-2-part-5/">Putting it all together and using the OnOpen event to insert a new 2-item menu entry on the spreadsheet’s page</a></li>
</ol>
<p><strong>Putting this into context: the Update request</strong></p>
<p>We&#8217;ve covered a lot of ground in the previous three parts in this series. Now we&#8217;re at the stage where we have the functions for</p>
<ul>
<li>creating a Ui for choosing an existing / creating a new tasklist</li>
<li>handling the button event on the Ui</li>
<li>getting a list of tasklists</li>
<li>retrieving URLs from a Google+ activity stream</li>
</ul>
<p>So the one main piece of work outstanding is synchronising the retrieved URLs as tasks on the chosen tasklist.</p>
<p>If you watch the <a href="http://www.youtube.com/watch?v=F08qS8ZmlZ0">screencast</a> shown in <a href="http://www.pipetree.com/qmacro/blog/2011/10/reading-list-mark-2-part-1/">Part 1</a> you&#8217;ll see that the synchronisation is part of a more general &#8216;update&#8217; request, that includes the fetching of new URLs from Google+ and synchronising them with the tasklist. So let&#8217;s have a look at the function that binds those two things together.</p>
<p>Here&#8217;s the update() function, which we&#8217;ll allow the user to call from a menu item (we&#8217;ll cover this in the next instalment).</p>
<pre class="javascript" name="code">READINGLISTCELL = 'D1';

function update() {
  // First, check that we have a tasklist id already; it's stored in
  // the comment section of the 'readinglistcell'
  var sh = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
  var taskListId = sh.getRange(READINGLISTCELL).getComment();
  // If we don't have an id, tell the user to choose a tasklist
  if(taskListId === '') {
    SpreadsheetApp.getActiveSpreadsheet().toast(
      "Use Articles -&gt; Select Task List to choose a task list",
      "No Task List",
      5
    );
  // Otherwise, we know which task list to synchronise with, so
  // go and update the reading list with URLs from the Google+ activity
  // list, and then sync that with the task list items
  } else {
    retrieveActivityUrls_();
    synchronise_(taskListId);
  }
}</pre>
<p>This function grabs a reference to the active sheet, and pulls the comment from the cell that we&#8217;ve designated as where the reading list tasklist info is stored: READINGLISTCELL. The name is stored in the cell, and the ID is stored in the cell&#8217;s comment. If there isn&#8217;t an ID, then we&#8217;ll ask the user to choose a tasklist using the Ui we built in <a href="http://www.pipetree.com/qmacro/blog/2011/10/reading-list-mark-2-part-2/">Part 2</a>. The <a href="http://code.google.com/googleapps/appsscript/class_browser.html">Browser</a> class in Google Apps Script&#8217;s <a href="http://code.google.com/googleapps/appsscript/service_base.html">Base Services</a> gives us a nice dialog box that looks like this:</p>
<div id="attachment_1198" class="wp-caption alignnone" style="width: 316px"><a href="http://www.pipetree.com/qmacro/blog/wp-content/uploads/2011/10/notamessage1.png"><img class="size-full wp-image-1198" title="Message Box" src="http://www.pipetree.com/qmacro/blog/wp-content/uploads/2011/10/notamessage1.png" alt="" width="306" height="229" /></a><p class="wp-caption-text">Message Box</p></div>
<p>But there&#8217;s also a nice visual message feature that&#8217;s available in the <a href="http://code.google.com/googleapps/appsscript/service_spreadsheet.html">Spreadsheet Services</a>, specific to a spreadsheet: <a href="http://code.google.com/googleapps/appsscript/class_spreadsheet.html#toast">toast()</a>. Calling this causes a popup to appear in the lower right of the screen, which stays visible for a short while. This is what it looks like:</p>
<div id="attachment_1177" class="wp-caption alignnone" style="width: 269px"><a href="http://www.pipetree.com/qmacro/blog/wp-content/uploads/2011/10/notasklist.png"><img class="size-full wp-image-1177" title="Toast message" src="http://www.pipetree.com/qmacro/blog/wp-content/uploads/2011/10/notasklist.png" alt="" width="259" height="140" /></a><p class="wp-caption-text">Toast message</p></div>
<p>Because the &#8216;toast&#8217; name is so evocative, we&#8217;ll use it in our function to prompt the user to choose a tasklist.</p>
<p>If there&#8217;s already a tasklist chosen, then we go straight into retrieving the URLs (see <a href="http://www.pipetree.com/qmacro/blog/2011/10/reading-list-mark-2-part-3/">Part 3</a>) and then call the synchronise_() function, passing the ID of the tasklist.</p>
<p><strong>Synchronising URLs and Tasks</strong></p>
<p>Ok, so what do we need to do to synchronise the URLs? It&#8217;s similar to the technique described in the great article &#8220;<a href="http://code.google.com/googleapps/appsscript/articles/google_apis_reading_list.html">Integrating with Google APIs &#8211; Creating a simple reading list</a>&#8220;. There are a couple of differences: I&#8217;m not going to use the <a href="http://code.google.com/googleapps/appsscript/service_urlshortener.html">UrlShortener Services</a>, and I&#8217;m going to try and reduce the number of API calls by bulk-grabbing the cell data.</p>
<p>First, we get a range reference on the active sheet, which equates to the list of URLs already there. We get all of the URLs (urlRange.getValues()) and all of the corresponding comments (urlRange.getComments()).</p>
<pre class="javascript" name="code">function synchronise_(taskListId) {

  // Grab list of all URLs, and associated comments
  var sh = SpreadsheetApp.getActiveSheet();
  var urlRange = sh.getRange(2, 1, sh.getLastRow() - 1, 1);
  var urls = urlRange.getValues();
  var comments = urlRange.getComments();</pre>
<p>We go through each of the URLs, and create a new task in the tasklist if there isn&#8217;t already something in the comment for that URL:</p>
<ul>
<li>instantiate a new task object: Tasks.newTask()</li>
<li>add the title: task.setTitle()</li>
<li>add the task to the tasklist: Tasks.Tasks.insert()</li>
<li>insert the new task&#8217;s ID into the comment for the URL: setComment()</li>
</ul>
<p>Otherwise we&#8217;ve already created a task for the URL, so we grab the task to get the status, and if it&#8217;s marked as completed, we format the URL and corresponding description (in the next column) to set strike-through text.</p>
<pre class="javascript" name="code">  // For each URL, check the status of the associated task.
  // If there isn't an associated task, create one.
  for (var i = 0, j = urls.length; i &lt; j; i++) {
    if (comments[i] == "") {
      Logger.log("New task");
      var task = Tasks.newTask();
      task.setTitle(urls[i]);
      var newTask = Tasks.Tasks.insert(task, taskListId);
      sh.getRange(i + 2, 1).setComment(newTask.getId());
    } else {
      Logger.log("Existing task");
      var existingTask = Tasks.Tasks.get(taskListId, comments[i][0]);
      if (existingTask.getStatus() === "completed") {
        sh.getRange(i + 2, 1, 1, 2).setFontLine('line-through');
      }
    }
  }
}</pre>
<p>That&#8217;s it. Stop by next time for the last part in this series, where we put everything together and insert a 2-item menu entry to tie it all together. Thanks for reading!</p>
<p>&nbsp;</p>
]]></content:encoded>
			<wfw:commentRss>http://www.pipetree.com/qmacro/blog/2011/10/reading-list-mark-2-part-4/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
	</channel>
</rss>

