Startsidan  ▸  Texter  ▸  Teknikblogg

Anders Hesselbom

Programmerare, skeptiker, sekulärhumanist, antirasist.
Författare till bok om C64 och senbliven lantis.
Röstar pirat.

Lathund XAML: Databinding

Kontrollen ListView kan användas för att presentera data i listform, och tillsammans med GridView kan man använda den för att presentera tabulär data i listform. Följande exempel fyller ett fönster med en ListView, som har en GridView med tre kolumner.

<ListView x:Name="listView" Margin="5,5,5,5">
   <ListView.View>
      <GridView>
         <GridViewColumn Header="First name" Width="100" />
         <GridViewColumn Header="Last name" Width="100" />
         <GridViewColumn Header="Birthdate" Width="100" />
      </GridView>
   </ListView.View>
</ListView>

Det enklaste sättet att lägga till data till listan är att binda dess kolumner till properties, och sedan binda listan till en samling vars objekt har dessa properties. I XAML uttrycks bindningen med DisplayMemberBinding.

<ListView x:Name="listView" Margin="5,5,5,5">
   <ListView.View>
      <GridView>
         <GridViewColumn Header="First name"
         Width="100" DisplayMemberBinding="{Binding FirstName}" />
         <GridViewColumn Header="Last name"
         Width="100" DisplayMemberBinding="{Binding LastName}" />
         <GridViewColumn Header="Birthdate"
         Width="100" DisplayMemberBinding="{Binding BirthDate}" />
      </GridView>
   </ListView.View>
</ListView>

Så här skulle klassen som beskriver objektet som vi ska placera i listan som ska bindas:

class Employee
{
   public string FirstName { get; set; }
   public string LastName { get; set; }
   public DateTime BirthDate { get; set; }
}

Slutligen, denna kod utför bindningen. Den kan t.ex. köras i fönstrets Initialized-event:

var emps = new List<Employee>();
emps.Add(new Employee() { FirstName = "Sven", LastName = "Svensson", BirthDate = new DateTime(1960, 1, 1) });
emps.Add(new Employee() { FirstName = "Klas", LastName = "Klasson", BirthDate = new DateTime(1970, 1, 1) });
emps.Add(new Employee() { FirstName = "Göran", LastName = "Göransson", BirthDate = new DateTime(1980, 1, 1) });
listView.ItemsSource = emps;

Förändringar som sker i listan under programmets gång reflekteras först när man anropar metoden Refresh på listans Items-property.

(listView.ItemsSource as List<Employee>).Add(
   new Employee()
   {
      FirstName = "Pierre",
      LastName = "Fridell",
      BirthDate = new DateTime(1955, 1, 1)
   });
listView.Items.Refresh();

Slutligen, om vi vill styra format eller design så kan vi placera en CellTemplate under en GridViewColumn, och placera värdet (eller propertynamnet i detta fall) där. Här använder jag en TextBlock-kontroll. För att centreringen av texten ska fungera, måste jag tala om att alla ListViewItem-objekt ska dras ut till sin fulla storlek.

<ListView x:Name="listView" Margin="5,5,5,5">
   <ListView.Resources>
      <Style TargetType="ListViewItem">
         <Setter Property="HorizontalContentAlignment" Value="Stretch" />
      </Style>
   </ListView.Resources>
   <ListView.View>
      <GridView>
         <GridViewColumn Header="First name" Width="100" DisplayMemberBinding="{Binding FirstName}" />
         <GridViewColumn Header="Last name" Width="100" DisplayMemberBinding="{Binding LastName}" />
         <GridViewColumn Header="Birthdate" Width="100">
            <GridViewColumn.CellTemplate>
               <DataTemplate>
                  <TextBlock Text="{Binding BirthDate, StringFormat=\{0:yyyy\}}" TextAlignment="Center"></TextBlock>
               </DataTemplate>
            </GridViewColumn.CellTemplate>
         </GridViewColumn>
      </GridView>
   </ListView.View>
</ListView>

Lathund XAML: Positionering

För att placera ut en knapp på en absolut position, sätt HorizontalAlignment till “Left” och VerticalAlignment till “Top”. Därefter, använd de första två talen i Margin för X- och Y-position. Exempel:

<Button x:Name="button" Content="Button"
HorizontalAlignment="Left" Margin="105,101,0,0"
VerticalAlignment="Top" Width="75"/>

Om man istället vill fästa knappen (eller vad det nu må vara för kontroll man jobbar med) över hela det tillgängliga området så används Margin för att ange avstånd från kanten. Här fyller knappen hela området, men lämnar tre pixlars marginal på alla fyra sidor.

<Button x:Name="button" Content="Button" Margin="3,3,3,3" />

Det innebär att man ganska enkelt kan bygga ett traditionellt användargränssnitt med en meny högst upp och ett statusfält längst ner enligt följande:

<Menu x:Name="menu" Height="28" Margin="0" VerticalAlignment="Top" />
<StatusBar Height="28" Margin="0" VerticalAlignment="Bottom" />

Om jag nu vill använda det resterande området för t.ex. en knapp, så måste jag öka den övre (andra värdet) och den undre (det fjärde värdet) så att inte knappen skymmer menyn eller statusfältet.

<Menu x:Name="menu" Height="28" Margin="0" VerticalAlignment="Top" />
<StatusBar Height="28" Margin="0" VerticalAlignment="Bottom" />
<Button x:Name="button" Content="Button" Margin="3,31,3,31" />

Alternativt kan man använda sig av en contaner som hanterar dockningen, en DockPanel. Här anger jag att menyn ska vara fäst högst upp och att statusfältet ska vara längst ner, genom att hänvisa till den. För att knappen ska ta upp det resterande området, räcker det att jag placerar den sist i listan, och sätter attributet LastChildFill till “True”.

<DockPanel Margin="0,0,0,0" LastChildFill="True">
   <Menu x:Name="menu" DockPanel.Dock="Top" Height="28" />
   <StatusBar DockPanel.Dock="Bottom" Height="29" />
   <Button x:Name="button" Content="Button" Margin="3,3,3,3" />
</DockPanel>

En uppenbar fördel med dockningspanelen är att man inte behöver specificera för knappen i mitten (eller vad man nu har för slags kontroll placerad där) hur stor den ovanliggande menyraden är. Och behöver man inte specificera det, så behöver man inte veta det, utan kan låta den ta upp så mycket plats som sitt innehåll, menyerna, kräver.

<DockPanel Margin="0,0,0,0" LastChildFill="True">
   <Menu x:Name="menu" DockPanel.Dock="Top">
      <MenuItem Header="File" Margin="4,4,4,4">
         <MenuItem Header="Quit" />
      </MenuItem>
   </Menu>
   <StatusBar DockPanel.Dock="Bottom" Height="29" />
   <Button x:Name="button" Content="Button" Margin="3,3,3,3" />
</DockPanel>

Generics i C#

Grovhet

För många står oregelbundenhet i motsats till regelbundenhet, men i den matematiska världen står regelbundenhet i motsats till grovhet. Tänk dig att du ska mäta omkretsen på denna figur, en kochkurva:

koch1

Ju finare passare du använder för att mäta omkretsen, desto längre är omkretsen.

passare

En grov inställning på passaren kommer att ge mätvärden vars summa är mycket lägre, vilket innebär att den grova inställningen på mätinstrumentet ger ett resultat som beskriver en mindre grov figur.

koch2

En finare inställning på passaren kommer att ge mätvärden vars summa är mycket högre, vilket innebär att den fina inställningen på mätinstrumentet ger ett resultat som beskriver en grövre figur.

koch3

Denna egenskap gäller inte bara för kochkurvan utan även för en kustlinje eller en bergssiluett. Se gärna Benoît Mandelbrots föreläsning på TED. Mandelbrot är en fransk matematiker som givit namn åt mandelbrotfraktalen.

Snittvärde

Jag fick en fråga om att räkna ut snittvärden. Det finns olika sätt att lösa det på, där det enklaste kanske är att använda Excel för att göra ett enkelt datablad. Jag tänkte visa hur man kan göra i C# för att få en start till ett registerprogram. För detta använder jag Visual Studio 2015 Community Edition som kan laddas hem gratis här. Välj att skapa ett nytt projekt.

bild1

Jag kör mot .NET Framework 4.5.2 (1) och har valt kategorin Windows under C# (2) och projekttypen Console Application (3). Se till att välja ett lämpligt projektnamn och en lämplig plats att spara projektet på (4). Sen är det bara att börja skriva.

Här har vi den grundläggande principen:

         //Några flyttal att beräkna snitt på.
         double[] tal = { 3.0, 4.0, 1.5, 2.0 };

         //Summera talen.
         var summa = 0.0;
         for (int i = 0; i < tal.Length; i++)
            summa += tal[i];

         //Dividera med antalet.
         var snitt = summa / tal.Length;

         //Presentera resultatet.
         Console.WriteLine(snitt);

         //Pausa tills användaren trycker Enter.
         Console.ReadLine();

Vi borde nu se att snittet av 3.0, 4.0, 1.5 och 2.0 är 2.625.

Eftersom vi har tillgång till namnrymden System.Linq så kan vi använda en inbyggd funktion för att räkna ut snittet. Detta ger samma resultat:

         //Några flyttal att beräkna snitt på.
         double[] tal = { 3.0, 4.0, 1.5, 2.0 };

         //Be om snittet.
         var snitt = tal.Average();

         //Presentera resultatet.
         Console.WriteLine(snitt);

         //Pausa tills användaren trycker Enter.
         Console.ReadLine();

Detta kan vi applicera om vi bygger en struktur som innehåller ett flyttal. Följande kod beskriver ett musikalbum med låtar. Låtarna har ett betyg mellan 1 och 10, och deras snitt ger oss ett betyg på musikalbumet.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Snitt
{
   class Program
   {
      static void Main(string[] args)
      {
         //Konstruera ett album.
         var a = new Album() { AlbumName = "A Night at the Opera",
                               ArtistName = "Queen" };
         //Lägg på låtar.
         a.Songs.Add(new Song() { TrackNumber = 1,
                                  TrackName = "Death on Two Legs",
                                  Rating = 7.0 });
         a.Songs.Add(new Song() { TrackNumber = 2,
                                  TrackName = "Lazing on a Sunday Afternoon",
                                  Rating = 4.0 });
         a.Songs.Add(new Song() { TrackNumber = 3,
                                  TrackName = "I'm in Love with My Car",
                                  Rating = 6.0 });

         //Hämta låtarnas betyg.
         var ratings = (from s in a.Songs
                       select s.Rating).ToArray();

         //Hämta ut låtarnas snittvärde och avrunda.
         var snitt = Math.Round(ratings.Average(), 2);

         //Presentera resultatet.
         Console.WriteLine(snitt);

         //Pausa tills användaren trycker Enter.
         Console.ReadLine();
      }
   }

   //Definiera en låt.
   public class Song
   {
      public int TrackNumber { get; set; }
      public string TrackName { get; set; }
      public double Rating { get; set; }
   }

   //Definiera ett musikalbum
   public class Album
   {
      public string ArtistName { get; set; }
      public string AlbumName { get; set; }
      public List<Song> Songs { get; set; } = new List<Song>();
   }
}

Detta ger oss svaret 5.67.

Klasserna Song och Album kan användas som en del av en Windows-applikation med ett grafiskt användargränssnitt. Projekttypen skulle kunna vara en Windows Forms Application. Att sammanställa en sådan applikation är ett ganska stort och tidskrävande projekt. En album-lista ska skapas, serialisering och deserialisering ska implementeras och det grafiska användargränssnittet ska byggas.

Delta

This is the result of today’s recording sessions. Delta, originally written and performed by Rob Hubbard, 1987.

Stora tal

Det finns ett mycket roligt klipp med karaktären Ali G där han ställer sig frågan om en dator någonsin kan räkna ut ett väldigt stort godtyckligt tal. Han får svaret att alla räkneövningar han kan nämna, kan räknas ut av en modern dator. Din miniräknare kommer förmodligen slå i taket när talen blir för stora, men en vanlig PC med Windows kan ge dig precis vilket svar som helst. Det krävs lite trixande under skalet för att få detta att fungera.

Heltal representeras normalt av en bit-struktur, alltså ett antal ettor och nollor. Ett 32-bitars heltal är ett heltal som beskrivs av 32 bitar (4 bytes). Bitrepresentationen är liknar binärrepresentationen av ett tal, vilket innebär att både bitrepresentationen av talet 8 och binärrepresentationen av talet 8 är 1000. Ju större tal man vill beskriva, desto fler bitar behöver man ha, och förr eller senare slår man i taket.

Men det finns en struktur i Windows som heter BigInteger som inte har någon begränsning när det kommer till heltalsrepresentationer och heltalsberäkningar. Det beror på att talen internt lagras som en teckensekvens istället för som ett bitmönster, där varje tecken i sin tur representeras av ett begränsat bitmönster. Då blir det hela en fråga om hur många tecken som får plats i minnet, vilket är väldigt många. För att få se vad BigInteger-strukturen kan göra, kan man skriva in en enkel kod i PowerShell som dubblerar ett tal ett antal gånger. Om jag börjar med talet 1 och dubblar det så får jag 2. Dubblar jag det så får jag 4, 8, 16, 32, 64, 128, 256, och så vidare. Ganska snart blir talet väldigt stort. Redan efter blott 100 dubbleringar landar man på talet 2 535 301 200 456 458 802 993 406 410 752 vars binära representation skulle bli väldigt stor. Men i en BigInteger-struktur är detta bara att betrakta som 31 tecken som avkodas till värden i turordning när beräkningar ska göras.

Så utrustade med BigInteger-strukturen kan vi se vad som händer när vi dubblerar ett tal 500 gånger. För att göra detta, skriv:

$x = New-Object System.Numerics.BigInteger 1; for ($i = 0; $i -le 500; $i++) { $x *= 2; Write-Output $x }

PowerShell levererar svaret på ett ögonblick. Talet 1 dubblat 500 gånger ger oss talet 6 546 781 215 792 283 740 026 379 393 655 198 304 433 284 092 086 129 578 966 582 736 192 267 592 809 349 109 766 540 184 651 808 314 301 773 368 255 120 142 018 434 513 091 770 786 106 657 055 178 752, vilket är ett så stort tal att det nästan är omöjligt att läsa ut och förstå. För att underlätta kan man använda scientific notation. Istället för att skriva ut föregående tal i sin fulla längd, kan man skriva:

6,55 * 10150

Eller:

6,55E150

Båda varianterna säger oss att talet börjar på 6 och innehåller 150 siffror till därefter, varav de första nästkommande är 55 (avrundat). Det totala antalet siffror i talet är alltså antalet siffror till vänster om decimalavgränsaren plus talet till höger om E. 151 stycken.

Så hur står sig en etta dubblerad femhundra gånger mot andra stora tal?

Vårt observerbara Universum uppskattas innehålla 1,7 * 1011 (eller 1,7E11) galaxer. Uppskattningsvis finns 1024 (1E24) stjärnor i Universum.

Båda dessa tal är alltså relativt små i jämförelse med den etta vi dubblade femhundra gånger. Hur är det med antalet atomer i vårt observerbara Universum? Faktum är att även det är ett relativt litet tal i detta sammanhang, nämligen 4 * 1080 (4E80), alltså en fyra följt av åttio nollor. 400 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000.

Så låt oss dubbla vår etta femtusen gånger. Även det räknas fram kvickt av PowerShell. Svaret är 282 493 406 427 885 207 367 041 933 403 229 466 733 779 235 036 908 223 362 737 617 171 423 633 968 541 502 511 617 825 263 342 305 274 671 206 416 862 732 165 528 407 676 139 958 676 671 942 371 453 279 846 862 103 555 703 730 798 023 755 999 290 263 414 138 746 996 425 262 647 505 106 222 430 745 688 071 901 801 071 909 721 466 836 906 811 151 133 473 603 131 174 810 929 399 280 998 101 699 398 944 715 801 811 235 142 753 236 456 432 868 426 363 041 983 113 354 252 997 303 564 408 348 123 661 878 478 353 722 682 766 588 036 480 451 677 385 451 192 294 010 288 486 562 150 551 258 990 678 187 626 397 933 471 267 212 659 382 047 684 908 251 671 777 313 746 267 962 574 481 960 017 676 147 336 443 608 528 865 821 788 061 578 040 438 881 156 396 976 534 679 536 477 744 559 804 314 840 614 495 141 020 847 691 737 745 193 471 783 611 637 455 592 871 506 037 036 173 282 712 025 702 605 093 453 646 018 500 436 656 036 503 814 680 490 899 726 366 531 275 975 724 397 022 092 725 970 923 899 174 562 238 279 814 456 008 771 885 761 907 917 633 109 135 250 592 173 833 771 549 657 868 899 882 724 833 177 350 653 880 665 122 207 329 113 965 244 413 668 948 439 622 163 744 809 859 006 963 982 753 480 759 651 997 582 823 759 605 435 167 770 997 150 230 598 943 486 938 482 234 140 460 796 206 757 230 465 587 420 581 985 312 889 685 791 023 660 711 466 304 041 608 315 840 180 083 623 903 760 913 411 030 936 698 892 365 463 484 655 371 978 555 215 241 419 051 756 637 532 976 736 697 930 030 949 995 728 239 530 882 866 713 856 024 688 223 531 470 672 787 115 758 429 874 008 695 136 417 331 917 435 528 118 587 185 775 028 585 687 114 094 178 329 752 966 233 231 383 772 407 625 995 111 380 343 784 339 467 510 448 938 064 950 157 595 661 802 643 159 880 254 674 421 388 754 566 879 844 560 548 121 596 469 573 480 869 786 916 240 396 682 202 067 625 013 440 093 219 782 321 400 568 004 201 960 905 928 079 577 408 670 605 238 675 195 724 104 384 560 742 962 264 328 294 373 028 338 181 834 383 818 752.

I scientific notation skrivs detta tal 2,82 * 101505 eller 2,82E1505. Med tanke på att vi ännu inte närmat oss någon bortre gräns, så kan man lugnt konstatera att den som äger en vanlig PC förvaltar en svindlande räkningskapacitet.

Gosbust 0.9.2

Version 0.9.2 av Gosbust finns nu att ladda hem. Tillåt mig presentera några exempel på vad aktuell version kan göra.

