Google Glass API

Dies ist eine Zusammenfassung aus dem Video zu Googles Glass API, wo die sogenannte Mirror-API beschrieben wird.

Timeline cards insert

Insert text card

1
2
3
4
5
6
7
8
9
POST /mirror/v1/timeline HTTP/1.1Host: www.googleapis.com
Authorization: Bearer{auth token}
Content-Type: application/json
Content-Length: 29
 
   {
      "text" : "Hello World"
   }

Insert multipart card

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
POST /mirror/v1/timeline HTTP/1.1Host: www.googleapis.com
Authorization: Bearer{auth token}
Content-Type: multipart/related;
boundary="mymultipartboundary"
Content-Length: {length}
 
--mymultipartboundary
Content-Type: application/json; charset=UTF-8
 
   { "text" : "Hello World" }
--mymultipartboundary
Content-Type: image/jpeg
Content-Transfer-Encoding: binary
 
[binary data]
--mymultipartboundary--
}

Insert card with HTML

1
2
3
4
5
6
7
POST /mirror/v1/timeline HTTP/1.1Host: www.googleapis.com
Authorization: Bearer {auth token}
Content-Type: application/json
Content-Length: 270
 
   { "html" : "" }

Insert card with HTML-pages

1
2
3
4
5
6
7
8
9
10
11
12
POST /mirror/v1/timeline HTTP/1.1Host: www.googleapis.com
Authorization: Bearer {auth token}
Content-Type: application/json
Content-Length: 28
 
   { "html" : "...",
     "htmlPages" : [
        "...",
        "..."
     ]
   }

Insert HTML bundle

1
2
3
4
5
6
7
8
9
10
POST /mirror/v1/timeline HTTP/1.1Host: www.googleapis.com
Authorization: Bearer {auth token}
Content-Type: application/json
Content-Length: 28
 
   {
      "html" : "...",
      "bundleId": "1234567890"
   }

Timeline cards update

1
2
3
4
5
6
7
8
9
PUT /mirror/v1/timeline/1234567890 HTTP/1.1Host: www.googleapis.com
Authorization: Bearer{auth token}
Content-Type: application/json
Content-Length: 29
 
   {
      "text" : "Hello World"
   }

Timeline cards delete

1
2
3
4
5
6
7
8
9
DELETE /mirror/v1/timeline/1234567890 HTTP/1.1Host: www.googleapis.com
Authorization: Bearer{auth token}
Content-Type: application/json
Content-Length: 29
 
   {
      "text" : "Hello World"
   }

Timeline cards get

Single item

1
2
3
GET /mirror/v1/timeline/1234567890 HTTP/1.1Host: www.googleapis.com
Authorization: Bearer{auth token}

Complete list of items

1
2
3
GET /mirror/v1/timeline HTTP/1.1Host: www.googleapis.com
Authorization: Bearer{auth token}

Card options

default option

1
2
3
4
5
6
7
8
9
10
11
12
POST /mirror/v1/timeline/ HTTP/1.1Content-Type: application/json
Content-Length: 87
 
   {
      "text" : "Hello World",
      "cardOptions" : [
        {
           "action" : "READ_ALOUD"
        }
      ]
   }

custom option

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
POST /mirror/v1/timeline/ HTTP/1.1Content-Type: application/json
Content-Length: 87
 
   {
      "text" : "Hello World",
      "cardOptions" : [
         {
            "action" : "CUSTOM",
            "id" : "love"
            "values" : [
            ]  
         }
      ]
   }

Subscriptions

1
2
3
4
5
6
7
8
9
10
POST /callback HTTP/1.1Content-Type: application/json
 
   {
      "collection" : "timeline",
      "itemId" : "1234567890",
      "operation" : "UPDATE",
      "userToken" : "example_user",
      "verifyToken" : "some_secret"
   }

Ocelot auf MacOSX installieren

Auf der Suche nach einer Möglichkeit CUDA Programme auf meinem Mac ausführen zu können, bin ich auf GPU Ocelot  gestossen. Ein “modular dynamic compilation framework for heterogeneous system“. Das heißt CUDA Programme werden weiterhin mit dem NVIDIA CUDA Compiler erstellt, nur das anstelle der CUDA Bibliothek libcudart.so die von Ocelot zur Verfügung gestellte Bibliothek libocelot.so benutzt bzw. gelinkt wird. So kann das Programm entsprechend auf verschiedenen Zielplatformen (heterogeneous system) ausgeführt werden. In meinem Fall auf einem x86 Mac mit Intel HD Graphics 3000. Zwar läuft das ganze langsamer, da es auf der CPU und nicht der GPU ausgeführt wird, aber für den “Introduction to Parallel Programming” Kurs auf Udacity reicht es aus.

