Zoek

Uitgebreid zoeken Artikelen per auteur

  

Surface development

Veel mensen die Surface voor het eerst zien ervaren het als iets ‘magisch’. De gebruikers zien een Surface niet als een PC maar als een gebruiksvoorwerp, en uiteraard is dit precies wat de bedoeling is.

Ook ontwikkelaars denken er zo over. Doordat de user interface niet lijkt op wat we gewend zijn van PC’s is de koppeling tussen PC- en Surface-ontwikkeling verbroken. Toch is het ontwikkelen van Surface-applicaties niet moeilijker dan het bouwen van andere applicaties met Windows Presentation Foundation (WPF). De moeilijkheid van het bouwen van Surface-applicaties ligt meer in het concept, de form factor en het maken van applicaties die van alle kanten benaderd kunnen worden. Liever gezegd: de ‘wat’ vraag is moeilijker te beantwoorden dan de ‘hoe’ vraag.

De specifieke Surface-uitdaging

Het ontwikkelen voor Surface is anders dan het schrijven van Windows of Web applicaties.

Er zijn een aantal dingen die het zo anders maken:

  • Er is geen boven en onderkant van het scherm: de applicaties moeten in principe van alle kanten te benaderen zijn;
  • Er is niet één gebruiker met één muiscursor: er kunnen (horen?) meerdere gebruikers tegelijkertijd aan het werk (te) zijn die ieder hun eigen ding doen;
  • Alles vindt plaats in één scherm: je kunt beter geen gebruik maken van andere schermen en popup windows;
  • De resolutie is beperkt tot 1024 bij 768 pixels, je hebt dus niet al te veel scherm ruimte;
  • Maak weinig gebruik van tekst invoer: Surface is geen ‘data entry’ platform;
  • Hou rekening met de fysieke beperking van de gebruikers: met een vinger is het moeilijk om heel nauwkeurig een element te selecteren. Vingers zijn minder nauwkeurig dan een muis!

Dit klinkt allemaal nogal beperkend, maar in de praktijk valt dat best mee. Zeker de resolutie klinkt als een belemmering maar als je het ziet draaien op je 30” Surface machine ziet het er allemaal toch goed uit. Je kunt alleen niet al te veel elementen op je scherm kwijt.

Ontwikkeltools

Een Surface-machine is te krijgen in twee varianten: de commercial uitvoering en de developer uitvoering. Indien je bij Microsoft de laatste koopt, krijg je, naast de indrukwekkende hardware, ook alle tools die je nodig hebt om applicaties te schrijven. Ook mensen met een Academic Alliance MSDN abonnement (de MSDNAA leden) hebben toegang tot de software.

Deze software bestaat uit een aantal onderdelen:

  1. De simulator: deze gebruiken we om onze code op te testen als we niet direct bij de Surface unit kunnen komen;
  2. Een SDK: alle libraries, samples en dergelijke zijn hier te vinden;
  3. Een aantal tools: denk hierbij aan een tool om tags te printen en om je applicatie een stress test te laten ondergaan.

De SDK draait momenteel alleen op 32-bitsversies van Windows Vista Business en hoger, en ook op Windows 7. Een 64 bits versie is er niet maar met enige hacken kun je dat wel aan de praat krijgen. Let wel op: dit is geen supported omgeving!

Je hebt uiteraard Visual Studio nodig, maar de C# Express-editie volstaat (dat is ook de versie die je bij je Surface-machine krijgt). Download wel SP1 en de XNA-toolkit; zonder deze installeert de SDK niet.

XNA of WPF?

Als je de SDK geïnstalleerd hebt, krijg je in je ‘New Project…’ dialoog in Visual Studio een paar extra templates te zien. Je kunt hier kiezen tussen een nieuw Surface-project in WPF of in XNA.

Fig. 1: Project-templates in VS2008 met Surface SDK

Wat moet je nu kiezen? Ga je voor XNA of voor WPF? En waarom hebben we die keuze? Het antwoord daarop ligt in het verleden.

XNA of WPF: voor Surface maakt het niet uit

Microsoft had ooit bedacht dat XNA het platform zou worden voor het ontwikkelen van applicaties voor devices. Als eerste was er de omgeving voor de XBox. Als je applicaties wilt ontwikkelen voor de XBox doe je dat in de XNA-omgeving. Later is daar de Zune bij gekomen: ook daarvoor moet je gebruik maken van de XNA-templates.

