Forleden ramte Nokia’s Amber update min Lumia 920.  Opdateringen indeholder en del forbedringer til Lumia, og ikke allesammen er beskrevet lige godt.  Dette er min hitliste over de bedste forbedringer i omvendt prioriteret rækkefølge.

  1. Nokia Glance. Jeg har aldrig før hørt om Glance, men det lader til at være en populær feature fra Nokia N9, som har været efterspurgt på Lumia.  Glance viser klokkeslet på låseskærmen, når man fører hånden henover telefonen.  En lidt pjattet feature, men det er faktisk ok at have, når telefonen ligger på bordet ved siden af en, og det skulle være implementeret på en meget batterivenlig måde.  Glance slåes til under Indstillinger –> skærm + tourch –> overblik. 

    wp_ss_20130822_0006
  2. Farveprofil. Lige ledes under Indstillinger –> skærm + touch finder man Lumia-farveprofil.  Her kan man som noget nyt indstille mætning og temperatur på Lumia’s display.

    wp_ss_20130822_0005
  3. Lagerkontrol.  Med lagerkontrol kan man se, hvor meget plads de enkelte apps bruger på telefonen.  Det er visuelt meget effektivt lavet.  App’en giver endda mulighed for at rydde op i temporære filer, hvis man er ved at løbe tør for plads.  Lagerkontrol findes under Indstillinger.

    wp_ss_20130822_0002wp_ss_20130822_0003wp_ss_20130822_0004
  4. Data sense. Data sense er ikke rigtig dokumenteret nogen steder som en del af Amber, men den dukkede op på min startskærm ifm. opdateringen.  Data sense giver et overblik over, hvad de forskellige apps bruger af dataforbindelse opdelt på wifi og mobilnet.

    wp_ss_20130822_0007wp_ss_20130822_0008
  5. Nokia Pro Cam.  Jeg overrasker mig selv ved at fremhæve en kamera apps om en af de bedste ting.  Jeg har aldrig forstået den forfærdelige hype der er omkring kameratelefoner.  Op til 40 mio. pixels og et objektiv, der er 3 mm i diameter, hænger bare ikke sammen.  Men måske netop derfor finder jeg Nokia Pro Cam forfriskende.  App’en giver nem adgang til indstilling af white balance, manuel/auto-fokus, ISO, shutter speed og eksponeringskompensation.  Så mangler jeg bare direkte indstilling af selve eksponeringen, som sjovt nok ikke er muligt.  Fokus er blevet meget mere stabil end i standardkameraet, hvilket er en fornøjelse.  App’en giver endda mulighed for at få vist forskellige gitterlinjer – bl.a. 2/3-dele, gyldent snit og kryds i midten.  Det er mere, end mit Nikon DSLR kan!  Det bedste er, at Amber giver mulighed for, at man kan bruge Pro Cam som default kamera via indstillinger som vist i skærmbilledet herunder.

    wp_ss_20130822_0010wp_ss_20130822_0009
  6. Support af CardDAV og CalDAV. Ja, du hørte rigtigt.  Det er nu igen muligt at synkronisere kontakter og kalender mellem Google Mail og WP8, hvilket ikke har været muligt på nye telefoner siden Google besluttede at lukke for Exchange ActiveSync protokollen (naturligivis baseret på fuldstændig faglige begrundelser – det havde ikke noget at gøre med, at alle Microsoft enheder bruger den protokol).

    Synkronisering med Google Mail.

Udover ovenstående 6 punkter, virker det som om, at batteritiden er blevet forbedret med Amber.  Det er muligvis bare ønsketækning fra min side.

Jeg har længe haft dette emne på listen over ting, jeg kunne skrive et par ord om på dotninjas.dk, og så sent som i dag fik jeg en mail fra en kollega, der ikke kunne få et af mine programmer til at køre, fordi programmet fejlagtigt påstod, at nogle filstier på netværkshares ikke fandtes. Problemet var, at han kørte programmet som administrator.

Ironisk nok kan man på Windows 7 komme ud for, at administrator elevation lader til at give begrænsede muligheder, når man tilgår netværkshares.  Dette er en velkendt “feature” i Windows 7, og der findes et workaround.  Løsningen er manuelt at rette i registry, som beskrevet i linket nederst.

