XamarinとFを使用したAndroidアプリの開発#

画像



こんにちは



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! -最初のレーキ。

すくい
Xlabによると、Android用のXamarinプログラミング。 私は彼に同意します:)

画像

プロジェクトをビルドすると、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#. , .








  1. 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#. , .








  2. 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#. , .








  3. 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#. , .








  4. 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#. , .








  5. 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#. , .








  6. 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#. , .








  7. 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#. , .








  8. 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#. , .








  1. 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#. , .








  2. 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#. , .








  3. 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#. , .








  4. 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#. , .








  5. 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#. , .











All Articles