Aangezien Surface gezien werd als device, lag het voor de hand om XNA in te zetten als ontwikkelplatform. Echter, tijdens de ontwikkeling van de SDK bleek dat er eigenlijk weinig verschil was tussen het bouwen voor Surface en voor normale Windows-applicaties. Toen is besloten om WPF als platform in te zetten als ontwikkelomgeving voor Surface. Het maakt niet zoveel uit welk van de twee je kiest, hoewel XNA iets meer gericht is op het low-level programmeren. Als je bijvoorbeeld de ruwe input van de camera’s wilt afvangen, moet je dat via XNA doen. WPF daarentegen biedt meer tools voor het schrijven van de business logic in je applicatie.

Daarnaast, maar dat is een persoonlijk gevoel, vind ik het vreemd om een serieuze applicatie te schrijven waarbij de hoofdregels de code ‘Game app = new Game()’ bevatten.

In de praktijk kiezen de meeste ontwikkelaars voor WPF.

De simulator

Fig. 2: De simulator aan het werk

Als je de SDK geïnstalleerd hebt, krijg je ook de Surface Simulator erbij. Deze tool stelt je in staat om je code op je werkstation te testen zonder dat je echt naar een Surface-machine moet gaan.

Het is wel belangrijk dat je je werk regelmatig op een fysieke Surface-machine draait: het is erg lastig om vanaf je desktop te controleren of je User Interface vanaf alle kanten van de tafel goed te gebruiken is. Ook het testen van je tags gaat makkelijker op de tafel zelf dan in de simulator.

Toch zul je merken dat, naarmate je meer ervaren wordt in Surface-development, de Simulator een enorm goede tool is. Bij Microsoft zelf hebben ze bij het Surface-team slechts één Surface-machine per ongeveer 8 ontwikkelaars: 90% van de tijd werken zij in de Simulator.

In de simulator kun je met meerdere muizen tegelijkertijd werken. Op die manier kun je meerdere gebruikers nadoen, maar in de praktijk is dat vrij lastig. Ik kan niet echt werken met een muis in iedere hand, maar misschien lukt het jou wel. Nodig is dit niet: je kunt met je muis een vinger nadoen, vastzetten en dan er een tweede vinger aan toevoegen. Je kunt je bewegingen opnemen en later weer afspelen zodat je een soort van test kunt maken.

Je kunt vingers en objecten simuleren en uiteraard van bijna alle mogelijkheden van de Surface-omgeving gebruik maken. Je kunt niet bij de ruwe camerabeelden komen: de Simulator heeft immers geen echte fysieke camera’s aan boord.

Voor de rest werkt de Simulator uitermate goed en is het een mooie manier om de bulk van je werk te doen. Alleen het fine-tunen en het testen van je applicaties hoef je dan nog op de Surface-machine zelf te doen.

Om applicaties te ontwikkelen heb je meer nodig dan alleen de Simulator. Na installatie krijg je dan ook nieuwe Visual Studio templates, een aantal tools en een nieuw stel WPF-controls.

Controls

Naast de standaard WPF-controls heb je na installatie van de SDK een extra set controls tot je beschikking. Deze controls zijn onder te verdelen in 3 categorieën:

  1. Afgeleide controls, deze zijn varianten van de standaard WPF-controls;
  2. Surface-specifieke controls, oftewel controls die je alleen voor Surface-applicaties kunt gebruiken;
  3. Non-Visual controls, die extra functionaliteit bieden.

Je ziet de controls in figuur 3.

Fig. 3: De toolbox met Surface-items

Afgeleide controls

Als je WPF gewend bent, ken je de standaard controls wel. Veel ervan kun je direct gebruiken in je Surface-applicatie; onze applicatie is immers een WPF-applicatie. Toch zijn er een paar dingen anders: Surface stelt speciale eisen aan de applicaties.

Surface-applicaties zijn bedoeld om door (meerdere) mensen gebruikt te worden, met behulp van vingers en objecten. Dit betekent dat de standaard controls niet voldoen. Denk b.v. aan een standaard checkbox. Door het aanklikken van deze control kun je een vinkje plaatsen of verwijderen. Dit vakje echter is vrij klein, te klein om met je vingers te bedienen. Voor Surface is dus een grotere control gemaakt.

