Mateusz Stawecki

Personal Site

Posts from the ‘Tech Log’ category

When watching the WWDC2015 Keynote, I’ve noticed that the Newsstand icon wasn’t on any of the screenshots. Hmm… interesting. Shortly after that Apple announced “News”, it was pretty clear Newsstand was getting a “replacement”. iOS9 is still in beta, so I guess anything can happen, but I think it’s time to declare the new world order…

#1 Newsstand is still a Category on the AppStore

Not much changed here, even the covers are still around.

Newsstand - AppStore

#2 Newsstand “shelves UI” and the icon are gone – replaced with a generic app group

Just like any other group, it contains apps and icons. Covers are gone. I guess magazine covers still make sense on the AppStore, if the app uses them internally.

Newsstand - app group

#3 Newsstand apps are finally free to leave the group and exist anywhere on your home screen

Newsstand - freedom

What’s up with News?

News is interesting, because it promotes a completely new format for displaying news content. Interestingly, by taking away the focus from apps, which is a quite unusual move. I’ve got used to Apple being all about Apps. The introduction of “seamless linking” might help our case – following article links inside news would allow you to navigate straight to your app.

So far, it seams that News is much closer to what Flipboard is rather than what Newsstand used to be. I don’t see how News would be a better choice for “magazines” (just to clarify – I mean the “magazine” format – regular bundle of content behind a cover), but maybe the “magazine” format is not right for mobile? Do we all have ADHD and can only handle flicking through streams nowadays?

Personally, I still believe in “magazines”, I still think people should try to run magazines on the AppStore. News might turn out to be a great solution for news portals, but I find it very hard to call “News” a replacement for “Newsstand”, because it’s such a huge shift – maybe an “alternate approach”? Apple hasn’t killed magazines just yet.

I’m eager to see how this plays out.

Leave a comment
During the 2013 WWDC alongside iOS7 Apple announced an exciting addition to its CoreLocation framework – a technology that could finally solve the problem of indoor location detection – iBeacons, by leveraging the under-utilised (at the time) Bluetooth Low Energy. The framework was hard to test at first due to lack of hardware providers for the actual beacons, but several startups and companies soon jumped at the opportunity and we could finally give it a proper shot. However, particularly in early releases of iOS7 the iBeacon tech seemed to disappoint with its poor accuracy and reliability. While the concept got a lot of developers excited, the amazement quickly turned into frustration. So, how well do iBeacons actually work nowadays?

Previous Experiments

Less than a year after release, I took part in making some experimental apps.
One which was a guided tour of an office building – related information was displayed when a new room was entered. The beacon accuracy wasn’t particularly important since the space was large. The demo worked fine, especially when the application was running in foreground.
The other one was done at Úll Conf 2014 and relied on the conference app waking up in background. For the first time we could test the setup across >100 devices. We’ve announced a scavenger hunt: once a device came in range with a beacon installed at one of our secret locations, an achievement badge was unlocked in the app. The experiment results were mixed, some things worked, some didn’t (I’ve summarised them last year). iBeacons seemed a little too young to be more than a curiosity. When iOS7 was updated with further fixes and later iOS8, we finally saw improvement. Apple was clearly updating iBeacons and other features which suffered from similar issues (e.g. multi-peer connectivity which was practically a dummy API in the initial release of iOS7). It’s understandable that these things take time to perfect and need to be tested in live conditions, which for a secretive company like Apple was impossible to do before the announcement. So, how far have we come?

“Well, this is going to be a problem.”

Fast forward to April 2015, I’ve attended Úll Conf again and this time we decided to try out a more ambitious setup. We’ve had a perfect opportunity to put together an audio tour to the Museum feature, which was a small exhibition of Apple devices and memorabilias. We had 12 kontakt.io beacons which we installed on some exhibition items.
In the end it worked out quite well:
 
 —
However, things didn’t start off very well at all. After we’ve setup the beacons, I’ve quickly realised that the app, which was tested against a much simpler setup didn’t behave the way we wanted. This was due to a several problems I’ve observed:

Ranging is far from perfect

