 
      こんにちは
Xamarinは最近、関数型プログラミング言語F#でモバイルアプリケーションを開発する競争を発表しました。
これは、完全なF#サポートを備えたXamarin 3のリリースによるものです。 特に長い間F#を見てきたので、私は日常の作業から気をそらして参加しようと決心しましたが、彼についてもっと詳しく知る機会はありませんでした。 競争に参加するために、私はYoモバイルアプリケーションの突然の離陸を議論する過程で誰かが提案したアイデアを持つアプリケーションを開発することにしました。 引用はここにあります:
スタートアップのアイデア、ワーキングタイトル「Where are you?」
意味は簡単です。少女はアプリケーションをインストールし、その中の若い男性の数を示し、その後、「どこにいますか?」というメッセージを送信するための大きなボタンが表示されます#Startup #idea
どうして?
ご注意
アプリケーションの作業中にこの投稿を書きました。 したがって、それは大きく、時にはあまり論理的ではありません。
Tシャツ
私が最初にしたことは、Xamarin Storeアプリをダウンロードして実行し、F#付きのTシャツを入手することでした。 Cと同じ#私はすでに持っています

むしろ、私は試してみましたが、すぐにビルドの問題をつかみました。 Xamarinの現在のバージョンはF#バージョン3.0をサポートしており、バージョンF#3.1.1のみが無料でダウンロードできます。
F#3.0はVisual Studio Express 2012 for Webパッケージ内にあり、Microsoft Web Platform Installerを使用してスタジオと共にインストールされます。 奇妙なアプローチ。
XamarinとF#が機能するには、FSarp.Coreバージョン4.3.0.0ビルドがGACにあれば十分です。 とにかく、もし誰かがそれを試してみたいなら、ここに直接リンクがあります。
はじめに
Xamarinは現在、Xamarin Studio内でのみF#をサポートしています。 だから、私はしばらくの間、私の大好きなVS2013を忘れて、全体としてかなり良い環境で作業しなければなりませんでした。 Android用の新しいアプリケーションの作成には数秒かかりました。ここでは、F#で動作するAndroid用のHello-worldアプリケーションがあります。
  MainActivity.fs 
        
        
        
      
    
      namespace Xakpc.WhereAreYou.Droid open System open Android.App open Android.Content open Android.OS open Android.Runtime open Android.Views open Android.Widget [<Activity (Label = "Xakpc.WhereAreYou.Droid", MainLauncher = true)>] type WhereAreYouActivity () = inherit Activity () let mutable count:int = 1 override this.OnCreate (bundle) = base.OnCreate (bundle) // Set our view from the "main" layout resource this.SetContentView (Resource_Layout.Main) // Get our button from the layout resource, and attach an event to it let button = this.FindViewById<Button>(Resource_Id.myButton) button.Click.Add (fun args -> button.Text <- sprintf "%d clicks!" count count <- count + 1 )
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     HabrはF#を色付けできないようです。 悲しみ、切望(しかし、ヴァラのサポートがあります)
戦いに行く、ナンバーワンを試みる
アプリケーションがどのように見えるかは、私には明らかでした、3つの画面、3つのプッシュ通知、バックエンドとしての古き良きAzure、vyrviglazny色(Yoに触発された)
次に、開発者の親友である鉛筆と紙。 Mocapesが描画され、コードに転送されました。 Xamarin Component Storeのコンポーネントをプロジェクトに追加します:Azure Mobile ServicesとGoogle Play Services(ICS-今は古いバージョンのAndroidに煩わされたくありません)。
集めてBAM! -最初のレーキ。
  すくい 
 プロジェクトをビルドすると、Xamarinはリソースファイルをビルドします。特に、私が理解しているように、リソースポインターや識別子を含むResource.Designer.fs
      
      ファイルを生成します。 特に、次のコードに変換される識別子Id.endへのポインターがあります
 // aapt resource value: 0x7f070013 static member end = 2131165203
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      単語の終わりはF#のキーであり、コンパイラはエラーを報告します。
   "end"    (FS0010)
      
      の
   "end"    (FS0010)
      
      。 これは、自分で解決できないエラーの1つです。残念ながら、これらのファイルの生成を制御することはできません。
私はすぐにXamarinフォーラムとTwitter Miguel de Icazaに書き込みました-すぐに応答を受け取りました! 開発者は、アルファ版ではこのエラーがすでに修正されていると報告しています。
Xamarin StudioをアルファチャネルとBAMに切り替える! -それでも動作しません。
それは判明します...
Windows Alphaチャンネルはまだそこにないようです...
まあ、それが「ある」まで待つだけで、まだ時間があります。 Google Play開発者サービスはそのままにしておきましょう。
F#について一言
プロジェクトを始めて、私はF#について何も知りませんでしたが、それは「クール」、「モダン」、「非常に便利」だったことを除いて。 新しいプロジェクトで彼を急襲しようとする試みは惨めに失敗しました。
let values = ["item1"; "item2"; "item3"]
      
      理由を理解しようとして、ほぼ15分を費やしました
let values = ["item1"; "item2"; "item3"]
      
      let values = ["item1"; "item2"; "item3"]
      
      はArrayAdapterコンストラクター
listView.Adapter <- new ArrayAdapter(this, Android.Resource.Layout.SimpleListItem1, Android.Resource.Id.Text1, values) 
      
        
        
        
      
      , ,  let values = [|"item1"; "item2"; "item3"|] -   string[],       list (IEnumerable   ) 
      
        
        
        
      
              F#.            www.tryfsharp.org/Learn 
      
        
        
        
      
      
 
      
        
        
        
      
          F# -  ,  
      
        
        
        
      
     
      
        
        
        
      
            F# For Fun And Profit 
      
        
        
        
      
     
      
        
        
        
      
       ,    
      
        
        
        
      
         - . 
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
     
      
        
        
        
      
            hash 
      
        
        
        
      
         MD5  F# 
      
        
        
        
      
      let MD5Hash (input : string) = use md5 = System.Security.Cryptography.MD5.Create() input |> System.Text.Encoding.ASCII.GetBytes |> md5.ComputeHash |> Seq.map (fun c -> c.ToString("X2")) |> Seq.reduce (+)
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
      |>
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      pipeline ,     . 
      
        
        
        
      
         :    GetBytes ->   ->      HEX  ->       (  reduce   +           ) ->    . 
      
        
        
        
      
     
      
        
        
        
      
      ,     C# using System; public string CreateMD5Hash (string input) { MD5 md5 = System.Security.Cryptography.MD5.Create(); byte[] inputBytes = System.Text.Encoding.ASCII.GetBytes (input); byte[] hashBytes = md5.ComputeHash (inputBytes); StringBuilder sb = new StringBuilder(); for (int i = 0; i < hashBytes.Length; i++) { sb.Append (hashBytes[i].ToString ("X2")); } return sb.ToString(); }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
     
      
        
        
        
      
              :        .       AzureServiceWorker (  CLR    ) 
      
        
        
        
      
     
      
        
        
        
      
              -   .   F#    !   Xamarin Studio            . 
      
        
        
        
      
      <ItemGroup> <Compile Include="Resources\Resource.designer.fs" /> <Compile Include="Properties\AssemblyInfo.fs" /> <Compile Include="Helpers\Helpers.fs" /> <Compile Include="Services\User.fs" /> <Compile Include="Services\AzureServiceWorker.fs" /> <Compile Include="IAmHereActivity.fs" /> <Compile Include="WhereAreYouActivity.fs" /> <Compile Include="SignInActivity.fs" /> </ItemGroup>
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
        
      
        
        
        
      
            :    .    Xamarin    Xamarin.Mobile 
      
        
        
        
      
     
      
        
        
        
      
          .  F#         TPL,     Task',      .     F#         Task.  ,     : 
      
        
        
        
      
     module Async = open System.Threading open System.Threading.Tasks let inline AwaitPlainTask (task: Task) = // rethrow exception from preceding task if it fauled let continuation (t : Task) : unit = match t.IsFaulted with | true -> raise t.Exception | arg -> () task.ContinueWith continuation |> Async.AwaitTask
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
             Async.AwaitIAsyncResult >> Async.Ignore
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
           
      
        
        
        
      
     
      
        
        
        
      
                
      
        
        
        
      
     let ExtractUserInfo (x : Contact) = let first = x.Phones |> Seq.tryPick(fun x -> if x.Type = PhoneType.Mobile then Some(x) else None) match first with | Some(first) -> let phone = first.Number |> StripChars [' ';'-';'(';')'] UserInfo.CreateUserInfo((MD5Hash phone), phone, x.DisplayName) | None -> UserInfo.CreateUserInfo("no mobile phone", "no mobile phone", "no mobile phone") // function for async list filling let FillContactsAsync = async { let book = new AddressBook (this) let! result = book.RequestPermission() |> Async.AwaitTask if result then _contacts <- book.ToList() |> Seq.filter (fun (x: Contact) -> not (Seq.isEmpty x.Phones)) |> Seq.map ExtractUserInfo |> Seq.sortBy(fun x -> x.DisplayName) |> Seq.toList let finalContacts = _contacts |> Seq.map (fun x -> x.DisplayName.ToUpperInvariant()) |> Seq.toArray this.ListAdapter <- new ArrayAdapter(this, Resource_Layout.row_contact, finalContacts) else System.Diagnostics.Debug.WriteLine("Permission denied by user or manifest") this.ListAdapter <- new ArrayAdapter(this, Resource_Layout.row_contact, Array.empty) }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
          
      
        
        
        
      
     book.ToList()
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
       List |> Seq.filter (fun (x: Contact) -> not (Seq.isEmpty x.Phones))
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
          |> Seq.map ExtractUserInfo
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
          Contracts  UserInfo,      UserInfo |> Seq.sortBy(fun x -> x.DisplayName)
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      |> Seq.toList
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
       List _contacts <-
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
        mutable  _contacts |> Seq.map (fun x -> x.DisplayName.ToUpperInvariant())<-
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
        UserInfo  string,     - -    |> Seq.toArray<-
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      List  Array    ArrayAdapter 
      
        
        
        
      
        -      List.   . 
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
     
      
        
        
        
      
     Azure Mobile Servcies 
      
        
        
        
      
       -    Azure Mobile Services.       NotificationHub,     Push    .   Azure    , ..      . 
      
        
        
        
      
     
      
        
        
        
      
          ,    
      
        
        
        
      
     module WruConstants = [<Literal>] let TotallyNotAzureServer = "https://YOUR.azure-mobile.net/"; [<Literal>] let TotallyNotAzureKey = "YOUR"
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
       
        
        
        
      
     member this.RegisterMe phone name regId = async { try let table = this.MobileService.GetTable<User>() let usr = { Id = "" PhoneHash = MD5Hash phone Nickname = name RegistrationId = regId } do! table.InsertAsync usr |> Async.AwaitPlainTask return (usr.Id, usr.PhoneHash, usr.Nickname) with | e -> System.Diagnostics.Trace.WriteLine(e.ToString) return (String.Empty,String.Empty,String.Empty) }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     member this.RegisterMe phone name regId = async {
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     -       (     )    .       "computation expression"   workflow.   { }       ! ( bang),  do! (do-bang)  let! (let bang)     User.    ,  F#        ,      
      
        
        
        
      
      let usr = { Id = "" PhoneHash = MD5Hash phone Nickname = name RegistrationId = regId }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     do! table.InsertAsync usr |> Async.AwaitPlainTask
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      do-bang,   await
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      C#. ..             continuation    . return (usr.Id, usr.PhoneHash, usr.Nickname)
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
          Tuple<string,string,string>     .  try ... with | e ->
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      try..catch
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      C# 
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
     
      
        
        
        
      
           .  F#    fst
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      snd
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
          .        2 .     : 
      
        
        
        
      
      let id (c,_,_) = c let phonehash (_,c,_) = c let nickname (_,_,c) = c
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
        : id tuple
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      Id  .. 
      
        
        
        
      
     
      
        
        
        
      
        5  Azure,       Push .       Azure Custom Api  
      
        
        
        
      
     
      
        
        
        
      
          exports.post = function(request, response) { // Use "request.service" to access features of your mobile service, eg: // var tables = request.service.tables; // var push = request.service.push; //response.send(statusCodes.OK, { message : 'Hello World!' }); console.log('Incoming call with requst: ', request.body.RequestId); var usersTable = request.service.tables.getTable('User'); usersTable.where( { id : request.body.TargetId } ) .read( { success: function(results) { if (results.length > 0) { var user = results[0] console.log('Send to results: ', user.Nickname, user.RegistrationId); request.service.push.gcm.send(user.RegistrationId, { RequesterId: request.body.RequesterId, RequesterNickname: request.body.RequesterName, TargetId: user.id, TargetNickname: user.Nickname }, { success: function(gcm_response) { console.log('Push notification sent: ', gcm_response); response.send(statusCodes.OK, { RequestedNickname : user.Nickname }); }, error: function(gcm_error) { console.log('Error sending push notification: ', gcm_error); response.send(statusCodes.INTERNAL_SERVER_ERROR, { RequestedNickname : user.Nickname }); } }); } else { response.send(statusCodes.NO_CONTENT, { RequestedNickname : "" }); } }, error: function(error) { console.log('Error read table: ', error); response.send(statusCodes.INTERNAL_SERVER_ERROR, { RequestedNickname : "" }); } }); };
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
        Push      
      
        
        
        
      
     // Perform Push operation member this.PushAsync targetId myId myNickname = async { try let (request : PushRequest) = { TargetId = targetId RequesterId = myId RequesterName = myNickname } let! result = this.MobileService.InvokeApiAsync<PushRequest, PushResponce>("pushhim", request) |> Async.AwaitTask return result.RequestedNickname with | e -> return e.ToString() }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
           ,    let-bang
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
       do!
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
       
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
          Google Play Services.     F#   .           .    : Xamarin.Android.Support.v7.AppCompat 
      
        
        
        
      
         , Google Play Services ,   . 
      
        
        
        
      
     
      
        
        
        
      
          push notification   .    GCM,  ID,     ID       Push  (.   pushhim).        BroadcastReciever       developer.android.com .     F#         Xamarin Component Store.     Google Cloud Messaging Client         GCM    .        ID 
      
        
        
        
      
     //Check to see that GCM is supported and that the manifest has the correct information GcmClient.CheckDevice(this) GcmClient.CheckManifest(this) // check google play if CheckPlayServices() then // Try to get registration id let regId = GcmClient.GetRegistrationId this if String.IsNullOrEmpty(regId) then // Call to Register the device for Push Notifications GcmClient.Register(this, WruConstants.GcmSender);
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
            
      
        
        
        
      
     
      
        
        
        
      
        . 
      
        
        
        
      
        , -  
      
        
        
        
      
         bitbucket.org/xakpc/whereareyou 
      
        
        
        
      
         ,     
      
        
        
        
      
              ,           "" . 
      
        
        
        
      
     
      
        
        
        
      
      
      
        
        
        
      
     ,   Android   F#.      . 
      
        
        
        
      
     ,       -  Android  F#.   ,       .
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
    
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
    渡すことができません
listView.Adapter <- new ArrayAdapter(this, Android.Resource.Layout.SimpleListItem1, Android.Resource.Id.Text1, values) 
      
        
        
        
      
      , ,  let values = [|"item1"; "item2"; "item3"|] -   string[],       list (IEnumerable   ) 
      
        
        
        
      
              F#.            www.tryfsharp.org/Learn 
      
        
        
        
      
      
 
      
        
        
        
      
          F# -  ,  
      
        
        
        
      
     
      
        
        
        
      
            F# For Fun And Profit 
      
        
        
        
      
     
      
        
        
        
      
       ,    
      
        
        
        
      
         - . 
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
     
      
        
        
        
      
            hash 
      
        
        
        
      
         MD5  F# 
      
        
        
        
      
      let MD5Hash (input : string) = use md5 = System.Security.Cryptography.MD5.Create() input |> System.Text.Encoding.ASCII.GetBytes |> md5.ComputeHash |> Seq.map (fun c -> c.ToString("X2")) |> Seq.reduce (+)
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
      |>
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      pipeline ,     . 
      
        
        
        
      
         :    GetBytes ->   ->      HEX  ->       (  reduce   +           ) ->    . 
      
        
        
        
      
     
      
        
        
        
      
      ,     C# using System; public string CreateMD5Hash (string input) { MD5 md5 = System.Security.Cryptography.MD5.Create(); byte[] inputBytes = System.Text.Encoding.ASCII.GetBytes (input); byte[] hashBytes = md5.ComputeHash (inputBytes); StringBuilder sb = new StringBuilder(); for (int i = 0; i < hashBytes.Length; i++) { sb.Append (hashBytes[i].ToString ("X2")); } return sb.ToString(); }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
     
      
        
        
        
      
              :        .       AzureServiceWorker (  CLR    ) 
      
        
        
        
      
     
      
        
        
        
      
              -   .   F#    !   Xamarin Studio            . 
      
        
        
        
      
      <ItemGroup> <Compile Include="Resources\Resource.designer.fs" /> <Compile Include="Properties\AssemblyInfo.fs" /> <Compile Include="Helpers\Helpers.fs" /> <Compile Include="Services\User.fs" /> <Compile Include="Services\AzureServiceWorker.fs" /> <Compile Include="IAmHereActivity.fs" /> <Compile Include="WhereAreYouActivity.fs" /> <Compile Include="SignInActivity.fs" /> </ItemGroup>
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
        
      
        
        
        
      
            :    .    Xamarin    Xamarin.Mobile 
      
        
        
        
      
     
      
        
        
        
      
          .  F#         TPL,     Task',      .     F#         Task.  ,     : 
      
        
        
        
      
     module Async = open System.Threading open System.Threading.Tasks let inline AwaitPlainTask (task: Task) = // rethrow exception from preceding task if it fauled let continuation (t : Task) : unit = match t.IsFaulted with | true -> raise t.Exception | arg -> () task.ContinueWith continuation |> Async.AwaitTask
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
             Async.AwaitIAsyncResult >> Async.Ignore
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
           
      
        
        
        
      
     
      
        
        
        
      
                
      
        
        
        
      
     let ExtractUserInfo (x : Contact) = let first = x.Phones |> Seq.tryPick(fun x -> if x.Type = PhoneType.Mobile then Some(x) else None) match first with | Some(first) -> let phone = first.Number |> StripChars [' ';'-';'(';')'] UserInfo.CreateUserInfo((MD5Hash phone), phone, x.DisplayName) | None -> UserInfo.CreateUserInfo("no mobile phone", "no mobile phone", "no mobile phone") // function for async list filling let FillContactsAsync = async { let book = new AddressBook (this) let! result = book.RequestPermission() |> Async.AwaitTask if result then _contacts <- book.ToList() |> Seq.filter (fun (x: Contact) -> not (Seq.isEmpty x.Phones)) |> Seq.map ExtractUserInfo |> Seq.sortBy(fun x -> x.DisplayName) |> Seq.toList let finalContacts = _contacts |> Seq.map (fun x -> x.DisplayName.ToUpperInvariant()) |> Seq.toArray this.ListAdapter <- new ArrayAdapter(this, Resource_Layout.row_contact, finalContacts) else System.Diagnostics.Debug.WriteLine("Permission denied by user or manifest") this.ListAdapter <- new ArrayAdapter(this, Resource_Layout.row_contact, Array.empty) }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
          
      
        
        
        
      
     book.ToList()
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
       List |> Seq.filter (fun (x: Contact) -> not (Seq.isEmpty x.Phones))
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
          |> Seq.map ExtractUserInfo
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
          Contracts  UserInfo,      UserInfo |> Seq.sortBy(fun x -> x.DisplayName)
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      |> Seq.toList
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
       List _contacts <-
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
        mutable  _contacts |> Seq.map (fun x -> x.DisplayName.ToUpperInvariant())<-
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
        UserInfo  string,     - -    |> Seq.toArray<-
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      List  Array    ArrayAdapter 
      
        
        
        
      
        -      List.   . 
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
     
      
        
        
        
      
     Azure Mobile Servcies 
      
        
        
        
      
       -    Azure Mobile Services.       NotificationHub,     Push    .   Azure    , ..      . 
      
        
        
        
      
     
      
        
        
        
      
          ,    
      
        
        
        
      
     module WruConstants = [<Literal>] let TotallyNotAzureServer = "https://YOUR.azure-mobile.net/"; [<Literal>] let TotallyNotAzureKey = "YOUR"
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
       
        
        
        
      
     member this.RegisterMe phone name regId = async { try let table = this.MobileService.GetTable<User>() let usr = { Id = "" PhoneHash = MD5Hash phone Nickname = name RegistrationId = regId } do! table.InsertAsync usr |> Async.AwaitPlainTask return (usr.Id, usr.PhoneHash, usr.Nickname) with | e -> System.Diagnostics.Trace.WriteLine(e.ToString) return (String.Empty,String.Empty,String.Empty) }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     member this.RegisterMe phone name regId = async {
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     -       (     )    .       "computation expression"   workflow.   { }       ! ( bang),  do! (do-bang)  let! (let bang)     User.    ,  F#        ,      
      
        
        
        
      
      let usr = { Id = "" PhoneHash = MD5Hash phone Nickname = name RegistrationId = regId }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     do! table.InsertAsync usr |> Async.AwaitPlainTask
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      do-bang,   await
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      C#. ..             continuation    . return (usr.Id, usr.PhoneHash, usr.Nickname)
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
          Tuple<string,string,string>     .  try ... with | e ->
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      try..catch
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      C# 
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
     
      
        
        
        
      
           .  F#    fst
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      snd
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
          .        2 .     : 
      
        
        
        
      
      let id (c,_,_) = c let phonehash (_,c,_) = c let nickname (_,_,c) = c
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
        : id tuple
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      Id  .. 
      
        
        
        
      
     
      
        
        
        
      
        5  Azure,       Push .       Azure Custom Api  
      
        
        
        
      
     
      
        
        
        
      
          exports.post = function(request, response) { // Use "request.service" to access features of your mobile service, eg: // var tables = request.service.tables; // var push = request.service.push; //response.send(statusCodes.OK, { message : 'Hello World!' }); console.log('Incoming call with requst: ', request.body.RequestId); var usersTable = request.service.tables.getTable('User'); usersTable.where( { id : request.body.TargetId } ) .read( { success: function(results) { if (results.length > 0) { var user = results[0] console.log('Send to results: ', user.Nickname, user.RegistrationId); request.service.push.gcm.send(user.RegistrationId, { RequesterId: request.body.RequesterId, RequesterNickname: request.body.RequesterName, TargetId: user.id, TargetNickname: user.Nickname }, { success: function(gcm_response) { console.log('Push notification sent: ', gcm_response); response.send(statusCodes.OK, { RequestedNickname : user.Nickname }); }, error: function(gcm_error) { console.log('Error sending push notification: ', gcm_error); response.send(statusCodes.INTERNAL_SERVER_ERROR, { RequestedNickname : user.Nickname }); } }); } else { response.send(statusCodes.NO_CONTENT, { RequestedNickname : "" }); } }, error: function(error) { console.log('Error read table: ', error); response.send(statusCodes.INTERNAL_SERVER_ERROR, { RequestedNickname : "" }); } }); };
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
        Push      
      
        
        
        
      
     // Perform Push operation member this.PushAsync targetId myId myNickname = async { try let (request : PushRequest) = { TargetId = targetId RequesterId = myId RequesterName = myNickname } let! result = this.MobileService.InvokeApiAsync<PushRequest, PushResponce>("pushhim", request) |> Async.AwaitTask return result.RequestedNickname with | e -> return e.ToString() }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
           ,    let-bang
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
       do!
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
       
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
          Google Play Services.     F#   .           .    : Xamarin.Android.Support.v7.AppCompat 
      
        
        
        
      
         , Google Play Services ,   . 
      
        
        
        
      
     
      
        
        
        
      
          push notification   .    GCM,  ID,     ID       Push  (.   pushhim).        BroadcastReciever       developer.android.com .     F#         Xamarin Component Store.     Google Cloud Messaging Client         GCM    .        ID 
      
        
        
        
      
     //Check to see that GCM is supported and that the manifest has the correct information GcmClient.CheckDevice(this) GcmClient.CheckManifest(this) // check google play if CheckPlayServices() then // Try to get registration id let regId = GcmClient.GetRegistrationId this if String.IsNullOrEmpty(regId) then // Call to Register the device for Push Notifications GcmClient.Register(this, WruConstants.GcmSender);
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
            
      
        
        
        
      
     
      
        
        
        
      
        . 
      
        
        
        
      
        , -  
      
        
        
        
      
         bitbucket.org/xakpc/whereareyou 
      
        
        
        
      
         ,     
      
        
        
        
      
              ,           "" . 
      
        
        
        
      
     
      
        
        
        
      
      
      
        
        
        
      
     ,   Android   F#.      . 
      
        
        
        
      
     ,       -  Android  F#.   ,       .
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
    
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
    listView.Adapter <- new ArrayAdapter(this, Android.Resource.Layout.SimpleListItem1, Android.Resource.Id.Text1, values) 
      
        
        
        
      
      , ,  let values = [|"item1"; "item2"; "item3"|]
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     -   string[],       list (IEnumerable   ) 
      
        
        
        
      
              F#.            www.tryfsharp.org/Learn 
      
        
        
        
      
      
 
      
        
        
        
      
          F# -  ,  
      
        
        
        
      
     
      
        
        
        
      
            F# For Fun And Profit 
      
        
        
        
      
     
      
        
        
        
      
       ,    
      
        
        
        
      
         - . 
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
     
      
        
        
        
      
            hash 
      
        
        
        
      
         MD5  F# 
      
        
        
        
      
      let MD5Hash (input : string) = use md5 = System.Security.Cryptography.MD5.Create() input |> System.Text.Encoding.ASCII.GetBytes |> md5.ComputeHash |> Seq.map (fun c -> c.ToString("X2")) |> Seq.reduce (+)
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
      |>
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      pipeline ,     . 
      
        
        
        
      
         :    GetBytes ->   ->      HEX  ->       (  reduce   +           ) ->    . 
      
        
        
        
      
     
      
        
        
        
      
      ,     C# using System; public string CreateMD5Hash (string input) { MD5 md5 = System.Security.Cryptography.MD5.Create(); byte[] inputBytes = System.Text.Encoding.ASCII.GetBytes (input); byte[] hashBytes = md5.ComputeHash (inputBytes); StringBuilder sb = new StringBuilder(); for (int i = 0; i < hashBytes.Length; i++) { sb.Append (hashBytes[i].ToString ("X2")); } return sb.ToString(); }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
     
      
        
        
        
      
              :        .       AzureServiceWorker (  CLR    ) 
      
        
        
        
      
     
      
        
        
        
      
              -   .   F#    !   Xamarin Studio            . 
      
        
        
        
      
      <ItemGroup> <Compile Include="Resources\Resource.designer.fs" /> <Compile Include="Properties\AssemblyInfo.fs" /> <Compile Include="Helpers\Helpers.fs" /> <Compile Include="Services\User.fs" /> <Compile Include="Services\AzureServiceWorker.fs" /> <Compile Include="IAmHereActivity.fs" /> <Compile Include="WhereAreYouActivity.fs" /> <Compile Include="SignInActivity.fs" /> </ItemGroup>
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
        
      
        
        
        
      
            :    .    Xamarin    Xamarin.Mobile 
      
        
        
        
      
     
      
        
        
        
      
          .  F#         TPL,     Task',      .     F#         Task.  ,     : 
      
        
        
        
      
     module Async = open System.Threading open System.Threading.Tasks let inline AwaitPlainTask (task: Task) = // rethrow exception from preceding task if it fauled let continuation (t : Task) : unit = match t.IsFaulted with | true -> raise t.Exception | arg -> () task.ContinueWith continuation |> Async.AwaitTask
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
             Async.AwaitIAsyncResult >> Async.Ignore
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
           
      
        
        
        
      
     
      
        
        
        
      
                
      
        
        
        
      
     let ExtractUserInfo (x : Contact) = let first = x.Phones |> Seq.tryPick(fun x -> if x.Type = PhoneType.Mobile then Some(x) else None) match first with | Some(first) -> let phone = first.Number |> StripChars [' ';'-';'(';')'] UserInfo.CreateUserInfo((MD5Hash phone), phone, x.DisplayName) | None -> UserInfo.CreateUserInfo("no mobile phone", "no mobile phone", "no mobile phone") // function for async list filling let FillContactsAsync = async { let book = new AddressBook (this) let! result = book.RequestPermission() |> Async.AwaitTask if result then _contacts <- book.ToList() |> Seq.filter (fun (x: Contact) -> not (Seq.isEmpty x.Phones)) |> Seq.map ExtractUserInfo |> Seq.sortBy(fun x -> x.DisplayName) |> Seq.toList let finalContacts = _contacts |> Seq.map (fun x -> x.DisplayName.ToUpperInvariant()) |> Seq.toArray this.ListAdapter <- new ArrayAdapter(this, Resource_Layout.row_contact, finalContacts) else System.Diagnostics.Debug.WriteLine("Permission denied by user or manifest") this.ListAdapter <- new ArrayAdapter(this, Resource_Layout.row_contact, Array.empty) }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
          
      
        
        
        
      
     book.ToList()
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
       List |> Seq.filter (fun (x: Contact) -> not (Seq.isEmpty x.Phones))
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
          |> Seq.map ExtractUserInfo
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
          Contracts  UserInfo,      UserInfo |> Seq.sortBy(fun x -> x.DisplayName)
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      |> Seq.toList
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
       List _contacts <-
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
        mutable  _contacts |> Seq.map (fun x -> x.DisplayName.ToUpperInvariant())<-
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
        UserInfo  string,     - -    |> Seq.toArray<-
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      List  Array    ArrayAdapter 
      
        
        
        
      
        -      List.   . 
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
     
      
        
        
        
      
     Azure Mobile Servcies 
      
        
        
        
      
       -    Azure Mobile Services.       NotificationHub,     Push    .   Azure    , ..      . 
      
        
        
        
      
     
      
        
        
        
      
          ,    
      
        
        
        
      
     module WruConstants = [<Literal>] let TotallyNotAzureServer = "https://YOUR.azure-mobile.net/"; [<Literal>] let TotallyNotAzureKey = "YOUR"
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
       
        
        
        
      
     member this.RegisterMe phone name regId = async { try let table = this.MobileService.GetTable<User>() let usr = { Id = "" PhoneHash = MD5Hash phone Nickname = name RegistrationId = regId } do! table.InsertAsync usr |> Async.AwaitPlainTask return (usr.Id, usr.PhoneHash, usr.Nickname) with | e -> System.Diagnostics.Trace.WriteLine(e.ToString) return (String.Empty,String.Empty,String.Empty) }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     member this.RegisterMe phone name regId = async {
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     -       (     )    .       "computation expression"   workflow.   { }       ! ( bang),  do! (do-bang)  let! (let bang)     User.    ,  F#        ,      
      
        
        
        
      
      let usr = { Id = "" PhoneHash = MD5Hash phone Nickname = name RegistrationId = regId }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     do! table.InsertAsync usr |> Async.AwaitPlainTask
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      do-bang,   await
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      C#. ..             continuation    . return (usr.Id, usr.PhoneHash, usr.Nickname)
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
          Tuple<string,string,string>     .  try ... with | e ->
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      try..catch
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      C# 
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
     
      
        
        
        
      
           .  F#    fst
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      snd
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
          .        2 .     : 
      
        
        
        
      
      let id (c,_,_) = c let phonehash (_,c,_) = c let nickname (_,_,c) = c
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
        : id tuple
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      Id  .. 
      
        
        
        
      
     
      
        
        
        
      
        5  Azure,       Push .       Azure Custom Api  
      
        
        
        
      
     
      
        
        
        
      
          exports.post = function(request, response) { // Use "request.service" to access features of your mobile service, eg: // var tables = request.service.tables; // var push = request.service.push; //response.send(statusCodes.OK, { message : 'Hello World!' }); console.log('Incoming call with requst: ', request.body.RequestId); var usersTable = request.service.tables.getTable('User'); usersTable.where( { id : request.body.TargetId } ) .read( { success: function(results) { if (results.length > 0) { var user = results[0] console.log('Send to results: ', user.Nickname, user.RegistrationId); request.service.push.gcm.send(user.RegistrationId, { RequesterId: request.body.RequesterId, RequesterNickname: request.body.RequesterName, TargetId: user.id, TargetNickname: user.Nickname }, { success: function(gcm_response) { console.log('Push notification sent: ', gcm_response); response.send(statusCodes.OK, { RequestedNickname : user.Nickname }); }, error: function(gcm_error) { console.log('Error sending push notification: ', gcm_error); response.send(statusCodes.INTERNAL_SERVER_ERROR, { RequestedNickname : user.Nickname }); } }); } else { response.send(statusCodes.NO_CONTENT, { RequestedNickname : "" }); } }, error: function(error) { console.log('Error read table: ', error); response.send(statusCodes.INTERNAL_SERVER_ERROR, { RequestedNickname : "" }); } }); };
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
        Push      
      
        
        
        
      
     // Perform Push operation member this.PushAsync targetId myId myNickname = async { try let (request : PushRequest) = { TargetId = targetId RequesterId = myId RequesterName = myNickname } let! result = this.MobileService.InvokeApiAsync<PushRequest, PushResponce>("pushhim", request) |> Async.AwaitTask return result.RequestedNickname with | e -> return e.ToString() }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
           ,    let-bang
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
       do!
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
       
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
          Google Play Services.     F#   .           .    : Xamarin.Android.Support.v7.AppCompat 
      
        
        
        
      
         , Google Play Services ,   . 
      
        
        
        
      
     
      
        
        
        
      
          push notification   .    GCM,  ID,     ID       Push  (.   pushhim).        BroadcastReciever       developer.android.com .     F#         Xamarin Component Store.     Google Cloud Messaging Client         GCM    .        ID 
      
        
        
        
      
     //Check to see that GCM is supported and that the manifest has the correct information GcmClient.CheckDevice(this) GcmClient.CheckManifest(this) // check google play if CheckPlayServices() then // Try to get registration id let regId = GcmClient.GetRegistrationId this if String.IsNullOrEmpty(regId) then // Call to Register the device for Push Notifications GcmClient.Register(this, WruConstants.GcmSender);
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
            
      
        
        
        
      
     
      
        
        
        
      
        . 
      
        
        
        
      
        , -  
      
        
        
        
      
         bitbucket.org/xakpc/whereareyou 
      
        
        
        
      
         ,     
      
        
        
        
      
              ,           "" . 
      
        
        
        
      
     
      
        
        
        
      
      
      
        
        
        
      
     ,   Android   F#.      . 
      
        
        
        
      
     ,       -  Android  F#.   ,       .
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
    listView.Adapter <- new ArrayAdapter(this, Android.Resource.Layout.SimpleListItem1, Android.Resource.Id.Text1, values) 
      
        
        
        
      
      , ,  let values = [|"item1"; "item2"; "item3"|]
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     -   string[],       list (IEnumerable   ) 
      
        
        
        
      
              F#.            www.tryfsharp.org/Learn 
      
        
        
        
      
      
 
      
        
        
        
      
          F# -  ,  
      
        
        
        
      
     
      
        
        
        
      
            F# For Fun And Profit 
      
        
        
        
      
     
      
        
        
        
      
       ,    
      
        
        
        
      
         - . 
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
     
      
        
        
        
      
            hash 
      
        
        
        
      
         MD5  F# 
      
        
        
        
      
      let MD5Hash (input : string) = use md5 = System.Security.Cryptography.MD5.Create() input |> System.Text.Encoding.ASCII.GetBytes |> md5.ComputeHash |> Seq.map (fun c -> c.ToString("X2")) |> Seq.reduce (+)
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
      |>
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      pipeline ,     . 
      
        
        
        
      
         :    GetBytes ->   ->      HEX  ->       (  reduce   +           ) ->    . 
      
        
        
        
      
     
      
        
        
        
      
      ,     C# using System; public string CreateMD5Hash (string input) { MD5 md5 = System.Security.Cryptography.MD5.Create(); byte[] inputBytes = System.Text.Encoding.ASCII.GetBytes (input); byte[] hashBytes = md5.ComputeHash (inputBytes); StringBuilder sb = new StringBuilder(); for (int i = 0; i < hashBytes.Length; i++) { sb.Append (hashBytes[i].ToString ("X2")); } return sb.ToString(); }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
     
      
        
        
        
      
              :        .       AzureServiceWorker (  CLR    ) 
      
        
        
        
      
     
      
        
        
        
      
              -   .   F#    !   Xamarin Studio            . 
      
        
        
        
      
      <ItemGroup> <Compile Include="Resources\Resource.designer.fs" /> <Compile Include="Properties\AssemblyInfo.fs" /> <Compile Include="Helpers\Helpers.fs" /> <Compile Include="Services\User.fs" /> <Compile Include="Services\AzureServiceWorker.fs" /> <Compile Include="IAmHereActivity.fs" /> <Compile Include="WhereAreYouActivity.fs" /> <Compile Include="SignInActivity.fs" /> </ItemGroup>
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
        
      
        
        
        
      
            :    .    Xamarin    Xamarin.Mobile 
      
        
        
        
      
     
      
        
        
        
      
          .  F#         TPL,     Task',      .     F#         Task.  ,     : 
      
        
        
        
      
     module Async = open System.Threading open System.Threading.Tasks let inline AwaitPlainTask (task: Task) = // rethrow exception from preceding task if it fauled let continuation (t : Task) : unit = match t.IsFaulted with | true -> raise t.Exception | arg -> () task.ContinueWith continuation |> Async.AwaitTask
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
             Async.AwaitIAsyncResult >> Async.Ignore
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
           
      
        
        
        
      
     
      
        
        
        
      
                
      
        
        
        
      
     let ExtractUserInfo (x : Contact) = let first = x.Phones |> Seq.tryPick(fun x -> if x.Type = PhoneType.Mobile then Some(x) else None) match first with | Some(first) -> let phone = first.Number |> StripChars [' ';'-';'(';')'] UserInfo.CreateUserInfo((MD5Hash phone), phone, x.DisplayName) | None -> UserInfo.CreateUserInfo("no mobile phone", "no mobile phone", "no mobile phone") // function for async list filling let FillContactsAsync = async { let book = new AddressBook (this) let! result = book.RequestPermission() |> Async.AwaitTask if result then _contacts <- book.ToList() |> Seq.filter (fun (x: Contact) -> not (Seq.isEmpty x.Phones)) |> Seq.map ExtractUserInfo |> Seq.sortBy(fun x -> x.DisplayName) |> Seq.toList let finalContacts = _contacts |> Seq.map (fun x -> x.DisplayName.ToUpperInvariant()) |> Seq.toArray this.ListAdapter <- new ArrayAdapter(this, Resource_Layout.row_contact, finalContacts) else System.Diagnostics.Debug.WriteLine("Permission denied by user or manifest") this.ListAdapter <- new ArrayAdapter(this, Resource_Layout.row_contact, Array.empty) }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
          
      
        
        
        
      
     book.ToList()
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
       List |> Seq.filter (fun (x: Contact) -> not (Seq.isEmpty x.Phones))
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
          |> Seq.map ExtractUserInfo
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
          Contracts  UserInfo,      UserInfo |> Seq.sortBy(fun x -> x.DisplayName)
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      |> Seq.toList
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
       List _contacts <-
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
        mutable  _contacts |> Seq.map (fun x -> x.DisplayName.ToUpperInvariant())<-
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
        UserInfo  string,     - -    |> Seq.toArray<-
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      List  Array    ArrayAdapter 
      
        
        
        
      
        -      List.   . 
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
     
      
        
        
        
      
     Azure Mobile Servcies 
      
        
        
        
      
       -    Azure Mobile Services.       NotificationHub,     Push    .   Azure    , ..      . 
      
        
        
        
      
     
      
        
        
        
      
          ,    
      
        
        
        
      
     module WruConstants = [<Literal>] let TotallyNotAzureServer = "https://YOUR.azure-mobile.net/"; [<Literal>] let TotallyNotAzureKey = "YOUR"
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
       
        
        
        
      
     member this.RegisterMe phone name regId = async { try let table = this.MobileService.GetTable<User>() let usr = { Id = "" PhoneHash = MD5Hash phone Nickname = name RegistrationId = regId } do! table.InsertAsync usr |> Async.AwaitPlainTask return (usr.Id, usr.PhoneHash, usr.Nickname) with | e -> System.Diagnostics.Trace.WriteLine(e.ToString) return (String.Empty,String.Empty,String.Empty) }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     member this.RegisterMe phone name regId = async {
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     -       (     )    .       "computation expression"   workflow.   { }       ! ( bang),  do! (do-bang)  let! (let bang)     User.    ,  F#        ,      
      
        
        
        
      
      let usr = { Id = "" PhoneHash = MD5Hash phone Nickname = name RegistrationId = regId }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     do! table.InsertAsync usr |> Async.AwaitPlainTask
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      do-bang,   await
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      C#. ..             continuation    . return (usr.Id, usr.PhoneHash, usr.Nickname)
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
          Tuple<string,string,string>     .  try ... with | e ->
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      try..catch
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      C# 
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
     
      
        
        
        
      
           .  F#    fst
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      snd
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
          .        2 .     : 
      
        
        
        
      
      let id (c,_,_) = c let phonehash (_,c,_) = c let nickname (_,_,c) = c
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
        : id tuple
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      Id  .. 
      
        
        
        
      
     
      
        
        
        
      
        5  Azure,       Push .       Azure Custom Api  
      
        
        
        
      
     
      
        
        
        
      
          exports.post = function(request, response) { // Use "request.service" to access features of your mobile service, eg: // var tables = request.service.tables; // var push = request.service.push; //response.send(statusCodes.OK, { message : 'Hello World!' }); console.log('Incoming call with requst: ', request.body.RequestId); var usersTable = request.service.tables.getTable('User'); usersTable.where( { id : request.body.TargetId } ) .read( { success: function(results) { if (results.length > 0) { var user = results[0] console.log('Send to results: ', user.Nickname, user.RegistrationId); request.service.push.gcm.send(user.RegistrationId, { RequesterId: request.body.RequesterId, RequesterNickname: request.body.RequesterName, TargetId: user.id, TargetNickname: user.Nickname }, { success: function(gcm_response) { console.log('Push notification sent: ', gcm_response); response.send(statusCodes.OK, { RequestedNickname : user.Nickname }); }, error: function(gcm_error) { console.log('Error sending push notification: ', gcm_error); response.send(statusCodes.INTERNAL_SERVER_ERROR, { RequestedNickname : user.Nickname }); } }); } else { response.send(statusCodes.NO_CONTENT, { RequestedNickname : "" }); } }, error: function(error) { console.log('Error read table: ', error); response.send(statusCodes.INTERNAL_SERVER_ERROR, { RequestedNickname : "" }); } }); };
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
        Push      
      
        
        
        
      
     // Perform Push operation member this.PushAsync targetId myId myNickname = async { try let (request : PushRequest) = { TargetId = targetId RequesterId = myId RequesterName = myNickname } let! result = this.MobileService.InvokeApiAsync<PushRequest, PushResponce>("pushhim", request) |> Async.AwaitTask return result.RequestedNickname with | e -> return e.ToString() }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
           ,    let-bang
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
       do!
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
       
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
          Google Play Services.     F#   .           .    : Xamarin.Android.Support.v7.AppCompat 
      
        
        
        
      
         , Google Play Services ,   . 
      
        
        
        
      
     
      
        
        
        
      
          push notification   .    GCM,  ID,     ID       Push  (.   pushhim).        BroadcastReciever       developer.android.com .     F#         Xamarin Component Store.     Google Cloud Messaging Client         GCM    .        ID 
      
        
        
        
      
     //Check to see that GCM is supported and that the manifest has the correct information GcmClient.CheckDevice(this) GcmClient.CheckManifest(this) // check google play if CheckPlayServices() then // Try to get registration id let regId = GcmClient.GetRegistrationId this if String.IsNullOrEmpty(regId) then // Call to Register the device for Push Notifications GcmClient.Register(this, WruConstants.GcmSender);
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
            
      
        
        
        
      
     
      
        
        
        
      
        . 
      
        
        
        
      
        , -  
      
        
        
        
      
         bitbucket.org/xakpc/whereareyou 
      
        
        
        
      
         ,     
      
        
        
        
      
              ,           "" . 
      
        
        
        
      
     
      
        
        
        
      
      
      
        
        
        
      
     ,   Android   F#.      . 
      
        
        
        
      
     ,       -  Android  F#.   ,       .
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     listView.Adapter <- new ArrayAdapter(this, Android.Resource.Layout.SimpleListItem1, Android.Resource.Id.Text1, values) 
      
        
        
        
      
      , ,  let values = [|"item1"; "item2"; "item3"|]
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     -   string[],       list (IEnumerable   ) 
      
        
        
        
      
              F#.            www.tryfsharp.org/Learn 
      
        
        
        
      
      
 
      
        
        
        
      
          F# -  ,  
      
        
        
        
      
     
      
        
        
        
      
            F# For Fun And Profit 
      
        
        
        
      
     
      
        
        
        
      
       ,    
      
        
        
        
      
         - . 
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
     
      
        
        
        
      
            hash 
      
        
        
        
      
         MD5  F# 
      
        
        
        
      
      let MD5Hash (input : string) = use md5 = System.Security.Cryptography.MD5.Create() input |> System.Text.Encoding.ASCII.GetBytes |> md5.ComputeHash |> Seq.map (fun c -> c.ToString("X2")) |> Seq.reduce (+)
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
      |>
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      pipeline ,     . 
      
        
        
        
      
         :    GetBytes ->   ->      HEX  ->       (  reduce   +           ) ->    . 
      
        
        
        
      
     
      
        
        
        
      
      ,     C# using System; public string CreateMD5Hash (string input) { MD5 md5 = System.Security.Cryptography.MD5.Create(); byte[] inputBytes = System.Text.Encoding.ASCII.GetBytes (input); byte[] hashBytes = md5.ComputeHash (inputBytes); StringBuilder sb = new StringBuilder(); for (int i = 0; i < hashBytes.Length; i++) { sb.Append (hashBytes[i].ToString ("X2")); } return sb.ToString(); }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
     
      
        
        
        
      
              :        .       AzureServiceWorker (  CLR    ) 
      
        
        
        
      
     
      
        
        
        
      
              -   .   F#    !   Xamarin Studio            . 
      
        
        
        
      
      <ItemGroup> <Compile Include="Resources\Resource.designer.fs" /> <Compile Include="Properties\AssemblyInfo.fs" /> <Compile Include="Helpers\Helpers.fs" /> <Compile Include="Services\User.fs" /> <Compile Include="Services\AzureServiceWorker.fs" /> <Compile Include="IAmHereActivity.fs" /> <Compile Include="WhereAreYouActivity.fs" /> <Compile Include="SignInActivity.fs" /> </ItemGroup>
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
        
      
        
        
        
      
            :    .    Xamarin    Xamarin.Mobile 
      
        
        
        
      
     
      
        
        
        
      
          .  F#         TPL,     Task',      .     F#         Task.  ,     : 
      
        
        
        
      
     module Async = open System.Threading open System.Threading.Tasks let inline AwaitPlainTask (task: Task) = // rethrow exception from preceding task if it fauled let continuation (t : Task) : unit = match t.IsFaulted with | true -> raise t.Exception | arg -> () task.ContinueWith continuation |> Async.AwaitTask
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
             Async.AwaitIAsyncResult >> Async.Ignore
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
           
      
        
        
        
      
     
      
        
        
        
      
                
      
        
        
        
      
     let ExtractUserInfo (x : Contact) = let first = x.Phones |> Seq.tryPick(fun x -> if x.Type = PhoneType.Mobile then Some(x) else None) match first with | Some(first) -> let phone = first.Number |> StripChars [' ';'-';'(';')'] UserInfo.CreateUserInfo((MD5Hash phone), phone, x.DisplayName) | None -> UserInfo.CreateUserInfo("no mobile phone", "no mobile phone", "no mobile phone") // function for async list filling let FillContactsAsync = async { let book = new AddressBook (this) let! result = book.RequestPermission() |> Async.AwaitTask if result then _contacts <- book.ToList() |> Seq.filter (fun (x: Contact) -> not (Seq.isEmpty x.Phones)) |> Seq.map ExtractUserInfo |> Seq.sortBy(fun x -> x.DisplayName) |> Seq.toList let finalContacts = _contacts |> Seq.map (fun x -> x.DisplayName.ToUpperInvariant()) |> Seq.toArray this.ListAdapter <- new ArrayAdapter(this, Resource_Layout.row_contact, finalContacts) else System.Diagnostics.Debug.WriteLine("Permission denied by user or manifest") this.ListAdapter <- new ArrayAdapter(this, Resource_Layout.row_contact, Array.empty) }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
          
      
        
        
        
      
     book.ToList()
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
       List |> Seq.filter (fun (x: Contact) -> not (Seq.isEmpty x.Phones))
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
          |> Seq.map ExtractUserInfo
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
          Contracts  UserInfo,      UserInfo |> Seq.sortBy(fun x -> x.DisplayName)
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      |> Seq.toList
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
       List _contacts <-
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
        mutable  _contacts |> Seq.map (fun x -> x.DisplayName.ToUpperInvariant())<-
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
        UserInfo  string,     - -    |> Seq.toArray<-
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      List  Array    ArrayAdapter 
      
        
        
        
      
        -      List.   . 
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
     
      
        
        
        
      
     Azure Mobile Servcies 
      
        
        
        
      
       -    Azure Mobile Services.       NotificationHub,     Push    .   Azure    , ..      . 
      
        
        
        
      
     
      
        
        
        
      
          ,    
      
        
        
        
      
     module WruConstants = [<Literal>] let TotallyNotAzureServer = "https://YOUR.azure-mobile.net/"; [<Literal>] let TotallyNotAzureKey = "YOUR"
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
       
        
        
        
      
     member this.RegisterMe phone name regId = async { try let table = this.MobileService.GetTable<User>() let usr = { Id = "" PhoneHash = MD5Hash phone Nickname = name RegistrationId = regId } do! table.InsertAsync usr |> Async.AwaitPlainTask return (usr.Id, usr.PhoneHash, usr.Nickname) with | e -> System.Diagnostics.Trace.WriteLine(e.ToString) return (String.Empty,String.Empty,String.Empty) }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     member this.RegisterMe phone name regId = async {
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     -       (     )    .       "computation expression"   workflow.   { }       ! ( bang),  do! (do-bang)  let! (let bang)     User.    ,  F#        ,      
      
        
        
        
      
      let usr = { Id = "" PhoneHash = MD5Hash phone Nickname = name RegistrationId = regId }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     do! table.InsertAsync usr |> Async.AwaitPlainTask
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      do-bang,   await
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      C#. ..             continuation    . return (usr.Id, usr.PhoneHash, usr.Nickname)
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
          Tuple<string,string,string>     .  try ... with | e ->
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      try..catch
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      C# 
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
     
      
        
        
        
      
           .  F#    fst
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      snd
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
          .        2 .     : 
      
        
        
        
      
      let id (c,_,_) = c let phonehash (_,c,_) = c let nickname (_,_,c) = c
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
        : id tuple
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      Id  .. 
      
        
        
        
      
     
      
        
        
        
      
        5  Azure,       Push .       Azure Custom Api  
      
        
        
        
      
     
      
        
        
        
      
          exports.post = function(request, response) { // Use "request.service" to access features of your mobile service, eg: // var tables = request.service.tables; // var push = request.service.push; //response.send(statusCodes.OK, { message : 'Hello World!' }); console.log('Incoming call with requst: ', request.body.RequestId); var usersTable = request.service.tables.getTable('User'); usersTable.where( { id : request.body.TargetId } ) .read( { success: function(results) { if (results.length > 0) { var user = results[0] console.log('Send to results: ', user.Nickname, user.RegistrationId); request.service.push.gcm.send(user.RegistrationId, { RequesterId: request.body.RequesterId, RequesterNickname: request.body.RequesterName, TargetId: user.id, TargetNickname: user.Nickname }, { success: function(gcm_response) { console.log('Push notification sent: ', gcm_response); response.send(statusCodes.OK, { RequestedNickname : user.Nickname }); }, error: function(gcm_error) { console.log('Error sending push notification: ', gcm_error); response.send(statusCodes.INTERNAL_SERVER_ERROR, { RequestedNickname : user.Nickname }); } }); } else { response.send(statusCodes.NO_CONTENT, { RequestedNickname : "" }); } }, error: function(error) { console.log('Error read table: ', error); response.send(statusCodes.INTERNAL_SERVER_ERROR, { RequestedNickname : "" }); } }); };
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
        Push      
      
        
        
        
      
     // Perform Push operation member this.PushAsync targetId myId myNickname = async { try let (request : PushRequest) = { TargetId = targetId RequesterId = myId RequesterName = myNickname } let! result = this.MobileService.InvokeApiAsync<PushRequest, PushResponce>("pushhim", request) |> Async.AwaitTask return result.RequestedNickname with | e -> return e.ToString() }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
           ,    let-bang
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
       do!
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
       
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
          Google Play Services.     F#   .           .    : Xamarin.Android.Support.v7.AppCompat 
      
        
        
        
      
         , Google Play Services ,   . 
      
        
        
        
      
     
      
        
        
        
      
          push notification   .    GCM,  ID,     ID       Push  (.   pushhim).        BroadcastReciever       developer.android.com .     F#         Xamarin Component Store.     Google Cloud Messaging Client         GCM    .        ID 
      
        
        
        
      
     //Check to see that GCM is supported and that the manifest has the correct information GcmClient.CheckDevice(this) GcmClient.CheckManifest(this) // check google play if CheckPlayServices() then // Try to get registration id let regId = GcmClient.GetRegistrationId this if String.IsNullOrEmpty(regId) then // Call to Register the device for Push Notifications GcmClient.Register(this, WruConstants.GcmSender);
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
            
      
        
        
        
      
     
      
        
        
        
      
        . 
      
        
        
        
      
        , -  
      
        
        
        
      
         bitbucket.org/xakpc/whereareyou 
      
        
        
        
      
         ,     
      
        
        
        
      
              ,           "" . 
      
        
        
        
      
     
      
        
        
        
      
      
      
        
        
        
      
     ,   Android   F#.      . 
      
        
        
        
      
     ,       -  Android  F#.   ,       .
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
    
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
 listView.Adapter <- new ArrayAdapter(this, Android.Resource.Layout.SimpleListItem1, Android.Resource.Id.Text1, values) 
      
        
        
        
      
      , ,  let values = [|"item1"; "item2"; "item3"|]
      
      - string[], list (IEnumerable )
F#. www.tryfsharp.org/Learn
 
 
      F# - ,
F# For Fun And Profit
,
- .
 
 
      hash
MD5 F#
 let MD5Hash (input : string) = use md5 = System.Security.Cryptography.MD5.Create() input |> System.Text.Encoding.ASCII.GetBytes |> md5.ComputeHash |> Seq.map (fun c -> c.ToString("X2")) |> Seq.reduce (+)
      
      |>
      
      pipeline , .
: GetBytes -> -> HEX -> ( reduce + ) -> .
, C#
using System; public string CreateMD5Hash (string input) { MD5 md5 = System.Security.Cryptography.MD5.Create(); byte[] inputBytes = System.Text.Encoding.ASCII.GetBytes (input); byte[] hashBytes = md5.ComputeHash (inputBytes); StringBuilder sb = new StringBuilder(); for (int i = 0; i < hashBytes.Length; i++) { sb.Append (hashBytes[i].ToString ("X2")); } return sb.ToString(); }
      
      : . AzureServiceWorker ( CLR )
- . F# ! Xamarin Studio .
 <ItemGroup> <Compile Include="Resources\Resource.designer.fs" /> <Compile Include="Properties\AssemblyInfo.fs" /> <Compile Include="Helpers\Helpers.fs" /> <Compile Include="Services\User.fs" /> <Compile Include="Services\AzureServiceWorker.fs" /> <Compile Include="IAmHereActivity.fs" /> <Compile Include="WhereAreYouActivity.fs" /> <Compile Include="SignInActivity.fs" /> </ItemGroup>
      
      : . Xamarin Xamarin.Mobile
. F# TPL, Task', . F# Task. , :
module Async = open System.Threading open System.Threading.Tasks let inline AwaitPlainTask (task: Task) = // rethrow exception from preceding task if it fauled let continuation (t : Task) : unit = match t.IsFaulted with | true -> raise t.Exception | arg -> () task.ContinueWith continuation |> Async.AwaitTask
      
      Async.AwaitIAsyncResult >> Async.Ignore
      
      let ExtractUserInfo (x : Contact) = let first = x.Phones |> Seq.tryPick(fun x -> if x.Type = PhoneType.Mobile then Some(x) else None) match first with | Some(first) -> let phone = first.Number |> StripChars [' ';'-';'(';')'] UserInfo.CreateUserInfo((MD5Hash phone), phone, x.DisplayName) | None -> UserInfo.CreateUserInfo("no mobile phone", "no mobile phone", "no mobile phone") // function for async list filling let FillContactsAsync = async { let book = new AddressBook (this) let! result = book.RequestPermission() |> Async.AwaitTask if result then _contacts <- book.ToList() |> Seq.filter (fun (x: Contact) -> not (Seq.isEmpty x.Phones)) |> Seq.map ExtractUserInfo |> Seq.sortBy(fun x -> x.DisplayName) |> Seq.toList let finalContacts = _contacts |> Seq.map (fun x -> x.DisplayName.ToUpperInvariant()) |> Seq.toArray this.ListAdapter <- new ArrayAdapter(this, Resource_Layout.row_contact, finalContacts) else System.Diagnostics.Debug.WriteLine("Permission denied by user or manifest") this.ListAdapter <- new ArrayAdapter(this, Resource_Layout.row_contact, Array.empty) }
      
      book.ToList()
      
      List
|> Seq.filter (fun (x: Contact) -> not (Seq.isEmpty x.Phones))
      
      |> Seq.map ExtractUserInfo
      
      Contracts UserInfo, UserInfo
|> Seq.sortBy(fun x -> x.DisplayName)
      
      |> Seq.toList
      
      List
_contacts <-
      
      mutable
_contacts |> Seq.map (fun x -> x.DisplayName.ToUpperInvariant())<-
      
      UserInfo string, - -
|> Seq.toArray<-
      
      List Array ArrayAdapter
- List. .
 
 
      Azure Mobile Servcies
- Azure Mobile Services. NotificationHub, Push . Azure , .. .
,
      
        
        
        
      
     module WruConstants = [<Literal>] let TotallyNotAzureServer = "https://YOUR.azure-mobile.net/"; [<Literal>] let TotallyNotAzureKey = "YOUR"
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
       
        
        
        
      
     member this.RegisterMe phone name regId = async { try let table = this.MobileService.GetTable<User>() let usr = { Id = "" PhoneHash = MD5Hash phone Nickname = name RegistrationId = regId } do! table.InsertAsync usr |> Async.AwaitPlainTask return (usr.Id, usr.PhoneHash, usr.Nickname) with | e -> System.Diagnostics.Trace.WriteLine(e.ToString) return (String.Empty,String.Empty,String.Empty) }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     member this.RegisterMe phone name regId = async {
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     -       (     )    .       "computation expression"   workflow.   { }       ! ( bang),  do! (do-bang)  let! (let bang)     User.    ,  F#        ,      
      
        
        
        
      
      let usr = { Id = "" PhoneHash = MD5Hash phone Nickname = name RegistrationId = regId }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     do! table.InsertAsync usr |> Async.AwaitPlainTask
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      do-bang,   await
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      C#. ..             continuation    . return (usr.Id, usr.PhoneHash, usr.Nickname)
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
          Tuple<string,string,string>     .  try ... with | e ->
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      try..catch
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      C# 
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
     
      
        
        
        
      
           .  F#    fst
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      snd
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
          .        2 .     : 
      
        
        
        
      
      let id (c,_,_) = c let phonehash (_,c,_) = c let nickname (_,_,c) = c
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
        : id tuple
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      Id  .. 
      
        
        
        
      
     
      
        
        
        
      
        5  Azure,       Push .       Azure Custom Api  
      
        
        
        
      
     
      
        
        
        
      
          exports.post = function(request, response) { // Use "request.service" to access features of your mobile service, eg: // var tables = request.service.tables; // var push = request.service.push; //response.send(statusCodes.OK, { message : 'Hello World!' }); console.log('Incoming call with requst: ', request.body.RequestId); var usersTable = request.service.tables.getTable('User'); usersTable.where( { id : request.body.TargetId } ) .read( { success: function(results) { if (results.length > 0) { var user = results[0] console.log('Send to results: ', user.Nickname, user.RegistrationId); request.service.push.gcm.send(user.RegistrationId, { RequesterId: request.body.RequesterId, RequesterNickname: request.body.RequesterName, TargetId: user.id, TargetNickname: user.Nickname }, { success: function(gcm_response) { console.log('Push notification sent: ', gcm_response); response.send(statusCodes.OK, { RequestedNickname : user.Nickname }); }, error: function(gcm_error) { console.log('Error sending push notification: ', gcm_error); response.send(statusCodes.INTERNAL_SERVER_ERROR, { RequestedNickname : user.Nickname }); } }); } else { response.send(statusCodes.NO_CONTENT, { RequestedNickname : "" }); } }, error: function(error) { console.log('Error read table: ', error); response.send(statusCodes.INTERNAL_SERVER_ERROR, { RequestedNickname : "" }); } }); };
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
        Push      
      
        
        
        
      
     // Perform Push operation member this.PushAsync targetId myId myNickname = async { try let (request : PushRequest) = { TargetId = targetId RequesterId = myId RequesterName = myNickname } let! result = this.MobileService.InvokeApiAsync<PushRequest, PushResponce>("pushhim", request) |> Async.AwaitTask return result.RequestedNickname with | e -> return e.ToString() }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
           ,    let-bang
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
       do!
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
       
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
          Google Play Services.     F#   .           .    : Xamarin.Android.Support.v7.AppCompat 
      
        
        
        
      
         , Google Play Services ,   . 
      
        
        
        
      
     
      
        
        
        
      
          push notification   .    GCM,  ID,     ID       Push  (.   pushhim).        BroadcastReciever       developer.android.com .     F#         Xamarin Component Store.     Google Cloud Messaging Client         GCM    .        ID 
      
        
        
        
      
     //Check to see that GCM is supported and that the manifest has the correct information GcmClient.CheckDevice(this) GcmClient.CheckManifest(this) // check google play if CheckPlayServices() then // Try to get registration id let regId = GcmClient.GetRegistrationId this if String.IsNullOrEmpty(regId) then // Call to Register the device for Push Notifications GcmClient.Register(this, WruConstants.GcmSender);
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
            
      
        
        
        
      
     
      
        
        
        
      
        . 
      
        
        
        
      
        , -  
      
        
        
        
      
         bitbucket.org/xakpc/whereareyou 
      
        
        
        
      
         ,     
      
        
        
        
      
              ,           "" . 
      
        
        
        
      
     
      
        
        
        
      
      
      
        
        
        
      
     ,   Android   F#.      . 
      
        
        
        
      
     ,       -  Android  F#.   ,       .listView.Adapter <- new ArrayAdapter(this, Android.Resource.Layout.SimpleListItem1, Android.Resource.Id.Text1, values) 
      
        
        
        
      
      , ,  let values = [|"item1"; "item2"; "item3"|]
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     -   string[],       list (IEnumerable   ) 
      
        
        
        
      
              F#.            www.tryfsharp.org/Learn 
      
        
        
        
      
      
 
      
        
        
        
      
          F# -  ,  
      
        
        
        
      
     
      
        
        
        
      
            F# For Fun And Profit 
      
        
        
        
      
     
      
        
        
        
      
       ,    
      
        
        
        
      
         - . 
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
     
      
        
        
        
      
            hash 
      
        
        
        
      
         MD5  F# 
      
        
        
        
      
      let MD5Hash (input : string) = use md5 = System.Security.Cryptography.MD5.Create() input |> System.Text.Encoding.ASCII.GetBytes |> md5.ComputeHash |> Seq.map (fun c -> c.ToString("X2")) |> Seq.reduce (+)
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
      |>
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      pipeline ,     . 
      
        
        
        
      
         :    GetBytes ->   ->      HEX  ->       (  reduce   +           ) ->    . 
      
        
        
        
      
     
      
        
        
        
      
      ,     C# using System; public string CreateMD5Hash (string input) { MD5 md5 = System.Security.Cryptography.MD5.Create(); byte[] inputBytes = System.Text.Encoding.ASCII.GetBytes (input); byte[] hashBytes = md5.ComputeHash (inputBytes); StringBuilder sb = new StringBuilder(); for (int i = 0; i < hashBytes.Length; i++) { sb.Append (hashBytes[i].ToString ("X2")); } return sb.ToString(); }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
     
      
        
        
        
      
              :        .       AzureServiceWorker (  CLR    ) 
      
        
        
        
      
     
      
        
        
        
      
              -   .   F#    !   Xamarin Studio            . 
      
        
        
        
      
      <ItemGroup> <Compile Include="Resources\Resource.designer.fs" /> <Compile Include="Properties\AssemblyInfo.fs" /> <Compile Include="Helpers\Helpers.fs" /> <Compile Include="Services\User.fs" /> <Compile Include="Services\AzureServiceWorker.fs" /> <Compile Include="IAmHereActivity.fs" /> <Compile Include="WhereAreYouActivity.fs" /> <Compile Include="SignInActivity.fs" /> </ItemGroup>
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
        
      
        
        
        
      
            :    .    Xamarin    Xamarin.Mobile 
      
        
        
        
      
     
      
        
        
        
      
          .  F#         TPL,     Task',      .     F#         Task.  ,     : 
      
        
        
        
      
     module Async = open System.Threading open System.Threading.Tasks let inline AwaitPlainTask (task: Task) = // rethrow exception from preceding task if it fauled let continuation (t : Task) : unit = match t.IsFaulted with | true -> raise t.Exception | arg -> () task.ContinueWith continuation |> Async.AwaitTask
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
             Async.AwaitIAsyncResult >> Async.Ignore
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
           
      
        
        
        
      
     
      
        
        
        
      
                
      
        
        
        
      
     let ExtractUserInfo (x : Contact) = let first = x.Phones |> Seq.tryPick(fun x -> if x.Type = PhoneType.Mobile then Some(x) else None) match first with | Some(first) -> let phone = first.Number |> StripChars [' ';'-';'(';')'] UserInfo.CreateUserInfo((MD5Hash phone), phone, x.DisplayName) | None -> UserInfo.CreateUserInfo("no mobile phone", "no mobile phone", "no mobile phone") // function for async list filling let FillContactsAsync = async { let book = new AddressBook (this) let! result = book.RequestPermission() |> Async.AwaitTask if result then _contacts <- book.ToList() |> Seq.filter (fun (x: Contact) -> not (Seq.isEmpty x.Phones)) |> Seq.map ExtractUserInfo |> Seq.sortBy(fun x -> x.DisplayName) |> Seq.toList let finalContacts = _contacts |> Seq.map (fun x -> x.DisplayName.ToUpperInvariant()) |> Seq.toArray this.ListAdapter <- new ArrayAdapter(this, Resource_Layout.row_contact, finalContacts) else System.Diagnostics.Debug.WriteLine("Permission denied by user or manifest") this.ListAdapter <- new ArrayAdapter(this, Resource_Layout.row_contact, Array.empty) }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
          
      
        
        
        
      
     book.ToList()
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
       List |> Seq.filter (fun (x: Contact) -> not (Seq.isEmpty x.Phones))
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
          |> Seq.map ExtractUserInfo
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
          Contracts  UserInfo,      UserInfo |> Seq.sortBy(fun x -> x.DisplayName)
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      |> Seq.toList
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
       List _contacts <-
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
        mutable  _contacts |> Seq.map (fun x -> x.DisplayName.ToUpperInvariant())<-
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
        UserInfo  string,     - -    |> Seq.toArray<-
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      List  Array    ArrayAdapter 
      
        
        
        
      
        -      List.   . 
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
     
      
        
        
        
      
     Azure Mobile Servcies 
      
        
        
        
      
       -    Azure Mobile Services.       NotificationHub,     Push    .   Azure    , ..      . 
      
        
        
        
      
     
      
        
        
        
      
          ,    
      
        
        
        
      
     module WruConstants = [<Literal>] let TotallyNotAzureServer = "https://YOUR.azure-mobile.net/"; [<Literal>] let TotallyNotAzureKey = "YOUR"
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
       
        
        
        
      
     member this.RegisterMe phone name regId = async { try let table = this.MobileService.GetTable<User>() let usr = { Id = "" PhoneHash = MD5Hash phone Nickname = name RegistrationId = regId } do! table.InsertAsync usr |> Async.AwaitPlainTask return (usr.Id, usr.PhoneHash, usr.Nickname) with | e -> System.Diagnostics.Trace.WriteLine(e.ToString) return (String.Empty,String.Empty,String.Empty) }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     member this.RegisterMe phone name regId = async {
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     -       (     )    .       "computation expression"   workflow.   { }       ! ( bang),  do! (do-bang)  let! (let bang)     User.    ,  F#        ,      
      
        
        
        
      
      let usr = { Id = "" PhoneHash = MD5Hash phone Nickname = name RegistrationId = regId }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     do! table.InsertAsync usr |> Async.AwaitPlainTask
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      do-bang,   await
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      C#. ..             continuation    . return (usr.Id, usr.PhoneHash, usr.Nickname)
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
          Tuple<string,string,string>     .  try ... with | e ->
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      try..catch
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      C# 
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
     
      
        
        
        
      
           .  F#    fst
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      snd
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
          .        2 .     : 
      
        
        
        
      
      let id (c,_,_) = c let phonehash (_,c,_) = c let nickname (_,_,c) = c
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
        : id tuple
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      Id  .. 
      
        
        
        
      
     
      
        
        
        
      
        5  Azure,       Push .       Azure Custom Api  
      
        
        
        
      
     
      
        
        
        
      
          exports.post = function(request, response) { // Use "request.service" to access features of your mobile service, eg: // var tables = request.service.tables; // var push = request.service.push; //response.send(statusCodes.OK, { message : 'Hello World!' }); console.log('Incoming call with requst: ', request.body.RequestId); var usersTable = request.service.tables.getTable('User'); usersTable.where( { id : request.body.TargetId } ) .read( { success: function(results) { if (results.length > 0) { var user = results[0] console.log('Send to results: ', user.Nickname, user.RegistrationId); request.service.push.gcm.send(user.RegistrationId, { RequesterId: request.body.RequesterId, RequesterNickname: request.body.RequesterName, TargetId: user.id, TargetNickname: user.Nickname }, { success: function(gcm_response) { console.log('Push notification sent: ', gcm_response); response.send(statusCodes.OK, { RequestedNickname : user.Nickname }); }, error: function(gcm_error) { console.log('Error sending push notification: ', gcm_error); response.send(statusCodes.INTERNAL_SERVER_ERROR, { RequestedNickname : user.Nickname }); } }); } else { response.send(statusCodes.NO_CONTENT, { RequestedNickname : "" }); } }, error: function(error) { console.log('Error read table: ', error); response.send(statusCodes.INTERNAL_SERVER_ERROR, { RequestedNickname : "" }); } }); };
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
        Push      
      
        
        
        
      
     // Perform Push operation member this.PushAsync targetId myId myNickname = async { try let (request : PushRequest) = { TargetId = targetId RequesterId = myId RequesterName = myNickname } let! result = this.MobileService.InvokeApiAsync<PushRequest, PushResponce>("pushhim", request) |> Async.AwaitTask return result.RequestedNickname with | e -> return e.ToString() }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
           ,    let-bang
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
       do!
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
       
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
          Google Play Services.     F#   .           .    : Xamarin.Android.Support.v7.AppCompat 
      
        
        
        
      
         , Google Play Services ,   . 
      
        
        
        
      
     
      
        
        
        
      
          push notification   .    GCM,  ID,     ID       Push  (.   pushhim).        BroadcastReciever       developer.android.com .     F#         Xamarin Component Store.     Google Cloud Messaging Client         GCM    .        ID 
      
        
        
        
      
     //Check to see that GCM is supported and that the manifest has the correct information GcmClient.CheckDevice(this) GcmClient.CheckManifest(this) // check google play if CheckPlayServices() then // Try to get registration id let regId = GcmClient.GetRegistrationId this if String.IsNullOrEmpty(regId) then // Call to Register the device for Push Notifications GcmClient.Register(this, WruConstants.GcmSender);
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
            
      
        
        
        
      
     
      
        
        
        
      
        . 
      
        
        
        
      
        , -  
      
        
        
        
      
         bitbucket.org/xakpc/whereareyou 
      
        
        
        
      
         ,     
      
        
        
        
      
              ,           "" . 
      
        
        
        
      
     
      
        
        
        
      
      
      
        
        
        
      
     ,   Android   F#.      . 
      
        
        
        
      
     ,       -  Android  F#.   ,       .
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
    listView.Adapter <- new ArrayAdapter(this, Android.Resource.Layout.SimpleListItem1, Android.Resource.Id.Text1, values) 
      
        
        
        
      
      , ,  let values = [|"item1"; "item2"; "item3"|]
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     -   string[],       list (IEnumerable   ) 
      
        
        
        
      
              F#.            www.tryfsharp.org/Learn 
      
        
        
        
      
      
 
      
        
        
        
      
          F# -  ,  
      
        
        
        
      
     
      
        
        
        
      
            F# For Fun And Profit 
      
        
        
        
      
     
      
        
        
        
      
       ,    
      
        
        
        
      
         - . 
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
     
      
        
        
        
      
            hash 
      
        
        
        
      
         MD5  F# 
      
        
        
        
      
      let MD5Hash (input : string) = use md5 = System.Security.Cryptography.MD5.Create() input |> System.Text.Encoding.ASCII.GetBytes |> md5.ComputeHash |> Seq.map (fun c -> c.ToString("X2")) |> Seq.reduce (+)
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
      |>
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      pipeline ,     . 
      
        
        
        
      
         :    GetBytes ->   ->      HEX  ->       (  reduce   +           ) ->    . 
      
        
        
        
      
     
      
        
        
        
      
      ,     C# using System; public string CreateMD5Hash (string input) { MD5 md5 = System.Security.Cryptography.MD5.Create(); byte[] inputBytes = System.Text.Encoding.ASCII.GetBytes (input); byte[] hashBytes = md5.ComputeHash (inputBytes); StringBuilder sb = new StringBuilder(); for (int i = 0; i < hashBytes.Length; i++) { sb.Append (hashBytes[i].ToString ("X2")); } return sb.ToString(); }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
     
      
        
        
        
      
              :        .       AzureServiceWorker (  CLR    ) 
      
        
        
        
      
     
      
        
        
        
      
              -   .   F#    !   Xamarin Studio            . 
      
        
        
        
      
      <ItemGroup> <Compile Include="Resources\Resource.designer.fs" /> <Compile Include="Properties\AssemblyInfo.fs" /> <Compile Include="Helpers\Helpers.fs" /> <Compile Include="Services\User.fs" /> <Compile Include="Services\AzureServiceWorker.fs" /> <Compile Include="IAmHereActivity.fs" /> <Compile Include="WhereAreYouActivity.fs" /> <Compile Include="SignInActivity.fs" /> </ItemGroup>
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
        
      
        
        
        
      
            :    .    Xamarin    Xamarin.Mobile 
      
        
        
        
      
     
      
        
        
        
      
          .  F#         TPL,     Task',      .     F#         Task.  ,     : 
      
        
        
        
      
     module Async = open System.Threading open System.Threading.Tasks let inline AwaitPlainTask (task: Task) = // rethrow exception from preceding task if it fauled let continuation (t : Task) : unit = match t.IsFaulted with | true -> raise t.Exception | arg -> () task.ContinueWith continuation |> Async.AwaitTask
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
             Async.AwaitIAsyncResult >> Async.Ignore
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
           
      
        
        
        
      
     
      
        
        
        
      
                
      
        
        
        
      
     let ExtractUserInfo (x : Contact) = let first = x.Phones |> Seq.tryPick(fun x -> if x.Type = PhoneType.Mobile then Some(x) else None) match first with | Some(first) -> let phone = first.Number |> StripChars [' ';'-';'(';')'] UserInfo.CreateUserInfo((MD5Hash phone), phone, x.DisplayName) | None -> UserInfo.CreateUserInfo("no mobile phone", "no mobile phone", "no mobile phone") // function for async list filling let FillContactsAsync = async { let book = new AddressBook (this) let! result = book.RequestPermission() |> Async.AwaitTask if result then _contacts <- book.ToList() |> Seq.filter (fun (x: Contact) -> not (Seq.isEmpty x.Phones)) |> Seq.map ExtractUserInfo |> Seq.sortBy(fun x -> x.DisplayName) |> Seq.toList let finalContacts = _contacts |> Seq.map (fun x -> x.DisplayName.ToUpperInvariant()) |> Seq.toArray this.ListAdapter <- new ArrayAdapter(this, Resource_Layout.row_contact, finalContacts) else System.Diagnostics.Debug.WriteLine("Permission denied by user or manifest") this.ListAdapter <- new ArrayAdapter(this, Resource_Layout.row_contact, Array.empty) }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
          
      
        
        
        
      
     book.ToList()
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
       List |> Seq.filter (fun (x: Contact) -> not (Seq.isEmpty x.Phones))
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
          |> Seq.map ExtractUserInfo
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
          Contracts  UserInfo,      UserInfo |> Seq.sortBy(fun x -> x.DisplayName)
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      |> Seq.toList
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
       List _contacts <-
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
        mutable  _contacts |> Seq.map (fun x -> x.DisplayName.ToUpperInvariant())<-
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
        UserInfo  string,     - -    |> Seq.toArray<-
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      List  Array    ArrayAdapter 
      
        
        
        
      
        -      List.   . 
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
     
      
        
        
        
      
     Azure Mobile Servcies 
      
        
        
        
      
       -    Azure Mobile Services.       NotificationHub,     Push    .   Azure    , ..      . 
      
        
        
        
      
     
      
        
        
        
      
          ,    
      
        
        
        
      
     module WruConstants = [<Literal>] let TotallyNotAzureServer = "https://YOUR.azure-mobile.net/"; [<Literal>] let TotallyNotAzureKey = "YOUR"
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
       
        
        
        
      
     member this.RegisterMe phone name regId = async { try let table = this.MobileService.GetTable<User>() let usr = { Id = "" PhoneHash = MD5Hash phone Nickname = name RegistrationId = regId } do! table.InsertAsync usr |> Async.AwaitPlainTask return (usr.Id, usr.PhoneHash, usr.Nickname) with | e -> System.Diagnostics.Trace.WriteLine(e.ToString) return (String.Empty,String.Empty,String.Empty) }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     member this.RegisterMe phone name regId = async {
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     -       (     )    .       "computation expression"   workflow.   { }       ! ( bang),  do! (do-bang)  let! (let bang)     User.    ,  F#        ,      
      
        
        
        
      
      let usr = { Id = "" PhoneHash = MD5Hash phone Nickname = name RegistrationId = regId }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     do! table.InsertAsync usr |> Async.AwaitPlainTask
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      do-bang,   await
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      C#. ..             continuation    . return (usr.Id, usr.PhoneHash, usr.Nickname)
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
          Tuple<string,string,string>     .  try ... with | e ->
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      try..catch
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      C# 
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
     
      
        
        
        
      
           .  F#    fst
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      snd
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
          .        2 .     : 
      
        
        
        
      
      let id (c,_,_) = c let phonehash (_,c,_) = c let nickname (_,_,c) = c
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
        : id tuple
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      Id  .. 
      
        
        
        
      
     
      
        
        
        
      
        5  Azure,       Push .       Azure Custom Api  
      
        
        
        
      
     
      
        
        
        
      
          exports.post = function(request, response) { // Use "request.service" to access features of your mobile service, eg: // var tables = request.service.tables; // var push = request.service.push; //response.send(statusCodes.OK, { message : 'Hello World!' }); console.log('Incoming call with requst: ', request.body.RequestId); var usersTable = request.service.tables.getTable('User'); usersTable.where( { id : request.body.TargetId } ) .read( { success: function(results) { if (results.length > 0) { var user = results[0] console.log('Send to results: ', user.Nickname, user.RegistrationId); request.service.push.gcm.send(user.RegistrationId, { RequesterId: request.body.RequesterId, RequesterNickname: request.body.RequesterName, TargetId: user.id, TargetNickname: user.Nickname }, { success: function(gcm_response) { console.log('Push notification sent: ', gcm_response); response.send(statusCodes.OK, { RequestedNickname : user.Nickname }); }, error: function(gcm_error) { console.log('Error sending push notification: ', gcm_error); response.send(statusCodes.INTERNAL_SERVER_ERROR, { RequestedNickname : user.Nickname }); } }); } else { response.send(statusCodes.NO_CONTENT, { RequestedNickname : "" }); } }, error: function(error) { console.log('Error read table: ', error); response.send(statusCodes.INTERNAL_SERVER_ERROR, { RequestedNickname : "" }); } }); };
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
        Push      
      
        
        
        
      
     // Perform Push operation member this.PushAsync targetId myId myNickname = async { try let (request : PushRequest) = { TargetId = targetId RequesterId = myId RequesterName = myNickname } let! result = this.MobileService.InvokeApiAsync<PushRequest, PushResponce>("pushhim", request) |> Async.AwaitTask return result.RequestedNickname with | e -> return e.ToString() }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
           ,    let-bang
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
       do!
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
       
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
          Google Play Services.     F#   .           .    : Xamarin.Android.Support.v7.AppCompat 
      
        
        
        
      
         , Google Play Services ,   . 
      
        
        
        
      
     
      
        
        
        
      
          push notification   .    GCM,  ID,     ID       Push  (.   pushhim).        BroadcastReciever       developer.android.com .     F#         Xamarin Component Store.     Google Cloud Messaging Client         GCM    .        ID 
      
        
        
        
      
     //Check to see that GCM is supported and that the manifest has the correct information GcmClient.CheckDevice(this) GcmClient.CheckManifest(this) // check google play if CheckPlayServices() then // Try to get registration id let regId = GcmClient.GetRegistrationId this if String.IsNullOrEmpty(regId) then // Call to Register the device for Push Notifications GcmClient.Register(this, WruConstants.GcmSender);
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
            
      
        
        
        
      
     
      
        
        
        
      
        . 
      
        
        
        
      
        , -  
      
        
        
        
      
         bitbucket.org/xakpc/whereareyou 
      
        
        
        
      
         ,     
      
        
        
        
      
              ,           "" . 
      
        
        
        
      
     
      
        
        
        
      
      
      
        
        
        
      
     ,   Android   F#.      . 
      
        
        
        
      
     ,       -  Android  F#.   ,       .
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
    listView.Adapter <- new ArrayAdapter(this, Android.Resource.Layout.SimpleListItem1, Android.Resource.Id.Text1, values) 
      
        
        
        
      
      , ,  let values = [|"item1"; "item2"; "item3"|]
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     -   string[],       list (IEnumerable   ) 
      
        
        
        
      
              F#.            www.tryfsharp.org/Learn 
      
        
        
        
      
      
 
      
        
        
        
      
          F# -  ,  
      
        
        
        
      
     
      
        
        
        
      
            F# For Fun And Profit 
      
        
        
        
      
     
      
        
        
        
      
       ,    
      
        
        
        
      
         - . 
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
     
      
        
        
        
      
            hash 
      
        
        
        
      
         MD5  F# 
      
        
        
        
      
      let MD5Hash (input : string) = use md5 = System.Security.Cryptography.MD5.Create() input |> System.Text.Encoding.ASCII.GetBytes |> md5.ComputeHash |> Seq.map (fun c -> c.ToString("X2")) |> Seq.reduce (+)
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
      |>
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      pipeline ,     . 
      
        
        
        
      
         :    GetBytes ->   ->      HEX  ->       (  reduce   +           ) ->    . 
      
        
        
        
      
     
      
        
        
        
      
      ,     C# using System; public string CreateMD5Hash (string input) { MD5 md5 = System.Security.Cryptography.MD5.Create(); byte[] inputBytes = System.Text.Encoding.ASCII.GetBytes (input); byte[] hashBytes = md5.ComputeHash (inputBytes); StringBuilder sb = new StringBuilder(); for (int i = 0; i < hashBytes.Length; i++) { sb.Append (hashBytes[i].ToString ("X2")); } return sb.ToString(); }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
     
      
        
        
        
      
              :        .       AzureServiceWorker (  CLR    ) 
      
        
        
        
      
     
      
        
        
        
      
              -   .   F#    !   Xamarin Studio            . 
      
        
        
        
      
      <ItemGroup> <Compile Include="Resources\Resource.designer.fs" /> <Compile Include="Properties\AssemblyInfo.fs" /> <Compile Include="Helpers\Helpers.fs" /> <Compile Include="Services\User.fs" /> <Compile Include="Services\AzureServiceWorker.fs" /> <Compile Include="IAmHereActivity.fs" /> <Compile Include="WhereAreYouActivity.fs" /> <Compile Include="SignInActivity.fs" /> </ItemGroup>
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
        
      
        
        
        
      
            :    .    Xamarin    Xamarin.Mobile 
      
        
        
        
      
     
      
        
        
        
      
          .  F#         TPL,     Task',      .     F#         Task.  ,     : 
      
        
        
        
      
     module Async = open System.Threading open System.Threading.Tasks let inline AwaitPlainTask (task: Task) = // rethrow exception from preceding task if it fauled let continuation (t : Task) : unit = match t.IsFaulted with | true -> raise t.Exception | arg -> () task.ContinueWith continuation |> Async.AwaitTask
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
             Async.AwaitIAsyncResult >> Async.Ignore
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
           
      
        
        
        
      
     
      
        
        
        
      
                
      
        
        
        
      
     let ExtractUserInfo (x : Contact) = let first = x.Phones |> Seq.tryPick(fun x -> if x.Type = PhoneType.Mobile then Some(x) else None) match first with | Some(first) -> let phone = first.Number |> StripChars [' ';'-';'(';')'] UserInfo.CreateUserInfo((MD5Hash phone), phone, x.DisplayName) | None -> UserInfo.CreateUserInfo("no mobile phone", "no mobile phone", "no mobile phone") // function for async list filling let FillContactsAsync = async { let book = new AddressBook (this) let! result = book.RequestPermission() |> Async.AwaitTask if result then _contacts <- book.ToList() |> Seq.filter (fun (x: Contact) -> not (Seq.isEmpty x.Phones)) |> Seq.map ExtractUserInfo |> Seq.sortBy(fun x -> x.DisplayName) |> Seq.toList let finalContacts = _contacts |> Seq.map (fun x -> x.DisplayName.ToUpperInvariant()) |> Seq.toArray this.ListAdapter <- new ArrayAdapter(this, Resource_Layout.row_contact, finalContacts) else System.Diagnostics.Debug.WriteLine("Permission denied by user or manifest") this.ListAdapter <- new ArrayAdapter(this, Resource_Layout.row_contact, Array.empty) }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
          
      
        
        
        
      
     book.ToList()
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
       List |> Seq.filter (fun (x: Contact) -> not (Seq.isEmpty x.Phones))
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
          |> Seq.map ExtractUserInfo
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
          Contracts  UserInfo,      UserInfo |> Seq.sortBy(fun x -> x.DisplayName)
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      |> Seq.toList
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
       List _contacts <-
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
        mutable  _contacts |> Seq.map (fun x -> x.DisplayName.ToUpperInvariant())<-
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
        UserInfo  string,     - -    |> Seq.toArray<-
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      List  Array    ArrayAdapter 
      
        
        
        
      
        -      List.   . 
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
     
      
        
        
        
      
     Azure Mobile Servcies 
      
        
        
        
      
       -    Azure Mobile Services.       NotificationHub,     Push    .   Azure    , ..      . 
      
        
        
        
      
     
      
        
        
        
      
          ,    
      
        
        
        
      
     module WruConstants = [<Literal>] let TotallyNotAzureServer = "https://YOUR.azure-mobile.net/"; [<Literal>] let TotallyNotAzureKey = "YOUR"
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
       
        
        
        
      
     member this.RegisterMe phone name regId = async { try let table = this.MobileService.GetTable<User>() let usr = { Id = "" PhoneHash = MD5Hash phone Nickname = name RegistrationId = regId } do! table.InsertAsync usr |> Async.AwaitPlainTask return (usr.Id, usr.PhoneHash, usr.Nickname) with | e -> System.Diagnostics.Trace.WriteLine(e.ToString) return (String.Empty,String.Empty,String.Empty) }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     member this.RegisterMe phone name regId = async {
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     -       (     )    .       "computation expression"   workflow.   { }       ! ( bang),  do! (do-bang)  let! (let bang)     User.    ,  F#        ,      
      
        
        
        
      
      let usr = { Id = "" PhoneHash = MD5Hash phone Nickname = name RegistrationId = regId }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     do! table.InsertAsync usr |> Async.AwaitPlainTask
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      do-bang,   await
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      C#. ..             continuation    . return (usr.Id, usr.PhoneHash, usr.Nickname)
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
          Tuple<string,string,string>     .  try ... with | e ->
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      try..catch
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      C# 
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
     
      
        
        
        
      
           .  F#    fst
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      snd
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
          .        2 .     : 
      
        
        
        
      
      let id (c,_,_) = c let phonehash (_,c,_) = c let nickname (_,_,c) = c
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
        : id tuple
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      Id  .. 
      
        
        
        
      
     
      
        
        
        
      
        5  Azure,       Push .       Azure Custom Api  
      
        
        
        
      
     
      
        
        
        
      
          exports.post = function(request, response) { // Use "request.service" to access features of your mobile service, eg: // var tables = request.service.tables; // var push = request.service.push; //response.send(statusCodes.OK, { message : 'Hello World!' }); console.log('Incoming call with requst: ', request.body.RequestId); var usersTable = request.service.tables.getTable('User'); usersTable.where( { id : request.body.TargetId } ) .read( { success: function(results) { if (results.length > 0) { var user = results[0] console.log('Send to results: ', user.Nickname, user.RegistrationId); request.service.push.gcm.send(user.RegistrationId, { RequesterId: request.body.RequesterId, RequesterNickname: request.body.RequesterName, TargetId: user.id, TargetNickname: user.Nickname }, { success: function(gcm_response) { console.log('Push notification sent: ', gcm_response); response.send(statusCodes.OK, { RequestedNickname : user.Nickname }); }, error: function(gcm_error) { console.log('Error sending push notification: ', gcm_error); response.send(statusCodes.INTERNAL_SERVER_ERROR, { RequestedNickname : user.Nickname }); } }); } else { response.send(statusCodes.NO_CONTENT, { RequestedNickname : "" }); } }, error: function(error) { console.log('Error read table: ', error); response.send(statusCodes.INTERNAL_SERVER_ERROR, { RequestedNickname : "" }); } }); };
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
        Push      
      
        
        
        
      
     // Perform Push operation member this.PushAsync targetId myId myNickname = async { try let (request : PushRequest) = { TargetId = targetId RequesterId = myId RequesterName = myNickname } let! result = this.MobileService.InvokeApiAsync<PushRequest, PushResponce>("pushhim", request) |> Async.AwaitTask return result.RequestedNickname with | e -> return e.ToString() }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
           ,    let-bang
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
       do!
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
       
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
          Google Play Services.     F#   .           .    : Xamarin.Android.Support.v7.AppCompat 
      
        
        
        
      
         , Google Play Services ,   . 
      
        
        
        
      
     
      
        
        
        
      
          push notification   .    GCM,  ID,     ID       Push  (.   pushhim).        BroadcastReciever       developer.android.com .     F#         Xamarin Component Store.     Google Cloud Messaging Client         GCM    .        ID 
      
        
        
        
      
     //Check to see that GCM is supported and that the manifest has the correct information GcmClient.CheckDevice(this) GcmClient.CheckManifest(this) // check google play if CheckPlayServices() then // Try to get registration id let regId = GcmClient.GetRegistrationId this if String.IsNullOrEmpty(regId) then // Call to Register the device for Push Notifications GcmClient.Register(this, WruConstants.GcmSender);
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
            
      
        
        
        
      
     
      
        
        
        
      
        . 
      
        
        
        
      
        , -  
      
        
        
        
      
         bitbucket.org/xakpc/whereareyou 
      
        
        
        
      
         ,     
      
        
        
        
      
              ,           "" . 
      
        
        
        
      
     
      
        
        
        
      
      
      
        
        
        
      
     ,   Android   F#.      . 
      
        
        
        
      
     ,       -  Android  F#.   ,       .
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     listView.Adapter <- new ArrayAdapter(this, Android.Resource.Layout.SimpleListItem1, Android.Resource.Id.Text1, values) 
      
        
        
        
      
      , ,  let values = [|"item1"; "item2"; "item3"|]
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     -   string[],       list (IEnumerable   ) 
      
        
        
        
      
              F#.            www.tryfsharp.org/Learn 
      
        
        
        
      
      
 
      
        
        
        
      
          F# -  ,  
      
        
        
        
      
     
      
        
        
        
      
            F# For Fun And Profit 
      
        
        
        
      
     
      
        
        
        
      
       ,    
      
        
        
        
      
         - . 
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
     
      
        
        
        
      
            hash 
      
        
        
        
      
         MD5  F# 
      
        
        
        
      
      let MD5Hash (input : string) = use md5 = System.Security.Cryptography.MD5.Create() input |> System.Text.Encoding.ASCII.GetBytes |> md5.ComputeHash |> Seq.map (fun c -> c.ToString("X2")) |> Seq.reduce (+)
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
      |>
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      pipeline ,     . 
      
        
        
        
      
         :    GetBytes ->   ->      HEX  ->       (  reduce   +           ) ->    . 
      
        
        
        
      
     
      
        
        
        
      
      ,     C# using System; public string CreateMD5Hash (string input) { MD5 md5 = System.Security.Cryptography.MD5.Create(); byte[] inputBytes = System.Text.Encoding.ASCII.GetBytes (input); byte[] hashBytes = md5.ComputeHash (inputBytes); StringBuilder sb = new StringBuilder(); for (int i = 0; i < hashBytes.Length; i++) { sb.Append (hashBytes[i].ToString ("X2")); } return sb.ToString(); }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
     
      
        
        
        
      
              :        .       AzureServiceWorker (  CLR    ) 
      
        
        
        
      
     
      
        
        
        
      
              -   .   F#    !   Xamarin Studio            . 
      
        
        
        
      
      <ItemGroup> <Compile Include="Resources\Resource.designer.fs" /> <Compile Include="Properties\AssemblyInfo.fs" /> <Compile Include="Helpers\Helpers.fs" /> <Compile Include="Services\User.fs" /> <Compile Include="Services\AzureServiceWorker.fs" /> <Compile Include="IAmHereActivity.fs" /> <Compile Include="WhereAreYouActivity.fs" /> <Compile Include="SignInActivity.fs" /> </ItemGroup>
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
        
      
        
        
        
      
            :    .    Xamarin    Xamarin.Mobile 
      
        
        
        
      
     
      
        
        
        
      
          .  F#         TPL,     Task',      .     F#         Task.  ,     : 
      
        
        
        
      
     module Async = open System.Threading open System.Threading.Tasks let inline AwaitPlainTask (task: Task) = // rethrow exception from preceding task if it fauled let continuation (t : Task) : unit = match t.IsFaulted with | true -> raise t.Exception | arg -> () task.ContinueWith continuation |> Async.AwaitTask
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
             Async.AwaitIAsyncResult >> Async.Ignore
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
           
      
        
        
        
      
     
      
        
        
        
      
                
      
        
        
        
      
     let ExtractUserInfo (x : Contact) = let first = x.Phones |> Seq.tryPick(fun x -> if x.Type = PhoneType.Mobile then Some(x) else None) match first with | Some(first) -> let phone = first.Number |> StripChars [' ';'-';'(';')'] UserInfo.CreateUserInfo((MD5Hash phone), phone, x.DisplayName) | None -> UserInfo.CreateUserInfo("no mobile phone", "no mobile phone", "no mobile phone") // function for async list filling let FillContactsAsync = async { let book = new AddressBook (this) let! result = book.RequestPermission() |> Async.AwaitTask if result then _contacts <- book.ToList() |> Seq.filter (fun (x: Contact) -> not (Seq.isEmpty x.Phones)) |> Seq.map ExtractUserInfo |> Seq.sortBy(fun x -> x.DisplayName) |> Seq.toList let finalContacts = _contacts |> Seq.map (fun x -> x.DisplayName.ToUpperInvariant()) |> Seq.toArray this.ListAdapter <- new ArrayAdapter(this, Resource_Layout.row_contact, finalContacts) else System.Diagnostics.Debug.WriteLine("Permission denied by user or manifest") this.ListAdapter <- new ArrayAdapter(this, Resource_Layout.row_contact, Array.empty) }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
          
      
        
        
        
      
     book.ToList()
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
       List |> Seq.filter (fun (x: Contact) -> not (Seq.isEmpty x.Phones))
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
          |> Seq.map ExtractUserInfo
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
          Contracts  UserInfo,      UserInfo |> Seq.sortBy(fun x -> x.DisplayName)
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      |> Seq.toList
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
       List _contacts <-
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
        mutable  _contacts |> Seq.map (fun x -> x.DisplayName.ToUpperInvariant())<-
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
        UserInfo  string,     - -    |> Seq.toArray<-
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      List  Array    ArrayAdapter 
      
        
        
        
      
        -      List.   . 
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
     
      
        
        
        
      
     Azure Mobile Servcies 
      
        
        
        
      
       -    Azure Mobile Services.       NotificationHub,     Push    .   Azure    , ..      . 
      
        
        
        
      
     
      
        
        
        
      
          ,    
      
        
        
        
      
     module WruConstants = [<Literal>] let TotallyNotAzureServer = "https://YOUR.azure-mobile.net/"; [<Literal>] let TotallyNotAzureKey = "YOUR"
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
       
        
        
        
      
     member this.RegisterMe phone name regId = async { try let table = this.MobileService.GetTable<User>() let usr = { Id = "" PhoneHash = MD5Hash phone Nickname = name RegistrationId = regId } do! table.InsertAsync usr |> Async.AwaitPlainTask return (usr.Id, usr.PhoneHash, usr.Nickname) with | e -> System.Diagnostics.Trace.WriteLine(e.ToString) return (String.Empty,String.Empty,String.Empty) }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     member this.RegisterMe phone name regId = async {
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     -       (     )    .       "computation expression"   workflow.   { }       ! ( bang),  do! (do-bang)  let! (let bang)     User.    ,  F#        ,      
      
        
        
        
      
      let usr = { Id = "" PhoneHash = MD5Hash phone Nickname = name RegistrationId = regId }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     do! table.InsertAsync usr |> Async.AwaitPlainTask
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      do-bang,   await
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      C#. ..             continuation    . return (usr.Id, usr.PhoneHash, usr.Nickname)
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
          Tuple<string,string,string>     .  try ... with | e ->
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      try..catch
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      C# 
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
     
      
        
        
        
      
           .  F#    fst
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      snd
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
          .        2 .     : 
      
        
        
        
      
      let id (c,_,_) = c let phonehash (_,c,_) = c let nickname (_,_,c) = c
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
        : id tuple
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      Id  .. 
      
        
        
        
      
     
      
        
        
        
      
        5  Azure,       Push .       Azure Custom Api  
      
        
        
        
      
     
      
        
        
        
      
          exports.post = function(request, response) { // Use "request.service" to access features of your mobile service, eg: // var tables = request.service.tables; // var push = request.service.push; //response.send(statusCodes.OK, { message : 'Hello World!' }); console.log('Incoming call with requst: ', request.body.RequestId); var usersTable = request.service.tables.getTable('User'); usersTable.where( { id : request.body.TargetId } ) .read( { success: function(results) { if (results.length > 0) { var user = results[0] console.log('Send to results: ', user.Nickname, user.RegistrationId); request.service.push.gcm.send(user.RegistrationId, { RequesterId: request.body.RequesterId, RequesterNickname: request.body.RequesterName, TargetId: user.id, TargetNickname: user.Nickname }, { success: function(gcm_response) { console.log('Push notification sent: ', gcm_response); response.send(statusCodes.OK, { RequestedNickname : user.Nickname }); }, error: function(gcm_error) { console.log('Error sending push notification: ', gcm_error); response.send(statusCodes.INTERNAL_SERVER_ERROR, { RequestedNickname : user.Nickname }); } }); } else { response.send(statusCodes.NO_CONTENT, { RequestedNickname : "" }); } }, error: function(error) { console.log('Error read table: ', error); response.send(statusCodes.INTERNAL_SERVER_ERROR, { RequestedNickname : "" }); } }); };
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
        Push      
      
        
        
        
      
     // Perform Push operation member this.PushAsync targetId myId myNickname = async { try let (request : PushRequest) = { TargetId = targetId RequesterId = myId RequesterName = myNickname } let! result = this.MobileService.InvokeApiAsync<PushRequest, PushResponce>("pushhim", request) |> Async.AwaitTask return result.RequestedNickname with | e -> return e.ToString() }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
           ,    let-bang
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
       do!
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
       
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
          Google Play Services.     F#   .           .    : Xamarin.Android.Support.v7.AppCompat 
      
        
        
        
      
         , Google Play Services ,   . 
      
        
        
        
      
     
      
        
        
        
      
          push notification   .    GCM,  ID,     ID       Push  (.   pushhim).        BroadcastReciever       developer.android.com .     F#         Xamarin Component Store.     Google Cloud Messaging Client         GCM    .        ID 
      
        
        
        
      
     //Check to see that GCM is supported and that the manifest has the correct information GcmClient.CheckDevice(this) GcmClient.CheckManifest(this) // check google play if CheckPlayServices() then // Try to get registration id let regId = GcmClient.GetRegistrationId this if String.IsNullOrEmpty(regId) then // Call to Register the device for Push Notifications GcmClient.Register(this, WruConstants.GcmSender);
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
            
      
        
        
        
      
     
      
        
        
        
      
        . 
      
        
        
        
      
        , -  
      
        
        
        
      
         bitbucket.org/xakpc/whereareyou 
      
        
        
        
      
         ,     
      
        
        
        
      
              ,           "" . 
      
        
        
        
      
     
      
        
        
        
      
      
      
        
        
        
      
     ,   Android   F#.      . 
      
        
        
        
      
     ,       -  Android  F#.   ,       .
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
    
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      listView.Adapter <- new ArrayAdapter(this, Android.Resource.Layout.SimpleListItem1, Android.Resource.Id.Text1, values) 
      
        
        
        
      
      , ,  let values = [|"item1"; "item2"; "item3"|]
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     -   string[],       list (IEnumerable   ) 
      
        
        
        
      
              F#.            www.tryfsharp.org/Learn 
      
        
        
        
      
      
 
      
        
        
        
      
          F# -  ,  
      
        
        
        
      
     
      
        
        
        
      
            F# For Fun And Profit 
      
        
        
        
      
     
      
        
        
        
      
       ,    
      
        
        
        
      
         - . 
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
     
      
        
        
        
      
            hash 
      
        
        
        
      
         MD5  F# 
      
        
        
        
      
      let MD5Hash (input : string) = use md5 = System.Security.Cryptography.MD5.Create() input |> System.Text.Encoding.ASCII.GetBytes |> md5.ComputeHash |> Seq.map (fun c -> c.ToString("X2")) |> Seq.reduce (+)
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
      |>
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      pipeline ,     . 
      
        
        
        
      
         :    GetBytes ->   ->      HEX  ->       (  reduce   +           ) ->    . 
      
        
        
        
      
     
      
        
        
        
      
      ,     C# using System; public string CreateMD5Hash (string input) { MD5 md5 = System.Security.Cryptography.MD5.Create(); byte[] inputBytes = System.Text.Encoding.ASCII.GetBytes (input); byte[] hashBytes = md5.ComputeHash (inputBytes); StringBuilder sb = new StringBuilder(); for (int i = 0; i < hashBytes.Length; i++) { sb.Append (hashBytes[i].ToString ("X2")); } return sb.ToString(); }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
     
      
        
        
        
      
              :        .       AzureServiceWorker (  CLR    ) 
      
        
        
        
      
     
      
        
        
        
      
              -   .   F#    !   Xamarin Studio            . 
      
        
        
        
      
      <ItemGroup> <Compile Include="Resources\Resource.designer.fs" /> <Compile Include="Properties\AssemblyInfo.fs" /> <Compile Include="Helpers\Helpers.fs" /> <Compile Include="Services\User.fs" /> <Compile Include="Services\AzureServiceWorker.fs" /> <Compile Include="IAmHereActivity.fs" /> <Compile Include="WhereAreYouActivity.fs" /> <Compile Include="SignInActivity.fs" /> </ItemGroup>
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
        
      
        
        
        
      
            :    .    Xamarin    Xamarin.Mobile 
      
        
        
        
      
     
      
        
        
        
      
          .  F#         TPL,     Task',      .     F#         Task.  ,     : 
      
        
        
        
      
     module Async = open System.Threading open System.Threading.Tasks let inline AwaitPlainTask (task: Task) = // rethrow exception from preceding task if it fauled let continuation (t : Task) : unit = match t.IsFaulted with | true -> raise t.Exception | arg -> () task.ContinueWith continuation |> Async.AwaitTask
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
             Async.AwaitIAsyncResult >> Async.Ignore
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
           
      
        
        
        
      
     
      
        
        
        
      
                
      
        
        
        
      
     let ExtractUserInfo (x : Contact) = let first = x.Phones |> Seq.tryPick(fun x -> if x.Type = PhoneType.Mobile then Some(x) else None) match first with | Some(first) -> let phone = first.Number |> StripChars [' ';'-';'(';')'] UserInfo.CreateUserInfo((MD5Hash phone), phone, x.DisplayName) | None -> UserInfo.CreateUserInfo("no mobile phone", "no mobile phone", "no mobile phone") // function for async list filling let FillContactsAsync = async { let book = new AddressBook (this) let! result = book.RequestPermission() |> Async.AwaitTask if result then _contacts <- book.ToList() |> Seq.filter (fun (x: Contact) -> not (Seq.isEmpty x.Phones)) |> Seq.map ExtractUserInfo |> Seq.sortBy(fun x -> x.DisplayName) |> Seq.toList let finalContacts = _contacts |> Seq.map (fun x -> x.DisplayName.ToUpperInvariant()) |> Seq.toArray this.ListAdapter <- new ArrayAdapter(this, Resource_Layout.row_contact, finalContacts) else System.Diagnostics.Debug.WriteLine("Permission denied by user or manifest") this.ListAdapter <- new ArrayAdapter(this, Resource_Layout.row_contact, Array.empty) }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
          
      
        
        
        
      
     book.ToList()
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
       List |> Seq.filter (fun (x: Contact) -> not (Seq.isEmpty x.Phones))
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
          |> Seq.map ExtractUserInfo
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
          Contracts  UserInfo,      UserInfo |> Seq.sortBy(fun x -> x.DisplayName)
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      |> Seq.toList
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
       List _contacts <-
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
        mutable  _contacts |> Seq.map (fun x -> x.DisplayName.ToUpperInvariant())<-
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
        UserInfo  string,     - -    |> Seq.toArray<-
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      List  Array    ArrayAdapter 
      
        
        
        
      
        -      List.   . 
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
     
      
        
        
        
      
     Azure Mobile Servcies 
      
        
        
        
      
       -    Azure Mobile Services.       NotificationHub,     Push    .   Azure    , ..      . 
      
        
        
        
      
     
      
        
        
        
      
          ,    
      
        
        
        
      
     module WruConstants = [<Literal>] let TotallyNotAzureServer = "https://YOUR.azure-mobile.net/"; [<Literal>] let TotallyNotAzureKey = "YOUR"
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
       
        
        
        
      
     member this.RegisterMe phone name regId = async { try let table = this.MobileService.GetTable<User>() let usr = { Id = "" PhoneHash = MD5Hash phone Nickname = name RegistrationId = regId } do! table.InsertAsync usr |> Async.AwaitPlainTask return (usr.Id, usr.PhoneHash, usr.Nickname) with | e -> System.Diagnostics.Trace.WriteLine(e.ToString) return (String.Empty,String.Empty,String.Empty) }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     member this.RegisterMe phone name regId = async {
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     -       (     )    .       "computation expression"   workflow.   { }       ! ( bang),  do! (do-bang)  let! (let bang)     User.    ,  F#        ,      
      
        
        
        
      
      let usr = { Id = "" PhoneHash = MD5Hash phone Nickname = name RegistrationId = regId }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     do! table.InsertAsync usr |> Async.AwaitPlainTask
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      do-bang,   await
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      C#. ..             continuation    . return (usr.Id, usr.PhoneHash, usr.Nickname)
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
          Tuple<string,string,string>     .  try ... with | e ->
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      try..catch
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      C# 
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
     
      
        
        
        
      
           .  F#    fst
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      snd
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
          .        2 .     : 
      
        
        
        
      
      let id (c,_,_) = c let phonehash (_,c,_) = c let nickname (_,_,c) = c
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
        : id tuple
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      Id  .. 
      
        
        
        
      
     
      
        
        
        
      
        5  Azure,       Push .       Azure Custom Api  
      
        
        
        
      
     
      
        
        
        
      
          exports.post = function(request, response) { // Use "request.service" to access features of your mobile service, eg: // var tables = request.service.tables; // var push = request.service.push; //response.send(statusCodes.OK, { message : 'Hello World!' }); console.log('Incoming call with requst: ', request.body.RequestId); var usersTable = request.service.tables.getTable('User'); usersTable.where( { id : request.body.TargetId } ) .read( { success: function(results) { if (results.length > 0) { var user = results[0] console.log('Send to results: ', user.Nickname, user.RegistrationId); request.service.push.gcm.send(user.RegistrationId, { RequesterId: request.body.RequesterId, RequesterNickname: request.body.RequesterName, TargetId: user.id, TargetNickname: user.Nickname }, { success: function(gcm_response) { console.log('Push notification sent: ', gcm_response); response.send(statusCodes.OK, { RequestedNickname : user.Nickname }); }, error: function(gcm_error) { console.log('Error sending push notification: ', gcm_error); response.send(statusCodes.INTERNAL_SERVER_ERROR, { RequestedNickname : user.Nickname }); } }); } else { response.send(statusCodes.NO_CONTENT, { RequestedNickname : "" }); } }, error: function(error) { console.log('Error read table: ', error); response.send(statusCodes.INTERNAL_SERVER_ERROR, { RequestedNickname : "" }); } }); };
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
        Push      
      
        
        
        
      
     // Perform Push operation member this.PushAsync targetId myId myNickname = async { try let (request : PushRequest) = { TargetId = targetId RequesterId = myId RequesterName = myNickname } let! result = this.MobileService.InvokeApiAsync<PushRequest, PushResponce>("pushhim", request) |> Async.AwaitTask return result.RequestedNickname with | e -> return e.ToString() }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
           ,    let-bang
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
       do!
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
       
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
          Google Play Services.     F#   .           .    : Xamarin.Android.Support.v7.AppCompat 
      
        
        
        
      
         , Google Play Services ,   . 
      
        
        
        
      
     
      
        
        
        
      
          push notification   .    GCM,  ID,     ID       Push  (.   pushhim).        BroadcastReciever       developer.android.com .     F#         Xamarin Component Store.     Google Cloud Messaging Client         GCM    .        ID 
      
        
        
        
      
     //Check to see that GCM is supported and that the manifest has the correct information GcmClient.CheckDevice(this) GcmClient.CheckManifest(this) // check google play if CheckPlayServices() then // Try to get registration id let regId = GcmClient.GetRegistrationId this if String.IsNullOrEmpty(regId) then // Call to Register the device for Push Notifications GcmClient.Register(this, WruConstants.GcmSender);
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
            
      
        
        
        
      
     
      
        
        
        
      
        . 
      
        
        
        
      
        , -  
      
        
        
        
      
         bitbucket.org/xakpc/whereareyou 
      
        
        
        
      
         ,     
      
        
        
        
      
              ,           "" . 
      
        
        
        
      
     
      
        
        
        
      
      
      
        
        
        
      
     ,   Android   F#.      . 
      
        
        
        
      
     ,       -  Android  F#.   ,       .
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
    listView.Adapter <- new ArrayAdapter(this, Android.Resource.Layout.SimpleListItem1, Android.Resource.Id.Text1, values) 
      
        
        
        
      
      , ,  let values = [|"item1"; "item2"; "item3"|]
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     -   string[],       list (IEnumerable   ) 
      
        
        
        
      
              F#.            www.tryfsharp.org/Learn 
      
        
        
        
      
      
 
      
        
        
        
      
          F# -  ,  
      
        
        
        
      
     
      
        
        
        
      
            F# For Fun And Profit 
      
        
        
        
      
     
      
        
        
        
      
       ,    
      
        
        
        
      
         - . 
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
     
      
        
        
        
      
            hash 
      
        
        
        
      
         MD5  F# 
      
        
        
        
      
      let MD5Hash (input : string) = use md5 = System.Security.Cryptography.MD5.Create() input |> System.Text.Encoding.ASCII.GetBytes |> md5.ComputeHash |> Seq.map (fun c -> c.ToString("X2")) |> Seq.reduce (+)
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
      |>
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      pipeline ,     . 
      
        
        
        
      
         :    GetBytes ->   ->      HEX  ->       (  reduce   +           ) ->    . 
      
        
        
        
      
     
      
        
        
        
      
      ,     C# using System; public string CreateMD5Hash (string input) { MD5 md5 = System.Security.Cryptography.MD5.Create(); byte[] inputBytes = System.Text.Encoding.ASCII.GetBytes (input); byte[] hashBytes = md5.ComputeHash (inputBytes); StringBuilder sb = new StringBuilder(); for (int i = 0; i < hashBytes.Length; i++) { sb.Append (hashBytes[i].ToString ("X2")); } return sb.ToString(); }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
     
      
        
        
        
      
              :        .       AzureServiceWorker (  CLR    ) 
      
        
        
        
      
     
      
        
        
        
      
              -   .   F#    !   Xamarin Studio            . 
      
        
        
        
      
      <ItemGroup> <Compile Include="Resources\Resource.designer.fs" /> <Compile Include="Properties\AssemblyInfo.fs" /> <Compile Include="Helpers\Helpers.fs" /> <Compile Include="Services\User.fs" /> <Compile Include="Services\AzureServiceWorker.fs" /> <Compile Include="IAmHereActivity.fs" /> <Compile Include="WhereAreYouActivity.fs" /> <Compile Include="SignInActivity.fs" /> </ItemGroup>
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
        
      
        
        
        
      
            :    .    Xamarin    Xamarin.Mobile 
      
        
        
        
      
     
      
        
        
        
      
          .  F#         TPL,     Task',      .     F#         Task.  ,     : 
      
        
        
        
      
     module Async = open System.Threading open System.Threading.Tasks let inline AwaitPlainTask (task: Task) = // rethrow exception from preceding task if it fauled let continuation (t : Task) : unit = match t.IsFaulted with | true -> raise t.Exception | arg -> () task.ContinueWith continuation |> Async.AwaitTask
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
             Async.AwaitIAsyncResult >> Async.Ignore
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
           
      
        
        
        
      
     
      
        
        
        
      
                
      
        
        
        
      
     let ExtractUserInfo (x : Contact) = let first = x.Phones |> Seq.tryPick(fun x -> if x.Type = PhoneType.Mobile then Some(x) else None) match first with | Some(first) -> let phone = first.Number |> StripChars [' ';'-';'(';')'] UserInfo.CreateUserInfo((MD5Hash phone), phone, x.DisplayName) | None -> UserInfo.CreateUserInfo("no mobile phone", "no mobile phone", "no mobile phone") // function for async list filling let FillContactsAsync = async { let book = new AddressBook (this) let! result = book.RequestPermission() |> Async.AwaitTask if result then _contacts <- book.ToList() |> Seq.filter (fun (x: Contact) -> not (Seq.isEmpty x.Phones)) |> Seq.map ExtractUserInfo |> Seq.sortBy(fun x -> x.DisplayName) |> Seq.toList let finalContacts = _contacts |> Seq.map (fun x -> x.DisplayName.ToUpperInvariant()) |> Seq.toArray this.ListAdapter <- new ArrayAdapter(this, Resource_Layout.row_contact, finalContacts) else System.Diagnostics.Debug.WriteLine("Permission denied by user or manifest") this.ListAdapter <- new ArrayAdapter(this, Resource_Layout.row_contact, Array.empty) }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
          
      
        
        
        
      
     book.ToList()
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
       List |> Seq.filter (fun (x: Contact) -> not (Seq.isEmpty x.Phones))
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
          |> Seq.map ExtractUserInfo
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
          Contracts  UserInfo,      UserInfo |> Seq.sortBy(fun x -> x.DisplayName)
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      |> Seq.toList
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
       List _contacts <-
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
        mutable  _contacts |> Seq.map (fun x -> x.DisplayName.ToUpperInvariant())<-
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
        UserInfo  string,     - -    |> Seq.toArray<-
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      List  Array    ArrayAdapter 
      
        
        
        
      
        -      List.   . 
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
     
      
        
        
        
      
     Azure Mobile Servcies 
      
        
        
        
      
       -    Azure Mobile Services.       NotificationHub,     Push    .   Azure    , ..      . 
      
        
        
        
      
     
      
        
        
        
      
          ,    
      
        
        
        
      
     module WruConstants = [<Literal>] let TotallyNotAzureServer = "https://YOUR.azure-mobile.net/"; [<Literal>] let TotallyNotAzureKey = "YOUR"
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
       
        
        
        
      
     member this.RegisterMe phone name regId = async { try let table = this.MobileService.GetTable<User>() let usr = { Id = "" PhoneHash = MD5Hash phone Nickname = name RegistrationId = regId } do! table.InsertAsync usr |> Async.AwaitPlainTask return (usr.Id, usr.PhoneHash, usr.Nickname) with | e -> System.Diagnostics.Trace.WriteLine(e.ToString) return (String.Empty,String.Empty,String.Empty) }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     member this.RegisterMe phone name regId = async {
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     -       (     )    .       "computation expression"   workflow.   { }       ! ( bang),  do! (do-bang)  let! (let bang)     User.    ,  F#        ,      
      
        
        
        
      
      let usr = { Id = "" PhoneHash = MD5Hash phone Nickname = name RegistrationId = regId }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     do! table.InsertAsync usr |> Async.AwaitPlainTask
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      do-bang,   await
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      C#. ..             continuation    . return (usr.Id, usr.PhoneHash, usr.Nickname)
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
          Tuple<string,string,string>     .  try ... with | e ->
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      try..catch
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      C# 
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
     
      
        
        
        
      
           .  F#    fst
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      snd
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
          .        2 .     : 
      
        
        
        
      
      let id (c,_,_) = c let phonehash (_,c,_) = c let nickname (_,_,c) = c
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
        : id tuple
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      Id  .. 
      
        
        
        
      
     
      
        
        
        
      
        5  Azure,       Push .       Azure Custom Api  
      
        
        
        
      
     
      
        
        
        
      
          exports.post = function(request, response) { // Use "request.service" to access features of your mobile service, eg: // var tables = request.service.tables; // var push = request.service.push; //response.send(statusCodes.OK, { message : 'Hello World!' }); console.log('Incoming call with requst: ', request.body.RequestId); var usersTable = request.service.tables.getTable('User'); usersTable.where( { id : request.body.TargetId } ) .read( { success: function(results) { if (results.length > 0) { var user = results[0] console.log('Send to results: ', user.Nickname, user.RegistrationId); request.service.push.gcm.send(user.RegistrationId, { RequesterId: request.body.RequesterId, RequesterNickname: request.body.RequesterName, TargetId: user.id, TargetNickname: user.Nickname }, { success: function(gcm_response) { console.log('Push notification sent: ', gcm_response); response.send(statusCodes.OK, { RequestedNickname : user.Nickname }); }, error: function(gcm_error) { console.log('Error sending push notification: ', gcm_error); response.send(statusCodes.INTERNAL_SERVER_ERROR, { RequestedNickname : user.Nickname }); } }); } else { response.send(statusCodes.NO_CONTENT, { RequestedNickname : "" }); } }, error: function(error) { console.log('Error read table: ', error); response.send(statusCodes.INTERNAL_SERVER_ERROR, { RequestedNickname : "" }); } }); };
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
        Push      
      
        
        
        
      
     // Perform Push operation member this.PushAsync targetId myId myNickname = async { try let (request : PushRequest) = { TargetId = targetId RequesterId = myId RequesterName = myNickname } let! result = this.MobileService.InvokeApiAsync<PushRequest, PushResponce>("pushhim", request) |> Async.AwaitTask return result.RequestedNickname with | e -> return e.ToString() }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
           ,    let-bang
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
       do!
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
       
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
          Google Play Services.     F#   .           .    : Xamarin.Android.Support.v7.AppCompat 
      
        
        
        
      
         , Google Play Services ,   . 
      
        
        
        
      
     
      
        
        
        
      
          push notification   .    GCM,  ID,     ID       Push  (.   pushhim).        BroadcastReciever       developer.android.com .     F#         Xamarin Component Store.     Google Cloud Messaging Client         GCM    .        ID 
      
        
        
        
      
     //Check to see that GCM is supported and that the manifest has the correct information GcmClient.CheckDevice(this) GcmClient.CheckManifest(this) // check google play if CheckPlayServices() then // Try to get registration id let regId = GcmClient.GetRegistrationId this if String.IsNullOrEmpty(regId) then // Call to Register the device for Push Notifications GcmClient.Register(this, WruConstants.GcmSender);
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
            
      
        
        
        
      
     
      
        
        
        
      
        . 
      
        
        
        
      
        , -  
      
        
        
        
      
         bitbucket.org/xakpc/whereareyou 
      
        
        
        
      
         ,     
      
        
        
        
      
              ,           "" . 
      
        
        
        
      
     
      
        
        
        
      
      
      
        
        
        
      
     ,   Android   F#.      . 
      
        
        
        
      
     ,       -  Android  F#.   ,       .
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     listView.Adapter <- new ArrayAdapter(this, Android.Resource.Layout.SimpleListItem1, Android.Resource.Id.Text1, values) 
      
        
        
        
      
      , ,  let values = [|"item1"; "item2"; "item3"|]
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     -   string[],       list (IEnumerable   ) 
      
        
        
        
      
              F#.            www.tryfsharp.org/Learn 
      
        
        
        
      
      
 
      
        
        
        
      
          F# -  ,  
      
        
        
        
      
     
      
        
        
        
      
            F# For Fun And Profit 
      
        
        
        
      
     
      
        
        
        
      
       ,    
      
        
        
        
      
         - . 
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
     
      
        
        
        
      
            hash 
      
        
        
        
      
         MD5  F# 
      
        
        
        
      
      let MD5Hash (input : string) = use md5 = System.Security.Cryptography.MD5.Create() input |> System.Text.Encoding.ASCII.GetBytes |> md5.ComputeHash |> Seq.map (fun c -> c.ToString("X2")) |> Seq.reduce (+)
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
      |>
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      pipeline ,     . 
      
        
        
        
      
         :    GetBytes ->   ->      HEX  ->       (  reduce   +           ) ->    . 
      
        
        
        
      
     
      
        
        
        
      
      ,     C# using System; public string CreateMD5Hash (string input) { MD5 md5 = System.Security.Cryptography.MD5.Create(); byte[] inputBytes = System.Text.Encoding.ASCII.GetBytes (input); byte[] hashBytes = md5.ComputeHash (inputBytes); StringBuilder sb = new StringBuilder(); for (int i = 0; i < hashBytes.Length; i++) { sb.Append (hashBytes[i].ToString ("X2")); } return sb.ToString(); }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
     
      
        
        
        
      
              :        .       AzureServiceWorker (  CLR    ) 
      
        
        
        
      
     
      
        
        
        
      
              -   .   F#    !   Xamarin Studio            . 
      
        
        
        
      
      <ItemGroup> <Compile Include="Resources\Resource.designer.fs" /> <Compile Include="Properties\AssemblyInfo.fs" /> <Compile Include="Helpers\Helpers.fs" /> <Compile Include="Services\User.fs" /> <Compile Include="Services\AzureServiceWorker.fs" /> <Compile Include="IAmHereActivity.fs" /> <Compile Include="WhereAreYouActivity.fs" /> <Compile Include="SignInActivity.fs" /> </ItemGroup>
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
        
      
        
        
        
      
            :    .    Xamarin    Xamarin.Mobile 
      
        
        
        
      
     
      
        
        
        
      
          .  F#         TPL,     Task',      .     F#         Task.  ,     : 
      
        
        
        
      
     module Async = open System.Threading open System.Threading.Tasks let inline AwaitPlainTask (task: Task) = // rethrow exception from preceding task if it fauled let continuation (t : Task) : unit = match t.IsFaulted with | true -> raise t.Exception | arg -> () task.ContinueWith continuation |> Async.AwaitTask
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
             Async.AwaitIAsyncResult >> Async.Ignore
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
           
      
        
        
        
      
     
      
        
        
        
      
                
      
        
        
        
      
     let ExtractUserInfo (x : Contact) = let first = x.Phones |> Seq.tryPick(fun x -> if x.Type = PhoneType.Mobile then Some(x) else None) match first with | Some(first) -> let phone = first.Number |> StripChars [' ';'-';'(';')'] UserInfo.CreateUserInfo((MD5Hash phone), phone, x.DisplayName) | None -> UserInfo.CreateUserInfo("no mobile phone", "no mobile phone", "no mobile phone") // function for async list filling let FillContactsAsync = async { let book = new AddressBook (this) let! result = book.RequestPermission() |> Async.AwaitTask if result then _contacts <- book.ToList() |> Seq.filter (fun (x: Contact) -> not (Seq.isEmpty x.Phones)) |> Seq.map ExtractUserInfo |> Seq.sortBy(fun x -> x.DisplayName) |> Seq.toList let finalContacts = _contacts |> Seq.map (fun x -> x.DisplayName.ToUpperInvariant()) |> Seq.toArray this.ListAdapter <- new ArrayAdapter(this, Resource_Layout.row_contact, finalContacts) else System.Diagnostics.Debug.WriteLine("Permission denied by user or manifest") this.ListAdapter <- new ArrayAdapter(this, Resource_Layout.row_contact, Array.empty) }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
          
      
        
        
        
      
     book.ToList()
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
       List |> Seq.filter (fun (x: Contact) -> not (Seq.isEmpty x.Phones))
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
          |> Seq.map ExtractUserInfo
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
          Contracts  UserInfo,      UserInfo |> Seq.sortBy(fun x -> x.DisplayName)
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      |> Seq.toList
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
       List _contacts <-
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
        mutable  _contacts |> Seq.map (fun x -> x.DisplayName.ToUpperInvariant())<-
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
        UserInfo  string,     - -    |> Seq.toArray<-
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      List  Array    ArrayAdapter 
      
        
        
        
      
        -      List.   . 
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
     
      
        
        
        
      
     Azure Mobile Servcies 
      
        
        
        
      
       -    Azure Mobile Services.       NotificationHub,     Push    .   Azure    , ..      . 
      
        
        
        
      
     
      
        
        
        
      
          ,    
      
        
        
        
      
     module WruConstants = [<Literal>] let TotallyNotAzureServer = "https://YOUR.azure-mobile.net/"; [<Literal>] let TotallyNotAzureKey = "YOUR"
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
       
        
        
        
      
     member this.RegisterMe phone name regId = async { try let table = this.MobileService.GetTable<User>() let usr = { Id = "" PhoneHash = MD5Hash phone Nickname = name RegistrationId = regId } do! table.InsertAsync usr |> Async.AwaitPlainTask return (usr.Id, usr.PhoneHash, usr.Nickname) with | e -> System.Diagnostics.Trace.WriteLine(e.ToString) return (String.Empty,String.Empty,String.Empty) }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     member this.RegisterMe phone name regId = async {
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     -       (     )    .       "computation expression"   workflow.   { }       ! ( bang),  do! (do-bang)  let! (let bang)     User.    ,  F#        ,      
      
        
        
        
      
      let usr = { Id = "" PhoneHash = MD5Hash phone Nickname = name RegistrationId = regId }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     do! table.InsertAsync usr |> Async.AwaitPlainTask
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      do-bang,   await
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      C#. ..             continuation    . return (usr.Id, usr.PhoneHash, usr.Nickname)
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
          Tuple<string,string,string>     .  try ... with | e ->
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      try..catch
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      C# 
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
     
      
        
        
        
      
           .  F#    fst
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      snd
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
          .        2 .     : 
      
        
        
        
      
      let id (c,_,_) = c let phonehash (_,c,_) = c let nickname (_,_,c) = c
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
        : id tuple
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      Id  .. 
      
        
        
        
      
     
      
        
        
        
      
        5  Azure,       Push .       Azure Custom Api  
      
        
        
        
      
     
      
        
        
        
      
          exports.post = function(request, response) { // Use "request.service" to access features of your mobile service, eg: // var tables = request.service.tables; // var push = request.service.push; //response.send(statusCodes.OK, { message : 'Hello World!' }); console.log('Incoming call with requst: ', request.body.RequestId); var usersTable = request.service.tables.getTable('User'); usersTable.where( { id : request.body.TargetId } ) .read( { success: function(results) { if (results.length > 0) { var user = results[0] console.log('Send to results: ', user.Nickname, user.RegistrationId); request.service.push.gcm.send(user.RegistrationId, { RequesterId: request.body.RequesterId, RequesterNickname: request.body.RequesterName, TargetId: user.id, TargetNickname: user.Nickname }, { success: function(gcm_response) { console.log('Push notification sent: ', gcm_response); response.send(statusCodes.OK, { RequestedNickname : user.Nickname }); }, error: function(gcm_error) { console.log('Error sending push notification: ', gcm_error); response.send(statusCodes.INTERNAL_SERVER_ERROR, { RequestedNickname : user.Nickname }); } }); } else { response.send(statusCodes.NO_CONTENT, { RequestedNickname : "" }); } }, error: function(error) { console.log('Error read table: ', error); response.send(statusCodes.INTERNAL_SERVER_ERROR, { RequestedNickname : "" }); } }); };
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
        Push      
      
        
        
        
      
     // Perform Push operation member this.PushAsync targetId myId myNickname = async { try let (request : PushRequest) = { TargetId = targetId RequesterId = myId RequesterName = myNickname } let! result = this.MobileService.InvokeApiAsync<PushRequest, PushResponce>("pushhim", request) |> Async.AwaitTask return result.RequestedNickname with | e -> return e.ToString() }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
           ,    let-bang
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
       do!
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
       
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
          Google Play Services.     F#   .           .    : Xamarin.Android.Support.v7.AppCompat 
      
        
        
        
      
         , Google Play Services ,   . 
      
        
        
        
      
     
      
        
        
        
      
          push notification   .    GCM,  ID,     ID       Push  (.   pushhim).        BroadcastReciever       developer.android.com .     F#         Xamarin Component Store.     Google Cloud Messaging Client         GCM    .        ID 
      
        
        
        
      
     //Check to see that GCM is supported and that the manifest has the correct information GcmClient.CheckDevice(this) GcmClient.CheckManifest(this) // check google play if CheckPlayServices() then // Try to get registration id let regId = GcmClient.GetRegistrationId this if String.IsNullOrEmpty(regId) then // Call to Register the device for Push Notifications GcmClient.Register(this, WruConstants.GcmSender);
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
            
      
        
        
        
      
     
      
        
        
        
      
        . 
      
        
        
        
      
        , -  
      
        
        
        
      
         bitbucket.org/xakpc/whereareyou 
      
        
        
        
      
         ,     
      
        
        
        
      
              ,           "" . 
      
        
        
        
      
     
      
        
        
        
      
      
      
        
        
        
      
     ,   Android   F#.      . 
      
        
        
        
      
     ,       -  Android  F#.   ,       .
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
    
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      listView.Adapter <- new ArrayAdapter(this, Android.Resource.Layout.SimpleListItem1, Android.Resource.Id.Text1, values) 
      
        
        
        
      
      , ,  let values = [|"item1"; "item2"; "item3"|]
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     -   string[],       list (IEnumerable   ) 
      
        
        
        
      
              F#.            www.tryfsharp.org/Learn 
      
        
        
        
      
      
 
      
        
        
        
      
          F# -  ,  
      
        
        
        
      
     
      
        
        
        
      
            F# For Fun And Profit 
      
        
        
        
      
     
      
        
        
        
      
       ,    
      
        
        
        
      
         - . 
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
     
      
        
        
        
      
            hash 
      
        
        
        
      
         MD5  F# 
      
        
        
        
      
      let MD5Hash (input : string) = use md5 = System.Security.Cryptography.MD5.Create() input |> System.Text.Encoding.ASCII.GetBytes |> md5.ComputeHash |> Seq.map (fun c -> c.ToString("X2")) |> Seq.reduce (+)
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
      |>
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      pipeline ,     . 
      
        
        
        
      
         :    GetBytes ->   ->      HEX  ->       (  reduce   +           ) ->    . 
      
        
        
        
      
     
      
        
        
        
      
      ,     C# using System; public string CreateMD5Hash (string input) { MD5 md5 = System.Security.Cryptography.MD5.Create(); byte[] inputBytes = System.Text.Encoding.ASCII.GetBytes (input); byte[] hashBytes = md5.ComputeHash (inputBytes); StringBuilder sb = new StringBuilder(); for (int i = 0; i < hashBytes.Length; i++) { sb.Append (hashBytes[i].ToString ("X2")); } return sb.ToString(); }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
     
      
        
        
        
      
              :        .       AzureServiceWorker (  CLR    ) 
      
        
        
        
      
     
      
        
        
        
      
              -   .   F#    !   Xamarin Studio            . 
      
        
        
        
      
      <ItemGroup> <Compile Include="Resources\Resource.designer.fs" /> <Compile Include="Properties\AssemblyInfo.fs" /> <Compile Include="Helpers\Helpers.fs" /> <Compile Include="Services\User.fs" /> <Compile Include="Services\AzureServiceWorker.fs" /> <Compile Include="IAmHereActivity.fs" /> <Compile Include="WhereAreYouActivity.fs" /> <Compile Include="SignInActivity.fs" /> </ItemGroup>
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
        
      
        
        
        
      
            :    .    Xamarin    Xamarin.Mobile 
      
        
        
        
      
     
      
        
        
        
      
          .  F#         TPL,     Task',      .     F#         Task.  ,     : 
      
        
        
        
      
     module Async = open System.Threading open System.Threading.Tasks let inline AwaitPlainTask (task: Task) = // rethrow exception from preceding task if it fauled let continuation (t : Task) : unit = match t.IsFaulted with | true -> raise t.Exception | arg -> () task.ContinueWith continuation |> Async.AwaitTask
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
             Async.AwaitIAsyncResult >> Async.Ignore
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
           
      
        
        
        
      
     
      
        
        
        
      
                
      
        
        
        
      
     let ExtractUserInfo (x : Contact) = let first = x.Phones |> Seq.tryPick(fun x -> if x.Type = PhoneType.Mobile then Some(x) else None) match first with | Some(first) -> let phone = first.Number |> StripChars [' ';'-';'(';')'] UserInfo.CreateUserInfo((MD5Hash phone), phone, x.DisplayName) | None -> UserInfo.CreateUserInfo("no mobile phone", "no mobile phone", "no mobile phone") // function for async list filling let FillContactsAsync = async { let book = new AddressBook (this) let! result = book.RequestPermission() |> Async.AwaitTask if result then _contacts <- book.ToList() |> Seq.filter (fun (x: Contact) -> not (Seq.isEmpty x.Phones)) |> Seq.map ExtractUserInfo |> Seq.sortBy(fun x -> x.DisplayName) |> Seq.toList let finalContacts = _contacts |> Seq.map (fun x -> x.DisplayName.ToUpperInvariant()) |> Seq.toArray this.ListAdapter <- new ArrayAdapter(this, Resource_Layout.row_contact, finalContacts) else System.Diagnostics.Debug.WriteLine("Permission denied by user or manifest") this.ListAdapter <- new ArrayAdapter(this, Resource_Layout.row_contact, Array.empty) }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
          
      
        
        
        
      
     book.ToList()
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
       List |> Seq.filter (fun (x: Contact) -> not (Seq.isEmpty x.Phones))
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
          |> Seq.map ExtractUserInfo
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
          Contracts  UserInfo,      UserInfo |> Seq.sortBy(fun x -> x.DisplayName)
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      |> Seq.toList
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
       List _contacts <-
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
        mutable  _contacts |> Seq.map (fun x -> x.DisplayName.ToUpperInvariant())<-
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
        UserInfo  string,     - -    |> Seq.toArray<-
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      List  Array    ArrayAdapter 
      
        
        
        
      
        -      List.   . 
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
     
      
        
        
        
      
     Azure Mobile Servcies 
      
        
        
        
      
       -    Azure Mobile Services.       NotificationHub,     Push    .   Azure    , ..      . 
      
        
        
        
      
     
      
        
        
        
      
          ,    
      
        
        
        
      
     module WruConstants = [<Literal>] let TotallyNotAzureServer = "https://YOUR.azure-mobile.net/"; [<Literal>] let TotallyNotAzureKey = "YOUR"
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
       
        
        
        
      
     member this.RegisterMe phone name regId = async { try let table = this.MobileService.GetTable<User>() let usr = { Id = "" PhoneHash = MD5Hash phone Nickname = name RegistrationId = regId } do! table.InsertAsync usr |> Async.AwaitPlainTask return (usr.Id, usr.PhoneHash, usr.Nickname) with | e -> System.Diagnostics.Trace.WriteLine(e.ToString) return (String.Empty,String.Empty,String.Empty) }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     member this.RegisterMe phone name regId = async {
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     -       (     )    .       "computation expression"   workflow.   { }       ! ( bang),  do! (do-bang)  let! (let bang)     User.    ,  F#        ,      
      
        
        
        
      
      let usr = { Id = "" PhoneHash = MD5Hash phone Nickname = name RegistrationId = regId }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     do! table.InsertAsync usr |> Async.AwaitPlainTask
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      do-bang,   await
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      C#. ..             continuation    . return (usr.Id, usr.PhoneHash, usr.Nickname)
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
          Tuple<string,string,string>     .  try ... with | e ->
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      try..catch
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      C# 
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
     
      
        
        
        
      
           .  F#    fst
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      snd
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
          .        2 .     : 
      
        
        
        
      
      let id (c,_,_) = c let phonehash (_,c,_) = c let nickname (_,_,c) = c
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
        : id tuple
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      Id  .. 
      
        
        
        
      
     
      
        
        
        
      
        5  Azure,       Push .       Azure Custom Api  
      
        
        
        
      
     
      
        
        
        
      
          exports.post = function(request, response) { // Use "request.service" to access features of your mobile service, eg: // var tables = request.service.tables; // var push = request.service.push; //response.send(statusCodes.OK, { message : 'Hello World!' }); console.log('Incoming call with requst: ', request.body.RequestId); var usersTable = request.service.tables.getTable('User'); usersTable.where( { id : request.body.TargetId } ) .read( { success: function(results) { if (results.length > 0) { var user = results[0] console.log('Send to results: ', user.Nickname, user.RegistrationId); request.service.push.gcm.send(user.RegistrationId, { RequesterId: request.body.RequesterId, RequesterNickname: request.body.RequesterName, TargetId: user.id, TargetNickname: user.Nickname }, { success: function(gcm_response) { console.log('Push notification sent: ', gcm_response); response.send(statusCodes.OK, { RequestedNickname : user.Nickname }); }, error: function(gcm_error) { console.log('Error sending push notification: ', gcm_error); response.send(statusCodes.INTERNAL_SERVER_ERROR, { RequestedNickname : user.Nickname }); } }); } else { response.send(statusCodes.NO_CONTENT, { RequestedNickname : "" }); } }, error: function(error) { console.log('Error read table: ', error); response.send(statusCodes.INTERNAL_SERVER_ERROR, { RequestedNickname : "" }); } }); };
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
        Push      
      
        
        
        
      
     // Perform Push operation member this.PushAsync targetId myId myNickname = async { try let (request : PushRequest) = { TargetId = targetId RequesterId = myId RequesterName = myNickname } let! result = this.MobileService.InvokeApiAsync<PushRequest, PushResponce>("pushhim", request) |> Async.AwaitTask return result.RequestedNickname with | e -> return e.ToString() }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
           ,    let-bang
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
       do!
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
       
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
          Google Play Services.     F#   .           .    : Xamarin.Android.Support.v7.AppCompat 
      
        
        
        
      
         , Google Play Services ,   . 
      
        
        
        
      
     
      
        
        
        
      
          push notification   .    GCM,  ID,     ID       Push  (.   pushhim).        BroadcastReciever       developer.android.com .     F#         Xamarin Component Store.     Google Cloud Messaging Client         GCM    .        ID 
      
        
        
        
      
     //Check to see that GCM is supported and that the manifest has the correct information GcmClient.CheckDevice(this) GcmClient.CheckManifest(this) // check google play if CheckPlayServices() then // Try to get registration id let regId = GcmClient.GetRegistrationId this if String.IsNullOrEmpty(regId) then // Call to Register the device for Push Notifications GcmClient.Register(this, WruConstants.GcmSender);
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
            
      
        
        
        
      
     
      
        
        
        
      
        . 
      
        
        
        
      
        , -  
      
        
        
        
      
         bitbucket.org/xakpc/whereareyou 
      
        
        
        
      
         ,     
      
        
        
        
      
              ,           "" . 
      
        
        
        
      
     
      
        
        
        
      
      
      
        
        
        
      
     ,   Android   F#.      . 
      
        
        
        
      
     ,       -  Android  F#.   ,       .
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
    listView.Adapter <- new ArrayAdapter(this, Android.Resource.Layout.SimpleListItem1, Android.Resource.Id.Text1, values) 
      
        
        
        
      
      , ,  let values = [|"item1"; "item2"; "item3"|]
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     -   string[],       list (IEnumerable   ) 
      
        
        
        
      
              F#.            www.tryfsharp.org/Learn 
      
        
        
        
      
      
 
      
        
        
        
      
          F# -  ,  
      
        
        
        
      
     
      
        
        
        
      
            F# For Fun And Profit 
      
        
        
        
      
     
      
        
        
        
      
       ,    
      
        
        
        
      
         - . 
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
     
      
        
        
        
      
            hash 
      
        
        
        
      
         MD5  F# 
      
        
        
        
      
      let MD5Hash (input : string) = use md5 = System.Security.Cryptography.MD5.Create() input |> System.Text.Encoding.ASCII.GetBytes |> md5.ComputeHash |> Seq.map (fun c -> c.ToString("X2")) |> Seq.reduce (+)
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
      |>
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      pipeline ,     . 
      
        
        
        
      
         :    GetBytes ->   ->      HEX  ->       (  reduce   +           ) ->    . 
      
        
        
        
      
     
      
        
        
        
      
      ,     C# using System; public string CreateMD5Hash (string input) { MD5 md5 = System.Security.Cryptography.MD5.Create(); byte[] inputBytes = System.Text.Encoding.ASCII.GetBytes (input); byte[] hashBytes = md5.ComputeHash (inputBytes); StringBuilder sb = new StringBuilder(); for (int i = 0; i < hashBytes.Length; i++) { sb.Append (hashBytes[i].ToString ("X2")); } return sb.ToString(); }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
     
      
        
        
        
      
              :        .       AzureServiceWorker (  CLR    ) 
      
        
        
        
      
     
      
        
        
        
      
              -   .   F#    !   Xamarin Studio            . 
      
        
        
        
      
      <ItemGroup> <Compile Include="Resources\Resource.designer.fs" /> <Compile Include="Properties\AssemblyInfo.fs" /> <Compile Include="Helpers\Helpers.fs" /> <Compile Include="Services\User.fs" /> <Compile Include="Services\AzureServiceWorker.fs" /> <Compile Include="IAmHereActivity.fs" /> <Compile Include="WhereAreYouActivity.fs" /> <Compile Include="SignInActivity.fs" /> </ItemGroup>
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
        
      
        
        
        
      
            :    .    Xamarin    Xamarin.Mobile 
      
        
        
        
      
     
      
        
        
        
      
          .  F#         TPL,     Task',      .     F#         Task.  ,     : 
      
        
        
        
      
     module Async = open System.Threading open System.Threading.Tasks let inline AwaitPlainTask (task: Task) = // rethrow exception from preceding task if it fauled let continuation (t : Task) : unit = match t.IsFaulted with | true -> raise t.Exception | arg -> () task.ContinueWith continuation |> Async.AwaitTask
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
             Async.AwaitIAsyncResult >> Async.Ignore
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
           
      
        
        
        
      
     
      
        
        
        
      
                
      
        
        
        
      
     let ExtractUserInfo (x : Contact) = let first = x.Phones |> Seq.tryPick(fun x -> if x.Type = PhoneType.Mobile then Some(x) else None) match first with | Some(first) -> let phone = first.Number |> StripChars [' ';'-';'(';')'] UserInfo.CreateUserInfo((MD5Hash phone), phone, x.DisplayName) | None -> UserInfo.CreateUserInfo("no mobile phone", "no mobile phone", "no mobile phone") // function for async list filling let FillContactsAsync = async { let book = new AddressBook (this) let! result = book.RequestPermission() |> Async.AwaitTask if result then _contacts <- book.ToList() |> Seq.filter (fun (x: Contact) -> not (Seq.isEmpty x.Phones)) |> Seq.map ExtractUserInfo |> Seq.sortBy(fun x -> x.DisplayName) |> Seq.toList let finalContacts = _contacts |> Seq.map (fun x -> x.DisplayName.ToUpperInvariant()) |> Seq.toArray this.ListAdapter <- new ArrayAdapter(this, Resource_Layout.row_contact, finalContacts) else System.Diagnostics.Debug.WriteLine("Permission denied by user or manifest") this.ListAdapter <- new ArrayAdapter(this, Resource_Layout.row_contact, Array.empty) }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
          
      
        
        
        
      
     book.ToList()
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
       List |> Seq.filter (fun (x: Contact) -> not (Seq.isEmpty x.Phones))
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
          |> Seq.map ExtractUserInfo
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
          Contracts  UserInfo,      UserInfo |> Seq.sortBy(fun x -> x.DisplayName)
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      |> Seq.toList
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
       List _contacts <-
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
        mutable  _contacts |> Seq.map (fun x -> x.DisplayName.ToUpperInvariant())<-
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
        UserInfo  string,     - -    |> Seq.toArray<-
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      List  Array    ArrayAdapter 
      
        
        
        
      
        -      List.   . 
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
     
      
        
        
        
      
     Azure Mobile Servcies 
      
        
        
        
      
       -    Azure Mobile Services.       NotificationHub,     Push    .   Azure    , ..      . 
      
        
        
        
      
     
      
        
        
        
      
          ,    
      
        
        
        
      
     module WruConstants = [<Literal>] let TotallyNotAzureServer = "https://YOUR.azure-mobile.net/"; [<Literal>] let TotallyNotAzureKey = "YOUR"
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
       
        
        
        
      
     member this.RegisterMe phone name regId = async { try let table = this.MobileService.GetTable<User>() let usr = { Id = "" PhoneHash = MD5Hash phone Nickname = name RegistrationId = regId } do! table.InsertAsync usr |> Async.AwaitPlainTask return (usr.Id, usr.PhoneHash, usr.Nickname) with | e -> System.Diagnostics.Trace.WriteLine(e.ToString) return (String.Empty,String.Empty,String.Empty) }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     member this.RegisterMe phone name regId = async {
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     -       (     )    .       "computation expression"   workflow.   { }       ! ( bang),  do! (do-bang)  let! (let bang)     User.    ,  F#        ,      
      
        
        
        
      
      let usr = { Id = "" PhoneHash = MD5Hash phone Nickname = name RegistrationId = regId }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     do! table.InsertAsync usr |> Async.AwaitPlainTask
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      do-bang,   await
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      C#. ..             continuation    . return (usr.Id, usr.PhoneHash, usr.Nickname)
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
          Tuple<string,string,string>     .  try ... with | e ->
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      try..catch
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      C# 
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
     
      
        
        
        
      
           .  F#    fst
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      snd
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
          .        2 .     : 
      
        
        
        
      
      let id (c,_,_) = c let phonehash (_,c,_) = c let nickname (_,_,c) = c
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
        : id tuple
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      Id  .. 
      
        
        
        
      
     
      
        
        
        
      
        5  Azure,       Push .       Azure Custom Api  
      
        
        
        
      
     
      
        
        
        
      
          exports.post = function(request, response) { // Use "request.service" to access features of your mobile service, eg: // var tables = request.service.tables; // var push = request.service.push; //response.send(statusCodes.OK, { message : 'Hello World!' }); console.log('Incoming call with requst: ', request.body.RequestId); var usersTable = request.service.tables.getTable('User'); usersTable.where( { id : request.body.TargetId } ) .read( { success: function(results) { if (results.length > 0) { var user = results[0] console.log('Send to results: ', user.Nickname, user.RegistrationId); request.service.push.gcm.send(user.RegistrationId, { RequesterId: request.body.RequesterId, RequesterNickname: request.body.RequesterName, TargetId: user.id, TargetNickname: user.Nickname }, { success: function(gcm_response) { console.log('Push notification sent: ', gcm_response); response.send(statusCodes.OK, { RequestedNickname : user.Nickname }); }, error: function(gcm_error) { console.log('Error sending push notification: ', gcm_error); response.send(statusCodes.INTERNAL_SERVER_ERROR, { RequestedNickname : user.Nickname }); } }); } else { response.send(statusCodes.NO_CONTENT, { RequestedNickname : "" }); } }, error: function(error) { console.log('Error read table: ', error); response.send(statusCodes.INTERNAL_SERVER_ERROR, { RequestedNickname : "" }); } }); };
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
        Push      
      
        
        
        
      
     // Perform Push operation member this.PushAsync targetId myId myNickname = async { try let (request : PushRequest) = { TargetId = targetId RequesterId = myId RequesterName = myNickname } let! result = this.MobileService.InvokeApiAsync<PushRequest, PushResponce>("pushhim", request) |> Async.AwaitTask return result.RequestedNickname with | e -> return e.ToString() }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
           ,    let-bang
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
       do!
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
       
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
          Google Play Services.     F#   .           .    : Xamarin.Android.Support.v7.AppCompat 
      
        
        
        
      
         , Google Play Services ,   . 
      
        
        
        
      
     
      
        
        
        
      
          push notification   .    GCM,  ID,     ID       Push  (.   pushhim).        BroadcastReciever       developer.android.com .     F#         Xamarin Component Store.     Google Cloud Messaging Client         GCM    .        ID 
      
        
        
        
      
     //Check to see that GCM is supported and that the manifest has the correct information GcmClient.CheckDevice(this) GcmClient.CheckManifest(this) // check google play if CheckPlayServices() then // Try to get registration id let regId = GcmClient.GetRegistrationId this if String.IsNullOrEmpty(regId) then // Call to Register the device for Push Notifications GcmClient.Register(this, WruConstants.GcmSender);
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
            
      
        
        
        
      
     
      
        
        
        
      
        . 
      
        
        
        
      
        , -  
      
        
        
        
      
         bitbucket.org/xakpc/whereareyou 
      
        
        
        
      
         ,     
      
        
        
        
      
              ,           "" . 
      
        
        
        
      
     
      
        
        
        
      
      
      
        
        
        
      
     ,   Android   F#.      . 
      
        
        
        
      
     ,       -  Android  F#.   ,       .
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     listView.Adapter <- new ArrayAdapter(this, Android.Resource.Layout.SimpleListItem1, Android.Resource.Id.Text1, values) 
      
        
        
        
      
      , ,  let values = [|"item1"; "item2"; "item3"|]
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     -   string[],       list (IEnumerable   ) 
      
        
        
        
      
              F#.            www.tryfsharp.org/Learn 
      
        
        
        
      
      
 
      
        
        
        
      
          F# -  ,  
      
        
        
        
      
     
      
        
        
        
      
            F# For Fun And Profit 
      
        
        
        
      
     
      
        
        
        
      
       ,    
      
        
        
        
      
         - . 
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
     
      
        
        
        
      
            hash 
      
        
        
        
      
         MD5  F# 
      
        
        
        
      
      let MD5Hash (input : string) = use md5 = System.Security.Cryptography.MD5.Create() input |> System.Text.Encoding.ASCII.GetBytes |> md5.ComputeHash |> Seq.map (fun c -> c.ToString("X2")) |> Seq.reduce (+)
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
      |>
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      pipeline ,     . 
      
        
        
        
      
         :    GetBytes ->   ->      HEX  ->       (  reduce   +           ) ->    . 
      
        
        
        
      
     
      
        
        
        
      
      ,     C# using System; public string CreateMD5Hash (string input) { MD5 md5 = System.Security.Cryptography.MD5.Create(); byte[] inputBytes = System.Text.Encoding.ASCII.GetBytes (input); byte[] hashBytes = md5.ComputeHash (inputBytes); StringBuilder sb = new StringBuilder(); for (int i = 0; i < hashBytes.Length; i++) { sb.Append (hashBytes[i].ToString ("X2")); } return sb.ToString(); }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
     
      
        
        
        
      
              :        .       AzureServiceWorker (  CLR    ) 
      
        
        
        
      
     
      
        
        
        
      
              -   .   F#    !   Xamarin Studio            . 
      
        
        
        
      
      <ItemGroup> <Compile Include="Resources\Resource.designer.fs" /> <Compile Include="Properties\AssemblyInfo.fs" /> <Compile Include="Helpers\Helpers.fs" /> <Compile Include="Services\User.fs" /> <Compile Include="Services\AzureServiceWorker.fs" /> <Compile Include="IAmHereActivity.fs" /> <Compile Include="WhereAreYouActivity.fs" /> <Compile Include="SignInActivity.fs" /> </ItemGroup>
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
        
      
        
        
        
      
            :    .    Xamarin    Xamarin.Mobile 
      
        
        
        
      
     
      
        
        
        
      
          .  F#         TPL,     Task',      .     F#         Task.  ,     : 
      
        
        
        
      
     module Async = open System.Threading open System.Threading.Tasks let inline AwaitPlainTask (task: Task) = // rethrow exception from preceding task if it fauled let continuation (t : Task) : unit = match t.IsFaulted with | true -> raise t.Exception | arg -> () task.ContinueWith continuation |> Async.AwaitTask
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
             Async.AwaitIAsyncResult >> Async.Ignore
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
           
      
        
        
        
      
     
      
        
        
        
      
                
      
        
        
        
      
     let ExtractUserInfo (x : Contact) = let first = x.Phones |> Seq.tryPick(fun x -> if x.Type = PhoneType.Mobile then Some(x) else None) match first with | Some(first) -> let phone = first.Number |> StripChars [' ';'-';'(';')'] UserInfo.CreateUserInfo((MD5Hash phone), phone, x.DisplayName) | None -> UserInfo.CreateUserInfo("no mobile phone", "no mobile phone", "no mobile phone") // function for async list filling let FillContactsAsync = async { let book = new AddressBook (this) let! result = book.RequestPermission() |> Async.AwaitTask if result then _contacts <- book.ToList() |> Seq.filter (fun (x: Contact) -> not (Seq.isEmpty x.Phones)) |> Seq.map ExtractUserInfo |> Seq.sortBy(fun x -> x.DisplayName) |> Seq.toList let finalContacts = _contacts |> Seq.map (fun x -> x.DisplayName.ToUpperInvariant()) |> Seq.toArray this.ListAdapter <- new ArrayAdapter(this, Resource_Layout.row_contact, finalContacts) else System.Diagnostics.Debug.WriteLine("Permission denied by user or manifest") this.ListAdapter <- new ArrayAdapter(this, Resource_Layout.row_contact, Array.empty) }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
          
      
        
        
        
      
     book.ToList()
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
       List |> Seq.filter (fun (x: Contact) -> not (Seq.isEmpty x.Phones))
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
          |> Seq.map ExtractUserInfo
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
          Contracts  UserInfo,      UserInfo |> Seq.sortBy(fun x -> x.DisplayName)
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      |> Seq.toList
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
       List _contacts <-
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
        mutable  _contacts |> Seq.map (fun x -> x.DisplayName.ToUpperInvariant())<-
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
        UserInfo  string,     - -    |> Seq.toArray<-
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      List  Array    ArrayAdapter 
      
        
        
        
      
        -      List.   . 
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
     
      
        
        
        
      
     Azure Mobile Servcies 
      
        
        
        
      
       -    Azure Mobile Services.       NotificationHub,     Push    .   Azure    , ..      . 
      
        
        
        
      
     
      
        
        
        
      
          ,    
      
        
        
        
      
     module WruConstants = [<Literal>] let TotallyNotAzureServer = "https://YOUR.azure-mobile.net/"; [<Literal>] let TotallyNotAzureKey = "YOUR"
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
       
        
        
        
      
     member this.RegisterMe phone name regId = async { try let table = this.MobileService.GetTable<User>() let usr = { Id = "" PhoneHash = MD5Hash phone Nickname = name RegistrationId = regId } do! table.InsertAsync usr |> Async.AwaitPlainTask return (usr.Id, usr.PhoneHash, usr.Nickname) with | e -> System.Diagnostics.Trace.WriteLine(e.ToString) return (String.Empty,String.Empty,String.Empty) }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     member this.RegisterMe phone name regId = async {
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     -       (     )    .       "computation expression"   workflow.   { }       ! ( bang),  do! (do-bang)  let! (let bang)     User.    ,  F#        ,      
      
        
        
        
      
      let usr = { Id = "" PhoneHash = MD5Hash phone Nickname = name RegistrationId = regId }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     do! table.InsertAsync usr |> Async.AwaitPlainTask
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      do-bang,   await
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      C#. ..             continuation    . return (usr.Id, usr.PhoneHash, usr.Nickname)
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
          Tuple<string,string,string>     .  try ... with | e ->
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      try..catch
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      C# 
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
     
      
        
        
        
      
           .  F#    fst
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      snd
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
          .        2 .     : 
      
        
        
        
      
      let id (c,_,_) = c let phonehash (_,c,_) = c let nickname (_,_,c) = c
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
        : id tuple
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      Id  .. 
      
        
        
        
      
     
      
        
        
        
      
        5  Azure,       Push .       Azure Custom Api  
      
        
        
        
      
     
      
        
        
        
      
          exports.post = function(request, response) { // Use "request.service" to access features of your mobile service, eg: // var tables = request.service.tables; // var push = request.service.push; //response.send(statusCodes.OK, { message : 'Hello World!' }); console.log('Incoming call with requst: ', request.body.RequestId); var usersTable = request.service.tables.getTable('User'); usersTable.where( { id : request.body.TargetId } ) .read( { success: function(results) { if (results.length > 0) { var user = results[0] console.log('Send to results: ', user.Nickname, user.RegistrationId); request.service.push.gcm.send(user.RegistrationId, { RequesterId: request.body.RequesterId, RequesterNickname: request.body.RequesterName, TargetId: user.id, TargetNickname: user.Nickname }, { success: function(gcm_response) { console.log('Push notification sent: ', gcm_response); response.send(statusCodes.OK, { RequestedNickname : user.Nickname }); }, error: function(gcm_error) { console.log('Error sending push notification: ', gcm_error); response.send(statusCodes.INTERNAL_SERVER_ERROR, { RequestedNickname : user.Nickname }); } }); } else { response.send(statusCodes.NO_CONTENT, { RequestedNickname : "" }); } }, error: function(error) { console.log('Error read table: ', error); response.send(statusCodes.INTERNAL_SERVER_ERROR, { RequestedNickname : "" }); } }); };
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
        Push      
      
        
        
        
      
     // Perform Push operation member this.PushAsync targetId myId myNickname = async { try let (request : PushRequest) = { TargetId = targetId RequesterId = myId RequesterName = myNickname } let! result = this.MobileService.InvokeApiAsync<PushRequest, PushResponce>("pushhim", request) |> Async.AwaitTask return result.RequestedNickname with | e -> return e.ToString() }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
           ,    let-bang
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
       do!
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
       
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
          Google Play Services.     F#   .           .    : Xamarin.Android.Support.v7.AppCompat 
      
        
        
        
      
         , Google Play Services ,   . 
      
        
        
        
      
     
      
        
        
        
      
          push notification   .    GCM,  ID,     ID       Push  (.   pushhim).        BroadcastReciever       developer.android.com .     F#         Xamarin Component Store.     Google Cloud Messaging Client         GCM    .        ID 
      
        
        
        
      
     //Check to see that GCM is supported and that the manifest has the correct information GcmClient.CheckDevice(this) GcmClient.CheckManifest(this) // check google play if CheckPlayServices() then // Try to get registration id let regId = GcmClient.GetRegistrationId this if String.IsNullOrEmpty(regId) then // Call to Register the device for Push Notifications GcmClient.Register(this, WruConstants.GcmSender);
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
            
      
        
        
        
      
     
      
        
        
        
      
        . 
      
        
        
        
      
        , -  
      
        
        
        
      
         bitbucket.org/xakpc/whereareyou 
      
        
        
        
      
         ,     
      
        
        
        
      
              ,           "" . 
      
        
        
        
      
     
      
        
        
        
      
      
      
        
        
        
      
     ,   Android   F#.      . 
      
        
        
        
      
     ,       -  Android  F#.   ,       .
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
    
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      listView.Adapter <- new ArrayAdapter(this, Android.Resource.Layout.SimpleListItem1, Android.Resource.Id.Text1, values) 
      
        
        
        
      
      , ,  let values = [|"item1"; "item2"; "item3"|]
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     -   string[],       list (IEnumerable   ) 
      
        
        
        
      
              F#.            www.tryfsharp.org/Learn 
      
        
        
        
      
      
 
      
        
        
        
      
          F# -  ,  
      
        
        
        
      
     
      
        
        
        
      
            F# For Fun And Profit 
      
        
        
        
      
     
      
        
        
        
      
       ,    
      
        
        
        
      
         - . 
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
     
      
        
        
        
      
            hash 
      
        
        
        
      
         MD5  F# 
      
        
        
        
      
      let MD5Hash (input : string) = use md5 = System.Security.Cryptography.MD5.Create() input |> System.Text.Encoding.ASCII.GetBytes |> md5.ComputeHash |> Seq.map (fun c -> c.ToString("X2")) |> Seq.reduce (+)
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
      |>
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      pipeline ,     . 
      
        
        
        
      
         :    GetBytes ->   ->      HEX  ->       (  reduce   +           ) ->    . 
      
        
        
        
      
     
      
        
        
        
      
      ,     C# using System; public string CreateMD5Hash (string input) { MD5 md5 = System.Security.Cryptography.MD5.Create(); byte[] inputBytes = System.Text.Encoding.ASCII.GetBytes (input); byte[] hashBytes = md5.ComputeHash (inputBytes); StringBuilder sb = new StringBuilder(); for (int i = 0; i < hashBytes.Length; i++) { sb.Append (hashBytes[i].ToString ("X2")); } return sb.ToString(); }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
     
      
        
        
        
      
              :        .       AzureServiceWorker (  CLR    ) 
      
        
        
        
      
     
      
        
        
        
      
              -   .   F#    !   Xamarin Studio            . 
      
        
        
        
      
      <ItemGroup> <Compile Include="Resources\Resource.designer.fs" /> <Compile Include="Properties\AssemblyInfo.fs" /> <Compile Include="Helpers\Helpers.fs" /> <Compile Include="Services\User.fs" /> <Compile Include="Services\AzureServiceWorker.fs" /> <Compile Include="IAmHereActivity.fs" /> <Compile Include="WhereAreYouActivity.fs" /> <Compile Include="SignInActivity.fs" /> </ItemGroup>
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
        
      
        
        
        
      
            :    .    Xamarin    Xamarin.Mobile 
      
        
        
        
      
     
      
        
        
        
      
          .  F#         TPL,     Task',      .     F#         Task.  ,     : 
      
        
        
        
      
     module Async = open System.Threading open System.Threading.Tasks let inline AwaitPlainTask (task: Task) = // rethrow exception from preceding task if it fauled let continuation (t : Task) : unit = match t.IsFaulted with | true -> raise t.Exception | arg -> () task.ContinueWith continuation |> Async.AwaitTask
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
             Async.AwaitIAsyncResult >> Async.Ignore
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
           
      
        
        
        
      
     
      
        
        
        
      
                
      
        
        
        
      
     let ExtractUserInfo (x : Contact) = let first = x.Phones |> Seq.tryPick(fun x -> if x.Type = PhoneType.Mobile then Some(x) else None) match first with | Some(first) -> let phone = first.Number |> StripChars [' ';'-';'(';')'] UserInfo.CreateUserInfo((MD5Hash phone), phone, x.DisplayName) | None -> UserInfo.CreateUserInfo("no mobile phone", "no mobile phone", "no mobile phone") // function for async list filling let FillContactsAsync = async { let book = new AddressBook (this) let! result = book.RequestPermission() |> Async.AwaitTask if result then _contacts <- book.ToList() |> Seq.filter (fun (x: Contact) -> not (Seq.isEmpty x.Phones)) |> Seq.map ExtractUserInfo |> Seq.sortBy(fun x -> x.DisplayName) |> Seq.toList let finalContacts = _contacts |> Seq.map (fun x -> x.DisplayName.ToUpperInvariant()) |> Seq.toArray this.ListAdapter <- new ArrayAdapter(this, Resource_Layout.row_contact, finalContacts) else System.Diagnostics.Debug.WriteLine("Permission denied by user or manifest") this.ListAdapter <- new ArrayAdapter(this, Resource_Layout.row_contact, Array.empty) }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
          
      
        
        
        
      
     book.ToList()
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
       List |> Seq.filter (fun (x: Contact) -> not (Seq.isEmpty x.Phones))
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
          |> Seq.map ExtractUserInfo
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
          Contracts  UserInfo,      UserInfo |> Seq.sortBy(fun x -> x.DisplayName)
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      |> Seq.toList
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
       List _contacts <-
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
        mutable  _contacts |> Seq.map (fun x -> x.DisplayName.ToUpperInvariant())<-
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
        UserInfo  string,     - -    |> Seq.toArray<-
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      List  Array    ArrayAdapter 
      
        
        
        
      
        -      List.   . 
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
     
      
        
        
        
      
     Azure Mobile Servcies 
      
        
        
        
      
       -    Azure Mobile Services.       NotificationHub,     Push    .   Azure    , ..      . 
      
        
        
        
      
     
      
        
        
        
      
          ,    
      
        
        
        
      
     module WruConstants = [<Literal>] let TotallyNotAzureServer = "https://YOUR.azure-mobile.net/"; [<Literal>] let TotallyNotAzureKey = "YOUR"
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
       
        
        
        
      
     member this.RegisterMe phone name regId = async { try let table = this.MobileService.GetTable<User>() let usr = { Id = "" PhoneHash = MD5Hash phone Nickname = name RegistrationId = regId } do! table.InsertAsync usr |> Async.AwaitPlainTask return (usr.Id, usr.PhoneHash, usr.Nickname) with | e -> System.Diagnostics.Trace.WriteLine(e.ToString) return (String.Empty,String.Empty,String.Empty) }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     member this.RegisterMe phone name regId = async {
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     -       (     )    .       "computation expression"   workflow.   { }       ! ( bang),  do! (do-bang)  let! (let bang)     User.    ,  F#        ,      
      
        
        
        
      
      let usr = { Id = "" PhoneHash = MD5Hash phone Nickname = name RegistrationId = regId }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     do! table.InsertAsync usr |> Async.AwaitPlainTask
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      do-bang,   await
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      C#. ..             continuation    . return (usr.Id, usr.PhoneHash, usr.Nickname)
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
          Tuple<string,string,string>     .  try ... with | e ->
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      try..catch
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      C# 
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
     
      
        
        
        
      
           .  F#    fst
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      snd
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
          .        2 .     : 
      
        
        
        
      
      let id (c,_,_) = c let phonehash (_,c,_) = c let nickname (_,_,c) = c
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
        : id tuple
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      Id  .. 
      
        
        
        
      
     
      
        
        
        
      
        5  Azure,       Push .       Azure Custom Api  
      
        
        
        
      
     
      
        
        
        
      
          exports.post = function(request, response) { // Use "request.service" to access features of your mobile service, eg: // var tables = request.service.tables; // var push = request.service.push; //response.send(statusCodes.OK, { message : 'Hello World!' }); console.log('Incoming call with requst: ', request.body.RequestId); var usersTable = request.service.tables.getTable('User'); usersTable.where( { id : request.body.TargetId } ) .read( { success: function(results) { if (results.length > 0) { var user = results[0] console.log('Send to results: ', user.Nickname, user.RegistrationId); request.service.push.gcm.send(user.RegistrationId, { RequesterId: request.body.RequesterId, RequesterNickname: request.body.RequesterName, TargetId: user.id, TargetNickname: user.Nickname }, { success: function(gcm_response) { console.log('Push notification sent: ', gcm_response); response.send(statusCodes.OK, { RequestedNickname : user.Nickname }); }, error: function(gcm_error) { console.log('Error sending push notification: ', gcm_error); response.send(statusCodes.INTERNAL_SERVER_ERROR, { RequestedNickname : user.Nickname }); } }); } else { response.send(statusCodes.NO_CONTENT, { RequestedNickname : "" }); } }, error: function(error) { console.log('Error read table: ', error); response.send(statusCodes.INTERNAL_SERVER_ERROR, { RequestedNickname : "" }); } }); };
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
        Push      
      
        
        
        
      
     // Perform Push operation member this.PushAsync targetId myId myNickname = async { try let (request : PushRequest) = { TargetId = targetId RequesterId = myId RequesterName = myNickname } let! result = this.MobileService.InvokeApiAsync<PushRequest, PushResponce>("pushhim", request) |> Async.AwaitTask return result.RequestedNickname with | e -> return e.ToString() }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
           ,    let-bang
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
       do!
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
       
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
          Google Play Services.     F#   .           .    : Xamarin.Android.Support.v7.AppCompat 
      
        
        
        
      
         , Google Play Services ,   . 
      
        
        
        
      
     
      
        
        
        
      
          push notification   .    GCM,  ID,     ID       Push  (.   pushhim).        BroadcastReciever       developer.android.com .     F#         Xamarin Component Store.     Google Cloud Messaging Client         GCM    .        ID 
      
        
        
        
      
     //Check to see that GCM is supported and that the manifest has the correct information GcmClient.CheckDevice(this) GcmClient.CheckManifest(this) // check google play if CheckPlayServices() then // Try to get registration id let regId = GcmClient.GetRegistrationId this if String.IsNullOrEmpty(regId) then // Call to Register the device for Push Notifications GcmClient.Register(this, WruConstants.GcmSender);
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
            
      
        
        
        
      
     
      
        
        
        
      
        . 
      
        
        
        
      
        , -  
      
        
        
        
      
         bitbucket.org/xakpc/whereareyou 
      
        
        
        
      
         ,     
      
        
        
        
      
              ,           "" . 
      
        
        
        
      
     
      
        
        
        
      
      
      
        
        
        
      
     ,   Android   F#.      . 
      
        
        
        
      
     ,       -  Android  F#.   ,       .
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     listView.Adapter <- new ArrayAdapter(this, Android.Resource.Layout.SimpleListItem1, Android.Resource.Id.Text1, values) 
      
        
        
        
      
      , ,  let values = [|"item1"; "item2"; "item3"|]
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     -   string[],       list (IEnumerable   ) 
      
        
        
        
      
              F#.            www.tryfsharp.org/Learn 
      
        
        
        
      
      
 
      
        
        
        
      
          F# -  ,  
      
        
        
        
      
     
      
        
        
        
      
            F# For Fun And Profit 
      
        
        
        
      
     
      
        
        
        
      
       ,    
      
        
        
        
      
         - . 
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
     
      
        
        
        
      
            hash 
      
        
        
        
      
         MD5  F# 
      
        
        
        
      
      let MD5Hash (input : string) = use md5 = System.Security.Cryptography.MD5.Create() input |> System.Text.Encoding.ASCII.GetBytes |> md5.ComputeHash |> Seq.map (fun c -> c.ToString("X2")) |> Seq.reduce (+)
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
      |>
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      pipeline ,     . 
      
        
        
        
      
         :    GetBytes ->   ->      HEX  ->       (  reduce   +           ) ->    . 
      
        
        
        
      
     
      
        
        
        
      
      ,     C# using System; public string CreateMD5Hash (string input) { MD5 md5 = System.Security.Cryptography.MD5.Create(); byte[] inputBytes = System.Text.Encoding.ASCII.GetBytes (input); byte[] hashBytes = md5.ComputeHash (inputBytes); StringBuilder sb = new StringBuilder(); for (int i = 0; i < hashBytes.Length; i++) { sb.Append (hashBytes[i].ToString ("X2")); } return sb.ToString(); }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
     
      
        
        
        
      
              :        .       AzureServiceWorker (  CLR    ) 
      
        
        
        
      
     
      
        
        
        
      
              -   .   F#    !   Xamarin Studio            . 
      
        
        
        
      
      <ItemGroup> <Compile Include="Resources\Resource.designer.fs" /> <Compile Include="Properties\AssemblyInfo.fs" /> <Compile Include="Helpers\Helpers.fs" /> <Compile Include="Services\User.fs" /> <Compile Include="Services\AzureServiceWorker.fs" /> <Compile Include="IAmHereActivity.fs" /> <Compile Include="WhereAreYouActivity.fs" /> <Compile Include="SignInActivity.fs" /> </ItemGroup>
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
        
      
        
        
        
      
            :    .    Xamarin    Xamarin.Mobile 
      
        
        
        
      
     
      
        
        
        
      
          .  F#         TPL,     Task',      .     F#         Task.  ,     : 
      
        
        
        
      
     module Async = open System.Threading open System.Threading.Tasks let inline AwaitPlainTask (task: Task) = // rethrow exception from preceding task if it fauled let continuation (t : Task) : unit = match t.IsFaulted with | true -> raise t.Exception | arg -> () task.ContinueWith continuation |> Async.AwaitTask
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
             Async.AwaitIAsyncResult >> Async.Ignore
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
           
      
        
        
        
      
     
      
        
        
        
      
                
      
        
        
        
      
     let ExtractUserInfo (x : Contact) = let first = x.Phones |> Seq.tryPick(fun x -> if x.Type = PhoneType.Mobile then Some(x) else None) match first with | Some(first) -> let phone = first.Number |> StripChars [' ';'-';'(';')'] UserInfo.CreateUserInfo((MD5Hash phone), phone, x.DisplayName) | None -> UserInfo.CreateUserInfo("no mobile phone", "no mobile phone", "no mobile phone") // function for async list filling let FillContactsAsync = async { let book = new AddressBook (this) let! result = book.RequestPermission() |> Async.AwaitTask if result then _contacts <- book.ToList() |> Seq.filter (fun (x: Contact) -> not (Seq.isEmpty x.Phones)) |> Seq.map ExtractUserInfo |> Seq.sortBy(fun x -> x.DisplayName) |> Seq.toList let finalContacts = _contacts |> Seq.map (fun x -> x.DisplayName.ToUpperInvariant()) |> Seq.toArray this.ListAdapter <- new ArrayAdapter(this, Resource_Layout.row_contact, finalContacts) else System.Diagnostics.Debug.WriteLine("Permission denied by user or manifest") this.ListAdapter <- new ArrayAdapter(this, Resource_Layout.row_contact, Array.empty) }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
          
      
        
        
        
      
     book.ToList()
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
       List |> Seq.filter (fun (x: Contact) -> not (Seq.isEmpty x.Phones))
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
          |> Seq.map ExtractUserInfo
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
          Contracts  UserInfo,      UserInfo |> Seq.sortBy(fun x -> x.DisplayName)
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      |> Seq.toList
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
       List _contacts <-
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
        mutable  _contacts |> Seq.map (fun x -> x.DisplayName.ToUpperInvariant())<-
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
        UserInfo  string,     - -    |> Seq.toArray<-
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      List  Array    ArrayAdapter 
      
        
        
        
      
        -      List.   . 
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
     
      
        
        
        
      
     Azure Mobile Servcies 
      
        
        
        
      
       -    Azure Mobile Services.       NotificationHub,     Push    .   Azure    , ..      . 
      
        
        
        
      
     
      
        
        
        
      
          ,    
      
        
        
        
      
     module WruConstants = [<Literal>] let TotallyNotAzureServer = "https://YOUR.azure-mobile.net/"; [<Literal>] let TotallyNotAzureKey = "YOUR"
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
       
        
        
        
      
     member this.RegisterMe phone name regId = async { try let table = this.MobileService.GetTable<User>() let usr = { Id = "" PhoneHash = MD5Hash phone Nickname = name RegistrationId = regId } do! table.InsertAsync usr |> Async.AwaitPlainTask return (usr.Id, usr.PhoneHash, usr.Nickname) with | e -> System.Diagnostics.Trace.WriteLine(e.ToString) return (String.Empty,String.Empty,String.Empty) }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     member this.RegisterMe phone name regId = async {
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     -       (     )    .       "computation expression"   workflow.   { }       ! ( bang),  do! (do-bang)  let! (let bang)     User.    ,  F#        ,      
      
        
        
        
      
      let usr = { Id = "" PhoneHash = MD5Hash phone Nickname = name RegistrationId = regId }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     do! table.InsertAsync usr |> Async.AwaitPlainTask
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      do-bang,   await
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      C#. ..             continuation    . return (usr.Id, usr.PhoneHash, usr.Nickname)
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
          Tuple<string,string,string>     .  try ... with | e ->
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      try..catch
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      C# 
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
     
      
        
        
        
      
           .  F#    fst
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      snd
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
          .        2 .     : 
      
        
        
        
      
      let id (c,_,_) = c let phonehash (_,c,_) = c let nickname (_,_,c) = c
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
        : id tuple
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      Id  .. 
      
        
        
        
      
     
      
        
        
        
      
        5  Azure,       Push .       Azure Custom Api  
      
        
        
        
      
     
      
        
        
        
      
          exports.post = function(request, response) { // Use "request.service" to access features of your mobile service, eg: // var tables = request.service.tables; // var push = request.service.push; //response.send(statusCodes.OK, { message : 'Hello World!' }); console.log('Incoming call with requst: ', request.body.RequestId); var usersTable = request.service.tables.getTable('User'); usersTable.where( { id : request.body.TargetId } ) .read( { success: function(results) { if (results.length > 0) { var user = results[0] console.log('Send to results: ', user.Nickname, user.RegistrationId); request.service.push.gcm.send(user.RegistrationId, { RequesterId: request.body.RequesterId, RequesterNickname: request.body.RequesterName, TargetId: user.id, TargetNickname: user.Nickname }, { success: function(gcm_response) { console.log('Push notification sent: ', gcm_response); response.send(statusCodes.OK, { RequestedNickname : user.Nickname }); }, error: function(gcm_error) { console.log('Error sending push notification: ', gcm_error); response.send(statusCodes.INTERNAL_SERVER_ERROR, { RequestedNickname : user.Nickname }); } }); } else { response.send(statusCodes.NO_CONTENT, { RequestedNickname : "" }); } }, error: function(error) { console.log('Error read table: ', error); response.send(statusCodes.INTERNAL_SERVER_ERROR, { RequestedNickname : "" }); } }); };
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
        Push      
      
        
        
        
      
     // Perform Push operation member this.PushAsync targetId myId myNickname = async { try let (request : PushRequest) = { TargetId = targetId RequesterId = myId RequesterName = myNickname } let! result = this.MobileService.InvokeApiAsync<PushRequest, PushResponce>("pushhim", request) |> Async.AwaitTask return result.RequestedNickname with | e -> return e.ToString() }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
           ,    let-bang
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
       do!
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
       
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
          Google Play Services.     F#   .           .    : Xamarin.Android.Support.v7.AppCompat 
      
        
        
        
      
         , Google Play Services ,   . 
      
        
        
        
      
     
      
        
        
        
      
          push notification   .    GCM,  ID,     ID       Push  (.   pushhim).        BroadcastReciever       developer.android.com .     F#         Xamarin Component Store.     Google Cloud Messaging Client         GCM    .        ID 
      
        
        
        
      
     //Check to see that GCM is supported and that the manifest has the correct information GcmClient.CheckDevice(this) GcmClient.CheckManifest(this) // check google play if CheckPlayServices() then // Try to get registration id let regId = GcmClient.GetRegistrationId this if String.IsNullOrEmpty(regId) then // Call to Register the device for Push Notifications GcmClient.Register(this, WruConstants.GcmSender);
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
            
      
        
        
        
      
     
      
        
        
        
      
        . 
      
        
        
        
      
        , -  
      
        
        
        
      
         bitbucket.org/xakpc/whereareyou 
      
        
        
        
      
         ,     
      
        
        
        
      
              ,           "" . 
      
        
        
        
      
     
      
        
        
        
      
      
      
        
        
        
      
     ,   Android   F#.      . 
      
        
        
        
      
     ,       -  Android  F#.   ,       .
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
    
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
 listView.Adapter <- new ArrayAdapter(this, Android.Resource.Layout.SimpleListItem1, Android.Resource.Id.Text1, values) 
      
        
        
        
      
      , ,  let values = [|"item1"; "item2"; "item3"|]
      
      - string[], list (IEnumerable )
F#. www.tryfsharp.org/Learn
 
 
      F# - ,
F# For Fun And Profit
,
- .
 
 
      hash
MD5 F#
 let MD5Hash (input : string) = use md5 = System.Security.Cryptography.MD5.Create() input |> System.Text.Encoding.ASCII.GetBytes |> md5.ComputeHash |> Seq.map (fun c -> c.ToString("X2")) |> Seq.reduce (+)
      
      |>
      
      pipeline , .
: GetBytes -> -> HEX -> ( reduce + ) -> .
, C#
using System; public string CreateMD5Hash (string input) { MD5 md5 = System.Security.Cryptography.MD5.Create(); byte[] inputBytes = System.Text.Encoding.ASCII.GetBytes (input); byte[] hashBytes = md5.ComputeHash (inputBytes); StringBuilder sb = new StringBuilder(); for (int i = 0; i < hashBytes.Length; i++) { sb.Append (hashBytes[i].ToString ("X2")); } return sb.ToString(); }
      
      : . AzureServiceWorker ( CLR )
- . F# ! Xamarin Studio .
 <ItemGroup> <Compile Include="Resources\Resource.designer.fs" /> <Compile Include="Properties\AssemblyInfo.fs" /> <Compile Include="Helpers\Helpers.fs" /> <Compile Include="Services\User.fs" /> <Compile Include="Services\AzureServiceWorker.fs" /> <Compile Include="IAmHereActivity.fs" /> <Compile Include="WhereAreYouActivity.fs" /> <Compile Include="SignInActivity.fs" /> </ItemGroup>
      
      : . Xamarin Xamarin.Mobile
. F# TPL, Task', . F# Task. , :
module Async = open System.Threading open System.Threading.Tasks let inline AwaitPlainTask (task: Task) = // rethrow exception from preceding task if it fauled let continuation (t : Task) : unit = match t.IsFaulted with | true -> raise t.Exception | arg -> () task.ContinueWith continuation |> Async.AwaitTask
      
      Async.AwaitIAsyncResult >> Async.Ignore
      
      let ExtractUserInfo (x : Contact) = let first = x.Phones |> Seq.tryPick(fun x -> if x.Type = PhoneType.Mobile then Some(x) else None) match first with | Some(first) -> let phone = first.Number |> StripChars [' ';'-';'(';')'] UserInfo.CreateUserInfo((MD5Hash phone), phone, x.DisplayName) | None -> UserInfo.CreateUserInfo("no mobile phone", "no mobile phone", "no mobile phone") // function for async list filling let FillContactsAsync = async { let book = new AddressBook (this) let! result = book.RequestPermission() |> Async.AwaitTask if result then _contacts <- book.ToList() |> Seq.filter (fun (x: Contact) -> not (Seq.isEmpty x.Phones)) |> Seq.map ExtractUserInfo |> Seq.sortBy(fun x -> x.DisplayName) |> Seq.toList let finalContacts = _contacts |> Seq.map (fun x -> x.DisplayName.ToUpperInvariant()) |> Seq.toArray this.ListAdapter <- new ArrayAdapter(this, Resource_Layout.row_contact, finalContacts) else System.Diagnostics.Debug.WriteLine("Permission denied by user or manifest") this.ListAdapter <- new ArrayAdapter(this, Resource_Layout.row_contact, Array.empty) }
      
      book.ToList()
      
      List
|> Seq.filter (fun (x: Contact) -> not (Seq.isEmpty x.Phones))
      
      |> Seq.map ExtractUserInfo
      
      Contracts UserInfo, UserInfo
|> Seq.sortBy(fun x -> x.DisplayName)
      
      |> Seq.toList
      
      List
_contacts <-
      
      mutable
_contacts |> Seq.map (fun x -> x.DisplayName.ToUpperInvariant())<-
      
      UserInfo string, - -
|> Seq.toArray<-
      
      List Array ArrayAdapter
- List. .
 
 
      Azure Mobile Servcies
- Azure Mobile Services. NotificationHub, Push . Azure , .. .
,
      
        
        
        
      
     module WruConstants = [<Literal>] let TotallyNotAzureServer = "https://YOUR.azure-mobile.net/"; [<Literal>] let TotallyNotAzureKey = "YOUR"
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
       
        
        
        
      
     member this.RegisterMe phone name regId = async { try let table = this.MobileService.GetTable<User>() let usr = { Id = "" PhoneHash = MD5Hash phone Nickname = name RegistrationId = regId } do! table.InsertAsync usr |> Async.AwaitPlainTask return (usr.Id, usr.PhoneHash, usr.Nickname) with | e -> System.Diagnostics.Trace.WriteLine(e.ToString) return (String.Empty,String.Empty,String.Empty) }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     member this.RegisterMe phone name regId = async {
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     -       (     )    .       "computation expression"   workflow.   { }       ! ( bang),  do! (do-bang)  let! (let bang)     User.    ,  F#        ,      
      
        
        
        
      
      let usr = { Id = "" PhoneHash = MD5Hash phone Nickname = name RegistrationId = regId }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     do! table.InsertAsync usr |> Async.AwaitPlainTask
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      do-bang,   await
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      C#. ..             continuation    . return (usr.Id, usr.PhoneHash, usr.Nickname)
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
          Tuple<string,string,string>     .  try ... with | e ->
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      try..catch
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      C# 
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
     
      
        
        
        
      
           .  F#    fst
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      snd
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
          .        2 .     : 
      
        
        
        
      
      let id (c,_,_) = c let phonehash (_,c,_) = c let nickname (_,_,c) = c
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
        : id tuple
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      Id  .. 
      
        
        
        
      
     
      
        
        
        
      
        5  Azure,       Push .       Azure Custom Api  
      
        
        
        
      
     
      
        
        
        
      
          exports.post = function(request, response) { // Use "request.service" to access features of your mobile service, eg: // var tables = request.service.tables; // var push = request.service.push; //response.send(statusCodes.OK, { message : 'Hello World!' }); console.log('Incoming call with requst: ', request.body.RequestId); var usersTable = request.service.tables.getTable('User'); usersTable.where( { id : request.body.TargetId } ) .read( { success: function(results) { if (results.length > 0) { var user = results[0] console.log('Send to results: ', user.Nickname, user.RegistrationId); request.service.push.gcm.send(user.RegistrationId, { RequesterId: request.body.RequesterId, RequesterNickname: request.body.RequesterName, TargetId: user.id, TargetNickname: user.Nickname }, { success: function(gcm_response) { console.log('Push notification sent: ', gcm_response); response.send(statusCodes.OK, { RequestedNickname : user.Nickname }); }, error: function(gcm_error) { console.log('Error sending push notification: ', gcm_error); response.send(statusCodes.INTERNAL_SERVER_ERROR, { RequestedNickname : user.Nickname }); } }); } else { response.send(statusCodes.NO_CONTENT, { RequestedNickname : "" }); } }, error: function(error) { console.log('Error read table: ', error); response.send(statusCodes.INTERNAL_SERVER_ERROR, { RequestedNickname : "" }); } }); };
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
        Push      
      
        
        
        
      
     // Perform Push operation member this.PushAsync targetId myId myNickname = async { try let (request : PushRequest) = { TargetId = targetId RequesterId = myId RequesterName = myNickname } let! result = this.MobileService.InvokeApiAsync<PushRequest, PushResponce>("pushhim", request) |> Async.AwaitTask return result.RequestedNickname with | e -> return e.ToString() }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
           ,    let-bang
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
       do!
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
       
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
          Google Play Services.     F#   .           .    : Xamarin.Android.Support.v7.AppCompat 
      
        
        
        
      
         , Google Play Services ,   . 
      
        
        
        
      
     
      
        
        
        
      
          push notification   .    GCM,  ID,     ID       Push  (.   pushhim).        BroadcastReciever       developer.android.com .     F#         Xamarin Component Store.     Google Cloud Messaging Client         GCM    .        ID 
      
        
        
        
      
     //Check to see that GCM is supported and that the manifest has the correct information GcmClient.CheckDevice(this) GcmClient.CheckManifest(this) // check google play if CheckPlayServices() then // Try to get registration id let regId = GcmClient.GetRegistrationId this if String.IsNullOrEmpty(regId) then // Call to Register the device for Push Notifications GcmClient.Register(this, WruConstants.GcmSender);
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
            
      
        
        
        
      
     
      
        
        
        
      
        . 
      
        
        
        
      
        , -  
      
        
        
        
      
         bitbucket.org/xakpc/whereareyou 
      
        
        
        
      
         ,     
      
        
        
        
      
              ,           "" . 
      
        
        
        
      
     
      
        
        
        
      
      
      
        
        
        
      
     ,   Android   F#.      . 
      
        
        
        
      
     ,       -  Android  F#.   ,       .listView.Adapter <- new ArrayAdapter(this, Android.Resource.Layout.SimpleListItem1, Android.Resource.Id.Text1, values) 
      
        
        
        
      
      , ,  let values = [|"item1"; "item2"; "item3"|]
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     -   string[],       list (IEnumerable   ) 
      
        
        
        
      
              F#.            www.tryfsharp.org/Learn 
      
        
        
        
      
      
 
      
        
        
        
      
          F# -  ,  
      
        
        
        
      
     
      
        
        
        
      
            F# For Fun And Profit 
      
        
        
        
      
     
      
        
        
        
      
       ,    
      
        
        
        
      
         - . 
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
     
      
        
        
        
      
            hash 
      
        
        
        
      
         MD5  F# 
      
        
        
        
      
      let MD5Hash (input : string) = use md5 = System.Security.Cryptography.MD5.Create() input |> System.Text.Encoding.ASCII.GetBytes |> md5.ComputeHash |> Seq.map (fun c -> c.ToString("X2")) |> Seq.reduce (+)
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
      |>
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      pipeline ,     . 
      
        
        
        
      
         :    GetBytes ->   ->      HEX  ->       (  reduce   +           ) ->    . 
      
        
        
        
      
     
      
        
        
        
      
      ,     C# using System; public string CreateMD5Hash (string input) { MD5 md5 = System.Security.Cryptography.MD5.Create(); byte[] inputBytes = System.Text.Encoding.ASCII.GetBytes (input); byte[] hashBytes = md5.ComputeHash (inputBytes); StringBuilder sb = new StringBuilder(); for (int i = 0; i < hashBytes.Length; i++) { sb.Append (hashBytes[i].ToString ("X2")); } return sb.ToString(); }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
     
      
        
        
        
      
              :        .       AzureServiceWorker (  CLR    ) 
      
        
        
        
      
     
      
        
        
        
      
              -   .   F#    !   Xamarin Studio            . 
      
        
        
        
      
      <ItemGroup> <Compile Include="Resources\Resource.designer.fs" /> <Compile Include="Properties\AssemblyInfo.fs" /> <Compile Include="Helpers\Helpers.fs" /> <Compile Include="Services\User.fs" /> <Compile Include="Services\AzureServiceWorker.fs" /> <Compile Include="IAmHereActivity.fs" /> <Compile Include="WhereAreYouActivity.fs" /> <Compile Include="SignInActivity.fs" /> </ItemGroup>
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
        
      
        
        
        
      
            :    .    Xamarin    Xamarin.Mobile 
      
        
        
        
      
     
      
        
        
        
      
          .  F#         TPL,     Task',      .     F#         Task.  ,     : 
      
        
        
        
      
     module Async = open System.Threading open System.Threading.Tasks let inline AwaitPlainTask (task: Task) = // rethrow exception from preceding task if it fauled let continuation (t : Task) : unit = match t.IsFaulted with | true -> raise t.Exception | arg -> () task.ContinueWith continuation |> Async.AwaitTask
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
             Async.AwaitIAsyncResult >> Async.Ignore
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
           
      
        
        
        
      
     
      
        
        
        
      
                
      
        
        
        
      
     let ExtractUserInfo (x : Contact) = let first = x.Phones |> Seq.tryPick(fun x -> if x.Type = PhoneType.Mobile then Some(x) else None) match first with | Some(first) -> let phone = first.Number |> StripChars [' ';'-';'(';')'] UserInfo.CreateUserInfo((MD5Hash phone), phone, x.DisplayName) | None -> UserInfo.CreateUserInfo("no mobile phone", "no mobile phone", "no mobile phone") // function for async list filling let FillContactsAsync = async { let book = new AddressBook (this) let! result = book.RequestPermission() |> Async.AwaitTask if result then _contacts <- book.ToList() |> Seq.filter (fun (x: Contact) -> not (Seq.isEmpty x.Phones)) |> Seq.map ExtractUserInfo |> Seq.sortBy(fun x -> x.DisplayName) |> Seq.toList let finalContacts = _contacts |> Seq.map (fun x -> x.DisplayName.ToUpperInvariant()) |> Seq.toArray this.ListAdapter <- new ArrayAdapter(this, Resource_Layout.row_contact, finalContacts) else System.Diagnostics.Debug.WriteLine("Permission denied by user or manifest") this.ListAdapter <- new ArrayAdapter(this, Resource_Layout.row_contact, Array.empty) }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
          
      
        
        
        
      
     book.ToList()
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
       List |> Seq.filter (fun (x: Contact) -> not (Seq.isEmpty x.Phones))
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
          |> Seq.map ExtractUserInfo
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
          Contracts  UserInfo,      UserInfo |> Seq.sortBy(fun x -> x.DisplayName)
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      |> Seq.toList
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
       List _contacts <-
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
        mutable  _contacts |> Seq.map (fun x -> x.DisplayName.ToUpperInvariant())<-
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
        UserInfo  string,     - -    |> Seq.toArray<-
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      List  Array    ArrayAdapter 
      
        
        
        
      
        -      List.   . 
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
     
      
        
        
        
      
     Azure Mobile Servcies 
      
        
        
        
      
       -    Azure Mobile Services.       NotificationHub,     Push    .   Azure    , ..      . 
      
        
        
        
      
     
      
        
        
        
      
          ,    
      
        
        
        
      
     module WruConstants = [<Literal>] let TotallyNotAzureServer = "https://YOUR.azure-mobile.net/"; [<Literal>] let TotallyNotAzureKey = "YOUR"
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
       
        
        
        
      
     member this.RegisterMe phone name regId = async { try let table = this.MobileService.GetTable<User>() let usr = { Id = "" PhoneHash = MD5Hash phone Nickname = name RegistrationId = regId } do! table.InsertAsync usr |> Async.AwaitPlainTask return (usr.Id, usr.PhoneHash, usr.Nickname) with | e -> System.Diagnostics.Trace.WriteLine(e.ToString) return (String.Empty,String.Empty,String.Empty) }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     member this.RegisterMe phone name regId = async {
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     -       (     )    .       "computation expression"   workflow.   { }       ! ( bang),  do! (do-bang)  let! (let bang)     User.    ,  F#        ,      
      
        
        
        
      
      let usr = { Id = "" PhoneHash = MD5Hash phone Nickname = name RegistrationId = regId }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     do! table.InsertAsync usr |> Async.AwaitPlainTask
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      do-bang,   await
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      C#. ..             continuation    . return (usr.Id, usr.PhoneHash, usr.Nickname)
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
          Tuple<string,string,string>     .  try ... with | e ->
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      try..catch
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      C# 
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
     
      
        
        
        
      
           .  F#    fst
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      snd
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
          .        2 .     : 
      
        
        
        
      
      let id (c,_,_) = c let phonehash (_,c,_) = c let nickname (_,_,c) = c
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
        : id tuple
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      Id  .. 
      
        
        
        
      
     
      
        
        
        
      
        5  Azure,       Push .       Azure Custom Api  
      
        
        
        
      
     
      
        
        
        
      
          exports.post = function(request, response) { // Use "request.service" to access features of your mobile service, eg: // var tables = request.service.tables; // var push = request.service.push; //response.send(statusCodes.OK, { message : 'Hello World!' }); console.log('Incoming call with requst: ', request.body.RequestId); var usersTable = request.service.tables.getTable('User'); usersTable.where( { id : request.body.TargetId } ) .read( { success: function(results) { if (results.length > 0) { var user = results[0] console.log('Send to results: ', user.Nickname, user.RegistrationId); request.service.push.gcm.send(user.RegistrationId, { RequesterId: request.body.RequesterId, RequesterNickname: request.body.RequesterName, TargetId: user.id, TargetNickname: user.Nickname }, { success: function(gcm_response) { console.log('Push notification sent: ', gcm_response); response.send(statusCodes.OK, { RequestedNickname : user.Nickname }); }, error: function(gcm_error) { console.log('Error sending push notification: ', gcm_error); response.send(statusCodes.INTERNAL_SERVER_ERROR, { RequestedNickname : user.Nickname }); } }); } else { response.send(statusCodes.NO_CONTENT, { RequestedNickname : "" }); } }, error: function(error) { console.log('Error read table: ', error); response.send(statusCodes.INTERNAL_SERVER_ERROR, { RequestedNickname : "" }); } }); };
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
        Push      
      
        
        
        
      
     // Perform Push operation member this.PushAsync targetId myId myNickname = async { try let (request : PushRequest) = { TargetId = targetId RequesterId = myId RequesterName = myNickname } let! result = this.MobileService.InvokeApiAsync<PushRequest, PushResponce>("pushhim", request) |> Async.AwaitTask return result.RequestedNickname with | e -> return e.ToString() }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
           ,    let-bang
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
       do!
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
       
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
          Google Play Services.     F#   .           .    : Xamarin.Android.Support.v7.AppCompat 
      
        
        
        
      
         , Google Play Services ,   . 
      
        
        
        
      
     
      
        
        
        
      
          push notification   .    GCM,  ID,     ID       Push  (.   pushhim).        BroadcastReciever       developer.android.com .     F#         Xamarin Component Store.     Google Cloud Messaging Client         GCM    .        ID 
      
        
        
        
      
     //Check to see that GCM is supported and that the manifest has the correct information GcmClient.CheckDevice(this) GcmClient.CheckManifest(this) // check google play if CheckPlayServices() then // Try to get registration id let regId = GcmClient.GetRegistrationId this if String.IsNullOrEmpty(regId) then // Call to Register the device for Push Notifications GcmClient.Register(this, WruConstants.GcmSender);
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
            
      
        
        
        
      
     
      
        
        
        
      
        . 
      
        
        
        
      
        , -  
      
        
        
        
      
         bitbucket.org/xakpc/whereareyou 
      
        
        
        
      
         ,     
      
        
        
        
      
              ,           "" . 
      
        
        
        
      
     
      
        
        
        
      
      
      
        
        
        
      
     ,   Android   F#.      . 
      
        
        
        
      
     ,       -  Android  F#.   ,       .
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     listView.Adapter <- new ArrayAdapter(this, Android.Resource.Layout.SimpleListItem1, Android.Resource.Id.Text1, values) 
      
        
        
        
      
      , ,  let values = [|"item1"; "item2"; "item3"|]
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     -   string[],       list (IEnumerable   ) 
      
        
        
        
      
              F#.            www.tryfsharp.org/Learn 
      
        
        
        
      
      
 
      
        
        
        
      
          F# -  ,  
      
        
        
        
      
     
      
        
        
        
      
            F# For Fun And Profit 
      
        
        
        
      
     
      
        
        
        
      
       ,    
      
        
        
        
      
         - . 
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
     
      
        
        
        
      
            hash 
      
        
        
        
      
         MD5  F# 
      
        
        
        
      
      let MD5Hash (input : string) = use md5 = System.Security.Cryptography.MD5.Create() input |> System.Text.Encoding.ASCII.GetBytes |> md5.ComputeHash |> Seq.map (fun c -> c.ToString("X2")) |> Seq.reduce (+)
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
      |>
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      pipeline ,     . 
      
        
        
        
      
         :    GetBytes ->   ->      HEX  ->       (  reduce   +           ) ->    . 
      
        
        
        
      
     
      
        
        
        
      
      ,     C# using System; public string CreateMD5Hash (string input) { MD5 md5 = System.Security.Cryptography.MD5.Create(); byte[] inputBytes = System.Text.Encoding.ASCII.GetBytes (input); byte[] hashBytes = md5.ComputeHash (inputBytes); StringBuilder sb = new StringBuilder(); for (int i = 0; i < hashBytes.Length; i++) { sb.Append (hashBytes[i].ToString ("X2")); } return sb.ToString(); }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
     
      
        
        
        
      
              :        .       AzureServiceWorker (  CLR    ) 
      
        
        
        
      
     
      
        
        
        
      
              -   .   F#    !   Xamarin Studio            . 
      
        
        
        
      
      <ItemGroup> <Compile Include="Resources\Resource.designer.fs" /> <Compile Include="Properties\AssemblyInfo.fs" /> <Compile Include="Helpers\Helpers.fs" /> <Compile Include="Services\User.fs" /> <Compile Include="Services\AzureServiceWorker.fs" /> <Compile Include="IAmHereActivity.fs" /> <Compile Include="WhereAreYouActivity.fs" /> <Compile Include="SignInActivity.fs" /> </ItemGroup>
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
        
      
        
        
        
      
            :    .    Xamarin    Xamarin.Mobile 
      
        
        
        
      
     
      
        
        
        
      
          .  F#         TPL,     Task',      .     F#         Task.  ,     : 
      
        
        
        
      
     module Async = open System.Threading open System.Threading.Tasks let inline AwaitPlainTask (task: Task) = // rethrow exception from preceding task if it fauled let continuation (t : Task) : unit = match t.IsFaulted with | true -> raise t.Exception | arg -> () task.ContinueWith continuation |> Async.AwaitTask
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
             Async.AwaitIAsyncResult >> Async.Ignore
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
           
      
        
        
        
      
     
      
        
        
        
      
                
      
        
        
        
      
     let ExtractUserInfo (x : Contact) = let first = x.Phones |> Seq.tryPick(fun x -> if x.Type = PhoneType.Mobile then Some(x) else None) match first with | Some(first) -> let phone = first.Number |> StripChars [' ';'-';'(';')'] UserInfo.CreateUserInfo((MD5Hash phone), phone, x.DisplayName) | None -> UserInfo.CreateUserInfo("no mobile phone", "no mobile phone", "no mobile phone") // function for async list filling let FillContactsAsync = async { let book = new AddressBook (this) let! result = book.RequestPermission() |> Async.AwaitTask if result then _contacts <- book.ToList() |> Seq.filter (fun (x: Contact) -> not (Seq.isEmpty x.Phones)) |> Seq.map ExtractUserInfo |> Seq.sortBy(fun x -> x.DisplayName) |> Seq.toList let finalContacts = _contacts |> Seq.map (fun x -> x.DisplayName.ToUpperInvariant()) |> Seq.toArray this.ListAdapter <- new ArrayAdapter(this, Resource_Layout.row_contact, finalContacts) else System.Diagnostics.Debug.WriteLine("Permission denied by user or manifest") this.ListAdapter <- new ArrayAdapter(this, Resource_Layout.row_contact, Array.empty) }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
          
      
        
        
        
      
     book.ToList()
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
       List |> Seq.filter (fun (x: Contact) -> not (Seq.isEmpty x.Phones))
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
          |> Seq.map ExtractUserInfo
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
          Contracts  UserInfo,      UserInfo |> Seq.sortBy(fun x -> x.DisplayName)
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      |> Seq.toList
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
       List _contacts <-
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
        mutable  _contacts |> Seq.map (fun x -> x.DisplayName.ToUpperInvariant())<-
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
        UserInfo  string,     - -    |> Seq.toArray<-
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      List  Array    ArrayAdapter 
      
        
        
        
      
        -      List.   . 
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
     
      
        
        
        
      
     Azure Mobile Servcies 
      
        
        
        
      
       -    Azure Mobile Services.       NotificationHub,     Push    .   Azure    , ..      . 
      
        
        
        
      
     
      
        
        
        
      
          ,    
      
        
        
        
      
     module WruConstants = [<Literal>] let TotallyNotAzureServer = "https://YOUR.azure-mobile.net/"; [<Literal>] let TotallyNotAzureKey = "YOUR"
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
       
        
        
        
      
     member this.RegisterMe phone name regId = async { try let table = this.MobileService.GetTable<User>() let usr = { Id = "" PhoneHash = MD5Hash phone Nickname = name RegistrationId = regId } do! table.InsertAsync usr |> Async.AwaitPlainTask return (usr.Id, usr.PhoneHash, usr.Nickname) with | e -> System.Diagnostics.Trace.WriteLine(e.ToString) return (String.Empty,String.Empty,String.Empty) }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     member this.RegisterMe phone name regId = async {
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     -       (     )    .       "computation expression"   workflow.   { }       ! ( bang),  do! (do-bang)  let! (let bang)     User.    ,  F#        ,      
      
        
        
        
      
      let usr = { Id = "" PhoneHash = MD5Hash phone Nickname = name RegistrationId = regId }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     do! table.InsertAsync usr |> Async.AwaitPlainTask
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      do-bang,   await
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      C#. ..             continuation    . return (usr.Id, usr.PhoneHash, usr.Nickname)
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
          Tuple<string,string,string>     .  try ... with | e ->
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      try..catch
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      C# 
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
     
      
        
        
        
      
           .  F#    fst
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      snd
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
          .        2 .     : 
      
        
        
        
      
      let id (c,_,_) = c let phonehash (_,c,_) = c let nickname (_,_,c) = c
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
        : id tuple
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      Id  .. 
      
        
        
        
      
     
      
        
        
        
      
        5  Azure,       Push .       Azure Custom Api  
      
        
        
        
      
     
      
        
        
        
      
          exports.post = function(request, response) { // Use "request.service" to access features of your mobile service, eg: // var tables = request.service.tables; // var push = request.service.push; //response.send(statusCodes.OK, { message : 'Hello World!' }); console.log('Incoming call with requst: ', request.body.RequestId); var usersTable = request.service.tables.getTable('User'); usersTable.where( { id : request.body.TargetId } ) .read( { success: function(results) { if (results.length > 0) { var user = results[0] console.log('Send to results: ', user.Nickname, user.RegistrationId); request.service.push.gcm.send(user.RegistrationId, { RequesterId: request.body.RequesterId, RequesterNickname: request.body.RequesterName, TargetId: user.id, TargetNickname: user.Nickname }, { success: function(gcm_response) { console.log('Push notification sent: ', gcm_response); response.send(statusCodes.OK, { RequestedNickname : user.Nickname }); }, error: function(gcm_error) { console.log('Error sending push notification: ', gcm_error); response.send(statusCodes.INTERNAL_SERVER_ERROR, { RequestedNickname : user.Nickname }); } }); } else { response.send(statusCodes.NO_CONTENT, { RequestedNickname : "" }); } }, error: function(error) { console.log('Error read table: ', error); response.send(statusCodes.INTERNAL_SERVER_ERROR, { RequestedNickname : "" }); } }); };
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
        Push      
      
        
        
        
      
     // Perform Push operation member this.PushAsync targetId myId myNickname = async { try let (request : PushRequest) = { TargetId = targetId RequesterId = myId RequesterName = myNickname } let! result = this.MobileService.InvokeApiAsync<PushRequest, PushResponce>("pushhim", request) |> Async.AwaitTask return result.RequestedNickname with | e -> return e.ToString() }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
           ,    let-bang
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
       do!
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
       
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
          Google Play Services.     F#   .           .    : Xamarin.Android.Support.v7.AppCompat 
      
        
        
        
      
         , Google Play Services ,   . 
      
        
        
        
      
     
      
        
        
        
      
          push notification   .    GCM,  ID,     ID       Push  (.   pushhim).        BroadcastReciever       developer.android.com .     F#         Xamarin Component Store.     Google Cloud Messaging Client         GCM    .        ID 
      
        
        
        
      
     //Check to see that GCM is supported and that the manifest has the correct information GcmClient.CheckDevice(this) GcmClient.CheckManifest(this) // check google play if CheckPlayServices() then // Try to get registration id let regId = GcmClient.GetRegistrationId this if String.IsNullOrEmpty(regId) then // Call to Register the device for Push Notifications GcmClient.Register(this, WruConstants.GcmSender);
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
            
      
        
        
        
      
     
      
        
        
        
      
        . 
      
        
        
        
      
        , -  
      
        
        
        
      
         bitbucket.org/xakpc/whereareyou 
      
        
        
        
      
         ,     
      
        
        
        
      
              ,           "" . 
      
        
        
        
      
     
      
        
        
        
      
      
      
        
        
        
      
     ,   Android   F#.      . 
      
        
        
        
      
     ,       -  Android  F#.   ,       .
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
    
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      listView.Adapter <- new ArrayAdapter(this, Android.Resource.Layout.SimpleListItem1, Android.Resource.Id.Text1, values) 
      
        
        
        
      
      , ,  let values = [|"item1"; "item2"; "item3"|]
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     -   string[],       list (IEnumerable   ) 
      
        
        
        
      
              F#.            www.tryfsharp.org/Learn 
      
        
        
        
      
      
 
      
        
        
        
      
          F# -  ,  
      
        
        
        
      
     
      
        
        
        
      
            F# For Fun And Profit 
      
        
        
        
      
     
      
        
        
        
      
       ,    
      
        
        
        
      
         - . 
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
     
      
        
        
        
      
            hash 
      
        
        
        
      
         MD5  F# 
      
        
        
        
      
      let MD5Hash (input : string) = use md5 = System.Security.Cryptography.MD5.Create() input |> System.Text.Encoding.ASCII.GetBytes |> md5.ComputeHash |> Seq.map (fun c -> c.ToString("X2")) |> Seq.reduce (+)
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
      |>
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      pipeline ,     . 
      
        
        
        
      
         :    GetBytes ->   ->      HEX  ->       (  reduce   +           ) ->    . 
      
        
        
        
      
     
      
        
        
        
      
      ,     C# using System; public string CreateMD5Hash (string input) { MD5 md5 = System.Security.Cryptography.MD5.Create(); byte[] inputBytes = System.Text.Encoding.ASCII.GetBytes (input); byte[] hashBytes = md5.ComputeHash (inputBytes); StringBuilder sb = new StringBuilder(); for (int i = 0; i < hashBytes.Length; i++) { sb.Append (hashBytes[i].ToString ("X2")); } return sb.ToString(); }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
     
      
        
        
        
      
              :        .       AzureServiceWorker (  CLR    ) 
      
        
        
        
      
     
      
        
        
        
      
              -   .   F#    !   Xamarin Studio            . 
      
        
        
        
      
      <ItemGroup> <Compile Include="Resources\Resource.designer.fs" /> <Compile Include="Properties\AssemblyInfo.fs" /> <Compile Include="Helpers\Helpers.fs" /> <Compile Include="Services\User.fs" /> <Compile Include="Services\AzureServiceWorker.fs" /> <Compile Include="IAmHereActivity.fs" /> <Compile Include="WhereAreYouActivity.fs" /> <Compile Include="SignInActivity.fs" /> </ItemGroup>
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
        
      
        
        
        
      
            :    .    Xamarin    Xamarin.Mobile 
      
        
        
        
      
     
      
        
        
        
      
          .  F#         TPL,     Task',      .     F#         Task.  ,     : 
      
        
        
        
      
     module Async = open System.Threading open System.Threading.Tasks let inline AwaitPlainTask (task: Task) = // rethrow exception from preceding task if it fauled let continuation (t : Task) : unit = match t.IsFaulted with | true -> raise t.Exception | arg -> () task.ContinueWith continuation |> Async.AwaitTask
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
             Async.AwaitIAsyncResult >> Async.Ignore
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
           
      
        
        
        
      
     
      
        
        
        
      
                
      
        
        
        
      
     let ExtractUserInfo (x : Contact) = let first = x.Phones |> Seq.tryPick(fun x -> if x.Type = PhoneType.Mobile then Some(x) else None) match first with | Some(first) -> let phone = first.Number |> StripChars [' ';'-';'(';')'] UserInfo.CreateUserInfo((MD5Hash phone), phone, x.DisplayName) | None -> UserInfo.CreateUserInfo("no mobile phone", "no mobile phone", "no mobile phone") // function for async list filling let FillContactsAsync = async { let book = new AddressBook (this) let! result = book.RequestPermission() |> Async.AwaitTask if result then _contacts <- book.ToList() |> Seq.filter (fun (x: Contact) -> not (Seq.isEmpty x.Phones)) |> Seq.map ExtractUserInfo |> Seq.sortBy(fun x -> x.DisplayName) |> Seq.toList let finalContacts = _contacts |> Seq.map (fun x -> x.DisplayName.ToUpperInvariant()) |> Seq.toArray this.ListAdapter <- new ArrayAdapter(this, Resource_Layout.row_contact, finalContacts) else System.Diagnostics.Debug.WriteLine("Permission denied by user or manifest") this.ListAdapter <- new ArrayAdapter(this, Resource_Layout.row_contact, Array.empty) }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
          
      
        
        
        
      
     book.ToList()
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
       List |> Seq.filter (fun (x: Contact) -> not (Seq.isEmpty x.Phones))
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
          |> Seq.map ExtractUserInfo
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
          Contracts  UserInfo,      UserInfo |> Seq.sortBy(fun x -> x.DisplayName)
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      |> Seq.toList
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
       List _contacts <-
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
        mutable  _contacts |> Seq.map (fun x -> x.DisplayName.ToUpperInvariant())<-
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
        UserInfo  string,     - -    |> Seq.toArray<-
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      List  Array    ArrayAdapter 
      
        
        
        
      
        -      List.   . 
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
     
      
        
        
        
      
     Azure Mobile Servcies 
      
        
        
        
      
       -    Azure Mobile Services.       NotificationHub,     Push    .   Azure    , ..      . 
      
        
        
        
      
     
      
        
        
        
      
          ,    
      
        
        
        
      
     module WruConstants = [<Literal>] let TotallyNotAzureServer = "https://YOUR.azure-mobile.net/"; [<Literal>] let TotallyNotAzureKey = "YOUR"
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
       
        
        
        
      
     member this.RegisterMe phone name regId = async { try let table = this.MobileService.GetTable<User>() let usr = { Id = "" PhoneHash = MD5Hash phone Nickname = name RegistrationId = regId } do! table.InsertAsync usr |> Async.AwaitPlainTask return (usr.Id, usr.PhoneHash, usr.Nickname) with | e -> System.Diagnostics.Trace.WriteLine(e.ToString) return (String.Empty,String.Empty,String.Empty) }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     member this.RegisterMe phone name regId = async {
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     -       (     )    .       "computation expression"   workflow.   { }       ! ( bang),  do! (do-bang)  let! (let bang)     User.    ,  F#        ,      
      
        
        
        
      
      let usr = { Id = "" PhoneHash = MD5Hash phone Nickname = name RegistrationId = regId }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     do! table.InsertAsync usr |> Async.AwaitPlainTask
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      do-bang,   await
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      C#. ..             continuation    . return (usr.Id, usr.PhoneHash, usr.Nickname)
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
          Tuple<string,string,string>     .  try ... with | e ->
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      try..catch
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      C# 
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
     
      
        
        
        
      
           .  F#    fst
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      snd
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
          .        2 .     : 
      
        
        
        
      
      let id (c,_,_) = c let phonehash (_,c,_) = c let nickname (_,_,c) = c
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
        : id tuple
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      Id  .. 
      
        
        
        
      
     
      
        
        
        
      
        5  Azure,       Push .       Azure Custom Api  
      
        
        
        
      
     
      
        
        
        
      
          exports.post = function(request, response) { // Use "request.service" to access features of your mobile service, eg: // var tables = request.service.tables; // var push = request.service.push; //response.send(statusCodes.OK, { message : 'Hello World!' }); console.log('Incoming call with requst: ', request.body.RequestId); var usersTable = request.service.tables.getTable('User'); usersTable.where( { id : request.body.TargetId } ) .read( { success: function(results) { if (results.length > 0) { var user = results[0] console.log('Send to results: ', user.Nickname, user.RegistrationId); request.service.push.gcm.send(user.RegistrationId, { RequesterId: request.body.RequesterId, RequesterNickname: request.body.RequesterName, TargetId: user.id, TargetNickname: user.Nickname }, { success: function(gcm_response) { console.log('Push notification sent: ', gcm_response); response.send(statusCodes.OK, { RequestedNickname : user.Nickname }); }, error: function(gcm_error) { console.log('Error sending push notification: ', gcm_error); response.send(statusCodes.INTERNAL_SERVER_ERROR, { RequestedNickname : user.Nickname }); } }); } else { response.send(statusCodes.NO_CONTENT, { RequestedNickname : "" }); } }, error: function(error) { console.log('Error read table: ', error); response.send(statusCodes.INTERNAL_SERVER_ERROR, { RequestedNickname : "" }); } }); };
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
        Push      
      
        
        
        
      
     // Perform Push operation member this.PushAsync targetId myId myNickname = async { try let (request : PushRequest) = { TargetId = targetId RequesterId = myId RequesterName = myNickname } let! result = this.MobileService.InvokeApiAsync<PushRequest, PushResponce>("pushhim", request) |> Async.AwaitTask return result.RequestedNickname with | e -> return e.ToString() }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
           ,    let-bang
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
       do!
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
       
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
          Google Play Services.     F#   .           .    : Xamarin.Android.Support.v7.AppCompat 
      
        
        
        
      
         , Google Play Services ,   . 
      
        
        
        
      
     
      
        
        
        
      
          push notification   .    GCM,  ID,     ID       Push  (.   pushhim).        BroadcastReciever       developer.android.com .     F#         Xamarin Component Store.     Google Cloud Messaging Client         GCM    .        ID 
      
        
        
        
      
     //Check to see that GCM is supported and that the manifest has the correct information GcmClient.CheckDevice(this) GcmClient.CheckManifest(this) // check google play if CheckPlayServices() then // Try to get registration id let regId = GcmClient.GetRegistrationId this if String.IsNullOrEmpty(regId) then // Call to Register the device for Push Notifications GcmClient.Register(this, WruConstants.GcmSender);
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
            
      
        
        
        
      
     
      
        
        
        
      
        . 
      
        
        
        
      
        , -  
      
        
        
        
      
         bitbucket.org/xakpc/whereareyou 
      
        
        
        
      
         ,     
      
        
        
        
      
              ,           "" . 
      
        
        
        
      
     
      
        
        
        
      
      
      
        
        
        
      
     ,   Android   F#.      . 
      
        
        
        
      
     ,       -  Android  F#.   ,       .
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     listView.Adapter <- new ArrayAdapter(this, Android.Resource.Layout.SimpleListItem1, Android.Resource.Id.Text1, values) 
      
        
        
        
      
      , ,  let values = [|"item1"; "item2"; "item3"|]
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     -   string[],       list (IEnumerable   ) 
      
        
        
        
      
              F#.            www.tryfsharp.org/Learn 
      
        
        
        
      
      
 
      
        
        
        
      
          F# -  ,  
      
        
        
        
      
     
      
        
        
        
      
            F# For Fun And Profit 
      
        
        
        
      
     
      
        
        
        
      
       ,    
      
        
        
        
      
         - . 
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
     
      
        
        
        
      
            hash 
      
        
        
        
      
         MD5  F# 
      
        
        
        
      
      let MD5Hash (input : string) = use md5 = System.Security.Cryptography.MD5.Create() input |> System.Text.Encoding.ASCII.GetBytes |> md5.ComputeHash |> Seq.map (fun c -> c.ToString("X2")) |> Seq.reduce (+)
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
      |>
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      pipeline ,     . 
      
        
        
        
      
         :    GetBytes ->   ->      HEX  ->       (  reduce   +           ) ->    . 
      
        
        
        
      
     
      
        
        
        
      
      ,     C# using System; public string CreateMD5Hash (string input) { MD5 md5 = System.Security.Cryptography.MD5.Create(); byte[] inputBytes = System.Text.Encoding.ASCII.GetBytes (input); byte[] hashBytes = md5.ComputeHash (inputBytes); StringBuilder sb = new StringBuilder(); for (int i = 0; i < hashBytes.Length; i++) { sb.Append (hashBytes[i].ToString ("X2")); } return sb.ToString(); }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
     
      
        
        
        
      
              :        .       AzureServiceWorker (  CLR    ) 
      
        
        
        
      
     
      
        
        
        
      
              -   .   F#    !   Xamarin Studio            . 
      
        
        
        
      
      <ItemGroup> <Compile Include="Resources\Resource.designer.fs" /> <Compile Include="Properties\AssemblyInfo.fs" /> <Compile Include="Helpers\Helpers.fs" /> <Compile Include="Services\User.fs" /> <Compile Include="Services\AzureServiceWorker.fs" /> <Compile Include="IAmHereActivity.fs" /> <Compile Include="WhereAreYouActivity.fs" /> <Compile Include="SignInActivity.fs" /> </ItemGroup>
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
        
      
        
        
        
      
            :    .    Xamarin    Xamarin.Mobile 
      
        
        
        
      
     
      
        
        
        
      
          .  F#         TPL,     Task',      .     F#         Task.  ,     : 
      
        
        
        
      
     module Async = open System.Threading open System.Threading.Tasks let inline AwaitPlainTask (task: Task) = // rethrow exception from preceding task if it fauled let continuation (t : Task) : unit = match t.IsFaulted with | true -> raise t.Exception | arg -> () task.ContinueWith continuation |> Async.AwaitTask
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
             Async.AwaitIAsyncResult >> Async.Ignore
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
           
      
        
        
        
      
     
      
        
        
        
      
                
      
        
        
        
      
     let ExtractUserInfo (x : Contact) = let first = x.Phones |> Seq.tryPick(fun x -> if x.Type = PhoneType.Mobile then Some(x) else None) match first with | Some(first) -> let phone = first.Number |> StripChars [' ';'-';'(';')'] UserInfo.CreateUserInfo((MD5Hash phone), phone, x.DisplayName) | None -> UserInfo.CreateUserInfo("no mobile phone", "no mobile phone", "no mobile phone") // function for async list filling let FillContactsAsync = async { let book = new AddressBook (this) let! result = book.RequestPermission() |> Async.AwaitTask if result then _contacts <- book.ToList() |> Seq.filter (fun (x: Contact) -> not (Seq.isEmpty x.Phones)) |> Seq.map ExtractUserInfo |> Seq.sortBy(fun x -> x.DisplayName) |> Seq.toList let finalContacts = _contacts |> Seq.map (fun x -> x.DisplayName.ToUpperInvariant()) |> Seq.toArray this.ListAdapter <- new ArrayAdapter(this, Resource_Layout.row_contact, finalContacts) else System.Diagnostics.Debug.WriteLine("Permission denied by user or manifest") this.ListAdapter <- new ArrayAdapter(this, Resource_Layout.row_contact, Array.empty) }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
          
      
        
        
        
      
     book.ToList()
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
       List |> Seq.filter (fun (x: Contact) -> not (Seq.isEmpty x.Phones))
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
          |> Seq.map ExtractUserInfo
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
          Contracts  UserInfo,      UserInfo |> Seq.sortBy(fun x -> x.DisplayName)
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      |> Seq.toList
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
       List _contacts <-
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
        mutable  _contacts |> Seq.map (fun x -> x.DisplayName.ToUpperInvariant())<-
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
        UserInfo  string,     - -    |> Seq.toArray<-
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      List  Array    ArrayAdapter 
      
        
        
        
      
        -      List.   . 
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
     
      
        
        
        
      
     Azure Mobile Servcies 
      
        
        
        
      
       -    Azure Mobile Services.       NotificationHub,     Push    .   Azure    , ..      . 
      
        
        
        
      
     
      
        
        
        
      
          ,    
      
        
        
        
      
     module WruConstants = [<Literal>] let TotallyNotAzureServer = "https://YOUR.azure-mobile.net/"; [<Literal>] let TotallyNotAzureKey = "YOUR"
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
       
        
        
        
      
     member this.RegisterMe phone name regId = async { try let table = this.MobileService.GetTable<User>() let usr = { Id = "" PhoneHash = MD5Hash phone Nickname = name RegistrationId = regId } do! table.InsertAsync usr |> Async.AwaitPlainTask return (usr.Id, usr.PhoneHash, usr.Nickname) with | e -> System.Diagnostics.Trace.WriteLine(e.ToString) return (String.Empty,String.Empty,String.Empty) }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     member this.RegisterMe phone name regId = async {
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     -       (     )    .       "computation expression"   workflow.   { }       ! ( bang),  do! (do-bang)  let! (let bang)     User.    ,  F#        ,      
      
        
        
        
      
      let usr = { Id = "" PhoneHash = MD5Hash phone Nickname = name RegistrationId = regId }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     do! table.InsertAsync usr |> Async.AwaitPlainTask
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      do-bang,   await
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      C#. ..             continuation    . return (usr.Id, usr.PhoneHash, usr.Nickname)
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
          Tuple<string,string,string>     .  try ... with | e ->
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      try..catch
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      C# 
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
     
      
        
        
        
      
           .  F#    fst
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      snd
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
          .        2 .     : 
      
        
        
        
      
      let id (c,_,_) = c let phonehash (_,c,_) = c let nickname (_,_,c) = c
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
        : id tuple
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      Id  .. 
      
        
        
        
      
     
      
        
        
        
      
        5  Azure,       Push .       Azure Custom Api  
      
        
        
        
      
     
      
        
        
        
      
          exports.post = function(request, response) { // Use "request.service" to access features of your mobile service, eg: // var tables = request.service.tables; // var push = request.service.push; //response.send(statusCodes.OK, { message : 'Hello World!' }); console.log('Incoming call with requst: ', request.body.RequestId); var usersTable = request.service.tables.getTable('User'); usersTable.where( { id : request.body.TargetId } ) .read( { success: function(results) { if (results.length > 0) { var user = results[0] console.log('Send to results: ', user.Nickname, user.RegistrationId); request.service.push.gcm.send(user.RegistrationId, { RequesterId: request.body.RequesterId, RequesterNickname: request.body.RequesterName, TargetId: user.id, TargetNickname: user.Nickname }, { success: function(gcm_response) { console.log('Push notification sent: ', gcm_response); response.send(statusCodes.OK, { RequestedNickname : user.Nickname }); }, error: function(gcm_error) { console.log('Error sending push notification: ', gcm_error); response.send(statusCodes.INTERNAL_SERVER_ERROR, { RequestedNickname : user.Nickname }); } }); } else { response.send(statusCodes.NO_CONTENT, { RequestedNickname : "" }); } }, error: function(error) { console.log('Error read table: ', error); response.send(statusCodes.INTERNAL_SERVER_ERROR, { RequestedNickname : "" }); } }); };
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
        Push      
      
        
        
        
      
     // Perform Push operation member this.PushAsync targetId myId myNickname = async { try let (request : PushRequest) = { TargetId = targetId RequesterId = myId RequesterName = myNickname } let! result = this.MobileService.InvokeApiAsync<PushRequest, PushResponce>("pushhim", request) |> Async.AwaitTask return result.RequestedNickname with | e -> return e.ToString() }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
           ,    let-bang
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
       do!
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
       
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
          Google Play Services.     F#   .           .    : Xamarin.Android.Support.v7.AppCompat 
      
        
        
        
      
         , Google Play Services ,   . 
      
        
        
        
      
     
      
        
        
        
      
          push notification   .    GCM,  ID,     ID       Push  (.   pushhim).        BroadcastReciever       developer.android.com .     F#         Xamarin Component Store.     Google Cloud Messaging Client         GCM    .        ID 
      
        
        
        
      
     //Check to see that GCM is supported and that the manifest has the correct information GcmClient.CheckDevice(this) GcmClient.CheckManifest(this) // check google play if CheckPlayServices() then // Try to get registration id let regId = GcmClient.GetRegistrationId this if String.IsNullOrEmpty(regId) then // Call to Register the device for Push Notifications GcmClient.Register(this, WruConstants.GcmSender);
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
            
      
        
        
        
      
     
      
        
        
        
      
        . 
      
        
        
        
      
        , -  
      
        
        
        
      
         bitbucket.org/xakpc/whereareyou 
      
        
        
        
      
         ,     
      
        
        
        
      
              ,           "" . 
      
        
        
        
      
     
      
        
        
        
      
      
      
        
        
        
      
     ,   Android   F#.      . 
      
        
        
        
      
     ,       -  Android  F#.   ,       .
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
    
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      listView.Adapter <- new ArrayAdapter(this, Android.Resource.Layout.SimpleListItem1, Android.Resource.Id.Text1, values) 
      
        
        
        
      
      , ,  let values = [|"item1"; "item2"; "item3"|]
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     -   string[],       list (IEnumerable   ) 
      
        
        
        
      
              F#.            www.tryfsharp.org/Learn 
      
        
        
        
      
      
 
      
        
        
        
      
          F# -  ,  
      
        
        
        
      
     
      
        
        
        
      
            F# For Fun And Profit 
      
        
        
        
      
     
      
        
        
        
      
       ,    
      
        
        
        
      
         - . 
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
     
      
        
        
        
      
            hash 
      
        
        
        
      
         MD5  F# 
      
        
        
        
      
      let MD5Hash (input : string) = use md5 = System.Security.Cryptography.MD5.Create() input |> System.Text.Encoding.ASCII.GetBytes |> md5.ComputeHash |> Seq.map (fun c -> c.ToString("X2")) |> Seq.reduce (+)
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
      |>
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      pipeline ,     . 
      
        
        
        
      
         :    GetBytes ->   ->      HEX  ->       (  reduce   +           ) ->    . 
      
        
        
        
      
     
      
        
        
        
      
      ,     C# using System; public string CreateMD5Hash (string input) { MD5 md5 = System.Security.Cryptography.MD5.Create(); byte[] inputBytes = System.Text.Encoding.ASCII.GetBytes (input); byte[] hashBytes = md5.ComputeHash (inputBytes); StringBuilder sb = new StringBuilder(); for (int i = 0; i < hashBytes.Length; i++) { sb.Append (hashBytes[i].ToString ("X2")); } return sb.ToString(); }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
     
      
        
        
        
      
              :        .       AzureServiceWorker (  CLR    ) 
      
        
        
        
      
     
      
        
        
        
      
              -   .   F#    !   Xamarin Studio            . 
      
        
        
        
      
      <ItemGroup> <Compile Include="Resources\Resource.designer.fs" /> <Compile Include="Properties\AssemblyInfo.fs" /> <Compile Include="Helpers\Helpers.fs" /> <Compile Include="Services\User.fs" /> <Compile Include="Services\AzureServiceWorker.fs" /> <Compile Include="IAmHereActivity.fs" /> <Compile Include="WhereAreYouActivity.fs" /> <Compile Include="SignInActivity.fs" /> </ItemGroup>
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
        
      
        
        
        
      
            :    .    Xamarin    Xamarin.Mobile 
      
        
        
        
      
     
      
        
        
        
      
          .  F#         TPL,     Task',      .     F#         Task.  ,     : 
      
        
        
        
      
     module Async = open System.Threading open System.Threading.Tasks let inline AwaitPlainTask (task: Task) = // rethrow exception from preceding task if it fauled let continuation (t : Task) : unit = match t.IsFaulted with | true -> raise t.Exception | arg -> () task.ContinueWith continuation |> Async.AwaitTask
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
             Async.AwaitIAsyncResult >> Async.Ignore
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
           
      
        
        
        
      
     
      
        
        
        
      
                
      
        
        
        
      
     let ExtractUserInfo (x : Contact) = let first = x.Phones |> Seq.tryPick(fun x -> if x.Type = PhoneType.Mobile then Some(x) else None) match first with | Some(first) -> let phone = first.Number |> StripChars [' ';'-';'(';')'] UserInfo.CreateUserInfo((MD5Hash phone), phone, x.DisplayName) | None -> UserInfo.CreateUserInfo("no mobile phone", "no mobile phone", "no mobile phone") // function for async list filling let FillContactsAsync = async { let book = new AddressBook (this) let! result = book.RequestPermission() |> Async.AwaitTask if result then _contacts <- book.ToList() |> Seq.filter (fun (x: Contact) -> not (Seq.isEmpty x.Phones)) |> Seq.map ExtractUserInfo |> Seq.sortBy(fun x -> x.DisplayName) |> Seq.toList let finalContacts = _contacts |> Seq.map (fun x -> x.DisplayName.ToUpperInvariant()) |> Seq.toArray this.ListAdapter <- new ArrayAdapter(this, Resource_Layout.row_contact, finalContacts) else System.Diagnostics.Debug.WriteLine("Permission denied by user or manifest") this.ListAdapter <- new ArrayAdapter(this, Resource_Layout.row_contact, Array.empty) }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
          
      
        
        
        
      
     book.ToList()
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
       List |> Seq.filter (fun (x: Contact) -> not (Seq.isEmpty x.Phones))
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
          |> Seq.map ExtractUserInfo
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
          Contracts  UserInfo,      UserInfo |> Seq.sortBy(fun x -> x.DisplayName)
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      |> Seq.toList
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
       List _contacts <-
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
        mutable  _contacts |> Seq.map (fun x -> x.DisplayName.ToUpperInvariant())<-
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
        UserInfo  string,     - -    |> Seq.toArray<-
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      List  Array    ArrayAdapter 
      
        
        
        
      
        -      List.   . 
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
     
      
        
        
        
      
     Azure Mobile Servcies 
      
        
        
        
      
       -    Azure Mobile Services.       NotificationHub,     Push    .   Azure    , ..      . 
      
        
        
        
      
     
      
        
        
        
      
          ,    
      
        
        
        
      
     module WruConstants = [<Literal>] let TotallyNotAzureServer = "https://YOUR.azure-mobile.net/"; [<Literal>] let TotallyNotAzureKey = "YOUR"
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
       
        
        
        
      
     member this.RegisterMe phone name regId = async { try let table = this.MobileService.GetTable<User>() let usr = { Id = "" PhoneHash = MD5Hash phone Nickname = name RegistrationId = regId } do! table.InsertAsync usr |> Async.AwaitPlainTask return (usr.Id, usr.PhoneHash, usr.Nickname) with | e -> System.Diagnostics.Trace.WriteLine(e.ToString) return (String.Empty,String.Empty,String.Empty) }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     member this.RegisterMe phone name regId = async {
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     -       (     )    .       "computation expression"   workflow.   { }       ! ( bang),  do! (do-bang)  let! (let bang)     User.    ,  F#        ,      
      
        
        
        
      
      let usr = { Id = "" PhoneHash = MD5Hash phone Nickname = name RegistrationId = regId }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     do! table.InsertAsync usr |> Async.AwaitPlainTask
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      do-bang,   await
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      C#. ..             continuation    . return (usr.Id, usr.PhoneHash, usr.Nickname)
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
          Tuple<string,string,string>     .  try ... with | e ->
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      try..catch
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      C# 
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
     
      
        
        
        
      
           .  F#    fst
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      snd
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
          .        2 .     : 
      
        
        
        
      
      let id (c,_,_) = c let phonehash (_,c,_) = c let nickname (_,_,c) = c
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
        : id tuple
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      Id  .. 
      
        
        
        
      
     
      
        
        
        
      
        5  Azure,       Push .       Azure Custom Api  
      
        
        
        
      
     
      
        
        
        
      
          exports.post = function(request, response) { // Use "request.service" to access features of your mobile service, eg: // var tables = request.service.tables; // var push = request.service.push; //response.send(statusCodes.OK, { message : 'Hello World!' }); console.log('Incoming call with requst: ', request.body.RequestId); var usersTable = request.service.tables.getTable('User'); usersTable.where( { id : request.body.TargetId } ) .read( { success: function(results) { if (results.length > 0) { var user = results[0] console.log('Send to results: ', user.Nickname, user.RegistrationId); request.service.push.gcm.send(user.RegistrationId, { RequesterId: request.body.RequesterId, RequesterNickname: request.body.RequesterName, TargetId: user.id, TargetNickname: user.Nickname }, { success: function(gcm_response) { console.log('Push notification sent: ', gcm_response); response.send(statusCodes.OK, { RequestedNickname : user.Nickname }); }, error: function(gcm_error) { console.log('Error sending push notification: ', gcm_error); response.send(statusCodes.INTERNAL_SERVER_ERROR, { RequestedNickname : user.Nickname }); } }); } else { response.send(statusCodes.NO_CONTENT, { RequestedNickname : "" }); } }, error: function(error) { console.log('Error read table: ', error); response.send(statusCodes.INTERNAL_SERVER_ERROR, { RequestedNickname : "" }); } }); };
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
        Push      
      
        
        
        
      
     // Perform Push operation member this.PushAsync targetId myId myNickname = async { try let (request : PushRequest) = { TargetId = targetId RequesterId = myId RequesterName = myNickname } let! result = this.MobileService.InvokeApiAsync<PushRequest, PushResponce>("pushhim", request) |> Async.AwaitTask return result.RequestedNickname with | e -> return e.ToString() }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
           ,    let-bang
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
       do!
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
       
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
          Google Play Services.     F#   .           .    : Xamarin.Android.Support.v7.AppCompat 
      
        
        
        
      
         , Google Play Services ,   . 
      
        
        
        
      
     
      
        
        
        
      
          push notification   .    GCM,  ID,     ID       Push  (.   pushhim).        BroadcastReciever       developer.android.com .     F#         Xamarin Component Store.     Google Cloud Messaging Client         GCM    .        ID 
      
        
        
        
      
     //Check to see that GCM is supported and that the manifest has the correct information GcmClient.CheckDevice(this) GcmClient.CheckManifest(this) // check google play if CheckPlayServices() then // Try to get registration id let regId = GcmClient.GetRegistrationId this if String.IsNullOrEmpty(regId) then // Call to Register the device for Push Notifications GcmClient.Register(this, WruConstants.GcmSender);
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
            
      
        
        
        
      
     
      
        
        
        
      
        . 
      
        
        
        
      
        , -  
      
        
        
        
      
         bitbucket.org/xakpc/whereareyou 
      
        
        
        
      
         ,     
      
        
        
        
      
              ,           "" . 
      
        
        
        
      
     
      
        
        
        
      
      
      
        
        
        
      
     ,   Android   F#.      . 
      
        
        
        
      
     ,       -  Android  F#.   ,       .
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
    -  listView.Adapter <- new ArrayAdapter(this, Android.Resource.Layout.SimpleListItem1, Android.Resource.Id.Text1, values)
 
 , , let values = [|"item1"; "item2"; "item3"|]
 
 
 
 - string[], list (IEnumerable )
 
 F#. www.tryfsharp.org/Learn
 
   
 
 F# - ,
 
 
 
 F# For Fun And Profit
 
 
 
 ,
 
 - .
 
 
 
   
 
 
 
 hash
 
 MD5 F#
 
 let MD5Hash (input : string) = use md5 = System.Security.Cryptography.MD5.Create() input |> System.Text.Encoding.ASCII.GetBytes |> md5.ComputeHash |> Seq.map (fun c -> c.ToString("X2")) |> Seq.reduce (+)
 
 
 
 
 
 
 
 |>
 
 
 
 pipeline , .
 
 : GetBytes -> -> HEX -> ( reduce + ) -> .
 
 
 
 , C#using System; public string CreateMD5Hash (string input) { MD5 md5 = System.Security.Cryptography.MD5.Create(); byte[] inputBytes = System.Text.Encoding.ASCII.GetBytes (input); byte[] hashBytes = md5.ComputeHash (inputBytes); StringBuilder sb = new StringBuilder(); for (int i = 0; i < hashBytes.Length; i++) { sb.Append (hashBytes[i].ToString ("X2")); } return sb.ToString(); }
 
 
 
 
 
 
 
 
 
 : . AzureServiceWorker ( CLR )
 
 
 
 - . F# ! Xamarin Studio .
 
 <ItemGroup> <Compile Include="Resources\Resource.designer.fs" /> <Compile Include="Properties\AssemblyInfo.fs" /> <Compile Include="Helpers\Helpers.fs" /> <Compile Include="Services\User.fs" /> <Compile Include="Services\AzureServiceWorker.fs" /> <Compile Include="IAmHereActivity.fs" /> <Compile Include="WhereAreYouActivity.fs" /> <Compile Include="SignInActivity.fs" /> </ItemGroup>
 
 
 
 
 
 
 
 
 
 : . Xamarin Xamarin.Mobile
 
 
 
 . F# TPL, Task', . F# Task. , :
 
 module Async = open System.Threading open System.Threading.Tasks let inline AwaitPlainTask (task: Task) = // rethrow exception from preceding task if it fauled let continuation (t : Task) : unit = match t.IsFaulted with | true -> raise t.Exception | arg -> () task.ContinueWith continuation |> Async.AwaitTask
 
 
 
 
 
 Async.AwaitIAsyncResult >> Async.Ignore
 
 
 
 
 
 
 
 
 
 let ExtractUserInfo (x : Contact) = let first = x.Phones |> Seq.tryPick(fun x -> if x.Type = PhoneType.Mobile then Some(x) else None) match first with | Some(first) -> let phone = first.Number |> StripChars [' ';'-';'(';')'] UserInfo.CreateUserInfo((MD5Hash phone), phone, x.DisplayName) | None -> UserInfo.CreateUserInfo("no mobile phone", "no mobile phone", "no mobile phone") // function for async list filling let FillContactsAsync = async { let book = new AddressBook (this) let! result = book.RequestPermission() |> Async.AwaitTask if result then _contacts <- book.ToList() |> Seq.filter (fun (x: Contact) -> not (Seq.isEmpty x.Phones)) |> Seq.map ExtractUserInfo |> Seq.sortBy(fun x -> x.DisplayName) |> Seq.toList let finalContacts = _contacts |> Seq.map (fun x -> x.DisplayName.ToUpperInvariant()) |> Seq.toArray this.ListAdapter <- new ArrayAdapter(this, Resource_Layout.row_contact, finalContacts) else System.Diagnostics.Debug.WriteLine("Permission denied by user or manifest") this.ListAdapter <- new ArrayAdapter(this, Resource_Layout.row_contact, Array.empty) }
 
 
 
 
 
 
 
 book.ToList()
 
 
 
 List|> Seq.filter (fun (x: Contact) -> not (Seq.isEmpty x.Phones))
 
 
 
 |> Seq.map ExtractUserInfo
 
 
 
 Contracts UserInfo, UserInfo|> Seq.sortBy(fun x -> x.DisplayName)
 
 
 
 |> Seq.toList
 
 
 
 List_contacts <-
 
 
 
 mutable_contacts |> Seq.map (fun x -> x.DisplayName.ToUpperInvariant())<-
 
 
 
 UserInfo string, - -|> Seq.toArray<-
 
 
 
 List Array ArrayAdapter
 
 - List. .
 
 
 
   
 
 
 
 Azure Mobile Servcies
 
 - Azure Mobile Services. NotificationHub, Push . Azure , .. .
 
 
 
 ,
 
 module WruConstants = [<Literal>] let TotallyNotAzureServer = "https://YOUR.azure-mobile.net/"; [<Literal>] let TotallyNotAzureKey = "YOUR"
 
 
 
 
 
 
 
 
 
 member this.RegisterMe phone name regId = async { try let table = this.MobileService.GetTable<User>() let usr = { Id = "" PhoneHash = MD5Hash phone Nickname = name RegistrationId = regId } do! table.InsertAsync usr |> Async.AwaitPlainTask return (usr.Id, usr.PhoneHash, usr.Nickname) with | e -> System.Diagnostics.Trace.WriteLine(e.ToString) return (String.Empty,String.Empty,String.Empty) }
 
 
 
 
 
 member this.RegisterMe phone name regId = async {
 
 
 
 - ( ) . "computation expression" workflow. { } ! ( bang), do! (do-bang) let! (let bang) User. , F# ,
 
 let usr = { Id = "" PhoneHash = MD5Hash phone Nickname = name RegistrationId = regId }
 
 
 
 do! table.InsertAsync usr |> Async.AwaitPlainTask
 
 
 
 do-bang,await
 
 
 
 C#. .. continuation .return (usr.Id, usr.PhoneHash, usr.Nickname)
 
 
 
 Tuple<string,string,string> .try ... with | e ->
 
 
 
 try..catch
 
 
 
 C#
 
 
 
   
 
 
 
 . F#fst
 
 
 
 snd
 
 
 
 . 2 . :
 
 let id (c,_,_) = c let phonehash (_,c,_) = c let nickname (_,_,c) = c
 
 
 
 
 
 :id tuple
 
 
 
 Id ..
 
 
 
 5 Azure, Push . Azure Custom Api
 
 
 
 exports.post = function(request, response) { // Use "request.service" to access features of your mobile service, eg: // var tables = request.service.tables; // var push = request.service.push; //response.send(statusCodes.OK, { message : 'Hello World!' }); console.log('Incoming call with requst: ', request.body.RequestId); var usersTable = request.service.tables.getTable('User'); usersTable.where( { id : request.body.TargetId } ) .read( { success: function(results) { if (results.length > 0) { var user = results[0] console.log('Send to results: ', user.Nickname, user.RegistrationId); request.service.push.gcm.send(user.RegistrationId, { RequesterId: request.body.RequesterId, RequesterNickname: request.body.RequesterName, TargetId: user.id, TargetNickname: user.Nickname }, { success: function(gcm_response) { console.log('Push notification sent: ', gcm_response); response.send(statusCodes.OK, { RequestedNickname : user.Nickname }); }, error: function(gcm_error) { console.log('Error sending push notification: ', gcm_error); response.send(statusCodes.INTERNAL_SERVER_ERROR, { RequestedNickname : user.Nickname }); } }); } else { response.send(statusCodes.NO_CONTENT, { RequestedNickname : "" }); } }, error: function(error) { console.log('Error read table: ', error); response.send(statusCodes.INTERNAL_SERVER_ERROR, { RequestedNickname : "" }); } }); };
 
 
 
 
 
 
 
 Push
 
 // Perform Push operation member this.PushAsync targetId myId myNickname = async { try let (request : PushRequest) = { TargetId = targetId RequesterId = myId RequesterName = myNickname } let! result = this.MobileService.InvokeApiAsync<PushRequest, PushResponce>("pushhim", request) |> Async.AwaitTask return result.RequestedNickname with | e -> return e.ToString() }
 
 
 
 
 
 
 
 ,let-bang
 
 
 
 do!
 
 
 
 
 
 
 
 
 
 
 
   
 
 Google Play Services. F# . . : Xamarin.Android.Support.v7.AppCompat
 
 , Google Play Services , .
 
 
 
 push notification . GCM, ID, ID Push (. pushhim). BroadcastReciever developer.android.com . F# Xamarin Component Store. Google Cloud Messaging Client GCM . ID
 
 //Check to see that GCM is supported and that the manifest has the correct information GcmClient.CheckDevice(this) GcmClient.CheckManifest(this) // check google play if CheckPlayServices() then // Try to get registration id let regId = GcmClient.GetRegistrationId this if String.IsNullOrEmpty(regId) then // Call to Register the device for Push Notifications GcmClient.Register(this, WruConstants.GcmSender);
 
 
 
 
 
 
 
   
 
 
 
 
 
 .
 
 , -
 
 bitbucket.org/xakpc/whereareyou
 
 ,
 
 , "" .
 
 
 
 
 
 , Android F#. .
 
 , - Android F#. , .
 
 
 
 
 
 
 
 
-  listView.Adapter <- new ArrayAdapter(this, Android.Resource.Layout.SimpleListItem1, Android.Resource.Id.Text1, values)
 
 , , let values = [|"item1"; "item2"; "item3"|]
 
 
 
 - string[], list (IEnumerable )
 
 F#. www.tryfsharp.org/Learn
 
   
 
 F# - ,
 
 
 
 F# For Fun And Profit
 
 
 
 ,
 
 - .
 
 
 
   
 
 
 
 hash
 
 MD5 F#
 
 let MD5Hash (input : string) = use md5 = System.Security.Cryptography.MD5.Create() input |> System.Text.Encoding.ASCII.GetBytes |> md5.ComputeHash |> Seq.map (fun c -> c.ToString("X2")) |> Seq.reduce (+)
 
 
 
 
 
 
 
 |>
 
 
 
 pipeline , .
 
 : GetBytes -> -> HEX -> ( reduce + ) -> .
 
 
 
 , C#using System; public string CreateMD5Hash (string input) { MD5 md5 = System.Security.Cryptography.MD5.Create(); byte[] inputBytes = System.Text.Encoding.ASCII.GetBytes (input); byte[] hashBytes = md5.ComputeHash (inputBytes); StringBuilder sb = new StringBuilder(); for (int i = 0; i < hashBytes.Length; i++) { sb.Append (hashBytes[i].ToString ("X2")); } return sb.ToString(); }
 
 
 
 
 
 
 
 
 
 : . AzureServiceWorker ( CLR )
 
 
 
 - . F# ! Xamarin Studio .
 
 <ItemGroup> <Compile Include="Resources\Resource.designer.fs" /> <Compile Include="Properties\AssemblyInfo.fs" /> <Compile Include="Helpers\Helpers.fs" /> <Compile Include="Services\User.fs" /> <Compile Include="Services\AzureServiceWorker.fs" /> <Compile Include="IAmHereActivity.fs" /> <Compile Include="WhereAreYouActivity.fs" /> <Compile Include="SignInActivity.fs" /> </ItemGroup>
 
 
 
 
 
 
 
 
 
 : . Xamarin Xamarin.Mobile
 
 
 
 . F# TPL, Task', . F# Task. , :
 
 module Async = open System.Threading open System.Threading.Tasks let inline AwaitPlainTask (task: Task) = // rethrow exception from preceding task if it fauled let continuation (t : Task) : unit = match t.IsFaulted with | true -> raise t.Exception | arg -> () task.ContinueWith continuation |> Async.AwaitTask
 
 
 
 
 
 Async.AwaitIAsyncResult >> Async.Ignore
 
 
 
 
 
 
 
 
 
 let ExtractUserInfo (x : Contact) = let first = x.Phones |> Seq.tryPick(fun x -> if x.Type = PhoneType.Mobile then Some(x) else None) match first with | Some(first) -> let phone = first.Number |> StripChars [' ';'-';'(';')'] UserInfo.CreateUserInfo((MD5Hash phone), phone, x.DisplayName) | None -> UserInfo.CreateUserInfo("no mobile phone", "no mobile phone", "no mobile phone") // function for async list filling let FillContactsAsync = async { let book = new AddressBook (this) let! result = book.RequestPermission() |> Async.AwaitTask if result then _contacts <- book.ToList() |> Seq.filter (fun (x: Contact) -> not (Seq.isEmpty x.Phones)) |> Seq.map ExtractUserInfo |> Seq.sortBy(fun x -> x.DisplayName) |> Seq.toList let finalContacts = _contacts |> Seq.map (fun x -> x.DisplayName.ToUpperInvariant()) |> Seq.toArray this.ListAdapter <- new ArrayAdapter(this, Resource_Layout.row_contact, finalContacts) else System.Diagnostics.Debug.WriteLine("Permission denied by user or manifest") this.ListAdapter <- new ArrayAdapter(this, Resource_Layout.row_contact, Array.empty) }
 
 
 
 
 
 
 
 book.ToList()
 
 
 
 List|> Seq.filter (fun (x: Contact) -> not (Seq.isEmpty x.Phones))
 
 
 
 |> Seq.map ExtractUserInfo
 
 
 
 Contracts UserInfo, UserInfo|> Seq.sortBy(fun x -> x.DisplayName)
 
 
 
 |> Seq.toList
 
 
 
 List_contacts <-
 
 
 
 mutable_contacts |> Seq.map (fun x -> x.DisplayName.ToUpperInvariant())<-
 
 
 
 UserInfo string, - -|> Seq.toArray<-
 
 
 
 List Array ArrayAdapter
 
 - List. .
 
 
 
   
 
 
 
 Azure Mobile Servcies
 
 - Azure Mobile Services. NotificationHub, Push . Azure , .. .
 
 
 
 ,
 
 module WruConstants = [<Literal>] let TotallyNotAzureServer = "https://YOUR.azure-mobile.net/"; [<Literal>] let TotallyNotAzureKey = "YOUR"
 
 
 
 
 
 
 
 
 
 member this.RegisterMe phone name regId = async { try let table = this.MobileService.GetTable<User>() let usr = { Id = "" PhoneHash = MD5Hash phone Nickname = name RegistrationId = regId } do! table.InsertAsync usr |> Async.AwaitPlainTask return (usr.Id, usr.PhoneHash, usr.Nickname) with | e -> System.Diagnostics.Trace.WriteLine(e.ToString) return (String.Empty,String.Empty,String.Empty) }
 
 
 
 
 
 member this.RegisterMe phone name regId = async {
 
 
 
 - ( ) . "computation expression" workflow. { } ! ( bang), do! (do-bang) let! (let bang) User. , F# ,
 
 let usr = { Id = "" PhoneHash = MD5Hash phone Nickname = name RegistrationId = regId }
 
 
 
 do! table.InsertAsync usr |> Async.AwaitPlainTask
 
 
 
 do-bang,await
 
 
 
 C#. .. continuation .return (usr.Id, usr.PhoneHash, usr.Nickname)
 
 
 
 Tuple<string,string,string> .try ... with | e ->
 
 
 
 try..catch
 
 
 
 C#
 
 
 
   
 
 
 
 . F#fst
 
 
 
 snd
 
 
 
 . 2 . :
 
 let id (c,_,_) = c let phonehash (_,c,_) = c let nickname (_,_,c) = c
 
 
 
 
 
 :id tuple
 
 
 
 Id ..
 
 
 
 5 Azure, Push . Azure Custom Api
 
 
 
 exports.post = function(request, response) { // Use "request.service" to access features of your mobile service, eg: // var tables = request.service.tables; // var push = request.service.push; //response.send(statusCodes.OK, { message : 'Hello World!' }); console.log('Incoming call with requst: ', request.body.RequestId); var usersTable = request.service.tables.getTable('User'); usersTable.where( { id : request.body.TargetId } ) .read( { success: function(results) { if (results.length > 0) { var user = results[0] console.log('Send to results: ', user.Nickname, user.RegistrationId); request.service.push.gcm.send(user.RegistrationId, { RequesterId: request.body.RequesterId, RequesterNickname: request.body.RequesterName, TargetId: user.id, TargetNickname: user.Nickname }, { success: function(gcm_response) { console.log('Push notification sent: ', gcm_response); response.send(statusCodes.OK, { RequestedNickname : user.Nickname }); }, error: function(gcm_error) { console.log('Error sending push notification: ', gcm_error); response.send(statusCodes.INTERNAL_SERVER_ERROR, { RequestedNickname : user.Nickname }); } }); } else { response.send(statusCodes.NO_CONTENT, { RequestedNickname : "" }); } }, error: function(error) { console.log('Error read table: ', error); response.send(statusCodes.INTERNAL_SERVER_ERROR, { RequestedNickname : "" }); } }); };
 
 
 
 
 
 
 
 Push
 
 // Perform Push operation member this.PushAsync targetId myId myNickname = async { try let (request : PushRequest) = { TargetId = targetId RequesterId = myId RequesterName = myNickname } let! result = this.MobileService.InvokeApiAsync<PushRequest, PushResponce>("pushhim", request) |> Async.AwaitTask return result.RequestedNickname with | e -> return e.ToString() }
 
 
 
 
 
 
 
 ,let-bang
 
 
 
 do!
 
 
 
 
 
 
 
 
 
 
 
   
 
 Google Play Services. F# . . : Xamarin.Android.Support.v7.AppCompat
 
 , Google Play Services , .
 
 
 
 push notification . GCM, ID, ID Push (. pushhim). BroadcastReciever developer.android.com . F# Xamarin Component Store. Google Cloud Messaging Client GCM . ID
 
 //Check to see that GCM is supported and that the manifest has the correct information GcmClient.CheckDevice(this) GcmClient.CheckManifest(this) // check google play if CheckPlayServices() then // Try to get registration id let regId = GcmClient.GetRegistrationId this if String.IsNullOrEmpty(regId) then // Call to Register the device for Push Notifications GcmClient.Register(this, WruConstants.GcmSender);
 
 
 
 
 
 
 
   
 
 
 
 
 
 .
 
 , -
 
 bitbucket.org/xakpc/whereareyou
 
 ,
 
 , "" .
 
 
 
 
 
 , Android F#. .
 
 , - Android F#. , .
 
 
 
 
 
 
 
 
-  listView.Adapter <- new ArrayAdapter(this, Android.Resource.Layout.SimpleListItem1, Android.Resource.Id.Text1, values)
 
 , , let values = [|"item1"; "item2"; "item3"|]
 
 
 
 - string[], list (IEnumerable )
 
 F#. www.tryfsharp.org/Learn
 
   
 
 F# - ,
 
 
 
 F# For Fun And Profit
 
 
 
 ,
 
 - .
 
 
 
   
 
 
 
 hash
 
 MD5 F#
 
 let MD5Hash (input : string) = use md5 = System.Security.Cryptography.MD5.Create() input |> System.Text.Encoding.ASCII.GetBytes |> md5.ComputeHash |> Seq.map (fun c -> c.ToString("X2")) |> Seq.reduce (+)
 
 
 
 
 
 
 
 |>
 
 
 
 pipeline , .
 
 : GetBytes -> -> HEX -> ( reduce + ) -> .
 
 
 
 , C#using System; public string CreateMD5Hash (string input) { MD5 md5 = System.Security.Cryptography.MD5.Create(); byte[] inputBytes = System.Text.Encoding.ASCII.GetBytes (input); byte[] hashBytes = md5.ComputeHash (inputBytes); StringBuilder sb = new StringBuilder(); for (int i = 0; i < hashBytes.Length; i++) { sb.Append (hashBytes[i].ToString ("X2")); } return sb.ToString(); }
 
 
 
 
 
 
 
 
 
 : . AzureServiceWorker ( CLR )
 
 
 
 - . F# ! Xamarin Studio .
 
 <ItemGroup> <Compile Include="Resources\Resource.designer.fs" /> <Compile Include="Properties\AssemblyInfo.fs" /> <Compile Include="Helpers\Helpers.fs" /> <Compile Include="Services\User.fs" /> <Compile Include="Services\AzureServiceWorker.fs" /> <Compile Include="IAmHereActivity.fs" /> <Compile Include="WhereAreYouActivity.fs" /> <Compile Include="SignInActivity.fs" /> </ItemGroup>
 
 
 
 
 
 
 
 
 
 : . Xamarin Xamarin.Mobile
 
 
 
 . F# TPL, Task', . F# Task. , :
 
 module Async = open System.Threading open System.Threading.Tasks let inline AwaitPlainTask (task: Task) = // rethrow exception from preceding task if it fauled let continuation (t : Task) : unit = match t.IsFaulted with | true -> raise t.Exception | arg -> () task.ContinueWith continuation |> Async.AwaitTask
 
 
 
 
 
 Async.AwaitIAsyncResult >> Async.Ignore
 
 
 
 
 
 
 
 
 
 let ExtractUserInfo (x : Contact) = let first = x.Phones |> Seq.tryPick(fun x -> if x.Type = PhoneType.Mobile then Some(x) else None) match first with | Some(first) -> let phone = first.Number |> StripChars [' ';'-';'(';')'] UserInfo.CreateUserInfo((MD5Hash phone), phone, x.DisplayName) | None -> UserInfo.CreateUserInfo("no mobile phone", "no mobile phone", "no mobile phone") // function for async list filling let FillContactsAsync = async { let book = new AddressBook (this) let! result = book.RequestPermission() |> Async.AwaitTask if result then _contacts <- book.ToList() |> Seq.filter (fun (x: Contact) -> not (Seq.isEmpty x.Phones)) |> Seq.map ExtractUserInfo |> Seq.sortBy(fun x -> x.DisplayName) |> Seq.toList let finalContacts = _contacts |> Seq.map (fun x -> x.DisplayName.ToUpperInvariant()) |> Seq.toArray this.ListAdapter <- new ArrayAdapter(this, Resource_Layout.row_contact, finalContacts) else System.Diagnostics.Debug.WriteLine("Permission denied by user or manifest") this.ListAdapter <- new ArrayAdapter(this, Resource_Layout.row_contact, Array.empty) }
 
 
 
 
 
 
 
 book.ToList()
 
 
 
 List|> Seq.filter (fun (x: Contact) -> not (Seq.isEmpty x.Phones))
 
 
 
 |> Seq.map ExtractUserInfo
 
 
 
 Contracts UserInfo, UserInfo|> Seq.sortBy(fun x -> x.DisplayName)
 
 
 
 |> Seq.toList
 
 
 
 List_contacts <-
 
 
 
 mutable_contacts |> Seq.map (fun x -> x.DisplayName.ToUpperInvariant())<-
 
 
 
 UserInfo string, - -|> Seq.toArray<-
 
 
 
 List Array ArrayAdapter
 
 - List. .
 
 
 
   
 
 
 
 Azure Mobile Servcies
 
 - Azure Mobile Services. NotificationHub, Push . Azure , .. .
 
 
 
 ,
 
 module WruConstants = [<Literal>] let TotallyNotAzureServer = "https://YOUR.azure-mobile.net/"; [<Literal>] let TotallyNotAzureKey = "YOUR"
 
 
 
 
 
 
 
 
 
 member this.RegisterMe phone name regId = async { try let table = this.MobileService.GetTable<User>() let usr = { Id = "" PhoneHash = MD5Hash phone Nickname = name RegistrationId = regId } do! table.InsertAsync usr |> Async.AwaitPlainTask return (usr.Id, usr.PhoneHash, usr.Nickname) with | e -> System.Diagnostics.Trace.WriteLine(e.ToString) return (String.Empty,String.Empty,String.Empty) }
 
 
 
 
 
 member this.RegisterMe phone name regId = async {
 
 
 
 - ( ) . "computation expression" workflow. { } ! ( bang), do! (do-bang) let! (let bang) User. , F# ,
 
 let usr = { Id = "" PhoneHash = MD5Hash phone Nickname = name RegistrationId = regId }
 
 
 
 do! table.InsertAsync usr |> Async.AwaitPlainTask
 
 
 
 do-bang,await
 
 
 
 C#. .. continuation .return (usr.Id, usr.PhoneHash, usr.Nickname)
 
 
 
 Tuple<string,string,string> .try ... with | e ->
 
 
 
 try..catch
 
 
 
 C#
 
 
 
   
 
 
 
 . F#fst
 
 
 
 snd
 
 
 
 . 2 . :
 
 let id (c,_,_) = c let phonehash (_,c,_) = c let nickname (_,_,c) = c
 
 
 
 
 
 :id tuple
 
 
 
 Id ..
 
 
 
 5 Azure, Push . Azure Custom Api
 
 
 
 exports.post = function(request, response) { // Use "request.service" to access features of your mobile service, eg: // var tables = request.service.tables; // var push = request.service.push; //response.send(statusCodes.OK, { message : 'Hello World!' }); console.log('Incoming call with requst: ', request.body.RequestId); var usersTable = request.service.tables.getTable('User'); usersTable.where( { id : request.body.TargetId } ) .read( { success: function(results) { if (results.length > 0) { var user = results[0] console.log('Send to results: ', user.Nickname, user.RegistrationId); request.service.push.gcm.send(user.RegistrationId, { RequesterId: request.body.RequesterId, RequesterNickname: request.body.RequesterName, TargetId: user.id, TargetNickname: user.Nickname }, { success: function(gcm_response) { console.log('Push notification sent: ', gcm_response); response.send(statusCodes.OK, { RequestedNickname : user.Nickname }); }, error: function(gcm_error) { console.log('Error sending push notification: ', gcm_error); response.send(statusCodes.INTERNAL_SERVER_ERROR, { RequestedNickname : user.Nickname }); } }); } else { response.send(statusCodes.NO_CONTENT, { RequestedNickname : "" }); } }, error: function(error) { console.log('Error read table: ', error); response.send(statusCodes.INTERNAL_SERVER_ERROR, { RequestedNickname : "" }); } }); };
 
 
 
 
 
 
 
 Push
 
 // Perform Push operation member this.PushAsync targetId myId myNickname = async { try let (request : PushRequest) = { TargetId = targetId RequesterId = myId RequesterName = myNickname } let! result = this.MobileService.InvokeApiAsync<PushRequest, PushResponce>("pushhim", request) |> Async.AwaitTask return result.RequestedNickname with | e -> return e.ToString() }
 
 
 
 
 
 
 
 ,let-bang
 
 
 
 do!
 
 
 
 
 
 
 
 
 
 
 
   
 
 Google Play Services. F# . . : Xamarin.Android.Support.v7.AppCompat
 
 , Google Play Services , .
 
 
 
 push notification . GCM, ID, ID Push (. pushhim). BroadcastReciever developer.android.com . F# Xamarin Component Store. Google Cloud Messaging Client GCM . ID
 
 //Check to see that GCM is supported and that the manifest has the correct information GcmClient.CheckDevice(this) GcmClient.CheckManifest(this) // check google play if CheckPlayServices() then // Try to get registration id let regId = GcmClient.GetRegistrationId this if String.IsNullOrEmpty(regId) then // Call to Register the device for Push Notifications GcmClient.Register(this, WruConstants.GcmSender);
 
 
 
 
 
 
 
   
 
 
 
 
 
 .
 
 , -
 
 bitbucket.org/xakpc/whereareyou
 
 ,
 
 , "" .
 
 
 
 
 
 , Android F#. .
 
 , - Android F#. , .
 
 
 
 
 
 
 
 
-  listView.Adapter <- new ArrayAdapter(this, Android.Resource.Layout.SimpleListItem1, Android.Resource.Id.Text1, values)
 
 , , let values = [|"item1"; "item2"; "item3"|]
 
 
 
 - string[], list (IEnumerable )
 
 F#. www.tryfsharp.org/Learn
 
   
 
 F# - ,
 
 
 
 F# For Fun And Profit
 
 
 
 ,
 
 - .
 
 
 
   
 
 
 
 hash
 
 MD5 F#
 
 let MD5Hash (input : string) = use md5 = System.Security.Cryptography.MD5.Create() input |> System.Text.Encoding.ASCII.GetBytes |> md5.ComputeHash |> Seq.map (fun c -> c.ToString("X2")) |> Seq.reduce (+)
 
 
 
 
 
 
 
 |>
 
 
 
 pipeline , .
 
 : GetBytes -> -> HEX -> ( reduce + ) -> .
 
 
 
 , C#using System; public string CreateMD5Hash (string input) { MD5 md5 = System.Security.Cryptography.MD5.Create(); byte[] inputBytes = System.Text.Encoding.ASCII.GetBytes (input); byte[] hashBytes = md5.ComputeHash (inputBytes); StringBuilder sb = new StringBuilder(); for (int i = 0; i < hashBytes.Length; i++) { sb.Append (hashBytes[i].ToString ("X2")); } return sb.ToString(); }
 
 
 
 
 
 
 
 
 
 : . AzureServiceWorker ( CLR )
 
 
 
 - . F# ! Xamarin Studio .
 
 <ItemGroup> <Compile Include="Resources\Resource.designer.fs" /> <Compile Include="Properties\AssemblyInfo.fs" /> <Compile Include="Helpers\Helpers.fs" /> <Compile Include="Services\User.fs" /> <Compile Include="Services\AzureServiceWorker.fs" /> <Compile Include="IAmHereActivity.fs" /> <Compile Include="WhereAreYouActivity.fs" /> <Compile Include="SignInActivity.fs" /> </ItemGroup>
 
 
 
 
 
 
 
 
 
 : . Xamarin Xamarin.Mobile
 
 
 
 . F# TPL, Task', . F# Task. , :
 
 module Async = open System.Threading open System.Threading.Tasks let inline AwaitPlainTask (task: Task) = // rethrow exception from preceding task if it fauled let continuation (t : Task) : unit = match t.IsFaulted with | true -> raise t.Exception | arg -> () task.ContinueWith continuation |> Async.AwaitTask
 
 
 
 
 
 Async.AwaitIAsyncResult >> Async.Ignore
 
 
 
 
 
 
 
 
 
 let ExtractUserInfo (x : Contact) = let first = x.Phones |> Seq.tryPick(fun x -> if x.Type = PhoneType.Mobile then Some(x) else None) match first with | Some(first) -> let phone = first.Number |> StripChars [' ';'-';'(';')'] UserInfo.CreateUserInfo((MD5Hash phone), phone, x.DisplayName) | None -> UserInfo.CreateUserInfo("no mobile phone", "no mobile phone", "no mobile phone") // function for async list filling let FillContactsAsync = async { let book = new AddressBook (this) let! result = book.RequestPermission() |> Async.AwaitTask if result then _contacts <- book.ToList() |> Seq.filter (fun (x: Contact) -> not (Seq.isEmpty x.Phones)) |> Seq.map ExtractUserInfo |> Seq.sortBy(fun x -> x.DisplayName) |> Seq.toList let finalContacts = _contacts |> Seq.map (fun x -> x.DisplayName.ToUpperInvariant()) |> Seq.toArray this.ListAdapter <- new ArrayAdapter(this, Resource_Layout.row_contact, finalContacts) else System.Diagnostics.Debug.WriteLine("Permission denied by user or manifest") this.ListAdapter <- new ArrayAdapter(this, Resource_Layout.row_contact, Array.empty) }
 
 
 
 
 
 
 
 book.ToList()
 
 
 
 List|> Seq.filter (fun (x: Contact) -> not (Seq.isEmpty x.Phones))
 
 
 
 |> Seq.map ExtractUserInfo
 
 
 
 Contracts UserInfo, UserInfo|> Seq.sortBy(fun x -> x.DisplayName)
 
 
 
 |> Seq.toList
 
 
 
 List_contacts <-
 
 
 
 mutable_contacts |> Seq.map (fun x -> x.DisplayName.ToUpperInvariant())<-
 
 
 
 UserInfo string, - -|> Seq.toArray<-
 
 
 
 List Array ArrayAdapter
 
 - List. .
 
 
 
   
 
 
 
 Azure Mobile Servcies
 
 - Azure Mobile Services. NotificationHub, Push . Azure , .. .
 
 
 
 ,
 
 module WruConstants = [<Literal>] let TotallyNotAzureServer = "https://YOUR.azure-mobile.net/"; [<Literal>] let TotallyNotAzureKey = "YOUR"
 
 
 
 
 
 
 
 
 
 member this.RegisterMe phone name regId = async { try let table = this.MobileService.GetTable<User>() let usr = { Id = "" PhoneHash = MD5Hash phone Nickname = name RegistrationId = regId } do! table.InsertAsync usr |> Async.AwaitPlainTask return (usr.Id, usr.PhoneHash, usr.Nickname) with | e -> System.Diagnostics.Trace.WriteLine(e.ToString) return (String.Empty,String.Empty,String.Empty) }
 
 
 
 
 
 member this.RegisterMe phone name regId = async {
 
 
 
 - ( ) . "computation expression" workflow. { } ! ( bang), do! (do-bang) let! (let bang) User. , F# ,
 
 let usr = { Id = "" PhoneHash = MD5Hash phone Nickname = name RegistrationId = regId }
 
 
 
 do! table.InsertAsync usr |> Async.AwaitPlainTask
 
 
 
 do-bang,await
 
 
 
 C#. .. continuation .return (usr.Id, usr.PhoneHash, usr.Nickname)
 
 
 
 Tuple<string,string,string> .try ... with | e ->
 
 
 
 try..catch
 
 
 
 C#
 
 
 
   
 
 
 
 . F#fst
 
 
 
 snd
 
 
 
 . 2 . :
 
 let id (c,_,_) = c let phonehash (_,c,_) = c let nickname (_,_,c) = c
 
 
 
 
 
 :id tuple
 
 
 
 Id ..
 
 
 
 5 Azure, Push . Azure Custom Api
 
 
 
 exports.post = function(request, response) { // Use "request.service" to access features of your mobile service, eg: // var tables = request.service.tables; // var push = request.service.push; //response.send(statusCodes.OK, { message : 'Hello World!' }); console.log('Incoming call with requst: ', request.body.RequestId); var usersTable = request.service.tables.getTable('User'); usersTable.where( { id : request.body.TargetId } ) .read( { success: function(results) { if (results.length > 0) { var user = results[0] console.log('Send to results: ', user.Nickname, user.RegistrationId); request.service.push.gcm.send(user.RegistrationId, { RequesterId: request.body.RequesterId, RequesterNickname: request.body.RequesterName, TargetId: user.id, TargetNickname: user.Nickname }, { success: function(gcm_response) { console.log('Push notification sent: ', gcm_response); response.send(statusCodes.OK, { RequestedNickname : user.Nickname }); }, error: function(gcm_error) { console.log('Error sending push notification: ', gcm_error); response.send(statusCodes.INTERNAL_SERVER_ERROR, { RequestedNickname : user.Nickname }); } }); } else { response.send(statusCodes.NO_CONTENT, { RequestedNickname : "" }); } }, error: function(error) { console.log('Error read table: ', error); response.send(statusCodes.INTERNAL_SERVER_ERROR, { RequestedNickname : "" }); } }); };
 
 
 
 
 
 
 
 Push
 
 // Perform Push operation member this.PushAsync targetId myId myNickname = async { try let (request : PushRequest) = { TargetId = targetId RequesterId = myId RequesterName = myNickname } let! result = this.MobileService.InvokeApiAsync<PushRequest, PushResponce>("pushhim", request) |> Async.AwaitTask return result.RequestedNickname with | e -> return e.ToString() }
 
 
 
 
 
 
 
 ,let-bang
 
 
 
 do!
 
 
 
 
 
 
 
 
 
 
 
   
 
 Google Play Services. F# . . : Xamarin.Android.Support.v7.AppCompat
 
 , Google Play Services , .
 
 
 
 push notification . GCM, ID, ID Push (. pushhim). BroadcastReciever developer.android.com . F# Xamarin Component Store. Google Cloud Messaging Client GCM . ID
 
 //Check to see that GCM is supported and that the manifest has the correct information GcmClient.CheckDevice(this) GcmClient.CheckManifest(this) // check google play if CheckPlayServices() then // Try to get registration id let regId = GcmClient.GetRegistrationId this if String.IsNullOrEmpty(regId) then // Call to Register the device for Push Notifications GcmClient.Register(this, WruConstants.GcmSender);
 
 
 
 
 
 
 
   
 
 
 
 
 
 .
 
 , -
 
 bitbucket.org/xakpc/whereareyou
 
 ,
 
 , "" .
 
 
 
 
 
 , Android F#. .
 
 , - Android F#. , .
 
 
 
 
 
 
 
 
-  listView.Adapter <- new ArrayAdapter(this, Android.Resource.Layout.SimpleListItem1, Android.Resource.Id.Text1, values)
 
 , , let values = [|"item1"; "item2"; "item3"|]
 
 
 
 - string[], list (IEnumerable )
 
 F#. www.tryfsharp.org/Learn
 
   
 
 F# - ,
 
 
 
 F# For Fun And Profit
 
 
 
 ,
 
 - .
 
 
 
   
 
 
 
 hash
 
 MD5 F#
 
 let MD5Hash (input : string) = use md5 = System.Security.Cryptography.MD5.Create() input |> System.Text.Encoding.ASCII.GetBytes |> md5.ComputeHash |> Seq.map (fun c -> c.ToString("X2")) |> Seq.reduce (+)
 
 
 
 
 
 
 
 |>
 
 
 
 pipeline , .
 
 : GetBytes -> -> HEX -> ( reduce + ) -> .
 
 
 
 , C#using System; public string CreateMD5Hash (string input) { MD5 md5 = System.Security.Cryptography.MD5.Create(); byte[] inputBytes = System.Text.Encoding.ASCII.GetBytes (input); byte[] hashBytes = md5.ComputeHash (inputBytes); StringBuilder sb = new StringBuilder(); for (int i = 0; i < hashBytes.Length; i++) { sb.Append (hashBytes[i].ToString ("X2")); } return sb.ToString(); }
 
 
 
 
 
 
 
 
 
 : . AzureServiceWorker ( CLR )
 
 
 
 - . F# ! Xamarin Studio .
 
 <ItemGroup> <Compile Include="Resources\Resource.designer.fs" /> <Compile Include="Properties\AssemblyInfo.fs" /> <Compile Include="Helpers\Helpers.fs" /> <Compile Include="Services\User.fs" /> <Compile Include="Services\AzureServiceWorker.fs" /> <Compile Include="IAmHereActivity.fs" /> <Compile Include="WhereAreYouActivity.fs" /> <Compile Include="SignInActivity.fs" /> </ItemGroup>
 
 
 
 
 
 
 
 
 
 : . Xamarin Xamarin.Mobile
 
 
 
 . F# TPL, Task', . F# Task. , :
 
 module Async = open System.Threading open System.Threading.Tasks let inline AwaitPlainTask (task: Task) = // rethrow exception from preceding task if it fauled let continuation (t : Task) : unit = match t.IsFaulted with | true -> raise t.Exception | arg -> () task.ContinueWith continuation |> Async.AwaitTask
 
 
 
 
 
 Async.AwaitIAsyncResult >> Async.Ignore
 
 
 
 
 
 
 
 
 
 let ExtractUserInfo (x : Contact) = let first = x.Phones |> Seq.tryPick(fun x -> if x.Type = PhoneType.Mobile then Some(x) else None) match first with | Some(first) -> let phone = first.Number |> StripChars [' ';'-';'(';')'] UserInfo.CreateUserInfo((MD5Hash phone), phone, x.DisplayName) | None -> UserInfo.CreateUserInfo("no mobile phone", "no mobile phone", "no mobile phone") // function for async list filling let FillContactsAsync = async { let book = new AddressBook (this) let! result = book.RequestPermission() |> Async.AwaitTask if result then _contacts <- book.ToList() |> Seq.filter (fun (x: Contact) -> not (Seq.isEmpty x.Phones)) |> Seq.map ExtractUserInfo |> Seq.sortBy(fun x -> x.DisplayName) |> Seq.toList let finalContacts = _contacts |> Seq.map (fun x -> x.DisplayName.ToUpperInvariant()) |> Seq.toArray this.ListAdapter <- new ArrayAdapter(this, Resource_Layout.row_contact, finalContacts) else System.Diagnostics.Debug.WriteLine("Permission denied by user or manifest") this.ListAdapter <- new ArrayAdapter(this, Resource_Layout.row_contact, Array.empty) }
 
 
 
 
 
 
 
 book.ToList()
 
 
 
 List|> Seq.filter (fun (x: Contact) -> not (Seq.isEmpty x.Phones))
 
 
 
 |> Seq.map ExtractUserInfo
 
 
 
 Contracts UserInfo, UserInfo|> Seq.sortBy(fun x -> x.DisplayName)
 
 
 
 |> Seq.toList
 
 
 
 List_contacts <-
 
 
 
 mutable_contacts |> Seq.map (fun x -> x.DisplayName.ToUpperInvariant())<-
 
 
 
 UserInfo string, - -|> Seq.toArray<-
 
 
 
 List Array ArrayAdapter
 
 - List. .
 
 
 
   
 
 
 
 Azure Mobile Servcies
 
 - Azure Mobile Services. NotificationHub, Push . Azure , .. .
 
 
 
 ,
 
 module WruConstants = [<Literal>] let TotallyNotAzureServer = "https://YOUR.azure-mobile.net/"; [<Literal>] let TotallyNotAzureKey = "YOUR"
 
 
 
 
 
 
 
 
 
 member this.RegisterMe phone name regId = async { try let table = this.MobileService.GetTable<User>() let usr = { Id = "" PhoneHash = MD5Hash phone Nickname = name RegistrationId = regId } do! table.InsertAsync usr |> Async.AwaitPlainTask return (usr.Id, usr.PhoneHash, usr.Nickname) with | e -> System.Diagnostics.Trace.WriteLine(e.ToString) return (String.Empty,String.Empty,String.Empty) }
 
 
 
 
 
 member this.RegisterMe phone name regId = async {
 
 
 
 - ( ) . "computation expression" workflow. { } ! ( bang), do! (do-bang) let! (let bang) User. , F# ,
 
 let usr = { Id = "" PhoneHash = MD5Hash phone Nickname = name RegistrationId = regId }
 
 
 
 do! table.InsertAsync usr |> Async.AwaitPlainTask
 
 
 
 do-bang,await
 
 
 
 C#. .. continuation .return (usr.Id, usr.PhoneHash, usr.Nickname)
 
 
 
 Tuple<string,string,string> .try ... with | e ->
 
 
 
 try..catch
 
 
 
 C#
 
 
 
   
 
 
 
 . F#fst
 
 
 
 snd
 
 
 
 . 2 . :
 
 let id (c,_,_) = c let phonehash (_,c,_) = c let nickname (_,_,c) = c
 
 
 
 
 
 :id tuple
 
 
 
 Id ..
 
 
 
 5 Azure, Push . Azure Custom Api
 
 
 
 exports.post = function(request, response) { // Use "request.service" to access features of your mobile service, eg: // var tables = request.service.tables; // var push = request.service.push; //response.send(statusCodes.OK, { message : 'Hello World!' }); console.log('Incoming call with requst: ', request.body.RequestId); var usersTable = request.service.tables.getTable('User'); usersTable.where( { id : request.body.TargetId } ) .read( { success: function(results) { if (results.length > 0) { var user = results[0] console.log('Send to results: ', user.Nickname, user.RegistrationId); request.service.push.gcm.send(user.RegistrationId, { RequesterId: request.body.RequesterId, RequesterNickname: request.body.RequesterName, TargetId: user.id, TargetNickname: user.Nickname }, { success: function(gcm_response) { console.log('Push notification sent: ', gcm_response); response.send(statusCodes.OK, { RequestedNickname : user.Nickname }); }, error: function(gcm_error) { console.log('Error sending push notification: ', gcm_error); response.send(statusCodes.INTERNAL_SERVER_ERROR, { RequestedNickname : user.Nickname }); } }); } else { response.send(statusCodes.NO_CONTENT, { RequestedNickname : "" }); } }, error: function(error) { console.log('Error read table: ', error); response.send(statusCodes.INTERNAL_SERVER_ERROR, { RequestedNickname : "" }); } }); };
 
 
 
 
 
 
 
 Push
 
 // Perform Push operation member this.PushAsync targetId myId myNickname = async { try let (request : PushRequest) = { TargetId = targetId RequesterId = myId RequesterName = myNickname } let! result = this.MobileService.InvokeApiAsync<PushRequest, PushResponce>("pushhim", request) |> Async.AwaitTask return result.RequestedNickname with | e -> return e.ToString() }
 
 
 
 
 
 
 
 ,let-bang
 
 
 
 do!
 
 
 
 
 
 
 
 
 
 
 
   
 
 Google Play Services. F# . . : Xamarin.Android.Support.v7.AppCompat
 
 , Google Play Services , .
 
 
 
 push notification . GCM, ID, ID Push (. pushhim). BroadcastReciever developer.android.com . F# Xamarin Component Store. Google Cloud Messaging Client GCM . ID
 
 //Check to see that GCM is supported and that the manifest has the correct information GcmClient.CheckDevice(this) GcmClient.CheckManifest(this) // check google play if CheckPlayServices() then // Try to get registration id let regId = GcmClient.GetRegistrationId this if String.IsNullOrEmpty(regId) then // Call to Register the device for Push Notifications GcmClient.Register(this, WruConstants.GcmSender);
 
 
 
 
 
 
 
   
 
 
 
 
 
 .
 
 , -
 
 bitbucket.org/xakpc/whereareyou
 
 ,
 
 , "" .
 
 
 
 
 
 , Android F#. .
 
 , - Android F#. , .
 
 
 
 
 
 
 
 
-  listView.Adapter <- new ArrayAdapter(this, Android.Resource.Layout.SimpleListItem1, Android.Resource.Id.Text1, values)
 
 , , let values = [|"item1"; "item2"; "item3"|]
 
 
 
 - string[], list (IEnumerable )
 
 F#. www.tryfsharp.org/Learn
 
   
 
 F# - ,
 
 
 
 F# For Fun And Profit
 
 
 
 ,
 
 - .
 
 
 
   
 
 
 
 hash
 
 MD5 F#
 
 let MD5Hash (input : string) = use md5 = System.Security.Cryptography.MD5.Create() input |> System.Text.Encoding.ASCII.GetBytes |> md5.ComputeHash |> Seq.map (fun c -> c.ToString("X2")) |> Seq.reduce (+)
 
 
 
 
 
 
 
 |>
 
 
 
 pipeline , .
 
 : GetBytes -> -> HEX -> ( reduce + ) -> .
 
 
 
 , C#using System; public string CreateMD5Hash (string input) { MD5 md5 = System.Security.Cryptography.MD5.Create(); byte[] inputBytes = System.Text.Encoding.ASCII.GetBytes (input); byte[] hashBytes = md5.ComputeHash (inputBytes); StringBuilder sb = new StringBuilder(); for (int i = 0; i < hashBytes.Length; i++) { sb.Append (hashBytes[i].ToString ("X2")); } return sb.ToString(); }
 
 
 
 
 
 
 
 
 
 : . AzureServiceWorker ( CLR )
 
 
 
 - . F# ! Xamarin Studio .
 
 <ItemGroup> <Compile Include="Resources\Resource.designer.fs" /> <Compile Include="Properties\AssemblyInfo.fs" /> <Compile Include="Helpers\Helpers.fs" /> <Compile Include="Services\User.fs" /> <Compile Include="Services\AzureServiceWorker.fs" /> <Compile Include="IAmHereActivity.fs" /> <Compile Include="WhereAreYouActivity.fs" /> <Compile Include="SignInActivity.fs" /> </ItemGroup>
 
 
 
 
 
 
 
 
 
 : . Xamarin Xamarin.Mobile
 
 
 
 . F# TPL, Task', . F# Task. , :
 
 module Async = open System.Threading open System.Threading.Tasks let inline AwaitPlainTask (task: Task) = // rethrow exception from preceding task if it fauled let continuation (t : Task) : unit = match t.IsFaulted with | true -> raise t.Exception | arg -> () task.ContinueWith continuation |> Async.AwaitTask
 
 
 
 
 
 Async.AwaitIAsyncResult >> Async.Ignore
 
 
 
 
 
 
 
 
 
 let ExtractUserInfo (x : Contact) = let first = x.Phones |> Seq.tryPick(fun x -> if x.Type = PhoneType.Mobile then Some(x) else None) match first with | Some(first) -> let phone = first.Number |> StripChars [' ';'-';'(';')'] UserInfo.CreateUserInfo((MD5Hash phone), phone, x.DisplayName) | None -> UserInfo.CreateUserInfo("no mobile phone", "no mobile phone", "no mobile phone") // function for async list filling let FillContactsAsync = async { let book = new AddressBook (this) let! result = book.RequestPermission() |> Async.AwaitTask if result then _contacts <- book.ToList() |> Seq.filter (fun (x: Contact) -> not (Seq.isEmpty x.Phones)) |> Seq.map ExtractUserInfo |> Seq.sortBy(fun x -> x.DisplayName) |> Seq.toList let finalContacts = _contacts |> Seq.map (fun x -> x.DisplayName.ToUpperInvariant()) |> Seq.toArray this.ListAdapter <- new ArrayAdapter(this, Resource_Layout.row_contact, finalContacts) else System.Diagnostics.Debug.WriteLine("Permission denied by user or manifest") this.ListAdapter <- new ArrayAdapter(this, Resource_Layout.row_contact, Array.empty) }
 
 
 
 
 
 
 
 book.ToList()
 
 
 
 List|> Seq.filter (fun (x: Contact) -> not (Seq.isEmpty x.Phones))
 
 
 
 |> Seq.map ExtractUserInfo
 
 
 
 Contracts UserInfo, UserInfo|> Seq.sortBy(fun x -> x.DisplayName)
 
 
 
 |> Seq.toList
 
 
 
 List_contacts <-
 
 
 
 mutable_contacts |> Seq.map (fun x -> x.DisplayName.ToUpperInvariant())<-
 
 
 
 UserInfo string, - -|> Seq.toArray<-
 
 
 
 List Array ArrayAdapter
 
 - List. .
 
 
 
   
 
 
 
 Azure Mobile Servcies
 
 - Azure Mobile Services. NotificationHub, Push . Azure , .. .
 
 
 
 ,
 
 module WruConstants = [<Literal>] let TotallyNotAzureServer = "https://YOUR.azure-mobile.net/"; [<Literal>] let TotallyNotAzureKey = "YOUR"
 
 
 
 
 
 
 
 
 
 member this.RegisterMe phone name regId = async { try let table = this.MobileService.GetTable<User>() let usr = { Id = "" PhoneHash = MD5Hash phone Nickname = name RegistrationId = regId } do! table.InsertAsync usr |> Async.AwaitPlainTask return (usr.Id, usr.PhoneHash, usr.Nickname) with | e -> System.Diagnostics.Trace.WriteLine(e.ToString) return (String.Empty,String.Empty,String.Empty) }
 
 
 
 
 
 member this.RegisterMe phone name regId = async {
 
 
 
 - ( ) . "computation expression" workflow. { } ! ( bang), do! (do-bang) let! (let bang) User. , F# ,
 
 let usr = { Id = "" PhoneHash = MD5Hash phone Nickname = name RegistrationId = regId }
 
 
 
 do! table.InsertAsync usr |> Async.AwaitPlainTask
 
 
 
 do-bang,await
 
 
 
 C#. .. continuation .return (usr.Id, usr.PhoneHash, usr.Nickname)
 
 
 
 Tuple<string,string,string> .try ... with | e ->
 
 
 
 try..catch
 
 
 
 C#
 
 
 
   
 
 
 
 . F#fst
 
 
 
 snd
 
 
 
 . 2 . :
 
 let id (c,_,_) = c let phonehash (_,c,_) = c let nickname (_,_,c) = c
 
 
 
 
 
 :id tuple
 
 
 
 Id ..
 
 
 
 5 Azure, Push . Azure Custom Api
 
 
 
 exports.post = function(request, response) { // Use "request.service" to access features of your mobile service, eg: // var tables = request.service.tables; // var push = request.service.push; //response.send(statusCodes.OK, { message : 'Hello World!' }); console.log('Incoming call with requst: ', request.body.RequestId); var usersTable = request.service.tables.getTable('User'); usersTable.where( { id : request.body.TargetId } ) .read( { success: function(results) { if (results.length > 0) { var user = results[0] console.log('Send to results: ', user.Nickname, user.RegistrationId); request.service.push.gcm.send(user.RegistrationId, { RequesterId: request.body.RequesterId, RequesterNickname: request.body.RequesterName, TargetId: user.id, TargetNickname: user.Nickname }, { success: function(gcm_response) { console.log('Push notification sent: ', gcm_response); response.send(statusCodes.OK, { RequestedNickname : user.Nickname }); }, error: function(gcm_error) { console.log('Error sending push notification: ', gcm_error); response.send(statusCodes.INTERNAL_SERVER_ERROR, { RequestedNickname : user.Nickname }); } }); } else { response.send(statusCodes.NO_CONTENT, { RequestedNickname : "" }); } }, error: function(error) { console.log('Error read table: ', error); response.send(statusCodes.INTERNAL_SERVER_ERROR, { RequestedNickname : "" }); } }); };
 
 
 
 
 
 
 
 Push
 
 // Perform Push operation member this.PushAsync targetId myId myNickname = async { try let (request : PushRequest) = { TargetId = targetId RequesterId = myId RequesterName = myNickname } let! result = this.MobileService.InvokeApiAsync<PushRequest, PushResponce>("pushhim", request) |> Async.AwaitTask return result.RequestedNickname with | e -> return e.ToString() }
 
 
 
 
 
 
 
 ,let-bang
 
 
 
 do!
 
 
 
 
 
 
 
 
 
 
 
   
 
 Google Play Services. F# . . : Xamarin.Android.Support.v7.AppCompat
 
 , Google Play Services , .
 
 
 
 push notification . GCM, ID, ID Push (. pushhim). BroadcastReciever developer.android.com . F# Xamarin Component Store. Google Cloud Messaging Client GCM . ID
 
 //Check to see that GCM is supported and that the manifest has the correct information GcmClient.CheckDevice(this) GcmClient.CheckManifest(this) // check google play if CheckPlayServices() then // Try to get registration id let regId = GcmClient.GetRegistrationId this if String.IsNullOrEmpty(regId) then // Call to Register the device for Push Notifications GcmClient.Register(this, WruConstants.GcmSender);
 
 
 
 
 
 
 
   
 
 
 
 
 
 .
 
 , -
 
 bitbucket.org/xakpc/whereareyou
 
 ,
 
 , "" .
 
 
 
 
 
 , Android F#. .
 
 , - Android F#. , .
 
 
 
 
 
 
 
 
-  listView.Adapter <- new ArrayAdapter(this, Android.Resource.Layout.SimpleListItem1, Android.Resource.Id.Text1, values)
 
 , , let values = [|"item1"; "item2"; "item3"|]
 
 
 
 - string[], list (IEnumerable )
 
 F#. www.tryfsharp.org/Learn
 
   
 
 F# - ,
 
 
 
 F# For Fun And Profit
 
 
 
 ,
 
 - .
 
 
 
   
 
 
 
 hash
 
 MD5 F#
 
 let MD5Hash (input : string) = use md5 = System.Security.Cryptography.MD5.Create() input |> System.Text.Encoding.ASCII.GetBytes |> md5.ComputeHash |> Seq.map (fun c -> c.ToString("X2")) |> Seq.reduce (+)
 
 
 
 
 
 
 
 |>
 
 
 
 pipeline , .
 
 : GetBytes -> -> HEX -> ( reduce + ) -> .
 
 
 
 , C#using System; public string CreateMD5Hash (string input) { MD5 md5 = System.Security.Cryptography.MD5.Create(); byte[] inputBytes = System.Text.Encoding.ASCII.GetBytes (input); byte[] hashBytes = md5.ComputeHash (inputBytes); StringBuilder sb = new StringBuilder(); for (int i = 0; i < hashBytes.Length; i++) { sb.Append (hashBytes[i].ToString ("X2")); } return sb.ToString(); }
 
 
 
 
 
 
 
 
 
 : . AzureServiceWorker ( CLR )
 
 
 
 - . F# ! Xamarin Studio .
 
 <ItemGroup> <Compile Include="Resources\Resource.designer.fs" /> <Compile Include="Properties\AssemblyInfo.fs" /> <Compile Include="Helpers\Helpers.fs" /> <Compile Include="Services\User.fs" /> <Compile Include="Services\AzureServiceWorker.fs" /> <Compile Include="IAmHereActivity.fs" /> <Compile Include="WhereAreYouActivity.fs" /> <Compile Include="SignInActivity.fs" /> </ItemGroup>
 
 
 
 
 
 
 
 
 
 : . Xamarin Xamarin.Mobile
 
 
 
 . F# TPL, Task', . F# Task. , :
 
 module Async = open System.Threading open System.Threading.Tasks let inline AwaitPlainTask (task: Task) = // rethrow exception from preceding task if it fauled let continuation (t : Task) : unit = match t.IsFaulted with | true -> raise t.Exception | arg -> () task.ContinueWith continuation |> Async.AwaitTask
 
 
 
 
 
 Async.AwaitIAsyncResult >> Async.Ignore
 
 
 
 
 
 
 
 
 
 let ExtractUserInfo (x : Contact) = let first = x.Phones |> Seq.tryPick(fun x -> if x.Type = PhoneType.Mobile then Some(x) else None) match first with | Some(first) -> let phone = first.Number |> StripChars [' ';'-';'(';')'] UserInfo.CreateUserInfo((MD5Hash phone), phone, x.DisplayName) | None -> UserInfo.CreateUserInfo("no mobile phone", "no mobile phone", "no mobile phone") // function for async list filling let FillContactsAsync = async { let book = new AddressBook (this) let! result = book.RequestPermission() |> Async.AwaitTask if result then _contacts <- book.ToList() |> Seq.filter (fun (x: Contact) -> not (Seq.isEmpty x.Phones)) |> Seq.map ExtractUserInfo |> Seq.sortBy(fun x -> x.DisplayName) |> Seq.toList let finalContacts = _contacts |> Seq.map (fun x -> x.DisplayName.ToUpperInvariant()) |> Seq.toArray this.ListAdapter <- new ArrayAdapter(this, Resource_Layout.row_contact, finalContacts) else System.Diagnostics.Debug.WriteLine("Permission denied by user or manifest") this.ListAdapter <- new ArrayAdapter(this, Resource_Layout.row_contact, Array.empty) }
 
 
 
 
 
 
 
 book.ToList()
 
 
 
 List|> Seq.filter (fun (x: Contact) -> not (Seq.isEmpty x.Phones))
 
 
 
 |> Seq.map ExtractUserInfo
 
 
 
 Contracts UserInfo, UserInfo|> Seq.sortBy(fun x -> x.DisplayName)
 
 
 
 |> Seq.toList
 
 
 
 List_contacts <-
 
 
 
 mutable_contacts |> Seq.map (fun x -> x.DisplayName.ToUpperInvariant())<-
 
 
 
 UserInfo string, - -|> Seq.toArray<-
 
 
 
 List Array ArrayAdapter
 
 - List. .
 
 
 
   
 
 
 
 Azure Mobile Servcies
 
 - Azure Mobile Services. NotificationHub, Push . Azure , .. .
 
 
 
 ,
 
 module WruConstants = [<Literal>] let TotallyNotAzureServer = "https://YOUR.azure-mobile.net/"; [<Literal>] let TotallyNotAzureKey = "YOUR"
 
 
 
 
 
 
 
 
 
 member this.RegisterMe phone name regId = async { try let table = this.MobileService.GetTable<User>() let usr = { Id = "" PhoneHash = MD5Hash phone Nickname = name RegistrationId = regId } do! table.InsertAsync usr |> Async.AwaitPlainTask return (usr.Id, usr.PhoneHash, usr.Nickname) with | e -> System.Diagnostics.Trace.WriteLine(e.ToString) return (String.Empty,String.Empty,String.Empty) }
 
 
 
 
 
 member this.RegisterMe phone name regId = async {
 
 
 
 - ( ) . "computation expression" workflow. { } ! ( bang), do! (do-bang) let! (let bang) User. , F# ,
 
 let usr = { Id = "" PhoneHash = MD5Hash phone Nickname = name RegistrationId = regId }
 
 
 
 do! table.InsertAsync usr |> Async.AwaitPlainTask
 
 
 
 do-bang,await
 
 
 
 C#. .. continuation .return (usr.Id, usr.PhoneHash, usr.Nickname)
 
 
 
 Tuple<string,string,string> .try ... with | e ->
 
 
 
 try..catch
 
 
 
 C#
 
 
 
   
 
 
 
 . F#fst
 
 
 
 snd
 
 
 
 . 2 . :
 
 let id (c,_,_) = c let phonehash (_,c,_) = c let nickname (_,_,c) = c
 
 
 
 
 
 :id tuple
 
 
 
 Id ..
 
 
 
 5 Azure, Push . Azure Custom Api
 
 
 
 exports.post = function(request, response) { // Use "request.service" to access features of your mobile service, eg: // var tables = request.service.tables; // var push = request.service.push; //response.send(statusCodes.OK, { message : 'Hello World!' }); console.log('Incoming call with requst: ', request.body.RequestId); var usersTable = request.service.tables.getTable('User'); usersTable.where( { id : request.body.TargetId } ) .read( { success: function(results) { if (results.length > 0) { var user = results[0] console.log('Send to results: ', user.Nickname, user.RegistrationId); request.service.push.gcm.send(user.RegistrationId, { RequesterId: request.body.RequesterId, RequesterNickname: request.body.RequesterName, TargetId: user.id, TargetNickname: user.Nickname }, { success: function(gcm_response) { console.log('Push notification sent: ', gcm_response); response.send(statusCodes.OK, { RequestedNickname : user.Nickname }); }, error: function(gcm_error) { console.log('Error sending push notification: ', gcm_error); response.send(statusCodes.INTERNAL_SERVER_ERROR, { RequestedNickname : user.Nickname }); } }); } else { response.send(statusCodes.NO_CONTENT, { RequestedNickname : "" }); } }, error: function(error) { console.log('Error read table: ', error); response.send(statusCodes.INTERNAL_SERVER_ERROR, { RequestedNickname : "" }); } }); };
 
 
 
 
 
 
 
 Push
 
 // Perform Push operation member this.PushAsync targetId myId myNickname = async { try let (request : PushRequest) = { TargetId = targetId RequesterId = myId RequesterName = myNickname } let! result = this.MobileService.InvokeApiAsync<PushRequest, PushResponce>("pushhim", request) |> Async.AwaitTask return result.RequestedNickname with | e -> return e.ToString() }
 
 
 
 
 
 
 
 ,let-bang
 
 
 
 do!
 
 
 
 
 
 
 
 
 
 
 
   
 
 Google Play Services. F# . . : Xamarin.Android.Support.v7.AppCompat
 
 , Google Play Services , .
 
 
 
 push notification . GCM, ID, ID Push (. pushhim). BroadcastReciever developer.android.com . F# Xamarin Component Store. Google Cloud Messaging Client GCM . ID
 
 //Check to see that GCM is supported and that the manifest has the correct information GcmClient.CheckDevice(this) GcmClient.CheckManifest(this) // check google play if CheckPlayServices() then // Try to get registration id let regId = GcmClient.GetRegistrationId this if String.IsNullOrEmpty(regId) then // Call to Register the device for Push Notifications GcmClient.Register(this, WruConstants.GcmSender);
 
 
 
 
 
 
 
   
 
 
 
 
 
 .
 
 , -
 
 bitbucket.org/xakpc/whereareyou
 
 ,
 
 , "" .
 
 
 
 
 
 , Android F#. .
 
 , - Android F#. , .
 
 
 
 
 
 
 
 
-  listView.Adapter <- new ArrayAdapter(this, Android.Resource.Layout.SimpleListItem1, Android.Resource.Id.Text1, values)
 
 , , let values = [|"item1"; "item2"; "item3"|]
 
 
 
 - string[], list (IEnumerable )
 
 F#. www.tryfsharp.org/Learn
 
   
 
 F# - ,
 
 
 
 F# For Fun And Profit
 
 
 
 ,
 
 - .
 
 
 
   
 
 
 
 hash
 
 MD5 F#
 
 let MD5Hash (input : string) = use md5 = System.Security.Cryptography.MD5.Create() input |> System.Text.Encoding.ASCII.GetBytes |> md5.ComputeHash |> Seq.map (fun c -> c.ToString("X2")) |> Seq.reduce (+)
 
 
 
 
 
 
 
 |>
 
 
 
 pipeline , .
 
 : GetBytes -> -> HEX -> ( reduce + ) -> .
 
 
 
 , C#using System; public string CreateMD5Hash (string input) { MD5 md5 = System.Security.Cryptography.MD5.Create(); byte[] inputBytes = System.Text.Encoding.ASCII.GetBytes (input); byte[] hashBytes = md5.ComputeHash (inputBytes); StringBuilder sb = new StringBuilder(); for (int i = 0; i < hashBytes.Length; i++) { sb.Append (hashBytes[i].ToString ("X2")); } return sb.ToString(); }
 
 
 
 
 
 
 
 
 
 : . AzureServiceWorker ( CLR )
 
 
 
 - . F# ! Xamarin Studio .
 
 <ItemGroup> <Compile Include="Resources\Resource.designer.fs" /> <Compile Include="Properties\AssemblyInfo.fs" /> <Compile Include="Helpers\Helpers.fs" /> <Compile Include="Services\User.fs" /> <Compile Include="Services\AzureServiceWorker.fs" /> <Compile Include="IAmHereActivity.fs" /> <Compile Include="WhereAreYouActivity.fs" /> <Compile Include="SignInActivity.fs" /> </ItemGroup>
 
 
 
 
 
 
 
 
 
 : . Xamarin Xamarin.Mobile
 
 
 
 . F# TPL, Task', . F# Task. , :
 
 module Async = open System.Threading open System.Threading.Tasks let inline AwaitPlainTask (task: Task) = // rethrow exception from preceding task if it fauled let continuation (t : Task) : unit = match t.IsFaulted with | true -> raise t.Exception | arg -> () task.ContinueWith continuation |> Async.AwaitTask
 
 
 
 
 
 Async.AwaitIAsyncResult >> Async.Ignore
 
 
 
 
 
 
 
 
 
 let ExtractUserInfo (x : Contact) = let first = x.Phones |> Seq.tryPick(fun x -> if x.Type = PhoneType.Mobile then Some(x) else None) match first with | Some(first) -> let phone = first.Number |> StripChars [' ';'-';'(';')'] UserInfo.CreateUserInfo((MD5Hash phone), phone, x.DisplayName) | None -> UserInfo.CreateUserInfo("no mobile phone", "no mobile phone", "no mobile phone") // function for async list filling let FillContactsAsync = async { let book = new AddressBook (this) let! result = book.RequestPermission() |> Async.AwaitTask if result then _contacts <- book.ToList() |> Seq.filter (fun (x: Contact) -> not (Seq.isEmpty x.Phones)) |> Seq.map ExtractUserInfo |> Seq.sortBy(fun x -> x.DisplayName) |> Seq.toList let finalContacts = _contacts |> Seq.map (fun x -> x.DisplayName.ToUpperInvariant()) |> Seq.toArray this.ListAdapter <- new ArrayAdapter(this, Resource_Layout.row_contact, finalContacts) else System.Diagnostics.Debug.WriteLine("Permission denied by user or manifest") this.ListAdapter <- new ArrayAdapter(this, Resource_Layout.row_contact, Array.empty) }
 
 
 
 
 
 
 
 book.ToList()
 
 
 
 List|> Seq.filter (fun (x: Contact) -> not (Seq.isEmpty x.Phones))
 
 
 
 |> Seq.map ExtractUserInfo
 
 
 
 Contracts UserInfo, UserInfo|> Seq.sortBy(fun x -> x.DisplayName)
 
 
 
 |> Seq.toList
 
 
 
 List_contacts <-
 
 
 
 mutable_contacts |> Seq.map (fun x -> x.DisplayName.ToUpperInvariant())<-
 
 
 
 UserInfo string, - -|> Seq.toArray<-
 
 
 
 List Array ArrayAdapter
 
 - List. .
 
 
 
   
 
 
 
 Azure Mobile Servcies
 
 - Azure Mobile Services. NotificationHub, Push . Azure , .. .
 
 
 
 ,
 
 module WruConstants = [<Literal>] let TotallyNotAzureServer = "https://YOUR.azure-mobile.net/"; [<Literal>] let TotallyNotAzureKey = "YOUR"
 
 
 
 
 
 
 
 
 
 member this.RegisterMe phone name regId = async { try let table = this.MobileService.GetTable<User>() let usr = { Id = "" PhoneHash = MD5Hash phone Nickname = name RegistrationId = regId } do! table.InsertAsync usr |> Async.AwaitPlainTask return (usr.Id, usr.PhoneHash, usr.Nickname) with | e -> System.Diagnostics.Trace.WriteLine(e.ToString) return (String.Empty,String.Empty,String.Empty) }
 
 
 
 
 
 member this.RegisterMe phone name regId = async {
 
 
 
 - ( ) . "computation expression" workflow. { } ! ( bang), do! (do-bang) let! (let bang) User. , F# ,
 
 let usr = { Id = "" PhoneHash = MD5Hash phone Nickname = name RegistrationId = regId }
 
 
 
 do! table.InsertAsync usr |> Async.AwaitPlainTask
 
 
 
 do-bang,await
 
 
 
 C#. .. continuation .return (usr.Id, usr.PhoneHash, usr.Nickname)
 
 
 
 Tuple<string,string,string> .try ... with | e ->
 
 
 
 try..catch
 
 
 
 C#
 
 
 
   
 
 
 
 . F#fst
 
 
 
 snd
 
 
 
 . 2 . :
 
 let id (c,_,_) = c let phonehash (_,c,_) = c let nickname (_,_,c) = c
 
 
 
 
 
 :id tuple
 
 
 
 Id ..
 
 
 
 5 Azure, Push . Azure Custom Api
 
 
 
 exports.post = function(request, response) { // Use "request.service" to access features of your mobile service, eg: // var tables = request.service.tables; // var push = request.service.push; //response.send(statusCodes.OK, { message : 'Hello World!' }); console.log('Incoming call with requst: ', request.body.RequestId); var usersTable = request.service.tables.getTable('User'); usersTable.where( { id : request.body.TargetId } ) .read( { success: function(results) { if (results.length > 0) { var user = results[0] console.log('Send to results: ', user.Nickname, user.RegistrationId); request.service.push.gcm.send(user.RegistrationId, { RequesterId: request.body.RequesterId, RequesterNickname: request.body.RequesterName, TargetId: user.id, TargetNickname: user.Nickname }, { success: function(gcm_response) { console.log('Push notification sent: ', gcm_response); response.send(statusCodes.OK, { RequestedNickname : user.Nickname }); }, error: function(gcm_error) { console.log('Error sending push notification: ', gcm_error); response.send(statusCodes.INTERNAL_SERVER_ERROR, { RequestedNickname : user.Nickname }); } }); } else { response.send(statusCodes.NO_CONTENT, { RequestedNickname : "" }); } }, error: function(error) { console.log('Error read table: ', error); response.send(statusCodes.INTERNAL_SERVER_ERROR, { RequestedNickname : "" }); } }); };
 
 
 
 
 
 
 
 Push
 
 // Perform Push operation member this.PushAsync targetId myId myNickname = async { try let (request : PushRequest) = { TargetId = targetId RequesterId = myId RequesterName = myNickname } let! result = this.MobileService.InvokeApiAsync<PushRequest, PushResponce>("pushhim", request) |> Async.AwaitTask return result.RequestedNickname with | e -> return e.ToString() }
 
 
 
 
 
 
 
 ,let-bang
 
 
 
 do!
 
 
 
 
 
 
 
 
 
 
 
   
 
 Google Play Services. F# . . : Xamarin.Android.Support.v7.AppCompat
 
 , Google Play Services , .
 
 
 
 push notification . GCM, ID, ID Push (. pushhim). BroadcastReciever developer.android.com . F# Xamarin Component Store. Google Cloud Messaging Client GCM . ID
 
 //Check to see that GCM is supported and that the manifest has the correct information GcmClient.CheckDevice(this) GcmClient.CheckManifest(this) // check google play if CheckPlayServices() then // Try to get registration id let regId = GcmClient.GetRegistrationId this if String.IsNullOrEmpty(regId) then // Call to Register the device for Push Notifications GcmClient.Register(this, WruConstants.GcmSender);
 
 
 
 
 
 
 
   
 
 
 
 
 
 .
 
 , -
 
 bitbucket.org/xakpc/whereareyou
 
 ,
 
 , "" .
 
 
 
 
 
 , Android F#. .
 
 , - Android F#. , .
 
 
 
 
 
 
 
 
listView.Adapter <- new ArrayAdapter(this, Android.Resource.Layout.SimpleListItem1, Android.Resource.Id.Text1, values) 
      
        
        
        
      
      , ,  let values = [|"item1"; "item2"; "item3"|]
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     -   string[],       list (IEnumerable   ) 
      
        
        
        
      
              F#.            www.tryfsharp.org/Learn 
      
        
        
        
      
      
 
      
        
        
        
      
          F# -  ,  
      
        
        
        
      
     
      
        
        
        
      
            F# For Fun And Profit 
      
        
        
        
      
     
      
        
        
        
      
       ,    
      
        
        
        
      
         - . 
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
     
      
        
        
        
      
            hash 
      
        
        
        
      
         MD5  F# 
      
        
        
        
      
      let MD5Hash (input : string) = use md5 = System.Security.Cryptography.MD5.Create() input |> System.Text.Encoding.ASCII.GetBytes |> md5.ComputeHash |> Seq.map (fun c -> c.ToString("X2")) |> Seq.reduce (+)
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
      |>
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      pipeline ,     . 
      
        
        
        
      
         :    GetBytes ->   ->      HEX  ->       (  reduce   +           ) ->    . 
      
        
        
        
      
     
      
        
        
        
      
      ,     C# using System; public string CreateMD5Hash (string input) { MD5 md5 = System.Security.Cryptography.MD5.Create(); byte[] inputBytes = System.Text.Encoding.ASCII.GetBytes (input); byte[] hashBytes = md5.ComputeHash (inputBytes); StringBuilder sb = new StringBuilder(); for (int i = 0; i < hashBytes.Length; i++) { sb.Append (hashBytes[i].ToString ("X2")); } return sb.ToString(); }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
     
      
        
        
        
      
              :        .       AzureServiceWorker (  CLR    ) 
      
        
        
        
      
     
      
        
        
        
      
              -   .   F#    !   Xamarin Studio            . 
      
        
        
        
      
      <ItemGroup> <Compile Include="Resources\Resource.designer.fs" /> <Compile Include="Properties\AssemblyInfo.fs" /> <Compile Include="Helpers\Helpers.fs" /> <Compile Include="Services\User.fs" /> <Compile Include="Services\AzureServiceWorker.fs" /> <Compile Include="IAmHereActivity.fs" /> <Compile Include="WhereAreYouActivity.fs" /> <Compile Include="SignInActivity.fs" /> </ItemGroup>
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
        
      
        
        
        
      
            :    .    Xamarin    Xamarin.Mobile 
      
        
        
        
      
     
      
        
        
        
      
          .  F#         TPL,     Task',      .     F#         Task.  ,     : 
      
        
        
        
      
     module Async = open System.Threading open System.Threading.Tasks let inline AwaitPlainTask (task: Task) = // rethrow exception from preceding task if it fauled let continuation (t : Task) : unit = match t.IsFaulted with | true -> raise t.Exception | arg -> () task.ContinueWith continuation |> Async.AwaitTask
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
             Async.AwaitIAsyncResult >> Async.Ignore
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
           
      
        
        
        
      
     
      
        
        
        
      
                
      
        
        
        
      
     let ExtractUserInfo (x : Contact) = let first = x.Phones |> Seq.tryPick(fun x -> if x.Type = PhoneType.Mobile then Some(x) else None) match first with | Some(first) -> let phone = first.Number |> StripChars [' ';'-';'(';')'] UserInfo.CreateUserInfo((MD5Hash phone), phone, x.DisplayName) | None -> UserInfo.CreateUserInfo("no mobile phone", "no mobile phone", "no mobile phone") // function for async list filling let FillContactsAsync = async { let book = new AddressBook (this) let! result = book.RequestPermission() |> Async.AwaitTask if result then _contacts <- book.ToList() |> Seq.filter (fun (x: Contact) -> not (Seq.isEmpty x.Phones)) |> Seq.map ExtractUserInfo |> Seq.sortBy(fun x -> x.DisplayName) |> Seq.toList let finalContacts = _contacts |> Seq.map (fun x -> x.DisplayName.ToUpperInvariant()) |> Seq.toArray this.ListAdapter <- new ArrayAdapter(this, Resource_Layout.row_contact, finalContacts) else System.Diagnostics.Debug.WriteLine("Permission denied by user or manifest") this.ListAdapter <- new ArrayAdapter(this, Resource_Layout.row_contact, Array.empty) }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
          
      
        
        
        
      
     book.ToList()
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
       List |> Seq.filter (fun (x: Contact) -> not (Seq.isEmpty x.Phones))
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
          |> Seq.map ExtractUserInfo
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
          Contracts  UserInfo,      UserInfo |> Seq.sortBy(fun x -> x.DisplayName)
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      |> Seq.toList
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
       List _contacts <-
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
        mutable  _contacts |> Seq.map (fun x -> x.DisplayName.ToUpperInvariant())<-
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
        UserInfo  string,     - -    |> Seq.toArray<-
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      List  Array    ArrayAdapter 
      
        
        
        
      
        -      List.   . 
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
     
      
        
        
        
      
     Azure Mobile Servcies 
      
        
        
        
      
       -    Azure Mobile Services.       NotificationHub,     Push    .   Azure    , ..      . 
      
        
        
        
      
     
      
        
        
        
      
          ,    
      
        
        
        
      
     module WruConstants = [<Literal>] let TotallyNotAzureServer = "https://YOUR.azure-mobile.net/"; [<Literal>] let TotallyNotAzureKey = "YOUR"
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
       
        
        
        
      
     member this.RegisterMe phone name regId = async { try let table = this.MobileService.GetTable<User>() let usr = { Id = "" PhoneHash = MD5Hash phone Nickname = name RegistrationId = regId } do! table.InsertAsync usr |> Async.AwaitPlainTask return (usr.Id, usr.PhoneHash, usr.Nickname) with | e -> System.Diagnostics.Trace.WriteLine(e.ToString) return (String.Empty,String.Empty,String.Empty) }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     member this.RegisterMe phone name regId = async {
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     -       (     )    .       "computation expression"   workflow.   { }       ! ( bang),  do! (do-bang)  let! (let bang)     User.    ,  F#        ,      
      
        
        
        
      
      let usr = { Id = "" PhoneHash = MD5Hash phone Nickname = name RegistrationId = regId }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     do! table.InsertAsync usr |> Async.AwaitPlainTask
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      do-bang,   await
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      C#. ..             continuation    . return (usr.Id, usr.PhoneHash, usr.Nickname)
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
          Tuple<string,string,string>     .  try ... with | e ->
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      try..catch
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      C# 
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
     
      
        
        
        
      
           .  F#    fst
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      snd
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
          .        2 .     : 
      
        
        
        
      
      let id (c,_,_) = c let phonehash (_,c,_) = c let nickname (_,_,c) = c
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
        : id tuple
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      Id  .. 
      
        
        
        
      
     
      
        
        
        
      
        5  Azure,       Push .       Azure Custom Api  
      
        
        
        
      
     
      
        
        
        
      
          exports.post = function(request, response) { // Use "request.service" to access features of your mobile service, eg: // var tables = request.service.tables; // var push = request.service.push; //response.send(statusCodes.OK, { message : 'Hello World!' }); console.log('Incoming call with requst: ', request.body.RequestId); var usersTable = request.service.tables.getTable('User'); usersTable.where( { id : request.body.TargetId } ) .read( { success: function(results) { if (results.length > 0) { var user = results[0] console.log('Send to results: ', user.Nickname, user.RegistrationId); request.service.push.gcm.send(user.RegistrationId, { RequesterId: request.body.RequesterId, RequesterNickname: request.body.RequesterName, TargetId: user.id, TargetNickname: user.Nickname }, { success: function(gcm_response) { console.log('Push notification sent: ', gcm_response); response.send(statusCodes.OK, { RequestedNickname : user.Nickname }); }, error: function(gcm_error) { console.log('Error sending push notification: ', gcm_error); response.send(statusCodes.INTERNAL_SERVER_ERROR, { RequestedNickname : user.Nickname }); } }); } else { response.send(statusCodes.NO_CONTENT, { RequestedNickname : "" }); } }, error: function(error) { console.log('Error read table: ', error); response.send(statusCodes.INTERNAL_SERVER_ERROR, { RequestedNickname : "" }); } }); };
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
        Push      
      
        
        
        
      
     // Perform Push operation member this.PushAsync targetId myId myNickname = async { try let (request : PushRequest) = { TargetId = targetId RequesterId = myId RequesterName = myNickname } let! result = this.MobileService.InvokeApiAsync<PushRequest, PushResponce>("pushhim", request) |> Async.AwaitTask return result.RequestedNickname with | e -> return e.ToString() }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
           ,    let-bang
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
       do!
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
       
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
          Google Play Services.     F#   .           .    : Xamarin.Android.Support.v7.AppCompat 
      
        
        
        
      
         , Google Play Services ,   . 
      
        
        
        
      
     
      
        
        
        
      
          push notification   .    GCM,  ID,     ID       Push  (.   pushhim).        BroadcastReciever       developer.android.com .     F#         Xamarin Component Store.     Google Cloud Messaging Client         GCM    .        ID 
      
        
        
        
      
     //Check to see that GCM is supported and that the manifest has the correct information GcmClient.CheckDevice(this) GcmClient.CheckManifest(this) // check google play if CheckPlayServices() then // Try to get registration id let regId = GcmClient.GetRegistrationId this if String.IsNullOrEmpty(regId) then // Call to Register the device for Push Notifications GcmClient.Register(this, WruConstants.GcmSender);
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
            
      
        
        
        
      
     
      
        
        
        
      
        . 
      
        
        
        
      
        , -  
      
        
        
        
      
         bitbucket.org/xakpc/whereareyou 
      
        
        
        
      
         ,     
      
        
        
        
      
              ,           "" . 
      
        
        
        
      
     
      
        
        
        
      
      
      
        
        
        
      
     ,   Android   F#.      . 
      
        
        
        
      
     ,       -  Android  F#.   ,       .
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
    listView.Adapter <- new ArrayAdapter(this, Android.Resource.Layout.SimpleListItem1, Android.Resource.Id.Text1, values) 
      
        
        
        
      
      , ,  let values = [|"item1"; "item2"; "item3"|]
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     -   string[],       list (IEnumerable   ) 
      
        
        
        
      
              F#.            www.tryfsharp.org/Learn 
      
        
        
        
      
      
 
      
        
        
        
      
          F# -  ,  
      
        
        
        
      
     
      
        
        
        
      
            F# For Fun And Profit 
      
        
        
        
      
     
      
        
        
        
      
       ,    
      
        
        
        
      
         - . 
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
     
      
        
        
        
      
            hash 
      
        
        
        
      
         MD5  F# 
      
        
        
        
      
      let MD5Hash (input : string) = use md5 = System.Security.Cryptography.MD5.Create() input |> System.Text.Encoding.ASCII.GetBytes |> md5.ComputeHash |> Seq.map (fun c -> c.ToString("X2")) |> Seq.reduce (+)
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
      |>
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      pipeline ,     . 
      
        
        
        
      
         :    GetBytes ->   ->      HEX  ->       (  reduce   +           ) ->    . 
      
        
        
        
      
     
      
        
        
        
      
      ,     C# using System; public string CreateMD5Hash (string input) { MD5 md5 = System.Security.Cryptography.MD5.Create(); byte[] inputBytes = System.Text.Encoding.ASCII.GetBytes (input); byte[] hashBytes = md5.ComputeHash (inputBytes); StringBuilder sb = new StringBuilder(); for (int i = 0; i < hashBytes.Length; i++) { sb.Append (hashBytes[i].ToString ("X2")); } return sb.ToString(); }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
     
      
        
        
        
      
              :        .       AzureServiceWorker (  CLR    ) 
      
        
        
        
      
     
      
        
        
        
      
              -   .   F#    !   Xamarin Studio            . 
      
        
        
        
      
      <ItemGroup> <Compile Include="Resources\Resource.designer.fs" /> <Compile Include="Properties\AssemblyInfo.fs" /> <Compile Include="Helpers\Helpers.fs" /> <Compile Include="Services\User.fs" /> <Compile Include="Services\AzureServiceWorker.fs" /> <Compile Include="IAmHereActivity.fs" /> <Compile Include="WhereAreYouActivity.fs" /> <Compile Include="SignInActivity.fs" /> </ItemGroup>
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
        
      
        
        
        
      
            :    .    Xamarin    Xamarin.Mobile 
      
        
        
        
      
     
      
        
        
        
      
          .  F#         TPL,     Task',      .     F#         Task.  ,     : 
      
        
        
        
      
     module Async = open System.Threading open System.Threading.Tasks let inline AwaitPlainTask (task: Task) = // rethrow exception from preceding task if it fauled let continuation (t : Task) : unit = match t.IsFaulted with | true -> raise t.Exception | arg -> () task.ContinueWith continuation |> Async.AwaitTask
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
             Async.AwaitIAsyncResult >> Async.Ignore
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
           
      
        
        
        
      
     
      
        
        
        
      
                
      
        
        
        
      
     let ExtractUserInfo (x : Contact) = let first = x.Phones |> Seq.tryPick(fun x -> if x.Type = PhoneType.Mobile then Some(x) else None) match first with | Some(first) -> let phone = first.Number |> StripChars [' ';'-';'(';')'] UserInfo.CreateUserInfo((MD5Hash phone), phone, x.DisplayName) | None -> UserInfo.CreateUserInfo("no mobile phone", "no mobile phone", "no mobile phone") // function for async list filling let FillContactsAsync = async { let book = new AddressBook (this) let! result = book.RequestPermission() |> Async.AwaitTask if result then _contacts <- book.ToList() |> Seq.filter (fun (x: Contact) -> not (Seq.isEmpty x.Phones)) |> Seq.map ExtractUserInfo |> Seq.sortBy(fun x -> x.DisplayName) |> Seq.toList let finalContacts = _contacts |> Seq.map (fun x -> x.DisplayName.ToUpperInvariant()) |> Seq.toArray this.ListAdapter <- new ArrayAdapter(this, Resource_Layout.row_contact, finalContacts) else System.Diagnostics.Debug.WriteLine("Permission denied by user or manifest") this.ListAdapter <- new ArrayAdapter(this, Resource_Layout.row_contact, Array.empty) }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
          
      
        
        
        
      
     book.ToList()
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
       List |> Seq.filter (fun (x: Contact) -> not (Seq.isEmpty x.Phones))
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
          |> Seq.map ExtractUserInfo
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
          Contracts  UserInfo,      UserInfo |> Seq.sortBy(fun x -> x.DisplayName)
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      |> Seq.toList
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
       List _contacts <-
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
        mutable  _contacts |> Seq.map (fun x -> x.DisplayName.ToUpperInvariant())<-
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
        UserInfo  string,     - -    |> Seq.toArray<-
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      List  Array    ArrayAdapter 
      
        
        
        
      
        -      List.   . 
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
     
      
        
        
        
      
     Azure Mobile Servcies 
      
        
        
        
      
       -    Azure Mobile Services.       NotificationHub,     Push    .   Azure    , ..      . 
      
        
        
        
      
     
      
        
        
        
      
          ,    
      
        
        
        
      
     module WruConstants = [<Literal>] let TotallyNotAzureServer = "https://YOUR.azure-mobile.net/"; [<Literal>] let TotallyNotAzureKey = "YOUR"
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
       
        
        
        
      
     member this.RegisterMe phone name regId = async { try let table = this.MobileService.GetTable<User>() let usr = { Id = "" PhoneHash = MD5Hash phone Nickname = name RegistrationId = regId } do! table.InsertAsync usr |> Async.AwaitPlainTask return (usr.Id, usr.PhoneHash, usr.Nickname) with | e -> System.Diagnostics.Trace.WriteLine(e.ToString) return (String.Empty,String.Empty,String.Empty) }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     member this.RegisterMe phone name regId = async {
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     -       (     )    .       "computation expression"   workflow.   { }       ! ( bang),  do! (do-bang)  let! (let bang)     User.    ,  F#        ,      
      
        
        
        
      
      let usr = { Id = "" PhoneHash = MD5Hash phone Nickname = name RegistrationId = regId }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     do! table.InsertAsync usr |> Async.AwaitPlainTask
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      do-bang,   await
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      C#. ..             continuation    . return (usr.Id, usr.PhoneHash, usr.Nickname)
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
          Tuple<string,string,string>     .  try ... with | e ->
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      try..catch
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      C# 
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
     
      
        
        
        
      
           .  F#    fst
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      snd
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
          .        2 .     : 
      
        
        
        
      
      let id (c,_,_) = c let phonehash (_,c,_) = c let nickname (_,_,c) = c
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
        : id tuple
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      Id  .. 
      
        
        
        
      
     
      
        
        
        
      
        5  Azure,       Push .       Azure Custom Api  
      
        
        
        
      
     
      
        
        
        
      
          exports.post = function(request, response) { // Use "request.service" to access features of your mobile service, eg: // var tables = request.service.tables; // var push = request.service.push; //response.send(statusCodes.OK, { message : 'Hello World!' }); console.log('Incoming call with requst: ', request.body.RequestId); var usersTable = request.service.tables.getTable('User'); usersTable.where( { id : request.body.TargetId } ) .read( { success: function(results) { if (results.length > 0) { var user = results[0] console.log('Send to results: ', user.Nickname, user.RegistrationId); request.service.push.gcm.send(user.RegistrationId, { RequesterId: request.body.RequesterId, RequesterNickname: request.body.RequesterName, TargetId: user.id, TargetNickname: user.Nickname }, { success: function(gcm_response) { console.log('Push notification sent: ', gcm_response); response.send(statusCodes.OK, { RequestedNickname : user.Nickname }); }, error: function(gcm_error) { console.log('Error sending push notification: ', gcm_error); response.send(statusCodes.INTERNAL_SERVER_ERROR, { RequestedNickname : user.Nickname }); } }); } else { response.send(statusCodes.NO_CONTENT, { RequestedNickname : "" }); } }, error: function(error) { console.log('Error read table: ', error); response.send(statusCodes.INTERNAL_SERVER_ERROR, { RequestedNickname : "" }); } }); };
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
        Push      
      
        
        
        
      
     // Perform Push operation member this.PushAsync targetId myId myNickname = async { try let (request : PushRequest) = { TargetId = targetId RequesterId = myId RequesterName = myNickname } let! result = this.MobileService.InvokeApiAsync<PushRequest, PushResponce>("pushhim", request) |> Async.AwaitTask return result.RequestedNickname with | e -> return e.ToString() }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
           ,    let-bang
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
       do!
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
       
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
          Google Play Services.     F#   .           .    : Xamarin.Android.Support.v7.AppCompat 
      
        
        
        
      
         , Google Play Services ,   . 
      
        
        
        
      
     
      
        
        
        
      
          push notification   .    GCM,  ID,     ID       Push  (.   pushhim).        BroadcastReciever       developer.android.com .     F#         Xamarin Component Store.     Google Cloud Messaging Client         GCM    .        ID 
      
        
        
        
      
     //Check to see that GCM is supported and that the manifest has the correct information GcmClient.CheckDevice(this) GcmClient.CheckManifest(this) // check google play if CheckPlayServices() then // Try to get registration id let regId = GcmClient.GetRegistrationId this if String.IsNullOrEmpty(regId) then // Call to Register the device for Push Notifications GcmClient.Register(this, WruConstants.GcmSender);
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
            
      
        
        
        
      
     
      
        
        
        
      
        . 
      
        
        
        
      
        , -  
      
        
        
        
      
         bitbucket.org/xakpc/whereareyou 
      
        
        
        
      
         ,     
      
        
        
        
      
              ,           "" . 
      
        
        
        
      
     
      
        
        
        
      
      
      
        
        
        
      
     ,   Android   F#.      . 
      
        
        
        
      
     ,       -  Android  F#.   ,       .
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
    listView.Adapter <- new ArrayAdapter(this, Android.Resource.Layout.SimpleListItem1, Android.Resource.Id.Text1, values) 
      
        
        
        
      
      , ,  let values = [|"item1"; "item2"; "item3"|]
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     -   string[],       list (IEnumerable   ) 
      
        
        
        
      
              F#.            www.tryfsharp.org/Learn 
      
        
        
        
      
      
 
      
        
        
        
      
          F# -  ,  
      
        
        
        
      
     
      
        
        
        
      
            F# For Fun And Profit 
      
        
        
        
      
     
      
        
        
        
      
       ,    
      
        
        
        
      
         - . 
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
     
      
        
        
        
      
            hash 
      
        
        
        
      
         MD5  F# 
      
        
        
        
      
      let MD5Hash (input : string) = use md5 = System.Security.Cryptography.MD5.Create() input |> System.Text.Encoding.ASCII.GetBytes |> md5.ComputeHash |> Seq.map (fun c -> c.ToString("X2")) |> Seq.reduce (+)
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
      |>
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      pipeline ,     . 
      
        
        
        
      
         :    GetBytes ->   ->      HEX  ->       (  reduce   +           ) ->    . 
      
        
        
        
      
     
      
        
        
        
      
      ,     C# using System; public string CreateMD5Hash (string input) { MD5 md5 = System.Security.Cryptography.MD5.Create(); byte[] inputBytes = System.Text.Encoding.ASCII.GetBytes (input); byte[] hashBytes = md5.ComputeHash (inputBytes); StringBuilder sb = new StringBuilder(); for (int i = 0; i < hashBytes.Length; i++) { sb.Append (hashBytes[i].ToString ("X2")); } return sb.ToString(); }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
     
      
        
        
        
      
              :        .       AzureServiceWorker (  CLR    ) 
      
        
        
        
      
     
      
        
        
        
      
              -   .   F#    !   Xamarin Studio            . 
      
        
        
        
      
      <ItemGroup> <Compile Include="Resources\Resource.designer.fs" /> <Compile Include="Properties\AssemblyInfo.fs" /> <Compile Include="Helpers\Helpers.fs" /> <Compile Include="Services\User.fs" /> <Compile Include="Services\AzureServiceWorker.fs" /> <Compile Include="IAmHereActivity.fs" /> <Compile Include="WhereAreYouActivity.fs" /> <Compile Include="SignInActivity.fs" /> </ItemGroup>
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
        
      
        
        
        
      
            :    .    Xamarin    Xamarin.Mobile 
      
        
        
        
      
     
      
        
        
        
      
          .  F#         TPL,     Task',      .     F#         Task.  ,     : 
      
        
        
        
      
     module Async = open System.Threading open System.Threading.Tasks let inline AwaitPlainTask (task: Task) = // rethrow exception from preceding task if it fauled let continuation (t : Task) : unit = match t.IsFaulted with | true -> raise t.Exception | arg -> () task.ContinueWith continuation |> Async.AwaitTask
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
             Async.AwaitIAsyncResult >> Async.Ignore
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
           
      
        
        
        
      
     
      
        
        
        
      
                
      
        
        
        
      
     let ExtractUserInfo (x : Contact) = let first = x.Phones |> Seq.tryPick(fun x -> if x.Type = PhoneType.Mobile then Some(x) else None) match first with | Some(first) -> let phone = first.Number |> StripChars [' ';'-';'(';')'] UserInfo.CreateUserInfo((MD5Hash phone), phone, x.DisplayName) | None -> UserInfo.CreateUserInfo("no mobile phone", "no mobile phone", "no mobile phone") // function for async list filling let FillContactsAsync = async { let book = new AddressBook (this) let! result = book.RequestPermission() |> Async.AwaitTask if result then _contacts <- book.ToList() |> Seq.filter (fun (x: Contact) -> not (Seq.isEmpty x.Phones)) |> Seq.map ExtractUserInfo |> Seq.sortBy(fun x -> x.DisplayName) |> Seq.toList let finalContacts = _contacts |> Seq.map (fun x -> x.DisplayName.ToUpperInvariant()) |> Seq.toArray this.ListAdapter <- new ArrayAdapter(this, Resource_Layout.row_contact, finalContacts) else System.Diagnostics.Debug.WriteLine("Permission denied by user or manifest") this.ListAdapter <- new ArrayAdapter(this, Resource_Layout.row_contact, Array.empty) }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
          
      
        
        
        
      
     book.ToList()
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
       List |> Seq.filter (fun (x: Contact) -> not (Seq.isEmpty x.Phones))
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
          |> Seq.map ExtractUserInfo
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
          Contracts  UserInfo,      UserInfo |> Seq.sortBy(fun x -> x.DisplayName)
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      |> Seq.toList
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
       List _contacts <-
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
        mutable  _contacts |> Seq.map (fun x -> x.DisplayName.ToUpperInvariant())<-
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
        UserInfo  string,     - -    |> Seq.toArray<-
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      List  Array    ArrayAdapter 
      
        
        
        
      
        -      List.   . 
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
     
      
        
        
        
      
     Azure Mobile Servcies 
      
        
        
        
      
       -    Azure Mobile Services.       NotificationHub,     Push    .   Azure    , ..      . 
      
        
        
        
      
     
      
        
        
        
      
          ,    
      
        
        
        
      
     module WruConstants = [<Literal>] let TotallyNotAzureServer = "https://YOUR.azure-mobile.net/"; [<Literal>] let TotallyNotAzureKey = "YOUR"
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
       
        
        
        
      
     member this.RegisterMe phone name regId = async { try let table = this.MobileService.GetTable<User>() let usr = { Id = "" PhoneHash = MD5Hash phone Nickname = name RegistrationId = regId } do! table.InsertAsync usr |> Async.AwaitPlainTask return (usr.Id, usr.PhoneHash, usr.Nickname) with | e -> System.Diagnostics.Trace.WriteLine(e.ToString) return (String.Empty,String.Empty,String.Empty) }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     member this.RegisterMe phone name regId = async {
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     -       (     )    .       "computation expression"   workflow.   { }       ! ( bang),  do! (do-bang)  let! (let bang)     User.    ,  F#        ,      
      
        
        
        
      
      let usr = { Id = "" PhoneHash = MD5Hash phone Nickname = name RegistrationId = regId }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     do! table.InsertAsync usr |> Async.AwaitPlainTask
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      do-bang,   await
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      C#. ..             continuation    . return (usr.Id, usr.PhoneHash, usr.Nickname)
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
          Tuple<string,string,string>     .  try ... with | e ->
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      try..catch
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      C# 
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
     
      
        
        
        
      
           .  F#    fst
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      snd
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
          .        2 .     : 
      
        
        
        
      
      let id (c,_,_) = c let phonehash (_,c,_) = c let nickname (_,_,c) = c
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
        : id tuple
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      Id  .. 
      
        
        
        
      
     
      
        
        
        
      
        5  Azure,       Push .       Azure Custom Api  
      
        
        
        
      
     
      
        
        
        
      
          exports.post = function(request, response) { // Use "request.service" to access features of your mobile service, eg: // var tables = request.service.tables; // var push = request.service.push; //response.send(statusCodes.OK, { message : 'Hello World!' }); console.log('Incoming call with requst: ', request.body.RequestId); var usersTable = request.service.tables.getTable('User'); usersTable.where( { id : request.body.TargetId } ) .read( { success: function(results) { if (results.length > 0) { var user = results[0] console.log('Send to results: ', user.Nickname, user.RegistrationId); request.service.push.gcm.send(user.RegistrationId, { RequesterId: request.body.RequesterId, RequesterNickname: request.body.RequesterName, TargetId: user.id, TargetNickname: user.Nickname }, { success: function(gcm_response) { console.log('Push notification sent: ', gcm_response); response.send(statusCodes.OK, { RequestedNickname : user.Nickname }); }, error: function(gcm_error) { console.log('Error sending push notification: ', gcm_error); response.send(statusCodes.INTERNAL_SERVER_ERROR, { RequestedNickname : user.Nickname }); } }); } else { response.send(statusCodes.NO_CONTENT, { RequestedNickname : "" }); } }, error: function(error) { console.log('Error read table: ', error); response.send(statusCodes.INTERNAL_SERVER_ERROR, { RequestedNickname : "" }); } }); };
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
        Push      
      
        
        
        
      
     // Perform Push operation member this.PushAsync targetId myId myNickname = async { try let (request : PushRequest) = { TargetId = targetId RequesterId = myId RequesterName = myNickname } let! result = this.MobileService.InvokeApiAsync<PushRequest, PushResponce>("pushhim", request) |> Async.AwaitTask return result.RequestedNickname with | e -> return e.ToString() }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
           ,    let-bang
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
       do!
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
       
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
          Google Play Services.     F#   .           .    : Xamarin.Android.Support.v7.AppCompat 
      
        
        
        
      
         , Google Play Services ,   . 
      
        
        
        
      
     
      
        
        
        
      
          push notification   .    GCM,  ID,     ID       Push  (.   pushhim).        BroadcastReciever       developer.android.com .     F#         Xamarin Component Store.     Google Cloud Messaging Client         GCM    .        ID 
      
        
        
        
      
     //Check to see that GCM is supported and that the manifest has the correct information GcmClient.CheckDevice(this) GcmClient.CheckManifest(this) // check google play if CheckPlayServices() then // Try to get registration id let regId = GcmClient.GetRegistrationId this if String.IsNullOrEmpty(regId) then // Call to Register the device for Push Notifications GcmClient.Register(this, WruConstants.GcmSender);
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
            
      
        
        
        
      
     
      
        
        
        
      
        . 
      
        
        
        
      
        , -  
      
        
        
        
      
         bitbucket.org/xakpc/whereareyou 
      
        
        
        
      
         ,     
      
        
        
        
      
              ,           "" . 
      
        
        
        
      
     
      
        
        
        
      
      
      
        
        
        
      
     ,   Android   F#.      . 
      
        
        
        
      
     ,       -  Android  F#.   ,       .
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     listView.Adapter <- new ArrayAdapter(this, Android.Resource.Layout.SimpleListItem1, Android.Resource.Id.Text1, values) 
      
        
        
        
      
      , ,  let values = [|"item1"; "item2"; "item3"|]
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     -   string[],       list (IEnumerable   ) 
      
        
        
        
      
              F#.            www.tryfsharp.org/Learn 
      
        
        
        
      
      
 
      
        
        
        
      
          F# -  ,  
      
        
        
        
      
     
      
        
        
        
      
            F# For Fun And Profit 
      
        
        
        
      
     
      
        
        
        
      
       ,    
      
        
        
        
      
         - . 
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
     
      
        
        
        
      
            hash 
      
        
        
        
      
         MD5  F# 
      
        
        
        
      
      let MD5Hash (input : string) = use md5 = System.Security.Cryptography.MD5.Create() input |> System.Text.Encoding.ASCII.GetBytes |> md5.ComputeHash |> Seq.map (fun c -> c.ToString("X2")) |> Seq.reduce (+)
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
      |>
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      pipeline ,     . 
      
        
        
        
      
         :    GetBytes ->   ->      HEX  ->       (  reduce   +           ) ->    . 
      
        
        
        
      
     
      
        
        
        
      
      ,     C# using System; public string CreateMD5Hash (string input) { MD5 md5 = System.Security.Cryptography.MD5.Create(); byte[] inputBytes = System.Text.Encoding.ASCII.GetBytes (input); byte[] hashBytes = md5.ComputeHash (inputBytes); StringBuilder sb = new StringBuilder(); for (int i = 0; i < hashBytes.Length; i++) { sb.Append (hashBytes[i].ToString ("X2")); } return sb.ToString(); }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
     
      
        
        
        
      
              :        .       AzureServiceWorker (  CLR    ) 
      
        
        
        
      
     
      
        
        
        
      
              -   .   F#    !   Xamarin Studio            . 
      
        
        
        
      
      <ItemGroup> <Compile Include="Resources\Resource.designer.fs" /> <Compile Include="Properties\AssemblyInfo.fs" /> <Compile Include="Helpers\Helpers.fs" /> <Compile Include="Services\User.fs" /> <Compile Include="Services\AzureServiceWorker.fs" /> <Compile Include="IAmHereActivity.fs" /> <Compile Include="WhereAreYouActivity.fs" /> <Compile Include="SignInActivity.fs" /> </ItemGroup>
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
        
      
        
        
        
      
            :    .    Xamarin    Xamarin.Mobile 
      
        
        
        
      
     
      
        
        
        
      
          .  F#         TPL,     Task',      .     F#         Task.  ,     : 
      
        
        
        
      
     module Async = open System.Threading open System.Threading.Tasks let inline AwaitPlainTask (task: Task) = // rethrow exception from preceding task if it fauled let continuation (t : Task) : unit = match t.IsFaulted with | true -> raise t.Exception | arg -> () task.ContinueWith continuation |> Async.AwaitTask
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
             Async.AwaitIAsyncResult >> Async.Ignore
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
           
      
        
        
        
      
     
      
        
        
        
      
                
      
        
        
        
      
     let ExtractUserInfo (x : Contact) = let first = x.Phones |> Seq.tryPick(fun x -> if x.Type = PhoneType.Mobile then Some(x) else None) match first with | Some(first) -> let phone = first.Number |> StripChars [' ';'-';'(';')'] UserInfo.CreateUserInfo((MD5Hash phone), phone, x.DisplayName) | None -> UserInfo.CreateUserInfo("no mobile phone", "no mobile phone", "no mobile phone") // function for async list filling let FillContactsAsync = async { let book = new AddressBook (this) let! result = book.RequestPermission() |> Async.AwaitTask if result then _contacts <- book.ToList() |> Seq.filter (fun (x: Contact) -> not (Seq.isEmpty x.Phones)) |> Seq.map ExtractUserInfo |> Seq.sortBy(fun x -> x.DisplayName) |> Seq.toList let finalContacts = _contacts |> Seq.map (fun x -> x.DisplayName.ToUpperInvariant()) |> Seq.toArray this.ListAdapter <- new ArrayAdapter(this, Resource_Layout.row_contact, finalContacts) else System.Diagnostics.Debug.WriteLine("Permission denied by user or manifest") this.ListAdapter <- new ArrayAdapter(this, Resource_Layout.row_contact, Array.empty) }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
          
      
        
        
        
      
     book.ToList()
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
       List |> Seq.filter (fun (x: Contact) -> not (Seq.isEmpty x.Phones))
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
          |> Seq.map ExtractUserInfo
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
          Contracts  UserInfo,      UserInfo |> Seq.sortBy(fun x -> x.DisplayName)
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      |> Seq.toList
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
       List _contacts <-
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
        mutable  _contacts |> Seq.map (fun x -> x.DisplayName.ToUpperInvariant())<-
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
        UserInfo  string,     - -    |> Seq.toArray<-
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      List  Array    ArrayAdapter 
      
        
        
        
      
        -      List.   . 
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
     
      
        
        
        
      
     Azure Mobile Servcies 
      
        
        
        
      
       -    Azure Mobile Services.       NotificationHub,     Push    .   Azure    , ..      . 
      
        
        
        
      
     
      
        
        
        
      
          ,    
      
        
        
        
      
     module WruConstants = [<Literal>] let TotallyNotAzureServer = "https://YOUR.azure-mobile.net/"; [<Literal>] let TotallyNotAzureKey = "YOUR"
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
       
        
        
        
      
     member this.RegisterMe phone name regId = async { try let table = this.MobileService.GetTable<User>() let usr = { Id = "" PhoneHash = MD5Hash phone Nickname = name RegistrationId = regId } do! table.InsertAsync usr |> Async.AwaitPlainTask return (usr.Id, usr.PhoneHash, usr.Nickname) with | e -> System.Diagnostics.Trace.WriteLine(e.ToString) return (String.Empty,String.Empty,String.Empty) }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     member this.RegisterMe phone name regId = async {
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     -       (     )    .       "computation expression"   workflow.   { }       ! ( bang),  do! (do-bang)  let! (let bang)     User.    ,  F#        ,      
      
        
        
        
      
      let usr = { Id = "" PhoneHash = MD5Hash phone Nickname = name RegistrationId = regId }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     do! table.InsertAsync usr |> Async.AwaitPlainTask
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      do-bang,   await
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      C#. ..             continuation    . return (usr.Id, usr.PhoneHash, usr.Nickname)
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
          Tuple<string,string,string>     .  try ... with | e ->
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      try..catch
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      C# 
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
     
      
        
        
        
      
           .  F#    fst
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      snd
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
          .        2 .     : 
      
        
        
        
      
      let id (c,_,_) = c let phonehash (_,c,_) = c let nickname (_,_,c) = c
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
        : id tuple
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      Id  .. 
      
        
        
        
      
     
      
        
        
        
      
        5  Azure,       Push .       Azure Custom Api  
      
        
        
        
      
     
      
        
        
        
      
          exports.post = function(request, response) { // Use "request.service" to access features of your mobile service, eg: // var tables = request.service.tables; // var push = request.service.push; //response.send(statusCodes.OK, { message : 'Hello World!' }); console.log('Incoming call with requst: ', request.body.RequestId); var usersTable = request.service.tables.getTable('User'); usersTable.where( { id : request.body.TargetId } ) .read( { success: function(results) { if (results.length > 0) { var user = results[0] console.log('Send to results: ', user.Nickname, user.RegistrationId); request.service.push.gcm.send(user.RegistrationId, { RequesterId: request.body.RequesterId, RequesterNickname: request.body.RequesterName, TargetId: user.id, TargetNickname: user.Nickname }, { success: function(gcm_response) { console.log('Push notification sent: ', gcm_response); response.send(statusCodes.OK, { RequestedNickname : user.Nickname }); }, error: function(gcm_error) { console.log('Error sending push notification: ', gcm_error); response.send(statusCodes.INTERNAL_SERVER_ERROR, { RequestedNickname : user.Nickname }); } }); } else { response.send(statusCodes.NO_CONTENT, { RequestedNickname : "" }); } }, error: function(error) { console.log('Error read table: ', error); response.send(statusCodes.INTERNAL_SERVER_ERROR, { RequestedNickname : "" }); } }); };
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
        Push      
      
        
        
        
      
     // Perform Push operation member this.PushAsync targetId myId myNickname = async { try let (request : PushRequest) = { TargetId = targetId RequesterId = myId RequesterName = myNickname } let! result = this.MobileService.InvokeApiAsync<PushRequest, PushResponce>("pushhim", request) |> Async.AwaitTask return result.RequestedNickname with | e -> return e.ToString() }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
           ,    let-bang
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
       do!
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
       
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
          Google Play Services.     F#   .           .    : Xamarin.Android.Support.v7.AppCompat 
      
        
        
        
      
         , Google Play Services ,   . 
      
        
        
        
      
     
      
        
        
        
      
          push notification   .    GCM,  ID,     ID       Push  (.   pushhim).        BroadcastReciever       developer.android.com .     F#         Xamarin Component Store.     Google Cloud Messaging Client         GCM    .        ID 
      
        
        
        
      
     //Check to see that GCM is supported and that the manifest has the correct information GcmClient.CheckDevice(this) GcmClient.CheckManifest(this) // check google play if CheckPlayServices() then // Try to get registration id let regId = GcmClient.GetRegistrationId this if String.IsNullOrEmpty(regId) then // Call to Register the device for Push Notifications GcmClient.Register(this, WruConstants.GcmSender);
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
            
      
        
        
        
      
     
      
        
        
        
      
        . 
      
        
        
        
      
        , -  
      
        
        
        
      
         bitbucket.org/xakpc/whereareyou 
      
        
        
        
      
         ,     
      
        
        
        
      
              ,           "" . 
      
        
        
        
      
     
      
        
        
        
      
      
      
        
        
        
      
     ,   Android   F#.      . 
      
        
        
        
      
     ,       -  Android  F#.   ,       .
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
    
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
 listView.Adapter <- new ArrayAdapter(this, Android.Resource.Layout.SimpleListItem1, Android.Resource.Id.Text1, values) 
      
        
        
        
      
      , ,  let values = [|"item1"; "item2"; "item3"|]
      
      - string[], list (IEnumerable )
F#. www.tryfsharp.org/Learn
 
 
      F# - ,
F# For Fun And Profit
,
- .
 
 
      hash
MD5 F#
 let MD5Hash (input : string) = use md5 = System.Security.Cryptography.MD5.Create() input |> System.Text.Encoding.ASCII.GetBytes |> md5.ComputeHash |> Seq.map (fun c -> c.ToString("X2")) |> Seq.reduce (+)
      
      |>
      
      pipeline , .
: GetBytes -> -> HEX -> ( reduce + ) -> .
, C#
using System; public string CreateMD5Hash (string input) { MD5 md5 = System.Security.Cryptography.MD5.Create(); byte[] inputBytes = System.Text.Encoding.ASCII.GetBytes (input); byte[] hashBytes = md5.ComputeHash (inputBytes); StringBuilder sb = new StringBuilder(); for (int i = 0; i < hashBytes.Length; i++) { sb.Append (hashBytes[i].ToString ("X2")); } return sb.ToString(); }
      
      : . AzureServiceWorker ( CLR )
- . F# ! Xamarin Studio .
 <ItemGroup> <Compile Include="Resources\Resource.designer.fs" /> <Compile Include="Properties\AssemblyInfo.fs" /> <Compile Include="Helpers\Helpers.fs" /> <Compile Include="Services\User.fs" /> <Compile Include="Services\AzureServiceWorker.fs" /> <Compile Include="IAmHereActivity.fs" /> <Compile Include="WhereAreYouActivity.fs" /> <Compile Include="SignInActivity.fs" /> </ItemGroup>
      
      : . Xamarin Xamarin.Mobile
. F# TPL, Task', . F# Task. , :
module Async = open System.Threading open System.Threading.Tasks let inline AwaitPlainTask (task: Task) = // rethrow exception from preceding task if it fauled let continuation (t : Task) : unit = match t.IsFaulted with | true -> raise t.Exception | arg -> () task.ContinueWith continuation |> Async.AwaitTask
      
      Async.AwaitIAsyncResult >> Async.Ignore
      
      let ExtractUserInfo (x : Contact) = let first = x.Phones |> Seq.tryPick(fun x -> if x.Type = PhoneType.Mobile then Some(x) else None) match first with | Some(first) -> let phone = first.Number |> StripChars [' ';'-';'(';')'] UserInfo.CreateUserInfo((MD5Hash phone), phone, x.DisplayName) | None -> UserInfo.CreateUserInfo("no mobile phone", "no mobile phone", "no mobile phone") // function for async list filling let FillContactsAsync = async { let book = new AddressBook (this) let! result = book.RequestPermission() |> Async.AwaitTask if result then _contacts <- book.ToList() |> Seq.filter (fun (x: Contact) -> not (Seq.isEmpty x.Phones)) |> Seq.map ExtractUserInfo |> Seq.sortBy(fun x -> x.DisplayName) |> Seq.toList let finalContacts = _contacts |> Seq.map (fun x -> x.DisplayName.ToUpperInvariant()) |> Seq.toArray this.ListAdapter <- new ArrayAdapter(this, Resource_Layout.row_contact, finalContacts) else System.Diagnostics.Debug.WriteLine("Permission denied by user or manifest") this.ListAdapter <- new ArrayAdapter(this, Resource_Layout.row_contact, Array.empty) }
      
      book.ToList()
      
      List
|> Seq.filter (fun (x: Contact) -> not (Seq.isEmpty x.Phones))
      
      |> Seq.map ExtractUserInfo
      
      Contracts UserInfo, UserInfo
|> Seq.sortBy(fun x -> x.DisplayName)
      
      |> Seq.toList
      
      List
_contacts <-
      
      mutable
_contacts |> Seq.map (fun x -> x.DisplayName.ToUpperInvariant())<-
      
      UserInfo string, - -
|> Seq.toArray<-
      
      List Array ArrayAdapter
- List. .
 
 
      Azure Mobile Servcies
- Azure Mobile Services. NotificationHub, Push . Azure , .. .
,
      
        
        
        
      
     module WruConstants = [<Literal>] let TotallyNotAzureServer = "https://YOUR.azure-mobile.net/"; [<Literal>] let TotallyNotAzureKey = "YOUR"
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
       
        
        
        
      
     member this.RegisterMe phone name regId = async { try let table = this.MobileService.GetTable<User>() let usr = { Id = "" PhoneHash = MD5Hash phone Nickname = name RegistrationId = regId } do! table.InsertAsync usr |> Async.AwaitPlainTask return (usr.Id, usr.PhoneHash, usr.Nickname) with | e -> System.Diagnostics.Trace.WriteLine(e.ToString) return (String.Empty,String.Empty,String.Empty) }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     member this.RegisterMe phone name regId = async {
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     -       (     )    .       "computation expression"   workflow.   { }       ! ( bang),  do! (do-bang)  let! (let bang)     User.    ,  F#        ,      
      
        
        
        
      
      let usr = { Id = "" PhoneHash = MD5Hash phone Nickname = name RegistrationId = regId }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     do! table.InsertAsync usr |> Async.AwaitPlainTask
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      do-bang,   await
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      C#. ..             continuation    . return (usr.Id, usr.PhoneHash, usr.Nickname)
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
          Tuple<string,string,string>     .  try ... with | e ->
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      try..catch
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      C# 
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
     
      
        
        
        
      
           .  F#    fst
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      snd
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
          .        2 .     : 
      
        
        
        
      
      let id (c,_,_) = c let phonehash (_,c,_) = c let nickname (_,_,c) = c
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
        : id tuple
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      Id  .. 
      
        
        
        
      
     
      
        
        
        
      
        5  Azure,       Push .       Azure Custom Api  
      
        
        
        
      
     
      
        
        
        
      
          exports.post = function(request, response) { // Use "request.service" to access features of your mobile service, eg: // var tables = request.service.tables; // var push = request.service.push; //response.send(statusCodes.OK, { message : 'Hello World!' }); console.log('Incoming call with requst: ', request.body.RequestId); var usersTable = request.service.tables.getTable('User'); usersTable.where( { id : request.body.TargetId } ) .read( { success: function(results) { if (results.length > 0) { var user = results[0] console.log('Send to results: ', user.Nickname, user.RegistrationId); request.service.push.gcm.send(user.RegistrationId, { RequesterId: request.body.RequesterId, RequesterNickname: request.body.RequesterName, TargetId: user.id, TargetNickname: user.Nickname }, { success: function(gcm_response) { console.log('Push notification sent: ', gcm_response); response.send(statusCodes.OK, { RequestedNickname : user.Nickname }); }, error: function(gcm_error) { console.log('Error sending push notification: ', gcm_error); response.send(statusCodes.INTERNAL_SERVER_ERROR, { RequestedNickname : user.Nickname }); } }); } else { response.send(statusCodes.NO_CONTENT, { RequestedNickname : "" }); } }, error: function(error) { console.log('Error read table: ', error); response.send(statusCodes.INTERNAL_SERVER_ERROR, { RequestedNickname : "" }); } }); };
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
        Push      
      
        
        
        
      
     // Perform Push operation member this.PushAsync targetId myId myNickname = async { try let (request : PushRequest) = { TargetId = targetId RequesterId = myId RequesterName = myNickname } let! result = this.MobileService.InvokeApiAsync<PushRequest, PushResponce>("pushhim", request) |> Async.AwaitTask return result.RequestedNickname with | e -> return e.ToString() }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
           ,    let-bang
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
       do!
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
       
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
          Google Play Services.     F#   .           .    : Xamarin.Android.Support.v7.AppCompat 
      
        
        
        
      
         , Google Play Services ,   . 
      
        
        
        
      
     
      
        
        
        
      
          push notification   .    GCM,  ID,     ID       Push  (.   pushhim).        BroadcastReciever       developer.android.com .     F#         Xamarin Component Store.     Google Cloud Messaging Client         GCM    .        ID 
      
        
        
        
      
     //Check to see that GCM is supported and that the manifest has the correct information GcmClient.CheckDevice(this) GcmClient.CheckManifest(this) // check google play if CheckPlayServices() then // Try to get registration id let regId = GcmClient.GetRegistrationId this if String.IsNullOrEmpty(regId) then // Call to Register the device for Push Notifications GcmClient.Register(this, WruConstants.GcmSender);
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
            
      
        
        
        
      
     
      
        
        
        
      
        . 
      
        
        
        
      
        , -  
      
        
        
        
      
         bitbucket.org/xakpc/whereareyou 
      
        
        
        
      
         ,     
      
        
        
        
      
              ,           "" . 
      
        
        
        
      
     
      
        
        
        
      
      
      
        
        
        
      
     ,   Android   F#.      . 
      
        
        
        
      
     ,       -  Android  F#.   ,       .listView.Adapter <- new ArrayAdapter(this, Android.Resource.Layout.SimpleListItem1, Android.Resource.Id.Text1, values) 
      
        
        
        
      
      , ,  let values = [|"item1"; "item2"; "item3"|]
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     -   string[],       list (IEnumerable   ) 
      
        
        
        
      
              F#.            www.tryfsharp.org/Learn 
      
        
        
        
      
      
 
      
        
        
        
      
          F# -  ,  
      
        
        
        
      
     
      
        
        
        
      
            F# For Fun And Profit 
      
        
        
        
      
     
      
        
        
        
      
       ,    
      
        
        
        
      
         - . 
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
     
      
        
        
        
      
            hash 
      
        
        
        
      
         MD5  F# 
      
        
        
        
      
      let MD5Hash (input : string) = use md5 = System.Security.Cryptography.MD5.Create() input |> System.Text.Encoding.ASCII.GetBytes |> md5.ComputeHash |> Seq.map (fun c -> c.ToString("X2")) |> Seq.reduce (+)
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
      |>
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      pipeline ,     . 
      
        
        
        
      
         :    GetBytes ->   ->      HEX  ->       (  reduce   +           ) ->    . 
      
        
        
        
      
     
      
        
        
        
      
      ,     C# using System; public string CreateMD5Hash (string input) { MD5 md5 = System.Security.Cryptography.MD5.Create(); byte[] inputBytes = System.Text.Encoding.ASCII.GetBytes (input); byte[] hashBytes = md5.ComputeHash (inputBytes); StringBuilder sb = new StringBuilder(); for (int i = 0; i < hashBytes.Length; i++) { sb.Append (hashBytes[i].ToString ("X2")); } return sb.ToString(); }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
     
      
        
        
        
      
              :        .       AzureServiceWorker (  CLR    ) 
      
        
        
        
      
     
      
        
        
        
      
              -   .   F#    !   Xamarin Studio            . 
      
        
        
        
      
      <ItemGroup> <Compile Include="Resources\Resource.designer.fs" /> <Compile Include="Properties\AssemblyInfo.fs" /> <Compile Include="Helpers\Helpers.fs" /> <Compile Include="Services\User.fs" /> <Compile Include="Services\AzureServiceWorker.fs" /> <Compile Include="IAmHereActivity.fs" /> <Compile Include="WhereAreYouActivity.fs" /> <Compile Include="SignInActivity.fs" /> </ItemGroup>
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
        
      
        
        
        
      
            :    .    Xamarin    Xamarin.Mobile 
      
        
        
        
      
     
      
        
        
        
      
          .  F#         TPL,     Task',      .     F#         Task.  ,     : 
      
        
        
        
      
     module Async = open System.Threading open System.Threading.Tasks let inline AwaitPlainTask (task: Task) = // rethrow exception from preceding task if it fauled let continuation (t : Task) : unit = match t.IsFaulted with | true -> raise t.Exception | arg -> () task.ContinueWith continuation |> Async.AwaitTask
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
             Async.AwaitIAsyncResult >> Async.Ignore
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
           
      
        
        
        
      
     
      
        
        
        
      
                
      
        
        
        
      
     let ExtractUserInfo (x : Contact) = let first = x.Phones |> Seq.tryPick(fun x -> if x.Type = PhoneType.Mobile then Some(x) else None) match first with | Some(first) -> let phone = first.Number |> StripChars [' ';'-';'(';')'] UserInfo.CreateUserInfo((MD5Hash phone), phone, x.DisplayName) | None -> UserInfo.CreateUserInfo("no mobile phone", "no mobile phone", "no mobile phone") // function for async list filling let FillContactsAsync = async { let book = new AddressBook (this) let! result = book.RequestPermission() |> Async.AwaitTask if result then _contacts <- book.ToList() |> Seq.filter (fun (x: Contact) -> not (Seq.isEmpty x.Phones)) |> Seq.map ExtractUserInfo |> Seq.sortBy(fun x -> x.DisplayName) |> Seq.toList let finalContacts = _contacts |> Seq.map (fun x -> x.DisplayName.ToUpperInvariant()) |> Seq.toArray this.ListAdapter <- new ArrayAdapter(this, Resource_Layout.row_contact, finalContacts) else System.Diagnostics.Debug.WriteLine("Permission denied by user or manifest") this.ListAdapter <- new ArrayAdapter(this, Resource_Layout.row_contact, Array.empty) }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
          
      
        
        
        
      
     book.ToList()
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
       List |> Seq.filter (fun (x: Contact) -> not (Seq.isEmpty x.Phones))
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
          |> Seq.map ExtractUserInfo
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
          Contracts  UserInfo,      UserInfo |> Seq.sortBy(fun x -> x.DisplayName)
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      |> Seq.toList
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
       List _contacts <-
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
        mutable  _contacts |> Seq.map (fun x -> x.DisplayName.ToUpperInvariant())<-
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
        UserInfo  string,     - -    |> Seq.toArray<-
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      List  Array    ArrayAdapter 
      
        
        
        
      
        -      List.   . 
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
     
      
        
        
        
      
     Azure Mobile Servcies 
      
        
        
        
      
       -    Azure Mobile Services.       NotificationHub,     Push    .   Azure    , ..      . 
      
        
        
        
      
     
      
        
        
        
      
          ,    
      
        
        
        
      
     module WruConstants = [<Literal>] let TotallyNotAzureServer = "https://YOUR.azure-mobile.net/"; [<Literal>] let TotallyNotAzureKey = "YOUR"
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
       
        
        
        
      
     member this.RegisterMe phone name regId = async { try let table = this.MobileService.GetTable<User>() let usr = { Id = "" PhoneHash = MD5Hash phone Nickname = name RegistrationId = regId } do! table.InsertAsync usr |> Async.AwaitPlainTask return (usr.Id, usr.PhoneHash, usr.Nickname) with | e -> System.Diagnostics.Trace.WriteLine(e.ToString) return (String.Empty,String.Empty,String.Empty) }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     member this.RegisterMe phone name regId = async {
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     -       (     )    .       "computation expression"   workflow.   { }       ! ( bang),  do! (do-bang)  let! (let bang)     User.    ,  F#        ,      
      
        
        
        
      
      let usr = { Id = "" PhoneHash = MD5Hash phone Nickname = name RegistrationId = regId }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     do! table.InsertAsync usr |> Async.AwaitPlainTask
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      do-bang,   await
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      C#. ..             continuation    . return (usr.Id, usr.PhoneHash, usr.Nickname)
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
          Tuple<string,string,string>     .  try ... with | e ->
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      try..catch
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      C# 
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
     
      
        
        
        
      
           .  F#    fst
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      snd
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
          .        2 .     : 
      
        
        
        
      
      let id (c,_,_) = c let phonehash (_,c,_) = c let nickname (_,_,c) = c
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
        : id tuple
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      Id  .. 
      
        
        
        
      
     
      
        
        
        
      
        5  Azure,       Push .       Azure Custom Api  
      
        
        
        
      
     
      
        
        
        
      
          exports.post = function(request, response) { // Use "request.service" to access features of your mobile service, eg: // var tables = request.service.tables; // var push = request.service.push; //response.send(statusCodes.OK, { message : 'Hello World!' }); console.log('Incoming call with requst: ', request.body.RequestId); var usersTable = request.service.tables.getTable('User'); usersTable.where( { id : request.body.TargetId } ) .read( { success: function(results) { if (results.length > 0) { var user = results[0] console.log('Send to results: ', user.Nickname, user.RegistrationId); request.service.push.gcm.send(user.RegistrationId, { RequesterId: request.body.RequesterId, RequesterNickname: request.body.RequesterName, TargetId: user.id, TargetNickname: user.Nickname }, { success: function(gcm_response) { console.log('Push notification sent: ', gcm_response); response.send(statusCodes.OK, { RequestedNickname : user.Nickname }); }, error: function(gcm_error) { console.log('Error sending push notification: ', gcm_error); response.send(statusCodes.INTERNAL_SERVER_ERROR, { RequestedNickname : user.Nickname }); } }); } else { response.send(statusCodes.NO_CONTENT, { RequestedNickname : "" }); } }, error: function(error) { console.log('Error read table: ', error); response.send(statusCodes.INTERNAL_SERVER_ERROR, { RequestedNickname : "" }); } }); };
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
        Push      
      
        
        
        
      
     // Perform Push operation member this.PushAsync targetId myId myNickname = async { try let (request : PushRequest) = { TargetId = targetId RequesterId = myId RequesterName = myNickname } let! result = this.MobileService.InvokeApiAsync<PushRequest, PushResponce>("pushhim", request) |> Async.AwaitTask return result.RequestedNickname with | e -> return e.ToString() }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
           ,    let-bang
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
       do!
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
       
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
          Google Play Services.     F#   .           .    : Xamarin.Android.Support.v7.AppCompat 
      
        
        
        
      
         , Google Play Services ,   . 
      
        
        
        
      
     
      
        
        
        
      
          push notification   .    GCM,  ID,     ID       Push  (.   pushhim).        BroadcastReciever       developer.android.com .     F#         Xamarin Component Store.     Google Cloud Messaging Client         GCM    .        ID 
      
        
        
        
      
     //Check to see that GCM is supported and that the manifest has the correct information GcmClient.CheckDevice(this) GcmClient.CheckManifest(this) // check google play if CheckPlayServices() then // Try to get registration id let regId = GcmClient.GetRegistrationId this if String.IsNullOrEmpty(regId) then // Call to Register the device for Push Notifications GcmClient.Register(this, WruConstants.GcmSender);
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
            
      
        
        
        
      
     
      
        
        
        
      
        . 
      
        
        
        
      
        , -  
      
        
        
        
      
         bitbucket.org/xakpc/whereareyou 
      
        
        
        
      
         ,     
      
        
        
        
      
              ,           "" . 
      
        
        
        
      
     
      
        
        
        
      
      
      
        
        
        
      
     ,   Android   F#.      . 
      
        
        
        
      
     ,       -  Android  F#.   ,       .
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     listView.Adapter <- new ArrayAdapter(this, Android.Resource.Layout.SimpleListItem1, Android.Resource.Id.Text1, values) 
      
        
        
        
      
      , ,  let values = [|"item1"; "item2"; "item3"|]
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     -   string[],       list (IEnumerable   ) 
      
        
        
        
      
              F#.            www.tryfsharp.org/Learn 
      
        
        
        
      
      
 
      
        
        
        
      
          F# -  ,  
      
        
        
        
      
     
      
        
        
        
      
            F# For Fun And Profit 
      
        
        
        
      
     
      
        
        
        
      
       ,    
      
        
        
        
      
         - . 
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
     
      
        
        
        
      
            hash 
      
        
        
        
      
         MD5  F# 
      
        
        
        
      
      let MD5Hash (input : string) = use md5 = System.Security.Cryptography.MD5.Create() input |> System.Text.Encoding.ASCII.GetBytes |> md5.ComputeHash |> Seq.map (fun c -> c.ToString("X2")) |> Seq.reduce (+)
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
      |>
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      pipeline ,     . 
      
        
        
        
      
         :    GetBytes ->   ->      HEX  ->       (  reduce   +           ) ->    . 
      
        
        
        
      
     
      
        
        
        
      
      ,     C# using System; public string CreateMD5Hash (string input) { MD5 md5 = System.Security.Cryptography.MD5.Create(); byte[] inputBytes = System.Text.Encoding.ASCII.GetBytes (input); byte[] hashBytes = md5.ComputeHash (inputBytes); StringBuilder sb = new StringBuilder(); for (int i = 0; i < hashBytes.Length; i++) { sb.Append (hashBytes[i].ToString ("X2")); } return sb.ToString(); }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
     
      
        
        
        
      
              :        .       AzureServiceWorker (  CLR    ) 
      
        
        
        
      
     
      
        
        
        
      
              -   .   F#    !   Xamarin Studio            . 
      
        
        
        
      
      <ItemGroup> <Compile Include="Resources\Resource.designer.fs" /> <Compile Include="Properties\AssemblyInfo.fs" /> <Compile Include="Helpers\Helpers.fs" /> <Compile Include="Services\User.fs" /> <Compile Include="Services\AzureServiceWorker.fs" /> <Compile Include="IAmHereActivity.fs" /> <Compile Include="WhereAreYouActivity.fs" /> <Compile Include="SignInActivity.fs" /> </ItemGroup>
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
        
      
        
        
        
      
            :    .    Xamarin    Xamarin.Mobile 
      
        
        
        
      
     
      
        
        
        
      
          .  F#         TPL,     Task',      .     F#         Task.  ,     : 
      
        
        
        
      
     module Async = open System.Threading open System.Threading.Tasks let inline AwaitPlainTask (task: Task) = // rethrow exception from preceding task if it fauled let continuation (t : Task) : unit = match t.IsFaulted with | true -> raise t.Exception | arg -> () task.ContinueWith continuation |> Async.AwaitTask
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
             Async.AwaitIAsyncResult >> Async.Ignore
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
           
      
        
        
        
      
     
      
        
        
        
      
                
      
        
        
        
      
     let ExtractUserInfo (x : Contact) = let first = x.Phones |> Seq.tryPick(fun x -> if x.Type = PhoneType.Mobile then Some(x) else None) match first with | Some(first) -> let phone = first.Number |> StripChars [' ';'-';'(';')'] UserInfo.CreateUserInfo((MD5Hash phone), phone, x.DisplayName) | None -> UserInfo.CreateUserInfo("no mobile phone", "no mobile phone", "no mobile phone") // function for async list filling let FillContactsAsync = async { let book = new AddressBook (this) let! result = book.RequestPermission() |> Async.AwaitTask if result then _contacts <- book.ToList() |> Seq.filter (fun (x: Contact) -> not (Seq.isEmpty x.Phones)) |> Seq.map ExtractUserInfo |> Seq.sortBy(fun x -> x.DisplayName) |> Seq.toList let finalContacts = _contacts |> Seq.map (fun x -> x.DisplayName.ToUpperInvariant()) |> Seq.toArray this.ListAdapter <- new ArrayAdapter(this, Resource_Layout.row_contact, finalContacts) else System.Diagnostics.Debug.WriteLine("Permission denied by user or manifest") this.ListAdapter <- new ArrayAdapter(this, Resource_Layout.row_contact, Array.empty) }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
          
      
        
        
        
      
     book.ToList()
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
       List |> Seq.filter (fun (x: Contact) -> not (Seq.isEmpty x.Phones))
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
          |> Seq.map ExtractUserInfo
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
          Contracts  UserInfo,      UserInfo |> Seq.sortBy(fun x -> x.DisplayName)
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      |> Seq.toList
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
       List _contacts <-
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
        mutable  _contacts |> Seq.map (fun x -> x.DisplayName.ToUpperInvariant())<-
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
        UserInfo  string,     - -    |> Seq.toArray<-
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      List  Array    ArrayAdapter 
      
        
        
        
      
        -      List.   . 
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
     
      
        
        
        
      
     Azure Mobile Servcies 
      
        
        
        
      
       -    Azure Mobile Services.       NotificationHub,     Push    .   Azure    , ..      . 
      
        
        
        
      
     
      
        
        
        
      
          ,    
      
        
        
        
      
     module WruConstants = [<Literal>] let TotallyNotAzureServer = "https://YOUR.azure-mobile.net/"; [<Literal>] let TotallyNotAzureKey = "YOUR"
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
       
        
        
        
      
     member this.RegisterMe phone name regId = async { try let table = this.MobileService.GetTable<User>() let usr = { Id = "" PhoneHash = MD5Hash phone Nickname = name RegistrationId = regId } do! table.InsertAsync usr |> Async.AwaitPlainTask return (usr.Id, usr.PhoneHash, usr.Nickname) with | e -> System.Diagnostics.Trace.WriteLine(e.ToString) return (String.Empty,String.Empty,String.Empty) }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     member this.RegisterMe phone name regId = async {
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     -       (     )    .       "computation expression"   workflow.   { }       ! ( bang),  do! (do-bang)  let! (let bang)     User.    ,  F#        ,      
      
        
        
        
      
      let usr = { Id = "" PhoneHash = MD5Hash phone Nickname = name RegistrationId = regId }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     do! table.InsertAsync usr |> Async.AwaitPlainTask
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      do-bang,   await
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      C#. ..             continuation    . return (usr.Id, usr.PhoneHash, usr.Nickname)
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
          Tuple<string,string,string>     .  try ... with | e ->
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      try..catch
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      C# 
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
     
      
        
        
        
      
           .  F#    fst
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      snd
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
          .        2 .     : 
      
        
        
        
      
      let id (c,_,_) = c let phonehash (_,c,_) = c let nickname (_,_,c) = c
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
        : id tuple
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      Id  .. 
      
        
        
        
      
     
      
        
        
        
      
        5  Azure,       Push .       Azure Custom Api  
      
        
        
        
      
     
      
        
        
        
      
          exports.post = function(request, response) { // Use "request.service" to access features of your mobile service, eg: // var tables = request.service.tables; // var push = request.service.push; //response.send(statusCodes.OK, { message : 'Hello World!' }); console.log('Incoming call with requst: ', request.body.RequestId); var usersTable = request.service.tables.getTable('User'); usersTable.where( { id : request.body.TargetId } ) .read( { success: function(results) { if (results.length > 0) { var user = results[0] console.log('Send to results: ', user.Nickname, user.RegistrationId); request.service.push.gcm.send(user.RegistrationId, { RequesterId: request.body.RequesterId, RequesterNickname: request.body.RequesterName, TargetId: user.id, TargetNickname: user.Nickname }, { success: function(gcm_response) { console.log('Push notification sent: ', gcm_response); response.send(statusCodes.OK, { RequestedNickname : user.Nickname }); }, error: function(gcm_error) { console.log('Error sending push notification: ', gcm_error); response.send(statusCodes.INTERNAL_SERVER_ERROR, { RequestedNickname : user.Nickname }); } }); } else { response.send(statusCodes.NO_CONTENT, { RequestedNickname : "" }); } }, error: function(error) { console.log('Error read table: ', error); response.send(statusCodes.INTERNAL_SERVER_ERROR, { RequestedNickname : "" }); } }); };
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
        Push      
      
        
        
        
      
     // Perform Push operation member this.PushAsync targetId myId myNickname = async { try let (request : PushRequest) = { TargetId = targetId RequesterId = myId RequesterName = myNickname } let! result = this.MobileService.InvokeApiAsync<PushRequest, PushResponce>("pushhim", request) |> Async.AwaitTask return result.RequestedNickname with | e -> return e.ToString() }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
           ,    let-bang
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
       do!
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
       
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
          Google Play Services.     F#   .           .    : Xamarin.Android.Support.v7.AppCompat 
      
        
        
        
      
         , Google Play Services ,   . 
      
        
        
        
      
     
      
        
        
        
      
          push notification   .    GCM,  ID,     ID       Push  (.   pushhim).        BroadcastReciever       developer.android.com .     F#         Xamarin Component Store.     Google Cloud Messaging Client         GCM    .        ID 
      
        
        
        
      
     //Check to see that GCM is supported and that the manifest has the correct information GcmClient.CheckDevice(this) GcmClient.CheckManifest(this) // check google play if CheckPlayServices() then // Try to get registration id let regId = GcmClient.GetRegistrationId this if String.IsNullOrEmpty(regId) then // Call to Register the device for Push Notifications GcmClient.Register(this, WruConstants.GcmSender);
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
            
      
        
        
        
      
     
      
        
        
        
      
        . 
      
        
        
        
      
        , -  
      
        
        
        
      
         bitbucket.org/xakpc/whereareyou 
      
        
        
        
      
         ,     
      
        
        
        
      
              ,           "" . 
      
        
        
        
      
     
      
        
        
        
      
      
      
        
        
        
      
     ,   Android   F#.      . 
      
        
        
        
      
     ,       -  Android  F#.   ,       .
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
    
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      listView.Adapter <- new ArrayAdapter(this, Android.Resource.Layout.SimpleListItem1, Android.Resource.Id.Text1, values) 
      
        
        
        
      
      , ,  let values = [|"item1"; "item2"; "item3"|]
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     -   string[],       list (IEnumerable   ) 
      
        
        
        
      
              F#.            www.tryfsharp.org/Learn 
      
        
        
        
      
      
 
      
        
        
        
      
          F# -  ,  
      
        
        
        
      
     
      
        
        
        
      
            F# For Fun And Profit 
      
        
        
        
      
     
      
        
        
        
      
       ,    
      
        
        
        
      
         - . 
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
     
      
        
        
        
      
            hash 
      
        
        
        
      
         MD5  F# 
      
        
        
        
      
      let MD5Hash (input : string) = use md5 = System.Security.Cryptography.MD5.Create() input |> System.Text.Encoding.ASCII.GetBytes |> md5.ComputeHash |> Seq.map (fun c -> c.ToString("X2")) |> Seq.reduce (+)
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
      |>
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      pipeline ,     . 
      
        
        
        
      
         :    GetBytes ->   ->      HEX  ->       (  reduce   +           ) ->    . 
      
        
        
        
      
     
      
        
        
        
      
      ,     C# using System; public string CreateMD5Hash (string input) { MD5 md5 = System.Security.Cryptography.MD5.Create(); byte[] inputBytes = System.Text.Encoding.ASCII.GetBytes (input); byte[] hashBytes = md5.ComputeHash (inputBytes); StringBuilder sb = new StringBuilder(); for (int i = 0; i < hashBytes.Length; i++) { sb.Append (hashBytes[i].ToString ("X2")); } return sb.ToString(); }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
     
      
        
        
        
      
              :        .       AzureServiceWorker (  CLR    ) 
      
        
        
        
      
     
      
        
        
        
      
              -   .   F#    !   Xamarin Studio            . 
      
        
        
        
      
      <ItemGroup> <Compile Include="Resources\Resource.designer.fs" /> <Compile Include="Properties\AssemblyInfo.fs" /> <Compile Include="Helpers\Helpers.fs" /> <Compile Include="Services\User.fs" /> <Compile Include="Services\AzureServiceWorker.fs" /> <Compile Include="IAmHereActivity.fs" /> <Compile Include="WhereAreYouActivity.fs" /> <Compile Include="SignInActivity.fs" /> </ItemGroup>
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
        
      
        
        
        
      
            :    .    Xamarin    Xamarin.Mobile 
      
        
        
        
      
     
      
        
        
        
      
          .  F#         TPL,     Task',      .     F#         Task.  ,     : 
      
        
        
        
      
     module Async = open System.Threading open System.Threading.Tasks let inline AwaitPlainTask (task: Task) = // rethrow exception from preceding task if it fauled let continuation (t : Task) : unit = match t.IsFaulted with | true -> raise t.Exception | arg -> () task.ContinueWith continuation |> Async.AwaitTask
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
             Async.AwaitIAsyncResult >> Async.Ignore
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
           
      
        
        
        
      
     
      
        
        
        
      
                
      
        
        
        
      
     let ExtractUserInfo (x : Contact) = let first = x.Phones |> Seq.tryPick(fun x -> if x.Type = PhoneType.Mobile then Some(x) else None) match first with | Some(first) -> let phone = first.Number |> StripChars [' ';'-';'(';')'] UserInfo.CreateUserInfo((MD5Hash phone), phone, x.DisplayName) | None -> UserInfo.CreateUserInfo("no mobile phone", "no mobile phone", "no mobile phone") // function for async list filling let FillContactsAsync = async { let book = new AddressBook (this) let! result = book.RequestPermission() |> Async.AwaitTask if result then _contacts <- book.ToList() |> Seq.filter (fun (x: Contact) -> not (Seq.isEmpty x.Phones)) |> Seq.map ExtractUserInfo |> Seq.sortBy(fun x -> x.DisplayName) |> Seq.toList let finalContacts = _contacts |> Seq.map (fun x -> x.DisplayName.ToUpperInvariant()) |> Seq.toArray this.ListAdapter <- new ArrayAdapter(this, Resource_Layout.row_contact, finalContacts) else System.Diagnostics.Debug.WriteLine("Permission denied by user or manifest") this.ListAdapter <- new ArrayAdapter(this, Resource_Layout.row_contact, Array.empty) }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
          
      
        
        
        
      
     book.ToList()
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
       List |> Seq.filter (fun (x: Contact) -> not (Seq.isEmpty x.Phones))
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
          |> Seq.map ExtractUserInfo
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
          Contracts  UserInfo,      UserInfo |> Seq.sortBy(fun x -> x.DisplayName)
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      |> Seq.toList
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
       List _contacts <-
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
        mutable  _contacts |> Seq.map (fun x -> x.DisplayName.ToUpperInvariant())<-
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
        UserInfo  string,     - -    |> Seq.toArray<-
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      List  Array    ArrayAdapter 
      
        
        
        
      
        -      List.   . 
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
     
      
        
        
        
      
     Azure Mobile Servcies 
      
        
        
        
      
       -    Azure Mobile Services.       NotificationHub,     Push    .   Azure    , ..      . 
      
        
        
        
      
     
      
        
        
        
      
          ,    
      
        
        
        
      
     module WruConstants = [<Literal>] let TotallyNotAzureServer = "https://YOUR.azure-mobile.net/"; [<Literal>] let TotallyNotAzureKey = "YOUR"
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
       
        
        
        
      
     member this.RegisterMe phone name regId = async { try let table = this.MobileService.GetTable<User>() let usr = { Id = "" PhoneHash = MD5Hash phone Nickname = name RegistrationId = regId } do! table.InsertAsync usr |> Async.AwaitPlainTask return (usr.Id, usr.PhoneHash, usr.Nickname) with | e -> System.Diagnostics.Trace.WriteLine(e.ToString) return (String.Empty,String.Empty,String.Empty) }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     member this.RegisterMe phone name regId = async {
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     -       (     )    .       "computation expression"   workflow.   { }       ! ( bang),  do! (do-bang)  let! (let bang)     User.    ,  F#        ,      
      
        
        
        
      
      let usr = { Id = "" PhoneHash = MD5Hash phone Nickname = name RegistrationId = regId }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     do! table.InsertAsync usr |> Async.AwaitPlainTask
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      do-bang,   await
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      C#. ..             continuation    . return (usr.Id, usr.PhoneHash, usr.Nickname)
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
          Tuple<string,string,string>     .  try ... with | e ->
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      try..catch
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      C# 
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
     
      
        
        
        
      
           .  F#    fst
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      snd
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
          .        2 .     : 
      
        
        
        
      
      let id (c,_,_) = c let phonehash (_,c,_) = c let nickname (_,_,c) = c
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
        : id tuple
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      Id  .. 
      
        
        
        
      
     
      
        
        
        
      
        5  Azure,       Push .       Azure Custom Api  
      
        
        
        
      
     
      
        
        
        
      
          exports.post = function(request, response) { // Use "request.service" to access features of your mobile service, eg: // var tables = request.service.tables; // var push = request.service.push; //response.send(statusCodes.OK, { message : 'Hello World!' }); console.log('Incoming call with requst: ', request.body.RequestId); var usersTable = request.service.tables.getTable('User'); usersTable.where( { id : request.body.TargetId } ) .read( { success: function(results) { if (results.length > 0) { var user = results[0] console.log('Send to results: ', user.Nickname, user.RegistrationId); request.service.push.gcm.send(user.RegistrationId, { RequesterId: request.body.RequesterId, RequesterNickname: request.body.RequesterName, TargetId: user.id, TargetNickname: user.Nickname }, { success: function(gcm_response) { console.log('Push notification sent: ', gcm_response); response.send(statusCodes.OK, { RequestedNickname : user.Nickname }); }, error: function(gcm_error) { console.log('Error sending push notification: ', gcm_error); response.send(statusCodes.INTERNAL_SERVER_ERROR, { RequestedNickname : user.Nickname }); } }); } else { response.send(statusCodes.NO_CONTENT, { RequestedNickname : "" }); } }, error: function(error) { console.log('Error read table: ', error); response.send(statusCodes.INTERNAL_SERVER_ERROR, { RequestedNickname : "" }); } }); };
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
        Push      
      
        
        
        
      
     // Perform Push operation member this.PushAsync targetId myId myNickname = async { try let (request : PushRequest) = { TargetId = targetId RequesterId = myId RequesterName = myNickname } let! result = this.MobileService.InvokeApiAsync<PushRequest, PushResponce>("pushhim", request) |> Async.AwaitTask return result.RequestedNickname with | e -> return e.ToString() }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
           ,    let-bang
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
       do!
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
       
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
          Google Play Services.     F#   .           .    : Xamarin.Android.Support.v7.AppCompat 
      
        
        
        
      
         , Google Play Services ,   . 
      
        
        
        
      
     
      
        
        
        
      
          push notification   .    GCM,  ID,     ID       Push  (.   pushhim).        BroadcastReciever       developer.android.com .     F#         Xamarin Component Store.     Google Cloud Messaging Client         GCM    .        ID 
      
        
        
        
      
     //Check to see that GCM is supported and that the manifest has the correct information GcmClient.CheckDevice(this) GcmClient.CheckManifest(this) // check google play if CheckPlayServices() then // Try to get registration id let regId = GcmClient.GetRegistrationId this if String.IsNullOrEmpty(regId) then // Call to Register the device for Push Notifications GcmClient.Register(this, WruConstants.GcmSender);
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
            
      
        
        
        
      
     
      
        
        
        
      
        . 
      
        
        
        
      
        , -  
      
        
        
        
      
         bitbucket.org/xakpc/whereareyou 
      
        
        
        
      
         ,     
      
        
        
        
      
              ,           "" . 
      
        
        
        
      
     
      
        
        
        
      
      
      
        
        
        
      
     ,   Android   F#.      . 
      
        
        
        
      
     ,       -  Android  F#.   ,       .
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     listView.Adapter <- new ArrayAdapter(this, Android.Resource.Layout.SimpleListItem1, Android.Resource.Id.Text1, values) 
      
        
        
        
      
      , ,  let values = [|"item1"; "item2"; "item3"|]
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     -   string[],       list (IEnumerable   ) 
      
        
        
        
      
              F#.            www.tryfsharp.org/Learn 
      
        
        
        
      
      
 
      
        
        
        
      
          F# -  ,  
      
        
        
        
      
     
      
        
        
        
      
            F# For Fun And Profit 
      
        
        
        
      
     
      
        
        
        
      
       ,    
      
        
        
        
      
         - . 
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
     
      
        
        
        
      
            hash 
      
        
        
        
      
         MD5  F# 
      
        
        
        
      
      let MD5Hash (input : string) = use md5 = System.Security.Cryptography.MD5.Create() input |> System.Text.Encoding.ASCII.GetBytes |> md5.ComputeHash |> Seq.map (fun c -> c.ToString("X2")) |> Seq.reduce (+)
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
      |>
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      pipeline ,     . 
      
        
        
        
      
         :    GetBytes ->   ->      HEX  ->       (  reduce   +           ) ->    . 
      
        
        
        
      
     
      
        
        
        
      
      ,     C# using System; public string CreateMD5Hash (string input) { MD5 md5 = System.Security.Cryptography.MD5.Create(); byte[] inputBytes = System.Text.Encoding.ASCII.GetBytes (input); byte[] hashBytes = md5.ComputeHash (inputBytes); StringBuilder sb = new StringBuilder(); for (int i = 0; i < hashBytes.Length; i++) { sb.Append (hashBytes[i].ToString ("X2")); } return sb.ToString(); }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
     
      
        
        
        
      
              :        .       AzureServiceWorker (  CLR    ) 
      
        
        
        
      
     
      
        
        
        
      
              -   .   F#    !   Xamarin Studio            . 
      
        
        
        
      
      <ItemGroup> <Compile Include="Resources\Resource.designer.fs" /> <Compile Include="Properties\AssemblyInfo.fs" /> <Compile Include="Helpers\Helpers.fs" /> <Compile Include="Services\User.fs" /> <Compile Include="Services\AzureServiceWorker.fs" /> <Compile Include="IAmHereActivity.fs" /> <Compile Include="WhereAreYouActivity.fs" /> <Compile Include="SignInActivity.fs" /> </ItemGroup>
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
        
      
        
        
        
      
            :    .    Xamarin    Xamarin.Mobile 
      
        
        
        
      
     
      
        
        
        
      
          .  F#         TPL,     Task',      .     F#         Task.  ,     : 
      
        
        
        
      
     module Async = open System.Threading open System.Threading.Tasks let inline AwaitPlainTask (task: Task) = // rethrow exception from preceding task if it fauled let continuation (t : Task) : unit = match t.IsFaulted with | true -> raise t.Exception | arg -> () task.ContinueWith continuation |> Async.AwaitTask
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
             Async.AwaitIAsyncResult >> Async.Ignore
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
           
      
        
        
        
      
     
      
        
        
        
      
                
      
        
        
        
      
     let ExtractUserInfo (x : Contact) = let first = x.Phones |> Seq.tryPick(fun x -> if x.Type = PhoneType.Mobile then Some(x) else None) match first with | Some(first) -> let phone = first.Number |> StripChars [' ';'-';'(';')'] UserInfo.CreateUserInfo((MD5Hash phone), phone, x.DisplayName) | None -> UserInfo.CreateUserInfo("no mobile phone", "no mobile phone", "no mobile phone") // function for async list filling let FillContactsAsync = async { let book = new AddressBook (this) let! result = book.RequestPermission() |> Async.AwaitTask if result then _contacts <- book.ToList() |> Seq.filter (fun (x: Contact) -> not (Seq.isEmpty x.Phones)) |> Seq.map ExtractUserInfo |> Seq.sortBy(fun x -> x.DisplayName) |> Seq.toList let finalContacts = _contacts |> Seq.map (fun x -> x.DisplayName.ToUpperInvariant()) |> Seq.toArray this.ListAdapter <- new ArrayAdapter(this, Resource_Layout.row_contact, finalContacts) else System.Diagnostics.Debug.WriteLine("Permission denied by user or manifest") this.ListAdapter <- new ArrayAdapter(this, Resource_Layout.row_contact, Array.empty) }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
          
      
        
        
        
      
     book.ToList()
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
       List |> Seq.filter (fun (x: Contact) -> not (Seq.isEmpty x.Phones))
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
          |> Seq.map ExtractUserInfo
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
          Contracts  UserInfo,      UserInfo |> Seq.sortBy(fun x -> x.DisplayName)
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      |> Seq.toList
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
       List _contacts <-
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
        mutable  _contacts |> Seq.map (fun x -> x.DisplayName.ToUpperInvariant())<-
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
        UserInfo  string,     - -    |> Seq.toArray<-
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      List  Array    ArrayAdapter 
      
        
        
        
      
        -      List.   . 
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
     
      
        
        
        
      
     Azure Mobile Servcies 
      
        
        
        
      
       -    Azure Mobile Services.       NotificationHub,     Push    .   Azure    , ..      . 
      
        
        
        
      
     
      
        
        
        
      
          ,    
      
        
        
        
      
     module WruConstants = [<Literal>] let TotallyNotAzureServer = "https://YOUR.azure-mobile.net/"; [<Literal>] let TotallyNotAzureKey = "YOUR"
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
       
        
        
        
      
     member this.RegisterMe phone name regId = async { try let table = this.MobileService.GetTable<User>() let usr = { Id = "" PhoneHash = MD5Hash phone Nickname = name RegistrationId = regId } do! table.InsertAsync usr |> Async.AwaitPlainTask return (usr.Id, usr.PhoneHash, usr.Nickname) with | e -> System.Diagnostics.Trace.WriteLine(e.ToString) return (String.Empty,String.Empty,String.Empty) }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     member this.RegisterMe phone name regId = async {
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     -       (     )    .       "computation expression"   workflow.   { }       ! ( bang),  do! (do-bang)  let! (let bang)     User.    ,  F#        ,      
      
        
        
        
      
      let usr = { Id = "" PhoneHash = MD5Hash phone Nickname = name RegistrationId = regId }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     do! table.InsertAsync usr |> Async.AwaitPlainTask
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      do-bang,   await
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      C#. ..             continuation    . return (usr.Id, usr.PhoneHash, usr.Nickname)
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
          Tuple<string,string,string>     .  try ... with | e ->
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      try..catch
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      C# 
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
     
      
        
        
        
      
           .  F#    fst
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      snd
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
          .        2 .     : 
      
        
        
        
      
      let id (c,_,_) = c let phonehash (_,c,_) = c let nickname (_,_,c) = c
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
        : id tuple
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      Id  .. 
      
        
        
        
      
     
      
        
        
        
      
        5  Azure,       Push .       Azure Custom Api  
      
        
        
        
      
     
      
        
        
        
      
          exports.post = function(request, response) { // Use "request.service" to access features of your mobile service, eg: // var tables = request.service.tables; // var push = request.service.push; //response.send(statusCodes.OK, { message : 'Hello World!' }); console.log('Incoming call with requst: ', request.body.RequestId); var usersTable = request.service.tables.getTable('User'); usersTable.where( { id : request.body.TargetId } ) .read( { success: function(results) { if (results.length > 0) { var user = results[0] console.log('Send to results: ', user.Nickname, user.RegistrationId); request.service.push.gcm.send(user.RegistrationId, { RequesterId: request.body.RequesterId, RequesterNickname: request.body.RequesterName, TargetId: user.id, TargetNickname: user.Nickname }, { success: function(gcm_response) { console.log('Push notification sent: ', gcm_response); response.send(statusCodes.OK, { RequestedNickname : user.Nickname }); }, error: function(gcm_error) { console.log('Error sending push notification: ', gcm_error); response.send(statusCodes.INTERNAL_SERVER_ERROR, { RequestedNickname : user.Nickname }); } }); } else { response.send(statusCodes.NO_CONTENT, { RequestedNickname : "" }); } }, error: function(error) { console.log('Error read table: ', error); response.send(statusCodes.INTERNAL_SERVER_ERROR, { RequestedNickname : "" }); } }); };
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
        Push      
      
        
        
        
      
     // Perform Push operation member this.PushAsync targetId myId myNickname = async { try let (request : PushRequest) = { TargetId = targetId RequesterId = myId RequesterName = myNickname } let! result = this.MobileService.InvokeApiAsync<PushRequest, PushResponce>("pushhim", request) |> Async.AwaitTask return result.RequestedNickname with | e -> return e.ToString() }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
           ,    let-bang
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
       do!
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
       
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
          Google Play Services.     F#   .           .    : Xamarin.Android.Support.v7.AppCompat 
      
        
        
        
      
         , Google Play Services ,   . 
      
        
        
        
      
     
      
        
        
        
      
          push notification   .    GCM,  ID,     ID       Push  (.   pushhim).        BroadcastReciever       developer.android.com .     F#         Xamarin Component Store.     Google Cloud Messaging Client         GCM    .        ID 
      
        
        
        
      
     //Check to see that GCM is supported and that the manifest has the correct information GcmClient.CheckDevice(this) GcmClient.CheckManifest(this) // check google play if CheckPlayServices() then // Try to get registration id let regId = GcmClient.GetRegistrationId this if String.IsNullOrEmpty(regId) then // Call to Register the device for Push Notifications GcmClient.Register(this, WruConstants.GcmSender);
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
            
      
        
        
        
      
     
      
        
        
        
      
        . 
      
        
        
        
      
        , -  
      
        
        
        
      
         bitbucket.org/xakpc/whereareyou 
      
        
        
        
      
         ,     
      
        
        
        
      
              ,           "" . 
      
        
        
        
      
     
      
        
        
        
      
      
      
        
        
        
      
     ,   Android   F#.      . 
      
        
        
        
      
     ,       -  Android  F#.   ,       .
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
    
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      listView.Adapter <- new ArrayAdapter(this, Android.Resource.Layout.SimpleListItem1, Android.Resource.Id.Text1, values) 
      
        
        
        
      
      , ,  let values = [|"item1"; "item2"; "item3"|]
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     -   string[],       list (IEnumerable   ) 
      
        
        
        
      
              F#.            www.tryfsharp.org/Learn 
      
        
        
        
      
      
 
      
        
        
        
      
          F# -  ,  
      
        
        
        
      
     
      
        
        
        
      
            F# For Fun And Profit 
      
        
        
        
      
     
      
        
        
        
      
       ,    
      
        
        
        
      
         - . 
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
     
      
        
        
        
      
            hash 
      
        
        
        
      
         MD5  F# 
      
        
        
        
      
      let MD5Hash (input : string) = use md5 = System.Security.Cryptography.MD5.Create() input |> System.Text.Encoding.ASCII.GetBytes |> md5.ComputeHash |> Seq.map (fun c -> c.ToString("X2")) |> Seq.reduce (+)
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
      |>
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      pipeline ,     . 
      
        
        
        
      
         :    GetBytes ->   ->      HEX  ->       (  reduce   +           ) ->    . 
      
        
        
        
      
     
      
        
        
        
      
      ,     C# using System; public string CreateMD5Hash (string input) { MD5 md5 = System.Security.Cryptography.MD5.Create(); byte[] inputBytes = System.Text.Encoding.ASCII.GetBytes (input); byte[] hashBytes = md5.ComputeHash (inputBytes); StringBuilder sb = new StringBuilder(); for (int i = 0; i < hashBytes.Length; i++) { sb.Append (hashBytes[i].ToString ("X2")); } return sb.ToString(); }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
     
      
        
        
        
      
              :        .       AzureServiceWorker (  CLR    ) 
      
        
        
        
      
     
      
        
        
        
      
              -   .   F#    !   Xamarin Studio            . 
      
        
        
        
      
      <ItemGroup> <Compile Include="Resources\Resource.designer.fs" /> <Compile Include="Properties\AssemblyInfo.fs" /> <Compile Include="Helpers\Helpers.fs" /> <Compile Include="Services\User.fs" /> <Compile Include="Services\AzureServiceWorker.fs" /> <Compile Include="IAmHereActivity.fs" /> <Compile Include="WhereAreYouActivity.fs" /> <Compile Include="SignInActivity.fs" /> </ItemGroup>
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
        
      
        
        
        
      
            :    .    Xamarin    Xamarin.Mobile 
      
        
        
        
      
     
      
        
        
        
      
          .  F#         TPL,     Task',      .     F#         Task.  ,     : 
      
        
        
        
      
     module Async = open System.Threading open System.Threading.Tasks let inline AwaitPlainTask (task: Task) = // rethrow exception from preceding task if it fauled let continuation (t : Task) : unit = match t.IsFaulted with | true -> raise t.Exception | arg -> () task.ContinueWith continuation |> Async.AwaitTask
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
             Async.AwaitIAsyncResult >> Async.Ignore
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
           
      
        
        
        
      
     
      
        
        
        
      
                
      
        
        
        
      
     let ExtractUserInfo (x : Contact) = let first = x.Phones |> Seq.tryPick(fun x -> if x.Type = PhoneType.Mobile then Some(x) else None) match first with | Some(first) -> let phone = first.Number |> StripChars [' ';'-';'(';')'] UserInfo.CreateUserInfo((MD5Hash phone), phone, x.DisplayName) | None -> UserInfo.CreateUserInfo("no mobile phone", "no mobile phone", "no mobile phone") // function for async list filling let FillContactsAsync = async { let book = new AddressBook (this) let! result = book.RequestPermission() |> Async.AwaitTask if result then _contacts <- book.ToList() |> Seq.filter (fun (x: Contact) -> not (Seq.isEmpty x.Phones)) |> Seq.map ExtractUserInfo |> Seq.sortBy(fun x -> x.DisplayName) |> Seq.toList let finalContacts = _contacts |> Seq.map (fun x -> x.DisplayName.ToUpperInvariant()) |> Seq.toArray this.ListAdapter <- new ArrayAdapter(this, Resource_Layout.row_contact, finalContacts) else System.Diagnostics.Debug.WriteLine("Permission denied by user or manifest") this.ListAdapter <- new ArrayAdapter(this, Resource_Layout.row_contact, Array.empty) }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
          
      
        
        
        
      
     book.ToList()
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
       List |> Seq.filter (fun (x: Contact) -> not (Seq.isEmpty x.Phones))
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
          |> Seq.map ExtractUserInfo
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
          Contracts  UserInfo,      UserInfo |> Seq.sortBy(fun x -> x.DisplayName)
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      |> Seq.toList
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
       List _contacts <-
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
        mutable  _contacts |> Seq.map (fun x -> x.DisplayName.ToUpperInvariant())<-
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
        UserInfo  string,     - -    |> Seq.toArray<-
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      List  Array    ArrayAdapter 
      
        
        
        
      
        -      List.   . 
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
     
      
        
        
        
      
     Azure Mobile Servcies 
      
        
        
        
      
       -    Azure Mobile Services.       NotificationHub,     Push    .   Azure    , ..      . 
      
        
        
        
      
     
      
        
        
        
      
          ,    
      
        
        
        
      
     module WruConstants = [<Literal>] let TotallyNotAzureServer = "https://YOUR.azure-mobile.net/"; [<Literal>] let TotallyNotAzureKey = "YOUR"
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
       
        
        
        
      
     member this.RegisterMe phone name regId = async { try let table = this.MobileService.GetTable<User>() let usr = { Id = "" PhoneHash = MD5Hash phone Nickname = name RegistrationId = regId } do! table.InsertAsync usr |> Async.AwaitPlainTask return (usr.Id, usr.PhoneHash, usr.Nickname) with | e -> System.Diagnostics.Trace.WriteLine(e.ToString) return (String.Empty,String.Empty,String.Empty) }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     member this.RegisterMe phone name regId = async {
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     -       (     )    .       "computation expression"   workflow.   { }       ! ( bang),  do! (do-bang)  let! (let bang)     User.    ,  F#        ,      
      
        
        
        
      
      let usr = { Id = "" PhoneHash = MD5Hash phone Nickname = name RegistrationId = regId }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     do! table.InsertAsync usr |> Async.AwaitPlainTask
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      do-bang,   await
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      C#. ..             continuation    . return (usr.Id, usr.PhoneHash, usr.Nickname)
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
          Tuple<string,string,string>     .  try ... with | e ->
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      try..catch
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      C# 
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
     
      
        
        
        
      
           .  F#    fst
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      snd
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
          .        2 .     : 
      
        
        
        
      
      let id (c,_,_) = c let phonehash (_,c,_) = c let nickname (_,_,c) = c
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
        : id tuple
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      Id  .. 
      
        
        
        
      
     
      
        
        
        
      
        5  Azure,       Push .       Azure Custom Api  
      
        
        
        
      
     
      
        
        
        
      
          exports.post = function(request, response) { // Use "request.service" to access features of your mobile service, eg: // var tables = request.service.tables; // var push = request.service.push; //response.send(statusCodes.OK, { message : 'Hello World!' }); console.log('Incoming call with requst: ', request.body.RequestId); var usersTable = request.service.tables.getTable('User'); usersTable.where( { id : request.body.TargetId } ) .read( { success: function(results) { if (results.length > 0) { var user = results[0] console.log('Send to results: ', user.Nickname, user.RegistrationId); request.service.push.gcm.send(user.RegistrationId, { RequesterId: request.body.RequesterId, RequesterNickname: request.body.RequesterName, TargetId: user.id, TargetNickname: user.Nickname }, { success: function(gcm_response) { console.log('Push notification sent: ', gcm_response); response.send(statusCodes.OK, { RequestedNickname : user.Nickname }); }, error: function(gcm_error) { console.log('Error sending push notification: ', gcm_error); response.send(statusCodes.INTERNAL_SERVER_ERROR, { RequestedNickname : user.Nickname }); } }); } else { response.send(statusCodes.NO_CONTENT, { RequestedNickname : "" }); } }, error: function(error) { console.log('Error read table: ', error); response.send(statusCodes.INTERNAL_SERVER_ERROR, { RequestedNickname : "" }); } }); };
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
        Push      
      
        
        
        
      
     // Perform Push operation member this.PushAsync targetId myId myNickname = async { try let (request : PushRequest) = { TargetId = targetId RequesterId = myId RequesterName = myNickname } let! result = this.MobileService.InvokeApiAsync<PushRequest, PushResponce>("pushhim", request) |> Async.AwaitTask return result.RequestedNickname with | e -> return e.ToString() }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
           ,    let-bang
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
       do!
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
       
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
          Google Play Services.     F#   .           .    : Xamarin.Android.Support.v7.AppCompat 
      
        
        
        
      
         , Google Play Services ,   . 
      
        
        
        
      
     
      
        
        
        
      
          push notification   .    GCM,  ID,     ID       Push  (.   pushhim).        BroadcastReciever       developer.android.com .     F#         Xamarin Component Store.     Google Cloud Messaging Client         GCM    .        ID 
      
        
        
        
      
     //Check to see that GCM is supported and that the manifest has the correct information GcmClient.CheckDevice(this) GcmClient.CheckManifest(this) // check google play if CheckPlayServices() then // Try to get registration id let regId = GcmClient.GetRegistrationId this if String.IsNullOrEmpty(regId) then // Call to Register the device for Push Notifications GcmClient.Register(this, WruConstants.GcmSender);
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
            
      
        
        
        
      
     
      
        
        
        
      
        . 
      
        
        
        
      
        , -  
      
        
        
        
      
         bitbucket.org/xakpc/whereareyou 
      
        
        
        
      
         ,     
      
        
        
        
      
              ,           "" . 
      
        
        
        
      
     
      
        
        
        
      
      
      
        
        
        
      
     ,   Android   F#.      . 
      
        
        
        
      
     ,       -  Android  F#.   ,       .
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
    -  listView.Adapter <- new ArrayAdapter(this, Android.Resource.Layout.SimpleListItem1, Android.Resource.Id.Text1, values)
 
 , , let values = [|"item1"; "item2"; "item3"|]
 
 
 
 - string[], list (IEnumerable )
 
 F#. www.tryfsharp.org/Learn
 
   
 
 F# - ,
 
 
 
 F# For Fun And Profit
 
 
 
 ,
 
 - .
 
 
 
   
 
 
 
 hash
 
 MD5 F#
 
 let MD5Hash (input : string) = use md5 = System.Security.Cryptography.MD5.Create() input |> System.Text.Encoding.ASCII.GetBytes |> md5.ComputeHash |> Seq.map (fun c -> c.ToString("X2")) |> Seq.reduce (+)
 
 
 
 
 
 
 
 |>
 
 
 
 pipeline , .
 
 : GetBytes -> -> HEX -> ( reduce + ) -> .
 
 
 
 , C#using System; public string CreateMD5Hash (string input) { MD5 md5 = System.Security.Cryptography.MD5.Create(); byte[] inputBytes = System.Text.Encoding.ASCII.GetBytes (input); byte[] hashBytes = md5.ComputeHash (inputBytes); StringBuilder sb = new StringBuilder(); for (int i = 0; i < hashBytes.Length; i++) { sb.Append (hashBytes[i].ToString ("X2")); } return sb.ToString(); }
 
 
 
 
 
 
 
 
 
 : . AzureServiceWorker ( CLR )
 
 
 
 - . F# ! Xamarin Studio .
 
 <ItemGroup> <Compile Include="Resources\Resource.designer.fs" /> <Compile Include="Properties\AssemblyInfo.fs" /> <Compile Include="Helpers\Helpers.fs" /> <Compile Include="Services\User.fs" /> <Compile Include="Services\AzureServiceWorker.fs" /> <Compile Include="IAmHereActivity.fs" /> <Compile Include="WhereAreYouActivity.fs" /> <Compile Include="SignInActivity.fs" /> </ItemGroup>
 
 
 
 
 
 
 
 
 
 : . Xamarin Xamarin.Mobile
 
 
 
 . F# TPL, Task', . F# Task. , :
 
 module Async = open System.Threading open System.Threading.Tasks let inline AwaitPlainTask (task: Task) = // rethrow exception from preceding task if it fauled let continuation (t : Task) : unit = match t.IsFaulted with | true -> raise t.Exception | arg -> () task.ContinueWith continuation |> Async.AwaitTask
 
 
 
 
 
 Async.AwaitIAsyncResult >> Async.Ignore
 
 
 
 
 
 
 
 
 
 let ExtractUserInfo (x : Contact) = let first = x.Phones |> Seq.tryPick(fun x -> if x.Type = PhoneType.Mobile then Some(x) else None) match first with | Some(first) -> let phone = first.Number |> StripChars [' ';'-';'(';')'] UserInfo.CreateUserInfo((MD5Hash phone), phone, x.DisplayName) | None -> UserInfo.CreateUserInfo("no mobile phone", "no mobile phone", "no mobile phone") // function for async list filling let FillContactsAsync = async { let book = new AddressBook (this) let! result = book.RequestPermission() |> Async.AwaitTask if result then _contacts <- book.ToList() |> Seq.filter (fun (x: Contact) -> not (Seq.isEmpty x.Phones)) |> Seq.map ExtractUserInfo |> Seq.sortBy(fun x -> x.DisplayName) |> Seq.toList let finalContacts = _contacts |> Seq.map (fun x -> x.DisplayName.ToUpperInvariant()) |> Seq.toArray this.ListAdapter <- new ArrayAdapter(this, Resource_Layout.row_contact, finalContacts) else System.Diagnostics.Debug.WriteLine("Permission denied by user or manifest") this.ListAdapter <- new ArrayAdapter(this, Resource_Layout.row_contact, Array.empty) }
 
 
 
 
 
 
 
 book.ToList()
 
 
 
 List|> Seq.filter (fun (x: Contact) -> not (Seq.isEmpty x.Phones))
 
 
 
 |> Seq.map ExtractUserInfo
 
 
 
 Contracts UserInfo, UserInfo|> Seq.sortBy(fun x -> x.DisplayName)
 
 
 
 |> Seq.toList
 
 
 
 List_contacts <-
 
 
 
 mutable_contacts |> Seq.map (fun x -> x.DisplayName.ToUpperInvariant())<-
 
 
 
 UserInfo string, - -|> Seq.toArray<-
 
 
 
 List Array ArrayAdapter
 
 - List. .
 
 
 
   
 
 
 
 Azure Mobile Servcies
 
 - Azure Mobile Services. NotificationHub, Push . Azure , .. .
 
 
 
 ,
 
 module WruConstants = [<Literal>] let TotallyNotAzureServer = "https://YOUR.azure-mobile.net/"; [<Literal>] let TotallyNotAzureKey = "YOUR"
 
 
 
 
 
 
 
 
 
 member this.RegisterMe phone name regId = async { try let table = this.MobileService.GetTable<User>() let usr = { Id = "" PhoneHash = MD5Hash phone Nickname = name RegistrationId = regId } do! table.InsertAsync usr |> Async.AwaitPlainTask return (usr.Id, usr.PhoneHash, usr.Nickname) with | e -> System.Diagnostics.Trace.WriteLine(e.ToString) return (String.Empty,String.Empty,String.Empty) }
 
 
 
 
 
 member this.RegisterMe phone name regId = async {
 
 
 
 - ( ) . "computation expression" workflow. { } ! ( bang), do! (do-bang) let! (let bang) User. , F# ,
 
 let usr = { Id = "" PhoneHash = MD5Hash phone Nickname = name RegistrationId = regId }
 
 
 
 do! table.InsertAsync usr |> Async.AwaitPlainTask
 
 
 
 do-bang,await
 
 
 
 C#. .. continuation .return (usr.Id, usr.PhoneHash, usr.Nickname)
 
 
 
 Tuple<string,string,string> .try ... with | e ->
 
 
 
 try..catch
 
 
 
 C#
 
 
 
   
 
 
 
 . F#fst
 
 
 
 snd
 
 
 
 . 2 . :
 
 let id (c,_,_) = c let phonehash (_,c,_) = c let nickname (_,_,c) = c
 
 
 
 
 
 :id tuple
 
 
 
 Id ..
 
 
 
 5 Azure, Push . Azure Custom Api
 
 
 
 exports.post = function(request, response) { // Use "request.service" to access features of your mobile service, eg: // var tables = request.service.tables; // var push = request.service.push; //response.send(statusCodes.OK, { message : 'Hello World!' }); console.log('Incoming call with requst: ', request.body.RequestId); var usersTable = request.service.tables.getTable('User'); usersTable.where( { id : request.body.TargetId } ) .read( { success: function(results) { if (results.length > 0) { var user = results[0] console.log('Send to results: ', user.Nickname, user.RegistrationId); request.service.push.gcm.send(user.RegistrationId, { RequesterId: request.body.RequesterId, RequesterNickname: request.body.RequesterName, TargetId: user.id, TargetNickname: user.Nickname }, { success: function(gcm_response) { console.log('Push notification sent: ', gcm_response); response.send(statusCodes.OK, { RequestedNickname : user.Nickname }); }, error: function(gcm_error) { console.log('Error sending push notification: ', gcm_error); response.send(statusCodes.INTERNAL_SERVER_ERROR, { RequestedNickname : user.Nickname }); } }); } else { response.send(statusCodes.NO_CONTENT, { RequestedNickname : "" }); } }, error: function(error) { console.log('Error read table: ', error); response.send(statusCodes.INTERNAL_SERVER_ERROR, { RequestedNickname : "" }); } }); };
 
 
 
 
 
 
 
 Push
 
 // Perform Push operation member this.PushAsync targetId myId myNickname = async { try let (request : PushRequest) = { TargetId = targetId RequesterId = myId RequesterName = myNickname } let! result = this.MobileService.InvokeApiAsync<PushRequest, PushResponce>("pushhim", request) |> Async.AwaitTask return result.RequestedNickname with | e -> return e.ToString() }
 
 
 
 
 
 
 
 ,let-bang
 
 
 
 do!
 
 
 
 
 
 
 
 
 
 
 
   
 
 Google Play Services. F# . . : Xamarin.Android.Support.v7.AppCompat
 
 , Google Play Services , .
 
 
 
 push notification . GCM, ID, ID Push (. pushhim). BroadcastReciever developer.android.com . F# Xamarin Component Store. Google Cloud Messaging Client GCM . ID
 
 //Check to see that GCM is supported and that the manifest has the correct information GcmClient.CheckDevice(this) GcmClient.CheckManifest(this) // check google play if CheckPlayServices() then // Try to get registration id let regId = GcmClient.GetRegistrationId this if String.IsNullOrEmpty(regId) then // Call to Register the device for Push Notifications GcmClient.Register(this, WruConstants.GcmSender);
 
 
 
 
 
 
 
   
 
 
 
 
 
 .
 
 , -
 
 bitbucket.org/xakpc/whereareyou
 
 ,
 
 , "" .
 
 
 
 
 
 , Android F#. .
 
 , - Android F#. , .
 
 
 
 
 
 
 
 
-  listView.Adapter <- new ArrayAdapter(this, Android.Resource.Layout.SimpleListItem1, Android.Resource.Id.Text1, values)
 
 , , let values = [|"item1"; "item2"; "item3"|]
 
 
 
 - string[], list (IEnumerable )
 
 F#. www.tryfsharp.org/Learn
 
   
 
 F# - ,
 
 
 
 F# For Fun And Profit
 
 
 
 ,
 
 - .
 
 
 
   
 
 
 
 hash
 
 MD5 F#
 
 let MD5Hash (input : string) = use md5 = System.Security.Cryptography.MD5.Create() input |> System.Text.Encoding.ASCII.GetBytes |> md5.ComputeHash |> Seq.map (fun c -> c.ToString("X2")) |> Seq.reduce (+)
 
 
 
 
 
 
 
 |>
 
 
 
 pipeline , .
 
 : GetBytes -> -> HEX -> ( reduce + ) -> .
 
 
 
 , C#using System; public string CreateMD5Hash (string input) { MD5 md5 = System.Security.Cryptography.MD5.Create(); byte[] inputBytes = System.Text.Encoding.ASCII.GetBytes (input); byte[] hashBytes = md5.ComputeHash (inputBytes); StringBuilder sb = new StringBuilder(); for (int i = 0; i < hashBytes.Length; i++) { sb.Append (hashBytes[i].ToString ("X2")); } return sb.ToString(); }
 
 
 
 
 
 
 
 
 
 : . AzureServiceWorker ( CLR )
 
 
 
 - . F# ! Xamarin Studio .
 
 <ItemGroup> <Compile Include="Resources\Resource.designer.fs" /> <Compile Include="Properties\AssemblyInfo.fs" /> <Compile Include="Helpers\Helpers.fs" /> <Compile Include="Services\User.fs" /> <Compile Include="Services\AzureServiceWorker.fs" /> <Compile Include="IAmHereActivity.fs" /> <Compile Include="WhereAreYouActivity.fs" /> <Compile Include="SignInActivity.fs" /> </ItemGroup>
 
 
 
 
 
 
 
 
 
 : . Xamarin Xamarin.Mobile
 
 
 
 . F# TPL, Task', . F# Task. , :
 
 module Async = open System.Threading open System.Threading.Tasks let inline AwaitPlainTask (task: Task) = // rethrow exception from preceding task if it fauled let continuation (t : Task) : unit = match t.IsFaulted with | true -> raise t.Exception | arg -> () task.ContinueWith continuation |> Async.AwaitTask
 
 
 
 
 
 Async.AwaitIAsyncResult >> Async.Ignore
 
 
 
 
 
 
 
 
 
 let ExtractUserInfo (x : Contact) = let first = x.Phones |> Seq.tryPick(fun x -> if x.Type = PhoneType.Mobile then Some(x) else None) match first with | Some(first) -> let phone = first.Number |> StripChars [' ';'-';'(';')'] UserInfo.CreateUserInfo((MD5Hash phone), phone, x.DisplayName) | None -> UserInfo.CreateUserInfo("no mobile phone", "no mobile phone", "no mobile phone") // function for async list filling let FillContactsAsync = async { let book = new AddressBook (this) let! result = book.RequestPermission() |> Async.AwaitTask if result then _contacts <- book.ToList() |> Seq.filter (fun (x: Contact) -> not (Seq.isEmpty x.Phones)) |> Seq.map ExtractUserInfo |> Seq.sortBy(fun x -> x.DisplayName) |> Seq.toList let finalContacts = _contacts |> Seq.map (fun x -> x.DisplayName.ToUpperInvariant()) |> Seq.toArray this.ListAdapter <- new ArrayAdapter(this, Resource_Layout.row_contact, finalContacts) else System.Diagnostics.Debug.WriteLine("Permission denied by user or manifest") this.ListAdapter <- new ArrayAdapter(this, Resource_Layout.row_contact, Array.empty) }
 
 
 
 
 
 
 
 book.ToList()
 
 
 
 List|> Seq.filter (fun (x: Contact) -> not (Seq.isEmpty x.Phones))
 
 
 
 |> Seq.map ExtractUserInfo
 
 
 
 Contracts UserInfo, UserInfo|> Seq.sortBy(fun x -> x.DisplayName)
 
 
 
 |> Seq.toList
 
 
 
 List_contacts <-
 
 
 
 mutable_contacts |> Seq.map (fun x -> x.DisplayName.ToUpperInvariant())<-
 
 
 
 UserInfo string, - -|> Seq.toArray<-
 
 
 
 List Array ArrayAdapter
 
 - List. .
 
 
 
   
 
 
 
 Azure Mobile Servcies
 
 - Azure Mobile Services. NotificationHub, Push . Azure , .. .
 
 
 
 ,
 
 module WruConstants = [<Literal>] let TotallyNotAzureServer = "https://YOUR.azure-mobile.net/"; [<Literal>] let TotallyNotAzureKey = "YOUR"
 
 
 
 
 
 
 
 
 
 member this.RegisterMe phone name regId = async { try let table = this.MobileService.GetTable<User>() let usr = { Id = "" PhoneHash = MD5Hash phone Nickname = name RegistrationId = regId } do! table.InsertAsync usr |> Async.AwaitPlainTask return (usr.Id, usr.PhoneHash, usr.Nickname) with | e -> System.Diagnostics.Trace.WriteLine(e.ToString) return (String.Empty,String.Empty,String.Empty) }
 
 
 
 
 
 member this.RegisterMe phone name regId = async {
 
 
 
 - ( ) . "computation expression" workflow. { } ! ( bang), do! (do-bang) let! (let bang) User. , F# ,
 
 let usr = { Id = "" PhoneHash = MD5Hash phone Nickname = name RegistrationId = regId }
 
 
 
 do! table.InsertAsync usr |> Async.AwaitPlainTask
 
 
 
 do-bang,await
 
 
 
 C#. .. continuation .return (usr.Id, usr.PhoneHash, usr.Nickname)
 
 
 
 Tuple<string,string,string> .try ... with | e ->
 
 
 
 try..catch
 
 
 
 C#
 
 
 
   
 
 
 
 . F#fst
 
 
 
 snd
 
 
 
 . 2 . :
 
 let id (c,_,_) = c let phonehash (_,c,_) = c let nickname (_,_,c) = c
 
 
 
 
 
 :id tuple
 
 
 
 Id ..
 
 
 
 5 Azure, Push . Azure Custom Api
 
 
 
 exports.post = function(request, response) { // Use "request.service" to access features of your mobile service, eg: // var tables = request.service.tables; // var push = request.service.push; //response.send(statusCodes.OK, { message : 'Hello World!' }); console.log('Incoming call with requst: ', request.body.RequestId); var usersTable = request.service.tables.getTable('User'); usersTable.where( { id : request.body.TargetId } ) .read( { success: function(results) { if (results.length > 0) { var user = results[0] console.log('Send to results: ', user.Nickname, user.RegistrationId); request.service.push.gcm.send(user.RegistrationId, { RequesterId: request.body.RequesterId, RequesterNickname: request.body.RequesterName, TargetId: user.id, TargetNickname: user.Nickname }, { success: function(gcm_response) { console.log('Push notification sent: ', gcm_response); response.send(statusCodes.OK, { RequestedNickname : user.Nickname }); }, error: function(gcm_error) { console.log('Error sending push notification: ', gcm_error); response.send(statusCodes.INTERNAL_SERVER_ERROR, { RequestedNickname : user.Nickname }); } }); } else { response.send(statusCodes.NO_CONTENT, { RequestedNickname : "" }); } }, error: function(error) { console.log('Error read table: ', error); response.send(statusCodes.INTERNAL_SERVER_ERROR, { RequestedNickname : "" }); } }); };
 
 
 
 
 
 
 
 Push
 
 // Perform Push operation member this.PushAsync targetId myId myNickname = async { try let (request : PushRequest) = { TargetId = targetId RequesterId = myId RequesterName = myNickname } let! result = this.MobileService.InvokeApiAsync<PushRequest, PushResponce>("pushhim", request) |> Async.AwaitTask return result.RequestedNickname with | e -> return e.ToString() }
 
 
 
 
 
 
 
 ,let-bang
 
 
 
 do!
 
 
 
 
 
 
 
 
 
 
 
   
 
 Google Play Services. F# . . : Xamarin.Android.Support.v7.AppCompat
 
 , Google Play Services , .
 
 
 
 push notification . GCM, ID, ID Push (. pushhim). BroadcastReciever developer.android.com . F# Xamarin Component Store. Google Cloud Messaging Client GCM . ID
 
 //Check to see that GCM is supported and that the manifest has the correct information GcmClient.CheckDevice(this) GcmClient.CheckManifest(this) // check google play if CheckPlayServices() then // Try to get registration id let regId = GcmClient.GetRegistrationId this if String.IsNullOrEmpty(regId) then // Call to Register the device for Push Notifications GcmClient.Register(this, WruConstants.GcmSender);
 
 
 
 
 
 
 
   
 
 
 
 
 
 .
 
 , -
 
 bitbucket.org/xakpc/whereareyou
 
 ,
 
 , "" .
 
 
 
 
 
 , Android F#. .
 
 , - Android F#. , .
 
 
 
 
 
 
 
 listView.Adapter <- new ArrayAdapter(this, Android.Resource.Layout.SimpleListItem1, Android.Resource.Id.Text1, values)
 
 , , let values = [|"item1"; "item2"; "item3"|]
 
 
 
 - string[], list (IEnumerable )
 
 F#. www.tryfsharp.org/Learn
 
   
 
 F# - ,
 
 
 
 F# For Fun And Profit
 
 
 
 ,
 
 - .
 
 
 
   
 
 
 
 hash
 
 MD5 F#
 
 let MD5Hash (input : string) = use md5 = System.Security.Cryptography.MD5.Create() input |> System.Text.Encoding.ASCII.GetBytes |> md5.ComputeHash |> Seq.map (fun c -> c.ToString("X2")) |> Seq.reduce (+)
 
 
 
 
 
 
 
 |>
 
 
 
 pipeline , .
 
 : GetBytes -> -> HEX -> ( reduce + ) -> .
 
 
 
 , C#using System; public string CreateMD5Hash (string input) { MD5 md5 = System.Security.Cryptography.MD5.Create(); byte[] inputBytes = System.Text.Encoding.ASCII.GetBytes (input); byte[] hashBytes = md5.ComputeHash (inputBytes); StringBuilder sb = new StringBuilder(); for (int i = 0; i < hashBytes.Length; i++) { sb.Append (hashBytes[i].ToString ("X2")); } return sb.ToString(); }
 
 
 
 
 
 
 
 
 
 : . AzureServiceWorker ( CLR )
 
 
 
 - . F# ! Xamarin Studio .
 
 <ItemGroup> <Compile Include="Resources\Resource.designer.fs" /> <Compile Include="Properties\AssemblyInfo.fs" /> <Compile Include="Helpers\Helpers.fs" /> <Compile Include="Services\User.fs" /> <Compile Include="Services\AzureServiceWorker.fs" /> <Compile Include="IAmHereActivity.fs" /> <Compile Include="WhereAreYouActivity.fs" /> <Compile Include="SignInActivity.fs" /> </ItemGroup>
 
 
 
 
 
 
 
 
 
 : . Xamarin Xamarin.Mobile
 
 
 
 . F# TPL, Task', . F# Task. , :
 
 module Async = open System.Threading open System.Threading.Tasks let inline AwaitPlainTask (task: Task) = // rethrow exception from preceding task if it fauled let continuation (t : Task) : unit = match t.IsFaulted with | true -> raise t.Exception | arg -> () task.ContinueWith continuation |> Async.AwaitTask
 
 
 
 
 
 Async.AwaitIAsyncResult >> Async.Ignore
 
 
 
 
 
 
 
 
 
 let ExtractUserInfo (x : Contact) = let first = x.Phones |> Seq.tryPick(fun x -> if x.Type = PhoneType.Mobile then Some(x) else None) match first with | Some(first) -> let phone = first.Number |> StripChars [' ';'-';'(';')'] UserInfo.CreateUserInfo((MD5Hash phone), phone, x.DisplayName) | None -> UserInfo.CreateUserInfo("no mobile phone", "no mobile phone", "no mobile phone") // function for async list filling let FillContactsAsync = async { let book = new AddressBook (this) let! result = book.RequestPermission() |> Async.AwaitTask if result then _contacts <- book.ToList() |> Seq.filter (fun (x: Contact) -> not (Seq.isEmpty x.Phones)) |> Seq.map ExtractUserInfo |> Seq.sortBy(fun x -> x.DisplayName) |> Seq.toList let finalContacts = _contacts |> Seq.map (fun x -> x.DisplayName.ToUpperInvariant()) |> Seq.toArray this.ListAdapter <- new ArrayAdapter(this, Resource_Layout.row_contact, finalContacts) else System.Diagnostics.Debug.WriteLine("Permission denied by user or manifest") this.ListAdapter <- new ArrayAdapter(this, Resource_Layout.row_contact, Array.empty) }
 
 
 
 
 
 
 
 book.ToList()
 
 
 
 List|> Seq.filter (fun (x: Contact) -> not (Seq.isEmpty x.Phones))
 
 
 
 |> Seq.map ExtractUserInfo
 
 
 
 Contracts UserInfo, UserInfo|> Seq.sortBy(fun x -> x.DisplayName)
 
 
 
 |> Seq.toList
 
 
 
 List_contacts <-
 
 
 
 mutable_contacts |> Seq.map (fun x -> x.DisplayName.ToUpperInvariant())<-
 
 
 
 UserInfo string, - -|> Seq.toArray<-
 
 
 
 List Array ArrayAdapter
 
 - List. .
 
 
 
   
 
 
 
 Azure Mobile Servcies
 
 - Azure Mobile Services. NotificationHub, Push . Azure , .. .
 
 
 
 ,
 
 module WruConstants = [<Literal>] let TotallyNotAzureServer = "https://YOUR.azure-mobile.net/"; [<Literal>] let TotallyNotAzureKey = "YOUR"
 
 
 
 
 
 
 
 
 
 member this.RegisterMe phone name regId = async { try let table = this.MobileService.GetTable<User>() let usr = { Id = "" PhoneHash = MD5Hash phone Nickname = name RegistrationId = regId } do! table.InsertAsync usr |> Async.AwaitPlainTask return (usr.Id, usr.PhoneHash, usr.Nickname) with | e -> System.Diagnostics.Trace.WriteLine(e.ToString) return (String.Empty,String.Empty,String.Empty) }
 
 
 
 
 
 member this.RegisterMe phone name regId = async {
 
 
 
 - ( ) . "computation expression" workflow. { } ! ( bang), do! (do-bang) let! (let bang) User. , F# ,
 
 let usr = { Id = "" PhoneHash = MD5Hash phone Nickname = name RegistrationId = regId }
 
 
 
 do! table.InsertAsync usr |> Async.AwaitPlainTask
 
 
 
 do-bang,await
 
 
 
 C#. .. continuation .return (usr.Id, usr.PhoneHash, usr.Nickname)
 
 
 
 Tuple<string,string,string> .try ... with | e ->
 
 
 
 try..catch
 
 
 
 C#
 
 
 
   
 
 
 
 . F#fst
 
 
 
 snd
 
 
 
 . 2 . :
 
 let id (c,_,_) = c let phonehash (_,c,_) = c let nickname (_,_,c) = c
 
 
 
 
 
 :id tuple
 
 
 
 Id ..
 
 
 
 5 Azure, Push . Azure Custom Api
 
 
 
 exports.post = function(request, response) { // Use "request.service" to access features of your mobile service, eg: // var tables = request.service.tables; // var push = request.service.push; //response.send(statusCodes.OK, { message : 'Hello World!' }); console.log('Incoming call with requst: ', request.body.RequestId); var usersTable = request.service.tables.getTable('User'); usersTable.where( { id : request.body.TargetId } ) .read( { success: function(results) { if (results.length > 0) { var user = results[0] console.log('Send to results: ', user.Nickname, user.RegistrationId); request.service.push.gcm.send(user.RegistrationId, { RequesterId: request.body.RequesterId, RequesterNickname: request.body.RequesterName, TargetId: user.id, TargetNickname: user.Nickname }, { success: function(gcm_response) { console.log('Push notification sent: ', gcm_response); response.send(statusCodes.OK, { RequestedNickname : user.Nickname }); }, error: function(gcm_error) { console.log('Error sending push notification: ', gcm_error); response.send(statusCodes.INTERNAL_SERVER_ERROR, { RequestedNickname : user.Nickname }); } }); } else { response.send(statusCodes.NO_CONTENT, { RequestedNickname : "" }); } }, error: function(error) { console.log('Error read table: ', error); response.send(statusCodes.INTERNAL_SERVER_ERROR, { RequestedNickname : "" }); } }); };
 
 
 
 
 
 
 
 Push
 
 // Perform Push operation member this.PushAsync targetId myId myNickname = async { try let (request : PushRequest) = { TargetId = targetId RequesterId = myId RequesterName = myNickname } let! result = this.MobileService.InvokeApiAsync<PushRequest, PushResponce>("pushhim", request) |> Async.AwaitTask return result.RequestedNickname with | e -> return e.ToString() }
 
 
 
 
 
 
 
 ,let-bang
 
 
 
 do!
 
 
 
 
 
 
 
 
 
 
 
   
 
 Google Play Services. F# . . : Xamarin.Android.Support.v7.AppCompat
 
 , Google Play Services , .
 
 
 
 push notification . GCM, ID, ID Push (. pushhim). BroadcastReciever developer.android.com . F# Xamarin Component Store. Google Cloud Messaging Client GCM . ID
 
 //Check to see that GCM is supported and that the manifest has the correct information GcmClient.CheckDevice(this) GcmClient.CheckManifest(this) // check google play if CheckPlayServices() then // Try to get registration id let regId = GcmClient.GetRegistrationId this if String.IsNullOrEmpty(regId) then // Call to Register the device for Push Notifications GcmClient.Register(this, WruConstants.GcmSender);
 
 
 
 
 
 
 
   
 
 
 
 
 
 .
 
 , -
 
 bitbucket.org/xakpc/whereareyou
 
 ,
 
 , "" .
 
 
 
 
 
 , Android F#. .
 
 , - Android F#. , .
 
 
 
 
 
 
 
 
-  listView.Adapter <- new ArrayAdapter(this, Android.Resource.Layout.SimpleListItem1, Android.Resource.Id.Text1, values)
 
 , , let values = [|"item1"; "item2"; "item3"|]
 
 
 
 - string[], list (IEnumerable )
 
 F#. www.tryfsharp.org/Learn
 
   
 
 F# - ,
 
 
 
 F# For Fun And Profit
 
 
 
 ,
 
 - .
 
 
 
   
 
 
 
 hash
 
 MD5 F#
 
 let MD5Hash (input : string) = use md5 = System.Security.Cryptography.MD5.Create() input |> System.Text.Encoding.ASCII.GetBytes |> md5.ComputeHash |> Seq.map (fun c -> c.ToString("X2")) |> Seq.reduce (+)
 
 
 
 
 
 
 
 |>
 
 
 
 pipeline , .
 
 : GetBytes -> -> HEX -> ( reduce + ) -> .
 
 
 
 , C#using System; public string CreateMD5Hash (string input) { MD5 md5 = System.Security.Cryptography.MD5.Create(); byte[] inputBytes = System.Text.Encoding.ASCII.GetBytes (input); byte[] hashBytes = md5.ComputeHash (inputBytes); StringBuilder sb = new StringBuilder(); for (int i = 0; i < hashBytes.Length; i++) { sb.Append (hashBytes[i].ToString ("X2")); } return sb.ToString(); }
 
 
 
 
 
 
 
 
 
 : . AzureServiceWorker ( CLR )
 
 
 
 - . F# ! Xamarin Studio .
 
 <ItemGroup> <Compile Include="Resources\Resource.designer.fs" /> <Compile Include="Properties\AssemblyInfo.fs" /> <Compile Include="Helpers\Helpers.fs" /> <Compile Include="Services\User.fs" /> <Compile Include="Services\AzureServiceWorker.fs" /> <Compile Include="IAmHereActivity.fs" /> <Compile Include="WhereAreYouActivity.fs" /> <Compile Include="SignInActivity.fs" /> </ItemGroup>
 
 
 
 
 
 
 
 
 
 : . Xamarin Xamarin.Mobile
 
 
 
 . F# TPL, Task', . F# Task. , :
 
 module Async = open System.Threading open System.Threading.Tasks let inline AwaitPlainTask (task: Task) = // rethrow exception from preceding task if it fauled let continuation (t : Task) : unit = match t.IsFaulted with | true -> raise t.Exception | arg -> () task.ContinueWith continuation |> Async.AwaitTask
 
 
 
 
 
 Async.AwaitIAsyncResult >> Async.Ignore
 
 
 
 
 
 
 
 
 
 let ExtractUserInfo (x : Contact) = let first = x.Phones |> Seq.tryPick(fun x -> if x.Type = PhoneType.Mobile then Some(x) else None) match first with | Some(first) -> let phone = first.Number |> StripChars [' ';'-';'(';')'] UserInfo.CreateUserInfo((MD5Hash phone), phone, x.DisplayName) | None -> UserInfo.CreateUserInfo("no mobile phone", "no mobile phone", "no mobile phone") // function for async list filling let FillContactsAsync = async { let book = new AddressBook (this) let! result = book.RequestPermission() |> Async.AwaitTask if result then _contacts <- book.ToList() |> Seq.filter (fun (x: Contact) -> not (Seq.isEmpty x.Phones)) |> Seq.map ExtractUserInfo |> Seq.sortBy(fun x -> x.DisplayName) |> Seq.toList let finalContacts = _contacts |> Seq.map (fun x -> x.DisplayName.ToUpperInvariant()) |> Seq.toArray this.ListAdapter <- new ArrayAdapter(this, Resource_Layout.row_contact, finalContacts) else System.Diagnostics.Debug.WriteLine("Permission denied by user or manifest") this.ListAdapter <- new ArrayAdapter(this, Resource_Layout.row_contact, Array.empty) }
 
 
 
 
 
 
 
 book.ToList()
 
 
 
 List|> Seq.filter (fun (x: Contact) -> not (Seq.isEmpty x.Phones))
 
 
 
 |> Seq.map ExtractUserInfo
 
 
 
 Contracts UserInfo, UserInfo|> Seq.sortBy(fun x -> x.DisplayName)
 
 
 
 |> Seq.toList
 
 
 
 List_contacts <-
 
 
 
 mutable_contacts |> Seq.map (fun x -> x.DisplayName.ToUpperInvariant())<-
 
 
 
 UserInfo string, - -|> Seq.toArray<-
 
 
 
 List Array ArrayAdapter
 
 - List. .
 
 
 
   
 
 
 
 Azure Mobile Servcies
 
 - Azure Mobile Services. NotificationHub, Push . Azure , .. .
 
 
 
 ,
 
 module WruConstants = [<Literal>] let TotallyNotAzureServer = "https://YOUR.azure-mobile.net/"; [<Literal>] let TotallyNotAzureKey = "YOUR"
 
 
 
 
 
 
 
 
 
 member this.RegisterMe phone name regId = async { try let table = this.MobileService.GetTable<User>() let usr = { Id = "" PhoneHash = MD5Hash phone Nickname = name RegistrationId = regId } do! table.InsertAsync usr |> Async.AwaitPlainTask return (usr.Id, usr.PhoneHash, usr.Nickname) with | e -> System.Diagnostics.Trace.WriteLine(e.ToString) return (String.Empty,String.Empty,String.Empty) }
 
 
 
 
 
 member this.RegisterMe phone name regId = async {
 
 
 
 - ( ) . "computation expression" workflow. { } ! ( bang), do! (do-bang) let! (let bang) User. , F# ,
 
 let usr = { Id = "" PhoneHash = MD5Hash phone Nickname = name RegistrationId = regId }
 
 
 
 do! table.InsertAsync usr |> Async.AwaitPlainTask
 
 
 
 do-bang,await
 
 
 
 C#. .. continuation .return (usr.Id, usr.PhoneHash, usr.Nickname)
 
 
 
 Tuple<string,string,string> .try ... with | e ->
 
 
 
 try..catch
 
 
 
 C#
 
 
 
   
 
 
 
 . F#fst
 
 
 
 snd
 
 
 
 . 2 . :
 
 let id (c,_,_) = c let phonehash (_,c,_) = c let nickname (_,_,c) = c
 
 
 
 
 
 :id tuple
 
 
 
 Id ..
 
 
 
 5 Azure, Push . Azure Custom Api
 
 
 
 exports.post = function(request, response) { // Use "request.service" to access features of your mobile service, eg: // var tables = request.service.tables; // var push = request.service.push; //response.send(statusCodes.OK, { message : 'Hello World!' }); console.log('Incoming call with requst: ', request.body.RequestId); var usersTable = request.service.tables.getTable('User'); usersTable.where( { id : request.body.TargetId } ) .read( { success: function(results) { if (results.length > 0) { var user = results[0] console.log('Send to results: ', user.Nickname, user.RegistrationId); request.service.push.gcm.send(user.RegistrationId, { RequesterId: request.body.RequesterId, RequesterNickname: request.body.RequesterName, TargetId: user.id, TargetNickname: user.Nickname }, { success: function(gcm_response) { console.log('Push notification sent: ', gcm_response); response.send(statusCodes.OK, { RequestedNickname : user.Nickname }); }, error: function(gcm_error) { console.log('Error sending push notification: ', gcm_error); response.send(statusCodes.INTERNAL_SERVER_ERROR, { RequestedNickname : user.Nickname }); } }); } else { response.send(statusCodes.NO_CONTENT, { RequestedNickname : "" }); } }, error: function(error) { console.log('Error read table: ', error); response.send(statusCodes.INTERNAL_SERVER_ERROR, { RequestedNickname : "" }); } }); };
 
 
 
 
 
 
 
 Push
 
 // Perform Push operation member this.PushAsync targetId myId myNickname = async { try let (request : PushRequest) = { TargetId = targetId RequesterId = myId RequesterName = myNickname } let! result = this.MobileService.InvokeApiAsync<PushRequest, PushResponce>("pushhim", request) |> Async.AwaitTask return result.RequestedNickname with | e -> return e.ToString() }
 
 
 
 
 
 
 
 ,let-bang
 
 
 
 do!
 
 
 
 
 
 
 
 
 
 
 
   
 
 Google Play Services. F# . . : Xamarin.Android.Support.v7.AppCompat
 
 , Google Play Services , .
 
 
 
 push notification . GCM, ID, ID Push (. pushhim). BroadcastReciever developer.android.com . F# Xamarin Component Store. Google Cloud Messaging Client GCM . ID
 
 //Check to see that GCM is supported and that the manifest has the correct information GcmClient.CheckDevice(this) GcmClient.CheckManifest(this) // check google play if CheckPlayServices() then // Try to get registration id let regId = GcmClient.GetRegistrationId this if String.IsNullOrEmpty(regId) then // Call to Register the device for Push Notifications GcmClient.Register(this, WruConstants.GcmSender);
 
 
 
 
 
 
 
   
 
 
 
 
 
 .
 
 , -
 
 bitbucket.org/xakpc/whereareyou
 
 ,
 
 , "" .
 
 
 
 
 
 , Android F#. .
 
 , - Android F#. , .
 
 
 
 
 
 
 
 
-  listView.Adapter <- new ArrayAdapter(this, Android.Resource.Layout.SimpleListItem1, Android.Resource.Id.Text1, values)
 
 , , let values = [|"item1"; "item2"; "item3"|]
 
 
 
 - string[], list (IEnumerable )
 
 F#. www.tryfsharp.org/Learn
 
   
 
 F# - ,
 
 
 
 F# For Fun And Profit
 
 
 
 ,
 
 - .
 
 
 
   
 
 
 
 hash
 
 MD5 F#
 
 let MD5Hash (input : string) = use md5 = System.Security.Cryptography.MD5.Create() input |> System.Text.Encoding.ASCII.GetBytes |> md5.ComputeHash |> Seq.map (fun c -> c.ToString("X2")) |> Seq.reduce (+)
 
 
 
 
 
 
 
 |>
 
 
 
 pipeline , .
 
 : GetBytes -> -> HEX -> ( reduce + ) -> .
 
 
 
 , C#using System; public string CreateMD5Hash (string input) { MD5 md5 = System.Security.Cryptography.MD5.Create(); byte[] inputBytes = System.Text.Encoding.ASCII.GetBytes (input); byte[] hashBytes = md5.ComputeHash (inputBytes); StringBuilder sb = new StringBuilder(); for (int i = 0; i < hashBytes.Length; i++) { sb.Append (hashBytes[i].ToString ("X2")); } return sb.ToString(); }
 
 
 
 
 
 
 
 
 
 : . AzureServiceWorker ( CLR )
 
 
 
 - . F# ! Xamarin Studio .
 
 <ItemGroup> <Compile Include="Resources\Resource.designer.fs" /> <Compile Include="Properties\AssemblyInfo.fs" /> <Compile Include="Helpers\Helpers.fs" /> <Compile Include="Services\User.fs" /> <Compile Include="Services\AzureServiceWorker.fs" /> <Compile Include="IAmHereActivity.fs" /> <Compile Include="WhereAreYouActivity.fs" /> <Compile Include="SignInActivity.fs" /> </ItemGroup>
 
 
 
 
 
 
 
 
 
 : . Xamarin Xamarin.Mobile
 
 
 
 . F# TPL, Task', . F# Task. , :
 
 module Async = open System.Threading open System.Threading.Tasks let inline AwaitPlainTask (task: Task) = // rethrow exception from preceding task if it fauled let continuation (t : Task) : unit = match t.IsFaulted with | true -> raise t.Exception | arg -> () task.ContinueWith continuation |> Async.AwaitTask
 
 
 
 
 
 Async.AwaitIAsyncResult >> Async.Ignore
 
 
 
 
 
 
 
 
 
 let ExtractUserInfo (x : Contact) = let first = x.Phones |> Seq.tryPick(fun x -> if x.Type = PhoneType.Mobile then Some(x) else None) match first with | Some(first) -> let phone = first.Number |> StripChars [' ';'-';'(';')'] UserInfo.CreateUserInfo((MD5Hash phone), phone, x.DisplayName) | None -> UserInfo.CreateUserInfo("no mobile phone", "no mobile phone", "no mobile phone") // function for async list filling let FillContactsAsync = async { let book = new AddressBook (this) let! result = book.RequestPermission() |> Async.AwaitTask if result then _contacts <- book.ToList() |> Seq.filter (fun (x: Contact) -> not (Seq.isEmpty x.Phones)) |> Seq.map ExtractUserInfo |> Seq.sortBy(fun x -> x.DisplayName) |> Seq.toList let finalContacts = _contacts |> Seq.map (fun x -> x.DisplayName.ToUpperInvariant()) |> Seq.toArray this.ListAdapter <- new ArrayAdapter(this, Resource_Layout.row_contact, finalContacts) else System.Diagnostics.Debug.WriteLine("Permission denied by user or manifest") this.ListAdapter <- new ArrayAdapter(this, Resource_Layout.row_contact, Array.empty) }
 
 
 
 
 
 
 
 book.ToList()
 
 
 
 List|> Seq.filter (fun (x: Contact) -> not (Seq.isEmpty x.Phones))
 
 
 
 |> Seq.map ExtractUserInfo
 
 
 
 Contracts UserInfo, UserInfo|> Seq.sortBy(fun x -> x.DisplayName)
 
 
 
 |> Seq.toList
 
 
 
 List_contacts <-
 
 
 
 mutable_contacts |> Seq.map (fun x -> x.DisplayName.ToUpperInvariant())<-
 
 
 
 UserInfo string, - -|> Seq.toArray<-
 
 
 
 List Array ArrayAdapter
 
 - List. .
 
 
 
   
 
 
 
 Azure Mobile Servcies
 
 - Azure Mobile Services. NotificationHub, Push . Azure , .. .
 
 
 
 ,
 
 module WruConstants = [<Literal>] let TotallyNotAzureServer = "https://YOUR.azure-mobile.net/"; [<Literal>] let TotallyNotAzureKey = "YOUR"
 
 
 
 
 
 
 
 
 
 member this.RegisterMe phone name regId = async { try let table = this.MobileService.GetTable<User>() let usr = { Id = "" PhoneHash = MD5Hash phone Nickname = name RegistrationId = regId } do! table.InsertAsync usr |> Async.AwaitPlainTask return (usr.Id, usr.PhoneHash, usr.Nickname) with | e -> System.Diagnostics.Trace.WriteLine(e.ToString) return (String.Empty,String.Empty,String.Empty) }
 
 
 
 
 
 member this.RegisterMe phone name regId = async {
 
 
 
 - ( ) . "computation expression" workflow. { } ! ( bang), do! (do-bang) let! (let bang) User. , F# ,
 
 let usr = { Id = "" PhoneHash = MD5Hash phone Nickname = name RegistrationId = regId }
 
 
 
 do! table.InsertAsync usr |> Async.AwaitPlainTask
 
 
 
 do-bang,await
 
 
 
 C#. .. continuation .return (usr.Id, usr.PhoneHash, usr.Nickname)
 
 
 
 Tuple<string,string,string> .try ... with | e ->
 
 
 
 try..catch
 
 
 
 C#
 
 
 
   
 
 
 
 . F#fst
 
 
 
 snd
 
 
 
 . 2 . :
 
 let id (c,_,_) = c let phonehash (_,c,_) = c let nickname (_,_,c) = c
 
 
 
 
 
 :id tuple
 
 
 
 Id ..
 
 
 
 5 Azure, Push . Azure Custom Api
 
 
 
 exports.post = function(request, response) { // Use "request.service" to access features of your mobile service, eg: // var tables = request.service.tables; // var push = request.service.push; //response.send(statusCodes.OK, { message : 'Hello World!' }); console.log('Incoming call with requst: ', request.body.RequestId); var usersTable = request.service.tables.getTable('User'); usersTable.where( { id : request.body.TargetId } ) .read( { success: function(results) { if (results.length > 0) { var user = results[0] console.log('Send to results: ', user.Nickname, user.RegistrationId); request.service.push.gcm.send(user.RegistrationId, { RequesterId: request.body.RequesterId, RequesterNickname: request.body.RequesterName, TargetId: user.id, TargetNickname: user.Nickname }, { success: function(gcm_response) { console.log('Push notification sent: ', gcm_response); response.send(statusCodes.OK, { RequestedNickname : user.Nickname }); }, error: function(gcm_error) { console.log('Error sending push notification: ', gcm_error); response.send(statusCodes.INTERNAL_SERVER_ERROR, { RequestedNickname : user.Nickname }); } }); } else { response.send(statusCodes.NO_CONTENT, { RequestedNickname : "" }); } }, error: function(error) { console.log('Error read table: ', error); response.send(statusCodes.INTERNAL_SERVER_ERROR, { RequestedNickname : "" }); } }); };
 
 
 
 
 
 
 
 Push
 
 // Perform Push operation member this.PushAsync targetId myId myNickname = async { try let (request : PushRequest) = { TargetId = targetId RequesterId = myId RequesterName = myNickname } let! result = this.MobileService.InvokeApiAsync<PushRequest, PushResponce>("pushhim", request) |> Async.AwaitTask return result.RequestedNickname with | e -> return e.ToString() }
 
 
 
 
 
 
 
 ,let-bang
 
 
 
 do!
 
 
 
 
 
 
 
 
 
 
 
   
 
 Google Play Services. F# . . : Xamarin.Android.Support.v7.AppCompat
 
 , Google Play Services , .
 
 
 
 push notification . GCM, ID, ID Push (. pushhim). BroadcastReciever developer.android.com . F# Xamarin Component Store. Google Cloud Messaging Client GCM . ID
 
 //Check to see that GCM is supported and that the manifest has the correct information GcmClient.CheckDevice(this) GcmClient.CheckManifest(this) // check google play if CheckPlayServices() then // Try to get registration id let regId = GcmClient.GetRegistrationId this if String.IsNullOrEmpty(regId) then // Call to Register the device for Push Notifications GcmClient.Register(this, WruConstants.GcmSender);
 
 
 
 
 
 
 
   
 
 
 
 
 
 .
 
 , -
 
 bitbucket.org/xakpc/whereareyou
 
 ,
 
 , "" .
 
 
 
 
 
 , Android F#. .
 
 , - Android F#. , .
 
 
 
 
 
 
 
 
-  listView.Adapter <- new ArrayAdapter(this, Android.Resource.Layout.SimpleListItem1, Android.Resource.Id.Text1, values)
 
 , , let values = [|"item1"; "item2"; "item3"|]
 
 
 
 - string[], list (IEnumerable )
 
 F#. www.tryfsharp.org/Learn
 
   
 
 F# - ,
 
 
 
 F# For Fun And Profit
 
 
 
 ,
 
 - .
 
 
 
   
 
 
 
 hash
 
 MD5 F#
 
 let MD5Hash (input : string) = use md5 = System.Security.Cryptography.MD5.Create() input |> System.Text.Encoding.ASCII.GetBytes |> md5.ComputeHash |> Seq.map (fun c -> c.ToString("X2")) |> Seq.reduce (+)
 
 
 
 
 
 
 
 |>
 
 
 
 pipeline , .
 
 : GetBytes -> -> HEX -> ( reduce + ) -> .
 
 
 
 , C#using System; public string CreateMD5Hash (string input) { MD5 md5 = System.Security.Cryptography.MD5.Create(); byte[] inputBytes = System.Text.Encoding.ASCII.GetBytes (input); byte[] hashBytes = md5.ComputeHash (inputBytes); StringBuilder sb = new StringBuilder(); for (int i = 0; i < hashBytes.Length; i++) { sb.Append (hashBytes[i].ToString ("X2")); } return sb.ToString(); }
 
 
 
 
 
 
 
 
 
 : . AzureServiceWorker ( CLR )
 
 
 
 - . F# ! Xamarin Studio .
 
 <ItemGroup> <Compile Include="Resources\Resource.designer.fs" /> <Compile Include="Properties\AssemblyInfo.fs" /> <Compile Include="Helpers\Helpers.fs" /> <Compile Include="Services\User.fs" /> <Compile Include="Services\AzureServiceWorker.fs" /> <Compile Include="IAmHereActivity.fs" /> <Compile Include="WhereAreYouActivity.fs" /> <Compile Include="SignInActivity.fs" /> </ItemGroup>
 
 
 
 
 
 
 
 
 
 : . Xamarin Xamarin.Mobile
 
 
 
 . F# TPL, Task', . F# Task. , :
 
 module Async = open System.Threading open System.Threading.Tasks let inline AwaitPlainTask (task: Task) = // rethrow exception from preceding task if it fauled let continuation (t : Task) : unit = match t.IsFaulted with | true -> raise t.Exception | arg -> () task.ContinueWith continuation |> Async.AwaitTask
 
 
 
 
 
 Async.AwaitIAsyncResult >> Async.Ignore
 
 
 
 
 
 
 
 
 
 let ExtractUserInfo (x : Contact) = let first = x.Phones |> Seq.tryPick(fun x -> if x.Type = PhoneType.Mobile then Some(x) else None) match first with | Some(first) -> let phone = first.Number |> StripChars [' ';'-';'(';')'] UserInfo.CreateUserInfo((MD5Hash phone), phone, x.DisplayName) | None -> UserInfo.CreateUserInfo("no mobile phone", "no mobile phone", "no mobile phone") // function for async list filling let FillContactsAsync = async { let book = new AddressBook (this) let! result = book.RequestPermission() |> Async.AwaitTask if result then _contacts <- book.ToList() |> Seq.filter (fun (x: Contact) -> not (Seq.isEmpty x.Phones)) |> Seq.map ExtractUserInfo |> Seq.sortBy(fun x -> x.DisplayName) |> Seq.toList let finalContacts = _contacts |> Seq.map (fun x -> x.DisplayName.ToUpperInvariant()) |> Seq.toArray this.ListAdapter <- new ArrayAdapter(this, Resource_Layout.row_contact, finalContacts) else System.Diagnostics.Debug.WriteLine("Permission denied by user or manifest") this.ListAdapter <- new ArrayAdapter(this, Resource_Layout.row_contact, Array.empty) }
 
 
 
 
 
 
 
 book.ToList()
 
 
 
 List|> Seq.filter (fun (x: Contact) -> not (Seq.isEmpty x.Phones))
 
 
 
 |> Seq.map ExtractUserInfo
 
 
 
 Contracts UserInfo, UserInfo|> Seq.sortBy(fun x -> x.DisplayName)
 
 
 
 |> Seq.toList
 
 
 
 List_contacts <-
 
 
 
 mutable_contacts |> Seq.map (fun x -> x.DisplayName.ToUpperInvariant())<-
 
 
 
 UserInfo string, - -|> Seq.toArray<-
 
 
 
 List Array ArrayAdapter
 
 - List. .
 
 
 
   
 
 
 
 Azure Mobile Servcies
 
 - Azure Mobile Services. NotificationHub, Push . Azure , .. .
 
 
 
 ,
 
 module WruConstants = [<Literal>] let TotallyNotAzureServer = "https://YOUR.azure-mobile.net/"; [<Literal>] let TotallyNotAzureKey = "YOUR"
 
 
 
 
 
 
 
 
 
 member this.RegisterMe phone name regId = async { try let table = this.MobileService.GetTable<User>() let usr = { Id = "" PhoneHash = MD5Hash phone Nickname = name RegistrationId = regId } do! table.InsertAsync usr |> Async.AwaitPlainTask return (usr.Id, usr.PhoneHash, usr.Nickname) with | e -> System.Diagnostics.Trace.WriteLine(e.ToString) return (String.Empty,String.Empty,String.Empty) }
 
 
 
 
 
 member this.RegisterMe phone name regId = async {
 
 
 
 - ( ) . "computation expression" workflow. { } ! ( bang), do! (do-bang) let! (let bang) User. , F# ,
 
 let usr = { Id = "" PhoneHash = MD5Hash phone Nickname = name RegistrationId = regId }
 
 
 
 do! table.InsertAsync usr |> Async.AwaitPlainTask
 
 
 
 do-bang,await
 
 
 
 C#. .. continuation .return (usr.Id, usr.PhoneHash, usr.Nickname)
 
 
 
 Tuple<string,string,string> .try ... with | e ->
 
 
 
 try..catch
 
 
 
 C#
 
 
 
   
 
 
 
 . F#fst
 
 
 
 snd
 
 
 
 . 2 . :
 
 let id (c,_,_) = c let phonehash (_,c,_) = c let nickname (_,_,c) = c
 
 
 
 
 
 :id tuple
 
 
 
 Id ..
 
 
 
 5 Azure, Push . Azure Custom Api
 
 
 
 exports.post = function(request, response) { // Use "request.service" to access features of your mobile service, eg: // var tables = request.service.tables; // var push = request.service.push; //response.send(statusCodes.OK, { message : 'Hello World!' }); console.log('Incoming call with requst: ', request.body.RequestId); var usersTable = request.service.tables.getTable('User'); usersTable.where( { id : request.body.TargetId } ) .read( { success: function(results) { if (results.length > 0) { var user = results[0] console.log('Send to results: ', user.Nickname, user.RegistrationId); request.service.push.gcm.send(user.RegistrationId, { RequesterId: request.body.RequesterId, RequesterNickname: request.body.RequesterName, TargetId: user.id, TargetNickname: user.Nickname }, { success: function(gcm_response) { console.log('Push notification sent: ', gcm_response); response.send(statusCodes.OK, { RequestedNickname : user.Nickname }); }, error: function(gcm_error) { console.log('Error sending push notification: ', gcm_error); response.send(statusCodes.INTERNAL_SERVER_ERROR, { RequestedNickname : user.Nickname }); } }); } else { response.send(statusCodes.NO_CONTENT, { RequestedNickname : "" }); } }, error: function(error) { console.log('Error read table: ', error); response.send(statusCodes.INTERNAL_SERVER_ERROR, { RequestedNickname : "" }); } }); };
 
 
 
 
 
 
 
 Push
 
 // Perform Push operation member this.PushAsync targetId myId myNickname = async { try let (request : PushRequest) = { TargetId = targetId RequesterId = myId RequesterName = myNickname } let! result = this.MobileService.InvokeApiAsync<PushRequest, PushResponce>("pushhim", request) |> Async.AwaitTask return result.RequestedNickname with | e -> return e.ToString() }
 
 
 
 
 
 
 
 ,let-bang
 
 
 
 do!
 
 
 
 
 
 
 
 
 
 
 
   
 
 Google Play Services. F# . . : Xamarin.Android.Support.v7.AppCompat
 
 , Google Play Services , .
 
 
 
 push notification . GCM, ID, ID Push (. pushhim). BroadcastReciever developer.android.com . F# Xamarin Component Store. Google Cloud Messaging Client GCM . ID
 
 //Check to see that GCM is supported and that the manifest has the correct information GcmClient.CheckDevice(this) GcmClient.CheckManifest(this) // check google play if CheckPlayServices() then // Try to get registration id let regId = GcmClient.GetRegistrationId this if String.IsNullOrEmpty(regId) then // Call to Register the device for Push Notifications GcmClient.Register(this, WruConstants.GcmSender);
 
 
 
 
 
 
 
   
 
 
 
 
 
 .
 
 , -
 
 bitbucket.org/xakpc/whereareyou
 
 ,
 
 , "" .
 
 
 
 
 
 , Android F#. .
 
 , - Android F#. , .
 
 
 
 
 
 
 
 
listView.Adapter <- new ArrayAdapter(this, Android.Resource.Layout.SimpleListItem1, Android.Resource.Id.Text1, values) 
      
        
        
        
      
      , ,  let values = [|"item1"; "item2"; "item3"|]
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     -   string[],       list (IEnumerable   ) 
      
        
        
        
      
              F#.            www.tryfsharp.org/Learn 
      
        
        
        
      
      
 
      
        
        
        
      
          F# -  ,  
      
        
        
        
      
     
      
        
        
        
      
            F# For Fun And Profit 
      
        
        
        
      
     
      
        
        
        
      
       ,    
      
        
        
        
      
         - . 
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
     
      
        
        
        
      
            hash 
      
        
        
        
      
         MD5  F# 
      
        
        
        
      
      let MD5Hash (input : string) = use md5 = System.Security.Cryptography.MD5.Create() input |> System.Text.Encoding.ASCII.GetBytes |> md5.ComputeHash |> Seq.map (fun c -> c.ToString("X2")) |> Seq.reduce (+)
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
      |>
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      pipeline ,     . 
      
        
        
        
      
         :    GetBytes ->   ->      HEX  ->       (  reduce   +           ) ->    . 
      
        
        
        
      
     
      
        
        
        
      
      ,     C# using System; public string CreateMD5Hash (string input) { MD5 md5 = System.Security.Cryptography.MD5.Create(); byte[] inputBytes = System.Text.Encoding.ASCII.GetBytes (input); byte[] hashBytes = md5.ComputeHash (inputBytes); StringBuilder sb = new StringBuilder(); for (int i = 0; i < hashBytes.Length; i++) { sb.Append (hashBytes[i].ToString ("X2")); } return sb.ToString(); }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
     
      
        
        
        
      
              :        .       AzureServiceWorker (  CLR    ) 
      
        
        
        
      
     
      
        
        
        
      
              -   .   F#    !   Xamarin Studio            . 
      
        
        
        
      
      <ItemGroup> <Compile Include="Resources\Resource.designer.fs" /> <Compile Include="Properties\AssemblyInfo.fs" /> <Compile Include="Helpers\Helpers.fs" /> <Compile Include="Services\User.fs" /> <Compile Include="Services\AzureServiceWorker.fs" /> <Compile Include="IAmHereActivity.fs" /> <Compile Include="WhereAreYouActivity.fs" /> <Compile Include="SignInActivity.fs" /> </ItemGroup>
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
        
      
        
        
        
      
            :    .    Xamarin    Xamarin.Mobile 
      
        
        
        
      
     
      
        
        
        
      
          .  F#         TPL,     Task',      .     F#         Task.  ,     : 
      
        
        
        
      
     module Async = open System.Threading open System.Threading.Tasks let inline AwaitPlainTask (task: Task) = // rethrow exception from preceding task if it fauled let continuation (t : Task) : unit = match t.IsFaulted with | true -> raise t.Exception | arg -> () task.ContinueWith continuation |> Async.AwaitTask
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
             Async.AwaitIAsyncResult >> Async.Ignore
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
           
      
        
        
        
      
     
      
        
        
        
      
                
      
        
        
        
      
     let ExtractUserInfo (x : Contact) = let first = x.Phones |> Seq.tryPick(fun x -> if x.Type = PhoneType.Mobile then Some(x) else None) match first with | Some(first) -> let phone = first.Number |> StripChars [' ';'-';'(';')'] UserInfo.CreateUserInfo((MD5Hash phone), phone, x.DisplayName) | None -> UserInfo.CreateUserInfo("no mobile phone", "no mobile phone", "no mobile phone") // function for async list filling let FillContactsAsync = async { let book = new AddressBook (this) let! result = book.RequestPermission() |> Async.AwaitTask if result then _contacts <- book.ToList() |> Seq.filter (fun (x: Contact) -> not (Seq.isEmpty x.Phones)) |> Seq.map ExtractUserInfo |> Seq.sortBy(fun x -> x.DisplayName) |> Seq.toList let finalContacts = _contacts |> Seq.map (fun x -> x.DisplayName.ToUpperInvariant()) |> Seq.toArray this.ListAdapter <- new ArrayAdapter(this, Resource_Layout.row_contact, finalContacts) else System.Diagnostics.Debug.WriteLine("Permission denied by user or manifest") this.ListAdapter <- new ArrayAdapter(this, Resource_Layout.row_contact, Array.empty) }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
          
      
        
        
        
      
     book.ToList()
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
       List |> Seq.filter (fun (x: Contact) -> not (Seq.isEmpty x.Phones))
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
          |> Seq.map ExtractUserInfo
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
          Contracts  UserInfo,      UserInfo |> Seq.sortBy(fun x -> x.DisplayName)
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      |> Seq.toList
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
       List _contacts <-
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
        mutable  _contacts |> Seq.map (fun x -> x.DisplayName.ToUpperInvariant())<-
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
        UserInfo  string,     - -    |> Seq.toArray<-
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      List  Array    ArrayAdapter 
      
        
        
        
      
        -      List.   . 
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
     
      
        
        
        
      
     Azure Mobile Servcies 
      
        
        
        
      
       -    Azure Mobile Services.       NotificationHub,     Push    .   Azure    , ..      . 
      
        
        
        
      
     
      
        
        
        
      
          ,    
      
        
        
        
      
     module WruConstants = [<Literal>] let TotallyNotAzureServer = "https://YOUR.azure-mobile.net/"; [<Literal>] let TotallyNotAzureKey = "YOUR"
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
       
        
        
        
      
     member this.RegisterMe phone name regId = async { try let table = this.MobileService.GetTable<User>() let usr = { Id = "" PhoneHash = MD5Hash phone Nickname = name RegistrationId = regId } do! table.InsertAsync usr |> Async.AwaitPlainTask return (usr.Id, usr.PhoneHash, usr.Nickname) with | e -> System.Diagnostics.Trace.WriteLine(e.ToString) return (String.Empty,String.Empty,String.Empty) }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     member this.RegisterMe phone name regId = async {
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     -       (     )    .       "computation expression"   workflow.   { }       ! ( bang),  do! (do-bang)  let! (let bang)     User.    ,  F#        ,      
      
        
        
        
      
      let usr = { Id = "" PhoneHash = MD5Hash phone Nickname = name RegistrationId = regId }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     do! table.InsertAsync usr |> Async.AwaitPlainTask
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      do-bang,   await
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      C#. ..             continuation    . return (usr.Id, usr.PhoneHash, usr.Nickname)
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
          Tuple<string,string,string>     .  try ... with | e ->
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      try..catch
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      C# 
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
     
      
        
        
        
      
           .  F#    fst
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      snd
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
          .        2 .     : 
      
        
        
        
      
      let id (c,_,_) = c let phonehash (_,c,_) = c let nickname (_,_,c) = c
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
        : id tuple
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      Id  .. 
      
        
        
        
      
     
      
        
        
        
      
        5  Azure,       Push .       Azure Custom Api  
      
        
        
        
      
     
      
        
        
        
      
          exports.post = function(request, response) { // Use "request.service" to access features of your mobile service, eg: // var tables = request.service.tables; // var push = request.service.push; //response.send(statusCodes.OK, { message : 'Hello World!' }); console.log('Incoming call with requst: ', request.body.RequestId); var usersTable = request.service.tables.getTable('User'); usersTable.where( { id : request.body.TargetId } ) .read( { success: function(results) { if (results.length > 0) { var user = results[0] console.log('Send to results: ', user.Nickname, user.RegistrationId); request.service.push.gcm.send(user.RegistrationId, { RequesterId: request.body.RequesterId, RequesterNickname: request.body.RequesterName, TargetId: user.id, TargetNickname: user.Nickname }, { success: function(gcm_response) { console.log('Push notification sent: ', gcm_response); response.send(statusCodes.OK, { RequestedNickname : user.Nickname }); }, error: function(gcm_error) { console.log('Error sending push notification: ', gcm_error); response.send(statusCodes.INTERNAL_SERVER_ERROR, { RequestedNickname : user.Nickname }); } }); } else { response.send(statusCodes.NO_CONTENT, { RequestedNickname : "" }); } }, error: function(error) { console.log('Error read table: ', error); response.send(statusCodes.INTERNAL_SERVER_ERROR, { RequestedNickname : "" }); } }); };
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
        Push      
      
        
        
        
      
     // Perform Push operation member this.PushAsync targetId myId myNickname = async { try let (request : PushRequest) = { TargetId = targetId RequesterId = myId RequesterName = myNickname } let! result = this.MobileService.InvokeApiAsync<PushRequest, PushResponce>("pushhim", request) |> Async.AwaitTask return result.RequestedNickname with | e -> return e.ToString() }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
           ,    let-bang
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
       do!
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
       
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
          Google Play Services.     F#   .           .    : Xamarin.Android.Support.v7.AppCompat 
      
        
        
        
      
         , Google Play Services ,   . 
      
        
        
        
      
     
      
        
        
        
      
          push notification   .    GCM,  ID,     ID       Push  (.   pushhim).        BroadcastReciever       developer.android.com .     F#         Xamarin Component Store.     Google Cloud Messaging Client         GCM    .        ID 
      
        
        
        
      
     //Check to see that GCM is supported and that the manifest has the correct information GcmClient.CheckDevice(this) GcmClient.CheckManifest(this) // check google play if CheckPlayServices() then // Try to get registration id let regId = GcmClient.GetRegistrationId this if String.IsNullOrEmpty(regId) then // Call to Register the device for Push Notifications GcmClient.Register(this, WruConstants.GcmSender);
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
            
      
        
        
        
      
     
      
        
        
        
      
        . 
      
        
        
        
      
        , -  
      
        
        
        
      
         bitbucket.org/xakpc/whereareyou 
      
        
        
        
      
         ,     
      
        
        
        
      
              ,           "" . 
      
        
        
        
      
     
      
        
        
        
      
      
      
        
        
        
      
     ,   Android   F#.      . 
      
        
        
        
      
     ,       -  Android  F#.   ,       .
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
    listView.Adapter <- new ArrayAdapter(this, Android.Resource.Layout.SimpleListItem1, Android.Resource.Id.Text1, values) 
      
        
        
        
      
      , ,  let values = [|"item1"; "item2"; "item3"|]
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     -   string[],       list (IEnumerable   ) 
      
        
        
        
      
              F#.            www.tryfsharp.org/Learn 
      
        
        
        
      
      
 
      
        
        
        
      
          F# -  ,  
      
        
        
        
      
     
      
        
        
        
      
            F# For Fun And Profit 
      
        
        
        
      
     
      
        
        
        
      
       ,    
      
        
        
        
      
         - . 
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
     
      
        
        
        
      
            hash 
      
        
        
        
      
         MD5  F# 
      
        
        
        
      
      let MD5Hash (input : string) = use md5 = System.Security.Cryptography.MD5.Create() input |> System.Text.Encoding.ASCII.GetBytes |> md5.ComputeHash |> Seq.map (fun c -> c.ToString("X2")) |> Seq.reduce (+)
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
      |>
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      pipeline ,     . 
      
        
        
        
      
         :    GetBytes ->   ->      HEX  ->       (  reduce   +           ) ->    . 
      
        
        
        
      
     
      
        
        
        
      
      ,     C# using System; public string CreateMD5Hash (string input) { MD5 md5 = System.Security.Cryptography.MD5.Create(); byte[] inputBytes = System.Text.Encoding.ASCII.GetBytes (input); byte[] hashBytes = md5.ComputeHash (inputBytes); StringBuilder sb = new StringBuilder(); for (int i = 0; i < hashBytes.Length; i++) { sb.Append (hashBytes[i].ToString ("X2")); } return sb.ToString(); }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
     
      
        
        
        
      
              :        .       AzureServiceWorker (  CLR    ) 
      
        
        
        
      
     
      
        
        
        
      
              -   .   F#    !   Xamarin Studio            . 
      
        
        
        
      
      <ItemGroup> <Compile Include="Resources\Resource.designer.fs" /> <Compile Include="Properties\AssemblyInfo.fs" /> <Compile Include="Helpers\Helpers.fs" /> <Compile Include="Services\User.fs" /> <Compile Include="Services\AzureServiceWorker.fs" /> <Compile Include="IAmHereActivity.fs" /> <Compile Include="WhereAreYouActivity.fs" /> <Compile Include="SignInActivity.fs" /> </ItemGroup>
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
        
      
        
        
        
      
            :    .    Xamarin    Xamarin.Mobile 
      
        
        
        
      
     
      
        
        
        
      
          .  F#         TPL,     Task',      .     F#         Task.  ,     : 
      
        
        
        
      
     module Async = open System.Threading open System.Threading.Tasks let inline AwaitPlainTask (task: Task) = // rethrow exception from preceding task if it fauled let continuation (t : Task) : unit = match t.IsFaulted with | true -> raise t.Exception | arg -> () task.ContinueWith continuation |> Async.AwaitTask
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
             Async.AwaitIAsyncResult >> Async.Ignore
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
           
      
        
        
        
      
     
      
        
        
        
      
                
      
        
        
        
      
     let ExtractUserInfo (x : Contact) = let first = x.Phones |> Seq.tryPick(fun x -> if x.Type = PhoneType.Mobile then Some(x) else None) match first with | Some(first) -> let phone = first.Number |> StripChars [' ';'-';'(';')'] UserInfo.CreateUserInfo((MD5Hash phone), phone, x.DisplayName) | None -> UserInfo.CreateUserInfo("no mobile phone", "no mobile phone", "no mobile phone") // function for async list filling let FillContactsAsync = async { let book = new AddressBook (this) let! result = book.RequestPermission() |> Async.AwaitTask if result then _contacts <- book.ToList() |> Seq.filter (fun (x: Contact) -> not (Seq.isEmpty x.Phones)) |> Seq.map ExtractUserInfo |> Seq.sortBy(fun x -> x.DisplayName) |> Seq.toList let finalContacts = _contacts |> Seq.map (fun x -> x.DisplayName.ToUpperInvariant()) |> Seq.toArray this.ListAdapter <- new ArrayAdapter(this, Resource_Layout.row_contact, finalContacts) else System.Diagnostics.Debug.WriteLine("Permission denied by user or manifest") this.ListAdapter <- new ArrayAdapter(this, Resource_Layout.row_contact, Array.empty) }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
          
      
        
        
        
      
     book.ToList()
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
       List |> Seq.filter (fun (x: Contact) -> not (Seq.isEmpty x.Phones))
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
          |> Seq.map ExtractUserInfo
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
          Contracts  UserInfo,      UserInfo |> Seq.sortBy(fun x -> x.DisplayName)
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      |> Seq.toList
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
       List _contacts <-
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
        mutable  _contacts |> Seq.map (fun x -> x.DisplayName.ToUpperInvariant())<-
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
        UserInfo  string,     - -    |> Seq.toArray<-
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      List  Array    ArrayAdapter 
      
        
        
        
      
        -      List.   . 
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
     
      
        
        
        
      
     Azure Mobile Servcies 
      
        
        
        
      
       -    Azure Mobile Services.       NotificationHub,     Push    .   Azure    , ..      . 
      
        
        
        
      
     
      
        
        
        
      
          ,    
      
        
        
        
      
     module WruConstants = [<Literal>] let TotallyNotAzureServer = "https://YOUR.azure-mobile.net/"; [<Literal>] let TotallyNotAzureKey = "YOUR"
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
       
        
        
        
      
     member this.RegisterMe phone name regId = async { try let table = this.MobileService.GetTable<User>() let usr = { Id = "" PhoneHash = MD5Hash phone Nickname = name RegistrationId = regId } do! table.InsertAsync usr |> Async.AwaitPlainTask return (usr.Id, usr.PhoneHash, usr.Nickname) with | e -> System.Diagnostics.Trace.WriteLine(e.ToString) return (String.Empty,String.Empty,String.Empty) }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     member this.RegisterMe phone name regId = async {
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     -       (     )    .       "computation expression"   workflow.   { }       ! ( bang),  do! (do-bang)  let! (let bang)     User.    ,  F#        ,      
      
        
        
        
      
      let usr = { Id = "" PhoneHash = MD5Hash phone Nickname = name RegistrationId = regId }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     do! table.InsertAsync usr |> Async.AwaitPlainTask
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      do-bang,   await
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      C#. ..             continuation    . return (usr.Id, usr.PhoneHash, usr.Nickname)
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
          Tuple<string,string,string>     .  try ... with | e ->
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      try..catch
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      C# 
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
     
      
        
        
        
      
           .  F#    fst
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      snd
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
          .        2 .     : 
      
        
        
        
      
      let id (c,_,_) = c let phonehash (_,c,_) = c let nickname (_,_,c) = c
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
        : id tuple
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      Id  .. 
      
        
        
        
      
     
      
        
        
        
      
        5  Azure,       Push .       Azure Custom Api  
      
        
        
        
      
     
      
        
        
        
      
          exports.post = function(request, response) { // Use "request.service" to access features of your mobile service, eg: // var tables = request.service.tables; // var push = request.service.push; //response.send(statusCodes.OK, { message : 'Hello World!' }); console.log('Incoming call with requst: ', request.body.RequestId); var usersTable = request.service.tables.getTable('User'); usersTable.where( { id : request.body.TargetId } ) .read( { success: function(results) { if (results.length > 0) { var user = results[0] console.log('Send to results: ', user.Nickname, user.RegistrationId); request.service.push.gcm.send(user.RegistrationId, { RequesterId: request.body.RequesterId, RequesterNickname: request.body.RequesterName, TargetId: user.id, TargetNickname: user.Nickname }, { success: function(gcm_response) { console.log('Push notification sent: ', gcm_response); response.send(statusCodes.OK, { RequestedNickname : user.Nickname }); }, error: function(gcm_error) { console.log('Error sending push notification: ', gcm_error); response.send(statusCodes.INTERNAL_SERVER_ERROR, { RequestedNickname : user.Nickname }); } }); } else { response.send(statusCodes.NO_CONTENT, { RequestedNickname : "" }); } }, error: function(error) { console.log('Error read table: ', error); response.send(statusCodes.INTERNAL_SERVER_ERROR, { RequestedNickname : "" }); } }); };
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
        Push      
      
        
        
        
      
     // Perform Push operation member this.PushAsync targetId myId myNickname = async { try let (request : PushRequest) = { TargetId = targetId RequesterId = myId RequesterName = myNickname } let! result = this.MobileService.InvokeApiAsync<PushRequest, PushResponce>("pushhim", request) |> Async.AwaitTask return result.RequestedNickname with | e -> return e.ToString() }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
           ,    let-bang
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
       do!
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
       
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
          Google Play Services.     F#   .           .    : Xamarin.Android.Support.v7.AppCompat 
      
        
        
        
      
         , Google Play Services ,   . 
      
        
        
        
      
     
      
        
        
        
      
          push notification   .    GCM,  ID,     ID       Push  (.   pushhim).        BroadcastReciever       developer.android.com .     F#         Xamarin Component Store.     Google Cloud Messaging Client         GCM    .        ID 
      
        
        
        
      
     //Check to see that GCM is supported and that the manifest has the correct information GcmClient.CheckDevice(this) GcmClient.CheckManifest(this) // check google play if CheckPlayServices() then // Try to get registration id let regId = GcmClient.GetRegistrationId this if String.IsNullOrEmpty(regId) then // Call to Register the device for Push Notifications GcmClient.Register(this, WruConstants.GcmSender);
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
            
      
        
        
        
      
     
      
        
        
        
      
        . 
      
        
        
        
      
        , -  
      
        
        
        
      
         bitbucket.org/xakpc/whereareyou 
      
        
        
        
      
         ,     
      
        
        
        
      
              ,           "" . 
      
        
        
        
      
     
      
        
        
        
      
      
      
        
        
        
      
     ,   Android   F#.      . 
      
        
        
        
      
     ,       -  Android  F#.   ,       .
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
    listView.Adapter <- new ArrayAdapter(this, Android.Resource.Layout.SimpleListItem1, Android.Resource.Id.Text1, values) 
      
        
        
        
      
      , ,  let values = [|"item1"; "item2"; "item3"|]
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     -   string[],       list (IEnumerable   ) 
      
        
        
        
      
              F#.            www.tryfsharp.org/Learn 
      
        
        
        
      
      
 
      
        
        
        
      
          F# -  ,  
      
        
        
        
      
     
      
        
        
        
      
            F# For Fun And Profit 
      
        
        
        
      
     
      
        
        
        
      
       ,    
      
        
        
        
      
         - . 
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
     
      
        
        
        
      
            hash 
      
        
        
        
      
         MD5  F# 
      
        
        
        
      
      let MD5Hash (input : string) = use md5 = System.Security.Cryptography.MD5.Create() input |> System.Text.Encoding.ASCII.GetBytes |> md5.ComputeHash |> Seq.map (fun c -> c.ToString("X2")) |> Seq.reduce (+)
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
      |>
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      pipeline ,     . 
      
        
        
        
      
         :    GetBytes ->   ->      HEX  ->       (  reduce   +           ) ->    . 
      
        
        
        
      
     
      
        
        
        
      
      ,     C# using System; public string CreateMD5Hash (string input) { MD5 md5 = System.Security.Cryptography.MD5.Create(); byte[] inputBytes = System.Text.Encoding.ASCII.GetBytes (input); byte[] hashBytes = md5.ComputeHash (inputBytes); StringBuilder sb = new StringBuilder(); for (int i = 0; i < hashBytes.Length; i++) { sb.Append (hashBytes[i].ToString ("X2")); } return sb.ToString(); }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
     
      
        
        
        
      
              :        .       AzureServiceWorker (  CLR    ) 
      
        
        
        
      
     
      
        
        
        
      
              -   .   F#    !   Xamarin Studio            . 
      
        
        
        
      
      <ItemGroup> <Compile Include="Resources\Resource.designer.fs" /> <Compile Include="Properties\AssemblyInfo.fs" /> <Compile Include="Helpers\Helpers.fs" /> <Compile Include="Services\User.fs" /> <Compile Include="Services\AzureServiceWorker.fs" /> <Compile Include="IAmHereActivity.fs" /> <Compile Include="WhereAreYouActivity.fs" /> <Compile Include="SignInActivity.fs" /> </ItemGroup>
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
        
      
        
        
        
      
            :    .    Xamarin    Xamarin.Mobile 
      
        
        
        
      
     
      
        
        
        
      
          .  F#         TPL,     Task',      .     F#         Task.  ,     : 
      
        
        
        
      
     module Async = open System.Threading open System.Threading.Tasks let inline AwaitPlainTask (task: Task) = // rethrow exception from preceding task if it fauled let continuation (t : Task) : unit = match t.IsFaulted with | true -> raise t.Exception | arg -> () task.ContinueWith continuation |> Async.AwaitTask
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
             Async.AwaitIAsyncResult >> Async.Ignore
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
           
      
        
        
        
      
     
      
        
        
        
      
                
      
        
        
        
      
     let ExtractUserInfo (x : Contact) = let first = x.Phones |> Seq.tryPick(fun x -> if x.Type = PhoneType.Mobile then Some(x) else None) match first with | Some(first) -> let phone = first.Number |> StripChars [' ';'-';'(';')'] UserInfo.CreateUserInfo((MD5Hash phone), phone, x.DisplayName) | None -> UserInfo.CreateUserInfo("no mobile phone", "no mobile phone", "no mobile phone") // function for async list filling let FillContactsAsync = async { let book = new AddressBook (this) let! result = book.RequestPermission() |> Async.AwaitTask if result then _contacts <- book.ToList() |> Seq.filter (fun (x: Contact) -> not (Seq.isEmpty x.Phones)) |> Seq.map ExtractUserInfo |> Seq.sortBy(fun x -> x.DisplayName) |> Seq.toList let finalContacts = _contacts |> Seq.map (fun x -> x.DisplayName.ToUpperInvariant()) |> Seq.toArray this.ListAdapter <- new ArrayAdapter(this, Resource_Layout.row_contact, finalContacts) else System.Diagnostics.Debug.WriteLine("Permission denied by user or manifest") this.ListAdapter <- new ArrayAdapter(this, Resource_Layout.row_contact, Array.empty) }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
          
      
        
        
        
      
     book.ToList()
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
       List |> Seq.filter (fun (x: Contact) -> not (Seq.isEmpty x.Phones))
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
          |> Seq.map ExtractUserInfo
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
          Contracts  UserInfo,      UserInfo |> Seq.sortBy(fun x -> x.DisplayName)
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      |> Seq.toList
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
       List _contacts <-
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
        mutable  _contacts |> Seq.map (fun x -> x.DisplayName.ToUpperInvariant())<-
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
        UserInfo  string,     - -    |> Seq.toArray<-
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      List  Array    ArrayAdapter 
      
        
        
        
      
        -      List.   . 
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
     
      
        
        
        
      
     Azure Mobile Servcies 
      
        
        
        
      
       -    Azure Mobile Services.       NotificationHub,     Push    .   Azure    , ..      . 
      
        
        
        
      
     
      
        
        
        
      
          ,    
      
        
        
        
      
     module WruConstants = [<Literal>] let TotallyNotAzureServer = "https://YOUR.azure-mobile.net/"; [<Literal>] let TotallyNotAzureKey = "YOUR"
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
       
        
        
        
      
     member this.RegisterMe phone name regId = async { try let table = this.MobileService.GetTable<User>() let usr = { Id = "" PhoneHash = MD5Hash phone Nickname = name RegistrationId = regId } do! table.InsertAsync usr |> Async.AwaitPlainTask return (usr.Id, usr.PhoneHash, usr.Nickname) with | e -> System.Diagnostics.Trace.WriteLine(e.ToString) return (String.Empty,String.Empty,String.Empty) }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     member this.RegisterMe phone name regId = async {
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     -       (     )    .       "computation expression"   workflow.   { }       ! ( bang),  do! (do-bang)  let! (let bang)     User.    ,  F#        ,      
      
        
        
        
      
      let usr = { Id = "" PhoneHash = MD5Hash phone Nickname = name RegistrationId = regId }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     do! table.InsertAsync usr |> Async.AwaitPlainTask
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      do-bang,   await
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      C#. ..             continuation    . return (usr.Id, usr.PhoneHash, usr.Nickname)
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
          Tuple<string,string,string>     .  try ... with | e ->
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      try..catch
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      C# 
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
     
      
        
        
        
      
           .  F#    fst
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      snd
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
          .        2 .     : 
      
        
        
        
      
      let id (c,_,_) = c let phonehash (_,c,_) = c let nickname (_,_,c) = c
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
        : id tuple
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      Id  .. 
      
        
        
        
      
     
      
        
        
        
      
        5  Azure,       Push .       Azure Custom Api  
      
        
        
        
      
     
      
        
        
        
      
          exports.post = function(request, response) { // Use "request.service" to access features of your mobile service, eg: // var tables = request.service.tables; // var push = request.service.push; //response.send(statusCodes.OK, { message : 'Hello World!' }); console.log('Incoming call with requst: ', request.body.RequestId); var usersTable = request.service.tables.getTable('User'); usersTable.where( { id : request.body.TargetId } ) .read( { success: function(results) { if (results.length > 0) { var user = results[0] console.log('Send to results: ', user.Nickname, user.RegistrationId); request.service.push.gcm.send(user.RegistrationId, { RequesterId: request.body.RequesterId, RequesterNickname: request.body.RequesterName, TargetId: user.id, TargetNickname: user.Nickname }, { success: function(gcm_response) { console.log('Push notification sent: ', gcm_response); response.send(statusCodes.OK, { RequestedNickname : user.Nickname }); }, error: function(gcm_error) { console.log('Error sending push notification: ', gcm_error); response.send(statusCodes.INTERNAL_SERVER_ERROR, { RequestedNickname : user.Nickname }); } }); } else { response.send(statusCodes.NO_CONTENT, { RequestedNickname : "" }); } }, error: function(error) { console.log('Error read table: ', error); response.send(statusCodes.INTERNAL_SERVER_ERROR, { RequestedNickname : "" }); } }); };
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
        Push      
      
        
        
        
      
     // Perform Push operation member this.PushAsync targetId myId myNickname = async { try let (request : PushRequest) = { TargetId = targetId RequesterId = myId RequesterName = myNickname } let! result = this.MobileService.InvokeApiAsync<PushRequest, PushResponce>("pushhim", request) |> Async.AwaitTask return result.RequestedNickname with | e -> return e.ToString() }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
           ,    let-bang
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
       do!
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
       
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
          Google Play Services.     F#   .           .    : Xamarin.Android.Support.v7.AppCompat 
      
        
        
        
      
         , Google Play Services ,   . 
      
        
        
        
      
     
      
        
        
        
      
          push notification   .    GCM,  ID,     ID       Push  (.   pushhim).        BroadcastReciever       developer.android.com .     F#         Xamarin Component Store.     Google Cloud Messaging Client         GCM    .        ID 
      
        
        
        
      
     //Check to see that GCM is supported and that the manifest has the correct information GcmClient.CheckDevice(this) GcmClient.CheckManifest(this) // check google play if CheckPlayServices() then // Try to get registration id let regId = GcmClient.GetRegistrationId this if String.IsNullOrEmpty(regId) then // Call to Register the device for Push Notifications GcmClient.Register(this, WruConstants.GcmSender);
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
            
      
        
        
        
      
     
      
        
        
        
      
        . 
      
        
        
        
      
        , -  
      
        
        
        
      
         bitbucket.org/xakpc/whereareyou 
      
        
        
        
      
         ,     
      
        
        
        
      
              ,           "" . 
      
        
        
        
      
     
      
        
        
        
      
      
      
        
        
        
      
     ,   Android   F#.      . 
      
        
        
        
      
     ,       -  Android  F#.   ,       .
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     listView.Adapter <- new ArrayAdapter(this, Android.Resource.Layout.SimpleListItem1, Android.Resource.Id.Text1, values) 
      
        
        
        
      
      , ,  let values = [|"item1"; "item2"; "item3"|]
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     -   string[],       list (IEnumerable   ) 
      
        
        
        
      
              F#.            www.tryfsharp.org/Learn 
      
        
        
        
      
      
 
      
        
        
        
      
          F# -  ,  
      
        
        
        
      
     
      
        
        
        
      
            F# For Fun And Profit 
      
        
        
        
      
     
      
        
        
        
      
       ,    
      
        
        
        
      
         - . 
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
     
      
        
        
        
      
            hash 
      
        
        
        
      
         MD5  F# 
      
        
        
        
      
      let MD5Hash (input : string) = use md5 = System.Security.Cryptography.MD5.Create() input |> System.Text.Encoding.ASCII.GetBytes |> md5.ComputeHash |> Seq.map (fun c -> c.ToString("X2")) |> Seq.reduce (+)
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
      |>
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      pipeline ,     . 
      
        
        
        
      
         :    GetBytes ->   ->      HEX  ->       (  reduce   +           ) ->    . 
      
        
        
        
      
     
      
        
        
        
      
      ,     C# using System; public string CreateMD5Hash (string input) { MD5 md5 = System.Security.Cryptography.MD5.Create(); byte[] inputBytes = System.Text.Encoding.ASCII.GetBytes (input); byte[] hashBytes = md5.ComputeHash (inputBytes); StringBuilder sb = new StringBuilder(); for (int i = 0; i < hashBytes.Length; i++) { sb.Append (hashBytes[i].ToString ("X2")); } return sb.ToString(); }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
     
      
        
        
        
      
              :        .       AzureServiceWorker (  CLR    ) 
      
        
        
        
      
     
      
        
        
        
      
              -   .   F#    !   Xamarin Studio            . 
      
        
        
        
      
      <ItemGroup> <Compile Include="Resources\Resource.designer.fs" /> <Compile Include="Properties\AssemblyInfo.fs" /> <Compile Include="Helpers\Helpers.fs" /> <Compile Include="Services\User.fs" /> <Compile Include="Services\AzureServiceWorker.fs" /> <Compile Include="IAmHereActivity.fs" /> <Compile Include="WhereAreYouActivity.fs" /> <Compile Include="SignInActivity.fs" /> </ItemGroup>
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
        
      
        
        
        
      
            :    .    Xamarin    Xamarin.Mobile 
      
        
        
        
      
     
      
        
        
        
      
          .  F#         TPL,     Task',      .     F#         Task.  ,     : 
      
        
        
        
      
     module Async = open System.Threading open System.Threading.Tasks let inline AwaitPlainTask (task: Task) = // rethrow exception from preceding task if it fauled let continuation (t : Task) : unit = match t.IsFaulted with | true -> raise t.Exception | arg -> () task.ContinueWith continuation |> Async.AwaitTask
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
             Async.AwaitIAsyncResult >> Async.Ignore
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
           
      
        
        
        
      
     
      
        
        
        
      
                
      
        
        
        
      
     let ExtractUserInfo (x : Contact) = let first = x.Phones |> Seq.tryPick(fun x -> if x.Type = PhoneType.Mobile then Some(x) else None) match first with | Some(first) -> let phone = first.Number |> StripChars [' ';'-';'(';')'] UserInfo.CreateUserInfo((MD5Hash phone), phone, x.DisplayName) | None -> UserInfo.CreateUserInfo("no mobile phone", "no mobile phone", "no mobile phone") // function for async list filling let FillContactsAsync = async { let book = new AddressBook (this) let! result = book.RequestPermission() |> Async.AwaitTask if result then _contacts <- book.ToList() |> Seq.filter (fun (x: Contact) -> not (Seq.isEmpty x.Phones)) |> Seq.map ExtractUserInfo |> Seq.sortBy(fun x -> x.DisplayName) |> Seq.toList let finalContacts = _contacts |> Seq.map (fun x -> x.DisplayName.ToUpperInvariant()) |> Seq.toArray this.ListAdapter <- new ArrayAdapter(this, Resource_Layout.row_contact, finalContacts) else System.Diagnostics.Debug.WriteLine("Permission denied by user or manifest") this.ListAdapter <- new ArrayAdapter(this, Resource_Layout.row_contact, Array.empty) }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
          
      
        
        
        
      
     book.ToList()
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
       List |> Seq.filter (fun (x: Contact) -> not (Seq.isEmpty x.Phones))
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
          |> Seq.map ExtractUserInfo
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
          Contracts  UserInfo,      UserInfo |> Seq.sortBy(fun x -> x.DisplayName)
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      |> Seq.toList
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
       List _contacts <-
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
        mutable  _contacts |> Seq.map (fun x -> x.DisplayName.ToUpperInvariant())<-
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
        UserInfo  string,     - -    |> Seq.toArray<-
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      List  Array    ArrayAdapter 
      
        
        
        
      
        -      List.   . 
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
     
      
        
        
        
      
     Azure Mobile Servcies 
      
        
        
        
      
       -    Azure Mobile Services.       NotificationHub,     Push    .   Azure    , ..      . 
      
        
        
        
      
     
      
        
        
        
      
          ,    
      
        
        
        
      
     module WruConstants = [<Literal>] let TotallyNotAzureServer = "https://YOUR.azure-mobile.net/"; [<Literal>] let TotallyNotAzureKey = "YOUR"
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
       
        
        
        
      
     member this.RegisterMe phone name regId = async { try let table = this.MobileService.GetTable<User>() let usr = { Id = "" PhoneHash = MD5Hash phone Nickname = name RegistrationId = regId } do! table.InsertAsync usr |> Async.AwaitPlainTask return (usr.Id, usr.PhoneHash, usr.Nickname) with | e -> System.Diagnostics.Trace.WriteLine(e.ToString) return (String.Empty,String.Empty,String.Empty) }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     member this.RegisterMe phone name regId = async {
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     -       (     )    .       "computation expression"   workflow.   { }       ! ( bang),  do! (do-bang)  let! (let bang)     User.    ,  F#        ,      
      
        
        
        
      
      let usr = { Id = "" PhoneHash = MD5Hash phone Nickname = name RegistrationId = regId }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     do! table.InsertAsync usr |> Async.AwaitPlainTask
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      do-bang,   await
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      C#. ..             continuation    . return (usr.Id, usr.PhoneHash, usr.Nickname)
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
          Tuple<string,string,string>     .  try ... with | e ->
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      try..catch
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      C# 
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
     
      
        
        
        
      
           .  F#    fst
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      snd
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
          .        2 .     : 
      
        
        
        
      
      let id (c,_,_) = c let phonehash (_,c,_) = c let nickname (_,_,c) = c
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
        : id tuple
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      Id  .. 
      
        
        
        
      
     
      
        
        
        
      
        5  Azure,       Push .       Azure Custom Api  
      
        
        
        
      
     
      
        
        
        
      
          exports.post = function(request, response) { // Use "request.service" to access features of your mobile service, eg: // var tables = request.service.tables; // var push = request.service.push; //response.send(statusCodes.OK, { message : 'Hello World!' }); console.log('Incoming call with requst: ', request.body.RequestId); var usersTable = request.service.tables.getTable('User'); usersTable.where( { id : request.body.TargetId } ) .read( { success: function(results) { if (results.length > 0) { var user = results[0] console.log('Send to results: ', user.Nickname, user.RegistrationId); request.service.push.gcm.send(user.RegistrationId, { RequesterId: request.body.RequesterId, RequesterNickname: request.body.RequesterName, TargetId: user.id, TargetNickname: user.Nickname }, { success: function(gcm_response) { console.log('Push notification sent: ', gcm_response); response.send(statusCodes.OK, { RequestedNickname : user.Nickname }); }, error: function(gcm_error) { console.log('Error sending push notification: ', gcm_error); response.send(statusCodes.INTERNAL_SERVER_ERROR, { RequestedNickname : user.Nickname }); } }); } else { response.send(statusCodes.NO_CONTENT, { RequestedNickname : "" }); } }, error: function(error) { console.log('Error read table: ', error); response.send(statusCodes.INTERNAL_SERVER_ERROR, { RequestedNickname : "" }); } }); };
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
        Push      
      
        
        
        
      
     // Perform Push operation member this.PushAsync targetId myId myNickname = async { try let (request : PushRequest) = { TargetId = targetId RequesterId = myId RequesterName = myNickname } let! result = this.MobileService.InvokeApiAsync<PushRequest, PushResponce>("pushhim", request) |> Async.AwaitTask return result.RequestedNickname with | e -> return e.ToString() }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
           ,    let-bang
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
       do!
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
       
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
          Google Play Services.     F#   .           .    : Xamarin.Android.Support.v7.AppCompat 
      
        
        
        
      
         , Google Play Services ,   . 
      
        
        
        
      
     
      
        
        
        
      
          push notification   .    GCM,  ID,     ID       Push  (.   pushhim).        BroadcastReciever       developer.android.com .     F#         Xamarin Component Store.     Google Cloud Messaging Client         GCM    .        ID 
      
        
        
        
      
     //Check to see that GCM is supported and that the manifest has the correct information GcmClient.CheckDevice(this) GcmClient.CheckManifest(this) // check google play if CheckPlayServices() then // Try to get registration id let regId = GcmClient.GetRegistrationId this if String.IsNullOrEmpty(regId) then // Call to Register the device for Push Notifications GcmClient.Register(this, WruConstants.GcmSender);
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
            
      
        
        
        
      
     
      
        
        
        
      
        . 
      
        
        
        
      
        , -  
      
        
        
        
      
         bitbucket.org/xakpc/whereareyou 
      
        
        
        
      
         ,     
      
        
        
        
      
              ,           "" . 
      
        
        
        
      
     
      
        
        
        
      
      
      
        
        
        
      
     ,   Android   F#.      . 
      
        
        
        
      
     ,       -  Android  F#.   ,       .
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
    
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      listView.Adapter <- new ArrayAdapter(this, Android.Resource.Layout.SimpleListItem1, Android.Resource.Id.Text1, values) 
      
        
        
        
      
      , ,  let values = [|"item1"; "item2"; "item3"|]
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     -   string[],       list (IEnumerable   ) 
      
        
        
        
      
              F#.            www.tryfsharp.org/Learn 
      
        
        
        
      
      
 
      
        
        
        
      
          F# -  ,  
      
        
        
        
      
     
      
        
        
        
      
            F# For Fun And Profit 
      
        
        
        
      
     
      
        
        
        
      
       ,    
      
        
        
        
      
         - . 
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
     
      
        
        
        
      
            hash 
      
        
        
        
      
         MD5  F# 
      
        
        
        
      
      let MD5Hash (input : string) = use md5 = System.Security.Cryptography.MD5.Create() input |> System.Text.Encoding.ASCII.GetBytes |> md5.ComputeHash |> Seq.map (fun c -> c.ToString("X2")) |> Seq.reduce (+)
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
      |>
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      pipeline ,     . 
      
        
        
        
      
         :    GetBytes ->   ->      HEX  ->       (  reduce   +           ) ->    . 
      
        
        
        
      
     
      
        
        
        
      
      ,     C# using System; public string CreateMD5Hash (string input) { MD5 md5 = System.Security.Cryptography.MD5.Create(); byte[] inputBytes = System.Text.Encoding.ASCII.GetBytes (input); byte[] hashBytes = md5.ComputeHash (inputBytes); StringBuilder sb = new StringBuilder(); for (int i = 0; i < hashBytes.Length; i++) { sb.Append (hashBytes[i].ToString ("X2")); } return sb.ToString(); }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
     
      
        
        
        
      
              :        .       AzureServiceWorker (  CLR    ) 
      
        
        
        
      
     
      
        
        
        
      
              -   .   F#    !   Xamarin Studio            . 
      
        
        
        
      
      <ItemGroup> <Compile Include="Resources\Resource.designer.fs" /> <Compile Include="Properties\AssemblyInfo.fs" /> <Compile Include="Helpers\Helpers.fs" /> <Compile Include="Services\User.fs" /> <Compile Include="Services\AzureServiceWorker.fs" /> <Compile Include="IAmHereActivity.fs" /> <Compile Include="WhereAreYouActivity.fs" /> <Compile Include="SignInActivity.fs" /> </ItemGroup>
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
        
      
        
        
        
      
            :    .    Xamarin    Xamarin.Mobile 
      
        
        
        
      
     
      
        
        
        
      
          .  F#         TPL,     Task',      .     F#         Task.  ,     : 
      
        
        
        
      
     module Async = open System.Threading open System.Threading.Tasks let inline AwaitPlainTask (task: Task) = // rethrow exception from preceding task if it fauled let continuation (t : Task) : unit = match t.IsFaulted with | true -> raise t.Exception | arg -> () task.ContinueWith continuation |> Async.AwaitTask
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
             Async.AwaitIAsyncResult >> Async.Ignore
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
           
      
        
        
        
      
     
      
        
        
        
      
                
      
        
        
        
      
     let ExtractUserInfo (x : Contact) = let first = x.Phones |> Seq.tryPick(fun x -> if x.Type = PhoneType.Mobile then Some(x) else None) match first with | Some(first) -> let phone = first.Number |> StripChars [' ';'-';'(';')'] UserInfo.CreateUserInfo((MD5Hash phone), phone, x.DisplayName) | None -> UserInfo.CreateUserInfo("no mobile phone", "no mobile phone", "no mobile phone") // function for async list filling let FillContactsAsync = async { let book = new AddressBook (this) let! result = book.RequestPermission() |> Async.AwaitTask if result then _contacts <- book.ToList() |> Seq.filter (fun (x: Contact) -> not (Seq.isEmpty x.Phones)) |> Seq.map ExtractUserInfo |> Seq.sortBy(fun x -> x.DisplayName) |> Seq.toList let finalContacts = _contacts |> Seq.map (fun x -> x.DisplayName.ToUpperInvariant()) |> Seq.toArray this.ListAdapter <- new ArrayAdapter(this, Resource_Layout.row_contact, finalContacts) else System.Diagnostics.Debug.WriteLine("Permission denied by user or manifest") this.ListAdapter <- new ArrayAdapter(this, Resource_Layout.row_contact, Array.empty) }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
          
      
        
        
        
      
     book.ToList()
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
       List |> Seq.filter (fun (x: Contact) -> not (Seq.isEmpty x.Phones))
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
          |> Seq.map ExtractUserInfo
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
          Contracts  UserInfo,      UserInfo |> Seq.sortBy(fun x -> x.DisplayName)
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      |> Seq.toList
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
       List _contacts <-
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
        mutable  _contacts |> Seq.map (fun x -> x.DisplayName.ToUpperInvariant())<-
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
        UserInfo  string,     - -    |> Seq.toArray<-
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      List  Array    ArrayAdapter 
      
        
        
        
      
        -      List.   . 
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
     
      
        
        
        
      
     Azure Mobile Servcies 
      
        
        
        
      
       -    Azure Mobile Services.       NotificationHub,     Push    .   Azure    , ..      . 
      
        
        
        
      
     
      
        
        
        
      
          ,    
      
        
        
        
      
     module WruConstants = [<Literal>] let TotallyNotAzureServer = "https://YOUR.azure-mobile.net/"; [<Literal>] let TotallyNotAzureKey = "YOUR"
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
       
        
        
        
      
     member this.RegisterMe phone name regId = async { try let table = this.MobileService.GetTable<User>() let usr = { Id = "" PhoneHash = MD5Hash phone Nickname = name RegistrationId = regId } do! table.InsertAsync usr |> Async.AwaitPlainTask return (usr.Id, usr.PhoneHash, usr.Nickname) with | e -> System.Diagnostics.Trace.WriteLine(e.ToString) return (String.Empty,String.Empty,String.Empty) }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     member this.RegisterMe phone name regId = async {
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     -       (     )    .       "computation expression"   workflow.   { }       ! ( bang),  do! (do-bang)  let! (let bang)     User.    ,  F#        ,      
      
        
        
        
      
      let usr = { Id = "" PhoneHash = MD5Hash phone Nickname = name RegistrationId = regId }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     do! table.InsertAsync usr |> Async.AwaitPlainTask
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      do-bang,   await
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      C#. ..             continuation    . return (usr.Id, usr.PhoneHash, usr.Nickname)
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
          Tuple<string,string,string>     .  try ... with | e ->
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      try..catch
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      C# 
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
     
      
        
        
        
      
           .  F#    fst
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      snd
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
          .        2 .     : 
      
        
        
        
      
      let id (c,_,_) = c let phonehash (_,c,_) = c let nickname (_,_,c) = c
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
        : id tuple
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      Id  .. 
      
        
        
        
      
     
      
        
        
        
      
        5  Azure,       Push .       Azure Custom Api  
      
        
        
        
      
     
      
        
        
        
      
          exports.post = function(request, response) { // Use "request.service" to access features of your mobile service, eg: // var tables = request.service.tables; // var push = request.service.push; //response.send(statusCodes.OK, { message : 'Hello World!' }); console.log('Incoming call with requst: ', request.body.RequestId); var usersTable = request.service.tables.getTable('User'); usersTable.where( { id : request.body.TargetId } ) .read( { success: function(results) { if (results.length > 0) { var user = results[0] console.log('Send to results: ', user.Nickname, user.RegistrationId); request.service.push.gcm.send(user.RegistrationId, { RequesterId: request.body.RequesterId, RequesterNickname: request.body.RequesterName, TargetId: user.id, TargetNickname: user.Nickname }, { success: function(gcm_response) { console.log('Push notification sent: ', gcm_response); response.send(statusCodes.OK, { RequestedNickname : user.Nickname }); }, error: function(gcm_error) { console.log('Error sending push notification: ', gcm_error); response.send(statusCodes.INTERNAL_SERVER_ERROR, { RequestedNickname : user.Nickname }); } }); } else { response.send(statusCodes.NO_CONTENT, { RequestedNickname : "" }); } }, error: function(error) { console.log('Error read table: ', error); response.send(statusCodes.INTERNAL_SERVER_ERROR, { RequestedNickname : "" }); } }); };
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
        Push      
      
        
        
        
      
     // Perform Push operation member this.PushAsync targetId myId myNickname = async { try let (request : PushRequest) = { TargetId = targetId RequesterId = myId RequesterName = myNickname } let! result = this.MobileService.InvokeApiAsync<PushRequest, PushResponce>("pushhim", request) |> Async.AwaitTask return result.RequestedNickname with | e -> return e.ToString() }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
           ,    let-bang
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
       do!
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
       
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
          Google Play Services.     F#   .           .    : Xamarin.Android.Support.v7.AppCompat 
      
        
        
        
      
         , Google Play Services ,   . 
      
        
        
        
      
     
      
        
        
        
      
          push notification   .    GCM,  ID,     ID       Push  (.   pushhim).        BroadcastReciever       developer.android.com .     F#         Xamarin Component Store.     Google Cloud Messaging Client         GCM    .        ID 
      
        
        
        
      
     //Check to see that GCM is supported and that the manifest has the correct information GcmClient.CheckDevice(this) GcmClient.CheckManifest(this) // check google play if CheckPlayServices() then // Try to get registration id let regId = GcmClient.GetRegistrationId this if String.IsNullOrEmpty(regId) then // Call to Register the device for Push Notifications GcmClient.Register(this, WruConstants.GcmSender);
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
            
      
        
        
        
      
     
      
        
        
        
      
        . 
      
        
        
        
      
        , -  
      
        
        
        
      
         bitbucket.org/xakpc/whereareyou 
      
        
        
        
      
         ,     
      
        
        
        
      
              ,           "" . 
      
        
        
        
      
     
      
        
        
        
      
      
      
        
        
        
      
     ,   Android   F#.      . 
      
        
        
        
      
     ,       -  Android  F#.   ,       .
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
    listView.Adapter <- new ArrayAdapter(this, Android.Resource.Layout.SimpleListItem1, Android.Resource.Id.Text1, values) 
      
        
        
        
      
      , ,  let values = [|"item1"; "item2"; "item3"|]
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     -   string[],       list (IEnumerable   ) 
      
        
        
        
      
              F#.            www.tryfsharp.org/Learn 
      
        
        
        
      
      
 
      
        
        
        
      
          F# -  ,  
      
        
        
        
      
     
      
        
        
        
      
            F# For Fun And Profit 
      
        
        
        
      
     
      
        
        
        
      
       ,    
      
        
        
        
      
         - . 
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
     
      
        
        
        
      
            hash 
      
        
        
        
      
         MD5  F# 
      
        
        
        
      
      let MD5Hash (input : string) = use md5 = System.Security.Cryptography.MD5.Create() input |> System.Text.Encoding.ASCII.GetBytes |> md5.ComputeHash |> Seq.map (fun c -> c.ToString("X2")) |> Seq.reduce (+)
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
      |>
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      pipeline ,     . 
      
        
        
        
      
         :    GetBytes ->   ->      HEX  ->       (  reduce   +           ) ->    . 
      
        
        
        
      
     
      
        
        
        
      
      ,     C# using System; public string CreateMD5Hash (string input) { MD5 md5 = System.Security.Cryptography.MD5.Create(); byte[] inputBytes = System.Text.Encoding.ASCII.GetBytes (input); byte[] hashBytes = md5.ComputeHash (inputBytes); StringBuilder sb = new StringBuilder(); for (int i = 0; i < hashBytes.Length; i++) { sb.Append (hashBytes[i].ToString ("X2")); } return sb.ToString(); }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
     
      
        
        
        
      
              :        .       AzureServiceWorker (  CLR    ) 
      
        
        
        
      
     
      
        
        
        
      
              -   .   F#    !   Xamarin Studio            . 
      
        
        
        
      
      <ItemGroup> <Compile Include="Resources\Resource.designer.fs" /> <Compile Include="Properties\AssemblyInfo.fs" /> <Compile Include="Helpers\Helpers.fs" /> <Compile Include="Services\User.fs" /> <Compile Include="Services\AzureServiceWorker.fs" /> <Compile Include="IAmHereActivity.fs" /> <Compile Include="WhereAreYouActivity.fs" /> <Compile Include="SignInActivity.fs" /> </ItemGroup>
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
        
      
        
        
        
      
            :    .    Xamarin    Xamarin.Mobile 
      
        
        
        
      
     
      
        
        
        
      
          .  F#         TPL,     Task',      .     F#         Task.  ,     : 
      
        
        
        
      
     module Async = open System.Threading open System.Threading.Tasks let inline AwaitPlainTask (task: Task) = // rethrow exception from preceding task if it fauled let continuation (t : Task) : unit = match t.IsFaulted with | true -> raise t.Exception | arg -> () task.ContinueWith continuation |> Async.AwaitTask
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
             Async.AwaitIAsyncResult >> Async.Ignore
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
           
      
        
        
        
      
     
      
        
        
        
      
                
      
        
        
        
      
     let ExtractUserInfo (x : Contact) = let first = x.Phones |> Seq.tryPick(fun x -> if x.Type = PhoneType.Mobile then Some(x) else None) match first with | Some(first) -> let phone = first.Number |> StripChars [' ';'-';'(';')'] UserInfo.CreateUserInfo((MD5Hash phone), phone, x.DisplayName) | None -> UserInfo.CreateUserInfo("no mobile phone", "no mobile phone", "no mobile phone") // function for async list filling let FillContactsAsync = async { let book = new AddressBook (this) let! result = book.RequestPermission() |> Async.AwaitTask if result then _contacts <- book.ToList() |> Seq.filter (fun (x: Contact) -> not (Seq.isEmpty x.Phones)) |> Seq.map ExtractUserInfo |> Seq.sortBy(fun x -> x.DisplayName) |> Seq.toList let finalContacts = _contacts |> Seq.map (fun x -> x.DisplayName.ToUpperInvariant()) |> Seq.toArray this.ListAdapter <- new ArrayAdapter(this, Resource_Layout.row_contact, finalContacts) else System.Diagnostics.Debug.WriteLine("Permission denied by user or manifest") this.ListAdapter <- new ArrayAdapter(this, Resource_Layout.row_contact, Array.empty) }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
          
      
        
        
        
      
     book.ToList()
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
       List |> Seq.filter (fun (x: Contact) -> not (Seq.isEmpty x.Phones))
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
          |> Seq.map ExtractUserInfo
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
          Contracts  UserInfo,      UserInfo |> Seq.sortBy(fun x -> x.DisplayName)
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      |> Seq.toList
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
       List _contacts <-
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
        mutable  _contacts |> Seq.map (fun x -> x.DisplayName.ToUpperInvariant())<-
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
        UserInfo  string,     - -    |> Seq.toArray<-
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      List  Array    ArrayAdapter 
      
        
        
        
      
        -      List.   . 
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
     
      
        
        
        
      
     Azure Mobile Servcies 
      
        
        
        
      
       -    Azure Mobile Services.       NotificationHub,     Push    .   Azure    , ..      . 
      
        
        
        
      
     
      
        
        
        
      
          ,    
      
        
        
        
      
     module WruConstants = [<Literal>] let TotallyNotAzureServer = "https://YOUR.azure-mobile.net/"; [<Literal>] let TotallyNotAzureKey = "YOUR"
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
       
        
        
        
      
     member this.RegisterMe phone name regId = async { try let table = this.MobileService.GetTable<User>() let usr = { Id = "" PhoneHash = MD5Hash phone Nickname = name RegistrationId = regId } do! table.InsertAsync usr |> Async.AwaitPlainTask return (usr.Id, usr.PhoneHash, usr.Nickname) with | e -> System.Diagnostics.Trace.WriteLine(e.ToString) return (String.Empty,String.Empty,String.Empty) }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     member this.RegisterMe phone name regId = async {
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     -       (     )    .       "computation expression"   workflow.   { }       ! ( bang),  do! (do-bang)  let! (let bang)     User.    ,  F#        ,      
      
        
        
        
      
      let usr = { Id = "" PhoneHash = MD5Hash phone Nickname = name RegistrationId = regId }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     do! table.InsertAsync usr |> Async.AwaitPlainTask
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      do-bang,   await
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      C#. ..             continuation    . return (usr.Id, usr.PhoneHash, usr.Nickname)
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
          Tuple<string,string,string>     .  try ... with | e ->
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      try..catch
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      C# 
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
     
      
        
        
        
      
           .  F#    fst
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      snd
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
          .        2 .     : 
      
        
        
        
      
      let id (c,_,_) = c let phonehash (_,c,_) = c let nickname (_,_,c) = c
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
        : id tuple
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      Id  .. 
      
        
        
        
      
     
      
        
        
        
      
        5  Azure,       Push .       Azure Custom Api  
      
        
        
        
      
     
      
        
        
        
      
          exports.post = function(request, response) { // Use "request.service" to access features of your mobile service, eg: // var tables = request.service.tables; // var push = request.service.push; //response.send(statusCodes.OK, { message : 'Hello World!' }); console.log('Incoming call with requst: ', request.body.RequestId); var usersTable = request.service.tables.getTable('User'); usersTable.where( { id : request.body.TargetId } ) .read( { success: function(results) { if (results.length > 0) { var user = results[0] console.log('Send to results: ', user.Nickname, user.RegistrationId); request.service.push.gcm.send(user.RegistrationId, { RequesterId: request.body.RequesterId, RequesterNickname: request.body.RequesterName, TargetId: user.id, TargetNickname: user.Nickname }, { success: function(gcm_response) { console.log('Push notification sent: ', gcm_response); response.send(statusCodes.OK, { RequestedNickname : user.Nickname }); }, error: function(gcm_error) { console.log('Error sending push notification: ', gcm_error); response.send(statusCodes.INTERNAL_SERVER_ERROR, { RequestedNickname : user.Nickname }); } }); } else { response.send(statusCodes.NO_CONTENT, { RequestedNickname : "" }); } }, error: function(error) { console.log('Error read table: ', error); response.send(statusCodes.INTERNAL_SERVER_ERROR, { RequestedNickname : "" }); } }); };
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
        Push      
      
        
        
        
      
     // Perform Push operation member this.PushAsync targetId myId myNickname = async { try let (request : PushRequest) = { TargetId = targetId RequesterId = myId RequesterName = myNickname } let! result = this.MobileService.InvokeApiAsync<PushRequest, PushResponce>("pushhim", request) |> Async.AwaitTask return result.RequestedNickname with | e -> return e.ToString() }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
           ,    let-bang
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
       do!
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
       
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
          Google Play Services.     F#   .           .    : Xamarin.Android.Support.v7.AppCompat 
      
        
        
        
      
         , Google Play Services ,   . 
      
        
        
        
      
     
      
        
        
        
      
          push notification   .    GCM,  ID,     ID       Push  (.   pushhim).        BroadcastReciever       developer.android.com .     F#         Xamarin Component Store.     Google Cloud Messaging Client         GCM    .        ID 
      
        
        
        
      
     //Check to see that GCM is supported and that the manifest has the correct information GcmClient.CheckDevice(this) GcmClient.CheckManifest(this) // check google play if CheckPlayServices() then // Try to get registration id let regId = GcmClient.GetRegistrationId this if String.IsNullOrEmpty(regId) then // Call to Register the device for Push Notifications GcmClient.Register(this, WruConstants.GcmSender);
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
            
      
        
        
        
      
     
      
        
        
        
      
        . 
      
        
        
        
      
        , -  
      
        
        
        
      
         bitbucket.org/xakpc/whereareyou 
      
        
        
        
      
         ,     
      
        
        
        
      
              ,           "" . 
      
        
        
        
      
     
      
        
        
        
      
      
      
        
        
        
      
     ,   Android   F#.      . 
      
        
        
        
      
     ,       -  Android  F#.   ,       .
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     listView.Adapter <- new ArrayAdapter(this, Android.Resource.Layout.SimpleListItem1, Android.Resource.Id.Text1, values) 
      
        
        
        
      
      , ,  let values = [|"item1"; "item2"; "item3"|]
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     -   string[],       list (IEnumerable   ) 
      
        
        
        
      
              F#.            www.tryfsharp.org/Learn 
      
        
        
        
      
      
 
      
        
        
        
      
          F# -  ,  
      
        
        
        
      
     
      
        
        
        
      
            F# For Fun And Profit 
      
        
        
        
      
     
      
        
        
        
      
       ,    
      
        
        
        
      
         - . 
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
     
      
        
        
        
      
            hash 
      
        
        
        
      
         MD5  F# 
      
        
        
        
      
      let MD5Hash (input : string) = use md5 = System.Security.Cryptography.MD5.Create() input |> System.Text.Encoding.ASCII.GetBytes |> md5.ComputeHash |> Seq.map (fun c -> c.ToString("X2")) |> Seq.reduce (+)
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
      |>
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      pipeline ,     . 
      
        
        
        
      
         :    GetBytes ->   ->      HEX  ->       (  reduce   +           ) ->    . 
      
        
        
        
      
     
      
        
        
        
      
      ,     C# using System; public string CreateMD5Hash (string input) { MD5 md5 = System.Security.Cryptography.MD5.Create(); byte[] inputBytes = System.Text.Encoding.ASCII.GetBytes (input); byte[] hashBytes = md5.ComputeHash (inputBytes); StringBuilder sb = new StringBuilder(); for (int i = 0; i < hashBytes.Length; i++) { sb.Append (hashBytes[i].ToString ("X2")); } return sb.ToString(); }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
     
      
        
        
        
      
              :        .       AzureServiceWorker (  CLR    ) 
      
        
        
        
      
     
      
        
        
        
      
              -   .   F#    !   Xamarin Studio            . 
      
        
        
        
      
      <ItemGroup> <Compile Include="Resources\Resource.designer.fs" /> <Compile Include="Properties\AssemblyInfo.fs" /> <Compile Include="Helpers\Helpers.fs" /> <Compile Include="Services\User.fs" /> <Compile Include="Services\AzureServiceWorker.fs" /> <Compile Include="IAmHereActivity.fs" /> <Compile Include="WhereAreYouActivity.fs" /> <Compile Include="SignInActivity.fs" /> </ItemGroup>
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
        
      
        
        
        
      
            :    .    Xamarin    Xamarin.Mobile 
      
        
        
        
      
     
      
        
        
        
      
          .  F#         TPL,     Task',      .     F#         Task.  ,     : 
      
        
        
        
      
     module Async = open System.Threading open System.Threading.Tasks let inline AwaitPlainTask (task: Task) = // rethrow exception from preceding task if it fauled let continuation (t : Task) : unit = match t.IsFaulted with | true -> raise t.Exception | arg -> () task.ContinueWith continuation |> Async.AwaitTask
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
             Async.AwaitIAsyncResult >> Async.Ignore
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
           
      
        
        
        
      
     
      
        
        
        
      
                
      
        
        
        
      
     let ExtractUserInfo (x : Contact) = let first = x.Phones |> Seq.tryPick(fun x -> if x.Type = PhoneType.Mobile then Some(x) else None) match first with | Some(first) -> let phone = first.Number |> StripChars [' ';'-';'(';')'] UserInfo.CreateUserInfo((MD5Hash phone), phone, x.DisplayName) | None -> UserInfo.CreateUserInfo("no mobile phone", "no mobile phone", "no mobile phone") // function for async list filling let FillContactsAsync = async { let book = new AddressBook (this) let! result = book.RequestPermission() |> Async.AwaitTask if result then _contacts <- book.ToList() |> Seq.filter (fun (x: Contact) -> not (Seq.isEmpty x.Phones)) |> Seq.map ExtractUserInfo |> Seq.sortBy(fun x -> x.DisplayName) |> Seq.toList let finalContacts = _contacts |> Seq.map (fun x -> x.DisplayName.ToUpperInvariant()) |> Seq.toArray this.ListAdapter <- new ArrayAdapter(this, Resource_Layout.row_contact, finalContacts) else System.Diagnostics.Debug.WriteLine("Permission denied by user or manifest") this.ListAdapter <- new ArrayAdapter(this, Resource_Layout.row_contact, Array.empty) }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
          
      
        
        
        
      
     book.ToList()
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
       List |> Seq.filter (fun (x: Contact) -> not (Seq.isEmpty x.Phones))
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
          |> Seq.map ExtractUserInfo
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
          Contracts  UserInfo,      UserInfo |> Seq.sortBy(fun x -> x.DisplayName)
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      |> Seq.toList
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
       List _contacts <-
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
        mutable  _contacts |> Seq.map (fun x -> x.DisplayName.ToUpperInvariant())<-
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
        UserInfo  string,     - -    |> Seq.toArray<-
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      List  Array    ArrayAdapter 
      
        
        
        
      
        -      List.   . 
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
     
      
        
        
        
      
     Azure Mobile Servcies 
      
        
        
        
      
       -    Azure Mobile Services.       NotificationHub,     Push    .   Azure    , ..      . 
      
        
        
        
      
     
      
        
        
        
      
          ,    
      
        
        
        
      
     module WruConstants = [<Literal>] let TotallyNotAzureServer = "https://YOUR.azure-mobile.net/"; [<Literal>] let TotallyNotAzureKey = "YOUR"
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
       
        
        
        
      
     member this.RegisterMe phone name regId = async { try let table = this.MobileService.GetTable<User>() let usr = { Id = "" PhoneHash = MD5Hash phone Nickname = name RegistrationId = regId } do! table.InsertAsync usr |> Async.AwaitPlainTask return (usr.Id, usr.PhoneHash, usr.Nickname) with | e -> System.Diagnostics.Trace.WriteLine(e.ToString) return (String.Empty,String.Empty,String.Empty) }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     member this.RegisterMe phone name regId = async {
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     -       (     )    .       "computation expression"   workflow.   { }       ! ( bang),  do! (do-bang)  let! (let bang)     User.    ,  F#        ,      
      
        
        
        
      
      let usr = { Id = "" PhoneHash = MD5Hash phone Nickname = name RegistrationId = regId }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     do! table.InsertAsync usr |> Async.AwaitPlainTask
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      do-bang,   await
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      C#. ..             continuation    . return (usr.Id, usr.PhoneHash, usr.Nickname)
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
          Tuple<string,string,string>     .  try ... with | e ->
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      try..catch
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      C# 
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
     
      
        
        
        
      
           .  F#    fst
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      snd
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
          .        2 .     : 
      
        
        
        
      
      let id (c,_,_) = c let phonehash (_,c,_) = c let nickname (_,_,c) = c
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
        : id tuple
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      Id  .. 
      
        
        
        
      
     
      
        
        
        
      
        5  Azure,       Push .       Azure Custom Api  
      
        
        
        
      
     
      
        
        
        
      
          exports.post = function(request, response) { // Use "request.service" to access features of your mobile service, eg: // var tables = request.service.tables; // var push = request.service.push; //response.send(statusCodes.OK, { message : 'Hello World!' }); console.log('Incoming call with requst: ', request.body.RequestId); var usersTable = request.service.tables.getTable('User'); usersTable.where( { id : request.body.TargetId } ) .read( { success: function(results) { if (results.length > 0) { var user = results[0] console.log('Send to results: ', user.Nickname, user.RegistrationId); request.service.push.gcm.send(user.RegistrationId, { RequesterId: request.body.RequesterId, RequesterNickname: request.body.RequesterName, TargetId: user.id, TargetNickname: user.Nickname }, { success: function(gcm_response) { console.log('Push notification sent: ', gcm_response); response.send(statusCodes.OK, { RequestedNickname : user.Nickname }); }, error: function(gcm_error) { console.log('Error sending push notification: ', gcm_error); response.send(statusCodes.INTERNAL_SERVER_ERROR, { RequestedNickname : user.Nickname }); } }); } else { response.send(statusCodes.NO_CONTENT, { RequestedNickname : "" }); } }, error: function(error) { console.log('Error read table: ', error); response.send(statusCodes.INTERNAL_SERVER_ERROR, { RequestedNickname : "" }); } }); };
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
        Push      
      
        
        
        
      
     // Perform Push operation member this.PushAsync targetId myId myNickname = async { try let (request : PushRequest) = { TargetId = targetId RequesterId = myId RequesterName = myNickname } let! result = this.MobileService.InvokeApiAsync<PushRequest, PushResponce>("pushhim", request) |> Async.AwaitTask return result.RequestedNickname with | e -> return e.ToString() }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
           ,    let-bang
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
       do!
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
       
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
          Google Play Services.     F#   .           .    : Xamarin.Android.Support.v7.AppCompat 
      
        
        
        
      
         , Google Play Services ,   . 
      
        
        
        
      
     
      
        
        
        
      
          push notification   .    GCM,  ID,     ID       Push  (.   pushhim).        BroadcastReciever       developer.android.com .     F#         Xamarin Component Store.     Google Cloud Messaging Client         GCM    .        ID 
      
        
        
        
      
     //Check to see that GCM is supported and that the manifest has the correct information GcmClient.CheckDevice(this) GcmClient.CheckManifest(this) // check google play if CheckPlayServices() then // Try to get registration id let regId = GcmClient.GetRegistrationId this if String.IsNullOrEmpty(regId) then // Call to Register the device for Push Notifications GcmClient.Register(this, WruConstants.GcmSender);
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
            
      
        
        
        
      
     
      
        
        
        
      
        . 
      
        
        
        
      
        , -  
      
        
        
        
      
         bitbucket.org/xakpc/whereareyou 
      
        
        
        
      
         ,     
      
        
        
        
      
              ,           "" . 
      
        
        
        
      
     
      
        
        
        
      
      
      
        
        
        
      
     ,   Android   F#.      . 
      
        
        
        
      
     ,       -  Android  F#.   ,       .
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
    
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      listView.Adapter <- new ArrayAdapter(this, Android.Resource.Layout.SimpleListItem1, Android.Resource.Id.Text1, values) 
      
        
        
        
      
      , ,  let values = [|"item1"; "item2"; "item3"|]
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     -   string[],       list (IEnumerable   ) 
      
        
        
        
      
              F#.            www.tryfsharp.org/Learn 
      
        
        
        
      
      
 
      
        
        
        
      
          F# -  ,  
      
        
        
        
      
     
      
        
        
        
      
            F# For Fun And Profit 
      
        
        
        
      
     
      
        
        
        
      
       ,    
      
        
        
        
      
         - . 
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
     
      
        
        
        
      
            hash 
      
        
        
        
      
         MD5  F# 
      
        
        
        
      
      let MD5Hash (input : string) = use md5 = System.Security.Cryptography.MD5.Create() input |> System.Text.Encoding.ASCII.GetBytes |> md5.ComputeHash |> Seq.map (fun c -> c.ToString("X2")) |> Seq.reduce (+)
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
      |>
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      pipeline ,     . 
      
        
        
        
      
         :    GetBytes ->   ->      HEX  ->       (  reduce   +           ) ->    . 
      
        
        
        
      
     
      
        
        
        
      
      ,     C# using System; public string CreateMD5Hash (string input) { MD5 md5 = System.Security.Cryptography.MD5.Create(); byte[] inputBytes = System.Text.Encoding.ASCII.GetBytes (input); byte[] hashBytes = md5.ComputeHash (inputBytes); StringBuilder sb = new StringBuilder(); for (int i = 0; i < hashBytes.Length; i++) { sb.Append (hashBytes[i].ToString ("X2")); } return sb.ToString(); }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
     
      
        
        
        
      
              :        .       AzureServiceWorker (  CLR    ) 
      
        
        
        
      
     
      
        
        
        
      
              -   .   F#    !   Xamarin Studio            . 
      
        
        
        
      
      <ItemGroup> <Compile Include="Resources\Resource.designer.fs" /> <Compile Include="Properties\AssemblyInfo.fs" /> <Compile Include="Helpers\Helpers.fs" /> <Compile Include="Services\User.fs" /> <Compile Include="Services\AzureServiceWorker.fs" /> <Compile Include="IAmHereActivity.fs" /> <Compile Include="WhereAreYouActivity.fs" /> <Compile Include="SignInActivity.fs" /> </ItemGroup>
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
        
      
        
        
        
      
            :    .    Xamarin    Xamarin.Mobile 
      
        
        
        
      
     
      
        
        
        
      
          .  F#         TPL,     Task',      .     F#         Task.  ,     : 
      
        
        
        
      
     module Async = open System.Threading open System.Threading.Tasks let inline AwaitPlainTask (task: Task) = // rethrow exception from preceding task if it fauled let continuation (t : Task) : unit = match t.IsFaulted with | true -> raise t.Exception | arg -> () task.ContinueWith continuation |> Async.AwaitTask
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
             Async.AwaitIAsyncResult >> Async.Ignore
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
           
      
        
        
        
      
     
      
        
        
        
      
                
      
        
        
        
      
     let ExtractUserInfo (x : Contact) = let first = x.Phones |> Seq.tryPick(fun x -> if x.Type = PhoneType.Mobile then Some(x) else None) match first with | Some(first) -> let phone = first.Number |> StripChars [' ';'-';'(';')'] UserInfo.CreateUserInfo((MD5Hash phone), phone, x.DisplayName) | None -> UserInfo.CreateUserInfo("no mobile phone", "no mobile phone", "no mobile phone") // function for async list filling let FillContactsAsync = async { let book = new AddressBook (this) let! result = book.RequestPermission() |> Async.AwaitTask if result then _contacts <- book.ToList() |> Seq.filter (fun (x: Contact) -> not (Seq.isEmpty x.Phones)) |> Seq.map ExtractUserInfo |> Seq.sortBy(fun x -> x.DisplayName) |> Seq.toList let finalContacts = _contacts |> Seq.map (fun x -> x.DisplayName.ToUpperInvariant()) |> Seq.toArray this.ListAdapter <- new ArrayAdapter(this, Resource_Layout.row_contact, finalContacts) else System.Diagnostics.Debug.WriteLine("Permission denied by user or manifest") this.ListAdapter <- new ArrayAdapter(this, Resource_Layout.row_contact, Array.empty) }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
          
      
        
        
        
      
     book.ToList()
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
       List |> Seq.filter (fun (x: Contact) -> not (Seq.isEmpty x.Phones))
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
          |> Seq.map ExtractUserInfo
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
          Contracts  UserInfo,      UserInfo |> Seq.sortBy(fun x -> x.DisplayName)
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      |> Seq.toList
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
       List _contacts <-
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
        mutable  _contacts |> Seq.map (fun x -> x.DisplayName.ToUpperInvariant())<-
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
        UserInfo  string,     - -    |> Seq.toArray<-
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      List  Array    ArrayAdapter 
      
        
        
        
      
        -      List.   . 
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
     
      
        
        
        
      
     Azure Mobile Servcies 
      
        
        
        
      
       -    Azure Mobile Services.       NotificationHub,     Push    .   Azure    , ..      . 
      
        
        
        
      
     
      
        
        
        
      
          ,    
      
        
        
        
      
     module WruConstants = [<Literal>] let TotallyNotAzureServer = "https://YOUR.azure-mobile.net/"; [<Literal>] let TotallyNotAzureKey = "YOUR"
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
       
        
        
        
      
     member this.RegisterMe phone name regId = async { try let table = this.MobileService.GetTable<User>() let usr = { Id = "" PhoneHash = MD5Hash phone Nickname = name RegistrationId = regId } do! table.InsertAsync usr |> Async.AwaitPlainTask return (usr.Id, usr.PhoneHash, usr.Nickname) with | e -> System.Diagnostics.Trace.WriteLine(e.ToString) return (String.Empty,String.Empty,String.Empty) }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     member this.RegisterMe phone name regId = async {
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     -       (     )    .       "computation expression"   workflow.   { }       ! ( bang),  do! (do-bang)  let! (let bang)     User.    ,  F#        ,      
      
        
        
        
      
      let usr = { Id = "" PhoneHash = MD5Hash phone Nickname = name RegistrationId = regId }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     do! table.InsertAsync usr |> Async.AwaitPlainTask
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      do-bang,   await
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      C#. ..             continuation    . return (usr.Id, usr.PhoneHash, usr.Nickname)
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
          Tuple<string,string,string>     .  try ... with | e ->
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      try..catch
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      C# 
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
     
      
        
        
        
      
           .  F#    fst
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      snd
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
          .        2 .     : 
      
        
        
        
      
      let id (c,_,_) = c let phonehash (_,c,_) = c let nickname (_,_,c) = c
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
        : id tuple
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      Id  .. 
      
        
        
        
      
     
      
        
        
        
      
        5  Azure,       Push .       Azure Custom Api  
      
        
        
        
      
     
      
        
        
        
      
          exports.post = function(request, response) { // Use "request.service" to access features of your mobile service, eg: // var tables = request.service.tables; // var push = request.service.push; //response.send(statusCodes.OK, { message : 'Hello World!' }); console.log('Incoming call with requst: ', request.body.RequestId); var usersTable = request.service.tables.getTable('User'); usersTable.where( { id : request.body.TargetId } ) .read( { success: function(results) { if (results.length > 0) { var user = results[0] console.log('Send to results: ', user.Nickname, user.RegistrationId); request.service.push.gcm.send(user.RegistrationId, { RequesterId: request.body.RequesterId, RequesterNickname: request.body.RequesterName, TargetId: user.id, TargetNickname: user.Nickname }, { success: function(gcm_response) { console.log('Push notification sent: ', gcm_response); response.send(statusCodes.OK, { RequestedNickname : user.Nickname }); }, error: function(gcm_error) { console.log('Error sending push notification: ', gcm_error); response.send(statusCodes.INTERNAL_SERVER_ERROR, { RequestedNickname : user.Nickname }); } }); } else { response.send(statusCodes.NO_CONTENT, { RequestedNickname : "" }); } }, error: function(error) { console.log('Error read table: ', error); response.send(statusCodes.INTERNAL_SERVER_ERROR, { RequestedNickname : "" }); } }); };
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
        Push      
      
        
        
        
      
     // Perform Push operation member this.PushAsync targetId myId myNickname = async { try let (request : PushRequest) = { TargetId = targetId RequesterId = myId RequesterName = myNickname } let! result = this.MobileService.InvokeApiAsync<PushRequest, PushResponce>("pushhim", request) |> Async.AwaitTask return result.RequestedNickname with | e -> return e.ToString() }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
           ,    let-bang
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
       do!
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
       
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
          Google Play Services.     F#   .           .    : Xamarin.Android.Support.v7.AppCompat 
      
        
        
        
      
         , Google Play Services ,   . 
      
        
        
        
      
     
      
        
        
        
      
          push notification   .    GCM,  ID,     ID       Push  (.   pushhim).        BroadcastReciever       developer.android.com .     F#         Xamarin Component Store.     Google Cloud Messaging Client         GCM    .        ID 
      
        
        
        
      
     //Check to see that GCM is supported and that the manifest has the correct information GcmClient.CheckDevice(this) GcmClient.CheckManifest(this) // check google play if CheckPlayServices() then // Try to get registration id let regId = GcmClient.GetRegistrationId this if String.IsNullOrEmpty(regId) then // Call to Register the device for Push Notifications GcmClient.Register(this, WruConstants.GcmSender);
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
            
      
        
        
        
      
     
      
        
        
        
      
        . 
      
        
        
        
      
        , -  
      
        
        
        
      
         bitbucket.org/xakpc/whereareyou 
      
        
        
        
      
         ,     
      
        
        
        
      
              ,           "" . 
      
        
        
        
      
     
      
        
        
        
      
      
      
        
        
        
      
     ,   Android   F#.      . 
      
        
        
        
      
     ,       -  Android  F#.   ,       .
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
    listView.Adapter <- new ArrayAdapter(this, Android.Resource.Layout.SimpleListItem1, Android.Resource.Id.Text1, values) 
      
        
        
        
      
      , ,  let values = [|"item1"; "item2"; "item3"|]
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     -   string[],       list (IEnumerable   ) 
      
        
        
        
      
              F#.            www.tryfsharp.org/Learn 
      
        
        
        
      
      
 
      
        
        
        
      
          F# -  ,  
      
        
        
        
      
     
      
        
        
        
      
            F# For Fun And Profit 
      
        
        
        
      
     
      
        
        
        
      
       ,    
      
        
        
        
      
         - . 
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
     
      
        
        
        
      
            hash 
      
        
        
        
      
         MD5  F# 
      
        
        
        
      
      let MD5Hash (input : string) = use md5 = System.Security.Cryptography.MD5.Create() input |> System.Text.Encoding.ASCII.GetBytes |> md5.ComputeHash |> Seq.map (fun c -> c.ToString("X2")) |> Seq.reduce (+)
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
      |>
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      pipeline ,     . 
      
        
        
        
      
         :    GetBytes ->   ->      HEX  ->       (  reduce   +           ) ->    . 
      
        
        
        
      
     
      
        
        
        
      
      ,     C# using System; public string CreateMD5Hash (string input) { MD5 md5 = System.Security.Cryptography.MD5.Create(); byte[] inputBytes = System.Text.Encoding.ASCII.GetBytes (input); byte[] hashBytes = md5.ComputeHash (inputBytes); StringBuilder sb = new StringBuilder(); for (int i = 0; i < hashBytes.Length; i++) { sb.Append (hashBytes[i].ToString ("X2")); } return sb.ToString(); }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
     
      
        
        
        
      
              :        .       AzureServiceWorker (  CLR    ) 
      
        
        
        
      
     
      
        
        
        
      
              -   .   F#    !   Xamarin Studio            . 
      
        
        
        
      
      <ItemGroup> <Compile Include="Resources\Resource.designer.fs" /> <Compile Include="Properties\AssemblyInfo.fs" /> <Compile Include="Helpers\Helpers.fs" /> <Compile Include="Services\User.fs" /> <Compile Include="Services\AzureServiceWorker.fs" /> <Compile Include="IAmHereActivity.fs" /> <Compile Include="WhereAreYouActivity.fs" /> <Compile Include="SignInActivity.fs" /> </ItemGroup>
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
        
      
        
        
        
      
            :    .    Xamarin    Xamarin.Mobile 
      
        
        
        
      
     
      
        
        
        
      
          .  F#         TPL,     Task',      .     F#         Task.  ,     : 
      
        
        
        
      
     module Async = open System.Threading open System.Threading.Tasks let inline AwaitPlainTask (task: Task) = // rethrow exception from preceding task if it fauled let continuation (t : Task) : unit = match t.IsFaulted with | true -> raise t.Exception | arg -> () task.ContinueWith continuation |> Async.AwaitTask
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
             Async.AwaitIAsyncResult >> Async.Ignore
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
           
      
        
        
        
      
     
      
        
        
        
      
                
      
        
        
        
      
     let ExtractUserInfo (x : Contact) = let first = x.Phones |> Seq.tryPick(fun x -> if x.Type = PhoneType.Mobile then Some(x) else None) match first with | Some(first) -> let phone = first.Number |> StripChars [' ';'-';'(';')'] UserInfo.CreateUserInfo((MD5Hash phone), phone, x.DisplayName) | None -> UserInfo.CreateUserInfo("no mobile phone", "no mobile phone", "no mobile phone") // function for async list filling let FillContactsAsync = async { let book = new AddressBook (this) let! result = book.RequestPermission() |> Async.AwaitTask if result then _contacts <- book.ToList() |> Seq.filter (fun (x: Contact) -> not (Seq.isEmpty x.Phones)) |> Seq.map ExtractUserInfo |> Seq.sortBy(fun x -> x.DisplayName) |> Seq.toList let finalContacts = _contacts |> Seq.map (fun x -> x.DisplayName.ToUpperInvariant()) |> Seq.toArray this.ListAdapter <- new ArrayAdapter(this, Resource_Layout.row_contact, finalContacts) else System.Diagnostics.Debug.WriteLine("Permission denied by user or manifest") this.ListAdapter <- new ArrayAdapter(this, Resource_Layout.row_contact, Array.empty) }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
          
      
        
        
        
      
     book.ToList()
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
       List |> Seq.filter (fun (x: Contact) -> not (Seq.isEmpty x.Phones))
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
          |> Seq.map ExtractUserInfo
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
          Contracts  UserInfo,      UserInfo |> Seq.sortBy(fun x -> x.DisplayName)
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      |> Seq.toList
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
       List _contacts <-
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
        mutable  _contacts |> Seq.map (fun x -> x.DisplayName.ToUpperInvariant())<-
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
        UserInfo  string,     - -    |> Seq.toArray<-
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      List  Array    ArrayAdapter 
      
        
        
        
      
        -      List.   . 
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
     
      
        
        
        
      
     Azure Mobile Servcies 
      
        
        
        
      
       -    Azure Mobile Services.       NotificationHub,     Push    .   Azure    , ..      . 
      
        
        
        
      
     
      
        
        
        
      
          ,    
      
        
        
        
      
     module WruConstants = [<Literal>] let TotallyNotAzureServer = "https://YOUR.azure-mobile.net/"; [<Literal>] let TotallyNotAzureKey = "YOUR"
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
       
        
        
        
      
     member this.RegisterMe phone name regId = async { try let table = this.MobileService.GetTable<User>() let usr = { Id = "" PhoneHash = MD5Hash phone Nickname = name RegistrationId = regId } do! table.InsertAsync usr |> Async.AwaitPlainTask return (usr.Id, usr.PhoneHash, usr.Nickname) with | e -> System.Diagnostics.Trace.WriteLine(e.ToString) return (String.Empty,String.Empty,String.Empty) }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     member this.RegisterMe phone name regId = async {
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     -       (     )    .       "computation expression"   workflow.   { }       ! ( bang),  do! (do-bang)  let! (let bang)     User.    ,  F#        ,      
      
        
        
        
      
      let usr = { Id = "" PhoneHash = MD5Hash phone Nickname = name RegistrationId = regId }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     do! table.InsertAsync usr |> Async.AwaitPlainTask
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      do-bang,   await
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      C#. ..             continuation    . return (usr.Id, usr.PhoneHash, usr.Nickname)
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
          Tuple<string,string,string>     .  try ... with | e ->
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      try..catch
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      C# 
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
     
      
        
        
        
      
           .  F#    fst
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      snd
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
          .        2 .     : 
      
        
        
        
      
      let id (c,_,_) = c let phonehash (_,c,_) = c let nickname (_,_,c) = c
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
        : id tuple
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      Id  .. 
      
        
        
        
      
     
      
        
        
        
      
        5  Azure,       Push .       Azure Custom Api  
      
        
        
        
      
     
      
        
        
        
      
          exports.post = function(request, response) { // Use "request.service" to access features of your mobile service, eg: // var tables = request.service.tables; // var push = request.service.push; //response.send(statusCodes.OK, { message : 'Hello World!' }); console.log('Incoming call with requst: ', request.body.RequestId); var usersTable = request.service.tables.getTable('User'); usersTable.where( { id : request.body.TargetId } ) .read( { success: function(results) { if (results.length > 0) { var user = results[0] console.log('Send to results: ', user.Nickname, user.RegistrationId); request.service.push.gcm.send(user.RegistrationId, { RequesterId: request.body.RequesterId, RequesterNickname: request.body.RequesterName, TargetId: user.id, TargetNickname: user.Nickname }, { success: function(gcm_response) { console.log('Push notification sent: ', gcm_response); response.send(statusCodes.OK, { RequestedNickname : user.Nickname }); }, error: function(gcm_error) { console.log('Error sending push notification: ', gcm_error); response.send(statusCodes.INTERNAL_SERVER_ERROR, { RequestedNickname : user.Nickname }); } }); } else { response.send(statusCodes.NO_CONTENT, { RequestedNickname : "" }); } }, error: function(error) { console.log('Error read table: ', error); response.send(statusCodes.INTERNAL_SERVER_ERROR, { RequestedNickname : "" }); } }); };
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
        Push      
      
        
        
        
      
     // Perform Push operation member this.PushAsync targetId myId myNickname = async { try let (request : PushRequest) = { TargetId = targetId RequesterId = myId RequesterName = myNickname } let! result = this.MobileService.InvokeApiAsync<PushRequest, PushResponce>("pushhim", request) |> Async.AwaitTask return result.RequestedNickname with | e -> return e.ToString() }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
           ,    let-bang
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
       do!
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
       
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
          Google Play Services.     F#   .           .    : Xamarin.Android.Support.v7.AppCompat 
      
        
        
        
      
         , Google Play Services ,   . 
      
        
        
        
      
     
      
        
        
        
      
          push notification   .    GCM,  ID,     ID       Push  (.   pushhim).        BroadcastReciever       developer.android.com .     F#         Xamarin Component Store.     Google Cloud Messaging Client         GCM    .        ID 
      
        
        
        
      
     //Check to see that GCM is supported and that the manifest has the correct information GcmClient.CheckDevice(this) GcmClient.CheckManifest(this) // check google play if CheckPlayServices() then // Try to get registration id let regId = GcmClient.GetRegistrationId this if String.IsNullOrEmpty(regId) then // Call to Register the device for Push Notifications GcmClient.Register(this, WruConstants.GcmSender);
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
            
      
        
        
        
      
     
      
        
        
        
      
        . 
      
        
        
        
      
        , -  
      
        
        
        
      
         bitbucket.org/xakpc/whereareyou 
      
        
        
        
      
         ,     
      
        
        
        
      
              ,           "" . 
      
        
        
        
      
     
      
        
        
        
      
      
      
        
        
        
      
     ,   Android   F#.      . 
      
        
        
        
      
     ,       -  Android  F#.   ,       .
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     listView.Adapter <- new ArrayAdapter(this, Android.Resource.Layout.SimpleListItem1, Android.Resource.Id.Text1, values) 
      
        
        
        
      
      , ,  let values = [|"item1"; "item2"; "item3"|]
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     -   string[],       list (IEnumerable   ) 
      
        
        
        
      
              F#.            www.tryfsharp.org/Learn 
      
        
        
        
      
      
 
      
        
        
        
      
          F# -  ,  
      
        
        
        
      
     
      
        
        
        
      
            F# For Fun And Profit 
      
        
        
        
      
     
      
        
        
        
      
       ,    
      
        
        
        
      
         - . 
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
     
      
        
        
        
      
            hash 
      
        
        
        
      
         MD5  F# 
      
        
        
        
      
      let MD5Hash (input : string) = use md5 = System.Security.Cryptography.MD5.Create() input |> System.Text.Encoding.ASCII.GetBytes |> md5.ComputeHash |> Seq.map (fun c -> c.ToString("X2")) |> Seq.reduce (+)
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
      |>
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      pipeline ,     . 
      
        
        
        
      
         :    GetBytes ->   ->      HEX  ->       (  reduce   +           ) ->    . 
      
        
        
        
      
     
      
        
        
        
      
      ,     C# using System; public string CreateMD5Hash (string input) { MD5 md5 = System.Security.Cryptography.MD5.Create(); byte[] inputBytes = System.Text.Encoding.ASCII.GetBytes (input); byte[] hashBytes = md5.ComputeHash (inputBytes); StringBuilder sb = new StringBuilder(); for (int i = 0; i < hashBytes.Length; i++) { sb.Append (hashBytes[i].ToString ("X2")); } return sb.ToString(); }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
     
      
        
        
        
      
              :        .       AzureServiceWorker (  CLR    ) 
      
        
        
        
      
     
      
        
        
        
      
              -   .   F#    !   Xamarin Studio            . 
      
        
        
        
      
      <ItemGroup> <Compile Include="Resources\Resource.designer.fs" /> <Compile Include="Properties\AssemblyInfo.fs" /> <Compile Include="Helpers\Helpers.fs" /> <Compile Include="Services\User.fs" /> <Compile Include="Services\AzureServiceWorker.fs" /> <Compile Include="IAmHereActivity.fs" /> <Compile Include="WhereAreYouActivity.fs" /> <Compile Include="SignInActivity.fs" /> </ItemGroup>
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
        
      
        
        
        
      
            :    .    Xamarin    Xamarin.Mobile 
      
        
        
        
      
     
      
        
        
        
      
          .  F#         TPL,     Task',      .     F#         Task.  ,     : 
      
        
        
        
      
     module Async = open System.Threading open System.Threading.Tasks let inline AwaitPlainTask (task: Task) = // rethrow exception from preceding task if it fauled let continuation (t : Task) : unit = match t.IsFaulted with | true -> raise t.Exception | arg -> () task.ContinueWith continuation |> Async.AwaitTask
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
             Async.AwaitIAsyncResult >> Async.Ignore
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
           
      
        
        
        
      
     
      
        
        
        
      
                
      
        
        
        
      
     let ExtractUserInfo (x : Contact) = let first = x.Phones |> Seq.tryPick(fun x -> if x.Type = PhoneType.Mobile then Some(x) else None) match first with | Some(first) -> let phone = first.Number |> StripChars [' ';'-';'(';')'] UserInfo.CreateUserInfo((MD5Hash phone), phone, x.DisplayName) | None -> UserInfo.CreateUserInfo("no mobile phone", "no mobile phone", "no mobile phone") // function for async list filling let FillContactsAsync = async { let book = new AddressBook (this) let! result = book.RequestPermission() |> Async.AwaitTask if result then _contacts <- book.ToList() |> Seq.filter (fun (x: Contact) -> not (Seq.isEmpty x.Phones)) |> Seq.map ExtractUserInfo |> Seq.sortBy(fun x -> x.DisplayName) |> Seq.toList let finalContacts = _contacts |> Seq.map (fun x -> x.DisplayName.ToUpperInvariant()) |> Seq.toArray this.ListAdapter <- new ArrayAdapter(this, Resource_Layout.row_contact, finalContacts) else System.Diagnostics.Debug.WriteLine("Permission denied by user or manifest") this.ListAdapter <- new ArrayAdapter(this, Resource_Layout.row_contact, Array.empty) }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
          
      
        
        
        
      
     book.ToList()
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
       List |> Seq.filter (fun (x: Contact) -> not (Seq.isEmpty x.Phones))
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
          |> Seq.map ExtractUserInfo
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
          Contracts  UserInfo,      UserInfo |> Seq.sortBy(fun x -> x.DisplayName)
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      |> Seq.toList
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
       List _contacts <-
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
        mutable  _contacts |> Seq.map (fun x -> x.DisplayName.ToUpperInvariant())<-
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
        UserInfo  string,     - -    |> Seq.toArray<-
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      List  Array    ArrayAdapter 
      
        
        
        
      
        -      List.   . 
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
     
      
        
        
        
      
     Azure Mobile Servcies 
      
        
        
        
      
       -    Azure Mobile Services.       NotificationHub,     Push    .   Azure    , ..      . 
      
        
        
        
      
     
      
        
        
        
      
          ,    
      
        
        
        
      
     module WruConstants = [<Literal>] let TotallyNotAzureServer = "https://YOUR.azure-mobile.net/"; [<Literal>] let TotallyNotAzureKey = "YOUR"
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
       
        
        
        
      
     member this.RegisterMe phone name regId = async { try let table = this.MobileService.GetTable<User>() let usr = { Id = "" PhoneHash = MD5Hash phone Nickname = name RegistrationId = regId } do! table.InsertAsync usr |> Async.AwaitPlainTask return (usr.Id, usr.PhoneHash, usr.Nickname) with | e -> System.Diagnostics.Trace.WriteLine(e.ToString) return (String.Empty,String.Empty,String.Empty) }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     member this.RegisterMe phone name regId = async {
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     -       (     )    .       "computation expression"   workflow.   { }       ! ( bang),  do! (do-bang)  let! (let bang)     User.    ,  F#        ,      
      
        
        
        
      
      let usr = { Id = "" PhoneHash = MD5Hash phone Nickname = name RegistrationId = regId }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     do! table.InsertAsync usr |> Async.AwaitPlainTask
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      do-bang,   await
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      C#. ..             continuation    . return (usr.Id, usr.PhoneHash, usr.Nickname)
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
          Tuple<string,string,string>     .  try ... with | e ->
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      try..catch
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      C# 
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
     
      
        
        
        
      
           .  F#    fst
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      snd
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
          .        2 .     : 
      
        
        
        
      
      let id (c,_,_) = c let phonehash (_,c,_) = c let nickname (_,_,c) = c
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
        : id tuple
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      Id  .. 
      
        
        
        
      
     
      
        
        
        
      
        5  Azure,       Push .       Azure Custom Api  
      
        
        
        
      
     
      
        
        
        
      
          exports.post = function(request, response) { // Use "request.service" to access features of your mobile service, eg: // var tables = request.service.tables; // var push = request.service.push; //response.send(statusCodes.OK, { message : 'Hello World!' }); console.log('Incoming call with requst: ', request.body.RequestId); var usersTable = request.service.tables.getTable('User'); usersTable.where( { id : request.body.TargetId } ) .read( { success: function(results) { if (results.length > 0) { var user = results[0] console.log('Send to results: ', user.Nickname, user.RegistrationId); request.service.push.gcm.send(user.RegistrationId, { RequesterId: request.body.RequesterId, RequesterNickname: request.body.RequesterName, TargetId: user.id, TargetNickname: user.Nickname }, { success: function(gcm_response) { console.log('Push notification sent: ', gcm_response); response.send(statusCodes.OK, { RequestedNickname : user.Nickname }); }, error: function(gcm_error) { console.log('Error sending push notification: ', gcm_error); response.send(statusCodes.INTERNAL_SERVER_ERROR, { RequestedNickname : user.Nickname }); } }); } else { response.send(statusCodes.NO_CONTENT, { RequestedNickname : "" }); } }, error: function(error) { console.log('Error read table: ', error); response.send(statusCodes.INTERNAL_SERVER_ERROR, { RequestedNickname : "" }); } }); };
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
        Push      
      
        
        
        
      
     // Perform Push operation member this.PushAsync targetId myId myNickname = async { try let (request : PushRequest) = { TargetId = targetId RequesterId = myId RequesterName = myNickname } let! result = this.MobileService.InvokeApiAsync<PushRequest, PushResponce>("pushhim", request) |> Async.AwaitTask return result.RequestedNickname with | e -> return e.ToString() }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
           ,    let-bang
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
       do!
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
       
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
          Google Play Services.     F#   .           .    : Xamarin.Android.Support.v7.AppCompat 
      
        
        
        
      
         , Google Play Services ,   . 
      
        
        
        
      
     
      
        
        
        
      
          push notification   .    GCM,  ID,     ID       Push  (.   pushhim).        BroadcastReciever       developer.android.com .     F#         Xamarin Component Store.     Google Cloud Messaging Client         GCM    .        ID 
      
        
        
        
      
     //Check to see that GCM is supported and that the manifest has the correct information GcmClient.CheckDevice(this) GcmClient.CheckManifest(this) // check google play if CheckPlayServices() then // Try to get registration id let regId = GcmClient.GetRegistrationId this if String.IsNullOrEmpty(regId) then // Call to Register the device for Push Notifications GcmClient.Register(this, WruConstants.GcmSender);
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
            
      
        
        
        
      
     
      
        
        
        
      
        . 
      
        
        
        
      
        , -  
      
        
        
        
      
         bitbucket.org/xakpc/whereareyou 
      
        
        
        
      
         ,     
      
        
        
        
      
              ,           "" . 
      
        
        
        
      
     
      
        
        
        
      
      
      
        
        
        
      
     ,   Android   F#.      . 
      
        
        
        
      
     ,       -  Android  F#.   ,       .
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
    
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      listView.Adapter <- new ArrayAdapter(this, Android.Resource.Layout.SimpleListItem1, Android.Resource.Id.Text1, values) 
      
        
        
        
      
      , ,  let values = [|"item1"; "item2"; "item3"|]
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     -   string[],       list (IEnumerable   ) 
      
        
        
        
      
              F#.            www.tryfsharp.org/Learn 
      
        
        
        
      
      
 
      
        
        
        
      
          F# -  ,  
      
        
        
        
      
     
      
        
        
        
      
            F# For Fun And Profit 
      
        
        
        
      
     
      
        
        
        
      
       ,    
      
        
        
        
      
         - . 
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
     
      
        
        
        
      
            hash 
      
        
        
        
      
         MD5  F# 
      
        
        
        
      
      let MD5Hash (input : string) = use md5 = System.Security.Cryptography.MD5.Create() input |> System.Text.Encoding.ASCII.GetBytes |> md5.ComputeHash |> Seq.map (fun c -> c.ToString("X2")) |> Seq.reduce (+)
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
      |>
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      pipeline ,     . 
      
        
        
        
      
         :    GetBytes ->   ->      HEX  ->       (  reduce   +           ) ->    . 
      
        
        
        
      
     
      
        
        
        
      
      ,     C# using System; public string CreateMD5Hash (string input) { MD5 md5 = System.Security.Cryptography.MD5.Create(); byte[] inputBytes = System.Text.Encoding.ASCII.GetBytes (input); byte[] hashBytes = md5.ComputeHash (inputBytes); StringBuilder sb = new StringBuilder(); for (int i = 0; i < hashBytes.Length; i++) { sb.Append (hashBytes[i].ToString ("X2")); } return sb.ToString(); }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
     
      
        
        
        
      
              :        .       AzureServiceWorker (  CLR    ) 
      
        
        
        
      
     
      
        
        
        
      
              -   .   F#    !   Xamarin Studio            . 
      
        
        
        
      
      <ItemGroup> <Compile Include="Resources\Resource.designer.fs" /> <Compile Include="Properties\AssemblyInfo.fs" /> <Compile Include="Helpers\Helpers.fs" /> <Compile Include="Services\User.fs" /> <Compile Include="Services\AzureServiceWorker.fs" /> <Compile Include="IAmHereActivity.fs" /> <Compile Include="WhereAreYouActivity.fs" /> <Compile Include="SignInActivity.fs" /> </ItemGroup>
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
        
      
        
        
        
      
            :    .    Xamarin    Xamarin.Mobile 
      
        
        
        
      
     
      
        
        
        
      
          .  F#         TPL,     Task',      .     F#         Task.  ,     : 
      
        
        
        
      
     module Async = open System.Threading open System.Threading.Tasks let inline AwaitPlainTask (task: Task) = // rethrow exception from preceding task if it fauled let continuation (t : Task) : unit = match t.IsFaulted with | true -> raise t.Exception | arg -> () task.ContinueWith continuation |> Async.AwaitTask
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
             Async.AwaitIAsyncResult >> Async.Ignore
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
           
      
        
        
        
      
     
      
        
        
        
      
                
      
        
        
        
      
     let ExtractUserInfo (x : Contact) = let first = x.Phones |> Seq.tryPick(fun x -> if x.Type = PhoneType.Mobile then Some(x) else None) match first with | Some(first) -> let phone = first.Number |> StripChars [' ';'-';'(';')'] UserInfo.CreateUserInfo((MD5Hash phone), phone, x.DisplayName) | None -> UserInfo.CreateUserInfo("no mobile phone", "no mobile phone", "no mobile phone") // function for async list filling let FillContactsAsync = async { let book = new AddressBook (this) let! result = book.RequestPermission() |> Async.AwaitTask if result then _contacts <- book.ToList() |> Seq.filter (fun (x: Contact) -> not (Seq.isEmpty x.Phones)) |> Seq.map ExtractUserInfo |> Seq.sortBy(fun x -> x.DisplayName) |> Seq.toList let finalContacts = _contacts |> Seq.map (fun x -> x.DisplayName.ToUpperInvariant()) |> Seq.toArray this.ListAdapter <- new ArrayAdapter(this, Resource_Layout.row_contact, finalContacts) else System.Diagnostics.Debug.WriteLine("Permission denied by user or manifest") this.ListAdapter <- new ArrayAdapter(this, Resource_Layout.row_contact, Array.empty) }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
          
      
        
        
        
      
     book.ToList()
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
       List |> Seq.filter (fun (x: Contact) -> not (Seq.isEmpty x.Phones))
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
          |> Seq.map ExtractUserInfo
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
          Contracts  UserInfo,      UserInfo |> Seq.sortBy(fun x -> x.DisplayName)
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      |> Seq.toList
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
       List _contacts <-
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
        mutable  _contacts |> Seq.map (fun x -> x.DisplayName.ToUpperInvariant())<-
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
        UserInfo  string,     - -    |> Seq.toArray<-
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      List  Array    ArrayAdapter 
      
        
        
        
      
        -      List.   . 
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
     
      
        
        
        
      
     Azure Mobile Servcies 
      
        
        
        
      
       -    Azure Mobile Services.       NotificationHub,     Push    .   Azure    , ..      . 
      
        
        
        
      
     
      
        
        
        
      
          ,    
      
        
        
        
      
     module WruConstants = [<Literal>] let TotallyNotAzureServer = "https://YOUR.azure-mobile.net/"; [<Literal>] let TotallyNotAzureKey = "YOUR"
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
       
        
        
        
      
     member this.RegisterMe phone name regId = async { try let table = this.MobileService.GetTable<User>() let usr = { Id = "" PhoneHash = MD5Hash phone Nickname = name RegistrationId = regId } do! table.InsertAsync usr |> Async.AwaitPlainTask return (usr.Id, usr.PhoneHash, usr.Nickname) with | e -> System.Diagnostics.Trace.WriteLine(e.ToString) return (String.Empty,String.Empty,String.Empty) }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     member this.RegisterMe phone name regId = async {
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     -       (     )    .       "computation expression"   workflow.   { }       ! ( bang),  do! (do-bang)  let! (let bang)     User.    ,  F#        ,      
      
        
        
        
      
      let usr = { Id = "" PhoneHash = MD5Hash phone Nickname = name RegistrationId = regId }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     do! table.InsertAsync usr |> Async.AwaitPlainTask
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      do-bang,   await
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      C#. ..             continuation    . return (usr.Id, usr.PhoneHash, usr.Nickname)
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
          Tuple<string,string,string>     .  try ... with | e ->
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      try..catch
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      C# 
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
     
      
        
        
        
      
           .  F#    fst
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      snd
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
          .        2 .     : 
      
        
        
        
      
      let id (c,_,_) = c let phonehash (_,c,_) = c let nickname (_,_,c) = c
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
        : id tuple
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      Id  .. 
      
        
        
        
      
     
      
        
        
        
      
        5  Azure,       Push .       Azure Custom Api  
      
        
        
        
      
     
      
        
        
        
      
          exports.post = function(request, response) { // Use "request.service" to access features of your mobile service, eg: // var tables = request.service.tables; // var push = request.service.push; //response.send(statusCodes.OK, { message : 'Hello World!' }); console.log('Incoming call with requst: ', request.body.RequestId); var usersTable = request.service.tables.getTable('User'); usersTable.where( { id : request.body.TargetId } ) .read( { success: function(results) { if (results.length > 0) { var user = results[0] console.log('Send to results: ', user.Nickname, user.RegistrationId); request.service.push.gcm.send(user.RegistrationId, { RequesterId: request.body.RequesterId, RequesterNickname: request.body.RequesterName, TargetId: user.id, TargetNickname: user.Nickname }, { success: function(gcm_response) { console.log('Push notification sent: ', gcm_response); response.send(statusCodes.OK, { RequestedNickname : user.Nickname }); }, error: function(gcm_error) { console.log('Error sending push notification: ', gcm_error); response.send(statusCodes.INTERNAL_SERVER_ERROR, { RequestedNickname : user.Nickname }); } }); } else { response.send(statusCodes.NO_CONTENT, { RequestedNickname : "" }); } }, error: function(error) { console.log('Error read table: ', error); response.send(statusCodes.INTERNAL_SERVER_ERROR, { RequestedNickname : "" }); } }); };
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
        Push      
      
        
        
        
      
     // Perform Push operation member this.PushAsync targetId myId myNickname = async { try let (request : PushRequest) = { TargetId = targetId RequesterId = myId RequesterName = myNickname } let! result = this.MobileService.InvokeApiAsync<PushRequest, PushResponce>("pushhim", request) |> Async.AwaitTask return result.RequestedNickname with | e -> return e.ToString() }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
           ,    let-bang
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
       do!
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
       
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
          Google Play Services.     F#   .           .    : Xamarin.Android.Support.v7.AppCompat 
      
        
        
        
      
         , Google Play Services ,   . 
      
        
        
        
      
     
      
        
        
        
      
          push notification   .    GCM,  ID,     ID       Push  (.   pushhim).        BroadcastReciever       developer.android.com .     F#         Xamarin Component Store.     Google Cloud Messaging Client         GCM    .        ID 
      
        
        
        
      
     //Check to see that GCM is supported and that the manifest has the correct information GcmClient.CheckDevice(this) GcmClient.CheckManifest(this) // check google play if CheckPlayServices() then // Try to get registration id let regId = GcmClient.GetRegistrationId this if String.IsNullOrEmpty(regId) then // Call to Register the device for Push Notifications GcmClient.Register(this, WruConstants.GcmSender);
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
            
      
        
        
        
      
     
      
        
        
        
      
        . 
      
        
        
        
      
        , -  
      
        
        
        
      
         bitbucket.org/xakpc/whereareyou 
      
        
        
        
      
         ,     
      
        
        
        
      
              ,           "" . 
      
        
        
        
      
     
      
        
        
        
      
      
      
        
        
        
      
     ,   Android   F#.      . 
      
        
        
        
      
     ,       -  Android  F#.   ,       .
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     listView.Adapter <- new ArrayAdapter(this, Android.Resource.Layout.SimpleListItem1, Android.Resource.Id.Text1, values) 
      
        
        
        
      
      , ,  let values = [|"item1"; "item2"; "item3"|]
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     -   string[],       list (IEnumerable   ) 
      
        
        
        
      
              F#.            www.tryfsharp.org/Learn 
      
        
        
        
      
      
 
      
        
        
        
      
          F# -  ,  
      
        
        
        
      
     
      
        
        
        
      
            F# For Fun And Profit 
      
        
        
        
      
     
      
        
        
        
      
       ,    
      
        
        
        
      
         - . 
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
     
      
        
        
        
      
            hash 
      
        
        
        
      
         MD5  F# 
      
        
        
        
      
      let MD5Hash (input : string) = use md5 = System.Security.Cryptography.MD5.Create() input |> System.Text.Encoding.ASCII.GetBytes |> md5.ComputeHash |> Seq.map (fun c -> c.ToString("X2")) |> Seq.reduce (+)
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
      |>
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      pipeline ,     . 
      
        
        
        
      
         :    GetBytes ->   ->      HEX  ->       (  reduce   +           ) ->    . 
      
        
        
        
      
     
      
        
        
        
      
      ,     C# using System; public string CreateMD5Hash (string input) { MD5 md5 = System.Security.Cryptography.MD5.Create(); byte[] inputBytes = System.Text.Encoding.ASCII.GetBytes (input); byte[] hashBytes = md5.ComputeHash (inputBytes); StringBuilder sb = new StringBuilder(); for (int i = 0; i < hashBytes.Length; i++) { sb.Append (hashBytes[i].ToString ("X2")); } return sb.ToString(); }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
     
      
        
        
        
      
              :        .       AzureServiceWorker (  CLR    ) 
      
        
        
        
      
     
      
        
        
        
      
              -   .   F#    !   Xamarin Studio            . 
      
        
        
        
      
      <ItemGroup> <Compile Include="Resources\Resource.designer.fs" /> <Compile Include="Properties\AssemblyInfo.fs" /> <Compile Include="Helpers\Helpers.fs" /> <Compile Include="Services\User.fs" /> <Compile Include="Services\AzureServiceWorker.fs" /> <Compile Include="IAmHereActivity.fs" /> <Compile Include="WhereAreYouActivity.fs" /> <Compile Include="SignInActivity.fs" /> </ItemGroup>
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
        
      
        
        
        
      
            :    .    Xamarin    Xamarin.Mobile 
      
        
        
        
      
     
      
        
        
        
      
          .  F#         TPL,     Task',      .     F#         Task.  ,     : 
      
        
        
        
      
     module Async = open System.Threading open System.Threading.Tasks let inline AwaitPlainTask (task: Task) = // rethrow exception from preceding task if it fauled let continuation (t : Task) : unit = match t.IsFaulted with | true -> raise t.Exception | arg -> () task.ContinueWith continuation |> Async.AwaitTask
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
             Async.AwaitIAsyncResult >> Async.Ignore
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
           
      
        
        
        
      
     
      
        
        
        
      
                
      
        
        
        
      
     let ExtractUserInfo (x : Contact) = let first = x.Phones |> Seq.tryPick(fun x -> if x.Type = PhoneType.Mobile then Some(x) else None) match first with | Some(first) -> let phone = first.Number |> StripChars [' ';'-';'(';')'] UserInfo.CreateUserInfo((MD5Hash phone), phone, x.DisplayName) | None -> UserInfo.CreateUserInfo("no mobile phone", "no mobile phone", "no mobile phone") // function for async list filling let FillContactsAsync = async { let book = new AddressBook (this) let! result = book.RequestPermission() |> Async.AwaitTask if result then _contacts <- book.ToList() |> Seq.filter (fun (x: Contact) -> not (Seq.isEmpty x.Phones)) |> Seq.map ExtractUserInfo |> Seq.sortBy(fun x -> x.DisplayName) |> Seq.toList let finalContacts = _contacts |> Seq.map (fun x -> x.DisplayName.ToUpperInvariant()) |> Seq.toArray this.ListAdapter <- new ArrayAdapter(this, Resource_Layout.row_contact, finalContacts) else System.Diagnostics.Debug.WriteLine("Permission denied by user or manifest") this.ListAdapter <- new ArrayAdapter(this, Resource_Layout.row_contact, Array.empty) }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
          
      
        
        
        
      
     book.ToList()
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
       List |> Seq.filter (fun (x: Contact) -> not (Seq.isEmpty x.Phones))
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
          |> Seq.map ExtractUserInfo
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
          Contracts  UserInfo,      UserInfo |> Seq.sortBy(fun x -> x.DisplayName)
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      |> Seq.toList
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
       List _contacts <-
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
        mutable  _contacts |> Seq.map (fun x -> x.DisplayName.ToUpperInvariant())<-
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
        UserInfo  string,     - -    |> Seq.toArray<-
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      List  Array    ArrayAdapter 
      
        
        
        
      
        -      List.   . 
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
     
      
        
        
        
      
     Azure Mobile Servcies 
      
        
        
        
      
       -    Azure Mobile Services.       NotificationHub,     Push    .   Azure    , ..      . 
      
        
        
        
      
     
      
        
        
        
      
          ,    
      
        
        
        
      
     module WruConstants = [<Literal>] let TotallyNotAzureServer = "https://YOUR.azure-mobile.net/"; [<Literal>] let TotallyNotAzureKey = "YOUR"
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
       
        
        
        
      
     member this.RegisterMe phone name regId = async { try let table = this.MobileService.GetTable<User>() let usr = { Id = "" PhoneHash = MD5Hash phone Nickname = name RegistrationId = regId } do! table.InsertAsync usr |> Async.AwaitPlainTask return (usr.Id, usr.PhoneHash, usr.Nickname) with | e -> System.Diagnostics.Trace.WriteLine(e.ToString) return (String.Empty,String.Empty,String.Empty) }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     member this.RegisterMe phone name regId = async {
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     -       (     )    .       "computation expression"   workflow.   { }       ! ( bang),  do! (do-bang)  let! (let bang)     User.    ,  F#        ,      
      
        
        
        
      
      let usr = { Id = "" PhoneHash = MD5Hash phone Nickname = name RegistrationId = regId }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     do! table.InsertAsync usr |> Async.AwaitPlainTask
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      do-bang,   await
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      C#. ..             continuation    . return (usr.Id, usr.PhoneHash, usr.Nickname)
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
          Tuple<string,string,string>     .  try ... with | e ->
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      try..catch
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      C# 
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
     
      
        
        
        
      
           .  F#    fst
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      snd
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
          .        2 .     : 
      
        
        
        
      
      let id (c,_,_) = c let phonehash (_,c,_) = c let nickname (_,_,c) = c
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
        : id tuple
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      Id  .. 
      
        
        
        
      
     
      
        
        
        
      
        5  Azure,       Push .       Azure Custom Api  
      
        
        
        
      
     
      
        
        
        
      
          exports.post = function(request, response) { // Use "request.service" to access features of your mobile service, eg: // var tables = request.service.tables; // var push = request.service.push; //response.send(statusCodes.OK, { message : 'Hello World!' }); console.log('Incoming call with requst: ', request.body.RequestId); var usersTable = request.service.tables.getTable('User'); usersTable.where( { id : request.body.TargetId } ) .read( { success: function(results) { if (results.length > 0) { var user = results[0] console.log('Send to results: ', user.Nickname, user.RegistrationId); request.service.push.gcm.send(user.RegistrationId, { RequesterId: request.body.RequesterId, RequesterNickname: request.body.RequesterName, TargetId: user.id, TargetNickname: user.Nickname }, { success: function(gcm_response) { console.log('Push notification sent: ', gcm_response); response.send(statusCodes.OK, { RequestedNickname : user.Nickname }); }, error: function(gcm_error) { console.log('Error sending push notification: ', gcm_error); response.send(statusCodes.INTERNAL_SERVER_ERROR, { RequestedNickname : user.Nickname }); } }); } else { response.send(statusCodes.NO_CONTENT, { RequestedNickname : "" }); } }, error: function(error) { console.log('Error read table: ', error); response.send(statusCodes.INTERNAL_SERVER_ERROR, { RequestedNickname : "" }); } }); };
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
        Push      
      
        
        
        
      
     // Perform Push operation member this.PushAsync targetId myId myNickname = async { try let (request : PushRequest) = { TargetId = targetId RequesterId = myId RequesterName = myNickname } let! result = this.MobileService.InvokeApiAsync<PushRequest, PushResponce>("pushhim", request) |> Async.AwaitTask return result.RequestedNickname with | e -> return e.ToString() }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
           ,    let-bang
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
       do!
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
       
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
          Google Play Services.     F#   .           .    : Xamarin.Android.Support.v7.AppCompat 
      
        
        
        
      
         , Google Play Services ,   . 
      
        
        
        
      
     
      
        
        
        
      
          push notification   .    GCM,  ID,     ID       Push  (.   pushhim).        BroadcastReciever       developer.android.com .     F#         Xamarin Component Store.     Google Cloud Messaging Client         GCM    .        ID 
      
        
        
        
      
     //Check to see that GCM is supported and that the manifest has the correct information GcmClient.CheckDevice(this) GcmClient.CheckManifest(this) // check google play if CheckPlayServices() then // Try to get registration id let regId = GcmClient.GetRegistrationId this if String.IsNullOrEmpty(regId) then // Call to Register the device for Push Notifications GcmClient.Register(this, WruConstants.GcmSender);
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
            
      
        
        
        
      
     
      
        
        
        
      
        . 
      
        
        
        
      
        , -  
      
        
        
        
      
         bitbucket.org/xakpc/whereareyou 
      
        
        
        
      
         ,     
      
        
        
        
      
              ,           "" . 
      
        
        
        
      
     
      
        
        
        
      
      
      
        
        
        
      
     ,   Android   F#.      . 
      
        
        
        
      
     ,       -  Android  F#.   ,       .
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
    
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
 listView.Adapter <- new ArrayAdapter(this, Android.Resource.Layout.SimpleListItem1, Android.Resource.Id.Text1, values) 
      
        
        
        
      
      , ,  let values = [|"item1"; "item2"; "item3"|]
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     -   string[],       list (IEnumerable   ) 
      
        
        
        
      
              F#.            www.tryfsharp.org/Learn 
      
        
        
        
      
      
 
      
        
        
        
      
          F# -  ,  
      
        
        
        
      
     
      
        
        
        
      
            F# For Fun And Profit 
      
        
        
        
      
     
      
        
        
        
      
       ,    
      
        
        
        
      
         - . 
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
     
      
        
        
        
      
            hash 
      
        
        
        
      
         MD5  F# 
      
        
        
        
      
      let MD5Hash (input : string) = use md5 = System.Security.Cryptography.MD5.Create() input |> System.Text.Encoding.ASCII.GetBytes |> md5.ComputeHash |> Seq.map (fun c -> c.ToString("X2")) |> Seq.reduce (+)
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
      |>
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      pipeline ,     . 
      
        
        
        
      
         :    GetBytes ->   ->      HEX  ->       (  reduce   +           ) ->    . 
      
        
        
        
      
     
      
        
        
        
      
      ,     C# using System; public string CreateMD5Hash (string input) { MD5 md5 = System.Security.Cryptography.MD5.Create(); byte[] inputBytes = System.Text.Encoding.ASCII.GetBytes (input); byte[] hashBytes = md5.ComputeHash (inputBytes); StringBuilder sb = new StringBuilder(); for (int i = 0; i < hashBytes.Length; i++) { sb.Append (hashBytes[i].ToString ("X2")); } return sb.ToString(); }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
     
      
        
        
        
      
              :        .       AzureServiceWorker (  CLR    ) 
      
        
        
        
      
     
      
        
        
        
      
              -   .   F#    !   Xamarin Studio            . 
      
        
        
        
      
      <ItemGroup> <Compile Include="Resources\Resource.designer.fs" /> <Compile Include="Properties\AssemblyInfo.fs" /> <Compile Include="Helpers\Helpers.fs" /> <Compile Include="Services\User.fs" /> <Compile Include="Services\AzureServiceWorker.fs" /> <Compile Include="IAmHereActivity.fs" /> <Compile Include="WhereAreYouActivity.fs" /> <Compile Include="SignInActivity.fs" /> </ItemGroup>
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
        
      
        
        
        
      
            :    .    Xamarin    Xamarin.Mobile 
      
        
        
        
      
     
      
        
        
        
      
          .  F#         TPL,     Task',      .     F#         Task.  ,     : 
      
        
        
        
      
     module Async = open System.Threading open System.Threading.Tasks let inline AwaitPlainTask (task: Task) = // rethrow exception from preceding task if it fauled let continuation (t : Task) : unit = match t.IsFaulted with | true -> raise t.Exception | arg -> () task.ContinueWith continuation |> Async.AwaitTask
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
             Async.AwaitIAsyncResult >> Async.Ignore
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
           
      
        
        
        
      
     
      
        
        
        
      
                
      
        
        
        
      
     let ExtractUserInfo (x : Contact) = let first = x.Phones |> Seq.tryPick(fun x -> if x.Type = PhoneType.Mobile then Some(x) else None) match first with | Some(first) -> let phone = first.Number |> StripChars [' ';'-';'(';')'] UserInfo.CreateUserInfo((MD5Hash phone), phone, x.DisplayName) | None -> UserInfo.CreateUserInfo("no mobile phone", "no mobile phone", "no mobile phone") // function for async list filling let FillContactsAsync = async { let book = new AddressBook (this) let! result = book.RequestPermission() |> Async.AwaitTask if result then _contacts <- book.ToList() |> Seq.filter (fun (x: Contact) -> not (Seq.isEmpty x.Phones)) |> Seq.map ExtractUserInfo |> Seq.sortBy(fun x -> x.DisplayName) |> Seq.toList let finalContacts = _contacts |> Seq.map (fun x -> x.DisplayName.ToUpperInvariant()) |> Seq.toArray this.ListAdapter <- new ArrayAdapter(this, Resource_Layout.row_contact, finalContacts) else System.Diagnostics.Debug.WriteLine("Permission denied by user or manifest") this.ListAdapter <- new ArrayAdapter(this, Resource_Layout.row_contact, Array.empty) }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
          
      
        
        
        
      
     book.ToList()
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
       List |> Seq.filter (fun (x: Contact) -> not (Seq.isEmpty x.Phones))
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
          |> Seq.map ExtractUserInfo
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
          Contracts  UserInfo,      UserInfo |> Seq.sortBy(fun x -> x.DisplayName)
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      |> Seq.toList
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
       List _contacts <-
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
        mutable  _contacts |> Seq.map (fun x -> x.DisplayName.ToUpperInvariant())<-
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
        UserInfo  string,     - -    |> Seq.toArray<-
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      List  Array    ArrayAdapter 
      
        
        
        
      
        -      List.   . 
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
     
      
        
        
        
      
     Azure Mobile Servcies 
      
        
        
        
      
       -    Azure Mobile Services.       NotificationHub,     Push    .   Azure    , ..      . 
      
        
        
        
      
     
      
        
        
        
      
          ,    
      
        
        
        
      
     module WruConstants = [<Literal>] let TotallyNotAzureServer = "https://YOUR.azure-mobile.net/"; [<Literal>] let TotallyNotAzureKey = "YOUR"
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
       
        
        
        
      
     member this.RegisterMe phone name regId = async { try let table = this.MobileService.GetTable<User>() let usr = { Id = "" PhoneHash = MD5Hash phone Nickname = name RegistrationId = regId } do! table.InsertAsync usr |> Async.AwaitPlainTask return (usr.Id, usr.PhoneHash, usr.Nickname) with | e -> System.Diagnostics.Trace.WriteLine(e.ToString) return (String.Empty,String.Empty,String.Empty) }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     member this.RegisterMe phone name regId = async {
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     -       (     )    .       "computation expression"   workflow.   { }       ! ( bang),  do! (do-bang)  let! (let bang)     User.    ,  F#        ,      
      
        
        
        
      
      let usr = { Id = "" PhoneHash = MD5Hash phone Nickname = name RegistrationId = regId }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     do! table.InsertAsync usr |> Async.AwaitPlainTask
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      do-bang,   await
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      C#. ..             continuation    . return (usr.Id, usr.PhoneHash, usr.Nickname)
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
          Tuple<string,string,string>     .  try ... with | e ->
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      try..catch
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      C# 
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
     
      
        
        
        
      
           .  F#    fst
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      snd
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
          .        2 .     : 
      
        
        
        
      
      let id (c,_,_) = c let phonehash (_,c,_) = c let nickname (_,_,c) = c
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
        : id tuple
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      Id  .. 
      
        
        
        
      
     
      
        
        
        
      
        5  Azure,       Push .       Azure Custom Api  
      
        
        
        
      
     
      
        
        
        
      
          exports.post = function(request, response) { // Use "request.service" to access features of your mobile service, eg: // var tables = request.service.tables; // var push = request.service.push; //response.send(statusCodes.OK, { message : 'Hello World!' }); console.log('Incoming call with requst: ', request.body.RequestId); var usersTable = request.service.tables.getTable('User'); usersTable.where( { id : request.body.TargetId } ) .read( { success: function(results) { if (results.length > 0) { var user = results[0] console.log('Send to results: ', user.Nickname, user.RegistrationId); request.service.push.gcm.send(user.RegistrationId, { RequesterId: request.body.RequesterId, RequesterNickname: request.body.RequesterName, TargetId: user.id, TargetNickname: user.Nickname }, { success: function(gcm_response) { console.log('Push notification sent: ', gcm_response); response.send(statusCodes.OK, { RequestedNickname : user.Nickname }); }, error: function(gcm_error) { console.log('Error sending push notification: ', gcm_error); response.send(statusCodes.INTERNAL_SERVER_ERROR, { RequestedNickname : user.Nickname }); } }); } else { response.send(statusCodes.NO_CONTENT, { RequestedNickname : "" }); } }, error: function(error) { console.log('Error read table: ', error); response.send(statusCodes.INTERNAL_SERVER_ERROR, { RequestedNickname : "" }); } }); };
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
        Push      
      
        
        
        
      
     // Perform Push operation member this.PushAsync targetId myId myNickname = async { try let (request : PushRequest) = { TargetId = targetId RequesterId = myId RequesterName = myNickname } let! result = this.MobileService.InvokeApiAsync<PushRequest, PushResponce>("pushhim", request) |> Async.AwaitTask return result.RequestedNickname with | e -> return e.ToString() }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
           ,    let-bang
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
       do!
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
       
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
          Google Play Services.     F#   .           .    : Xamarin.Android.Support.v7.AppCompat 
      
        
        
        
      
         , Google Play Services ,   . 
      
        
        
        
      
     
      
        
        
        
      
          push notification   .    GCM,  ID,     ID       Push  (.   pushhim).        BroadcastReciever       developer.android.com .     F#         Xamarin Component Store.     Google Cloud Messaging Client         GCM    .        ID 
      
        
        
        
      
     //Check to see that GCM is supported and that the manifest has the correct information GcmClient.CheckDevice(this) GcmClient.CheckManifest(this) // check google play if CheckPlayServices() then // Try to get registration id let regId = GcmClient.GetRegistrationId this if String.IsNullOrEmpty(regId) then // Call to Register the device for Push Notifications GcmClient.Register(this, WruConstants.GcmSender);
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
            
      
        
        
        
      
     
      
        
        
        
      
        . 
      
        
        
        
      
        , -  
      
        
        
        
      
         bitbucket.org/xakpc/whereareyou 
      
        
        
        
      
         ,     
      
        
        
        
      
              ,           "" . 
      
        
        
        
      
     
      
        
        
        
      
      
      
        
        
        
      
     ,   Android   F#.      . 
      
        
        
        
      
     ,       -  Android  F#.   ,       .listView.Adapter <- new ArrayAdapter(this, Android.Resource.Layout.SimpleListItem1, Android.Resource.Id.Text1, values) 
      
        
        
        
      
      , ,  let values = [|"item1"; "item2"; "item3"|]
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     -   string[],       list (IEnumerable   ) 
      
        
        
        
      
              F#.            www.tryfsharp.org/Learn 
      
        
        
        
      
      
 
      
        
        
        
      
          F# -  ,  
      
        
        
        
      
     
      
        
        
        
      
            F# For Fun And Profit 
      
        
        
        
      
     
      
        
        
        
      
       ,    
      
        
        
        
      
         - . 
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
     
      
        
        
        
      
            hash 
      
        
        
        
      
         MD5  F# 
      
        
        
        
      
      let MD5Hash (input : string) = use md5 = System.Security.Cryptography.MD5.Create() input |> System.Text.Encoding.ASCII.GetBytes |> md5.ComputeHash |> Seq.map (fun c -> c.ToString("X2")) |> Seq.reduce (+)
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
      |>
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      pipeline ,     . 
      
        
        
        
      
         :    GetBytes ->   ->      HEX  ->       (  reduce   +           ) ->    . 
      
        
        
        
      
     
      
        
        
        
      
      ,     C# using System; public string CreateMD5Hash (string input) { MD5 md5 = System.Security.Cryptography.MD5.Create(); byte[] inputBytes = System.Text.Encoding.ASCII.GetBytes (input); byte[] hashBytes = md5.ComputeHash (inputBytes); StringBuilder sb = new StringBuilder(); for (int i = 0; i < hashBytes.Length; i++) { sb.Append (hashBytes[i].ToString ("X2")); } return sb.ToString(); }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
     
      
        
        
        
      
              :        .       AzureServiceWorker (  CLR    ) 
      
        
        
        
      
     
      
        
        
        
      
              -   .   F#    !   Xamarin Studio            . 
      
        
        
        
      
      <ItemGroup> <Compile Include="Resources\Resource.designer.fs" /> <Compile Include="Properties\AssemblyInfo.fs" /> <Compile Include="Helpers\Helpers.fs" /> <Compile Include="Services\User.fs" /> <Compile Include="Services\AzureServiceWorker.fs" /> <Compile Include="IAmHereActivity.fs" /> <Compile Include="WhereAreYouActivity.fs" /> <Compile Include="SignInActivity.fs" /> </ItemGroup>
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
        
      
        
        
        
      
            :    .    Xamarin    Xamarin.Mobile 
      
        
        
        
      
     
      
        
        
        
      
          .  F#         TPL,     Task',      .     F#         Task.  ,     : 
      
        
        
        
      
     module Async = open System.Threading open System.Threading.Tasks let inline AwaitPlainTask (task: Task) = // rethrow exception from preceding task if it fauled let continuation (t : Task) : unit = match t.IsFaulted with | true -> raise t.Exception | arg -> () task.ContinueWith continuation |> Async.AwaitTask
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
             Async.AwaitIAsyncResult >> Async.Ignore
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
           
      
        
        
        
      
     
      
        
        
        
      
                
      
        
        
        
      
     let ExtractUserInfo (x : Contact) = let first = x.Phones |> Seq.tryPick(fun x -> if x.Type = PhoneType.Mobile then Some(x) else None) match first with | Some(first) -> let phone = first.Number |> StripChars [' ';'-';'(';')'] UserInfo.CreateUserInfo((MD5Hash phone), phone, x.DisplayName) | None -> UserInfo.CreateUserInfo("no mobile phone", "no mobile phone", "no mobile phone") // function for async list filling let FillContactsAsync = async { let book = new AddressBook (this) let! result = book.RequestPermission() |> Async.AwaitTask if result then _contacts <- book.ToList() |> Seq.filter (fun (x: Contact) -> not (Seq.isEmpty x.Phones)) |> Seq.map ExtractUserInfo |> Seq.sortBy(fun x -> x.DisplayName) |> Seq.toList let finalContacts = _contacts |> Seq.map (fun x -> x.DisplayName.ToUpperInvariant()) |> Seq.toArray this.ListAdapter <- new ArrayAdapter(this, Resource_Layout.row_contact, finalContacts) else System.Diagnostics.Debug.WriteLine("Permission denied by user or manifest") this.ListAdapter <- new ArrayAdapter(this, Resource_Layout.row_contact, Array.empty) }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
          
      
        
        
        
      
     book.ToList()
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
       List |> Seq.filter (fun (x: Contact) -> not (Seq.isEmpty x.Phones))
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
          |> Seq.map ExtractUserInfo
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
          Contracts  UserInfo,      UserInfo |> Seq.sortBy(fun x -> x.DisplayName)
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      |> Seq.toList
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
       List _contacts <-
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
        mutable  _contacts |> Seq.map (fun x -> x.DisplayName.ToUpperInvariant())<-
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
        UserInfo  string,     - -    |> Seq.toArray<-
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      List  Array    ArrayAdapter 
      
        
        
        
      
        -      List.   . 
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
     
      
        
        
        
      
     Azure Mobile Servcies 
      
        
        
        
      
       -    Azure Mobile Services.       NotificationHub,     Push    .   Azure    , ..      . 
      
        
        
        
      
     
      
        
        
        
      
          ,    
      
        
        
        
      
     module WruConstants = [<Literal>] let TotallyNotAzureServer = "https://YOUR.azure-mobile.net/"; [<Literal>] let TotallyNotAzureKey = "YOUR"
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
       
        
        
        
      
     member this.RegisterMe phone name regId = async { try let table = this.MobileService.GetTable<User>() let usr = { Id = "" PhoneHash = MD5Hash phone Nickname = name RegistrationId = regId } do! table.InsertAsync usr |> Async.AwaitPlainTask return (usr.Id, usr.PhoneHash, usr.Nickname) with | e -> System.Diagnostics.Trace.WriteLine(e.ToString) return (String.Empty,String.Empty,String.Empty) }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     member this.RegisterMe phone name regId = async {
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     -       (     )    .       "computation expression"   workflow.   { }       ! ( bang),  do! (do-bang)  let! (let bang)     User.    ,  F#        ,      
      
        
        
        
      
      let usr = { Id = "" PhoneHash = MD5Hash phone Nickname = name RegistrationId = regId }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     do! table.InsertAsync usr |> Async.AwaitPlainTask
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      do-bang,   await
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      C#. ..             continuation    . return (usr.Id, usr.PhoneHash, usr.Nickname)
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
          Tuple<string,string,string>     .  try ... with | e ->
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      try..catch
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      C# 
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
     
      
        
        
        
      
           .  F#    fst
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      snd
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
          .        2 .     : 
      
        
        
        
      
      let id (c,_,_) = c let phonehash (_,c,_) = c let nickname (_,_,c) = c
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
        : id tuple
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      Id  .. 
      
        
        
        
      
     
      
        
        
        
      
        5  Azure,       Push .       Azure Custom Api  
      
        
        
        
      
     
      
        
        
        
      
          exports.post = function(request, response) { // Use "request.service" to access features of your mobile service, eg: // var tables = request.service.tables; // var push = request.service.push; //response.send(statusCodes.OK, { message : 'Hello World!' }); console.log('Incoming call with requst: ', request.body.RequestId); var usersTable = request.service.tables.getTable('User'); usersTable.where( { id : request.body.TargetId } ) .read( { success: function(results) { if (results.length > 0) { var user = results[0] console.log('Send to results: ', user.Nickname, user.RegistrationId); request.service.push.gcm.send(user.RegistrationId, { RequesterId: request.body.RequesterId, RequesterNickname: request.body.RequesterName, TargetId: user.id, TargetNickname: user.Nickname }, { success: function(gcm_response) { console.log('Push notification sent: ', gcm_response); response.send(statusCodes.OK, { RequestedNickname : user.Nickname }); }, error: function(gcm_error) { console.log('Error sending push notification: ', gcm_error); response.send(statusCodes.INTERNAL_SERVER_ERROR, { RequestedNickname : user.Nickname }); } }); } else { response.send(statusCodes.NO_CONTENT, { RequestedNickname : "" }); } }, error: function(error) { console.log('Error read table: ', error); response.send(statusCodes.INTERNAL_SERVER_ERROR, { RequestedNickname : "" }); } }); };
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
        Push      
      
        
        
        
      
     // Perform Push operation member this.PushAsync targetId myId myNickname = async { try let (request : PushRequest) = { TargetId = targetId RequesterId = myId RequesterName = myNickname } let! result = this.MobileService.InvokeApiAsync<PushRequest, PushResponce>("pushhim", request) |> Async.AwaitTask return result.RequestedNickname with | e -> return e.ToString() }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
           ,    let-bang
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
       do!
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
       
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
          Google Play Services.     F#   .           .    : Xamarin.Android.Support.v7.AppCompat 
      
        
        
        
      
         , Google Play Services ,   . 
      
        
        
        
      
     
      
        
        
        
      
          push notification   .    GCM,  ID,     ID       Push  (.   pushhim).        BroadcastReciever       developer.android.com .     F#         Xamarin Component Store.     Google Cloud Messaging Client         GCM    .        ID 
      
        
        
        
      
     //Check to see that GCM is supported and that the manifest has the correct information GcmClient.CheckDevice(this) GcmClient.CheckManifest(this) // check google play if CheckPlayServices() then // Try to get registration id let regId = GcmClient.GetRegistrationId this if String.IsNullOrEmpty(regId) then // Call to Register the device for Push Notifications GcmClient.Register(this, WruConstants.GcmSender);
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
            
      
        
        
        
      
     
      
        
        
        
      
        . 
      
        
        
        
      
        , -  
      
        
        
        
      
         bitbucket.org/xakpc/whereareyou 
      
        
        
        
      
         ,     
      
        
        
        
      
              ,           "" . 
      
        
        
        
      
     
      
        
        
        
      
      
      
        
        
        
      
     ,   Android   F#.      . 
      
        
        
        
      
     ,       -  Android  F#.   ,       .
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
    listView.Adapter <- new ArrayAdapter(this, Android.Resource.Layout.SimpleListItem1, Android.Resource.Id.Text1, values) 
      
        
        
        
      
      , ,  let values = [|"item1"; "item2"; "item3"|]
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     -   string[],       list (IEnumerable   ) 
      
        
        
        
      
              F#.            www.tryfsharp.org/Learn 
      
        
        
        
      
      
 
      
        
        
        
      
          F# -  ,  
      
        
        
        
      
     
      
        
        
        
      
            F# For Fun And Profit 
      
        
        
        
      
     
      
        
        
        
      
       ,    
      
        
        
        
      
         - . 
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
     
      
        
        
        
      
            hash 
      
        
        
        
      
         MD5  F# 
      
        
        
        
      
      let MD5Hash (input : string) = use md5 = System.Security.Cryptography.MD5.Create() input |> System.Text.Encoding.ASCII.GetBytes |> md5.ComputeHash |> Seq.map (fun c -> c.ToString("X2")) |> Seq.reduce (+)
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
      |>
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      pipeline ,     . 
      
        
        
        
      
         :    GetBytes ->   ->      HEX  ->       (  reduce   +           ) ->    . 
      
        
        
        
      
     
      
        
        
        
      
      ,     C# using System; public string CreateMD5Hash (string input) { MD5 md5 = System.Security.Cryptography.MD5.Create(); byte[] inputBytes = System.Text.Encoding.ASCII.GetBytes (input); byte[] hashBytes = md5.ComputeHash (inputBytes); StringBuilder sb = new StringBuilder(); for (int i = 0; i < hashBytes.Length; i++) { sb.Append (hashBytes[i].ToString ("X2")); } return sb.ToString(); }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
     
      
        
        
        
      
              :        .       AzureServiceWorker (  CLR    ) 
      
        
        
        
      
     
      
        
        
        
      
              -   .   F#    !   Xamarin Studio            . 
      
        
        
        
      
      <ItemGroup> <Compile Include="Resources\Resource.designer.fs" /> <Compile Include="Properties\AssemblyInfo.fs" /> <Compile Include="Helpers\Helpers.fs" /> <Compile Include="Services\User.fs" /> <Compile Include="Services\AzureServiceWorker.fs" /> <Compile Include="IAmHereActivity.fs" /> <Compile Include="WhereAreYouActivity.fs" /> <Compile Include="SignInActivity.fs" /> </ItemGroup>
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
        
      
        
        
        
      
            :    .    Xamarin    Xamarin.Mobile 
      
        
        
        
      
     
      
        
        
        
      
          .  F#         TPL,     Task',      .     F#         Task.  ,     : 
      
        
        
        
      
     module Async = open System.Threading open System.Threading.Tasks let inline AwaitPlainTask (task: Task) = // rethrow exception from preceding task if it fauled let continuation (t : Task) : unit = match t.IsFaulted with | true -> raise t.Exception | arg -> () task.ContinueWith continuation |> Async.AwaitTask
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
             Async.AwaitIAsyncResult >> Async.Ignore
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
           
      
        
        
        
      
     
      
        
        
        
      
                
      
        
        
        
      
     let ExtractUserInfo (x : Contact) = let first = x.Phones |> Seq.tryPick(fun x -> if x.Type = PhoneType.Mobile then Some(x) else None) match first with | Some(first) -> let phone = first.Number |> StripChars [' ';'-';'(';')'] UserInfo.CreateUserInfo((MD5Hash phone), phone, x.DisplayName) | None -> UserInfo.CreateUserInfo("no mobile phone", "no mobile phone", "no mobile phone") // function for async list filling let FillContactsAsync = async { let book = new AddressBook (this) let! result = book.RequestPermission() |> Async.AwaitTask if result then _contacts <- book.ToList() |> Seq.filter (fun (x: Contact) -> not (Seq.isEmpty x.Phones)) |> Seq.map ExtractUserInfo |> Seq.sortBy(fun x -> x.DisplayName) |> Seq.toList let finalContacts = _contacts |> Seq.map (fun x -> x.DisplayName.ToUpperInvariant()) |> Seq.toArray this.ListAdapter <- new ArrayAdapter(this, Resource_Layout.row_contact, finalContacts) else System.Diagnostics.Debug.WriteLine("Permission denied by user or manifest") this.ListAdapter <- new ArrayAdapter(this, Resource_Layout.row_contact, Array.empty) }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
          
      
        
        
        
      
     book.ToList()
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
       List |> Seq.filter (fun (x: Contact) -> not (Seq.isEmpty x.Phones))
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
          |> Seq.map ExtractUserInfo
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
          Contracts  UserInfo,      UserInfo |> Seq.sortBy(fun x -> x.DisplayName)
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      |> Seq.toList
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
       List _contacts <-
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
        mutable  _contacts |> Seq.map (fun x -> x.DisplayName.ToUpperInvariant())<-
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
        UserInfo  string,     - -    |> Seq.toArray<-
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      List  Array    ArrayAdapter 
      
        
        
        
      
        -      List.   . 
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
     
      
        
        
        
      
     Azure Mobile Servcies 
      
        
        
        
      
       -    Azure Mobile Services.       NotificationHub,     Push    .   Azure    , ..      . 
      
        
        
        
      
     
      
        
        
        
      
          ,    
      
        
        
        
      
     module WruConstants = [<Literal>] let TotallyNotAzureServer = "https://YOUR.azure-mobile.net/"; [<Literal>] let TotallyNotAzureKey = "YOUR"
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
       
        
        
        
      
     member this.RegisterMe phone name regId = async { try let table = this.MobileService.GetTable<User>() let usr = { Id = "" PhoneHash = MD5Hash phone Nickname = name RegistrationId = regId } do! table.InsertAsync usr |> Async.AwaitPlainTask return (usr.Id, usr.PhoneHash, usr.Nickname) with | e -> System.Diagnostics.Trace.WriteLine(e.ToString) return (String.Empty,String.Empty,String.Empty) }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     member this.RegisterMe phone name regId = async {
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     -       (     )    .       "computation expression"   workflow.   { }       ! ( bang),  do! (do-bang)  let! (let bang)     User.    ,  F#        ,      
      
        
        
        
      
      let usr = { Id = "" PhoneHash = MD5Hash phone Nickname = name RegistrationId = regId }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     do! table.InsertAsync usr |> Async.AwaitPlainTask
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      do-bang,   await
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      C#. ..             continuation    . return (usr.Id, usr.PhoneHash, usr.Nickname)
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
          Tuple<string,string,string>     .  try ... with | e ->
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      try..catch
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      C# 
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
     
      
        
        
        
      
           .  F#    fst
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      snd
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
          .        2 .     : 
      
        
        
        
      
      let id (c,_,_) = c let phonehash (_,c,_) = c let nickname (_,_,c) = c
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
        : id tuple
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      Id  .. 
      
        
        
        
      
     
      
        
        
        
      
        5  Azure,       Push .       Azure Custom Api  
      
        
        
        
      
     
      
        
        
        
      
          exports.post = function(request, response) { // Use "request.service" to access features of your mobile service, eg: // var tables = request.service.tables; // var push = request.service.push; //response.send(statusCodes.OK, { message : 'Hello World!' }); console.log('Incoming call with requst: ', request.body.RequestId); var usersTable = request.service.tables.getTable('User'); usersTable.where( { id : request.body.TargetId } ) .read( { success: function(results) { if (results.length > 0) { var user = results[0] console.log('Send to results: ', user.Nickname, user.RegistrationId); request.service.push.gcm.send(user.RegistrationId, { RequesterId: request.body.RequesterId, RequesterNickname: request.body.RequesterName, TargetId: user.id, TargetNickname: user.Nickname }, { success: function(gcm_response) { console.log('Push notification sent: ', gcm_response); response.send(statusCodes.OK, { RequestedNickname : user.Nickname }); }, error: function(gcm_error) { console.log('Error sending push notification: ', gcm_error); response.send(statusCodes.INTERNAL_SERVER_ERROR, { RequestedNickname : user.Nickname }); } }); } else { response.send(statusCodes.NO_CONTENT, { RequestedNickname : "" }); } }, error: function(error) { console.log('Error read table: ', error); response.send(statusCodes.INTERNAL_SERVER_ERROR, { RequestedNickname : "" }); } }); };
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
        Push      
      
        
        
        
      
     // Perform Push operation member this.PushAsync targetId myId myNickname = async { try let (request : PushRequest) = { TargetId = targetId RequesterId = myId RequesterName = myNickname } let! result = this.MobileService.InvokeApiAsync<PushRequest, PushResponce>("pushhim", request) |> Async.AwaitTask return result.RequestedNickname with | e -> return e.ToString() }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
           ,    let-bang
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
       do!
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
       
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
          Google Play Services.     F#   .           .    : Xamarin.Android.Support.v7.AppCompat 
      
        
        
        
      
         , Google Play Services ,   . 
      
        
        
        
      
     
      
        
        
        
      
          push notification   .    GCM,  ID,     ID       Push  (.   pushhim).        BroadcastReciever       developer.android.com .     F#         Xamarin Component Store.     Google Cloud Messaging Client         GCM    .        ID 
      
        
        
        
      
     //Check to see that GCM is supported and that the manifest has the correct information GcmClient.CheckDevice(this) GcmClient.CheckManifest(this) // check google play if CheckPlayServices() then // Try to get registration id let regId = GcmClient.GetRegistrationId this if String.IsNullOrEmpty(regId) then // Call to Register the device for Push Notifications GcmClient.Register(this, WruConstants.GcmSender);
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
            
      
        
        
        
      
     
      
        
        
        
      
        . 
      
        
        
        
      
        , -  
      
        
        
        
      
         bitbucket.org/xakpc/whereareyou 
      
        
        
        
      
         ,     
      
        
        
        
      
              ,           "" . 
      
        
        
        
      
     
      
        
        
        
      
      
      
        
        
        
      
     ,   Android   F#.      . 
      
        
        
        
      
     ,       -  Android  F#.   ,       .
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
    listView.Adapter <- new ArrayAdapter(this, Android.Resource.Layout.SimpleListItem1, Android.Resource.Id.Text1, values) 
      
        
        
        
      
      , ,  let values = [|"item1"; "item2"; "item3"|]
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     -   string[],       list (IEnumerable   ) 
      
        
        
        
      
              F#.            www.tryfsharp.org/Learn 
      
        
        
        
      
      
 
      
        
        
        
      
          F# -  ,  
      
        
        
        
      
     
      
        
        
        
      
            F# For Fun And Profit 
      
        
        
        
      
     
      
        
        
        
      
       ,    
      
        
        
        
      
         - . 
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
     
      
        
        
        
      
            hash 
      
        
        
        
      
         MD5  F# 
      
        
        
        
      
      let MD5Hash (input : string) = use md5 = System.Security.Cryptography.MD5.Create() input |> System.Text.Encoding.ASCII.GetBytes |> md5.ComputeHash |> Seq.map (fun c -> c.ToString("X2")) |> Seq.reduce (+)
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
      |>
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      pipeline ,     . 
      
        
        
        
      
         :    GetBytes ->   ->      HEX  ->       (  reduce   +           ) ->    . 
      
        
        
        
      
     
      
        
        
        
      
      ,     C# using System; public string CreateMD5Hash (string input) { MD5 md5 = System.Security.Cryptography.MD5.Create(); byte[] inputBytes = System.Text.Encoding.ASCII.GetBytes (input); byte[] hashBytes = md5.ComputeHash (inputBytes); StringBuilder sb = new StringBuilder(); for (int i = 0; i < hashBytes.Length; i++) { sb.Append (hashBytes[i].ToString ("X2")); } return sb.ToString(); }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
     
      
        
        
        
      
              :        .       AzureServiceWorker (  CLR    ) 
      
        
        
        
      
     
      
        
        
        
      
              -   .   F#    !   Xamarin Studio            . 
      
        
        
        
      
      <ItemGroup> <Compile Include="Resources\Resource.designer.fs" /> <Compile Include="Properties\AssemblyInfo.fs" /> <Compile Include="Helpers\Helpers.fs" /> <Compile Include="Services\User.fs" /> <Compile Include="Services\AzureServiceWorker.fs" /> <Compile Include="IAmHereActivity.fs" /> <Compile Include="WhereAreYouActivity.fs" /> <Compile Include="SignInActivity.fs" /> </ItemGroup>
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
        
      
        
        
        
      
            :    .    Xamarin    Xamarin.Mobile 
      
        
        
        
      
     
      
        
        
        
      
          .  F#         TPL,     Task',      .     F#         Task.  ,     : 
      
        
        
        
      
     module Async = open System.Threading open System.Threading.Tasks let inline AwaitPlainTask (task: Task) = // rethrow exception from preceding task if it fauled let continuation (t : Task) : unit = match t.IsFaulted with | true -> raise t.Exception | arg -> () task.ContinueWith continuation |> Async.AwaitTask
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
             Async.AwaitIAsyncResult >> Async.Ignore
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
           
      
        
        
        
      
     
      
        
        
        
      
                
      
        
        
        
      
     let ExtractUserInfo (x : Contact) = let first = x.Phones |> Seq.tryPick(fun x -> if x.Type = PhoneType.Mobile then Some(x) else None) match first with | Some(first) -> let phone = first.Number |> StripChars [' ';'-';'(';')'] UserInfo.CreateUserInfo((MD5Hash phone), phone, x.DisplayName) | None -> UserInfo.CreateUserInfo("no mobile phone", "no mobile phone", "no mobile phone") // function for async list filling let FillContactsAsync = async { let book = new AddressBook (this) let! result = book.RequestPermission() |> Async.AwaitTask if result then _contacts <- book.ToList() |> Seq.filter (fun (x: Contact) -> not (Seq.isEmpty x.Phones)) |> Seq.map ExtractUserInfo |> Seq.sortBy(fun x -> x.DisplayName) |> Seq.toList let finalContacts = _contacts |> Seq.map (fun x -> x.DisplayName.ToUpperInvariant()) |> Seq.toArray this.ListAdapter <- new ArrayAdapter(this, Resource_Layout.row_contact, finalContacts) else System.Diagnostics.Debug.WriteLine("Permission denied by user or manifest") this.ListAdapter <- new ArrayAdapter(this, Resource_Layout.row_contact, Array.empty) }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
          
      
        
        
        
      
     book.ToList()
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
       List |> Seq.filter (fun (x: Contact) -> not (Seq.isEmpty x.Phones))
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
          |> Seq.map ExtractUserInfo
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
          Contracts  UserInfo,      UserInfo |> Seq.sortBy(fun x -> x.DisplayName)
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      |> Seq.toList
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
       List _contacts <-
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
        mutable  _contacts |> Seq.map (fun x -> x.DisplayName.ToUpperInvariant())<-
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
        UserInfo  string,     - -    |> Seq.toArray<-
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      List  Array    ArrayAdapter 
      
        
        
        
      
        -      List.   . 
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
     
      
        
        
        
      
     Azure Mobile Servcies 
      
        
        
        
      
       -    Azure Mobile Services.       NotificationHub,     Push    .   Azure    , ..      . 
      
        
        
        
      
     
      
        
        
        
      
          ,    
      
        
        
        
      
     module WruConstants = [<Literal>] let TotallyNotAzureServer = "https://YOUR.azure-mobile.net/"; [<Literal>] let TotallyNotAzureKey = "YOUR"
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
       
        
        
        
      
     member this.RegisterMe phone name regId = async { try let table = this.MobileService.GetTable<User>() let usr = { Id = "" PhoneHash = MD5Hash phone Nickname = name RegistrationId = regId } do! table.InsertAsync usr |> Async.AwaitPlainTask return (usr.Id, usr.PhoneHash, usr.Nickname) with | e -> System.Diagnostics.Trace.WriteLine(e.ToString) return (String.Empty,String.Empty,String.Empty) }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     member this.RegisterMe phone name regId = async {
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     -       (     )    .       "computation expression"   workflow.   { }       ! ( bang),  do! (do-bang)  let! (let bang)     User.    ,  F#        ,      
      
        
        
        
      
      let usr = { Id = "" PhoneHash = MD5Hash phone Nickname = name RegistrationId = regId }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     do! table.InsertAsync usr |> Async.AwaitPlainTask
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      do-bang,   await
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      C#. ..             continuation    . return (usr.Id, usr.PhoneHash, usr.Nickname)
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
          Tuple<string,string,string>     .  try ... with | e ->
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      try..catch
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      C# 
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
     
      
        
        
        
      
           .  F#    fst
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      snd
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
          .        2 .     : 
      
        
        
        
      
      let id (c,_,_) = c let phonehash (_,c,_) = c let nickname (_,_,c) = c
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
        : id tuple
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      Id  .. 
      
        
        
        
      
     
      
        
        
        
      
        5  Azure,       Push .       Azure Custom Api  
      
        
        
        
      
     
      
        
        
        
      
          exports.post = function(request, response) { // Use "request.service" to access features of your mobile service, eg: // var tables = request.service.tables; // var push = request.service.push; //response.send(statusCodes.OK, { message : 'Hello World!' }); console.log('Incoming call with requst: ', request.body.RequestId); var usersTable = request.service.tables.getTable('User'); usersTable.where( { id : request.body.TargetId } ) .read( { success: function(results) { if (results.length > 0) { var user = results[0] console.log('Send to results: ', user.Nickname, user.RegistrationId); request.service.push.gcm.send(user.RegistrationId, { RequesterId: request.body.RequesterId, RequesterNickname: request.body.RequesterName, TargetId: user.id, TargetNickname: user.Nickname }, { success: function(gcm_response) { console.log('Push notification sent: ', gcm_response); response.send(statusCodes.OK, { RequestedNickname : user.Nickname }); }, error: function(gcm_error) { console.log('Error sending push notification: ', gcm_error); response.send(statusCodes.INTERNAL_SERVER_ERROR, { RequestedNickname : user.Nickname }); } }); } else { response.send(statusCodes.NO_CONTENT, { RequestedNickname : "" }); } }, error: function(error) { console.log('Error read table: ', error); response.send(statusCodes.INTERNAL_SERVER_ERROR, { RequestedNickname : "" }); } }); };
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
        Push      
      
        
        
        
      
     // Perform Push operation member this.PushAsync targetId myId myNickname = async { try let (request : PushRequest) = { TargetId = targetId RequesterId = myId RequesterName = myNickname } let! result = this.MobileService.InvokeApiAsync<PushRequest, PushResponce>("pushhim", request) |> Async.AwaitTask return result.RequestedNickname with | e -> return e.ToString() }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
           ,    let-bang
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
       do!
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
       
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
          Google Play Services.     F#   .           .    : Xamarin.Android.Support.v7.AppCompat 
      
        
        
        
      
         , Google Play Services ,   . 
      
        
        
        
      
     
      
        
        
        
      
          push notification   .    GCM,  ID,     ID       Push  (.   pushhim).        BroadcastReciever       developer.android.com .     F#         Xamarin Component Store.     Google Cloud Messaging Client         GCM    .        ID 
      
        
        
        
      
     //Check to see that GCM is supported and that the manifest has the correct information GcmClient.CheckDevice(this) GcmClient.CheckManifest(this) // check google play if CheckPlayServices() then // Try to get registration id let regId = GcmClient.GetRegistrationId this if String.IsNullOrEmpty(regId) then // Call to Register the device for Push Notifications GcmClient.Register(this, WruConstants.GcmSender);
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
            
      
        
        
        
      
     
      
        
        
        
      
        . 
      
        
        
        
      
        , -  
      
        
        
        
      
         bitbucket.org/xakpc/whereareyou 
      
        
        
        
      
         ,     
      
        
        
        
      
              ,           "" . 
      
        
        
        
      
     
      
        
        
        
      
      
      
        
        
        
      
     ,   Android   F#.      . 
      
        
        
        
      
     ,       -  Android  F#.   ,       .
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     listView.Adapter <- new ArrayAdapter(this, Android.Resource.Layout.SimpleListItem1, Android.Resource.Id.Text1, values) 
      
        
        
        
      
      , ,  let values = [|"item1"; "item2"; "item3"|]
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     -   string[],       list (IEnumerable   ) 
      
        
        
        
      
              F#.            www.tryfsharp.org/Learn 
      
        
        
        
      
      
 
      
        
        
        
      
          F# -  ,  
      
        
        
        
      
     
      
        
        
        
      
            F# For Fun And Profit 
      
        
        
        
      
     
      
        
        
        
      
       ,    
      
        
        
        
      
         - . 
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
     
      
        
        
        
      
            hash 
      
        
        
        
      
         MD5  F# 
      
        
        
        
      
      let MD5Hash (input : string) = use md5 = System.Security.Cryptography.MD5.Create() input |> System.Text.Encoding.ASCII.GetBytes |> md5.ComputeHash |> Seq.map (fun c -> c.ToString("X2")) |> Seq.reduce (+)
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
      |>
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      pipeline ,     . 
      
        
        
        
      
         :    GetBytes ->   ->      HEX  ->       (  reduce   +           ) ->    . 
      
        
        
        
      
     
      
        
        
        
      
      ,     C# using System; public string CreateMD5Hash (string input) { MD5 md5 = System.Security.Cryptography.MD5.Create(); byte[] inputBytes = System.Text.Encoding.ASCII.GetBytes (input); byte[] hashBytes = md5.ComputeHash (inputBytes); StringBuilder sb = new StringBuilder(); for (int i = 0; i < hashBytes.Length; i++) { sb.Append (hashBytes[i].ToString ("X2")); } return sb.ToString(); }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
     
      
        
        
        
      
              :        .       AzureServiceWorker (  CLR    ) 
      
        
        
        
      
     
      
        
        
        
      
              -   .   F#    !   Xamarin Studio            . 
      
        
        
        
      
      <ItemGroup> <Compile Include="Resources\Resource.designer.fs" /> <Compile Include="Properties\AssemblyInfo.fs" /> <Compile Include="Helpers\Helpers.fs" /> <Compile Include="Services\User.fs" /> <Compile Include="Services\AzureServiceWorker.fs" /> <Compile Include="IAmHereActivity.fs" /> <Compile Include="WhereAreYouActivity.fs" /> <Compile Include="SignInActivity.fs" /> </ItemGroup>
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
        
      
        
        
        
      
            :    .    Xamarin    Xamarin.Mobile 
      
        
        
        
      
     
      
        
        
        
      
          .  F#         TPL,     Task',      .     F#         Task.  ,     : 
      
        
        
        
      
     module Async = open System.Threading open System.Threading.Tasks let inline AwaitPlainTask (task: Task) = // rethrow exception from preceding task if it fauled let continuation (t : Task) : unit = match t.IsFaulted with | true -> raise t.Exception | arg -> () task.ContinueWith continuation |> Async.AwaitTask
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
             Async.AwaitIAsyncResult >> Async.Ignore
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
           
      
        
        
        
      
     
      
        
        
        
      
                
      
        
        
        
      
     let ExtractUserInfo (x : Contact) = let first = x.Phones |> Seq.tryPick(fun x -> if x.Type = PhoneType.Mobile then Some(x) else None) match first with | Some(first) -> let phone = first.Number |> StripChars [' ';'-';'(';')'] UserInfo.CreateUserInfo((MD5Hash phone), phone, x.DisplayName) | None -> UserInfo.CreateUserInfo("no mobile phone", "no mobile phone", "no mobile phone") // function for async list filling let FillContactsAsync = async { let book = new AddressBook (this) let! result = book.RequestPermission() |> Async.AwaitTask if result then _contacts <- book.ToList() |> Seq.filter (fun (x: Contact) -> not (Seq.isEmpty x.Phones)) |> Seq.map ExtractUserInfo |> Seq.sortBy(fun x -> x.DisplayName) |> Seq.toList let finalContacts = _contacts |> Seq.map (fun x -> x.DisplayName.ToUpperInvariant()) |> Seq.toArray this.ListAdapter <- new ArrayAdapter(this, Resource_Layout.row_contact, finalContacts) else System.Diagnostics.Debug.WriteLine("Permission denied by user or manifest") this.ListAdapter <- new ArrayAdapter(this, Resource_Layout.row_contact, Array.empty) }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
          
      
        
        
        
      
     book.ToList()
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
       List |> Seq.filter (fun (x: Contact) -> not (Seq.isEmpty x.Phones))
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
          |> Seq.map ExtractUserInfo
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
          Contracts  UserInfo,      UserInfo |> Seq.sortBy(fun x -> x.DisplayName)
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      |> Seq.toList
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
       List _contacts <-
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
        mutable  _contacts |> Seq.map (fun x -> x.DisplayName.ToUpperInvariant())<-
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
        UserInfo  string,     - -    |> Seq.toArray<-
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      List  Array    ArrayAdapter 
      
        
        
        
      
        -      List.   . 
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
     
      
        
        
        
      
     Azure Mobile Servcies 
      
        
        
        
      
       -    Azure Mobile Services.       NotificationHub,     Push    .   Azure    , ..      . 
      
        
        
        
      
     
      
        
        
        
      
          ,    
      
        
        
        
      
     module WruConstants = [<Literal>] let TotallyNotAzureServer = "https://YOUR.azure-mobile.net/"; [<Literal>] let TotallyNotAzureKey = "YOUR"
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
       
        
        
        
      
     member this.RegisterMe phone name regId = async { try let table = this.MobileService.GetTable<User>() let usr = { Id = "" PhoneHash = MD5Hash phone Nickname = name RegistrationId = regId } do! table.InsertAsync usr |> Async.AwaitPlainTask return (usr.Id, usr.PhoneHash, usr.Nickname) with | e -> System.Diagnostics.Trace.WriteLine(e.ToString) return (String.Empty,String.Empty,String.Empty) }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     member this.RegisterMe phone name regId = async {
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     -       (     )    .       "computation expression"   workflow.   { }       ! ( bang),  do! (do-bang)  let! (let bang)     User.    ,  F#        ,      
      
        
        
        
      
      let usr = { Id = "" PhoneHash = MD5Hash phone Nickname = name RegistrationId = regId }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     do! table.InsertAsync usr |> Async.AwaitPlainTask
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      do-bang,   await
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      C#. ..             continuation    . return (usr.Id, usr.PhoneHash, usr.Nickname)
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
          Tuple<string,string,string>     .  try ... with | e ->
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      try..catch
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      C# 
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
     
      
        
        
        
      
           .  F#    fst
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      snd
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
          .        2 .     : 
      
        
        
        
      
      let id (c,_,_) = c let phonehash (_,c,_) = c let nickname (_,_,c) = c
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
        : id tuple
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      Id  .. 
      
        
        
        
      
     
      
        
        
        
      
        5  Azure,       Push .       Azure Custom Api  
      
        
        
        
      
     
      
        
        
        
      
          exports.post = function(request, response) { // Use "request.service" to access features of your mobile service, eg: // var tables = request.service.tables; // var push = request.service.push; //response.send(statusCodes.OK, { message : 'Hello World!' }); console.log('Incoming call with requst: ', request.body.RequestId); var usersTable = request.service.tables.getTable('User'); usersTable.where( { id : request.body.TargetId } ) .read( { success: function(results) { if (results.length > 0) { var user = results[0] console.log('Send to results: ', user.Nickname, user.RegistrationId); request.service.push.gcm.send(user.RegistrationId, { RequesterId: request.body.RequesterId, RequesterNickname: request.body.RequesterName, TargetId: user.id, TargetNickname: user.Nickname }, { success: function(gcm_response) { console.log('Push notification sent: ', gcm_response); response.send(statusCodes.OK, { RequestedNickname : user.Nickname }); }, error: function(gcm_error) { console.log('Error sending push notification: ', gcm_error); response.send(statusCodes.INTERNAL_SERVER_ERROR, { RequestedNickname : user.Nickname }); } }); } else { response.send(statusCodes.NO_CONTENT, { RequestedNickname : "" }); } }, error: function(error) { console.log('Error read table: ', error); response.send(statusCodes.INTERNAL_SERVER_ERROR, { RequestedNickname : "" }); } }); };
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
        Push      
      
        
        
        
      
     // Perform Push operation member this.PushAsync targetId myId myNickname = async { try let (request : PushRequest) = { TargetId = targetId RequesterId = myId RequesterName = myNickname } let! result = this.MobileService.InvokeApiAsync<PushRequest, PushResponce>("pushhim", request) |> Async.AwaitTask return result.RequestedNickname with | e -> return e.ToString() }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
           ,    let-bang
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
       do!
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
       
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
          Google Play Services.     F#   .           .    : Xamarin.Android.Support.v7.AppCompat 
      
        
        
        
      
         , Google Play Services ,   . 
      
        
        
        
      
     
      
        
        
        
      
          push notification   .    GCM,  ID,     ID       Push  (.   pushhim).        BroadcastReciever       developer.android.com .     F#         Xamarin Component Store.     Google Cloud Messaging Client         GCM    .        ID 
      
        
        
        
      
     //Check to see that GCM is supported and that the manifest has the correct information GcmClient.CheckDevice(this) GcmClient.CheckManifest(this) // check google play if CheckPlayServices() then // Try to get registration id let regId = GcmClient.GetRegistrationId this if String.IsNullOrEmpty(regId) then // Call to Register the device for Push Notifications GcmClient.Register(this, WruConstants.GcmSender);
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
            
      
        
        
        
      
     
      
        
        
        
      
        . 
      
        
        
        
      
        , -  
      
        
        
        
      
         bitbucket.org/xakpc/whereareyou 
      
        
        
        
      
         ,     
      
        
        
        
      
              ,           "" . 
      
        
        
        
      
     
      
        
        
        
      
      
      
        
        
        
      
     ,   Android   F#.      . 
      
        
        
        
      
     ,       -  Android  F#.   ,       .
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
    
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      listView.Adapter <- new ArrayAdapter(this, Android.Resource.Layout.SimpleListItem1, Android.Resource.Id.Text1, values) 
      
        
        
        
      
      , ,  let values = [|"item1"; "item2"; "item3"|]
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     -   string[],       list (IEnumerable   ) 
      
        
        
        
      
              F#.            www.tryfsharp.org/Learn 
      
        
        
        
      
      
 
      
        
        
        
      
          F# -  ,  
      
        
        
        
      
     
      
        
        
        
      
            F# For Fun And Profit 
      
        
        
        
      
     
      
        
        
        
      
       ,    
      
        
        
        
      
         - . 
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
     
      
        
        
        
      
            hash 
      
        
        
        
      
         MD5  F# 
      
        
        
        
      
      let MD5Hash (input : string) = use md5 = System.Security.Cryptography.MD5.Create() input |> System.Text.Encoding.ASCII.GetBytes |> md5.ComputeHash |> Seq.map (fun c -> c.ToString("X2")) |> Seq.reduce (+)
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
      |>
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      pipeline ,     . 
      
        
        
        
      
         :    GetBytes ->   ->      HEX  ->       (  reduce   +           ) ->    . 
      
        
        
        
      
     
      
        
        
        
      
      ,     C# using System; public string CreateMD5Hash (string input) { MD5 md5 = System.Security.Cryptography.MD5.Create(); byte[] inputBytes = System.Text.Encoding.ASCII.GetBytes (input); byte[] hashBytes = md5.ComputeHash (inputBytes); StringBuilder sb = new StringBuilder(); for (int i = 0; i < hashBytes.Length; i++) { sb.Append (hashBytes[i].ToString ("X2")); } return sb.ToString(); }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
     
      
        
        
        
      
              :        .       AzureServiceWorker (  CLR    ) 
      
        
        
        
      
     
      
        
        
        
      
              -   .   F#    !   Xamarin Studio            . 
      
        
        
        
      
      <ItemGroup> <Compile Include="Resources\Resource.designer.fs" /> <Compile Include="Properties\AssemblyInfo.fs" /> <Compile Include="Helpers\Helpers.fs" /> <Compile Include="Services\User.fs" /> <Compile Include="Services\AzureServiceWorker.fs" /> <Compile Include="IAmHereActivity.fs" /> <Compile Include="WhereAreYouActivity.fs" /> <Compile Include="SignInActivity.fs" /> </ItemGroup>
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
        
      
        
        
        
      
            :    .    Xamarin    Xamarin.Mobile 
      
        
        
        
      
     
      
        
        
        
      
          .  F#         TPL,     Task',      .     F#         Task.  ,     : 
      
        
        
        
      
     module Async = open System.Threading open System.Threading.Tasks let inline AwaitPlainTask (task: Task) = // rethrow exception from preceding task if it fauled let continuation (t : Task) : unit = match t.IsFaulted with | true -> raise t.Exception | arg -> () task.ContinueWith continuation |> Async.AwaitTask
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
             Async.AwaitIAsyncResult >> Async.Ignore
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
           
      
        
        
        
      
     
      
        
        
        
      
                
      
        
        
        
      
     let ExtractUserInfo (x : Contact) = let first = x.Phones |> Seq.tryPick(fun x -> if x.Type = PhoneType.Mobile then Some(x) else None) match first with | Some(first) -> let phone = first.Number |> StripChars [' ';'-';'(';')'] UserInfo.CreateUserInfo((MD5Hash phone), phone, x.DisplayName) | None -> UserInfo.CreateUserInfo("no mobile phone", "no mobile phone", "no mobile phone") // function for async list filling let FillContactsAsync = async { let book = new AddressBook (this) let! result = book.RequestPermission() |> Async.AwaitTask if result then _contacts <- book.ToList() |> Seq.filter (fun (x: Contact) -> not (Seq.isEmpty x.Phones)) |> Seq.map ExtractUserInfo |> Seq.sortBy(fun x -> x.DisplayName) |> Seq.toList let finalContacts = _contacts |> Seq.map (fun x -> x.DisplayName.ToUpperInvariant()) |> Seq.toArray this.ListAdapter <- new ArrayAdapter(this, Resource_Layout.row_contact, finalContacts) else System.Diagnostics.Debug.WriteLine("Permission denied by user or manifest") this.ListAdapter <- new ArrayAdapter(this, Resource_Layout.row_contact, Array.empty) }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
          
      
        
        
        
      
     book.ToList()
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
       List |> Seq.filter (fun (x: Contact) -> not (Seq.isEmpty x.Phones))
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
          |> Seq.map ExtractUserInfo
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
          Contracts  UserInfo,      UserInfo |> Seq.sortBy(fun x -> x.DisplayName)
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      |> Seq.toList
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
       List _contacts <-
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
        mutable  _contacts |> Seq.map (fun x -> x.DisplayName.ToUpperInvariant())<-
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
        UserInfo  string,     - -    |> Seq.toArray<-
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      List  Array    ArrayAdapter 
      
        
        
        
      
        -      List.   . 
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
     
      
        
        
        
      
     Azure Mobile Servcies 
      
        
        
        
      
       -    Azure Mobile Services.       NotificationHub,     Push    .   Azure    , ..      . 
      
        
        
        
      
     
      
        
        
        
      
          ,    
      
        
        
        
      
     module WruConstants = [<Literal>] let TotallyNotAzureServer = "https://YOUR.azure-mobile.net/"; [<Literal>] let TotallyNotAzureKey = "YOUR"
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
       
        
        
        
      
     member this.RegisterMe phone name regId = async { try let table = this.MobileService.GetTable<User>() let usr = { Id = "" PhoneHash = MD5Hash phone Nickname = name RegistrationId = regId } do! table.InsertAsync usr |> Async.AwaitPlainTask return (usr.Id, usr.PhoneHash, usr.Nickname) with | e -> System.Diagnostics.Trace.WriteLine(e.ToString) return (String.Empty,String.Empty,String.Empty) }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     member this.RegisterMe phone name regId = async {
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     -       (     )    .       "computation expression"   workflow.   { }       ! ( bang),  do! (do-bang)  let! (let bang)     User.    ,  F#        ,      
      
        
        
        
      
      let usr = { Id = "" PhoneHash = MD5Hash phone Nickname = name RegistrationId = regId }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     do! table.InsertAsync usr |> Async.AwaitPlainTask
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      do-bang,   await
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      C#. ..             continuation    . return (usr.Id, usr.PhoneHash, usr.Nickname)
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
          Tuple<string,string,string>     .  try ... with | e ->
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      try..catch
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      C# 
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
     
      
        
        
        
      
           .  F#    fst
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      snd
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
          .        2 .     : 
      
        
        
        
      
      let id (c,_,_) = c let phonehash (_,c,_) = c let nickname (_,_,c) = c
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
        : id tuple
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      Id  .. 
      
        
        
        
      
     
      
        
        
        
      
        5  Azure,       Push .       Azure Custom Api  
      
        
        
        
      
     
      
        
        
        
      
          exports.post = function(request, response) { // Use "request.service" to access features of your mobile service, eg: // var tables = request.service.tables; // var push = request.service.push; //response.send(statusCodes.OK, { message : 'Hello World!' }); console.log('Incoming call with requst: ', request.body.RequestId); var usersTable = request.service.tables.getTable('User'); usersTable.where( { id : request.body.TargetId } ) .read( { success: function(results) { if (results.length > 0) { var user = results[0] console.log('Send to results: ', user.Nickname, user.RegistrationId); request.service.push.gcm.send(user.RegistrationId, { RequesterId: request.body.RequesterId, RequesterNickname: request.body.RequesterName, TargetId: user.id, TargetNickname: user.Nickname }, { success: function(gcm_response) { console.log('Push notification sent: ', gcm_response); response.send(statusCodes.OK, { RequestedNickname : user.Nickname }); }, error: function(gcm_error) { console.log('Error sending push notification: ', gcm_error); response.send(statusCodes.INTERNAL_SERVER_ERROR, { RequestedNickname : user.Nickname }); } }); } else { response.send(statusCodes.NO_CONTENT, { RequestedNickname : "" }); } }, error: function(error) { console.log('Error read table: ', error); response.send(statusCodes.INTERNAL_SERVER_ERROR, { RequestedNickname : "" }); } }); };
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
        Push      
      
        
        
        
      
     // Perform Push operation member this.PushAsync targetId myId myNickname = async { try let (request : PushRequest) = { TargetId = targetId RequesterId = myId RequesterName = myNickname } let! result = this.MobileService.InvokeApiAsync<PushRequest, PushResponce>("pushhim", request) |> Async.AwaitTask return result.RequestedNickname with | e -> return e.ToString() }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
           ,    let-bang
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
       do!
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
       
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
          Google Play Services.     F#   .           .    : Xamarin.Android.Support.v7.AppCompat 
      
        
        
        
      
         , Google Play Services ,   . 
      
        
        
        
      
     
      
        
        
        
      
          push notification   .    GCM,  ID,     ID       Push  (.   pushhim).        BroadcastReciever       developer.android.com .     F#         Xamarin Component Store.     Google Cloud Messaging Client         GCM    .        ID 
      
        
        
        
      
     //Check to see that GCM is supported and that the manifest has the correct information GcmClient.CheckDevice(this) GcmClient.CheckManifest(this) // check google play if CheckPlayServices() then // Try to get registration id let regId = GcmClient.GetRegistrationId this if String.IsNullOrEmpty(regId) then // Call to Register the device for Push Notifications GcmClient.Register(this, WruConstants.GcmSender);
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
            
      
        
        
        
      
     
      
        
        
        
      
        . 
      
        
        
        
      
        , -  
      
        
        
        
      
         bitbucket.org/xakpc/whereareyou 
      
        
        
        
      
         ,     
      
        
        
        
      
              ,           "" . 
      
        
        
        
      
     
      
        
        
        
      
      
      
        
        
        
      
     ,   Android   F#.      . 
      
        
        
        
      
     ,       -  Android  F#.   ,       .
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
    listView.Adapter <- new ArrayAdapter(this, Android.Resource.Layout.SimpleListItem1, Android.Resource.Id.Text1, values) 
      
        
        
        
      
      , ,  let values = [|"item1"; "item2"; "item3"|]
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     -   string[],       list (IEnumerable   ) 
      
        
        
        
      
              F#.            www.tryfsharp.org/Learn 
      
        
        
        
      
      
 
      
        
        
        
      
          F# -  ,  
      
        
        
        
      
     
      
        
        
        
      
            F# For Fun And Profit 
      
        
        
        
      
     
      
        
        
        
      
       ,    
      
        
        
        
      
         - . 
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
     
      
        
        
        
      
            hash 
      
        
        
        
      
         MD5  F# 
      
        
        
        
      
      let MD5Hash (input : string) = use md5 = System.Security.Cryptography.MD5.Create() input |> System.Text.Encoding.ASCII.GetBytes |> md5.ComputeHash |> Seq.map (fun c -> c.ToString("X2")) |> Seq.reduce (+)
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
      |>
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      pipeline ,     . 
      
        
        
        
      
         :    GetBytes ->   ->      HEX  ->       (  reduce   +           ) ->    . 
      
        
        
        
      
     
      
        
        
        
      
      ,     C# using System; public string CreateMD5Hash (string input) { MD5 md5 = System.Security.Cryptography.MD5.Create(); byte[] inputBytes = System.Text.Encoding.ASCII.GetBytes (input); byte[] hashBytes = md5.ComputeHash (inputBytes); StringBuilder sb = new StringBuilder(); for (int i = 0; i < hashBytes.Length; i++) { sb.Append (hashBytes[i].ToString ("X2")); } return sb.ToString(); }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
     
      
        
        
        
      
              :        .       AzureServiceWorker (  CLR    ) 
      
        
        
        
      
     
      
        
        
        
      
              -   .   F#    !   Xamarin Studio            . 
      
        
        
        
      
      <ItemGroup> <Compile Include="Resources\Resource.designer.fs" /> <Compile Include="Properties\AssemblyInfo.fs" /> <Compile Include="Helpers\Helpers.fs" /> <Compile Include="Services\User.fs" /> <Compile Include="Services\AzureServiceWorker.fs" /> <Compile Include="IAmHereActivity.fs" /> <Compile Include="WhereAreYouActivity.fs" /> <Compile Include="SignInActivity.fs" /> </ItemGroup>
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
        
      
        
        
        
      
            :    .    Xamarin    Xamarin.Mobile 
      
        
        
        
      
     
      
        
        
        
      
          .  F#         TPL,     Task',      .     F#         Task.  ,     : 
      
        
        
        
      
     module Async = open System.Threading open System.Threading.Tasks let inline AwaitPlainTask (task: Task) = // rethrow exception from preceding task if it fauled let continuation (t : Task) : unit = match t.IsFaulted with | true -> raise t.Exception | arg -> () task.ContinueWith continuation |> Async.AwaitTask
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
             Async.AwaitIAsyncResult >> Async.Ignore
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
           
      
        
        
        
      
     
      
        
        
        
      
                
      
        
        
        
      
     let ExtractUserInfo (x : Contact) = let first = x.Phones |> Seq.tryPick(fun x -> if x.Type = PhoneType.Mobile then Some(x) else None) match first with | Some(first) -> let phone = first.Number |> StripChars [' ';'-';'(';')'] UserInfo.CreateUserInfo((MD5Hash phone), phone, x.DisplayName) | None -> UserInfo.CreateUserInfo("no mobile phone", "no mobile phone", "no mobile phone") // function for async list filling let FillContactsAsync = async { let book = new AddressBook (this) let! result = book.RequestPermission() |> Async.AwaitTask if result then _contacts <- book.ToList() |> Seq.filter (fun (x: Contact) -> not (Seq.isEmpty x.Phones)) |> Seq.map ExtractUserInfo |> Seq.sortBy(fun x -> x.DisplayName) |> Seq.toList let finalContacts = _contacts |> Seq.map (fun x -> x.DisplayName.ToUpperInvariant()) |> Seq.toArray this.ListAdapter <- new ArrayAdapter(this, Resource_Layout.row_contact, finalContacts) else System.Diagnostics.Debug.WriteLine("Permission denied by user or manifest") this.ListAdapter <- new ArrayAdapter(this, Resource_Layout.row_contact, Array.empty) }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
          
      
        
        
        
      
     book.ToList()
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
       List |> Seq.filter (fun (x: Contact) -> not (Seq.isEmpty x.Phones))
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
          |> Seq.map ExtractUserInfo
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
          Contracts  UserInfo,      UserInfo |> Seq.sortBy(fun x -> x.DisplayName)
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      |> Seq.toList
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
       List _contacts <-
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
        mutable  _contacts |> Seq.map (fun x -> x.DisplayName.ToUpperInvariant())<-
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
        UserInfo  string,     - -    |> Seq.toArray<-
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      List  Array    ArrayAdapter 
      
        
        
        
      
        -      List.   . 
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
     
      
        
        
        
      
     Azure Mobile Servcies 
      
        
        
        
      
       -    Azure Mobile Services.       NotificationHub,     Push    .   Azure    , ..      . 
      
        
        
        
      
     
      
        
        
        
      
          ,    
      
        
        
        
      
     module WruConstants = [<Literal>] let TotallyNotAzureServer = "https://YOUR.azure-mobile.net/"; [<Literal>] let TotallyNotAzureKey = "YOUR"
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
       
        
        
        
      
     member this.RegisterMe phone name regId = async { try let table = this.MobileService.GetTable<User>() let usr = { Id = "" PhoneHash = MD5Hash phone Nickname = name RegistrationId = regId } do! table.InsertAsync usr |> Async.AwaitPlainTask return (usr.Id, usr.PhoneHash, usr.Nickname) with | e -> System.Diagnostics.Trace.WriteLine(e.ToString) return (String.Empty,String.Empty,String.Empty) }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     member this.RegisterMe phone name regId = async {
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     -       (     )    .       "computation expression"   workflow.   { }       ! ( bang),  do! (do-bang)  let! (let bang)     User.    ,  F#        ,      
      
        
        
        
      
      let usr = { Id = "" PhoneHash = MD5Hash phone Nickname = name RegistrationId = regId }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     do! table.InsertAsync usr |> Async.AwaitPlainTask
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      do-bang,   await
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      C#. ..             continuation    . return (usr.Id, usr.PhoneHash, usr.Nickname)
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
          Tuple<string,string,string>     .  try ... with | e ->
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      try..catch
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      C# 
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
     
      
        
        
        
      
           .  F#    fst
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      snd
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
          .        2 .     : 
      
        
        
        
      
      let id (c,_,_) = c let phonehash (_,c,_) = c let nickname (_,_,c) = c
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
        : id tuple
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      Id  .. 
      
        
        
        
      
     
      
        
        
        
      
        5  Azure,       Push .       Azure Custom Api  
      
        
        
        
      
     
      
        
        
        
      
          exports.post = function(request, response) { // Use "request.service" to access features of your mobile service, eg: // var tables = request.service.tables; // var push = request.service.push; //response.send(statusCodes.OK, { message : 'Hello World!' }); console.log('Incoming call with requst: ', request.body.RequestId); var usersTable = request.service.tables.getTable('User'); usersTable.where( { id : request.body.TargetId } ) .read( { success: function(results) { if (results.length > 0) { var user = results[0] console.log('Send to results: ', user.Nickname, user.RegistrationId); request.service.push.gcm.send(user.RegistrationId, { RequesterId: request.body.RequesterId, RequesterNickname: request.body.RequesterName, TargetId: user.id, TargetNickname: user.Nickname }, { success: function(gcm_response) { console.log('Push notification sent: ', gcm_response); response.send(statusCodes.OK, { RequestedNickname : user.Nickname }); }, error: function(gcm_error) { console.log('Error sending push notification: ', gcm_error); response.send(statusCodes.INTERNAL_SERVER_ERROR, { RequestedNickname : user.Nickname }); } }); } else { response.send(statusCodes.NO_CONTENT, { RequestedNickname : "" }); } }, error: function(error) { console.log('Error read table: ', error); response.send(statusCodes.INTERNAL_SERVER_ERROR, { RequestedNickname : "" }); } }); };
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
        Push      
      
        
        
        
      
     // Perform Push operation member this.PushAsync targetId myId myNickname = async { try let (request : PushRequest) = { TargetId = targetId RequesterId = myId RequesterName = myNickname } let! result = this.MobileService.InvokeApiAsync<PushRequest, PushResponce>("pushhim", request) |> Async.AwaitTask return result.RequestedNickname with | e -> return e.ToString() }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
           ,    let-bang
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
       do!
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
       
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
          Google Play Services.     F#   .           .    : Xamarin.Android.Support.v7.AppCompat 
      
        
        
        
      
         , Google Play Services ,   . 
      
        
        
        
      
     
      
        
        
        
      
          push notification   .    GCM,  ID,     ID       Push  (.   pushhim).        BroadcastReciever       developer.android.com .     F#         Xamarin Component Store.     Google Cloud Messaging Client         GCM    .        ID 
      
        
        
        
      
     //Check to see that GCM is supported and that the manifest has the correct information GcmClient.CheckDevice(this) GcmClient.CheckManifest(this) // check google play if CheckPlayServices() then // Try to get registration id let regId = GcmClient.GetRegistrationId this if String.IsNullOrEmpty(regId) then // Call to Register the device for Push Notifications GcmClient.Register(this, WruConstants.GcmSender);
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
            
      
        
        
        
      
     
      
        
        
        
      
        . 
      
        
        
        
      
        , -  
      
        
        
        
      
         bitbucket.org/xakpc/whereareyou 
      
        
        
        
      
         ,     
      
        
        
        
      
              ,           "" . 
      
        
        
        
      
     
      
        
        
        
      
      
      
        
        
        
      
     ,   Android   F#.      . 
      
        
        
        
      
     ,       -  Android  F#.   ,       .
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
    listView.Adapter <- new ArrayAdapter(this, Android.Resource.Layout.SimpleListItem1, Android.Resource.Id.Text1, values) 
      
        
        
        
      
      , ,  let values = [|"item1"; "item2"; "item3"|]
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     -   string[],       list (IEnumerable   ) 
      
        
        
        
      
              F#.            www.tryfsharp.org/Learn 
      
        
        
        
      
      
 
      
        
        
        
      
          F# -  ,  
      
        
        
        
      
     
      
        
        
        
      
            F# For Fun And Profit 
      
        
        
        
      
     
      
        
        
        
      
       ,    
      
        
        
        
      
         - . 
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
     
      
        
        
        
      
            hash 
      
        
        
        
      
         MD5  F# 
      
        
        
        
      
      let MD5Hash (input : string) = use md5 = System.Security.Cryptography.MD5.Create() input |> System.Text.Encoding.ASCII.GetBytes |> md5.ComputeHash |> Seq.map (fun c -> c.ToString("X2")) |> Seq.reduce (+)
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
      |>
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      pipeline ,     . 
      
        
        
        
      
         :    GetBytes ->   ->      HEX  ->       (  reduce   +           ) ->    . 
      
        
        
        
      
     
      
        
        
        
      
      ,     C# using System; public string CreateMD5Hash (string input) { MD5 md5 = System.Security.Cryptography.MD5.Create(); byte[] inputBytes = System.Text.Encoding.ASCII.GetBytes (input); byte[] hashBytes = md5.ComputeHash (inputBytes); StringBuilder sb = new StringBuilder(); for (int i = 0; i < hashBytes.Length; i++) { sb.Append (hashBytes[i].ToString ("X2")); } return sb.ToString(); }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
     
      
        
        
        
      
              :        .       AzureServiceWorker (  CLR    ) 
      
        
        
        
      
     
      
        
        
        
      
              -   .   F#    !   Xamarin Studio            . 
      
        
        
        
      
      <ItemGroup> <Compile Include="Resources\Resource.designer.fs" /> <Compile Include="Properties\AssemblyInfo.fs" /> <Compile Include="Helpers\Helpers.fs" /> <Compile Include="Services\User.fs" /> <Compile Include="Services\AzureServiceWorker.fs" /> <Compile Include="IAmHereActivity.fs" /> <Compile Include="WhereAreYouActivity.fs" /> <Compile Include="SignInActivity.fs" /> </ItemGroup>
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
        
      
        
        
        
      
            :    .    Xamarin    Xamarin.Mobile 
      
        
        
        
      
     
      
        
        
        
      
          .  F#         TPL,     Task',      .     F#         Task.  ,     : 
      
        
        
        
      
     module Async = open System.Threading open System.Threading.Tasks let inline AwaitPlainTask (task: Task) = // rethrow exception from preceding task if it fauled let continuation (t : Task) : unit = match t.IsFaulted with | true -> raise t.Exception | arg -> () task.ContinueWith continuation |> Async.AwaitTask
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
             Async.AwaitIAsyncResult >> Async.Ignore
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
           
      
        
        
        
      
     
      
        
        
        
      
                
      
        
        
        
      
     let ExtractUserInfo (x : Contact) = let first = x.Phones |> Seq.tryPick(fun x -> if x.Type = PhoneType.Mobile then Some(x) else None) match first with | Some(first) -> let phone = first.Number |> StripChars [' ';'-';'(';')'] UserInfo.CreateUserInfo((MD5Hash phone), phone, x.DisplayName) | None -> UserInfo.CreateUserInfo("no mobile phone", "no mobile phone", "no mobile phone") // function for async list filling let FillContactsAsync = async { let book = new AddressBook (this) let! result = book.RequestPermission() |> Async.AwaitTask if result then _contacts <- book.ToList() |> Seq.filter (fun (x: Contact) -> not (Seq.isEmpty x.Phones)) |> Seq.map ExtractUserInfo |> Seq.sortBy(fun x -> x.DisplayName) |> Seq.toList let finalContacts = _contacts |> Seq.map (fun x -> x.DisplayName.ToUpperInvariant()) |> Seq.toArray this.ListAdapter <- new ArrayAdapter(this, Resource_Layout.row_contact, finalContacts) else System.Diagnostics.Debug.WriteLine("Permission denied by user or manifest") this.ListAdapter <- new ArrayAdapter(this, Resource_Layout.row_contact, Array.empty) }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
          
      
        
        
        
      
     book.ToList()
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
       List |> Seq.filter (fun (x: Contact) -> not (Seq.isEmpty x.Phones))
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
          |> Seq.map ExtractUserInfo
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
          Contracts  UserInfo,      UserInfo |> Seq.sortBy(fun x -> x.DisplayName)
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      |> Seq.toList
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
       List _contacts <-
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
        mutable  _contacts |> Seq.map (fun x -> x.DisplayName.ToUpperInvariant())<-
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
        UserInfo  string,     - -    |> Seq.toArray<-
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      List  Array    ArrayAdapter 
      
        
        
        
      
        -      List.   . 
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
     
      
        
        
        
      
     Azure Mobile Servcies 
      
        
        
        
      
       -    Azure Mobile Services.       NotificationHub,     Push    .   Azure    , ..      . 
      
        
        
        
      
     
      
        
        
        
      
          ,    
      
        
        
        
      
     module WruConstants = [<Literal>] let TotallyNotAzureServer = "https://YOUR.azure-mobile.net/"; [<Literal>] let TotallyNotAzureKey = "YOUR"
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
       
        
        
        
      
     member this.RegisterMe phone name regId = async { try let table = this.MobileService.GetTable<User>() let usr = { Id = "" PhoneHash = MD5Hash phone Nickname = name RegistrationId = regId } do! table.InsertAsync usr |> Async.AwaitPlainTask return (usr.Id, usr.PhoneHash, usr.Nickname) with | e -> System.Diagnostics.Trace.WriteLine(e.ToString) return (String.Empty,String.Empty,String.Empty) }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     member this.RegisterMe phone name regId = async {
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     -       (     )    .       "computation expression"   workflow.   { }       ! ( bang),  do! (do-bang)  let! (let bang)     User.    ,  F#        ,      
      
        
        
        
      
      let usr = { Id = "" PhoneHash = MD5Hash phone Nickname = name RegistrationId = regId }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     do! table.InsertAsync usr |> Async.AwaitPlainTask
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      do-bang,   await
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      C#. ..             continuation    . return (usr.Id, usr.PhoneHash, usr.Nickname)
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
          Tuple<string,string,string>     .  try ... with | e ->
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      try..catch
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      C# 
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
     
      
        
        
        
      
           .  F#    fst
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      snd
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
          .        2 .     : 
      
        
        
        
      
      let id (c,_,_) = c let phonehash (_,c,_) = c let nickname (_,_,c) = c
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
        : id tuple
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      Id  .. 
      
        
        
        
      
     
      
        
        
        
      
        5  Azure,       Push .       Azure Custom Api  
      
        
        
        
      
     
      
        
        
        
      
          exports.post = function(request, response) { // Use "request.service" to access features of your mobile service, eg: // var tables = request.service.tables; // var push = request.service.push; //response.send(statusCodes.OK, { message : 'Hello World!' }); console.log('Incoming call with requst: ', request.body.RequestId); var usersTable = request.service.tables.getTable('User'); usersTable.where( { id : request.body.TargetId } ) .read( { success: function(results) { if (results.length > 0) { var user = results[0] console.log('Send to results: ', user.Nickname, user.RegistrationId); request.service.push.gcm.send(user.RegistrationId, { RequesterId: request.body.RequesterId, RequesterNickname: request.body.RequesterName, TargetId: user.id, TargetNickname: user.Nickname }, { success: function(gcm_response) { console.log('Push notification sent: ', gcm_response); response.send(statusCodes.OK, { RequestedNickname : user.Nickname }); }, error: function(gcm_error) { console.log('Error sending push notification: ', gcm_error); response.send(statusCodes.INTERNAL_SERVER_ERROR, { RequestedNickname : user.Nickname }); } }); } else { response.send(statusCodes.NO_CONTENT, { RequestedNickname : "" }); } }, error: function(error) { console.log('Error read table: ', error); response.send(statusCodes.INTERNAL_SERVER_ERROR, { RequestedNickname : "" }); } }); };
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
        Push      
      
        
        
        
      
     // Perform Push operation member this.PushAsync targetId myId myNickname = async { try let (request : PushRequest) = { TargetId = targetId RequesterId = myId RequesterName = myNickname } let! result = this.MobileService.InvokeApiAsync<PushRequest, PushResponce>("pushhim", request) |> Async.AwaitTask return result.RequestedNickname with | e -> return e.ToString() }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
           ,    let-bang
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
       do!
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
       
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
          Google Play Services.     F#   .           .    : Xamarin.Android.Support.v7.AppCompat 
      
        
        
        
      
         , Google Play Services ,   . 
      
        
        
        
      
     
      
        
        
        
      
          push notification   .    GCM,  ID,     ID       Push  (.   pushhim).        BroadcastReciever       developer.android.com .     F#         Xamarin Component Store.     Google Cloud Messaging Client         GCM    .        ID 
      
        
        
        
      
     //Check to see that GCM is supported and that the manifest has the correct information GcmClient.CheckDevice(this) GcmClient.CheckManifest(this) // check google play if CheckPlayServices() then // Try to get registration id let regId = GcmClient.GetRegistrationId this if String.IsNullOrEmpty(regId) then // Call to Register the device for Push Notifications GcmClient.Register(this, WruConstants.GcmSender);
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
            
      
        
        
        
      
     
      
        
        
        
      
        . 
      
        
        
        
      
        , -  
      
        
        
        
      
         bitbucket.org/xakpc/whereareyou 
      
        
        
        
      
         ,     
      
        
        
        
      
              ,           "" . 
      
        
        
        
      
     
      
        
        
        
      
      
      
        
        
        
      
     ,   Android   F#.      . 
      
        
        
        
      
     ,       -  Android  F#.   ,       .
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     listView.Adapter <- new ArrayAdapter(this, Android.Resource.Layout.SimpleListItem1, Android.Resource.Id.Text1, values) 
      
        
        
        
      
      , ,  let values = [|"item1"; "item2"; "item3"|]
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     -   string[],       list (IEnumerable   ) 
      
        
        
        
      
              F#.            www.tryfsharp.org/Learn 
      
        
        
        
      
      
 
      
        
        
        
      
          F# -  ,  
      
        
        
        
      
     
      
        
        
        
      
            F# For Fun And Profit 
      
        
        
        
      
     
      
        
        
        
      
       ,    
      
        
        
        
      
         - . 
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
     
      
        
        
        
      
            hash 
      
        
        
        
      
         MD5  F# 
      
        
        
        
      
      let MD5Hash (input : string) = use md5 = System.Security.Cryptography.MD5.Create() input |> System.Text.Encoding.ASCII.GetBytes |> md5.ComputeHash |> Seq.map (fun c -> c.ToString("X2")) |> Seq.reduce (+)
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
      |>
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      pipeline ,     . 
      
        
        
        
      
         :    GetBytes ->   ->      HEX  ->       (  reduce   +           ) ->    . 
      
        
        
        
      
     
      
        
        
        
      
      ,     C# using System; public string CreateMD5Hash (string input) { MD5 md5 = System.Security.Cryptography.MD5.Create(); byte[] inputBytes = System.Text.Encoding.ASCII.GetBytes (input); byte[] hashBytes = md5.ComputeHash (inputBytes); StringBuilder sb = new StringBuilder(); for (int i = 0; i < hashBytes.Length; i++) { sb.Append (hashBytes[i].ToString ("X2")); } return sb.ToString(); }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
     
      
        
        
        
      
              :        .       AzureServiceWorker (  CLR    ) 
      
        
        
        
      
     
      
        
        
        
      
              -   .   F#    !   Xamarin Studio            . 
      
        
        
        
      
      <ItemGroup> <Compile Include="Resources\Resource.designer.fs" /> <Compile Include="Properties\AssemblyInfo.fs" /> <Compile Include="Helpers\Helpers.fs" /> <Compile Include="Services\User.fs" /> <Compile Include="Services\AzureServiceWorker.fs" /> <Compile Include="IAmHereActivity.fs" /> <Compile Include="WhereAreYouActivity.fs" /> <Compile Include="SignInActivity.fs" /> </ItemGroup>
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
        
      
        
        
        
      
            :    .    Xamarin    Xamarin.Mobile 
      
        
        
        
      
     
      
        
        
        
      
          .  F#         TPL,     Task',      .     F#         Task.  ,     : 
      
        
        
        
      
     module Async = open System.Threading open System.Threading.Tasks let inline AwaitPlainTask (task: Task) = // rethrow exception from preceding task if it fauled let continuation (t : Task) : unit = match t.IsFaulted with | true -> raise t.Exception | arg -> () task.ContinueWith continuation |> Async.AwaitTask
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
             Async.AwaitIAsyncResult >> Async.Ignore
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
           
      
        
        
        
      
     
      
        
        
        
      
                
      
        
        
        
      
     let ExtractUserInfo (x : Contact) = let first = x.Phones |> Seq.tryPick(fun x -> if x.Type = PhoneType.Mobile then Some(x) else None) match first with | Some(first) -> let phone = first.Number |> StripChars [' ';'-';'(';')'] UserInfo.CreateUserInfo((MD5Hash phone), phone, x.DisplayName) | None -> UserInfo.CreateUserInfo("no mobile phone", "no mobile phone", "no mobile phone") // function for async list filling let FillContactsAsync = async { let book = new AddressBook (this) let! result = book.RequestPermission() |> Async.AwaitTask if result then _contacts <- book.ToList() |> Seq.filter (fun (x: Contact) -> not (Seq.isEmpty x.Phones)) |> Seq.map ExtractUserInfo |> Seq.sortBy(fun x -> x.DisplayName) |> Seq.toList let finalContacts = _contacts |> Seq.map (fun x -> x.DisplayName.ToUpperInvariant()) |> Seq.toArray this.ListAdapter <- new ArrayAdapter(this, Resource_Layout.row_contact, finalContacts) else System.Diagnostics.Debug.WriteLine("Permission denied by user or manifest") this.ListAdapter <- new ArrayAdapter(this, Resource_Layout.row_contact, Array.empty) }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
          
      
        
        
        
      
     book.ToList()
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
       List |> Seq.filter (fun (x: Contact) -> not (Seq.isEmpty x.Phones))
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
          |> Seq.map ExtractUserInfo
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
          Contracts  UserInfo,      UserInfo |> Seq.sortBy(fun x -> x.DisplayName)
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      |> Seq.toList
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
       List _contacts <-
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
        mutable  _contacts |> Seq.map (fun x -> x.DisplayName.ToUpperInvariant())<-
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
        UserInfo  string,     - -    |> Seq.toArray<-
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      List  Array    ArrayAdapter 
      
        
        
        
      
        -      List.   . 
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
     
      
        
        
        
      
     Azure Mobile Servcies 
      
        
        
        
      
       -    Azure Mobile Services.       NotificationHub,     Push    .   Azure    , ..      . 
      
        
        
        
      
     
      
        
        
        
      
          ,    
      
        
        
        
      
     module WruConstants = [<Literal>] let TotallyNotAzureServer = "https://YOUR.azure-mobile.net/"; [<Literal>] let TotallyNotAzureKey = "YOUR"
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
       
        
        
        
      
     member this.RegisterMe phone name regId = async { try let table = this.MobileService.GetTable<User>() let usr = { Id = "" PhoneHash = MD5Hash phone Nickname = name RegistrationId = regId } do! table.InsertAsync usr |> Async.AwaitPlainTask return (usr.Id, usr.PhoneHash, usr.Nickname) with | e -> System.Diagnostics.Trace.WriteLine(e.ToString) return (String.Empty,String.Empty,String.Empty) }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     member this.RegisterMe phone name regId = async {
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     -       (     )    .       "computation expression"   workflow.   { }       ! ( bang),  do! (do-bang)  let! (let bang)     User.    ,  F#        ,      
      
        
        
        
      
      let usr = { Id = "" PhoneHash = MD5Hash phone Nickname = name RegistrationId = regId }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     do! table.InsertAsync usr |> Async.AwaitPlainTask
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      do-bang,   await
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      C#. ..             continuation    . return (usr.Id, usr.PhoneHash, usr.Nickname)
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
          Tuple<string,string,string>     .  try ... with | e ->
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      try..catch
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      C# 
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
     
      
        
        
        
      
           .  F#    fst
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      snd
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
          .        2 .     : 
      
        
        
        
      
      let id (c,_,_) = c let phonehash (_,c,_) = c let nickname (_,_,c) = c
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
        : id tuple
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      Id  .. 
      
        
        
        
      
     
      
        
        
        
      
        5  Azure,       Push .       Azure Custom Api  
      
        
        
        
      
     
      
        
        
        
      
          exports.post = function(request, response) { // Use "request.service" to access features of your mobile service, eg: // var tables = request.service.tables; // var push = request.service.push; //response.send(statusCodes.OK, { message : 'Hello World!' }); console.log('Incoming call with requst: ', request.body.RequestId); var usersTable = request.service.tables.getTable('User'); usersTable.where( { id : request.body.TargetId } ) .read( { success: function(results) { if (results.length > 0) { var user = results[0] console.log('Send to results: ', user.Nickname, user.RegistrationId); request.service.push.gcm.send(user.RegistrationId, { RequesterId: request.body.RequesterId, RequesterNickname: request.body.RequesterName, TargetId: user.id, TargetNickname: user.Nickname }, { success: function(gcm_response) { console.log('Push notification sent: ', gcm_response); response.send(statusCodes.OK, { RequestedNickname : user.Nickname }); }, error: function(gcm_error) { console.log('Error sending push notification: ', gcm_error); response.send(statusCodes.INTERNAL_SERVER_ERROR, { RequestedNickname : user.Nickname }); } }); } else { response.send(statusCodes.NO_CONTENT, { RequestedNickname : "" }); } }, error: function(error) { console.log('Error read table: ', error); response.send(statusCodes.INTERNAL_SERVER_ERROR, { RequestedNickname : "" }); } }); };
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
        Push      
      
        
        
        
      
     // Perform Push operation member this.PushAsync targetId myId myNickname = async { try let (request : PushRequest) = { TargetId = targetId RequesterId = myId RequesterName = myNickname } let! result = this.MobileService.InvokeApiAsync<PushRequest, PushResponce>("pushhim", request) |> Async.AwaitTask return result.RequestedNickname with | e -> return e.ToString() }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
           ,    let-bang
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
       do!
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
       
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
          Google Play Services.     F#   .           .    : Xamarin.Android.Support.v7.AppCompat 
      
        
        
        
      
         , Google Play Services ,   . 
      
        
        
        
      
     
      
        
        
        
      
          push notification   .    GCM,  ID,     ID       Push  (.   pushhim).        BroadcastReciever       developer.android.com .     F#         Xamarin Component Store.     Google Cloud Messaging Client         GCM    .        ID 
      
        
        
        
      
     //Check to see that GCM is supported and that the manifest has the correct information GcmClient.CheckDevice(this) GcmClient.CheckManifest(this) // check google play if CheckPlayServices() then // Try to get registration id let regId = GcmClient.GetRegistrationId this if String.IsNullOrEmpty(regId) then // Call to Register the device for Push Notifications GcmClient.Register(this, WruConstants.GcmSender);
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
            
      
        
        
        
      
     
      
        
        
        
      
        . 
      
        
        
        
      
        , -  
      
        
        
        
      
         bitbucket.org/xakpc/whereareyou 
      
        
        
        
      
         ,     
      
        
        
        
      
              ,           "" . 
      
        
        
        
      
     
      
        
        
        
      
      
      
        
        
        
      
     ,   Android   F#.      . 
      
        
        
        
      
     ,       -  Android  F#.   ,       .
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
    
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
 listView.Adapter <- new ArrayAdapter(this, Android.Resource.Layout.SimpleListItem1, Android.Resource.Id.Text1, values) 
      
        
        
        
      
      , ,  let values = [|"item1"; "item2"; "item3"|]
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     -   string[],       list (IEnumerable   ) 
      
        
        
        
      
              F#.            www.tryfsharp.org/Learn 
      
        
        
        
      
      
 
      
        
        
        
      
          F# -  ,  
      
        
        
        
      
     
      
        
        
        
      
            F# For Fun And Profit 
      
        
        
        
      
     
      
        
        
        
      
       ,    
      
        
        
        
      
         - . 
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
     
      
        
        
        
      
            hash 
      
        
        
        
      
         MD5  F# 
      
        
        
        
      
      let MD5Hash (input : string) = use md5 = System.Security.Cryptography.MD5.Create() input |> System.Text.Encoding.ASCII.GetBytes |> md5.ComputeHash |> Seq.map (fun c -> c.ToString("X2")) |> Seq.reduce (+)
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
      |>
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      pipeline ,     . 
      
        
        
        
      
         :    GetBytes ->   ->      HEX  ->       (  reduce   +           ) ->    . 
      
        
        
        
      
     
      
        
        
        
      
      ,     C# using System; public string CreateMD5Hash (string input) { MD5 md5 = System.Security.Cryptography.MD5.Create(); byte[] inputBytes = System.Text.Encoding.ASCII.GetBytes (input); byte[] hashBytes = md5.ComputeHash (inputBytes); StringBuilder sb = new StringBuilder(); for (int i = 0; i < hashBytes.Length; i++) { sb.Append (hashBytes[i].ToString ("X2")); } return sb.ToString(); }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
     
      
        
        
        
      
              :        .       AzureServiceWorker (  CLR    ) 
      
        
        
        
      
     
      
        
        
        
      
              -   .   F#    !   Xamarin Studio            . 
      
        
        
        
      
      <ItemGroup> <Compile Include="Resources\Resource.designer.fs" /> <Compile Include="Properties\AssemblyInfo.fs" /> <Compile Include="Helpers\Helpers.fs" /> <Compile Include="Services\User.fs" /> <Compile Include="Services\AzureServiceWorker.fs" /> <Compile Include="IAmHereActivity.fs" /> <Compile Include="WhereAreYouActivity.fs" /> <Compile Include="SignInActivity.fs" /> </ItemGroup>
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
        
      
        
        
        
      
            :    .    Xamarin    Xamarin.Mobile 
      
        
        
        
      
     
      
        
        
        
      
          .  F#         TPL,     Task',      .     F#         Task.  ,     : 
      
        
        
        
      
     module Async = open System.Threading open System.Threading.Tasks let inline AwaitPlainTask (task: Task) = // rethrow exception from preceding task if it fauled let continuation (t : Task) : unit = match t.IsFaulted with | true -> raise t.Exception | arg -> () task.ContinueWith continuation |> Async.AwaitTask
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
             Async.AwaitIAsyncResult >> Async.Ignore
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
           
      
        
        
        
      
     
      
        
        
        
      
                
      
        
        
        
      
     let ExtractUserInfo (x : Contact) = let first = x.Phones |> Seq.tryPick(fun x -> if x.Type = PhoneType.Mobile then Some(x) else None) match first with | Some(first) -> let phone = first.Number |> StripChars [' ';'-';'(';')'] UserInfo.CreateUserInfo((MD5Hash phone), phone, x.DisplayName) | None -> UserInfo.CreateUserInfo("no mobile phone", "no mobile phone", "no mobile phone") // function for async list filling let FillContactsAsync = async { let book = new AddressBook (this) let! result = book.RequestPermission() |> Async.AwaitTask if result then _contacts <- book.ToList() |> Seq.filter (fun (x: Contact) -> not (Seq.isEmpty x.Phones)) |> Seq.map ExtractUserInfo |> Seq.sortBy(fun x -> x.DisplayName) |> Seq.toList let finalContacts = _contacts |> Seq.map (fun x -> x.DisplayName.ToUpperInvariant()) |> Seq.toArray this.ListAdapter <- new ArrayAdapter(this, Resource_Layout.row_contact, finalContacts) else System.Diagnostics.Debug.WriteLine("Permission denied by user or manifest") this.ListAdapter <- new ArrayAdapter(this, Resource_Layout.row_contact, Array.empty) }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
          
      
        
        
        
      
     book.ToList()
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
       List |> Seq.filter (fun (x: Contact) -> not (Seq.isEmpty x.Phones))
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
          |> Seq.map ExtractUserInfo
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
          Contracts  UserInfo,      UserInfo |> Seq.sortBy(fun x -> x.DisplayName)
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      |> Seq.toList
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
       List _contacts <-
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
        mutable  _contacts |> Seq.map (fun x -> x.DisplayName.ToUpperInvariant())<-
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
        UserInfo  string,     - -    |> Seq.toArray<-
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      List  Array    ArrayAdapter 
      
        
        
        
      
        -      List.   . 
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
     
      
        
        
        
      
     Azure Mobile Servcies 
      
        
        
        
      
       -    Azure Mobile Services.       NotificationHub,     Push    .   Azure    , ..      . 
      
        
        
        
      
     
      
        
        
        
      
          ,    
      
        
        
        
      
     module WruConstants = [<Literal>] let TotallyNotAzureServer = "https://YOUR.azure-mobile.net/"; [<Literal>] let TotallyNotAzureKey = "YOUR"
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
       
        
        
        
      
     member this.RegisterMe phone name regId = async { try let table = this.MobileService.GetTable<User>() let usr = { Id = "" PhoneHash = MD5Hash phone Nickname = name RegistrationId = regId } do! table.InsertAsync usr |> Async.AwaitPlainTask return (usr.Id, usr.PhoneHash, usr.Nickname) with | e -> System.Diagnostics.Trace.WriteLine(e.ToString) return (String.Empty,String.Empty,String.Empty) }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     member this.RegisterMe phone name regId = async {
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     -       (     )    .       "computation expression"   workflow.   { }       ! ( bang),  do! (do-bang)  let! (let bang)     User.    ,  F#        ,      
      
        
        
        
      
      let usr = { Id = "" PhoneHash = MD5Hash phone Nickname = name RegistrationId = regId }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     do! table.InsertAsync usr |> Async.AwaitPlainTask
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      do-bang,   await
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      C#. ..             continuation    . return (usr.Id, usr.PhoneHash, usr.Nickname)
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
          Tuple<string,string,string>     .  try ... with | e ->
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      try..catch
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      C# 
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
     
      
        
        
        
      
           .  F#    fst
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      snd
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
          .        2 .     : 
      
        
        
        
      
      let id (c,_,_) = c let phonehash (_,c,_) = c let nickname (_,_,c) = c
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
        : id tuple
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      Id  .. 
      
        
        
        
      
     
      
        
        
        
      
        5  Azure,       Push .       Azure Custom Api  
      
        
        
        
      
     
      
        
        
        
      
          exports.post = function(request, response) { // Use "request.service" to access features of your mobile service, eg: // var tables = request.service.tables; // var push = request.service.push; //response.send(statusCodes.OK, { message : 'Hello World!' }); console.log('Incoming call with requst: ', request.body.RequestId); var usersTable = request.service.tables.getTable('User'); usersTable.where( { id : request.body.TargetId } ) .read( { success: function(results) { if (results.length > 0) { var user = results[0] console.log('Send to results: ', user.Nickname, user.RegistrationId); request.service.push.gcm.send(user.RegistrationId, { RequesterId: request.body.RequesterId, RequesterNickname: request.body.RequesterName, TargetId: user.id, TargetNickname: user.Nickname }, { success: function(gcm_response) { console.log('Push notification sent: ', gcm_response); response.send(statusCodes.OK, { RequestedNickname : user.Nickname }); }, error: function(gcm_error) { console.log('Error sending push notification: ', gcm_error); response.send(statusCodes.INTERNAL_SERVER_ERROR, { RequestedNickname : user.Nickname }); } }); } else { response.send(statusCodes.NO_CONTENT, { RequestedNickname : "" }); } }, error: function(error) { console.log('Error read table: ', error); response.send(statusCodes.INTERNAL_SERVER_ERROR, { RequestedNickname : "" }); } }); };
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
        Push      
      
        
        
        
      
     // Perform Push operation member this.PushAsync targetId myId myNickname = async { try let (request : PushRequest) = { TargetId = targetId RequesterId = myId RequesterName = myNickname } let! result = this.MobileService.InvokeApiAsync<PushRequest, PushResponce>("pushhim", request) |> Async.AwaitTask return result.RequestedNickname with | e -> return e.ToString() }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
           ,    let-bang
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
       do!
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
       
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
          Google Play Services.     F#   .           .    : Xamarin.Android.Support.v7.AppCompat 
      
        
        
        
      
         , Google Play Services ,   . 
      
        
        
        
      
     
      
        
        
        
      
          push notification   .    GCM,  ID,     ID       Push  (.   pushhim).        BroadcastReciever       developer.android.com .     F#         Xamarin Component Store.     Google Cloud Messaging Client         GCM    .        ID 
      
        
        
        
      
     //Check to see that GCM is supported and that the manifest has the correct information GcmClient.CheckDevice(this) GcmClient.CheckManifest(this) // check google play if CheckPlayServices() then // Try to get registration id let regId = GcmClient.GetRegistrationId this if String.IsNullOrEmpty(regId) then // Call to Register the device for Push Notifications GcmClient.Register(this, WruConstants.GcmSender);
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
            
      
        
        
        
      
     
      
        
        
        
      
        . 
      
        
        
        
      
        , -  
      
        
        
        
      
         bitbucket.org/xakpc/whereareyou 
      
        
        
        
      
         ,     
      
        
        
        
      
              ,           "" . 
      
        
        
        
      
     
      
        
        
        
      
      
      
        
        
        
      
     ,   Android   F#.      . 
      
        
        
        
      
     ,       -  Android  F#.   ,       .listView.Adapter <- new ArrayAdapter(this, Android.Resource.Layout.SimpleListItem1, Android.Resource.Id.Text1, values) 
      
        
        
        
      
      , ,  let values = [|"item1"; "item2"; "item3"|]
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     -   string[],       list (IEnumerable   ) 
      
        
        
        
      
              F#.            www.tryfsharp.org/Learn 
      
        
        
        
      
      
 
      
        
        
        
      
          F# -  ,  
      
        
        
        
      
     
      
        
        
        
      
            F# For Fun And Profit 
      
        
        
        
      
     
      
        
        
        
      
       ,    
      
        
        
        
      
         - . 
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
     
      
        
        
        
      
            hash 
      
        
        
        
      
         MD5  F# 
      
        
        
        
      
      let MD5Hash (input : string) = use md5 = System.Security.Cryptography.MD5.Create() input |> System.Text.Encoding.ASCII.GetBytes |> md5.ComputeHash |> Seq.map (fun c -> c.ToString("X2")) |> Seq.reduce (+)
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
      |>
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      pipeline ,     . 
      
        
        
        
      
         :    GetBytes ->   ->      HEX  ->       (  reduce   +           ) ->    . 
      
        
        
        
      
     
      
        
        
        
      
      ,     C# using System; public string CreateMD5Hash (string input) { MD5 md5 = System.Security.Cryptography.MD5.Create(); byte[] inputBytes = System.Text.Encoding.ASCII.GetBytes (input); byte[] hashBytes = md5.ComputeHash (inputBytes); StringBuilder sb = new StringBuilder(); for (int i = 0; i < hashBytes.Length; i++) { sb.Append (hashBytes[i].ToString ("X2")); } return sb.ToString(); }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
     
      
        
        
        
      
              :        .       AzureServiceWorker (  CLR    ) 
      
        
        
        
      
     
      
        
        
        
      
              -   .   F#    !   Xamarin Studio            . 
      
        
        
        
      
      <ItemGroup> <Compile Include="Resources\Resource.designer.fs" /> <Compile Include="Properties\AssemblyInfo.fs" /> <Compile Include="Helpers\Helpers.fs" /> <Compile Include="Services\User.fs" /> <Compile Include="Services\AzureServiceWorker.fs" /> <Compile Include="IAmHereActivity.fs" /> <Compile Include="WhereAreYouActivity.fs" /> <Compile Include="SignInActivity.fs" /> </ItemGroup>
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
        
      
        
        
        
      
            :    .    Xamarin    Xamarin.Mobile 
      
        
        
        
      
     
      
        
        
        
      
          .  F#         TPL,     Task',      .     F#         Task.  ,     : 
      
        
        
        
      
     module Async = open System.Threading open System.Threading.Tasks let inline AwaitPlainTask (task: Task) = // rethrow exception from preceding task if it fauled let continuation (t : Task) : unit = match t.IsFaulted with | true -> raise t.Exception | arg -> () task.ContinueWith continuation |> Async.AwaitTask
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
             Async.AwaitIAsyncResult >> Async.Ignore
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
           
      
        
        
        
      
     
      
        
        
        
      
                
      
        
        
        
      
     let ExtractUserInfo (x : Contact) = let first = x.Phones |> Seq.tryPick(fun x -> if x.Type = PhoneType.Mobile then Some(x) else None) match first with | Some(first) -> let phone = first.Number |> StripChars [' ';'-';'(';')'] UserInfo.CreateUserInfo((MD5Hash phone), phone, x.DisplayName) | None -> UserInfo.CreateUserInfo("no mobile phone", "no mobile phone", "no mobile phone") // function for async list filling let FillContactsAsync = async { let book = new AddressBook (this) let! result = book.RequestPermission() |> Async.AwaitTask if result then _contacts <- book.ToList() |> Seq.filter (fun (x: Contact) -> not (Seq.isEmpty x.Phones)) |> Seq.map ExtractUserInfo |> Seq.sortBy(fun x -> x.DisplayName) |> Seq.toList let finalContacts = _contacts |> Seq.map (fun x -> x.DisplayName.ToUpperInvariant()) |> Seq.toArray this.ListAdapter <- new ArrayAdapter(this, Resource_Layout.row_contact, finalContacts) else System.Diagnostics.Debug.WriteLine("Permission denied by user or manifest") this.ListAdapter <- new ArrayAdapter(this, Resource_Layout.row_contact, Array.empty) }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
          
      
        
        
        
      
     book.ToList()
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
       List |> Seq.filter (fun (x: Contact) -> not (Seq.isEmpty x.Phones))
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
          |> Seq.map ExtractUserInfo
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
          Contracts  UserInfo,      UserInfo |> Seq.sortBy(fun x -> x.DisplayName)
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      |> Seq.toList
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
       List _contacts <-
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
        mutable  _contacts |> Seq.map (fun x -> x.DisplayName.ToUpperInvariant())<-
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
        UserInfo  string,     - -    |> Seq.toArray<-
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      List  Array    ArrayAdapter 
      
        
        
        
      
        -      List.   . 
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
     
      
        
        
        
      
     Azure Mobile Servcies 
      
        
        
        
      
       -    Azure Mobile Services.       NotificationHub,     Push    .   Azure    , ..      . 
      
        
        
        
      
     
      
        
        
        
      
          ,    
      
        
        
        
      
     module WruConstants = [<Literal>] let TotallyNotAzureServer = "https://YOUR.azure-mobile.net/"; [<Literal>] let TotallyNotAzureKey = "YOUR"
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
       
        
        
        
      
     member this.RegisterMe phone name regId = async { try let table = this.MobileService.GetTable<User>() let usr = { Id = "" PhoneHash = MD5Hash phone Nickname = name RegistrationId = regId } do! table.InsertAsync usr |> Async.AwaitPlainTask return (usr.Id, usr.PhoneHash, usr.Nickname) with | e -> System.Diagnostics.Trace.WriteLine(e.ToString) return (String.Empty,String.Empty,String.Empty) }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     member this.RegisterMe phone name regId = async {
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     -       (     )    .       "computation expression"   workflow.   { }       ! ( bang),  do! (do-bang)  let! (let bang)     User.    ,  F#        ,      
      
        
        
        
      
      let usr = { Id = "" PhoneHash = MD5Hash phone Nickname = name RegistrationId = regId }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     do! table.InsertAsync usr |> Async.AwaitPlainTask
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      do-bang,   await
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      C#. ..             continuation    . return (usr.Id, usr.PhoneHash, usr.Nickname)
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
          Tuple<string,string,string>     .  try ... with | e ->
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      try..catch
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      C# 
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
     
      
        
        
        
      
           .  F#    fst
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      snd
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
          .        2 .     : 
      
        
        
        
      
      let id (c,_,_) = c let phonehash (_,c,_) = c let nickname (_,_,c) = c
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
        : id tuple
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      Id  .. 
      
        
        
        
      
     
      
        
        
        
      
        5  Azure,       Push .       Azure Custom Api  
      
        
        
        
      
     
      
        
        
        
      
          exports.post = function(request, response) { // Use "request.service" to access features of your mobile service, eg: // var tables = request.service.tables; // var push = request.service.push; //response.send(statusCodes.OK, { message : 'Hello World!' }); console.log('Incoming call with requst: ', request.body.RequestId); var usersTable = request.service.tables.getTable('User'); usersTable.where( { id : request.body.TargetId } ) .read( { success: function(results) { if (results.length > 0) { var user = results[0] console.log('Send to results: ', user.Nickname, user.RegistrationId); request.service.push.gcm.send(user.RegistrationId, { RequesterId: request.body.RequesterId, RequesterNickname: request.body.RequesterName, TargetId: user.id, TargetNickname: user.Nickname }, { success: function(gcm_response) { console.log('Push notification sent: ', gcm_response); response.send(statusCodes.OK, { RequestedNickname : user.Nickname }); }, error: function(gcm_error) { console.log('Error sending push notification: ', gcm_error); response.send(statusCodes.INTERNAL_SERVER_ERROR, { RequestedNickname : user.Nickname }); } }); } else { response.send(statusCodes.NO_CONTENT, { RequestedNickname : "" }); } }, error: function(error) { console.log('Error read table: ', error); response.send(statusCodes.INTERNAL_SERVER_ERROR, { RequestedNickname : "" }); } }); };
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
        Push      
      
        
        
        
      
     // Perform Push operation member this.PushAsync targetId myId myNickname = async { try let (request : PushRequest) = { TargetId = targetId RequesterId = myId RequesterName = myNickname } let! result = this.MobileService.InvokeApiAsync<PushRequest, PushResponce>("pushhim", request) |> Async.AwaitTask return result.RequestedNickname with | e -> return e.ToString() }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
           ,    let-bang
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
       do!
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
       
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
          Google Play Services.     F#   .           .    : Xamarin.Android.Support.v7.AppCompat 
      
        
        
        
      
         , Google Play Services ,   . 
      
        
        
        
      
     
      
        
        
        
      
          push notification   .    GCM,  ID,     ID       Push  (.   pushhim).        BroadcastReciever       developer.android.com .     F#         Xamarin Component Store.     Google Cloud Messaging Client         GCM    .        ID 
      
        
        
        
      
     //Check to see that GCM is supported and that the manifest has the correct information GcmClient.CheckDevice(this) GcmClient.CheckManifest(this) // check google play if CheckPlayServices() then // Try to get registration id let regId = GcmClient.GetRegistrationId this if String.IsNullOrEmpty(regId) then // Call to Register the device for Push Notifications GcmClient.Register(this, WruConstants.GcmSender);
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
     
      
        
        
        
      
      
 
      
        
        
        
      
            
      
        
        
        
      
     
      
        
        
        
      
        . 
      
        
        
        
      
        , -  
      
        
        
        
      
         bitbucket.org/xakpc/whereareyou 
      
        
        
        
      
         ,     
      
        
        
        
      
              ,           "" . 
      
        
        
        
      
     
      
        
        
        
      
      
      
        
        
        
      
     ,   Android   F#.      . 
      
        
        
        
      
     ,       -  Android  F#.   ,       .
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
       
 
       
 
      