1. Maxim Moiseev
  2. Linq2vk

Commits

Maxim Moiseev  committed ba36385

Visual Studio 2010 solution/projects added. files reorganized

  • Participants
  • Parent commits 441eeb7
  • Branches default

Comments (0)

Files changed (17)

File src/Common/Api.fs

View file
+namespace Linq2vk.Core.Implementation
+
+open Linq2vk.Core
+
+module Api =
+
+    let WindowWidth = 10
+
+    open DataKind
+
+    // q -- initial query (See Query module)
+    // w -- window size
+    // s -- initial index
+    let getWindowedFrom s w q =
+        let rec loop a b =
+            seq {
+                let url = q |> Query.addFrom a |> Query.addTo b |> Query.toUrl
+                printfn "Url: %s" url
+                let text = Net.requestTextSync url
+                match text with
+                | JsonArr arr ->
+                    yield! Seq.map string arr
+                    if arr.Count <> 0 then
+                        yield! loop (b+1) (b+w)
+                | JsonData o ->
+                    let (ok, dict) = o.TryGetValue("d")
+                    if ok then
+                        yield! Seq.map string dict
+                | JsonReturnCode c -> ()
+            }
+
+        loop s (w-1)
+    
+    let getAll =
+        getWindowedFrom 0 WindowWidth
+    
+    let getAllFrom s =
+        getWindowedFrom s WindowWidth
+        
+    let getOne q =
+        let url = q |> Query.toUrl
+        printfn "Url: %s" url
+        Net.requestTextSync url

File src/Common/Data.fs

View file
+namespace Linq2vk.Core
+
+open System
+
+type Action =
+    | Profile
+
+    | Friends
+    | FriendsMutual
+    | FriendsOnline
+    | FriendsNew
+    
+    | Photos
+    | PhotosWith
+    | PhotosNew
+    
+    | Activity
+    
+    | Fave
+    | FaveOnline
+    | Faved
+    
+    | UpdatesActivity
+    | UpdatesFriends
+    | UpdatesPhotos
+    | UpdatesTaggedPhotos
+    
+    | Message
+    | Inbox
+    | Outbox
+    
+    
+type IFriend =
+    abstract Id : int64
+    abstract Name : string
+    abstract PhotoUrl : string
+    abstract IsOnline : bool
+    
+type IStatus =
+    abstract Id : string
+    abstract UserId : int64
+    abstract StatusId : int64
+    abstract Reserved : int
+    abstract Name : string
+    abstract Timestamp : DateTime
+    abstract Text : string
+    
+type IPhoto =
+    abstract Id : string
+    abstract OwnerId : int64
+    abstract PhotoId : int64
+    abstract ThumbnailUrl : string
+    abstract ImageUrl : string
+    
+type Gender =
+    | Female = 1
+    | Male   = 2
+
+type MaritalStatus =
+    | Single            = 1
+    | InRelationships   = 2
+    | Engaged           = 3
+    | Married           = 4
+    | Complicated       = 5
+    | LookingFor        = 6
+    
+type PoliticalViews =
+    | Communist         = 1
+    | Socialist         = 2
+    | Moderate          = 3
+    | Liberal           = 4
+    | Conservative      = 5
+    | Monarchist        = 6
+    | Ultraconservative = 7
+    | Apathetic         = 8
+    
+type IUserProfile =
+    abstract UserId : int64
+    abstract FirstName : string
+    abstract LastName : string
+    abstract MaidenName : string
+    abstract CurrentStatus : IStatus
+    abstract CountryId : int64
+    abstract ISOCountryCode : string
+    abstract CityId : int64
+    abstract CityName : string
+    abstract Gender : Gender
+    abstract PhotoUrl : string
+    abstract BirthdayDay : int
+    abstract BirthdayMonth : int
+    abstract BirthdayYear : int
+    abstract MaritalStatus : MaritalStatus
+    abstract PoliticalViews : PoliticalViews
+    abstract Friends : IFriend array
+    abstract FriendsOnline : IFriend array
+    abstract FriendsMutual : IFriend array
+    abstract UploadedPhotos : IPhoto array
+    abstract PhotosWith : IPhoto array
+
+[<AutoOpen>]
+module Tools =
+    let unquote (s:string) =
+        s.[1..(s.Length-2)]
+        
+    let string' = unquote << string
+
+    let UnixTimeStart = DateTime(1970, 1, 1)
+    let fromUnixtime (x:int64) = 
+         UnixTimeStart + TimeSpan.FromSeconds(x |> float)
+
+module Make =
+    open System.Text.RegularExpressions
+    open Newtonsoft.Json.Linq
+        
+    let parseComplexId id =
+        let idRx = Regex("([0-9]+)_([\-0-9]+)")
+        let m = idRx.Match(id)
+        let parseGroup (i:int) =
+            m.Groups.[i].Value |> int64
+        
+        if m.Success then 
+            (parseGroup 1, parseGroup 2)
+        else
+            raise <| ArgumentException(sprintf "Invalid complex id format: %s" id)
+
+    let friend (ts:JToken array) =
+        { new IFriend with 
+            override this.Id = ts.[0] |> int64
+            override this.Name = ts.[1] |> string'
+            override this.PhotoUrl = ts.[2] |> string'
+            override this.IsOnline = 1 = (ts.[3] |> int)
+        }
+
+    let status (ts:JToken array) =
+        let parseTimestamp (token:JToken) =
+            // This is the UserAPI! Sometimes timestamp is a number,
+            // sometimes it is a string containing that number
+            let timestamp =
+                if token.Type = JTokenType.String then
+                    token |> string'
+                else
+                    token |> string
+            timestamp |> int64 |> fromUnixtime
+    
+        let (_, statusId) = parseComplexId (ts.[0] |> string)
+        { new IStatus with
+            override this.Id = ts.[0] |> string
+            override this.UserId = ts.[1] |> int64
+            override this.StatusId = statusId
+            override this.Reserved = 0
+            override this.Name = ts.[3] |> string'
+            override this.Timestamp = 
+                if statusId <> -1L then
+                    parseTimestamp ts.[4]
+                else
+                    DateTime.MinValue
+            override this.Text = ts.[5] |> string'
+        }
+        
+    let photo (ts:JToken array) =
+        let (ownerId, photoId) = parseComplexId (ts.[0] |> string)
+        { new IPhoto with
+            override this.Id = ts.[0] |> string
+            override this.OwnerId = ownerId
+            override this.PhotoId = photoId
+            override this.ThumbnailUrl = ts.[1] |> string'
+            override this.ImageUrl = ts.[2] |> string'
+        }
+        
+module Conversions =
+    open Linq2vk.Core.Implementation.DataKind
+    
+    let toFriend = function
+        | JsonArr arr -> Make.friend (Seq.toArray arr)
+        | _ -> raise <| NotSupportedException "Conversion only supported for JsonArr"
+        
+    let toItemArray conv = function
+        |JsonArr arr -> arr |> Seq.map (string >> conv) |> Seq.toArray
+        | _ -> raise <| NotSupportedException "Conversion only supported for JsonArr"
+
+    let toStatus = function
+        | JsonArr arr ->
+            Make.status (Seq.toArray arr)
+        | JsonData o ->
+            Make.status (Seq.toArray (o.PropertyValues()))
+        | _ -> raise <| NotSupportedException "Conversion only supported for JsonArr or JsonData"
+
+    let toPhoto = function
+        | JsonArr arr -> Make.photo (Seq.toArray arr)
+        | _ -> raise <| NotSupportedException "Conversion only supported for JsonArr"
+
+    let toUserProfile = function
+        | JsonData o ->
+            { new IUserProfile with
+                override this.UserId = o.["id"] |> int64
+                override this.FirstName = o.["fn"] |> string'
+                override this.LastName = o.["ln"] |> string'
+                override this.MaidenName = o.["mn"] |> string'
+                override this.CurrentStatus = o.["actv"] |> string |> toStatus
+                override this.CountryId = o.["ht"].["coi"] |> int64
+                override this.ISOCountryCode = o.["ht"].["con"] |> string'
+                override this.CityId = o.["ht"].["cii"] |> int64
+                override this.CityName = o.["ht"].["cin"] |> string'
+                override this.Gender = o.["sx"] |> int |> enum<Gender>
+                override this.PhotoUrl = o.["bp"] |> string'
+                override this.BirthdayDay = o.["bd"] |> int
+                override this.BirthdayMonth = o.["bm"] |> int
+                override this.BirthdayYear = o.["by"] |> int
+                override this.MaritalStatus = o.["fs"] |> int |> enum<MaritalStatus>
+                override this.PoliticalViews = o.["pv"] |> int |> enum<PoliticalViews>
+                override this.Friends = o.["fr"].["d"] |> string |> toItemArray toFriend
+                override this.FriendsOnline = o.["fro"].["d"] |> string |> toItemArray toFriend
+                override this.FriendsMutual = o.["frm"].["d"] |> string |> toItemArray toFriend
+                override this.UploadedPhotos = o.["ph"].["d"] |> string |> toItemArray toPhoto
+                override this.PhotosWith = o.["phw"].["d"] |> string |> toItemArray toPhoto
+            }
+        | _ -> raise <| NotSupportedException "Conversion only supported for JsonArr"