On iOS8 I’ve noticed a lot of improvement in the ranging results, but occasional issues still arise:
  • beacons may randomly drop off: don’t be surprised when a ranged beacon disappears only to re-appear on next range
  • When looking at RSSI, be aware that it is equal to 0 when the beacon is in unknown proximity:
    CLBeacon (uuid:…, major:0, minor:1, proximity:0 +/- -1.00m, rssi:0)
  • approximate distances are inaccurate and signal strength reading may fluctuate
When using multiple beacons in a dense setup these inaccuracies will prove particularly difficult.
Solutions:
  • make sure your ranging code compensates for some of these issues: if you’re displaying content for the nearest beacons, don’t trust the result immediately, put a threshold on when a beacon is considered as “the nearest beacon”.

Screenshot 2015-06-11 01.52.13

  • compensate with the user flow. We’ve been very ambitious: the app would display content as soon as a new beacon was considered the closest. On top of that we’ve set the audio to play automatically. This meant that when things went wrong, the current audio track for the item was interrupted with the false-positive result. Why not advertise that a location is available, but allow the user to confirm interaction in a non-intrusive way.
  • compensate with how you structure your information. E.g. you could cluster several  items around a single beacon, instead of having a really dense setup.
The way you compensate will have its trade offs, so you want to pick the right trade off for your use case.

Different devices will give different results

Besides issues with ranging itself, remember that different iPhone/iPad models will have different chipsets and construction. That will lead to inconsistent results.
Here’s a sample i recorded at the Museum, when standing ~50cm from beacon no 1. (iBeacon was behind glass). Each device was in exactly the same spot.
museum

Spot the iBeacons! 😉

iBeacon Ranging Comparison
As you can see, even the loose definition of the three proximity states …Isn’t loose enough!
  • Immediate: Within a few centimeters
  • Near: Within a couple of meters
  • Far: Greater than 10 meters away

Yeah, right!

To avoid fluctuations between beacons, one of the things I’ve tried was to accept only beacons ranged as “immediate” but it was surprisingly rare to observe that state on the old iPad Retina.

Background location monitoring doesn’t work immediately after boot

This is a really important thing to remember when testing background ranging capabilities. Give it at least 10mins for iOS to start looking for your location in background. If you expect for your app to wake up soon after a restart, it won’t work. iOS is taking its time to wake up all of its background services. This is a rare case when the common “have you tried turning it on and off?” approach, actually makes things worse.
Testing iBeacons will require a bit of patience and may require some ingenuity, just ask Ben Dodson and his — clever way to “simulate” entering and leaving regions:

Conclusion

iBeacons aren’t perfect, but they’ve certainly improved. Simple use cases will work pretty well. More complex use cases just require a bit of extra care. The technology enables a lot of new possibilities, from simple ideas like reminding your conference attendees what the WiFi password is when they arrive at your venue, to an immersive shopping or museum experience.
What worries me a little is that we haven’t seen a lot of real case studies in the wild. Imagination’s the limit, but clearly iBeacons haven’t been fully embraced yet. It certainly may be due to their rough start, but as with any technology, if it’s used for its own sake and doesn’t provide actual value to end users, it’s usage is doomed to fail. Can iBeacons actually add real value to the mobile experience? Are they reliable enough to do so? I think so, but during development, make sure you understand their quirks and limitations.

If you want to play with iBeacons, you can do it easily by building something with Glide – our app creation platform. Check it out here.
2 Comments
Úll Conf iOS app

Úll Conf iOS app

This year at Úll Conf I had the pleasure of working with the organisers on creating the Úll iOS app. In order to build and publish the application we used Glide – an app creation platform, which I’m working on with Chris Harris. While the key feature of Glide is easy content collation via Dropbox – which allowed us to easily publish the schedule, photographs and speaker information – we’ve been recently experimenting with Apple’s iBeacons.

The conference took place at the Lyrath hotel, in charming Kilkenny, Ireland. The venue was quite large and had several interesting facilities, that we wanted to expose to the participants of the conference.

On Tuesday morning we’ve sent out a notification and published several clues linked to each place. In each room we’ve setup a kontakt.io beacon. We configured our content to post a notification when the beacon was ranged and unlock content related to the room, which included beautiful illustrations done by Carolina Buzio.

