
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

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 ) 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 "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.Alpha channel is not quite there yet yet ...
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#. , .listView.Adapter <- new ArrayAdapter(this, Android.Resource.Layout.SimpleListItem1, Android.Resource.Id.Text1, values)
, , let values = [|"item1"; "item2"; "item3"|] - string[], list (IEnumerable )
F#. www.tryfsharp.org/Learn

F# - ,
F# For Fun And Profit
,
- .

hash
MD5 F#
let MD5Hash (input : string) = use md5 = System.Security.Cryptography.MD5.Create() input |> System.Text.Encoding.ASCII.GetBytes |> md5.ComputeHash |> Seq.map (fun c -> c.ToString("X2")) |> Seq.reduce (+)
|> pipeline , .
: GetBytes -> -> HEX -> ( reduce + ) -> .
, C# using System; public string CreateMD5Hash (string input) { MD5 md5 = System.Security.Cryptography.MD5.Create(); byte[] inputBytes = System.Text.Encoding.ASCII.GetBytes (input); byte[] hashBytes = md5.ComputeHash (inputBytes); StringBuilder sb = new StringBuilder(); for (int i = 0; i < hashBytes.Length; i++) { sb.Append (hashBytes[i].ToString ("X2")); } return sb.ToString(); }
: . AzureServiceWorker ( CLR )
- . F# ! Xamarin Studio .
<ItemGroup> <Compile Include="Resources\Resource.designer.fs" /> <Compile Include="Properties\AssemblyInfo.fs" /> <Compile Include="Helpers\Helpers.fs" /> <Compile Include="Services\User.fs" /> <Compile Include="Services\AzureServiceWorker.fs" /> <Compile Include="IAmHereActivity.fs" /> <Compile Include="WhereAreYouActivity.fs" /> <Compile Include="SignInActivity.fs" /> </ItemGroup>
: . Xamarin Xamarin.Mobile
. F# TPL, Task', . F# Task. , :
module Async = open System.Threading open System.Threading.Tasks let inline AwaitPlainTask (task: Task) = // rethrow exception from preceding task if it fauled let continuation (t : Task) : unit = match t.IsFaulted with | true -> raise t.Exception | arg -> () task.ContinueWith continuation |> Async.AwaitTask
Async.AwaitIAsyncResult >> Async.Ignore
let ExtractUserInfo (x : Contact) = let first = x.Phones |> Seq.tryPick(fun x -> if x.Type = PhoneType.Mobile then Some(x) else None) match first with | Some(first) -> let phone = first.Number |> StripChars [' ';'-';'(';')'] UserInfo.CreateUserInfo((MD5Hash phone), phone, x.DisplayName) | None -> UserInfo.CreateUserInfo("no mobile phone", "no mobile phone", "no mobile phone") // function for async list filling let FillContactsAsync = async { let book = new AddressBook (this) let! result = book.RequestPermission() |> Async.AwaitTask if result then _contacts <- book.ToList() |> Seq.filter (fun (x: Contact) -> not (Seq.isEmpty x.Phones)) |> Seq.map ExtractUserInfo |> Seq.sortBy(fun x -> x.DisplayName) |> Seq.toList let finalContacts = _contacts |> Seq.map (fun x -> x.DisplayName.ToUpperInvariant()) |> Seq.toArray this.ListAdapter <- new ArrayAdapter(this, Resource_Layout.row_contact, finalContacts) else System.Diagnostics.Debug.WriteLine("Permission denied by user or manifest") this.ListAdapter <- new ArrayAdapter(this, Resource_Layout.row_contact, Array.empty) }
book.ToList() List |> Seq.filter (fun (x: Contact) -> not (Seq.isEmpty x.Phones)) |> Seq.map ExtractUserInfo Contracts UserInfo, UserInfo |> Seq.sortBy(fun x -> x.DisplayName) |> Seq.toList List _contacts <- mutable _contacts |> Seq.map (fun x -> x.DisplayName.ToUpperInvariant())<- UserInfo string, - - |> Seq.toArray<- List Array ArrayAdapter
- List. .

Azure Mobile Servcies
- Azure Mobile Services. NotificationHub, Push . Azure , .. .
, 
module WruConstants = [<Literal>] let TotallyNotAzureServer = "https://YOUR.azure-mobile.net/"; [<Literal>] let TotallyNotAzureKey = "YOUR"
member this.RegisterMe phone name regId = async { try let table = this.MobileService.GetTable<User>() let usr = { Id = "" PhoneHash = MD5Hash phone Nickname = name RegistrationId = regId } do! table.InsertAsync usr |> Async.AwaitPlainTask return (usr.Id, usr.PhoneHash, usr.Nickname) with | e -> System.Diagnostics.Trace.WriteLine(e.ToString) return (String.Empty,String.Empty,String.Empty) }
member this.RegisterMe phone name regId = async { - ( ) . "computation expression" workflow. { } ! ( bang), do! (do-bang) let! (let bang) User. , F# ,
let usr = { Id = "" PhoneHash = MD5Hash phone Nickname = name RegistrationId = regId } do! table.InsertAsync usr |> Async.AwaitPlainTask do-bang, await C#. .. continuation . return (usr.Id, usr.PhoneHash, usr.Nickname) Tuple<string,string,string> . try ... with | e -> try..catch C#

. F# fst snd . 2 . :
let id (c,_,_) = c let phonehash (_,c,_) = c let nickname (_,_,c) = c
: id tuple Id ..
5 Azure, Push . Azure Custom Api
exports.post = function(request, response) { // Use "request.service" to access features of your mobile service, eg: // var tables = request.service.tables; // var push = request.service.push; //response.send(statusCodes.OK, { message : 'Hello World!' }); console.log('Incoming call with requst: ', request.body.RequestId); var usersTable = request.service.tables.getTable('User'); usersTable.where( { id : request.body.TargetId } ) .read( { success: function(results) { if (results.length > 0) { var user = results[0] console.log('Send to results: ', user.Nickname, user.RegistrationId); request.service.push.gcm.send(user.RegistrationId, { RequesterId: request.body.RequesterId, RequesterNickname: request.body.RequesterName, TargetId: user.id, TargetNickname: user.Nickname }, { success: function(gcm_response) { console.log('Push notification sent: ', gcm_response); response.send(statusCodes.OK, { RequestedNickname : user.Nickname }); }, error: function(gcm_error) { console.log('Error sending push notification: ', gcm_error); response.send(statusCodes.INTERNAL_SERVER_ERROR, { RequestedNickname : user.Nickname }); } }); } else { response.send(statusCodes.NO_CONTENT, { RequestedNickname : "" }); } }, error: function(error) { console.log('Error read table: ', error); response.send(statusCodes.INTERNAL_SERVER_ERROR, { RequestedNickname : "" }); } }); };
Push
// Perform Push operation member this.PushAsync targetId myId myNickname = async { try let (request : PushRequest) = { TargetId = targetId RequesterId = myId RequesterName = myNickname } let! result = this.MobileService.InvokeApiAsync<PushRequest, PushResponce>("pushhim", request) |> Async.AwaitTask return result.RequestedNickname with | e -> return e.ToString() }
, let-bang do!

Google Play Services. F# . . : Xamarin.Android.Support.v7.AppCompat
, Google Play Services , .
push notification . GCM, ID, ID Push (. pushhim). BroadcastReciever developer.android.com . F# Xamarin Component Store. Google Cloud Messaging Client GCM . ID
//Check to see that GCM is supported and that the manifest has the correct information GcmClient.CheckDevice(this) GcmClient.CheckManifest(this) // check google play if CheckPlayServices() then // Try to get registration id let regId = GcmClient.GetRegistrationId this if String.IsNullOrEmpty(regId) then // Call to Register the device for Push Notifications GcmClient.Register(this, WruConstants.GcmSender);

.
, -
bitbucket.org/xakpc/whereareyou
,
, "" .
, Android F#. .
, - Android F#. , .listView.Adapter <- new ArrayAdapter(this, Android.Resource.Layout.SimpleListItem1, Android.Resource.Id.Text1, values)
, , let values = [|"item1"; "item2"; "item3"|] - string[], list (IEnumerable )
F#. www.tryfsharp.org/Learn

F# - ,
F# For Fun And Profit
,
- .

hash
MD5 F#
let MD5Hash (input : string) = use md5 = System.Security.Cryptography.MD5.Create() input |> System.Text.Encoding.ASCII.GetBytes |> md5.ComputeHash |> Seq.map (fun c -> c.ToString("X2")) |> Seq.reduce (+)
|> pipeline , .
: GetBytes -> -> HEX -> ( reduce + ) -> .
, C# using System; public string CreateMD5Hash (string input) { MD5 md5 = System.Security.Cryptography.MD5.Create(); byte[] inputBytes = System.Text.Encoding.ASCII.GetBytes (input); byte[] hashBytes = md5.ComputeHash (inputBytes); StringBuilder sb = new StringBuilder(); for (int i = 0; i < hashBytes.Length; i++) { sb.Append (hashBytes[i].ToString ("X2")); } return sb.ToString(); }
: . AzureServiceWorker ( CLR )
- . F# ! Xamarin Studio .
<ItemGroup> <Compile Include="Resources\Resource.designer.fs" /> <Compile Include="Properties\AssemblyInfo.fs" /> <Compile Include="Helpers\Helpers.fs" /> <Compile Include="Services\User.fs" /> <Compile Include="Services\AzureServiceWorker.fs" /> <Compile Include="IAmHereActivity.fs" /> <Compile Include="WhereAreYouActivity.fs" /> <Compile Include="SignInActivity.fs" /> </ItemGroup>
: . Xamarin Xamarin.Mobile
. F# TPL, Task', . F# Task. , :
module Async = open System.Threading open System.Threading.Tasks let inline AwaitPlainTask (task: Task) = // rethrow exception from preceding task if it fauled let continuation (t : Task) : unit = match t.IsFaulted with | true -> raise t.Exception | arg -> () task.ContinueWith continuation |> Async.AwaitTask
Async.AwaitIAsyncResult >> Async.Ignore
let ExtractUserInfo (x : Contact) = let first = x.Phones |> Seq.tryPick(fun x -> if x.Type = PhoneType.Mobile then Some(x) else None) match first with | Some(first) -> let phone = first.Number |> StripChars [' ';'-';'(';')'] UserInfo.CreateUserInfo((MD5Hash phone), phone, x.DisplayName) | None -> UserInfo.CreateUserInfo("no mobile phone", "no mobile phone", "no mobile phone") // function for async list filling let FillContactsAsync = async { let book = new AddressBook (this) let! result = book.RequestPermission() |> Async.AwaitTask if result then _contacts <- book.ToList() |> Seq.filter (fun (x: Contact) -> not (Seq.isEmpty x.Phones)) |> Seq.map ExtractUserInfo |> Seq.sortBy(fun x -> x.DisplayName) |> Seq.toList let finalContacts = _contacts |> Seq.map (fun x -> x.DisplayName.ToUpperInvariant()) |> Seq.toArray this.ListAdapter <- new ArrayAdapter(this, Resource_Layout.row_contact, finalContacts) else System.Diagnostics.Debug.WriteLine("Permission denied by user or manifest") this.ListAdapter <- new ArrayAdapter(this, Resource_Layout.row_contact, Array.empty) }
book.ToList() List |> Seq.filter (fun (x: Contact) -> not (Seq.isEmpty x.Phones)) |> Seq.map ExtractUserInfo Contracts UserInfo, UserInfo |> Seq.sortBy(fun x -> x.DisplayName) |> Seq.toList List _contacts <- mutable _contacts |> Seq.map (fun x -> x.DisplayName.ToUpperInvariant())<- UserInfo string, - - |> Seq.toArray<- List Array ArrayAdapter
- List. .

Azure Mobile Servcies
- Azure Mobile Services. NotificationHub, Push . Azure , .. .
, 
module WruConstants = [<Literal>] let TotallyNotAzureServer = "https://YOUR.azure-mobile.net/"; [<Literal>] let TotallyNotAzureKey = "YOUR"
member this.RegisterMe phone name regId = async { try let table = this.MobileService.GetTable<User>() let usr = { Id = "" PhoneHash = MD5Hash phone Nickname = name RegistrationId = regId } do! table.InsertAsync usr |> Async.AwaitPlainTask return (usr.Id, usr.PhoneHash, usr.Nickname) with | e -> System.Diagnostics.Trace.WriteLine(e.ToString) return (String.Empty,String.Empty,String.Empty) }
member this.RegisterMe phone name regId = async { - ( ) . "computation expression" workflow. { } ! ( bang), do! (do-bang) let! (let bang) User. , F# ,
let usr = { Id = "" PhoneHash = MD5Hash phone Nickname = name RegistrationId = regId } do! table.InsertAsync usr |> Async.AwaitPlainTask do-bang, await C#. .. continuation . return (usr.Id, usr.PhoneHash, usr.Nickname) Tuple<string,string,string> . try ... with | e -> try..catch C#

. F# fst snd . 2 . :
let id (c,_,_) = c let phonehash (_,c,_) = c let nickname (_,_,c) = c
: id tuple Id ..
5 Azure, Push . Azure Custom Api
exports.post = function(request, response) { // Use "request.service" to access features of your mobile service, eg: // var tables = request.service.tables; // var push = request.service.push; //response.send(statusCodes.OK, { message : 'Hello World!' }); console.log('Incoming call with requst: ', request.body.RequestId); var usersTable = request.service.tables.getTable('User'); usersTable.where( { id : request.body.TargetId } ) .read( { success: function(results) { if (results.length > 0) { var user = results[0] console.log('Send to results: ', user.Nickname, user.RegistrationId); request.service.push.gcm.send(user.RegistrationId, { RequesterId: request.body.RequesterId, RequesterNickname: request.body.RequesterName, TargetId: user.id, TargetNickname: user.Nickname }, { success: function(gcm_response) { console.log('Push notification sent: ', gcm_response); response.send(statusCodes.OK, { RequestedNickname : user.Nickname }); }, error: function(gcm_error) { console.log('Error sending push notification: ', gcm_error); response.send(statusCodes.INTERNAL_SERVER_ERROR, { RequestedNickname : user.Nickname }); } }); } else { response.send(statusCodes.NO_CONTENT, { RequestedNickname : "" }); } }, error: function(error) { console.log('Error read table: ', error); response.send(statusCodes.INTERNAL_SERVER_ERROR, { RequestedNickname : "" }); } }); };
Push
// Perform Push operation member this.PushAsync targetId myId myNickname = async { try let (request : PushRequest) = { TargetId = targetId RequesterId = myId RequesterName = myNickname } let! result = this.MobileService.InvokeApiAsync<PushRequest, PushResponce>("pushhim", request) |> Async.AwaitTask return result.RequestedNickname with | e -> return e.ToString() }
, let-bang do!

Google Play Services. F# . . : Xamarin.Android.Support.v7.AppCompat
, Google Play Services , .
push notification . GCM, ID, ID Push (. pushhim). BroadcastReciever developer.android.com . F# Xamarin Component Store. Google Cloud Messaging Client GCM . ID
//Check to see that GCM is supported and that the manifest has the correct information GcmClient.CheckDevice(this) GcmClient.CheckManifest(this) // check google play if CheckPlayServices() then // Try to get registration id let regId = GcmClient.GetRegistrationId this if String.IsNullOrEmpty(regId) then // Call to Register the device for Push Notifications GcmClient.Register(this, WruConstants.GcmSender);

.
, -
bitbucket.org/xakpc/whereareyou
,
, "" .
, Android F#. .
, - Android F#. , .listView.Adapter <- new ArrayAdapter(this, Android.Resource.Layout.SimpleListItem1, Android.Resource.Id.Text1, values)
, , let values = [|"item1"; "item2"; "item3"|] - string[], list (IEnumerable )
F#. www.tryfsharp.org/Learn

F# - ,
F# For Fun And Profit
,
- .

hash
MD5 F#
let MD5Hash (input : string) = use md5 = System.Security.Cryptography.MD5.Create() input |> System.Text.Encoding.ASCII.GetBytes |> md5.ComputeHash |> Seq.map (fun c -> c.ToString("X2")) |> Seq.reduce (+)
|> pipeline , .
: GetBytes -> -> HEX -> ( reduce + ) -> .
, C# using System; public string CreateMD5Hash (string input) { MD5 md5 = System.Security.Cryptography.MD5.Create(); byte[] inputBytes = System.Text.Encoding.ASCII.GetBytes (input); byte[] hashBytes = md5.ComputeHash (inputBytes); StringBuilder sb = new StringBuilder(); for (int i = 0; i < hashBytes.Length; i++) { sb.Append (hashBytes[i].ToString ("X2")); } return sb.ToString(); }
: . AzureServiceWorker ( CLR )
- . F# ! Xamarin Studio .
<ItemGroup> <Compile Include="Resources\Resource.designer.fs" /> <Compile Include="Properties\AssemblyInfo.fs" /> <Compile Include="Helpers\Helpers.fs" /> <Compile Include="Services\User.fs" /> <Compile Include="Services\AzureServiceWorker.fs" /> <Compile Include="IAmHereActivity.fs" /> <Compile Include="WhereAreYouActivity.fs" /> <Compile Include="SignInActivity.fs" /> </ItemGroup>
: . Xamarin Xamarin.Mobile
. F# TPL, Task', . F# Task. , :
module Async = open System.Threading open System.Threading.Tasks let inline AwaitPlainTask (task: Task) = // rethrow exception from preceding task if it fauled let continuation (t : Task) : unit = match t.IsFaulted with | true -> raise t.Exception | arg -> () task.ContinueWith continuation |> Async.AwaitTask
Async.AwaitIAsyncResult >> Async.Ignore
let ExtractUserInfo (x : Contact) = let first = x.Phones |> Seq.tryPick(fun x -> if x.Type = PhoneType.Mobile then Some(x) else None) match first with | Some(first) -> let phone = first.Number |> StripChars [' ';'-';'(';')'] UserInfo.CreateUserInfo((MD5Hash phone), phone, x.DisplayName) | None -> UserInfo.CreateUserInfo("no mobile phone", "no mobile phone", "no mobile phone") // function for async list filling let FillContactsAsync = async { let book = new AddressBook (this) let! result = book.RequestPermission() |> Async.AwaitTask if result then _contacts <- book.ToList() |> Seq.filter (fun (x: Contact) -> not (Seq.isEmpty x.Phones)) |> Seq.map ExtractUserInfo |> Seq.sortBy(fun x -> x.DisplayName) |> Seq.toList let finalContacts = _contacts |> Seq.map (fun x -> x.DisplayName.ToUpperInvariant()) |> Seq.toArray this.ListAdapter <- new ArrayAdapter(this, Resource_Layout.row_contact, finalContacts) else System.Diagnostics.Debug.WriteLine("Permission denied by user or manifest") this.ListAdapter <- new ArrayAdapter(this, Resource_Layout.row_contact, Array.empty) }
book.ToList() List |> Seq.filter (fun (x: Contact) -> not (Seq.isEmpty x.Phones)) |> Seq.map ExtractUserInfo Contracts UserInfo, UserInfo |> Seq.sortBy(fun x -> x.DisplayName) |> Seq.toList List _contacts <- mutable _contacts |> Seq.map (fun x -> x.DisplayName.ToUpperInvariant())<- UserInfo string, - - |> Seq.toArray<- List Array ArrayAdapter
- List. .

Azure Mobile Servcies
- Azure Mobile Services. NotificationHub, Push . Azure , .. .
, 
module WruConstants = [<Literal>] let TotallyNotAzureServer = "https://YOUR.azure-mobile.net/"; [<Literal>] let TotallyNotAzureKey = "YOUR"
member this.RegisterMe phone name regId = async { try let table = this.MobileService.GetTable<User>() let usr = { Id = "" PhoneHash = MD5Hash phone Nickname = name RegistrationId = regId } do! table.InsertAsync usr |> Async.AwaitPlainTask return (usr.Id, usr.PhoneHash, usr.Nickname) with | e -> System.Diagnostics.Trace.WriteLine(e.ToString) return (String.Empty,String.Empty,String.Empty) }
member this.RegisterMe phone name regId = async { - ( ) . "computation expression" workflow. { } ! ( bang), do! (do-bang) let! (let bang) User. , F# ,
let usr = { Id = "" PhoneHash = MD5Hash phone Nickname = name RegistrationId = regId } do! table.InsertAsync usr |> Async.AwaitPlainTask do-bang, await C#. .. continuation . return (usr.Id, usr.PhoneHash, usr.Nickname) Tuple<string,string,string> . try ... with | e -> try..catch C#

. F# fst snd . 2 . :
let id (c,_,_) = c let phonehash (_,c,_) = c let nickname (_,_,c) = c
: id tuple Id ..
5 Azure, Push . Azure Custom Api
exports.post = function(request, response) { // Use "request.service" to access features of your mobile service, eg: // var tables = request.service.tables; // var push = request.service.push; //response.send(statusCodes.OK, { message : 'Hello World!' }); console.log('Incoming call with requst: ', request.body.RequestId); var usersTable = request.service.tables.getTable('User'); usersTable.where( { id : request.body.TargetId } ) .read( { success: function(results) { if (results.length > 0) { var user = results[0] console.log('Send to results: ', user.Nickname, user.RegistrationId); request.service.push.gcm.send(user.RegistrationId, { RequesterId: request.body.RequesterId, RequesterNickname: request.body.RequesterName, TargetId: user.id, TargetNickname: user.Nickname }, { success: function(gcm_response) { console.log('Push notification sent: ', gcm_response); response.send(statusCodes.OK, { RequestedNickname : user.Nickname }); }, error: function(gcm_error) { console.log('Error sending push notification: ', gcm_error); response.send(statusCodes.INTERNAL_SERVER_ERROR, { RequestedNickname : user.Nickname }); } }); } else { response.send(statusCodes.NO_CONTENT, { RequestedNickname : "" }); } }, error: function(error) { console.log('Error read table: ', error); response.send(statusCodes.INTERNAL_SERVER_ERROR, { RequestedNickname : "" }); } }); };
Push
// Perform Push operation member this.PushAsync targetId myId myNickname = async { try let (request : PushRequest) = { TargetId = targetId RequesterId = myId RequesterName = myNickname } let! result = this.MobileService.InvokeApiAsync<PushRequest, PushResponce>("pushhim", request) |> Async.AwaitTask return result.RequestedNickname with | e -> return e.ToString() }
, let-bang do!

Google Play Services. F# . . : Xamarin.Android.Support.v7.AppCompat
, Google Play Services , .
push notification . GCM, ID, ID Push (. pushhim). BroadcastReciever developer.android.com . F# Xamarin Component Store. Google Cloud Messaging Client GCM . ID
//Check to see that GCM is supported and that the manifest has the correct information GcmClient.CheckDevice(this) GcmClient.CheckManifest(this) // check google play if CheckPlayServices() then // Try to get registration id let regId = GcmClient.GetRegistrationId this if String.IsNullOrEmpty(regId) then // Call to Register the device for Push Notifications GcmClient.Register(this, WruConstants.GcmSender);

.
, -
bitbucket.org/xakpc/whereareyou
,
, "" .
, Android F#. .
, - Android F#. , .listView.Adapter <- new ArrayAdapter(this, Android.Resource.Layout.SimpleListItem1, Android.Resource.Id.Text1, values)
, , let values = [|"item1"; "item2"; "item3"|] - string[], list (IEnumerable )
F#. www.tryfsharp.org/Learn

F# - ,
F# For Fun And Profit
,
- .

hash
MD5 F#
let MD5Hash (input : string) = use md5 = System.Security.Cryptography.MD5.Create() input |> System.Text.Encoding.ASCII.GetBytes |> md5.ComputeHash |> Seq.map (fun c -> c.ToString("X2")) |> Seq.reduce (+)
|> pipeline , .
: GetBytes -> -> HEX -> ( reduce + ) -> .
, C# using System; public string CreateMD5Hash (string input) { MD5 md5 = System.Security.Cryptography.MD5.Create(); byte[] inputBytes = System.Text.Encoding.ASCII.GetBytes (input); byte[] hashBytes = md5.ComputeHash (inputBytes); StringBuilder sb = new StringBuilder(); for (int i = 0; i < hashBytes.Length; i++) { sb.Append (hashBytes[i].ToString ("X2")); } return sb.ToString(); }
: . AzureServiceWorker ( CLR )
- . F# ! Xamarin Studio .
<ItemGroup> <Compile Include="Resources\Resource.designer.fs" /> <Compile Include="Properties\AssemblyInfo.fs" /> <Compile Include="Helpers\Helpers.fs" /> <Compile Include="Services\User.fs" /> <Compile Include="Services\AzureServiceWorker.fs" /> <Compile Include="IAmHereActivity.fs" /> <Compile Include="WhereAreYouActivity.fs" /> <Compile Include="SignInActivity.fs" /> </ItemGroup>
: . Xamarin Xamarin.Mobile
. F# TPL, Task', . F# Task. , :
module Async = open System.Threading open System.Threading.Tasks let inline AwaitPlainTask (task: Task) = // rethrow exception from preceding task if it fauled let continuation (t : Task) : unit = match t.IsFaulted with | true -> raise t.Exception | arg -> () task.ContinueWith continuation |> Async.AwaitTask
Async.AwaitIAsyncResult >> Async.Ignore
let ExtractUserInfo (x : Contact) = let first = x.Phones |> Seq.tryPick(fun x -> if x.Type = PhoneType.Mobile then Some(x) else None) match first with | Some(first) -> let phone = first.Number |> StripChars [' ';'-';'(';')'] UserInfo.CreateUserInfo((MD5Hash phone), phone, x.DisplayName) | None -> UserInfo.CreateUserInfo("no mobile phone", "no mobile phone", "no mobile phone") // function for async list filling let FillContactsAsync = async { let book = new AddressBook (this) let! result = book.RequestPermission() |> Async.AwaitTask if result then _contacts <- book.ToList() |> Seq.filter (fun (x: Contact) -> not (Seq.isEmpty x.Phones)) |> Seq.map ExtractUserInfo |> Seq.sortBy(fun x -> x.DisplayName) |> Seq.toList let finalContacts = _contacts |> Seq.map (fun x -> x.DisplayName.ToUpperInvariant()) |> Seq.toArray this.ListAdapter <- new ArrayAdapter(this, Resource_Layout.row_contact, finalContacts) else System.Diagnostics.Debug.WriteLine("Permission denied by user or manifest") this.ListAdapter <- new ArrayAdapter(this, Resource_Layout.row_contact, Array.empty) }
book.ToList() List |> Seq.filter (fun (x: Contact) -> not (Seq.isEmpty x.Phones)) |> Seq.map ExtractUserInfo Contracts UserInfo, UserInfo |> Seq.sortBy(fun x -> x.DisplayName) |> Seq.toList List _contacts <- mutable _contacts |> Seq.map (fun x -> x.DisplayName.ToUpperInvariant())<- UserInfo string, - - |> Seq.toArray<- List Array ArrayAdapter
- List. .

Azure Mobile Servcies
- Azure Mobile Services. NotificationHub, Push . Azure , .. .
, 
module WruConstants = [<Literal>] let TotallyNotAzureServer = "https://YOUR.azure-mobile.net/"; [<Literal>] let TotallyNotAzureKey = "YOUR"
member this.RegisterMe phone name regId = async { try let table = this.MobileService.GetTable<User>() let usr = { Id = "" PhoneHash = MD5Hash phone Nickname = name RegistrationId = regId } do! table.InsertAsync usr |> Async.AwaitPlainTask return (usr.Id, usr.PhoneHash, usr.Nickname) with | e -> System.Diagnostics.Trace.WriteLine(e.ToString) return (String.Empty,String.Empty,String.Empty) }
member this.RegisterMe phone name regId = async { - ( ) . "computation expression" workflow. { } ! ( bang), do! (do-bang) let! (let bang) User. , F# ,
let usr = { Id = "" PhoneHash = MD5Hash phone Nickname = name RegistrationId = regId } do! table.InsertAsync usr |> Async.AwaitPlainTask do-bang, await C#. .. continuation . return (usr.Id, usr.PhoneHash, usr.Nickname) Tuple<string,string,string> . try ... with | e -> try..catch C#

. F# fst snd . 2 . :
let id (c,_,_) = c let phonehash (_,c,_) = c let nickname (_,_,c) = c
: id tuple Id ..
5 Azure, Push . Azure Custom Api
exports.post = function(request, response) { // Use "request.service" to access features of your mobile service, eg: // var tables = request.service.tables; // var push = request.service.push; //response.send(statusCodes.OK, { message : 'Hello World!' }); console.log('Incoming call with requst: ', request.body.RequestId); var usersTable = request.service.tables.getTable('User'); usersTable.where( { id : request.body.TargetId } ) .read( { success: function(results) { if (results.length > 0) { var user = results[0] console.log('Send to results: ', user.Nickname, user.RegistrationId); request.service.push.gcm.send(user.RegistrationId, { RequesterId: request.body.RequesterId, RequesterNickname: request.body.RequesterName, TargetId: user.id, TargetNickname: user.Nickname }, { success: function(gcm_response) { console.log('Push notification sent: ', gcm_response); response.send(statusCodes.OK, { RequestedNickname : user.Nickname }); }, error: function(gcm_error) { console.log('Error sending push notification: ', gcm_error); response.send(statusCodes.INTERNAL_SERVER_ERROR, { RequestedNickname : user.Nickname }); } }); } else { response.send(statusCodes.NO_CONTENT, { RequestedNickname : "" }); } }, error: function(error) { console.log('Error read table: ', error); response.send(statusCodes.INTERNAL_SERVER_ERROR, { RequestedNickname : "" }); } }); };
Push
// Perform Push operation member this.PushAsync targetId myId myNickname = async { try let (request : PushRequest) = { TargetId = targetId RequesterId = myId RequesterName = myNickname } let! result = this.MobileService.InvokeApiAsync<PushRequest, PushResponce>("pushhim", request) |> Async.AwaitTask return result.RequestedNickname with | e -> return e.ToString() }
, let-bang do!

Google Play Services. F# . . : Xamarin.Android.Support.v7.AppCompat
, Google Play Services , .
push notification . GCM, ID, ID Push (. pushhim). BroadcastReciever developer.android.com . F# Xamarin Component Store. Google Cloud Messaging Client GCM . ID
//Check to see that GCM is supported and that the manifest has the correct information GcmClient.CheckDevice(this) GcmClient.CheckManifest(this) // check google play if CheckPlayServices() then // Try to get registration id let regId = GcmClient.GetRegistrationId this if String.IsNullOrEmpty(regId) then // Call to Register the device for Push Notifications GcmClient.Register(this, WruConstants.GcmSender);

.
, -
bitbucket.org/xakpc/whereareyou
,
, "" .
, Android F#. .
, - Android F#. , .listView.Adapter <- new ArrayAdapter(this, Android.Resource.Layout.SimpleListItem1, Android.Resource.Id.Text1, values)
, , let values = [|"item1"; "item2"; "item3"|] - string[], list (IEnumerable )
F#. www.tryfsharp.org/Learn

F# - ,
F# For Fun And Profit
,
- .

hash
MD5 F#
let MD5Hash (input : string) = use md5 = System.Security.Cryptography.MD5.Create() input |> System.Text.Encoding.ASCII.GetBytes |> md5.ComputeHash |> Seq.map (fun c -> c.ToString("X2")) |> Seq.reduce (+)
|> pipeline , .
: GetBytes -> -> HEX -> ( reduce + ) -> .
, C# using System; public string CreateMD5Hash (string input) { MD5 md5 = System.Security.Cryptography.MD5.Create(); byte[] inputBytes = System.Text.Encoding.ASCII.GetBytes (input); byte[] hashBytes = md5.ComputeHash (inputBytes); StringBuilder sb = new StringBuilder(); for (int i = 0; i < hashBytes.Length; i++) { sb.Append (hashBytes[i].ToString ("X2")); } return sb.ToString(); }
: . AzureServiceWorker ( CLR )
- . F# ! Xamarin Studio .
<ItemGroup> <Compile Include="Resources\Resource.designer.fs" /> <Compile Include="Properties\AssemblyInfo.fs" /> <Compile Include="Helpers\Helpers.fs" /> <Compile Include="Services\User.fs" /> <Compile Include="Services\AzureServiceWorker.fs" /> <Compile Include="IAmHereActivity.fs" /> <Compile Include="WhereAreYouActivity.fs" /> <Compile Include="SignInActivity.fs" /> </ItemGroup>
: . Xamarin Xamarin.Mobile
. F# TPL, Task', . F# Task. , :
module Async = open System.Threading open System.Threading.Tasks let inline AwaitPlainTask (task: Task) = // rethrow exception from preceding task if it fauled let continuation (t : Task) : unit = match t.IsFaulted with | true -> raise t.Exception | arg -> () task.ContinueWith continuation |> Async.AwaitTask
Async.AwaitIAsyncResult >> Async.Ignore
let ExtractUserInfo (x : Contact) = let first = x.Phones |> Seq.tryPick(fun x -> if x.Type = PhoneType.Mobile then Some(x) else None) match first with | Some(first) -> let phone = first.Number |> StripChars [' ';'-';'(';')'] UserInfo.CreateUserInfo((MD5Hash phone), phone, x.DisplayName) | None -> UserInfo.CreateUserInfo("no mobile phone", "no mobile phone", "no mobile phone") // function for async list filling let FillContactsAsync = async { let book = new AddressBook (this) let! result = book.RequestPermission() |> Async.AwaitTask if result then _contacts <- book.ToList() |> Seq.filter (fun (x: Contact) -> not (Seq.isEmpty x.Phones)) |> Seq.map ExtractUserInfo |> Seq.sortBy(fun x -> x.DisplayName) |> Seq.toList let finalContacts = _contacts |> Seq.map (fun x -> x.DisplayName.ToUpperInvariant()) |> Seq.toArray this.ListAdapter <- new ArrayAdapter(this, Resource_Layout.row_contact, finalContacts) else System.Diagnostics.Debug.WriteLine("Permission denied by user or manifest") this.ListAdapter <- new ArrayAdapter(this, Resource_Layout.row_contact, Array.empty) }
book.ToList() List |> Seq.filter (fun (x: Contact) -> not (Seq.isEmpty x.Phones)) |> Seq.map ExtractUserInfo Contracts UserInfo, UserInfo |> Seq.sortBy(fun x -> x.DisplayName) |> Seq.toList List _contacts <- mutable _contacts |> Seq.map (fun x -> x.DisplayName.ToUpperInvariant())<- UserInfo string, - - |> Seq.toArray<- List Array ArrayAdapter
- List. .

Azure Mobile Servcies
- Azure Mobile Services. NotificationHub, Push . Azure , .. .
, 
module WruConstants = [<Literal>] let TotallyNotAzureServer = "https://YOUR.azure-mobile.net/"; [<Literal>] let TotallyNotAzureKey = "YOUR"
member this.RegisterMe phone name regId = async { try let table = this.MobileService.GetTable<User>() let usr = { Id = "" PhoneHash = MD5Hash phone Nickname = name RegistrationId = regId } do! table.InsertAsync usr |> Async.AwaitPlainTask return (usr.Id, usr.PhoneHash, usr.Nickname) with | e -> System.Diagnostics.Trace.WriteLine(e.ToString) return (String.Empty,String.Empty,String.Empty) }
member this.RegisterMe phone name regId = async { - ( ) . "computation expression" workflow. { } ! ( bang), do! (do-bang) let! (let bang) User. , F# ,
let usr = { Id = "" PhoneHash = MD5Hash phone Nickname = name RegistrationId = regId } do! table.InsertAsync usr |> Async.AwaitPlainTask do-bang, await C#. .. continuation . return (usr.Id, usr.PhoneHash, usr.Nickname) Tuple<string,string,string> . try ... with | e -> try..catch C#

. F# fst snd . 2 . :
let id (c,_,_) = c let phonehash (_,c,_) = c let nickname (_,_,c) = c
: id tuple Id ..
5 Azure, Push . Azure Custom Api
exports.post = function(request, response) { // Use "request.service" to access features of your mobile service, eg: // var tables = request.service.tables; // var push = request.service.push; //response.send(statusCodes.OK, { message : 'Hello World!' }); console.log('Incoming call with requst: ', request.body.RequestId); var usersTable = request.service.tables.getTable('User'); usersTable.where( { id : request.body.TargetId } ) .read( { success: function(results) { if (results.length > 0) { var user = results[0] console.log('Send to results: ', user.Nickname, user.RegistrationId); request.service.push.gcm.send(user.RegistrationId, { RequesterId: request.body.RequesterId, RequesterNickname: request.body.RequesterName, TargetId: user.id, TargetNickname: user.Nickname }, { success: function(gcm_response) { console.log('Push notification sent: ', gcm_response); response.send(statusCodes.OK, { RequestedNickname : user.Nickname }); }, error: function(gcm_error) { console.log('Error sending push notification: ', gcm_error); response.send(statusCodes.INTERNAL_SERVER_ERROR, { RequestedNickname : user.Nickname }); } }); } else { response.send(statusCodes.NO_CONTENT, { RequestedNickname : "" }); } }, error: function(error) { console.log('Error read table: ', error); response.send(statusCodes.INTERNAL_SERVER_ERROR, { RequestedNickname : "" }); } }); };
Push
// Perform Push operation member this.PushAsync targetId myId myNickname = async { try let (request : PushRequest) = { TargetId = targetId RequesterId = myId RequesterName = myNickname } let! result = this.MobileService.InvokeApiAsync<PushRequest, PushResponce>("pushhim", request) |> Async.AwaitTask return result.RequestedNickname with | e -> return e.ToString() }
, let-bang do!

Google Play Services. F# . . : Xamarin.Android.Support.v7.AppCompat
, Google Play Services , .
push notification . GCM, ID, ID Push (. pushhim). BroadcastReciever developer.android.com . F# Xamarin Component Store. Google Cloud Messaging Client GCM . ID
//Check to see that GCM is supported and that the manifest has the correct information GcmClient.CheckDevice(this) GcmClient.CheckManifest(this) // check google play if CheckPlayServices() then // Try to get registration id let regId = GcmClient.GetRegistrationId this if String.IsNullOrEmpty(regId) then // Call to Register the device for Push Notifications GcmClient.Register(this, WruConstants.GcmSender);

.
, -
bitbucket.org/xakpc/whereareyou
,
, "" .
, Android F#. .
, - Android F#. , .listView.Adapter <- new ArrayAdapter(this, Android.Resource.Layout.SimpleListItem1, Android.Resource.Id.Text1, values)
, , let values = [|"item1"; "item2"; "item3"|] - string[], list (IEnumerable )
F#. www.tryfsharp.org/Learn

F# - ,
F# For Fun And Profit
,
- .

hash
MD5 F#
let MD5Hash (input : string) = use md5 = System.Security.Cryptography.MD5.Create() input |> System.Text.Encoding.ASCII.GetBytes |> md5.ComputeHash |> Seq.map (fun c -> c.ToString("X2")) |> Seq.reduce (+)
|> pipeline , .
: GetBytes -> -> HEX -> ( reduce + ) -> .
, C# using System; public string CreateMD5Hash (string input) { MD5 md5 = System.Security.Cryptography.MD5.Create(); byte[] inputBytes = System.Text.Encoding.ASCII.GetBytes (input); byte[] hashBytes = md5.ComputeHash (inputBytes); StringBuilder sb = new StringBuilder(); for (int i = 0; i < hashBytes.Length; i++) { sb.Append (hashBytes[i].ToString ("X2")); } return sb.ToString(); }
: . AzureServiceWorker ( CLR )
- . F# ! Xamarin Studio .
<ItemGroup> <Compile Include="Resources\Resource.designer.fs" /> <Compile Include="Properties\AssemblyInfo.fs" /> <Compile Include="Helpers\Helpers.fs" /> <Compile Include="Services\User.fs" /> <Compile Include="Services\AzureServiceWorker.fs" /> <Compile Include="IAmHereActivity.fs" /> <Compile Include="WhereAreYouActivity.fs" /> <Compile Include="SignInActivity.fs" /> </ItemGroup>
: . Xamarin Xamarin.Mobile
. F# TPL, Task', . F# Task. , :
module Async = open System.Threading open System.Threading.Tasks let inline AwaitPlainTask (task: Task) = // rethrow exception from preceding task if it fauled let continuation (t : Task) : unit = match t.IsFaulted with | true -> raise t.Exception | arg -> () task.ContinueWith continuation |> Async.AwaitTask
Async.AwaitIAsyncResult >> Async.Ignore
let ExtractUserInfo (x : Contact) = let first = x.Phones |> Seq.tryPick(fun x -> if x.Type = PhoneType.Mobile then Some(x) else None) match first with | Some(first) -> let phone = first.Number |> StripChars [' ';'-';'(';')'] UserInfo.CreateUserInfo((MD5Hash phone), phone, x.DisplayName) | None -> UserInfo.CreateUserInfo("no mobile phone", "no mobile phone", "no mobile phone") // function for async list filling let FillContactsAsync = async { let book = new AddressBook (this) let! result = book.RequestPermission() |> Async.AwaitTask if result then _contacts <- book.ToList() |> Seq.filter (fun (x: Contact) -> not (Seq.isEmpty x.Phones)) |> Seq.map ExtractUserInfo |> Seq.sortBy(fun x -> x.DisplayName) |> Seq.toList let finalContacts = _contacts |> Seq.map (fun x -> x.DisplayName.ToUpperInvariant()) |> Seq.toArray this.ListAdapter <- new ArrayAdapter(this, Resource_Layout.row_contact, finalContacts) else System.Diagnostics.Debug.WriteLine("Permission denied by user or manifest") this.ListAdapter <- new ArrayAdapter(this, Resource_Layout.row_contact, Array.empty) }
book.ToList() List |> Seq.filter (fun (x: Contact) -> not (Seq.isEmpty x.Phones)) |> Seq.map ExtractUserInfo Contracts UserInfo, UserInfo |> Seq.sortBy(fun x -> x.DisplayName) |> Seq.toList List _contacts <- mutable _contacts |> Seq.map (fun x -> x.DisplayName.ToUpperInvariant())<- UserInfo string, - - |> Seq.toArray<- List Array ArrayAdapter
- List. .

Azure Mobile Servcies
- Azure Mobile Services. NotificationHub, Push . Azure , .. .
, 
module WruConstants = [<Literal>] let TotallyNotAzureServer = "https://YOUR.azure-mobile.net/"; [<Literal>] let TotallyNotAzureKey = "YOUR"
member this.RegisterMe phone name regId = async { try let table = this.MobileService.GetTable<User>() let usr = { Id = "" PhoneHash = MD5Hash phone Nickname = name RegistrationId = regId } do! table.InsertAsync usr |> Async.AwaitPlainTask return (usr.Id, usr.PhoneHash, usr.Nickname) with | e -> System.Diagnostics.Trace.WriteLine(e.ToString) return (String.Empty,String.Empty,String.Empty) }
member this.RegisterMe phone name regId = async { - ( ) . "computation expression" workflow. { } ! ( bang), do! (do-bang) let! (let bang) User. , F# ,
let usr = { Id = "" PhoneHash = MD5Hash phone Nickname = name RegistrationId = regId } do! table.InsertAsync usr |> Async.AwaitPlainTask do-bang, await C#. .. continuation . return (usr.Id, usr.PhoneHash, usr.Nickname) Tuple<string,string,string> . try ... with | e -> try..catch C#

. F# fst snd . 2 . :
let id (c,_,_) = c let phonehash (_,c,_) = c let nickname (_,_,c) = c
: id tuple Id ..
5 Azure, Push . Azure Custom Api
exports.post = function(request, response) { // Use "request.service" to access features of your mobile service, eg: // var tables = request.service.tables; // var push = request.service.push; //response.send(statusCodes.OK, { message : 'Hello World!' }); console.log('Incoming call with requst: ', request.body.RequestId); var usersTable = request.service.tables.getTable('User'); usersTable.where( { id : request.body.TargetId } ) .read( { success: function(results) { if (results.length > 0) { var user = results[0] console.log('Send to results: ', user.Nickname, user.RegistrationId); request.service.push.gcm.send(user.RegistrationId, { RequesterId: request.body.RequesterId, RequesterNickname: request.body.RequesterName, TargetId: user.id, TargetNickname: user.Nickname }, { success: function(gcm_response) { console.log('Push notification sent: ', gcm_response); response.send(statusCodes.OK, { RequestedNickname : user.Nickname }); }, error: function(gcm_error) { console.log('Error sending push notification: ', gcm_error); response.send(statusCodes.INTERNAL_SERVER_ERROR, { RequestedNickname : user.Nickname }); } }); } else { response.send(statusCodes.NO_CONTENT, { RequestedNickname : "" }); } }, error: function(error) { console.log('Error read table: ', error); response.send(statusCodes.INTERNAL_SERVER_ERROR, { RequestedNickname : "" }); } }); };
Push
// Perform Push operation member this.PushAsync targetId myId myNickname = async { try let (request : PushRequest) = { TargetId = targetId RequesterId = myId RequesterName = myNickname } let! result = this.MobileService.InvokeApiAsync<PushRequest, PushResponce>("pushhim", request) |> Async.AwaitTask return result.RequestedNickname with | e -> return e.ToString() }
, let-bang do!

Google Play Services. F# . . : Xamarin.Android.Support.v7.AppCompat
, Google Play Services , .
push notification . GCM, ID, ID Push (. pushhim). BroadcastReciever developer.android.com . F# Xamarin Component Store. Google Cloud Messaging Client GCM . ID
//Check to see that GCM is supported and that the manifest has the correct information GcmClient.CheckDevice(this) GcmClient.CheckManifest(this) // check google play if CheckPlayServices() then // Try to get registration id let regId = GcmClient.GetRegistrationId this if String.IsNullOrEmpty(regId) then // Call to Register the device for Push Notifications GcmClient.Register(this, WruConstants.GcmSender);

.
, -
bitbucket.org/xakpc/whereareyou
,
, "" .
, Android F#. .
, - Android F#. , .listView.Adapter <- new ArrayAdapter(this, Android.Resource.Layout.SimpleListItem1, Android.Resource.Id.Text1, values)
, , let values = [|"item1"; "item2"; "item3"|] - string[], list (IEnumerable )
F#. www.tryfsharp.org/Learn

F# - ,
F# For Fun And Profit
,
- .

hash
MD5 F#
let MD5Hash (input : string) = use md5 = System.Security.Cryptography.MD5.Create() input |> System.Text.Encoding.ASCII.GetBytes |> md5.ComputeHash |> Seq.map (fun c -> c.ToString("X2")) |> Seq.reduce (+)
|> pipeline , .
: GetBytes -> -> HEX -> ( reduce + ) -> .
, C# using System; public string CreateMD5Hash (string input) { MD5 md5 = System.Security.Cryptography.MD5.Create(); byte[] inputBytes = System.Text.Encoding.ASCII.GetBytes (input); byte[] hashBytes = md5.ComputeHash (inputBytes); StringBuilder sb = new StringBuilder(); for (int i = 0; i < hashBytes.Length; i++) { sb.Append (hashBytes[i].ToString ("X2")); } return sb.ToString(); }
: . AzureServiceWorker ( CLR )
- . F# ! Xamarin Studio .
<ItemGroup> <Compile Include="Resources\Resource.designer.fs" /> <Compile Include="Properties\AssemblyInfo.fs" /> <Compile Include="Helpers\Helpers.fs" /> <Compile Include="Services\User.fs" /> <Compile Include="Services\AzureServiceWorker.fs" /> <Compile Include="IAmHereActivity.fs" /> <Compile Include="WhereAreYouActivity.fs" /> <Compile Include="SignInActivity.fs" /> </ItemGroup>
: . Xamarin Xamarin.Mobile
. F# TPL, Task', . F# Task. , :
module Async = open System.Threading open System.Threading.Tasks let inline AwaitPlainTask (task: Task) = // rethrow exception from preceding task if it fauled let continuation (t : Task) : unit = match t.IsFaulted with | true -> raise t.Exception | arg -> () task.ContinueWith continuation |> Async.AwaitTask
Async.AwaitIAsyncResult >> Async.Ignore
let ExtractUserInfo (x : Contact) = let first = x.Phones |> Seq.tryPick(fun x -> if x.Type = PhoneType.Mobile then Some(x) else None) match first with | Some(first) -> let phone = first.Number |> StripChars [' ';'-';'(';')'] UserInfo.CreateUserInfo((MD5Hash phone), phone, x.DisplayName) | None -> UserInfo.CreateUserInfo("no mobile phone", "no mobile phone", "no mobile phone") // function for async list filling let FillContactsAsync = async { let book = new AddressBook (this) let! result = book.RequestPermission() |> Async.AwaitTask if result then _contacts <- book.ToList() |> Seq.filter (fun (x: Contact) -> not (Seq.isEmpty x.Phones)) |> Seq.map ExtractUserInfo |> Seq.sortBy(fun x -> x.DisplayName) |> Seq.toList let finalContacts = _contacts |> Seq.map (fun x -> x.DisplayName.ToUpperInvariant()) |> Seq.toArray this.ListAdapter <- new ArrayAdapter(this, Resource_Layout.row_contact, finalContacts) else System.Diagnostics.Debug.WriteLine("Permission denied by user or manifest") this.ListAdapter <- new ArrayAdapter(this, Resource_Layout.row_contact, Array.empty) }
book.ToList() List |> Seq.filter (fun (x: Contact) -> not (Seq.isEmpty x.Phones)) |> Seq.map ExtractUserInfo Contracts UserInfo, UserInfo |> Seq.sortBy(fun x -> x.DisplayName) |> Seq.toList List _contacts <- mutable _contacts |> Seq.map (fun x -> x.DisplayName.ToUpperInvariant())<- UserInfo string, - - |> Seq.toArray<- List Array ArrayAdapter
- List. .

Azure Mobile Servcies
- Azure Mobile Services. NotificationHub, Push . Azure , .. .
, 
module WruConstants = [<Literal>] let TotallyNotAzureServer = "https://YOUR.azure-mobile.net/"; [<Literal>] let TotallyNotAzureKey = "YOUR"
member this.RegisterMe phone name regId = async { try let table = this.MobileService.GetTable<User>() let usr = { Id = "" PhoneHash = MD5Hash phone Nickname = name RegistrationId = regId } do! table.InsertAsync usr |> Async.AwaitPlainTask return (usr.Id, usr.PhoneHash, usr.Nickname) with | e -> System.Diagnostics.Trace.WriteLine(e.ToString) return (String.Empty,String.Empty,String.Empty) }
member this.RegisterMe phone name regId = async { - ( ) . "computation expression" workflow. { } ! ( bang), do! (do-bang) let! (let bang) User. , F# ,
let usr = { Id = "" PhoneHash = MD5Hash phone Nickname = name RegistrationId = regId } do! table.InsertAsync usr |> Async.AwaitPlainTask do-bang, await C#. .. continuation . return (usr.Id, usr.PhoneHash, usr.Nickname) Tuple<string,string,string> . try ... with | e -> try..catch C#

. F# fst snd . 2 . :
let id (c,_,_) = c let phonehash (_,c,_) = c let nickname (_,_,c) = c
: id tuple Id ..
5 Azure, Push . Azure Custom Api
exports.post = function(request, response) { // Use "request.service" to access features of your mobile service, eg: // var tables = request.service.tables; // var push = request.service.push; //response.send(statusCodes.OK, { message : 'Hello World!' }); console.log('Incoming call with requst: ', request.body.RequestId); var usersTable = request.service.tables.getTable('User'); usersTable.where( { id : request.body.TargetId } ) .read( { success: function(results) { if (results.length > 0) { var user = results[0] console.log('Send to results: ', user.Nickname, user.RegistrationId); request.service.push.gcm.send(user.RegistrationId, { RequesterId: request.body.RequesterId, RequesterNickname: request.body.RequesterName, TargetId: user.id, TargetNickname: user.Nickname }, { success: function(gcm_response) { console.log('Push notification sent: ', gcm_response); response.send(statusCodes.OK, { RequestedNickname : user.Nickname }); }, error: function(gcm_error) { console.log('Error sending push notification: ', gcm_error); response.send(statusCodes.INTERNAL_SERVER_ERROR, { RequestedNickname : user.Nickname }); } }); } else { response.send(statusCodes.NO_CONTENT, { RequestedNickname : "" }); } }, error: function(error) { console.log('Error read table: ', error); response.send(statusCodes.INTERNAL_SERVER_ERROR, { RequestedNickname : "" }); } }); };
Push
// Perform Push operation member this.PushAsync targetId myId myNickname = async { try let (request : PushRequest) = { TargetId = targetId RequesterId = myId RequesterName = myNickname } let! result = this.MobileService.InvokeApiAsync<PushRequest, PushResponce>("pushhim", request) |> Async.AwaitTask return result.RequestedNickname with | e -> return e.ToString() }
, let-bang do!

Google Play Services. F# . . : Xamarin.Android.Support.v7.AppCompat
, Google Play Services , .
push notification . GCM, ID, ID Push (. pushhim). BroadcastReciever developer.android.com . F# Xamarin Component Store. Google Cloud Messaging Client GCM . ID
//Check to see that GCM is supported and that the manifest has the correct information GcmClient.CheckDevice(this) GcmClient.CheckManifest(this) // check google play if CheckPlayServices() then // Try to get registration id let regId = GcmClient.GetRegistrationId this if String.IsNullOrEmpty(regId) then // Call to Register the device for Push Notifications GcmClient.Register(this, WruConstants.GcmSender);

.
, -
bitbucket.org/xakpc/whereareyou
,
, "" .
, Android F#. .
, - Android F#. , .listView.Adapter <- new ArrayAdapter(this, Android.Resource.Layout.SimpleListItem1, Android.Resource.Id.Text1, values)
, , let values = [|"item1"; "item2"; "item3"|] - string[], list (IEnumerable )
F#. www.tryfsharp.org/Learn

F# - ,
F# For Fun And Profit
,
- .

hash
MD5 F#
let MD5Hash (input : string) = use md5 = System.Security.Cryptography.MD5.Create() input |> System.Text.Encoding.ASCII.GetBytes |> md5.ComputeHash |> Seq.map (fun c -> c.ToString("X2")) |> Seq.reduce (+)
|> pipeline , .
: GetBytes -> -> HEX -> ( reduce + ) -> .
, C# using System; public string CreateMD5Hash (string input) { MD5 md5 = System.Security.Cryptography.MD5.Create(); byte[] inputBytes = System.Text.Encoding.ASCII.GetBytes (input); byte[] hashBytes = md5.ComputeHash (inputBytes); StringBuilder sb = new StringBuilder(); for (int i = 0; i < hashBytes.Length; i++) { sb.Append (hashBytes[i].ToString ("X2")); } return sb.ToString(); }
: . AzureServiceWorker ( CLR )
- . F# ! Xamarin Studio .
<ItemGroup> <Compile Include="Resources\Resource.designer.fs" /> <Compile Include="Properties\AssemblyInfo.fs" /> <Compile Include="Helpers\Helpers.fs" /> <Compile Include="Services\User.fs" /> <Compile Include="Services\AzureServiceWorker.fs" /> <Compile Include="IAmHereActivity.fs" /> <Compile Include="WhereAreYouActivity.fs" /> <Compile Include="SignInActivity.fs" /> </ItemGroup>
: . Xamarin Xamarin.Mobile
. F# TPL, Task', . F# Task. , :
module Async = open System.Threading open System.Threading.Tasks let inline AwaitPlainTask (task: Task) = // rethrow exception from preceding task if it fauled let continuation (t : Task) : unit = match t.IsFaulted with | true -> raise t.Exception | arg -> () task.ContinueWith continuation |> Async.AwaitTask
Async.AwaitIAsyncResult >> Async.Ignore
let ExtractUserInfo (x : Contact) = let first = x.Phones |> Seq.tryPick(fun x -> if x.Type = PhoneType.Mobile then Some(x) else None) match first with | Some(first) -> let phone = first.Number |> StripChars [' ';'-';'(';')'] UserInfo.CreateUserInfo((MD5Hash phone), phone, x.DisplayName) | None -> UserInfo.CreateUserInfo("no mobile phone", "no mobile phone", "no mobile phone") // function for async list filling let FillContactsAsync = async { let book = new AddressBook (this) let! result = book.RequestPermission() |> Async.AwaitTask if result then _contacts <- book.ToList() |> Seq.filter (fun (x: Contact) -> not (Seq.isEmpty x.Phones)) |> Seq.map ExtractUserInfo |> Seq.sortBy(fun x -> x.DisplayName) |> Seq.toList let finalContacts = _contacts |> Seq.map (fun x -> x.DisplayName.ToUpperInvariant()) |> Seq.toArray this.ListAdapter <- new ArrayAdapter(this, Resource_Layout.row_contact, finalContacts) else System.Diagnostics.Debug.WriteLine("Permission denied by user or manifest") this.ListAdapter <- new ArrayAdapter(this, Resource_Layout.row_contact, Array.empty) }
book.ToList() List |> Seq.filter (fun (x: Contact) -> not (Seq.isEmpty x.Phones)) |> Seq.map ExtractUserInfo Contracts UserInfo, UserInfo |> Seq.sortBy(fun x -> x.DisplayName) |> Seq.toList List _contacts <- mutable _contacts |> Seq.map (fun x -> x.DisplayName.ToUpperInvariant())<- UserInfo string, - - |> Seq.toArray<- List Array ArrayAdapter
- List. .

Azure Mobile Servcies
- Azure Mobile Services. NotificationHub, Push . Azure , .. .
, 
module WruConstants = [<Literal>] let TotallyNotAzureServer = "https://YOUR.azure-mobile.net/"; [<Literal>] let TotallyNotAzureKey = "YOUR"
member this.RegisterMe phone name regId = async { try let table = this.MobileService.GetTable<User>() let usr = { Id = "" PhoneHash = MD5Hash phone Nickname = name RegistrationId = regId } do! table.InsertAsync usr |> Async.AwaitPlainTask return (usr.Id, usr.PhoneHash, usr.Nickname) with | e -> System.Diagnostics.Trace.WriteLine(e.ToString) return (String.Empty,String.Empty,String.Empty) }
member this.RegisterMe phone name regId = async { - ( ) . "computation expression" workflow. { } ! ( bang), do! (do-bang) let! (let bang) User. , F# ,
let usr = { Id = "" PhoneHash = MD5Hash phone Nickname = name RegistrationId = regId } do! table.InsertAsync usr |> Async.AwaitPlainTask do-bang, await C#. .. continuation . return (usr.Id, usr.PhoneHash, usr.Nickname) Tuple<string,string,string> . try ... with | e -> try..catch C#

. F# fst snd . 2 . :
let id (c,_,_) = c let phonehash (_,c,_) = c let nickname (_,_,c) = c
: id tuple Id ..
5 Azure, Push . Azure Custom Api
exports.post = function(request, response) { // Use "request.service" to access features of your mobile service, eg: // var tables = request.service.tables; // var push = request.service.push; //response.send(statusCodes.OK, { message : 'Hello World!' }); console.log('Incoming call with requst: ', request.body.RequestId); var usersTable = request.service.tables.getTable('User'); usersTable.where( { id : request.body.TargetId } ) .read( { success: function(results) { if (results.length > 0) { var user = results[0] console.log('Send to results: ', user.Nickname, user.RegistrationId); request.service.push.gcm.send(user.RegistrationId, { RequesterId: request.body.RequesterId, RequesterNickname: request.body.RequesterName, TargetId: user.id, TargetNickname: user.Nickname }, { success: function(gcm_response) { console.log('Push notification sent: ', gcm_response); response.send(statusCodes.OK, { RequestedNickname : user.Nickname }); }, error: function(gcm_error) { console.log('Error sending push notification: ', gcm_error); response.send(statusCodes.INTERNAL_SERVER_ERROR, { RequestedNickname : user.Nickname }); } }); } else { response.send(statusCodes.NO_CONTENT, { RequestedNickname : "" }); } }, error: function(error) { console.log('Error read table: ', error); response.send(statusCodes.INTERNAL_SERVER_ERROR, { RequestedNickname : "" }); } }); };
Push
// Perform Push operation member this.PushAsync targetId myId myNickname = async { try let (request : PushRequest) = { TargetId = targetId RequesterId = myId RequesterName = myNickname } let! result = this.MobileService.InvokeApiAsync<PushRequest, PushResponce>("pushhim", request) |> Async.AwaitTask return result.RequestedNickname with | e -> return e.ToString() }
, let-bang do!

Google Play Services. F# . . : Xamarin.Android.Support.v7.AppCompat
, Google Play Services , .
push notification . GCM, ID, ID Push (. pushhim). BroadcastReciever developer.android.com . F# Xamarin Component Store. Google Cloud Messaging Client GCM . ID
//Check to see that GCM is supported and that the manifest has the correct information GcmClient.CheckDevice(this) GcmClient.CheckManifest(this) // check google play if CheckPlayServices() then // Try to get registration id let regId = GcmClient.GetRegistrationId this if String.IsNullOrEmpty(regId) then // Call to Register the device for Push Notifications GcmClient.Register(this, WruConstants.GcmSender);

.
, -
bitbucket.org/xakpc/whereareyou
,
, "" .
, Android F#. .
, - Android F#. , .listView.Adapter <- new ArrayAdapter(this, Android.Resource.Layout.SimpleListItem1, Android.Resource.Id.Text1, values)
, , let values = [|"item1"; "item2"; "item3"|] - string[], list (IEnumerable )
F#. www.tryfsharp.org/Learn

F# - ,
F# For Fun And Profit
,
- .

hash
MD5 F#
let MD5Hash (input : string) = use md5 = System.Security.Cryptography.MD5.Create() input |> System.Text.Encoding.ASCII.GetBytes |> md5.ComputeHash |> Seq.map (fun c -> c.ToString("X2")) |> Seq.reduce (+)
|> pipeline , .
: GetBytes -> -> HEX -> ( reduce + ) -> .
, C# using System; public string CreateMD5Hash (string input) { MD5 md5 = System.Security.Cryptography.MD5.Create(); byte[] inputBytes = System.Text.Encoding.ASCII.GetBytes (input); byte[] hashBytes = md5.ComputeHash (inputBytes); StringBuilder sb = new StringBuilder(); for (int i = 0; i < hashBytes.Length; i++) { sb.Append (hashBytes[i].ToString ("X2")); } return sb.ToString(); }
: . AzureServiceWorker ( CLR )
- . F# ! Xamarin Studio .
<ItemGroup> <Compile Include="Resources\Resource.designer.fs" /> <Compile Include="Properties\AssemblyInfo.fs" /> <Compile Include="Helpers\Helpers.fs" /> <Compile Include="Services\User.fs" /> <Compile Include="Services\AzureServiceWorker.fs" /> <Compile Include="IAmHereActivity.fs" /> <Compile Include="WhereAreYouActivity.fs" /> <Compile Include="SignInActivity.fs" /> </ItemGroup>
: . Xamarin Xamarin.Mobile
. F# TPL, Task', . F# Task. , :
module Async = open System.Threading open System.Threading.Tasks let inline AwaitPlainTask (task: Task) = // rethrow exception from preceding task if it fauled let continuation (t : Task) : unit = match t.IsFaulted with | true -> raise t.Exception | arg -> () task.ContinueWith continuation |> Async.AwaitTask
Async.AwaitIAsyncResult >> Async.Ignore
let ExtractUserInfo (x : Contact) = let first = x.Phones |> Seq.tryPick(fun x -> if x.Type = PhoneType.Mobile then Some(x) else None) match first with | Some(first) -> let phone = first.Number |> StripChars [' ';'-';'(';')'] UserInfo.CreateUserInfo((MD5Hash phone), phone, x.DisplayName) | None -> UserInfo.CreateUserInfo("no mobile phone", "no mobile phone", "no mobile phone") // function for async list filling let FillContactsAsync = async { let book = new AddressBook (this) let! result = book.RequestPermission() |> Async.AwaitTask if result then _contacts <- book.ToList() |> Seq.filter (fun (x: Contact) -> not (Seq.isEmpty x.Phones)) |> Seq.map ExtractUserInfo |> Seq.sortBy(fun x -> x.DisplayName) |> Seq.toList let finalContacts = _contacts |> Seq.map (fun x -> x.DisplayName.ToUpperInvariant()) |> Seq.toArray this.ListAdapter <- new ArrayAdapter(this, Resource_Layout.row_contact, finalContacts) else System.Diagnostics.Debug.WriteLine("Permission denied by user or manifest") this.ListAdapter <- new ArrayAdapter(this, Resource_Layout.row_contact, Array.empty) }
book.ToList() List |> Seq.filter (fun (x: Contact) -> not (Seq.isEmpty x.Phones)) |> Seq.map ExtractUserInfo Contracts UserInfo, UserInfo |> Seq.sortBy(fun x -> x.DisplayName) |> Seq.toList List _contacts <- mutable _contacts |> Seq.map (fun x -> x.DisplayName.ToUpperInvariant())<- UserInfo string, - - |> Seq.toArray<- List Array ArrayAdapter
- List. .

Azure Mobile Servcies
- Azure Mobile Services. NotificationHub, Push . Azure , .. .
, 
module WruConstants = [<Literal>] let TotallyNotAzureServer = "https://YOUR.azure-mobile.net/"; [<Literal>] let TotallyNotAzureKey = "YOUR"
member this.RegisterMe phone name regId = async { try let table = this.MobileService.GetTable<User>() let usr = { Id = "" PhoneHash = MD5Hash phone Nickname = name RegistrationId = regId } do! table.InsertAsync usr |> Async.AwaitPlainTask return (usr.Id, usr.PhoneHash, usr.Nickname) with | e -> System.Diagnostics.Trace.WriteLine(e.ToString) return (String.Empty,String.Empty,String.Empty) }
member this.RegisterMe phone name regId = async { - ( ) . "computation expression" workflow. { } ! ( bang), do! (do-bang) let! (let bang) User. , F# ,
let usr = { Id = "" PhoneHash = MD5Hash phone Nickname = name RegistrationId = regId } do! table.InsertAsync usr |> Async.AwaitPlainTask do-bang, await C#. .. continuation . return (usr.Id, usr.PhoneHash, usr.Nickname) Tuple<string,string,string> . try ... with | e -> try..catch C#

. F# fst snd . 2 . :
let id (c,_,_) = c let phonehash (_,c,_) = c let nickname (_,_,c) = c
: id tuple Id ..
5 Azure, Push . Azure Custom Api
exports.post = function(request, response) { // Use "request.service" to access features of your mobile service, eg: // var tables = request.service.tables; // var push = request.service.push; //response.send(statusCodes.OK, { message : 'Hello World!' }); console.log('Incoming call with requst: ', request.body.RequestId); var usersTable = request.service.tables.getTable('User'); usersTable.where( { id : request.body.TargetId } ) .read( { success: function(results) { if (results.length > 0) { var user = results[0] console.log('Send to results: ', user.Nickname, user.RegistrationId); request.service.push.gcm.send(user.RegistrationId, { RequesterId: request.body.RequesterId, RequesterNickname: request.body.RequesterName, TargetId: user.id, TargetNickname: user.Nickname }, { success: function(gcm_response) { console.log('Push notification sent: ', gcm_response); response.send(statusCodes.OK, { RequestedNickname : user.Nickname }); }, error: function(gcm_error) { console.log('Error sending push notification: ', gcm_error); response.send(statusCodes.INTERNAL_SERVER_ERROR, { RequestedNickname : user.Nickname }); } }); } else { response.send(statusCodes.NO_CONTENT, { RequestedNickname : "" }); } }, error: function(error) { console.log('Error read table: ', error); response.send(statusCodes.INTERNAL_SERVER_ERROR, { RequestedNickname : "" }); } }); };
Push
// Perform Push operation member this.PushAsync targetId myId myNickname = async { try let (request : PushRequest) = { TargetId = targetId RequesterId = myId RequesterName = myNickname } let! result = this.MobileService.InvokeApiAsync<PushRequest, PushResponce>("pushhim", request) |> Async.AwaitTask return result.RequestedNickname with | e -> return e.ToString() }
, let-bang do!

Google Play Services. F# . . : Xamarin.Android.Support.v7.AppCompat
, Google Play Services , .
push notification . GCM, ID, ID Push (. pushhim). BroadcastReciever developer.android.com . F# Xamarin Component Store. Google Cloud Messaging Client GCM . ID
//Check to see that GCM is supported and that the manifest has the correct information GcmClient.CheckDevice(this) GcmClient.CheckManifest(this) // check google play if CheckPlayServices() then // Try to get registration id let regId = GcmClient.GetRegistrationId this if String.IsNullOrEmpty(regId) then // Call to Register the device for Push Notifications GcmClient.Register(this, WruConstants.GcmSender);

.
, -
bitbucket.org/xakpc/whereareyou
,
, "" .
, Android F#. .
, - Android F#. , .listView.Adapter <- new ArrayAdapter(this, Android.Resource.Layout.SimpleListItem1, Android.Resource.Id.Text1, values)
, , let values = [|"item1"; "item2"; "item3"|] - string[], list (IEnumerable )
F#. www.tryfsharp.org/Learn

F# - ,
F# For Fun And Profit
,
- .

hash
MD5 F#
let MD5Hash (input : string) = use md5 = System.Security.Cryptography.MD5.Create() input |> System.Text.Encoding.ASCII.GetBytes |> md5.ComputeHash |> Seq.map (fun c -> c.ToString("X2")) |> Seq.reduce (+)
|> pipeline , .
: GetBytes -> -> HEX -> ( reduce + ) -> .
, C# using System; public string CreateMD5Hash (string input) { MD5 md5 = System.Security.Cryptography.MD5.Create(); byte[] inputBytes = System.Text.Encoding.ASCII.GetBytes (input); byte[] hashBytes = md5.ComputeHash (inputBytes); StringBuilder sb = new StringBuilder(); for (int i = 0; i < hashBytes.Length; i++) { sb.Append (hashBytes[i].ToString ("X2")); } return sb.ToString(); }
: . AzureServiceWorker ( CLR )
- . F# ! Xamarin Studio .
<ItemGroup> <Compile Include="Resources\Resource.designer.fs" /> <Compile Include="Properties\AssemblyInfo.fs" /> <Compile Include="Helpers\Helpers.fs" /> <Compile Include="Services\User.fs" /> <Compile Include="Services\AzureServiceWorker.fs" /> <Compile Include="IAmHereActivity.fs" /> <Compile Include="WhereAreYouActivity.fs" /> <Compile Include="SignInActivity.fs" /> </ItemGroup>
: . Xamarin Xamarin.Mobile
. F# TPL, Task', . F# Task. , :
module Async = open System.Threading open System.Threading.Tasks let inline AwaitPlainTask (task: Task) = // rethrow exception from preceding task if it fauled let continuation (t : Task) : unit = match t.IsFaulted with | true -> raise t.Exception | arg -> () task.ContinueWith continuation |> Async.AwaitTask
Async.AwaitIAsyncResult >> Async.Ignore
let ExtractUserInfo (x : Contact) = let first = x.Phones |> Seq.tryPick(fun x -> if x.Type = PhoneType.Mobile then Some(x) else None) match first with | Some(first) -> let phone = first.Number |> StripChars [' ';'-';'(';')'] UserInfo.CreateUserInfo((MD5Hash phone), phone, x.DisplayName) | None -> UserInfo.CreateUserInfo("no mobile phone", "no mobile phone", "no mobile phone") // function for async list filling let FillContactsAsync = async { let book = new AddressBook (this) let! result = book.RequestPermission() |> Async.AwaitTask if result then _contacts <- book.ToList() |> Seq.filter (fun (x: Contact) -> not (Seq.isEmpty x.Phones)) |> Seq.map ExtractUserInfo |> Seq.sortBy(fun x -> x.DisplayName) |> Seq.toList let finalContacts = _contacts |> Seq.map (fun x -> x.DisplayName.ToUpperInvariant()) |> Seq.toArray this.ListAdapter <- new ArrayAdapter(this, Resource_Layout.row_contact, finalContacts) else System.Diagnostics.Debug.WriteLine("Permission denied by user or manifest") this.ListAdapter <- new ArrayAdapter(this, Resource_Layout.row_contact, Array.empty) }
book.ToList() List |> Seq.filter (fun (x: Contact) -> not (Seq.isEmpty x.Phones)) |> Seq.map ExtractUserInfo Contracts UserInfo, UserInfo |> Seq.sortBy(fun x -> x.DisplayName) |> Seq.toList List _contacts <- mutable _contacts |> Seq.map (fun x -> x.DisplayName.ToUpperInvariant())<- UserInfo string, - - |> Seq.toArray<- List Array ArrayAdapter
- List. .

Azure Mobile Servcies
- Azure Mobile Services. NotificationHub, Push . Azure , .. .
, 
module WruConstants = [<Literal>] let TotallyNotAzureServer = "https://YOUR.azure-mobile.net/"; [<Literal>] let TotallyNotAzureKey = "YOUR"
member this.RegisterMe phone name regId = async { try let table = this.MobileService.GetTable<User>() let usr = { Id = "" PhoneHash = MD5Hash phone Nickname = name RegistrationId = regId } do! table.InsertAsync usr |> Async.AwaitPlainTask return (usr.Id, usr.PhoneHash, usr.Nickname) with | e -> System.Diagnostics.Trace.WriteLine(e.ToString) return (String.Empty,String.Empty,String.Empty) }
member this.RegisterMe phone name regId = async { - ( ) . "computation expression" workflow. { } ! ( bang), do! (do-bang) let! (let bang) User. , F# ,
let usr = { Id = "" PhoneHash = MD5Hash phone Nickname = name RegistrationId = regId } do! table.InsertAsync usr |> Async.AwaitPlainTask do-bang, await C#. .. continuation . return (usr.Id, usr.PhoneHash, usr.Nickname) Tuple<string,string,string> . try ... with | e -> try..catch C#

. F# fst snd . 2 . :
let id (c,_,_) = c let phonehash (_,c,_) = c let nickname (_,_,c) = c
: id tuple Id ..
5 Azure, Push . Azure Custom Api
exports.post = function(request, response) { // Use "request.service" to access features of your mobile service, eg: // var tables = request.service.tables; // var push = request.service.push; //response.send(statusCodes.OK, { message : 'Hello World!' }); console.log('Incoming call with requst: ', request.body.RequestId); var usersTable = request.service.tables.getTable('User'); usersTable.where( { id : request.body.TargetId } ) .read( { success: function(results) { if (results.length > 0) { var user = results[0] console.log('Send to results: ', user.Nickname, user.RegistrationId); request.service.push.gcm.send(user.RegistrationId, { RequesterId: request.body.RequesterId, RequesterNickname: request.body.RequesterName, TargetId: user.id, TargetNickname: user.Nickname }, { success: function(gcm_response) { console.log('Push notification sent: ', gcm_response); response.send(statusCodes.OK, { RequestedNickname : user.Nickname }); }, error: function(gcm_error) { console.log('Error sending push notification: ', gcm_error); response.send(statusCodes.INTERNAL_SERVER_ERROR, { RequestedNickname : user.Nickname }); } }); } else { response.send(statusCodes.NO_CONTENT, { RequestedNickname : "" }); } }, error: function(error) { console.log('Error read table: ', error); response.send(statusCodes.INTERNAL_SERVER_ERROR, { RequestedNickname : "" }); } }); };
Push
// Perform Push operation member this.PushAsync targetId myId myNickname = async { try let (request : PushRequest) = { TargetId = targetId RequesterId = myId RequesterName = myNickname } let! result = this.MobileService.InvokeApiAsync<PushRequest, PushResponce>("pushhim", request) |> Async.AwaitTask return result.RequestedNickname with | e -> return e.ToString() }
, let-bang do!

Google Play Services. F# . . : Xamarin.Android.Support.v7.AppCompat
, Google Play Services , .
push notification . GCM, ID, ID Push (. pushhim). BroadcastReciever developer.android.com . F# Xamarin Component Store. Google Cloud Messaging Client GCM . ID
//Check to see that GCM is supported and that the manifest has the correct information GcmClient.CheckDevice(this) GcmClient.CheckManifest(this) // check google play if CheckPlayServices() then // Try to get registration id let regId = GcmClient.GetRegistrationId this if String.IsNullOrEmpty(regId) then // Call to Register the device for Push Notifications GcmClient.Register(this, WruConstants.GcmSender);

.
, -
bitbucket.org/xakpc/whereareyou
,
, "" .
, Android F#. .
, - Android F#. , .listView.Adapter <- new ArrayAdapter(this, Android.Resource.Layout.SimpleListItem1, Android.Resource.Id.Text1, values)
, , let values = [|"item1"; "item2"; "item3"|] - string[], list (IEnumerable )
F#. www.tryfsharp.org/Learn

F# - ,
F# For Fun And Profit
,
- .

hash
MD5 F#
let MD5Hash (input : string) = use md5 = System.Security.Cryptography.MD5.Create() input |> System.Text.Encoding.ASCII.GetBytes |> md5.ComputeHash |> Seq.map (fun c -> c.ToString("X2")) |> Seq.reduce (+)
|> pipeline , .
: GetBytes -> -> HEX -> ( reduce + ) -> .
, C# using System; public string CreateMD5Hash (string input) { MD5 md5 = System.Security.Cryptography.MD5.Create(); byte[] inputBytes = System.Text.Encoding.ASCII.GetBytes (input); byte[] hashBytes = md5.ComputeHash (inputBytes); StringBuilder sb = new StringBuilder(); for (int i = 0; i < hashBytes.Length; i++) { sb.Append (hashBytes[i].ToString ("X2")); } return sb.ToString(); }
: . AzureServiceWorker ( CLR )
- . F# ! Xamarin Studio .
<ItemGroup> <Compile Include="Resources\Resource.designer.fs" /> <Compile Include="Properties\AssemblyInfo.fs" /> <Compile Include="Helpers\Helpers.fs" /> <Compile Include="Services\User.fs" /> <Compile Include="Services\AzureServiceWorker.fs" /> <Compile Include="IAmHereActivity.fs" /> <Compile Include="WhereAreYouActivity.fs" /> <Compile Include="SignInActivity.fs" /> </ItemGroup>
: . Xamarin Xamarin.Mobile
. F# TPL, Task', . F# Task. , :
module Async = open System.Threading open System.Threading.Tasks let inline AwaitPlainTask (task: Task) = // rethrow exception from preceding task if it fauled let continuation (t : Task) : unit = match t.IsFaulted with | true -> raise t.Exception | arg -> () task.ContinueWith continuation |> Async.AwaitTask
Async.AwaitIAsyncResult >> Async.Ignore
let ExtractUserInfo (x : Contact) = let first = x.Phones |> Seq.tryPick(fun x -> if x.Type = PhoneType.Mobile then Some(x) else None) match first with | Some(first) -> let phone = first.Number |> StripChars [' ';'-';'(';')'] UserInfo.CreateUserInfo((MD5Hash phone), phone, x.DisplayName) | None -> UserInfo.CreateUserInfo("no mobile phone", "no mobile phone", "no mobile phone") // function for async list filling let FillContactsAsync = async { let book = new AddressBook (this) let! result = book.RequestPermission() |> Async.AwaitTask if result then _contacts <- book.ToList() |> Seq.filter (fun (x: Contact) -> not (Seq.isEmpty x.Phones)) |> Seq.map ExtractUserInfo |> Seq.sortBy(fun x -> x.DisplayName) |> Seq.toList let finalContacts = _contacts |> Seq.map (fun x -> x.DisplayName.ToUpperInvariant()) |> Seq.toArray this.ListAdapter <- new ArrayAdapter(this, Resource_Layout.row_contact, finalContacts) else System.Diagnostics.Debug.WriteLine("Permission denied by user or manifest") this.ListAdapter <- new ArrayAdapter(this, Resource_Layout.row_contact, Array.empty) }
book.ToList() List |> Seq.filter (fun (x: Contact) -> not (Seq.isEmpty x.Phones)) |> Seq.map ExtractUserInfo Contracts UserInfo, UserInfo |> Seq.sortBy(fun x -> x.DisplayName) |> Seq.toList List _contacts <- mutable _contacts |> Seq.map (fun x -> x.DisplayName.ToUpperInvariant())<- UserInfo string, - - |> Seq.toArray<- List Array ArrayAdapter
- List. .

Azure Mobile Servcies
- Azure Mobile Services. NotificationHub, Push . Azure , .. .
, 
module WruConstants = [<Literal>] let TotallyNotAzureServer = "https://YOUR.azure-mobile.net/"; [<Literal>] let TotallyNotAzureKey = "YOUR"
member this.RegisterMe phone name regId = async { try let table = this.MobileService.GetTable<User>() let usr = { Id = "" PhoneHash = MD5Hash phone Nickname = name RegistrationId = regId } do! table.InsertAsync usr |> Async.AwaitPlainTask return (usr.Id, usr.PhoneHash, usr.Nickname) with | e -> System.Diagnostics.Trace.WriteLine(e.ToString) return (String.Empty,String.Empty,String.Empty) }
member this.RegisterMe phone name regId = async { - ( ) . "computation expression" workflow. { } ! ( bang), do! (do-bang) let! (let bang) User. , F# ,
let usr = { Id = "" PhoneHash = MD5Hash phone Nickname = name RegistrationId = regId } do! table.InsertAsync usr |> Async.AwaitPlainTask do-bang, await C#. .. continuation . return (usr.Id, usr.PhoneHash, usr.Nickname) Tuple<string,string,string> . try ... with | e -> try..catch C#

. F# fst snd . 2 . :
let id (c,_,_) = c let phonehash (_,c,_) = c let nickname (_,_,c) = c
: id tuple Id ..
5 Azure, Push . Azure Custom Api
exports.post = function(request, response) { // Use "request.service" to access features of your mobile service, eg: // var tables = request.service.tables; // var push = request.service.push; //response.send(statusCodes.OK, { message : 'Hello World!' }); console.log('Incoming call with requst: ', request.body.RequestId); var usersTable = request.service.tables.getTable('User'); usersTable.where( { id : request.body.TargetId } ) .read( { success: function(results) { if (results.length > 0) { var user = results[0] console.log('Send to results: ', user.Nickname, user.RegistrationId); request.service.push.gcm.send(user.RegistrationId, { RequesterId: request.body.RequesterId, RequesterNickname: request.body.RequesterName, TargetId: user.id, TargetNickname: user.Nickname }, { success: function(gcm_response) { console.log('Push notification sent: ', gcm_response); response.send(statusCodes.OK, { RequestedNickname : user.Nickname }); }, error: function(gcm_error) { console.log('Error sending push notification: ', gcm_error); response.send(statusCodes.INTERNAL_SERVER_ERROR, { RequestedNickname : user.Nickname }); } }); } else { response.send(statusCodes.NO_CONTENT, { RequestedNickname : "" }); } }, error: function(error) { console.log('Error read table: ', error); response.send(statusCodes.INTERNAL_SERVER_ERROR, { RequestedNickname : "" }); } }); };
Push
// Perform Push operation member this.PushAsync targetId myId myNickname = async { try let (request : PushRequest) = { TargetId = targetId RequesterId = myId RequesterName = myNickname } let! result = this.MobileService.InvokeApiAsync<PushRequest, PushResponce>("pushhim", request) |> Async.AwaitTask return result.RequestedNickname with | e -> return e.ToString() }
, let-bang do!

Google Play Services. F# . . : Xamarin.Android.Support.v7.AppCompat
, Google Play Services , .
push notification . GCM, ID, ID Push (. pushhim). BroadcastReciever developer.android.com . F# Xamarin Component Store. Google Cloud Messaging Client GCM . ID
//Check to see that GCM is supported and that the manifest has the correct information GcmClient.CheckDevice(this) GcmClient.CheckManifest(this) // check google play if CheckPlayServices() then // Try to get registration id let regId = GcmClient.GetRegistrationId this if String.IsNullOrEmpty(regId) then // Call to Register the device for Push Notifications GcmClient.Register(this, WruConstants.GcmSender);

.
, -
bitbucket.org/xakpc/whereareyou
,
, "" .
, Android F#. .
, - Android F#. , .listView.Adapter <- new ArrayAdapter(this, Android.Resource.Layout.SimpleListItem1, Android.Resource.Id.Text1, values)
, , let values = [|"item1"; "item2"; "item3"|] - string[], list (IEnumerable )
F#. www.tryfsharp.org/Learn

F# - ,
F# For Fun And Profit
,
- .

hash
MD5 F#
let MD5Hash (input : string) = use md5 = System.Security.Cryptography.MD5.Create() input |> System.Text.Encoding.ASCII.GetBytes |> md5.ComputeHash |> Seq.map (fun c -> c.ToString("X2")) |> Seq.reduce (+)
|> pipeline , .
: GetBytes -> -> HEX -> ( reduce + ) -> .
, C# using System; public string CreateMD5Hash (string input) { MD5 md5 = System.Security.Cryptography.MD5.Create(); byte[] inputBytes = System.Text.Encoding.ASCII.GetBytes (input); byte[] hashBytes = md5.ComputeHash (inputBytes); StringBuilder sb = new StringBuilder(); for (int i = 0; i < hashBytes.Length; i++) { sb.Append (hashBytes[i].ToString ("X2")); } return sb.ToString(); }
: . AzureServiceWorker ( CLR )
- . F# ! Xamarin Studio .
<ItemGroup> <Compile Include="Resources\Resource.designer.fs" /> <Compile Include="Properties\AssemblyInfo.fs" /> <Compile Include="Helpers\Helpers.fs" /> <Compile Include="Services\User.fs" /> <Compile Include="Services\AzureServiceWorker.fs" /> <Compile Include="IAmHereActivity.fs" /> <Compile Include="WhereAreYouActivity.fs" /> <Compile Include="SignInActivity.fs" /> </ItemGroup>
: . Xamarin Xamarin.Mobile
. F# TPL, Task', . F# Task. , :
module Async = open System.Threading open System.Threading.Tasks let inline AwaitPlainTask (task: Task) = // rethrow exception from preceding task if it fauled let continuation (t : Task) : unit = match t.IsFaulted with | true -> raise t.Exception | arg -> () task.ContinueWith continuation |> Async.AwaitTask
Async.AwaitIAsyncResult >> Async.Ignore
let ExtractUserInfo (x : Contact) = let first = x.Phones |> Seq.tryPick(fun x -> if x.Type = PhoneType.Mobile then Some(x) else None) match first with | Some(first) -> let phone = first.Number |> StripChars [' ';'-';'(';')'] UserInfo.CreateUserInfo((MD5Hash phone), phone, x.DisplayName) | None -> UserInfo.CreateUserInfo("no mobile phone", "no mobile phone", "no mobile phone") // function for async list filling let FillContactsAsync = async { let book = new AddressBook (this) let! result = book.RequestPermission() |> Async.AwaitTask if result then _contacts <- book.ToList() |> Seq.filter (fun (x: Contact) -> not (Seq.isEmpty x.Phones)) |> Seq.map ExtractUserInfo |> Seq.sortBy(fun x -> x.DisplayName) |> Seq.toList let finalContacts = _contacts |> Seq.map (fun x -> x.DisplayName.ToUpperInvariant()) |> Seq.toArray this.ListAdapter <- new ArrayAdapter(this, Resource_Layout.row_contact, finalContacts) else System.Diagnostics.Debug.WriteLine("Permission denied by user or manifest") this.ListAdapter <- new ArrayAdapter(this, Resource_Layout.row_contact, Array.empty) }
book.ToList() List |> Seq.filter (fun (x: Contact) -> not (Seq.isEmpty x.Phones)) |> Seq.map ExtractUserInfo Contracts UserInfo, UserInfo |> Seq.sortBy(fun x -> x.DisplayName) |> Seq.toList List _contacts <- mutable _contacts |> Seq.map (fun x -> x.DisplayName.ToUpperInvariant())<- UserInfo string, - - |> Seq.toArray<- List Array ArrayAdapter
- List. .

Azure Mobile Servcies
- Azure Mobile Services. NotificationHub, Push . Azure , .. .
, 
module WruConstants = [<Literal>] let TotallyNotAzureServer = "https://YOUR.azure-mobile.net/"; [<Literal>] let TotallyNotAzureKey = "YOUR"
member this.RegisterMe phone name regId = async { try let table = this.MobileService.GetTable<User>() let usr = { Id = "" PhoneHash = MD5Hash phone Nickname = name RegistrationId = regId } do! table.InsertAsync usr |> Async.AwaitPlainTask return (usr.Id, usr.PhoneHash, usr.Nickname) with | e -> System.Diagnostics.Trace.WriteLine(e.ToString) return (String.Empty,String.Empty,String.Empty) }
member this.RegisterMe phone name regId = async { - ( ) . "computation expression" workflow. { } ! ( bang), do! (do-bang) let! (let bang) User. , F# ,
let usr = { Id = "" PhoneHash = MD5Hash phone Nickname = name RegistrationId = regId } do! table.InsertAsync usr |> Async.AwaitPlainTask do-bang, await C#. .. continuation . return (usr.Id, usr.PhoneHash, usr.Nickname) Tuple<string,string,string> . try ... with | e -> try..catch C#

. F# fst snd . 2 . :
let id (c,_,_) = c let phonehash (_,c,_) = c let nickname (_,_,c) = c
: id tuple Id ..
5 Azure, Push . Azure Custom Api
exports.post = function(request, response) { // Use "request.service" to access features of your mobile service, eg: // var tables = request.service.tables; // var push = request.service.push; //response.send(statusCodes.OK, { message : 'Hello World!' }); console.log('Incoming call with requst: ', request.body.RequestId); var usersTable = request.service.tables.getTable('User'); usersTable.where( { id : request.body.TargetId } ) .read( { success: function(results) { if (results.length > 0) { var user = results[0] console.log('Send to results: ', user.Nickname, user.RegistrationId); request.service.push.gcm.send(user.RegistrationId, { RequesterId: request.body.RequesterId, RequesterNickname: request.body.RequesterName, TargetId: user.id, TargetNickname: user.Nickname }, { success: function(gcm_response) { console.log('Push notification sent: ', gcm_response); response.send(statusCodes.OK, { RequestedNickname : user.Nickname }); }, error: function(gcm_error) { console.log('Error sending push notification: ', gcm_error); response.send(statusCodes.INTERNAL_SERVER_ERROR, { RequestedNickname : user.Nickname }); } }); } else { response.send(statusCodes.NO_CONTENT, { RequestedNickname : "" }); } }, error: function(error) { console.log('Error read table: ', error); response.send(statusCodes.INTERNAL_SERVER_ERROR, { RequestedNickname : "" }); } }); };
Push
// Perform Push operation member this.PushAsync targetId myId myNickname = async { try let (request : PushRequest) = { TargetId = targetId RequesterId = myId RequesterName = myNickname } let! result = this.MobileService.InvokeApiAsync<PushRequest, PushResponce>("pushhim", request) |> Async.AwaitTask return result.RequestedNickname with | e -> return e.ToString() }
, let-bang do!

Google Play Services. F# . . : Xamarin.Android.Support.v7.AppCompat
, Google Play Services , .
push notification . GCM, ID, ID Push (. pushhim). BroadcastReciever developer.android.com . F# Xamarin Component Store. Google Cloud Messaging Client GCM . ID
//Check to see that GCM is supported and that the manifest has the correct information GcmClient.CheckDevice(this) GcmClient.CheckManifest(this) // check google play if CheckPlayServices() then // Try to get registration id let regId = GcmClient.GetRegistrationId this if String.IsNullOrEmpty(regId) then // Call to Register the device for Push Notifications GcmClient.Register(this, WruConstants.GcmSender);

.
, -
bitbucket.org/xakpc/whereareyou
,
, "" .
, Android F#. .
, - Android F#. , .listView.Adapter <- new ArrayAdapter(this, Android.Resource.Layout.SimpleListItem1, Android.Resource.Id.Text1, values)
, , let values = [|"item1"; "item2"; "item3"|] - string[], list (IEnumerable )
F#. www.tryfsharp.org/Learn

F# - ,
F# For Fun And Profit
,
- .

hash
MD5 F#
let MD5Hash (input : string) = use md5 = System.Security.Cryptography.MD5.Create() input |> System.Text.Encoding.ASCII.GetBytes |> md5.ComputeHash |> Seq.map (fun c -> c.ToString("X2")) |> Seq.reduce (+)
|> pipeline , .
: GetBytes -> -> HEX -> ( reduce + ) -> .
, C# using System; public string CreateMD5Hash (string input) { MD5 md5 = System.Security.Cryptography.MD5.Create(); byte[] inputBytes = System.Text.Encoding.ASCII.GetBytes (input); byte[] hashBytes = md5.ComputeHash (inputBytes); StringBuilder sb = new StringBuilder(); for (int i = 0; i < hashBytes.Length; i++) { sb.Append (hashBytes[i].ToString ("X2")); } return sb.ToString(); }
: . AzureServiceWorker ( CLR )
- . F# ! Xamarin Studio .
<ItemGroup> <Compile Include="Resources\Resource.designer.fs" /> <Compile Include="Properties\AssemblyInfo.fs" /> <Compile Include="Helpers\Helpers.fs" /> <Compile Include="Services\User.fs" /> <Compile Include="Services\AzureServiceWorker.fs" /> <Compile Include="IAmHereActivity.fs" /> <Compile Include="WhereAreYouActivity.fs" /> <Compile Include="SignInActivity.fs" /> </ItemGroup>
: . Xamarin Xamarin.Mobile
. F# TPL, Task', . F# Task. , :
module Async = open System.Threading open System.Threading.Tasks let inline AwaitPlainTask (task: Task) = // rethrow exception from preceding task if it fauled let continuation (t : Task) : unit = match t.IsFaulted with | true -> raise t.Exception | arg -> () task.ContinueWith continuation |> Async.AwaitTask
Async.AwaitIAsyncResult >> Async.Ignore
let ExtractUserInfo (x : Contact) = let first = x.Phones |> Seq.tryPick(fun x -> if x.Type = PhoneType.Mobile then Some(x) else None) match first with | Some(first) -> let phone = first.Number |> StripChars [' ';'-';'(';')'] UserInfo.CreateUserInfo((MD5Hash phone), phone, x.DisplayName) | None -> UserInfo.CreateUserInfo("no mobile phone", "no mobile phone", "no mobile phone") // function for async list filling let FillContactsAsync = async { let book = new AddressBook (this) let! result = book.RequestPermission() |> Async.AwaitTask if result then _contacts <- book.ToList() |> Seq.filter (fun (x: Contact) -> not (Seq.isEmpty x.Phones)) |> Seq.map ExtractUserInfo |> Seq.sortBy(fun x -> x.DisplayName) |> Seq.toList let finalContacts = _contacts |> Seq.map (fun x -> x.DisplayName.ToUpperInvariant()) |> Seq.toArray this.ListAdapter <- new ArrayAdapter(this, Resource_Layout.row_contact, finalContacts) else System.Diagnostics.Debug.WriteLine("Permission denied by user or manifest") this.ListAdapter <- new ArrayAdapter(this, Resource_Layout.row_contact, Array.empty) }
book.ToList() List |> Seq.filter (fun (x: Contact) -> not (Seq.isEmpty x.Phones)) |> Seq.map ExtractUserInfo Contracts UserInfo, UserInfo |> Seq.sortBy(fun x -> x.DisplayName) |> Seq.toList List _contacts <- mutable _contacts |> Seq.map (fun x -> x.DisplayName.ToUpperInvariant())<- UserInfo string, - - |> Seq.toArray<- List Array ArrayAdapter
- List. .

Azure Mobile Servcies
- Azure Mobile Services. NotificationHub, Push . Azure , .. .
, 
module WruConstants = [<Literal>] let TotallyNotAzureServer = "https://YOUR.azure-mobile.net/"; [<Literal>] let TotallyNotAzureKey = "YOUR"
member this.RegisterMe phone name regId = async { try let table = this.MobileService.GetTable<User>() let usr = { Id = "" PhoneHash = MD5Hash phone Nickname = name RegistrationId = regId } do! table.InsertAsync usr |> Async.AwaitPlainTask return (usr.Id, usr.PhoneHash, usr.Nickname) with | e -> System.Diagnostics.Trace.WriteLine(e.ToString) return (String.Empty,String.Empty,String.Empty) }
member this.RegisterMe phone name regId = async { - ( ) . "computation expression" workflow. { } ! ( bang), do! (do-bang) let! (let bang) User. , F# ,
let usr = { Id = "" PhoneHash = MD5Hash phone Nickname = name RegistrationId = regId } do! table.InsertAsync usr |> Async.AwaitPlainTask do-bang, await C#. .. continuation . return (usr.Id, usr.PhoneHash, usr.Nickname) Tuple<string,string,string> . try ... with | e -> try..catch C#

. F# fst snd . 2 . :
let id (c,_,_) = c let phonehash (_,c,_) = c let nickname (_,_,c) = c
: id tuple Id ..
5 Azure, Push . Azure Custom Api
exports.post = function(request, response) { // Use "request.service" to access features of your mobile service, eg: // var tables = request.service.tables; // var push = request.service.push; //response.send(statusCodes.OK, { message : 'Hello World!' }); console.log('Incoming call with requst: ', request.body.RequestId); var usersTable = request.service.tables.getTable('User'); usersTable.where( { id : request.body.TargetId } ) .read( { success: function(results) { if (results.length > 0) { var user = results[0] console.log('Send to results: ', user.Nickname, user.RegistrationId); request.service.push.gcm.send(user.RegistrationId, { RequesterId: request.body.RequesterId, RequesterNickname: request.body.RequesterName, TargetId: user.id, TargetNickname: user.Nickname }, { success: function(gcm_response) { console.log('Push notification sent: ', gcm_response); response.send(statusCodes.OK, { RequestedNickname : user.Nickname }); }, error: function(gcm_error) { console.log('Error sending push notification: ', gcm_error); response.send(statusCodes.INTERNAL_SERVER_ERROR, { RequestedNickname : user.Nickname }); } }); } else { response.send(statusCodes.NO_CONTENT, { RequestedNickname : "" }); } }, error: function(error) { console.log('Error read table: ', error); response.send(statusCodes.INTERNAL_SERVER_ERROR, { RequestedNickname : "" }); } }); };
Push
// Perform Push operation member this.PushAsync targetId myId myNickname = async { try let (request : PushRequest) = { TargetId = targetId RequesterId = myId RequesterName = myNickname } let! result = this.MobileService.InvokeApiAsync<PushRequest, PushResponce>("pushhim", request) |> Async.AwaitTask return result.RequestedNickname with | e -> return e.ToString() }
, let-bang do!

Google Play Services. F# . . : Xamarin.Android.Support.v7.AppCompat
, Google Play Services , .
push notification . GCM, ID, ID Push (. pushhim). BroadcastReciever developer.android.com . F# Xamarin Component Store. Google Cloud Messaging Client GCM . ID
//Check to see that GCM is supported and that the manifest has the correct information GcmClient.CheckDevice(this) GcmClient.CheckManifest(this) // check google play if CheckPlayServices() then // Try to get registration id let regId = GcmClient.GetRegistrationId this if String.IsNullOrEmpty(regId) then // Call to Register the device for Push Notifications GcmClient.Register(this, WruConstants.GcmSender);

.
, -
bitbucket.org/xakpc/whereareyou
,
, "" .
, Android F#. .
, - Android F#. , . listView.Adapter <- new ArrayAdapter(this, Android.Resource.Layout.SimpleListItem1, Android.Resource.Id.Text1, values) 
  , ,  let values = [|"item1"; "item2"; "item3"|] -   string[],       list (IEnumerable   ) 
          F#.            www.tryfsharp.org/Learn 
 
 
      F# -  ,  
 
        F# For Fun And Profit 
 
   ,    
     - . 
 
 
 
 
        hash 
     MD5  F# 
  let MD5Hash (input : string) = use md5 = System.Security.Cryptography.MD5.Create() input |> System.Text.Encoding.ASCII.GetBytes |> md5.ComputeHash |> Seq.map (fun c -> c.ToString("X2")) |> Seq.reduce (+) 
 
  |>  pipeline ,     . 
     :    GetBytes ->   ->      HEX  ->       (  reduce   +           ) ->    . 
 
  ,     C# using System; public string CreateMD5Hash (string input) { MD5 md5 = System.Security.Cryptography.MD5.Create(); byte[] inputBytes = System.Text.Encoding.ASCII.GetBytes (input); byte[] hashBytes = md5.ComputeHash (inputBytes); StringBuilder sb = new StringBuilder(); for (int i = 0; i < hashBytes.Length; i++) { sb.Append (hashBytes[i].ToString ("X2")); } return sb.ToString(); } 
 
 
          :        .       AzureServiceWorker (  CLR    ) 
 
          -   .   F#    !   Xamarin Studio            . 
  <ItemGroup> <Compile Include="Resources\Resource.designer.fs" /> <Compile Include="Properties\AssemblyInfo.fs" /> <Compile Include="Helpers\Helpers.fs" /> <Compile Include="Services\User.fs" /> <Compile Include="Services\AzureServiceWorker.fs" /> <Compile Include="IAmHereActivity.fs" /> <Compile Include="WhereAreYouActivity.fs" /> <Compile Include="SignInActivity.fs" /> </ItemGroup> 
 
    
        :    .    Xamarin    Xamarin.Mobile 
 
      .  F#         TPL,     Task',      .     F#         Task.  ,     : 
 module Async = open System.Threading open System.Threading.Tasks let inline AwaitPlainTask (task: Task) = // rethrow exception from preceding task if it fauled let continuation (t : Task) : unit = match t.IsFaulted with | true -> raise t.Exception | arg -> () task.ContinueWith continuation |> Async.AwaitTask 
         Async.AwaitIAsyncResult >> Async.Ignore       
 
            
 let ExtractUserInfo (x : Contact) = let first = x.Phones |> Seq.tryPick(fun x -> if x.Type = PhoneType.Mobile then Some(x) else None) match first with | Some(first) -> let phone = first.Number |> StripChars [' ';'-';'(';')'] UserInfo.CreateUserInfo((MD5Hash phone), phone, x.DisplayName) | None -> UserInfo.CreateUserInfo("no mobile phone", "no mobile phone", "no mobile phone") // function for async list filling let FillContactsAsync = async { let book = new AddressBook (this) let! result = book.RequestPermission() |> Async.AwaitTask if result then _contacts <- book.ToList() |> Seq.filter (fun (x: Contact) -> not (Seq.isEmpty x.Phones)) |> Seq.map ExtractUserInfo |> Seq.sortBy(fun x -> x.DisplayName) |> Seq.toList let finalContacts = _contacts |> Seq.map (fun x -> x.DisplayName.ToUpperInvariant()) |> Seq.toArray this.ListAdapter <- new ArrayAdapter(this, Resource_Layout.row_contact, finalContacts) else System.Diagnostics.Debug.WriteLine("Permission denied by user or manifest") this.ListAdapter <- new ArrayAdapter(this, Resource_Layout.row_contact, Array.empty) } 
      
 book.ToList()   List |> Seq.filter (fun (x: Contact) -> not (Seq.isEmpty x.Phones))      |> Seq.map ExtractUserInfo      Contracts  UserInfo,      UserInfo |> Seq.sortBy(fun x -> x.DisplayName)  |> Seq.toList   List _contacts <-    mutable  _contacts |> Seq.map (fun x -> x.DisplayName.ToUpperInvariant())<-    UserInfo  string,     - -    |> Seq.toArray<-  List  Array    ArrayAdapter 
    -      List.   . 
 
 
 
 
 Azure Mobile Servcies 
   -    Azure Mobile Services.       NotificationHub,     Push    .   Azure    , ..      . 
 
      ,    
 module WruConstants = [<Literal>] let TotallyNotAzureServer = "https://YOUR.azure-mobile.net/"; [<Literal>] let TotallyNotAzureKey = "YOUR" 
 
       
 member this.RegisterMe phone name regId = async { try let table = this.MobileService.GetTable<User>() let usr = { Id = "" PhoneHash = MD5Hash phone Nickname = name RegistrationId = regId } do! table.InsertAsync usr |> Async.AwaitPlainTask return (usr.Id, usr.PhoneHash, usr.Nickname) with | e -> System.Diagnostics.Trace.WriteLine(e.ToString) return (String.Empty,String.Empty,String.Empty) } 
 member this.RegisterMe phone name regId = async { -       (     )    .       "computation expression"   workflow.   { }       ! ( bang),  do! (do-bang)  let! (let bang)     User.    ,  F#        ,      
  let usr = { Id = "" PhoneHash = MD5Hash phone Nickname = name RegistrationId = regId } do! table.InsertAsync usr |> Async.AwaitPlainTask  do-bang,   await  C#. ..             continuation    . return (usr.Id, usr.PhoneHash, usr.Nickname)      Tuple<string,string,string>     .  try ... with | e ->  try..catch  C# 
 
 
 
 
       .  F#    fst  snd      .        2 .     : 
  let id (c,_,_) = c let phonehash (_,c,_) = c let nickname (_,_,c) = c 
    : id tuple  Id  .. 
 
    5  Azure,       Push .       Azure Custom Api  
 
      exports.post = function(request, response) { // Use "request.service" to access features of your mobile service, eg: // var tables = request.service.tables; // var push = request.service.push; //response.send(statusCodes.OK, { message : 'Hello World!' }); console.log('Incoming call with requst: ', request.body.RequestId); var usersTable = request.service.tables.getTable('User'); usersTable.where( { id : request.body.TargetId } ) .read( { success: function(results) { if (results.length > 0) { var user = results[0] console.log('Send to results: ', user.Nickname, user.RegistrationId); request.service.push.gcm.send(user.RegistrationId, { RequesterId: request.body.RequesterId, RequesterNickname: request.body.RequesterName, TargetId: user.id, TargetNickname: user.Nickname }, { success: function(gcm_response) { console.log('Push notification sent: ', gcm_response); response.send(statusCodes.OK, { RequestedNickname : user.Nickname }); }, error: function(gcm_error) { console.log('Error sending push notification: ', gcm_error); response.send(statusCodes.INTERNAL_SERVER_ERROR, { RequestedNickname : user.Nickname }); } }); } else { response.send(statusCodes.NO_CONTENT, { RequestedNickname : "" }); } }, error: function(error) { console.log('Error read table: ', error); response.send(statusCodes.INTERNAL_SERVER_ERROR, { RequestedNickname : "" }); } }); }; 
 
    Push      
 // Perform Push operation member this.PushAsync targetId myId myNickname = async { try let (request : PushRequest) = { TargetId = targetId RequesterId = myId RequesterName = myNickname } let! result = this.MobileService.InvokeApiAsync<PushRequest, PushResponce>("pushhim", request) |> Async.AwaitTask return result.RequestedNickname with | e -> return e.ToString() } 
 
       ,    let-bang   do! 
 
   
 
 
 
      Google Play Services.     F#   .           .    : Xamarin.Android.Support.v7.AppCompat 
     , Google Play Services ,   . 
 
      push notification   .    GCM,  ID,     ID       Push  (.   pushhim).        BroadcastReciever       developer.android.com .     F#         Xamarin Component Store.     Google Cloud Messaging Client         GCM    .        ID 
 //Check to see that GCM is supported and that the manifest has the correct information GcmClient.CheckDevice(this) GcmClient.CheckManifest(this) // check google play if CheckPlayServices() then // Try to get registration id let regId = GcmClient.GetRegistrationId this if String.IsNullOrEmpty(regId) then // Call to Register the device for Push Notifications GcmClient.Register(this, WruConstants.GcmSender); 
 
 
 
        
 
    . 
    , -  
     bitbucket.org/xakpc/whereareyou 
     ,     
          ,           "" . 
 
  
 ,   Android   F#.      . 
 ,       -  Android  F#.   ,       . listView.Adapter <- new ArrayAdapter(this, Android.Resource.Layout.SimpleListItem1, Android.Resource.Id.Text1, values)
, , let values = [|"item1"; "item2"; "item3"|] - string[], list (IEnumerable )
F#. www.tryfsharp.org/Learn

F# - ,
F# For Fun And Profit
,
- .

hash
MD5 F#
let MD5Hash (input : string) = use md5 = System.Security.Cryptography.MD5.Create() input |> System.Text.Encoding.ASCII.GetBytes |> md5.ComputeHash |> Seq.map (fun c -> c.ToString("X2")) |> Seq.reduce (+)
|> pipeline , .
: GetBytes -> -> HEX -> ( reduce + ) -> .
, C# using System; public string CreateMD5Hash (string input) { MD5 md5 = System.Security.Cryptography.MD5.Create(); byte[] inputBytes = System.Text.Encoding.ASCII.GetBytes (input); byte[] hashBytes = md5.ComputeHash (inputBytes); StringBuilder sb = new StringBuilder(); for (int i = 0; i < hashBytes.Length; i++) { sb.Append (hashBytes[i].ToString ("X2")); } return sb.ToString(); }
: . AzureServiceWorker ( CLR )
- . F# ! Xamarin Studio .
<ItemGroup> <Compile Include="Resources\Resource.designer.fs" /> <Compile Include="Properties\AssemblyInfo.fs" /> <Compile Include="Helpers\Helpers.fs" /> <Compile Include="Services\User.fs" /> <Compile Include="Services\AzureServiceWorker.fs" /> <Compile Include="IAmHereActivity.fs" /> <Compile Include="WhereAreYouActivity.fs" /> <Compile Include="SignInActivity.fs" /> </ItemGroup>
: . Xamarin Xamarin.Mobile
. F# TPL, Task', . F# Task. , :
module Async = open System.Threading open System.Threading.Tasks let inline AwaitPlainTask (task: Task) = // rethrow exception from preceding task if it fauled let continuation (t : Task) : unit = match t.IsFaulted with | true -> raise t.Exception | arg -> () task.ContinueWith continuation |> Async.AwaitTask
Async.AwaitIAsyncResult >> Async.Ignore
let ExtractUserInfo (x : Contact) = let first = x.Phones |> Seq.tryPick(fun x -> if x.Type = PhoneType.Mobile then Some(x) else None) match first with | Some(first) -> let phone = first.Number |> StripChars [' ';'-';'(';')'] UserInfo.CreateUserInfo((MD5Hash phone), phone, x.DisplayName) | None -> UserInfo.CreateUserInfo("no mobile phone", "no mobile phone", "no mobile phone") // function for async list filling let FillContactsAsync = async { let book = new AddressBook (this) let! result = book.RequestPermission() |> Async.AwaitTask if result then _contacts <- book.ToList() |> Seq.filter (fun (x: Contact) -> not (Seq.isEmpty x.Phones)) |> Seq.map ExtractUserInfo |> Seq.sortBy(fun x -> x.DisplayName) |> Seq.toList let finalContacts = _contacts |> Seq.map (fun x -> x.DisplayName.ToUpperInvariant()) |> Seq.toArray this.ListAdapter <- new ArrayAdapter(this, Resource_Layout.row_contact, finalContacts) else System.Diagnostics.Debug.WriteLine("Permission denied by user or manifest") this.ListAdapter <- new ArrayAdapter(this, Resource_Layout.row_contact, Array.empty) }
book.ToList() List |> Seq.filter (fun (x: Contact) -> not (Seq.isEmpty x.Phones)) |> Seq.map ExtractUserInfo Contracts UserInfo, UserInfo |> Seq.sortBy(fun x -> x.DisplayName) |> Seq.toList List _contacts <- mutable _contacts |> Seq.map (fun x -> x.DisplayName.ToUpperInvariant())<- UserInfo string, - - |> Seq.toArray<- List Array ArrayAdapter
- List. .

Azure Mobile Servcies
- Azure Mobile Services. NotificationHub, Push . Azure , .. .
, 
module WruConstants = [<Literal>] let TotallyNotAzureServer = "https://YOUR.azure-mobile.net/"; [<Literal>] let TotallyNotAzureKey = "YOUR"
member this.RegisterMe phone name regId = async { try let table = this.MobileService.GetTable<User>() let usr = { Id = "" PhoneHash = MD5Hash phone Nickname = name RegistrationId = regId } do! table.InsertAsync usr |> Async.AwaitPlainTask return (usr.Id, usr.PhoneHash, usr.Nickname) with | e -> System.Diagnostics.Trace.WriteLine(e.ToString) return (String.Empty,String.Empty,String.Empty) }
member this.RegisterMe phone name regId = async { - ( ) . "computation expression" workflow. { } ! ( bang), do! (do-bang) let! (let bang) User. , F# ,
let usr = { Id = "" PhoneHash = MD5Hash phone Nickname = name RegistrationId = regId } do! table.InsertAsync usr |> Async.AwaitPlainTask do-bang, await C#. .. continuation . return (usr.Id, usr.PhoneHash, usr.Nickname) Tuple<string,string,string> . try ... with | e -> try..catch C#

. F# fst snd . 2 . :
let id (c,_,_) = c let phonehash (_,c,_) = c let nickname (_,_,c) = c
: id tuple Id ..
5 Azure, Push . Azure Custom Api
exports.post = function(request, response) { // Use "request.service" to access features of your mobile service, eg: // var tables = request.service.tables; // var push = request.service.push; //response.send(statusCodes.OK, { message : 'Hello World!' }); console.log('Incoming call with requst: ', request.body.RequestId); var usersTable = request.service.tables.getTable('User'); usersTable.where( { id : request.body.TargetId } ) .read( { success: function(results) { if (results.length > 0) { var user = results[0] console.log('Send to results: ', user.Nickname, user.RegistrationId); request.service.push.gcm.send(user.RegistrationId, { RequesterId: request.body.RequesterId, RequesterNickname: request.body.RequesterName, TargetId: user.id, TargetNickname: user.Nickname }, { success: function(gcm_response) { console.log('Push notification sent: ', gcm_response); response.send(statusCodes.OK, { RequestedNickname : user.Nickname }); }, error: function(gcm_error) { console.log('Error sending push notification: ', gcm_error); response.send(statusCodes.INTERNAL_SERVER_ERROR, { RequestedNickname : user.Nickname }); } }); } else { response.send(statusCodes.NO_CONTENT, { RequestedNickname : "" }); } }, error: function(error) { console.log('Error read table: ', error); response.send(statusCodes.INTERNAL_SERVER_ERROR, { RequestedNickname : "" }); } }); };
Push
// Perform Push operation member this.PushAsync targetId myId myNickname = async { try let (request : PushRequest) = { TargetId = targetId RequesterId = myId RequesterName = myNickname } let! result = this.MobileService.InvokeApiAsync<PushRequest, PushResponce>("pushhim", request) |> Async.AwaitTask return result.RequestedNickname with | e -> return e.ToString() }
, let-bang do!

Google Play Services. F# . . : Xamarin.Android.Support.v7.AppCompat
, Google Play Services , .
push notification . GCM, ID, ID Push (. pushhim). BroadcastReciever developer.android.com . F# Xamarin Component Store. Google Cloud Messaging Client GCM . ID
//Check to see that GCM is supported and that the manifest has the correct information GcmClient.CheckDevice(this) GcmClient.CheckManifest(this) // check google play if CheckPlayServices() then // Try to get registration id let regId = GcmClient.GetRegistrationId this if String.IsNullOrEmpty(regId) then // Call to Register the device for Push Notifications GcmClient.Register(this, WruConstants.GcmSender);

.
, -
bitbucket.org/xakpc/whereareyou
,
, "" .
, Android F#. .
, - Android F#. , . listView.Adapter <- new ArrayAdapter(this, Android.Resource.Layout.SimpleListItem1, Android.Resource.Id.Text1, values) 
  , ,  let values = [|"item1"; "item2"; "item3"|] -   string[],       list (IEnumerable   ) 
          F#.            www.tryfsharp.org/Learn 
 
 
      F# -  ,  
 
        F# For Fun And Profit 
 
   ,    
     - . 
 
 
 
 
        hash 
     MD5  F# 
  let MD5Hash (input : string) = use md5 = System.Security.Cryptography.MD5.Create() input |> System.Text.Encoding.ASCII.GetBytes |> md5.ComputeHash |> Seq.map (fun c -> c.ToString("X2")) |> Seq.reduce (+) 
 
  |>  pipeline ,     . 
     :    GetBytes ->   ->      HEX  ->       (  reduce   +           ) ->    . 
 
  ,     C# using System; public string CreateMD5Hash (string input) { MD5 md5 = System.Security.Cryptography.MD5.Create(); byte[] inputBytes = System.Text.Encoding.ASCII.GetBytes (input); byte[] hashBytes = md5.ComputeHash (inputBytes); StringBuilder sb = new StringBuilder(); for (int i = 0; i < hashBytes.Length; i++) { sb.Append (hashBytes[i].ToString ("X2")); } return sb.ToString(); } 
 
 
          :        .       AzureServiceWorker (  CLR    ) 
 
          -   .   F#    !   Xamarin Studio            . 
  <ItemGroup> <Compile Include="Resources\Resource.designer.fs" /> <Compile Include="Properties\AssemblyInfo.fs" /> <Compile Include="Helpers\Helpers.fs" /> <Compile Include="Services\User.fs" /> <Compile Include="Services\AzureServiceWorker.fs" /> <Compile Include="IAmHereActivity.fs" /> <Compile Include="WhereAreYouActivity.fs" /> <Compile Include="SignInActivity.fs" /> </ItemGroup> 
 
    
        :    .    Xamarin    Xamarin.Mobile 
 
      .  F#         TPL,     Task',      .     F#         Task.  ,     : 
 module Async = open System.Threading open System.Threading.Tasks let inline AwaitPlainTask (task: Task) = // rethrow exception from preceding task if it fauled let continuation (t : Task) : unit = match t.IsFaulted with | true -> raise t.Exception | arg -> () task.ContinueWith continuation |> Async.AwaitTask 
         Async.AwaitIAsyncResult >> Async.Ignore       
 
            
 let ExtractUserInfo (x : Contact) = let first = x.Phones |> Seq.tryPick(fun x -> if x.Type = PhoneType.Mobile then Some(x) else None) match first with | Some(first) -> let phone = first.Number |> StripChars [' ';'-';'(';')'] UserInfo.CreateUserInfo((MD5Hash phone), phone, x.DisplayName) | None -> UserInfo.CreateUserInfo("no mobile phone", "no mobile phone", "no mobile phone") // function for async list filling let FillContactsAsync = async { let book = new AddressBook (this) let! result = book.RequestPermission() |> Async.AwaitTask if result then _contacts <- book.ToList() |> Seq.filter (fun (x: Contact) -> not (Seq.isEmpty x.Phones)) |> Seq.map ExtractUserInfo |> Seq.sortBy(fun x -> x.DisplayName) |> Seq.toList let finalContacts = _contacts |> Seq.map (fun x -> x.DisplayName.ToUpperInvariant()) |> Seq.toArray this.ListAdapter <- new ArrayAdapter(this, Resource_Layout.row_contact, finalContacts) else System.Diagnostics.Debug.WriteLine("Permission denied by user or manifest") this.ListAdapter <- new ArrayAdapter(this, Resource_Layout.row_contact, Array.empty) } 
      
 book.ToList()   List |> Seq.filter (fun (x: Contact) -> not (Seq.isEmpty x.Phones))      |> Seq.map ExtractUserInfo      Contracts  UserInfo,      UserInfo |> Seq.sortBy(fun x -> x.DisplayName)  |> Seq.toList   List _contacts <-    mutable  _contacts |> Seq.map (fun x -> x.DisplayName.ToUpperInvariant())<-    UserInfo  string,     - -    |> Seq.toArray<-  List  Array    ArrayAdapter 
    -      List.   . 
 
 
 
 
 Azure Mobile Servcies 
   -    Azure Mobile Services.       NotificationHub,     Push    .   Azure    , ..      . 
 
      ,    
 module WruConstants = [<Literal>] let TotallyNotAzureServer = "https://YOUR.azure-mobile.net/"; [<Literal>] let TotallyNotAzureKey = "YOUR" 
 
       
 member this.RegisterMe phone name regId = async { try let table = this.MobileService.GetTable<User>() let usr = { Id = "" PhoneHash = MD5Hash phone Nickname = name RegistrationId = regId } do! table.InsertAsync usr |> Async.AwaitPlainTask return (usr.Id, usr.PhoneHash, usr.Nickname) with | e -> System.Diagnostics.Trace.WriteLine(e.ToString) return (String.Empty,String.Empty,String.Empty) } 
 member this.RegisterMe phone name regId = async { -       (     )    .       "computation expression"   workflow.   { }       ! ( bang),  do! (do-bang)  let! (let bang)     User.    ,  F#        ,      
  let usr = { Id = "" PhoneHash = MD5Hash phone Nickname = name RegistrationId = regId } do! table.InsertAsync usr |> Async.AwaitPlainTask  do-bang,   await  C#. ..             continuation    . return (usr.Id, usr.PhoneHash, usr.Nickname)      Tuple<string,string,string>     .  try ... with | e ->  try..catch  C# 
 
 
 
 
       .  F#    fst  snd      .        2 .     : 
  let id (c,_,_) = c let phonehash (_,c,_) = c let nickname (_,_,c) = c 
    : id tuple  Id  .. 
 
    5  Azure,       Push .       Azure Custom Api  
 
      exports.post = function(request, response) { // Use "request.service" to access features of your mobile service, eg: // var tables = request.service.tables; // var push = request.service.push; //response.send(statusCodes.OK, { message : 'Hello World!' }); console.log('Incoming call with requst: ', request.body.RequestId); var usersTable = request.service.tables.getTable('User'); usersTable.where( { id : request.body.TargetId } ) .read( { success: function(results) { if (results.length > 0) { var user = results[0] console.log('Send to results: ', user.Nickname, user.RegistrationId); request.service.push.gcm.send(user.RegistrationId, { RequesterId: request.body.RequesterId, RequesterNickname: request.body.RequesterName, TargetId: user.id, TargetNickname: user.Nickname }, { success: function(gcm_response) { console.log('Push notification sent: ', gcm_response); response.send(statusCodes.OK, { RequestedNickname : user.Nickname }); }, error: function(gcm_error) { console.log('Error sending push notification: ', gcm_error); response.send(statusCodes.INTERNAL_SERVER_ERROR, { RequestedNickname : user.Nickname }); } }); } else { response.send(statusCodes.NO_CONTENT, { RequestedNickname : "" }); } }, error: function(error) { console.log('Error read table: ', error); response.send(statusCodes.INTERNAL_SERVER_ERROR, { RequestedNickname : "" }); } }); }; 
 
    Push      
 // Perform Push operation member this.PushAsync targetId myId myNickname = async { try let (request : PushRequest) = { TargetId = targetId RequesterId = myId RequesterName = myNickname } let! result = this.MobileService.InvokeApiAsync<PushRequest, PushResponce>("pushhim", request) |> Async.AwaitTask return result.RequestedNickname with | e -> return e.ToString() } 
 
       ,    let-bang   do! 
 
   
 
 
 
      Google Play Services.     F#   .           .    : Xamarin.Android.Support.v7.AppCompat 
     , Google Play Services ,   . 
 
      push notification   .    GCM,  ID,     ID       Push  (.   pushhim).        BroadcastReciever       developer.android.com .     F#         Xamarin Component Store.     Google Cloud Messaging Client         GCM    .        ID 
 //Check to see that GCM is supported and that the manifest has the correct information GcmClient.CheckDevice(this) GcmClient.CheckManifest(this) // check google play if CheckPlayServices() then // Try to get registration id let regId = GcmClient.GetRegistrationId this if String.IsNullOrEmpty(regId) then // Call to Register the device for Push Notifications GcmClient.Register(this, WruConstants.GcmSender); 
 
 
 
        
 
    . 
    , -  
     bitbucket.org/xakpc/whereareyou 
     ,     
          ,           "" . 
 
  
 ,   Android   F#.      . 
 ,       -  Android  F#.   ,       . listView.Adapter <- new ArrayAdapter(this, Android.Resource.Layout.SimpleListItem1, Android.Resource.Id.Text1, values)
, , let values = [|"item1"; "item2"; "item3"|] - string[], list (IEnumerable )
F#. www.tryfsharp.org/Learn

F# - ,
F# For Fun And Profit
,
- .

hash
MD5 F#
let MD5Hash (input : string) = use md5 = System.Security.Cryptography.MD5.Create() input |> System.Text.Encoding.ASCII.GetBytes |> md5.ComputeHash |> Seq.map (fun c -> c.ToString("X2")) |> Seq.reduce (+)
|> pipeline , .
: GetBytes -> -> HEX -> ( reduce + ) -> .
, C# using System; public string CreateMD5Hash (string input) { MD5 md5 = System.Security.Cryptography.MD5.Create(); byte[] inputBytes = System.Text.Encoding.ASCII.GetBytes (input); byte[] hashBytes = md5.ComputeHash (inputBytes); StringBuilder sb = new StringBuilder(); for (int i = 0; i < hashBytes.Length; i++) { sb.Append (hashBytes[i].ToString ("X2")); } return sb.ToString(); }
: . AzureServiceWorker ( CLR )
- . F# ! Xamarin Studio .
<ItemGroup> <Compile Include="Resources\Resource.designer.fs" /> <Compile Include="Properties\AssemblyInfo.fs" /> <Compile Include="Helpers\Helpers.fs" /> <Compile Include="Services\User.fs" /> <Compile Include="Services\AzureServiceWorker.fs" /> <Compile Include="IAmHereActivity.fs" /> <Compile Include="WhereAreYouActivity.fs" /> <Compile Include="SignInActivity.fs" /> </ItemGroup>
: . Xamarin Xamarin.Mobile
. F# TPL, Task', . F# Task. , :
module Async = open System.Threading open System.Threading.Tasks let inline AwaitPlainTask (task: Task) = // rethrow exception from preceding task if it fauled let continuation (t : Task) : unit = match t.IsFaulted with | true -> raise t.Exception | arg -> () task.ContinueWith continuation |> Async.AwaitTask
Async.AwaitIAsyncResult >> Async.Ignore
let ExtractUserInfo (x : Contact) = let first = x.Phones |> Seq.tryPick(fun x -> if x.Type = PhoneType.Mobile then Some(x) else None) match first with | Some(first) -> let phone = first.Number |> StripChars [' ';'-';'(';')'] UserInfo.CreateUserInfo((MD5Hash phone), phone, x.DisplayName) | None -> UserInfo.CreateUserInfo("no mobile phone", "no mobile phone", "no mobile phone") // function for async list filling let FillContactsAsync = async { let book = new AddressBook (this) let! result = book.RequestPermission() |> Async.AwaitTask if result then _contacts <- book.ToList() |> Seq.filter (fun (x: Contact) -> not (Seq.isEmpty x.Phones)) |> Seq.map ExtractUserInfo |> Seq.sortBy(fun x -> x.DisplayName) |> Seq.toList let finalContacts = _contacts |> Seq.map (fun x -> x.DisplayName.ToUpperInvariant()) |> Seq.toArray this.ListAdapter <- new ArrayAdapter(this, Resource_Layout.row_contact, finalContacts) else System.Diagnostics.Debug.WriteLine("Permission denied by user or manifest") this.ListAdapter <- new ArrayAdapter(this, Resource_Layout.row_contact, Array.empty) }
book.ToList() List |> Seq.filter (fun (x: Contact) -> not (Seq.isEmpty x.Phones)) |> Seq.map ExtractUserInfo Contracts UserInfo, UserInfo |> Seq.sortBy(fun x -> x.DisplayName) |> Seq.toList List _contacts <- mutable _contacts |> Seq.map (fun x -> x.DisplayName.ToUpperInvariant())<- UserInfo string, - - |> Seq.toArray<- List Array ArrayAdapter
- List. .

Azure Mobile Servcies
- Azure Mobile Services. NotificationHub, Push . Azure , .. .
, 
module WruConstants = [<Literal>] let TotallyNotAzureServer = "https://YOUR.azure-mobile.net/"; [<Literal>] let TotallyNotAzureKey = "YOUR"
member this.RegisterMe phone name regId = async { try let table = this.MobileService.GetTable<User>() let usr = { Id = "" PhoneHash = MD5Hash phone Nickname = name RegistrationId = regId } do! table.InsertAsync usr |> Async.AwaitPlainTask return (usr.Id, usr.PhoneHash, usr.Nickname) with | e -> System.Diagnostics.Trace.WriteLine(e.ToString) return (String.Empty,String.Empty,String.Empty) }
member this.RegisterMe phone name regId = async { - ( ) . "computation expression" workflow. { } ! ( bang), do! (do-bang) let! (let bang) User. , F# ,
let usr = { Id = "" PhoneHash = MD5Hash phone Nickname = name RegistrationId = regId } do! table.InsertAsync usr |> Async.AwaitPlainTask do-bang, await C#. .. continuation . return (usr.Id, usr.PhoneHash, usr.Nickname) Tuple<string,string,string> . try ... with | e -> try..catch C#

. F# fst snd . 2 . :
let id (c,_,_) = c let phonehash (_,c,_) = c let nickname (_,_,c) = c
: id tuple Id ..
5 Azure, Push . Azure Custom Api
exports.post = function(request, response) { // Use "request.service" to access features of your mobile service, eg: // var tables = request.service.tables; // var push = request.service.push; //response.send(statusCodes.OK, { message : 'Hello World!' }); console.log('Incoming call with requst: ', request.body.RequestId); var usersTable = request.service.tables.getTable('User'); usersTable.where( { id : request.body.TargetId } ) .read( { success: function(results) { if (results.length > 0) { var user = results[0] console.log('Send to results: ', user.Nickname, user.RegistrationId); request.service.push.gcm.send(user.RegistrationId, { RequesterId: request.body.RequesterId, RequesterNickname: request.body.RequesterName, TargetId: user.id, TargetNickname: user.Nickname }, { success: function(gcm_response) { console.log('Push notification sent: ', gcm_response); response.send(statusCodes.OK, { RequestedNickname : user.Nickname }); }, error: function(gcm_error) { console.log('Error sending push notification: ', gcm_error); response.send(statusCodes.INTERNAL_SERVER_ERROR, { RequestedNickname : user.Nickname }); } }); } else { response.send(statusCodes.NO_CONTENT, { RequestedNickname : "" }); } }, error: function(error) { console.log('Error read table: ', error); response.send(statusCodes.INTERNAL_SERVER_ERROR, { RequestedNickname : "" }); } }); };
Push
// Perform Push operation member this.PushAsync targetId myId myNickname = async { try let (request : PushRequest) = { TargetId = targetId RequesterId = myId RequesterName = myNickname } let! result = this.MobileService.InvokeApiAsync<PushRequest, PushResponce>("pushhim", request) |> Async.AwaitTask return result.RequestedNickname with | e -> return e.ToString() }
, let-bang do!

Google Play Services. F# . . : Xamarin.Android.Support.v7.AppCompat
, Google Play Services , .
push notification . GCM, ID, ID Push (. pushhim). BroadcastReciever developer.android.com . F# Xamarin Component Store. Google Cloud Messaging Client GCM . ID
//Check to see that GCM is supported and that the manifest has the correct information GcmClient.CheckDevice(this) GcmClient.CheckManifest(this) // check google play if CheckPlayServices() then // Try to get registration id let regId = GcmClient.GetRegistrationId this if String.IsNullOrEmpty(regId) then // Call to Register the device for Push Notifications GcmClient.Register(this, WruConstants.GcmSender);

.
, -
bitbucket.org/xakpc/whereareyou
,
, "" .
, Android F#. .
, - Android F#. , .listView.Adapter <- new ArrayAdapter(this, Android.Resource.Layout.SimpleListItem1, Android.Resource.Id.Text1, values)
, , let values = [|"item1"; "item2"; "item3"|] - string[], list (IEnumerable )
F#. www.tryfsharp.org/Learn

F# - ,
F# For Fun And Profit
,
- .

hash
MD5 F#
let MD5Hash (input : string) = use md5 = System.Security.Cryptography.MD5.Create() input |> System.Text.Encoding.ASCII.GetBytes |> md5.ComputeHash |> Seq.map (fun c -> c.ToString("X2")) |> Seq.reduce (+)
|> pipeline , .
: GetBytes -> -> HEX -> ( reduce + ) -> .
, C# using System; public string CreateMD5Hash (string input) { MD5 md5 = System.Security.Cryptography.MD5.Create(); byte[] inputBytes = System.Text.Encoding.ASCII.GetBytes (input); byte[] hashBytes = md5.ComputeHash (inputBytes); StringBuilder sb = new StringBuilder(); for (int i = 0; i < hashBytes.Length; i++) { sb.Append (hashBytes[i].ToString ("X2")); } return sb.ToString(); }
: . AzureServiceWorker ( CLR )
- . F# ! Xamarin Studio .
<ItemGroup> <Compile Include="Resources\Resource.designer.fs" /> <Compile Include="Properties\AssemblyInfo.fs" /> <Compile Include="Helpers\Helpers.fs" /> <Compile Include="Services\User.fs" /> <Compile Include="Services\AzureServiceWorker.fs" /> <Compile Include="IAmHereActivity.fs" /> <Compile Include="WhereAreYouActivity.fs" /> <Compile Include="SignInActivity.fs" /> </ItemGroup>
: . Xamarin Xamarin.Mobile
. F# TPL, Task', . F# Task. , :
module Async = open System.Threading open System.Threading.Tasks let inline AwaitPlainTask (task: Task) = // rethrow exception from preceding task if it fauled let continuation (t : Task) : unit = match t.IsFaulted with | true -> raise t.Exception | arg -> () task.ContinueWith continuation |> Async.AwaitTask
Async.AwaitIAsyncResult >> Async.Ignore
let ExtractUserInfo (x : Contact) = let first = x.Phones |> Seq.tryPick(fun x -> if x.Type = PhoneType.Mobile then Some(x) else None) match first with | Some(first) -> let phone = first.Number |> StripChars [' ';'-';'(';')'] UserInfo.CreateUserInfo((MD5Hash phone), phone, x.DisplayName) | None -> UserInfo.CreateUserInfo("no mobile phone", "no mobile phone", "no mobile phone") // function for async list filling let FillContactsAsync = async { let book = new AddressBook (this) let! result = book.RequestPermission() |> Async.AwaitTask if result then _contacts <- book.ToList() |> Seq.filter (fun (x: Contact) -> not (Seq.isEmpty x.Phones)) |> Seq.map ExtractUserInfo |> Seq.sortBy(fun x -> x.DisplayName) |> Seq.toList let finalContacts = _contacts |> Seq.map (fun x -> x.DisplayName.ToUpperInvariant()) |> Seq.toArray this.ListAdapter <- new ArrayAdapter(this, Resource_Layout.row_contact, finalContacts) else System.Diagnostics.Debug.WriteLine("Permission denied by user or manifest") this.ListAdapter <- new ArrayAdapter(this, Resource_Layout.row_contact, Array.empty) }
book.ToList() List |> Seq.filter (fun (x: Contact) -> not (Seq.isEmpty x.Phones)) |> Seq.map ExtractUserInfo Contracts UserInfo, UserInfo |> Seq.sortBy(fun x -> x.DisplayName) |> Seq.toList List _contacts <- mutable _contacts |> Seq.map (fun x -> x.DisplayName.ToUpperInvariant())<- UserInfo string, - - |> Seq.toArray<- List Array ArrayAdapter
- List. .

Azure Mobile Servcies
- Azure Mobile Services. NotificationHub, Push . Azure , .. .
, 
module WruConstants = [<Literal>] let TotallyNotAzureServer = "https://YOUR.azure-mobile.net/"; [<Literal>] let TotallyNotAzureKey = "YOUR"
member this.RegisterMe phone name regId = async { try let table = this.MobileService.GetTable<User>() let usr = { Id = "" PhoneHash = MD5Hash phone Nickname = name RegistrationId = regId } do! table.InsertAsync usr |> Async.AwaitPlainTask return (usr.Id, usr.PhoneHash, usr.Nickname) with | e -> System.Diagnostics.Trace.WriteLine(e.ToString) return (String.Empty,String.Empty,String.Empty) }
member this.RegisterMe phone name regId = async { - ( ) . "computation expression" workflow. { } ! ( bang), do! (do-bang) let! (let bang) User. , F# ,
let usr = { Id = "" PhoneHash = MD5Hash phone Nickname = name RegistrationId = regId } do! table.InsertAsync usr |> Async.AwaitPlainTask do-bang, await C#. .. continuation . return (usr.Id, usr.PhoneHash, usr.Nickname) Tuple<string,string,string> . try ... with | e -> try..catch C#

. F# fst snd . 2 . :
let id (c,_,_) = c let phonehash (_,c,_) = c let nickname (_,_,c) = c
: id tuple Id ..
5 Azure, Push . Azure Custom Api
exports.post = function(request, response) { // Use "request.service" to access features of your mobile service, eg: // var tables = request.service.tables; // var push = request.service.push; //response.send(statusCodes.OK, { message : 'Hello World!' }); console.log('Incoming call with requst: ', request.body.RequestId); var usersTable = request.service.tables.getTable('User'); usersTable.where( { id : request.body.TargetId } ) .read( { success: function(results) { if (results.length > 0) { var user = results[0] console.log('Send to results: ', user.Nickname, user.RegistrationId); request.service.push.gcm.send(user.RegistrationId, { RequesterId: request.body.RequesterId, RequesterNickname: request.body.RequesterName, TargetId: user.id, TargetNickname: user.Nickname }, { success: function(gcm_response) { console.log('Push notification sent: ', gcm_response); response.send(statusCodes.OK, { RequestedNickname : user.Nickname }); }, error: function(gcm_error) { console.log('Error sending push notification: ', gcm_error); response.send(statusCodes.INTERNAL_SERVER_ERROR, { RequestedNickname : user.Nickname }); } }); } else { response.send(statusCodes.NO_CONTENT, { RequestedNickname : "" }); } }, error: function(error) { console.log('Error read table: ', error); response.send(statusCodes.INTERNAL_SERVER_ERROR, { RequestedNickname : "" }); } }); };
Push
// Perform Push operation member this.PushAsync targetId myId myNickname = async { try let (request : PushRequest) = { TargetId = targetId RequesterId = myId RequesterName = myNickname } let! result = this.MobileService.InvokeApiAsync<PushRequest, PushResponce>("pushhim", request) |> Async.AwaitTask return result.RequestedNickname with | e -> return e.ToString() }
, let-bang do!

Google Play Services. F# . . : Xamarin.Android.Support.v7.AppCompat
, Google Play Services , .
push notification . GCM, ID, ID Push (. pushhim). BroadcastReciever developer.android.com . F# Xamarin Component Store. Google Cloud Messaging Client GCM . ID
//Check to see that GCM is supported and that the manifest has the correct information GcmClient.CheckDevice(this) GcmClient.CheckManifest(this) // check google play if CheckPlayServices() then // Try to get registration id let regId = GcmClient.GetRegistrationId this if String.IsNullOrEmpty(regId) then // Call to Register the device for Push Notifications GcmClient.Register(this, WruConstants.GcmSender);

.
, -
bitbucket.org/xakpc/whereareyou
,
, "" .
, Android F#. .
, - Android F#. , .listView.Adapter <- new ArrayAdapter(this, Android.Resource.Layout.SimpleListItem1, Android.Resource.Id.Text1, values)
, , let values = [|"item1"; "item2"; "item3"|] - string[], list (IEnumerable )
F#. www.tryfsharp.org/Learn

F# - ,
F# For Fun And Profit
,
- .

hash
MD5 F#
let MD5Hash (input : string) = use md5 = System.Security.Cryptography.MD5.Create() input |> System.Text.Encoding.ASCII.GetBytes |> md5.ComputeHash |> Seq.map (fun c -> c.ToString("X2")) |> Seq.reduce (+)
|> pipeline , .
: GetBytes -> -> HEX -> ( reduce + ) -> .
, C# using System; public string CreateMD5Hash (string input) { MD5 md5 = System.Security.Cryptography.MD5.Create(); byte[] inputBytes = System.Text.Encoding.ASCII.GetBytes (input); byte[] hashBytes = md5.ComputeHash (inputBytes); StringBuilder sb = new StringBuilder(); for (int i = 0; i < hashBytes.Length; i++) { sb.Append (hashBytes[i].ToString ("X2")); } return sb.ToString(); }
: . AzureServiceWorker ( CLR )
- . F# ! Xamarin Studio .
<ItemGroup> <Compile Include="Resources\Resource.designer.fs" /> <Compile Include="Properties\AssemblyInfo.fs" /> <Compile Include="Helpers\Helpers.fs" /> <Compile Include="Services\User.fs" /> <Compile Include="Services\AzureServiceWorker.fs" /> <Compile Include="IAmHereActivity.fs" /> <Compile Include="WhereAreYouActivity.fs" /> <Compile Include="SignInActivity.fs" /> </ItemGroup>
: . Xamarin Xamarin.Mobile
. F# TPL, Task', . F# Task. , :
module Async = open System.Threading open System.Threading.Tasks let inline AwaitPlainTask (task: Task) = // rethrow exception from preceding task if it fauled let continuation (t : Task) : unit = match t.IsFaulted with | true -> raise t.Exception | arg -> () task.ContinueWith continuation |> Async.AwaitTask
Async.AwaitIAsyncResult >> Async.Ignore
let ExtractUserInfo (x : Contact) = let first = x.Phones |> Seq.tryPick(fun x -> if x.Type = PhoneType.Mobile then Some(x) else None) match first with | Some(first) -> let phone = first.Number |> StripChars [' ';'-';'(';')'] UserInfo.CreateUserInfo((MD5Hash phone), phone, x.DisplayName) | None -> UserInfo.CreateUserInfo("no mobile phone", "no mobile phone", "no mobile phone") // function for async list filling let FillContactsAsync = async { let book = new AddressBook (this) let! result = book.RequestPermission() |> Async.AwaitTask if result then _contacts <- book.ToList() |> Seq.filter (fun (x: Contact) -> not (Seq.isEmpty x.Phones)) |> Seq.map ExtractUserInfo |> Seq.sortBy(fun x -> x.DisplayName) |> Seq.toList let finalContacts = _contacts |> Seq.map (fun x -> x.DisplayName.ToUpperInvariant()) |> Seq.toArray this.ListAdapter <- new ArrayAdapter(this, Resource_Layout.row_contact, finalContacts) else System.Diagnostics.Debug.WriteLine("Permission denied by user or manifest") this.ListAdapter <- new ArrayAdapter(this, Resource_Layout.row_contact, Array.empty) }
book.ToList() List |> Seq.filter (fun (x: Contact) -> not (Seq.isEmpty x.Phones)) |> Seq.map ExtractUserInfo Contracts UserInfo, UserInfo |> Seq.sortBy(fun x -> x.DisplayName) |> Seq.toList List _contacts <- mutable _contacts |> Seq.map (fun x -> x.DisplayName.ToUpperInvariant())<- UserInfo string, - - |> Seq.toArray<- List Array ArrayAdapter
- List. .

Azure Mobile Servcies
- Azure Mobile Services. NotificationHub, Push . Azure , .. .
, 
module WruConstants = [<Literal>] let TotallyNotAzureServer = "https://YOUR.azure-mobile.net/"; [<Literal>] let TotallyNotAzureKey = "YOUR"
member this.RegisterMe phone name regId = async { try let table = this.MobileService.GetTable<User>() let usr = { Id = "" PhoneHash = MD5Hash phone Nickname = name RegistrationId = regId } do! table.InsertAsync usr |> Async.AwaitPlainTask return (usr.Id, usr.PhoneHash, usr.Nickname) with | e -> System.Diagnostics.Trace.WriteLine(e.ToString) return (String.Empty,String.Empty,String.Empty) }
member this.RegisterMe phone name regId = async { - ( ) . "computation expression" workflow. { } ! ( bang), do! (do-bang) let! (let bang) User. , F# ,
let usr = { Id = "" PhoneHash = MD5Hash phone Nickname = name RegistrationId = regId } do! table.InsertAsync usr |> Async.AwaitPlainTask do-bang, await C#. .. continuation . return (usr.Id, usr.PhoneHash, usr.Nickname) Tuple<string,string,string> . try ... with | e -> try..catch C#

. F# fst snd . 2 . :
let id (c,_,_) = c let phonehash (_,c,_) = c let nickname (_,_,c) = c
: id tuple Id ..
5 Azure, Push . Azure Custom Api
exports.post = function(request, response) { // Use "request.service" to access features of your mobile service, eg: // var tables = request.service.tables; // var push = request.service.push; //response.send(statusCodes.OK, { message : 'Hello World!' }); console.log('Incoming call with requst: ', request.body.RequestId); var usersTable = request.service.tables.getTable('User'); usersTable.where( { id : request.body.TargetId } ) .read( { success: function(results) { if (results.length > 0) { var user = results[0] console.log('Send to results: ', user.Nickname, user.RegistrationId); request.service.push.gcm.send(user.RegistrationId, { RequesterId: request.body.RequesterId, RequesterNickname: request.body.RequesterName, TargetId: user.id, TargetNickname: user.Nickname }, { success: function(gcm_response) { console.log('Push notification sent: ', gcm_response); response.send(statusCodes.OK, { RequestedNickname : user.Nickname }); }, error: function(gcm_error) { console.log('Error sending push notification: ', gcm_error); response.send(statusCodes.INTERNAL_SERVER_ERROR, { RequestedNickname : user.Nickname }); } }); } else { response.send(statusCodes.NO_CONTENT, { RequestedNickname : "" }); } }, error: function(error) { console.log('Error read table: ', error); response.send(statusCodes.INTERNAL_SERVER_ERROR, { RequestedNickname : "" }); } }); };
Push
// Perform Push operation member this.PushAsync targetId myId myNickname = async { try let (request : PushRequest) = { TargetId = targetId RequesterId = myId RequesterName = myNickname } let! result = this.MobileService.InvokeApiAsync<PushRequest, PushResponce>("pushhim", request) |> Async.AwaitTask return result.RequestedNickname with | e -> return e.ToString() }
, let-bang do!

Google Play Services. F# . . : Xamarin.Android.Support.v7.AppCompat
, Google Play Services , .
push notification . GCM, ID, ID Push (. pushhim). BroadcastReciever developer.android.com . F# Xamarin Component Store. Google Cloud Messaging Client GCM . ID
//Check to see that GCM is supported and that the manifest has the correct information GcmClient.CheckDevice(this) GcmClient.CheckManifest(this) // check google play if CheckPlayServices() then // Try to get registration id let regId = GcmClient.GetRegistrationId this if String.IsNullOrEmpty(regId) then // Call to Register the device for Push Notifications GcmClient.Register(this, WruConstants.GcmSender);

.
, -
bitbucket.org/xakpc/whereareyou
,
, "" .
, Android F#. .
, - Android F#. , . listView.Adapter <- new ArrayAdapter(this, Android.Resource.Layout.SimpleListItem1, Android.Resource.Id.Text1, values) 
  , ,  let values = [|"item1"; "item2"; "item3"|] -   string[],       list (IEnumerable   ) 
          F#.            www.tryfsharp.org/Learn 
 
 
      F# -  ,  
 
        F# For Fun And Profit 
 
   ,    
     - . 
 
 
 
 
        hash 
     MD5  F# 
  let MD5Hash (input : string) = use md5 = System.Security.Cryptography.MD5.Create() input |> System.Text.Encoding.ASCII.GetBytes |> md5.ComputeHash |> Seq.map (fun c -> c.ToString("X2")) |> Seq.reduce (+) 
 
  |>  pipeline ,     . 
     :    GetBytes ->   ->      HEX  ->       (  reduce   +           ) ->    . 
 
  ,     C# using System; public string CreateMD5Hash (string input) { MD5 md5 = System.Security.Cryptography.MD5.Create(); byte[] inputBytes = System.Text.Encoding.ASCII.GetBytes (input); byte[] hashBytes = md5.ComputeHash (inputBytes); StringBuilder sb = new StringBuilder(); for (int i = 0; i < hashBytes.Length; i++) { sb.Append (hashBytes[i].ToString ("X2")); } return sb.ToString(); } 
 
 
          :        .       AzureServiceWorker (  CLR    ) 
 
          -   .   F#    !   Xamarin Studio            . 
  <ItemGroup> <Compile Include="Resources\Resource.designer.fs" /> <Compile Include="Properties\AssemblyInfo.fs" /> <Compile Include="Helpers\Helpers.fs" /> <Compile Include="Services\User.fs" /> <Compile Include="Services\AzureServiceWorker.fs" /> <Compile Include="IAmHereActivity.fs" /> <Compile Include="WhereAreYouActivity.fs" /> <Compile Include="SignInActivity.fs" /> </ItemGroup> 
 
    
        :    .    Xamarin    Xamarin.Mobile 
 
      .  F#         TPL,     Task',      .     F#         Task.  ,     : 
 module Async = open System.Threading open System.Threading.Tasks let inline AwaitPlainTask (task: Task) = // rethrow exception from preceding task if it fauled let continuation (t : Task) : unit = match t.IsFaulted with | true -> raise t.Exception | arg -> () task.ContinueWith continuation |> Async.AwaitTask 
         Async.AwaitIAsyncResult >> Async.Ignore       
 
            
 let ExtractUserInfo (x : Contact) = let first = x.Phones |> Seq.tryPick(fun x -> if x.Type = PhoneType.Mobile then Some(x) else None) match first with | Some(first) -> let phone = first.Number |> StripChars [' ';'-';'(';')'] UserInfo.CreateUserInfo((MD5Hash phone), phone, x.DisplayName) | None -> UserInfo.CreateUserInfo("no mobile phone", "no mobile phone", "no mobile phone") // function for async list filling let FillContactsAsync = async { let book = new AddressBook (this) let! result = book.RequestPermission() |> Async.AwaitTask if result then _contacts <- book.ToList() |> Seq.filter (fun (x: Contact) -> not (Seq.isEmpty x.Phones)) |> Seq.map ExtractUserInfo |> Seq.sortBy(fun x -> x.DisplayName) |> Seq.toList let finalContacts = _contacts |> Seq.map (fun x -> x.DisplayName.ToUpperInvariant()) |> Seq.toArray this.ListAdapter <- new ArrayAdapter(this, Resource_Layout.row_contact, finalContacts) else System.Diagnostics.Debug.WriteLine("Permission denied by user or manifest") this.ListAdapter <- new ArrayAdapter(this, Resource_Layout.row_contact, Array.empty) } 
      
 book.ToList()   List |> Seq.filter (fun (x: Contact) -> not (Seq.isEmpty x.Phones))      |> Seq.map ExtractUserInfo      Contracts  UserInfo,      UserInfo |> Seq.sortBy(fun x -> x.DisplayName)  |> Seq.toList   List _contacts <-    mutable  _contacts |> Seq.map (fun x -> x.DisplayName.ToUpperInvariant())<-    UserInfo  string,     - -    |> Seq.toArray<-  List  Array    ArrayAdapter 
    -      List.   . 
 
 
 
 
 Azure Mobile Servcies 
   -    Azure Mobile Services.       NotificationHub,     Push    .   Azure    , ..      . 
 
      ,    
 module WruConstants = [<Literal>] let TotallyNotAzureServer = "https://YOUR.azure-mobile.net/"; [<Literal>] let TotallyNotAzureKey = "YOUR" 
 
       
 member this.RegisterMe phone name regId = async { try let table = this.MobileService.GetTable<User>() let usr = { Id = "" PhoneHash = MD5Hash phone Nickname = name RegistrationId = regId } do! table.InsertAsync usr |> Async.AwaitPlainTask return (usr.Id, usr.PhoneHash, usr.Nickname) with | e -> System.Diagnostics.Trace.WriteLine(e.ToString) return (String.Empty,String.Empty,String.Empty) } 
 member this.RegisterMe phone name regId = async { -       (     )    .       "computation expression"   workflow.   { }       ! ( bang),  do! (do-bang)  let! (let bang)     User.    ,  F#        ,      
  let usr = { Id = "" PhoneHash = MD5Hash phone Nickname = name RegistrationId = regId } do! table.InsertAsync usr |> Async.AwaitPlainTask  do-bang,   await  C#. ..             continuation    . return (usr.Id, usr.PhoneHash, usr.Nickname)      Tuple<string,string,string>     .  try ... with | e ->  try..catch  C# 
 
 
 
 
       .  F#    fst  snd      .        2 .     : 
  let id (c,_,_) = c let phonehash (_,c,_) = c let nickname (_,_,c) = c 
    : id tuple  Id  .. 
 
    5  Azure,       Push .       Azure Custom Api  
 
      exports.post = function(request, response) { // Use "request.service" to access features of your mobile service, eg: // var tables = request.service.tables; // var push = request.service.push; //response.send(statusCodes.OK, { message : 'Hello World!' }); console.log('Incoming call with requst: ', request.body.RequestId); var usersTable = request.service.tables.getTable('User'); usersTable.where( { id : request.body.TargetId } ) .read( { success: function(results) { if (results.length > 0) { var user = results[0] console.log('Send to results: ', user.Nickname, user.RegistrationId); request.service.push.gcm.send(user.RegistrationId, { RequesterId: request.body.RequesterId, RequesterNickname: request.body.RequesterName, TargetId: user.id, TargetNickname: user.Nickname }, { success: function(gcm_response) { console.log('Push notification sent: ', gcm_response); response.send(statusCodes.OK, { RequestedNickname : user.Nickname }); }, error: function(gcm_error) { console.log('Error sending push notification: ', gcm_error); response.send(statusCodes.INTERNAL_SERVER_ERROR, { RequestedNickname : user.Nickname }); } }); } else { response.send(statusCodes.NO_CONTENT, { RequestedNickname : "" }); } }, error: function(error) { console.log('Error read table: ', error); response.send(statusCodes.INTERNAL_SERVER_ERROR, { RequestedNickname : "" }); } }); }; 
 
    Push      
 // Perform Push operation member this.PushAsync targetId myId myNickname = async { try let (request : PushRequest) = { TargetId = targetId RequesterId = myId RequesterName = myNickname } let! result = this.MobileService.InvokeApiAsync<PushRequest, PushResponce>("pushhim", request) |> Async.AwaitTask return result.RequestedNickname with | e -> return e.ToString() } 
 
       ,    let-bang   do! 
 
   
 
 
 
      Google Play Services.     F#   .           .    : Xamarin.Android.Support.v7.AppCompat 
     , Google Play Services ,   . 
 
      push notification   .    GCM,  ID,     ID       Push  (.   pushhim).        BroadcastReciever       developer.android.com .     F#         Xamarin Component Store.     Google Cloud Messaging Client         GCM    .        ID 
 //Check to see that GCM is supported and that the manifest has the correct information GcmClient.CheckDevice(this) GcmClient.CheckManifest(this) // check google play if CheckPlayServices() then // Try to get registration id let regId = GcmClient.GetRegistrationId this if String.IsNullOrEmpty(regId) then // Call to Register the device for Push Notifications GcmClient.Register(this, WruConstants.GcmSender); 
 
 
 
        
 
    . 
    , -  
     bitbucket.org/xakpc/whereareyou 
     ,     
          ,           "" . 
 
  
 ,   Android   F#.      . 
 ,       -  Android  F#.   ,       . listView.Adapter <- new ArrayAdapter(this, Android.Resource.Layout.SimpleListItem1, Android.Resource.Id.Text1, values)
, , let values = [|"item1"; "item2"; "item3"|] - string[], list (IEnumerable )
F#. www.tryfsharp.org/Learn

F# - ,
F# For Fun And Profit
,
- .

hash
MD5 F#
let MD5Hash (input : string) = use md5 = System.Security.Cryptography.MD5.Create() input |> System.Text.Encoding.ASCII.GetBytes |> md5.ComputeHash |> Seq.map (fun c -> c.ToString("X2")) |> Seq.reduce (+)
|> pipeline , .
: GetBytes -> -> HEX -> ( reduce + ) -> .
, C# using System; public string CreateMD5Hash (string input) { MD5 md5 = System.Security.Cryptography.MD5.Create(); byte[] inputBytes = System.Text.Encoding.ASCII.GetBytes (input); byte[] hashBytes = md5.ComputeHash (inputBytes); StringBuilder sb = new StringBuilder(); for (int i = 0; i < hashBytes.Length; i++) { sb.Append (hashBytes[i].ToString ("X2")); } return sb.ToString(); }
: . AzureServiceWorker ( CLR )
- . F# ! Xamarin Studio .
<ItemGroup> <Compile Include="Resources\Resource.designer.fs" /> <Compile Include="Properties\AssemblyInfo.fs" /> <Compile Include="Helpers\Helpers.fs" /> <Compile Include="Services\User.fs" /> <Compile Include="Services\AzureServiceWorker.fs" /> <Compile Include="IAmHereActivity.fs" /> <Compile Include="WhereAreYouActivity.fs" /> <Compile Include="SignInActivity.fs" /> </ItemGroup>
: . Xamarin Xamarin.Mobile
. F# TPL, Task', . F# Task. , :
module Async = open System.Threading open System.Threading.Tasks let inline AwaitPlainTask (task: Task) = // rethrow exception from preceding task if it fauled let continuation (t : Task) : unit = match t.IsFaulted with | true -> raise t.Exception | arg -> () task.ContinueWith continuation |> Async.AwaitTask
Async.AwaitIAsyncResult >> Async.Ignore
let ExtractUserInfo (x : Contact) = let first = x.Phones |> Seq.tryPick(fun x -> if x.Type = PhoneType.Mobile then Some(x) else None) match first with | Some(first) -> let phone = first.Number |> StripChars [' ';'-';'(';')'] UserInfo.CreateUserInfo((MD5Hash phone), phone, x.DisplayName) | None -> UserInfo.CreateUserInfo("no mobile phone", "no mobile phone", "no mobile phone") // function for async list filling let FillContactsAsync = async { let book = new AddressBook (this) let! result = book.RequestPermission() |> Async.AwaitTask if result then _contacts <- book.ToList() |> Seq.filter (fun (x: Contact) -> not (Seq.isEmpty x.Phones)) |> Seq.map ExtractUserInfo |> Seq.sortBy(fun x -> x.DisplayName) |> Seq.toList let finalContacts = _contacts |> Seq.map (fun x -> x.DisplayName.ToUpperInvariant()) |> Seq.toArray this.ListAdapter <- new ArrayAdapter(this, Resource_Layout.row_contact, finalContacts) else System.Diagnostics.Debug.WriteLine("Permission denied by user or manifest") this.ListAdapter <- new ArrayAdapter(this, Resource_Layout.row_contact, Array.empty) }
book.ToList() List |> Seq.filter (fun (x: Contact) -> not (Seq.isEmpty x.Phones)) |> Seq.map ExtractUserInfo Contracts UserInfo, UserInfo |> Seq.sortBy(fun x -> x.DisplayName) |> Seq.toList List _contacts <- mutable _contacts |> Seq.map (fun x -> x.DisplayName.ToUpperInvariant())<- UserInfo string, - - |> Seq.toArray<- List Array ArrayAdapter
- List. .

Azure Mobile Servcies
- Azure Mobile Services. NotificationHub, Push . Azure , .. .
, 
module WruConstants = [<Literal>] let TotallyNotAzureServer = "https://YOUR.azure-mobile.net/"; [<Literal>] let TotallyNotAzureKey = "YOUR"
member this.RegisterMe phone name regId = async { try let table = this.MobileService.GetTable<User>() let usr = { Id = "" PhoneHash = MD5Hash phone Nickname = name RegistrationId = regId } do! table.InsertAsync usr |> Async.AwaitPlainTask return (usr.Id, usr.PhoneHash, usr.Nickname) with | e -> System.Diagnostics.Trace.WriteLine(e.ToString) return (String.Empty,String.Empty,String.Empty) }
member this.RegisterMe phone name regId = async { - ( ) . "computation expression" workflow. { } ! ( bang), do! (do-bang) let! (let bang) User. , F# ,
let usr = { Id = "" PhoneHash = MD5Hash phone Nickname = name RegistrationId = regId } do! table.InsertAsync usr |> Async.AwaitPlainTask do-bang, await C#. .. continuation . return (usr.Id, usr.PhoneHash, usr.Nickname) Tuple<string,string,string> . try ... with | e -> try..catch C#

. F# fst snd . 2 . :
let id (c,_,_) = c let phonehash (_,c,_) = c let nickname (_,_,c) = c
: id tuple Id ..
5 Azure, Push . Azure Custom Api
exports.post = function(request, response) { // Use "request.service" to access features of your mobile service, eg: // var tables = request.service.tables; // var push = request.service.push; //response.send(statusCodes.OK, { message : 'Hello World!' }); console.log('Incoming call with requst: ', request.body.RequestId); var usersTable = request.service.tables.getTable('User'); usersTable.where( { id : request.body.TargetId } ) .read( { success: function(results) { if (results.length > 0) { var user = results[0] console.log('Send to results: ', user.Nickname, user.RegistrationId); request.service.push.gcm.send(user.RegistrationId, { RequesterId: request.body.RequesterId, RequesterNickname: request.body.RequesterName, TargetId: user.id, TargetNickname: user.Nickname }, { success: function(gcm_response) { console.log('Push notification sent: ', gcm_response); response.send(statusCodes.OK, { RequestedNickname : user.Nickname }); }, error: function(gcm_error) { console.log('Error sending push notification: ', gcm_error); response.send(statusCodes.INTERNAL_SERVER_ERROR, { RequestedNickname : user.Nickname }); } }); } else { response.send(statusCodes.NO_CONTENT, { RequestedNickname : "" }); } }, error: function(error) { console.log('Error read table: ', error); response.send(statusCodes.INTERNAL_SERVER_ERROR, { RequestedNickname : "" }); } }); };
Push
// Perform Push operation member this.PushAsync targetId myId myNickname = async { try let (request : PushRequest) = { TargetId = targetId RequesterId = myId RequesterName = myNickname } let! result = this.MobileService.InvokeApiAsync<PushRequest, PushResponce>("pushhim", request) |> Async.AwaitTask return result.RequestedNickname with | e -> return e.ToString() }
, let-bang do!

Google Play Services. F# . . : Xamarin.Android.Support.v7.AppCompat
, Google Play Services , .
push notification . GCM, ID, ID Push (. pushhim). BroadcastReciever developer.android.com . F# Xamarin Component Store. Google Cloud Messaging Client GCM . ID
//Check to see that GCM is supported and that the manifest has the correct information GcmClient.CheckDevice(this) GcmClient.CheckManifest(this) // check google play if CheckPlayServices() then // Try to get registration id let regId = GcmClient.GetRegistrationId this if String.IsNullOrEmpty(regId) then // Call to Register the device for Push Notifications GcmClient.Register(this, WruConstants.GcmSender);

.
, -
bitbucket.org/xakpc/whereareyou
,
, "" .
, Android F#. .
, - Android F#. , .listView.Adapter <- new ArrayAdapter(this, Android.Resource.Layout.SimpleListItem1, Android.Resource.Id.Text1, values)
, , let values = [|"item1"; "item2"; "item3"|] - string[], list (IEnumerable )
F#. www.tryfsharp.org/Learn

F# - ,
F# For Fun And Profit
,
- .

hash
MD5 F#
let MD5Hash (input : string) = use md5 = System.Security.Cryptography.MD5.Create() input |> System.Text.Encoding.ASCII.GetBytes |> md5.ComputeHash |> Seq.map (fun c -> c.ToString("X2")) |> Seq.reduce (+)
|> pipeline , .
: GetBytes -> -> HEX -> ( reduce + ) -> .
, C# using System; public string CreateMD5Hash (string input) { MD5 md5 = System.Security.Cryptography.MD5.Create(); byte[] inputBytes = System.Text.Encoding.ASCII.GetBytes (input); byte[] hashBytes = md5.ComputeHash (inputBytes); StringBuilder sb = new StringBuilder(); for (int i = 0; i < hashBytes.Length; i++) { sb.Append (hashBytes[i].ToString ("X2")); } return sb.ToString(); }
: . AzureServiceWorker ( CLR )
- . F# ! Xamarin Studio .
<ItemGroup> <Compile Include="Resources\Resource.designer.fs" /> <Compile Include="Properties\AssemblyInfo.fs" /> <Compile Include="Helpers\Helpers.fs" /> <Compile Include="Services\User.fs" /> <Compile Include="Services\AzureServiceWorker.fs" /> <Compile Include="IAmHereActivity.fs" /> <Compile Include="WhereAreYouActivity.fs" /> <Compile Include="SignInActivity.fs" /> </ItemGroup>
: . Xamarin Xamarin.Mobile
. F# TPL, Task', . F# Task. , :
module Async = open System.Threading open System.Threading.Tasks let inline AwaitPlainTask (task: Task) = // rethrow exception from preceding task if it fauled let continuation (t : Task) : unit = match t.IsFaulted with | true -> raise t.Exception | arg -> () task.ContinueWith continuation |> Async.AwaitTask
Async.AwaitIAsyncResult >> Async.Ignore
let ExtractUserInfo (x : Contact) = let first = x.Phones |> Seq.tryPick(fun x -> if x.Type = PhoneType.Mobile then Some(x) else None) match first with | Some(first) -> let phone = first.Number |> StripChars [' ';'-';'(';')'] UserInfo.CreateUserInfo((MD5Hash phone), phone, x.DisplayName) | None -> UserInfo.CreateUserInfo("no mobile phone", "no mobile phone", "no mobile phone") // function for async list filling let FillContactsAsync = async { let book = new AddressBook (this) let! result = book.RequestPermission() |> Async.AwaitTask if result then _contacts <- book.ToList() |> Seq.filter (fun (x: Contact) -> not (Seq.isEmpty x.Phones)) |> Seq.map ExtractUserInfo |> Seq.sortBy(fun x -> x.DisplayName) |> Seq.toList let finalContacts = _contacts |> Seq.map (fun x -> x.DisplayName.ToUpperInvariant()) |> Seq.toArray this.ListAdapter <- new ArrayAdapter(this, Resource_Layout.row_contact, finalContacts) else System.Diagnostics.Debug.WriteLine("Permission denied by user or manifest") this.ListAdapter <- new ArrayAdapter(this, Resource_Layout.row_contact, Array.empty) }
book.ToList() List |> Seq.filter (fun (x: Contact) -> not (Seq.isEmpty x.Phones)) |> Seq.map ExtractUserInfo Contracts UserInfo, UserInfo |> Seq.sortBy(fun x -> x.DisplayName) |> Seq.toList List _contacts <- mutable _contacts |> Seq.map (fun x -> x.DisplayName.ToUpperInvariant())<- UserInfo string, - - |> Seq.toArray<- List Array ArrayAdapter
- List. .

Azure Mobile Servcies
- Azure Mobile Services. NotificationHub, Push . Azure , .. .
, 
module WruConstants = [<Literal>] let TotallyNotAzureServer = "https://YOUR.azure-mobile.net/"; [<Literal>] let TotallyNotAzureKey = "YOUR"
member this.RegisterMe phone name regId = async { try let table = this.MobileService.GetTable<User>() let usr = { Id = "" PhoneHash = MD5Hash phone Nickname = name RegistrationId = regId } do! table.InsertAsync usr |> Async.AwaitPlainTask return (usr.Id, usr.PhoneHash, usr.Nickname) with | e -> System.Diagnostics.Trace.WriteLine(e.ToString) return (String.Empty,String.Empty,String.Empty) }
member this.RegisterMe phone name regId = async { - ( ) . "computation expression" workflow. { } ! ( bang), do! (do-bang) let! (let bang) User. , F# ,
let usr = { Id = "" PhoneHash = MD5Hash phone Nickname = name RegistrationId = regId } do! table.InsertAsync usr |> Async.AwaitPlainTask do-bang, await C#. .. continuation . return (usr.Id, usr.PhoneHash, usr.Nickname) Tuple<string,string,string> . try ... with | e -> try..catch C#

. F# fst snd . 2 . :
let id (c,_,_) = c let phonehash (_,c,_) = c let nickname (_,_,c) = c
: id tuple Id ..
5 Azure, Push . Azure Custom Api
exports.post = function(request, response) { // Use "request.service" to access features of your mobile service, eg: // var tables = request.service.tables; // var push = request.service.push; //response.send(statusCodes.OK, { message : 'Hello World!' }); console.log('Incoming call with requst: ', request.body.RequestId); var usersTable = request.service.tables.getTable('User'); usersTable.where( { id : request.body.TargetId } ) .read( { success: function(results) { if (results.length > 0) { var user = results[0] console.log('Send to results: ', user.Nickname, user.RegistrationId); request.service.push.gcm.send(user.RegistrationId, { RequesterId: request.body.RequesterId, RequesterNickname: request.body.RequesterName, TargetId: user.id, TargetNickname: user.Nickname }, { success: function(gcm_response) { console.log('Push notification sent: ', gcm_response); response.send(statusCodes.OK, { RequestedNickname : user.Nickname }); }, error: function(gcm_error) { console.log('Error sending push notification: ', gcm_error); response.send(statusCodes.INTERNAL_SERVER_ERROR, { RequestedNickname : user.Nickname }); } }); } else { response.send(statusCodes.NO_CONTENT, { RequestedNickname : "" }); } }, error: function(error) { console.log('Error read table: ', error); response.send(statusCodes.INTERNAL_SERVER_ERROR, { RequestedNickname : "" }); } }); };
Push
// Perform Push operation member this.PushAsync targetId myId myNickname = async { try let (request : PushRequest) = { TargetId = targetId RequesterId = myId RequesterName = myNickname } let! result = this.MobileService.InvokeApiAsync<PushRequest, PushResponce>("pushhim", request) |> Async.AwaitTask return result.RequestedNickname with | e -> return e.ToString() }
, let-bang do!

Google Play Services. F# . . : Xamarin.Android.Support.v7.AppCompat
, Google Play Services , .
push notification . GCM, ID, ID Push (. pushhim). BroadcastReciever developer.android.com . F# Xamarin Component Store. Google Cloud Messaging Client GCM . ID
//Check to see that GCM is supported and that the manifest has the correct information GcmClient.CheckDevice(this) GcmClient.CheckManifest(this) // check google play if CheckPlayServices() then // Try to get registration id let regId = GcmClient.GetRegistrationId this if String.IsNullOrEmpty(regId) then // Call to Register the device for Push Notifications GcmClient.Register(this, WruConstants.GcmSender);

.
, -
bitbucket.org/xakpc/whereareyou
,
, "" .
, Android F#. .
, - Android F#. , .listView.Adapter <- new ArrayAdapter(this, Android.Resource.Layout.SimpleListItem1, Android.Resource.Id.Text1, values)
, , let values = [|"item1"; "item2"; "item3"|] - string[], list (IEnumerable )
F#. www.tryfsharp.org/Learn

F# - ,
F# For Fun And Profit
,
- .

hash
MD5 F#
let MD5Hash (input : string) = use md5 = System.Security.Cryptography.MD5.Create() input |> System.Text.Encoding.ASCII.GetBytes |> md5.ComputeHash |> Seq.map (fun c -> c.ToString("X2")) |> Seq.reduce (+)
|> pipeline , .
: GetBytes -> -> HEX -> ( reduce + ) -> .
, C# using System; public string CreateMD5Hash (string input) { MD5 md5 = System.Security.Cryptography.MD5.Create(); byte[] inputBytes = System.Text.Encoding.ASCII.GetBytes (input); byte[] hashBytes = md5.ComputeHash (inputBytes); StringBuilder sb = new StringBuilder(); for (int i = 0; i < hashBytes.Length; i++) { sb.Append (hashBytes[i].ToString ("X2")); } return sb.ToString(); }
: . AzureServiceWorker ( CLR )
- . F# ! Xamarin Studio .
<ItemGroup> <Compile Include="Resources\Resource.designer.fs" /> <Compile Include="Properties\AssemblyInfo.fs" /> <Compile Include="Helpers\Helpers.fs" /> <Compile Include="Services\User.fs" /> <Compile Include="Services\AzureServiceWorker.fs" /> <Compile Include="IAmHereActivity.fs" /> <Compile Include="WhereAreYouActivity.fs" /> <Compile Include="SignInActivity.fs" /> </ItemGroup>
: . Xamarin Xamarin.Mobile
. F# TPL, Task', . F# Task. , :
module Async = open System.Threading open System.Threading.Tasks let inline AwaitPlainTask (task: Task) = // rethrow exception from preceding task if it fauled let continuation (t : Task) : unit = match t.IsFaulted with | true -> raise t.Exception | arg -> () task.ContinueWith continuation |> Async.AwaitTask
Async.AwaitIAsyncResult >> Async.Ignore
let ExtractUserInfo (x : Contact) = let first = x.Phones |> Seq.tryPick(fun x -> if x.Type = PhoneType.Mobile then Some(x) else None) match first with | Some(first) -> let phone = first.Number |> StripChars [' ';'-';'(';')'] UserInfo.CreateUserInfo((MD5Hash phone), phone, x.DisplayName) | None -> UserInfo.CreateUserInfo("no mobile phone", "no mobile phone", "no mobile phone") // function for async list filling let FillContactsAsync = async { let book = new AddressBook (this) let! result = book.RequestPermission() |> Async.AwaitTask if result then _contacts <- book.ToList() |> Seq.filter (fun (x: Contact) -> not (Seq.isEmpty x.Phones)) |> Seq.map ExtractUserInfo |> Seq.sortBy(fun x -> x.DisplayName) |> Seq.toList let finalContacts = _contacts |> Seq.map (fun x -> x.DisplayName.ToUpperInvariant()) |> Seq.toArray this.ListAdapter <- new ArrayAdapter(this, Resource_Layout.row_contact, finalContacts) else System.Diagnostics.Debug.WriteLine("Permission denied by user or manifest") this.ListAdapter <- new ArrayAdapter(this, Resource_Layout.row_contact, Array.empty) }
book.ToList() List |> Seq.filter (fun (x: Contact) -> not (Seq.isEmpty x.Phones)) |> Seq.map ExtractUserInfo Contracts UserInfo, UserInfo |> Seq.sortBy(fun x -> x.DisplayName) |> Seq.toList List _contacts <- mutable _contacts |> Seq.map (fun x -> x.DisplayName.ToUpperInvariant())<- UserInfo string, - - |> Seq.toArray<- List Array ArrayAdapter
- List. .

Azure Mobile Servcies
- Azure Mobile Services. NotificationHub, Push . Azure , .. .
, 
module WruConstants = [<Literal>] let TotallyNotAzureServer = "https://YOUR.azure-mobile.net/"; [<Literal>] let TotallyNotAzureKey = "YOUR"
member this.RegisterMe phone name regId = async { try let table = this.MobileService.GetTable<User>() let usr = { Id = "" PhoneHash = MD5Hash phone Nickname = name RegistrationId = regId } do! table.InsertAsync usr |> Async.AwaitPlainTask return (usr.Id, usr.PhoneHash, usr.Nickname) with | e -> System.Diagnostics.Trace.WriteLine(e.ToString) return (String.Empty,String.Empty,String.Empty) }
member this.RegisterMe phone name regId = async { - ( ) . "computation expression" workflow. { } ! ( bang), do! (do-bang) let! (let bang) User. , F# ,
let usr = { Id = "" PhoneHash = MD5Hash phone Nickname = name RegistrationId = regId } do! table.InsertAsync usr |> Async.AwaitPlainTask do-bang, await C#. .. continuation . return (usr.Id, usr.PhoneHash, usr.Nickname) Tuple<string,string,string> . try ... with | e -> try..catch C#

. F# fst snd . 2 . :
let id (c,_,_) = c let phonehash (_,c,_) = c let nickname (_,_,c) = c
: id tuple Id ..
5 Azure, Push . Azure Custom Api
exports.post = function(request, response) { // Use "request.service" to access features of your mobile service, eg: // var tables = request.service.tables; // var push = request.service.push; //response.send(statusCodes.OK, { message : 'Hello World!' }); console.log('Incoming call with requst: ', request.body.RequestId); var usersTable = request.service.tables.getTable('User'); usersTable.where( { id : request.body.TargetId } ) .read( { success: function(results) { if (results.length > 0) { var user = results[0] console.log('Send to results: ', user.Nickname, user.RegistrationId); request.service.push.gcm.send(user.RegistrationId, { RequesterId: request.body.RequesterId, RequesterNickname: request.body.RequesterName, TargetId: user.id, TargetNickname: user.Nickname }, { success: function(gcm_response) { console.log('Push notification sent: ', gcm_response); response.send(statusCodes.OK, { RequestedNickname : user.Nickname }); }, error: function(gcm_error) { console.log('Error sending push notification: ', gcm_error); response.send(statusCodes.INTERNAL_SERVER_ERROR, { RequestedNickname : user.Nickname }); } }); } else { response.send(statusCodes.NO_CONTENT, { RequestedNickname : "" }); } }, error: function(error) { console.log('Error read table: ', error); response.send(statusCodes.INTERNAL_SERVER_ERROR, { RequestedNickname : "" }); } }); };
Push
// Perform Push operation member this.PushAsync targetId myId myNickname = async { try let (request : PushRequest) = { TargetId = targetId RequesterId = myId RequesterName = myNickname } let! result = this.MobileService.InvokeApiAsync<PushRequest, PushResponce>("pushhim", request) |> Async.AwaitTask return result.RequestedNickname with | e -> return e.ToString() }
, let-bang do!

Google Play Services. F# . . : Xamarin.Android.Support.v7.AppCompat
, Google Play Services , .
push notification . GCM, ID, ID Push (. pushhim). BroadcastReciever developer.android.com . F# Xamarin Component Store. Google Cloud Messaging Client GCM . ID
//Check to see that GCM is supported and that the manifest has the correct information GcmClient.CheckDevice(this) GcmClient.CheckManifest(this) // check google play if CheckPlayServices() then // Try to get registration id let regId = GcmClient.GetRegistrationId this if String.IsNullOrEmpty(regId) then // Call to Register the device for Push Notifications GcmClient.Register(this, WruConstants.GcmSender);

.
, -
bitbucket.org/xakpc/whereareyou
,
, "" .
, Android F#. .
, - Android F#. , .listView.Adapter <- new ArrayAdapter(this, Android.Resource.Layout.SimpleListItem1, Android.Resource.Id.Text1, values)
, , let values = [|"item1"; "item2"; "item3"|] - string[], list (IEnumerable )
F#. www.tryfsharp.org/Learn

F# - ,
F# For Fun And Profit
,
- .

hash
MD5 F#
let MD5Hash (input : string) = use md5 = System.Security.Cryptography.MD5.Create() input |> System.Text.Encoding.ASCII.GetBytes |> md5.ComputeHash |> Seq.map (fun c -> c.ToString("X2")) |> Seq.reduce (+)
|> pipeline , .
: GetBytes -> -> HEX -> ( reduce + ) -> .
, C# using System; public string CreateMD5Hash (string input) { MD5 md5 = System.Security.Cryptography.MD5.Create(); byte[] inputBytes = System.Text.Encoding.ASCII.GetBytes (input); byte[] hashBytes = md5.ComputeHash (inputBytes); StringBuilder sb = new StringBuilder(); for (int i = 0; i < hashBytes.Length; i++) { sb.Append (hashBytes[i].ToString ("X2")); } return sb.ToString(); }
: . AzureServiceWorker ( CLR )
- . F# ! Xamarin Studio .
<ItemGroup> <Compile Include="Resources\Resource.designer.fs" /> <Compile Include="Properties\AssemblyInfo.fs" /> <Compile Include="Helpers\Helpers.fs" /> <Compile Include="Services\User.fs" /> <Compile Include="Services\AzureServiceWorker.fs" /> <Compile Include="IAmHereActivity.fs" /> <Compile Include="WhereAreYouActivity.fs" /> <Compile Include="SignInActivity.fs" /> </ItemGroup>
: . Xamarin Xamarin.Mobile
. F# TPL, Task', . F# Task. , :
module Async = open System.Threading open System.Threading.Tasks let inline AwaitPlainTask (task: Task) = // rethrow exception from preceding task if it fauled let continuation (t : Task) : unit = match t.IsFaulted with | true -> raise t.Exception | arg -> () task.ContinueWith continuation |> Async.AwaitTask
Async.AwaitIAsyncResult >> Async.Ignore
let ExtractUserInfo (x : Contact) = let first = x.Phones |> Seq.tryPick(fun x -> if x.Type = PhoneType.Mobile then Some(x) else None) match first with | Some(first) -> let phone = first.Number |> StripChars [' ';'-';'(';')'] UserInfo.CreateUserInfo((MD5Hash phone), phone, x.DisplayName) | None -> UserInfo.CreateUserInfo("no mobile phone", "no mobile phone", "no mobile phone") // function for async list filling let FillContactsAsync = async { let book = new AddressBook (this) let! result = book.RequestPermission() |> Async.AwaitTask if result then _contacts <- book.ToList() |> Seq.filter (fun (x: Contact) -> not (Seq.isEmpty x.Phones)) |> Seq.map ExtractUserInfo |> Seq.sortBy(fun x -> x.DisplayName) |> Seq.toList let finalContacts = _contacts |> Seq.map (fun x -> x.DisplayName.ToUpperInvariant()) |> Seq.toArray this.ListAdapter <- new ArrayAdapter(this, Resource_Layout.row_contact, finalContacts) else System.Diagnostics.Debug.WriteLine("Permission denied by user or manifest") this.ListAdapter <- new ArrayAdapter(this, Resource_Layout.row_contact, Array.empty) }
book.ToList() List |> Seq.filter (fun (x: Contact) -> not (Seq.isEmpty x.Phones)) |> Seq.map ExtractUserInfo Contracts UserInfo, UserInfo |> Seq.sortBy(fun x -> x.DisplayName) |> Seq.toList List _contacts <- mutable _contacts |> Seq.map (fun x -> x.DisplayName.ToUpperInvariant())<- UserInfo string, - - |> Seq.toArray<- List Array ArrayAdapter
- List. .

Azure Mobile Servcies
- Azure Mobile Services. NotificationHub, Push . Azure , .. .
, 
module WruConstants = [<Literal>] let TotallyNotAzureServer = "https://YOUR.azure-mobile.net/"; [<Literal>] let TotallyNotAzureKey = "YOUR"
member this.RegisterMe phone name regId = async { try let table = this.MobileService.GetTable<User>() let usr = { Id = "" PhoneHash = MD5Hash phone Nickname = name RegistrationId = regId } do! table.InsertAsync usr |> Async.AwaitPlainTask return (usr.Id, usr.PhoneHash, usr.Nickname) with | e -> System.Diagnostics.Trace.WriteLine(e.ToString) return (String.Empty,String.Empty,String.Empty) }
member this.RegisterMe phone name regId = async { - ( ) . "computation expression" workflow. { } ! ( bang), do! (do-bang) let! (let bang) User. , F# ,
let usr = { Id = "" PhoneHash = MD5Hash phone Nickname = name RegistrationId = regId } do! table.InsertAsync usr |> Async.AwaitPlainTask do-bang, await C#. .. continuation . return (usr.Id, usr.PhoneHash, usr.Nickname) Tuple<string,string,string> . try ... with | e -> try..catch C#

. F# fst snd . 2 . :
let id (c,_,_) = c let phonehash (_,c,_) = c let nickname (_,_,c) = c
: id tuple Id ..
5 Azure, Push . Azure Custom Api
exports.post = function(request, response) { // Use "request.service" to access features of your mobile service, eg: // var tables = request.service.tables; // var push = request.service.push; //response.send(statusCodes.OK, { message : 'Hello World!' }); console.log('Incoming call with requst: ', request.body.RequestId); var usersTable = request.service.tables.getTable('User'); usersTable.where( { id : request.body.TargetId } ) .read( { success: function(results) { if (results.length > 0) { var user = results[0] console.log('Send to results: ', user.Nickname, user.RegistrationId); request.service.push.gcm.send(user.RegistrationId, { RequesterId: request.body.RequesterId, RequesterNickname: request.body.RequesterName, TargetId: user.id, TargetNickname: user.Nickname }, { success: function(gcm_response) { console.log('Push notification sent: ', gcm_response); response.send(statusCodes.OK, { RequestedNickname : user.Nickname }); }, error: function(gcm_error) { console.log('Error sending push notification: ', gcm_error); response.send(statusCodes.INTERNAL_SERVER_ERROR, { RequestedNickname : user.Nickname }); } }); } else { response.send(statusCodes.NO_CONTENT, { RequestedNickname : "" }); } }, error: function(error) { console.log('Error read table: ', error); response.send(statusCodes.INTERNAL_SERVER_ERROR, { RequestedNickname : "" }); } }); };
Push
// Perform Push operation member this.PushAsync targetId myId myNickname = async { try let (request : PushRequest) = { TargetId = targetId RequesterId = myId RequesterName = myNickname } let! result = this.MobileService.InvokeApiAsync<PushRequest, PushResponce>("pushhim", request) |> Async.AwaitTask return result.RequestedNickname with | e -> return e.ToString() }
, let-bang do!

Google Play Services. F# . . : Xamarin.Android.Support.v7.AppCompat
, Google Play Services , .
push notification . GCM, ID, ID Push (. pushhim). BroadcastReciever developer.android.com . F# Xamarin Component Store. Google Cloud Messaging Client GCM . ID
//Check to see that GCM is supported and that the manifest has the correct information GcmClient.CheckDevice(this) GcmClient.CheckManifest(this) // check google play if CheckPlayServices() then // Try to get registration id let regId = GcmClient.GetRegistrationId this if String.IsNullOrEmpty(regId) then // Call to Register the device for Push Notifications GcmClient.Register(this, WruConstants.GcmSender);

.
, -
bitbucket.org/xakpc/whereareyou
,
, "" .
, Android F#. .
, - Android F#. , .listView.Adapter <- new ArrayAdapter(this, Android.Resource.Layout.SimpleListItem1, Android.Resource.Id.Text1, values)
, , let values = [|"item1"; "item2"; "item3"|] - string[], list (IEnumerable )
F#. www.tryfsharp.org/Learn

F# - ,
F# For Fun And Profit
,
- .

hash
MD5 F#
let MD5Hash (input : string) = use md5 = System.Security.Cryptography.MD5.Create() input |> System.Text.Encoding.ASCII.GetBytes |> md5.ComputeHash |> Seq.map (fun c -> c.ToString("X2")) |> Seq.reduce (+)
|> pipeline , .
: GetBytes -> -> HEX -> ( reduce + ) -> .
, C# using System; public string CreateMD5Hash (string input) { MD5 md5 = System.Security.Cryptography.MD5.Create(); byte[] inputBytes = System.Text.Encoding.ASCII.GetBytes (input); byte[] hashBytes = md5.ComputeHash (inputBytes); StringBuilder sb = new StringBuilder(); for (int i = 0; i < hashBytes.Length; i++) { sb.Append (hashBytes[i].ToString ("X2")); } return sb.ToString(); }
: . AzureServiceWorker ( CLR )
- . F# ! Xamarin Studio .
<ItemGroup> <Compile Include="Resources\Resource.designer.fs" /> <Compile Include="Properties\AssemblyInfo.fs" /> <Compile Include="Helpers\Helpers.fs" /> <Compile Include="Services\User.fs" /> <Compile Include="Services\AzureServiceWorker.fs" /> <Compile Include="IAmHereActivity.fs" /> <Compile Include="WhereAreYouActivity.fs" /> <Compile Include="SignInActivity.fs" /> </ItemGroup>
: . Xamarin Xamarin.Mobile
. F# TPL, Task', . F# Task. , :
module Async = open System.Threading open System.Threading.Tasks let inline AwaitPlainTask (task: Task) = // rethrow exception from preceding task if it fauled let continuation (t : Task) : unit = match t.IsFaulted with | true -> raise t.Exception | arg -> () task.ContinueWith continuation |> Async.AwaitTask
Async.AwaitIAsyncResult >> Async.Ignore
let ExtractUserInfo (x : Contact) = let first = x.Phones |> Seq.tryPick(fun x -> if x.Type = PhoneType.Mobile then Some(x) else None) match first with | Some(first) -> let phone = first.Number |> StripChars [' ';'-';'(';')'] UserInfo.CreateUserInfo((MD5Hash phone), phone, x.DisplayName) | None -> UserInfo.CreateUserInfo("no mobile phone", "no mobile phone", "no mobile phone") // function for async list filling let FillContactsAsync = async { let book = new AddressBook (this) let! result = book.RequestPermission() |> Async.AwaitTask if result then _contacts <- book.ToList() |> Seq.filter (fun (x: Contact) -> not (Seq.isEmpty x.Phones)) |> Seq.map ExtractUserInfo |> Seq.sortBy(fun x -> x.DisplayName) |> Seq.toList let finalContacts = _contacts |> Seq.map (fun x -> x.DisplayName.ToUpperInvariant()) |> Seq.toArray this.ListAdapter <- new ArrayAdapter(this, Resource_Layout.row_contact, finalContacts) else System.Diagnostics.Debug.WriteLine("Permission denied by user or manifest") this.ListAdapter <- new ArrayAdapter(this, Resource_Layout.row_contact, Array.empty) }
book.ToList() List |> Seq.filter (fun (x: Contact) -> not (Seq.isEmpty x.Phones)) |> Seq.map ExtractUserInfo Contracts UserInfo, UserInfo |> Seq.sortBy(fun x -> x.DisplayName) |> Seq.toList List _contacts <- mutable _contacts |> Seq.map (fun x -> x.DisplayName.ToUpperInvariant())<- UserInfo string, - - |> Seq.toArray<- List Array ArrayAdapter
- List. .

Azure Mobile Servcies
- Azure Mobile Services. NotificationHub, Push . Azure , .. .
, 
module WruConstants = [<Literal>] let TotallyNotAzureServer = "https://YOUR.azure-mobile.net/"; [<Literal>] let TotallyNotAzureKey = "YOUR"
member this.RegisterMe phone name regId = async { try let table = this.MobileService.GetTable<User>() let usr = { Id = "" PhoneHash = MD5Hash phone Nickname = name RegistrationId = regId } do! table.InsertAsync usr |> Async.AwaitPlainTask return (usr.Id, usr.PhoneHash, usr.Nickname) with | e -> System.Diagnostics.Trace.WriteLine(e.ToString) return (String.Empty,String.Empty,String.Empty) }
member this.RegisterMe phone name regId = async { - ( ) . "computation expression" workflow. { } ! ( bang), do! (do-bang) let! (let bang) User. , F# ,
let usr = { Id = "" PhoneHash = MD5Hash phone Nickname = name RegistrationId = regId } do! table.InsertAsync usr |> Async.AwaitPlainTask do-bang, await C#. .. continuation . return (usr.Id, usr.PhoneHash, usr.Nickname) Tuple<string,string,string> . try ... with | e -> try..catch C#

. F# fst snd . 2 . :
let id (c,_,_) = c let phonehash (_,c,_) = c let nickname (_,_,c) = c
: id tuple Id ..
5 Azure, Push . Azure Custom Api
exports.post = function(request, response) { // Use "request.service" to access features of your mobile service, eg: // var tables = request.service.tables; // var push = request.service.push; //response.send(statusCodes.OK, { message : 'Hello World!' }); console.log('Incoming call with requst: ', request.body.RequestId); var usersTable = request.service.tables.getTable('User'); usersTable.where( { id : request.body.TargetId } ) .read( { success: function(results) { if (results.length > 0) { var user = results[0] console.log('Send to results: ', user.Nickname, user.RegistrationId); request.service.push.gcm.send(user.RegistrationId, { RequesterId: request.body.RequesterId, RequesterNickname: request.body.RequesterName, TargetId: user.id, TargetNickname: user.Nickname }, { success: function(gcm_response) { console.log('Push notification sent: ', gcm_response); response.send(statusCodes.OK, { RequestedNickname : user.Nickname }); }, error: function(gcm_error) { console.log('Error sending push notification: ', gcm_error); response.send(statusCodes.INTERNAL_SERVER_ERROR, { RequestedNickname : user.Nickname }); } }); } else { response.send(statusCodes.NO_CONTENT, { RequestedNickname : "" }); } }, error: function(error) { console.log('Error read table: ', error); response.send(statusCodes.INTERNAL_SERVER_ERROR, { RequestedNickname : "" }); } }); };
Push
// Perform Push operation member this.PushAsync targetId myId myNickname = async { try let (request : PushRequest) = { TargetId = targetId RequesterId = myId RequesterName = myNickname } let! result = this.MobileService.InvokeApiAsync<PushRequest, PushResponce>("pushhim", request) |> Async.AwaitTask return result.RequestedNickname with | e -> return e.ToString() }
, let-bang do!

Google Play Services. F# . . : Xamarin.Android.Support.v7.AppCompat
, Google Play Services , .
push notification . GCM, ID, ID Push (. pushhim). BroadcastReciever developer.android.com . F# Xamarin Component Store. Google Cloud Messaging Client GCM . ID
//Check to see that GCM is supported and that the manifest has the correct information GcmClient.CheckDevice(this) GcmClient.CheckManifest(this) // check google play if CheckPlayServices() then // Try to get registration id let regId = GcmClient.GetRegistrationId this if String.IsNullOrEmpty(regId) then // Call to Register the device for Push Notifications GcmClient.Register(this, WruConstants.GcmSender);

.
, -
bitbucket.org/xakpc/whereareyou
,
, "" .
, Android F#. .
, - Android F#. , .listView.Adapter <- new ArrayAdapter(this, Android.Resource.Layout.SimpleListItem1, Android.Resource.Id.Text1, values)
, , let values = [|"item1"; "item2"; "item3"|] - string[], list (IEnumerable )
F#. www.tryfsharp.org/Learn

F# - ,
F# For Fun And Profit
,
- .

hash
MD5 F#
let MD5Hash (input : string) = use md5 = System.Security.Cryptography.MD5.Create() input |> System.Text.Encoding.ASCII.GetBytes |> md5.ComputeHash |> Seq.map (fun c -> c.ToString("X2")) |> Seq.reduce (+)
|> pipeline , .
: GetBytes -> -> HEX -> ( reduce + ) -> .
, C# using System; public string CreateMD5Hash (string input) { MD5 md5 = System.Security.Cryptography.MD5.Create(); byte[] inputBytes = System.Text.Encoding.ASCII.GetBytes (input); byte[] hashBytes = md5.ComputeHash (inputBytes); StringBuilder sb = new StringBuilder(); for (int i = 0; i < hashBytes.Length; i++) { sb.Append (hashBytes[i].ToString ("X2")); } return sb.ToString(); }
: . AzureServiceWorker ( CLR )
- . F# ! Xamarin Studio .
<ItemGroup> <Compile Include="Resources\Resource.designer.fs" /> <Compile Include="Properties\AssemblyInfo.fs" /> <Compile Include="Helpers\Helpers.fs" /> <Compile Include="Services\User.fs" /> <Compile Include="Services\AzureServiceWorker.fs" /> <Compile Include="IAmHereActivity.fs" /> <Compile Include="WhereAreYouActivity.fs" /> <Compile Include="SignInActivity.fs" /> </ItemGroup>
: . Xamarin Xamarin.Mobile
. F# TPL, Task', . F# Task. , :
module Async = open System.Threading open System.Threading.Tasks let inline AwaitPlainTask (task: Task) = // rethrow exception from preceding task if it fauled let continuation (t : Task) : unit = match t.IsFaulted with | true -> raise t.Exception | arg -> () task.ContinueWith continuation |> Async.AwaitTask
Async.AwaitIAsyncResult >> Async.Ignore
let ExtractUserInfo (x : Contact) = let first = x.Phones |> Seq.tryPick(fun x -> if x.Type = PhoneType.Mobile then Some(x) else None) match first with | Some(first) -> let phone = first.Number |> StripChars [' ';'-';'(';')'] UserInfo.CreateUserInfo((MD5Hash phone), phone, x.DisplayName) | None -> UserInfo.CreateUserInfo("no mobile phone", "no mobile phone", "no mobile phone") // function for async list filling let FillContactsAsync = async { let book = new AddressBook (this) let! result = book.RequestPermission() |> Async.AwaitTask if result then _contacts <- book.ToList() |> Seq.filter (fun (x: Contact) -> not (Seq.isEmpty x.Phones)) |> Seq.map ExtractUserInfo |> Seq.sortBy(fun x -> x.DisplayName) |> Seq.toList let finalContacts = _contacts |> Seq.map (fun x -> x.DisplayName.ToUpperInvariant()) |> Seq.toArray this.ListAdapter <- new ArrayAdapter(this, Resource_Layout.row_contact, finalContacts) else System.Diagnostics.Debug.WriteLine("Permission denied by user or manifest") this.ListAdapter <- new ArrayAdapter(this, Resource_Layout.row_contact, Array.empty) }
book.ToList() List |> Seq.filter (fun (x: Contact) -> not (Seq.isEmpty x.Phones)) |> Seq.map ExtractUserInfo Contracts UserInfo, UserInfo |> Seq.sortBy(fun x -> x.DisplayName) |> Seq.toList List _contacts <- mutable _contacts |> Seq.map (fun x -> x.DisplayName.ToUpperInvariant())<- UserInfo string, - - |> Seq.toArray<- List Array ArrayAdapter
- List. .

Azure Mobile Servcies
- Azure Mobile Services. NotificationHub, Push . Azure , .. .
, 
module WruConstants = [<Literal>] let TotallyNotAzureServer = "https://YOUR.azure-mobile.net/"; [<Literal>] let TotallyNotAzureKey = "YOUR"
member this.RegisterMe phone name regId = async { try let table = this.MobileService.GetTable<User>() let usr = { Id = "" PhoneHash = MD5Hash phone Nickname = name RegistrationId = regId } do! table.InsertAsync usr |> Async.AwaitPlainTask return (usr.Id, usr.PhoneHash, usr.Nickname) with | e -> System.Diagnostics.Trace.WriteLine(e.ToString) return (String.Empty,String.Empty,String.Empty) }
member this.RegisterMe phone name regId = async { - ( ) . "computation expression" workflow. { } ! ( bang), do! (do-bang) let! (let bang) User. , F# ,
let usr = { Id = "" PhoneHash = MD5Hash phone Nickname = name RegistrationId = regId } do! table.InsertAsync usr |> Async.AwaitPlainTask do-bang, await C#. .. continuation . return (usr.Id, usr.PhoneHash, usr.Nickname) Tuple<string,string,string> . try ... with | e -> try..catch C#

. F# fst snd . 2 . :
let id (c,_,_) = c let phonehash (_,c,_) = c let nickname (_,_,c) = c
: id tuple Id ..
5 Azure, Push . Azure Custom Api
exports.post = function(request, response) { // Use "request.service" to access features of your mobile service, eg: // var tables = request.service.tables; // var push = request.service.push; //response.send(statusCodes.OK, { message : 'Hello World!' }); console.log('Incoming call with requst: ', request.body.RequestId); var usersTable = request.service.tables.getTable('User'); usersTable.where( { id : request.body.TargetId } ) .read( { success: function(results) { if (results.length > 0) { var user = results[0] console.log('Send to results: ', user.Nickname, user.RegistrationId); request.service.push.gcm.send(user.RegistrationId, { RequesterId: request.body.RequesterId, RequesterNickname: request.body.RequesterName, TargetId: user.id, TargetNickname: user.Nickname }, { success: function(gcm_response) { console.log('Push notification sent: ', gcm_response); response.send(statusCodes.OK, { RequestedNickname : user.Nickname }); }, error: function(gcm_error) { console.log('Error sending push notification: ', gcm_error); response.send(statusCodes.INTERNAL_SERVER_ERROR, { RequestedNickname : user.Nickname }); } }); } else { response.send(statusCodes.NO_CONTENT, { RequestedNickname : "" }); } }, error: function(error) { console.log('Error read table: ', error); response.send(statusCodes.INTERNAL_SERVER_ERROR, { RequestedNickname : "" }); } }); };
Push
// Perform Push operation member this.PushAsync targetId myId myNickname = async { try let (request : PushRequest) = { TargetId = targetId RequesterId = myId RequesterName = myNickname } let! result = this.MobileService.InvokeApiAsync<PushRequest, PushResponce>("pushhim", request) |> Async.AwaitTask return result.RequestedNickname with | e -> return e.ToString() }
, let-bang do!

Google Play Services. F# . . : Xamarin.Android.Support.v7.AppCompat
, Google Play Services , .
push notification . GCM, ID, ID Push (. pushhim). BroadcastReciever developer.android.com . F# Xamarin Component Store. Google Cloud Messaging Client GCM . ID
//Check to see that GCM is supported and that the manifest has the correct information GcmClient.CheckDevice(this) GcmClient.CheckManifest(this) // check google play if CheckPlayServices() then // Try to get registration id let regId = GcmClient.GetRegistrationId this if String.IsNullOrEmpty(regId) then // Call to Register the device for Push Notifications GcmClient.Register(this, WruConstants.GcmSender);

.
, -
bitbucket.org/xakpc/whereareyou
,
, "" .
, Android F#. .
, - Android F#. , . listView.Adapter <- new ArrayAdapter(this, Android.Resource.Layout.SimpleListItem1, Android.Resource.Id.Text1, values) 
  , ,  let values = [|"item1"; "item2"; "item3"|] -   string[],       list (IEnumerable   ) 
          F#.            www.tryfsharp.org/Learn 
 
 
      F# -  ,  
 
        F# For Fun And Profit 
 
   ,    
     - . 
 
 
 
 
        hash 
     MD5  F# 
  let MD5Hash (input : string) = use md5 = System.Security.Cryptography.MD5.Create() input |> System.Text.Encoding.ASCII.GetBytes |> md5.ComputeHash |> Seq.map (fun c -> c.ToString("X2")) |> Seq.reduce (+) 
 
  |>  pipeline ,     . 
     :    GetBytes ->   ->      HEX  ->       (  reduce   +           ) ->    . 
 
  ,     C# using System; public string CreateMD5Hash (string input) { MD5 md5 = System.Security.Cryptography.MD5.Create(); byte[] inputBytes = System.Text.Encoding.ASCII.GetBytes (input); byte[] hashBytes = md5.ComputeHash (inputBytes); StringBuilder sb = new StringBuilder(); for (int i = 0; i < hashBytes.Length; i++) { sb.Append (hashBytes[i].ToString ("X2")); } return sb.ToString(); } 
 
 
          :        .       AzureServiceWorker (  CLR    ) 
 
          -   .   F#    !   Xamarin Studio            . 
  <ItemGroup> <Compile Include="Resources\Resource.designer.fs" /> <Compile Include="Properties\AssemblyInfo.fs" /> <Compile Include="Helpers\Helpers.fs" /> <Compile Include="Services\User.fs" /> <Compile Include="Services\AzureServiceWorker.fs" /> <Compile Include="IAmHereActivity.fs" /> <Compile Include="WhereAreYouActivity.fs" /> <Compile Include="SignInActivity.fs" /> </ItemGroup> 
 
    
        :    .    Xamarin    Xamarin.Mobile 
 
      .  F#         TPL,     Task',      .     F#         Task.  ,     : 
 module Async = open System.Threading open System.Threading.Tasks let inline AwaitPlainTask (task: Task) = // rethrow exception from preceding task if it fauled let continuation (t : Task) : unit = match t.IsFaulted with | true -> raise t.Exception | arg -> () task.ContinueWith continuation |> Async.AwaitTask 
         Async.AwaitIAsyncResult >> Async.Ignore       
 
            
 let ExtractUserInfo (x : Contact) = let first = x.Phones |> Seq.tryPick(fun x -> if x.Type = PhoneType.Mobile then Some(x) else None) match first with | Some(first) -> let phone = first.Number |> StripChars [' ';'-';'(';')'] UserInfo.CreateUserInfo((MD5Hash phone), phone, x.DisplayName) | None -> UserInfo.CreateUserInfo("no mobile phone", "no mobile phone", "no mobile phone") // function for async list filling let FillContactsAsync = async { let book = new AddressBook (this) let! result = book.RequestPermission() |> Async.AwaitTask if result then _contacts <- book.ToList() |> Seq.filter (fun (x: Contact) -> not (Seq.isEmpty x.Phones)) |> Seq.map ExtractUserInfo |> Seq.sortBy(fun x -> x.DisplayName) |> Seq.toList let finalContacts = _contacts |> Seq.map (fun x -> x.DisplayName.ToUpperInvariant()) |> Seq.toArray this.ListAdapter <- new ArrayAdapter(this, Resource_Layout.row_contact, finalContacts) else System.Diagnostics.Debug.WriteLine("Permission denied by user or manifest") this.ListAdapter <- new ArrayAdapter(this, Resource_Layout.row_contact, Array.empty) } 
      
 book.ToList()   List |> Seq.filter (fun (x: Contact) -> not (Seq.isEmpty x.Phones))      |> Seq.map ExtractUserInfo      Contracts  UserInfo,      UserInfo |> Seq.sortBy(fun x -> x.DisplayName)  |> Seq.toList   List _contacts <-    mutable  _contacts |> Seq.map (fun x -> x.DisplayName.ToUpperInvariant())<-    UserInfo  string,     - -    |> Seq.toArray<-  List  Array    ArrayAdapter 
    -      List.   . 
 
 
 
 
 Azure Mobile Servcies 
   -    Azure Mobile Services.       NotificationHub,     Push    .   Azure    , ..      . 
 
      ,    
 module WruConstants = [<Literal>] let TotallyNotAzureServer = "https://YOUR.azure-mobile.net/"; [<Literal>] let TotallyNotAzureKey = "YOUR" 
 
       
 member this.RegisterMe phone name regId = async { try let table = this.MobileService.GetTable<User>() let usr = { Id = "" PhoneHash = MD5Hash phone Nickname = name RegistrationId = regId } do! table.InsertAsync usr |> Async.AwaitPlainTask return (usr.Id, usr.PhoneHash, usr.Nickname) with | e -> System.Diagnostics.Trace.WriteLine(e.ToString) return (String.Empty,String.Empty,String.Empty) } 
 member this.RegisterMe phone name regId = async { -       (     )    .       "computation expression"   workflow.   { }       ! ( bang),  do! (do-bang)  let! (let bang)     User.    ,  F#        ,      
  let usr = { Id = "" PhoneHash = MD5Hash phone Nickname = name RegistrationId = regId } do! table.InsertAsync usr |> Async.AwaitPlainTask  do-bang,   await  C#. ..             continuation    . return (usr.Id, usr.PhoneHash, usr.Nickname)      Tuple<string,string,string>     .  try ... with | e ->  try..catch  C# 
 
 
 
 
       .  F#    fst  snd      .        2 .     : 
  let id (c,_,_) = c let phonehash (_,c,_) = c let nickname (_,_,c) = c 
    : id tuple  Id  .. 
 
    5  Azure,       Push .       Azure Custom Api  
 
      exports.post = function(request, response) { // Use "request.service" to access features of your mobile service, eg: // var tables = request.service.tables; // var push = request.service.push; //response.send(statusCodes.OK, { message : 'Hello World!' }); console.log('Incoming call with requst: ', request.body.RequestId); var usersTable = request.service.tables.getTable('User'); usersTable.where( { id : request.body.TargetId } ) .read( { success: function(results) { if (results.length > 0) { var user = results[0] console.log('Send to results: ', user.Nickname, user.RegistrationId); request.service.push.gcm.send(user.RegistrationId, { RequesterId: request.body.RequesterId, RequesterNickname: request.body.RequesterName, TargetId: user.id, TargetNickname: user.Nickname }, { success: function(gcm_response) { console.log('Push notification sent: ', gcm_response); response.send(statusCodes.OK, { RequestedNickname : user.Nickname }); }, error: function(gcm_error) { console.log('Error sending push notification: ', gcm_error); response.send(statusCodes.INTERNAL_SERVER_ERROR, { RequestedNickname : user.Nickname }); } }); } else { response.send(statusCodes.NO_CONTENT, { RequestedNickname : "" }); } }, error: function(error) { console.log('Error read table: ', error); response.send(statusCodes.INTERNAL_SERVER_ERROR, { RequestedNickname : "" }); } }); }; 
 
    Push      
 // Perform Push operation member this.PushAsync targetId myId myNickname = async { try let (request : PushRequest) = { TargetId = targetId RequesterId = myId RequesterName = myNickname } let! result = this.MobileService.InvokeApiAsync<PushRequest, PushResponce>("pushhim", request) |> Async.AwaitTask return result.RequestedNickname with | e -> return e.ToString() } 
 
       ,    let-bang   do! 
 
   
 
 
 
      Google Play Services.     F#   .           .    : Xamarin.Android.Support.v7.AppCompat 
     , Google Play Services ,   . 
 
      push notification   .    GCM,  ID,     ID       Push  (.   pushhim).        BroadcastReciever       developer.android.com .     F#         Xamarin Component Store.     Google Cloud Messaging Client         GCM    .        ID 
 //Check to see that GCM is supported and that the manifest has the correct information GcmClient.CheckDevice(this) GcmClient.CheckManifest(this) // check google play if CheckPlayServices() then // Try to get registration id let regId = GcmClient.GetRegistrationId this if String.IsNullOrEmpty(regId) then // Call to Register the device for Push Notifications GcmClient.Register(this, WruConstants.GcmSender); 
 
 
 
        
 
    . 
    , -  
     bitbucket.org/xakpc/whereareyou 
     ,     
          ,           "" . 
 
  
 ,   Android   F#.      . 
 ,       -  Android  F#.   ,       . listView.Adapter <- new ArrayAdapter(this, Android.Resource.Layout.SimpleListItem1, Android.Resource.Id.Text1, values)
, , let values = [|"item1"; "item2"; "item3"|] - string[], list (IEnumerable )
F#. www.tryfsharp.org/Learn

F# - ,
F# For Fun And Profit
,
- .

hash
MD5 F#
let MD5Hash (input : string) = use md5 = System.Security.Cryptography.MD5.Create() input |> System.Text.Encoding.ASCII.GetBytes |> md5.ComputeHash |> Seq.map (fun c -> c.ToString("X2")) |> Seq.reduce (+)
|> pipeline , .
: GetBytes -> -> HEX -> ( reduce + ) -> .
, C# using System; public string CreateMD5Hash (string input) { MD5 md5 = System.Security.Cryptography.MD5.Create(); byte[] inputBytes = System.Text.Encoding.ASCII.GetBytes (input); byte[] hashBytes = md5.ComputeHash (inputBytes); StringBuilder sb = new StringBuilder(); for (int i = 0; i < hashBytes.Length; i++) { sb.Append (hashBytes[i].ToString ("X2")); } return sb.ToString(); }
: . AzureServiceWorker ( CLR )
- . F# ! Xamarin Studio .
<ItemGroup> <Compile Include="Resources\Resource.designer.fs" /> <Compile Include="Properties\AssemblyInfo.fs" /> <Compile Include="Helpers\Helpers.fs" /> <Compile Include="Services\User.fs" /> <Compile Include="Services\AzureServiceWorker.fs" /> <Compile Include="IAmHereActivity.fs" /> <Compile Include="WhereAreYouActivity.fs" /> <Compile Include="SignInActivity.fs" /> </ItemGroup>
: . Xamarin Xamarin.Mobile
. F# TPL, Task', . F# Task. , :
module Async = open System.Threading open System.Threading.Tasks let inline AwaitPlainTask (task: Task) = // rethrow exception from preceding task if it fauled let continuation (t : Task) : unit = match t.IsFaulted with | true -> raise t.Exception | arg -> () task.ContinueWith continuation |> Async.AwaitTask
Async.AwaitIAsyncResult >> Async.Ignore
let ExtractUserInfo (x : Contact) = let first = x.Phones |> Seq.tryPick(fun x -> if x.Type = PhoneType.Mobile then Some(x) else None) match first with | Some(first) -> let phone = first.Number |> StripChars [' ';'-';'(';')'] UserInfo.CreateUserInfo((MD5Hash phone), phone, x.DisplayName) | None -> UserInfo.CreateUserInfo("no mobile phone", "no mobile phone", "no mobile phone") // function for async list filling let FillContactsAsync = async { let book = new AddressBook (this) let! result = book.RequestPermission() |> Async.AwaitTask if result then _contacts <- book.ToList() |> Seq.filter (fun (x: Contact) -> not (Seq.isEmpty x.Phones)) |> Seq.map ExtractUserInfo |> Seq.sortBy(fun x -> x.DisplayName) |> Seq.toList let finalContacts = _contacts |> Seq.map (fun x -> x.DisplayName.ToUpperInvariant()) |> Seq.toArray this.ListAdapter <- new ArrayAdapter(this, Resource_Layout.row_contact, finalContacts) else System.Diagnostics.Debug.WriteLine("Permission denied by user or manifest") this.ListAdapter <- new ArrayAdapter(this, Resource_Layout.row_contact, Array.empty) }
book.ToList() List |> Seq.filter (fun (x: Contact) -> not (Seq.isEmpty x.Phones)) |> Seq.map ExtractUserInfo Contracts UserInfo, UserInfo |> Seq.sortBy(fun x -> x.DisplayName) |> Seq.toList List _contacts <- mutable _contacts |> Seq.map (fun x -> x.DisplayName.ToUpperInvariant())<- UserInfo string, - - |> Seq.toArray<- List Array ArrayAdapter
- List. .

Azure Mobile Servcies
- Azure Mobile Services. NotificationHub, Push . Azure , .. .
, 
module WruConstants = [<Literal>] let TotallyNotAzureServer = "https://YOUR.azure-mobile.net/"; [<Literal>] let TotallyNotAzureKey = "YOUR"
member this.RegisterMe phone name regId = async { try let table = this.MobileService.GetTable<User>() let usr = { Id = "" PhoneHash = MD5Hash phone Nickname = name RegistrationId = regId } do! table.InsertAsync usr |> Async.AwaitPlainTask return (usr.Id, usr.PhoneHash, usr.Nickname) with | e -> System.Diagnostics.Trace.WriteLine(e.ToString) return (String.Empty,String.Empty,String.Empty) }
member this.RegisterMe phone name regId = async { - ( ) . "computation expression" workflow. { } ! ( bang), do! (do-bang) let! (let bang) User. , F# ,
let usr = { Id = "" PhoneHash = MD5Hash phone Nickname = name RegistrationId = regId } do! table.InsertAsync usr |> Async.AwaitPlainTask do-bang, await C#. .. continuation . return (usr.Id, usr.PhoneHash, usr.Nickname) Tuple<string,string,string> . try ... with | e -> try..catch C#

. F# fst snd . 2 . :
let id (c,_,_) = c let phonehash (_,c,_) = c let nickname (_,_,c) = c
: id tuple Id ..
5 Azure, Push . Azure Custom Api
exports.post = function(request, response) { // Use "request.service" to access features of your mobile service, eg: // var tables = request.service.tables; // var push = request.service.push; //response.send(statusCodes.OK, { message : 'Hello World!' }); console.log('Incoming call with requst: ', request.body.RequestId); var usersTable = request.service.tables.getTable('User'); usersTable.where( { id : request.body.TargetId } ) .read( { success: function(results) { if (results.length > 0) { var user = results[0] console.log('Send to results: ', user.Nickname, user.RegistrationId); request.service.push.gcm.send(user.RegistrationId, { RequesterId: request.body.RequesterId, RequesterNickname: request.body.RequesterName, TargetId: user.id, TargetNickname: user.Nickname }, { success: function(gcm_response) { console.log('Push notification sent: ', gcm_response); response.send(statusCodes.OK, { RequestedNickname : user.Nickname }); }, error: function(gcm_error) { console.log('Error sending push notification: ', gcm_error); response.send(statusCodes.INTERNAL_SERVER_ERROR, { RequestedNickname : user.Nickname }); } }); } else { response.send(statusCodes.NO_CONTENT, { RequestedNickname : "" }); } }, error: function(error) { console.log('Error read table: ', error); response.send(statusCodes.INTERNAL_SERVER_ERROR, { RequestedNickname : "" }); } }); };
Push
// Perform Push operation member this.PushAsync targetId myId myNickname = async { try let (request : PushRequest) = { TargetId = targetId RequesterId = myId RequesterName = myNickname } let! result = this.MobileService.InvokeApiAsync<PushRequest, PushResponce>("pushhim", request) |> Async.AwaitTask return result.RequestedNickname with | e -> return e.ToString() }
, let-bang do!

Google Play Services. F# . . : Xamarin.Android.Support.v7.AppCompat
, Google Play Services , .
push notification . GCM, ID, ID Push (. pushhim). BroadcastReciever developer.android.com . F# Xamarin Component Store. Google Cloud Messaging Client GCM . ID
//Check to see that GCM is supported and that the manifest has the correct information GcmClient.CheckDevice(this) GcmClient.CheckManifest(this) // check google play if CheckPlayServices() then // Try to get registration id let regId = GcmClient.GetRegistrationId this if String.IsNullOrEmpty(regId) then // Call to Register the device for Push Notifications GcmClient.Register(this, WruConstants.GcmSender);

.
, -
bitbucket.org/xakpc/whereareyou
,
, "" .
, Android F#. .
, - Android F#. , .listView.Adapter <- new ArrayAdapter(this, Android.Resource.Layout.SimpleListItem1, Android.Resource.Id.Text1, values)
, , let values = [|"item1"; "item2"; "item3"|] - string[], list (IEnumerable )
F#. www.tryfsharp.org/Learn

F# - ,
F# For Fun And Profit
,
- .

hash
MD5 F#
let MD5Hash (input : string) = use md5 = System.Security.Cryptography.MD5.Create() input |> System.Text.Encoding.ASCII.GetBytes |> md5.ComputeHash |> Seq.map (fun c -> c.ToString("X2")) |> Seq.reduce (+)
|> pipeline , .
: GetBytes -> -> HEX -> ( reduce + ) -> .
, C# using System; public string CreateMD5Hash (string input) { MD5 md5 = System.Security.Cryptography.MD5.Create(); byte[] inputBytes = System.Text.Encoding.ASCII.GetBytes (input); byte[] hashBytes = md5.ComputeHash (inputBytes); StringBuilder sb = new StringBuilder(); for (int i = 0; i < hashBytes.Length; i++) { sb.Append (hashBytes[i].ToString ("X2")); } return sb.ToString(); }
: . AzureServiceWorker ( CLR )
- . F# ! Xamarin Studio .
<ItemGroup> <Compile Include="Resources\Resource.designer.fs" /> <Compile Include="Properties\AssemblyInfo.fs" /> <Compile Include="Helpers\Helpers.fs" /> <Compile Include="Services\User.fs" /> <Compile Include="Services\AzureServiceWorker.fs" /> <Compile Include="IAmHereActivity.fs" /> <Compile Include="WhereAreYouActivity.fs" /> <Compile Include="SignInActivity.fs" /> </ItemGroup>
: . Xamarin Xamarin.Mobile
. F# TPL, Task', . F# Task. , :
module Async = open System.Threading open System.Threading.Tasks let inline AwaitPlainTask (task: Task) = // rethrow exception from preceding task if it fauled let continuation (t : Task) : unit = match t.IsFaulted with | true -> raise t.Exception | arg -> () task.ContinueWith continuation |> Async.AwaitTask
Async.AwaitIAsyncResult >> Async.Ignore
let ExtractUserInfo (x : Contact) = let first = x.Phones |> Seq.tryPick(fun x -> if x.Type = PhoneType.Mobile then Some(x) else None) match first with | Some(first) -> let phone = first.Number |> StripChars [' ';'-';'(';')'] UserInfo.CreateUserInfo((MD5Hash phone), phone, x.DisplayName) | None -> UserInfo.CreateUserInfo("no mobile phone", "no mobile phone", "no mobile phone") // function for async list filling let FillContactsAsync = async { let book = new AddressBook (this) let! result = book.RequestPermission() |> Async.AwaitTask if result then _contacts <- book.ToList() |> Seq.filter (fun (x: Contact) -> not (Seq.isEmpty x.Phones)) |> Seq.map ExtractUserInfo |> Seq.sortBy(fun x -> x.DisplayName) |> Seq.toList let finalContacts = _contacts |> Seq.map (fun x -> x.DisplayName.ToUpperInvariant()) |> Seq.toArray this.ListAdapter <- new ArrayAdapter(this, Resource_Layout.row_contact, finalContacts) else System.Diagnostics.Debug.WriteLine("Permission denied by user or manifest") this.ListAdapter <- new ArrayAdapter(this, Resource_Layout.row_contact, Array.empty) }
book.ToList() List |> Seq.filter (fun (x: Contact) -> not (Seq.isEmpty x.Phones)) |> Seq.map ExtractUserInfo Contracts UserInfo, UserInfo |> Seq.sortBy(fun x -> x.DisplayName) |> Seq.toList List _contacts <- mutable _contacts |> Seq.map (fun x -> x.DisplayName.ToUpperInvariant())<- UserInfo string, - - |> Seq.toArray<- List Array ArrayAdapter
- List. .

Azure Mobile Servcies
- Azure Mobile Services. NotificationHub, Push . Azure , .. .
, 
module WruConstants = [<Literal>] let TotallyNotAzureServer = "https://YOUR.azure-mobile.net/"; [<Literal>] let TotallyNotAzureKey = "YOUR"
member this.RegisterMe phone name regId = async { try let table = this.MobileService.GetTable<User>() let usr = { Id = "" PhoneHash = MD5Hash phone Nickname = name RegistrationId = regId } do! table.InsertAsync usr |> Async.AwaitPlainTask return (usr.Id, usr.PhoneHash, usr.Nickname) with | e -> System.Diagnostics.Trace.WriteLine(e.ToString) return (String.Empty,String.Empty,String.Empty) }
member this.RegisterMe phone name regId = async { - ( ) . "computation expression" workflow. { } ! ( bang), do! (do-bang) let! (let bang) User. , F# ,
let usr = { Id = "" PhoneHash = MD5Hash phone Nickname = name RegistrationId = regId } do! table.InsertAsync usr |> Async.AwaitPlainTask do-bang, await C#. .. continuation . return (usr.Id, usr.PhoneHash, usr.Nickname) Tuple<string,string,string> . try ... with | e -> try..catch C#

. F# fst snd . 2 . :
let id (c,_,_) = c let phonehash (_,c,_) = c let nickname (_,_,c) = c
: id tuple Id ..
5 Azure, Push . Azure Custom Api
exports.post = function(request, response) { // Use "request.service" to access features of your mobile service, eg: // var tables = request.service.tables; // var push = request.service.push; //response.send(statusCodes.OK, { message : 'Hello World!' }); console.log('Incoming call with requst: ', request.body.RequestId); var usersTable = request.service.tables.getTable('User'); usersTable.where( { id : request.body.TargetId } ) .read( { success: function(results) { if (results.length > 0) { var user = results[0] console.log('Send to results: ', user.Nickname, user.RegistrationId); request.service.push.gcm.send(user.RegistrationId, { RequesterId: request.body.RequesterId, RequesterNickname: request.body.RequesterName, TargetId: user.id, TargetNickname: user.Nickname }, { success: function(gcm_response) { console.log('Push notification sent: ', gcm_response); response.send(statusCodes.OK, { RequestedNickname : user.Nickname }); }, error: function(gcm_error) { console.log('Error sending push notification: ', gcm_error); response.send(statusCodes.INTERNAL_SERVER_ERROR, { RequestedNickname : user.Nickname }); } }); } else { response.send(statusCodes.NO_CONTENT, { RequestedNickname : "" }); } }, error: function(error) { console.log('Error read table: ', error); response.send(statusCodes.INTERNAL_SERVER_ERROR, { RequestedNickname : "" }); } }); };
Push
// Perform Push operation member this.PushAsync targetId myId myNickname = async { try let (request : PushRequest) = { TargetId = targetId RequesterId = myId RequesterName = myNickname } let! result = this.MobileService.InvokeApiAsync<PushRequest, PushResponce>("pushhim", request) |> Async.AwaitTask return result.RequestedNickname with | e -> return e.ToString() }
, let-bang do!

Google Play Services. F# . . : Xamarin.Android.Support.v7.AppCompat
, Google Play Services , .
push notification . GCM, ID, ID Push (. pushhim). BroadcastReciever developer.android.com . F# Xamarin Component Store. Google Cloud Messaging Client GCM . ID
//Check to see that GCM is supported and that the manifest has the correct information GcmClient.CheckDevice(this) GcmClient.CheckManifest(this) // check google play if CheckPlayServices() then // Try to get registration id let regId = GcmClient.GetRegistrationId this if String.IsNullOrEmpty(regId) then // Call to Register the device for Push Notifications GcmClient.Register(this, WruConstants.GcmSender);

.
, -
bitbucket.org/xakpc/whereareyou
,
, "" .
, Android F#. .
, - Android F#. , . listView.Adapter <- new ArrayAdapter(this, Android.Resource.Layout.SimpleListItem1, Android.Resource.Id.Text1, values) 
  , ,  let values = [|"item1"; "item2"; "item3"|] -   string[],       list (IEnumerable   ) 
          F#.            www.tryfsharp.org/Learn 
 
 
      F# -  ,  
 
        F# For Fun And Profit 
 
   ,    
     - . 
 
 
 
 
        hash 
     MD5  F# 
  let MD5Hash (input : string) = use md5 = System.Security.Cryptography.MD5.Create() input |> System.Text.Encoding.ASCII.GetBytes |> md5.ComputeHash |> Seq.map (fun c -> c.ToString("X2")) |> Seq.reduce (+) 
 
  |>  pipeline ,     . 
     :    GetBytes ->   ->      HEX  ->       (  reduce   +           ) ->    . 
 
  ,     C# using System; public string CreateMD5Hash (string input) { MD5 md5 = System.Security.Cryptography.MD5.Create(); byte[] inputBytes = System.Text.Encoding.ASCII.GetBytes (input); byte[] hashBytes = md5.ComputeHash (inputBytes); StringBuilder sb = new StringBuilder(); for (int i = 0; i < hashBytes.Length; i++) { sb.Append (hashBytes[i].ToString ("X2")); } return sb.ToString(); } 
 
 
          :        .       AzureServiceWorker (  CLR    ) 
 
          -   .   F#    !   Xamarin Studio            . 
  <ItemGroup> <Compile Include="Resources\Resource.designer.fs" /> <Compile Include="Properties\AssemblyInfo.fs" /> <Compile Include="Helpers\Helpers.fs" /> <Compile Include="Services\User.fs" /> <Compile Include="Services\AzureServiceWorker.fs" /> <Compile Include="IAmHereActivity.fs" /> <Compile Include="WhereAreYouActivity.fs" /> <Compile Include="SignInActivity.fs" /> </ItemGroup> 
 
    
        :    .    Xamarin    Xamarin.Mobile 
 
      .  F#         TPL,     Task',      .     F#         Task.  ,     : 
 module Async = open System.Threading open System.Threading.Tasks let inline AwaitPlainTask (task: Task) = // rethrow exception from preceding task if it fauled let continuation (t : Task) : unit = match t.IsFaulted with | true -> raise t.Exception | arg -> () task.ContinueWith continuation |> Async.AwaitTask 
         Async.AwaitIAsyncResult >> Async.Ignore       
 
            
 let ExtractUserInfo (x : Contact) = let first = x.Phones |> Seq.tryPick(fun x -> if x.Type = PhoneType.Mobile then Some(x) else None) match first with | Some(first) -> let phone = first.Number |> StripChars [' ';'-';'(';')'] UserInfo.CreateUserInfo((MD5Hash phone), phone, x.DisplayName) | None -> UserInfo.CreateUserInfo("no mobile phone", "no mobile phone", "no mobile phone") // function for async list filling let FillContactsAsync = async { let book = new AddressBook (this) let! result = book.RequestPermission() |> Async.AwaitTask if result then _contacts <- book.ToList() |> Seq.filter (fun (x: Contact) -> not (Seq.isEmpty x.Phones)) |> Seq.map ExtractUserInfo |> Seq.sortBy(fun x -> x.DisplayName) |> Seq.toList let finalContacts = _contacts |> Seq.map (fun x -> x.DisplayName.ToUpperInvariant()) |> Seq.toArray this.ListAdapter <- new ArrayAdapter(this, Resource_Layout.row_contact, finalContacts) else System.Diagnostics.Debug.WriteLine("Permission denied by user or manifest") this.ListAdapter <- new ArrayAdapter(this, Resource_Layout.row_contact, Array.empty) } 
      
 book.ToList()   List |> Seq.filter (fun (x: Contact) -> not (Seq.isEmpty x.Phones))      |> Seq.map ExtractUserInfo      Contracts  UserInfo,      UserInfo |> Seq.sortBy(fun x -> x.DisplayName)  |> Seq.toList   List _contacts <-    mutable  _contacts |> Seq.map (fun x -> x.DisplayName.ToUpperInvariant())<-    UserInfo  string,     - -    |> Seq.toArray<-  List  Array    ArrayAdapter 
    -      List.   . 
 
 
 
 
 Azure Mobile Servcies 
   -    Azure Mobile Services.       NotificationHub,     Push    .   Azure    , ..      . 
 
      ,    
 module WruConstants = [<Literal>] let TotallyNotAzureServer = "https://YOUR.azure-mobile.net/"; [<Literal>] let TotallyNotAzureKey = "YOUR" 
 
       
 member this.RegisterMe phone name regId = async { try let table = this.MobileService.GetTable<User>() let usr = { Id = "" PhoneHash = MD5Hash phone Nickname = name RegistrationId = regId } do! table.InsertAsync usr |> Async.AwaitPlainTask return (usr.Id, usr.PhoneHash, usr.Nickname) with | e -> System.Diagnostics.Trace.WriteLine(e.ToString) return (String.Empty,String.Empty,String.Empty) } 
 member this.RegisterMe phone name regId = async { -       (     )    .       "computation expression"   workflow.   { }       ! ( bang),  do! (do-bang)  let! (let bang)     User.    ,  F#        ,      
  let usr = { Id = "" PhoneHash = MD5Hash phone Nickname = name RegistrationId = regId } do! table.InsertAsync usr |> Async.AwaitPlainTask  do-bang,   await  C#. ..             continuation    . return (usr.Id, usr.PhoneHash, usr.Nickname)      Tuple<string,string,string>     .  try ... with | e ->  try..catch  C# 
 
 
 
 
       .  F#    fst  snd      .        2 .     : 
  let id (c,_,_) = c let phonehash (_,c,_) = c let nickname (_,_,c) = c 
    : id tuple  Id  .. 
 
    5  Azure,       Push .       Azure Custom Api  
 
      exports.post = function(request, response) { // Use "request.service" to access features of your mobile service, eg: // var tables = request.service.tables; // var push = request.service.push; //response.send(statusCodes.OK, { message : 'Hello World!' }); console.log('Incoming call with requst: ', request.body.RequestId); var usersTable = request.service.tables.getTable('User'); usersTable.where( { id : request.body.TargetId } ) .read( { success: function(results) { if (results.length > 0) { var user = results[0] console.log('Send to results: ', user.Nickname, user.RegistrationId); request.service.push.gcm.send(user.RegistrationId, { RequesterId: request.body.RequesterId, RequesterNickname: request.body.RequesterName, TargetId: user.id, TargetNickname: user.Nickname }, { success: function(gcm_response) { console.log('Push notification sent: ', gcm_response); response.send(statusCodes.OK, { RequestedNickname : user.Nickname }); }, error: function(gcm_error) { console.log('Error sending push notification: ', gcm_error); response.send(statusCodes.INTERNAL_SERVER_ERROR, { RequestedNickname : user.Nickname }); } }); } else { response.send(statusCodes.NO_CONTENT, { RequestedNickname : "" }); } }, error: function(error) { console.log('Error read table: ', error); response.send(statusCodes.INTERNAL_SERVER_ERROR, { RequestedNickname : "" }); } }); }; 
 
    Push      
 // Perform Push operation member this.PushAsync targetId myId myNickname = async { try let (request : PushRequest) = { TargetId = targetId RequesterId = myId RequesterName = myNickname } let! result = this.MobileService.InvokeApiAsync<PushRequest, PushResponce>("pushhim", request) |> Async.AwaitTask return result.RequestedNickname with | e -> return e.ToString() } 
 
       ,    let-bang   do! 
 
   
 
 
 
      Google Play Services.     F#   .           .    : Xamarin.Android.Support.v7.AppCompat 
     , Google Play Services ,   . 
 
      push notification   .    GCM,  ID,     ID       Push  (.   pushhim).        BroadcastReciever       developer.android.com .     F#         Xamarin Component Store.     Google Cloud Messaging Client         GCM    .        ID 
 //Check to see that GCM is supported and that the manifest has the correct information GcmClient.CheckDevice(this) GcmClient.CheckManifest(this) // check google play if CheckPlayServices() then // Try to get registration id let regId = GcmClient.GetRegistrationId this if String.IsNullOrEmpty(regId) then // Call to Register the device for Push Notifications GcmClient.Register(this, WruConstants.GcmSender); 
 
 
 
        
 
    . 
    , -  
     bitbucket.org/xakpc/whereareyou 
     ,     
          ,           "" . 
 
  
 ,   Android   F#.      . 
 ,       -  Android  F#.   ,       . listView.Adapter <- new ArrayAdapter(this, Android.Resource.Layout.SimpleListItem1, Android.Resource.Id.Text1, values)
, , let values = [|"item1"; "item2"; "item3"|] - string[], list (IEnumerable )
F#. www.tryfsharp.org/Learn

F# - ,
F# For Fun And Profit
,
- .

hash
MD5 F#
let MD5Hash (input : string) = use md5 = System.Security.Cryptography.MD5.Create() input |> System.Text.Encoding.ASCII.GetBytes |> md5.ComputeHash |> Seq.map (fun c -> c.ToString("X2")) |> Seq.reduce (+)
|> pipeline , .
: GetBytes -> -> HEX -> ( reduce + ) -> .
, C# using System; public string CreateMD5Hash (string input) { MD5 md5 = System.Security.Cryptography.MD5.Create(); byte[] inputBytes = System.Text.Encoding.ASCII.GetBytes (input); byte[] hashBytes = md5.ComputeHash (inputBytes); StringBuilder sb = new StringBuilder(); for (int i = 0; i < hashBytes.Length; i++) { sb.Append (hashBytes[i].ToString ("X2")); } return sb.ToString(); }
: . AzureServiceWorker ( CLR )
- . F# ! Xamarin Studio .
<ItemGroup> <Compile Include="Resources\Resource.designer.fs" /> <Compile Include="Properties\AssemblyInfo.fs" /> <Compile Include="Helpers\Helpers.fs" /> <Compile Include="Services\User.fs" /> <Compile Include="Services\AzureServiceWorker.fs" /> <Compile Include="IAmHereActivity.fs" /> <Compile Include="WhereAreYouActivity.fs" /> <Compile Include="SignInActivity.fs" /> </ItemGroup>
: . Xamarin Xamarin.Mobile
. F# TPL, Task', . F# Task. , :
module Async = open System.Threading open System.Threading.Tasks let inline AwaitPlainTask (task: Task) = // rethrow exception from preceding task if it fauled let continuation (t : Task) : unit = match t.IsFaulted with | true -> raise t.Exception | arg -> () task.ContinueWith continuation |> Async.AwaitTask
Async.AwaitIAsyncResult >> Async.Ignore
let ExtractUserInfo (x : Contact) = let first = x.Phones |> Seq.tryPick(fun x -> if x.Type = PhoneType.Mobile then Some(x) else None) match first with | Some(first) -> let phone = first.Number |> StripChars [' ';'-';'(';')'] UserInfo.CreateUserInfo((MD5Hash phone), phone, x.DisplayName) | None -> UserInfo.CreateUserInfo("no mobile phone", "no mobile phone", "no mobile phone") // function for async list filling let FillContactsAsync = async { let book = new AddressBook (this) let! result = book.RequestPermission() |> Async.AwaitTask if result then _contacts <- book.ToList() |> Seq.filter (fun (x: Contact) -> not (Seq.isEmpty x.Phones)) |> Seq.map ExtractUserInfo |> Seq.sortBy(fun x -> x.DisplayName) |> Seq.toList let finalContacts = _contacts |> Seq.map (fun x -> x.DisplayName.ToUpperInvariant()) |> Seq.toArray this.ListAdapter <- new ArrayAdapter(this, Resource_Layout.row_contact, finalContacts) else System.Diagnostics.Debug.WriteLine("Permission denied by user or manifest") this.ListAdapter <- new ArrayAdapter(this, Resource_Layout.row_contact, Array.empty) }
book.ToList() List |> Seq.filter (fun (x: Contact) -> not (Seq.isEmpty x.Phones)) |> Seq.map ExtractUserInfo Contracts UserInfo, UserInfo |> Seq.sortBy(fun x -> x.DisplayName) |> Seq.toList List _contacts <- mutable _contacts |> Seq.map (fun x -> x.DisplayName.ToUpperInvariant())<- UserInfo string, - - |> Seq.toArray<- List Array ArrayAdapter
- List. .

Azure Mobile Servcies
- Azure Mobile Services. NotificationHub, Push . Azure , .. .
, 
module WruConstants = [<Literal>] let TotallyNotAzureServer = "https://YOUR.azure-mobile.net/"; [<Literal>] let TotallyNotAzureKey = "YOUR"
member this.RegisterMe phone name regId = async { try let table = this.MobileService.GetTable<User>() let usr = { Id = "" PhoneHash = MD5Hash phone Nickname = name RegistrationId = regId } do! table.InsertAsync usr |> Async.AwaitPlainTask return (usr.Id, usr.PhoneHash, usr.Nickname) with | e -> System.Diagnostics.Trace.WriteLine(e.ToString) return (String.Empty,String.Empty,String.Empty) }
member this.RegisterMe phone name regId = async { - ( ) . "computation expression" workflow. { } ! ( bang), do! (do-bang) let! (let bang) User. , F# ,
let usr = { Id = "" PhoneHash = MD5Hash phone Nickname = name RegistrationId = regId } do! table.InsertAsync usr |> Async.AwaitPlainTask do-bang, await C#. .. continuation . return (usr.Id, usr.PhoneHash, usr.Nickname) Tuple<string,string,string> . try ... with | e -> try..catch C#

. F# fst snd . 2 . :
let id (c,_,_) = c let phonehash (_,c,_) = c let nickname (_,_,c) = c
: id tuple Id ..
5 Azure, Push . Azure Custom Api
exports.post = function(request, response) { // Use "request.service" to access features of your mobile service, eg: // var tables = request.service.tables; // var push = request.service.push; //response.send(statusCodes.OK, { message : 'Hello World!' }); console.log('Incoming call with requst: ', request.body.RequestId); var usersTable = request.service.tables.getTable('User'); usersTable.where( { id : request.body.TargetId } ) .read( { success: function(results) { if (results.length > 0) { var user = results[0] console.log('Send to results: ', user.Nickname, user.RegistrationId); request.service.push.gcm.send(user.RegistrationId, { RequesterId: request.body.RequesterId, RequesterNickname: request.body.RequesterName, TargetId: user.id, TargetNickname: user.Nickname }, { success: function(gcm_response) { console.log('Push notification sent: ', gcm_response); response.send(statusCodes.OK, { RequestedNickname : user.Nickname }); }, error: function(gcm_error) { console.log('Error sending push notification: ', gcm_error); response.send(statusCodes.INTERNAL_SERVER_ERROR, { RequestedNickname : user.Nickname }); } }); } else { response.send(statusCodes.NO_CONTENT, { RequestedNickname : "" }); } }, error: function(error) { console.log('Error read table: ', error); response.send(statusCodes.INTERNAL_SERVER_ERROR, { RequestedNickname : "" }); } }); };
Push
// Perform Push operation member this.PushAsync targetId myId myNickname = async { try let (request : PushRequest) = { TargetId = targetId RequesterId = myId RequesterName = myNickname } let! result = this.MobileService.InvokeApiAsync<PushRequest, PushResponce>("pushhim", request) |> Async.AwaitTask return result.RequestedNickname with | e -> return e.ToString() }
, let-bang do!

Google Play Services. F# . . : Xamarin.Android.Support.v7.AppCompat
, Google Play Services , .
push notification . GCM, ID, ID Push (. pushhim). BroadcastReciever developer.android.com . F# Xamarin Component Store. Google Cloud Messaging Client GCM . ID
//Check to see that GCM is supported and that the manifest has the correct information GcmClient.CheckDevice(this) GcmClient.CheckManifest(this) // check google play if CheckPlayServices() then // Try to get registration id let regId = GcmClient.GetRegistrationId this if String.IsNullOrEmpty(regId) then // Call to Register the device for Push Notifications GcmClient.Register(this, WruConstants.GcmSender);

.
, -
bitbucket.org/xakpc/whereareyou
,
, "" .
, Android F#. .
, - Android F#. , .listView.Adapter <- new ArrayAdapter(this, Android.Resource.Layout.SimpleListItem1, Android.Resource.Id.Text1, values)
, , let values = [|"item1"; "item2"; "item3"|] - string[], list (IEnumerable )
F#. www.tryfsharp.org/Learn

F# - ,
F# For Fun And Profit
,
- .

hash
MD5 F#
let MD5Hash (input : string) = use md5 = System.Security.Cryptography.MD5.Create() input |> System.Text.Encoding.ASCII.GetBytes |> md5.ComputeHash |> Seq.map (fun c -> c.ToString("X2")) |> Seq.reduce (+)
|> pipeline , .
: GetBytes -> -> HEX -> ( reduce + ) -> .
, C# using System; public string CreateMD5Hash (string input) { MD5 md5 = System.Security.Cryptography.MD5.Create(); byte[] inputBytes = System.Text.Encoding.ASCII.GetBytes (input); byte[] hashBytes = md5.ComputeHash (inputBytes); StringBuilder sb = new StringBuilder(); for (int i = 0; i < hashBytes.Length; i++) { sb.Append (hashBytes[i].ToString ("X2")); } return sb.ToString(); }
: . AzureServiceWorker ( CLR )
- . F# ! Xamarin Studio .
<ItemGroup> <Compile Include="Resources\Resource.designer.fs" /> <Compile Include="Properties\AssemblyInfo.fs" /> <Compile Include="Helpers\Helpers.fs" /> <Compile Include="Services\User.fs" /> <Compile Include="Services\AzureServiceWorker.fs" /> <Compile Include="IAmHereActivity.fs" /> <Compile Include="WhereAreYouActivity.fs" /> <Compile Include="SignInActivity.fs" /> </ItemGroup>
: . Xamarin Xamarin.Mobile
. F# TPL, Task', . F# Task. , :
module Async = open System.Threading open System.Threading.Tasks let inline AwaitPlainTask (task: Task) = // rethrow exception from preceding task if it fauled let continuation (t : Task) : unit = match t.IsFaulted with | true -> raise t.Exception | arg -> () task.ContinueWith continuation |> Async.AwaitTask
Async.AwaitIAsyncResult >> Async.Ignore
let ExtractUserInfo (x : Contact) = let first = x.Phones |> Seq.tryPick(fun x -> if x.Type = PhoneType.Mobile then Some(x) else None) match first with | Some(first) -> let phone = first.Number |> StripChars [' ';'-';'(';')'] UserInfo.CreateUserInfo((MD5Hash phone), phone, x.DisplayName) | None -> UserInfo.CreateUserInfo("no mobile phone", "no mobile phone", "no mobile phone") // function for async list filling let FillContactsAsync = async { let book = new AddressBook (this) let! result = book.RequestPermission() |> Async.AwaitTask if result then _contacts <- book.ToList() |> Seq.filter (fun (x: Contact) -> not (Seq.isEmpty x.Phones)) |> Seq.map ExtractUserInfo |> Seq.sortBy(fun x -> x.DisplayName) |> Seq.toList let finalContacts = _contacts |> Seq.map (fun x -> x.DisplayName.ToUpperInvariant()) |> Seq.toArray this.ListAdapter <- new ArrayAdapter(this, Resource_Layout.row_contact, finalContacts) else System.Diagnostics.Debug.WriteLine("Permission denied by user or manifest") this.ListAdapter <- new ArrayAdapter(this, Resource_Layout.row_contact, Array.empty) }
book.ToList() List |> Seq.filter (fun (x: Contact) -> not (Seq.isEmpty x.Phones)) |> Seq.map ExtractUserInfo Contracts UserInfo, UserInfo |> Seq.sortBy(fun x -> x.DisplayName) |> Seq.toList List _contacts <- mutable _contacts |> Seq.map (fun x -> x.DisplayName.ToUpperInvariant())<- UserInfo string, - - |> Seq.toArray<- List Array ArrayAdapter
- List. .

Azure Mobile Servcies
- Azure Mobile Services. NotificationHub, Push . Azure , .. .
, 
module WruConstants = [<Literal>] let TotallyNotAzureServer = "https://YOUR.azure-mobile.net/"; [<Literal>] let TotallyNotAzureKey = "YOUR"
member this.RegisterMe phone name regId = async { try let table = this.MobileService.GetTable<User>() let usr = { Id = "" PhoneHash = MD5Hash phone Nickname = name RegistrationId = regId } do! table.InsertAsync usr |> Async.AwaitPlainTask return (usr.Id, usr.PhoneHash, usr.Nickname) with | e -> System.Diagnostics.Trace.WriteLine(e.ToString) return (String.Empty,String.Empty,String.Empty) }
member this.RegisterMe phone name regId = async { - ( ) . "computation expression" workflow. { } ! ( bang), do! (do-bang) let! (let bang) User. , F# ,
let usr = { Id = "" PhoneHash = MD5Hash phone Nickname = name RegistrationId = regId } do! table.InsertAsync usr |> Async.AwaitPlainTask do-bang, await C#. .. continuation . return (usr.Id, usr.PhoneHash, usr.Nickname) Tuple<string,string,string> . try ... with | e -> try..catch C#

. F# fst snd . 2 . :
let id (c,_,_) = c let phonehash (_,c,_) = c let nickname (_,_,c) = c
: id tuple Id ..
5 Azure, Push . Azure Custom Api
exports.post = function(request, response) { // Use "request.service" to access features of your mobile service, eg: // var tables = request.service.tables; // var push = request.service.push; //response.send(statusCodes.OK, { message : 'Hello World!' }); console.log('Incoming call with requst: ', request.body.RequestId); var usersTable = request.service.tables.getTable('User'); usersTable.where( { id : request.body.TargetId } ) .read( { success: function(results) { if (results.length > 0) { var user = results[0] console.log('Send to results: ', user.Nickname, user.RegistrationId); request.service.push.gcm.send(user.RegistrationId, { RequesterId: request.body.RequesterId, RequesterNickname: request.body.RequesterName, TargetId: user.id, TargetNickname: user.Nickname }, { success: function(gcm_response) { console.log('Push notification sent: ', gcm_response); response.send(statusCodes.OK, { RequestedNickname : user.Nickname }); }, error: function(gcm_error) { console.log('Error sending push notification: ', gcm_error); response.send(statusCodes.INTERNAL_SERVER_ERROR, { RequestedNickname : user.Nickname }); } }); } else { response.send(statusCodes.NO_CONTENT, { RequestedNickname : "" }); } }, error: function(error) { console.log('Error read table: ', error); response.send(statusCodes.INTERNAL_SERVER_ERROR, { RequestedNickname : "" }); } }); };
Push
// Perform Push operation member this.PushAsync targetId myId myNickname = async { try let (request : PushRequest) = { TargetId = targetId RequesterId = myId RequesterName = myNickname } let! result = this.MobileService.InvokeApiAsync<PushRequest, PushResponce>("pushhim", request) |> Async.AwaitTask return result.RequestedNickname with | e -> return e.ToString() }
, let-bang do!

Google Play Services. F# . . : Xamarin.Android.Support.v7.AppCompat
, Google Play Services , .
push notification . GCM, ID, ID Push (. pushhim). BroadcastReciever developer.android.com . F# Xamarin Component Store. Google Cloud Messaging Client GCM . ID
//Check to see that GCM is supported and that the manifest has the correct information GcmClient.CheckDevice(this) GcmClient.CheckManifest(this) // check google play if CheckPlayServices() then // Try to get registration id let regId = GcmClient.GetRegistrationId this if String.IsNullOrEmpty(regId) then // Call to Register the device for Push Notifications GcmClient.Register(this, WruConstants.GcmSender);

.
, -
bitbucket.org/xakpc/whereareyou
,
, "" .
, Android F#. .
, - Android F#. , . listView.Adapter <- new ArrayAdapter(this, Android.Resource.Layout.SimpleListItem1, Android.Resource.Id.Text1, values) 
  , ,  let values = [|"item1"; "item2"; "item3"|] -   string[],       list (IEnumerable   ) 
          F#.            www.tryfsharp.org/Learn 
 
 
      F# -  ,  
 
        F# For Fun And Profit 
 
   ,    
     - . 
 
 
 
 
        hash 
     MD5  F# 
  let MD5Hash (input : string) = use md5 = System.Security.Cryptography.MD5.Create() input |> System.Text.Encoding.ASCII.GetBytes |> md5.ComputeHash |> Seq.map (fun c -> c.ToString("X2")) |> Seq.reduce (+) 
 
  |>  pipeline ,     . 
     :    GetBytes ->   ->      HEX  ->       (  reduce   +           ) ->    . 
 
  ,     C# using System; public string CreateMD5Hash (string input) { MD5 md5 = System.Security.Cryptography.MD5.Create(); byte[] inputBytes = System.Text.Encoding.ASCII.GetBytes (input); byte[] hashBytes = md5.ComputeHash (inputBytes); StringBuilder sb = new StringBuilder(); for (int i = 0; i < hashBytes.Length; i++) { sb.Append (hashBytes[i].ToString ("X2")); } return sb.ToString(); } 
 
 
          :        .       AzureServiceWorker (  CLR    ) 
 
          -   .   F#    !   Xamarin Studio            . 
  <ItemGroup> <Compile Include="Resources\Resource.designer.fs" /> <Compile Include="Properties\AssemblyInfo.fs" /> <Compile Include="Helpers\Helpers.fs" /> <Compile Include="Services\User.fs" /> <Compile Include="Services\AzureServiceWorker.fs" /> <Compile Include="IAmHereActivity.fs" /> <Compile Include="WhereAreYouActivity.fs" /> <Compile Include="SignInActivity.fs" /> </ItemGroup> 
 
    
        :    .    Xamarin    Xamarin.Mobile 
 
      .  F#         TPL,     Task',      .     F#         Task.  ,     : 
 module Async = open System.Threading open System.Threading.Tasks let inline AwaitPlainTask (task: Task) = // rethrow exception from preceding task if it fauled let continuation (t : Task) : unit = match t.IsFaulted with | true -> raise t.Exception | arg -> () task.ContinueWith continuation |> Async.AwaitTask 
         Async.AwaitIAsyncResult >> Async.Ignore       
 
            
 let ExtractUserInfo (x : Contact) = let first = x.Phones |> Seq.tryPick(fun x -> if x.Type = PhoneType.Mobile then Some(x) else None) match first with | Some(first) -> let phone = first.Number |> StripChars [' ';'-';'(';')'] UserInfo.CreateUserInfo((MD5Hash phone), phone, x.DisplayName) | None -> UserInfo.CreateUserInfo("no mobile phone", "no mobile phone", "no mobile phone") // function for async list filling let FillContactsAsync = async { let book = new AddressBook (this) let! result = book.RequestPermission() |> Async.AwaitTask if result then _contacts <- book.ToList() |> Seq.filter (fun (x: Contact) -> not (Seq.isEmpty x.Phones)) |> Seq.map ExtractUserInfo |> Seq.sortBy(fun x -> x.DisplayName) |> Seq.toList let finalContacts = _contacts |> Seq.map (fun x -> x.DisplayName.ToUpperInvariant()) |> Seq.toArray this.ListAdapter <- new ArrayAdapter(this, Resource_Layout.row_contact, finalContacts) else System.Diagnostics.Debug.WriteLine("Permission denied by user or manifest") this.ListAdapter <- new ArrayAdapter(this, Resource_Layout.row_contact, Array.empty) } 
      
 book.ToList()   List |> Seq.filter (fun (x: Contact) -> not (Seq.isEmpty x.Phones))      |> Seq.map ExtractUserInfo      Contracts  UserInfo,      UserInfo |> Seq.sortBy(fun x -> x.DisplayName)  |> Seq.toList   List _contacts <-    mutable  _contacts |> Seq.map (fun x -> x.DisplayName.ToUpperInvariant())<-    UserInfo  string,     - -    |> Seq.toArray<-  List  Array    ArrayAdapter 
    -      List.   . 
 
 
 
 
 Azure Mobile Servcies 
   -    Azure Mobile Services.       NotificationHub,     Push    .   Azure    , ..      . 
 
      ,    
 module WruConstants = [<Literal>] let TotallyNotAzureServer = "https://YOUR.azure-mobile.net/"; [<Literal>] let TotallyNotAzureKey = "YOUR" 
 
       
 member this.RegisterMe phone name regId = async { try let table = this.MobileService.GetTable<User>() let usr = { Id = "" PhoneHash = MD5Hash phone Nickname = name RegistrationId = regId } do! table.InsertAsync usr |> Async.AwaitPlainTask return (usr.Id, usr.PhoneHash, usr.Nickname) with | e -> System.Diagnostics.Trace.WriteLine(e.ToString) return (String.Empty,String.Empty,String.Empty) } 
 member this.RegisterMe phone name regId = async { -       (     )    .       "computation expression"   workflow.   { }       ! ( bang),  do! (do-bang)  let! (let bang)     User.    ,  F#        ,      
  let usr = { Id = "" PhoneHash = MD5Hash phone Nickname = name RegistrationId = regId } do! table.InsertAsync usr |> Async.AwaitPlainTask  do-bang,   await  C#. ..             continuation    . return (usr.Id, usr.PhoneHash, usr.Nickname)      Tuple<string,string,string>     .  try ... with | e ->  try..catch  C# 
 
 
 
 
       .  F#    fst  snd      .        2 .     : 
  let id (c,_,_) = c let phonehash (_,c,_) = c let nickname (_,_,c) = c 
    : id tuple  Id  .. 
 
    5  Azure,       Push .       Azure Custom Api  
 
      exports.post = function(request, response) { // Use "request.service" to access features of your mobile service, eg: // var tables = request.service.tables; // var push = request.service.push; //response.send(statusCodes.OK, { message : 'Hello World!' }); console.log('Incoming call with requst: ', request.body.RequestId); var usersTable = request.service.tables.getTable('User'); usersTable.where( { id : request.body.TargetId } ) .read( { success: function(results) { if (results.length > 0) { var user = results[0] console.log('Send to results: ', user.Nickname, user.RegistrationId); request.service.push.gcm.send(user.RegistrationId, { RequesterId: request.body.RequesterId, RequesterNickname: request.body.RequesterName, TargetId: user.id, TargetNickname: user.Nickname }, { success: function(gcm_response) { console.log('Push notification sent: ', gcm_response); response.send(statusCodes.OK, { RequestedNickname : user.Nickname }); }, error: function(gcm_error) { console.log('Error sending push notification: ', gcm_error); response.send(statusCodes.INTERNAL_SERVER_ERROR, { RequestedNickname : user.Nickname }); } }); } else { response.send(statusCodes.NO_CONTENT, { RequestedNickname : "" }); } }, error: function(error) { console.log('Error read table: ', error); response.send(statusCodes.INTERNAL_SERVER_ERROR, { RequestedNickname : "" }); } }); }; 
 
    Push      
 // Perform Push operation member this.PushAsync targetId myId myNickname = async { try let (request : PushRequest) = { TargetId = targetId RequesterId = myId RequesterName = myNickname } let! result = this.MobileService.InvokeApiAsync<PushRequest, PushResponce>("pushhim", request) |> Async.AwaitTask return result.RequestedNickname with | e -> return e.ToString() } 
 
       ,    let-bang   do! 
 
   
 
 
 
      Google Play Services.     F#   .           .    : Xamarin.Android.Support.v7.AppCompat 
     , Google Play Services ,   . 
 
      push notification   .    GCM,  ID,     ID       Push  (.   pushhim).        BroadcastReciever       developer.android.com .     F#         Xamarin Component Store.     Google Cloud Messaging Client         GCM    .        ID 
 //Check to see that GCM is supported and that the manifest has the correct information GcmClient.CheckDevice(this) GcmClient.CheckManifest(this) // check google play if CheckPlayServices() then // Try to get registration id let regId = GcmClient.GetRegistrationId this if String.IsNullOrEmpty(regId) then // Call to Register the device for Push Notifications GcmClient.Register(this, WruConstants.GcmSender); 
 
 
 
        
 
    . 
    , -  
     bitbucket.org/xakpc/whereareyou 
     ,     
          ,           "" . 
 
  
 ,   Android   F#.      . 
 ,       -  Android  F#.   ,       . listView.Adapter <- new ArrayAdapter(this, Android.Resource.Layout.SimpleListItem1, Android.Resource.Id.Text1, values)
, , let values = [|"item1"; "item2"; "item3"|] - string[], list (IEnumerable )
F#. www.tryfsharp.org/Learn

F# - ,
F# For Fun And Profit
,
- .

hash
MD5 F#
let MD5Hash (input : string) = use md5 = System.Security.Cryptography.MD5.Create() input |> System.Text.Encoding.ASCII.GetBytes |> md5.ComputeHash |> Seq.map (fun c -> c.ToString("X2")) |> Seq.reduce (+)
|> pipeline , .
: GetBytes -> -> HEX -> ( reduce + ) -> .
, C# using System; public string CreateMD5Hash (string input) { MD5 md5 = System.Security.Cryptography.MD5.Create(); byte[] inputBytes = System.Text.Encoding.ASCII.GetBytes (input); byte[] hashBytes = md5.ComputeHash (inputBytes); StringBuilder sb = new StringBuilder(); for (int i = 0; i < hashBytes.Length; i++) { sb.Append (hashBytes[i].ToString ("X2")); } return sb.ToString(); }
: . AzureServiceWorker ( CLR )
- . F# ! Xamarin Studio .
<ItemGroup> <Compile Include="Resources\Resource.designer.fs" /> <Compile Include="Properties\AssemblyInfo.fs" /> <Compile Include="Helpers\Helpers.fs" /> <Compile Include="Services\User.fs" /> <Compile Include="Services\AzureServiceWorker.fs" /> <Compile Include="IAmHereActivity.fs" /> <Compile Include="WhereAreYouActivity.fs" /> <Compile Include="SignInActivity.fs" /> </ItemGroup>
: . Xamarin Xamarin.Mobile
. F# TPL, Task', . F# Task. , :
module Async = open System.Threading open System.Threading.Tasks let inline AwaitPlainTask (task: Task) = // rethrow exception from preceding task if it fauled let continuation (t : Task) : unit = match t.IsFaulted with | true -> raise t.Exception | arg -> () task.ContinueWith continuation |> Async.AwaitTask
Async.AwaitIAsyncResult >> Async.Ignore
let ExtractUserInfo (x : Contact) = let first = x.Phones |> Seq.tryPick(fun x -> if x.Type = PhoneType.Mobile then Some(x) else None) match first with | Some(first) -> let phone = first.Number |> StripChars [' ';'-';'(';')'] UserInfo.CreateUserInfo((MD5Hash phone), phone, x.DisplayName) | None -> UserInfo.CreateUserInfo("no mobile phone", "no mobile phone", "no mobile phone") // function for async list filling let FillContactsAsync = async { let book = new AddressBook (this) let! result = book.RequestPermission() |> Async.AwaitTask if result then _contacts <- book.ToList() |> Seq.filter (fun (x: Contact) -> not (Seq.isEmpty x.Phones)) |> Seq.map ExtractUserInfo |> Seq.sortBy(fun x -> x.DisplayName) |> Seq.toList let finalContacts = _contacts |> Seq.map (fun x -> x.DisplayName.ToUpperInvariant()) |> Seq.toArray this.ListAdapter <- new ArrayAdapter(this, Resource_Layout.row_contact, finalContacts) else System.Diagnostics.Debug.WriteLine("Permission denied by user or manifest") this.ListAdapter <- new ArrayAdapter(this, Resource_Layout.row_contact, Array.empty) }
book.ToList() List |> Seq.filter (fun (x: Contact) -> not (Seq.isEmpty x.Phones)) |> Seq.map ExtractUserInfo Contracts UserInfo, UserInfo |> Seq.sortBy(fun x -> x.DisplayName) |> Seq.toList List _contacts <- mutable _contacts |> Seq.map (fun x -> x.DisplayName.ToUpperInvariant())<- UserInfo string, - - |> Seq.toArray<- List Array ArrayAdapter
- List. .

Azure Mobile Servcies
- Azure Mobile Services. NotificationHub, Push . Azure , .. .
, 
module WruConstants = [<Literal>] let TotallyNotAzureServer = "https://YOUR.azure-mobile.net/"; [<Literal>] let TotallyNotAzureKey = "YOUR"
member this.RegisterMe phone name regId = async { try let table = this.MobileService.GetTable<User>() let usr = { Id = "" PhoneHash = MD5Hash phone Nickname = name RegistrationId = regId } do! table.InsertAsync usr |> Async.AwaitPlainTask return (usr.Id, usr.PhoneHash, usr.Nickname) with | e -> System.Diagnostics.Trace.WriteLine(e.ToString) return (String.Empty,String.Empty,String.Empty) }
member this.RegisterMe phone name regId = async { - ( ) . "computation expression" workflow. { } ! ( bang), do! (do-bang) let! (let bang) User. , F# ,
let usr = { Id = "" PhoneHash = MD5Hash phone Nickname = name RegistrationId = regId } do! table.InsertAsync usr |> Async.AwaitPlainTask do-bang, await C#. .. continuation . return (usr.Id, usr.PhoneHash, usr.Nickname) Tuple<string,string,string> . try ... with | e -> try..catch C#

. F# fst snd . 2 . :
let id (c,_,_) = c let phonehash (_,c,_) = c let nickname (_,_,c) = c
: id tuple Id ..
5 Azure, Push . Azure Custom Api
exports.post = function(request, response) { // Use "request.service" to access features of your mobile service, eg: // var tables = request.service.tables; // var push = request.service.push; //response.send(statusCodes.OK, { message : 'Hello World!' }); console.log('Incoming call with requst: ', request.body.RequestId); var usersTable = request.service.tables.getTable('User'); usersTable.where( { id : request.body.TargetId } ) .read( { success: function(results) { if (results.length > 0) { var user = results[0] console.log('Send to results: ', user.Nickname, user.RegistrationId); request.service.push.gcm.send(user.RegistrationId, { RequesterId: request.body.RequesterId, RequesterNickname: request.body.RequesterName, TargetId: user.id, TargetNickname: user.Nickname }, { success: function(gcm_response) { console.log('Push notification sent: ', gcm_response); response.send(statusCodes.OK, { RequestedNickname : user.Nickname }); }, error: function(gcm_error) { console.log('Error sending push notification: ', gcm_error); response.send(statusCodes.INTERNAL_SERVER_ERROR, { RequestedNickname : user.Nickname }); } }); } else { response.send(statusCodes.NO_CONTENT, { RequestedNickname : "" }); } }, error: function(error) { console.log('Error read table: ', error); response.send(statusCodes.INTERNAL_SERVER_ERROR, { RequestedNickname : "" }); } }); };
Push
// Perform Push operation member this.PushAsync targetId myId myNickname = async { try let (request : PushRequest) = { TargetId = targetId RequesterId = myId RequesterName = myNickname } let! result = this.MobileService.InvokeApiAsync<PushRequest, PushResponce>("pushhim", request) |> Async.AwaitTask return result.RequestedNickname with | e -> return e.ToString() }
, let-bang do!

Google Play Services. F# . . : Xamarin.Android.Support.v7.AppCompat
, Google Play Services , .
push notification . GCM, ID, ID Push (. pushhim). BroadcastReciever developer.android.com . F# Xamarin Component Store. Google Cloud Messaging Client GCM . ID
//Check to see that GCM is supported and that the manifest has the correct information GcmClient.CheckDevice(this) GcmClient.CheckManifest(this) // check google play if CheckPlayServices() then // Try to get registration id let regId = GcmClient.GetRegistrationId this if String.IsNullOrEmpty(regId) then // Call to Register the device for Push Notifications GcmClient.Register(this, WruConstants.GcmSender);

.
, -
bitbucket.org/xakpc/whereareyou
,
, "" .
, Android F#. .
, - Android F#. , .listView.Adapter <- new ArrayAdapter(this, Android.Resource.Layout.SimpleListItem1, Android.Resource.Id.Text1, values)
, , let values = [|"item1"; "item2"; "item3"|] - string[], list (IEnumerable )
F#. www.tryfsharp.org/Learn

F# - ,
F# For Fun And Profit
,
- .

hash
MD5 F#
let MD5Hash (input : string) = use md5 = System.Security.Cryptography.MD5.Create() input |> System.Text.Encoding.ASCII.GetBytes |> md5.ComputeHash |> Seq.map (fun c -> c.ToString("X2")) |> Seq.reduce (+)
|> pipeline , .
: GetBytes -> -> HEX -> ( reduce + ) -> .
, C# using System; public string CreateMD5Hash (string input) { MD5 md5 = System.Security.Cryptography.MD5.Create(); byte[] inputBytes = System.Text.Encoding.ASCII.GetBytes (input); byte[] hashBytes = md5.ComputeHash (inputBytes); StringBuilder sb = new StringBuilder(); for (int i = 0; i < hashBytes.Length; i++) { sb.Append (hashBytes[i].ToString ("X2")); } return sb.ToString(); }
: . AzureServiceWorker ( CLR )
- . F# ! Xamarin Studio .
<ItemGroup> <Compile Include="Resources\Resource.designer.fs" /> <Compile Include="Properties\AssemblyInfo.fs" /> <Compile Include="Helpers\Helpers.fs" /> <Compile Include="Services\User.fs" /> <Compile Include="Services\AzureServiceWorker.fs" /> <Compile Include="IAmHereActivity.fs" /> <Compile Include="WhereAreYouActivity.fs" /> <Compile Include="SignInActivity.fs" /> </ItemGroup>
: . Xamarin Xamarin.Mobile
. F# TPL, Task', . F# Task. , :
module Async = open System.Threading open System.Threading.Tasks let inline AwaitPlainTask (task: Task) = // rethrow exception from preceding task if it fauled let continuation (t : Task) : unit = match t.IsFaulted with | true -> raise t.Exception | arg -> () task.ContinueWith continuation |> Async.AwaitTask
Async.AwaitIAsyncResult >> Async.Ignore
let ExtractUserInfo (x : Contact) = let first = x.Phones |> Seq.tryPick(fun x -> if x.Type = PhoneType.Mobile then Some(x) else None) match first with | Some(first) -> let phone = first.Number |> StripChars [' ';'-';'(';')'] UserInfo.CreateUserInfo((MD5Hash phone), phone, x.DisplayName) | None -> UserInfo.CreateUserInfo("no mobile phone", "no mobile phone", "no mobile phone") // function for async list filling let FillContactsAsync = async { let book = new AddressBook (this) let! result = book.RequestPermission() |> Async.AwaitTask if result then _contacts <- book.ToList() |> Seq.filter (fun (x: Contact) -> not (Seq.isEmpty x.Phones)) |> Seq.map ExtractUserInfo |> Seq.sortBy(fun x -> x.DisplayName) |> Seq.toList let finalContacts = _contacts |> Seq.map (fun x -> x.DisplayName.ToUpperInvariant()) |> Seq.toArray this.ListAdapter <- new ArrayAdapter(this, Resource_Layout.row_contact, finalContacts) else System.Diagnostics.Debug.WriteLine("Permission denied by user or manifest") this.ListAdapter <- new ArrayAdapter(this, Resource_Layout.row_contact, Array.empty) }
book.ToList() List |> Seq.filter (fun (x: Contact) -> not (Seq.isEmpty x.Phones)) |> Seq.map ExtractUserInfo Contracts UserInfo, UserInfo |> Seq.sortBy(fun x -> x.DisplayName) |> Seq.toList List _contacts <- mutable _contacts |> Seq.map (fun x -> x.DisplayName.ToUpperInvariant())<- UserInfo string, - - |> Seq.toArray<- List Array ArrayAdapter
- List. .

Azure Mobile Servcies
- Azure Mobile Services. NotificationHub, Push . Azure , .. .
, 
module WruConstants = [<Literal>] let TotallyNotAzureServer = "https://YOUR.azure-mobile.net/"; [<Literal>] let TotallyNotAzureKey = "YOUR"
member this.RegisterMe phone name regId = async { try let table = this.MobileService.GetTable<User>() let usr = { Id = "" PhoneHash = MD5Hash phone Nickname = name RegistrationId = regId } do! table.InsertAsync usr |> Async.AwaitPlainTask return (usr.Id, usr.PhoneHash, usr.Nickname) with | e -> System.Diagnostics.Trace.WriteLine(e.ToString) return (String.Empty,String.Empty,String.Empty) }
member this.RegisterMe phone name regId = async { - ( ) . "computation expression" workflow. { } ! ( bang), do! (do-bang) let! (let bang) User. , F# ,
let usr = { Id = "" PhoneHash = MD5Hash phone Nickname = name RegistrationId = regId } do! table.InsertAsync usr |> Async.AwaitPlainTask do-bang, await C#. .. continuation . return (usr.Id, usr.PhoneHash, usr.Nickname) Tuple<string,string,string> . try ... with | e -> try..catch C#

. F# fst snd . 2 . :
let id (c,_,_) = c let phonehash (_,c,_) = c let nickname (_,_,c) = c
: id tuple Id ..
5 Azure, Push . Azure Custom Api
exports.post = function(request, response) { // Use "request.service" to access features of your mobile service, eg: // var tables = request.service.tables; // var push = request.service.push; //response.send(statusCodes.OK, { message : 'Hello World!' }); console.log('Incoming call with requst: ', request.body.RequestId); var usersTable = request.service.tables.getTable('User'); usersTable.where( { id : request.body.TargetId } ) .read( { success: function(results) { if (results.length > 0) { var user = results[0] console.log('Send to results: ', user.Nickname, user.RegistrationId); request.service.push.gcm.send(user.RegistrationId, { RequesterId: request.body.RequesterId, RequesterNickname: request.body.RequesterName, TargetId: user.id, TargetNickname: user.Nickname }, { success: function(gcm_response) { console.log('Push notification sent: ', gcm_response); response.send(statusCodes.OK, { RequestedNickname : user.Nickname }); }, error: function(gcm_error) { console.log('Error sending push notification: ', gcm_error); response.send(statusCodes.INTERNAL_SERVER_ERROR, { RequestedNickname : user.Nickname }); } }); } else { response.send(statusCodes.NO_CONTENT, { RequestedNickname : "" }); } }, error: function(error) { console.log('Error read table: ', error); response.send(statusCodes.INTERNAL_SERVER_ERROR, { RequestedNickname : "" }); } }); };
Push
// Perform Push operation member this.PushAsync targetId myId myNickname = async { try let (request : PushRequest) = { TargetId = targetId RequesterId = myId RequesterName = myNickname } let! result = this.MobileService.InvokeApiAsync<PushRequest, PushResponce>("pushhim", request) |> Async.AwaitTask return result.RequestedNickname with | e -> return e.ToString() }
, let-bang do!

Google Play Services. F# . . : Xamarin.Android.Support.v7.AppCompat
, Google Play Services , .
push notification . GCM, ID, ID Push (. pushhim). BroadcastReciever developer.android.com . F# Xamarin Component Store. Google Cloud Messaging Client GCM . ID
//Check to see that GCM is supported and that the manifest has the correct information GcmClient.CheckDevice(this) GcmClient.CheckManifest(this) // check google play if CheckPlayServices() then // Try to get registration id let regId = GcmClient.GetRegistrationId this if String.IsNullOrEmpty(regId) then // Call to Register the device for Push Notifications GcmClient.Register(this, WruConstants.GcmSender);

.
, -
bitbucket.org/xakpc/whereareyou
,
, "" .
, Android F#. .
, - Android F#. , .listView.Adapter <- new ArrayAdapter(this, Android.Resource.Layout.SimpleListItem1, Android.Resource.Id.Text1, values)
, , let values = [|"item1"; "item2"; "item3"|] - string[], list (IEnumerable )
F#. www.tryfsharp.org/Learn

F# - ,
F# For Fun And Profit
,
- .

hash
MD5 F#
let MD5Hash (input : string) = use md5 = System.Security.Cryptography.MD5.Create() input |> System.Text.Encoding.ASCII.GetBytes |> md5.ComputeHash |> Seq.map (fun c -> c.ToString("X2")) |> Seq.reduce (+)
|> pipeline , .
: GetBytes -> -> HEX -> ( reduce + ) -> .
, C# using System; public string CreateMD5Hash (string input) { MD5 md5 = System.Security.Cryptography.MD5.Create(); byte[] inputBytes = System.Text.Encoding.ASCII.GetBytes (input); byte[] hashBytes = md5.ComputeHash (inputBytes); StringBuilder sb = new StringBuilder(); for (int i = 0; i < hashBytes.Length; i++) { sb.Append (hashBytes[i].ToString ("X2")); } return sb.ToString(); }
: . AzureServiceWorker ( CLR )
- . F# ! Xamarin Studio .
<ItemGroup> <Compile Include="Resources\Resource.designer.fs" /> <Compile Include="Properties\AssemblyInfo.fs" /> <Compile Include="Helpers\Helpers.fs" /> <Compile Include="Services\User.fs" /> <Compile Include="Services\AzureServiceWorker.fs" /> <Compile Include="IAmHereActivity.fs" /> <Compile Include="WhereAreYouActivity.fs" /> <Compile Include="SignInActivity.fs" /> </ItemGroup>
: . Xamarin Xamarin.Mobile
. F# TPL, Task', . F# Task. , :
module Async = open System.Threading open System.Threading.Tasks let inline AwaitPlainTask (task: Task) = // rethrow exception from preceding task if it fauled let continuation (t : Task) : unit = match t.IsFaulted with | true -> raise t.Exception | arg -> () task.ContinueWith continuation |> Async.AwaitTask
Async.AwaitIAsyncResult >> Async.Ignore
let ExtractUserInfo (x : Contact) = let first = x.Phones |> Seq.tryPick(fun x -> if x.Type = PhoneType.Mobile then Some(x) else None) match first with | Some(first) -> let phone = first.Number |> StripChars [' ';'-';'(';')'] UserInfo.CreateUserInfo((MD5Hash phone), phone, x.DisplayName) | None -> UserInfo.CreateUserInfo("no mobile phone", "no mobile phone", "no mobile phone") // function for async list filling let FillContactsAsync = async { let book = new AddressBook (this) let! result = book.RequestPermission() |> Async.AwaitTask if result then _contacts <- book.ToList() |> Seq.filter (fun (x: Contact) -> not (Seq.isEmpty x.Phones)) |> Seq.map ExtractUserInfo |> Seq.sortBy(fun x -> x.DisplayName) |> Seq.toList let finalContacts = _contacts |> Seq.map (fun x -> x.DisplayName.ToUpperInvariant()) |> Seq.toArray this.ListAdapter <- new ArrayAdapter(this, Resource_Layout.row_contact, finalContacts) else System.Diagnostics.Debug.WriteLine("Permission denied by user or manifest") this.ListAdapter <- new ArrayAdapter(this, Resource_Layout.row_contact, Array.empty) }
book.ToList() List |> Seq.filter (fun (x: Contact) -> not (Seq.isEmpty x.Phones)) |> Seq.map ExtractUserInfo Contracts UserInfo, UserInfo |> Seq.sortBy(fun x -> x.DisplayName) |> Seq.toList List _contacts <- mutable _contacts |> Seq.map (fun x -> x.DisplayName.ToUpperInvariant())<- UserInfo string, - - |> Seq.toArray<- List Array ArrayAdapter
- List. .

Azure Mobile Servcies
- Azure Mobile Services. NotificationHub, Push . Azure , .. .
, 
module WruConstants = [<Literal>] let TotallyNotAzureServer = "https://YOUR.azure-mobile.net/"; [<Literal>] let TotallyNotAzureKey = "YOUR"
member this.RegisterMe phone name regId = async { try let table = this.MobileService.GetTable<User>() let usr = { Id = "" PhoneHash = MD5Hash phone Nickname = name RegistrationId = regId } do! table.InsertAsync usr |> Async.AwaitPlainTask return (usr.Id, usr.PhoneHash, usr.Nickname) with | e -> System.Diagnostics.Trace.WriteLine(e.ToString) return (String.Empty,String.Empty,String.Empty) }
member this.RegisterMe phone name regId = async { - ( ) . "computation expression" workflow. { } ! ( bang), do! (do-bang) let! (let bang) User. , F# ,
let usr = { Id = "" PhoneHash = MD5Hash phone Nickname = name RegistrationId = regId } do! table.InsertAsync usr |> Async.AwaitPlainTask do-bang, await C#. .. continuation . return (usr.Id, usr.PhoneHash, usr.Nickname) Tuple<string,string,string> . try ... with | e -> try..catch C#

. F# fst snd . 2 . :
let id (c,_,_) = c let phonehash (_,c,_) = c let nickname (_,_,c) = c
: id tuple Id ..
5 Azure, Push . Azure Custom Api
exports.post = function(request, response) { // Use "request.service" to access features of your mobile service, eg: // var tables = request.service.tables; // var push = request.service.push; //response.send(statusCodes.OK, { message : 'Hello World!' }); console.log('Incoming call with requst: ', request.body.RequestId); var usersTable = request.service.tables.getTable('User'); usersTable.where( { id : request.body.TargetId } ) .read( { success: function(results) { if (results.length > 0) { var user = results[0] console.log('Send to results: ', user.Nickname, user.RegistrationId); request.service.push.gcm.send(user.RegistrationId, { RequesterId: request.body.RequesterId, RequesterNickname: request.body.RequesterName, TargetId: user.id, TargetNickname: user.Nickname }, { success: function(gcm_response) { console.log('Push notification sent: ', gcm_response); response.send(statusCodes.OK, { RequestedNickname : user.Nickname }); }, error: function(gcm_error) { console.log('Error sending push notification: ', gcm_error); response.send(statusCodes.INTERNAL_SERVER_ERROR, { RequestedNickname : user.Nickname }); } }); } else { response.send(statusCodes.NO_CONTENT, { RequestedNickname : "" }); } }, error: function(error) { console.log('Error read table: ', error); response.send(statusCodes.INTERNAL_SERVER_ERROR, { RequestedNickname : "" }); } }); };
Push
// Perform Push operation member this.PushAsync targetId myId myNickname = async { try let (request : PushRequest) = { TargetId = targetId RequesterId = myId RequesterName = myNickname } let! result = this.MobileService.InvokeApiAsync<PushRequest, PushResponce>("pushhim", request) |> Async.AwaitTask return result.RequestedNickname with | e -> return e.ToString() }
, let-bang do!

Google Play Services. F# . . : Xamarin.Android.Support.v7.AppCompat
, Google Play Services , .
push notification . GCM, ID, ID Push (. pushhim). BroadcastReciever developer.android.com . F# Xamarin Component Store. Google Cloud Messaging Client GCM . ID
//Check to see that GCM is supported and that the manifest has the correct information GcmClient.CheckDevice(this) GcmClient.CheckManifest(this) // check google play if CheckPlayServices() then // Try to get registration id let regId = GcmClient.GetRegistrationId this if String.IsNullOrEmpty(regId) then // Call to Register the device for Push Notifications GcmClient.Register(this, WruConstants.GcmSender);

.
, -
bitbucket.org/xakpc/whereareyou
,
, "" .
, Android F#. .
, - Android F#. , .listView.Adapter <- new ArrayAdapter(this, Android.Resource.Layout.SimpleListItem1, Android.Resource.Id.Text1, values)
, , let values = [|"item1"; "item2"; "item3"|] - string[], list (IEnumerable )
F#. www.tryfsharp.org/Learn

F# - ,
F# For Fun And Profit
,
- .

hash
MD5 F#
let MD5Hash (input : string) = use md5 = System.Security.Cryptography.MD5.Create() input |> System.Text.Encoding.ASCII.GetBytes |> md5.ComputeHash |> Seq.map (fun c -> c.ToString("X2")) |> Seq.reduce (+)
|> pipeline , .
: GetBytes -> -> HEX -> ( reduce + ) -> .
, C# using System; public string CreateMD5Hash (string input) { MD5 md5 = System.Security.Cryptography.MD5.Create(); byte[] inputBytes = System.Text.Encoding.ASCII.GetBytes (input); byte[] hashBytes = md5.ComputeHash (inputBytes); StringBuilder sb = new StringBuilder(); for (int i = 0; i < hashBytes.Length; i++) { sb.Append (hashBytes[i].ToString ("X2")); } return sb.ToString(); }
: . AzureServiceWorker ( CLR )
- . F# ! Xamarin Studio .
<ItemGroup> <Compile Include="Resources\Resource.designer.fs" /> <Compile Include="Properties\AssemblyInfo.fs" /> <Compile Include="Helpers\Helpers.fs" /> <Compile Include="Services\User.fs" /> <Compile Include="Services\AzureServiceWorker.fs" /> <Compile Include="IAmHereActivity.fs" /> <Compile Include="WhereAreYouActivity.fs" /> <Compile Include="SignInActivity.fs" /> </ItemGroup>
: . Xamarin Xamarin.Mobile
. F# TPL, Task', . F# Task. , :
module Async = open System.Threading open System.Threading.Tasks let inline AwaitPlainTask (task: Task) = // rethrow exception from preceding task if it fauled let continuation (t : Task) : unit = match t.IsFaulted with | true -> raise t.Exception | arg -> () task.ContinueWith continuation |> Async.AwaitTask
Async.AwaitIAsyncResult >> Async.Ignore
let ExtractUserInfo (x : Contact) = let first = x.Phones |> Seq.tryPick(fun x -> if x.Type = PhoneType.Mobile then Some(x) else None) match first with | Some(first) -> let phone = first.Number |> StripChars [' ';'-';'(';')'] UserInfo.CreateUserInfo((MD5Hash phone), phone, x.DisplayName) | None -> UserInfo.CreateUserInfo("no mobile phone", "no mobile phone", "no mobile phone") // function for async list filling let FillContactsAsync = async { let book = new AddressBook (this) let! result = book.RequestPermission() |> Async.AwaitTask if result then _contacts <- book.ToList() |> Seq.filter (fun (x: Contact) -> not (Seq.isEmpty x.Phones)) |> Seq.map ExtractUserInfo |> Seq.sortBy(fun x -> x.DisplayName) |> Seq.toList let finalContacts = _contacts |> Seq.map (fun x -> x.DisplayName.ToUpperInvariant()) |> Seq.toArray this.ListAdapter <- new ArrayAdapter(this, Resource_Layout.row_contact, finalContacts) else System.Diagnostics.Debug.WriteLine("Permission denied by user or manifest") this.ListAdapter <- new ArrayAdapter(this, Resource_Layout.row_contact, Array.empty) }
book.ToList() List |> Seq.filter (fun (x: Contact) -> not (Seq.isEmpty x.Phones)) |> Seq.map ExtractUserInfo Contracts UserInfo, UserInfo |> Seq.sortBy(fun x -> x.DisplayName) |> Seq.toList List _contacts <- mutable _contacts |> Seq.map (fun x -> x.DisplayName.ToUpperInvariant())<- UserInfo string, - - |> Seq.toArray<- List Array ArrayAdapter
- List. .

Azure Mobile Servcies
- Azure Mobile Services. NotificationHub, Push . Azure , .. .
, 
module WruConstants = [<Literal>] let TotallyNotAzureServer = "https://YOUR.azure-mobile.net/"; [<Literal>] let TotallyNotAzureKey = "YOUR"
member this.RegisterMe phone name regId = async { try let table = this.MobileService.GetTable<User>() let usr = { Id = "" PhoneHash = MD5Hash phone Nickname = name RegistrationId = regId } do! table.InsertAsync usr |> Async.AwaitPlainTask return (usr.Id, usr.PhoneHash, usr.Nickname) with | e -> System.Diagnostics.Trace.WriteLine(e.ToString) return (String.Empty,String.Empty,String.Empty) }
member this.RegisterMe phone name regId = async { - ( ) . "computation expression" workflow. { } ! ( bang), do! (do-bang) let! (let bang) User. , F# ,
let usr = { Id = "" PhoneHash = MD5Hash phone Nickname = name RegistrationId = regId } do! table.InsertAsync usr |> Async.AwaitPlainTask do-bang, await C#. .. continuation . return (usr.Id, usr.PhoneHash, usr.Nickname) Tuple<string,string,string> . try ... with | e -> try..catch C#

. F# fst snd . 2 . :
let id (c,_,_) = c let phonehash (_,c,_) = c let nickname (_,_,c) = c
: id tuple Id ..
5 Azure, Push . Azure Custom Api
exports.post = function(request, response) { // Use "request.service" to access features of your mobile service, eg: // var tables = request.service.tables; // var push = request.service.push; //response.send(statusCodes.OK, { message : 'Hello World!' }); console.log('Incoming call with requst: ', request.body.RequestId); var usersTable = request.service.tables.getTable('User'); usersTable.where( { id : request.body.TargetId } ) .read( { success: function(results) { if (results.length > 0) { var user = results[0] console.log('Send to results: ', user.Nickname, user.RegistrationId); request.service.push.gcm.send(user.RegistrationId, { RequesterId: request.body.RequesterId, RequesterNickname: request.body.RequesterName, TargetId: user.id, TargetNickname: user.Nickname }, { success: function(gcm_response) { console.log('Push notification sent: ', gcm_response); response.send(statusCodes.OK, { RequestedNickname : user.Nickname }); }, error: function(gcm_error) { console.log('Error sending push notification: ', gcm_error); response.send(statusCodes.INTERNAL_SERVER_ERROR, { RequestedNickname : user.Nickname }); } }); } else { response.send(statusCodes.NO_CONTENT, { RequestedNickname : "" }); } }, error: function(error) { console.log('Error read table: ', error); response.send(statusCodes.INTERNAL_SERVER_ERROR, { RequestedNickname : "" }); } }); };
Push
// Perform Push operation member this.PushAsync targetId myId myNickname = async { try let (request : PushRequest) = { TargetId = targetId RequesterId = myId RequesterName = myNickname } let! result = this.MobileService.InvokeApiAsync<PushRequest, PushResponce>("pushhim", request) |> Async.AwaitTask return result.RequestedNickname with | e -> return e.ToString() }
, let-bang do!

Google Play Services. F# . . : Xamarin.Android.Support.v7.AppCompat
, Google Play Services , .
push notification . GCM, ID, ID Push (. pushhim). BroadcastReciever developer.android.com . F# Xamarin Component Store. Google Cloud Messaging Client GCM . ID
//Check to see that GCM is supported and that the manifest has the correct information GcmClient.CheckDevice(this) GcmClient.CheckManifest(this) // check google play if CheckPlayServices() then // Try to get registration id let regId = GcmClient.GetRegistrationId this if String.IsNullOrEmpty(regId) then // Call to Register the device for Push Notifications GcmClient.Register(this, WruConstants.GcmSender);

.
, -
bitbucket.org/xakpc/whereareyou
,
, "" .
, Android F#. .
, - Android F#. , .listView.Adapter <- new ArrayAdapter(this, Android.Resource.Layout.SimpleListItem1, Android.Resource.Id.Text1, values)
, , let values = [|"item1"; "item2"; "item3"|] - string[], list (IEnumerable )
F#. www.tryfsharp.org/Learn

F# - ,
F# For Fun And Profit
,
- .

hash
MD5 F#
let MD5Hash (input : string) = use md5 = System.Security.Cryptography.MD5.Create() input |> System.Text.Encoding.ASCII.GetBytes |> md5.ComputeHash |> Seq.map (fun c -> c.ToString("X2")) |> Seq.reduce (+)
|> pipeline , .
: GetBytes -> -> HEX -> ( reduce + ) -> .
, C# using System; public string CreateMD5Hash (string input) { MD5 md5 = System.Security.Cryptography.MD5.Create(); byte[] inputBytes = System.Text.Encoding.ASCII.GetBytes (input); byte[] hashBytes = md5.ComputeHash (inputBytes); StringBuilder sb = new StringBuilder(); for (int i = 0; i < hashBytes.Length; i++) { sb.Append (hashBytes[i].ToString ("X2")); } return sb.ToString(); }
: . AzureServiceWorker ( CLR )
- . F# ! Xamarin Studio .
<ItemGroup> <Compile Include="Resources\Resource.designer.fs" /> <Compile Include="Properties\AssemblyInfo.fs" /> <Compile Include="Helpers\Helpers.fs" /> <Compile Include="Services\User.fs" /> <Compile Include="Services\AzureServiceWorker.fs" /> <Compile Include="IAmHereActivity.fs" /> <Compile Include="WhereAreYouActivity.fs" /> <Compile Include="SignInActivity.fs" /> </ItemGroup>
: . Xamarin Xamarin.Mobile
. F# TPL, Task', . F# Task. , :
module Async = open System.Threading open System.Threading.Tasks let inline AwaitPlainTask (task: Task) = // rethrow exception from preceding task if it fauled let continuation (t : Task) : unit = match t.IsFaulted with | true -> raise t.Exception | arg -> () task.ContinueWith continuation |> Async.AwaitTask
Async.AwaitIAsyncResult >> Async.Ignore
let ExtractUserInfo (x : Contact) = let first = x.Phones |> Seq.tryPick(fun x -> if x.Type = PhoneType.Mobile then Some(x) else None) match first with | Some(first) -> let phone = first.Number |> StripChars [' ';'-';'(';')'] UserInfo.CreateUserInfo((MD5Hash phone), phone, x.DisplayName) | None -> UserInfo.CreateUserInfo("no mobile phone", "no mobile phone", "no mobile phone") // function for async list filling let FillContactsAsync = async { let book = new AddressBook (this) let! result = book.RequestPermission() |> Async.AwaitTask if result then _contacts <- book.ToList() |> Seq.filter (fun (x: Contact) -> not (Seq.isEmpty x.Phones)) |> Seq.map ExtractUserInfo |> Seq.sortBy(fun x -> x.DisplayName) |> Seq.toList let finalContacts = _contacts |> Seq.map (fun x -> x.DisplayName.ToUpperInvariant()) |> Seq.toArray this.ListAdapter <- new ArrayAdapter(this, Resource_Layout.row_contact, finalContacts) else System.Diagnostics.Debug.WriteLine("Permission denied by user or manifest") this.ListAdapter <- new ArrayAdapter(this, Resource_Layout.row_contact, Array.empty) }
book.ToList() List |> Seq.filter (fun (x: Contact) -> not (Seq.isEmpty x.Phones)) |> Seq.map ExtractUserInfo Contracts UserInfo, UserInfo |> Seq.sortBy(fun x -> x.DisplayName) |> Seq.toList List _contacts <- mutable _contacts |> Seq.map (fun x -> x.DisplayName.ToUpperInvariant())<- UserInfo string, - - |> Seq.toArray<- List Array ArrayAdapter
- List. .

Azure Mobile Servcies
- Azure Mobile Services. NotificationHub, Push . Azure , .. .
, 
module WruConstants = [<Literal>] let TotallyNotAzureServer = "https://YOUR.azure-mobile.net/"; [<Literal>] let TotallyNotAzureKey = "YOUR"
member this.RegisterMe phone name regId = async { try let table = this.MobileService.GetTable<User>() let usr = { Id = "" PhoneHash = MD5Hash phone Nickname = name RegistrationId = regId } do! table.InsertAsync usr |> Async.AwaitPlainTask return (usr.Id, usr.PhoneHash, usr.Nickname) with | e -> System.Diagnostics.Trace.WriteLine(e.ToString) return (String.Empty,String.Empty,String.Empty) }
member this.RegisterMe phone name regId = async { - ( ) . "computation expression" workflow. { } ! ( bang), do! (do-bang) let! (let bang) User. , F# ,
let usr = { Id = "" PhoneHash = MD5Hash phone Nickname = name RegistrationId = regId } do! table.InsertAsync usr |> Async.AwaitPlainTask do-bang, await C#. .. continuation . return (usr.Id, usr.PhoneHash, usr.Nickname) Tuple<string,string,string> . try ... with | e -> try..catch C#

. F# fst snd . 2 . :
let id (c,_,_) = c let phonehash (_,c,_) = c let nickname (_,_,c) = c
: id tuple Id ..
5 Azure, Push . Azure Custom Api
exports.post = function(request, response) { // Use "request.service" to access features of your mobile service, eg: // var tables = request.service.tables; // var push = request.service.push; //response.send(statusCodes.OK, { message : 'Hello World!' }); console.log('Incoming call with requst: ', request.body.RequestId); var usersTable = request.service.tables.getTable('User'); usersTable.where( { id : request.body.TargetId } ) .read( { success: function(results) { if (results.length > 0) { var user = results[0] console.log('Send to results: ', user.Nickname, user.RegistrationId); request.service.push.gcm.send(user.RegistrationId, { RequesterId: request.body.RequesterId, RequesterNickname: request.body.RequesterName, TargetId: user.id, TargetNickname: user.Nickname }, { success: function(gcm_response) { console.log('Push notification sent: ', gcm_response); response.send(statusCodes.OK, { RequestedNickname : user.Nickname }); }, error: function(gcm_error) { console.log('Error sending push notification: ', gcm_error); response.send(statusCodes.INTERNAL_SERVER_ERROR, { RequestedNickname : user.Nickname }); } }); } else { response.send(statusCodes.NO_CONTENT, { RequestedNickname : "" }); } }, error: function(error) { console.log('Error read table: ', error); response.send(statusCodes.INTERNAL_SERVER_ERROR, { RequestedNickname : "" }); } }); };
Push
// Perform Push operation member this.PushAsync targetId myId myNickname = async { try let (request : PushRequest) = { TargetId = targetId RequesterId = myId RequesterName = myNickname } let! result = this.MobileService.InvokeApiAsync<PushRequest, PushResponce>("pushhim", request) |> Async.AwaitTask return result.RequestedNickname with | e -> return e.ToString() }
, let-bang do!

Google Play Services. F# . . : Xamarin.Android.Support.v7.AppCompat
, Google Play Services , .
push notification . GCM, ID, ID Push (. pushhim). BroadcastReciever developer.android.com . F# Xamarin Component Store. Google Cloud Messaging Client GCM . ID
//Check to see that GCM is supported and that the manifest has the correct information GcmClient.CheckDevice(this) GcmClient.CheckManifest(this) // check google play if CheckPlayServices() then // Try to get registration id let regId = GcmClient.GetRegistrationId this if String.IsNullOrEmpty(regId) then // Call to Register the device for Push Notifications GcmClient.Register(this, WruConstants.GcmSender);

.
, -
bitbucket.org/xakpc/whereareyou
,
, "" .
, Android F#. .
, - Android F#. , . listView.Adapter <- new ArrayAdapter(this, Android.Resource.Layout.SimpleListItem1, Android.Resource.Id.Text1, values) 
  , ,  let values = [|"item1"; "item2"; "item3"|] -   string[],       list (IEnumerable   ) 
          F#.            www.tryfsharp.org/Learn 
 
 
      F# -  ,  
 
        F# For Fun And Profit 
 
   ,    
     - . 
 
 
 
 
        hash 
     MD5  F# 
  let MD5Hash (input : string) = use md5 = System.Security.Cryptography.MD5.Create() input |> System.Text.Encoding.ASCII.GetBytes |> md5.ComputeHash |> Seq.map (fun c -> c.ToString("X2")) |> Seq.reduce (+) 
 
  |>  pipeline ,     . 
     :    GetBytes ->   ->      HEX  ->       (  reduce   +           ) ->    . 
 
  ,     C# using System; public string CreateMD5Hash (string input) { MD5 md5 = System.Security.Cryptography.MD5.Create(); byte[] inputBytes = System.Text.Encoding.ASCII.GetBytes (input); byte[] hashBytes = md5.ComputeHash (inputBytes); StringBuilder sb = new StringBuilder(); for (int i = 0; i < hashBytes.Length; i++) { sb.Append (hashBytes[i].ToString ("X2")); } return sb.ToString(); } 
 
 
          :        .       AzureServiceWorker (  CLR    ) 
 
          -   .   F#    !   Xamarin Studio            . 
  <ItemGroup> <Compile Include="Resources\Resource.designer.fs" /> <Compile Include="Properties\AssemblyInfo.fs" /> <Compile Include="Helpers\Helpers.fs" /> <Compile Include="Services\User.fs" /> <Compile Include="Services\AzureServiceWorker.fs" /> <Compile Include="IAmHereActivity.fs" /> <Compile Include="WhereAreYouActivity.fs" /> <Compile Include="SignInActivity.fs" /> </ItemGroup> 
 
    
        :    .    Xamarin    Xamarin.Mobile 
 
      .  F#         TPL,     Task',      .     F#         Task.  ,     : 
 module Async = open System.Threading open System.Threading.Tasks let inline AwaitPlainTask (task: Task) = // rethrow exception from preceding task if it fauled let continuation (t : Task) : unit = match t.IsFaulted with | true -> raise t.Exception | arg -> () task.ContinueWith continuation |> Async.AwaitTask 
         Async.AwaitIAsyncResult >> Async.Ignore       
 
            
 let ExtractUserInfo (x : Contact) = let first = x.Phones |> Seq.tryPick(fun x -> if x.Type = PhoneType.Mobile then Some(x) else None) match first with | Some(first) -> let phone = first.Number |> StripChars [' ';'-';'(';')'] UserInfo.CreateUserInfo((MD5Hash phone), phone, x.DisplayName) | None -> UserInfo.CreateUserInfo("no mobile phone", "no mobile phone", "no mobile phone") // function for async list filling let FillContactsAsync = async { let book = new AddressBook (this) let! result = book.RequestPermission() |> Async.AwaitTask if result then _contacts <- book.ToList() |> Seq.filter (fun (x: Contact) -> not (Seq.isEmpty x.Phones)) |> Seq.map ExtractUserInfo |> Seq.sortBy(fun x -> x.DisplayName) |> Seq.toList let finalContacts = _contacts |> Seq.map (fun x -> x.DisplayName.ToUpperInvariant()) |> Seq.toArray this.ListAdapter <- new ArrayAdapter(this, Resource_Layout.row_contact, finalContacts) else System.Diagnostics.Debug.WriteLine("Permission denied by user or manifest") this.ListAdapter <- new ArrayAdapter(this, Resource_Layout.row_contact, Array.empty) } 
      
 book.ToList()   List |> Seq.filter (fun (x: Contact) -> not (Seq.isEmpty x.Phones))      |> Seq.map ExtractUserInfo      Contracts  UserInfo,      UserInfo |> Seq.sortBy(fun x -> x.DisplayName)  |> Seq.toList   List _contacts <-    mutable  _contacts |> Seq.map (fun x -> x.DisplayName.ToUpperInvariant())<-    UserInfo  string,     - -    |> Seq.toArray<-  List  Array    ArrayAdapter 
    -      List.   . 
 
 
 
 
 Azure Mobile Servcies 
   -    Azure Mobile Services.       NotificationHub,     Push    .   Azure    , ..      . 
 
      ,    
 module WruConstants = [<Literal>] let TotallyNotAzureServer = "https://YOUR.azure-mobile.net/"; [<Literal>] let TotallyNotAzureKey = "YOUR" 
 
       
 member this.RegisterMe phone name regId = async { try let table = this.MobileService.GetTable<User>() let usr = { Id = "" PhoneHash = MD5Hash phone Nickname = name RegistrationId = regId } do! table.InsertAsync usr |> Async.AwaitPlainTask return (usr.Id, usr.PhoneHash, usr.Nickname) with | e -> System.Diagnostics.Trace.WriteLine(e.ToString) return (String.Empty,String.Empty,String.Empty) } 
 member this.RegisterMe phone name regId = async { -       (     )    .       "computation expression"   workflow.   { }       ! ( bang),  do! (do-bang)  let! (let bang)     User.    ,  F#        ,      
  let usr = { Id = "" PhoneHash = MD5Hash phone Nickname = name RegistrationId = regId } do! table.InsertAsync usr |> Async.AwaitPlainTask  do-bang,   await  C#. ..             continuation    . return (usr.Id, usr.PhoneHash, usr.Nickname)      Tuple<string,string,string>     .  try ... with | e ->  try..catch  C# 
 
 
 
 
       .  F#    fst  snd      .        2 .     : 
  let id (c,_,_) = c let phonehash (_,c,_) = c let nickname (_,_,c) = c 
    : id tuple  Id  .. 
 
    5  Azure,       Push .       Azure Custom Api  
 
      exports.post = function(request, response) { // Use "request.service" to access features of your mobile service, eg: // var tables = request.service.tables; // var push = request.service.push; //response.send(statusCodes.OK, { message : 'Hello World!' }); console.log('Incoming call with requst: ', request.body.RequestId); var usersTable = request.service.tables.getTable('User'); usersTable.where( { id : request.body.TargetId } ) .read( { success: function(results) { if (results.length > 0) { var user = results[0] console.log('Send to results: ', user.Nickname, user.RegistrationId); request.service.push.gcm.send(user.RegistrationId, { RequesterId: request.body.RequesterId, RequesterNickname: request.body.RequesterName, TargetId: user.id, TargetNickname: user.Nickname }, { success: function(gcm_response) { console.log('Push notification sent: ', gcm_response); response.send(statusCodes.OK, { RequestedNickname : user.Nickname }); }, error: function(gcm_error) { console.log('Error sending push notification: ', gcm_error); response.send(statusCodes.INTERNAL_SERVER_ERROR, { RequestedNickname : user.Nickname }); } }); } else { response.send(statusCodes.NO_CONTENT, { RequestedNickname : "" }); } }, error: function(error) { console.log('Error read table: ', error); response.send(statusCodes.INTERNAL_SERVER_ERROR, { RequestedNickname : "" }); } }); }; 
 
    Push      
 // Perform Push operation member this.PushAsync targetId myId myNickname = async { try let (request : PushRequest) = { TargetId = targetId RequesterId = myId RequesterName = myNickname } let! result = this.MobileService.InvokeApiAsync<PushRequest, PushResponce>("pushhim", request) |> Async.AwaitTask return result.RequestedNickname with | e -> return e.ToString() } 
 
       ,    let-bang   do! 
 
   
 
 
 
      Google Play Services.     F#   .           .    : Xamarin.Android.Support.v7.AppCompat 
     , Google Play Services ,   . 
 
      push notification   .    GCM,  ID,     ID       Push  (.   pushhim).        BroadcastReciever       developer.android.com .     F#         Xamarin Component Store.     Google Cloud Messaging Client         GCM    .        ID 
 //Check to see that GCM is supported and that the manifest has the correct information GcmClient.CheckDevice(this) GcmClient.CheckManifest(this) // check google play if CheckPlayServices() then // Try to get registration id let regId = GcmClient.GetRegistrationId this if String.IsNullOrEmpty(regId) then // Call to Register the device for Push Notifications GcmClient.Register(this, WruConstants.GcmSender); 
 
 
 
        
 
    . 
    , -  
     bitbucket.org/xakpc/whereareyou 
     ,     
          ,           "" . 
 
  
 ,   Android   F#.      . 
 ,       -  Android  F#.   ,       . listView.Adapter <- new ArrayAdapter(this, Android.Resource.Layout.SimpleListItem1, Android.Resource.Id.Text1, values)
, , let values = [|"item1"; "item2"; "item3"|] - string[], list (IEnumerable )
F#. www.tryfsharp.org/Learn

F# - ,
F# For Fun And Profit
,
- .

hash
MD5 F#
let MD5Hash (input : string) = use md5 = System.Security.Cryptography.MD5.Create() input |> System.Text.Encoding.ASCII.GetBytes |> md5.ComputeHash |> Seq.map (fun c -> c.ToString("X2")) |> Seq.reduce (+)
|> pipeline , .
: GetBytes -> -> HEX -> ( reduce + ) -> .
, C# using System; public string CreateMD5Hash (string input) { MD5 md5 = System.Security.Cryptography.MD5.Create(); byte[] inputBytes = System.Text.Encoding.ASCII.GetBytes (input); byte[] hashBytes = md5.ComputeHash (inputBytes); StringBuilder sb = new StringBuilder(); for (int i = 0; i < hashBytes.Length; i++) { sb.Append (hashBytes[i].ToString ("X2")); } return sb.ToString(); }
: . AzureServiceWorker ( CLR )
- . F# ! Xamarin Studio .
<ItemGroup> <Compile Include="Resources\Resource.designer.fs" /> <Compile Include="Properties\AssemblyInfo.fs" /> <Compile Include="Helpers\Helpers.fs" /> <Compile Include="Services\User.fs" /> <Compile Include="Services\AzureServiceWorker.fs" /> <Compile Include="IAmHereActivity.fs" /> <Compile Include="WhereAreYouActivity.fs" /> <Compile Include="SignInActivity.fs" /> </ItemGroup>
: . Xamarin Xamarin.Mobile
. F# TPL, Task', . F# Task. , :
module Async = open System.Threading open System.Threading.Tasks let inline AwaitPlainTask (task: Task) = // rethrow exception from preceding task if it fauled let continuation (t : Task) : unit = match t.IsFaulted with | true -> raise t.Exception | arg -> () task.ContinueWith continuation |> Async.AwaitTask
Async.AwaitIAsyncResult >> Async.Ignore
let ExtractUserInfo (x : Contact) = let first = x.Phones |> Seq.tryPick(fun x -> if x.Type = PhoneType.Mobile then Some(x) else None) match first with | Some(first) -> let phone = first.Number |> StripChars [' ';'-';'(';')'] UserInfo.CreateUserInfo((MD5Hash phone), phone, x.DisplayName) | None -> UserInfo.CreateUserInfo("no mobile phone", "no mobile phone", "no mobile phone") // function for async list filling let FillContactsAsync = async { let book = new AddressBook (this) let! result = book.RequestPermission() |> Async.AwaitTask if result then _contacts <- book.ToList() |> Seq.filter (fun (x: Contact) -> not (Seq.isEmpty x.Phones)) |> Seq.map ExtractUserInfo |> Seq.sortBy(fun x -> x.DisplayName) |> Seq.toList let finalContacts = _contacts |> Seq.map (fun x -> x.DisplayName.ToUpperInvariant()) |> Seq.toArray this.ListAdapter <- new ArrayAdapter(this, Resource_Layout.row_contact, finalContacts) else System.Diagnostics.Debug.WriteLine("Permission denied by user or manifest") this.ListAdapter <- new ArrayAdapter(this, Resource_Layout.row_contact, Array.empty) }
book.ToList() List |> Seq.filter (fun (x: Contact) -> not (Seq.isEmpty x.Phones)) |> Seq.map ExtractUserInfo Contracts UserInfo, UserInfo |> Seq.sortBy(fun x -> x.DisplayName) |> Seq.toList List _contacts <- mutable _contacts |> Seq.map (fun x -> x.DisplayName.ToUpperInvariant())<- UserInfo string, - - |> Seq.toArray<- List Array ArrayAdapter
- List. .

Azure Mobile Servcies
- Azure Mobile Services. NotificationHub, Push . Azure , .. .
, 
module WruConstants = [<Literal>] let TotallyNotAzureServer = "https://YOUR.azure-mobile.net/"; [<Literal>] let TotallyNotAzureKey = "YOUR"
member this.RegisterMe phone name regId = async { try let table = this.MobileService.GetTable<User>() let usr = { Id = "" PhoneHash = MD5Hash phone Nickname = name RegistrationId = regId } do! table.InsertAsync usr |> Async.AwaitPlainTask return (usr.Id, usr.PhoneHash, usr.Nickname) with | e -> System.Diagnostics.Trace.WriteLine(e.ToString) return (String.Empty,String.Empty,String.Empty) }
member this.RegisterMe phone name regId = async { - ( ) . "computation expression" workflow. { } ! ( bang), do! (do-bang) let! (let bang) User. , F# ,
let usr = { Id = "" PhoneHash = MD5Hash phone Nickname = name RegistrationId = regId } do! table.InsertAsync usr |> Async.AwaitPlainTask do-bang, await C#. .. continuation . return (usr.Id, usr.PhoneHash, usr.Nickname) Tuple<string,string,string> . try ... with | e -> try..catch C#

. F# fst snd . 2 . :
let id (c,_,_) = c let phonehash (_,c,_) = c let nickname (_,_,c) = c
: id tuple Id ..
5 Azure, Push . Azure Custom Api
exports.post = function(request, response) { // Use "request.service" to access features of your mobile service, eg: // var tables = request.service.tables; // var push = request.service.push; //response.send(statusCodes.OK, { message : 'Hello World!' }); console.log('Incoming call with requst: ', request.body.RequestId); var usersTable = request.service.tables.getTable('User'); usersTable.where( { id : request.body.TargetId } ) .read( { success: function(results) { if (results.length > 0) { var user = results[0] console.log('Send to results: ', user.Nickname, user.RegistrationId); request.service.push.gcm.send(user.RegistrationId, { RequesterId: request.body.RequesterId, RequesterNickname: request.body.RequesterName, TargetId: user.id, TargetNickname: user.Nickname }, { success: function(gcm_response) { console.log('Push notification sent: ', gcm_response); response.send(statusCodes.OK, { RequestedNickname : user.Nickname }); }, error: function(gcm_error) { console.log('Error sending push notification: ', gcm_error); response.send(statusCodes.INTERNAL_SERVER_ERROR, { RequestedNickname : user.Nickname }); } }); } else { response.send(statusCodes.NO_CONTENT, { RequestedNickname : "" }); } }, error: function(error) { console.log('Error read table: ', error); response.send(statusCodes.INTERNAL_SERVER_ERROR, { RequestedNickname : "" }); } }); };
Push
// Perform Push operation member this.PushAsync targetId myId myNickname = async { try let (request : PushRequest) = { TargetId = targetId RequesterId = myId RequesterName = myNickname } let! result = this.MobileService.InvokeApiAsync<PushRequest, PushResponce>("pushhim", request) |> Async.AwaitTask return result.RequestedNickname with | e -> return e.ToString() }
, let-bang do!

Google Play Services. F# . . : Xamarin.Android.Support.v7.AppCompat
, Google Play Services , .
push notification . GCM, ID, ID Push (. pushhim). BroadcastReciever developer.android.com . F# Xamarin Component Store. Google Cloud Messaging Client GCM . ID
//Check to see that GCM is supported and that the manifest has the correct information GcmClient.CheckDevice(this) GcmClient.CheckManifest(this) // check google play if CheckPlayServices() then // Try to get registration id let regId = GcmClient.GetRegistrationId this if String.IsNullOrEmpty(regId) then // Call to Register the device for Push Notifications GcmClient.Register(this, WruConstants.GcmSender);

.
, -
bitbucket.org/xakpc/whereareyou
,
, "" .
, Android F#. .
, - Android F#. , .listView.Adapter <- new ArrayAdapter(this, Android.Resource.Layout.SimpleListItem1, Android.Resource.Id.Text1, values)
, , let values = [|"item1"; "item2"; "item3"|] - string[], list (IEnumerable )
F#. www.tryfsharp.org/Learn

F# - ,
F# For Fun And Profit
,
- .

hash
MD5 F#
let MD5Hash (input : string) = use md5 = System.Security.Cryptography.MD5.Create() input |> System.Text.Encoding.ASCII.GetBytes |> md5.ComputeHash |> Seq.map (fun c -> c.ToString("X2")) |> Seq.reduce (+)
|> pipeline , .
: GetBytes -> -> HEX -> ( reduce + ) -> .
, C# using System; public string CreateMD5Hash (string input) { MD5 md5 = System.Security.Cryptography.MD5.Create(); byte[] inputBytes = System.Text.Encoding.ASCII.GetBytes (input); byte[] hashBytes = md5.ComputeHash (inputBytes); StringBuilder sb = new StringBuilder(); for (int i = 0; i < hashBytes.Length; i++) { sb.Append (hashBytes[i].ToString ("X2")); } return sb.ToString(); }
: . AzureServiceWorker ( CLR )
- . F# ! Xamarin Studio .
<ItemGroup> <Compile Include="Resources\Resource.designer.fs" /> <Compile Include="Properties\AssemblyInfo.fs" /> <Compile Include="Helpers\Helpers.fs" /> <Compile Include="Services\User.fs" /> <Compile Include="Services\AzureServiceWorker.fs" /> <Compile Include="IAmHereActivity.fs" /> <Compile Include="WhereAreYouActivity.fs" /> <Compile Include="SignInActivity.fs" /> </ItemGroup>
: . Xamarin Xamarin.Mobile
. F# TPL, Task', . F# Task. , :
module Async = open System.Threading open System.Threading.Tasks let inline AwaitPlainTask (task: Task) = // rethrow exception from preceding task if it fauled let continuation (t : Task) : unit = match t.IsFaulted with | true -> raise t.Exception | arg -> () task.ContinueWith continuation |> Async.AwaitTask
Async.AwaitIAsyncResult >> Async.Ignore
let ExtractUserInfo (x : Contact) = let first = x.Phones |> Seq.tryPick(fun x -> if x.Type = PhoneType.Mobile then Some(x) else None) match first with | Some(first) -> let phone = first.Number |> StripChars [' ';'-';'(';')'] UserInfo.CreateUserInfo((MD5Hash phone), phone, x.DisplayName) | None -> UserInfo.CreateUserInfo("no mobile phone", "no mobile phone", "no mobile phone") // function for async list filling let FillContactsAsync = async { let book = new AddressBook (this) let! result = book.RequestPermission() |> Async.AwaitTask if result then _contacts <- book.ToList() |> Seq.filter (fun (x: Contact) -> not (Seq.isEmpty x.Phones)) |> Seq.map ExtractUserInfo |> Seq.sortBy(fun x -> x.DisplayName) |> Seq.toList let finalContacts = _contacts |> Seq.map (fun x -> x.DisplayName.ToUpperInvariant()) |> Seq.toArray this.ListAdapter <- new ArrayAdapter(this, Resource_Layout.row_contact, finalContacts) else System.Diagnostics.Debug.WriteLine("Permission denied by user or manifest") this.ListAdapter <- new ArrayAdapter(this, Resource_Layout.row_contact, Array.empty) }
book.ToList() List |> Seq.filter (fun (x: Contact) -> not (Seq.isEmpty x.Phones)) |> Seq.map ExtractUserInfo Contracts UserInfo, UserInfo |> Seq.sortBy(fun x -> x.DisplayName) |> Seq.toList List _contacts <- mutable _contacts |> Seq.map (fun x -> x.DisplayName.ToUpperInvariant())<- UserInfo string, - - |> Seq.toArray<- List Array ArrayAdapter
- List. .

Azure Mobile Servcies
- Azure Mobile Services. NotificationHub, Push . Azure , .. .
, 
module WruConstants = [<Literal>] let TotallyNotAzureServer = "https://YOUR.azure-mobile.net/"; [<Literal>] let TotallyNotAzureKey = "YOUR"
member this.RegisterMe phone name regId = async { try let table = this.MobileService.GetTable<User>() let usr = { Id = "" PhoneHash = MD5Hash phone Nickname = name RegistrationId = regId } do! table.InsertAsync usr |> Async.AwaitPlainTask return (usr.Id, usr.PhoneHash, usr.Nickname) with | e -> System.Diagnostics.Trace.WriteLine(e.ToString) return (String.Empty,String.Empty,String.Empty) }
member this.RegisterMe phone name regId = async { - ( ) . "computation expression" workflow. { } ! ( bang), do! (do-bang) let! (let bang) User. , F# ,
let usr = { Id = "" PhoneHash = MD5Hash phone Nickname = name RegistrationId = regId } do! table.InsertAsync usr |> Async.AwaitPlainTask do-bang, await C#. .. continuation . return (usr.Id, usr.PhoneHash, usr.Nickname) Tuple<string,string,string> . try ... with | e -> try..catch C#

. F# fst snd . 2 . :
let id (c,_,_) = c let phonehash (_,c,_) = c let nickname (_,_,c) = c
: id tuple Id ..
5 Azure, Push . Azure Custom Api
exports.post = function(request, response) { // Use "request.service" to access features of your mobile service, eg: // var tables = request.service.tables; // var push = request.service.push; //response.send(statusCodes.OK, { message : 'Hello World!' }); console.log('Incoming call with requst: ', request.body.RequestId); var usersTable = request.service.tables.getTable('User'); usersTable.where( { id : request.body.TargetId } ) .read( { success: function(results) { if (results.length > 0) { var user = results[0] console.log('Send to results: ', user.Nickname, user.RegistrationId); request.service.push.gcm.send(user.RegistrationId, { RequesterId: request.body.RequesterId, RequesterNickname: request.body.RequesterName, TargetId: user.id, TargetNickname: user.Nickname }, { success: function(gcm_response) { console.log('Push notification sent: ', gcm_response); response.send(statusCodes.OK, { RequestedNickname : user.Nickname }); }, error: function(gcm_error) { console.log('Error sending push notification: ', gcm_error); response.send(statusCodes.INTERNAL_SERVER_ERROR, { RequestedNickname : user.Nickname }); } }); } else { response.send(statusCodes.NO_CONTENT, { RequestedNickname : "" }); } }, error: function(error) { console.log('Error read table: ', error); response.send(statusCodes.INTERNAL_SERVER_ERROR, { RequestedNickname : "" }); } }); };
Push
// Perform Push operation member this.PushAsync targetId myId myNickname = async { try let (request : PushRequest) = { TargetId = targetId RequesterId = myId RequesterName = myNickname } let! result = this.MobileService.InvokeApiAsync<PushRequest, PushResponce>("pushhim", request) |> Async.AwaitTask return result.RequestedNickname with | e -> return e.ToString() }
, let-bang do!

Google Play Services. F# . . : Xamarin.Android.Support.v7.AppCompat
, Google Play Services , .
push notification . GCM, ID, ID Push (. pushhim). BroadcastReciever developer.android.com . F# Xamarin Component Store. Google Cloud Messaging Client GCM . ID
//Check to see that GCM is supported and that the manifest has the correct information GcmClient.CheckDevice(this) GcmClient.CheckManifest(this) // check google play if CheckPlayServices() then // Try to get registration id let regId = GcmClient.GetRegistrationId this if String.IsNullOrEmpty(regId) then // Call to Register the device for Push Notifications GcmClient.Register(this, WruConstants.GcmSender);

.
, -
bitbucket.org/xakpc/whereareyou
,
, "" .
, Android F#. .
, - Android F#. , .listView.Adapter <- new ArrayAdapter(this, Android.Resource.Layout.SimpleListItem1, Android.Resource.Id.Text1, values)
, , let values = [|"item1"; "item2"; "item3"|] - string[], list (IEnumerable )
F#. www.tryfsharp.org/Learn

F# - ,
F# For Fun And Profit
,
- .

hash
MD5 F#
let MD5Hash (input : string) = use md5 = System.Security.Cryptography.MD5.Create() input |> System.Text.Encoding.ASCII.GetBytes |> md5.ComputeHash |> Seq.map (fun c -> c.ToString("X2")) |> Seq.reduce (+)
|> pipeline , .
: GetBytes -> -> HEX -> ( reduce + ) -> .
, C# using System; public string CreateMD5Hash (string input) { MD5 md5 = System.Security.Cryptography.MD5.Create(); byte[] inputBytes = System.Text.Encoding.ASCII.GetBytes (input); byte[] hashBytes = md5.ComputeHash (inputBytes); StringBuilder sb = new StringBuilder(); for (int i = 0; i < hashBytes.Length; i++) { sb.Append (hashBytes[i].ToString ("X2")); } return sb.ToString(); }
: . AzureServiceWorker ( CLR )
- . F# ! Xamarin Studio .
<ItemGroup> <Compile Include="Resources\Resource.designer.fs" /> <Compile Include="Properties\AssemblyInfo.fs" /> <Compile Include="Helpers\Helpers.fs" /> <Compile Include="Services\User.fs" /> <Compile Include="Services\AzureServiceWorker.fs" /> <Compile Include="IAmHereActivity.fs" /> <Compile Include="WhereAreYouActivity.fs" /> <Compile Include="SignInActivity.fs" /> </ItemGroup>
: . Xamarin Xamarin.Mobile
. F# TPL, Task', . F# Task. , :
module Async = open System.Threading open System.Threading.Tasks let inline AwaitPlainTask (task: Task) = // rethrow exception from preceding task if it fauled let continuation (t : Task) : unit = match t.IsFaulted with | true -> raise t.Exception | arg -> () task.ContinueWith continuation |> Async.AwaitTask
Async.AwaitIAsyncResult >> Async.Ignore
let ExtractUserInfo (x : Contact) = let first = x.Phones |> Seq.tryPick(fun x -> if x.Type = PhoneType.Mobile then Some(x) else None) match first with | Some(first) -> let phone = first.Number |> StripChars [' ';'-';'(';')'] UserInfo.CreateUserInfo((MD5Hash phone), phone, x.DisplayName) | None -> UserInfo.CreateUserInfo("no mobile phone", "no mobile phone", "no mobile phone") // function for async list filling let FillContactsAsync = async { let book = new AddressBook (this) let! result = book.RequestPermission() |> Async.AwaitTask if result then _contacts <- book.ToList() |> Seq.filter (fun (x: Contact) -> not (Seq.isEmpty x.Phones)) |> Seq.map ExtractUserInfo |> Seq.sortBy(fun x -> x.DisplayName) |> Seq.toList let finalContacts = _contacts |> Seq.map (fun x -> x.DisplayName.ToUpperInvariant()) |> Seq.toArray this.ListAdapter <- new ArrayAdapter(this, Resource_Layout.row_contact, finalContacts) else System.Diagnostics.Debug.WriteLine("Permission denied by user or manifest") this.ListAdapter <- new ArrayAdapter(this, Resource_Layout.row_contact, Array.empty) }
book.ToList() List |> Seq.filter (fun (x: Contact) -> not (Seq.isEmpty x.Phones)) |> Seq.map ExtractUserInfo Contracts UserInfo, UserInfo |> Seq.sortBy(fun x -> x.DisplayName) |> Seq.toList List _contacts <- mutable _contacts |> Seq.map (fun x -> x.DisplayName.ToUpperInvariant())<- UserInfo string, - - |> Seq.toArray<- List Array ArrayAdapter
- List. .

Azure Mobile Servcies
- Azure Mobile Services. NotificationHub, Push . Azure , .. .
, 
module WruConstants = [<Literal>] let TotallyNotAzureServer = "https://YOUR.azure-mobile.net/"; [<Literal>] let TotallyNotAzureKey = "YOUR"
member this.RegisterMe phone name regId = async { try let table = this.MobileService.GetTable<User>() let usr = { Id = "" PhoneHash = MD5Hash phone Nickname = name RegistrationId = regId } do! table.InsertAsync usr |> Async.AwaitPlainTask return (usr.Id, usr.PhoneHash, usr.Nickname) with | e -> System.Diagnostics.Trace.WriteLine(e.ToString) return (String.Empty,String.Empty,String.Empty) }
member this.RegisterMe phone name regId = async { - ( ) . "computation expression" workflow. { } ! ( bang), do! (do-bang) let! (let bang) User. , F# ,
let usr = { Id = "" PhoneHash = MD5Hash phone Nickname = name RegistrationId = regId } do! table.InsertAsync usr |> Async.AwaitPlainTask do-bang, await C#. .. continuation . return (usr.Id, usr.PhoneHash, usr.Nickname) Tuple<string,string,string> . try ... with | e -> try..catch C#

. F# fst snd . 2 . :
let id (c,_,_) = c let phonehash (_,c,_) = c let nickname (_,_,c) = c
: id tuple Id ..
5 Azure, Push . Azure Custom Api
exports.post = function(request, response) { // Use "request.service" to access features of your mobile service, eg: // var tables = request.service.tables; // var push = request.service.push; //response.send(statusCodes.OK, { message : 'Hello World!' }); console.log('Incoming call with requst: ', request.body.RequestId); var usersTable = request.service.tables.getTable('User'); usersTable.where( { id : request.body.TargetId } ) .read( { success: function(results) { if (results.length > 0) { var user = results[0] console.log('Send to results: ', user.Nickname, user.RegistrationId); request.service.push.gcm.send(user.RegistrationId, { RequesterId: request.body.RequesterId, RequesterNickname: request.body.RequesterName, TargetId: user.id, TargetNickname: user.Nickname }, { success: function(gcm_response) { console.log('Push notification sent: ', gcm_response); response.send(statusCodes.OK, { RequestedNickname : user.Nickname }); }, error: function(gcm_error) { console.log('Error sending push notification: ', gcm_error); response.send(statusCodes.INTERNAL_SERVER_ERROR, { RequestedNickname : user.Nickname }); } }); } else { response.send(statusCodes.NO_CONTENT, { RequestedNickname : "" }); } }, error: function(error) { console.log('Error read table: ', error); response.send(statusCodes.INTERNAL_SERVER_ERROR, { RequestedNickname : "" }); } }); };
Push
// Perform Push operation member this.PushAsync targetId myId myNickname = async { try let (request : PushRequest) = { TargetId = targetId RequesterId = myId RequesterName = myNickname } let! result = this.MobileService.InvokeApiAsync<PushRequest, PushResponce>("pushhim", request) |> Async.AwaitTask return result.RequestedNickname with | e -> return e.ToString() }
, let-bang do!

Google Play Services. F# . . : Xamarin.Android.Support.v7.AppCompat
, Google Play Services , .
push notification . GCM, ID, ID Push (. pushhim). BroadcastReciever developer.android.com . F# Xamarin Component Store. Google Cloud Messaging Client GCM . ID
//Check to see that GCM is supported and that the manifest has the correct information GcmClient.CheckDevice(this) GcmClient.CheckManifest(this) // check google play if CheckPlayServices() then // Try to get registration id let regId = GcmClient.GetRegistrationId this if String.IsNullOrEmpty(regId) then // Call to Register the device for Push Notifications GcmClient.Register(this, WruConstants.GcmSender);

.
, -
bitbucket.org/xakpc/whereareyou
,
, "" .
, Android F#. .
, - Android F#. , .listView.Adapter <- new ArrayAdapter(this, Android.Resource.Layout.SimpleListItem1, Android.Resource.Id.Text1, values)
, , let values = [|"item1"; "item2"; "item3"|] - string[], list (IEnumerable )
F#. www.tryfsharp.org/Learn

F# - ,
F# For Fun And Profit
,
- .

hash
MD5 F#
let MD5Hash (input : string) = use md5 = System.Security.Cryptography.MD5.Create() input |> System.Text.Encoding.ASCII.GetBytes |> md5.ComputeHash |> Seq.map (fun c -> c.ToString("X2")) |> Seq.reduce (+)
|> pipeline , .
: GetBytes -> -> HEX -> ( reduce + ) -> .
, C# using System; public string CreateMD5Hash (string input) { MD5 md5 = System.Security.Cryptography.MD5.Create(); byte[] inputBytes = System.Text.Encoding.ASCII.GetBytes (input); byte[] hashBytes = md5.ComputeHash (inputBytes); StringBuilder sb = new StringBuilder(); for (int i = 0; i < hashBytes.Length; i++) { sb.Append (hashBytes[i].ToString ("X2")); } return sb.ToString(); }
: . AzureServiceWorker ( CLR )
- . F# ! Xamarin Studio .
<ItemGroup> <Compile Include="Resources\Resource.designer.fs" /> <Compile Include="Properties\AssemblyInfo.fs" /> <Compile Include="Helpers\Helpers.fs" /> <Compile Include="Services\User.fs" /> <Compile Include="Services\AzureServiceWorker.fs" /> <Compile Include="IAmHereActivity.fs" /> <Compile Include="WhereAreYouActivity.fs" /> <Compile Include="SignInActivity.fs" /> </ItemGroup>
: . Xamarin Xamarin.Mobile
. F# TPL, Task', . F# Task. , :
module Async = open System.Threading open System.Threading.Tasks let inline AwaitPlainTask (task: Task) = // rethrow exception from preceding task if it fauled let continuation (t : Task) : unit = match t.IsFaulted with | true -> raise t.Exception | arg -> () task.ContinueWith continuation |> Async.AwaitTask
Async.AwaitIAsyncResult >> Async.Ignore
let ExtractUserInfo (x : Contact) = let first = x.Phones |> Seq.tryPick(fun x -> if x.Type = PhoneType.Mobile then Some(x) else None) match first with | Some(first) -> let phone = first.Number |> StripChars [' ';'-';'(';')'] UserInfo.CreateUserInfo((MD5Hash phone), phone, x.DisplayName) | None -> UserInfo.CreateUserInfo("no mobile phone", "no mobile phone", "no mobile phone") // function for async list filling let FillContactsAsync = async { let book = new AddressBook (this) let! result = book.RequestPermission() |> Async.AwaitTask if result then _contacts <- book.ToList() |> Seq.filter (fun (x: Contact) -> not (Seq.isEmpty x.Phones)) |> Seq.map ExtractUserInfo |> Seq.sortBy(fun x -> x.DisplayName) |> Seq.toList let finalContacts = _contacts |> Seq.map (fun x -> x.DisplayName.ToUpperInvariant()) |> Seq.toArray this.ListAdapter <- new ArrayAdapter(this, Resource_Layout.row_contact, finalContacts) else System.Diagnostics.Debug.WriteLine("Permission denied by user or manifest") this.ListAdapter <- new ArrayAdapter(this, Resource_Layout.row_contact, Array.empty) }
book.ToList() List |> Seq.filter (fun (x: Contact) -> not (Seq.isEmpty x.Phones)) |> Seq.map ExtractUserInfo Contracts UserInfo, UserInfo |> Seq.sortBy(fun x -> x.DisplayName) |> Seq.toList List _contacts <- mutable _contacts |> Seq.map (fun x -> x.DisplayName.ToUpperInvariant())<- UserInfo string, - - |> Seq.toArray<- List Array ArrayAdapter
- List. .

Azure Mobile Servcies
- Azure Mobile Services. NotificationHub, Push . Azure , .. .
, 
module WruConstants = [<Literal>] let TotallyNotAzureServer = "https://YOUR.azure-mobile.net/"; [<Literal>] let TotallyNotAzureKey = "YOUR"
member this.RegisterMe phone name regId = async { try let table = this.MobileService.GetTable<User>() let usr = { Id = "" PhoneHash = MD5Hash phone Nickname = name RegistrationId = regId } do! table.InsertAsync usr |> Async.AwaitPlainTask return (usr.Id, usr.PhoneHash, usr.Nickname) with | e -> System.Diagnostics.Trace.WriteLine(e.ToString) return (String.Empty,String.Empty,String.Empty) }
member this.RegisterMe phone name regId = async { - ( ) . "computation expression" workflow. { } ! ( bang), do! (do-bang) let! (let bang) User. , F# ,
let usr = { Id = "" PhoneHash = MD5Hash phone Nickname = name RegistrationId = regId } do! table.InsertAsync usr |> Async.AwaitPlainTask do-bang, await C#. .. continuation . return (usr.Id, usr.PhoneHash, usr.Nickname) Tuple<string,string,string> . try ... with | e -> try..catch C#

. F# fst snd . 2 . :
let id (c,_,_) = c let phonehash (_,c,_) = c let nickname (_,_,c) = c
: id tuple Id ..
5 Azure, Push . Azure Custom Api
exports.post = function(request, response) { // Use "request.service" to access features of your mobile service, eg: // var tables = request.service.tables; // var push = request.service.push; //response.send(statusCodes.OK, { message : 'Hello World!' }); console.log('Incoming call with requst: ', request.body.RequestId); var usersTable = request.service.tables.getTable('User'); usersTable.where( { id : request.body.TargetId } ) .read( { success: function(results) { if (results.length > 0) { var user = results[0] console.log('Send to results: ', user.Nickname, user.RegistrationId); request.service.push.gcm.send(user.RegistrationId, { RequesterId: request.body.RequesterId, RequesterNickname: request.body.RequesterName, TargetId: user.id, TargetNickname: user.Nickname }, { success: function(gcm_response) { console.log('Push notification sent: ', gcm_response); response.send(statusCodes.OK, { RequestedNickname : user.Nickname }); }, error: function(gcm_error) { console.log('Error sending push notification: ', gcm_error); response.send(statusCodes.INTERNAL_SERVER_ERROR, { RequestedNickname : user.Nickname }); } }); } else { response.send(statusCodes.NO_CONTENT, { RequestedNickname : "" }); } }, error: function(error) { console.log('Error read table: ', error); response.send(statusCodes.INTERNAL_SERVER_ERROR, { RequestedNickname : "" }); } }); };
Push
// Perform Push operation member this.PushAsync targetId myId myNickname = async { try let (request : PushRequest) = { TargetId = targetId RequesterId = myId RequesterName = myNickname } let! result = this.MobileService.InvokeApiAsync<PushRequest, PushResponce>("pushhim", request) |> Async.AwaitTask return result.RequestedNickname with | e -> return e.ToString() }
, let-bang do!

Google Play Services. F# . . : Xamarin.Android.Support.v7.AppCompat
, Google Play Services , .
push notification . GCM, ID, ID Push (. pushhim). BroadcastReciever developer.android.com . F# Xamarin Component Store. Google Cloud Messaging Client GCM . ID
//Check to see that GCM is supported and that the manifest has the correct information GcmClient.CheckDevice(this) GcmClient.CheckManifest(this) // check google play if CheckPlayServices() then // Try to get registration id let regId = GcmClient.GetRegistrationId this if String.IsNullOrEmpty(regId) then // Call to Register the device for Push Notifications GcmClient.Register(this, WruConstants.GcmSender);

.
, -
bitbucket.org/xakpc/whereareyou
,
, "" .
, Android F#. .
, - Android F#. , .listView.Adapter <- new ArrayAdapter(this, Android.Resource.Layout.SimpleListItem1, Android.Resource.Id.Text1, values)
, , let values = [|"item1"; "item2"; "item3"|] - string[], list (IEnumerable )
F#. www.tryfsharp.org/Learn

F# - ,
F# For Fun And Profit
,
- .

hash
MD5 F#
let MD5Hash (input : string) = use md5 = System.Security.Cryptography.MD5.Create() input |> System.Text.Encoding.ASCII.GetBytes |> md5.ComputeHash |> Seq.map (fun c -> c.ToString("X2")) |> Seq.reduce (+)
|> pipeline , .
: GetBytes -> -> HEX -> ( reduce + ) -> .
, C# using System; public string CreateMD5Hash (string input) { MD5 md5 = System.Security.Cryptography.MD5.Create(); byte[] inputBytes = System.Text.Encoding.ASCII.GetBytes (input); byte[] hashBytes = md5.ComputeHash (inputBytes); StringBuilder sb = new StringBuilder(); for (int i = 0; i < hashBytes.Length; i++) { sb.Append (hashBytes[i].ToString ("X2")); } return sb.ToString(); }
: . AzureServiceWorker ( CLR )
- . F# ! Xamarin Studio .
<ItemGroup> <Compile Include="Resources\Resource.designer.fs" /> <Compile Include="Properties\AssemblyInfo.fs" /> <Compile Include="Helpers\Helpers.fs" /> <Compile Include="Services\User.fs" /> <Compile Include="Services\AzureServiceWorker.fs" /> <Compile Include="IAmHereActivity.fs" /> <Compile Include="WhereAreYouActivity.fs" /> <Compile Include="SignInActivity.fs" /> </ItemGroup>
: . Xamarin Xamarin.Mobile
. F# TPL, Task', . F# Task. , :
module Async = open System.Threading open System.Threading.Tasks let inline AwaitPlainTask (task: Task) = // rethrow exception from preceding task if it fauled let continuation (t : Task) : unit = match t.IsFaulted with | true -> raise t.Exception | arg -> () task.ContinueWith continuation |> Async.AwaitTask
Async.AwaitIAsyncResult >> Async.Ignore
let ExtractUserInfo (x : Contact) = let first = x.Phones |> Seq.tryPick(fun x -> if x.Type = PhoneType.Mobile then Some(x) else None) match first with | Some(first) -> let phone = first.Number |> StripChars [' ';'-';'(';')'] UserInfo.CreateUserInfo((MD5Hash phone), phone, x.DisplayName) | None -> UserInfo.CreateUserInfo("no mobile phone", "no mobile phone", "no mobile phone") // function for async list filling let FillContactsAsync = async { let book = new AddressBook (this) let! result = book.RequestPermission() |> Async.AwaitTask if result then _contacts <- book.ToList() |> Seq.filter (fun (x: Contact) -> not (Seq.isEmpty x.Phones)) |> Seq.map ExtractUserInfo |> Seq.sortBy(fun x -> x.DisplayName) |> Seq.toList let finalContacts = _contacts |> Seq.map (fun x -> x.DisplayName.ToUpperInvariant()) |> Seq.toArray this.ListAdapter <- new ArrayAdapter(this, Resource_Layout.row_contact, finalContacts) else System.Diagnostics.Debug.WriteLine("Permission denied by user or manifest") this.ListAdapter <- new ArrayAdapter(this, Resource_Layout.row_contact, Array.empty) }
book.ToList() List |> Seq.filter (fun (x: Contact) -> not (Seq.isEmpty x.Phones)) |> Seq.map ExtractUserInfo Contracts UserInfo, UserInfo |> Seq.sortBy(fun x -> x.DisplayName) |> Seq.toList List _contacts <- mutable _contacts |> Seq.map (fun x -> x.DisplayName.ToUpperInvariant())<- UserInfo string, - - |> Seq.toArray<- List Array ArrayAdapter
- List. .

Azure Mobile Servcies
- Azure Mobile Services. NotificationHub, Push . Azure , .. .
, 
module WruConstants = [<Literal>] let TotallyNotAzureServer = "https://YOUR.azure-mobile.net/"; [<Literal>] let TotallyNotAzureKey = "YOUR"
member this.RegisterMe phone name regId = async { try let table = this.MobileService.GetTable<User>() let usr = { Id = "" PhoneHash = MD5Hash phone Nickname = name RegistrationId = regId } do! table.InsertAsync usr |> Async.AwaitPlainTask return (usr.Id, usr.PhoneHash, usr.Nickname) with | e -> System.Diagnostics.Trace.WriteLine(e.ToString) return (String.Empty,String.Empty,String.Empty) }
member this.RegisterMe phone name regId = async { - ( ) . "computation expression" workflow. { } ! ( bang), do! (do-bang) let! (let bang) User. , F# ,
let usr = { Id = "" PhoneHash = MD5Hash phone Nickname = name RegistrationId = regId } do! table.InsertAsync usr |> Async.AwaitPlainTask do-bang, await C#. .. continuation . return (usr.Id, usr.PhoneHash, usr.Nickname) Tuple<string,string,string> . try ... with | e -> try..catch C#

. F# fst snd . 2 . :
let id (c,_,_) = c let phonehash (_,c,_) = c let nickname (_,_,c) = c
: id tuple Id ..
5 Azure, Push . Azure Custom Api
exports.post = function(request, response) { // Use "request.service" to access features of your mobile service, eg: // var tables = request.service.tables; // var push = request.service.push; //response.send(statusCodes.OK, { message : 'Hello World!' }); console.log('Incoming call with requst: ', request.body.RequestId); var usersTable = request.service.tables.getTable('User'); usersTable.where( { id : request.body.TargetId } ) .read( { success: function(results) { if (results.length > 0) { var user = results[0] console.log('Send to results: ', user.Nickname, user.RegistrationId); request.service.push.gcm.send(user.RegistrationId, { RequesterId: request.body.RequesterId, RequesterNickname: request.body.RequesterName, TargetId: user.id, TargetNickname: user.Nickname }, { success: function(gcm_response) { console.log('Push notification sent: ', gcm_response); response.send(statusCodes.OK, { RequestedNickname : user.Nickname }); }, error: function(gcm_error) { console.log('Error sending push notification: ', gcm_error); response.send(statusCodes.INTERNAL_SERVER_ERROR, { RequestedNickname : user.Nickname }); } }); } else { response.send(statusCodes.NO_CONTENT, { RequestedNickname : "" }); } }, error: function(error) { console.log('Error read table: ', error); response.send(statusCodes.INTERNAL_SERVER_ERROR, { RequestedNickname : "" }); } }); };
Push
// Perform Push operation member this.PushAsync targetId myId myNickname = async { try let (request : PushRequest) = { TargetId = targetId RequesterId = myId RequesterName = myNickname } let! result = this.MobileService.InvokeApiAsync<PushRequest, PushResponce>("pushhim", request) |> Async.AwaitTask return result.RequestedNickname with | e -> return e.ToString() }
, let-bang do!

Google Play Services. F# . . : Xamarin.Android.Support.v7.AppCompat
, Google Play Services , .
push notification . GCM, ID, ID Push (. pushhim). BroadcastReciever developer.android.com . F# Xamarin Component Store. Google Cloud Messaging Client GCM . ID
//Check to see that GCM is supported and that the manifest has the correct information GcmClient.CheckDevice(this) GcmClient.CheckManifest(this) // check google play if CheckPlayServices() then // Try to get registration id let regId = GcmClient.GetRegistrationId this if String.IsNullOrEmpty(regId) then // Call to Register the device for Push Notifications GcmClient.Register(this, WruConstants.GcmSender);

.
, -
bitbucket.org/xakpc/whereareyou
,
, "" .
, Android F#. .
, - Android F#. , .Source: https://habr.com/ru/post/228783/
All Articles