Fork me on GitHub

All

Code Snippet:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
type 'a ListLazy = Cons of 'a * 'a ListLazy Lazy | Nil

module List =
  module Lazy =
    let single h = Cons(h, lazy (Nil))
    let cons h l = Cons(h, lazy (l))
    let head = function | Nil -> failwith "empty list" | Cons(h,_) -> h
    let tail = function | Nil -> failwith "empty list" | Cons(_,t) -> t.Force()
    let rec iter f = function
      | Nil -> () | Cons(h,t) -> f h; iter f (t.Force())
    let rec map f = function
      | Nil -> Nil | Cons(h,t) -> Cons(f h, lazy (map f (t.Force())))
    let rec fold f init = function
      | Nil -> init | Cons(h,t) -> fold f (f init h) (t.Force())
    let rec foldBack f init = function
      | Nil -> init | Cons(h,t) -> f h (lazy (foldBack f init (t.Force())))
    let rec unfold f init = f init |> function
      | None -> Nil | Some(a,s) -> Cons (a, lazy (unfold f s))
    let rec reduce f = function
      | Nil -> failwith "empty list" | Cons(h,t) -> fold f h (t.Force())
    let rec reduceBack f = function
      | Nil -> failwith "empty list" | Cons(h,t) -> foldBack f h (t.Force())
    let rec skip n = function
      | Nil -> Nil | Cons(h,t) -> (n = 0I) |> function
        | true  -> cons h (t.Force())
        | false -> skip (n-1I) (t.Force())
    let rec take n = function
      | Nil -> Nil | Cons(h,t) -> (n = 0I) |> function
        | true  -> Nil
        | false -> Cons(h, lazy (take (n-1I) (t.Force())))
    let rec append l1 l2 = l1 |> function
      | Nil -> l2 | Cons(h,t) -> Cons(h, lazy (append (t.Force()) l2))
    let rec concat = function
      | Nil -> Nil | Cons(h,t) -> append h (concat (t.Force()))
    let rec ofList = function
      | [] -> Nil | h :: t -> cons h (ofList t)
    let toList l =
      let rec toList' acc = function
        | Nil -> List.rev acc
        | Cons(h,t) -> toList' (h::acc) (t.Force())
      toList' [] l

Code output:

> 
type 'a ListLazy =
  | Cons of 'a * Lazy<'a ListLazy>
  | Nil