2014-05-04 21.45.36

Overall, everything went well. A few takeaways from the experiment:

  • detecting another beacon in the same region doesn’t usually wake up the app again. One of the workarounds I’m using is continuing to range beacons in background, by requesting a background task. That obviously only works for a finite amount of time.
    Another solution is to use multiple beacons regions, but rememeber that you can track up to 20. You’ll also need re-programmable beacons! As Apple points out, you could reconfigure which regions you’re tracking based on where you are.
  • make sure people have Bluetooth turned on. Biggest “oops!” of the experiment. The app didn’t inform the users to switch on bluetooth.
  • Beacons.

    We used kontakt.io beacons supplied by @dermdaly

    dissapearing beacon bug: one of the bugs that I noticed was that often ranged beacons dissapeared several scans after they were initially ranged. In our case this wasn’t a huge problem, we just needed to range it once, but if you’re depending on the beacon to stick around on that list (while you’re actually in range), it’s a problem.

  • beacons not working until device reboot: it’s 2014 and some people still had to restart their phones in order for beacons to work. No comments here.

 


All iBeacons aside, I highly recommend both Úll Conf and Lyrath 🙂

 

Lyrath

Leave a comment

I had a little play with different documentation generators recently and it inspired me to write a handy little tool to review all your “//TODO:” comments in code. There’s a lot of criticism around putting “TODO” and “FIXME” etc in code, it does sometimes end up quite badly. However, if you try to grasp it and use it to get a better overview of your progress, it might not be all that bad. As usual… it’s quite cool what you can do with bash.

Very minimalistic shell script, grab it as a Gist: https://gist.github.com/1212539

Leave a comment

I wanted to call this post “Project Cemetery”. Some experiments go bad, some go good. This one went far better than I expected, but besides interesting results, nothing really kicked off. Let me start from the beginning then. Last year (2010) I met a group of awesome people – employees of the OTHER media, who showed off some cool stuff in Mobile. One thing was particularly cool. A 3d app prototype in WebKit showed off by Chris Harris (@_ChrisHarris). Couple months later, I was lucky enough to join the team and work on a web app written with JS and CSS transforms. After that I got really excited about how much rendering power you can squeeze out from a browser on an iPhone, I decided to play a bit more with 3d transforms, see where it takes me.

Experiment #1: 3D Sci-Fi Racing game

(try it on Safari/WebKit nightly)
controls: arrow keys, space, C

I got carried away on this one! It was pretty cool, but runs correctly only on Safari/WebKit nightly. It has a physics engine, collision detection. All graphics using pure CSS3. Some of you may wonder: why not WebGL? Well.. there is one major problem with WebGL – it’s not supported on any mobile devices at the moment! And it might not be for a while, but while experiment no 1 was pretty cool, it failed to run on the iPhone. I’ve tried optimising, but I had to change the concept and do it from scratch. I was scratching my head, if it’s even worth trying, since there isn’t much of a case for such usage of this technology. It couldn’t compete with native 3d games. I finally got convinced by Chris: “iAds. You can use this in iAds.”. It made perfect sense, I then realised that when I saw the iAd keynote, I hated these ads, especially the games. Toy Story 3 puzzle game? :/ Ugh!! Here’s my shot at a game embeddable in iAds:

Experiment #2: 3D Platform game optimised for iOS

(try it on any WebKit browser including iOS)
controls on PC: arrow keys, space.

Boom! By the end of November 2010 it was finished. No-one could believe that this was a Web-app. And it ran on an iPhone 3G! You basically play a penguin who picks up ice cream 😀 I’ve been looking into selling this piece as a framework, but it didn’t work out. Turns out trying to work with ad agencies is quite hard too. If anyone’s still interested, give us a shout. I enjoyed the “journey” and got some cool demos out of it 😉 Gotta keep on trying!

Leave a comment

