diff --git a/README.md b/README.md
index 892af198fd60b87200647db4639f033123113e86..32f1ba5406e30f3fe51a672105ecf9e58aa58467 100644
--- a/README.md
+++ b/README.md
@@ -1,8 +1,10 @@
+<img src="illustrations/vipslogo_512.png" alt="VIPS Logo" height="250"/>
+
 # VIPS Documentation
 
 Tor-Einar Skog, NIBIO
 
-Last edit: 2022-09-22
+Last edit: 2023-02-21
 
 ## About this project
 Since VIPS consists of multiple subsystems, this project is a starting point for VIPS documentation, describing the system as a whole. Documentation to each subsystem is linked from here. 
diff --git a/illustrations/1000000000000231000000EA513D951D10FB401A.png b/illustrations/1000000000000231000000EA513D951D10FB401A.png
new file mode 100644
index 0000000000000000000000000000000000000000..f340ecc7275d9dedc76f6b723d540aa74ebb8545
Binary files /dev/null and b/illustrations/1000000000000231000000EA513D951D10FB401A.png differ
diff --git a/illustrations/100000000000023E00000127794CBD73893684FD.png b/illustrations/100000000000023E00000127794CBD73893684FD.png
new file mode 100644
index 0000000000000000000000000000000000000000..7d596b29914b61e050e025902228bb9159c9b6dc
Binary files /dev/null and b/illustrations/100000000000023E00000127794CBD73893684FD.png differ
diff --git a/illustrations/1000020100000133000000BB86A5F55961F51482.png b/illustrations/1000020100000133000000BB86A5F55961F51482.png
new file mode 100644
index 0000000000000000000000000000000000000000..8a5ac8bbb91ab1f92a6b81e4c119ba9150a6a97b
Binary files /dev/null and b/illustrations/1000020100000133000000BB86A5F55961F51482.png differ
diff --git a/illustrations/10000201000001C600000114CFEBC2611F68F805.png b/illustrations/10000201000001C600000114CFEBC2611F68F805.png
new file mode 100644
index 0000000000000000000000000000000000000000..5a617b04c92d01f32a8a4ba079fdc6b3146a8ee5
Binary files /dev/null and b/illustrations/10000201000001C600000114CFEBC2611F68F805.png differ
diff --git a/illustrations/1000020100000C87000003AB1EE1DCC0A9D89A5A.png b/illustrations/1000020100000C87000003AB1EE1DCC0A9D89A5A.png
new file mode 100644
index 0000000000000000000000000000000000000000..636bf7f3b206f709c94f4aa93175a065413d1b1f
Binary files /dev/null and b/illustrations/1000020100000C87000003AB1EE1DCC0A9D89A5A.png differ
diff --git a/illustrations/2000000200000141000000D2526EAC50AF7907D2.eps b/illustrations/2000000200000141000000D2526EAC50AF7907D2.eps
new file mode 100644
index 0000000000000000000000000000000000000000..28dbd2ff887463aabb804c632973336db2cdcfe0
--- /dev/null
+++ b/illustrations/2000000200000141000000D2526EAC50AF7907D2.eps
@@ -0,0 +1,905 @@
+%!PS-Adobe-3.0 EPSF-3.0
+%%Creator: GIMP PostScript file plugin V 1.17 by Peter Kirchgessner
+%%Title: LogoRundet_sh_med_farge.eps
+%%CreationDate: Fri Apr  1 14:48:54 2011
+%%DocumentData: Clean7Bit
+%%LanguageLevel: 2
+%%Pages: 1
+%%BoundingBox: 14 14 334 223
+%%EndComments
+%%BeginProlog
+% Use own dictionary to avoid conflicts
+10 dict begin
+%%EndProlog
+%%Page: 1 1
+% Translate for offset
+14.173228346456694 14.173228346456694 translate
+% Translate to begin of first scanline
+0 208.08000000000004 translate
+319.68000000000006 -208.08000000000004 scale
+% Image geometry
+444 289 8
+% Transformation matrix
+[ 444 0 0 289 0 0 ]
+% Strings to hold RGB-samples per scanline
+/rstr 444 string def
+/gstr 444 string def
+/bstr 444 string def
+{currentfile /ASCII85Decode filter /RunLengthDecode filter rstr readstring pop}
+{currentfile /ASCII85Decode filter /RunLengthDecode filter gstr readstring pop}
+{currentfile /ASCII85Decode filter /RunLengthDecode filter bstr readstring pop}
+true 3
+%%BeginData:        18257 ASCII Bytes
+colorimage
+JcC<$JcE^hJ,~>
+JcC<$JcE^hJ,~>
+JcC<$JcE^hJ,~>
+JcC<$JcE^hJ,~>
+JcC<$JcE^hJ,~>
+JcC<$JcE^hJ,~>
+JcC<$JcE^hJ,~>
+JcC<$JcE^hJ,~>
+JcC<$JcE^hJ,~>
+JcC<$JcE^hJ,~>
+JcC<$JcE^hJ,~>
+JcC<$JcE^hJ,~>
+JcC<$JcE^hJ,~>
+JcC<$JcE^hJ,~>
+JcC<$JcE^hJ,~>
+JcC<$JcE^hJ,~>
+JcC<$JcE^hJ,~>
+JcC<$JcE^hJ,~>
+JcC<$JcE^hJ,~>
+JcC<$JcE^hJ,~>
+JcC<$JcE^hJ,~>
+JcC<$JcE^hJ,~>
+JcC<$JcE^hJ,~>
+JcC<$JcE^hJ,~>
+JcC<$JcE^hJ,~>
+JcC<$JcE^hJ,~>
+JcC<$JcE^hJ,~>
+JcC<$JcE^hJ,~>
+JcC<$JcE^hJ,~>
+JcC<$JcE^hJ,~>
+JcC<$JcE^hJ,~>
+JcC<$JcE^hJ,~>
+JcC<$JcE^hJ,~>
+JcC<$JcE^hJ,~>
+JcC<$JcE^hJ,~>
+JcC<$JcE^hJ,~>
+JcC<$JcE^hJ,~>
+JcC<$JcE^hJ,~>
+JcC<$JcE^hJ,~>
+JcC<$JcE^hJ,~>
+JcC<$JcE^hJ,~>
+JcC<$JcE^hJ,~>
+JcC<$JcE^hJ,~>
+JcC<$JcE^hJ,~>
+JcC<$JcE^hJ,~>
+JcC<$JcE^hJ,~>
+JcC<$JcE^hJ,~>
+JcC<$JcE^hJ,~>
+JcC<$JcE^hJ,~>
+JcC<$JcE^hJ,~>
+JcC<$JcE^hJ,~>
+JcC<$JcE^hJ,~>
+JcC<$JcE^hJ,~>
+JcC<$JcE^hJ,~>
+JcC<$JcE^hJ,~>
+JcC<$JcE^hJ,~>
+JcC<$JcE^hJ,~>
+JcC<$JcE^hJ,~>
+JcC<$JcE^hJ,~>
+JcC<$JcE^hJ,~>
+JcC<$JcE^hJ,~>
+JcC<$JcE^hJ,~>
+JcC<$JcE^hJ,~>
+JcC<$JcE^hJ,~>
+JcC<$JcE^hJ,~>
+JcC<$JcE^hJ,~>
+JcC<$JcE^hJ,~>
+JcC<$JcE^hJ,~>
+JcC<$JcE^hJ,~>
+JcC<$JcE^hJ,~>
+JcC<$JcE^hJ,~>
+JcC<$JcE^hJ,~>
+JcC<$JcE^hJ,~>
+JcC<$JcE^hJ,~>
+JcC<$JcE^hJ,~>
+JcC<$JcE^hJ,~>
+JcC<$JcE^hJ,~>
+JcC<$JcE^hJ,~>
+JcC<$JcE^hJ,~>
+JcC<$JcE^hJ,~>
+JcC<$JcE^hJ,~>
+JcC<$JcE^hJ,~>
+JcC<$JcE^hJ,~>
+JcC<$JcE^hJ,~>
+JcC<$JcE^hJ,~>
+JcC<$JcE^hJ,~>
+JcC<$JcE^hJ,~>
+JcC<$JcE^hJ,~>
+JcC<$JcE^hJ,~>
+JcC<$JcE^hJ,~>
+JcC<$JcE^hJ,~>
+JcC<$JcE^hJ,~>
+JcC<$JcE^hJ,~>
+JcC<$JcE^hJ,~>
+JcC<$JcE^hJ,~>
+JcC<$JcE^hJ,~>
+JcC<$JcE^hJ,~>
+JcC<$JcE^hJ,~>
+JcC<$JcE^hJ,~>
+JcC<$JcE^hJ,~>
+JcC<$JcE^hJ,~>
+JcC<$JcE^hJ,~>
+JcC<$JcE^hJ,~>
+JcC<$JcE^hJ,~>
+JcC<$JcE^hJ,~>
+JcC<$JcE^hJ,~>
+JcC<$JcE^hJ,~>
+JcC<$JcE^hJ,~>
+JcC<$JcE^hJ,~>
+JcC<$JcE^hJ,~>
+JcC<$JcE^hJ,~>
+JcC<$JcE^hJ,~>
+JcC<$JcE^hJ,~>
+JcC<$JcE^hJ,~>
+JcC<$JcE^hJ,~>
+JcC<$JcE^hJ,~>
+JcC<$JcE^hJ,~>
+JcC<$JcE^hJ,~>
+JcC<$JcE^hJ,~>
+JcC<$JcE^hJ,~>
+JcC<$JcE^hJ,~>
+JcC<$JcE^hJ,~>
+JcC<$JcE^hJ,~>
+JcC<$JcE^hJ,~>
+JcC<$JcE^hJ,~>
+JcC<$JcE^hJ,~>
+JcC<$JcE^hJ,~>
+JcC<$JcE^hJ,~>
+JcC<$JcE^hJ,~>
+JcC<$JcE^hJ,~>
+JcC<$JcE^hJ,~>
+JcC<$JcE^hJ,~>
+JcC<$JcE^hJ,~>
+JcC<$JcE^hJ,~>
+JcC<$JcE^hJ,~>
+JcC<$JcE^hJ,~>
+JcC<$JcE^hJ,~>
+JcC<$JcE^hJ,~>
+JcC<$JcE^hJ,~>
+JcC<$JcE^hJ,~>
+JcC<$JcE^hJ,~>
+JcC<$JcE^hJ,~>
+JcC<$JcE^hJ,~>
+JcC<$JcE^hJ,~>
+JcDYJoK@d*XT*e~>
+JcDYJoRDGlXT*e~>
+JcDYJoML2>XT*e~>
+JcDqRjZS1pZi>O~>
+JcDqRjaVj]Zi>O~>
+JcDqRj\^U/Zi>O~>
+JcE%Ui]VkmZi>O~>
+JcE%UidZOZZi>O~>
+JcE%Ui_b:,Zi>O~>
+JcE1Yh`ZPjZN#F~>
+JcE1Yhg^4WZN#F~>
+JcE1Yhbet)ZN#F~>
+JcE7[hE?GiZ2]=~>
+JcE7[hLC+VZ2]=~>
+JcE7[hGJk(Z2]=~>
+JcE=]h*$>hYlB4~>
+JcE=]h1("UYlB4~>
+JcE=]h,/b'YlB4~>
+JcEC_gHC,fYlB4~>
+JcEC_gOFeSYlB4~>
+JcEC_gJNP%YlB4~>
+JcEIag-(#eYQ'+~>
+JcEIag4+\RYQ'+~>
+JcEIag/3G$YQ'+~>
+JcELbg-(#eY5a"~>
+JcELbg4+\RY5a"~>
+JcELbg/3G$Y5a"~>
+JcEOcg-(#eXoEn~>
+JcEOcg4+\RXoEn~>
+JcEOcg/3G$XoEn~>
+JcERdffaodXoEn~>
+JcERdfmeSQXoEn~>
+JcERdfhm>#XoEn~>
+JcEUeffaodXT*e~>
+JcEUefmeSQXT*e~>
+JcEUefhm>#XT*e~>
+JcEXfffaodX8d\~>
+JcEXffmeSQX8d\~>
+JcEXffhm>#X8d\~>
+JcE[gffaodWrIS~>
+JcE[gfmeSQWrIS~>
+JcE[gfhm>#WrIS~>
+JcE^hfKFfcWrIS~>
+JcE^hfRJJPWrIS~>
+JcE^hfMR5"WrIS~>
+JcEaifKFfcWW.J~>
+JcEaifRJJPWW.J~>
+JcEaifMR5"WW.J~>
+JcEdjfKFfcW;hA~>
+JcEdjfRJJPW;hA~>
+JcEdjfMR5"W;hA~>
+JcEgkf0+]bW;hA~>
+JcEgkf7/AOW;hA~>
+JcEgkf27,!W;hA~>
+JcEgkfKFfcVuM8~>
+JcEgkfRJJPVuM8~>
+JcEgkfMR5"VuM8~>
+JcEjlfKFfcVZ2/~>
+JcEjlfRJJPVZ2/~>
+JcEjlfMR5"VZ2/~>
+JcEmmfKFfcV>l&~>
+JcEmmfRJJPV>l&~>
+JcEmmfMR5"V>l&~>
+JcEpnf0+]bV>l&~>
+JcEpnf7/AOV>l&~>
+JcEpnf27,!V>l&~>
+JcEpnfKFfcV#Pr~>
+JcEpnfRJJPV#Pr~>
+JcEpnfMR5"V#Pr~>
+JcEsofKFfcU]5i~>
+JcEsofRJJPU]5i~>
+JcEsofMR5"U]5i~>
+JcF!pfKFfcUAo`~>
+JcF!pfRJJPUAo`~>
+JcF!pfMR5"UAo`~>
+JcF!pfKFfcUAo`~>
+JcF!pfRJJPUAo`~>
+JcF!pfMR5"UAo`~>
+JcF$qfKFfcU&TW~>
+JcF$qfRJJPU&TW~>
+JcF$qfMR5"U&TW~>
+JcF'rfKFfcT`9N~>
+JcF'rfRJJPT`9N~>
+JcF'rfMR5"T`9N~>
+JcF*sfKFfcTDsE~>
+JcF*sfRJJPTDsE~>
+JcF*sfMR5"TDsE~>
+JcF*sfKFfcTDsE~>
+JcF*sfRJJPTDsE~>
+JcF*sfMR5"TDsE~>
+JcF-tfKFfcT)X<~>
+JcF-tfRJJPT)X<~>
+JcF-tfMR5"T)X<~>
+JcF0ufKFfcSc=3~>
+JcF0ufRJJPSc=3~>
+JcF0ufMR5"Sc=3~>
+JcF4!fKFfcSH"*~>
+JcF4!fRJJPSH"*~>
+JcF4!fMR5"SH"*~>
+JcF4!fKFfcSH"*~>
+JcF4!fRJJPSH"*~>
+JcF4!fMR5"SH"*~>
+JcF7"fKFfcS,\!~>
+JcF7"fRJJPS,\!~>
+JcF7"fMR5"S,\!~>
+JcF:#fKFfcRf@m~>
+JcF:#fRJJPRf@m~>
+JcF:#fMR5"Rf@m~>
+JcF:#ffaodRK%d~>
+JcF:#fmeSQRK%d~>
+JcF:#fhm>#RK%d~>
+JcF=$fKFfcRK%d~>
+JcF=$fRJJPRK%d~>
+JcF=$fMR5"RK%d~>
+JcF@%fKFfcR/_[~>
+JcF@%fRJJPR/_[~>
+JcF@%fMR5"R/_[~>
+JcFC&fKFfcQiDR~>
+JcFC&fRJJPQiDR~>
+JcFC&fMR5"QiDR~>
+JcFC&ffaodQN)I~>
+JcFC&fmeSQQN)I~>
+JcFC&fhm>#QN)I~>
+JcFF'fKFfcQN)I~>
+JcFF'fRJJPQN)I~>
+JcFF'fMR5"QN)I~>
+JcFI(fKFfcQ2c@~>
+JcFI(fRJJPQ2c@~>
+JcFI(fMR5"Q2c@~>
+JcFI(ffaodPlH7~>
+JcFI(fmeSQPlH7~>
+JcFI(fhm>#PlH7~>
+JcFL)ffaodPQ-.~>
+JcFL)fmeSQPQ-.~>
+JcFL)fhm>#PQ-.~>
+JcFO*fKFfcPQ-.~>
+JcFO*fRJJPPQ-.~>
+JcFO*fMR5"PQ-.~>
+JcFR+fKFfcP5g%~>
+JcFR+fRJJPP5g%~>
+JcFR+fMR5"P5g%~>
+JcFR+ffaodOoKq~>
+JcFR+fmeSQOoKq~>
+JcFR+fhm>#OoKq~>
+JcFU,ffaodOT0h~>
+JcFU,fmeSQOT0h~>
+JcFU,fhm>#OT0h~>
+JcFX-fKFfcOT0h~>
+JcFX-fRJJPOT0h~>
+JcFX-fMR5"OT0h~>
+JcF[.fKFfcO8j_~>
+JcF[.fRJJPO8j_~>
+JcF[.fMR5"O8j_~>
+JcF[.ffaodNrOV~>
+JcF[.fmeSQNrOV~>
+JcF[.fhm>#NrOV~>
+JcF^/fKFfcNrOV~>
+JcF^/fRJJPNrOV~>
+JcF^/fMR5"NrOV~>
+JcFa0fKFfcNW4M~>
+JcFa0fRJJPNW4M~>
+JcFa0fMR5"NW4M~>
+JcFa0ffaodN;nD~>
+JcFa0fmeSQN;nD~>
+JcFa0fhm>#N;nD~>
+JcFd1ffaodMuS;~>
+JcFd1fmeSQMuS;~>
+JcFd1fhm>#MuS;~>
+JcFg2fKFfcMuS;~>
+JcFg2fRJJPMuS;~>
+JcFg2fMR5"MuS;~>
+JcFj3fKFfcMZ82~>
+JcFj3fRJJPMZ82~>
+JcFj3fMR5"MZ82~>
+JcFj3ffaodM>r)~>
+JcFj3fmeSQM>r)~>
+JcFj3fhm>#M>r)~>
+JcFm4ffaodM#Vu~>
+JcFm4fmeSQM#Vu~>
+JcFm4fhm>#M#Vu~>
+JcFp5fKFfcM#Vu~>
+JcFp5fRJJPM#Vu~>
+JcFp5fMR5"M#Vu~>
+JcFp5ffaodL];l~>
+JcFp5fmeSQL];l~>
+JcFp5fhm>#L];l~>
+JcF[.iB;blLAuc~>
+JcF[.iI?FYLAuc~>
+JcF[.iDG1+LAuc~>
+JcFR+jZS1pL&ZZ~>
+JcFR+jaVj]L&ZZ~>
+JcFR+j\^U/L&ZZ~>
+JcFL)k<4CrL&ZZ~>
+JcFL)kC8'_L&ZZ~>
+JcFL)k>?g1L&ZZ~>
+JcFF'l90^uK`?Q~>
+JcFF'l@4BbK`?Q~>
+JcFF'l;<-4K`?Q~>
+JcFC&lofq"KE$H~>
+JcFC&m!jTdKE$H~>
+JcFC&lqr?6KE$H~>
+JcF@%mQH.$K)^?~>
+JcF@%mXKffK)^?~>
+JcF@%mSSQ8K)^?~>
+JcF:#n3)@&K)^?~>
+JcF:#n:-#hK)^?~>
+JcF:#n54c:K)^?~>
+JcF:#nNDI'JcC6~>
+JcF:#nUH,iJcC6~>
+JcF:#nPOl;JcC6~>
+!<;LNJcFp5o0%[)l2SO^g&HR~>
+!<;M;JcFp5o7)>kl2SPKg&HR~>
+!<;LbJcFp5o21)=l2SOrg&HR~>
+!<;4FJcG0<V*2QmZT[7HJ,~>
+!<;53JcG0<V165ZZ[^p5J,~>
+!<;4ZJcG0<V,=u,ZVfZ\J,~>
+s8V.CJcG9?T0:<rX$,PDJ,~>
+s8V/0JcG9?T7=u_X+041J,~>
+s8V.WJcG9?T2E`1X&7sXJ,~>
+rr;"AJcG?AS3>0tVEO,BJ,~>
+rr;#.JcG?AS:AiaVLRe/J,~>
+rr;"UJcG?AS5IT3VGZOVJ,~>
+rr:n>JcGECRm#4"U-7c@J,~>
+rr:o+JcGECRt&ldU4;G-J,~>
+rr:nRJcGECRo.W6U/C1TJ,~>
+rVtb<JcGHDR6B1%SiuE>J,~>
+rVtc)JcGHDR=EigSq$)+J,~>
+rVtbPJcGHDR8MT9Sl+hRJ,~>
+r;YV:JcGNFQTa(&Rm$0=J,~>
+r;YW'JcGNFQ[d`hRt'i*J,~>
+r;YVNJcGNFQVlK:Ro/SQJ,~>
+r;YS9JcGQGQ9F%'R6C!<J,~>
+r;YT&JcGQGQ@I]iR=FZ)J,~>
+r;YSMJcGQGQ;QH;R8NDPJ,~>
+qu>G7JcGTHPs+%)QTag;J,~>
+qu>H$JcGTHQ%.]kQ[eK(J,~>
+qu>GKJcGTHPu6H=QVm5OJ,~>
+qZ#>6JcGWIPWe"*Ps+X:J,~>
+qZ#?#JcGWIP^hZlQ%/<'J,~>
+qZ#>JJcGWIPYpE>Pu7&NJ,~>
+qZ#;5JcGZJP!.n+P<JI9J,~>
+qZ#<"JcGZJP(2QmPCN-&J,~>
+qZ#;IJcGZJP#:<?P>UlMJ,~>
+q>]24JcGZJP!.t-OZi:8J,~>
+q>]3!JcGZJP(2WoOals%J,~>
+q>]2HJcGZJP#:BAO\t]LJ,~>
+q#B&2JcG`LOZhq.O$3+7J,~>
+q#B&tJcG`LOalTpO+6d$J,~>
+q#B&FJcG`LO\t?BO&>NKJ,~>
+q#B&2JcG`LOZhq.O$3+7J,~>
+q#B&tJcG`LOalTpO+6d$J,~>
+q#B&FJcG`LO\t?BO&>NKJ,~>
+p]&r1JcGcMO?Mn/NBQq6J,~>
+p]&rsJcGcMOFQQqNIUU#J,~>
+p]&rEJcGcMOAY<CND]?JJ,~>
+pA`i0Jc>`MO$2k0M`pb5J,~>
+pA`irJc>`MO+6NrMgtF"J,~>
+pA`iDJc>`MO&>9DMc'0IJ,~>
+p&E`/JcC`nmJi)-p&BO~>
+p&E`qJcCa[mJi)op&BO~>
+p&E`CJcCa-mJi)Ap&BO~>
+p&E].K)^fnn,J8.p&BO~>
+p&E]pK)^g[n,J8pp&BO~>
+p&E]BK)^g-n,J8Bp&BO~>
+o`*T-K`?rnnGe>.pA]X~>
+o`*ToK`?s[nGe>ppA]X~>
+o`*TAK`?s-nGe>BpA]X~>
+oDdN-K`?rnnGe>.pA]X~>
+oDdNoK`?s[nGe>ppA]X~>
+oDdNAK`?s-nGe>BpA]X~>
+oDdK,L&[#no)FM/pA]X~>
+oDdKnL&[$[o)FMqpA]X~>
+oDdK@L&[$-o)FMCpA]X~>
+o)IB+LB!,oo)FM/pA]X~>
+o)IBmLB!-\o)FMqpA]X~>
+o)IB?LB!-.o)FMCpA]X~>
+nc.<+LB!)noDaV0pA]X~>
+nc.<mLB!*[oDaVrpA]X~>
+nc.<?LB!*-oDaVDpA]X~>
+nc.9*\,QFke,P1dp&Bb0p]#a~>
+nc.9l\,QGXe,P2Qp&Bbrp]#a~>
+nc.9>\,QG*e,P2#p&BbDp]#a~>
+nGh0)\c;XleGk:ep&Bb0p]#a~>
+nGh0k\c;YYeGk;Rp&Bbrp]#a~>
+nGh0=\c;Y+eGk;$p&BbDp]#a~>
+n,M*)])V[kf)LFepA]k1p]#a~>
+n,M*k])V\Xf)LGRpA]ksp]#a~>
+n,M*=])V\*f)LG$pA]kEp]#a~>
+n,M'(]`7jlf)LFepA]k1p]#a~>
+n,M'j]`7kYf)LGRpA]ksp]#a~>
+n,M'<]`7k+f)LG$pA]kEp]#a~>
+mf1s'^&Rplf`-Req#?%2p]#a~>
+mf1si^&RqYf`-SRq#?%tp]#a~>
+mf1s;^&Rq+f`-S$q#?%Fp]#a~>
+mJkm'^An!lf`-Req#?%2p]#a~>
+mJkmi^An"Yf`-SRq#?%tp]#a~>
+mJkm;^An"+f`-S$q#?%Fp]#a~>
+m/Pd&_#O-lgAcafq#?%2p]#a~>
+m/Pdh_#O.YgAcbSq#?%tp]#a~>
+m/Pd:_#O.+gAcb%q#?%Fp]#a~>
+m/Pa%_Z09lOoNTfq>]G;Rf@m~>
+m/Pag_Z0:YOoNUSq>]H(Rf@m~>
+m/Pa9_Z0:+OoNU%q>]GORf@m~>
+li5[%_uK<kM>u'gq>]J<RK%d~>
+li5[g_uK=XM>u(Tq>]K)RK%d~>
+li5[9_uK=*M>u(&q>]JPRK%d~>
+lMoR$`;fBki;`g?WrL[6q>]M=R/_[~>
+lMoRf`;fCXi;`h,WrL\#q>]N*R/_[~>
+lMoR8`;fC*i;`gSWrL[Jq>]MQR/_[~>
+lMoO#`rGNkirB!@VZ5@5qZ#Y?QiDR~>
+lMoOe`rGOXirB"-VZ5A"qZ#Z,QiDR~>
+lMoO7`rGO*irB!TVZ5@IqZ#YSQiDR~>
+l2TI#a8bQjjo>6AV>o:5qZ#Y?QiDR~>
+l2TIea8bRWjo>7.V>o;"qZ#Z,QiDR~>
+l2TI7a8bR)jo>6UV>o:IqZ#YSQiDR~>
+kl9@"aoCZikl:NCU]9.5qZ#Y?QiDR~>
+kl9@daoC[Vkl:O0U]9/"qZ#Z,QiDR~>
+kl9@6aoC[(kl:NWU]9.IqZ#YSQiDR~>
+kl9=!b5^]hm/QlEUAs%4qu>eAQN)I~>
+kl9=cb5^^Um/Qm2UAs&!qu>f.QN)I~>
+kl9=5b5^^'m/QlYUAs%Hqu>eUQN)I~>
+kPs7!bQ$]fnGi5GU&Wt4qu>eAQN)I~>
+kPs7cbQ$^SnGi64U&Wu!qu>f.QN)I~>
+kPs75bQ$^%nGi5[U&WtHqu>eUQN)I~>
+k5X-uc2Zcdq#BnJT`<n4qu>eAQN)I~>
+k5X.bc2ZdQq#Bo7T`<o!qu>f.QN)I~>
+k5X.4c2Zd#q#Bn^T`<nHqu>eUQN)I~>
+k5X*tci;*MTE!h4qu>eAQN)I~>
+k5X+aci;+:TE!i!qu>f.QN)I~>
+k5X+3ci;*aTE!hHqu>eUQN)I~>
+jo=$tci;*MTE!e3r;YnBQN)I~>
+jo=%aci;+:TE!eur;Yo/QN)I~>
+jo=%3ci;*aTE!eGr;YnVQN)I~>
+jT!psdJq9NT)[_3r;YkAQiDR~>
+jT!q`dJq:;T)[_ur;Yl.QiDR~>
+jT!q2dJq9bT)[_Gr;YkUQiDR~>
+j8[gre,RHOT)[_3r;YkAQiDR~>
+j8[h_e,RI<T)[_ur;Yl.QiDR~>
+j8[h1e,RHcT)[_Gr;YkUQiDR~>
+j8[greGmNOSc@Y3r;YkAQiDR~>
+j8[h_eGmO<Sc@Yur;Yl.QiDR~>
+j8[h1eGmNcSc@YGr;YkUQiDR~>
+ir@^qec3WPSc@Y3r;Yh@R/_[~>
+ir@_^ec3X=Sc@Yur;Yi-R/_[~>
+ir@_0ec3WdSc@YGr;YhTR/_[~>
+iW%UpfDifQSc@Y3r;Ye?RK%d~>
+iW%V]fDig>Sc@Yur;Yf,RK%d~>
+iW%V/fDifeSc@YGr;YeSRK%d~>
+iW%Upf`/lQSc@V2rVth>S,\!~>
+iW%V]f`/m>Sc@VtrVti+S,\!~>
+iW%V/f`/leSc@VFrVthRS,\!~>
+i;_LogAf&RSH%P2rVtV8U&TW~>
+i;_M\gAf'?SH%PtrVtW%U&TW~>
+i;_M.gAf&fSH%PFrVtVLU&TW~>
+huDCnh#G5SSH%P2rVsi"\,Us~>
+huDD[h#G6@SH%PtrVsid\,Us~>
+huDD-h#G5gSH%PFrVsi6\,Us~>
+huDCnh#G5SSH%P2rVrcYec1.~>
+huDD[h#G6@SH%PtrVrdFec1.~>
+huDD-h#G5gSH%PFrVrcmec1.~>
+hZ):mhZ(DTSH%P2rVr!Cli2J~>
+hZ);ZhZ(EASH%PtrVr"0li2J~>
+hZ);,hZ(DhSH%PFrVr!Wli2J~>
+h>c1li;^SUSH%P2rVqg>nGe"~>
+h>c2Yi;^TBSH%PtrVqh+nGe"~>
+h>c2+i;^SiSH%PFrVqgRnGe"~>
+h#H+liW$YUSH%P2rVqa<o)F4~>
+h#H,YiW$ZBSH%PtrVqb)o)F4~>
+h#H,+iW$YiSH%PFrVqaPo)F4~>
+h#H(kir?bVSH%P2rVq[:o`'F~>
+h#H)Xir?cCSH%PtrVq\'o`'F~>
+h#H)*ir?bjSH%PFrVq[No`'F~>
+g],tjjSuqWSH%P2rVqU8pA]X~>
+g],uWjSurDSH%PtrVqV%pA]X~>
+g],u)jSuqkSH%PFrVqULpA]X~>
+gAfnjjo<"WSH%P2r;VL7p]#a~>
+gAfoWjo<#DSH%Ptr;VM$p]#a~>
+gAfo)jo<"kSH%PFr;VLKp]#a~>
+gAfkikPr1XSH%P2r;VI6q#>j~>
+gAflVkPr2ESH%Ptr;VJ#q#>j~>
+gAfl(kPr1lSH%PFr;VIJq#>j~>
+g&Kbhkl8:YSH%M1rVqO6q>Ys~>
+g&KcUkl8;FSH%MsrVqP#q>Ys~>
+g&Kc'kl8:mSH%MErVqOJq>Ys~>
+f`0\hl2S@YSH%M1rVqL5qYu'~>
+f`0]Ul2SAFSH%MsrVqM"qYu'~>
+f`0]'l2S@mSH%MErVqLIqYu'~>
+f`0Ygli4OZSH%M1rVqI4qu;0~>
+f`0ZTli4PGSH%MsrVqJ!qu;0~>
+f`0Z&li4OnSH%MErVqIHqu;0~>
+fDjPfmJj^[SH%M1rVqI4qu;0~>
+fDjQSmJj_HSH%MsrVqJ!qu;0~>
+fDjQ%mJj^oSH%MErVqIHqu;0~>
+f)OJfmf0d[SH%M1r;V@3r;V9~>
+f)OKSmf0eHSH%Msr;V@ur;V9~>
+f)OK%mf0doSH%MEr;V@Gr;V9~>
+f)OGen,Km\SH%M1r;V=2rVqB~>
+f)OHRn,KnISH%Msr;V=trVqB~>
+f)OH$n,KmpSH%MEr;V=FrVqB~>
+ec4>dnc.6)!<;"@SH%M1r;V=2rVqB~>
+ec4?Qnc.6k!<;#-SH%Msr;V=trVqB~>
+ec4?#nc.6=!<;"TSH%MEr;V=FrVqB~>
+eGn8do)I<)!<;"@SH%M1qu;72rVqB~>
+eGn9Qo)I<k!<;#-SH%Msqu;7trVqB~>
+eGn9#o)I<=!<;"TSH%MEqu;7FrVqB~>
+e,S/co`*N+s8V%@SH%M1qu;41rr7K~>
+e,S0Po`*Nms8V&-SH%Msqu;4srr7K~>
+e,S0"o`*N?s8V%TSH%MEqu;4Err7K~>
+e,S,bp&EZ-rr:q?SH%M1qYu.1rr7K~>
+e,S-Op&EZorr:r,SH%MsqYu.srr7K~>
+e,S-!p&EZArr:qSSH%MEqYu.Err7K~>
+df8&bpA`c.rVth>SH%M1qYu+0s8RT~>
+df8'OpA`cprVti+SH%MsqYu+rs8RT~>
+df8'!pA`cBrVthRSH%MEqYu+Ds8RT~>
+dJqraq#Ar/rVth>SH%M1q>Z%0s8RT~>
+dJqsNq#ArqrVti+SH%Msq>Z%rs8RT~>
+dJqruq#ArCrVthRSH%MEq>Z%Ds8RT~>
+dJqo`qZ#/1r;Y_=SH%M1q>Z%0s8RT~>
+dJqpMqZ#/sr;Y`*SH%Msq>Z%rs8RT~>
+dJqotqZ#/Er;Y_QSH%MEq>Z%Ds8RT~>
+d/Vi`qZ#22qu>V<SH%M1q#>q/!<7Q~>
+d/VjMqZ#2tqu>W)SH%Msq#>qq!<7Q~>
+d/VitqZ#2Fqu>VPSH%MEq#>qC!<7Q~>
+ci;`_r;YD4qZ#M;SH%M1p]#k/!<7Q~>
+ci;aLr;YE!qZ#N(SH%Msp]#kq!<7Q~>
+ci;`sr;YDHqZ#MOSH%MEp]#kC!<7Q~>
+ci;]^rr:S5qZ#M;SH%M1pA]e/!<7Q~>
+ci;^Krr:T"qZ#N(SH%MspA]eq!<7Q~>
+ci;]rrr:SIqZ#MOSH%MEpA]eC!<7Q~>
+cMuW^s8U\6q>]D:SH%M1p&B_/!<7Q~>
+cMuXKs8U]#q>]E'SH%Msp&B_q!<7Q~>
+cMuWrs8U\Jq>]DNSH%MEp&B_C!<7Q~>
+c2Y%3q#B;9SH%M1o)FM/!<7Q~>
+c2Y%uq#B<&SH%Mso)FMq!<7Q~>
+c2Y%Gq#B;MSH%MEo)FMC!<7Q~>
+c2Y(4p]'28SH%P2n,J5-J,~>
+c2Y)!p]'3%SH%Ptn,J5oJ,~>
+c2Y(Hp]'2LSH%PFn,J5AJ,~>
+bl>"4p]'28SH%P2li2r-J,~>
+bl>#!p]'3%SH%Ptli2roJ,~>
+bl>"Hp]'2LSH%PFli2rAJ,~>
+bQ"t5pAa)7SH%P2gAda-J,~>
+bQ"u"pAa*$SH%PtgAdaoJ,~>
+bQ"tIpAa)KSH%PFgAdaAJ,~>
+b5\q6p&Eu6SH%P2^Akc-J,~>
+b5\r#p&F!#SH%Pt^AkcoJ,~>
+b5\qJp&EuJSH%PF^AkcAJ,~>
+b5\t7o`*l5SH%P2UAre-J,~>
+b5\u$o`*m"SH%PtUAreoJ,~>
+b5\tKo`*lISH%PFUAreAJ,~>
+aoAn7o`*l5SH%P2QiH#-J,~>
+aoAo$o`*m"SH%PtQiH#oJ,~>
+aoAnKo`*lISH%PFQiH#AJ,~>
+aT&k8oDdc4SH%P2PlKf-J,~>
+aT&l%oDdd!SH%PtPlKfoJ,~>
+aT&kLoDdcHSH%PFPlKfAJ,~>
+aT&n9o)IZ3SH%P2PQ0`-J,~>
+aT&o&o)IZuSH%PtPQ0`oJ,~>
+aT&nMo)IZGSH%PFPQ0`AJ,~>
+a8`k:nc.Q2Sc@V2P5jZ-J,~>
+a8`l'nc.QtSc@VtP5jZoJ,~>
+a8`kNnc.QFSc@VFP5jZAJ,~>
+`rEe:nc.Q2Sc@V2P5jZ-J,~>
+`rEf'nc.QtSc@VtP5jZoJ,~>
+`rEeNnc.QFSc@VFP5jZAJ,~>
+`rEh;nGhH1Sc@V2OoOT-J,~>
+`rEi(nGhHsSc@VtOoOToJ,~>
+`rEhOnGhHESc@VFOoOTAJ,~>
+`W*e<n,M?0Sc@V2OoOT-J,~>
+`W*f)n,M?rSc@VtOoOToJ,~>
+`W*ePn,M?DSc@VFOoOTAJ,~>
+`;db=mf26/Sc@V2OoOT-J,~>
+`;dc*mf26qSc@VtOoOToJ,~>
+`;dbQmf26CSc@VFOoOTAJ,~>
+`;db=mf26/T)[\2OoOT-J,~>
+`;dc*mf26qT)[\tOoOToJ,~>
+`;dbQmf26CT)[\FOoOTAJ,~>
+_uI_>mJl-.TE!e3OT4K,J,~>
+_uI`+mJl-pTE!euOT4KnJ,~>
+_uI_RmJl-BTE!eGOT4K@J,~>
+_Z.\?m/Q$-TE!e3OT4K,J,~>
+_Z.],m/Q$oTE!euOT4KnJ,~>
+_Z.\Sm/Q$ATE!eGOT4K@J,~>
+_>hV?m/Q$-T`<k3OT4K,J,~>
+_>hW,m/Q$oT`<kuOT4KnJ,~>
+_>hVSm/Q$AT`<kGOT4K@J,~>
+_>hY@li5p,U&Wq3OT4K,J,~>
+_>hZ-li5pnU&WquOT4KnJ,~>
+_>hYTli5p@U&WqGOT4K@J,~>
+_#MVAlMog+UAs"3OT4K,J,~>
+_#MW.lMogmUAs"uOT4KnJ,~>
+_#MVUlMog?UAs"GOT4K@J,~>
+^]2SBl2T^*V#T.3OT4K,J,~>
+^]2T/l2T^lV#T.uOT4KnJ,~>
+^]2SVl2T^>V#T.GOT4K@J,~>
+^]2SBl2T^*V>o43OoOQ,J,~>
+^]2T/l2T^lV>o4uOoOQnJ,~>
+^]2SVl2T^>V>o4GOoOQ@J,~>
+^AlPCkl9U)W;kF3OoOQ,J,~>
+^AlQ0kl9UkW;kFuOoOQnJ,~>
+^AlPWkl9U=W;kFGOoOQ@J,~>
+^&QMDkPsL(XT-a4OoON+J,~>
+^&QN1kPsLjXT-b!OoONmJ,~>
+^&QMXkPsL<XT-aHOoON?J,~>
+^&QPEk5XC'ZiA64PlK`+J,~>
+^&QQ2k5XCiZiA7!PlK`mJ,~>
+^&QPYk5XC;ZiA6HPlK`?J,~>
+]`6JEk5XC'o`'h4jo:H+J,~>
+]`6K2k5XCio`'i!jo:HmJ,~>
+]`6JYk5XC;o`'hHjo:H?J,~>
+]DpGFjo=:&o`'h4kl6Z+J,~>
+]DpH3jo=:ho`'i!kl6ZmJ,~>
+]DpGZjo=::o`'hHkl6Z?J,~>
+])UDGjT"1%o`'k5l2Q]*J,~>
+])UE4jT"1go`'l"l2Q]lJ,~>
+])UD[jT"19o`'kIl2Q]>J,~>
+])UGHj8\($o`'k5li2i*J,~>
+])UH5j8\(fo`'l"li2ilJ,~>
+])UG\j8\(8o`'kIli2i>J,~>
+\c:AHj8\($o`'k5mJhu*J,~>
+\c:B5j8\(fo`'l"mJhulJ,~>
+\c:A\j8\(8o`'kImJhu>J,~>
+\Gt>Iir@t#o`'k5mf/)+!<7Q~>
+\Gt?6ir@teo`'l"mf/)m!<7Q~>
+\Gt>]ir@t7o`'kImf/)?!<7Q~>
+\GtAJiW%k"o`'n6n,J,*!<7Q~>
+\GtB7iW%kdo`'o#n,J,l!<7Q~>
+\GtA^iW%k6o`'nJn,J,>!<7Q~>
+\,Y>Ki;_b!o`'n6nGe2*!<7Q~>
+\,Y?8i;_bco`'o#nGe2l!<7Q~>
+\,Y>_i;_b5o`'nJnGe2>!<7Q~>
+[f>8Ki;_b!o`'n6nc+8*!<7Q~>
+[f>98i;_bco`'o#nc+8l!<7Q~>
+[f>8_i;_b5o`'nJnc+8>!<7Q~>
+[f>;LhuD\!oDah6nc+8*s8RT~>
+[f><9huD\coDai#nc+8ls8RT~>
+[f>;`huD\5oDahJnc+8>s8RT~>
+[K#8MhZ)RuoDah6o)F>*s8RT~>
+[K#9:hZ)SboDai#o)F>ls8RT~>
+[K#8ahZ)S4oDahJo)F>>s8RT~>
+[/]5Nh>cItoDak7nc+5)s8RT~>
+[/]6;h>cJaoDal$nc+5ks8RT~>
+[/]5bh>cJ3oDakKnc+5=s8RT~>
+[/]5Nh>cLuo)Fb6o)F;)s8RT~>
+[/]6;h>cMbo)Fc#o)F;ks8RT~>
+[/]5bh>cM4o)FbJo)F;=s8RT~>
+ZiB2Oh#HCto)Fe7o)F;)rr7K~>
+ZiB3<h#HDao)Ff$o)F;krr7K~>
+ZiB2ch#HD3o)FeKo)F;=rr7K~>
+ZN'/Pg]-:so)Fe7o)F;)rr7K~>
+ZN'0=g]-;`o)Ff$o)F;krr7K~>
+ZN'/dg]-;2o)FeKo)F;=rr7K~>
+Z2a,QgAg4snc+_7o)F;)rVqB~>
+Z2a->gAg5`nc+`$o)F;krVqB~>
+Z2a,egAg52nc+_Ko)F;=rVqB~>
+Z2a,QgAg7tnGeV6o)F;)rVqB~>
+Z2a->gAg8anGeW#o)F;krVqB~>
+Z2a,egAg83nGeVJo)F;=rVqB~>
+YlF)Rg&L.snGeY7o)F;)r;V9~>
+YlF*?g&L/`nGeZ$o)F;kr;V9~>
+YlF)fg&L/2nGeYKo)F;=r;V9~>
+YQ+&Sf`1(sn,JS7nc+2(r;V9~>
+YQ+'@f`1)`n,JT$nc+2jr;V9~>
+YQ+&gf`1)2n,JSKnc+2<r;V9~>
+YQ+)TfDk"smf/J6nc+5)qu;0~>
+YQ+*AfDk#`mf/K#nc+5kqu;0~>
+YQ+)hfDk#2mf/JJnc+5=qu;0~>
+Y5e#TfDk"smf/M7nc+5)qYu'~>
+Y5e$AfDk#`mf/N$nc+5kqYu'~>
+Y5e#hfDk#2mf/MKnc+5=qYu'~>
+XoIuUf)OqsmJiG7nGe,(qYu'~>
+XoJ!Bf)Or`mJiH$nGe,jqYu'~>
+XoIuif)Or2mJiGKnGe,<qYu'~>
+XoJ#Vec4ksm/NA7n,J&(q>Ys~>
+XoJ$Cec4l`m/NB$n,J&jq>Ys~>
+XoJ#jec4l2m/NAKn,J&<q>Ys~>
+XT.uWeGnesli3;7mf.u(q#>j~>
+XT/!DeGnf`li3<$mf.ujq#>j~>
+XT.ukeGnf2li3;Kmf.u<q#>j~>
+X8hoWeGnhtlMm88m/Mf'p]#a~>
+X8hpDeGnialMm9%m/Mfip]#a~>
+X8hokeGni3lMm8Lm/Mf;p]#a~>
+X8hrXe,Seukl7)7li2c(p&BO~>
+X8hsEe,Sfbkl7*$li2cjp&BO~>
+X8hrle,Sf4kl7)Kli2c<p&BO~>
+WrMoYdf8_ukPq&8l2QT'o`'F~>
+WrMpFdf8`bkPq'%l2QTio`'F~>
+WrMomdf8`4kPq&Ll2QT;o`'F~>
+WW2iYdf8f"jo:o8kPpE&oDa=~>
+WW2jFdf8fdjo:p%kPpEhoDa=~>
+WW2imdf8f6jo:oLkPpE:oDa=~>
+W;lfZdJr`"jSto:jSt3&nGe"~>
+W;lgGdJr`djStp'jSt3hnGe"~>
+W;lfndJr`6jStoNjSt3:nGe"~>
+W;li[d/W`$iW#`;i;\m%mJh\~>
+W;ljHd/W`fiW#a(i;\mgmJh\~>
+W;liod/W`8iW#`Oi;\m9mJh\~>
+VuH`[ci<`&hZ']@f`/3>bl<1~>
+VuHaHci<`hhZ'^-f`/4+bl<1~>
+VuH`oci<`:hZ']Tf`/3Rbl<1~>
+JcEdji]VkmT)X<~>
+JcEdjidZOZT)X<~>
+JcEdji_b:,T)X<~>
+JcEdji]VkmT)X<~>
+JcEdjidZOZT)X<~>
+JcEdji_b:,T)X<~>
+JcEdji]VkmT)X<~>
+JcEdjidZOZT)X<~>
+JcEdji_b:,T)X<~>
+JcEdji]VkmT)X<~>
+JcEdjidZOZT)X<~>
+JcEdji_b:,T)X<~>
+JcEdji]VkmT)X<~>
+JcEdjidZOZT)X<~>
+JcEdji_b:,T)X<~>
+JcEdji]VkmT)X<~>
+JcEdjidZOZT)X<~>
+JcEdji_b:,T)X<~>
+JcEdji]VkmT)X<~>
+JcEdjidZOZT)X<~>
+JcEdji_b:,T)X<~>
+JcEdji]VkmT)X<~>
+JcEdjidZOZT)X<~>
+JcEdji_b:,T)X<~>
+JcEdji]VkmT)X<~>
+JcEdjidZOZT)X<~>
+JcEdji_b:,T)X<~>
+JcEdji]VkmT)X<~>
+JcEdjidZOZT)X<~>
+JcEdji_b:,T)X<~>
+JcEdji]VkmT)X<~>
+JcEdjidZOZT)X<~>
+JcEdji_b:,T)X<~>
+JcEdji]VkmT)X<~>
+JcEdjidZOZT)X<~>
+JcEdji_b:,T)X<~>
+JcEdji]VkmT)X<~>
+JcEdjidZOZT)X<~>
+JcEdji_b:,T)X<~>
+JcEdji]VkmT)X<~>
+JcEdjidZOZT)X<~>
+JcEdji_b:,T)X<~>
+JcEdji]VkmT)X<~>
+JcEdjidZOZT)X<~>
+JcEdji_b:,T)X<~>
+JcEdji]VkmT)X<~>
+JcEdjidZOZT)X<~>
+JcEdji_b:,T)X<~>
+JcEdji]VkmT)X<~>
+JcEdjidZOZT)X<~>
+JcEdji_b:,T)X<~>
+JcEdji]VkmT)X<~>
+JcEdjidZOZT)X<~>
+JcEdji_b:,T)X<~>
+JcEdji]VkmT)X<~>
+JcEdjidZOZT)X<~>
+JcEdji_b:,T)X<~>
+JcEdji]VkmT)X<~>
+JcEdjidZOZT)X<~>
+JcEdji_b:,T)X<~>
+JcEdji]VkmT)X<~>
+JcEdjidZOZT)X<~>
+JcEdji_b:,T)X<~>
+JcEdjj#qtnSc=3~>
+JcEdjj*uX[Sc=3~>
+JcEdjj&(C-Sc=3~>
+JcEdjj#qtnSc=3~>
+JcEdjj*uX[Sc=3~>
+JcEdjj&(C-Sc=3~>
+JcEdjj#qtnSc=3~>
+JcEdjj*uX[Sc=3~>
+JcEdjj&(C-Sc=3~>
+JcEdjj?8(oSH"*~>
+JcEdjjF;a\SH"*~>
+JcEdjjACL.SH"*~>
+JcEdjj?8(oSH"*~>
+JcEdjjF;a\SH"*~>
+JcEdjjACL.SH"*~>
+JcEdjjZS1pS,\!~>
+JcEdjjaVj]S,\!~>
+JcEdjj\^U/S,\!~>
+JcEdjjun:qRf@m~>
+JcEdjk'qs^Rf@m~>
+JcEdjk#$^0Rf@m~>
+JcEdjjun:qRf@m~>
+JcEdjk'qs^Rf@m~>
+JcEdjk#$^0Rf@m~>
+JcEdjk<4CrRK%d~>
+JcEdjkC8'_RK%d~>
+JcEdjk>?g1RK%d~>
+JcEdjkWOLsR/_[~>
+JcEdjk^S0`R/_[~>
+JcEdjkYZp2R/_[~>
+JcEdjkrjUtQiDR~>
+JcEdjl$n9aQiDR~>
+JcEdjku!$3QiDR~>
+JcEdjl90^uQN)I~>
+JcEdjl@4BbQN)I~>
+JcEdjl;<-4QN)I~>
+JcEdjlTKh!Q2c@~>
+JcEdjl[OKcQ2c@~>
+JcEdjlVW65Q2c@~>
+JcEdjlofq"PlH7~>
+JcEdjm!jTdPlH7~>
+JcEdjlqr?6PlH7~>
+JcEdjmQH.$P5g%~>
+JcEdjmXKffP5g%~>
+JcEdjmSSQ8P5g%~>
+JcEdjmlc7%OoKq~>
+JcEdjmsfogOoKq~>
+JcEdjmnnZ9OoKq~>
+JcEdjnNDI'O8j_~>
+JcEdjnUH,iO8j_~>
+JcEdjnPOl;O8j_~>
+JcEdjo0%[)NW4M~>
+JcEdjo7)>kNW4M~>
+JcEdjo21)=NW4M~>
+JcEdjp-"!,MZ82~>
+JcEdjp4%YnMZ82~>
+JcEdjp/-D@MZ82~>
+JcC<$JcE^hJ,~>
+JcC<$JcE^hJ,~>
+JcC<$JcE^hJ,~>
+%%EndData
+showpage
+%%Trailer
+end
+%%EOF
diff --git a/illustrations/vipslogo_512.png b/illustrations/vipslogo_512.png
new file mode 100644
index 0000000000000000000000000000000000000000..f4e416ef1adf3fa60969a5cfb1fd6387ee867ae3
Binary files /dev/null and b/illustrations/vipslogo_512.png differ
diff --git a/input_data.md b/input_data.md
new file mode 100644
index 0000000000000000000000000000000000000000..1f9a61d8712a34be947a5e5f426076240cec47a1
--- /dev/null
+++ b/input_data.md
@@ -0,0 +1,3 @@
+<img src="illustrations/vipslogo_512.png" alt="VIPS Logo" height="250"/>
+
+# VIPS Model input data
\ No newline at end of file
diff --git a/model_development_java.md b/model_development_java.md
new file mode 100644
index 0000000000000000000000000000000000000000..b21795748e0e55833ef9780d6dddf520f7a88085
--- /dev/null
+++ b/model_development_java.md
@@ -0,0 +1,698 @@
+<img src="illustrations/vipslogo_512.png" alt="VIPS Logo" height="250"/>
+
+# Developing a model using Java
+This page builds on [A step-by-step introduction to implementing prediction models in VIPS](model_implementation.md)
+
+What you need to develop a VIPS model is basically:
+
+-   A decent coding environment (IDE) like NetBeans, Eclipse or
+    IntelliJ.
+-   A library of VIPS classes called [VIPSCommon](https://gitlab.nibio.no/VIPS/VIPSCommon)
+-   A testing framework like Junit. This is normally bundled with your
+    IDE (see above)
+
+The normal workflow is that you have some [correctly formatted weather data](weather_data.md) in a file that you put on the project's
+classpath, you mix this with the other configuration data and develop
+the model based on these input data. You must have one main class that
+implements the Model interface, which is available in the VIPSCommon.jar
+library. The test framework can be used to test single methods that are
+part of the algorithms or you can test the complete model.
+
+When you're happy with how the model works you can test deploy it to the
+VIPSCore server (TODO: Document this)
+
+## Implementing a forecasting model
+
+
+In this project, we are going to implement a forecasting model for a
+virtual fungus called «Fungus pilosus flavis» (please bear with me, any
+phytopatologists who might read this). Let\'s say that it there is a
+forecasting model for it that states that
+
+-   There is no infection risk until you have reached 500 day degrees
+    (celcius)
+-   After that, the risk multiplies by 2 for each consecutive hour of
+    leaf wetness (starting at 1 on the first hour). When reaching the
+    threshold of 24, there is serious risk of infection, and measures
+    should be taken.
+
+We'll be using NetBeans IDE for this example, but the process should be
+transferable to other IDEs. NetBeans can be downloaded from here:
+<https://netbeans.org/downloads/> Select either the Java EE version or
+the one with everything. Follow the install instructions and start
+Netbeans.
+
+### Creating a new NetBeans project for the forecasting model
+
+1.  Start the NetBeans application and remove the `Start Page`. Select
+    `File -> New Project` and select project type `Java Application`.
+    Put it somewhere that you'll remember.
+2.  NetBeans sets up the project structure for you, but you should
+    create a package. Right click `Source Packages` and select `New ->
+    Java Package`. Name it whatever you want, e.g.
+    `com.acme.vips.funguspilosusflavis`
+3.  Create the main model class: Right click on the package and select
+    `New -\> Java Class`. Name it e.g. `FungusPilosusFlavisModel`
+4.  The next thing you should do is to add the basic dependencency for
+    the model: The library called `VIPSCommon`. Right click on `Libraries`
+    and select `Add JAR/Folder`. Locate the file (it should be included
+    with this documentation) and add it.
+
+Now you should be ready to code.
+
+### Working on the model class
+
+
+1.  To make sure that the file is compliant with the VIPS Model
+    specifications, change this
+    ```java
+    public class FungusPilosusFlavisModel {
+    ```
+    to this
+    ```java
+    public class FungusPilosusFlavisModel implements Model{
+    ```
+2.  NetBeans complains. Click on the light bulb that pops up in the
+    gutter, and select `Add import for no.bioforsk.vips.model.Model`
+3.  NetBeans complains again. Click on the light bulb and select
+    `Implement all abstract methods`
+4.  NetBeans creates all the methods that are part of the Model
+    **interface**. Please note that these methods at the moment do not
+    do anything, except cause an error (throw an
+    UnsupportedOperationException) if they are called. The
+    implementation of the methods is entirely up to you.
+
+Now the class is ready to be programmed and do some calculations.
+
+[]{#anchor-8}Create the method for finding when 500 day degrees has been passed
+-------------------------------------------------------------------------------
+
+To find out when 500 day degrees (since some date) have passed, you need
+the mean temperature of each day. All weather observations in VIPS are
+represented by an instance of the object WeatherObservation. This object
+has a few important properties:
+
+-   ElementMeasurementTypeId: Rain, mean temperature, leaf wetness etc.
+-   TimeMeasured
+-   LogInterval: Hourly, Daily, Monthly measurement
+-   Value: the numerical value of the weather observation
+
+We need a list of one WeatherObservation with mean temperature per day.
+So we could start by writing this method:
+
+[]{#anchor-9}[]{#anchor-10}public Date
+getDateWhenDayDegreeLimitHasPassed(List\<WeatherObservation\>
+observations)
+
+{
+
+}
+
+NetBeans complains, because it can\'t find the definition of
+WeatherObservation. Click on the light bulb and select «Add import for
+no.bioforsk.vips.entity.WeatherObservation», and then «Add import for
+java.util.Date»). NetBeans still complains, but that\'s because the
+method does not return anything yet. So a simple approach could be:
+
+1.  Loop through all the WeatherObservation objects, and add the value
+    to the total day degree sum as we do so
+2.  When the threshold of 500 has been reached, return the date of that
+    WeatherObservation object.
+
+Sample code for this could be:
+
+*public Date
+getDateWhenDayDegreeLimitHasPassed(List\<WeatherObservation\>
+observations){*
+
+// Make sure the observations are in chronological order
+
+Collections.sort(observations);
+
+// Initalize the day degree counter
+
+Double dayDegrees = 0.0;
+
+// Iterate through the list of observations
+
+for(WeatherObservation obs:observations)
+
+{
+
+// Make sure it\'s only daily temperature observations that are used
+
+if(obs.getLogIntervalId()
+
+.equals(WeatherObservation.LOG\_INTERVAL\_ID\_1D)
+
+&& obs.getElementMeasurementTypeId()
+
+.equals(WeatherElements.TEMPERATURE\_MEAN))
+
+{
+
+// Add to dayDegree sum
+
+dayDegrees += obs.getValue();
+
+// If threshold is reached, return the date of the current temperature
+
+// measurement
+
+if(dayDegrees \>= 500.0)
+
+{
+
+return obs.getTimeMeasured();
+
+}
+
+}
+
+}
+
+// We have finished looping through the observations, and dayDegrees has
+
+// not passed 500. So we can\'t return a Date, we must return NULL
+(nothing)
+
+return null;
+
+}
+
+[]{#anchor-11}Creating the method to calculate the infection risk
+-----------------------------------------------------------------
+
+We can operate on hourly weather data for leaf wetness and calculate the
+infection risk. Data in will be a list of weather observations (leaf
+wetness, hourly). Output data will be a dictionary with timestamp as
+key, and the infection risk as value. So for instance for 24th July 2014
+14:00 UTC there will be only one value.
+
+An example of a solution can be:
+
+public Map\<Date, Integer\> getInfectionRisk(List\<WeatherObservation\>
+observations)
+
+{
+
+// Create the map with dates and infection risk values
+
+Map\<Date, Integer\> riskMap = new HashMap\<\>();
+
+// Make sure the observations are in chronological order
+
+Collections.sort(observations);
+
+// Counter for consecutive hours of leaf wetness
+
+Integer consecutiveHoursOfLeafWetness = 0;
+
+// Loop through the list of observations
+
+for(WeatherObservation obs:observations)
+
+{
+
+// We define a lower threshold for leaf wetnes to be 10mins/hour
+
+if(obs.getValue() \> 10.0)
+
+{
+
+// Leaf wetness registered, add to consecutive hours counter
+
+consecutiveHoursOfLeafWetness++;
+
+}
+
+else
+
+{
+
+// No leaf wetness, reset counter
+
+consecutiveHoursOfLeafWetness = 0;
+
+}
+
+// We set the risk value
+
+riskMap.put(obs.getTimeMeasured(), consecutiveHoursOfLeafWetness \* 2);
+
+}
+
+// Return the map with all values
+
+return riskMap;
+
+}
+
+[]{#anchor-12}How can we be sure that these methods work? Testing to the rescue
+-------------------------------------------------------------------------------
+
+In order to ensure that the methods work, we should test them. Ok, maybe
+these methods are so simple that they do not need testing. But in most
+models you will have complex calculations, and for that you need testing
+to ensure correctness.
+
+For Java, the most common method is to use a testing framework called
+Junit (which is part of a larger family of testing frameworks for
+different programming languages called «xUnit»,
+see:<http://en.wikipedia.org/wiki/XUnit>). To set up a test for the
+model class, right click on it (In the «Projects» tab and select «Tools
+-\> Create/Update tests». Click OK in the dialog box. A test class is
+created for you, and all public methods in the model class have gotten
+their corresponding test methods. When you run the test, which you can
+do by right clicking the model class and select «Test File» or just hit
+\[CTRL-F6\], you will see that all tests fail. This is by design. It's
+now up to you to select which test methods to keep.
+
+A weather data file is included in the documentation. Copy this into the
+«test» folder
+
+### []{#anchor-13}How testing works in JUnit 
+
+Let\'s begin with writing a very simple test method:
+
+\@Test
+
+public void HelloTest()
+
+{
+
+String expected = \"Hello Test!\";
+
+String result = \"HellOOO Test!\";
+
+Assert.assertEquals(expected,result);
+
+}
+
+The method has \@Test before the declaration. This is a so called
+annotation, which helps JUnit find which methods in the class are
+actually meant to be methods to run during a test. The test consists of
+two string variables (expected and result). These variables are asserted
+(or expected) to be equal, and this is tested using the
+Assert.assertEquals method in JUnit. Of course the two strings are not
+equal, so the test will fail. You can try that by simply entering the
+key combination \[ALT\] + \[F6\], which runs all tests for the current
+project. You should see this in the lower part of NetBeans:
+
+![](illustrations/100000000000023E00000127794CBD73893684FD.png)
+
+Now you can try to make the test pass. You can do that by setting the
+strings to have the same value. Run the test again (\[ALT\] + \[F6\]),
+then you should see that the test passes:
+
+![](illustrations/1000000000000231000000EA513D951D10FB401A.png)
+
+So now we can add a test for one of the methods that we created in the
+FungusPilosusFlavisModel class. Let\'s start with testing if
+getDateWhenDayDegreeLimitHasPassed can find the correct date for when we
+have passed 500 day degrees. We use the data from the file
+«JSONWeatherdata.json» (you\'ll find it under «Other Test Sources»).
+These data are quite easy to import into a spreadsheet. By doing that,
+you can add the temperatures, and find that at July 8th 2012, the day
+degrees have reached a value of 509.5. So we can test this in the
+following way.
+
+```java
+@Test
+public void []{#anchor-14}canFindDateWhenDayDegreeLimitPassed()
+{
+    FungusPilosusFlavisModel instance = new FungusPilosusFlavisModel();
+
+    // We create the expected date
+    Calendar cal =
+    Calendar.getInstance(TimeZone.getTimeZone("Europe/Oslo"));
+    cal.set(2012, Calendar.JULY, 8, 0, 0, 0);
+    cal.set(Calendar.MILLISECOND, 0);
+    Date expected = cal.getTime();
+
+    ModelConfiguration config = new WeatherDataFileReader().getModelConfigurationWithWeatherData("/JSONWeatherData.json", "FUNGUSPILO");
+
+    List<WeatherObservation> observations = (List<WeatherObservation>)config.getConfigParameter("observations");
+
+    Date result = instance.getDateWhenDayDegreeLimitHasPassed(observations);
+
+    assertEquals(expected,result);
+
+}
+```
+
+If you run the tests now, you\'ll (hopefully) see that both tests
+passed. Both tests? Yes, you have two tests:
+
+-   helloTest
+-   canFindDateWhenDayDegreeLimitPassed
+
+Each time you change the program and compile it, these tests are run.
+This means that if you change something in the program (either
+intentionally or unintentionally) that makes these tests fail, **you
+will be informed**. This might not seem so relevant for such a simple
+program, but believe me, it will save your day when the code gets big
+and ugly. Also, writing tests helps you think of how the program works.
+If you write the tests first, you will think more clearly about the
+problem, in my experience.
+
+**Exercise: Write a test for getInfectionRisk()**
+
+### Putting it together
+
+
+We now have the most important methods created (and successfully
+tested). What we need to do now is to get data in (set configuration,
+get weather data etc) and get the results out in the expected format.
+
+#### Data in
+
+Input data are sendt in a large lump called a ModelConfiguration. It\'s
+a key based store of many different kind of objects, in principle almost
+any Java object: Numbers, strings, dates, WeatherObservations. This
+configuration object is sent to the model through the method
+setConfiguration. So to get the weather data, we need to extract them
+from the configuration object in that method. An example of how to do
+this is as follows:
+
+First, at the top of the class, declare the object that holds the
+weather data:
+
+```java
+    List<WeatherObservation> observations;
+```
+This list will stay empty (NULL) until setConfiguration does something
+about it. So let\'s do that, e.g.:
+
+```java
+    @Override
+    public void setConfiguration(ModelConfiguration config) throws  ConfigValidationException {
+
+    // We use an object mapper, because we don\'t know if the objects inside
+    // the ModelConfiguration are simply instances of HashMaps or instances
+    // of proper classes. Usually (when sent over the wire using REST), they
+    // are the former.
+
+    ObjectMapper mapper = new ObjectMapper();
+
+    // Get the observation list
+    this.observations = mapper.convertValue(config.getConfigParameter("observations"),
+        new TypeReference\<List\<WeatherObservation\>\>(){});
+
+    // After this we should do validation of the data, but that's for another lesson
+
+    }
+```
+So now we have the weather data in a list, and we can start using them
+
+#### Data out
+
+Data out are sent as a list of Result objects. The method to get the
+data is called `getResult()`, surprisingly. An example of this method
+could be:
+
+```java
+    @Override
+    public List<Result> getResult() throws ModelExcecutionException {
+
+        // Initialize the list of results
+        List<Result> results = new ArrayList<>();
+
+        // Ensure that the observations are in chronoligical order
+        Collections.sort(this.observations);
+
+        // Which date did day degree sum exceed 500?
+        Date dayDegreeLimitReachedDate = this.getDateWhenDayDegreeLimitHasPassed(this.observations);
+    
+        // Get infection risk for the whole period
+        Map<Date, Integer\> uncontrolledInfectionRisk = this.getInfectionRisk(this.observations);
+
+        // Get all dates from the map of infection risk
+        List<Date> dateList = new ArrayList(uncontrolledInfectionRisk.keySet());
+        Collections.sort(dateList);
+
+        // Loop through dates
+        for(Date currentDate:dateList)
+        {
+            // Create a new result object
+            Result result = new ResultImpl();
+            // Set the timestamp on it
+            result.setResultValidTime(currentDate);
+            // If we're after the date of day degree sum \> 500, use the infectionrisk
+            if(currentDate.compareTo(dayDegreeLimitReachedDate) >= 0)
+            {
+                // Set infection risk
+                result.setValue(this.getModelId().toString(), FungusPilosusFlavisModel.CONTROLLED_INFECTION_RISK, uncontrolledInfectionRisk.get(currentDate).toString());
+            }
+            else
+            {
+                // Set infection risk to 0
+                result.setValue(this.getModelId().toString(), FungusPilosusFlavisModel.CONTROLLED_INFECTION_RISK, "0");
+            }
+
+            // Set the warning status
+            // If controlled infection risk \< 64, status is NO RISK
+            // Otherwise it's HIGH RISK
+            result.setWarningStatus(uncontrolledInfectionRisk.get(currentDate) < 64 ? Result.WARNING_STATUS_NO_RISK :Result.WARNING_STATUS_HIGH_RISK);
+
+            // Add result to list
+            results.add(result);
+        }
+        // We're done!
+        return results;
+    }
+```
+
+Netbeans will complain, because you haven\'t defined the global constant
+CONTROLLED_INFECTION_RISK. You can define it at the top of the class:
+
+```java
+public final static String CONTROLLED_INFECTION_RISK = "CONTROLLED_INFECTION_RISK";
+```
+
+How do we know that `getResult()` works? Let's test it! We can start with
+writing this test method:
+
+```java
+@Test
+public void modelWorksAsExpected()
+{
+    try {
+    FungusPilosusFlavisModel instance = new FungusPilosusFlavisModel();
+
+    // Get weather observations from file
+    ModelConfiguration config = this.getConfiguration("/JSONWeatherData.json");
+    instance.setConfiguration(config);
+    List<Result> results = instance.getResult();
+
+    } catch (ConfigValidationException | ModelExcecutionException ex) {
+        fail(ex.getMessage());
+    }
+}
+```
+
+This test does not (yet) test the results, it only tests that the method
+doesn\'t fail when run. If you try to run the tests, you\'ll see that it
+actually fails. This is because the method `getModelId()` has not been
+implemented correctly. Fix that by adding the modelId to the class (at
+the top):
+
+```java
+public final static ModelId modelId = new ModelId("FUNGUSPILO");
+```
+
+The string `"FUNGUSPILO"` is now the unique ID for this model. The ID must
+be a string of 10 characters. It could be anything (as long as it\'s 10
+characters long), but it\'s recommended that it is some sort of
+abbreviation that gives a human reader a clue about which model it is.
+
+Running the test again should make all tests pass.
+
+One behavior that could be tested, is that the infection risk is always
+0 and the warning status == LOW when the result is from before the day
+when day degree sum exceeds 500. We put that into our test:
+
+```java
+@Test
+
+public void modelWorksAsExpected()
+{
+
+    try {
+
+    FungusPilosusFlavisModel instance = new FungusPilosusFlavisModel();
+
+    // Get weather observations from file
+
+    ModelConfiguration config =
+    this.getConfiguration("/JSONWeatherData.json");
+
+    instance.setConfiguration(config);
+
+    List<WeatherObservation> observations =
+    (List<WeatherObservation>)config.getConfigParameter("observations");
+
+    Date dayDegreeLimit =
+    instance.getDateWhenDayDegreeLimitHasPassed(observations);
+
+    // Check that all results before date for day degree limit are zero
+
+    List<Result> results = instance.getResult();
+
+    for(Result result:results)
+    {
+    if(result.getResultValidTime().compareTo(dayDegreeLimit) \<= 0)
+    {
+
+    Assert.assertEquals(
+    "0",
+
+    result.getValue(FungusPilosusFlavisModel.modelId.toString(),
+    FungusPilosusFlavisModel.CONTROLLED\_INFECTION\_RISK)
+
+    );
+
+    Assert.assertEquals(Result.WARNING\_STATUS\_NO\_RISK,
+    result.getWarningStatus());
+
+    }
+
+    }
+
+    } catch (ConfigValidationException \| ModelExcecutionException ex) {
+
+    fail(ex.getMessage());
+
+    }
+
+}
+```
+
+**Exercise**: Write a test (or add to the one above) that checks that the
+infection risk is calculated correctly **after** the day when day degree
+sum exceeds 500.
+
+#### Implementing the meta information methods
+
+
+So, now you have a forecasting model that produces the expected results.
+When this model is deployed to the VIPS core runtime, it is discovered
+automatically and added to the list of available models. In order for
+other systems (like VIPSLogic or another client) to be able to query and
+show information about the model, it needs to implement the methods that
+provide documentation:
+
+-   getModelName() - the name of the model. For instance «Fungus pilosus
+    flavis model»
+-   getLicense() - Open Source? Proprietary? Your pick
+-   getCopyright() - For instance «(c) 2014 Bioforsk»
+-   getModelDescription() - Detailed description of how the model works,
+    from a biological perspective
+-   getModelUsage() - How to configure the model (what parameters are
+    needed, what values may they have and so on)
+-   getSampleConfig() - A sample JSON configuration file.
+
+Most of these methods have two versions: One takes language into
+account, one doesn\'t. Translation in model documentation is part of a
+presently unwritten chapter. For now, you can do this if you want as a
+general pattern:
+
+```java
+    @Override
+    public String getModelName() {
+        return this.getModelName(Model.DEFAULT_LANGUAGE);
+    }
+
+    @Override
+    public String getModelName(String language) {
+        return "Fungus pilosus flavis model";
+    }
+```
+
+This way you only need to change the implementation one place, in the
+language dependent method.
+
+## Learning from an existing model's code
+
+So far we have done the very basics of the most important parts of the
+model implementation. There\'s a lot more to it than this. For further
+study, we recommend that you take a look at the version of [NIBIO's
+forecasting model for apple scab](https://gitlab.nibio.no/VIPS/Model_APPLESCABM). 
+
+## Even more functionality
+### Translation utilities
+
+You can extend the no.nibio.vips.i18n.I18nImpl class for easy
+translation of text that the class provides. In that case, provide a set
+of properties files (which makes up a resource bundle) that you can
+specify in the model constructor, e.g. like this:
+
+```java
+public AppleScabModel()
+{
+    // Setting the file name of the resource bundle
+    super("no.nibio.vips.model.applescabmodel.texts");
+    this.weatherUtil = new WeatherUtil();
+    this.modelUtil = new ModelUtil();
+}
+```
+
+NetBeans has good support for this, read more about resource bundles
+here
+<https://docs.oracle.com/javase/tutorial/i18n/resbundle/concept.html>
+
+To get a translation from the resource bundles, follow this example:
+
+```java
+@Override
+public String getModelName() {
+    return this.getModelName(Model.DEFAULT_LANGUAGE);
+
+}
+
+@Override
+public String getModelName(String language) {
+    return this.getText("name", language);
+}
+```
+### Including images in the description
+
+You can include images in the description text for the model. The images
+are embedded to the text as \<img/\> tags with the image base64 encoded
+inside the src-attribute. For instance:
+
+```html
+<img
+src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAc)[...]" alt="Illustration 1A" title="Illustration 1A"/>
+```
+
+The \<img/\> tags are created from template tags that you insert into
+the document. These tags looks like this:
+
+```
+{{filename=\"/path/to/filename.jpg\" description=\"Sample description\" float=\"\[CSSFloat property\]\"}}
+```
+
+The path is relative to the path in your jarfile.
+
+To enable this functionality, use the ModelUtil class from VIPSCommon.
+For instance like this:
+
+```java
+@Override
+public String getModelDescription(String language) {
+    try
+    {
+        return
+        this.modelUtil.getTextWithBase64EncodedImages(this.getText("description",
+        language), this.getClass());
+    }
+    catch(IOException ex)
+    {
+        return this.getText("description", language);
+    }
+}
+
+```
+
+
diff --git a/model_development_python.md b/model_development_python.md
new file mode 100644
index 0000000000000000000000000000000000000000..bc0abf67269c07f5207901e183fc02cd81926ff0
--- /dev/null
+++ b/model_development_python.md
@@ -0,0 +1,4 @@
+<img src="illustrations/vipslogo_512.png" alt="VIPS Logo" height="250"/>
+
+# Developing a model using Python
+This page builds on [A step-by-step introduction to implementing prediction models in VIPS](model_implementation.md)
\ No newline at end of file
diff --git a/model_implementation.md b/model_implementation.md
new file mode 100644
index 0000000000000000000000000000000000000000..4666376c6b1c0ef9fcbaf44435a62efcc34ea190
--- /dev/null
+++ b/model_implementation.md
@@ -0,0 +1,79 @@
+<img src="illustrations/vipslogo_512.png" alt="VIPS Logo" height="250"/>
+
+# A step-by-step introduction to implementing prediction models in VIPS
+
+Tor-Einar Skog, Senior developer, NIBIO
+
+Updated: 2023-02-21
+
+## What you will learn
+This document describes how to implement and test a forecasting model
+that can be used on the VIPS platform.
+
+## Prerequisites
+
+-   You should be familiar with how the VIPS system works. It is
+    recommended that you read [this](README.md)
+-   You should have a basic understanding either of 
+    - the Java programming language.
+    - the Python programming language
+-   You should be somewhat familiar with using an IDE (Integrated Development Enviroment), such as (depending on your choice of programming language):
+    - NetBeans (Java)
+    - IntelliJ (Java)
+    - Eclipse (Java/Python ++)
+    - PyCharm (Python)
+    - MS Visual Studio Code (Python/Java ++)
+-   You need the library for your programming language, either
+    - For Java: [VIPSCommon](https://gitlab.nibio.no/VIPS/VIPSCommon)
+    - For Python: [VIPSCore-Python-Common](https://gitlab.nibio.no/VIPS/vipscore-python-common)
+-   It is also recommended to have an existing VIPS Model implementation as a reference,
+for instance
+    - For Java: [Carrot rust fly temperature model](https://gitlab.nibio.no/VIPS/Model_PSILARTEMP)
+    - For Python: [Reference model](https://gitlab.nibio.no/VIPS/models/python/referencemodel)
+
+## Model design in VIPS
+
+### The structure of a model
+
+
+![](illustrations/10000201000001C600000114CFEBC2611F68F805.png)
+
+A model is conceptually illustrated above. You have a
+set of input data in some form, you have the analysis/algorithms
+happening inside the model, and the model returns a set of results. In
+VIPS, certain design requirements must be met:
+
+-   The model must be programmed either in 
+    - **Java** or another language that can
+    run on the Java Virtual Machine. This includes JavaScript and R.
+    - **Python v3**
+-   The model must fulfill the Model design contranct
+    -  **Java**: the Model interface, which is in the [VIPSCommon](https://gitlab.nibio.no/VIPS/VIPSCommon) JAR
+    - **Python**: The VIPSModel Abstract Base Class, which is in the [VIPSCore-Python-Common](https://gitlab.nibio.no/VIPS/vipscore-python-common) package
+-   The model must be packaged as an independent component
+    - **Java**: JAR (Java Archive) file
+    - **Python**: PIP package
+-   The **input data** must be in a [specific format](input_data.md)
+-   **Results** must be returned in a [specific format](result_data.md)
+-   The model must provide its own description and usage information in
+    at least English and aditionally in any preferred language
+
+When a model meets these requirements, it can be deployed to the 
+- **Java** [VIPS Core runtime server](https://gitlab.nibio.no/VIPS/VIPSCore)
+- **Python** [VIPSCore-Python runtime server](https://gitlab.nibio.no/VIPS/VIPSCore-Python)
+
+...and be made available without any more
+configuration. The model can be called over HTTP/REST from any
+authenticated client on the Internet. 
+
+### Developing a model
+[Developing a model using Java](model_development_java.md)
+
+[Developing a model using Python](model_development_python.md)
+
+### Developing a model using R
+Renjin is a JVM implementation of R, which makes it possible to run R
+scripts on the JVM and pass data between Java and R. Read more here:
+<http://www.renjin.org/>
+
+We have an actual implementation of a model in R, the [Leaf blotch model for wheat](https://gitlab.nibio.no/VIPS/model_leafblotch)
\ No newline at end of file
diff --git a/result_data.md b/result_data.md
new file mode 100644
index 0000000000000000000000000000000000000000..adcfd258ccbf04fb8830a1a000c2424f731ba060
--- /dev/null
+++ b/result_data.md
@@ -0,0 +1,3 @@
+<img src="illustrations/vipslogo_512.png" alt="VIPS Logo" height="250"/>
+
+# Specification of VIPS model result data
diff --git a/weather_data.md b/weather_data.md
index 9b1934d7e1a172320b6850dde41be38192ecd657..57f69e89277a87bc2852582e87aa42f1e896939b 100644
--- a/weather_data.md
+++ b/weather_data.md
@@ -1,3 +1,5 @@
+<img src="illustrations/vipslogo_512.png" alt="VIPS Logo" height="250"/>
+
 # Specification of external weather data source for VIPS
 
 ## Preface