File src/Common/DataKind.fs

View file
+namespace Linq2vk.Core.Implementation
+
+module DataKind =
+
+    open Newtonsoft.Json.Linq
+    
+    let (|JsonData|JsonArr|JsonReturnCode|) (s:string) =
+//        printfn "(%s)" s
+        if s.[0] = '{' then
+            let jo = JObject.Parse s
+            let (b, d) = jo.TryGetValue("ok")
+            if b then
+                JsonReturnCode (int d)
+            else
+                JsonData jo
+        else
+            JsonArr (JArray.Parse s)

File src/Common/Net.fs

View file
+namespace Linq2vk.Core.Implementation
+
+module Net =
+    open System
+    open System.IO
+    open System.Net
+
+#if ASYNC    
+    let getUrlResponse (url:string) =
+        async {
+            let req = HttpWebRequest.Create(url)
+            let! resp = req.AsyncGetResponse()
+            return resp :?> HttpWebResponse
+        }
+   
+    let processUrlResponse (url:string) f =
+        async {
+            let! resp = getUrlResponse url
+            return f resp
+        }
+        
+    let requestStream url =
+        async {
+            let! resp = getUrlResponse url
+            return resp.GetResponseStream()
+        }
+        
+    let requestText url =
+        async {
+            let! resp = getUrlResponse url
+            use stream = resp.GetResponseStream()
+            use reader = new StreamReader(stream)
+            return reader.ReadToEnd()
+        }
+#endif
+
+    let getUrlResponseSync (url:string) =
+        let req = HttpWebRequest.Create(url) :?> HttpWebRequest
+        use allDone = new System.Threading.AutoResetEvent(false)
+        
+        let (resp:WebResponse ref) = ref null
+        let onResponse (asyncRes:IAsyncResult) =
+            resp := req.EndGetResponse(asyncRes)
+            
+            let httpResp = !resp :?> HttpWebResponse
+            printfn "%A" httpResp.ResponseUri
+            
+            allDone.Set() |> ignore
+            ()
+            
+        let asyncRes = req.BeginGetResponse(AsyncCallback(onResponse), null)
+        
+        // TODO: Possible problems with infinite lock.
+        allDone.WaitOne() |> ignore
+        !resp :?> HttpWebResponse
+   
+    let processUrlResponseSync (url:string) f =
+        let resp = getUrlResponseSync url
+        f resp
+        
+    let requestTextSync url =
+        let resp = getUrlResponseSync url
+        use stream = resp.GetResponseStream()
+        use reader = new StreamReader(stream)
+        reader.ReadToEnd()