Ever had this problem? You were so excited to see, if some piece of code works on your live system, that you forgot to change database access configuration and file paths? Probably not, because we’re all respected professionals here *wink* and the case is usually: it’s 10pm, still at the office and x product is launching tomorrow and you accidentally overwritten the configuration, because you didn’t have time to finish the deployment script :P. Or maybe you have to deploy your application to even more than two machines? Well, here’s a small cheat sheet.

The lazy way


switch (php_uname('n')) {
    case 'livedevhost04':
		$dbhost = 'sql.example.com'; $dbuser = 'myapp_user';
		$dbpass = 's7d6y3726ye86'; $db = 'myappdb';
		break;
    case 'Mateusz-Laptop.local':
		$dbhost = 'localhost'; $dbuser = 'root';
		$dbpass = ''; $db = 'testdb';
    	break;
    default:
       echo 'No configuration found for host: '.php_uname('n'); exit;
}

This way is quite nice for most scenarios. Very convenient. Get the machine’s hostname, add a “case” to the switch with server’s configuration and you’re good! If you’re deploying through some sort of SFTP/WebDAV protocol, you can easily upload files without any additional modification before running the script. The same with deployment techniques like Deploy using Git.
The only problem is that you’re slightly exposing configuration settings for all your boxes. If you don’t feel comfortable with this, try a different technique like symlinks to a local configuration file.
Personally, I use it quite often. It’s better and way less annoying than swapping commented settings.

The ‘bash’ way

This can be used for many different scenarios. Not just files, but also directories. Here’s a very nice and readable script for symlinking stuff based on local hostname:

#!/bin/bash

targetfile=webroot/config.php
fromscheme=webroot/config._HOST_.php

fromfile=${fromscheme/_HOST_/`hostname`};

if [ -e $fromfile ]
then
 rm $targetfile
 ln -s $fromfile $targetfile
 echo $fromfile == $targetfile
else
 echo [ERROR] Local configuration file not found: $fromfile
fi

Additionally, you might want to execute a custom script that will do something for you after retrieving a configuration set.
Notice the “webroot/”, please keep sensitive scripts outside your document root, mkaay? Maybe even clean them up after deploy and keep them in repo!

You’re only in trouble, if you don’t have access to a bash shell on your hosting server (use first method) or you’re running Windows (you can try cygwin if you’re mad enough ;] )

A JavaScript Bonus

You’d be surprised how many times, I almost did something very silly on a deployed version of an ajax based application. As a bonus, here’s a script you can put in your app, to help you identify, which build you’re currently working on. Especially useful, when running on iOS in web app mode.

<div style='display:none;color:red;' id='devnotification'>TEST SERVER</div>


var currentHost = location.href.split('/')[2];
if (currentHost == 'localhost' || currentHost == 'dev.example.com')
document.getElementById('devnotification').style.display = 'block';

Enjoy! And remember to run your tests kids!

1 Comment

Getting cross-site content with JavaScript is cool, since it usually requires a tiny bit of extra effort when designing the feeds or deploying a callback proxy. Thanks to Yahoo Pipes it has now become very easy to get any content, even a whole web page and crunch it in your JavaScript web app.
First go to pipes.yahoo.com and Create a new Pipe. You’re going to have to log in.
Drag “URL Input” from “User inputs” to your pipe diagram. Now get back to “Sources”. If you’re planning on fetching a website, drag “Fetch Page”. If it’s a JSON or XML feed “Fetch Data” (all data will be automatically transformed ).
The next step is linking the elements together. Drag a link from the “URL Input” into you source’s URL Attribute and from sources output to Pipe Output.
Your pipe should look something like this:

Click “Save” and “Run Pipe…”. You’ll be taken to the pipe information page, where you can enter the URL which you want to proxy. Submit with “Run Pipe”, after it has loaded, select “Get as JSON”.
You should see some nice JSON with the transformed content. The URL to such pipe looks like this:
http://pipes.yahoo.com/pipes/pipe.run?_id=d53d0d4793aa292d3e02885ba9b22cba&_render=json&fromurl=http://stawecki.com
Now guess how to add a callback 😉
http://pipes.yahoo.com/pipes/pipe.run?_id=d53d0d4793aa292d3e02885ba9b22cba&_render=json&fromurl=http://stawecki.com&_callback=test
Surprise 😉 There is an underscore before “callback” attribute name. (weirrrd) For anyone who is new to XSS, “callback” is basically the name of a JavaScript function that receives the content. To show how it works, here’s a simple script that downloads a website and returns the response’s character length:


	function test(response) {
		try {
			alert( 'Content size: '+
			response.value.items[0].content.length );
			} catch(err) { alert('Invalid response'+err); }
		}

	function getURL(urlstr) {
		var ka = document.createElement('script');
		ka.type = 'text/javascript';
		ka.src =
'http://pipes.yahoo.com/pipes/pipe.run?_id=d53d0d4793aa292d3e02885ba9b22cba&_render=json&fromurl='+
		escape(urlstr) + '&_callback=test';
		var ks = document.getElementsByTagName('script')[0];
		ks.parentNode.insertBefore(ka, ks);
	}

And here’s a live version to try:
Simple Pipes Callback

Here’s a slightly more complicated example. I’m getting HTML content, parsing it internally and listing all links on the website (NICE!):
Link Scraper Demo

These examples used “Fetch Page” in pipes. Here’s an example of reading an RSS feed using “Fetch Data”. This script alerts the most recent news item from an external RSS feed. Notice that Yahoo Pipes conveniently transforms any feed to JSON (or XML if you really really want).


	function test(response) {
		try {
			var newsItem = response.value.items[0].channel.item[0];
			alert( newsItem.pubDate +" - " + newsItem.title +" - " + newsItem.description );
			} catch(err) { alert('Invalid response'+err); }
	}

	function getURL(urlstr) {
		var ka = document.createElement('script');
		ka.type = 'text/javascript';
		ka.src =
		'http://pipes.yahoo.com/pipes/pipe.run?_id=4d625dfe6977e71acb45db4aa51726a6&_render=json&feedurl='+
		escape(urlstr) + '&_callback=test';
		var ks = document.getElementsByTagName('script')[0];
		ks.parentNode.insertBefore(ka, ks);
	}

And here’s a live version to try with BBC News RSS feed:
Simple RSS Callback

Now go and cross site the hell out of the internetz! Soon slightly more practical examples.

1 Comment

I’ve been recently having a lot of thoughts on live data and visualisation. Tweet Splash presents data available through Twitter API. This time, I’m going to set up cheap event tracking, which you can very easily use in many different situations and review later on Google Spreadsheets.

1. Setting up and playing with Google Docs: Forms

Log into your Google Account and go to Google Docs. Press “Create New” -> Form
I’ll call my form “Blog Searches”. Let’s have only one “question” which will represent our event or query made by a user. In my case, question title is “keyword”, question type Text and question is required. Click “Done” and make sure you delete “Sample question 2”. Save the form and click the link at the bottom to see the public version of your form.

It should look more or less like this. You can try, if it works by posting a test keyword, then go back to the document list and enter the form again, this time in a Spreadsheet form.

Now it’s time for the hacky part. Go to the public version of the form and look up the source (usually right-click “View Source” ;] ).

We need to retrieve 2 values: Form Action URL – to know where the form is posted to and Input Text’s Name, to know what’s the name of out “Keyword” parameter.

Form Action URL will be here (in red, it’s the attribute value of “action” in the “form” tag):

<form action="https://spreadsheets.google.com/formResponse?formkey=dDVCMlYzMmpuWTg0VUhZUkltaXl5OEE6MQ&amp;ifq" method="POST" id="ss-form">

Input Text’s Name (in red, attribute value of “name” in the only “text” input field):

<input type="text" name="entry.0.single" value="" class="ss-q-short" id="entry_0">

Now let’s try a small trick I discovered. Usually the form data is sent through a POST request, however turns out Google doesn’t mind, if you send values over a typical GET, which means you can put them as a part of your URL! In my case I’m going to this URL in my browser (note that I ignored the “ifq” parameter):

https://spreadsheets.google.com/formResponse?formkey=dDVCMlYzMmpuWTg0VUhZUkltaXl
5OEE6MQ&entry.0.single=Testing+GET+form+submission