Download

Die Sourcen befinden sich auf der Projekt Seite GPU Ocelot und können so wie auf dort beschrieben über Subversion runtergeladen werden:

svn checkout http://gpuocelot.googlecode.com/svn/trunk/ gpuocelot-read-only

Zusätzlich werden noch weitere Programme/Bibliotheken und eine funktionierende CUDA Installation erwaretet. Siehe GPU Ocelot Wiki.

Install

Sobald die Sourcen verfügbar und alle notwendigen Pakete installier sind, kann über:

./build.py --install

installiert werden. Die genauen Anweisungen können auch im GPU Ocelot Wiki nachgelesen werden.

Mac spezifische Installation/Einstellungen

Da die Installation bei mir nicht ganz reibungslos geklappt hat, habe ich hier alle Einstellungen und Installationsschritte aufgeschrieben, die notwendig waren um erfolgreich CUDA Programme auszuführen:

PTXLexer issue: .

debug_build/ocelot/ptxgrammar.hpp:355:14: error: 'PTXLexer' is not a member of 'parser'

Es kommt zu Problemem mit dem Code in der Datei ptxgrammar.hpp in Zeile 354. Ein einfaches Auskommentieren dieser Zeile hilft hier weiter.

OpenGL issue:

Die GL Bibliotheken auf dem Mac heißen OpenGL und nicht GL. Somit müß an jeder Stelle wo diese genutzt werden die Zeile von

#include <GL/gl.h>

in

#include <OpenGL/gl.h>

geändert werden. Zum Glück sind es nicht soviele.

Boost issue:
Die boost Installation wird in /usr/lib erwartet. Mac ports hat die Bibliotheken aber in /opt/local/lib installiert. Somit muß auch das entsprechend angepaßt werden. Dafür muß die build_environment.py Datei im gpuocelot/ocelot/scripts Verzeichnis modifiziert werden.

System

Rechner:
Mac OSX 10.8.3
MacBook Pro 13 Zoll, Ende 2011
Grafikkarte Intel HD Graphics 3000 384 MB

NVCC:
nvcc: NVIDIA (R) Cuda compiler driver
Copyright (c) 2005-2012 NVIDIA Corporation
Built on Fri_Sep_28_16:10:16_PDT_2012
Cuda compilation tools, release 5.0, V0.2.1221

AVR USB Programmer

Für das Programmieren der AVR Microcontroller habe ich einen USB Atmel ISP Programmer zusammengebaut. Davon existieren im Internet unterschieldiche Versionen, die sich auf den ersten Blick nur im Layout unterscheiden. Meine Entscheidung ist auf den Bausatz von Ulrich Radig gefallen, da dieser passgenau auf ein sehr schönes Gehäuse ausgelegt ist.

Die Platinenmaße wurden entsprechend dem Fischer Gehäuse bei Reichelt (FR 55 25 80 ME :: FISCHER Frame-Gehäuse 55×80) gewählt. Man kann es dort für 11,95 € (Stand 2011) bestellen.

Damit der USB-Stecker, das ISP Kabel und die 2 Status-LEDs von außen sichtbar sind, habe ich mir Schablonen erstellt, um die Bohrungen an der entsprechenden Stelle vorzunehmen.

Blende für das Layout von Ulrich Radig in einem Fischer Gehäuse

Blende für das Layout von Ulrich Radig in einem Fischer Gehäuse

Die Schablonen sind mit SketchUp in einem Verhältnis von 1:1 erstellt. Zum Ausdrucken habe ich folgendes PDF erstellt (BlendeUSBasp). Damit sollte ein passgenauer Ausdruck am Schnellsten klappen. Zu beachten ist, dass die Druckereinstellungen die Datei wiederum 1:1 wiedergeben sollten und keine Skalierung vornehmen. Ich habe mich hier an der Kantenlänge der Blende orientiert und diese mit dem Ausdruck verglichen.

Nach dem die Schablone aufgeklebt und mit einem Standbohrer bearbeitet wurde, war der Rest nur noch reine Feil-Arbeit.