Ook een Button is anders dan je gewend bent. Naast het grotere formaat is het gedrag van een button ook anders. Stel je eens voor: iemand plaatst zijn vinger op de button. Een tweede persoon plaatst zijn vinger ernaast, op dezelfde button. De eerste persoon verwijdert zijn vinger weer. Wat moet er nu gebeuren? In standaard Windows-applicaties kennen we dit probleem niet: er is immers maar één muis. De Surface Button control zorgt ervoor dat dit soort gebeurtenissen goed afgehandeld worden (voor de volledigheid: er is een ContactRemoved event die afgevuurd wordt voor iedere vinger die van de control af gaat, maar het Click-event wordt pas afgevuurd als alle vingers weg zijn.)

De afgeleide controls staan in de volgende tabel:

Control Opmerkingen
SurfaceScrollBar  
SurfaceButton  
SurfaceCheckBox  
SurfaceContextMenu Bij voorkeur niet gebruiken
SurfaceInkCanvas  
SurfaceTextBox Indien deze control geactiveerd wordt, verschijnt er een keyboard op het scherm. Er kan slechts één keyboard tegelijk aanwezig zijn.
SurfaceMenu Bij voorkeur niet gebruiken
SurfaceMenuItem Bij voorkeur niet gebruiken
SurfaceSlider  
SurfaceListBox  
SurfaceListBoxItem  
SurfaceRadioButton  
SurfaceScrollViewer  
SurfacePasswordBox Ook hier verschijnt bij het activeren een keyboard, echter de toetsaanslagen zijn niet zichtbaar. In een multi-user omgeving kun je twijfelen aan het nut hiervan (iedereen kijkt mee terwijl je het wachtwoord invoert...)

Bij een aantal van deze controls (vooral de menu’s) heb ik vermeld dat je ze beter niet kunt gebruiken. De reden hiervoor is dat het gebruik van menu’s niet intuïtief werkt, het staat de acceptatie van je applicatie in de weg. Indien je toch een menu wilt gebruiken, kun je beter voor de speciale ElementMenu kiezen.

Surface specifiek

Een aantal controls zijn speciaal ontwikkeld voor Surface. Momenteel zie ik hier en daar al open source libraries verschijnen met meer controls, dus je bent niet beperkt tot dit lijstje.

Control Opmerkingen
ElementMenu Een speciaal menu voor Surface. Werkt meer intuitief dan de standaard context menu maar is functioneel vergelijkbaar
ElementMenuItem Dit zijn de items in het ElementMenu
LibraryBar Een speciale container
LibraryBarItem Items in de LibraryBar
LibraryStack Een soort ListBox, maar dan met elementen over elkaar heen geplaatst.
LibraryStackItem Items in de LibraryStack
LibraryContainer Een mengvorm van de LibraryBar en de LibraryStack: de gebruiker kan tijdens gebruik switchen tussen de LibraryBar en de LibraryStack modus
ScatterView Een soort ListBox waarbij de elementen vrij over het scherm kunnen worden verplaatst, geroteerd en vergroot of verkleind.
ScatterViewItem De items die in de ScatterView zitten. Hier kun je per item aangeven of ze mogen worden verplaatst, van grootte veranderd en/of geroteerd.

In figuur 4 zie je een voorbeeld van een LibraryBar, met daarin 3 LibraryBarItems. De gebruiker kan deze met de vingers selecteren en ze eventueel ergens naar toe slepen.

Fig. 4: De LibraryBar in actie

Non-Visual Controls

Momenteel is er maar één non-visual control, en dat is de TagVisualizer. Hier ga ik later in dit artikel dieper op in. Hij staat hier alleen even voor de volledigheid.

Contacts

De kracht van Surface zit hem in het gebruik ervan. Een goede Surface-applicatie moet uitnodigen tot gebruik; mensen moeten er graag aan zitten. Nu is ‘eraan zitten’ niet zo’n probleem, maar het is wel prettig als we in onze applicaties ook iets kunnen doen met die aanrakingen.

Surface is geen touch-systeem. Veel mensen noemen het een aanraakscherm maar dat is niet correct. Surface is, zoals dat zo mooi heet, vision based. Met andere woorden: er zitten camera’s in het systeem die door het scherm naar buiten kijken en detecteren wat er gebeurt. Dit maakt het mogelijk om objecten te herkennen, iets wat met een aanraak-systeem niet zou kunnen.