Basically, to the URL, you append an “ampersand symbol”, name of the field e.g. “entry.0.single”, an “equals sign” and finally a message. Remember that a text in a URL has to be properly encoded e.g. spaces are turned into a “+” or “%20”, a browser will do it for you.
If you check your spreadsheet now, you should see the message:

Now I will show two methods for mixing this up with your website or service: sever side and client side.

2a. Submitting an event – Server side

I’m going to show the server side method first, since it’s really the best way to do it. If you can you should avoid exposing tricks like this, primarily because it’s easy to recover your form URL from a piece of a publicly available JavaScript, which means somebody might play a nasty trick on you and post some trash into your spreadsheet. On the other hand, if you do it through JavaScript, the user can decide not to be tracked by turning JavaScript off. Here are some examples of a server-side post.

In PHP there are several ways of fetching a URL, this is an example of posting a search query made by user. You can put this code in your index.php and it won’t be called unless parameter “s” is passed. Change it to the parameter name you are using for search or page name, or put a different version of the fetch in different files and provide a predefined event description string.

if (isset($_GET['s']))
file_get_contents(
'https://spreadsheets.google.com/formResponse?formkey=dDVCMlYzMmpuWTg0VUhZUkltaXl5OEE6MQ'.
'&entry.0.single=' . urlencode($_GET['s']) );

Java: (works also on App Engine)


public class ExampleServlet extends HttpServlet {

	public void doGet(HttpServletRequest request, HttpServletResponse resp)
			throws IOException {
		resp.setContentType("text/plain");
		if (request.getParameter("search") != null &&
			!request.getParameter("search").trim().equals("") )
			ExampleServlet.touchURL(
		"https://spreadsheets.google.com/formResponse?formkey="+
		"dDVCMlYzMmpuWTg0VUhZUkltaXl5OEE6MQ&entry.0.single="+
		URLEncoder.encode( request.getParameter("search") , "UTF-8") );
	}

	   public static void touchURL(String address) {
	    	  try {
	              URL url = new URL(address);
	              url.openConnection().getInputStream().close();
	          } catch (Exception e) {
	        	  e.printStackTrace();
	          }
	    }
      }

2b. Submitting an event – Client side

If you’re not lucky enough to be able to modify your backend code e.g. your using Shopify or similar, but you have access to the site’s templates and you can put in some JavaScript, you can still submit an event. Here’s how you do it in JS:


(function() {
var paramsplit = location.href.split('s=');
if (paramsplit.length > 1) {
var keyword = paramsplit[1].split('&')[0];
var ka = document.createElement('script'); ka.type = 'text/javascript';
ka.src =
'https://spreadsheets.google.com/formResponse?formkey='+
'dDVCMlYzMmpuWTg0VUhZUkltaXl5OEE6MQ&entry.0.single='
+ keyword;
var ks = document.getElementsByTagName('script')[0];
ks.parentNode.insertBefore(ka, ks);
}
})();

The script above performs a string split looking for parameter “s=”, which in my case is the search query parameter. If there is none, there will only be one element in the array – the location url itself and the rest of the script will not be executed. Otherwise, another split will separate the keyword from other parameters and the URL to the spreadsheet form will be fetched like an external script file.
This method has some pitfalls. First of all, anyone can see this code and start sending some trash or fake data. It’s also not very clean, because it causes a JavasScript parse error. The browser basically tries to execute the fetched HTML Form code as JavaScript. In order to avoid this you can deploy a simple Google App Engine application or a PHP script somewhere that fetches the URL but ignores the content and provide the URL to this application instead of the Form URL. You can use the Java example from before.
Update: you can also retrieve it as a valid response by calling the form through Yahoo Pipes! Check out my next article on how to do that. Great if you’re expecting a lot of form submissions but don’t want to host it 😉
To hide your code you can try tools like http://www.javascriptobfuscator.com/ , but currently there isn’t a 100% secure method of doing this, that’s why server-side submission is the best option.

3. Reviewing collected data