En god tommelfingerregel er aldrig at kræve UAC elevation for sine applikationer.  Men selv Visual Studio kræver nogle gange elevation.  Det er f.eks. nødvendigt, når man vil køre ASP.NET web sites på den rigtige IIS (i stedet for IIS Express), eller man ønsker at bruge debugfunktionaliteten attach to process.

I så fald kan det workaround, der er beskrevet i følgende TechNet artikel, være nyttigt:

http://technet.microsoft.com/en-us/library/ee844140(v=ws.10).aspx

Jeg tror, de fleste har prøvet det: Man sidder og roder i SQL Server Management Studio med 200 forskellige queries på forskellige databaser, og pludselig er man kommet til at køre en DROP eller DELETE statement i den forkerte database.

Der findes en option i SSMS, der kan hjælpe til med at mindske risikoen for at lave den type bommerter: Man kan farvekode sine queries alt efter, hvilken server man er forbundet til.  F.eks. kan man give alle queries, der er forbundet til ens produktionsserver, en rød farve, mens queries mod testserveren er grønne (den farvekombination virker selvfølgelig kun, hvis man ikke er rød/grøn farveblind).  Det ser ud som vist herunder.

image

Farven sættes i “Connect to Database Engine” skærmbilledet.  Tryk “Options >>” og vælg fanen “Connection Properties”.  Sæt et hak i “Use Custom Color” og vælg den ønskede farve.  SSMS husker den valgte farve pr. server.  Nogle gange er det nødvendigt at genstarte SSMS for at ændringen får effekt på nye queries.

image

Normalt forventer man, at hvis a + b giver c, så vil a + b altid give c.  I programmering skal man have en vis tolerance mht. præcision, når man bruger doubles og floats, men hvis a + b giver c i et program, forventer man samme resultat, uanset hvornår man laver beregningen indenfor samme proces.

Sådan troede jeg det var indtil fornylig, hvor én af vores unit tests fejlede – tilsyneladende lidt tilfældigt.  For kørte jeg den pågældende unit test alene, var der ingen fejl.  Kørte jeg den sammen med de andre unit tests i projektet, fejlede den.  Jeg fik ret hurtigt identificeret, hvilke andre unit tests, der drillede, og den fejlende unit test havde absolut intet med de andre unit tests at gøre.  Der var ingen fælles kode.

For nemheds skyld vil jeg kalde den fejlende unit test for A, og kalde de andre unit tests, som forårsagede fejlen i A for B. 

Test A tester kode indeholdende komplekse beregninger (Nelder-Mead), og fejlen gjorde, at det endelige resultat endte med en difference på 0.5!  Det er meget i min verden.

Test B er lidt speciel.  Den tester funktionalitet til at indlæse data fra et regneark.  Dvs. koden, som B tester, benytter Microsoft’s ACE driver. Efter en del test af denne driver, og noget der ligner to dages riven i mit eget hår, var jeg i stand til at genskabe problematikken med et simpelt eksempel, hvor resultat af et gangestykke med doubles gave forskellige resultater før og efter kald til ACE driveren.

Et spørgsmål på StackOverflow affødte en forklaring: “… unmanaged code may be tinkering with the FPU control word and change the way it calculates”.  Der blev også foreslået en løsning, nemlig et kald til _fpreset, som “resets the floating point package”.

Den foreslåede løsning virker, men jeg føler mig ikke overbevist om, at jeg egentlig har lyst til at bruge ACE driveren direkte i vores produktionskode.  En rådslagning med Daniel (også kendt er på sitet som ne0san) førte frem til en anden løsning, nemlig at spawn en ny process, som indlæser data fra regnearket, og kommunikerer data tilbage til hovedprocessen vha. named pipes (måske et emne for en kommende dotninjas blog).  Det virker.  Om det er en bedre løsning end _fpreset er svært at sige.

Betragt følgende stump SQL og overvej resultatet:

SET ANSI_NULLS ON;
SELECT 
CASE 
    WHEN NOT 'EnStreng' IN ('A', NULL) THEN 'Ja'
    ELSE 'Nej'
END

Hvis du gættede på, at resultatet ville blive ‘Nej’, er du klogere end mig (hvilket mange er).  Sagen er, at med ANSI_NULL ON, vil alle sammenligninger med NULL returnere værdien UNKNOWN, og alle boolean operatorer vil returnere UNKNOWN, når de bruges sammen med UNKNOWN.  Derfor vil første case aldrig evaluere til TRUE.