Und hier das Resultat (leider etwas dunkel)

iOS – Dauerhaftes Speichern von Werten

NSUserDefaults:
Beschreibung der Klasse bei Apple

Speichern des Wertes:

[[NSUserDefaults standardUserDefaults] setObject:someVal 
                                       forKey:someKey];

Auslesen des Wertes:

Field.text = [[NSUserDefaults standardUserDefaults] 
                              stringForKey:someKey];

Löschen des Wertes:

[[NSUserDefaults standardUserDefaults] 
                              removeObjectForKey:somekey];

Move Subversion repository

To move a subversion repository from one server to another you need to “export” the data from the old repository and “import” it to the new one.

Export

The export of the complete repository can be done with and without admin rights. Both require (remote) console access on the machine where the repository is located.

If admin access is available, then a

svnadmin dump local-rep > filename

is all to get all the revisons and the revision history out of the repository.

If no admin access is available, then the repository needs to be synced and then dumped. To create a synced copy of the repository and dump it afterwards, the following shell-script can be used:

DEST=$1
SRC=$2
 
svnadmin create $DEST
 
cat <<'EOF' > $DEST/hooks/pre-revprop-change
#!/bin/sh
USER="$3"
 
if [ "$USER" = "user_name" ]; then exit 0; fi
 
echo "Only the svnsync user can change revprops" >&2
exit 1
EOF
 
chmod +x $DEST/hooks/pre-revprop-change
svnsync init file://`pwd`/$DEST svn://$SRC
svnsync sync file://`pwd`/$DEST
svnadmin dump $DEST > ${DEST}-dump.txt

 

Changes to the repository structure

If the directory structure needs to be changed, then the dump file can be manipulated accordingly.
Lines starting with Node-path: and Node-copyfrom-path: must be manipulated, so that the wanted structure will be created. If additional directories are necessary, then they need to be created manually.
Before they are used, the following lines have to be issued:

Node-path: newDir
Node-kind: dir
Node-action: add
Prop-content-length: 10
Content-length: 10
 
PROPS-END

Then all the node-path and node-copyfrom-path lines have to be changes from

Node-path: oldDir/oldSubDir

to

Node-path: newDir/oldDir/oldSubDir

Import

To load the dump files to the destination repository, you will need files access. Then you can issue the follwing command and wait for the magic to happen:

svnadmin load repository-name < path-to-dump-file

iOS Programmierung: Show modal view

Protokoll das von der aufrufenden Klasse implementiert werden muss:

@protocol InfoViewClosedDelegate <NSObject>
@required
-(void)doneReadingTheInfo;
@end

Aufgerufene Klasse: Vorsicht beim Freigeben des Speichers. Da die Klasse die Elternklasse zum schließen informiert, sollte der Speicher nicht in der Kind- und der Elternklasse freigegeben werden. Dies kann zu Programmabrüchen führen.

@interface InfoViewController : UIViewController {
	id <InfoViewClosedDelegate> delegate;
}
@property (retain) id delegate;
-(IBAction)close:(UIButton *)sender;
@end
 
 
@implementation InfoViewController
 
@synthesize delegate;
 
-(IBAction)close:(UIButton *)sender {
        [[self delegate] doneReadingTheInfo];
}
@end

Aufrufende Klasse:

@interface LoginViewController : UIViewController <InfoViewClosedDelegate> {
...
}
 
-(IBAction)btnInfoClicked:(UIButton *)sender;
-(void)doneReadingTheInfo;

Funktion die ein “on touch” Ereignis abfängt und einen neuen View lädt:

-(IBAction)btnInfoClicked:(UIButton *)sender {
NSLog(@"Info button touched");
 
/* dismiss the keyboard in any case */
if (active != nil) {
NSLog(@"Force the keyboard to be closed");
[active resignFirstResponder];
}
InfoViewController *infoVC = [[InfoViewController alloc] initWithNibName:@"InfoView" bundle:nil];
if (infoVC != nil) {
NSLog(@"Create info view");
infoVC.delegate = self;
[self presentModalViewController:(UIViewController *)infoVC animated:(BOOL)YES];
[infoVC release];
}
NSLog(@"Info button end");
}

Funktion zum schließen:

-(void)doneReadingTheInfo {
	NSLog(@"InfoView will be closed");
	[self dismissModalViewControllerAnimated:YES];
}