Let’s get back to the spreadsheet now. Of course, we can just observe the events here just as they are, but there is just one more trick I will reveal 🙂
Go do a different cell e.g. D2 and try a sorting formula:
=Sort(A1:B1000, A1:A1000, FALSE)
This will sort the whole data set based only on the date. The last attribute is FALSE which means it will be descending sort. This way you don’t need to scroll down to see the newest events.
You can also publish the top of the sorted data set as an RSS feed, by going to the Share menu, “Publish as a web page”. Set automatic publishing (unfortunately far from real-time ;/ ) and generate a link in the appropriate format to your sorted data set in cells e.g. D3:E15. You can use tools like http://twitterfeed.com/ to link it to your Twitter notification account!

4. Use cases

I started off with a simple use case of event logging on websites, but there are many other ways in which you can use Forms. You can do any type of logging information: from servers, mobile devices, receiving errors with stack traces, receiving other server notifications, keeping a simple backup database. First off, a lot of you might say: this is ridiculous! you don’t use forms for suff like this! You use specialised analytics and loggers etc. That’s true, but still the beauty of Forms is it’s simplicity. You can very quickly deploy any kind of logging or tracking and see, if it’s even worth going further. So, before you spend hours implementing a cool fast real time notification system for your platform, see what kind of data you might get by taking Forms for a spin.
And that’s it for now. Next time i’ll show how to deploy a dedicated real-time event tracking application.

2 Comments

Name: Tweet Splash
Motto: Make a splash for your event, conference, presentation, gathering…

Link: http://tweetsplash.com/

Summary:
JavaScript based Twitter client for real time Twitter search, easily configured for any event. The purpose of this program is to quickly deliver a “splash screen” on a monitor or projector that will engage event participants into a discussion on twitter.
Tweet Splash is also a YouTube API, Google Mobilizer mashup.

Everything is embedded in one file, easy to customise, great for playing around with Twitter Search API.

Features:
– Link preview
– Remote YouTube jukebox
– Polls from tweets

Coming soon:
– URL Handler
– Html5 Local Storage for configuration

Leave a comment

This scenario is for people who want to put their Macs to sleep after a certain activity that you know will take ‘x’ amount of time, like: watching a movie, downloading a file.

In other words: auto shutdown Mac after certain amount of time.

There’s quite a few apps that might do this for you, but I’m going to show you how to do it the geeky way using the Terminal 🙂

Let’s say you’re going to watch a 2h movie and you want your Mac to go to sleep right after it finishes. Open your Terminal and write:

sleep $[120*60]; osascript -e ‘tell application “System Events” to sleep’

The first part with ‘sleep’ calculates the number of seconds in 120 minutes using bash’s arithmetic expressions and passes it to the ‘sleep’ function. After ‘sleep’ wakes up, we run a simple script that puts your Mac to sleep. Of course you can put any amount of time you need (it’s usually better to put too much than too little 😉 )

If you plan on using this quite often, it’s best to write a short script:

#!/bin/bash
d=$1
while [ -z $d ]; do
read -p “Duration (minutes): ” d
done
sleep $[$d*60]
echo “. . . z z z Z Z Z”
osascript -e ‘tell application “System Events” to sleep’

Save it somewhere in your path, if you can (enabling and using “root” user in Mac OS X), remember to do a ‘chmod +x’ on the file and you’re ready to go.
If you don’t want to use “root”, put it somewhere in your user directory e.g. make a directory “scripts” in “Library” and put your script there.
Create a “.bash_login” script file that will append your private scripts directory to the current path:

#!/bin/bash
PATH=$PATH:/Users/mateusz/Library/scripts

If you’re ready, just pass the number of minutes as an argument (I called my script “sleepafter”):

bash-3.2$ sleepafter 120

The “while” loop in my script makes sure that “sleep” has a value to work with. This way you can easily run the script from Spotlight:

bash-3.2$ sleepafter
Duration (minutes): 60

If you are invoking a task that ends the application process after finishing, then simply add the “put to sleep” script at the end. E.g. when compiling something:

make; make install; sleepafter now

E.g. when using applications like ‘wget’ for downloading files:

wget “http://server/bigfile.bin&#8221;; sleepafter now

Let me know, if you have any good ideas on modifying that script!
That is all 🙂

Leave a comment