<?xml version="1.0" encoding="UTF-8"?>
<commit>
  <added type="array"/>
  <modified type="array">
    <modified>
      <diff>@@ -31,14 +31,19 @@
     &lt;WarningLevel&gt;3&lt;/WarningLevel&gt;
   &lt;/PropertyGroup&gt;
   &lt;ItemGroup&gt;
-    &lt;Compile Include=&quot;misc/extensions.fs&quot; /&gt;
-    &lt;Compile Include=&quot;dataaccess/httpxml.fs&quot; /&gt;
-    &lt;Compile Include=&quot;dataaccess/gutenberg.fs&quot; /&gt;
-    &lt;Compile Include=&quot;clustering/hierclustering.fs&quot; /&gt;
-    &lt;Compile Include=&quot;clustering/multidscaling.fs&quot; /&gt;
-    &lt;Compile Include=&quot;treatment/blogs.fs&quot; /&gt;
-    &lt;Compile Include=&quot;treatment/gdata.fs&quot; /&gt;
-    &lt;Compile Include=&quot;presentation/tagcloud.fs&quot; /&gt;
+    &lt;Compile Include=&quot;misc\extensions.fs&quot; /&gt;
+    &lt;Compile Include=&quot;dataaccess\csvreader.fs&quot; /&gt;
+    &lt;Compile Include=&quot;dataaccess\httpxml.fs&quot; /&gt;
+    &lt;Compile Include=&quot;dataaccess\yfinance.fs&quot; /&gt;
+    &lt;Compile Include=&quot;dataaccess\gutenberg.fs&quot; /&gt;
+    &lt;Compile Include=&quot;optimization\optimizer.fs&quot; /&gt;
+    &lt;Compile Include=&quot;geneticalgos\geneticequ.fs&quot; /&gt;
+    &lt;Compile Include=&quot;clustering\hierclustering.fs&quot; /&gt;
+    &lt;Compile Include=&quot;clustering\multidscaling.fs&quot; /&gt;
+    &lt;Compile Include=&quot;treatment\blogs.fs&quot; /&gt;
+    &lt;Compile Include=&quot;treatment\gdata.fs&quot; /&gt;
+    &lt;Compile Include=&quot;presentation\dendrogram.fs&quot; /&gt;
+    &lt;Compile Include=&quot;presentation\tagcloud.fs&quot; /&gt;
   &lt;/ItemGroup&gt;
   &lt;ItemGroup&gt;
     &lt;Reference Include=&quot;FSharp.PowerPack, Version=1.9.6.2, Culture=neutral, PublicKeyToken=a19089b1c74d0809&quot;&gt;</diff>
      <filename>Strangelights.DataTools.fsproj</filename>
    </modified>
    <modified>
      <diff>@@ -1,6 +1,11 @@
 &#65279;#light
-namespace Strangelights.HierarchicalClustering
-open Strangelights.Extensions
+// Copyright (c) 2009 All Right Reserved, Robert Pickering
+//
+// This source is subject to the GLPv2, please see Strangelights.DataTools.gpl-2.0.txt.
+// Contact Robert Pickering via: http://strangelights.com/
+
+namespace Strangelights.DataTools.Clustering
+open Strangelights.DataTools.Extensions
 
 type BiculsterNodeDetails&lt;'a&gt; =
     | Node of NodeDetails&lt;'a&gt;
@@ -18,17 +23,17 @@ and BiculsterNode&lt;'a&gt; =
 module Clustering =
     /// turns a list of cluster nodes into a hierarchal cluster tree
     let buildClusterTree progress clusters =
-        let keys m = Map.to_seq m |&gt; PSeq.map snd
+        let keys m = Map.to_seq m |&gt; Seq.cmap snd
         let compareNodes { NameValueParis = c1 } { NameValueParis = c2 } =
             let wc1, wc2 = keys c1, keys c2
-            1. - abs (Correlations.pearson wc1 wc2)
+            1. - abs (Measures.pearson wc1 wc2)
         let initComparisons = 
             progress (Printf.sprintf &quot;Building initial comparison set ...&quot;)
             let clusters = Set.to_seq (Set.of_seq clusters)
-            let clusterParis = SeqenceOps.combinations2 clusters
+            let clusterParis = Seq.combinations2 clusters
             //Seq.iter (fun (x,y) -&gt; if x = y then System.Windows.MessageBox.Show (&quot;found pair &quot; + (any_to_string x) + (any_to_string y)) |&gt; ignore) toto
             clusterParis
-            |&gt; PSeq.map (fun (c1, c2) -&gt; compareNodes c1 c2, (c1, c2))
+            |&gt; Seq.cmap (fun (c1, c2) -&gt; compareNodes c1 c2, (c1, c2))
             |&gt; Map.of_seq
         let averageWordMap wc1 wc2 =
             Seq.map2 (fun (word, v1) (_, v2) -&gt; word, (v1 + v2) / 2.) (Map.to_list wc2) (Map.to_list wc1)
@@ -44,8 +49,8 @@ module Clustering =
                                               Right = c2;
                                               Distance = dist; } }
             let restClusters = Seq.filter (fun x -&gt; not (x = c1 || x = c2)) clusters
-            let newComps = PSeq.map (fun c -&gt; compareNodes node c, (node, c)) restClusters
-            let comparisons = PSeq.fold (fun acc (dist, comps) -&gt; Map.add dist comps acc) restComps newComps
+            let newComps = Seq.cmap (fun c -&gt; compareNodes node c, (node, c)) restClusters
+            let comparisons = Seq.fold (fun acc (dist, comps) -&gt; Map.add dist comps acc) restComps newComps
             if Seq.length restClusters = 0 then
                 node
             else</diff>
      <filename>clustering/hierclustering.fs</filename>
    </modified>
    <modified>
      <diff>@@ -1,148 +1,152 @@
 #light