Det stora tillskottet handlar om stödet för arrayer. Kommandot ARRY tar ett namn (A-Z, A#-Z#, A$-Z$ eller A?-Z?) samt önskat antal element. 5 ger fem element med index 0-4.

ARRY A 5

Detta kolliderar inte med en eventuell enskild buffer som heter A. R$ och R$[3] lagras i olika minnesstrukturer. För att nå individuella element används hakparenteser. Detta skapar ett slumptal i arrayen A’s första element:

RAND A[0]

Om jag läser av element 0 borde jag se ett heltal, vilket som helst men troligen inte 0.

<<A[0]

Element 1 borde däremot fortfarande ha värdet 0, eftersom ingen tilldelning gjorts än.

<<A[1]

Om jag skulle önska ha ett slumptal i samtliga element i arrayen A, kan jag ersätta indexet med tre punkter:

RAND A[...]

Nu kan jag läsa av vilket element som helst (0-4) och få ett värde. Om jag skulle önska se samtliga element så kan jag skriva följande:

<<A[...]

Modulus kan inte appliceras på samtliga element i en array, så skulle jag önska att alla slumptal ska ligga mellan 0 och 9 kan jag skriva följande:

0>>I Mod: A[I]%10>>A[I] I++ I<10>>R? GOTO R? Mod

Om du använvänder konsollen så skulle bubbelsortering av 10 tal mellan 0 och 99 skulle se ut så här:

10 ARRY A 10 RAND A[...]
20 0>>I Mod: A[I]%100>>A[I] I++ I<10>>R? GOTO R? Mod
30 <<"Ej sorterat:" <<A[...]
40 0>>I 0>>J
50 Repeat: A[I]>A[J]>>S? GOSB S? Swap
60 I++ I>9>>I? GOSB I? NextOuter GOTO 1 Repeat
70 ShowResult: <<"Sorterat:" <<A[...]
80 QUIT 0
90 (Swap A[I]<>A[J] )
100 (NextOuter 0>>I J++ J>9>>J? GOTO J? ShowResult )

Notera att QUIT 0 lika gärna kan ersättas med RTRN. Om callstacken är tom har dessa två kommandon samma betydelse. Men om man skulle vilja avsluta med en felkod så kan QUIT n användas.

(Om du läser in en fil istället för att använda konsollen behövs inte radnumren.)

Mycket nöje!

Konsollen i Gosbust 0.9.1

En liten förhandstitt på vad som är på gång i Gosbust.

Lite roliga skivor

Medan jag städade och sorterade skivor så hittade jag några roliga som jag ville visa upp för världen. Mycket nöje!

Två nya podcastavsnitt

I avsnitt 130 av Radio Houdi pratar vi bl.a. om nationaldagsfirande, gudomlig healing, rasism och Queen. Lyssna här!

Och i avsnitt 57 av Commoflage gräver vi i vanlig ordning ner oss i den underbara C64-musiken. Lyssna här!

Nytt kodexempel – Gissa ett tal

Gosbust finns i ny version (0.9) och med ett nytt exempelprogram. Följande fungerar med version 0.9 eller senare av Gosbust som finns att ladda ner här.

0>>X
/* Trolla fram ett slumptal mellan 1 och 100. */
RAND C C%100>>C C++

Restart:
/* Fråga användaren efter ett tal mellan 1 och 100. */
<<"Skriv ett tal mellan 1 och 100."
X++ ->A$ A$>>A>>I? !I? GOTO I? Restart

/* Sätt flaggor som beskriver om gissningen
var rätt, för liten eller för stor. */
A>C>>S? A<C>>L? A=C>>C?

GOSB S? TooHigh
GOSB L? TooLow
GOTO C? Correct
GOTO 1 Restart

(TooHigh <<"För stort!" )
(TooLow <<"För litet!" )
Correct: <<"Rätt!" <<X

guess

Om du vill fuska, komplettera med <<C på raden före Restart: så ser du det rätta svaret på skärmen.

Anropa alla klienter från ASP.NET

SignalR är ett ramverk som låter webbklienter prata direkt med webbservern via sockets, och som låter webbservern prata direkt med klienterna på samma sätt. Tack vare SignalR kan du göra funktionsanrop direkt till de användare som för tillfället råkar surfa på din hemsida. SignalR bygger ovanpå ramverket OWIN för ASP.NET.

I detta exempel arbetar jag i Visual Studio 2013 med ett projekt av typen ASP.NET MVC, så jag utgår alltså ifrån Microsofts exempelprogram som levereras som mall i Visual Studio 2013.

signalr1

För att komma igång ska vi:

  • Installera paketet SignalR i projektet.
  • Läsa in JavaScript-filen för SignalR.
  • Koppla SignalR-hubbarna till OWIN.
  • Skapa en hubb.

Därefter är det fritt fram att börja kommunicera!

För att installera SignalR, skriv följade i Package Manager Console:

Install-Package Microsoft.AspNet.SignalR

Eftersom SignalR ligger i version 2.2 när jag skriver detta, så kompletteras mitt program med filerna jquery.signalR-2.2.0.js och jquery.signalR-2.2.0.min.js i mappen Scripts, men tänk på att versionsnumret kan variera om du vill testa detta.

Därefter ska det minimerade scriptet inkluderas i de vyer som SignalR ska fungera på. Jag hade tänkt mig att kunna använda den överallt, så jag lägger in scriptet i Views/Shared/_Layout.cshtml. Vi ska även läsa in det autogenererade scriptet signalr/hubs.

<script type="text/javascript"
   src="~/scripts/jquery.signalR-2.2.0.min.js"></script>

Jag föredrar att flytta upp de script som redan ligger på sidan till dokumentets head-sektion, så att den ser ut så här:

<head>
   <meta charset="utf-8" />
   <meta name="viewport" content="width=device-width, initial-scale=1.0">
   <title>@ViewBag.Title - My ASP.NET Application</title>
   @Styles.Render("~/Content/css")
   @Scripts.Render("~/bundles/modernizr")
   @Scripts.Render("~/bundles/jquery")
   @Scripts.Render("~/bundles/bootstrap")
   <script type="text/javascript"
     src="~/scripts/jquery.signalR-2.2.0.min.js"></script>
   
   @RenderSection("scripts", required: false)
</head>

I nästa steg ska vi koppla SignalR-hubbarna till OWIN. Hubbarna, alltså kommunikationsnaven, har ett client-attribut som används för att prata med klienten och ett server-attribut som används för att prata med servern, och identifieras av adressen “/signalr” om vi inte sagt något annat. För att göra kopplingen behöver vi ha en OWIN Startup class. Högerklicka på ditt projektnamn i Solution Explorer, välj att lägga till en OWIN Startup class. Kalla den för OwinStartup. Det ger oss följande kod:

using System;
using System.Threading.Tasks;
using Microsoft.Owin;
using Owin;

[assembly: OwinStartup(typeof(WebApplication3.OwinStartup))]

namespace WebApplication3
{
   public class Startup
   {
      public void Configuration(IAppBuilder app)
      {
         // For more information on...
      }
   }
}

Ersätt kommentaren i funktionen Configuration med följande anrop:

app.MapSignalR();

Nu har vi gjort de förberedelser som behövs för att kommunicera. Till att börja med tänkte jag att klienten ska få skicka ett meddelande till servern när användaren klickar på en knapp.

Den sista förberedelsen innan vi kan börja är att skapa en hubb. En hubb är en klass som ärver från Microsoft.AspNet.SignalR.Hub. Kontrollera att du har mappen App_Code, annars kan den skapas från menyn som visas när man högerklickar på projektnamnet. Sedan, högerklicka på mappen App_Code och lägg till en klass av typen SignalR Hub Class (v2). Ge den namnet MinTestHub. Det går också att lägga till en vanlig klass och läsa in namnrymden Microsoft.AspNet.SignalR, och sedan ärva från Hub. Här i kan vi skriva de funktioner som vi vill exponera för klienterna, i mitt fall SkickaMeddelande.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using Microsoft.AspNet.SignalR;

namespace WebApplication3.App_Code
{
   public class MinTestHub : Hub
   {
      public void SkickaMeddelande(string meddelande)
      {
         this.Clients.All.servernPratar(
            "Ett meddelande: " + meddelande);
      }
   }
}

Visual Studios texteditor är inte speciellt hjälpsam eftersom koden är dynamisk och okänd för Visual Studio, men detta betyder att när en klient får för sig att anropa servern med SignalR, så svarar servern genom att anropa alla klienter.

Tänk på att hubben exponeras som ett attribut till ett JavaScript-objekt, connection, på klientsidan med första bokstaven som gemen, vilket betyder att denna hubb kommer att heta minTestHub på klienten – inte MinTestHub.

För att summera klassen MinTestHub: Funktionen SkickaMeddelande exponeras för klienterna och låter dem prata med servern. Servern svarar genom att anropa JavaScript-funktionen servernPratar hos alla klienterna.

Det som återstår nu är klientkoden. Jag skriver den i applikationens startsida, Views/Home/Index.cshtml.

På en lämplig plats vill jag ha en knapp kallad SendFromClient och därefter öppnar jag ett script-block.

<input type="button" id="SendFromClient" value="Send from client" />
<script type="text/javascript">

</script>

All kod skriver jag i jQuery:s uppstartevent. Det innebär att hela koden är inkapslad av $(function () { och });. I script-blocket gör jag två saker. Först ansluter jag mig till hubben och tillhandahåller definitionen av servernPratar, alltså skriver vad som ska hända när ett anrop från servern kommer in.

var testhub = $.connection.minTestHub;
testhub.client.servernPratar = function (meddelande) {
   alert(meddelande);
};

Därefter, när hubben är startad, så talar jag om vad som ska hända när knappen blir klickad på. Då vill jag anropa funktionen skickaMeddelande på servern.

$.connection.hub.start().done(function () {
   $("#SendFromClient").click(function () {
      testhub.server.skickaMeddelande("Hej från klienten!");
   });
});

Hela klientkoden som jag infogar ser alltså ut så här:

<input type="button" id="SendFromClient" value="Send from client" />

<script type="text/javascript">
   $(function () {

      var testhub = $.connection.minTestHub;
      testhub.client.servernPratar = function (meddelande) {
         alert(meddelande);
      };

      $.connection.hub.start().done(function () {
         $("#SendFromClient").click(function () {
            testhub.server.skickaMeddelande("Hej från klienten!");
         });
      });
   });
</script>

Om du testar att öppna flera webbläsare och surfar till din applikation, kommer du att se att när du klickar på knappen på en av dem, så visar sig meddelanderutan i alla. (För bäst effekt, använd olika webbläsare med tanke på att en meddelanderuta kan blockera andra meddelanderutor.)

Hubben i din server blir hårt belastad kan meddelanden skickas i okontrollerad ordning. Det beror på att anropen till klienten är asynkrona, men detta kan avhjälpas med async och await.

Om aktörer

Det finns tre olika typer av aktörer i Akka .NET. Nedan använder jag en ReceiveActor som utmärker sig genom att den använder funktionen Receive för att ta emot ett meddelande. Exemplen som följer förutsätter att namnrymden Akka.Actor är inläst. Alla aktörer har en sökväg som är oberoende av vilken CLR-klass som beskriver dem. Givet att system är ett initierat aktörssystem med namnet MittSystem och att vi har två aktörer…

public class EnRootActor : ReceiveActor
{
}

public class EnAnnanActor : ReceiveActor
{
}

…så kommer denna kod att fallera eftersom båda aktörerna, trots sina olika klasser, gör anspråk på samma sökväg:

var a = system.ActorOf<EnRootActor>("MinRoot");
Console.WriteLine(a.Path);
var b = system.ActorOf<EnAnnanActor>("MinRoot");
Console.WriteLine(b.Path);

Jag använder Akka .NET lokalt, vilket syns på sökvägen som är akka://MittSystem/user/MinRoot vilket innebär protokollet akka, aktörssystemet MittSystem följt av sökvägen user/MinRoot. Alla användardefinierade aktörer ligger under user.

Både a och b kan samexistera givet att vi ger dem unika namn.

Aktörer behöver inte skapas på rootnivå. Om en aktör skapar en aktör organiseras den nya aktören under den som skapar aktören.

public class EnRootActor : ReceiveActor
{
   public EnRootActor()
   {
      this.Receive<Message>(m =>
      {
         var c = Context.ActorOf<EnAnnanActor>("Child");
         Console.WriteLine(c.Path);
      });
   }
}

I ovanstående fall har c sökvägen akka://MittSystem/user/MinRoot/MinChild, och eftersom vi har ett villkorslöst skapande så stöter vi på problem nästa gång vi skickar ett meddelande till EnRootActor eftersom MinChild inte kan skapas mer än en gång.

Akka .NET erbjuder möjligheten att erhålla referenser till existerande aktörer genom funktionen ActorSelection som kan agera antingen på systemet eller i kontexten för någon existerande aktör.

I detta exempel (en Console Application) är skapas en tredje aktör när aktör a hanterar meddelandet som skickas till den. Den tredje aktören får sedan ett meddelande skickat till sig från Main, vilket är en annan tråd.

class Program
{
   private static ActorSystem system;

   static void Main(string[] args)
   {
      var system = ActorSystem.Create("MittSystem");
      var a = system.ActorOf<EnRootActor>("MinRoot");
      Console.WriteLine(a.Path);
      var b = system.ActorOf<EnAnnanActor>("EnTillRoot");
      Console.WriteLine(b.Path);
      a.Tell(new Message("Helloooooo!"));

      //Godtycklig paus eftersom childaktören
      //skapas på en annan tråd.
      System.Threading.Thread.Sleep(1000);

      //Erhåll en referens till childaktören
      //och skicka ett meddelande.
      system.ActorSelection(
         "akka://MittSystem/user/MinRoot/Child").Tell(
         new Message("Snodd ref."));

      Console.ReadLine();
   }
}

public class EnRootActor : ReceiveActor
{
   public EnRootActor()
   {
      this.Receive<Message>(m =>
      {
         Console.WriteLine(m.Text);
         //Skapa en ny.
         var c = Context.ActorOf<EnAnnanActor>("Child");
         Console.WriteLine(c.Path);
      });
   }
}
   
public class EnAnnanActor : ReceiveActor
{
   public EnAnnanActor()
   {
      this.Receive<Message>(m => Console.WriteLine(m.Text));
   }
}

public class Message
{
   public string Text { get; private set; }
   public Message(string text)
   {
      this.Text = text;
   }
}

För att inte programmet ska krascha nästa gång EnRootActor tar emot meddelandet, kan man kort och gott kolla om childaktören redan är skapad.

public class EnRootActor : ReceiveActor
{
   public EnRootActor()
   {
      this.Receive<Message>(m =>
      {
         Console.WriteLine(m.Text);

         //Skapa en ny om det behövs.
         if (Context.GetChildren().Count() <= 0)
         {
            var c = Context.ActorOf<EnAnnanActor>("Child");
            Console.WriteLine(c.Path);
         }
      });
   }
}

Skulle man till äventyrs vara intresserad av vilka aktörer som är childaktörer går det bra att läsa av deras sökväg eller kanske bara deras namn:

foreach (var x in Context.GetChildren())
   Console.WriteLine(x.Path.Name);

Så här ser samma exempel ut i Visual Basic (förutsatt att du lagt på Akka .NET med NuGet):

Imports Akka.Actor

Module Module1

   Private sys As ActorSystem

   Sub Main()
      sys = ActorSystem.Create("MittSystem")
      Dim a = sys.ActorOf(Of EnRootActor)("MinRoot")
      Console.WriteLine(a.Path)
      Dim B = sys.ActorOf(Of EnAnnanActor)("EnTillRoot")
      a.Tell(New Message("Helloooooo!"))
      System.Threading.Thread.Sleep(1000)
      sys.ActorSelection( _
         "akka://MittSystem/user/MinRoot/Child").Tell( _
         New Message("Snodd ref."))
      a.Tell(New Message("Tjo!"))
      Console.ReadLine()
   End Sub

End Module

Public Class EnRootActor
   Inherits ReceiveActor

   Public Sub New()
      Me.Receive(Of Message)(AddressOf Me.ReceiveMessage)
   End Sub

   Private Sub ReceiveMessage(m As Message)
      Console.WriteLine(m.Text)
      If Context.GetChildren().Count() <= 0 Then
         Dim c = Context.ActorOf(Of EnAnnanActor)("Child")
         Console.WriteLine(c.Path)
      End If
   End Sub

End Class

Public Class EnAnnanActor
   Inherits ReceiveActor

   Public Sub New()
      Me.Receive(Of Message)(AddressOf Me.ReceiveMessage)
   End Sub

   Private Sub ReceiveMessage(m As Message)
      Console.WriteLine(m.Text)
   End Sub

End Class

Public Class Message

   Public Property Text() As String

   Public Sub New(Text As String)
      Me.Text = Text
   End Sub

End Class

Förutom ReceiveActor som alltså anropar funktionen Receive för att ta emot meddelanden, så har vi även TypedActor och UntypedActor.

En TypedActor anropar inte funktionen Receive för att ta emot meddelanden, utan har en överlagring av Handle för varje meddelandetyp som aktören kan hantera. En TypedActor ärver därför inte bara från basklassen TypedActor, utan även från det generiska interfacet IHandle<> för varje meddelandetyp som aktören ska hantera. Om man jobbar med klassen TypedActor betalar man med lite minskad flexibilitet, men vinner i ökad struktur. I detta exempel kan aktören ta emot både meddelande av typen A och B (där A och B är vanliga CLR-klasser).

class Program
{
   private static ActorSystem system;

   static void Main(string[] args)
   {
      var system = ActorSystem.Create("MittSystem");
      var actor = system.ActorOf<MyTypedActor>("MinActor");
      actor.Tell(new A());
      actor.Tell(new B());
      Console.ReadLine();
   }
}

public class MyTypedActor : TypedActor, IHandle<A>, IHandle<B>
{
   public void Handle(A message)
   {
      Console.WriteLine("Tack för A!");
   }

   public void Handle(B message)
   {
      Console.WriteLine("Tack för B!");
   }
}

public class A
{
}

public class B
{
}

En UntypedActor fungerar enligt samma princip, fast utan typer. Den har en enda funktion som blir anropad vid inkommande meddelande, och den funktionen tar emot meddelandet i object-format. Jag personligen kan inte se någon speciell poäng i att välja att ärva från UntypedActor, för om man inte har behov av typlåsningen så är ReceiveActor ett bättre val. Notera att UntypedActor skriver över funktionen OnReceive.

class Program
{
   private static ActorSystem system;

   static void Main(string[] args)
   {
      var system = ActorSystem.Create("MittSystem");
      var actor = system.ActorOf("MinActor");
      actor.Tell(new A());
      actor.Tell(new B());
      Console.ReadLine();
   }
}

public class MyUntypedActor : UntypedActor
{
   protected override void OnReceive(object message)
   {
      if (message.GetType() == typeof(A))
         Console.WriteLine("Tack för A!");
      else if (message.GetType() == typeof(B))
         Console.WriteLine("Tack för B!");
   }
}

public class A
{
}

public class B
{
}

Schemalagda meddelanden i Akka .NET

Denna gång tänker jag använda en Windows Forms Application för att visa schemaläggaren i Akka .NET. Som vanligt, för att komma åt Akka .NET i ditt projekt, växla till fönstret Package Manager Console och skriv Install-Package Akka. Om du inte ser Package Manager Console, klicka på rullgardinsmenyn Tools, välj Library Package Manager och Package Manager Console.

Programmet består av följande meddelandeklass:

public class TimedMessage
{
   public string Message { get; private set; }
   public TimedMessage(string message)
   {
      this.Message = message;
   }
}

…och följande aktör:

public class Listen : ReceiveActor
{
   public Listen()
   {
      this.Receive<TimedMessage>(x =>
      {
         System.Diagnostics.Debug.WriteLine(x.Message);
      });
   }
}

Huvudfönstret har läst in namnrymden Akka.Actor för att några extension methods ska vara tillgängliga…

using Akka.Actor;

…och innehåller en knapp som heter button1. I formulärets Load-event skapas aktörssystemet och aktören och under knappen så skickar jag ett meddelande (TimedMessage) till aktören.

public partial class Form1 : Form
{
   private ActorSystem actorSystem;
   private IActorRef listen;

   public Form1()
   {
      InitializeComponent();
   }

   private void button1_Click(object sender, EventArgs e)
   {
      this.listen.Tell(new TimedMessage("Helloooo!"));
   }

   private void Form1_Load(object sender, EventArgs e)
   {
      this.actorSystem = ActorSystem.Create("ActorSystem");
      this.listen = this.actorSystem.ActorOf(
         Props.Create(typeof(Listen)));
   }
}

Om du testar detta lilla exempel så märker du att meddelandet går iväg till aktören i samma ögonblick som du klickar på knappen. Men istället för att anropa aktörens Tell-funktion i Click-eventet, så kan vi använda aktörssystemets Scheduler-property. Den har ett antal funktioner för schemaläggning och upprepning. Följande förändring gör att meddelandet går iväg först tre sekunder efter att man klickar på knappen.

private void button1_Click(object sender, EventArgs e)
{
   this.actorSystem.Scheduler.ScheduleTellOnce(
      TimeSpan.FromSeconds(3), this.listen,
      new TimedMessage("Helloooo!"), ActorRefs.Nobody);
}

Funktionen ScheduleTellOnce schemalägger ett meddelande istället för att skicka iväg det direkt. Det är det första argumentet som bestämmer när meddelandet ska gå iväg. Uttrycket TimeSpan.FromSeconds(3) säger att meddelandet ska gå iväg efter tre sekunder, oavsett vad klockan är. Schemaläggaren förväntar sig att man anger relativa tider, så om jag vill att meddelandet ska gå iväg ett bestämt klockslag, t.ex. den 19/5 kl. 13:30, kan jag istället skriva new DateTime(2015, 5, 19, 13, 30, 0).Subtract(DateTime.Now).

Det andra argumentet är aktören som ta emot meddelandet. I mitt exempel finns endast en aktör, så den skickar jag in. Det tredje argumentet är meddelandet som ska skickas. Slutligen, det fjärde argumentet är avsändaren. Om det är en aktör som skickar meddelandet, skriver man normalt this.Self, men det går bra att skicka in en annan aktör här.

I mitt fall när det inte finns någon aktör som avsändare (det är ju formuläret som skickar) så kan det vara frestande att skicka in null, men i dagsläget fungerar inte det. Klassen ActorRefs innehåller konstanter som kan användas som substitut för en avsändare, och Nobody betyder just ingen. (Detta kan komma att ändras.)

Men tänk dig att du vill bli informerad när något inte händer. Från första klicket vill du veta om användaren fortsätter att klicka var tredje sekund, eller om användaren har blivit passiv. Det kan vi lösa på följande vis:

1. När första klicket inträffar, säger vi att vi vill ha ett meddelande om tre sekunder.

2. När knappen blir klickad på nästa gång, inom tre sekunder, så avbryter vi beställningen, och gör om den på nytt.

3. Skulle användaren inte klicka inom tre sekunder så går meddelandet iväg eftersom det inte hunnit avbrytas. Således vet vi att användaren har blivit passiv.

Detta kräver minimala förändringar. Först vill vi ha ett kvitto på beställningen. För detta använder jag en medlemsvariabel av typen Akka.Actor.ICancelable.

private ICancelable idle_detector = null;

Funktionen ScheduleTellOnce ger ingen retur, men ScheduleTellOnceCancelable ger ett svar i ICancelable-format som jag kan lagra i min nya medlemsvariabel. När användaren klickar, kan jag kolla om det finns en liggande beställning, och i så fall kan jag avbryta den – eftersom användaren klickat så är han ju inte inaktiv.

private void button1_Click(object sender, EventArgs e)
{
   if (!(this.idle_detector == null))
      this.idle_detector.Cancel();
   this.idle_detector =
      this.actorSystem.Scheduler.ScheduleTellOnceCancelable(
      TimeSpan.FromSeconds(3), this.listen,
      new TimedMessage("Idle!!!"), ActorRefs.Nobody);
}

För att testa programmet, starta och klicka lite då och då på knappen. För varje gång tre sekunder får passera utan något klick så går meddelandet iväg till aktören.

Excel-SM avgjort

Då var första Excel-SM avgjort hos Microsoft i Akalla.

11329978_1456121171351889_6754263162152353179_n

Vinnaren Patrik Von Knorring (nedan) körde faktiskt Excel på svenska, lite som extra utmaning.

10411080_1456128681351138_2790449441832854668_n

Akka .NET Remote duplex

Jag har tidigare visat hur man skickar enkla meddelanden med Akka .NET Remote. Exemplet bestod av tre projekt, en server, ett datalager och en klient. Här tänkte jag visa hur man använder Akka .NET Remote för att både skicka och ta emot meddelanden. I detta exempel återanvänder jag servern BioServer och datalagret BioData från det förra exemplet.

vs

Tanken är alltså att programmet är ett enkelt bokningssystem för en liten biograf med tre sittplatser. Denna gång tänker jag utöka datalagret med lite nya meddelanden och servern med kapaciteten att svara på inkommande anrop. Dessutom bygger jag en ny grafisk klient.

Datalagret
I den förra versionen hade vi bara ett enda definierat meddelande i datalagret, klassen Bokningsmeddelande. Detta meddelande finns kvar, men nu kompletterar vi med Bokningssvar som ska skickas tillbaka till klienten som skickar in ett Bokningsmeddelande.

public class Bokningsmeddelande
{
   public int StolNr { get; private set; }
   public int BokadAv { get; private set; }
   public Bokningsmeddelande(int stolNr, int bokadAv)
   {
      this.StolNr = stolNr;
      this.BokadAv = bokadAv;
   }

   public override string ToString()
   {
      return string.Format(
         "Bokning från {0} på stol {1}.",
         this.BokadAv, this.StolNr);
   }
}

public class Bokninssvar
{
   public bool BokningAccepterad { get; private set; }
   public int StolNr { get; private set; }
   public Bokninssvar(bool bokningAccepterad, int stolNr)
   {
      this.BokningAccepterad = bokningAccepterad;
      this.StolNr = stolNr;
   }
}

Servern
Låt oss börja med att implementera stödet för Bokningsmeddelande och Bokningssvar.

Klassen Stollista, alltså den bokningsbara resursen, har jag valt att utöka med en funktion som kan uppge vem som bokat en plats.

public int BokadAv(int stolNr)
{
   var stol = this.Find(m => m.StolNr == stolNr);
   if (stol == null)
      return 0;
   else
      return stol.BokadAv;
}

Det innebär att hela klassen nu ser ut så här:

class Stollista : List
{
   public override string ToString()
   {
      var ret = new System.Text.StringBuilder();
      foreach (var s in this)
         ret.AppendLine(s.ToString());
      return ret.ToString();
   }

   public bool Boka(int stolNr, int bokadAv)
   {
      var stol = this.Find(m => m.StolNr == stolNr);
      if (stol == null)
         return false;
      stol.BokadAv = bokadAv;
      return true;
   }

   public int BokadAv(int stolNr)
   {
      var stol = this.Find(m => m.StolNr == stolNr);
      if (stol == null)
         return 0;
      else
         return stol.BokadAv;
   }
}

Dessutom har jag modifierat aktören Bokningsaktor så att den kontrollerar huruvida den önskade stolen är bokningsbar, och meddelar klienten om bokningen accepteras. Notera hur aktören använder propertyn Sender för att kommunicera med avsändaren.

class Bokningsaktor : Akka.Actor.ReceiveActor
{

   public Bokningsaktor()
   {
      this.Receive(b => {
         Console.WriteLine("Ny bokning!");
         if (Program.stolar.BokadAv(b.StolNr) == 0 ||
            Program.stolar.BokadAv(b.StolNr) == b.BokadAv)
         {
            Program.stolar.Boka(b.StolNr, b.BokadAv);
            this.Sender.Tell(new BioData.Bokninssvar(true, b.StolNr));
         }
         else
            this.Sender.Tell(new BioData.Bokninssvar(false, b.StolNr));
         Console.WriteLine(Program.stolar.ToString());
      });
   }
}

Den nya klienten
I detta fall vill jag ha en grafisk klient för att kunna representera svaren från servern på ett någorlunda snyggt sätt. Jag har skapat en applikation av typen Windows Forms Application, satt referenser till Akka .NET och Akka .NET Remote med hjälp av NuGet samt satt en referens till datalagret BioData. Dessutom vill jag läsa in namnrymden Akka.Actor för att komma åt en extension method – en överlagring av funktionen ActorOf.

using Akka.Actor;

Vidare väljer jag att hålla en referens till mitt aktörssystem i huvudformuläret.

private Akka.Actor.ActorSystem system;

På formuläret har jag placerat ut ett textfält där användaren förväntas infoga sitt användar-ID (ett heltal) samt tre knappar som representerar de tre bokningsbara stolarna. Man förväntas ange sitt ID i textfältet innan man klickar på någon knapp.

form

I formulärets Load-event initierar jag aktörssystemet på samma sätt som tidigare, men sparar nu referensen i medlemsvariabeln som jag deklarerade ovan.

private void Form1_Load(object sender, EventArgs e)
{
   var config = Akka.Configuration.ConfigurationFactory.ParseString(@"
akka {
    actor {
        provider = ""Akka.Remote.RemoteActorRefProvider, Akka.Remote""
    }
    remote {
        helios.tcp {
            port = 0
            hostname = localhost
        }
    }
}
");
   this.system = ActorSystem.Create("Bokningsklient", config);         
}

Eventet FormClosed får sköta uppstädningen.

private void Form1_FormClosed(object sender, FormClosedEventArgs e)
{
   this.system.Shutdown();
   this.system.Dispose();
}

Sedan ska Click-eventet under varje knapp inleda bokningsförfarandet.

private void btnStol1_Click(object sender, EventArgs e)
{
   this.Boka(1);
}

private void btnStol2_Click(object sender, EventArgs e)
{
   this.Boka(2);
}

private void btnStol3_Click(object sender, EventArgs e)
{
   this.Boka(3);
}

För att aktören ska kunna komma åt knapparna direkt, har jag även en enkel funktion som tar ett stolsnummer och ger en referens till en knapp.

public Button Stolreferens(int StolNr)
{
   Button[] ret = { this.btnStol1, this.btnStol2, this.btnStol3 };
   return ret[StolNr - 1];
}

Sista funktionen i formuläret är den som utför själva bokningen. Notera att vi skickar med en referens till en lokal aktör som ska kunna ta emot svaret från servern.

private void Boka(int StolNr)
{
   var avsandare = this.system.ActorOf();
   var bokare = this.system.ActorSelection(
      "akka.tcp://AllaBokare@localhost:8080/user/Bokare");
   bokare.Tell(new BioData.Bokningsmeddelande(StolNr,
      int.Parse(txtAnvID.Text)), avsandare);
}

Den lokala aktören ser ut så här. Notera att den innehåller lite fulkod för att erhålla en referens till formuläret i fråga. Koden förmodar att formuläret är ensamt i programmet.

public class LocalActor : Akka.Actor.ReceiveActor
{
   public LocalActor()
   {
      this.Receive(s =>
      {
         var stol = (Application.OpenForms[0]
            as Form1).Stolreferens(s.StolNr);
         stol.BackColor = s.BokningAccepterad ? Color.Green : Color.Red;
      });
   }
}

Varje klient som klickar på en knapp för att utföra en bokning, kommer att få en bekräftelse genom att knappen blir grön. Om stolen inte är bokningsbar blir istället knappen röd.

form2

Introduktion till Akka .NET Remote

Akka .NET Remote låter aktörerna i Akka .NET skicka meddelanden till andra processer genom Windows Sockets. Det innebär att ett system kan distribueras över flera processer oavsett om de ligger på samma fysiska maskin eller på en annan maskin i nätverket.

Arkitekturen i Akka .NET Remote är serverfri – varje peer kan kontakta och kommunicera med vilken annan peer som helst, givet att namn och port är känt. Det innebär att om du bygger en server, kan den utan problem förmedla direktkontakt mellan sina klienter.

Detta exempel visar ett mycket enkelt bokningssystem av en biosalong med tre stolar. Systemet består av tre stycken projekt, en server, ett datalager och en klient. Servern och klienten är Console Applications (C#) och datalagret är ett klassbibliotek.

vs

Servern
Låt oss börja med att titta på servern. I mitt exempel heter den BioServer. All kod som visas i servern förutsätter följande:

1. Akka .NET är installerat. Detta kan göras med följande Nuget-kommando:

Install-Package Akka

2. Akka .NET Remote är installerat.

Install-Package Akka.Remote

3. Följande using-sats:

using Akka.Actor;

Så här ser huvudprogrammet ut:

class Program
{
   public static Stollista stolar;

   static void Main(string[] args)
   {
      var config =
         Akka.Configuration.ConfigurationFactory.ParseString(@"
akka {
    actor {
        provider = ""Akka.Remote.RemoteActorRefProvider, Akka.Remote""
    }

    remote {
        helios.tcp {
            port = 8080
            hostname = localhost
        }
    }
}
");

      stolar = new Stollista()
         { new Stol(1), new Stol(2), new Stol(3) };
      Console.WriteLine(stolar.ToString());

      using (var system =
         Akka.Actor.ActorSystem.Create("AllaBokare", config))
      {
         var bokare = system.ActorOf(new
            Akka.Actor.Props(typeof(Bokningsaktor)),"Bokare");
         Console.ReadLine();
      }
   }
}

Notera att konfigurationen anger vilken port servern ska lyssna på (8080). Den kodraden har jag klippt ut från dokumentationen för Akka .NET Remote och klistrat in här. Portnumret måste vara förutbestämt för att den första klienten ska kunna hitta servern.

Därefter har jag min biosalong bestående av tre stolar. Dessa beskrivs av följande klasser:

class Stollista : List<Stol>
{
   public override string ToString()
   {
      var ret = new System.Text.StringBuilder();
      foreach (var s in this)
         ret.AppendLine(s.ToString());
      return ret.ToString();
   }

   public bool Boka(int stolNr, int bokadAv)
   {
      var stol = this.Find(m => m.StolNr == stolNr);
      if (stol == null)
         return false;
      stol.BokadAv = bokadAv;
      return true;
   }
}

Därefter använder jag Akka.Actor.ActorSystem.Create för att skapa mitt aktörssystem (kallad AllaBokare) på samma sätt som om jag hade tänkt att använda Akka .NET i en och samma process, och i using-blocket för aktörssystemet så skapar jag min aktör (kallad Bokare). Det som återstår i servern är klassen som beskriver aktören. Den ser ut så här:

class Bokningsaktor : Akka.Actor.ReceiveActor
{

   public Bokningsaktor()
   {
      this.Receive(b => {
         Console.WriteLine("Ny bokning!");
         Program.stolar.Boka(b.StolNr, b.BokadAv);
         Console.WriteLine(Program.stolar.ToString());
      });
   }
}

Datalagret
Datalagret har jag valt att lägga i ett annat projekt i samma lösning som servern. Jag har kallat datalagret för BioData. Här finns en klass som beskriver meddelandet som klienten kan skicka till servern.

public class Bokningsmeddelande
{
   public int StolNr { get; private set; }
   public int BokadAv { get; private set; }
   public Bokningsmeddelande(int stolNr, int bokadAv)
   {
      this.StolNr = stolNr;
      this.BokadAv = bokadAv;
   }

   public override string ToString()
   {
      return string.Format("Bokning från {0} på stol {1}.",
         this.BokadAv, this.StolNr);
   }
}

Både servern och klienten ska ha en referens till datalagret.

Klienten
Klienten är mycket enkel. Notera först skillnaden i konfigurationen mellan klienten och servern. Servern har port 8080, vilket klienten måste veta om för att kunna hitta servern. Men när klienten gjort sig tillkänna så vet servern vilken port klienten använder, därför behöver vi inte bestämma någon port åt klienten. Att ange port 0 är att begära dynamisk port.

Därefter skapar vi ett aktörssystem med det godtyckliga namnet Bokningsklient. Från systemet i klienten väljer vi att ansluta oss till servern genom att anropa ActorSelection. Som argument använder jag sökvägen till aktören på servern (som hette Bokare i systemet AllaBokare). Slutligen samlar jag in information från slutanvändaren som skickas till servern med metoden Tell. Så här ser källkoden för klienten ut:

class Program
{
   static void Main(string[] args)
   {
      var config = Akka.Configuration.ConfigurationFactory.ParseString(@"
akka {
    actor {
        provider = ""Akka.Remote.RemoteActorRefProvider, Akka.Remote""
    }
    remote {
        helios.tcp {
            port = 0
            hostname = localhost
        }
    }
}
");

      using (var system =
         Akka.Actor.ActorSystem.Create("Bokningsklient", config))
      {
         var bokare = system.ActorSelection(
            "akka.tcp://AllaBokare@localhost:8080/user/Bokare");
         Console.Write("Vad är ditt användar-ID? Skriv ett heltal. ");
         var userId = int.Parse(Console.ReadLine());
         while(true)
         {
            Console.Write("Vilken stol vill du boka? (1-3) ");
            var stol = Console.ReadLine();
            if (stol == "")
               break;
            bokare.Tell(new
               BioData.Bokningsmeddelande(int.Parse(stol), userId));
         }
         system.Shutdown();
      }
   }
}

Bilden visar servern bakom en klient.

akka_remote

Eftersom portnumret tilldelas till klienten dynamiskt så kan flera klienter startas och boka platser. Och eftersom arkitekturen i Akka .NET Remote är peer-to-peer så kan dessa skicka meddelanden till varandra.

Introduktion till Gosbust

Efter mycket om och men så kan nu mitt programmeringsspråk Gosbust laddas hem. Ladda hem filen Gosbust.zip och packa upp innehållet, Gosbust.exe, på lämplig plats. Om du bara vill testa lite, duger skrivbordet bra. Om du vill köra ett eget program så kan du använda t.ex. Anteckningar för att skriva programmet, spara det och skicka det som argument till Gosbust.exe. Men om du bara vill titta på språket och labba lite, kan du starta Gosbust genom att dubbelklicka på Gosbust.exe. Du möts då av detta:

gosbust

Jag vill igen betona att detta programmeringsspråk är utvecklat lite som ett terapiprojekt, och är absolut inget jag förespråkar användning av, även om jag förmodligen kommer implementera något skarpt i detta bara-för-att… 😉

Konsolen förstår några enkla kommandon och dessa presenteras för användaren när han startar Gosbust. Om man skriver något som konsolen inte förstår så skickas det vidare till kompilatorn som försöker exekvera. Om du vill testa något av de medföljande tre exempelprogrammen, skriv namnet på programmet. Gosbust visar källkoden för programmet och frågar om du vill köra. Varje gång du skriver RESET eller kör ett exempelprogram så töms minnet och du förlorar alla dina variabler.

Gosbust version 0.8 känner till fyra olika datatyper. Heltal (32-bit), flyttal, bitar och strängar. För att skriva ut ett värde på skärmen, t.ex. ett heltal, skriv << direkt åtföljt av värdet som du vill skriva ut. Detta skriver ut talet 5:

<<5

Heltal känns igen av Gosbust på att de endast innehåller tecknen 0-9. Flyttal innehåller en punkt, bitar är en nolla eller en etta (0/1) och strängar är allt annat. Om du vill att Gosbust ska skriva Hej!, skriv:

<<Hej!

Däremot, om du vill att Gosbust ska skriva ut Hej världen! kan du inte skriva så här:

<<Hej världen!

Det bror på att Gosbust tror att du har skickat två instruktioner, och den andra (världen!) känns inte igen av kompilatorn. Om Hej världen! kapslas in av citattecken, så fungerar det som förväntat.

<<"Hej världen!"

Gosbust är typsäkert. När man lagrar data i en variabel, måste variabeln vara av den typ som datat man försöker lagra. Variablernas namn är i denna version begränsat till en bokstav och en eventuell typmarkör. Detta lagrar heltalet 10 i variabeln A:

10>>A

Du kan läsa av värdet av A genom att skriva <<A. Variabler som lagrar bitar heter A? till Z?, flyttal lagras i A# till Z# och strängar lagras i A$ till Z$. Det är inte tillåtet att läsa av en variabel som inte är initierad. Detta ger ett fel:

<<A$

Men om du först skriver t.ex. “Hej!”>>A$ kommer <<A$ att fungera. Om du vill radera minnet, skriv reset.

gosbust2

Provkör gärna testprogrammen genom att skriva fibonacci, fizzbuzz eller primes. Mycket nöje!

SKYpe? Apple?

Knappt har vi vant oss att säga OneDrive istället för SkyDrive om Microsofts molnlagringstjänst innan DN meddelar att Microsofts telefontjänst Skype inte får heta Skype, eftersom det är för likt mediebolaget Sky.

“Det är inte bara namnen med ordet “Sky” som liknar varandra utan även Skypes logotyp, med en molnformad kant runt namnet Skype, som skapar associationer till ordet “Sky”, menar domstolen.”

Ja, vad är det egentligen som är vad här?

Även Apple och Apple har bråkat om att namnen har varit lika, men eftersom Apple och Apple var i olika branscher – Apple säljer musik och Apple säljer datorer – så gjordes en överenskommelse om att så länge Apple håller sig borta från musikbranschen så kan man leva med förväxlingsrisken. När Apple sedan gav sig in i musikbranschen så valde Apple 2006 att stämma Apple. Apple vann. Apple fick använda sin logga för att lansera sin musiktjänst.

Fem nyheter i VB.NET 2015

Nu när Visual Studio 2015 CTP finns att ladda hem, går det bra att testa vad som är nytt i senaste versionen av Visual Basic. Och i ärlighetens namn är det inte speciellt mycket som hänt i språket, men här är fem stycken guldkorn.

Enterslag i strängar
I tidigare versioner av VB.NET fanns inget sätt att ange att en sträng skulle innehålla radbryten. För att skapa en sträng med radbryten var man tvungen att t.ex. konkatenera in ControlChars.CrLf eller använda StringBuilder-objektets AppendLine. Men nu är det fullt tillåtet att skriva enterslagen direkt i källkoden. Detta exempel skapar en sträng innehållande tre textrader:

Dim X = "Jag
är en
sträng med tre rader!"

Stränginterpolering
Och apropå strängar så stöder nu VB.NET stränginterpolering. Tidigare när man infogade variabla värden i en sträng använde man funktionen String.Format. I detta exempel är X och Y flyttal:

Dim S =
   String.Format("Värdet av X är {0:n1} och y är {1:n1}",
   X, Y)

Notera hur jag först anger mina platshållare i strängen, för att sedan låta övriga parametrar fylla dessa platshållare. Med prefixet $ kan jag stoppa in referenserna direkt in i strängen. Så istället för att först ange plats 0 och sedan fylla ut den med X, så kan jag direkt säga att jag vill ha in värdet av X i strängen. Och editorns IntelliSense hänger med!

Dim S = $"Värdet av X är {X:n1} och y är {Y:n1}"

Null propagation
Tänk dig att du har en variabel som representerar en anställd (klassen Employee). Du vill läsa av dess property FirstName, så här:

Dim N = E.FirstName

Problemet är bara att variabeln E kan vara oinitierad, och i så fall uppstår NullReferenceException i programmet. Men du kanske vill ha ut förnamnet om det finns ett Employee-objekt i E, annars en tom sträng. Detta brukar VB-programmerare hantera så här:

Dim N = If(E Is Nothing, "", E.FirstName)

Med hjälp av null propagation kan man nu skriva så här:

Dim N = E?.FirstName

Om E är oinitierad (Nothing i VB), så är nu N en oinitierad strängvariabel.

NameOf
Igen, tänk dig att jag har en klass som heter Employee och att den har en property som heter FirstName. Om jag vill att en strängvariabel ska innehålla namnet på propertyn FirstName, kanske för att jag vill använda reflection mot ett objekt av typen Employee, skulle jag kunna göra så här:

Dim S = "FirstName"

Problemet med ovanstående kod är givetvis att om jag ger min property ett nytt namn så slutar koden att fungera, eftersom strängkonstanten “FirstName” inte längre delar namn med propertyn i fråga. Det har inte funnits något bra sätt att göra detta på i VB. Om jag t.ex. vet att FirstName är den första propertyn, kan jag förvisso skriva så här:

Dim S = GetType(Employee).GetProperties()(0).Name

Men detta är precis lika instabilt eftersom koden nu rasar om någon lägger till en ny property före FirstName. Men i VB.NET 2015 kan jag kort och gott skriva så här:

Dim S = NameOf(E.FirstName)

Nu kommer värdet “FirstName” lagras i S, och om vi refaktorerar koden, kommer ovanstående rad att följa efter.

Kommentarer i LINQ
Den sista språkliga förbättringen ger oss möjlighet att skapa kommentarer i en LINQ-fråga. Tänk att vi har en lista av Employee-objekt enligt följande:

Dim X As New List(Of Employee)()
X.Add(New Employee("Sven"))
X.Add(New Employee("Gunnar"))

Om jag vill ha en fråga som hämtar de objekt vars förnamn börjar på G, kan jag uttrycka mig så här:

Dim Svar = From E In X
           Where E.FirstName.StartsWith("G")
           Select E

Men om jag skulle få för mig att kommentera mitt i programsatsen, t.ex. efter X på rad 1, efter (“G”) på rad två eller efter E på rad 3, skulle programmet rasa.

Dim Svar = From E In X                       'Men nu kan jag
           Where E.FirstName.StartsWith("G") 'kommentera
           Select E                          'vart jag vill!

Avslutningsvis vill jag kommentera att kodeditorn fått sig ett rejält lyft, där det som sticker ut mest är en referensräknare på alla objekt man skapar – gissningsvis ett mycket efterfrågat tillägg.

Vad ska språket heta?

Uppdatering 2015-05-02: Språket kommer att heta Gosbust – ett genialt namn med referenser både till andra språk, populärkultur och till nyckelord i detta språk. Upphovsmannen till namnet är anonym, men har fler fyndigheter på sin meritlista, t.ex. ordet som bättre än något annat beskriver kristendomens gud Jahve – UMO (Undetectable Mythological Object).

Uppdatering 2015-05-03: Under ett tidigt stadium av språkets utveckling så skrev man A>>1 för att lagra 1 i variabeln A. Nu när Gosbust går att ladda hem är detta ändrat. Numera skriver man istället 1>>A för att lagra 1 i variabeln A. Uttrycket A>>1 ger ett kompileringsfel idag. Detta gäller för alla datatyper, och även för de underliggande instruktionerna. PUTI A 1 ska nu skrivas PUTI 1 A, där 1 är värdet som ska lagras och A är variabeln den ska lagras i.

Först och främst vill jag betona att detta språk är lite av ett terapiarbete för mig – det kommer absolut inte lösa världsproblemen eller frälsa några programmerare. Parsern är inte hierarkisk och upplägget är inspirerat av Assembler på Commodore 128. Detta innebär att språket består av instruktioner, där varje instruktion alltid tar samma antal argument. Det innebär att man inte behöver ha olika separatorer mellan argumenten och mellan programsatserna. Om ett kommando tar två argument kommer kompilatorn att läsa två argument och sedan anta att det nästa som påträffas är nästa kommando. Som separator används whitespace (blanksteg, tabb eller enterslag), och det går bra att infoga flera whitespaces efter tycke, men endast på de platser där det ska vara whitespaces. Det går inte att undvika whitespaces där whitespaces förväntas.

Följande kod placerar värdet 1 i heltalsvariabeln A, följt av en kommentar:

PUTI A 1 /* Sparar 1 i A */

Detta däremot kommer inte att fungera eftersom uttrycket 1/* inte är en giltig heltalskonstant:

PUTI A 1/* Sparar 1 i A */

Notera att variablernas datatyp härleds från deras namn. Variabler utan postfix, t.ex. A, B eller C antas vara 32-bitars heltal. Variabler vars namn slutar med $, t.ex. A$, B$ eller C$ antas vara strängar. Frågetecken betyder bit (t.ex. A?) och korsbrygga betyder flyttal (t.ex. A#).

Det finns ett enkelt syntaxlager ovanpå instruktionerna som syftar till att öka läsbarheten. PUTI A 1 kan kortas ner till 1>>A. Detta program visar de 20 första talen i Fibonacci-sekvensen (utom 0):

PUTI 1 A
GETI A
PUTI 1 B
GETI B
PUTI 0 X
PROC Run
   ADDI A B C
   GETI C
   INCI X
   SWPI A B
   SWPI B C
   LETI X 18 J?
   GOTO J? Run
GETS "Done!"

Första raden placerar 1 i variabeln A. GETI A presenterar värdet av A. PROC Run markerar starten av en subrutin som kort och gott heter Run – subrutiner kan heta vad som helst, men om namnet består av något annat än bokstäverna A-Z måste namnet kapslas in av citattecken. Subrutiner körs även om de inte blir anropade, så efter PUTI X 0 (rad 5) kommer ADDI A B C (rad 7) att köras (fallthrough). ADDI A B C sparar summan av A och B i C, vilket kan kortas ner till A+B>>C. INCI X ökar X med 1, vilket kan kortas ner till X++. SWAPI A B låter värdet av A hamna i B och värdet av B hamna i A, vilket kan kortas ner till A<>B. LETI X 18 J? testar huruvida X är mindre än 18, och lagrar i så fall 1 i J?, annars 0. Detta kan kortas ner till X<18>>J?. Motsvarigheten heter GRTI. GOTO J? Run anropar subrutinen Run (i detta fall rekursivt) om värdet av J? är 1.

Så här ser den korta versionen av mitt lilla Fibonacci-program ut:

1>>A <<A 1>>B <<B 0>>X
Run: A+B>>C <<C X++ A<>B B<>C X<18>>J?
GOTO J? Run
<<"Done!"

Apropå anrop så finns två nyckelord för att anropa subrutiner: GOTO och GOSB. Skillnaden mellan dessa är att GOTO egentligen bara ändrar nuvarande exekveringspunkt, medan GOSB (“go sub”) dessutom lagrar vilken plats man lämnar i en enkel callstack. Subrutiner som anropas med GOSB kan lämna tillbaka kontrollen till den anropande koden genom instruktionen RTRN (“return”) som plockar ett värde från callstacken. Om RTRN används när callstacken är tom avslutas programmet.

Trots att språket varken är färdigt eller släppt så finns redan konceptet som en Ruby DSL. Tack Jonas Elfström!

Jag återkommer med fler kodsnuttar, och tar tacksamt emot tips på namn! (Dawkins är upptaget eftersom eftersom den berömde biologen Richard Dawkins faktiskt också har designat ett programmeringsspråk.)

Uppdatering: Tidigare idag publicerade Roger Alsing en Fizz Buzz på Facebook. Finessen med hans Fizz Buzz var att den saknade tester, utan utnyttjade objektorienteringen i C# för att få till serien. Mitt språk är tyvärr inte objektorienterat, men så här ser en fungerande Fizz Buzz ut:

1>>I
Run:
   1>>C? I%3>>F F=0>>F? I%5>>B B=0>>B? F?&B?>>X?
   GOSB X? FizzBuzz
   GOSB B? Buzz
   GOSB F? Fizz
   GOSB C? NoFizzBuzz
   I++ I<101>>J?
   GOTO J? Run
/* Quit! */
RTRN

/* Sub routines... */
FizzBuzz: 0>>F? 0>>B? 0>>C? <<"Fizz Buzz" RTRN
Buzz: 0>>F? 0>>C? <<"Buzz" RTRN
Fizz: 0>>C? <<"Fizz" RTRN
NoFizzBuzz: <<I RTRN

Sci-Fi World

Det är ännu inte för sent att besöka Sci-Fi World i Stockholm, som har öppet även imorgon söndag. Jag spenderade lördagen där, och nördade loss rejält bland Magic-kort och D&D-tärningar. Väldigt mycket kretsade kring Stjärnornas Krig. Dragplåstren var Robert Patrick, Ray Park, Samantha Fox, Joe Cantillo och Sam Jones.

Sam J. Jones spelade Flash Gordon 1980 (som Queen gjorde soundtracket till) och sig själv i filmen Ted.

WP_20150425_008

Detta är bilen Kit från tv-serien Knight Rider med David Hasselhoff:

WP_20150425_027

Har tar min dotter kort på mig och Samantha Fox (som sjöng in en låt till Terror på Elm Street 5):

WP_20150425_011

Detta är Robert Patrick som spelade T-1000 i filmen Terminator 2 och John Doggett i Arkiv X:

WP_20150425_019

Enkel trådning i .NET med Akka

Historiskt sett har det varit ganska komplicerat att bygga multitrådade applikationer i .NET. Rent tekniskt var det enkelt att sjösätta en tråd med hjälp av klassen System.Threading.Thread, men om mycket skulle göras började koden ganska snabbt likna spaghetti. För att minska ner koden kan man använda multitrådade delegater istället för objekt av typen Thread, men det löste inte problemet med spaghettikod. Nyckelorden asynk och await löste både komplexiteten med hopp och returvärde, men var ganska hårt knutet till modellen TAP.

Om jag väljer att jobba med Akka .NET blir trådningen ännu mer hanterad, fast kring en mycket friare modell än TAP, nämligen Actor Model. (I alla nedanstående exempel jobbar jag i Visual Studio 2013.) Tänk dig att jobbar i Windows Forms och att du vill utföra något som kräver ungefär fem sekunders arbete och sedan visar ett meddelande när arbetet är utfört. Min erfarenhet är att Akka .NET fortfarande kan utsättas för förändringar i sitt publika API, så den exakta kodens utseende kan variera – jag kör Akka 1.0.0. För att visa detta skapar jag ett helt nytt Windows Forms-projekt (C# med .NET Framework 4.5.1) och installerar Akka .NET från Package Manager Console genom att skriva:

Install-Package Akka

Om du inte ser Package Manager Console, Klicka Tools, NuGet Package Manager och Package Manager Console.

Akka .NET använder meddelanden för att kommunicera. Meddelanden är kort och gott godtyckliga objekt som initieras och skickas i samband med att ett asynkront anrop görs. Meddelandet bör vara immutable, alltså meddelandet ska inte kunna modifieras, vilket kan implementeras genom att objektets data inte har några publika setters.

class AkkaMessage
{
   public string MyValue { get; private set; }

   public AkkaMessage(string myValue)
   {
      this.MyValue = myValue;
   }
}

En actor (aktör) är den t.ex. det objekt som kan ta emot ett meddelande och agera på det. Det som utmärker en sådan aktör är basklassen Akka.Actor.ReceiveActor samt konstruktorn som tar emot meddelandet som skickas till den. För att ta emot meddelandet används den generiska metoden Receive vars argument är det som ska göras med meddelandet. Den generiska metodens typparameter är meddelandeklassen. Så i följande kod anropar vi Receive och skickar med kod jobbar i fem sekunder för att sedan visa en meddelanderuta.

class AkkaActor : Akka.Actor.ReceiveActor
{
   public AkkaActor()
   {
      this.Receive(x =>
         {
            System.Threading.Thread.Sleep(5000);
            System.Windows.Forms.MessageBox.Show(x.MyValue);
         }
      );
   }
}

Nu återstår bara initieringen och själva anropet. Följande kod har jag skrivit i mitt programs huvudformulär. Först har jag ett privat fält av typen Akka.Actor.ActorSystem som representerar motorn i Akka – det s.k. actorsystemet. I Load-eventet för formuläret initierar jag systemet med funktionen Create. Create vill ha ett namn på systemet i sin kostruktor. Slutligen, under Click-eventet på en knapp på formuläret så gör jag anropet som ska hanteras av aktören ovan.

Den första raden anropar funktionen ActorOf för att erhålla en referens till en aktör. Den andra raden utför utför anropet med hjälp av funktionen Tell, och låter ett meddelande skickas med som argument. Meddelandet måste vara av typen AkkaMessage, eftersom jag hårdkodade aktören att hantera den typen.

public partial class Form1 : Form
{
   private Akka.Actor.ActorSystem actorSystem;

   public Form1()
   {
      InitializeComponent();
   }

   private void Form1_Load(object sender, EventArgs e)
   {
      this.actorSystem =
         Akka.Actor.ActorSystem.Create("ActorSystem");
   }

   private void button1_Click(object sender, EventArgs e)
   {
      var m = this.actorSystem.ActorOf(new
         Akka.Actor.Props(typeof(AkkaActor)));
      m.Tell(new AkkaMessage("Hello!"), m);
   }
}

När du kör programmet, notera att programmets fönster är svarsbenäget under den tid programmet pausar pausar (anropet på Sleep), vilket säger oss att aktören och formuläret körs på olika trådar.

Om du istället hade velat implementera detta i Visual Basic, skulle ditt meddelande kunna se ut så här:

Public Class AkkaMessage
   Public Property MyValue() As String
   Public Sub New(MyValue As String)
      Me.MyValue = MyValue
   End Sub
End Class

Aktören skulle kunna se ut så här:

Public Class AkkaActor
   Inherits Akka.Actor.ReceiveActor

   Public Sub New()
      Me.Receive(Of AkkaMessage)(AddressOf MyMessageHandler)
   End Sub

   Private Sub MyMessageHandler(X As AkkaMessage)
      System.Threading.Thread.Sleep(5000)
      MessageBox.Show(X.MyValue)
   End Sub

End Class

Och slutligen, formuläret skulle kunna se ut så här:

Public Class Form1

   Private ActorSystem As Akka.Actor.ActorSystem

   Private Sub Form1_Load(sender As Object, _
      e As EventArgs) Handles MyBase.Load
      Me.ActorSystem = Akka.Actor.ActorSystem.Create("ActorSystem")
   End Sub

   Private Sub Button1_Click(sender As Object, _
      e As EventArgs) Handles Button1.Click
      Dim M = Me.ActorSystem.ActorOf( _
         New Akka.Actor.Props(GetType(AkkaActor)))
      M.Tell(New AkkaMessage("Hello!"), M)
   End Sub

End Class

Betydelsen av ordet “nörd” är justerat

Mattias Boström twittrade (följ!) detta igår:

“Nörd” har fått ändrad definition i nya SAOL-upplagan (upptill på bilden).

Han bifogar två bilder föreställande den tidigare och den reviderade definitionen från Svenska Akademiens ordlista, där den tidigare lyder “enkelspårig och löjeväckande person, tönt” och den nya lyder “person som har ett stort specialintresse och som därför kan verka något enkelspårig“.

Eventuellt kan min syn på ordet vara färgad av hur vi använde ordet på 80-talet eftersom jag knappt använt ordet sedan dess, men då var “nörd” svengelska för “nerd” som fortfarande är en nedsättande beskrivning av någon som är lite töntig. Men de som beskriver sig själva som nördar idag, väljer alltså inte ett negativt ord för att påvisa självdistans, utan ett ord som betraktas som relativt neutralt.

Den som vill ta sig an kulturskatten av college- och high school-filmer från 80-talet kommer fortfarande komma i kontakt med “nördar” i ordets gamla bemärkelse, men dessa kanske vi ska benämna som “nerdar” idag för att visa kopplingen till det engelska ordet “nerd”.

Vad sägs om höjdarfilmen “Nördarna kommer!” (Revenge of the nerds) från 1985:

Eller klassikern “Drömtjejen” (Weird Science), också från 1985:

Mycket nöje!

Commoflage 54

Lyssna gärna på Commoflage avsnitt 54 när Henrik Andersson och jag diskuterar bl.a. lagringshastigheter på Commodore 64. Mycket nöje!

11083657_1436862563277750_203473098906490422_n

Färger i datorer

Under knappt hälften av den tid vi haft datorer, har dessa varit oförmögna att visa färggrafik. De har presenterat sitt utdata med tända eller släckta bildelement. De första datorerna hade ingen bildskärm alls. Datamaskinen ENIAC (1946) levererade sitt utdata i form av hål i pappskivor, och en av de första hemdatorerna, Altair 8800 (1974), hade några röda lysdioder. Rätt snabbt ansåg man att den mest effektiva metoden att presentera utdata var att visa “tecken” på en tv-skärm, som t.ex. Commodore PET (1977) gjorde. En svart skärm visade 40 x 25 gröna tecken som byggdes av 8 x 8 bildelement (pixlar), alltså 64 punkter per tecken och 320 x 200 punkter totalt. Datorer med bildskärm var alltså som regel monokroma på 70-talet, vilket betyder att de skiljer på tända eller släckta bildelement utan att lägga någon annan aspekt i bildelementens färg. Grafiken kostade bara en bit per pixel, alltså 8 kilobytes totalt (320 x 200 / 8 = 8000).

År 1980 fick vi uppleva den första hemdatorn som kunde visa grafik i färg – TRS-80 Color Computer 1. Just färgen var så pass viktig att själva operativsystemet, en BASIC-interpretator, fick namnet Color BASIC 1.0. Om det är tillåtet att uttrycka sig i moderna mått: Datorn var utrustad med en processor på knappt 0,0009 gigahertz, vilket är klent jämfört med dagens mobiltelefoner som klarar kring 2,0 gigahertz (iPhone 6 har en processor på 1,6 GHz och Nokia Lumia 930 har en processor på 2,2 GHz). TRS-80 var utrustad med ett minne på 0,000004 GB (vilket kan jämföras med dagens standard på 8 GB) och den var helt utan sekundär lagring, vilket idag kan handla om hårddiskar på terabytes.

Personligen stannade jag vid monokroma datorer ganska länge. Jag gick från Sinclair ZX81 till Luxor ABC80. När mina vänner började använda Vic 20, Sinclair Spectrum och Commodore 64, så harvade jag vidare med min ZX81 ända fram till år 1986 då jag fick tillgång till en Commodore 128 med en 1571:a som sekundär lagringsenhet, vilket både innebar att jag kunde avbryta mitt arbete på kvällen, och återuppta gårdagens arbete dagen efter, genom att återkalla det från sekundärminnet.

På den tiden använde man alltså en bit per bildelement. Varje bildelement (eller pixel) utgör en punkt i den matris som utgör skärmbilden, och varje bildelement beskrevs av en bit. Commodore 64 hade en palett av på 16 olika färger, men en bild på 200 x 320 pixlar kunde bara visa två av dessa färger: En förgrundsfärg och en bakgrundsfärg. Varje bildelement kunde fortfarande bara vara tänt eller släckt. Men C64:an hade dessutom ett flerfärgsläge.

Genom att para ihop två pixlar, fick man helt plötsligt två bitar per pixel. Förvisso var dessa pixlar större, vilket gjorde att grafiken blev kantigare, men nu kunde varje pixel (totalt 160 x 200 avlånga pixlar) beskriva ett värde av fyra tillgängliga (00, 01, 10 eller 11) istället för bara 0 eller 1. Därmed kunde C64 visa fyra av sina 16 färger på skärmen, om än på bekostnad av antalet pixlar. De fyra färgerna valdes från listan av 16 tillgängliga färger.

Sedan har datorerna succesivt utrustats med mer grafikminne och större färgpalett. På 90-talet fanns persondatorer som med nästan fem gånger så hög upplösning (640 x 480 pixlar) kunde 256 färger ur en palett på 16,8 miljoner färger, vilket kräver 1 megabyte grafikminne. Varje pixel beskrevs av en byte istället för en bit, och varje byte var en referens till en palett.

Idag har man dels betydligt fler bildelement på skärmen, och dessutom kostar man på sig hela tre bytes per bildelement. Detta ger oss 24 bitar per pixel, vilket ger oss möjlighet att ha 16,8 miljoner kombinationer av tända och släckta bitar per pixel. Därmed har vi eliminerat behovet av att ha en palett att hänvisa till – varje pixel kan beskriva en färg istället för bara en position i en palett, där de första 8 bitarna av 28 beskriver färgens röda del, de nästa 8 beskriver färgens gröna del och de sista 8 beskriver färgens blå del. Utifrån dessa tre färger kan vi få fram alla tänkbara färger genom additiv färgblandning.

Att förstå additiv färgblandning är enkelt om man tänker sig att man befinner sig i ett vitt rum utan fönster eller belysning. Trots att rummet är vitt så ser vi bara svart, eftersom inget ljus kommer in i våra ögon. Men om du lyser med en röd ficklampa på den vita väggen, kommer åtminstone rött ljus att komma in i dina ögon. Den vita väggen reflekterar alla frekvenser, och eftersom endast rött ljus strålar mot väggen, är det endast rött ljus som kommer in i våra ögon. Men om vi samtidigt lyser med en grön ficklampa på samma punkt på väggen, kommer både röda och gröna strålar att reflekteras från väggen, vilket vi uppfattar som gul färg.

Om vi låter varje pixel beskriva sin egen färg, men tänker oss att varje pixel endast består av tre bitar där den första representerar röd, den andra grön och den tredje blå, kan vi visa åtta olika färger.

000 skulle vara svart, eftersom ingen av färgerna lyser.

100 skulle ge röd färg, eftersom den första representerar röd. Av samma skäl skulle 010 vara grön och 001 vara blå.

bild1

Om vi istället för tre bitar (en per grundfärg) skulle ha sex bitar per pixel (två per grundfärg), behöver inte röd bara vara tänd eller släkt (0 eller 1). Nu kan vi säga att 00 betyder släckt, 01 betyder 33% röd, 10 betyder 67% röd och 11 betyder 100% röd.

bild2

Detta öppnar som synes för möjligheten att visa mörkröd, du kan nu skapa ljusröd (eller rosa) genom att visa mycket röd och lite grön och blå. Vi kan visa lite av alla färger och få grå, vi kan visa en färg som är på väg att bli lila utan att bara fullt lila. Vi kan även visa lite av varje färg, med övervikt på grön för att få en grågrön nyans.

bild3

Ju fler bitar vi avsätter för varje pixel, desto fler färger kan vi visa, men minnesåtgången blir såklart större. Och någonstans vid åtta bitar per färg, alltså 24 bitar, finns en bra kompromiss mellan minnesåtgång och bra återgivning. Det kan finnas anledningar att avsätta ännu fler bitar per pixel för den som vill göra avancerade manipulationer som drar ner bildens kvalité, så att man har en bild som tål att tappa kvalité utan att betraktaren märker något, men då drar man oftast ner bilden till 24 bitar när bilden är färdigmanipulerad och ska betraktas.

Nokia och SJ? Windows Phone och SJ?

Vissa som kör Windows Phone, särskilt de som kör Nokia, får erfara att det är omständligt för SJ att läsa SMS-biljetten automatiskt, om det ens går. SJ’s personal brukar spekulera om orsaken, mest i form av artighetskonversation, men ingen verkar ha koll. Är Nokias skärm för blank? Är bakgrundsfärgen fel? Svaret är valet av typsnitt.

SJ’s app letar efter en rektangel som består av fyra sifferrader. Beroende på vilka dessa siffror är, är inte marginalen alltid jämn, vilket syns på denna bild:

wp_ss_20150319_0002

En lösning på problemet skulle kunna vara att hålla ner fingret över SMS:biljetten så att context-menyn visas, välja att kopiera, och klistra in biljetten i OneNote, som av en händelse har ett typsnitt som visar alla siffror i samma bredd:

wp_ss_20150319_0001

Därför kan SJ läsa av biljetten på ett kick, om du först lägger den i OneNote.

Kom igång med C128 Assembler

Idag finns en hel del produkter för att utveckla program till Commodore 64 eller 128 på en modern PC, vilket är betydligt enklare än att göra det direkt på målmaskinen. Följ dessa steg för att komma igång med Assembler i Commodore 128.

1. Ladda hem Vice. Vice emulerar de flesta Commodore-maskinerna, vilket förutom C64/C128 även innefattar Pet, Vic 20 och Commodore +4.

2. Ladda hem CBM .prg Studio. Detta är en fullfjädrad integrerad utvecklingsmiljö för valfri Commodore-maskin.

3. Starta CBM .prg Studio. Välj Tools -> Options. Klicka på fliken Emulator Control. Bocka för C128 och peka C128-emulatorn från Vice (filen x128.exe).

4. Välj File -> New Project. Kryssa i C128, klicka Next. Vid Project Location, klicka Browse och välj var du vill spara din källkod. Därefter, klicka Next och Create.

5. I fönstret Project Explorer, högerklicka på Assembly Files och välj Add New File. Tillhandahåll ett filnamn med filändelsen .asm.

6. Det sista du måste göra för att komma igång, är att ange ditt programs startadress. Först i din .asm-fil, skriv:

*=$2000

Symbolen * representerar programmets start och $2000 är den hexadecimala representationen av 8192. Detta betyder alltså att ditt program startas med SYS 8192. När du väl börjar koda ditt program måste du tänka på att CBM .prg Studio antar att en indragning betyder att du vill göra en programsats. Låt säga att du vill förändra borderfärgen vars minnesadress är 53280 (D020 i hex), kan du skriva följande program (och notera indragningarna):

*=$2000
        inc $D020
        brk

Instruktionen inc ökar värdet med 1 på angiven minnesadress och brk avbryter programmet. Nu har du ett fungerande program. Öppna programmet genom att trycka på F5. Stäng fönstret som visar disassemblyn (Assembly Dump) och notera hur Vice visar en C128 med ditt program inläst i minnet. Om du vill kontrollera värdet av $D020, skriv:

PRINT PEEK(53280)

Notera värdet som står där, t.ex. 253. Starta ditt program genom att skriva:

SYS 8192

Och direkt därefter, tryck X följt av Enter för att lämna Commodore 128:ans maskinkodsmonitor. Eftersom programmet ökar värdet av 53280 med 1, borde borderfärgen nu vara ljusblå, eftersom ljusblå ligger som nästa färg efter ljusgrön. Och mycket riktigt, upprepa PRINT PEEK(53280) och konstatera att värdet har ökat med 1, till t.ex. 254.

bild1

Kör programmet igen genom att skriva SYS 8192 igen. Nu har vi ökat 53280 med 1 igen, vilket ger ljusgrå borderfärg. Om du vill kan du titta på disassemblyn innan du lämnar monitorn genom att skriva D2000 och sedan X.

bild2

När du är färdig kan du stänga emulatorn (eller emulatorerna) – en ny öppnas varje gång du kör programmet.

Introduktion till binär logik, del 2 av 2

Introduktion till binär logik, del 1 av 2

20 gems of the nineties

1. Extreme – Hole Hearted (1991)

2. Jellyfish – The King is Half-Undressed (1990)

3. Presley’s Band Cover Wet Wet Wet – Love is all around (1994) – (Live version)

4. Ten Sharp – “You” (1991)

5. Pink Floyd – High Hopes (1994) – (Live version)

6. Michael Jackson- In The Closet (1991)

7. Queen – The Show Must Go On (1991)

8. Sinéad O’Connor – Nothing Compares 2 U (1990)

9. R.E.M. – Losing My Religion (1991)

10. Pet Shop Boys – Being Boring (1990)

11. Roger Waters – Amused to Death (1992) – (Live versioninterview)

12. Metallica – Enter Sandman (1991)

13. Guns N’ Roses – You Could Be Mine (1991)

14. No Doubt – Don’t Speak (1996)

15. 4 Non Blondes – What’s Up (1993)

16. Adamski (feat. Seal) – Killer (1990)

17. Unholy – Kiss (1992) – (Live version)

18. Angel – Sommaren i City (1991)

19. Jamiroquai – Virtual Insanity (1996)

20. Babylon Zoo – Spaceman (1996)

Lorenz-attraktionen

Läs gärna min text om Loernz-attraktionen, med tillhörande PowerShell-implementation, på Humanistbloggen!

Uppdatering 2015-01-02: Jonas Elfström har översatt PowerShell-koden till Swift.

Färgpaletten i Acorn Electron

Acorn Electron kan förvisso visa 16 olika färger, men kan bara visa 8 olika nyanser. Dessa unika nyanser ligger på position 0 till 7 på färgpaletten.

0 – Svart
1 – Röd
2 – Grön
3 – Gul
4 – Blå
5 – Lila
6 – Turkos
7 – Vit

De resterande färgerna återanvänder dessa nyanser i blinkande form.

8 – Blinkande svart/vit
9 – Blinkande röd/turkos
10 – Blinkande grön/lila
11 – Blinkande gul/blå
12 – Blinkande blå/gul
13 – Blinkande lila/grön
14 – Blinkande turkos/röd
15 – Blinkande vit/svart

För att se hur blinkande svart/vit ser ut bredvid blinkande vit/svart, testa gärna detta program:

10 MODE 1
20 VDU 19, 0, 0, 0, 0, 0
30 VDU 19, 1, 8, 0, 0, 0
40 VDU 19, 2, 15, 0, 0, 0
50 GCOL 0, 1
60 MOVE 50, 50
70 DRAW 100, 50
80 GCOL 0, 2
90 MOVE 60, 60
100 DRAW 110, 60

Rad 10 anger 320 * 256 pixlar med fyra färger. Rad 20 anger att den virtuella färgen 0 betyder svart. Rad 30 anger att den virtuella färgen 1 betyder blinkande svart/vit. Rad 40 anger att den virtuella färgen 2 betyder blinkande vit/svart. Därefter (rad 50-70) ritas en kort horisontell linje i undre vänstra hörnet med färg 1 (blinkande svart/vit). Sist (rad 80-100) ritas en till kort horisontell linje strax ovanför till höger. Detta ger illusionen att linjen hoppar fram och tillbaka, eftersom när den ena är vit är den andra svart.

Den första nollan i GCOL (rad 50 eller rad 80) betyder att pixlarna ska ritas, men genom att sätta andra värden där, kan man använda logiska operationer på pixlarna, som t.ex. OR, AND, EOR eller INVERT. Den andra siffran i GCOL är val av logisk färg.

För att få bort de blinkande linjerna, rensa grafikminnet med kommandot CLG.

Grafiklägen i Acorn Electron

Vissa av er kanske minns Acorn Electron från 1983. På den tiden var PC-datorer både relativt dyra och oförmögna att visa grafik. Företaget Acorn hade en billigare maskin i sortementet, Electron, som kunde avsätta 20 kb för grafik, vilket kunde innebära monokrom grafik 640 * 256 pixlar, eller så mycket som 16 färger i lågupplöst läge (160 * 256 pixlar).

Acorn Electron  - Foto: Oscar Orallo

Acorn Electron – Foto: Oscar Orallo

Den som vill programmera sin Electron kan använda den inbyggda BBC Basic-tolken, där kommandot MODE 0 ger monokrom högupplöst grafik (första bilden) och MODE 2 ger lågupplöst grafik med 16 färger (andra bilden). Den som förväntar sig sexton olika nyanser kommer att bli besviken, och bör välja ett läge med färre färger – Electron kan bara visa 8 nyanser.

bild1

bild2

För den som inte är beredd offra tjugotusen bytes för grafik kan använda sin Electron i text only-läge (40 * 25 tecken) för endast 8 k genom att skriva MODE 6. Givet att du väljer läge 2 så kan du använda alla 16 färger, vilket tyvärr handlar om svart (0) röd (1), grön, gul, blå, lila, turkos och vit (7), samt blinkande svart/vit (8), röd/cyan (9), grön/lila, gul/blå och deras omvända (12-15). Om du inte tror mig, bör du köra detta program som använder 320 * 256 pixlar med 4 färger (läge 1):

10 MODE 1
20 VDU 19, 0, 9
30 PRINT "NU BLINKAR ROD OCH CYAN"
40 PRINT "TRYCK ENTER."
50 INPUT A$
60 VDU 19, 0, 14
70 PRINT "NU BLINKAR CYAN OCH ROD."

Inte nog med att detta program illustrerar det bisarra med att avsätta minne för bit-kombinationer som egentligen inte är speciellt unika, programmet belyser dessutom något som ser ut som en bugg.

Kommandot PRINT “TJOHEJ” ger utdatat TJOHEJ, såvida det inte föregås av VDU 19 – då tappar Electron bort tre bytes och ger HEJ, vilket illustreras av följande program, som förutom en massa vackra färger ger TJOHEJ och HEJ som utdata:

10 PRINT "TJOHEJ"
20 VDU 19, 0, 2
30 PRINT "TJOHEJ"

bild3

Detta beror på att även om du inte behöver fler parametrar, lyssnar VDU 19 efter ytterligare tre bytes, och tar vad den kan få. Man löser problemet t.ex. genom att fylla upp med nollor.

10 PRINT "TJOHEJ"
20 VDU 19, 0, 2, 0, 0, 0
30 PRINT "TJOHEJ"

Ovanstående kod ger verkligen TJOHEJ följt av TJOHEJ.

God Jul och Gott Nytt 2015

Word 5.5 under DosBox

DosBox är en DOS-emulator som fungerar under bl.a. Windows 8.1 som ger utmärkt stöd för att köra DOS-program i fönster eller i helskärmsläge (växla med Alt+Enter). Jag tror att det primära syftet är att kunna spela de gamla favoritspelen från 90-talet på sin moderna PC, men emulatorn öppnar även för andra tillämpningar.

Jag laddade hem Microsoft Word 5.5 för DOS, och placerade den packade filen i en undermapp till mappen jag använder som hårdisk i DOS, i mitt fall C:\DosBox\Word\word.exe. Tänk på att DosBox ska vara startad när du ändrar i filsystemet.

Med filen på plats kan man starta DosBox och göra mappen till sin C-disk genom följande kommando:

MOUNT C C:\DosBox

Sedan är det bara att skriva C: för att komma dit, och påbörja installationen. Installationen sker i två steg. Först ska Wd55_ben.exe köras, så att filerna packas upp. Därefter ska installationsprogrammet köras. Låt inte installationsprogrammet ändra i några inställningar eftersom DosBox redan styr upp allt som behöver styras upp.

Efter installationen märkte jag att muspekaren inte reagerade som den skulle, men efter att ha avslutat Word och DosBox, och sedan startat dem igen, har jag inte märkt av det felet. Sen är det bara att flyga in i inställningarna och göra önskvärda inställningar, och börja skriva. Mycket nöje!

För att hitta länken till installationsfilen Wd55_ben.exe, besök denna sida och sök reda på textstycket “If you just want to get your free Word for DOS, click this link and the almighty Microsoft download deity will cause it to appear on your PC”.

EaseUS Partition Master

If a hard disk partition suddenly disappears and shows up in Disk Manager as unallocated space, the program EaseUS Partition Master solve the problem. The program can repair the partition and assign a drive letter to it, so that your files become available again.

The program is free to use, but the installer would like to put a lot of junk in your computer. Also, the program will remain running after use, so remember to uninstall from the control panel when the program is no longer needed.

Installera GitHub på Windows

Dessa steg installerar GitHub på Windows 8.1, och sjösätter ett projekt.

1. Ladda hem GitHub för Windows.

2. Installera genom att köra GitHubSetup.exe.

3. Under tiden GitHub installerar, passa på att skaffa ett konto på github.com/join. När kontot är registrerat, måste det aktiveras.

4. När installationen är klar, logga in i klientapplikationen.

5. Ett repository motsvarar ett projekt. För att skapa ett repository, klicka på symbolen + i klientapplikationens dashboard, högst uppe till vänster. Ge projektet ett lämpligt namn, och välj var du vill ha källkodsfilerna lagrade. Därefter, klicka Create repository.

6. För att börja arbeta mot GitHub, skapa ett nytt Visual Studio-projekt inuti mappen som utgör ditt repository, alternativt flytta in ett existerande Visual Studio-projekt i mappen som utgör ditt repository.

7. GitHub reagerar genom att presentera texten Uncommitted changes. För att skicka filerna till GitHub, klicka Show bredvid texten Uncommited changes, fyll i fältet Summary och om så önskas även Description, och klicka Commit to master.

8. Publicera projektet genom att klicka Publish Repository längst uppe till höger, och sedan Publish [namn på repository].

9. Slutligen ska de övriga programmerarna anges. Öppna projektets hemsida genom att högerklicka på repositoryts namn till vänster, och välj View on GitHub.

10. På projektets hemsida klicka + uppe till höger och välj New collaborator. Fyll en annan programmerares användarnamn och klicka Add collaborator. Upprepa så många gånger som behövs.

Projektet är nu tillgängligt för de som pekats ut som collaborators.

SQL 2012 Dependency Browser

SQL 2012 Dependency Browser is a simple application for viewing what database objects that depends on a specific object, for example what tables that are used by a view.

Setup program for version 1.0 with build date 2014-11-24 can be downloaded using this link. Click here to download the executable only.

SQL 2012 Dependency Browser

Anropa en web service från PowerShell

För att sätta en servicereferens inne i Visual Studio måste man (numera) följa dessa steg:

1. Högerklicka på References i Solution Explorer, välj Add Service Reference.

2. Klicka på knappen Advanced.

3. Klicka på knappen Add Web Reference.

4. Ange sin URL, typiskt en asmx-fil i Microsoft-världen, och klicka Add Reference.

Som exempel finns en publik web service som konverterar mellan Celsius och Fahrenheit (och vise versa) på följande URL: http://www.w3schools.com/webservices/tempconvert.asmx

Därefter genereras en proxy, som kan användas inifrån projektet, t.ex. så här (i C#):

using (var x = new com.w3schools.www.TempConvert())
{
   Console.WriteLine(x.CelsiusToFahrenheit("20"));
}

I PowerShell har vi inte samma möjlighet att generera en proxy via att använda ett grafiskt användargränssnitt, men vi kan antingen utveckla en DLL-fil i C# och använda den från PowerShell, eller använda en CmdLet som heter New-WebServiceProxy. Detta skapar en proxy, och lagrar resultatet i $FtoC:

$FtoC = New-WebServiceProxy -Uri http://www.w3schools.com/webservices/tempconvert.asmx

Sedan är det bara att anropa:

$FtoC.CelsiusToFahrenheit("20")

Förhoppningsvis borde både PowerShell och C# vara överens om att 20 grader C är lika med 68 grader F.

Simple full screen support in Windows Forms

These simple steps lets you create a Windows Forms application with full screen support. I have changed the DoubleBuffered property to true for flicker free redrawing, StartPosition to Manual to be able to manage startup position in code and KeyPreview to true.

This code in the Load event handler will position the window and restore the fullscreen state.

var s = this.GetScreen();
this.Top = s.WorkingArea.Top + 40; this.Left = s.WorkingArea.Left + 40;
this.Width = s.WorkingArea.Width - 80; this.Height =
                                             s.WorkingArea.Height - 80;
if ((Application.UserAppDataRegistry.GetValue("Fullscreen",
                                         "false") as string) == "true")
   this.ToggleFullscreen();

This is the KeyDown event handler that will enable the user to press F11 or Alt+Enter to toggle fullscreen.

private void MainForm_KeyDown(object sender, KeyEventArgs e)
{
   if(((e.KeyCode == Keys.Enter) && e.Alt) || (e.KeyCode == Keys.F11))
      this.ToggleFullscreen();
}

The FormClosing event handler stores the screen state:

private void MainForm_FormClosing(object sender, FormClosingEventArgs e)
{
   if (this.FormBorderStyle ==
                        System.Windows.Forms.FormBorderStyle.Sizable)
      Application.UserAppDataRegistry.SetValue("Fullscreen", "false");
   else
      Application.UserAppDataRegistry.SetValue("Fullscreen", "true");
}

And here are the GetScreen and ToggleFullscreen functions:

private Screen GetScreen()
{
   var s = Screen.FromPoint(new Point((int)(this.Left + (this.Width / 2)),
                                    (int)(this.Top + (this.Height / 2))));
   return s ?? Screen.PrimaryScreen;
}

private void ToggleFullscreen()
{
   var s = this.GetScreen();
   if (this.FormBorderStyle ==
       System.Windows.Forms.FormBorderStyle.Sizable)
   {
      this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.None;
      this.Top = s.Bounds.Top;
      this.Left = s.Bounds.Left;
      this.Width = s.Bounds.Width;
      this.Height = s.Bounds.Height;
   }
   else
   {
      this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.Sizable;
      this.Top = s.WorkingArea.Top + 40; this.Left =
         s.WorkingArea.Left + 40;
      this.Width = s.WorkingArea.Width - 80; this.Height =
         s.WorkingArea.Height - 80;
   }
 }

Finally, the Resize event handler should invalidate the form, and the Paint event handler should contain the drawing instructions.

Vinylbekännelser 2012

Mellan januari och mars 2012 släppte Björn Johansson och jag tio avsnitt av musikpodden Vinylbekännelser. Ljudet är aningen överstyrt, och om vi återkommer med en ny säsong (vilket inte är omöjligt), så lovar vi att hålla en jämn och bra ljudkvalité. Jag hoppas att du upptäcker något nytt! Här finns en spellista med alla avsnitt (i omvänd ordning). Och här följer en lista över avsnitten från första säsongen:

Avsnitt 1 med Patsy Cline, Crossroad Jam, Alcazar och Björn Afzelius.

Avsnitt 2 med Karin Glenmark, Electric Banana Band, Roger Waters och George Michael.

Avsnitt 3 med Leo Sayer, Slade, Bros och Mireille Mathieu.

Avsnitt 4 med Anne-Marie David, Evan, Nova och Tose Proeski.

Avsnitt 5 med Pat Benatar, Patsy Cline, Boyzone och Pet Shop Boys.

Avsnitt 6 med Matt Monro, Ann Blyth & Vic Damone, Vaya Con Dios och Jellyfish.

Avsnitt 7 med Björn Skifs, Breathe, Janne Schaffer och Adolphson & Falk.

Avsnitt 8 med Dive, Tomas Dileva, Martika och Double Fantasy.

Avsnitt 9 med Kikki Danielsson, Mia Martini & Roberto Murolo, Planet P Project och The Knife.

Avsnitt 10 med Kim Wilde, Karin Glenmark, The Rescuers och Louis Armstrong.

Tre podcasts!

Det är ju dags för den årliga omröstningen till Podradiopriset.  Själv har jag givetvis lagt en röst på Radio Houdi som jag gör tillsammans med John Houdi. Jag har även röstat på Kvack, en skeptisk podcast som bl.a. görs av min vän David Björnfot. Men så måste jag nämna kategorin musik, där Commoflage är nominerad. Commoflage är en fenomenal podcast av Henrik Andersson som främst spelar remixad C64-musik.

10 excellent fifties / sixties covers

1. Phil Collins – A Groovy Kind of Love

This song was originally performed by Diane & Annita in the mid sixties, but Collins turned it to a huge hit in the eighties. I did not appreciate this back in the days, but now this song really takes me back to my teens.

2. Freddie Mercury – The Great Pretender

A shameless exploitation of this mid fifties song by The Platters, recorded just to show off Freddie Mercury´s excellent voice.

3. David Lee Roth – Just a gigolo

Extra points for all the references to other eighties videos. The song origins from a early 1900 piece by Roger A. Graham and Spencer Williams (“I Ain’t Got Nobody”) and were made famous by Louis Prima in the 1950’s.

4. Whitesnake – Day Tripper

The only thing you can depend on with Whitesnake, David Coverdale’s excellent vocals. At the beginning of their careers they did a cover of The Beatles Day Tripper (1966).

5. Fine Young Cannibals -Suspicious Minds

I really love the Fine Young Cannibals, but the original version (Elvis Presley 1969) gives tough competition.

6. Motley Crue – Helter Skelter

Originally performed by The Beatles in 1968, recorded by Motley Crue on the Shout at the Devil album from 1983.

7. Yes – Every Little Thing

Original by The Beatles (1964), covered by Yes in 1969. Great musical efforts!

8. Twisted Sister – Leader of the Pack

An excellent song by the very beautiful and talented Ellie Greenwich, first performed by The Shangri-Las in 1964.

9. Phil Collins – You Can’t Hurry Love

Excellent cover version of a classic Supremes song. Collins provides a very loving kind of satire in this version, quite similar to what you find in the Genesis song Jesus He Knows Me.

10. Michael Jackson – Come Together

This is the only Michael Jackson song that I genuinely like, probably because of my relation to the original song by The Beatles from 1969.

Sprite collision detection

The Commodore 128 has built in sprite collision detection, but since Commodore Basic 7.0 is so slow, it must be used with some care. To demonstrate this, I have used SPRDEF to create two masterpieces. This is sprite 1:

s1

And this is sprite 2, this is excellent:

s2

I want to demonstrate the level of detail of the collision detection by turning both sprites on at an overlapping position, but not and colliding position, and then read out the collision flags. If you are doing this on your own Commodore 128, you might want to adjust the positions if your sprites are not identical to mine.

s3

The image shows that the sprites share an overlapping position, but they do not collide. There are no overlapping pixels. Yet, the BUMP(1) function will return 3 in this situation. The value 3 means that flag 1 and 2 are turned on, indicating that sprite 1 and  2 are colliding, even though they just share position. However, the size of the sprite is determined by the smallest rectangle that include all pixels of the sprite, which is second best after pixel perfect collision detection.

Game programming in Commodore Basic 7 is futile. Despite this cheating, the sprites moves faster than the Basic interpreter can handle. To see this, you can make the sprites move towards each other, and their positions if they collide. You should see that not all collisions are acted upon.

s4

I will vote for me

We are about a month away from the election to the Swedish parliament, and as a liberal I was planning to go with Sweden’s only liberal party, The Pirate Party. However, since their current support is way under the required 4% and because of their resent support for the socialist idea of “citizen salary”, I am voting for myself. Anyone who gets two votes or more, must according to Swedish law be counted and accounted. So if my name shows up on the official election site, there is another one out there who has voted for me! 🙂

Färger på Vic 20

Här finns mina videos om retro computing.

5 pre-femenist videos

Some good songs with videos made before the feminist revolution.

5. Scorpions – Rhythm Of Love

4. Kiss – Take it off

3. Twinkle – Hello Hello

2. Alice Cooper – Poison

1. Günther – Ding Dong Song

Max objektorienterar

Se så enkelt det kan bli! Läs detta av Christian Engvall!

Max objektorienterar

Categories: General



En kopp kaffe!

Bjud mig på en kopp kaffe (20:-) som tack för bra innehåll!

Bjud på en kopp kaffe!

Om...

Kontaktuppgifter, med mera, finns här.

Följ mig

Twitter Instagram
GitHub RSS

Public Service

Folkbildning om public service.

Hem   |   linktr.ee/hesselbom   |   winsoft.se   |   80tal.se   |   Filmtips