File src/Common/Query.fs

View file
+namespace Linq2vk.Core.Implementation
+
+open System.Collections.Generic
+open Linq2vk.Core
+
+module Query =
+    
+    let init (sid:string) =
+        [("sid", sid)]
+        
+    let add (k:string) (v:'a) q =
+        (k, v.ToString()) :: q
+        
+    let toUrl q =
+        let prefix = "http://userapi.com/data?"
+        let makepair (k, v) =
+            sprintf "%s=%s" k v
+        let urlQuery = q |> (Seq.map makepair >> Seq.toArray >> (fun xs -> System.String.Join("&", xs)))
+        prefix + urlQuery
+
+    let addAction (act:Action) =
+        add "act" <|
+            match act with
+            | Friends               -> "friends"
+            | UpdatesActivity       -> "updates_activity"
+            | UpdatesFriends        -> "updates_friends"
+            | UpdatesPhotos         -> "updates_photos"
+            | UpdatesTaggedPhotos   -> "updates_tagged_photos"
+            | Profile               -> "profile"
+            | _                     -> failwith "Not implemented"
+            
+    // TODO: why does not point-free style work here?
+    let addId id = add "id" id
+    let addTo toVal = add "to" toVal
+    let addFrom from = add "from" from

File src/Common/UserAPI.fs

View file
+namespace Linq2vk.Core
+
+open System
+open System.Net
+open System.Text.RegularExpressions
+open Linq2vk.Core.Implementation
+
+type UserAPI (prjId:int64) =
+    let WindowSize = 10
+    
+    let mutable _sid = String.Empty
+    
+    let query act =
+        Query.init _sid |> Query.addAction act
+        
+    let userQuery uid act =
+        query act |> Query.addId uid
+        
+    let getItem conv q =
+        q |> Api.getOne |> conv
+        
+    let getAllItems conv q =
+        q |> Api.getAll |> Seq.map conv
+    
+    member this.LoggedIn
+        with get () = String.IsNullOrEmpty(_sid)
+        
+    member this.Login(usr:string, pwd:string) =
+        let query =
+            sprintf "http://login.userapi.com/auth?login=force&site=%d&email=%s&pass=%s" prjId usr pwd
+            
+        let getSid (resp:HttpWebResponse) =        
+            let sidRx = Regex("sid=([a-z0-9]+)")
+            
+            let getMatchedGroup (rx:Regex) =
+                rx.Match >> (fun m -> m.Groups.[1].Value)
+
+            let sid =
+                resp.ResponseUri.AbsoluteUri |> getMatchedGroup sidRx                   
+            sid
+            
+        let sid =
+            Net.processUrlResponseSync query getSid
+        
+        _sid <- sid
+        this.LoggedIn
+
+    member private this.GetFriendsFrom(queryF) =
+        queryF Action.Friends
+        |> getItem Conversions.toFriend
+    
+    member private this.GetFriends(uid:int64) =
+        this.GetFriendsFrom (userQuery uid)
+            
+    member this.MyFriends
+        with get () =
+            this.GetFriendsFrom query
+        
+    member this.StatusUpdates
+        with get () =
+            query Action.UpdatesActivity |>
+                getAllItems Conversions.toStatus
+                
+    member this.FriendsOfFriends
+        with get () =
+            query Action.UpdatesFriends |>
+                getAllItems Conversions.toFriend
+            
+    member this.FriendsPhotos
+        with get () =
+            query Action.UpdatesPhotos |>
+                getAllItems Conversions.toPhoto
+            
+    member this.FriendsTaggedPhotos
+        with get () =
+            query Action.UpdatesTaggedPhotos |>
+                getAllItems Conversions.toPhoto
+
+    member private this.GetProfileFrom(queryF) =
+        queryF Action.Profile
+        |> getItem Conversions.toUserProfile
+    
+    member this.GetUserProfile (uid:int64) =
+        this.GetProfileFrom (userQuery uid)
+        
+    member this.MyProfile
+        with get () = 
+            this.GetProfileFrom query

File src/Linq2vk.Core.Silverlight/Linq2vk.Core.Silverlight.2010.fsproj

View file
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <PropertyGroup>
+    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+    <ProductVersion>8.0.30703</ProductVersion>
+    <SchemaVersion>2.0</SchemaVersion>
+    <ProjectGuid>{05d5ede1-5b6f-48d3-b627-e9bf498773ec}</ProjectGuid>
+    <OutputType>Library</OutputType>
+    <AssemblyName>Linq2vk.Core.Silverlight.2010</AssemblyName>
+    <TargetFrameworkVersion>v3.0</TargetFrameworkVersion>
+    <SilverlightVersion>$(TargetFrameworkVersion)</SilverlightVersion>
+    <FileAlignment>512</FileAlignment>
+    <AllowCrossTargeting>true</AllowCrossTargeting>
+    <ProjectTypeGuids>{A1591282-1198-4647-A2B1-27E5FF5F6F3B};{f2a71f9b-5d33-465a-a702-920d77279786}</ProjectTypeGuids>
+    <Name>Linq2vk.Core.Silverlight.2010</Name>
+    <TargetFrameworkIdentifier>Silverlight</TargetFrameworkIdentifier>
+    <SilverlightApplication>false</SilverlightApplication>
+    <ValidateXaml>true</ValidateXaml>
+    <ThrowErrorsInValidation>false</ThrowErrorsInValidation>
+    <RootNamespace>Linq2vk.Core.Silverlight.2010</RootNamespace>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+    <DebugSymbols>true</DebugSymbols>
+    <DebugType>full</DebugType>
+    <Optimize>false</Optimize>
+    <OutputPath>bin\Debug\</OutputPath>
+    <DefineConstants>DEBUG;TRACE;SILVERLIGHT</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>3</WarningLevel>
+    <DocumentationFile>bin\Debug\Linq2vk.Core.Silverlight.2010.XML</DocumentationFile>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+    <DebugType>pdbonly</DebugType>
+    <Optimize>true</Optimize>
+    <OutputPath>bin\Release\</OutputPath>
+    <DefineConstants>TRACE;SILVERLIGHT</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>3</WarningLevel>
+    <DocumentationFile>bin\Release\Linq2vk.Core.Silverlight.2010.XML</DocumentationFile>
+  </PropertyGroup>
+  <ItemGroup>
+    <Reference Include="mscorlib" />
+    <Reference Include="FSharp.Core">
+      <HintPath>$(ProgramFiles)\Microsoft F#\Silverlight\Libraries\Client\$(SilverlightVersion)\FSharp.Core.dll</HintPath>
+    </Reference>
+    <Reference Include="Newtonsoft.Json.Silverlight">
+      <HintPath>..\..\lib\jsonnet\Silverlight\Newtonsoft.Json.Silverlight.dll</HintPath>
+    </Reference>
+    <Reference Include="System" />
+    <Reference Include="System.Core" />
+    <Reference Include="System.Net" />
+    <Reference Include="System.Windows" />
+    <Reference Include="System.Windows.Browser" />
+    <Reference Include="System.Xml" />
+  </ItemGroup>
+  <ItemGroup>
+    <Compile Include="..\Common\DataKind.fs">
+      <Link>DataKind.fs</Link>
+    </Compile>
+    <Compile Include="..\Common\Data.fs">
+      <Link>Data.fs</Link>
+    </Compile>
+    <Compile Include="..\Common\Net.fs">
+      <Link>Net.fs</Link>
+    </Compile>
+    <Compile Include="..\Common\Query.fs">
+      <Link>Query.fs</Link>
+    </Compile>
+    <Compile Include="..\Common\Api.fs">
+      <Link>Api.fs</Link>
+    </Compile>
+    <Compile Include="..\Common\UserAPI.fs">
+      <Link>UserAPI.fs</Link>
+    </Compile>
+  </ItemGroup>
+  <Import Project="$(MSBuildExtensionsPath32)\FSharp\1.0\Microsoft.FSharp.Targets" Condition="!Exists('$(MSBuildBinPath)\Microsoft.Build.Tasks.v4.0.dll')" />
+  <Import Project="$(MSBuildExtensionsPath32)\..\Microsoft F#\v4.0\Microsoft.FSharp.Targets" Condition=" Exists('$(MSBuildBinPath)\Microsoft.Build.Tasks.v4.0.dll')" />
+  <Import Project="$(MSBuildExtensionsPath32)\Microsoft\Silverlight\$(SilverlightVersion)\Microsoft.Silverlight.Common.targets" />
+  <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 
+	     Other similar extension points exist, see Microsoft.Common.targets.
+	<Target Name="BeforeBuild">
+	</Target>
+	<Target Name="AfterBuild">
+	</Target>
+	-->
+</Project>

File src/Linq2vk.Core.Silverlight/Linq2vk.Core.Silverlight.fsproj

View file
     </Reference>
   </ItemGroup>
   <ItemGroup>
-    <Compile Include="..\Linq2vk.Core\DataKind.fs">
+    <Compile Include="..\Common\DataKind.fs">
       <Link>DataKind.fs</Link>
     </Compile>
-    <Compile Include="..\Linq2vk.Core\Data.fs">
+    <Compile Include="..\Common\Data.fs">
       <Link>Data.fs</Link>
     </Compile>
-    <Compile Include="..\Linq2vk.Core\Query.fs">
+    <Compile Include="..\Common\Net.fs">
+      <Link>Net.fs</Link>
+    </Compile>
+    <Compile Include="..\Common\Query.fs">
       <Link>Query.fs</Link>
     </Compile>
-    <Compile Include="..\Linq2vk.Core\Net.fs">
-      <Link>Net.fs</Link>
-    </Compile>
-    <Compile Include="..\Linq2vk.Core\Api.fs">
+    <Compile Include="..\Common\Api.fs">
       <Link>Api.fs</Link>
     </Compile>
-    <Compile Include="..\Linq2vk.Core\UserAPI.fs">
+    <Compile Include="..\Common\UserAPI.fs">
       <Link>UserAPI.fs</Link>
     </Compile>
   </ItemGroup>

File src/Linq2vk.Core/Api.fs

-namespace Linq2vk.Core.Implementation
-
-open Linq2vk.Core
-
-module Api =
-
-    let WindowWidth = 10
-
-    open DataKind
-
-    // q -- initial query (See Query module)
-    // w -- window size
-    // s -- initial index
-    let getWindowedFrom s w q =
-        let rec loop a b =
-            seq {
-                let url = q |> Query.addFrom a |> Query.addTo b |> Query.toUrl
-                printfn "Url: %s" url
-                let text = Net.requestTextSync url
-                match text with
-                | JsonArr arr ->
-                    yield! Seq.map string arr
-                    if arr.Count <> 0 then
-                        yield! loop (b+1) (b+w)
-                | JsonData o ->
-                    let (ok, dict) = o.TryGetValue("d")
-                    if ok then
-                        yield! Seq.map string dict
-                | JsonReturnCode c -> ()
-            }
-
-        loop s (w-1)
-    
-    let getAll =
-        getWindowedFrom 0 WindowWidth
-    
-    let getAllFrom s =
-        getWindowedFrom s WindowWidth
-        
-    let getOne q =
-        let url = q |> Query.toUrl
-        printfn "Url: %s" url
-        Net.requestTextSync url

File src/Linq2vk.Core/Data.fs

-namespace Linq2vk.Core
-
-open System
-
-type Action =
-    | Profile
-
-    | Friends
-    | FriendsMutual
-    | FriendsOnline
-    | FriendsNew
-    
-    | Photos
-    | PhotosWith
-    | PhotosNew
-    
-    | Activity
-    
-    | Fave
-    | FaveOnline
-    | Faved
-    
-    | UpdatesActivity
-    | UpdatesFriends
-    | UpdatesPhotos
-    | UpdatesTaggedPhotos
-    
-    | Message
-    | Inbox
-    | Outbox
-    
-    
-type IFriend =
-    abstract Id : int64
-    abstract Name : string
-    abstract PhotoUrl : string
-    abstract IsOnline : bool
-    
-type IStatus =
-    abstract Id : string
-    abstract UserId : int64
-    abstract StatusId : int64
-    abstract Reserved : int
-    abstract Name : string
-    abstract Timestamp : DateTime
-    abstract Text : string
-    
-type IPhoto =
-    abstract Id : string
-    abstract OwnerId : int64
-    abstract PhotoId : int64
-    abstract ThumbnailUrl : string
-    abstract ImageUrl : string
-    
-type Gender =
-    | Female = 1
-    | Male   = 2
-
-type MaritalStatus =
-    | Single            = 1
-    | InRelationships   = 2
-    | Engaged           = 3
-    | Married           = 4
-    | Complicated       = 5
-    | LookingFor        = 6
-    
-type PoliticalViews =
-    | Communist         = 1
-    | Socialist         = 2
-    | Moderate          = 3
-    | Liberal           = 4
-    | Conservative      = 5
-    | Monarchist        = 6
-    | Ultraconservative = 7
-    | Apathetic         = 8
-    
-type IUserProfile =
-    abstract UserId : int64
-    abstract FirstName : string
-    abstract LastName : string
-    abstract MaidenName : string
-    abstract CurrentStatus : IStatus
-    abstract CountryId : int64
-    abstract ISOCountryCode : string
-    abstract CityId : int64
-    abstract CityName : string
-    abstract Gender : Gender
-    abstract PhotoUrl : string
-    abstract BirthdayDay : int
-    abstract BirthdayMonth : int
-    abstract BirthdayYear : int
-    abstract MaritalStatus : MaritalStatus
-    abstract PoliticalViews : PoliticalViews
-    abstract Friends : IFriend array
-    abstract FriendsOnline : IFriend array
-    abstract FriendsMutual : IFriend array
-    abstract UploadedPhotos : IPhoto array
-    abstract PhotosWith : IPhoto array
-
-[<AutoOpen>]
-module Tools =
-    let unquote (s:string) =
-        s.[1..(s.Length-2)]
-        
-    let string' = unquote << string
-
-    let UnixTimeStart = DateTime(1970, 1, 1)
-    let fromUnixtime (x:int64) = 
-         UnixTimeStart + TimeSpan.FromSeconds(x |> float)
-
-module Make =
-    open System.Text.RegularExpressions
-    open Newtonsoft.Json.Linq
-        
-    let parseComplexId id =
-        let idRx = Regex("([0-9]+)_([\-0-9]+)")
-        let m = idRx.Match(id)
-        let parseGroup (i:int) =
-            m.Groups.[i].Value |> int64
-        
-        if m.Success then 
-            (parseGroup 1, parseGroup 2)
-        else
-            raise <| ArgumentException(sprintf "Invalid complex id format: %s" id)
-
-    let friend (ts:JToken array) =
-        { new IFriend with 
-            override this.Id = ts.[0] |> int64
-            override this.Name = ts.[1] |> string'
-            override this.PhotoUrl = ts.[2] |> string'
-            override this.IsOnline = 1 = (ts.[3] |> int)
-        }
-
-    let status (ts:JToken array) =
-        let parseTimestamp (token:JToken) =
-            // This is the UserAPI! Sometimes timestamp is a number,
-            // sometimes it is a string containing that number
-            let timestamp =
-                if token.Type = JTokenType.String then
-                    token |> string'
-                else
-                    token |> string
-            timestamp |> int64 |> fromUnixtime
-    
-        let (_, statusId) = parseComplexId (ts.[0] |> string)
-        { new IStatus with
-            override this.Id = ts.[0] |> string
-            override this.UserId = ts.[1] |> int64
-            override this.StatusId = statusId
-            override this.Reserved = 0
-            override this.Name = ts.[3] |> string'
-            override this.Timestamp = 
-                if statusId <> -1L then
-                    parseTimestamp ts.[4]
-                else
-                    DateTime.MinValue
-            override this.Text = ts.[5] |> string'
-        }
-        
-    let photo (ts:JToken array) =
-        let (ownerId, photoId) = parseComplexId (ts.[0] |> string)
-        { new IPhoto with
-            override this.Id = ts.[0] |> string
-            override this.OwnerId = ownerId
-            override this.PhotoId = photoId
-            override this.ThumbnailUrl = ts.[1] |> string'
-            override this.ImageUrl = ts.[2] |> string'
-        }
-        
-module Conversions =
-    open Linq2vk.Core.Implementation.DataKind
-    
-    let toFriend = function
-        | JsonArr arr -> Make.friend (Seq.toArray arr)
-        | _ -> raise <| NotSupportedException "Conversion only supported for JsonArr"
-        
-    let toItemArray conv = function
-        |JsonArr arr -> arr |> Seq.map (string >> conv) |> Seq.toArray
-        | _ -> raise <| NotSupportedException "Conversion only supported for JsonArr"
-
-    let toStatus = function
-        | JsonArr arr ->
-            Make.status (Seq.toArray arr)
-        | JsonData o ->
-            Make.status (Seq.toArray (o.PropertyValues()))
-        | _ -> raise <| NotSupportedException "Conversion only supported for JsonArr or JsonData"
-
-    let toPhoto = function
-        | JsonArr arr -> Make.photo (Seq.toArray arr)
-        | _ -> raise <| NotSupportedException "Conversion only supported for JsonArr"
-
-    let toUserProfile = function
-        | JsonData o ->
-            { new IUserProfile with
-                override this.UserId = o.["id"] |> int64
-                override this.FirstName = o.["fn"] |> string'
-                override this.LastName = o.["ln"] |> string'
-                override this.MaidenName = o.["mn"] |> string'
-                override this.CurrentStatus = o.["actv"] |> string |> toStatus
-                override this.CountryId = o.["ht"].["coi"] |> int64
-                override this.ISOCountryCode = o.["ht"].["con"] |> string'
-                override this.CityId = o.["ht"].["cii"] |> int64
-                override this.CityName = o.["ht"].["cin"] |> string'
-                override this.Gender = o.["sx"] |> int |> enum<Gender>
-                override this.PhotoUrl = o.["bp"] |> string'
-                override this.BirthdayDay = o.["bd"] |> int
-                override this.BirthdayMonth = o.["bm"] |> int
-                override this.BirthdayYear = o.["by"] |> int
-                override this.MaritalStatus = o.["fs"] |> int |> enum<MaritalStatus>
-                override this.PoliticalViews = o.["pv"] |> int |> enum<PoliticalViews>
-                override this.Friends = o.["fr"].["d"] |> string |> toItemArray toFriend
-                override this.FriendsOnline = o.["fro"].["d"] |> string |> toItemArray toFriend
-                override this.FriendsMutual = o.["frm"].["d"] |> string |> toItemArray toFriend
-                override this.UploadedPhotos = o.["ph"].["d"] |> string |> toItemArray toPhoto
-                override this.PhotosWith = o.["phw"].["d"] |> string |> toItemArray toPhoto
-            }
-        | _ -> raise <| NotSupportedException "Conversion only supported for JsonArr"

File src/Linq2vk.Core/DataKind.fs

-namespace Linq2vk.Core.Implementation
-
-module DataKind =
-
-    open Newtonsoft.Json.Linq
-    
-    let (|JsonData|JsonArr|JsonReturnCode|) (s:string) =
-//        printfn "(%s)" s
-        if s.[0] = '{' then
-            let jo = JObject.Parse s
-            let (b, d) = jo.TryGetValue("ok")
-            if b then
-                JsonReturnCode (int d)
-            else
-                JsonData jo
-        else
-            JsonArr (JArray.Parse s)

File src/Linq2vk.Core/Linq2vk.Core.2010.fsproj

View file
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <PropertyGroup>
+    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+    <ProductVersion>8.0.30703</ProductVersion>
+    <SchemaVersion>2.0</SchemaVersion>
+    <ProjectGuid>{219f29d7-c41a-4c66-a740-8f20d724fd2b}</ProjectGuid>
+    <OutputType>Library</OutputType>
+    <RootNamespace>Linq2vk.Core.2010</RootNamespace>
+    <AssemblyName>Linq2vk.Core.2010</AssemblyName>
+    <TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
+    <Name>Linq2vk.Core.2010</Name>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+    <DebugSymbols>true</DebugSymbols>
+    <DebugType>full</DebugType>
+    <Optimize>false</Optimize>
+    <Tailcalls>false</Tailcalls>
+    <OutputPath>bin\Debug\</OutputPath>
+    <DefineConstants>DEBUG;TRACE</DefineConstants>
+    <WarningLevel>3</WarningLevel>
+    <DocumentationFile>bin\Debug\Linq2vk.Core.2010.XML</DocumentationFile>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+    <DebugType>pdbonly</DebugType>
+    <Optimize>true</Optimize>
+    <Tailcalls>true</Tailcalls>
+    <OutputPath>bin\Release\</OutputPath>
+    <DefineConstants>TRACE</DefineConstants>
+    <WarningLevel>3</WarningLevel>
+    <DocumentationFile>bin\Release\Linq2vk.Core.2010.XML</DocumentationFile>
+  </PropertyGroup>
+  <ItemGroup>
+    <Reference Include="mscorlib" />
+    <Reference Include="FSharp.Core" />
+    <Reference Include="Newtonsoft.Json">
+      <HintPath>..\..\lib\jsonnet\DotNet\Newtonsoft.Json.dll</HintPath>
+    </Reference>
+    <Reference Include="System" />
+    <Reference Include="System.Core" />
+    <Reference Include="System.Numerics" />
+  </ItemGroup>
+  <ItemGroup>
+    <Compile Include="..\Common\DataKind.fs">
+      <Link>DataKind.fs</Link>
+    </Compile>
+    <Compile Include="..\Common\Data.fs">
+      <Link>Data.fs</Link>
+    </Compile>
+    <Compile Include="..\Common\Net.fs">
+      <Link>Net.fs</Link>
+    </Compile>
+    <Compile Include="..\Common\Query.fs">
+      <Link>Query.fs</Link>
+    </Compile>
+    <Compile Include="..\Common\Api.fs">
+      <Link>Api.fs</Link>
+    </Compile>
+    <Compile Include="..\Common\UserAPI.fs">
+      <Link>UserAPI.fs</Link>
+    </Compile>
+  </ItemGroup>
+  <Import Project="$(MSBuildExtensionsPath32)\FSharp\1.0\Microsoft.FSharp.Targets" Condition="!Exists('$(MSBuildBinPath)\Microsoft.Build.Tasks.v4.0.dll')" />
+  <Import Project="$(MSBuildExtensionsPath32)\..\Microsoft F#\v4.0\Microsoft.FSharp.Targets" Condition=" Exists('$(MSBuildBinPath)\Microsoft.Build.Tasks.v4.0.dll')" />
+  <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 
+	     Other similar extension points exist, see Microsoft.Common.targets.
+	<Target Name="BeforeBuild">
+	</Target>
+	<Target Name="AfterBuild">
+	</Target>
+	-->
+</Project>

File src/Linq2vk.Core/Linq2vk.Core.fsproj

View file
     </Reference>
   </ItemGroup>
   <ItemGroup>
-    <Compile Include="DataKind.fs" />
-    <Compile Include="Data.fs" />
-    <Compile Include="Query.fs" />
-    <Compile Include="Net.fs" />
-    <Compile Include="Api.fs" />
-    <Compile Include="UserAPI.fs" />
+    <Compile Include="..\Common\DataKind.fs">
+      <Link>DataKind.fs</Link>
+    </Compile>
+    <Compile Include="..\Common\Data.fs">
+      <Link>Data.fs</Link>
+    </Compile>
+    <Compile Include="..\Common\Net.fs">
+      <Link>Net.fs</Link>
+    </Compile>
+    <Compile Include="..\Common\Query.fs">
+      <Link>Query.fs</Link>
+    </Compile>
+    <Compile Include="..\Common\Api.fs">
+      <Link>Api.fs</Link>
+    </Compile>
+    <Compile Include="..\Common\UserAPI.fs">
+      <Link>UserAPI.fs</Link>
+    </Compile>
   </ItemGroup>
   <Import Project="$(MSBuildExtensionsPath32)\FSharp\1.0\Microsoft.FSharp.Targets" />
   <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 

File src/Linq2vk.Core/Net.fs

-namespace Linq2vk.Core.Implementation
-
-module Net =
-    open System
-    open System.IO
-    open System.Net
-
-#if ASYNC    
-    let getUrlResponse (url:string) =
-        async {
-            let req = HttpWebRequest.Create(url)
-            let! resp = req.AsyncGetResponse()
-            return resp :?> HttpWebResponse
-        }
-   
-    let processUrlResponse (url:string) f =
-        async {
-            let! resp = getUrlResponse url
-            return f resp
-        }
-        
-    let requestStream url =
-        async {
-            let! resp = getUrlResponse url
-            return resp.GetResponseStream()
-        }
-        
-    let requestText url =
-        async {
-            let! resp = getUrlResponse url
-            use stream = resp.GetResponseStream()
-            use reader = new StreamReader(stream)
-            return reader.ReadToEnd()
-        }
-#endif
-
-    let getUrlResponseSync (url:string) =
-        let req = HttpWebRequest.Create(url) :?> HttpWebRequest
-        use allDone = new System.Threading.AutoResetEvent(false)
-        
-        let (resp:WebResponse ref) = ref null
-        let onResponse (asyncRes:IAsyncResult) =
-            resp := req.EndGetResponse(asyncRes)
-            
-            let httpResp = !resp :?> HttpWebResponse
-            printfn "%A" httpResp.ResponseUri
-            
-            allDone.Set() |> ignore
-            ()
-            
-        let asyncRes = req.BeginGetResponse(AsyncCallback(onResponse), null)
-        
-        // TODO: Possible problems with infinite lock.
-        allDone.WaitOne() |> ignore
-        !resp :?> HttpWebResponse
-   
-    let processUrlResponseSync (url:string) f =
-        let resp = getUrlResponseSync url
-        f resp
-        
-    let requestTextSync url =
-        let resp = getUrlResponseSync url
-        use stream = resp.GetResponseStream()
-        use reader = new StreamReader(stream)
-        reader.ReadToEnd()

File src/Linq2vk.Core/Query.fs

-namespace Linq2vk.Core.Implementation
-
-open System.Collections.Generic
-open Linq2vk.Core
-
-module Query =
-    
-    let init (sid:string) =
-        [("sid", sid)]
-        
-    let add (k:string) (v:'a) q =
-        (k, v.ToString()) :: q
-        
-    let toUrl q =
-        let prefix = "http://userapi.com/data?"
-        let makepair (k, v) =
-            sprintf "%s=%s" k v
-        let urlQuery = q |> (Seq.map makepair >> Seq.toArray >> (fun xs -> System.String.Join("&", xs)))
-        prefix + urlQuery
-
-    let addAction (act:Action) =
-        add "act" <|
-            match act with
-            | Friends               -> "friends"
-            | UpdatesActivity       -> "updates_activity"
-            | UpdatesFriends        -> "updates_friends"
-            | UpdatesPhotos         -> "updates_photos"
-            | UpdatesTaggedPhotos   -> "updates_tagged_photos"
-            | Profile               -> "profile"
-            | _                     -> failwith "Not implemented"
-            
-    // TODO: why does not point-free style work here?
-    let addId id = add "id" id
-    let addTo toVal = add "to" toVal
-    let addFrom from = add "from" from

File src/Linq2vk.Core/UserAPI.fs

-namespace Linq2vk.Core
-
-open System
-open System.Net
-open System.Text.RegularExpressions
-open Linq2vk.Core.Implementation
-
-type UserAPI (prjId:int64) =
-    let WindowSize = 10
-    
-    let mutable _sid = String.Empty
-    
-    let query act =
-        Query.init _sid |> Query.addAction act
-        
-    let userQuery uid act =
-        query act |> Query.addId uid
-        
-    let getItem conv q =
-        q |> Api.getOne |> conv
-        
-    let getAllItems conv q =
-        q |> Api.getAll |> Seq.map conv
-    
-    member this.LoggedIn
-        with get () = String.IsNullOrEmpty(_sid)
-        
-    member this.Login(usr:string, pwd:string) =
-        let query =
-            sprintf "http://login.userapi.com/auth?login=force&site=%d&email=%s&pass=%s" prjId usr pwd
-            
-        let getSid (resp:HttpWebResponse) =        
-            let sidRx = Regex("sid=([a-z0-9]+)")
-            
-            let getMatchedGroup (rx:Regex) =
-                rx.Match >> (fun m -> m.Groups.[1].Value)
-
-            let sid =
-                resp.ResponseUri.AbsoluteUri |> getMatchedGroup sidRx                   
-            sid
-            
-        let sid =
-            Net.processUrlResponseSync query getSid
-        
-        _sid <- sid
-        this.LoggedIn
-
-    member private this.GetFriendsFrom(queryF) =
-        queryF Action.Friends
-        |> getItem Conversions.toFriend
-    
-    member private this.GetFriends(uid:int64) =
-        this.GetFriendsFrom (userQuery uid)
-            
-    member this.MyFriends
-        with get () =
-            this.GetFriendsFrom query
-        
-    member this.StatusUpdates
-        with get () =
-            query Action.UpdatesActivity |>
-                getAllItems Conversions.toStatus
-                
-    member this.FriendsOfFriends
-        with get () =
-            query Action.UpdatesFriends |>
-                getAllItems Conversions.toFriend
-            
-    member this.FriendsPhotos
-        with get () =
-            query Action.UpdatesPhotos |>
-                getAllItems Conversions.toPhoto
-            
-    member this.FriendsTaggedPhotos
-        with get () =
-            query Action.UpdatesTaggedPhotos |>
-                getAllItems Conversions.toPhoto
-
-    member private this.GetProfileFrom(queryF) =
-        queryF Action.Profile
-        |> getItem Conversions.toUserProfile
-    
-    member this.GetUserProfile (uid:int64) =
-        this.GetProfileFrom (userQuery uid)
-        
-    member this.MyProfile
-        with get () = 
-            this.GetProfileFrom query

File src/Linq2vk.vs2010.sln

View file
+
+Microsoft Visual Studio Solution File, Format Version 11.00
+# Visual Studio 2010
+Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "Linq2vk.Core.2010", "Linq2vk.Core\Linq2vk.Core.2010.fsproj", "{219F29D7-C41A-4C66-A740-8F20D724FD2B}"
+EndProject
+Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "Linq2vk.Core.Silverlight.2010", "Linq2vk.Core.Silverlight\Linq2vk.Core.Silverlight.2010.fsproj", "{05D5EDE1-5B6F-48D3-B627-E9BF498773EC}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|Any CPU = Debug|Any CPU
+		Release|Any CPU = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{219F29D7-C41A-4C66-A740-8F20D724FD2B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{219F29D7-C41A-4C66-A740-8F20D724FD2B}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{219F29D7-C41A-4C66-A740-8F20D724FD2B}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{219F29D7-C41A-4C66-A740-8F20D724FD2B}.Release|Any CPU.Build.0 = Release|Any CPU
+		{05D5EDE1-5B6F-48D3-B627-E9BF498773EC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{05D5EDE1-5B6F-48D3-B627-E9BF498773EC}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{05D5EDE1-5B6F-48D3-B627-E9BF498773EC}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{05D5EDE1-5B6F-48D3-B627-E9BF498773EC}.Release|Any CPU.Build.0 = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+EndGlobal