In je code moet je uiteraard ook bij de contacten kunnen. Veel contact-gebaseerde events worden al opgevangen door de Surface-controls: een SurfaceButton b.v. kan zelf omgaan met de contacten die op het scherm geplaatst worden en er weer vanaf gehaald worden. Somsmoet je echter zelf iets met de contacten doen. Het is b.v. mogelijk om te detecteren welke gebruiker iets op de machine doet. Nou ja, niet echt detecteren maar je kunt een aardige gok maken.

Surface is Vision Based, niet Touch Based

Als iemand zijn vinger op het scherm plaatst, ziet het systeem dat. Het leuke is dat als je je vinger op het scherm neerzet, er een schaduw ontstaat onder je vinger; deze schaduw wordt lichter naarmate je vinger verder van het scherm is. Op deze manier ontstaat er een plaatje wat een beetje op een komeet lijkt: een duidelijke afdruk bij het puntje van de vinger met een vager wordende staat in de richting van de hand.

Op basis daarvan kan de Surface-omgeving de hoek bepalen waaronder de vinger op het scherm staat, en daarmee kun je dus raden waar de gebruiker staat (mensen leggen hun vinger meestal in het verlengde van hun arm neer).

private void OnContactDown(DependencyObject sender,
  ContactEventArgs e)
{
  // Is het een vinger?
  if (e.Contact.IsFingerRecognized)
  {
    // Wat is de hoek?
    double angle = e.Contact.GetOrientation(this);
    // Bereken het kwadrant
    if (angle....)
  }
}

Mocht je nu een contact op het scherm hebben wat geen vinger is, dan kun je de locatie, de bounding-rectangle enz. opvragen. Op die manier kun je alle soorten objecten herkennen en er iets mee doen.

Tags

Als je een Surface-machine koopt krijg je er een groot vel bij, met daarop 255 stickers. Deze stickers, voorzien van een stippenpatroon, kun je gebruiken om objecten te ‘taggen’. De stickers worden door Surface herkend en behandeld als Contacts. Dit stippenplaatje noemen we de tags.

Byte Tags

Er zijn twee soorten tags: we kennen de byte tag en de identity tag. De byte tags bevatten, zoals de naam al suggereert, een bytewaarde. Ze kunnen dus waardes tussen 0 en 255 bevatten. Figuur 5 laat een voorbeeld van zo’n byte tag zien, in dit geval met de waarde 42 (2A hexadecimaal)

Fig. 5: ByteTag 42

Door het contrast tussen de witte stippen en de zwarte achtergrond kan Surface dit herkennen als een byte tag en de waarde daarvan doorgeven aan je applicatie. En hier komt de non-visual control TagVisualizer om de hoek kijken.

De TagVisualizer control is een control die je ergens op je scherm plaatst. Je kunt hem het hele scherm laten beslaan of slechts een deel ervan. Op het moment dat het systeem at runtime een tag op een TagVisualizer ziet, zal het de juiste events afvuren zodat je weet waar de tag geplaatst is en welke waarde deze bevat. Kijk eens naar het volgende stukje XAML code:

<s:TagVisualizer
  VisualizationAdded="TagVisualizer_VisualizationAdded"
  VisualizationRemoved="TagVisualizer_VisualizationRemoved">
  <!-- Bepaal welke tags geldig zijn -->
  <s:TagVisualizer.Definitions>
    <s:ByteTagVisualizationDefinition Value="#2A"/>
    <s:ByteTagVisualizationDefinition Value="#F0"/>
  </s:TagVisualizer.Definitions>
</s:TagVisualizer>

Hier plaatsen we in het scherm (het hele scherm om precies te zijn) een TagVisualizer. We geven hem twee event-handlers mee: één om af te vangen dat er een tag geplaatst wordt, en één om af te vangen dat de tag weer van het scherm genomen wordt.

Verder definiëren we dat hij alleen mag reageren op de byte tags met de waardes #2A en #F0. Alle andere worden genegeerd. Meer heb je niet nodig om je systeem te laten reageren op tags!

Nu is dit leuk, maar als je dit zou gebruiken krijg je op het moment dat de tag geplaatst wordt een standaard plaatje op je scherm, in de vorm van een draadkruis zoals we dat in schietspelletjes kennen. Dat is meestal niet wat je wilt: je wilt meestal een afbeelding, een stel controls of iets anders betekenisvols op je scherm plaatsen.

