<?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>Marcus Povey &#187; api</title>
	<atom:link href="http://www.marcus-povey.co.uk/tag/api/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.marcus-povey.co.uk</link>
	<description>Making the world a better place, one byte at a time...</description>
	<lastBuildDate>Fri, 27 Jan 2012 15:45:26 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.1.1</generator>
	<atom:link rel='hub' href='http://www.marcus-povey.co.uk/?pushpress=hub'/>
		<item>
		<title>Latakoo Flight API bindings for Python, PHP, Ruby and .NET</title>
		<link>http://www.marcus-povey.co.uk/2012/01/13/latakoo-flight-api-bindings-for-python-php-and-net/</link>
		<comments>http://www.marcus-povey.co.uk/2012/01/13/latakoo-flight-api-bindings-for-python-php-and-net/#comments</comments>
		<pubDate>Fri, 13 Jan 2012 08:40:00 +0000</pubDate>
		<dc:creator>Marcus Povey</dc:creator>
				<category><![CDATA[Latakoo]]></category>
		<category><![CDATA[.net]]></category>
		<category><![CDATA[api]]></category>
		<category><![CDATA[C]]></category>
		<category><![CDATA[github]]></category>
		<category><![CDATA[latakoo]]></category>
		<category><![CDATA[library]]></category>
		<category><![CDATA[mono]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[python]]></category>
		<category><![CDATA[ruby]]></category>

		<guid isPermaLink="false">http://www.marcus-povey.co.uk/?p=988</guid>
		<description><![CDATA[I got bored one evening, so I hacked together the beginnings of an API library for latakoo Flight. Currently it&#8217;s available in three four tasty flavours &#8211; PHP, Python, Ruby and C# .NET / Mono. The libraries are minimal but functional; they let you perform both anonymous and authenticated queries against the latakoo API endpoint, [...]]]></description>
			<content:encoded><![CDATA[<p><img src="http://www.marcus-povey.co.uk/wp-content/pythonmonophplatakoo.jpg" align="right" width="200" />I got bored one evening, so I hacked together the beginnings of an API library for <a href="http://latakoo.com">latakoo Flight</a>. Currently it&#8217;s available in <strike>three</strike> four tasty flavours &#8211; <a href="https://github.com/mapkyca/Latakoo-Flight-API-Client/tree/master/php">PHP</a>, <a href="https://github.com/mapkyca/Latakoo-Flight-API-Client/tree/master/python">Python</a>, <a href="https://github.com/mapkyca/Latakoo-Flight-API-Client/tree/master/ruby">Ruby</a> and <a href="https://github.com/mapkyca/Latakoo-Flight-API-Client/tree/master/mono">C# .NET / Mono</a>.</p>
<p>The libraries are minimal but functional; they let you perform both anonymous and authenticated queries against the latakoo API endpoint, but I&#8217;ve only had time to add method wrappers for a few of api calls. Feel free to fork the project to help flesh these out!</p>
<p>Hopefully these libraries will make it easier to get the power of <a href="http://latakoo.com">latakoo</a> behind your project. </p>
<p>Happy hacking!</p>
<p>&raquo; <a href="http://docs.latakoo.com">API Documentation</a><br />
&raquo; <a href="https://github.com/mapkyca/Latakoo-Flight-API-Client">Github Project Page</a></p>
<div class="wsbuttons">
	<div class="shareblob facebook">
		<div class="fb-like" data-href="http://www.marcus-povey.co.uk/2012/01/13/latakoo-flight-api-bindings-for-python-php-and-net/" data-send="false" data-layout="box_count" data-width="60" data-show-faces="false" data-colorscheme="light"></div>
	</div>

	<div class="shareblob google">
		<div class="g-plusone" data-size="tall" data-href="http://www.marcus-povey.co.uk/2012/01/13/latakoo-flight-api-bindings-for-python-php-and-net/"></div>
	</div>

	<div class="shareblob twitter">
		<div class="twitter">
			<a href="https://twitter.com/share?url=http%3A%2F%2Fwww.marcus-povey.co.uk%2F2012%2F01%2F13%2Flatakoo-flight-api-bindings-for-python-php-and-net%2F&count=vertical" class="twitter-share-button" data-lang="en">Tweet</a>
			<script>!function(d,s,id){var js,fjs=d.getElementsByTagName(s)[0];if(!d.getElementById(id)){js=d.createElement(s);js.id=id;js.src="//platform.twitter.com/widgets.js";fjs.parentNode.insertBefore(js,fjs);}}(document,"script","twitter-wjs");</script>
		</div>
	</div>

</div>
	]]></content:encoded>
			<wfw:commentRss>http://www.marcus-povey.co.uk/2012/01/13/latakoo-flight-api-bindings-for-python-php-and-net/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Idea: Lets give roads, junctions and intersections URLs</title>
		<link>http://www.marcus-povey.co.uk/2011/12/08/idea-lets-give-roads-junctions-and-intersections-urls/</link>
		<comments>http://www.marcus-povey.co.uk/2011/12/08/idea-lets-give-roads-junctions-and-intersections-urls/#comments</comments>
		<pubDate>Thu, 08 Dec 2011 16:23:33 +0000</pubDate>
		<dc:creator>Marcus Povey</dc:creator>
				<category><![CDATA[Data]]></category>
		<category><![CDATA[Software]]></category>
		<category><![CDATA[api]]></category>
		<category><![CDATA[feeds]]></category>
		<category><![CDATA[google]]></category>
		<category><![CDATA[ifttt]]></category>
		<category><![CDATA[maps]]></category>
		<category><![CDATA[traffic]]></category>
		<category><![CDATA[urls]]></category>

		<guid isPermaLink="false">http://www.marcus-povey.co.uk/?p=821</guid>
		<description><![CDATA[I like feeds and APIs. Feeds and APIs provide ways for others to access a service and to recombine the data in new and unexpected ways. Ways that have consistently been proven to be beneficial to both parties (which makes google&#8217;s increasing antipathy towards them an interesting, not to mention short sighted, trend). Anyway, it [...]]]></description>
			<content:encoded><![CDATA[<p><img src="http://www.marcus-povey.co.uk/wp-content/DSC_0237-300x199.jpg" width="200" align="right" />I like feeds and APIs.</p>
<p>Feeds and APIs provide ways for others to access a service and to recombine the data in new and unexpected ways. Ways that have consistently been proven to be beneficial to both parties (which makes google&#8217;s increasing antipathy towards them an interesting, not to mention short sighted, trend).</p>
<p>Anyway, it was one morning when I was attempting to find a route to work for my girlfriend which bypassed the numerous arterial route crashes that had happened that morning and <a href="https://twitter.com/#!/mapkyca/status/141458360263389184">I found myself pondering thus</a>&#8230;</p>
<p>&#8230; wouldn&#8217;t it be cool if roads and junctions had permanent URLs, and better yet if you could get a data feed on them? </p>
<p>This would let you do many cool things, for example you could enter your route to work and get a status of the traffic en route &#8211; or at the very least attach a particular traffic blackspot (in our case the <em>13 bends of death</em> on the <a href="http://en.wikipedia.org/wiki/A4074_road">A4074</a>) to <a href="http://ifttt.com/">ifttt</a> and get SMS alerts if there was a problem.</p>
<p>Giving roads and junctions addressable urls would be an obvious extension to the google maps API, but given that Google won&#8217;t even let you embed a map in a page if it contains a traffic data overlay it seems unlikely they&#8217;ll provide such access to their data. Other sources such as the <a href="http://developer.yahoo.com/traffic/rest/V1/index.html">Yahoo&#8217;s traffic API</a> has long since been shut down.</p>
<p><strong>So, what alternative traffic data sources could we use?</strong></p>
<p>One possible data source we could use would be to parse a <a href="https://twitter.com/#!/search/a4074">twitter search for the road in question</a>. We both currently use ifttt hookups to get alerts for certain key roads, so the basic concept is sound.</p>
<p>This isn&#8217;t perfect, for example there is no understanding of the context of a message &#8211; so for example a message saying <em>&#8220;No traffic problems on the A4074&#8243;</em> and <em>&#8220;Terrible crash on the A4074&#8243;</em> would both trigger the alert, but only the latter would indicate a problem.</p>
<p>The other problem of course is that it also relies on people tweeting, but in effect this would actually pull in quite a diverse range of secondary sources &#8211; in my case, for example, it also pulls in any source that feed into the <a href="http://jackfm.co.uk/">local radio station</a> &#8211; which includes reports from their traffic spotter plane.</p>
<p>As an individual without access to data from traffic sensors, or any ability to collect data directly (unlike, say, google who can use position reports from android phones), we are pretty much limited to collecting data from secondary sources as far as I can see.</p>
<p>What other sources could we use?</p>
<div class="wsbuttons">
	<div class="shareblob facebook">
		<div class="fb-like" data-href="http://www.marcus-povey.co.uk/2011/12/08/idea-lets-give-roads-junctions-and-intersections-urls/" data-send="false" data-layout="box_count" data-width="60" data-show-faces="false" data-colorscheme="light"></div>
	</div>

	<div class="shareblob google">
		<div class="g-plusone" data-size="tall" data-href="http://www.marcus-povey.co.uk/2011/12/08/idea-lets-give-roads-junctions-and-intersections-urls/"></div>
	</div>

	<div class="shareblob twitter">
		<div class="twitter">
			<a href="https://twitter.com/share?url=http%3A%2F%2Fwww.marcus-povey.co.uk%2F2011%2F12%2F08%2Fidea-lets-give-roads-junctions-and-intersections-urls%2F&count=vertical" class="twitter-share-button" data-lang="en">Tweet</a>
			<script>!function(d,s,id){var js,fjs=d.getElementsByTagName(s)[0];if(!d.getElementById(id)){js=d.createElement(s);js.id=id;js.src="//platform.twitter.com/widgets.js";fjs.parentNode.insertBefore(js,fjs);}}(document,"script","twitter-wjs");</script>
		</div>
	</div>

</div>
	]]></content:encoded>
			<wfw:commentRss>http://www.marcus-povey.co.uk/2011/12/08/idea-lets-give-roads-junctions-and-intersections-urls/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Using Elgg&#8217;s REST-like API</title>
		<link>http://www.marcus-povey.co.uk/2009/08/25/using-elggs-rest-like-api/</link>
		<comments>http://www.marcus-povey.co.uk/2009/08/25/using-elggs-rest-like-api/#comments</comments>
		<pubDate>Tue, 25 Aug 2009 14:20:04 +0000</pubDate>
		<dc:creator>Marcus Povey</dc:creator>
				<category><![CDATA[elgg]]></category>
		<category><![CDATA[#ue]]></category>
		<category><![CDATA[api]]></category>
		<category><![CDATA[endpoint]]></category>
		<category><![CDATA[get]]></category>
		<category><![CDATA[handler]]></category>
		<category><![CDATA[howto]]></category>
		<category><![CDATA[post]]></category>
		<category><![CDATA[rest]]></category>
		<category><![CDATA[token]]></category>
		<category><![CDATA[tutorial]]></category>

		<guid isPermaLink="false">http://www.marcus-povey.co.uk/?p=272</guid>
		<description><![CDATA[Another one of Elgg&#8216;s less documented but very powerful features is the ability to expose functionality from the core and user modules in a standard way via a REST like API. This gives you the opportunity to develop interoperable web services and provide them to the users of your site, all in a standardised way. [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://xkcd.com/262/"><img title="in_ur_reality" src="http://www.marcus-povey.co.uk/wp-content/in_ur_reality.png" alt="in_ur_reality" width="200" align="right" /></a>Another one of <a href="http://www.elgg.org">Elgg</a>&#8216;s less documented but very powerful features is the ability to expose functionality from the core and user modules in a standard way via a REST like API.</p>
<p>This gives you the opportunity to develop interoperable web services and provide them to the users of your site, all in a standardised way.</p>
<h2>The endpoint</h2>
<p>To make an API call you must direct your query at a special URL. This query will be either a GET or a POST query (depending on the command you are executing), the specific endpoint you use depends on the format you want the return value returned in.</p>
<p>The endpoint:</p>
<blockquote><p><code>http://yoursite.com/pg/api/<strong>[protocol]</strong>/<strong>[return format]</strong>/</code></p></blockquote>
<p>Where:</p>
<ul>
<li><strong>[protocol]</strong> is the protocol being used, in this case and for the moment only &#8220;rest&#8221; is supported.</li>
<li><strong>[return format]</strong> is the format you want your information returned in, either &#8220;php&#8221;, &#8220;json&#8221; or &#8220;xml&#8221;.</li>
</ul>
<p>This endpoint should then be passed the method and any parameters as GET variables, so for example:</p>
<blockquote><p><code>http://yoursite.com/pg/api/rest/xml/?method=test.test&amp;myparam=foo&amp;anotherparam=bar</code></p></blockquote>
<p>Would pass &#8220;foo&#8221; and &#8220;bar&#8221; as the given named parameters to the function &#8220;test.test&#8221; and return the result in XML format.</p>
<p>Notice here also that the API uses the &#8220;PG&#8221; page handler extension, this means that it would be a relatively simple matter to add a new API protocol or replace the entire API subsystem in a module &#8211; should you be so inclined.</p>
<p><strong>Return result</strong></p>
<p>The result of the api call will be an entity encoded in your chosen format.</p>
<p>This entity will have a &#8220;status&#8221; parameter &#8211; zero for success, non-zero denotes an error. Result data will be in the &#8220;result&#8221; parameter. You may also receive some messages and debug information.</p>
<h2>Exporting a function</h2>
<p>Any Elgg function &#8211; core or module &#8211; can be exposed via the API, all you have to do is declare it using <code><a href="http://reference.elgg.org/api_8php.html#3ee7de907c28ff90ec8b7ffc52254484">expose_function()</a></code> from within your code, passing the method name, handler and any parameters (note that these parameters must be declared in the same order as they appear in your function).</p>
<p><strong>Listing functions</strong></p>
<p>You can see a list of all registered functions using the built in api command &#8220;system.api.list&#8221;, this is also a useful test to see if your client is configured correctly.</p>
<p>E.g.</p>
<blockquote><p><code>http://yoursite.com/pg/api/rest/xml/?method=system.api.list</code></p></blockquote>
<h2>Authorising and authenticating</h2>
<p>Most commands will require some form of authorisation in order to function. There are two main types of authorisation &#8211; protocol level which determines whether a given client is permitted to connect, and user level where a command whereby a user requires a special token in lieu of a username and password.</p>
<p><strong>Protocol level authentication</strong><br />
Protocol level authentication is a way to ensure that commands only come from approved clients for which you have previously given keys. This is in keeping with many web based API systems and permits you to disconnect clients who abuse your system, or track usage for accountancy purposes.</p>
<p>The client must send a <a href="http://en.wikipedia.org/wiki/HMAC">HMAC</a> signature together with a set of special HTTP headers when making a call. This ensures that the API call is being made from the stated client and that the data has not been tampered with.</p>
<p>Eagle-eyed readers with long memories will see a lot of similarity with the <a href="http://www.marcus-povey.co.uk/2008/02/21/getting-started-with-the-elggvoices-api-part-1-api-basics/">ElggVoices API</a> I wrote about previously.</p>
<p>The HMAC must be constructed over the following data:</p>
<ul>
<li>The Secret Key provided by the target Elgg install (as provided easily by the APIAdmin plugin).</li>
<li>The current unix time in microseconds as a floating point decimal, produced my microtime(true).</li>
<li>Your API key identifying you to the Elgg api server (companion to your secret key).</li>
<li>URLEncoded string representation of any GET variable parameters, eg &#8220;method=test.test&amp;foo=bar&#8221;</li>
<li>If you are sending post data, the hash of this data.</li>
</ul>
<p>Some extra information must be added to the HTTP header in order for this data to be correctly processed:</p>
<ul>
<li><strong>X-Elgg-apikey</strong> &#8211; The API key (not the secret key!)</li>
<li><strong>X-Elgg-time</strong> &#8211; Microtime used in the HMAC calculation</li>
<li><strong>X-Elgg-hmac</strong> &#8211; The HMAC as hex characters.</li>
<li><strong>X-Elgg-hmac-algo</strong> &#8211; The algorithm used in the HMAC calculation &#8211; eg, sha1, md5 etc</li>
</ul>
<p>If you are sending POST data you must also send:</p>
<ul>
<li><strong>X-Elgg-posthash</strong> &#8211; The hash of the POST data.</li>
<li><strong>X-Elgg-posthash-algo</strong> &#8211; The algorithm used to produce the POST data hash &#8211; eg, md5.</li>
<li><strong>Content-type</strong> &#8211; The content type of the data you are sending (if in doubt use <code>application/octet-stream</code>).</li>
<li><strong>Content-Length</strong> &#8211; The length in bytes of your POST data.</li>
</ul>
<p>Much of this will be handled for you if you use the <a href="http://reference.elgg.org/api_8php.html#8b98a982e4462bfa0c752e124bb98c0c">built in Elgg API Client</a>.</p>
<p><strong>User level tokens</strong></p>
<p>User level tokens are used to identify a specific user on the target system, in much the same way as if they were to log in with their user name and password, but without the need to send this for every API call.</p>
<p>Tokens are time limited, and so it will be necessary for your client to periodically refresh the token they use to identify the user.</p>
<p>Tokens are generated by using the API command &#8220;auth.gettoken&#8221; and passing the username and password as parameters, eg:</p>
<blockquote><p><code>http://yoursite.com/pg/api/rest/xml/?method=auth.gettoken&amp;username=foo&amp;password=bar</code></p></blockquote>
<p><strong>Anonymous methods</strong><br />
Anonymous methods (such as &#8220;system.api.list&#8221;) can be executed without any form of authentication, thus accepting connections from any client and regardless of whether they provide a user token. This is useful in certain situations and it goes without saying that you don&#8217;t expose sensitive functionality this way.</p>
<p>To do so set $anonymous=true in your call to expose_function().</p>
<p><small>Image “<a href="http://xkcd.com/262/">In UR Reality</a>” by <a href="http://www.xkcd.com">XKCD</a></small></p>
<div class="wsbuttons">
	<div class="shareblob facebook">
		<div class="fb-like" data-href="http://www.marcus-povey.co.uk/2009/08/25/using-elggs-rest-like-api/" data-send="false" data-layout="box_count" data-width="60" data-show-faces="false" data-colorscheme="light"></div>
	</div>

	<div class="shareblob google">
		<div class="g-plusone" data-size="tall" data-href="http://www.marcus-povey.co.uk/2009/08/25/using-elggs-rest-like-api/"></div>
	</div>

	<div class="shareblob twitter">
		<div class="twitter">
			<a href="https://twitter.com/share?url=http%3A%2F%2Fwww.marcus-povey.co.uk%2F2009%2F08%2F25%2Fusing-elggs-rest-like-api%2F&count=vertical" class="twitter-share-button" data-lang="en">Tweet</a>
			<script>!function(d,s,id){var js,fjs=d.getElementsByTagName(s)[0];if(!d.getElementById(id)){js=d.createElement(s);js.id=id;js.src="//platform.twitter.com/widgets.js";fjs.parentNode.insertBefore(js,fjs);}}(document,"script","twitter-wjs");</script>
		</div>
	</div>

</div>
	]]></content:encoded>
			<wfw:commentRss>http://www.marcus-povey.co.uk/2009/08/25/using-elggs-rest-like-api/feed/</wfw:commentRss>
		<slash:comments>7</slash:comments>
		</item>
		<item>
		<title>The case for OpenID lite</title>
		<link>http://www.marcus-povey.co.uk/2009/04/08/the-case-for-openid-lite/</link>
		<comments>http://www.marcus-povey.co.uk/2009/04/08/the-case-for-openid-lite/#comments</comments>
		<pubDate>Wed, 08 Apr 2009 14:59:54 +0000</pubDate>
		<dc:creator>Marcus Povey</dc:creator>
				<category><![CDATA[Software]]></category>
		<category><![CDATA[api]]></category>
		<category><![CDATA[barcamptransparency]]></category>
		<category><![CDATA[oauth]]></category>
		<category><![CDATA[openid]]></category>
		<category><![CDATA[rest]]></category>

		<guid isPermaLink="false">http://www.marcus-povey.co.uk/?p=170</guid>
		<description><![CDATA[Recently &#8211; both in my roll as a developer on the Elgg project, and as one of the organisers of Barcamp Transparency &#8211; I have found myself having to sign up for a whole bunch of accounts for various sites. Each one asks me to fill in a profile, and each time I end up [...]]]></description>
			<content:encoded><![CDATA[<p>Recently &#8211; both in my roll as a developer on the <a href="http://www.elgg.org">Elgg project</a>, and as one of the organisers of <a href="http://barcamptransparency.pbwiki.com/FrontPage">Barcamp Transparency</a> &#8211; I have found myself having to sign up for a whole bunch of accounts for various sites.</p>
<p>Each one asks me to fill in a profile, and each time I end up repeating myself. I am sick of it. This is the kind of thing <a href="http://en.wikipedia.org/wiki/OpenID">OpenID</a> was developed to partially solve, however I think this is overkill.</p>
<p>OpenID (<a href="http://benwerd.com/2009/04/notes-from-barcamp-oxford/">as mentioned elsewhere</a>) has problems and its uptake is declining. I rather think this is because it is trying to do far too much.</p>
<p><a href="http://www.gravatar.com">Gravatar</a> on the other-hand is simple and to the point, requires the end user to do very little and is pretty damn simple to implement from a server point of view.</p>
<p>Could the same approach be used for profile fields? I think yes, and here&#8217;s how it might work&#8230;</p>
<ul>
<li>First of all, we have a site somewhere which lets a user create an account and fill in their profile fields.</li>
<li>The profile comes pre-populated with common labels (name, description, location, interests etc), but lets users add extra fields if they like.</li>
<li>The service has a REST like API at the back end which accepts queries like: <strong>http://fooprofile.com/api/<em>[field]</em>/<em>[md5 hash of email address]</em>/</strong> to which it returns a blob of text.</li>
<li>When a user creates a new account on bar.com, that site should attempt to pre-populate any profile fields with data from the service based on an md5 hash of their email address. These can of course be overridden locally.</li>
<li>Periodically bar.com should update its fields via the API, unless the user has overridden the profile field (or has otherwise selected not to do so).</li>
</ul>
<p>Crucially with this light method, the user experience of the site remains pretty much unchanged and all the hard work is done magically in the background.</p>
<p>I also think that there is no need to specify what fields constitute a profile. The semantics of this will likely evolve naturally over time and there is no way to predict what extra fields will be needed. You wouldn&#8217;t dictate what tags someone would use, so why dictate profile fields?</p>
<p>In phase two of this you could easily imagine using <a href="http://en.wikipedia.org/wiki/OAuth">OAuth</a> to decide which fields a site has access to.</p>
<p>You could also imagine multiple providers being possible (providing the api was consistent). So when a user signs in to bar.com they are asked who there provider is &#8211; so they could select fooprofile.com or wibbleprofile.co.uk or any other provider. This would keep OpenID&#8217;s distributed nature, but without confusing the user too much &#8211; a url is always a url in this model.</p>
<p>So all that leaves is the single point authentication aspect as a distinct and separate problem, and one which must be solved in a way that is transparent to the user &#8211; perhaps an encrypted and <a href="http://en.wikipedia.org/wiki/Public_key">public key</a> authenticated token exchange using a similar technology as the above?</p>
<p>Just pondering&#8230;.</p>
<p><strong>Update:</strong> I have bashed together an example of the sort of thing I was talking about over here: <a href="http://skunk.marcus-povey.co.uk/aer/">http://skunk.marcus-povey.co.uk/aer/</a></p>
<div class="wsbuttons">
	<div class="shareblob facebook">
		<div class="fb-like" data-href="http://www.marcus-povey.co.uk/2009/04/08/the-case-for-openid-lite/" data-send="false" data-layout="box_count" data-width="60" data-show-faces="false" data-colorscheme="light"></div>
	</div>

	<div class="shareblob google">
		<div class="g-plusone" data-size="tall" data-href="http://www.marcus-povey.co.uk/2009/04/08/the-case-for-openid-lite/"></div>
	</div>

	<div class="shareblob twitter">
		<div class="twitter">
			<a href="https://twitter.com/share?url=http%3A%2F%2Fwww.marcus-povey.co.uk%2F2009%2F04%2F08%2Fthe-case-for-openid-lite%2F&count=vertical" class="twitter-share-button" data-lang="en">Tweet</a>
			<script>!function(d,s,id){var js,fjs=d.getElementsByTagName(s)[0];if(!d.getElementById(id)){js=d.createElement(s);js.id=id;js.src="//platform.twitter.com/widgets.js";fjs.parentNode.insertBefore(js,fjs);}}(document,"script","twitter-wjs");</script>
		</div>
	</div>

</div>
	]]></content:encoded>
			<wfw:commentRss>http://www.marcus-povey.co.uk/2009/04/08/the-case-for-openid-lite/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Bug tracking</title>
		<link>http://www.marcus-povey.co.uk/2009/03/10/bug-tracking/</link>
		<comments>http://www.marcus-povey.co.uk/2009/03/10/bug-tracking/#comments</comments>
		<pubDate>Tue, 10 Mar 2009 16:46:48 +0000</pubDate>
		<dc:creator>Marcus Povey</dc:creator>
				<category><![CDATA[Software]]></category>
		<category><![CDATA[api]]></category>
		<category><![CDATA[bugtrackers]]></category>
		<category><![CDATA[bugzilla]]></category>
		<category><![CDATA[eclipse]]></category>
		<category><![CDATA[mylyn]]></category>
		<category><![CDATA[svn]]></category>
		<category><![CDATA[tag]]></category>
		<category><![CDATA[tag clustering]]></category>
		<category><![CDATA[trac]]></category>

		<guid isPermaLink="false">http://www.marcus-povey.co.uk/?p=136</guid>
		<description><![CDATA[Over on his blog, my good friend and colleague Ben has written a good post about bugtrackers. He is essentially complaining that there are currently none available that are good for both developers and end users. Broadly speaking I agree with him. The two main players &#8211; Bugzilla and Trac &#8211; are both lacking. Bugzilla&#8217;s [...]]]></description>
			<content:encoded><![CDATA[<p>Over on his blog, my good friend and colleague Ben has written a <a href="http://benwerd.com/2009/03/bug-tracking/">good post about bugtrackers</a>. He is essentially complaining that there are currently none available that are good for both developers and end users.</p>
<p>Broadly speaking I agree with him. The two main players &#8211; <a href="http://www.bugzilla.org">Bugzilla</a> and <a href="http://trac.edgewall.org/">Trac</a> &#8211; are both lacking. Bugzilla&#8217;s interface has notable usability issues, and trac too is somewhat lacking.</p>
<p>In both cases however, the core functionality of what a bugtracker actually <em>does</em> &#8211; a prioritised and editable todo list &#8211; works perfectly.</p>
<p>The problem is interface.</p>
<p>How do we create one that is useful to both developers (who need quite detailed settings) and end users (who need a simple interface and in many cases need a certain amount of hand holding in order to fill in a report which is useful to the developer)?</p>
<p>Thinking back to my usage of both Bugzilla and Trac &#8211; the answer is that we don&#8217;t.</p>
<p>Let me explain: I have used both Bugzilla and Trac in anguish on large projects for many many years, but I have hardly ever used the default interface &#8211; currently I use the excellent <a href="http://www.eclipse.org/mylyn/">Mylyn</a> (nee Mylar) for <a href="http://www.eclipse.org/">Eclipse</a>. For me a bugtracker is a central todo list accessible from anywhere &#8211; combined with a central svn repo it becomes possible for me to continue to do work anywhere there is a computer and internet connection&#8230; invaluable if you spend any amount of time travelling.</p>
<p>It seems to me that a good approach would be to have the bug tracker entirely API driven (more so than it is now &#8211; which in many cases is a later bolt on), that way it would be possible to provide a variety of expert interfaces for developers and a simplified interface for end users &#8211; rather than having one interface try and do it all.</p>
<p>This interface should hold peoples hand and ask specific targeted questions to encourage non-programmers to provide reports which will be useful to developers.</p>
<p>Tagging (and tag clustering) could be a useful technique to then group issues together &#8211; making it easy to find related issues and to spot duplicates.</p>
<p>Building on some social technology to establish relationships between issues, comment around them and attach files and other media could also be useful.</p>
<p>If the underlining engine is the same this shouldn&#8217;t involve too much in the way of work duplication, but will allow for tighter integration with the tools and workflow people actually use.</p>
<div class="wsbuttons">
	<div class="shareblob facebook">
		<div class="fb-like" data-href="http://www.marcus-povey.co.uk/2009/03/10/bug-tracking/" data-send="false" data-layout="box_count" data-width="60" data-show-faces="false" data-colorscheme="light"></div>
	</div>

	<div class="shareblob google">
		<div class="g-plusone" data-size="tall" data-href="http://www.marcus-povey.co.uk/2009/03/10/bug-tracking/"></div>
	</div>

	<div class="shareblob twitter">
		<div class="twitter">
			<a href="https://twitter.com/share?url=http%3A%2F%2Fwww.marcus-povey.co.uk%2F2009%2F03%2F10%2Fbug-tracking%2F&count=vertical" class="twitter-share-button" data-lang="en">Tweet</a>
			<script>!function(d,s,id){var js,fjs=d.getElementsByTagName(s)[0];if(!d.getElementById(id)){js=d.createElement(s);js.id=id;js.src="//platform.twitter.com/widgets.js";fjs.parentNode.insertBefore(js,fjs);}}(document,"script","twitter-wjs");</script>
		</div>
	</div>

</div>
	]]></content:encoded>
			<wfw:commentRss>http://www.marcus-povey.co.uk/2009/03/10/bug-tracking/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Overriding icons</title>
		<link>http://www.marcus-povey.co.uk/2008/10/20/overriding-icons/</link>
		<comments>http://www.marcus-povey.co.uk/2008/10/20/overriding-icons/#comments</comments>
		<pubDate>Mon, 20 Oct 2008 11:47:53 +0000</pubDate>
		<dc:creator>Marcus Povey</dc:creator>
				<category><![CDATA[elgg]]></category>
		<category><![CDATA[api]]></category>
		<category><![CDATA[gravatar]]></category>
		<category><![CDATA[plugin]]></category>

		<guid isPermaLink="false">http://www.marcus-povey.co.uk/?p=99</guid>
		<description><![CDATA[Following on from my previous post about doing things the Elgg way, I thought I&#8217;d illustrate some of what I was talking about by building out a quick plugin while the kettle boiled for my tea. This plugin uses the hooks present in Elgg &#8211; specifically the getIcon() api &#8211; to provide Gravatar icons for [...]]]></description>
			<content:encoded><![CDATA[<p>Following on from my previous post about <a href="http://www.marcus-povey.co.uk/2008/10/17/the-elgg-way/">doing things the Elgg way</a>, I thought I&#8217;d illustrate some of what I was talking about by <a href="http://community.elgg.org/pg/plugins/marcus/read/3400/simple-gravatar-plugin">building out a quick plugin while the kettle boiled for my tea</a>.</p>
<p>This plugin uses the hooks present in Elgg &#8211; specifically the getIcon() api &#8211; to provide <a href="http://www.gravatar.com">Gravatar</a> icons for users which have not provided their own.</p>
<p>On many platforms this might have been an onerous task, but on Elgg it literally took me 15 minutes (in fact, it took me longer to write this post than the plugin).</p>
<p>If a user defines their own icon it will use that, but if they haven&#8217;t provided one it will use their email address to find their gravatar icon.</p>
<p>This is accomplished by setting the priority of the hook somewhere after the icon handler provided by the profile plugin, and before the default icon handler.</p>
<p>Anyway, here is the code:</p>
<blockquote><p><code>&lt;?php<br />
/**<br />
* Simple gravatar integration for Elgg.<br />
* Scratching an itch! (+ a good example of icon overloading)<br />
*<br />
* TODO:<br />
* 1) Fallback to elgg default icons instead of gravatar one for missing images<br />
* 2) Have sizes better handle changes in defaults for theming<br />
*<br />
* @package ElggGravatar<br />
* @license http://www.gnu.org/licenses/old-licenses/gpl-2.0.html GNU Public License version 2<br />
* @author Curverider Ltd<br />
* @copyright Curverider Ltd 2008<br />
* @link http://elgg.com/<br />
*/</code></p>
<p><code>/**<br />
* Init.<br />
*<br />
*/<br />
function gravatar_init()<br />
{<br />
// Now override icons. Note priority: This sits somewhere between the profile user icons and default icons -<br />
// so if you specify an icon for a user it will use that, else it will try a gravatar icon.<br />
register_plugin_hook('entity:icon:url', 'user', 'gravatar_usericon_hook', 900);<br />
}</code></p>
<p><code>/**<br />
* This hooks into the getIcon API and returns a gravatar icon where possible<br />
*<br />
* @param unknown_type $hook<br />
* @param unknown_type $entity_type<br />
* @param unknown_type $returnvalue<br />
* @param unknown_type $params<br />
* @return unknown<br />
*/<br />
function gravatar_usericon_hook($hook, $entity_type, $returnvalue, $params)<br />
{<br />
global $CONFIG;</code></p>
<p><code>// Size lookup. TODO: Do this better to allow for changed themes.<br />
$size_lookup = array(<br />
'master' =&gt; '200',<br />
'large' =&gt; '200',<br />
'topbar' =&gt; '16',<br />
'tiny' =&gt; '25',<br />
'small' =&gt; '40',<br />
'medium' =&gt; '100'<br />
);</code></p>
<p><code>if ((!$returnvalue) &amp;&amp; ($hook == 'entity:icon:url') &amp;&amp; ($params['entity'] instanceof ElggUser))<br />
{<br />
$size = 40;<br />
if (isset($size_lookup[$params['size']]))<br />
$size = $size_lookup[$params['size']];</code></p>
<p><code>return "http://www.gravatar.com/avatar/".md5($params['entity']-&gt;email) . ".jpg?s=$size";<br />
}<br />
}</code></p>
<p><code>// Initialise plugin<br />
register_elgg_event_handler('init','system','gravatar_init');<br />
?&gt;</code></p></blockquote>
<p>Pretty simple.</p>
<div class="wsbuttons">
	<div class="shareblob facebook">
		<div class="fb-like" data-href="http://www.marcus-povey.co.uk/2008/10/20/overriding-icons/" data-send="false" data-layout="box_count" data-width="60" data-show-faces="false" data-colorscheme="light"></div>
	</div>

	<div class="shareblob google">
		<div class="g-plusone" data-size="tall" data-href="http://www.marcus-povey.co.uk/2008/10/20/overriding-icons/"></div>
	</div>

	<div class="shareblob twitter">
		<div class="twitter">
			<a href="https://twitter.com/share?url=http%3A%2F%2Fwww.marcus-povey.co.uk%2F2008%2F10%2F20%2Foverriding-icons%2F&count=vertical" class="twitter-share-button" data-lang="en">Tweet</a>
			<script>!function(d,s,id){var js,fjs=d.getElementsByTagName(s)[0];if(!d.getElementById(id)){js=d.createElement(s);js.id=id;js.src="//platform.twitter.com/widgets.js";fjs.parentNode.insertBefore(js,fjs);}}(document,"script","twitter-wjs");</script>
		</div>
	</div>

</div>
	]]></content:encoded>
			<wfw:commentRss>http://www.marcus-povey.co.uk/2008/10/20/overriding-icons/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>APIs and data formats</title>
		<link>http://www.marcus-povey.co.uk/2008/08/19/apis-and-data-formats/</link>
		<comments>http://www.marcus-povey.co.uk/2008/08/19/apis-and-data-formats/#comments</comments>
		<pubDate>Tue, 19 Aug 2008 18:42:02 +0000</pubDate>
		<dc:creator>Marcus Povey</dc:creator>
				<category><![CDATA[elgg]]></category>
		<category><![CDATA[api]]></category>
		<category><![CDATA[data formats]]></category>
		<category><![CDATA[mashup]]></category>

		<guid isPermaLink="false">http://www.marcus-povey.co.uk/?p=78</guid>
		<description><![CDATA[Now that Elgg 1.0 is finally out of the door, I think it is time to talk a little bit about about some of the more advanced features &#8211; namely APIs and data formats! Elgg 1.0 provides a number of ways at getting at your data, including a number of natively supported data formats; including [...]]]></description>
			<content:encoded><![CDATA[<p>Now that Elgg 1.0 is finally out of the door, I think it is time to talk a little bit about about some of the more advanced features &#8211; namely APIs and data formats!</p>
<p>Elgg 1.0 provides a number of ways at getting at your data, including a number of natively supported data formats; including OpenDD (of course), JSON, PHP, and of course RSS.</p>
<p>If you&#8217;re putting together a mashup, you can use these views very simply. You may have noticed when you&#8217;re looking at a page with a list of items on it, that there are buttons in the top left which link to either a RSS or an OpenDD view.</p>
<p>Now when you click on one of those you&#8217;ll see your data presented in an entirely different way. Now one of the fun things you can do is change that by altering the &#8220;view&#8221; parameter, for example &#8220;view=json&#8221; to get a JSON view.</p>
<p>You can export individual items of data (that you have access to) in different ways by visiting the &#8220;export&#8221; url. For example, to export GUID 1 (which will almost certainly be the first site you set up) visit:</p>
<p><code>http://mysite.com/export/opendd/1/</code></p>
<p>Of course, if you replace &#8220;opendd&#8221; with &#8220;json&#8221; or &#8220;php&#8221; you can see this data presented in an entirely different way. Additionally, you can also add support for other formats, <a href="http://www.marcus-povey.co.uk/page/5/">as I discussed in a previous article</a>.</p>
<p>On top of that, there is an API system where plugin writers can export a function as public. These functions can then be called via a rest-like api (<a href="http://docs.elgg.org/wiki/Engine/RestApi">discussed in more detail here</a>).</p>
<p>You can then select how you want to then see that data &#8211; whether its PHP, XML or JSON etc.</p>
<p>So, in a nutshell, Elgg has some quite powerful tools for quickly and easily creating some pretty funky mashups. Have fun!</p>
<div class="wsbuttons">
	<div class="shareblob facebook">
		<div class="fb-like" data-href="http://www.marcus-povey.co.uk/2008/08/19/apis-and-data-formats/" data-send="false" data-layout="box_count" data-width="60" data-show-faces="false" data-colorscheme="light"></div>
	</div>

	<div class="shareblob google">
		<div class="g-plusone" data-size="tall" data-href="http://www.marcus-povey.co.uk/2008/08/19/apis-and-data-formats/"></div>
	</div>

	<div class="shareblob twitter">
		<div class="twitter">
			<a href="https://twitter.com/share?url=http%3A%2F%2Fwww.marcus-povey.co.uk%2F2008%2F08%2F19%2Fapis-and-data-formats%2F&count=vertical" class="twitter-share-button" data-lang="en">Tweet</a>
			<script>!function(d,s,id){var js,fjs=d.getElementsByTagName(s)[0];if(!d.getElementById(id)){js=d.createElement(s);js.id=id;js.src="//platform.twitter.com/widgets.js";fjs.parentNode.insertBefore(js,fjs);}}(document,"script","twitter-wjs");</script>
		</div>
	</div>

</div>
	]]></content:encoded>
			<wfw:commentRss>http://www.marcus-povey.co.uk/2008/08/19/apis-and-data-formats/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Connecting to elggVoices with C</title>
		<link>http://www.marcus-povey.co.uk/2008/02/28/connecting-to-elggvoices-with-c/</link>
		<comments>http://www.marcus-povey.co.uk/2008/02/28/connecting-to-elggvoices-with-c/#comments</comments>
		<pubDate>Thu, 28 Feb 2008 16:34:52 +0000</pubDate>
		<dc:creator>Marcus Povey</dc:creator>
				<category><![CDATA[Software]]></category>
		<category><![CDATA[api]]></category>
		<category><![CDATA[C]]></category>
		<category><![CDATA[elggvoices]]></category>

		<guid isPermaLink="false">http://www.marcus-povey.co.uk/2008/02/28/connecting-to-elggvoices-with-c/</guid>
		<description><![CDATA[The other week I posted a PHP example for connecting to the elggVoices API. For those of you interested in developing desktop applications, here is some example code for doing the same thing in C/C++. This code is designed to be built into a library (either a static or dynamic) but could probably be directly [...]]]></description>
			<content:encoded><![CDATA[<p>The other week I posted a <a href="http://www.marcus-povey.co.uk/2008/02/25/getting-started-with-the-elggvoices-api-part-4-putting-it-all-together/">PHP example for connecting to the elggVoices API</a>. For those of you interested in developing desktop applications, here is some example code for doing the same thing in C/C++.</p>
<p>This code is designed to be built into a library (either a static or dynamic) but could probably be directly included without too much trouble. It is tested and works fine on Linux, but should also build as a Windows DLL without too much trouble. Windows doesn&#8217;t support <code>gettimeofday</code>, so this has been rewritten.</p>
<p>You will also need to install <a href="http://curl.haxx.se/libcurl/">libcurl</a> and <a href="http://www.cryptopp.com/">cryptopp</a>, on Debian/Ubuntu these are apt-gettable.</p>
<p><strong>searunner.h</strong></p>
<blockquote><p><code>/**<br />
* @file searunner.h Searunner C++ Client library.<br />
* This is the main include file for the Linux/Win32 client api for the<br />
* searunner social networking platform.<br />
* @author Marcus Povey &lt;marcus@dushka.co.uk&gt;<br />
*/<br />
#ifndef SEARUNNER_H_<br />
#define SEARUNNER_H_</code></p>
<p><code>/** Some definitions */<br />
#define VERSION     "0.1.0"</code></p>
<p><code>#ifdef WIN32<br />
// Windows Only</code></p>
<p><code>#ifdef LIBSEARUNNERW32_EXPORTS<br />
#define LIBSEARUNNERW32_API __declspec(dllexport)<br />
#else<br />
#define LIBSEARUNNERW32_API __declspec(dllimport)<br />
#endif</code></p>
<p><code>#include &lt;winsock2.h&gt;</code></p>
<p><code>// Map snprintf to _snprintf<br />
#define snprintf _snprintf</code></p>
<p><code>#endif</code></p>
<p><code>#ifdef LINUX<br />
// Linux</code></p>
<p><code>#define LIBSEARUNNERW32_API</code></p>
<p><code>#include &lt;sys/types.h&gt;<br />
#include &lt;sys/socket.h&gt;<br />
#include &lt;sys/time.h&gt;<br />
#include &lt;netinet/in.h&gt;<br />
#include &lt;unistd.h&gt;<br />
#include &lt;netdb.h&gt;</code></p>
<p><code>#endif</code></p>
<p><code>/* Include crypto++ lib from www.cryptopp.com */<br />
#include &lt;crypto++/cryptlib.h&gt;</code></p>
<p><code>/**<br />
* Create the configuration structure.<br />
*/<br />
typedef struct {<br />
char apikey[33];<br />
char secret[33];<br />
char endpoint[255];<br />
char hmac_algo[8];<br />
char hash_algo[8];<br />
} SearunnerConfig;</code><br />
<code><br />
extern LIBSEARUNNERW32_API SearunnerConfig hSearunnerConfig;</code></p>
<p><code>/** Get call */<br />
#define SEARUNNER_CALLMODE_GET         0<br />
/** Post call */<br />
#define SEARUNNER_CALLMODE_POST        1</code></p>
<p><code>/** CURL Write function callback type */<br />
typedef size_t (*CURLOPT_WRITEFUNCTION_CALLBACK)( void *ptr, size_t size, size_t nmemb, void *stream);</code></p>
<p><code>/**<br />
* Initialisation the API client.<br />
* This function initialises the api client configuration structure ready for use.<br />
* @param api_key The API key you have been provided with.<br />
* @param secret The secret key you have been provided with.<br />
* @param endpoint_url The API Endpoint.<br />
*/<br />
LIBSEARUNNERW32_API int searunner_initialise_api(const char * api_key, const char * secret, const char * endpoint_url);</code></p>
<p><code>/**<br />
* Raw POST request.<br />
* @param parameters List of parameters.<br />
* @param postData Optional post data in post call or null if this is a GET call.<br />
* @param postdata_length The length of the data being sent.<br />
* @param content_type Optional content type or null if this is a GET call.<br />
* @param buffer The buffer to write the result into [OUT]<br />
* @param buffer_size The size of the buffer<br />
* @return The amount actually written.<br />
*/<br />
LIBSEARUNNERW32_API int __searunner_post_call(const char * parameters, unsigned char * postData, int postdata_length, char * content_type, CURLOPT_WRITEFUNCTION_CALLBACK curl_read_func);</code></p>
<p><code>/**<br />
* Raw GET request.<br />
* @param parameters List of parameters.<br />
* @param buffer The buffer to write the result into [OUT]<br />
* @param buffer_size The size of the buffer<br />
* @return The amount actually written.<br />
*/<br />
LIBSEARUNNERW32_API int __searunner_get_call(const char * parameters, CURLOPT_WRITEFUNCTION_CALLBACK curl_read_func);</code></p>
<p><code>/**<br />
* Make a searunner call.<br />
* @param method Method call.<br />
* @param parameters List of parameters.<br />
* @param postData Optional post data in post call or null if this is a GET call.<br />
* @param postdata_length The length of the data being sent.<br />
* @param content_type Optional content type or null if this is a GET call.<br />
* @param buffer The buffer to write the result into [OUT]<br />
* @param buffer_size The size of the buffer<br />
* @return The amount actually written.<br />
*/<br />
LIBSEARUNNERW32_API int __searunner_call(int method, const char * parameters, unsigned char * postData, int postdata_length, char * content_type, CURLOPT_WRITEFUNCTION_CALLBACK curl_read_func);</code></p>
<p><code>#endif /*SEARUNNER_H_*/</code></p></blockquote>
<p><strong>searunner.cpp</strong></p>
<blockquote><p> <code>/**<br />
* @file searunner.cpp<br />
* Main functions and Win32 DLL entrypoint.<br />
* @author Marcus Povey &lt;marcus@dushka.co.uk&gt;<br />
*/</code></p>
<p><code>#include "searunner.h"<br />
#include &lt;stdio.h&gt;<br />
#include &lt;stdlib.h&gt;<br />
#include &lt;string.h&gt;<br />
#include &lt;crypto++/sha.h&gt;<br />
#include &lt;crypto++/hmac.h&gt;<br />
#include &lt;crypto++/hex.h&gt;<br />
#include &lt;crypto++/filters.h&gt;<br />
#include &lt;curl/curl.h&gt;<br />
#include &lt;time.h&gt;<br />
</code></p>
<p><code>/* Configuration structure */<br />
LIBSEARUNNERW32_API SearunnerConfig hSearunnerConfig;</code></p>
<p><code>/* Utility functions used internally */<br />
#ifdef WIN32</code></p>
<p><code>#if defined(_MSC_VER) || defined(_MSC_EXTENSIONS)<br />
#define DELTA_EPOCH_IN_MICROSECS  11644473600000000Ui64<br />
#else<br />
#define DELTA_EPOCH_IN_MICROSECS  11644473600000000ULL<br />
#endif</code></p>
<p><code>struct timezone<br />
{<br />
int  tz_minuteswest; /* minutes W of Greenwich */<br />
int  tz_dsttime;     /* type of dst correction */<br />
};</code></p>
<p><code>/**<br />
* Replacement gettimeofday function for windows.<br />
* Obtained from http://www.openasthra.com/c-tidbits/gettimeofday-function-for-windows/<br />
*/<br />
int gettimeofday(struct timeval *tv, struct timezone *tz)<br />
{<br />
FILETIME ft;<br />
unsigned __int64 tmpres = 0;<br />
static int tzflag;</code></p>
<p><code>if (NULL != tv)<br />
{<br />
GetSystemTimeAsFileTime(&amp;ft);</code></p>
<p><code>tmpres |= ft.dwHighDateTime;<br />
tmpres &lt;&lt;= 32;<br />
tmpres |= ft.dwLowDateTime;</code></p>
<p><code>/*converting file time to unix epoch*/<br />
tmpres /= 10;  /*convert into microseconds*/<br />
tmpres -= DELTA_EPOCH_IN_MICROSECS;<br />
tv-&gt;tv_sec = (long)(tmpres / 1000000UL);<br />
tv-&gt;tv_usec = (long)(tmpres % 1000000UL);<br />
}</code></p>
<p><code>if (NULL != tz)<br />
{<br />
if (!tzflag)<br />
{<br />
_tzset();<br />
tzflag++;<br />
}<br />
tz-&gt;tz_minuteswest = _timezone / 60;<br />
tz-&gt;tz_dsttime = _daylight;<br />
}</code></p>
<p><code>return 0;<br />
}</code></p>
<p><code>#endif</code></p>
<p><code>#define MICRO_IN_SEC 1000000.00</code></p>
<p><code>/**<br />
* Micro time function.<br />
*<br />
* Example usage:<br />
*<br />
* char oo[100];<br />
* microtime(oo);<br />
* printf(oo);<br />
*<br />
* @param buffer Where to output variables.<br />
*/<br />
int microtime(char * buffer)<br />
{<br />
struct timeval tp;<br />
long sec = 0L;<br />
double msec = 0.0;<br />
char ret[100];</code></p>
<p><code>if (gettimeofday((struct timeval *) &amp;tp, (NULL)) == 0)<br />
{<br />
msec = (double) (tp.tv_usec / MICRO_IN_SEC);<br />
sec = tp.tv_sec;</code></p>
<p><code>if (msec &gt;= 1.0) msec -= (long) msec;</code><br />
<code><br />
int msec2 = (int)(msec*100);</code></p>
<p><code>snprintf(ret, 100, "%ld.%d",  sec, msec2);<br />
strcpy(buffer, ret);<br />
return 0;<br />
}</code></p>
<p><code>return -1;<br />
}</code></p>
<p><code>/**<br />
* Calculate a hmac for the given data.<br />
*<br />
* Example usage:<br />
*<br />
* char oo [2*CryptoPP::SHA1::DIGESTSIZE+1];<br />
* calculate_hmac(&amp;hSearunnerConfig, "1", "2", "3", oo, 2*CryptoPP::SHA1::DIGESTSIZE+1);<br />
* printf(oo);<br />
*<br />
* @param time String representation of time<br />
* @param get_variables String of parameters<br />
* @param post_hash The hash<br />
* @param buffer The buffer<br />
* @param bugger_size Size of the buffer<br />
*/<br />
int calculate_hmac(<br />
const char * time,<br />
const char * get_variables,<br />
const char * post_hash,</code></p>
<p><code>char * buffer, int buffer_size)<br />
{<br />
memset(buffer,0,buffer_size);</code></p>
<p><code>if (strcmp(hSearunnerConfig.hmac_algo, "sha1")==0)<br />
{<br />
// Sha1</code></p>
<p><code>// Check the buffer size before we do anything<br />
if (buffer_size&lt;2*CryptoPP::SHA1::DIGESTSIZE + 1) return -1;</code></p>
<p><code>// Initialise memory<br />
unsigned char tmp[ 2*CryptoPP::SHA1::DIGESTSIZE + 1 ];<br />
memset(tmp,0,2*CryptoPP::SHA1::DIGESTSIZE + 1);</code></p>
<p><code>// Compute HMAC<br />
CryptoPP::HMAC&lt;CryptoPP::SHA1&gt; hmac((const byte*)hSearunnerConfig.secret, strlen(hSearunnerConfig.secret));<br />
hmac.Update((const byte*)time, strlen(time));<br />
hmac.Update((const byte*)hSearunnerConfig.apikey, strlen(hSearunnerConfig.apikey));<br />
hmac.Update((const byte*)get_variables, strlen(get_variables));<br />
if (post_hash) hmac.Update((const byte*)post_hash, strlen(post_hash));</code></p>
<p><code>hmac.Final((byte*)tmp);</code></p>
<p><code>// hex encode<br />
CryptoPP::HexEncoder encoder;<br />
encoder.Attach(new CryptoPP::ArraySink((byte*)buffer, 2*CryptoPP::SHA1::DIGESTSIZE));<br />
encoder.Put(tmp, sizeof(tmp));<br />
encoder.MessageEnd();</code></p>
<p><code>// Convert to lower case<br />
for (int n = 0; n&lt;buffer_size; n++)<br />
if (buffer[n]!=0) buffer[n] = tolower(buffer[n]);</code></p>
<p><code>return 0;<br />
}</code></p>
<p><code>return -1;<br />
}</code></p>
<p><code>/*<br />
* Calculate the hash of some POST data.<br />
* TODO: Tidy this up<br />
* TODO: Support more algorithms<br />
*<br />
* Example usage:<br />
*<br />
* char oo [2*CryptoPP::MD5::DIGESTSIZE+1];<br />
* calculate_POST_hash(&amp;hSearunnerConfig, (unsigned char*)"test", 4, oo, 2*CryptoPP::MD5::DIGESTSIZE+1);<br />
* printf(oo);<br />
*<br />
* @param postdata The data<br />
* @param postlength The length<br />
* @param outputbuffer The buffer<br />
* @param outputbuffer_size The size of the output buffer<br />
*/<br />
int calculate_POST_hash(const unsigned char * postdata, int postlength, char * outputbuffer, int outputbuffer_size)<br />
{<br />
memset(outputbuffer,0,outputbuffer_size);</code></p>
<p><code>if (strcmp(hSearunnerConfig.hash_algo, "sha1")==0)<br />
{<br />
// Check the buffer size before we do anything<br />
if (outputbuffer_size&lt;2*CryptoPP::SHA1::DIGESTSIZE + 1) return -1;</code><br />
<code><br />
// Initialise memory<br />
unsigned char tmp[ 2*CryptoPP::SHA1::DIGESTSIZE + 1 ];<br />
memset(tmp,0,2*CryptoPP::SHA1::DIGESTSIZE + 1);</code></p>
<p><code>// Calculate the digest<br />
CryptoPP::SHA1 hash;<br />
hash.CalculateDigest((byte*)tmp, (const byte*)postdata, postlength);</code></p>
<p><code>// hex encode<br />
CryptoPP::HexEncoder encoder;<br />
encoder.Attach(new CryptoPP::ArraySink((byte*)outputbuffer, 2*CryptoPP::SHA1::DIGESTSIZE));<br />
encoder.Put(tmp, sizeof(tmp));<br />
encoder.MessageEnd();</code></p>
<p><code>// Convert to lower case<br />
for (int n = 0; n&lt;outputbuffer_size; n++)<br />
if (outputbuffer[n]!=0) outputbuffer[n] = tolower(outputbuffer[n]);</code></p>
<p><code>return 0;<br />
}</code></p>
<p><code>return -1;<br />
}</code></p>
<p><code>/*************************************/</code></p>
<p><code>LIBSEARUNNERW32_API int searunner_initialise_api(const char * api_key, const char * secret, const char * endpoint_url)<br />
{<br />
strcpy(hSearunnerConfig.apikey, api_key);<br />
strcpy(hSearunnerConfig.secret, secret);<br />
strcpy(hSearunnerConfig.endpoint, endpoint_url);<br />
strcpy(hSearunnerConfig.hmac_algo, "sha1");<br />
strcpy(hSearunnerConfig.hash_algo, "sha1");<br />
return 0;<br />
}</code></p>
<p><code>LIBSEARUNNERW32_API int __searunner_call(int method,<br />
const char * parameters,<br />
unsigned char * postData,<br />
int postdata_length,<br />
char * content_type,<br />
CURLOPT_WRITEFUNCTION_CALLBACK curl_read_func)<br />
{<br />
char url[2048] = {""};<br />
char posthash[256] = {""};<br />
char hmac[256] = {""};<br />
char tmp[100] = {""};</code></p>
<p><code>struct curl_slist *headerlist = NULL;</code></p>
<p><code>// Get the microtime for now<br />
char time[100];<br />
microtime(time);</code></p>
<p><code>// Construct URL<br />
strcpy(url, hSearunnerConfig.endpoint);<br />
strcat(url, "?");<br />
strcat(url, parameters);</code></p>
<p><code>// If post data, hash it<br />
if (postdata_length &gt; 0)<br />
calculate_POST_hash(postData, postdata_length, posthash, 256);</code></p>
<p><code>// Constract the hmac<br />
calculate_hmac(time, parameters, posthash, hmac, 256);</code></p>
<p><code>// Initialise CURL<br />
CURL * curl = curl_easy_init();<br />
if(curl) {</code></p>
<p><code>// Set headers<br />
sprintf(tmp, "X-Searunner-apikey: %s", hSearunnerConfig.apikey);<br />
headerlist = curl_slist_append(headerlist, tmp);</code></p>
<p><code>sprintf(tmp, "X-Searunner-time: %s", time);<br />
headerlist = curl_slist_append(headerlist, tmp);</code></p>
<p><code>sprintf(tmp, "X-Searunner-hmac-algo: %s", hSearunnerConfig.hmac_algo);<br />
headerlist = curl_slist_append(headerlist, tmp);</code></p>
<p><code>sprintf(tmp, "X-Searunner-hmac: %s", hmac);<br />
headerlist = curl_slist_append(headerlist, tmp);</code></p>
<p><code>// Set options<br />
if (method == SEARUNNER_CALLMODE_POST)<br />
{<br />
curl_easy_setopt(curl, CURLOPT_POST, 1); // Use POST</code></p>
<p>s<code>printf(tmp, "X-Searunner-posthash: %s", posthash);<br />
headerlist = curl_slist_append(headerlist, tmp);</code></p>
<p><code>sprintf(tmp, "X-Searunner-posthash-algo: %s", hSearunnerConfig.hash_algo);<br />
headerlist = curl_slist_append(headerlist, tmp);</code></p>
<p><code>sprintf(tmp, "Content-type: %s", content_type);<br />
headerlist = curl_slist_append(headerlist, tmp);</code></p>
<p><code>sprintf(tmp, "Content-Length: %d", postdata_length);<br />
headerlist = curl_slist_append(headerlist, tmp);</code></p>
<p><code>curl_easy_setopt(curl, CURLOPT_POSTFIELDS, postData); // Set the post data<br />
curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, postdata_length);<br />
}</code></p>
<p><code>curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headerlist); // Set the headers<br />
curl_easy_setopt(curl,CURLOPT_URL, url); // Set the url<br />
curl_easy_setopt(curl, CURLOPT_READFUNCTION, curl_read_func); // Use our own read function</code></p>
<p><code>// Make call<br />
CURLcode res = curl_easy_perform(curl);</code></p>
<p><code>// Clean up<br />
curl_easy_cleanup(curl);</code></p>
<p><code>return res;<br />
}</code></p>
<p><code>return 0;<br />
}</code></p>
<p><code>LIBSEARUNNERW32_API int __searunner_post_call(const char * parameters, unsigned char * postData, int postdata_length, char * content_type, CURLOPT_WRITEFUNCTION_CALLBACK curl_read_func)<br />
{<br />
return __searunner_call(SEARUNNER_CALLMODE_POST, parameters, postData, postdata_length, content_type, curl_read_func);<br />
}</code></p>
<p><code>LIBSEARUNNERW32_API int __searunner_get_call(const char * parameters, CURLOPT_WRITEFUNCTION_CALLBACK curl_read_func)<br />
{<br />
return __searunner_call(SEARUNNER_CALLMODE_GET, parameters, NULL, 0,  NULL, curl_read_func);<br />
}</code></p>
<p><code>#ifdef WIN32</code></p>
<p><code>/*<br />
Windows Only DLL entrypoint.<br />
*/</code></p>
<p><code>BOOL APIENTRY DllMain( HANDLE hModule,<br />
DWORD  ul_reason_for_call,<br />
LPVOID lpReserved<br />
)<br />
{<br />
switch (ul_reason_for_call)<br />
{<br />
case DLL_PROCESS_ATTACH:<br />
case DLL_THREAD_ATTACH:<br />
case DLL_THREAD_DETACH:<br />
case DLL_PROCESS_DETACH:<br />
break;<br />
}<br />
return TRUE;<br />
}</code><br />
<code><br />
#endif</code></p></blockquote>
<div class="wsbuttons">
	<div class="shareblob facebook">
		<div class="fb-like" data-href="http://www.marcus-povey.co.uk/2008/02/28/connecting-to-elggvoices-with-c/" data-send="false" data-layout="box_count" data-width="60" data-show-faces="false" data-colorscheme="light"></div>
	</div>

	<div class="shareblob google">
		<div class="g-plusone" data-size="tall" data-href="http://www.marcus-povey.co.uk/2008/02/28/connecting-to-elggvoices-with-c/"></div>
	</div>

	<div class="shareblob twitter">
		<div class="twitter">
			<a href="https://twitter.com/share?url=http%3A%2F%2Fwww.marcus-povey.co.uk%2F2008%2F02%2F28%2Fconnecting-to-elggvoices-with-c%2F&count=vertical" class="twitter-share-button" data-lang="en">Tweet</a>
			<script>!function(d,s,id){var js,fjs=d.getElementsByTagName(s)[0];if(!d.getElementById(id)){js=d.createElement(s);js.id=id;js.src="//platform.twitter.com/widgets.js";fjs.parentNode.insertBefore(js,fjs);}}(document,"script","twitter-wjs");</script>
		</div>
	</div>

</div>
	]]></content:encoded>
			<wfw:commentRss>http://www.marcus-povey.co.uk/2008/02/28/connecting-to-elggvoices-with-c/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Getting started with the elggVoices API (part 4 &#8211; Putting it all together)</title>
		<link>http://www.marcus-povey.co.uk/2008/02/25/getting-started-with-the-elggvoices-api-part-4-putting-it-all-together/</link>
		<comments>http://www.marcus-povey.co.uk/2008/02/25/getting-started-with-the-elggvoices-api-part-4-putting-it-all-together/#comments</comments>
		<pubDate>Mon, 25 Feb 2008 12:35:48 +0000</pubDate>
		<dc:creator>Marcus Povey</dc:creator>
				<category><![CDATA[Software]]></category>
		<category><![CDATA[api]]></category>
		<category><![CDATA[elggvoices]]></category>
		<category><![CDATA[howto]]></category>

		<guid isPermaLink="false">http://www.marcus-povey.co.uk/2008/02/25/getting-started-with-the-elggvoices-api-part-4-putting-it-all-together/</guid>
		<description><![CDATA[In yesterday&#8217;s article, we took a look at the server&#8217;s reply format. You now have all the information you need to construct the core of a library and start making server requests. Here is some sample PHP code for making POST and GET style queries. This library will let you make a query, and return [...]]]></description>
			<content:encoded><![CDATA[<p>In <a href="http://www.marcus-povey.co.uk/2008/02/24/getting-started-with-the-elggvoices-api-part-3-the-reply/">yesterday&#8217;s article</a>, we took a look at the server&#8217;s reply format. You now have all the information you need to construct the core of a library and start making server requests.</p>
<p>Here is some sample PHP code for making POST and GET style queries. This library will let you make a query, and return a <code>stdClass</code> object containing the serialised fields as described yesterday, from this you can build wrapper functions for the methods.</p>
<blockquote><p>  <code>$API_CLIENT = new stdClass;</code></p>
<p><code>// Configure your client<br />
$API_CLIENT-&gt;api_key = "<strong>your api key</strong>";<br />
$API_CLIENT-&gt;secret = "<strong>your secret key</strong>";<br />
$API_CLIENT-&gt;api_endpoint = "http://elggvoices.com/api/v1/";<br />
$API_CLIENT-&gt;hmac_algo = 'sha256';<br />
$API_CLIENT-&gt;postdata_hash_algo = 'md5';</code></p>
<p><code>// Status variables we can query later<br />
$LAST_CALL = null;<br />
$LAST_CALL_RAW = "";<br />
$LAST_ERROR = null;</code></p>
<p><code>/**<br />
* Generate our HMAC.<br />
*/<br />
function calculate_hmac($algo, $time, $api_key, $secret_key, $get_variables, $post_hash = "")<br />
{<br />
$ctx = hash_init($algo, HASH_HMAC, $secret_key);<br />
hash_update($ctx, trim($time));<br />
hash_update($ctx, trim($api_key));<br />
hash_update($ctx, trim($get_variables));<br />
if (trim($post_hash)!="") hash_update($ctx, trim($post_hash));<br />
return hash_final($ctx);<br />
}</code></p>
<p><code>/**<br />
* Generate our POST hash.<br />
*/<br />
function calculate_posthash($postdata, $algo)<br />
{<br />
$ctx = hash_init($algo);<br />
hash_update($ctx, $postdata);<br />
return hash_final($ctx);<br />
}</code></p>
<p><code>/**<br />
* Serialise HTTP headers.<br />
*/<br />
function serialise_headers(array $headers)<br />
{<br />
$headers_str = "";<br />
foreach ($headers as $k =&gt; $v)<br />
$headers_str .= trim($k) . ": " . trim($v) . "\r\n";<br />
return trim($headers_str);<br />
}</code></p>
<p><code>/**<br />
* Make a raw call.<br />
* @param array $method Method call parameters.<br />
* @param string $postdata Optional POST data.<br />
* @param string $content_type The content type.<br />
* @return stdClass<br />
*/<br />
function call(array $method, $postdata = "", $content_type = 'application/octet-stream')<br />
{</code><code><br />
// Get the config<br />
global $API_CLIENT, $LAST_CALL, $LAST_CALL_RAW, $LAST_ERROR; </code></p>
<p><code>$headers = array();<br />
$encoded_params = array();</code></p>
<p><code>$time = microtime(true); // Get the current time in microseconds<br />
$request = ($postdata!="" ? "POST" : "GET"); // Get the request method, either post or get</code></p>
<p><code>// Hard code the format - we're using PHP, so lets use PHP serialisation.<br />
$method['format'] = "php";</code></p>
<p><code>// URL encode all the parameters<br />
foreach ($method as $k =&gt; $v){<br />
$encoded_params[] = urlencode($k).'='.urlencode($v);<br />
}<br />
</code><br />
<code>$params = implode('&amp;', $encoded_params);</code></p>
<p><code>// Put together the query string<br />
$url = $API_CLIENT-&gt;api_endpoint."?". $params;</code></p>
<p><code>// Construct headers<br />
$posthash = "";<br />
if ($request=='POST')<br />
{<br />
$posthash = calculate_posthash($postdata, $API_CLIENT-&gt;postdata_hash_algo);<br />
$headers['X-Searunner-posthash'] = $posthash;<br />
$headers['X-Searunner-posthash-algo'] = $API_CLIENT-&gt;postdata_hash_algo;<br />
$headers['Content-type'] = $content_type;<br />
$headers['Content-Length'] = strlen($postdata);<br />
}</code></p>
<p><code>$headers['X-Searunner-apikey'] = $API_CLIENT-&gt;api_key;<br />
$headers['X-Searunner-time'] = $time;<br />
$headers['X-Searunner-hmac-algo'] = $API_CLIENT-&gt;hmac_algo;<br />
$headers['X-Searunner-hmac'] = calculate_hmac($API_CLIENT-&gt;hmac_algo,<br />
$time,<br />
$API_CLIENT-&gt;api_key,<br />
$API_CLIENT-&gt;secret,<br />
$params,<br />
$posthash<br />
);</code></p>
<p><code>// Configure stream options<br />
$opts = array(<br />
'http'=&gt;array(<br />
'method'=&gt; $request,<br />
'header'=&gt; serialise_headers($headers)<br />
)<br />
);</code></p>
<p><code>// If this is a post request then set the content<br />
if ($request=='POST')<br />
$opts['http']['content'] = $postdata; </code></p>
<p><code>// Set stream options<br />
$context = stream_context_create($opts);</code></p>
<p><code>// Send the query and get the result and decode.<br />
$LAST_CALL_RAW = file_get_contents($url, false, $context);<br />
$LAST_CALL = unserialize($LAST_CALL_RAW);</code></p>
<p><code>if (($LAST_CALL) &amp;&amp; ($LAST_CALL-&gt;status!=0)) // Check to see if this was an error<br />
$LAST_ERROR = $LAST_CALL;</code></p>
<p><code>return $LAST_CALL; // Return a stdClass containing the API result<br />
}</code></p>
<p><code>// Example GET call<br />
$get = call(<br />
array (<br />
'method' =&gt; 'test.test',<br />
'variable1' =&gt; 1,<br />
'variable2' =&gt; "test string"<br />
)<br />
);<br />
</code><code><br />
// Example POST call<br />
$post = call(<br />
array (<br />
'method' =&gt; 'test.test',<br />
'variable1' =&gt; 1,<br />
'variable2' =&gt; "test string"<br />
),<br />
"Some post data"<br />
);</code></p>
<p><code>// Output<br />
echo "Example GET result: \n";<br />
print_r($get);</code></p>
<p><code>echo "Example POST result: \n";<br />
print_r($post);<br />
</code></p></blockquote>
<div class="wsbuttons">
	<div class="shareblob facebook">
		<div class="fb-like" data-href="http://www.marcus-povey.co.uk/2008/02/25/getting-started-with-the-elggvoices-api-part-4-putting-it-all-together/" data-send="false" data-layout="box_count" data-width="60" data-show-faces="false" data-colorscheme="light"></div>
	</div>

	<div class="shareblob google">
		<div class="g-plusone" data-size="tall" data-href="http://www.marcus-povey.co.uk/2008/02/25/getting-started-with-the-elggvoices-api-part-4-putting-it-all-together/"></div>
	</div>

	<div class="shareblob twitter">
		<div class="twitter">
			<a href="https://twitter.com/share?url=http%3A%2F%2Fwww.marcus-povey.co.uk%2F2008%2F02%2F25%2Fgetting-started-with-the-elggvoices-api-part-4-putting-it-all-together%2F&count=vertical" class="twitter-share-button" data-lang="en">Tweet</a>
			<script>!function(d,s,id){var js,fjs=d.getElementsByTagName(s)[0];if(!d.getElementById(id)){js=d.createElement(s);js.id=id;js.src="//platform.twitter.com/widgets.js";fjs.parentNode.insertBefore(js,fjs);}}(document,"script","twitter-wjs");</script>
		</div>
	</div>

</div>
	]]></content:encoded>
			<wfw:commentRss>http://www.marcus-povey.co.uk/2008/02/25/getting-started-with-the-elggvoices-api-part-4-putting-it-all-together/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Getting started with the elggVoices API (part 3 &#8211; The reply)</title>
		<link>http://www.marcus-povey.co.uk/2008/02/24/getting-started-with-the-elggvoices-api-part-3-the-reply/</link>
		<comments>http://www.marcus-povey.co.uk/2008/02/24/getting-started-with-the-elggvoices-api-part-3-the-reply/#comments</comments>
		<pubDate>Sun, 24 Feb 2008 18:55:54 +0000</pubDate>
		<dc:creator>Marcus Povey</dc:creator>
				<category><![CDATA[Software]]></category>
		<category><![CDATA[api]]></category>
		<category><![CDATA[elggvoices]]></category>
		<category><![CDATA[howto]]></category>

		<guid isPermaLink="false">http://www.marcus-povey.co.uk/2008/02/24/getting-started-with-the-elggvoices-api-part-3-the-reply/</guid>
		<description><![CDATA[On Friday we discussed how to construct an API request, today we will discuss how to handle the response that the server returns. Server replies The elggVoices server will respond with a result packet containing a number of fields. The format of this reply depends on the format requested. From the manual: &#8216;status&#8217;: The status [...]]]></description>
			<content:encoded><![CDATA[<p>On Friday we discussed how to <a href="http://www.marcus-povey.co.uk/2008/02/22/getting-started-with-the-elggvoices-api-part-2-the-request/">construct an API request</a>, today we will discuss how to handle the response that the server returns.</p>
<h2>Server replies</h2>
<p>The <a href="http://www.elggvoices.com">elggVoices</a> server will respond with a result packet containing a number of fields. The format of this reply depends on the format requested. From the manual:</p>
<blockquote>
<ul>
<li><strong>&#8216;status&#8217;</strong>: The status code, 0 for success or a non-zero error code.</li>
<li><strong>&#8216;message&#8217;</strong>: If the status code is non-zero this contains a human readable<br />
explanation.</li>
<li><strong>&#8216;result&#8217;</strong>: The mixed result of the execution, this may be a simple type<br />
(int, string etc), an array or even an object, depending on the API being<br />
called (see also result objects).</li>
<li><strong>&#8216;runtime_errors&#8217;</strong>: If there have been any runtime errors picked up by<br />
the internal error handler during the execution of the command, these<br />
are given here in an array.</li>
</ul>
</blockquote>
<p>The server result will be returned, serialised in the requested format (xml,php or json).</p>
<p>Errors will often give details pointing to what went wrong, these can be helpful when debugging your application or when looking for support on the forums.</p>
<p>Have a look at this XML formatted error message, XML success messages will be of a similar format:</p>
<blockquote><p><code>&lt;SearunnerResult&gt;<br />
&lt;status type="integer"&gt;-1&lt;/status&gt;<br />
&lt;message type="string"&gt;Missing X-Searunner-apikey HTTP header&lt;/message&gt;<br />
&lt;result type="string"&gt;exception 'APIException' with message 'Missing X-Searunner-apikey HTTP header' in /home/liveshouts/html/lib/api/validation.php:109<br />
Stack trace:<br />
#0 /home/liveshouts/html/api/endpoints/rest.php(19): get_and_validate_api_headers()<br />
#1 {main}&lt;/result&gt;<br />
&lt;runtime_errors type="array"&gt;<br />
&lt;array_item name="0" type="string" &gt;DEBUG: 2008-02-24 18:38:19 (UTC): &amp; quot;Undefined index:  method&amp; quot;<br />
in file /home/liveshouts/html/lib/engine/input.php (line 30)&lt;/array_item&gt;<br />
&lt;array_item name="1" type="string"&gt;DEBUG: 2008-02-24 18:38:19 (UTC): &amp;quot;Undefined index:  HTTP_X_SEARUNNER_APIKEY&amp;quot; in file /home/liveshouts/html/lib/api/validation.php (line 107)&lt;/array_item&gt;<br />
&lt;/runtime_errors&gt;<br />
&lt;/SearunnerResult&gt;</code></p></blockquote>
<blockquote>
<div class="wsbuttons">
	<div class="shareblob facebook">
		<div class="fb-like" data-href="http://www.marcus-povey.co.uk/2008/02/24/getting-started-with-the-elggvoices-api-part-3-the-reply/" data-send="false" data-layout="box_count" data-width="60" data-show-faces="false" data-colorscheme="light"></div>
	</div>

	<div class="shareblob google">
		<div class="g-plusone" data-size="tall" data-href="http://www.marcus-povey.co.uk/2008/02/24/getting-started-with-the-elggvoices-api-part-3-the-reply/"></div>
	</div>

	<div class="shareblob twitter">
		<div class="twitter">
			<a href="https://twitter.com/share?url=http%3A%2F%2Fwww.marcus-povey.co.uk%2F2008%2F02%2F24%2Fgetting-started-with-the-elggvoices-api-part-3-the-reply%2F&count=vertical" class="twitter-share-button" data-lang="en">Tweet</a>
			<script>!function(d,s,id){var js,fjs=d.getElementsByTagName(s)[0];if(!d.getElementById(id)){js=d.createElement(s);js.id=id;js.src="//platform.twitter.com/widgets.js";fjs.parentNode.insertBefore(js,fjs);}}(document,"script","twitter-wjs");</script>
		</div>
	</div>

</div>
	]]></content:encoded>
			<wfw:commentRss>http://www.marcus-povey.co.uk/2008/02/24/getting-started-with-the-elggvoices-api-part-3-the-reply/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
	</channel>
</rss>