Som hovedregel må man aldrig bruge =, < og > ved sammenligninger med NULL, når ANSI_NULL er ON.

For fremtidige versioner af SQL Server (hvad så end det betyder) vil ANSI_NULLS altid være ON.  Mere info her: http://msdn.microsoft.com/en-us/library/ms188048(v=sql.110).aspx

 

Forleden blev jeg mindet om SQLCMD Mode i SQL Server Management Studio.  Jeg brugte det flittigt i en periode for nogle år tilbage, men er af en eller anden grund kommet væk fra det.  SQLCMD Mode gør det muligt at kalde sqlcmd.exe direkte i sine SQL scripts i SSMS, og det kan være ganske nyttigt. 

Opsætning

For at slå SQLCMD Mode til, skal man trykke på knappen SQLCMD Mode i værktøjslinjen i SSMS.  Som standard er denne knap ikke synlig.  For at tilføje den skal man gå ind under Tools –> Customize menuen.  Under fanen Commands skal man trykke Add Command og finde knappen under Query kategorien.  Man kan også bruge menuen Query –> SQLCMD Mode.

image

Når SQLCMD Mode er slået til, kan man fra SSMS eksekvere SQLCMD kommander ved at skrive et kolon (‘:’) foran kommandoen.  SQLCMD kommandoer fremhæves som grå linjer i SSMS. 

Ændre forbindelse til SQL Server

En af de gode kommandoer er :Connect.  Med :Connect kan man forbinde til en SQL Server direkte fra sit SQL script:

image

Det betyder, at man kan gemme forbindelsesinformation direkte i sine SQL filer.

Variable

En anden nyttig funktion er muligheden for at definere variable. I nedenstående eksempel benytter jeg det til hurtigt at generere noget testdata.  Jeg har defineret en tabel kaldet Table_1, der har default værdier på alle kolonner.  Vha. SQLCMD’s mulighed for at definere variable og SSMS’ definition af GO, kan jeg eksekvere min INSERT statement 10 gange:

image

Eksekvering af cmd prompt kommandoer

SQLCMD kan selvfølgelig også andre sjove ting.  F.eks. kan man eksekvere almindelige cmd prompt kommandoer vha. ‘!!’, hvis man skulle få lyst til det:

image

Standardopsætning

Hvis man som standard ønsker at åbne alle SQL scripts i SQLCMD Mode i SSMS, skal man gå ind under Tools –> Options og tilvælge det:

image

Der er sagt og skrevet mange dårlige ting om Microsoft Surface RT.  Jeg har selv haft en RT siden den kom til Danmark, og jeg er ikke enig med den negative kritik, Surface har fået.  Generelt mener jeg, at mange mennesker rakker ned på Microsoft produkter, bare fordi det er moderne.  Jeg går hermed i mod strømmen.