module List = begin
  module Lazy = begin
    val single : h:'a -> 'a ListLazy
    val cons : h:'a -> l:'a ListLazy -> 'a ListLazy
    val head : _arg1:'a ListLazy -> 'a
    val tail : _arg1:'a ListLazy -> 'a ListLazy
    val iter : f:('a -> unit) -> _arg1:'a ListLazy -> unit
    val map : f:('a -> 'b) -> _arg1:'a ListLazy -> 'b ListLazy
    val fold : f:('a -> 'b -> 'a) -> init:'a -> _arg1:'b ListLazy -> 'a
    val foldBack :
      f:('a -> Lazy<'b> -> 'b) -> init:'b -> _arg1:'a ListLazy -> 'b
    val unfold : f:('a -> ('b * 'a) option) -> init:'a -> 'b ListLazy
    val reduce : f:('a -> 'a -> 'a) -> _arg1:'a ListLazy -> 'a
    val reduceBack : f:('a -> Lazy<'a> -> 'a) -> _arg1:'a ListLazy -> 'a
    val skip :
      n:System.Numerics.BigInteger -> _arg1:'a ListLazy -> 'a ListLazy
    val take :
      n:System.Numerics.BigInteger -> _arg1:'a ListLazy -> 'a ListLazy
    val append : l1:'a ListLazy -> l2:'a ListLazy -> 'a ListLazy
    val concat : _arg1:'a ListLazy ListLazy -> 'a ListLazy
    val ofList : _arg1:'a list -> 'a ListLazy
    val toList : l:'a ListLazy -> 'a list
  end
end

Infinite Fibonacci (and squared) sequence

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
let fib =
  (List.Lazy.single 0I,
   List.Lazy.unfold(fun (a1,a2) -> Some(a1+a2,(a2,a1+a2))) (1I,0I))
  ||> List.Lazy.append

let fibSquared =
  fib |> List.Lazy.foldBack(fun x l -> Cons(x*x,l)) Nil

fib
|> List.Lazy.take 10I
|> List.Lazy.iter(printf "%A ")

fibSquared
|> List.Lazy.take 10I
|> List.Lazy.iter(printf "%A ")
> 
val fib : System.Numerics.BigInteger ListLazy = Cons (0,Value is not created.)
val fibSquared : System.Numerics.BigInteger ListLazy =
  Cons (0,Value is not created.)

> 0 1 1 2 3 5 8 13 21 34 val it : unit = ()
> 0 1 1 4 9 25 64 169 441 1156 val it : unit = ()

Runtime errors when skipping/taking on empty sequences (F# Seq)

1
2
3
4
5
6
fib
|> List.Lazy.take 10I
|> List.Lazy.toList
|> List.toSeq
|> Seq.skip 20 
|> Seq.iter(printf "%A ")
> val it : seq<System.Numerics.BigInteger> =
  Error: The input sequence has an insufficient number of elements.
1
2
3
4
5
6
fib
|> List.Lazy.take 10I
|> List.Lazy.toList
|> List.toSeq
|> Seq.take 20
|> Seq.iter(printf "%A ")
> 0 1 1 2 3 5 8 13 21 34 System.InvalidOperationException: The input sequence has an insufficient number of elements.
  at Microsoft.FSharp.Collections.SeqModule+Take@999[System.Numerics.BigInteger].GenerateNext (IEnumerable`1& next) [0x00000] in <filename unknown>:0 
  at Microsoft.FSharp.Core.CompilerServices.GeneratedSequenceBase`1[System.Numerics.BigInteger].MoveNextImpl () [0x00000] in <filename unknown>:0 
  at Microsoft.FSharp.Core.CompilerServices.GeneratedSequenceBase`1[System.Numerics.BigInteger].System-Collections-IEnumerator-MoveNext () [0x00000] in <filename unknown>:0 
  at Microsoft.FSharp.Collections.SeqModule.Iterate[BigInteger] (Microsoft.FSharp.Core.FSharpFunc`2 action, IEnumerable`1 source) [0x00000] in <filename unknown>:0 
  at <StartupCode$FSI_0047>.$FSI_0047.main@ () [0x00000] in <filename unknown>:0 
  at (wrapper managed-to-native) System.Reflection.MonoMethod:InternalInvoke (System.Reflection.MonoMethod,object,object[],System.Exception&)
  at System.Reflection.MonoMethod.Invoke (System.Object obj, BindingFlags invokeAttr, System.Reflection.Binder binder, System.Object[] parameters, System.Globalization.CultureInfo culture) [0x00000] in <filename unknown>:0 
Stopped due to error

No runtime errors when skipping/taking on empty lists

1
2
3
4
5
6
7
8
9
fib
|> List.Lazy.take 10I
|> List.Lazy.skip 20I // Behave as C# Linq.Enumerable.Skip
|> List.Lazy.iter(printf "%A ")

fib
|> List.Lazy.take 10I
|> List.Lazy.take 20I // Behave as C# Linq.Enumerable.Take (or F# Seq.truncate)
|> List.Lazy.iter(printf "%A ")
> val it : unit = ()
> 0 1 1 2 3 5 8 13 21 34 val it : unit = ()

References:

All

Code Snippet:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
module Helpers = 
  let permutations ls = 
    let rec insertions x = function
      | []             -> [[x]]
      | (y :: ys) as l -> (x::l)::(List.map (fun x -> y::x) (insertions x ys))
    let rec permutations' = function
      | []      -> seq [ [] ]
      | x :: xs -> Seq.concat (Seq.map (insertions x) (permutations' xs))
    ls |> permutations'
    
module PrisonersHatsPuzzle =
  type Hat = Red | Blue
  type Prisoner = Hat
  type Prisoners = Prisoner * Prisoner * Prisoner * Prisoner
  type Guess = Prisoners -> Prisoner * Hat

  // Bullet-proof logic for the prisoners to always go free:
  // 
  // As the fourth prisoner is behind a screen, we don't care about him.
  // If the last prisoner sees two equal colored hats, he knows he has the
  // the opposite and hereby he can call out the color.
  // In case the last prisoner doesn't call out his color, the second from
  // behind will know that he doesn't have the same color hat as the prisoner
  // in front of him, else the last one would have called it, hereby, he
  // can safely call out the opposite color of the prisoners hat in 
  // front of him.
  // 
  let guess : Guess =
    fun prisoners ->
      let a,b,c,d = prisoners
      match a,b,c,d with
        | (_,Red,Red,_)   -> a,Blue
        | (_,Blue,Blue,_) -> a,Red
        | (_,_,Blue,_)    -> b,Red
        | (_,_,Red,_)     -> b,Blue

open Helpers
open PrisonersHatsPuzzle

let hats = [Hat.Red; Hat.Blue; Hat.Red; Hat.Blue;]

let alwaysGoFree =
  permutations hats
  |> Seq.map(fun xs ->
    match xs with
      | a::b::c::d::[] -> a,b,c,d
      | _ -> failwith "never")
  |> Seq.map(fun x -> guess x)
  |> Seq.toArray

Code output:

module Helpers = begin
  val permutations : ls:'a list -> seq<'a list>
end
module PrisonersHatsPuzzle = begin
  type Hat =
    | Red
    | Blue
  type Prisoner = Hat
  type Prisoners = Prisoner * Prisoner * Prisoner * Prisoner
  type Guess = Prisoners -> Prisoner * Hat
  val guess : Prisoner * Prisoner * Prisoner * Prisoner -> Prisoner * Hat
end

val hats : Hat list = [Red; Blue; Red; Blue]

val alwaysGoFree : (Prisoner * Hat) [] =
  [|(Blue, Blue); (Blue, Blue); (Blue, Blue); (Red, Red); (Red, Red);
    (Red, Red); (Blue, Blue); (Red, Red); (Red, Red); (Red, Red); (Blue, Blue);
    (Red, Red); (Red, Red); (Red, Red); (Blue, Blue); (Blue, Blue); (Red, Red);
    (Red, Red); (Blue, Blue); (Blue, Blue); (Blue, Blue); (Blue, Blue);
    (Blue, Blue); (Red, Red)|]

References:

First thing first

Before you can create your own F# logo, you will need a drawing/editing program with support for layers. If you work on a Windows box, you might as well go with Paint.NET - Free Software for Digital Photo Editing, but if you are on a *nix box as myself, you might want to give Pinta: Painting Made Simple a try.

Your logo file should preferable be in a looseless format and with the following measurements: 200 pixels x 200 pixels.

The last step before you can make your own logo is to download both:

from the The F# Software Foundation Logo for F#. You should have the following in a local folder by now:

[ mon@mbai7 logos ] ll
total 20K
-rw-r--r-- 1 mon staff 7.7K Oct 11 21:02 delegate_frm_logo.ora
-rw-r--r-- 1 mon staff 4.0K Oct 11 20:37 delegate_frm_logo.png
-rw-r--r-- 1 mon staff 1.3K Oct  6 14:56 fsharp100mcdark.png
-rw-r--r-- 1 mon staff 1.5K Oct  6 14:56 fsharp100mclight.png
[ mon@mbai7 logos ]

Let’s do it!

The initial logo looks like this: All

Once the file is open in Pinta, we will create a new file with the same dimensions and save it with the OpenRaster format (.ora). This format supports layers, which is indispensable for this kind of work. We will create an empty layer called frm and we will import the fsharp100mclight.png as a layer (Menu |> Layers |> Import from File…)

All

We will now choose our logo file and select all and copy it.

All

Afterwards, we will paste it into the frm layer. As the frm layer is below the transparent F# logo layer, the F# logo will still be visible (slightly).

All

The reason the logo is not blending in well is because I have a black background. In order to make the logo visible, I will change the colors to dark green and light green.

Remark: This is actually not allowed as it will violate the usage guidelines: “Don’t change the colors”. For more info, please contact @ReedCopsey

All

And you are done:

All

Easy right? Btw I tried out changing a bit the colors in order to comply with the terms of use:

All

… I’m not convinced though.

Update: @ReedCopsey sent me the following logo which is pretty much awesome!!!

All

I have no clue how he has done it, but at least it doens’t violate the terms of use. The lesson learned here is that the F# Comunity will help you out if you aren’t able to do it yourself which is pretty cool.

It wasn’t that bad, Nykredit only lost 650.000 USD but …

A couple of days ago, a Danish Finance Institution, Nykredit, was in the media due to a stock mistake: Stock mistake costs Nykredit millions. The mistake was that instead of selling 4 A.P. Møller - Mærsk B at 14.000 DKK/stock, the stock broker sold 14.000 shares to the price of 4 DKK/stock.

A bit of simple mathematics will show us how bad that deal was:

  • 14000 x 14000 - 14000 x 4 = 195.944.000 DKK

in looses, more or less 33 million dollars. The finance institution was lucky that the deal was made in the last five minutes before the close of trading, where all deal are secret and the final price is set when trading in closed, which in this case was 13.980 DKK/Stock. Nykredit only lost 3.780.000 DKK, about 650.000 USD, which given the circumstances wasn’t that bad.

You might be thinking: “How the heck can a Finance Institution make such a big mistake, aren’t these guys supposed to be looking after our money?” but then you also might think: “Well these greedy bastards had a lot to do with the financial crisis so …” The main issue here is, why would the stock broker even be allowed to make this kind of mistakes? The answer would be that most business critical solutions are still made with an old fashioned approach.

I will, in very few lines of F# code, show how this kind of mistakes would never be possible by using their Units of Measure to construct a very simple but correct and robust DSL (Domain specific language):

1
2
3
4
5
6
7
8
9
10
11
12
open System

[<Measure>] type DKK
[<Measure>] type STOCK

let priceMaerskB : int<DKK/STOCK> = 14000<DKK/STOCK>

let buyPrice  (stocks:int<STOCK>)                        = stocks*priceMaerskB
let sellPrice (stocks:int<STOCK>) (price:int<DKK/STOCK>) = stocks*price

buyPrice  4<STOCK>
sellPrice 4<STOCK> 13900<DKK/STOCK>

In the example above, the stock broker needs to explicitly assign to each of the used integers, a corresponding units of measure tag. The result is what we intended it to be, which we also don’t need to make any kind of unit test, as we have ensured that is not possible to represent an illegal statement with our domain:

[<Measure>]
type DKK
[<Measure>]
type STOCK
val priceMaerskB : int<DKK/STOCK> = 14000
val buyPrice : stocks:int<STOCK> -> int<DKK>
val sellPrice : stocks:int<STOCK> -> price:int<DKK/STOCK> -> int<DKK>
val it : int<DKK> = 56000
val it : int<DKK> = 55600

Sadly, there are still to many people, in charge, that live in the past and keep banging their heads against the same walls over and over again instead of taking a ladder and climb over them once and for all … Anyway, if you want to read a few testimonials on how using this kind of approach, please visit:

The funny stuff …

All

NuGet Snippet:

C:\_tmp\performanceTest>nuget install -ExcludeVersion canopy
Attempting to resolve dependency 'Selenium.WebDriver (= 2.42.0)'.
Attempting to resolve dependency 'Selenium.Support (= 2.42.0)'.
Attempting to resolve dependency 'SizSelCsZzz (= 0.3.36.0)'.
Attempting to resolve dependency 'Newtonsoft.Json (= 6.0)'.
Installing 'Selenium.WebDriver 2.42.0'.
Successfully installed 'Selenium.WebDriver 2.42.0'.
Installing 'Selenium.Support 2.42.0'.
Successfully installed 'Selenium.Support 2.42.0'.
Installing 'Newtonsoft.Json 6.0.1'.
Successfully installed 'Newtonsoft.Json 6.0.1'.
Installing 'SizSelCsZzz 0.3.36.0'.
Successfully installed 'SizSelCsZzz 0.3.36.0'.
Installing 'canopy 0.9.11'.
Successfully installed 'canopy 0.9.11'.
 
C:\_tmp\performanceTest>

Script Snippet (DG.StressTest.Browser.cmd):

@echo off

:: Add the paths for the F# SDK 3.x (from higher version to lower)
set FSHARPSDK=^
C:\Program Files (x86)\Microsoft SDKs\F#\3.1\Framework\v4.0\;^
C:\Program Files (x86)\Microsoft SDKs\F#\3.0\Framework\v4.0\

cls

:: Execute the script "only" with the first "fsianycpu.exe" found
for %%i in (fsianycpu.exe) do "%%~$FSHARPSDK:i" DG.StressTest.Browser.fsx %*

pause

Code Snippet (DG.StressTest.Browser.fsx):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
//nuget install -ExcludeVersion canopy
#r @"Selenium.Support\lib\net40\WebDriver.Support.dll"
#r @"Selenium.WebDriver\lib\net40\WebDriver.dll"
#r @"canopy\lib\canopy.dll"
 
#load @"DG.Auth.fsx" // Just contains let usr = "usr" and let pwd = "pwd"
 
open System
open System.IO
 
open canopy
open runner
open configuration
 
/// Config canopy
compareTimeout <- 30.0
 
/// Utils
let timestamp  () = DateTime.Now.ToString("o").Replace(":","")
let timestamp' () = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")
 
let string2float = function
  | (n,s) -> match Double.TryParse s with | true, value -> value * n | _ -> 0.
 
let parse (s:string) = 
  match s with
    | ms when s.Contains("ms")     ->    1., ms.Replace(" ms","")
    | KB when s.Contains("KB/sec") ->    1., KB.Replace(" KB/sec","")
    | MB when s.Contains("MB/sec") -> 1000., MB.Replace(" MB/sec","")
    | _ -> failwith "Not recognized unit"
  |> string2float |> int
 
/// Local files / folders
let output = @".\output.csv"
let source = @".source\"
 
/// Connection info:
let uriMain = Uri(@"https://org.crm4.dynamics.com");
let uriDiag = Uri(uriMain.AbsoluteUri + @"/tools/diagnostics/diag.aspx")
 
/// Save to .source folder
let save2source data =
  File.WriteAllText(source + timestamp() + ".log", data)
 
/// Browser Performance Test MS CRM Online
let rec performanceTestCrm date path = 
  match (date > DateTime.Now) with
  | true -> 
    click "#runBtn_all"
 
    waitFor (fun () -> (read "#td_status_all") = "complete")
 
    save2source (read "#resultConsole")
 
    let latency, speed, jsArray, jsMorph, jsBase64, jsDOM =
      parse (read "#td_result_latency"),
      parse (read "#td_result_bandwidth"),
      parse (read "#td_result_jsArrayBenchmark"),
      parse (read "#td_result_jsMorphBenchmark"),
      parse (read "#td_result_jsBase64Benchmark"),
      parse (read "#td_result_jsDomBenchmark")
 
    let sw = File.AppendText(path)
    sw.WriteLine(
      sprintf "%s;%i;%i;%i;%i;%i;%i;"
        (timestamp'()) latency speed jsArray jsMorph jsBase64 jsDOM)
    sw.Dispose()
 
    reload()
 
    performanceTestCrm date path
  | false -> ()
 
/// Start Browser Response Test:
start chrome
 
"MS CRM Online Browser Performance Test" &&& fun _ ->
  // Clear output.csv and .source folder
  File.Exists(output) |> function 
    | true -> File.Delete(output)
    | false -> ()
  Directory.EnumerateFiles(@".source","*.log",SearchOption.AllDirectories)
  |> Seq.iter(fun x -> File.Delete(x))
 
  // Go to MS CRM Online
  url uriMain.AbsoluteUri
 
  // Login
  "#cred_userid_inputtext"   << DG.Auth.usr
  "#cred_password_inputtext" << DG.Auth.pwd
  click "#cred_sign_in_button"
  press enter
 
  // Go to diag url
  url uriDiag.AbsoluteUri
 
  // Start and Stop DateTimes
  let startDate = DateTime.Now
  let stopDate  = startDate.AddMinutes(60.)
 
  let sw = File.CreateText(output)
  sw.WriteLine(
    "Timestamp (ISO 8601);Latency (ms);Speed (KB/sec);" +
    "JS Array (ms);JS Morph (ms);JS Base64 (ms);JS DOM (ms);"
  )
  sw.Dispose()
 
  performanceTestCrm stopDate output
 
run()
 
quit()

Code result:

Starting ChromeDriver (v2.10.267521) on port 64015
Only local connections are allowed.
Test: Browser Performance Test MS CRM Online
Passed
 
60 minutes 19 seconds to execute
1 passed
0 failed
Press any key to continue . . .

Code result (output.csv):

Timestamp (ISO 8601);Latency (ms);Speed (KB/sec);JS Array (ms);JS Morph (ms);JS Base64 (ms);JS DOM (ms);
2014-09-18 22:59:59;47;302;229;33;5;13;
2014-09-18 23:00:03;47;302;197;46;6;17;
2014-09-18 23:00:07;48;322;192;45;4;18;
2014-09-18 23:00:10;48;315;186;36;4;12;
2014-09-18 23:00:14;46;302;186;32;3;13;
2014-09-18 23:00:17;47;322;186;33;3;13;
...
2014-09-18 23:59:59;48;329;194;47;4;17;

Code result (.source\2014-09-18T225959.2540079+0200.log):

=== Latency Test Info ===
Number of times run: 20
Run 1 time: 46 ms
Run 2 time: 51 ms
Run 3 time: 48 ms
Run 4 time: 47 ms
Run 5 time: 48 ms
Run 6 time: 45 ms
Run 7 time: 46 ms
Run 8 time: 46 ms
Run 9 time: 46 ms
Run 10 time: 52 ms
Run 11 time: 50 ms
Run 12 time: 47 ms
Run 13 time: 47 ms
Run 14 time: 45 ms
Run 15 time: 44 ms
Run 16 time: 47 ms
Run 17 time: 48 ms
Run 18 time: 48 ms
Run 19 time: 45 ms
Run 20 time: 50 ms
Average latency: 47 ms
Client Time: Thu, 18 Sep 2014 20:59:57 GMT
 
=== Bandwidth Test Info ===
Run 1
  Time: 56 ms
  Blob Size: 15180 bytes
  Speed: 264 KB/sec
Run 2
  Time: 49 ms
  Blob Size: 15180 bytes
  Speed: 302 KB/sec
Run 3
  Time: 50 ms
  Blob Size: 15180 bytes
  Speed: 296 KB/sec
Run 4
  Time: 49 ms
  Blob Size: 15180 bytes
  Speed: 302 KB/sec
Run 5
  Time: 51 ms
  Blob Size: 15180 bytes
  Speed: 290 KB/sec
Run 6
  Time: 51 ms
  Blob Size: 15180 bytes
  Speed: 290 KB/sec
Run 7
  Time: 52 ms
  Blob Size: 15180 bytes
  Speed: 285 KB/sec
Run 8
  Time: 52 ms
  Blob Size: 15180 bytes
  Speed: 285 KB/sec
Run 9
  Time: 50 ms
  Blob Size: 15180 bytes
  Speed: 296 KB/sec
Run 10
  Time: 53 ms
  Blob Size: 15180 bytes
  Speed: 279 KB/sec
Max Download speed: 302 KB/sec
Client Time: Thu, 18 Sep 2014 20:59:58 GMT
 
=== Browser Info ===
Browser CodeName: Mozilla
Browser Name: Netscape
Browser Version: 5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/37.0.2062.120 Safari/537.36
Cookies Enabled: true
Platform: Win32
User-agent header: Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/37.0.2062.120 Safari/537.36
Client Time: Thu, 18 Sep 2014 20:59:58 GMT
 
=== Machine Info ===
Client IP Address: XXX.XXX.XXX.XXX
Client Time: Thu, 18 Sep 2014 20:59:58 GMT
 
=== Array Manipultaion Benchmark ===
Time: 229 ms
Client Time: Thu, 18 Sep 2014 20:59:58 GMT
 
=== Morph Benchmark ===
Time: 33 ms
Client Time: Thu, 18 Sep 2014 20:59:58 GMT
 
=== Base 64 Benchmark ===
Time: 5 ms
Client Time: Thu, 18 Sep 2014 20:59:59 GMT
 
=== DOM Benchmark ===
Total Time: 13 ms
Breakdown:
  Append:  3ms
  Prepend: 5ms
  Index:   0ms
  Insert:  4ms
  Remove:  1ms
Client Time: Thu, 18 Sep 2014 20:59:59 GMT
 
=== Organization Info ===
Organization name: orgSomeIdNumber
Is Live: True
Server time: 9/18/2014 8:59:55 PM UTC
Url: https://org.crm4.dynamics.com//tools/diagnostics/diag.aspx
Client Time: Thu, 18 Sep 2014 20:59:59 GMT

Chart diagrams:

All

All

All

Architecture (Lenovo ThinkPad W540):

All