📜 ⬆️ ⬇️

Developing an Android Application with Xamarin and F #

image

Hello!

Recently, Xamarin announced a competition to develop a mobile application in the functional programming language F #.
This was due to the release of Xamarin 3 with full F # support. I decided to distract from everyday tasks and try to participate, especially since I have been looking at F # for a long time, but I didn’t have a chance to get to know him more. To participate in the competition, I decided to develop an application whose idea was proposed by someone in the process of discussing the sudden take-off of the Yo mobile app. Here is a quote:
The idea for a startup, the working name of "where are you?".
')
The meaning is simple, the girl installs the application, indicates the number of her young man in it, and then a big button appears to send the message “where are you?” #Startup #idea

Why not?

Note
I wrote this post while working on the application. Therefore, it is large and sometimes not very logical.


T-shirt


The first thing I did was download and launch the Xamarin Store application to get a T-shirt with F #. I already have the same with C #
image


Rather, I tried, but immediately grabbed the problem with the construction. It turns out the current version of Xamarin supports F # version 3.0, and only version F # 3.1.1 is free to download.

F # 3.0 is located inside the Visual Studio Express 2012 for Web package and is installed with the studio using the Microsoft Web Platform Installer. Strange approach.
For Xamarin and F # to work, it is enough for the FSharp.Core build of version 4.3.0.0 to be in the GAC. Anyway, here’s a direct link if anyone wants to try.

Beginning of work


Now Xamarin supports F # only inside Xamarin Studio. So I had to forget about my beloved VS2013 for a while and work in this generally quite good environment. Creating a new application for Android took a couple of seconds and here we have a working Hello-world Android application on F #
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 ) 


It seems Habr does not know how to color F #. Sadness (but there is support for Vala)

Immediately to Fight, Attempt number one


How the application should look like to me was obvious, 3 screens, 3 push notifications, good old Azure as a backend, vivid colors (inspired by Yo)
Further the best friend of the developer, a pencil and a piece of paper. Drew mokapy and forward to the code. Add components from the Xamarin Component Store to the project: Azure Mobile Services and Google Play Services (ICS - I don’t want to bother with old versions of Android now).
We collect and BAM! - the first rake.
Grabelki
Programming on Xamarin for Android, according to Xlab . I agree with him :)
image
When building a project, Xamarin builds resource files, in particular, it generates a Resource.Designer.fs file containing, as far as I understand, pointers and / or resource identifiers. In particular, there is a pointer to the Id.end identifier which is translated into the following code
 // aapt resource value: 0x7f070013 static member end = 2131165203 

and the word end is key for F # and the compiler reports an error The "end" (FS0010) . And this is one of the errors that you cannot solve yourself, the management of the generation of these files is unfortunately not available to us.
I immediately wrote to the Xamarin forum and Miguel de Icaza on Twitter - and I got an answer promptly! Developers report that this bug has already been fixed in the alpha version.
I switch Xamarin Studio to alpha channel and BAM! - still does not work.
It turns out ...
Alpha channel is not quite there yet yet ...

Well, it remains only to wait until it is "there", there is still time. Let's leave Google Play Services alone.

A few words about F #

When I started the project, I did not know anything about F #, except that it is “cool”, “modern”, and “extremely comfortable.” An attempt to take it overnight in a new project failed miserably. I spent almost fifteen minutes trying to understand why let values = ["item1"; "item2"; "item3"] let values = ["item1"; "item2"; "item3"] let values = ["item1"; "item2"; "item3"] cannot be passed to the ArrayAdapter's constructor 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#. , .

Source: https://habr.com/ru/post/228783/


All Articles