I mine øjne er Surface en tablet computer og dermed en konkurrent til iPad.  Man bør ikke forvente mere af en Surface end af en iPad, og det er måske der, folk misforstår Surface.  Jeg tror ikke, at Surface vil slå iPad.  Men det burde den, og her er 5 (fuldstændig subjektive) grunde til det (i tilfældig rækkefølge):

  1. Split screen.  Idéen med at vise to apps samtidig, med et 1/3 – 2/3 split er genial.  Jeg har f.eks. ofte Skype chat kørende i siden, mens jeg sidder og læser.  Eller f.eks. har jeg Bing Search i siden, mens jeg surfer i Internet Explorer.  Når man klikker på et søgeresultat i Bing Search, vises web siden i IE.  Det kan man ikke engang gøre på en desktop computer!
    Skærmbillede (5)
  2. Touch Cover. Det er virkelig lækkert med et (næsten) full size tastatur, som endda fungerer som cover.  Man skal vænne sig til det, men det er muligt at skrive med næsten fuld hastighed med 10-fingersystem.
  3. Store/små bogstaver på onscreen-keyboard.  På Surface kan man tydeligt se, om man har shift trykket ned, for onscreen-keyboard skifter mellem store og små bogstaver.  Det er en meget lille detalje, men det irriterer mig, at iPad/iPhone ikke gør det.
    Skærmbillede (8)Skærmbillede (7)
  4. Live tiles.  Nogle bliver forvirrede over dem – jeg elsker dem.  Man kan med det samme se, hvem seneste mails er fra, næste kalenderaftale, seneste nyheder, dagens udvikling på C20-indekset, Facebook-opdateringer fra sine søstre, chat-beskeder på Skype osv. osv.  Live tiles er et lækkert alternativ til iPad’s ikoner, der står passive og nærmest skriger til hinanden efter opmærksomhed.
    image
  5. USB-stik.  Det lille USB-stik i siden kombineret med Windows’ væld af drivers gør en verden til forskel.  Sæt dit 5 år gamle Nikon kamera i uden brug af adapter eller noget og overfør (RAW) billederne uden problemer.  Sæt din 4 år gamle Brother laser printer til 800 kr. i og print uden problemer.  Sæt din Windows Phone telefon i og overfør musik og billeder uden problemer.  Jeg har ikke oplevet nogensomhelst problemer med at skulle sætte en disk i A-drevet eller andet, som f.eks. det skete for So Ein Ding.  Alt har virket i første hug for mig.
  6. (ok, jeg løj, der er mere end 5 grunde) Flash.  Det er vel efterhånden kun Danske Spil tilbage, som bruger Flash, men engang imellem er det nyttigt at sidde med en maskine, der kan vise Flash.  Og det kan Surface.
  7. Mini-SD port.  Jeg har endnu ikke haft brug for den, men det er en rar fornemmelse, at den er der.
  8. App-skift med et swipe.  Swipe én gang med venstre tommeltot for at skifte til forrige app.  Swipe en gang ud og ind og se hele listen af kørende apps.  Det er utroligt nemt og intuitivt.
    Skærmbillede (12)
  9. Charms.  Charms er de små ikoner, der kommer frem, når man swiper med højre tommeltot.  Uanset hvilken app, man kører, kan man her finde app’ens indstillinger og muligheder for deling (via Facebook, Skydrive, mail etc).  Det er godt tænkt, fordi det giver konsistens gennem alle apps.  Faktisk er hele konceptet med at bruge tommeltotterne til at styre Surface god.
    Skærmbillede (11)
  10. Flere brugere.  En Surface kan have flere logins.  Slut med at have konens baggrundsbillede af havens pæoner på sin tablet.

Som det måske fremgår, er jeg rigtig glad for Surface.  Det betyder ikke, at den er perfekt.  Jeg håber, at Microsoft en dag kommer med en RT version af Office, så desktoppen helt kan fjernes fra RT.  Der er kommet en udmærket OneNote app, men de andre Office produkter eksekveres på desktoppen, og det er en skam. 

Jeg håber også, at firmaer og udviklere verden over får øjnene op for Surface, så udbuddet af apps bliver større.

Og jeg håber, Microsoft vil gøre noget ved vægten på Surface.  Jeg vil skyde på, at den vejer ca. det samme som en iPad 1.

Det er en god og velkendt tommelfingerregel, at man skal placere et fotografis emne eller “action” 1/3 inde i billedet.  Denne regel er kendt som “Rule of Thirds”.  Det gælder både vertikalt og horisontalt. 

Selvom man ikke kender reglen, vil mange automatisk alligevel bruge den, når de fotograferer, for på en eller anden måde virker det harmonisk for mennesker (og sikkert også for chimpanser, siden vi nu har så meget til fælles med dem).

Digitalkameraproducenter er så flinke at give fotografer mulighed for at få vist guidelines inde i kameraets viewfinder for at hjælpe med at holde kameraet lige etc.  Siden Rule of Thirds er en universiel regel for fotografer, kan jeg simpelthen ikke begribe, hvor de guidelines i mit kamera benytter 4. dele i stedet for 3. dele.  Det ville da gøre livet nemmere.

Sådan ser min viewfinder ud.  Har de brugt en helt ny endnu ukendt regel kaldet Rule of Fourths?

d80_viewfinder_anim.gif

Da async/await pattern blev introduceret med C# 5, blev hele .NET frameworket gennemarbejdet, så relevante asynkrone metoder blev awaitable og fik Task som returværdi.

Det gælder ikke Windows Phone API’en.  Specielt gælder det ikke for WebClient, der i .NET 4.5 bl.a. har fået DownloadDataTaskAsync, der returnerer en Task, og dermed er awaitable.  Til Silverlight må man nøjes med DownloadDataAsync, som er baseret på Event-Based Asynchronous Pattern (EAP) gennem DownloadDataCompleted.