Om dat voor elkaar te krijgen moeten we een speciaal soort UserControl definiëren, de zogenaamde TagVisualization class. Dit is gewoon een UserControl met wat extra waardes. Op het moment dat we dan een tag op het systeem zetten die herkend wordt, zal Surface een instance maken van deze UserControl en plaatst deze op de plek van de tag. Als je de tag draait, zal de UserControl mee draaien. Als je de tag verwijdert, verdwijnt ook de User Control. Dit is overigens instelbaar: je kunt er ook voor kiezen hem te laten staan, of pas na 10 seconden te laten verdwijnen, enz.

<s:TagVisualization
  x:Class="SurfaceApplication2.MyTagVisualization"
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/
    presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  xmlns:s="http://schemas.microsoft.com/surface/2008"
  Loaded="MyTagVisualization_Loaded"
  Width="200" Height="150">
  <StackPanel Orientation="Horizontal">
    <StackPanel>
      <Label Content="Naam"  />
      <Label Content="Bedrijf"/>
    </StackPanel>
    <StackPanel>
      <Label x:Name="lblName"/>
      <Label x:Name="lblCompany"/>
    </StackPanel>
  </StackPanel>
</s:TagVisualization>

In bovenstaand voorbeeld definieer ik een TagVisualization class. Het is een user-control die twee labels weergeeft: een naam en een bedrijfsnaam. Op het moment dat deze aangemaakt wordt, wordt het MyTagVisualization_Loaded event afgevuurd. Hierin kunnen we dan kijken wat de bijbehorende Tag-waarde is zodat we de labels kunnen voorzien van zinnige data.

Het enige wat we nu nog moeten doen is de ByteTagVisualizationDefinition die hoort bij de TagVisualizer, aanpassen zodat hij de nieuwe control gebruikt. Dit doen we door de Source Property in te vullen met de naam van de XAML van de UserControl. Als we het systeem nu draaien en we plaatsen er de juiste tag op, ziet het er zo uit:

Fig. 6: Tags in action

Het rode vierkantje is de gesimuleerde geplaatste tag van de Surface Simulator. Ik heb hem iets gedraaid zodat je ziet dat onze UserControl mee draait.

Ik geef toe, echt zinvol is deze applicatie niet, maar met een beetje fantasie kun je zelf andere toepassingen bedenken.

In de TagVisualization kun je ook nog aangeven waar de sticker zit op het fysieke object: het lukt namelijk vrijwel nooit (of is ook niet wenselijk) om je tag precies recht en in het midden van je object te krijgen.

Identity Tags

Byte Tags kunnen, zoals de naam al suggereert, een bytewaarde bevatten. Als je echter b.v. brieven naar al je klanten wilt sturen, en op die brieven een unieke tag wilt printen die ze dan in je winkel op de Surface kunnen leggen voor hun speciale, persoonlijke aanbieding, dan heb je aan 255 waardes waarschijnlijk niet genoeg.

Je wilt meer mogelijkheden hebben, en om aan die wens tegemoet te komen is er in Service Pack 1 van de SDK de Identity Tag toegevoegd. De waarde van een Identity Tag is een GUID, dus een getal tussen de 0 en 2^128. Je hebt ruwweg 3.4e+38 mogelijkheden. Dat moet, zelfs voor de grootste bedrijven, voldoende zijn om alle klanten een unieke code te geven ;-).

Identity Tags zijn groter dan Byte Tags. Ze worden ook iets minder snel herkend. Daarom is het aan te raden om Byte Tags te gebruiken voor objecten die veel verplaatst worden en Identity Tags voor objecten die vrij statisch op het scherm blijven staan.

Voor je code maakt het niet veel uit of je Byte Tags of Identity Tags gebruikt: in de TagVisualizer schrijf je in plaats van een ByteTagVisualizationDefinition een IdentityTagVisualizationDefinition en je bent klaar. Oh ja, een Byte Tag heeft een value property, een Identity Tag heeft een Series (de eerste 64 bits) en een Value (de laatste 64 bits) property, maar voor de rest zijn ze gelijk. Ze zien er uit als in figuur 7.

Fig. 7: Identity Tag

Deployment

Het installeren van een applicatie op Surface gaat iets anders dan je wellicht gewend bent.

De Visual Studio Template genereert een XML-bestand voor je met daarin een aantal settings die je nodig hebt voor het uitrollen van je applicatie naar de Surface-machine.

Dit bestand ziet er als volgt uit:

<?xml version="1.0" encoding="utf-8" ?>
<ss:ApplicationInfo
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xmlns:ss="http://schemas.microsoft.com/Surface/2007/
   ApplicationMetadata">
  <Application>
    <Title>SDN Surface</Title>
    <Description>Demo applicatie voor de SDN</Description>
    <ExecutableFile>
      c:\apps\SurfaceApplication2.exe
    </ExecutableFile>
    <Arguments></Arguments>
    <IconImageFile>c:\apps\Resources\icon.png</IconImageFile>
    <Preview>
      <PreviewImageFile>
        c:\apps\Resources\iconPreview.png
      </PreviewImageFile>
    </Preview>
    <Tags>
      <ByteTag Value="2A">
        <Actions>
          <Launch />
        </Actions>
      </ByteTag>
    </Tags>
  </Application>
</ss:ApplicationInfo>

In dit XML-bestand zet je een aantal zaken:

  1. De titel: deze verschijnt boven het menu-item in het Surface-menu;
  2. Een omschrijving: deze verschijnt onder het menu-item in Surface;
  3. Het pad naar de executable: dit moet een absoluut pad zijn;
  4. Eventuele argumenten om je applicatie mee op te starten;
  5. Een pad naar een plaatje wat als icoon gaat werken: dit is geen echt Windows ioon, deze plaatjes zijn groter dan dat;
  6. Een Preview: dit is wat getoond wordt als je applicatie de focus krijgt in het menu. Dit kan ook een video zijn waarin je laat zien wat je applicatie doet!

Daarnaast heb ik in deze XML ook de tags gedefinieerd. Ik heb de Tag 2A (42 dus...) gekoppeld aan onze applicatie. Dit houdt in dat als iemand, wanneer dan ook, een bytetag op het systeem plaatst met deze code, hij de mogelijkheid krijgt om de applicatie direct op te starten. Dus: de applicatie kan gestart worden simpelweg door een object met de juiste tag te plaatsen.

Dit biedt enorm veel mogelijkheden: denk b.v. eens aan het onderwijs. De onderwijzer geeft aan een groepje kinderen een kaartje met daarop de tag die de rekenapplicatie start. Daarna krijgt een ander groepje een kaartje die de taal-applicatie toont. Geen moeilijke menu’s meer maar simpelweg iets op het scherm neerzetten en je applicatie draait!

Om je applicatie uit te rollen moet je alle bestanden kopiëren naar de locatie die in het XML-bestand staat aangegeven. Daarna moet je het XML-bestand zelf plaatsen in de directory C:\ProgramData\Microsoft\Surface\Programs. Als je dat gedaan hebt, en je hebt geen fouten in je XML-bestand gemaakt, dan verschijnt je applicatie in het menu en je gebruikers kunnen er mee aan de gang!

De tools zijn er, de hardware is er, nu de ideeën nog!

Conclusie

Dit is slechts een korte introductie van de hulpmiddelen die je hebt als je gaat ontwikkelen voor Surface. Maar, als je eenmaal gewend bent aan de omgeving, zul je merken dat de techniek, hoewel uitdagend en spannend, niet de beperkende factor is. Het bedenken van goede Surface-oplossingen, die gebruik maken van de 360 graden interface, van objecten en het verschil tussen de fysieke en virtuele wereld wegneemt, dat is een stuk lastiger. Surface is typisch een omgeving voor mensen die niet (willen?) weten dat ze met een computer werken, hou daar rekening mee in je ontwerp.

De tools zijn er, de hardware is er, nu de ideeën nog! De SDK is een goed stuk software waarmee je in staat bent om snel productief te zijn. Dus bedenk een goede oplossing, vind een Surface-machine om op te testen en leef je uit!

