martes, 29 de septiembre de 2015

SAP HANA on the OCaml hump

This post was originally posted on SAP HANA on the OCaml hump.


OCaml is an industrial strength programming language supporting functional, imperative and object-oriented styles.



Sounds nice, right? OCaml is the next step of the Caml programming language.

Having learning other functional programming languages like Haskell and Erlang, OCaml was the next obvious choice for me…so I decided to start learning it…not an easy task for sure…but really fun and enlighten.

So…no example or demonstration would be complete if we didn’t hook it up with SAP HANA, right? So…let’s go and do it -;)

First, we need to create a Calculation View and call it “FLIGHTS_BY_CARRIER”. It will be composed of two tables, SCARR and SFLIGHT.

First, we need to create a Join object and link the table by MANDT and CARRID. From here select the following fields as output MANDT, CARRID, CARRNAME, PRICE and CURRENCY.

Then create an Aggregation object selecting the fields CARRNAME, PRICE (As Aggregated Column) and CURRENCY. Filter the CURRENCY field by ‘USD’.

Then create a Projection object and select only PRICE and CARRNAME.

On the Semantics object make sure to select “CROSS CLIENT” as the Default Client.


Now, switch to the SAP HANA Development View and create a new repository. Call it “Flights”.

Create a new “XS Engine” project and call it “Flights” as well. Link it to the “Flights” repository.

Create an empty “.xsapp” file.

Create a file called “.xsaccess” with the following code.

.xsaccess
{
          "exposed" : true,
          "authentication" : [ { "method" : "Basic" } ]
}

Finally create a file called “flights.xsodata” with the following code

flights.xodata
service {
          "Blag/FLIGHTS_BY_CARRIER.calculationview" as "FLIGHTS" keys 
                                                        generate local "Id";
}

Activate your project and launch it on your browser, you should see something like this…


The SAP HANA part is done…so we can move into the OCaml part…

For first timers, OPAM (the package manager for OCaml can be tricky and sometimes frustrating), so let’s make your lives easier by following this single easy steps…on a terminal session type this…

opam init
eval `opam config env`
opam switch 4.01.0
eval `opam config env`
opam install core utop core_extended async uri yojson cohttp lwt ezjsonm

It will take a while but by installing all the required packages in a single command, prevents errors from happening.

To code for OCaml I use one of the most awesome editors I have ever found…Geany. It comes almost pre-configured to handle a lot of programming languages, but just to make sure, here’s how I configure it to work with OCaml.

First, create a file and save it as OCaml_HANA.ml

Then, click on the “Choose more build actions” button


The little half arrow on the right of the brown brick looking button. This will open the following screen


On Compile put the following

corebuild -pkg yojson,cohttp.async,cohttp.lwt,lwt,ezjsonm "%e.native"

And on Execute put

“./%e.native”

With that, we should be more than ready to start coding -:) Copy and paste the following code…

OCaml_HANA.ml
open Core.Std
open Yojson.Basic.Util
open Ezjsonm

let get_definition_from_json json =
 let json = Ezjsonm.from_string(json) in
 let json = Ezjsonm.(find json ["d";"results"]) in
 let json = Ezjsonm.to_string(json) in
 let json = Yojson.Basic.from_string(json) in
 let json = Yojson.Basic.Util.to_list json in
 let carrname = Yojson.Basic.Util.filter_member "CARRNAME" json in
 let carrname = Yojson.Basic.Util.filter_string carrname in
 let price = Yojson.Basic.Util.filter_member "PRICE" json in
 let price = Yojson.Basic.Util.filter_string price in
 printf "Reading SAP HANA from OCaml\n\n";
 for i = 0 to List.length(carrname) - 1 do
  printf "%s: %s\n" (List.nth_exn carrname i) (List.nth_exn price i)
done