I System.Threading.Tasks namespacet findes en klasse kaldet TaskCompletionSource.  Denne klasse er netop beregnet til EAP scenarier, fordi den opretter en task, som man kan sætte op til at vente på, at en event bliver kaldt.  Dette gøres vha. af SetResult og SetException.  Kalder man en af de to metoder, vil den tilhørende Task afsluttes.  Vha. af TaskCompletionSource har jeg lavet følgende awaitable extension metoder til WebClient, som gør det muligt at lave awaitables for hver af de 4 HTTP metoder GET, POST, PUT og DELETE.  Metoderne benytter JSON via Json.NET:

    public static class WebClientExtensions
    {
        public static Task<T> GetAsync<T>(this WebClient client, Uri uri)
        {
            var tcs = new TaskCompletionSource<T>();
            client.DownloadStringCompleted += (s, e) =>
                {
                    if (e.Error == null)
                    {
                        T result = JsonConvert.DeserializeObject<T>(e.Result);
                        tcs.SetResult(result);
                    }
                    else
                    {
                        tcs.SetException(e.Error);
                    }
                };
            client.DownloadStringAsync(uri);
            return tcs.Task;
        }

        public static Task PostAsync<T>(this WebClient client, Uri uri, T item)
        {
            var tcs = new TaskCompletionSource<string>();
            client.Headers["Content-Type"] = "application/json";
            client.UploadStringCompleted += (s, e) =>
            {
                if (e.Error == null)
                {
                    tcs.SetResult(e.Result);
                }
                else
                {
                    tcs.SetException(e.Error);
                }
            };

            string data = JsonConvert.SerializeObject(item);

            client.UploadStringAsync(uri, "POST", data);
            return tcs.Task;
        }

        public static Task PutAsync<T>(this WebClient client, Uri uri, T item)
        {
            var tcs = new TaskCompletionSource<string>();
            client.Headers["Content-Type"] = "application/json";
            client.UploadStringCompleted += (s, e) =>
            {
                if (e.Error == null)
                {
                    tcs.SetResult(e.Result);
                }
                else
                {
                    tcs.SetException(e.Error);
                }
            };

            string data = JsonConvert.SerializeObject(item);

            client.UploadStringAsync(uri, "PUT", data);
            return tcs.Task;
        }

        public static Task DeleteAsync(this WebClient client, Uri uri)
        {
            var tcs = new TaskCompletionSource<string>();
            client.UploadStringCompleted += (s, e) =>
            {
                if (e.Error == null)
                {
                    tcs.SetResult(e.Result);
                }
                else
                {
                    tcs.SetException(e.Error);
                }
            };

            client.UploadStringAsync(uri, "DELETE", "");
            return tcs.Task;
        }

Du kan læse mere om TaskCompletionSource hos Stephen Toub, som er en af de ypperste, når det kommer til parallelisering i .NET.

Jeg har haft stor glæde af de ovenstående WebClient extensions, men min glæde var endnu større, da jeg fornylig læste, at Microsoft arbejder på en port af HttpClient til Windows Phone, og har gjort det tilgængeligt via NuGet.  Jeg har endnu ikke prøvet det, men det virker lovende.

Jeg læste forleden om dårlige vaner, man typisk har som (amatør)fotograf.  Jeg kan nikke til samtlige af dem, og jeg kan såmænd tilføje en, som virkelig plager mig, og som man ser hos rigtig mange amatørfotografer inklusive mig selv.  Vi taler om skæv horisont. 

Mange gange er jeg vendt hjem efter en tur med kameraet fuld af forventning til, at jeg denne har fået netop dét ene supershot i kassen, som skal gøre mig rig og berømt.  Men skuffelsen er stor, når jeg endnu engang kan se, at horisonten  gud-hjælpe-mig er skæv igen.

Aaaaaaaargh!

Hver gang jeg er ude med kameraet, tænker jeg: Husk nu at holde det lige, og kig efter guidelines i søgeren.  To minutter efter, har jeg glemt alt om det og kommer hjem med skæve billeder.  En skæv horisont på et landskabsbillede er ikke i orden.

Selvfølgelig kan det rettes op i billedbehandlingen, men så mister jeg pixels, og hvis der er et motiv, som fylder hele billedet, kan det måske ikke lade sig gøre.

Case in point:

DSC_0343