Commentaar van anderen:
replica handbags op 16-7-2010 om 9:35
Having fallenDesigner Handbags in love with horological complicationsbally handbags, de Grisogono has added a new balenciaga replica handbagscomplication to its model collection - the replica Hermesannual calendar. This remarkable swiss watchescomplication is featured by the brand'sreplica omega new Instrumento Novantatre paul smith men's bagdesign.The dial of the timepiece handbags todscatches attention due to the oddlyceline bags placed pair of dial openingsA.Lange & Sohne for sale. These small arc-shaped windows are Tag Heuer for saleplaced at 12 and 8 o'clockcroum for sale, displaying the date and the monthchopard for sale. The hours and minutes are shown by a pair of hands. The seconds hand is featured on a separateA.Lange & Sohne for salesub-dial found at 5 o'clock. The latest timekeeping Rado for salecreation from de Grisogonogucci handbags has incorporated a complicated movement. Thereplica handbags Instrumento Novantatre's self-winding mechanical chanel handbagsmovement automatically takesTag Heuer for sale account of the irregular length of 30-day and replica hermes handbags31-day months.
Tiffany jewelry op 28-7-2010 om 4:27
Tiffany jewelry manufacturers directory,cheap jewelry - lots of registered importers and exporters. Cheap tiffany jewelry manufacturers, Tiffany & co jewelry suppliers, tiffany jewelry wholesales, Tiffany Watches,exporters, sellers, traders and gold tiffany jewelry Distributors from China and around the world at www.goldtiffanyjewelry.com Tiffany jewelry exporters, Tiffany Accessories, Tiffany Bangles, Tiffany Bracelet, Discont Tiffany Bracelet, Discount Tiffany Cufflinks, Fashion Tiffany Earring, Tiffany Necklaces , Discount Tiffany Necklaces, Tiffany Rings, Tiffany Watches
maomao op 30-7-2010 om 6:14

Luxury watches - exudes a new site, Rolex presents the world's wonderful! Replica Rolex is a Swiss watches manufacturer, formerly known as Wilsdorf and Davis Company, by the German (Hans Wilsdof) and the British Davis (Alfred Davis) in a partnership in London in 1905. Polyandry in 1908 by the Hansiweier Division (Hans Wilsdof) Laxiadefen in Switzerland (La Chaux-de-Fonds) Registry was renamed rolex. Best in the world watches.Classic Swiss watches, men watches, watches brand, authentic quality highlights. Creation and production of replica watches are based on a simple and witty invention, Replica Breitling Bvlgari watches Replica Cartier Chanel watches Replica Tag Heuer Replica Omega Replica Ulysse-Nardin this is the "spring", replica watches it can tighten up and store energy, and can slowly release energy to drive the running gear and watch the pointer, to show Time function.Let me into your replica watches, listen to your heartbeat close seo to the arm, montres rolex replica watches Breitling replica Hublot replica Omega replica U-Boat watches the first time with you to be happy ,replica handbags gucci handbags Chanel handbags Balenciaga handbags Burberry handbags Prada handbags like you slept deeply at night, with you every second, let my heart as you countdown, ticking is my prayers replica Handbags Mont Blanc Pen Dunhill Lighter Looking for? To find the cheap replica? let go buy cheap handbags gucci handbags chanel handbags Hermes handbags Hermes handbags replica Hermes Hermes Kelly handbags Miu Miu handbags replica watches replica rolex and more replica watches on sale. You can buy the cheapest replica Rolex cheap rolex Swiss Replica watches Swiss watches Swiss Rolex or Free shipping. We carry all replica handbags brands,knock off handbags replica handbags fake handbags knock off Louis Vuitton Louis Vuitton handbags replica Louis Vuitton handbags replica Louis Vuitton Gucci handbags knock off gucci handbags Prada handbags fake Gucci handbags Hermes handbags Burberry handbags chanel handbags replica Chanel handbags Looking for Cheap and Discount Handbags Designer handbags Louis Vuitton handbags and many more designers Cheap Replica Designer Handbags For Sale! knock off handbags replica handbags replica bags wallets Louis Vuitton handbags of top most designer. replica Louis Vuitton handbags fake Louis Vuitton handbags Gucci handbags Gucci bags replica Gucci handbags Online China replica Goods offer cheapest designer Prada handbags replica Prada handbags Hermes handbags Burberry handbags Chanel handbags replica Chanel handbags most of them are genuine leather Designer handbags Discount handbags cheap handbags replica handbags on sale.Order 2010 Designer Handbags.We have tons of sale replica watches replica handbags keen sale,replica rolex replica watches rolex replica with free shipping.cheap rolex fake rolex rolex watches replica rolex watches Swiss watches Swiss Rolex replica watches replica watches replica handbags replica watches replica watches and Many More Luxury Brand Replica handbags knock off handbags fake handbags knock off Louis Vuitton Louis Vuitton handbags replica Louis Vuitton handbags fake Louis Vuitton handbags Gucci handbags Gucci bags replica Gucci handbags fake Gucci handbags knock off gucci handbags Prada handbags replica Prada handbags Designer handbags Discount handbags replica handbags chanel handbags Finest Workmanship,Quality Guaranteed

Geef feedback:
Verzend Commentaar