let fetch uri =
 let cred = Cohttp.Auth.string_of_credential(`Basic("SYSTEM", "YourPassword")) in
 let headers = Cohttp.Header.init() in 
 let headers = Cohttp.Header.add headers "Authorization" cred in
 let open Lwt in
 Cohttp_lwt_unix.Client.get ~headers:headers uri 
 >>= fun (_,body) ->
 Cohttp_lwt_body.to_string_list body
 >>= fun strings ->
 return(get_definition_from_json (String.concat strings))  

let () =
  let hana_uri = Uri.of_string "http://YourServer:8000/Flights/flights.xsodata
                                /FLIGHTS?$format=json"
  in Lwt_main.run (fetch hana_uri)

Save your file, press the “Compile the current file” button. The first on the previous images which shows a triangle with an arrow and a ball (all in nice 3D) and then press the “Run or view the current file” button. Last one on the previous image which shows two engines.


You will notice that it comes pretty fast…

Now…something funny about my code…and that might be because of two simple reasons…

• I’m still learning OCaml
• The documentation for external packages is almost non-existent (Actually, I need to browse the GitHub source codes in order to achieve most of the code)

So…the funny thing is that I’m using two different JSON libraries to actually read the ODATA generated by SAP HANA…by using only one I couldn’t manage to get the information that I needed…so using both and extracting pieces from here and there I actually got what I wanted…not so fun when you are doing it…but in the end there a big reward on finally being able to compile it and get the desired output -;)

Greetings,

Blag.
Development Culture.

lunes, 28 de septiembre de 2015

Amazon Alexa and Philips Hue

This post was originally posted on Amazon Alexa and Philips Hue.



If you are an SAP Employee, please follow us on Jam.


Since we got the Amazon Alexa on the d-shop here at SAP Labs Silicon Valley...I have been looking for new ways to make it interact with many things...so a couple of days my good friend and colleague Aaron Williams asked me about the Philips Hue...

At first...I wasn't sure it was going to work, because as everybody knows...the Hue needs to be on the same network to be able to work...and Amazon Lambda is sitting on a server who knows where...so I start looking into it...

When using the Amazon Alexa app we can hook up the Hue to allow Alexa to turn on and off the light...but nothing more...

You need to go to Settings --> Connected Home -> Discover Devices (It will ask you to push the button on the Hue Bridge).

For sure...this wasn't enough for me...so I kept thinking about it and realized that "Hey!...the Philips Hue works when you want to change the lights...and it does it remotely...so there must be a way to do it"...

Gladly...I found this blog...Philips Hue Remote API Explained...where the author basically explains how you can "trick" Hue into thinking that you are connecting from your IPhone...hence...you're doing a remote connection...genius if you ask me -;)

For this to work you need to create a meethue account...just singing using your Google account didn't worked for me...


By the way...if you find something like this at the end "%3D" simply change it for an "="

Having both the BridgeId and AccessToken we should be ready to go  -;)

We need to create both a Function and a Skill...please refer to this blog Amazon Alexa and SAP HANA to create them...

The function will be called getLights and the skill Lights. The Invocation Name will be "lights".

Here's the Interaction Model that we're going to use...

Intent Schema
{
  "intents": [
    {
      "intent": "GetLightsIntent",
      "slots": [
        {
          "name": "color",
          "type": "LITERAL"
        }
      ]
    },
    {
      "intent": "HelpIntent",
      "slots": []
    }
  ]
}

Sample Utterances
GetLightsIntent color {red|color}
GetLightsIntent color {blue|color}
GetLightsIntent color {green|color}
GetLightsIntent color {pink|color}
GetLightsIntent color {purple|color}
GetLightsIntent color {aqua|color}
GetLightsIntent color {white|color}
GetLightsIntent color {yellow|color}
GetLightsIntent color {black|color}

HelpIntent help
HelpIntent help me
HelpIntent what can I ask you
HelpIntent get help
HelpIntent to help
HelpIntent to help me
HelpIntent what commands can I ask
HelpIntent what commands can I say
HelpIntent what can I do
HelpIntent what can I use this for
HelpIntent what questions can I ask
HelpIntent what can you do
HelpIntent what do you do
HelpIntent how do I use you
HelpIntent how can I use you
HelpIntent what can you tell me
HelpIntent how do i change colors

Now...the most important thing is the code -:P

Let’s create a folder and call it “Lights” or something nice like that…then create a folder called “src”. Copy the code from here...and create a file called “AlexaSkills.js”

We’re going to need to install the request package on our function, so do the following on a terminal

sudo npm install --prefix=~/Alexa/Lights/src request

This will create a folder called “node_modules” with the package in our project folder…then create a file called “index.js” and copy and paste the following code…

index.js
var request = require("request")
  , AlexaSkill = require('./AlexaSkill')
  , APP_ID     = 'YourAPPId'
  , TOKEN = 'YourAccessToken';

var error = function (err, response, body) {
    console.log('ERROR [%s]', err);
};

var getJsonFromLights = function(color,callback){
switch(color){
 case 'red':
  x = 0.674; y = 0.322; break;
 case 'green':
  x = 0.408; y = 0.517; break;
 case 'blue':
  x = 0.168; y = 0.041; break;
 case 'white':
  x = 0.3227; y = 0.329; break;
 case 'yellow':
  x = 0.4317; y = 0.4996; break;
 case 'purple':
  x = 0.2725; y = 0.1096; break;
 case 'orange':
  x = 0.5562; y = 0.4084; break;
 case 'pink':
  x = 0.3944; y = 0.3093; break;
 case 'black':
  x = 0.168; y = 0.041; break;    
 case 'aqua':
  x = 0.2858; y = 0.2747; break;
 default:
  x = 0.3227; y = 0.329; break;
}

var options = { method: 'POST',
                url: 'https://www.meethue.com/api/sendmessage',
                qs: { token: TOKEN},
                headers: { 'content-type': 'application/x-www-form-urlencoded' },
                body: 'clipmessage={ bridgeId: "YourBridgeId", 
                                     clipCommand:  {url:"/api/0/lights/1/state", 
                                     method: "PUT", body: {xy:[' + x + ',' + y + ']}}}' };

var error_log = "";

request(options, function (error, response, body) {
 if (!error) {
  error_log = color;
 }else{
  error_log = "There was a mistake";
 }
 callback(error_log);
    });
}

var handleLightsRequest = function(intent, session, response){
  getJsonFromLights(intent.slots.color.value, function(data){
 var text = 'The color has been changed to ' + data;
    var cardText = 'The color has been changed to ' + intent.slots.color.value;

    var heading = 'The color has been changed to ' + intent.slots.color.value;
    response.tellWithCard(text, heading, cardText);
  });
};

var Lights = function(){
  AlexaSkill.call(this, APP_ID);
};

Lights.prototype = Object.create(AlexaSkill.prototype);
Lights.prototype.constructor = Lights;

Lights.prototype.eventHandlers.onSessionStarted = function(sessionStartedRequest, session){
  console.log("onSessionStarted requestId: " + sessionStartedRequest.requestId
      + ", sessionId: " + session.sessionId);
};

Lights.prototype.eventHandlers.onLaunch = function(launchRequest, session, response){
  // This is when they launch the skill but don't specify what they want.

  var output = 'Welcome to Hue Lights. Please say a color';

  var reprompt = 'Which color would you like?';

  response.ask(output, reprompt);

  console.log("onLaunch requestId: " + launchRequest.requestId
      + ", sessionId: " + session.sessionId);
};

Lights.prototype.intentHandlers = {
  GetLightsIntent: function(intent, session, response){
    handleLightsRequest(intent, session, response);
  },

  HelpIntent: function(intent, session, response){
    var speechOutput = 'Change your Hue Light to any color. Which color would you like?';
    response.ask(speechOutput);
  }
};

exports.handler = function(event, context) {
    var skill = new Lights();
    skill.execute(event, context);
};

When it's done...simply compress the node_module folder, AlexaSkills.js and index.js files into a .zip file called Lights.zip and upload it to your Amazon Lambda...

To call this skill on Alexa...you can do the following...

  • Alexa, turn on lamp 1 (Taking into account that your light my be called different)
  • Alexa, ask lights for color blue
  • Alexa, turn off lamp 1

You can see the available colors in the code...but just in case they should be...

  • Red
  • Green
  • Blue
  • Aqua
  • Pink
  • White
  • Black
  • Yellow
  • Purple
  • Orange

 And of course...here's the video  -:D


Greetings,

Blag.
Development Culture.

jueves, 24 de septiembre de 2015

R - My journey so far

The first time I heard about R, was about 4 years ago...a couple of week after I joined SAP. At that time I read in one of our internal documents that SAP HANA was going to be able to interact with the R programming Language.

At first, I was totally clueless about R...I had never heard from it before...so I of course start looking for some more information, download R and RStudio and start learning how to use it...

After some time...I posted my first blog talking about R...that was on November 28, 2011...the blog was Dealing with R and HANA...

After that I kept learning and using it whenever it was suitable...and I end up writing my most successful blog on the SAP Community Network...that was on May 21, 2012.


That up to now, has 21,879 views and 62 comments, 16 likes and 32 bookmarks.

R is huge...it really is...there's thousands of packages that solve thousands of issues...so that's when I start reading R related books from my good friends at Packt Publishing...




As I was improving my R skills...I knew that something was missing...I really didn't knew much about Statistics and my Machine Learning skills were pretty dull as well...that's when I read another awesome book...and I think my favorite book on R so far...

Machine Learning with R (See my review here).



Another topic that it's interesting is Social Media...and how to get value out of it...




If you're wondering how Social Media can be used with R, then please take a look at my blog Getting Flexible with SAP HANA where I use SAP HANA, R, Twitter and Schema Flexibility to analyze hashtags that can be further explored using for example SAP Lumira.

If you are into the Bioinformatics world...which I'm not -:( You should appreciate this book...



And there are some more books that I haven't read yet, but might help you to get started into the R world like...


So...why are all this books important? Well...obviously, they are all about R and R is amazing and becoming more important each and every day...

Look at this video to realize why Data Science is a hot topic to learn...

Or you just can download it as a nice PDF for offline reading http://bit.ly/1MryNha

Also...by just reading this blog post...you have the opportunity to buy any of these books with a 50% discount by using this code at checkout time...

SIXRB50


A big opportunity NOT to be missed out...


The validity of codes till 31st October. Limited copies are available.

Greetings,

Blag.
Development Culture.

Join us for Geeky Thursday on October

What's Geeky Thursday?

It's an event that happens every Thursday per week. An hour and little bit more of "hands-on" session where not so common programming languages (ex: Lua, Julia, R, Haskell) and Programming Paradimgs (Functional, Stack Based, Logical, Object-Oriented) are being presented.

Why Geeky Thursday?

Because Developers...because knowing just a couple of programming languages is not enough...because learning another paradigm can expand your horizons and make a better developer.

Geeky Thursday is hands-on...do I need my laptop?

Well...it really depends on you...the source code is going to be available...it's going to be explained and run on-site...there's not going to be live typing...but it's always better if you can compile and run the examples yourself...

Is Geeky Thursday only about Programming?

No...without any aims to become a "Brown Bag Session"...Geeky Thursday looks forward to become a "Mini Meetup" space...where cool things can be explored.

Is Geeky Thursday held only on Silicon Valley?

For now...it is...but...if you manage or you are in touch with a d-shop manager, ask him/her to get in touch with me (a.tejada.galindo@sap.com)...I would be more than happy to share my slides and anything needed to expand Geeky Thursday to other locations.

Is any space limitation?

Yes, we can invite 10 people from SAP and we have space for 5 people that external to SAP. Depending on the attendance level we might increase this values.

Can I host a Geeky Thursday event?

Of course! You're more than welcome! Just get in touch with me and will be setup an slot for you!

Scheduled Geeky Thursdays

R Programming Language --> October 8 from 1:00 to 2:00pm (d-shop on Building 9 at SAP Labs Silicon Valley)

For SAP Employees

https://jam4.sapjam.com/groups/sh2Kp26QQkHwkMPFAEqAD9/events/K7BJsIiucH7XjLszzcO0Eh

For Externals

https://www.eventbrite.com/myevent?eid=18783268261

R is a programming language and software environment for statistical computing and graphics. Please join us to learn the basics of R.

You can download R from here https://cran.r-project.org/

You can download RStudio from here https://www.rstudio.com/

Julia Programming Language --> October 15 from 1:00 to 2:00pm (d-shop on Building 9 at SAP Labs Silicon Valley)

For SAP Employees

https://jam4.sapjam.com/groups/sh2Kp26QQkHwkMPFAEqAD9/events/5FieiznXF6EgaGfg34qKdd

For Externals

https://www.eventbrite.com/myevent?eid=18783317408

Julia is a high-level dynamic programming language designed to address the requirements of high-performance numerical and scientific computing while also being effective for general-purpose programming, even web use or as a specification language.

You can download Julia from here http://julialang.org/

Clojure Programming Language --> October 29 from 1:00 to 2:00pm (d-shop on Building 9 at SAP Labs Silicon Valley)

For SAP Employees

https://jam4.sapjam.com/groups/sh2Kp26QQkHwkMPFAEqAD9/events/RoZ8dId4NGqxzWCys2hMN4

For Externals

https://www.eventbrite.com/myevent?eid=18783402663

Clojure is a dynamic programming language that targets the Java Virtual Machine (and the CLR, and JavaScript). It is designed to be a general-purpose language, combining the approachability and interactive development of a scripting language with an efficient and robust infrastructure for multithreaded programming. Clojure is a dialect of Lisp, and shares with Lisp the code-as-data philosophy and a powerful macro system.

You can download Clojure from here http://clojure.org/

Greetings,

Blag.
Development Culture.

miércoles, 23 de septiembre de 2015

(Defining SAP HANA (OData) with Racket)

This post was originally posted on (Defining SAP HANA (OData) with Racket).

Racket is a full spectrum programming language that goes beyond Lisp and Scheme with dialects that support objects, types, laziness and more. And that more means Functional, Procedural, Object Oriented, Logic, Reflective and Meta.

Basically…Racket is the new name of PLT Scheme. And PLT Scheme comes from the Lisp family.

So, before we move on…I want to share an XKCD comic that brings some light about Lisp -:)


First, we need to create a Calculation View and call it “FLIGHTS_BY_CARRIER”. It will be composed of two tables, SCARR and SFLIGHT.

First, we need to create a Join object and link the table by MANDT and CARRID. From here select the following fields as output MANDT, CARRID, CARRNAME, PRICE and CURRENCY.

Then create an Aggregation object selecting the fields CARRNAME, PRICE (As Aggregated Column) and CURRENCY. Filter the CURRENCY field by ‘USD’.

Then create a Projection object and select only PRICE and CARRNAME.

On the Semantics object make sure to select “CROSS CLIENT” as the Default Client.


Now, switch to the SAP HANA Development View and create a new repository. Call it “Flights”.

Create a new “XS Engine” project and call it “Flights” as well. Link it to the “Flights” repository.

Create an empty “.xsapp” file.

Create a file called “.xsaccess” with the following code.

.xsaccess
{
          "exposed" : true,
          "authentication" : [ { "method" : "Basic" } ]
}

Finally create a file called “flights.xsodata” with the following code
flights.xodata
service {
          "Blag/FLIGHTS_BY_CARRIER.calculationview" as "FLIGHTS" keys 
                                                        generate local "Id";
}

Activate your project and launch it on your browser, you should see something like this…


The SAP HANA part is done…so we can move into the Racket part…

Racket is a very complete programming language…so no external packages are needed…

To code for Racket I use the best Racket editor “Dr. Racket” that is actually embedded in the Racket installer…so again…no need to worry -:)

Copy and paste the following code…

Racket_HANA.rkt
#lang racket
(require json)
(require net/base64)
(require net/url)

(define make-auth-header
     (list (string-append
       "Authorization: Basic "
       (bytes->string/utf-8
        (base64-encode
         (string->bytes/utf-8
          (string-append "SYSTEM" ":" "YourPassword")))))))

(define (get_path path params)
  (port->string(get-pure-port path params)))

(define json (string->jsexpr (get_path (string->url "YouServer:8000/Flights/flights.xsodata/FLIGHTS?$format=json") 
                              make-auth-header)))
(define results (hash-ref (hash-ref json 'd) 'results))

(define (show_info results len ctr)
  (cond [(or (= ctr len) (< ctr len))
         (string-append (hash-ref (list-ref results ctr) 'CARRNAME) ": "
                        (hash-ref (list-ref results 0) 'PRICE) "\n"
                        (show_info results len (add1 ctr)))]
        [(> ctr len)
         (string-append "" "\n")]))

(display (show_info results (sub1 (length results)) 0))

Now you see it…Racket is all about parenthesis -:) Anyway…press the run button and you will have this…


I have been interfacing SAP HANA OData with a lot of languages…and so far…Racket has been one of my fastest implementations…while it’s hard to get used to all these weird parenthesis…it’s a very nice and powerful language…and thing get done faster that one could imagine…

Greetings,

Blag.
Development Culture.

viernes, 18 de septiembre de 2015

LED is my new Hello World - Falcon Time

Following my tradition...here's my LED Numbers app using Falcon...I used my Julia code as a base start...and I gotta say...the code is pretty much the same...which is nice for now...but I hope to find some hidden and weird features as I learn more about Falcon -;)

Here's the source code...

LED_Numbers.fal
leds =  ["0" => [" _  ","| | ","|_| "],
         "1" => ["  ","| ","| "],
         "2" => [" _  "," _| ","|_  "],
         "3" => ["_  ","_| ","_| "],
         "4" => ["    ","|_| ","  | "],
         "5" => [" _  ","|_  "," _| "],
         "6" => [" _  ","|_  ","|_| "],
         "7" => ["_   "," |  "," |  "],
         "8" => [" _  ","|_| ","|_| "],
         "9" => [" _  ","|_| "," _| "]]
   
print("Enter a number: ")
number = input()
len = number.len()
for i in [0:3]
 for j in [0:len]
  print(leds[number[j]][i])
 end
 printl("")
end

And of course...here are the pictures...



Greetings,

Blag.
Development Culture.

My first post on Falcon

I discovered Falcon a couple of months ago...but didn't have the time to start playing with it...


Falcon is an open source, multi-paradigm programming language. While it looks like a new programming language, it's actually kind of old having it's first appearance on 2003...

Syntactically, it's pretty similar to Lua...which means is kind of similar to Go or C++...but of course it has some pretty and unique cool features -;)

For now...I just ported my Lua version of the Fibonacci Numbers...and beside the fact that Falcon doesn't use "then" and the fact that Falcon can't concatenate numbers with string (but can concatenate string with numbers)...the code is pretty much the same...

Let's see how it goes when I code my LED Numbers app -;)

Here's the code...

fibonacci.fal
function fib(num,a,b)
 result = ""
 if a > 0 and num > 1
  result = result + (a+b) + " " + fib(num-1,a+b,a)
 elif a == 0
  result = "" + a + " " + b + " " + (a+b) + " " + fib(num-1,a+b,b)
 end
 return result 
end

print("Enter a number: ")
num = int( input() )
print(fib(num,0,1))

Here's the result...



Greetings,

Blag.
Development Culture.

jueves, 17 de septiembre de 2015

Purely SAP HANA with Haskell

This post was originally posted on Purely SAP HANA with Haskell.


Haskell is a general-purpose purely functional programming language with non-strict semantics and strong static typing.


What does that means? Nothing…just that Haskell is the most pure programming language around…which means that there are not and cannot be side effects…like Haskellers like to say…”If it compiles…it will always work”…

There’s an XKCD cartoon that nicely resumes what Haskell is about -;)


Well…I will run it -:P What I love about Haskell is that it really makes you forget everything you learned before…once assigned, a variable can’t never change its value…recursion is a must…printing on the terminal is considered impure, but there’s of course a work around it…everything is a function…forget about Classes and Objects…pattern matching is your best friend…and so many more cool things -;)

So…no example or demonstration would be complete if we didn’t hook it up with SAP HANA, right? So…let’s go and do it -;)

First, we need to create a Calculation View and call it “FLIGHTS_BY_CARRIER”. It will be composed of two tables, SCARR and SFLIGHT.

First, we need to create a Join object and link the table by MANDT and CARRID. From here select the following fields as output MANDT, CARRID, CARRNAME, PRICE and CURRENCY.

Then create an Aggregation object selecting the fields CARRNAME, PRICE (As Aggregated Column) and CURRENCY. Filter the CURRENCY field by ‘USD’.

Then create a Projection object and select only PRICE and CARRNAME.

On the Semantics object make sure to select “CROSS CLIENT” as the Default Client.


Now, switch to the SAP HANA Development View and create a new repository. Call it “Flights”.

Create a new “XS Engine” project and call it “Flights” as well. Link it to the “Flights” repository.

Create an empty “.xsapp” file.

Create a file called “.xsaccess” with the following code.

.xsaccess
{
          "exposed" : true,
          "authentication" : [ { "method" : "Basic" } ]
}

Finally create a file called “flights.xsodata” with the following code

flights.xsodata
service {
          "Blag/FLIGHTS_BY_CARRIER.calculationview" as "FLIGHTS" keys 
                                                        generate local "Id";
}

Activate your project and launch it on your browser, you should see something like this…


The SAP HANA part is done…so we can move into the Haskell part…

On a terminal session type this…

cabal update
cabal install --j --disable-tests wreq
In later versions of wreq, lens and aeson are already included…but just in case…
cabal install lens
cabal install aeson

To code for Haskell I use one of the most awesome editors I have ever found…Geany. It comes almost pre-configured to handle a lot of programming languages, so you will be ready to code for Haskell.

Basically you only need to press the “Run or view the current file”, last image that shows some engines…which basically will bring up GHCi which is the Glasgow Haskell Compiler Interactive.


With that, we should be more than ready to start coding -:) Copy and paste the following code…

Haskell_HANA.hs
{-# LANGUAGE OverloadedStrings #-}
import Network.Wreq
import Control.Lens
import Data.Aeson
import Data.Aeson.Lens
import Data.Aeson.Types
import Data.Text
import Data.Vector
import Prelude as P
import qualified Data.ByteString.Lazy as B

get_info :: B.ByteString -> Text -> Text -> Text -> Text -> Int -> Int -> String
get_info json d results carrname price len ctr
 | ctr < len = unpack(json ^. key d . key results . nth ctr . key carrname . _String) P.++ 
               ": " P.++ unpack(json ^. key d . key results . nth ctr . key price . _String) P.++ "\n" 
               P.++ get_info json d results carrname price len (ctr+1)
 | ctr >= len = []

main :: IO ()
main = do
 let d = pack "d"
 let results = pack "results"
 let carrname = pack "CARRNAME"
 let price = pack "PRICE"
 let opts = defaults & auth ?~ basicAuth "SYSTEM" "YourPassword"
 r <- getWith opts "http://YourHANAServer:8000/Flights/flights.xsodata/FLIGHTS?$format=json"
 let json = r ^. responseBody
 let results_array = json ^. key d . key results . _Array
 let len = Data.Vector.length results_array
 putStr $ get_info json d results carrname price len 0

Save your file and press the “Run or view the current file” button.


You will need to use the format “:l name_of_your_file” to load it into memory and then you can just call the main function to execute it -;)

I have to say…Haskell is not an easy language…and pulling out this blog wasn’t an easy task either…I need to do a lot of research…but gladly the Wreq and Aeson packages are simply awesome!

Greetings,

Blag.
Development Expert.

viernes, 11 de septiembre de 2015

SAP HANA through the looking Glass

This post was originally posted on SAP HANA through the looking Glass.



If you are an SAP Employee, please follow us on Jam.


Even when Google Glass is no more...at least not for individuals…I thought that connecting it to SAP HANA would make for a nice blog...because after all we have one at the d-shop…so here we go -;)


First, we need to create a Calculation View and call it “FLIGHTS_BY_CARRIER”. It will be composed of two tables, SCARR and SFLIGHT.

First, we need to create a Join object and link the table by MANDT and CARRID. From here select the following fields as output MANDT, CARRID, CARRNAME, PRICE and CURRENCY.

Then create an Aggregation object selecting the fields CARRNAME, PRICE (As Aggregated Column) and CURRENCY. Filter the CURRENCY field by ‘USD’.

Then create a Projection object and select only PRICE and CARRNAME.

On the Semantics object make sure to select “CROSS CLIENT” as the Default Client.


Now, switch to the SAP HANA Development View and create a new repository. Call it “Flights”.

Create a new “XS Engine” project and call it “Flights” as well. Link it to the “Flights” repository.

Create an empty “.xsapp” file.

Create a file called “.xsaccess” with the following code.

.xsaccess
{
          "exposed" : true,
          "authentication" : [ { "method" : "Basic" } ]
}

Finally create a file called “flights.xsodata” with the following code

Flights.xodata
service {
          "Blag/FLIGHTS_BY_CARRIER.calculationview" as "FLIGHTS" keys 
                                                        generate local "Id";
}

Activate your project and launch it on your browser, you should see something like this…


The SAP HANA part is done…so we can move into the Google Glass part…

First, download Android Studio and update your SDK Manager to include the following…API 19 including Google Glass Kit Preview.


Create a new project and call it “GLASS_HANA” or whatever you fancy…


On the next screen, uncheck “Phone and Tablet” and check “Glass”. Make sure that “Glass Development Kit Preview (API 19) is selected.


Choose “Immersion Activity”.


Leave the “MainActiviy” name and change the Activity Title if you want.


On the “MainActivity” file copy the following code

MainActivity.java
package glass.app.com.flightsreport;

import com.google.android.glass.media.Sounds;
import com.google.android.glass.widget.CardBuilder;
import com.google.android.glass.widget.CardScrollAdapter;
import com.google.android.glass.widget.CardScrollView;

import android.app.Activity;
import android.content.Context;
import android.media.AudioManager;
import android.os.Bundle;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import com.android.volley.RequestQueue;
import com.android.volley.toolbox.Volley;
import android.speech.RecognizerIntent;
import android.speech.tts.TextToSpeech;

public class MainActivity extends Activity {

    /**
     * {@link CardScrollView} to use as the main content view.
     */
    private CardScrollView mCardScroller;
    private TextToSpeech mTTS;
    private RequestQueue mQueue;

    /**
     * "Hello World!" {@link View} generated by {@link #buildView()}.
     */
    private View mView;

    @Override
    protected void onCreate(Bundle bundle) {
        super.onCreate(bundle);

        mView = buildView();

        mCardScroller = new CardScrollView(this);
        mCardScroller.setAdapter(new CardScrollAdapter() {
            @Override
            public int getCount() {
                return 1;
            }

            @Override
            public Object getItem(int position) {
                return mView;
            }

            @Override
            public View getView(int position, View convertView, ViewGroup parent) {
                return mView;
            }

            @Override
            public int getPosition(Object item) {
                if (mView.equals(item)) {
                    return 0;
                }
                return AdapterView.INVALID_POSITION;
            }
        });
        // Handle the TAP event.
        mCardScroller.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView parent, View view, int position, long id) {
                // Plays disallowed sound to indicate that TAP actions are not supported.
                AudioManager am = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
                am.playSoundEffect(Sounds.DISALLOWED);
            }
        });
        setContentView(mCardScroller);
    }

    @Override
    protected void onResume() {
        super.onResume();
        mCardScroller.activate();
    }

    @Override
    protected void onPause() {
        mCardScroller.deactivate();
        mTTS.shutdown();
        super.onPause();
    }

    /**
     * Builds a Glass styled "Hello World!" view using the {@link CardBuilder} class.
     */
    private View buildView() {
        mTTS = new TextToSpeech(this, new TextToSpeech.OnInitListener() {
            @Override
            public void onInit(int status) {
            }
        });
        final CardBuilder card = new CardBuilder(this, CardBuilder.Layout.TEXT);
        mQueue = Volley.newRequestQueue(this);
        final String carrName = getIntent().getExtras().getStringArrayList(RecognizerIntent.EXTRA_RESULTS).get(0);
        HANAFlightsAPI.getFlightsData(carrName, mQueue, new HANAFlightsAPI.Callback() {
            @Override
            public void onFlightsData(HANAFlightsAPI.FlightsData flightsData) {
                card.setText(flightsData.price);
                card.setFootnote(flightsData.carrierName);
                setContentView(card.getView());
            }
        });

        return card.getView();
    }
}

Create a new file and call it “HANAFlightsAPI” and copy the following code

HANAFlightsAPI.java
package glass.app.com.flightsreport;

import android.util.Log;
import com.android.volley.RequestQueue;
import com.android.volley.Response;
import com.android.volley.VolleyError;
import com.android.volley.toolbox.JsonObjectRequest;
import org.json.JSONException;
import org.json.JSONObject;
import android.util.Base64;
import java.util.HashMap;
import java.util.Map;
import com.android.volley.AuthFailureError;
import java.net.URI;
import java.net.URISyntaxException;

public class HANAFlightsAPI {
    /**
     * Open Weather Map API Endpoint
     */
    public static final String URL = "http://YourServer:8000/Flights/flights.xsodata/FLIGHTS?$format=json&
                                      $filter=CARRNAME%20eq%20";

    /**
     * Object containing qualitative description of weather as well as temperature in Fahrenheit.
     */
    public static class FlightsData {

        public final String carrierName;
        public final String price;

        public FlightsData(String carrierName, String price) {
            this.carrierName = carrierName;
            this.price = price;
        }
    }

    public interface Callback {
        void onFlightsData(FlightsData flightsData);
    }

      public static void getFlightsData(String carrierName, RequestQueue queue, final Callback callback) {
        URI uri = null;
        try {
            uri = new URI(carrierName.replaceAll(" ", "%20"));
        } catch (URISyntaxException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        queue.add(new JsonObjectRequest(URL + "%27" + uri + "%27", null,
                new Response.Listener<JSONObject>() {
                    @Override
                    public void onResponse(JSONObject response) {
                        String carrier = "";
                        String price = "";
                        try {
                            JSONObject results = (JSONObject) response.getJSONObject("d").getJSONArray("results").get(0);
                            carrier = results.getString("CARRNAME");
                            price = results.getString("PRICE");
                        } catch (JSONException e) {
                            e.printStackTrace();
                        }
                        callback.onFlightsData(new FlightsData(carrier, price));
                    }
                }, new Response.ErrorListener() {
            @Override
            public void onErrorResponse(VolleyError error) {
                Log.e("onErrorResponse", error.getMessage());
            }
        }) {

            @Override
            public Map<String, String> getHeaders() throws AuthFailureError {
                HashMap<String, String> headers = new HashMap<String, String>();
                String creds = String.format("%s:%s", "SYSTEM", "YourPassword");
                String auth = "Basic " + Base64.encodeToString(creds.getBytes(), Base64.DEFAULT);
                headers.put("Authorization", auth);
                return headers;
            }
        });
    }
}

Go the second build.gradle file (the one that says “Module.app”) and add this...

Module.app
dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    compile 'com.mcxiaoke.volley:library:1.0.+'
    androidTestCompile 'org.hamcrest:hamcrest-all:1.3'
}

This will add the Volley library which is an HTTP library designed to make Android apps networking easier and faster.

Open the file “voice_trigger.xml” and copy the following code

voice_trigger.xml
<?xml version="1.0" encoding="utf-8"?>

<trigger keyword="Flight Report">
    <input prompt="Which Carrier?"/>
</trigger>

Open the file “strings.xml” and copy the following code

strings.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
    <string name="app_name">Flights Report</string>
    <string name="glass_voice_trigger">flights report</string>
    <string name="glass_voice_prompt">which carrier?</string>
</resources>

Open the file “AndroidManifest.xml” and copy the following code

AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="glass.app.com.flightsreport">

    <uses-permission android:name="com.google.android.glass.permission.DEVELOPMENT"/>
    <uses-permission android:name="android.permission.INTERNET"/>

    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="Flights Report">

        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="com.google.android.glass.action.VOICE_TRIGGER"/>
            </intent-filter>
            <meta-data
                android:name="com.google.android.glass.VoiceTrigger"
                android:resource="@xml/voice_trigger"/>
        </activity>

    </application>
</manifest>

We’re almost ready…we need to connect our Google Glass and make sure it’s on Debug On.

Navigate to “Settings” and enter it.


Navigate to “Device info” and click it


Navigate to “Turn on debug” and click it. It should become “Turn off debug”


With that we will be able to link our Google Glass to our Android Studio project. Simply run it and you will see this on the Glass.


Click to enter it and you will see the main screen


Say a carrier name like “American Airlines”


Wait and the application will connect to our SAP HANA OData and display the result


Now, to not make you believe that I’m just making this up…try another one…like “Lufthansa”


Wait to see the result…


Cool, huh? You could also ask for “Delta Airlines” or “United Airlines”…if you ask for something else, it might give you back the result for the most approximate name or just the default one.

I’m happy enough with this little project -;)

Greetings,

Blag.
Development Culture.

miércoles, 9 de septiembre de 2015

Amazon Alexa and SAP HANA

This post was originally posted on Amazon Alexa and SAP HANA.



If you are an SAP Employee, please follow us on Jam.


Amazon Alexa (Formerly Amazon Echo) is an awesome technology that allows you to give voice commands and get cool answers. Yes…it’s like Siri but from Amazon. Also, it doesn’t live on your cellphone, as Alexa is black cylinder packed up with seven microphones and very loud speakers.




We just get one for the d-shop almost a week ago…so of course…I needed to hack it and make it work with SAP HANA -;)

First, we need to create a Calculation View and call it “FLIGHTS_BY_CARRIER”. It will be composed of two tables, SCARR and SFLIGHT.

First, we need to create a Join object and link the table by MANDT and CARRID. From here select the following fields as output MANDT, CARRID, CARRNAME, PRICE and CURRENCY.

Then create an Aggregation object selecting the fields CARRNAME, PRICE (As Aggregated Column) and CURRENCY. Filter the CURRENCY field by ‘USD’.

Then create a Projection object and select only PRICE and CARRNAME.

On the Semantics object make sure to select “CROSS CLIENT” as the Default Client.

Now, switch to the SAP HANA Development View and create a new repository. Call it “Flights”.

Create a new “XS Engine” project and call it “Flights” as well. Link it to the “Flights” repository.

Create an empty “.xsapp” file.

Create a file called “.xsaccess” with the following code.

.xsaccess
{
          "exposed" : true,
          "authentication" : [ { "method" : "Basic" } ]
}

Finally create a file called “flights.xsodata” with the following code

Flights.xodata
service {
          "Blag/FLIGHTS_BY_CARRIER.calculationview" as "FLIGHTS" keys 
                                                        generate local "Id";
}

Activate your project and launch it on your browser, you should see something like this…


The SAP HANA part is done…so we can move into the Amazon Alexa part…

I need to thank this blog post Alexa Skills Tutorial: The Definitive Guide to Coding for the Amazon Echo as it really helped me to write my own blog post -;)

In order to code for Amazon Alexa, we can use a new and awesome service from Amazon called Amazon Lambda…which basically allows you to define a NodeJS service that will run only when you need it to run…and also allows you to use the first million requests per month for free…

First…log into your Amazon Web Services Account and get into Amazon Lambda. Make sure you are on the North Virginia region…otherwise this will not work…

Once in there…create a new lambda function and select alexa-skills-kit-color-expert


Then, select the “Alexa Skills Kit” Event Source Type…


Then, we need to configure our function…meaning, we need to name it…


Leave the code entry type for later and choose a role…


Choose Basic execution role and a pop up will be shown…


Press the “Allow it” button at the bottom. Continue and finally press the “Create Function” button. A ARN number will be generated for your function, take note of it as we will need it on the next step.

Now, we need to go to http://developer.amazon.com and log in.

Choose Apps & Services --> Alexa --> Alexa Skills Set.


Press the “Add New Skill” button and enter the Name, Invocation Name (How are we going to call it from Alexa), version and the Endpoint (In this case, the ARN number from our Lambda Function)…


When we click on next, an Application Id number will be generated. Take note of it as we will need it on the coding part…

The Interaction Model section is very important as here we’re going to define the “Intent Schema” and “Sample Utterances”…the first will define the parameters that we’re going to send to Alexa and the second is how we are going to call our application.

Intent Schema
{
  "intents": [
    {
      "intent": "GetSAPHANAIntent",
      "slots": [
        {
          "name": "airline",
          "type": "LITERAL"
        }
      ]
    },
    {
      "intent": "HelpIntent",
      "slots": []
    }
  ]
}

Our variable is going to be called “airline” and it’s going to be a LITERAL…other types are NUMBER, DATE, TIME and DURATION. The intent is the method that we’re going to call in our code…


Sample Utterances
GetSAPHANAIntent get total amount for airline {American Airlines|airline}
GetSAPHANAIntent get total amount for airline {United Airlines|airline}
GetSAPHANAIntent get total amount for airline {Delta Airlines|airline}
GetSAPHANAIntent get total amount for airline {Lufthansa Airlines|airline}
GetSAPHANAIntent get amount for {Delta Airlines|airline}
GetSAPHANAIntent get amount for {Lufthansa|airline}
GetSAPHANAIntent get amount for {United Airlines|airline}
GetSAPHANAIntent get amount for {American Airlines|airline}
GetSAPHANAIntent get {United Airlines|airline}
GetSAPHANAIntent get {Lufthansa|airline}
GetSAPHANAIntent get {Delta Airlines|airline}
GetSAPHANAIntent get {American Airlines|airline}

HelpIntent help
HelpIntent help me
HelpIntent what can I ask you
HelpIntent get help
HelpIntent to help
HelpIntent to help me
HelpIntent what commands can I ask
HelpIntent what commands can I say
HelpIntent what can I do
HelpIntent what can I use this for
HelpIntent what questions can I ask
HelpIntent what can you do
HelpIntent what do you do
HelpIntent how do I use you
HelpIntent how can I use you
HelpIntent what can you tell me
HelpIntent how do i get an amount

The Test section is where we can test our application by sending a utterance like “get American Airlines”…we need to create our function code before we can test it…so don’t worry about this for now…


Forget about the Publishing Information section unless you really want to publish your application…

Let’s create a folder and call it “Alexa_HANA” or something nice like that…then create a folder called “src”. Copy the code from here and create a file called “AlexaSkills.js”

We’re going to need to install the node-rest-client package on our function, so do the following on a terminal

sudo npm install --prefix=~/Alexa_HANA/src node-rest-client

This will create a folder called “node_modules” with the package in our project folder…then create a file called “index.js” and copy and paste the following code…

index.js
var Client = require('node-rest-client').Client
  , AlexaSkill = require('./AlexaSkill')
  , APP_ID     = 'amzn1.echo-sdk-ams.app.XXX';

var error = function (err, response, body) {
    console.log('ERROR [%s]', err);
};

function toTitleCase(str)
{
    return str.replace(/\w\S*/g, function(txt){return txt.charAt(0).toUpperCase() + txt.substr(1).toLowerCase();});
}

var getJsonFromHANA = function(airline, callback){
 var sAirline = toTitleCase(airline);
 var options_auth={user:"SYSTEM",password:"YourPassword"};
 client = new Client(options_auth);
 client.get("http://YourServer:8000/Flights/flights.xsodata/FLIGHTS?$format=json&$filter=CARRNAME eq \'" + 
                    sAirline + "\'", function(data, response){
  if (data.d.results[0] != undefined){
   var Amount = data.d.results[0].PRICE; 
  }else{
   var Amount = "Sorry I coudln't find that airline"; 
  }
  callback(Amount);
 }).on('error',function(err){
            callback("Sorry there was a connection error");
       });
}

var handleHANARequest = function(intent, session, response){
  getJsonFromHANA(intent.slots.airline.value, function(data){
 var text = data;
    var cardText = 'Total sales are: ' + text;

    var heading = 'Total sales for: ' + intent.slots.airline.value;
    response.tellWithCard(text, heading, cardText);
  });
};

var HANA = function(){
  AlexaSkill.call(this, APP_ID);
};

HANA.prototype = Object.create(AlexaSkill.prototype);
HANA.prototype.constructor = HANA;

HANA.prototype.eventHandlers.onSessionStarted = function(sessionStartedRequest, session){
  console.log("onSessionStarted requestId: " + sessionStartedRequest.requestId
      + ", sessionId: " + session.sessionId);
};

HANA.prototype.eventHandlers.onLaunch = function(launchRequest, session, response){
  // This is when they launch the skill but don't specify what they want.
  var output = 'Welcome to S A P HANA. ' +
    'Say an Airline Name.';

  var reprompt = 'Which Airline would you like?';

  response.ask(output, reprompt);

  console.log("onLaunch requestId: " + launchRequest.requestId
      + ", sessionId: " + session.sessionId);
};

HANA.prototype.intentHandlers = {
  GetSAPHANAIntent: function(intent, session, response){
    handleHANARequest(intent, session, response);
  },

  HelpIntent: function(intent, session, response){
    var speechOutput = 'Get the total amount for any airline. ' +
      'Which Airline would you like?';
    response.ask(speechOutput);
  }
};

exports.handler = function(event, context) {
    var skill = new HANA();
    skill.execute(event, context);
};

Once is done, we will need to .zip the files…so go into your “src” folder and create a .zip file that include the “node_modules” folder, the AlexaSkills.js file and the index.js file…you can call the .zip file “SAPHANA.zip”.

Now, go back to your Amazon Lambda function and choose the Code tab. Then choose “Upload a .ZIP file” and press Upload. Choose your SAPHANA.zip file and then press the “Save” button.



With that…we should be ready to keep going -;)

We can now use the Test section of our Alexa Skill…



Once you know it’s working…you can test your function in your Amazon Alexa by saying…

“Alexa ask get hana”

And then “get American Airlines” or “get total amount for Delta Airlines”

Here’s a video to show you how it works -:)


As you can see…it’s actually pretty easy but there’s something you need to keep in mind…Alexa will not be able to recognize everything you say…so you need to be careful with your utterances…also…in SAP HANA we have “American Airlines” but Alexa will understand “american airlines”…that’s why I needed to capitalize the first letter as otherwise, both are different airline names -;)

Greetings,

Blag.
Development Culture.