-namespace Strangelights.DataTools.Sources
-#time
-#r &quot;Ionic.Utils.Zip.dll&quot;;;
-#r &quot;ICSharpCode.SharpZipLib.dll&quot;;;
-module Gutenberg =
-    open System
-    open System.IO
-    open System.IO.Compression
-    open ICSharpCode.SharpZipLib.Zip
-    open System.Net
-    open System.Xml
-    open System.Xml.XPath
+// Copyright (c) 2009 All Right Reserved, Robert Pickering
+//
+// This source is subject to the GLPv2, please see Strangelights.DataTools.gpl-2.0.txt.
+// Contact Robert Pickering via: http://strangelights.com/
+
+module Strangelights.DataTools.Gutenberg
+open System
+open System.IO
+open System.IO.Compression
+open System.Net
+open System.Xml
+open System.Xml.XPath
+open ICSharpCode.SharpZipLib.Zip
+
+let DefaultIndexUrl =  &quot;http://www.gutenberg.org/feeds/catalog.rdf.zip&quot;
+
+type Book = 
+    { Id: string;
+      Title: string;
+      Author: string }
+
+type GutenbergIndexFile(url) =
+    let uri = new Uri(url)
+    let stream =
+        let ext = Path.GetExtension(uri.LocalPath)
+        let filePath =
+            if uri.IsFile then
+                uri.LocalPath
+            else
+                let wc = new WebClient()
+                let temp = Path.GetTempFileName()
+                let tempExt = Path.ChangeExtension(temp, ext)
+                File.Move(temp, tempExt)
+                wc.DownloadFile(uri, tempExt)
+                tempExt
+        if ext = &quot;.zip&quot; then
+            let zip = new ZipFile(filePath)
+            zip.GetInputStream(0L)
+        else
+            File.OpenRead(filePath) :&gt; Stream
+    let xdoc = XPathDocument(stream)
+    let nav = xdoc.CreateNavigator()
+    let mngr = new XmlNamespaceManager(new NameTable())
+    let namespaces =
+        [ &quot;rdf&quot;, &quot;http://www.w3.org/1999/02/22-rdf-syntax-ns#&quot;;
+          &quot;rdfs&quot;, &quot;http://www.w3.org/2000/01/rdf-schema#&quot;;
+          &quot;xsi&quot;, &quot;http://www.w3.org/2001/XMLSchema-instance&quot;;
+          &quot;dc&quot;, &quot;http://purl.org/dc/elements/1.1/&quot;;
+          &quot;dcterms&quot;, &quot;http://purl.org/dc/terms/&quot;;
+          &quot;dcmitype&quot;, &quot;http://purl.org/dc/dcmitype/&quot;;
+          &quot;cc&quot;, &quot;http://web.resource.org/cc/&quot;;
+          &quot;pgterms&quot;, &quot;http://www.gutenberg.org/rdfterms/&quot; ]
+    do List.iter (fun (prefix,url) -&gt; mngr.AddNamespace(prefix,url)) namespaces
     
-    let DefaultIndexUrl =  &quot;http://www.gutenberg.org/feeds/catalog.rdf.zip&quot;
+    let search query =
+        let xpath = nav.Compile(query)
+        do xpath.SetContext(mngr)
+        let iter = nav.Select(xpath)
+        seq { for x in iter -&gt; x.ToString() }
     
-    type Book = 
-        { Id: string;
-          Title: string;
-          Author: string }
+    member x.FindIdByTitleExcat title =
+        let query = Printf.sprintf &quot;rdf:RDF/pgterms:etext[dc:title = '%s']/@rdf:ID&quot; title
+        search query
+    member x.FindIdByTitle title =
+        let query = Printf.sprintf &quot;rdf:RDF/pgterms:etext[contains(dc:title,'%s')]/@rdf:ID&quot; title
+        search query
 
-    type GutenbergIndexFile(url) =
-        let uri = new Uri(url)
-        let stream =
-            let ext = Path.GetExtension(uri.LocalPath)
-            let filePath =
-                if uri.IsFile then
-                    uri.LocalPath
-                else
-                    let wc = new WebClient()
-                    let temp = Path.GetTempFileName()
-                    let tempExt = Path.ChangeExtension(temp, ext)
-                    File.Move(temp, tempExt)
-                    wc.DownloadFile(uri, tempExt)
-                    tempExt
-            if ext = &quot;.zip&quot; then
-                let zip = new ZipFile(filePath)
-                zip.GetInputStream(0L)
-            else
-                File.OpenRead(filePath) :&gt; Stream
-        let xdoc = XPathDocument(stream)
-        let nav = xdoc.CreateNavigator()
-        let mngr = new XmlNamespaceManager(new NameTable())
-        let namespaces =
-            [ &quot;rdf&quot;, &quot;http://www.w3.org/1999/02/22-rdf-syntax-ns#&quot;;
-              &quot;rdfs&quot;, &quot;http://www.w3.org/2000/01/rdf-schema#&quot;;
-              &quot;xsi&quot;, &quot;http://www.w3.org/2001/XMLSchema-instance&quot;;
-              &quot;dc&quot;, &quot;http://purl.org/dc/elements/1.1/&quot;;
-              &quot;dcterms&quot;, &quot;http://purl.org/dc/terms/&quot;;
-              &quot;dcmitype&quot;, &quot;http://purl.org/dc/dcmitype/&quot;;
-              &quot;cc&quot;, &quot;http://web.resource.org/cc/&quot;;
-              &quot;pgterms&quot;, &quot;http://www.gutenberg.org/rdfterms/&quot; ]
-        do List.iter (fun (prefix,url) -&gt; mngr.AddNamespace(prefix,url)) namespaces
-        
-        let search query =
-            let xpath = nav.Compile(query)
-            do xpath.SetContext(mngr)
-            let iter = nav.Select(xpath)
-            seq { for x in iter -&gt; x.ToString() }
-        
-        member x.FindIdByTitleExcat title =
-            let query = Printf.sprintf &quot;rdf:RDF/pgterms:etext[dc:title = '%s']/@rdf:ID&quot; title
-            search query
-        member x.FindIdByTitle title =
-            let query = Printf.sprintf &quot;rdf:RDF/pgterms:etext[contains(dc:title,'%s')]/@rdf:ID&quot; title
-            search query
+    member x.FindIdByAuthorExact title =
+        let query = Printf.sprintf &quot;rdf:RDF/pgterms:etext[dc:creator = '%s']/@rdf:ID&quot; title
+        search query
+    member x.FindIdByAuthor title =
+        let query = Printf.sprintf &quot;rdf:RDF/pgterms:etext[contains(dc:creator,'%s')]/@rdf:ID&quot; title
+        search query
+    
+    member x.FindBookById id =
+        let query = Printf.sprintf &quot;rdf:RDF/pgterms:etext[@rdf:ID = '%s']&quot; id
+        let xpath = nav.Compile(query)
+        do xpath.SetContext(mngr)
+        let node = nav.SelectSingleNode(xpath)
+        let res = node.MoveToFirstChild()
+        let author = ref &quot;&quot;
+        let title = ref &quot;&quot;
+        while node.MoveToNext() do
+            match node.Name with
+            | &quot;dc:title&quot; -&gt; title := node.Value
+            | &quot;dc:creator&quot; -&gt; author := node.Value
+            | _ -&gt; ()
+        { Id = id;
+          Title = !title;
+          Author = !author; }
+          
+    member x.FindBookByTitleExcat title =
+        let ids = x.FindIdByTitleExcat title
+        Seq.map x.FindBookById ids
+    member x.FindBookByTitle title =
+        let ids = x.FindIdByTitle title
+        Seq.map x.FindBookById ids
 
-        member x.FindIdByAuthorExact title =
-            let query = Printf.sprintf &quot;rdf:RDF/pgterms:etext[dc:creator = '%s']/@rdf:ID&quot; title
-            search query
-        member x.FindIdByAuthor title =
-            let query = Printf.sprintf &quot;rdf:RDF/pgterms:etext[contains(dc:creator,'%s')]/@rdf:ID&quot; title
-            search query
+    member x.FindBookByAuthorExact title =
+        let ids = x.FindIdByAuthorExact title
+        Seq.map x.FindBookById ids
+    member x.FindBookByAuthor title =
+        let ids = x.FindIdByAuthor title
+        Seq.map x.FindBookById ids
         
-        member x.FindBookById id =
-            let query = Printf.sprintf &quot;rdf:RDF/pgterms:etext[@rdf:ID = '%s']&quot; id
-            let xpath = nav.Compile(query)
-            do xpath.SetContext(mngr)
-            let node = nav.SelectSingleNode(xpath)
-            let res = node.MoveToFirstChild()
-            let author = ref &quot;&quot;
-            let title = ref &quot;&quot;
-            while node.MoveToNext() do
-                match node.Name with
-                | &quot;dc:title&quot; -&gt; title := node.Value
-                | &quot;dc:creator&quot; -&gt; author := node.Value
-                | _ -&gt; ()
-            { Id = id;
-              Title = !title;
-              Author = !author; }
-              
-        member x.FindBookByTitleExcat title =
-            let ids = x.FindIdByTitleExcat title
-            Seq.map x.FindBookById ids
-        member x.FindBookByTitle title =
-            let ids = x.FindIdByTitle title
-            Seq.map x.FindBookById ids
+    member x.DowloadBookById id directory =
+        let query = Printf.sprintf &quot;rdf:RDF/pgterms:file[contains(dc:format/dcterms:IMT/rdf:value, 'text/plain;') and dcterms:isFormatOf/@rdf:resource = '#%s']/@rdf:about&quot; id
+        let xpath = nav.Compile(query)
+        do xpath.SetContext(mngr)
+        let urls = nav.Select(xpath)
+        for url in urls do
+            let url = url.ToString()
+            //Printf.printfn &quot;Downloading: %s&quot; url
+            let wc = new WebClient()
+            let uri = new Uri(url.ToString().Replace(&quot;&amp;&quot;, &quot;http://www.gutenberg.org/dirs/&quot;))
+            let filename = Path.GetFileName(uri.LocalPath)
+            wc.DownloadFile(uri, Path.Combine(directory, filename))
+    
+    member x.DownloadBookByTitleExcat title dir =
+        let ids = x.FindIdByTitleExcat title
+        ids |&gt; Seq.iter (fun id -&gt; x.DowloadBookById id dir) 
+    member x.DownloadBookByTitle title dir =
+        let ids = x.FindIdByTitle title
+        ids |&gt; Seq.iter (fun id -&gt; x.DowloadBookById id dir) 
 
-        member x.FindBookByAuthorExact title =
-            let ids = x.FindIdByAuthorExact title
-            Seq.map x.FindBookById ids
-        member x.FindBookByAuthor title =
-            let ids = x.FindIdByAuthor title
-            Seq.map x.FindBookById ids
-            
-        member x.DowloadBookById id directory =
-            let query = Printf.sprintf &quot;rdf:RDF/pgterms:file[contains(dc:format/dcterms:IMT/rdf:value, 'text/plain;') and dcterms:isFormatOf/@rdf:resource = '#%s']/@rdf:about&quot; id
-            let xpath = nav.Compile(query)
-            do xpath.SetContext(mngr)
-            let urls = nav.Select(xpath)
-            for url in urls do
-                let url = url.ToString()
-                //Printf.printfn &quot;Downloading: %s&quot; url
-                let wc = new WebClient()
-                let uri = new Uri(url.ToString().Replace(&quot;&amp;&quot;, &quot;http://www.gutenberg.org/dirs/&quot;))
-                let filename = Path.GetFileName(uri.LocalPath)
-                wc.DownloadFile(uri, Path.Combine(directory, filename))
+    member x.DownloadBookByAuthorExact title dir =
+        let ids = x.FindIdByAuthorExact title
+        ids |&gt; Seq.iter (fun id -&gt; x.DowloadBookById id dir) 
+    member x.DownloadBookByAuthor title dir =
+        let ids = x.FindIdByAuthor title
+        ids |&gt; Seq.iter (fun id -&gt; x.DowloadBookById id dir) 
         
-        member x.DownloadBookByTitleExcat title dir =
-            let ids = x.FindIdByTitleExcat title
-            ids |&gt; Seq.iter (fun id -&gt; x.DowloadBookById id dir) 
-        member x.DownloadBookByTitle title dir =
-            let ids = x.FindIdByTitle title
-            ids |&gt; Seq.iter (fun id -&gt; x.DowloadBookById id dir) 
 
-        member x.DownloadBookByAuthorExact title dir =
-            let ids = x.FindIdByAuthorExact title
-            ids |&gt; Seq.iter (fun id -&gt; x.DowloadBookById id dir) 
-        member x.DownloadBookByAuthor title dir =
-            let ids = x.FindIdByAuthor title
-            ids |&gt; Seq.iter (fun id -&gt; x.DowloadBookById id dir) 
-            
+#if INTERACTIVE 
 (*
 &lt;pgterms:file rdf:about=&quot;&amp;f;2/6/1/4/26143/26143-8.txt&quot;&gt;
-  &lt;dc:format&gt;&lt;dcterms:IMT&gt;&lt;rdf:value&gt;text/plain; charset=&quot;iso-8859-1&quot;&lt;/rdf:value&gt;&lt;/dcterms:IMT&gt;&lt;/dc:format&gt;
-  &lt;dcterms:extent&gt;381655&lt;/dcterms:extent&gt;
-  &lt;dcterms:modified&gt;&lt;dcterms:W3CDTF&gt;&lt;rdf:value&gt;2008-07-28&lt;/rdf:value&gt;&lt;/dcterms:W3CDTF&gt;&lt;/dcterms:modified&gt;
-  &lt;dcterms:isFormatOf rdf:resource=&quot;#etext26143&quot; /&gt;
+&lt;dc:format&gt;&lt;dcterms:IMT&gt;&lt;rdf:value&gt;text/plain; charset=&quot;iso-8859-1&quot;&lt;/rdf:value&gt;&lt;/dcterms:IMT&gt;&lt;/dc:format&gt;
+&lt;dcterms:extent&gt;381655&lt;/dcterms:extent&gt;
+&lt;dcterms:modified&gt;&lt;dcterms:W3CDTF&gt;&lt;rdf:value&gt;2008-07-28&lt;/rdf:value&gt;&lt;/dcterms:W3CDTF&gt;&lt;/dcterms:modified&gt;
+&lt;dcterms:isFormatOf rdf:resource=&quot;#etext26143&quot; /&gt;
 &lt;/pgterms:file&gt;
- 
+
 *)
-    
+
 // tests
-    let test = DefaultIndexUrl //@&quot;D:\gutenberg\catalog.rdf.zip&quot;
-    let index = new GutenbergIndexFile(&quot;D:\gutenberg\catalog.rdf.zip&quot;)
-    index.DownloadBookByAuthor &quot;Dickens&quot; &quot;D:\gutenberg\dickens&quot;
-    index.DowloadBookById &quot;etext6096&quot;  &quot;D:\gutenberg&quot;
+let test = DefaultIndexUrl //@&quot;D:\gutenberg\catalog.rdf.zip&quot;
+let index = new GutenbergIndexFile(&quot;D:\gutenberg\catalog.rdf.zip&quot;)
+index.DownloadBookByAuthor &quot;Dickens&quot; &quot;D:\gutenberg\dickens&quot;
+index.DowloadBookById &quot;etext6096&quot;  &quot;D:\gutenberg&quot;
 //printfn &quot;hello&quot;
+#endif
\ No newline at end of file</diff>
      <filename>dataaccess/gutenberg.fs</filename>
    </modified>
    <modified>
      <diff>@@ -3,7 +3,7 @@
     Title=&quot;Blog Hierarical Clustering&quot; Height=&quot;600&quot; Width=&quot;800&quot;&gt;
     &lt;Grid&gt;
         &lt;Button Height=&quot;23&quot; HorizontalAlignment=&quot;Right&quot; Name=&quot;startButton&quot; VerticalAlignment=&quot;Top&quot; Width=&quot;75&quot;&gt;Start&lt;/Button&gt;
-        &lt;TextBox Height=&quot;23&quot; Margin=&quot;0,1.861,77.77,0&quot; Name=&quot;opmlUrl&quot; VerticalAlignment=&quot;Top&quot;&gt;http://www.currybet.net/download/opml/top100ukblogs.xml&lt;/TextBox&gt;
+        &lt;TextBox Height=&quot;23&quot; Margin=&quot;0,1.861,77.77,0&quot; Name=&quot;opmlUrl&quot; VerticalAlignment=&quot;Top&quot;&gt;D:\code\github\HierarchicalClustering\data\blogs&lt;/TextBox&gt;
         &lt;TextBox Height=&quot;23&quot; Name=&quot;statusBar&quot; VerticalAlignment=&quot;Bottom&quot; IsReadOnly=&quot;True&quot; /&gt;
         &lt;TabControl Margin=&quot;0,62.216,0,28.58&quot;&gt;
             &lt;TabItem Header=&quot;Tree&quot;&gt;
@@ -14,6 +14,9 @@
                     &lt;TextBox Name=&quot;outputDetail&quot; Height=&quot;93.324&quot; HorizontalAlignment=&quot;Right&quot; VerticalAlignment=&quot;Top&quot; Width=&quot;275.528&quot; HorizontalScrollBarVisibility=&quot;Auto&quot; VerticalScrollBarVisibility=&quot;Auto&quot; /&gt;
                 &lt;/Grid&gt;
             &lt;/TabItem&gt;
+            &lt;TabItem Header=&quot;Dendrogram&quot; Name=&quot;dendrogram&quot;&gt;
+
+            &lt;/TabItem&gt;
             &lt;TabItem Header=&quot;Master Word List&quot;&gt;
                 &lt;Grid&gt;
                     &lt;TextBox Name=&quot;choosenWords&quot; IsReadOnly=&quot;True&quot; VerticalScrollBarVisibility=&quot;Auto&quot; HorizontalAlignment=&quot;Left&quot; Width=&quot;241.501&quot; HorizontalScrollBarVisibility=&quot;Auto&quot; /&gt;
@@ -21,6 +24,12 @@
                     &lt;TextBox Name=&quot;masterWordList&quot; IsReadOnly=&quot;True&quot; HorizontalAlignment=&quot;Right&quot; VerticalScrollBarVisibility=&quot;Auto&quot; Width=&quot;241.501&quot; HorizontalScrollBarVisibility=&quot;Auto&quot; /&gt;
                 &lt;/Grid&gt;
             &lt;/TabItem&gt;
+            &lt;TabItem Header=&quot;Tag Cloud&quot; Name=&quot;tagCloud&quot;&gt;
+
+            &lt;/TabItem&gt;
+            &lt;TabItem Header=&quot;Multi D Scaling View&quot; Name=&quot;multidscale&quot;&gt;
+
+            &lt;/TabItem&gt;
             &lt;TabItem Header=&quot;Current Post&quot; Name=&quot;currentPost&quot;&gt;
                 &lt;Grid&gt;
                     &lt;WebBrowser Name=&quot;postBrowser&quot; Margin=&quot;0,37.154,0,0&quot; /&gt;
@@ -30,8 +39,8 @@
         &lt;/TabControl&gt;
         &lt;TextBox Name=&quot;urlLimit&quot; Height=&quot;23&quot; HorizontalAlignment=&quot;Left&quot; Margin=&quot;72.215,32.219,0,0&quot; VerticalAlignment=&quot;Top&quot; Width=&quot;31.108&quot;&gt;12&lt;/TextBox&gt;
         &lt;TextBox Name=&quot;timeout&quot; Height=&quot;23&quot; HorizontalAlignment=&quot;Left&quot; Margin=&quot;175.538,32.219,0,0&quot; VerticalAlignment=&quot;Top&quot; Width=&quot;24&quot;&gt;30&lt;/TextBox&gt;
-        &lt;TextBox Name=&quot;lowerBounds&quot; Height=&quot;23&quot; Margin=&quot;264.718,32.219,0,0&quot; VerticalAlignment=&quot;Top&quot; HorizontalAlignment=&quot;Left&quot; Width=&quot;52.217&quot;&gt;0.3&lt;/TextBox&gt;
-        &lt;TextBox Name=&quot;upperBounds&quot; Height=&quot;23&quot; HorizontalAlignment=&quot;Left&quot; Margin=&quot;325.523,32.219,0,0&quot; VerticalAlignment=&quot;Top&quot; Width=&quot;52.217&quot;&gt;2&lt;/TextBox&gt;
+        &lt;TextBox Name=&quot;lowerBounds&quot; Height=&quot;23&quot; Margin=&quot;264.718,32.219,0,0&quot; VerticalAlignment=&quot;Top&quot; HorizontalAlignment=&quot;Left&quot; Width=&quot;52.217&quot;&gt;0.01&lt;/TextBox&gt;
+        &lt;TextBox Name=&quot;upperBounds&quot; Height=&quot;23&quot; HorizontalAlignment=&quot;Left&quot; Margin=&quot;325.523,32.219,0,0&quot; VerticalAlignment=&quot;Top&quot; Width=&quot;52.217&quot;&gt;1&lt;/TextBox&gt;
         &lt;Label Height=&quot;28&quot; HorizontalAlignment=&quot;Left&quot; Margin=&quot;5,30.219,0,0&quot; VerticalAlignment=&quot;Top&quot; Width=&quot;63.327&quot;&gt;Url Limit:&lt;/Label&gt;
         &lt;Label Height=&quot;28&quot; HorizontalAlignment=&quot;Left&quot; Margin=&quot;111.1,30.219,0,0&quot; VerticalAlignment=&quot;Top&quot; Width=&quot;63.327&quot;&gt;Timeout:&lt;/Label&gt;
         &lt;Label Height=&quot;28&quot; HorizontalAlignment=&quot;Left&quot; Margin=&quot;209.979,30.219,0,0&quot; VerticalAlignment=&quot;Top&quot; Width=&quot;63.327&quot;&gt;Bounds:&lt;/Label&gt;</diff>
      <filename>examples/Window1.xaml</filename>
    </modified>
    <modified>
      <diff>@@ -1,6 +1,11 @@
 &#65279;#light
+// Copyright (c) 2009 All Right Reserved, Robert Pickering
+//
+// This source is subject to the GLPv2, please see Strangelights.DataTools.gpl-2.0.txt.
+// Contact Robert Pickering via: http://strangelights.com/
 
 open System
+open System.Globalization
 open System.Windows
 open System.Windows.Controls
 open System.Windows.Markup
@@ -11,8 +16,50 @@ open System.Windows.Threading
 open System.Threading
 open System.ComponentModel
 open System.Diagnostics
-open Strangelights.Extensions
-open Strangelights.HierarchicalClustering
+open Strangelights.DataTools.Extensions
+open Strangelights.DataTools.Treatment
+open Strangelights.DataTools.Clustering
+
+type MutliDScaling2DViewer(data) as x =
+    inherit FrameworkElement()
+    override x.OnRender(dc: DrawingContext) =
+        let width, height =  x.ActualWidth, x.ActualHeight
+        for { DataName = label; Location = loc } in data do
+            let x, y, color =
+                match loc with
+                | [ x; y ] -&gt; x, y, None
+                | [ x; y; color ] -&gt; x, y, Some color
+                | _ -&gt; failwith (Printf.sprintf &quot;unsupported dims: %i&quot; (List.length loc))
+            let x, y = x * width, y * height
+            let brush = 
+                match color with
+                | None -&gt; Brushes.Black
+                | Some x -&gt;
+                    let red = byte (x * 255.)
+                    let blue = byte ((1. - x) * 255.)
+                    new SolidColorBrush(Color.FromRgb(red, byte 0, blue))
+            let text = new FormattedText(label, CultureInfo.GetCultureInfo(&quot;en-us&quot;),
+                                         FlowDirection.LeftToRight,
+                                         new Typeface(&quot;Verdana&quot;),
+                                         10., brush)
+            dc.DrawText(text, new Point(x + 5., y - 7.))
+
+//type MutliDScaling3DViewer(data) as x =
+//    inherit Viewport3D()
+//    do for { DataName = label; Location = loc } in data do
+//            let x, y, z =
+//                match loc with
+//                | [ x; y; z ] -&gt; x, y, z
+//                | _ -&gt; failwith (Printf.sprintf &quot;unsupported dims: %i&quot; (List.length loc))
+//            ()
+            //let x, y = x * width, y * height
+//            let P
+//            let text = new FormattedText(label, CultureInfo.GetCultureInfo(&quot;en-us&quot;),
+//                                         FlowDirection.LeftToRight,
+//                                         new Typeface(&quot;Verdana&quot;),
+//                                         10., Brushes.Black)
+//            dc.DrawText(text, new Point(x + 5., y - 7.))
+
     
 let processWords words =
     words
@@ -49,6 +96,9 @@ let statusBar = window.FindName(&quot;statusBar&quot;) :?&gt; TextBox
 let currentPost = window.FindName(&quot;currentPost&quot;) :?&gt; TabItem
 let currentUrl = window.FindName(&quot;currentUrl&quot;) :?&gt; TextBox
 let postBrowser = window.FindName(&quot;postBrowser&quot;) :?&gt; WebBrowser
+let tagCloudContainer = window.FindName(&quot;tagCloud&quot;) :?&gt; TabItem
+let dendrogramContainer = window.FindName(&quot;dendrogram&quot;) :?&gt; TabItem
+let multidscaleContainer = window.FindName(&quot;multidscale&quot;) :?&gt; TabItem
 
 let progress s =
     statusBar.Dispatcher.Invoke(DispatcherPriority.Normal, new Invokee(fun _ -&gt; statusBar.Text &lt;- s)) |&gt; ignore
@@ -94,6 +144,8 @@ let start() =
     enable false
     let bgwkr = new BackgroundWorker()
     let url, limit = opmlUrl.Text, Int32.Parse(urlLimit.Text)
+    let uri = new Uri(url)
+    let local = uri.IsFile
     let upperBounds = Double.Parse(upperBounds.Text) / 100. 
     let lowerBounds = Double.Parse(lowerBounds.Text) / 100. 
     let timeout = Int32.Parse(timeout.Text) * 1000
@@ -101,19 +153,44 @@ let start() =
     let stopwatch = new Stopwatch()
     bgwkr.DoWork.Add(fun ea -&gt;
         stopwatch.Start()
-        ea.Result &lt;- BlogTreatment.processOpml progress url lowerBounds upperBounds limit timeout)
+        ea.Result &lt;- BlogTreatment.processOpmlAll progress local url lowerBounds upperBounds limit timeout)
 
     let showResult result =
         drawTree treeView.Items result.BiculsterTree
-        let total = float result.MasterWordList.Count
+        let total = Map.fold_left(fun total _ count -&gt; total + count) 0. result.MasterWordList
         processWords (Map.to_seq result.MasterWordList)
         |&gt; Seq.iter (fun (word, count) -&gt;  masterWordList.AppendText(Printf.sprintf &quot;%s: %f = %f%%\n&quot; word count ((count / total) * 100.)))
-        let chosenWords = Seq.map (fun word -&gt; word, result.MasterWordList.[word]) result.ChosenWords
+        let chosenWords = Seq.cmap (fun word -&gt; word, result.MasterWordList.[word]) result.ChosenWords
         chosenWords
         |&gt; Seq.iter (fun (word, count) -&gt;  choosenWordsAlph.AppendText(Printf.sprintf &quot;%s: %f = %f%%\n&quot; word count ((count / total) * 100.)))
         processWords chosenWords
         |&gt; Seq.iter (fun (word, count) -&gt;  choosenWords.AppendText(Printf.sprintf &quot;%s: %f = %f%%\n&quot; word count ((count / total) * 100.)))
+
+        let rec accNodes acc node =
+            match node.NodeDetails with
+            | Node { Left = left; Right = right; Distance = dist } -&gt;
+                let acc = accNodes acc left
+                accNodes acc right
+            | Leaf node -&gt; node :: acc
+        
+        let tagCloud = new TagCloud(chosenWords, accNodes [] result.BiculsterTree)
+        tagCloud.BlogClicked.Add(fun { Name = name; Url = url } -&gt;
+            currentUrl.Text &lt;- url
+            postBrowser.Navigate(new Uri(url))
+            currentPost.IsSelected &lt;- true)
+        tagCloudContainer.Content &lt;- tagCloud
+
+        let rec mapNodes node =
+            match node.NodeDetails with
+            | Leaf { Name = name } -&gt; { NodeDetails = Leaf name; NameValueParis = node.NameValueParis }
+            | Node { Left = left; Right = right; Distance = dist } -&gt;
+                { NodeDetails = Node { Distance = dist; Left = mapNodes left; Right = mapNodes right; }
+                  NameValueParis = node.NameValueParis }
+        let node = mapNodes result.BiculsterTree
+        dendrogramContainer.Content &lt;- new Dendrogram(node.NodeDetails)
+        multidscaleContainer.Content &lt;- new MutliDScaling2DViewer(result.MulitDScaling)
         enable true
+
         progress (Printf.sprintf &quot;Done - Processed: %i in %O&quot; result.ProcessedBlogs stopwatch.Elapsed)
         
     bgwkr.RunWorkerCompleted.Add(fun ea -&gt;
@@ -132,7 +209,6 @@ let main() =
             let tvi = ea.NewValue :?&gt; TreeViewItem
             nodeSelectChanged (tvi.Tag :?&gt; BiculsterNode&lt;BlogLeafDetails&gt;))
     startButton.Click.Add(fun _ -&gt; start())
-    
     let app = new Application() in 
     app.Run(window) |&gt; ignore
  </diff>
      <filename>examples/blogsFrontEnd.fs</filename>
    </modified>
    <modified>
      <diff>@@ -1,4 +1,8 @@
 &#65279;#light
+// Copyright (c) 2009 All Right Reserved, Robert Pickering
+//
+// This source is subject to the GLPv2, please see Strangelights.DataTools.gpl-2.0.txt.
+// Contact Robert Pickering via: http://strangelights.com/
 
 #if INTERACTIVE
 #r &quot;PresentationCore&quot;;;
@@ -17,8 +21,9 @@
 #endif
 
 open System
-open Strangelights.Extensions
-open Strangelights.HierarchicalClustering
+open Strangelights.DataTools
+open Strangelights.DataTools.Extensions
+open Strangelights.DataTools.Clustering
 
 let progress = printfn &quot;%s&quot;
 </diff>
      <filename>examples/gdataFrontEnd.fs</filename>
    </modified>
    <modified>
      <diff>@@ -1,5 +1,10 @@
 &#65279;#light
+// Copyright (c) 2009 All Right Reserved, Robert Pickering
+//
+// This source is subject to the GLPv2, please see Strangelights.DataTools.gpl-2.0.txt.
+// Contact Robert Pickering via: http://strangelights.com/
 
+#r &quot;FSharp.PowerPack&quot;;;
 #r &quot;PresentationCore&quot;;;
 #r &quot;PresentationFramework&quot;;;
 #r &quot;System.Core&quot;;;
@@ -7,15 +12,19 @@
 #r &quot;System.Xml&quot;;;
 #r &quot;WindowsBase&quot;;;
 
-#load &quot;extensions.fs&quot;;;
-#load &quot;dataAccess.fs&quot;;;
-#load &quot;clustering.fs&quot;;;
-#load &quot;gdata.fs&quot;;;
-#load &quot;algo.fs&quot;;;
-#load &quot;dendrogram.fs&quot;;;
+#load &quot;../misc/extensions.fs&quot;;;
+#load &quot;../dataaccess/csvreader.fs&quot;;;
+#load &quot;../dataaccess/httpxml.fs&quot;;;
+#load &quot;../dataaccess/yfinance.fs&quot;;;
+#load &quot;../clustering/hierclustering.fs&quot;;;
+#load &quot;../clustering/multidscaling.fs&quot;;;
+#load &quot;../treatment/gdata.fs&quot;;;
+#load &quot;../treatment/blogs.fs&quot;;;
+#load &quot;../presentation/dendrogram.fs&quot;;;
+#load &quot;../presentation/tagcloud.fs&quot;;;
 
-open Strangelights.Extensions
-open Strangelights.HierarchicalClustering
+open Strangelights.DataTools.Extensions
+open Strangelights.DataTools.Clustering
 
 // how to report progress
 let progress = printfn &quot;%s&quot;
@@ -28,7 +37,7 @@ let lowerLimit = 0.003
 let upperLimit = 0.2
 
 // get the URLs and titles from the &quot;OPML&quot; file
-let urls = Async.Run(DataAccess.getContents progress url BlogTreatment.treatOpml (Seq.of_list []))
+let urls = Async.Run(HttpXml.getContents progress url BlogTreatment.treatOpml (Seq.of_list []))
 let urls' = Seq.take limit urls
 
 // download the URLs 
@@ -37,3 +46,26 @@ let masterList, blogs = BlogTreatment.titleUlrsToWordCountMap progress timeout u
 let clusterTree, chosen =
     Seq.filter (fun { BlogWordCount = wc } -&gt; not (Map.is_empty wc)) blogs
     |&gt; BlogTreatment.clusterWordCounts progress lowerLimit upperLimit masterList
+
+open System.IO
+
+DataAccess.getContents progress url (fun _ stream -&gt; 
+            let sr = new StreamReader(stream)
+            File.WriteAllText(@&quot;D:\code\github\HierarchicalClustering\data\blogs\top100ukblogs.opml&quot;, sr.ReadToEnd()))
+            ()
+            
+Async.Run it
+
+let safeName (s: string) =
+    let chars = Path.GetInvalidFileNameChars()
+    chars |&gt;
+    Seq.fold (fun (s: string) c -&gt;
+        s.Replace(c.ToString(), &quot;&quot;)) s
+
+let getBlog (name, url) =
+    DataAccess.getContents progress url (fun _ stream -&gt; 
+                let sr = new StreamReader(stream)
+                File.WriteAllText(Path.Combine(@&quot;D:\code\github\HierarchicalClustering\data\blogs&quot;, (safeName name) + &quot;.xml&quot;), sr.ReadToEnd()))
+                ()
+
+Async.Run(Async.Parallel(Seq.map getBlog urls))
\ No newline at end of file</diff>
      <filename>examples/tests.fsx</filename>
    </modified>
    <modified>
      <diff>@@ -4,7 +4,7 @@
 // This source is subject to the GLPv2, please see Strangelights.DataTools.gpl-2.0.txt.
 // Contact Robert Pickering via: http://strangelights.com/
 
-namespace Strangelights.GenericAlgorithms
+namespace Strangelights.DataTools
 open System
 open Microsoft.FSharp.Math
 
@@ -119,8 +119,8 @@ module GenericExpressions =
         | x -&gt; Nullary(x)
 
     type HoleTree =
-      | LeftHole of (Expression * Expression -&gt; Expression) * HoleTree * Expression
-      | RightHole of (Expression * Expression -&gt; Expression) * Expression * HoleTree
+      | LeftHole of (UntypedExpression * UntypedExpression -&gt; UntypedExpression) * HoleTree * UntypedExpression
+      | RightHole of (UntypedExpression * UntypedExpression -&gt; UntypedExpression) * UntypedExpression * HoleTree
       | Hole
 
     let rec plug = function</diff>
      <filename>geneticalgos/geneticequ.fs</filename>
    </modified>
    <modified>
      <diff>@@ -1,5 +1,10 @@
 &#65279;#light
-namespace Strangelights.Extensions
+// Copyright (c) 2009 All Right Reserved, Robert Pickering
+//
+// This source is subject to the GLPv2, please see Strangelights.DataTools.gpl-2.0.txt.
+// Contact Robert Pickering via: http://strangelights.com/
+
+namespace Strangelights.DataTools.Extensions
 open System
 open System.Linq
 
@@ -7,25 +12,34 @@ module PSeq =
     // Import some stuff from PLink
     let asParallel list: IParallelEnumerable&lt;_&gt; = ParallelQuery.AsParallel(list)
     let map f list = ParallelEnumerable.Select(asParallel list, new Func&lt;_, _&gt;(f))
-    let reduce f list = ParallelEnumerable.Aggregate(asParallel list, new Func&lt;_, _, _&gt;(f));
-    let fold f acc list = ParallelEnumerable.Aggregate(asParallel list, acc, new Func&lt;_, _, _&gt;(f));
-
-module Net =
-    /// Add the GetResponseAsync to the WebRequest class so it can
-    /// be used in async workflows. 
-    type System.Net.WebRequest with
-        member x.GetResponseAsync() =
-            Async.BuildPrimitive(x.BeginGetResponse, x.EndGetResponse)
+    let reduce f list = ParallelEnumerable.Aggregate(asParallel list, new Func&lt;_, _, _&gt;(f))
+    let fold f acc list = ParallelEnumerable.Aggregate(asParallel list, acc, new Func&lt;_, _, _&gt;(f))
             
-module SeqenceOps =
+module Seq =
+    let cmap f s = Seq.map f s |&gt; Seq.cache
+    let rec combinations n items =
+        let rec comb n curn items combs =
+            cmap (fun item -&gt;
+                        match curn with
+                        | 1 -&gt; Seq.concat (comb n 2 (Seq.filter (fun x -&gt; x &lt;&gt; item) items) (seq { yield seq { yield item } }))
+                        | _ when n = curn -&gt;
+                            seq { for comb in combs do yield Seq.cons item comb }
+                        | _ -&gt;
+                            Seq.concat (comb n (curn + 1) (Seq.filter (fun x -&gt; x &lt;&gt; item) items) (seq { for comb in combs do yield Seq.cons item comb })) )
+                        items
+        Seq.concat (comb n 1 items (Seq.of_list []))
+
     /// combine every item with every other item
     let rec combinations2 items =
-      let head = Seq.hd items
-      let items' = Seq.skip 1 items
-      seq { for el in items' do
-                yield head, el
-            if Seq.length items' &gt; 1 then
-                yield! combinations2 items' }
+        let combs = combinations 2 items
+        cmap (fun l -&gt; Seq.nth 0 l, Seq.nth 1 l) combs
+//    let rec combinations2 items =
+//      let head = Seq.hd items
+//      let items' = Seq.skip 1 items
+//      seq { for el in items' do
+//                yield head, el
+//            if Seq.length items' &gt; 1 then
+//                yield! combinations2 items' }
 module MapOps =
     // merge two word count lists
     let mergeFloatMap wc1 wc2 =
@@ -35,10 +49,15 @@ module MapOps =
             | None -&gt; Map.add word count acc
         Seq.fold merge wc1 (Map.to_seq wc2)
 
-module Correlations =
+module Measures =
+    let euclidean (wc1: seq&lt;float&gt;) (wc2: seq&lt;float&gt;) =
+        let vectors = Seq.zip wc1 wc2
+        let total = vectors |&gt; Seq.fold (fun acc (p, q) -&gt; acc + ((p - q) ** 2.)) 0.
+        sqrt total
+            
     /// pearson conversion - measures the distance between two list of floats
     let pearson (wc1: seq&lt;float&gt;) (wc2: seq&lt;float&gt;) =
-        let sum = PSeq.reduce (+)
+        let sum = Seq.reduce (+)
         let sum1 = sum wc1
         let sum2 = sum wc2
         </diff>
      <filename>misc/extensions.fs</filename>
    </modified>
    <modified>
      <diff>@@ -1,10 +1,15 @@
 #light
-namespace Strangelights.HierarchicalClustering
+// Copyright (c) 2009 All Right Reserved, Robert Pickering
+//
+// This source is subject to the GLPv2, Please see the Strangelights.DataTools.gpl-2.0.txt.
+// Contact Robert Pickering via: http://strangelights.com/
+
+namespace Strangelights.DataTools.Clustering
 open System
 open System.Globalization
 open System.Windows
 open System.Windows.Media
-open Strangelights.HierarchicalClustering
+open Strangelights.DataTools.Clustering
 
 type Dendrogram(t) =
     inherit FrameworkElement()</diff>
      <filename>presentation/dendrogram.fs</filename>
    </modified>
    <modified>
      <diff>@@ -1,4 +1,8 @@
 &#65279;#light
+// Copyright (c) 2009 All Right Reserved, Robert Pickering
+//
+// This source is subject to the GLPv2, Please see the Strangelights.DataTools.gpl-2.0.txt.
+// Contact Robert Pickering via: http://strangelights.com/
 
 namespace Strangelights.DataTools.Clustering
 open System
@@ -7,6 +11,7 @@ open System.Windows
 open System.Windows.Controls
 open System.Windows.Media
 open Strangelights.DataTools.Clustering
+open Strangelights.DataTools.Treatment
 
 type TagCloud(words: seq&lt;string * float&gt;, blogs: seq&lt;BlogLeafDetails&gt;) as x =
     inherit WrapPanel()</diff>
      <filename>presentation/tagcloud.fs</filename>
    </modified>
    <modified>
      <diff>@@ -1,13 +1,19 @@
 &#65279;#light
-namespace Strangelights.HierarchicalClustering
+// Copyright (c) 2009 All Right Reserved, Robert Pickering
+//
+// This source is subject to the GLPv2, please see Strangelights.DataTools.gpl-2.0.txt.
+// Contact Robert Pickering via: http://strangelights.com/
+
+namespace Strangelights.DataTools.Treatment
 open System
 open System.Net
 open System.IO
 open System.Xml.XPath
 open System.Text.RegularExpressions
 open System.Xml
-open Strangelights.Extensions
-open Strangelights.HierarchicalClustering
+open Strangelights.DataTools.DataAccess
+open Strangelights.DataTools.Extensions
+open Strangelights.DataTools.Clustering
 
 type Blog = 
     { Title: string;
@@ -46,6 +52,7 @@ type BlogLeafDetails =
       
 type Result = 
     { BiculsterTree: BiculsterNode&lt;BlogLeafDetails&gt;;
+      MulitDScaling: seq&lt;MultiDResult&gt;;
       MasterWordList: Map&lt;string, float&gt;;
       ChosenWords: seq&lt;string&gt;;
       ProcessedBlogs: int }
@@ -55,8 +62,8 @@ module BlogTreatment =
     /// pairs of titles and URL
     let treatOpml progress (stream: Stream) =
         let xdoc = new XPathDocument(stream)
-        let titles = DataAccess.queryXdoc xdoc &quot;opml/body/outline/outline/@title&quot;
-        let urls = DataAccess.queryXdoc xdoc &quot;opml/body/outline/outline/@xmlUrl&quot; 
+        let titles = HttpXml.queryXdoc xdoc &quot;opml/body/outline/outline/@title&quot;
+        let urls = HttpXml.queryXdoc xdoc &quot;opml/body/outline/outline/@xmlUrl&quot; 
         progress (Printf.sprintf &quot;urls: %i&quot; (Seq.length urls))
         progress (Printf.sprintf &quot;titles: %i&quot; (Seq.length titles))
         Seq.zip titles urls 
@@ -92,10 +99,10 @@ module BlogTreatment =
             else
                 Map.add word 1. acc
         let treatPostList posts =
-            let words = Seq.concat (Seq.map (fun post -&gt; treatText post) posts)
-            PSeq.fold countWords Map.empty words
+            let words = Seq.concat (Seq.cmap (fun post -&gt; treatText post) posts)
+            Seq.fold countWords Map.empty words
                 
-        let posts = DataAccess.queryXdoc xdoc &quot;rss/channel/item/description&quot;
+        let posts = HttpXml.queryXdoc xdoc &quot;rss/channel/item/description&quot;
         progress (Printf.sprintf &quot;items: %i&quot; (Seq.length posts))
         let wordMap = treatPostList posts
         let blog = { Title = title; Url = url; BlogWordCount = wordMap }
@@ -104,17 +111,20 @@ module BlogTreatment =
 
     /// download opml stream then turn into title/url paris
     let opmlFileToTitleUlrs progress url limit = 
-        let urlsWorkflow = DataAccess.getContents progress url treatOpml (Seq.of_list [])
+        let urlsWorkflow = HttpXml.getContents progress url treatOpml (Seq.of_list [])
         let urls = Async.Run urlsWorkflow
         Seq.take (min limit (Seq.length urls)) urls
 
     /// download rss files and turn into word/count maps     
-    let titleUlrsToWordCountMap progress timeout urls = 
+    let titleUlrsToWordCountMap local progress timeout urls = 
         let receiver = new ReceiveBlogAgent()
         let flows = 
             urls 
-            |&gt; Seq.map (fun (title, url) -&gt; 
-                DataAccess.getContents progress url (treatRss title url receiver) ())
+            |&gt; Seq.cmap (fun (title, url) -&gt;
+                if local then
+                    HttpXml.getContents progress url (treatRss title url receiver) ()
+                else
+                    HttpXml.getContentsLocal progress url (treatRss title url receiver) ())
         try
             Async.Run (Async.Parallel flows, timeout = timeout) |&gt; ignore
         with :? TimeoutException -&gt; progress &quot;Request timed out&quot;
@@ -126,7 +136,7 @@ module BlogTreatment =
     let clusterWordCounts progress lowerBound upperBound masterList blogs =
         // remove words that are uncommon or too common
         let remove (wordCount: Map&lt;_, _&gt;) =
-            let count = (float wordCount.Count)
+            let count = Map.fold_left(fun total _ count -&gt; total + count) 0. wordCount
             wordCount |&gt; Map.filter (fun word wc -&gt; 
                 let frac = wc / count
                 //printfn &quot;%s: %i / %i = %f&quot; word wc count frac
@@ -137,12 +147,12 @@ module BlogTreatment =
             masterList
             |&gt; remove
             |&gt; Map.to_seq
-            |&gt; Seq.map fst
+            |&gt; Seq.cmap fst
         
         // ensure wordcount only contains words from master list    
         let addjustToMasterList wordCount =
             masterWordList 
-            |&gt; Seq.map (fun word -&gt; 
+            |&gt; Seq.cmap (fun word -&gt; 
                 match Map.tryfind word wordCount with
                 | Some count -&gt; word, count
                 | None -&gt; word, 0.)
@@ -152,22 +162,51 @@ module BlogTreatment =
         let clustersList =
             blogs
             |&gt; Seq.sort_by (fun { Title = title } -&gt; title)
-            |&gt; PSeq.map (fun { Title = title; Url = url; BlogWordCount = wordmap } -&gt;
+            |&gt; Seq.cmap (fun { Title = title; Url = url; BlogWordCount = wordmap } -&gt;
                     { NameValueParis = addjustToMasterList wordmap;
                       NodeDetails = Leaf { Name = title;
                                            Url = url;
                                            OriginalWordCount = wordmap; }; })
+            |&gt; Seq.cache
 
-        Clustering.buildClusterTree progress clustersList, masterWordList
+        clustersList, masterWordList
 
-    /// process a word count into a hierarical cluster.
-    let processOpml progress url lowerLimit upperLimit limit timeout =
+    let processOpmlToInitClusters progress local url lowerLimit upperLimit limit timeout =
         let masterList, blogs =
-            opmlFileToTitleUlrs progress url limit
-            |&gt; titleUlrsToWordCountMap progress timeout
-        let clusterTree, chosen =
+            if local then
+                Directory.GetFiles(url)
+                |&gt; Seq.cmap (fun path -&gt; Path.GetFileNameWithoutExtension(path), path)
+                |&gt; Seq.take limit
+                |&gt; titleUlrsToWordCountMap local progress timeout
+            else
+                opmlFileToTitleUlrs progress url limit
+                |&gt; titleUlrsToWordCountMap local progress timeout
+        let clustersList, chosen =
             Seq.filter (fun { BlogWordCount = wc } -&gt; not (Map.is_empty wc)) blogs
             //|&gt; (fun blogs -&gt; Set.to_seq (Set.of_seq blogs))
             |&gt; clusterWordCounts progress lowerLimit upperLimit masterList
-        { BiculsterTree = clusterTree; MasterWordList = masterList;
-          ChosenWords = chosen; ProcessedBlogs = Seq.length blogs }
\ No newline at end of file
+        masterList, blogs, clustersList, chosen
+
+    let mdScaling progress clustersList =
+        let getName node =
+            match node with
+            | Leaf { Name = n } -&gt; n
+            | Node _ -&gt; &quot;&quot;
+        let namesVectors = 
+            Seq.cmap (fun { NameValueParis = wc; NodeDetails = nd } -&gt; { DataName = getName nd; Vector = List.map snd (Map.to_list wc) }) clustersList
+            |&gt; Seq.cache
+        MultiD.scaleDown progress 3 namesVectors 0.01
+
+    /// process a word count into a hierarical cluster.
+    let processOpmlAll progress local url lowerLimit upperLimit limit timeout =
+        let masterList, blogs, clustersList, chosen =
+            processOpmlToInitClusters progress local url lowerLimit upperLimit limit timeout
+        { BiculsterTree = Clustering.buildClusterTree progress clustersList; 
+          MulitDScaling = mdScaling progress clustersList;
+          MasterWordList = masterList;
+          ChosenWords = chosen; ProcessedBlogs = Seq.length blogs }
+
+    let processOpmlToMdScaling progress local url lowerLimit upperLimit limit timeout =
+        let masterList, blogs, clustersList, chosen =
+            processOpmlToInitClusters progress local url lowerLimit upperLimit limit timeout
+        mdScaling progress clustersList
\ No newline at end of file</diff>
      <filename>treatment/blogs.fs</filename>
    </modified>
    <modified>
      <diff>@@ -1,7 +1,13 @@
 &#65279;#light
+// Copyright (c) 2009 All Right Reserved, Robert Pickering
+//
+// This source is subject to the GLPv2, please see Strangelights.DataTools.gpl-2.0.txt.
+// Contact Robert Pickering via: http://strangelights.com/
+
 open System
-open Strangelights.Extensions
-open Strangelights.HierarchicalClustering
+open Strangelights.DataTools.DataAccess
+open Strangelights.DataTools.Extensions
+open Strangelights.DataTools.Clustering
 
 type Location =
     { Country: string;
@@ -22,7 +28,7 @@ let getData progress makeUrl urls =
         async { let url = makeUrl key
                 let cols = Seq.map fst colNames
                 let names = Seq.skip 1 (Seq.map snd colNames)
-                let! data = DataAccess.getGoogleSpreadSheet progress url cols
+                let! data = HttpXml.getGoogleSpreadSheet progress url cols
                 return Seq.map (createLocation names) data  }
     Async.Run (Async.Parallel (List.map getData urls))
 </diff>
      <filename>treatment/gdata.fs</filename>
    </modified>
  </modified>
  <removed type="array"/>
  <parents type="array">
    <parent>
      <id>973be01679d75ba6b06b5f2ccf02bb2b88f5a5d0</id>
    </parent>
  </parents>
  <author>
    <name>Robert Pickering</name>
    <email>robert@strangelights.com</email>
  </author>
  <url>http://github.com/robertpi/fscollintelli/commit/a28431f1e0207482250f2e604d0f21aa9d3a697f</url>
  <id>a28431f1e0207482250f2e604d0f21aa9d3a697f</id>
  <committed-date>2009-04-11T00:49:31-07:00</committed-date>
  <authored-date>2009-04-11T00:49:31-07:00</authored-date>
  <message>Commit stuff that was missing because I don't know how to use GIT yet</message>
  <tree>7458abc1490e6ef0691941951b4183b4db9465c2</tree>
  <committer>
    <name>Robert Pickering</name>
    <email>robert@strangelights.com</email>
  </committer>
</commit>
