Tuesday, August 09, 2016

Microsoft HoloLens en el SAP’s d-shop

Este post fué posteado originalmente en Microsoft HoloLens on SAP’s d-shop.


Una de las metas principales del SAP’s d-shop es recolectar, aprender y compartir conocimientos en las últimas tecnologías y el Microsoft HoloLens no ha estado fuera de nuestro radar -;)

Pero…que es HoloLens?


HoloLens es un dispositivo de Mixed Reality…que es basicamente una mezcla de Virtual (Oculus Rift) y Augmented (Google Glass) Realities.

Una de las capacidades más importantes del Mixed Reality es que te permite crear Hologramas que pueden ser mezclados con el mundo real e interactuar con el.

HoloLens hace un mapeo de tu cuarto y puede reconocer que tienes una mesa de café, un sofá, una lámpara, y demás…cuando posicionas tus Hologramas en la mesa o en el sofá, el Holograma no va pasar a través de el, más bien va a "sentarse" encima…y esto te permite hacer cosas asombrosas como crear una Holograma de una lampara que va a ser posicionada al costado del sofá para ver como se vería. Y este es solo uno de los múltiples casos de uso que el HoloLens puede proporcionar.

En el d-shop Silicon Valley, creemos que utilizar y programar el HoloLens es una experiencia asombrosa.

Así que…que necesitas para comenzar a programar y crear experiencias asombrosas?

En esta página encontrarás todas las herramientas que necesitas, las cuales incluyen Visual Studio, una versión a la medida de Unity3D y el emulador del HoloLens.

Además, también sería excelente para ti echarle un vistazo a los videos del Holographic Academy…los cuales te guía a través de los conceptos básicos de la programación en HoloLens…

Pero…con este blog queremos mostrarte un video con algunos de los demos/proyectos que hemos creado en el d-shop Silicon Valley.

Word Clock Con esta aplicación, puedes literalmente leer la hora -;) Esto demuestra el de texo en Unity y fué adaptado de una aplicación escrita en Python.

d-shop Robot Esta aplicación utiliza un model del robot del d-shop diseñado utilizándo Blender. Esto demuestra el uso de Spatial Mapping y comandos simples de voz.

SAP Puzzle Game Esta aplicación muestra un juego de rompecabeza deslizable que tiene dos modos…fácil y dificil…demuestra como recortar una imagen y distribuirla en multiples cubos, también demuestra el uso de comandos de voz simples y física.

HoloHouse Esta aplicación es un proyecto diseñado para un banco en Dubai para ser utilizado como aplicación de Bienes Raices. Los modelos fueron diseñados utilizándo 3ds Max por una compañía externa. Esta aplicación demuestra el uso del Scripting en Unity para rotar las casas, decolorar las luces, levantar el techo y los pisos de las casas y mostrar señalizaciones.




Ahora que has visto lo que se puede hacer en un par de semanas…por que no te unes a nosotros en el d-shop y nos muestras que es lo tú puedes hacer! -:D

Saludos,

Blag.
Development Culture.

Sunday, August 07, 2016

El primer Hackaton de Hololens del d-shop

Este post fué posteado originalmente en d-shop's very first Hololens Hackaton.


El Miércoles 3 de Agosto, tuvimos el primer Hackaton de Hololens en el d-shop’s de SAP. Personas que nunca antes habían utilizado Unity3D y que nunca antes habían programado para el Hololens se reunieron para tener una divertiva y emocionante experiencia de aprendizaje.


Gracias al trabajo duro y esfuerzos de organización de mis compañeros de equipo Aaron Williams y Julia Satsuta tuvimos 3 personas asombrozas de Microsoft, Vlad Kolesnikov, Petri Wihelmsen y Jaime Rodriguez.


El primer día hubo explicaciones de que es el Hololens…una rápida introducción a Unity3D y una parte de Design Thinking/Brainstorming donde los equipos pudieron planear sus ideas.

El segundo día arrancó con programación en Hololens y apoyo por nuestro lado. La personas estaban completamente emocionadas y con energía…intentándo cosas en el editor de Unity3D…en el emulador de Hololens y en el mismo dispositivo.

Como una manera de incluir a más personas y dejar que los equipos pudieran trabajar sin distracciones, tuvimos una sesión sobre Hololens en el Edificio 7…abierto para todos lo que querían asistir…




Luego de eso, regresamos para poder continuar ayudándo y apoyándos a los equipos. Ellos necesitaban estar totalmente listos a las 3:30pm puesto que teniamos la presentación de demos a las 4:00pm.

La presentación de demos estuvo localizada en la cafetería del Edificio 8.



Tuvimos a 5 equipos presentándo su impresionante trabajo…

Holoterior

Diseña el cuarto de tus sueños




Mechannotate
Ordena parte de repuesto a medida que las necesitas...no pierdas el tiempo llenándo formularios




Next Talent

Motiva a tus nuevos empleados ofreciéndoles una inmersión en tu historia y cultura




TripIp

Planeando tu próximo viaje? Obtén el asiento que es más comfortable para ti




The Wesley Crushers

Se rompio una de tus cañerías? Revisala...mídela y pide un repuesto




Como pueden ver…todos los equipos pusieron todo su esfuerzo y crearon demos realmente alucinantes…pero…siempre debe haber solo un ganador…así que el último equipo en presentarse fué también el equipo de ganó…así que…felicidades al equipo “The Wesley Crushers”!

Luego de esta emocionante experiencia…estoy seguro de que vamos a regresar por más…Hololens es aún una tecnología muy nueva, así que aún hay mucho por aprender, mucho por hackear y muchisimas posibilidades.

Si estás en Palo Alto…ven y visítianos! Recuerden que el d-shop está localizado en el primer piso del Edificio 9 en Deer Creek Road -;)

Saludos,

Blag.
Development Culture.

Monday, February 08, 2016

Hay una fiesta en la casa de Alexa

Este post fué posteado originalmente en  There's a party at Alexa's place.


Este es mi primer blog del año…así que quería que fuera algo realmente bueno y extenso -:) Ya saben que me encanta la programación en R…pero también me encantan otras tecnologías…así que tomar varias de ellas y interconectarlas es lo que realmente me hace feliz.

Ahora…se estarán preguntándo por el título del post…”Hay una fiesta en la casa de Alexa”…bueno…quería describir el blog de una manera divertida…así que veamos que vamos a construir -;)


Tienen alguna idea? Basicamente…vamos a utilizar Amazon Alexa como nuestro UI…cuando preguntemos un comando…vamos a llamar a un servidor NodeJS en Heroku (Que dicho sea de paso tiene un cliente PhantomJS instalado)…este NodeJS va a llamar a un servidor R en Heroku (Utilizándo un servidor Rook)…y este servidor R va a llamar a HANA Cloud Platform para obtener información de vuelos y generar interesántes gráficos que van a ser retornados al servidor NodeJS el cual va a llamar a nuestro navegador de internet para mostrar los gráficos generados por nuestro servidor de R…por supuesto…al utilizar PhantomJS vamos a leer la página web generada en el navegador y esto va a ser enviado de vuelta a Amazon Alexa para que ella pueda leernos la respuesta…suficientemente intersánte para ustedes? Así lo espero -:) Me tomó más de 2 semanas tener todo esto listo y funcionándo…así que debería gustárles -:P

Así que…veamoslo en algunos cuantos pasos…

OBTENER UNA CUENTA DE HANA CLOUD PLATFORM

Ya deberían tener una…si no…simplemente entre aquí y creen una…

Luego…necesitamos descargar HANA Cloud Platform SDK extraerlo y modificar el archivo tools/neo.sh en la línea 57…

En vez de esto…

javaExe="$JAVA_HOME/bin/$javaCommand"

Debemos utilizar esto…

javaExe="$JAVA_HOME"

Por qué? Bueno…tendrá sentido más adelánte…o quizás tenga sentido ahora -;) Si tienen el cliente de SAP HANA instaládo…de otra manera puedes descargarlo de aquí y tomen en cuenta que vamos a tener que copiar el archivo ngdbc.jar

OBTENIÉNDO LA DATA QUE VAMOS A UTILIZAR

Como siempre…en casi todos mis blogs…vamos a utilizar tablas de modelo de vuelos…el cual por supuesto…no existe en HANA Cloud Platform…

La manera más sencilla (por lo menos para mí) fué acceder a un servidor R/3…y simplemente descargar las tablas como archivos XLS…convertirlos a archivos CSV y subirlos a HCP…

Y dicho sea de paso…por alguna razón mi R/3 no tenía American Airlines listado en la tabla SCARR…así que simplemente lo agregué -;)

Ahora…si no tienen acceso a un servidor de R/3...entonces pueden descargar las tablas en formato CSV en este enlace

CREAR EL SERVIDOR R EN HEROKU

Si no tienen instaládo el Heroku Tool Belt…vayan y consigánlo…

Pasos para instalar R en Heroku con capacidades gráficas
mkdkir myproject && cd myproject
mkdir bin
echo “puts ‘OK’ > config.ru
echo “source ‘http://rubygems.org’\n gem ‘rack’” > Gemfile
#Abre la carpeta de tu proyecto y modifica el archivo Gemfile para reemplazar “\n” con un salto de línea…
bundle install
git init . && git add . && git commit –m “Init”
heroku apps:create myproject –stack=cedar
git push heroku master
#Copia y pega el contenido de installR.sh en la carpeta /bin de tu proyecto
git add . && git commit –am “message” && git push heroku master
heroku ps:scale web=0

installR.sh
#!/bin/bash

function download() {
  if [ ! -f "$2" ]; then
    echo Downloading $2...
    curl $1 -o $2
  else
    echo Got $2...
  fi
}

set -e
 
r_version="${1:-3.2.3}"
r_version_major=${r_version:0:1}
 
if [ -z "$r_version" ]; then
  echo "USAGE: $0 VERSION"
  exit 1
fi
 
basedir="$( cd -P "$( dirname "$0" )" && pwd )"
 
# create output directory
vendordir=/app/vendor
mkdir -p $vendordir

# R
download http://cran.r-project.org/src/base/R-$r_version_major/R-$r_version.tar.gz R-$r_version.tar.gz
tar xzf R-$r_version.tar.gz

# build R
echo ============================================================
echo Building R
echo ============================================================
cd $basedir/R-$r_version/

./configure --prefix=$vendordir/R --with-blas --with-lapack --enable-R-shlib --with-readline=no --with-x=yes
make

cd /app/bin
ln -s R-$r_version/bin/R

rm R-3.2.3.tar.gz
rm -rf erb gem irb rake rdoc ri ruby testrb
rm ruby.exe

cd /app/bin/R-$r_version

rm -rf src
rm Make*
rm -rf doc
rm -rf tests
rm README ChangeLog COPYING INSTALL SVN-REVISION VERSION

Ahora…necesitamos hacer un paso muy importánte -:) Debemos instalar el totalmente asombroso heroku-buildpack-multi de ddollar.

heroku buildpacks:set https://github.com/ddollar/heroku-buildpack-multi.git

Luego de eso…debemos crear un par de archivos…uno llamado .buildpacks y el otro Aptfile.

.buildpacks
https://github.com/ddollar/heroku-buildpack-apt
https://github.com/heroku/heroku-buildpack-ruby
Aptfile
gfortran
libatlas-base-dev
libatlas-dev
liblapack-dev

Ahora viene la parte interesánte…instalar R -;)

Finalmente...instalándo R...
git add . && git commit –am “message” && git push heroku master
heroku ps:scale web=0
heroku run bash
cd bin/
./installR.sh

Con esto listo…vamos a tener todas las librerías que faltaban y que son necesarias para poder compilar R en el nuevo Cedar Stack de Heroku y además…vamos a tener un R finamente instalado y es más...con capacidades gráficas…pero por supuesto…aún no hemos terminado…

Instalándo las librerias de R
#Esto va a abrir R en Heroku…
R
#Esto va a instalar las librerías con sus dependencias correspondientes
install.packages("Rook",dependencies=TRUE)
install.packages("Cairo",dependencies=TRUE)
install.packages("maps",dependencies=TRUE)
install.packages("forecast",dependencies=TRUE)
install.packages("plotrix",dependencies=TRUE)
install.packages("ggplot2",dependencies=TRUE)
install.packages("ggmap",dependencies=TRUE)
install.packages("rJava",dependencies=TRUE)
install.packages("RJDBC",dependencies=TRUE)
q()

Perfecto…estamos casi listos -;) El problema con Heroku es que es de solo lectura…lo cual significa que una vez que te desconectas…vas a perder todo tu trabajo -:(

Así que…necesitamos hacerle un backup y mandarlo a otro lado…yo utilicé mi servidor de R en Amazon WebServices para esto…

Primero…debemos comprimir la carpeta bin así…

tar -cvzf bin.tar.gz bin

y luego debemos grabar el archivo en nuestro servidor externo…

scp -i XXX.pem bin.tar.gz ec2-user@X.X.X.X:~/Blag/bin.tar.gz

y por supuesto luego de eso lo necesitamos en nuestra carpeta de proyecto…así que debemos enviarlo desde nuestro servidor externo de vuelta hacia nuestra carpeta de proyecto, donde simplemente deberemos descomprimirlo…

scp -i XXX.pem ec2-user@X.X.X.X:~/Blag/bin.tar.gz bin.tar.gz

Una vez que esto está listo…debemos hacer algo realmente rápido…

Si todavía siguen en el Heroku bash…simplemente ejecuten

which java

y tomen nota de la ruta…

Ahora…podemos cerrar Heroku y continuar…copiamos el archivo bin.tar.gz en nuestra carpeta de proyecto y lo descomprimimos…luego…creamos los siguientes archivos…

config.ru
`/app/bin/R-3.2.3/bin/R –e “source(‘/app/demo.R’)”`
demo.R
library("Rook")
library("ggmap")
library("maptools")
library("maps")
library("Cairo")
library("RJDBC")

myPort <- as.numeric(Sys.getenv("PORT"))
#myPort <- 8000
myInterface <- "0.0.0.0"
status <- .Call(tools:::startHTTPD, myInterface, myPort)

newapp<-function(env){
  req<-Rook::Request$new(env)
  res<-Rook::Response$new()

  pass<-system('./hcp.sh',intern=T)
  jdbcDriver <- JDBC("com.sap.db.jdbc.Driver","ngdbc.jar", identifier.quote="`")
  conn_server <- dbConnect(jdbcDriver, "jdbc:sap://localhost:30015", "DEV_6O3Q8EAM96G64Q8M0P5KLA1A3",pass[1])
  airports_param<- dbGetQuery(conn_server, "SELECT ID FROM NEO_BLR8NOQVY6TG8KXKQJ003WVOJ.SAIRPORT")
  sairport<-data.frame(IATA=airports_param$ID)
  airports<-read.csv("airports.dat", header = FALSE)
  colnames(airports)<-c("ID", "name", "city", "country", "IATA", "ICAO", "lat", "lon")
  airports<-subset(airports, IATA %in% sairport$IATA)
  keeps <- c("city","country","IATA","lat","lon")
  airports<-airports[keeps]    
  
  if(req$params()$airports != '')
  {
    count_sairport<-nrow(airports)
    mp <- NULL
    mapWorld <- borders("world", colour="gray50")
    mp <- ggplot() + mapWorld
    CairoJPEG(filename = "R_Plot.jpg", width = 680, height = 680)
    mp <- mp+ geom_point(aes(x=airports$lon, y=airports$lat) ,color="red", size=3) 
    show(mp)
    dev.off()
  }else if(req$params()$us_airports != '')
  {
    US_Airports<-airports[airports$country == "United States", ]
    count_sairport<-nrow(US_Airports)
    mp <- NULL
    mapWorld <- borders("state", colour="gray50")
    mp <- ggplot() +  mapWorld
    mp <- mp+geom_point(aes(x=US_Airports$lon, y=US_Airports$lat) ,color="red", size=3)+
           geom_text(data=US_Airports, aes(US_Airports$lon, US_Airports$lat, label = US_Airports$city), size=6)
    CairoJPEG(filename = "R_Plot.jpg", width = 680, height = 680)
    show(mp)
    dev.off()
  }else if(req$params()$carriers != '')
  {
    US_Airports<-airports[airports$country == "United States", ]
    US_Airports<-as.vector(t(US_Airports))
    US_Airports<-paste(shQuote(US_Airports), collapse=", ")
    #query<-paste("SELECT CARRID, DISTANCE FROM NEO_BLR8NOQVY6TG8KXKQJ003WVOJ.SPFLI WHERE AIRPFROM IN (",US_Airports,")")
    query<-paste("SELECT SPFLI.CARRID,CARRNAME,DISTANCE FROM NEO_BLR8NOQVY6TG8KXKQJ003WVOJ.SPFLI 
             INNER JOIN NEO_BLR8NOQVY6TG8KXKQJ003WVOJ.SCARR ON SPFLI.CARRID = SCARR.CARRID
             WHERE AIRPFROM IN (",US_Airports,")")
    result<-dbGetQuery(conn_server,query)
    result$DISTANCE<-sub(",\\d+","",result$DISTANCE)
    result$DISTANCE<-sub("\\.","",result$DISTANCE)
    carriers<-data.frame(CARRID=result$CARRID,CARRNAME=result$CARRNAME,
                         DISTANCE=as.numeric(result$DISTANCE),stringsAsFactors = FALSE)
    carriers_sum<-aggregate(DISTANCE~CARRID + CARRNAME,data=carriers,FUN=sum)
    cols<-c('CARRNAME','DISTANCE')
    data <- apply( carriers_sum[ , cols ] , 1 , paste , collapse = " " )
    count_sairport<-paste(shQuote(data), collapse=", ")
    mp <- NULL
    CairoJPEG(filename = "R_Plot.jpg", width = 680, height = 680)
    mp<-ggplot(carriers_sum,aes(x=CARRID,y=DISTANCE,fill=CARRID))+
        geom_bar(position="dodge",stat="identity")
    show(mp)
    dev.off()
  }
  
  size <- as.integer(system("stat --format %s R_Plot.jpg", intern=T))
  to.read = file("R_Plot.jpg", "rb")
  #x<-readBin(to.read, raw(),n=18674)
  x<-readBin(to.read, raw(),n=size)
  hex<-paste(x, collapse = "")
  hex<-paste(hex,count_sairport,sep = "/")
  close(to.read)
  
  res$write(hex)
  res$finish()
}

unlockBinding("httpdPort", environment(tools:::startDynamicHelp))
assign("httpdPort", myPort, environment(tools:::startDynamicHelp))

server = Rhttpd$new()
server$listenAddr <- myInterface
server$listenPort <- myPort
server$add(app = newapp, name = "summarize")

while(T) {
  Sys.sleep(10000)
}

Así que…hay que tomarnos un tiempo para entender que está pasándo en este código…vamos a crear un servidor Rook…que nos va a permitir crear páginas web en R…luego, vamos a utilizar nuestro script hcp.sh para obtener el password de nuestro HANA Cloud Platform bridge…para que podamos tener una conexión JDBC con la base de datos…de ahí queremos obtener una lista de los aeropuertos y también leer los aeropuertos de archivo que se detalla más adelánte (este archivo de aeropuertos contiene la geolocalización de los aeropuertos). Con esto…queremos filtrar los aeropuertos de HANA con los aeropuertos del archivo…para no tener ninguna información extra…ahora…tenemos tres opciones…aeropuertos, aeropuertos de US o líneas aereas…el primero va a generar un mapa del mundo con todos los aerpuertos como pequeños puntos rojos…el segundo va a generar un mapa de los aeropuertos de Estados Unidos con los aeropuertos como pequeños puntos rojos pero también mostrándo los nombres de las ciudades…el último va a generar un histográma geométrico el detalle de la distancia recorrida por las aerolíneas…más adelánte…vamos a leer la información del gráfico generado para crear una cadenas hexadecimal del gráfico además de información adicional que  Alexa debería recitar…bastante sencillo, no?

Procfile
web: bundle exec rackup config.ru

Queremos que este servidor R pueda acceder a HANA Cloud Platform…así que hagamos eso antes de continuar…

Con la ruta de Java…aplicamos este comándo…

heroku config:set JAVA_HOME='/usr/bin/java'

Ahora…Copia los siguiente archivos en la carpeta de tu proyecto…

carpeta “tools” del HANA Cloud Platform SDK
ngdbc.jar del cliente SAP HANA

Además…crea este pequeño script que nos va a permitir conectárnos a HCP…

hcp.sh
#!/bin/bash -e

user=YourUserName
account=YourAccount
HCP_PASSWORD=YourPassword

json=$(tools/./neo.sh open-db-tunnel -i blaghanax -h hanatrial.ondemand.com -a 
       "$account" -u "$user" -p "$HCP_PASSWORD" --background --output json)
regex='.*"host":"([^"]*)".*"port":([^,]*),.*"instanceNumber":"([^"]*)".
        *"dbUser":"([^"]*)".*"dbUserPassword":"([^"]*)".*"sessionId":"([^"]*)".*'
[[ $json =~ $regex ]]
dbHost=${BASH_REMATCH[1]}
dbPort=${BASH_REMATCH[2]}
dbInstance=${BASH_REMATCH[3]}
dbUser=${BASH_REMATCH[4]}
dbPassword=${BASH_REMATCH[5]}
tunnelSessionId=${BASH_REMATCH[6]}

echo $dbPassword

Impresionante…ya casi estamos listos…por favor descarguen este archivo de aeropuertos y guardénlo en su carpeta de proyecto…

Finalmente…con todos los archivos en su lugar podemos enviar todo de vuelta a heroku…así que hagan login a su Heroku tool belt y escriban lo siguiente…

Poniéndo todo en su lugar
git add .
git commit –am “message”
git push heroku master
heroku ps:scale web=1

R debería estar instalado y listo para funcionar -;) Así que deberíamos seguir adelánte y continuar con nuestro servidor NodeJS en Heroku…

Creándo NodeJS en Heroku con PhamtomJS

Creamos un folder llamado mynodeproject y dentro creamos los siguientes archivos…

package.json
{
  "dependencies": {
    "ws": "1.0.1",
    "request": "2.67.0",
    "express": "4.13.3",
    "phantomjs-prebuilt": "2.1.3"
  },
  "engines": {
    "node": "0.12.7"
  }
}
Procfile
web: node index.js
index.js
var WebSocketServer = require("ws").Server
  , http = require("http")
  , express = require("express")
  , request = require('request')
  , fs = require('fs')
  , app = express()
  , arr = []
  , msg = ""
  , port = process.env.PORT || 5000
  , childProcess = require('child_process')
  , phantomjs = require('phantomjs-prebuilt')
  , path = require('path')
  , binPath = phantomjs.path;

app.use(express.static(__dirname + "/"))

var server = http.createServer(app)
server.listen(port)

var wss = new WebSocketServer({server: server})

var childArgs = [path.join(__dirname, 'phantom.js')]
var childStats = [path.join(__dirname, 'readphantom.js')]

app.get('/path', function (req, res) {
 if(req.query.command == 'map'){
  URL = "http://blagrookheroku.herokuapp.com/custom/summarize?airports=xyz&us_airports=&carriers=";
  request(URL, function (error, response, body) {
   if (!error) {
    arr = body.split("/");
    msg = "There are " + arr[1] + " airports around the world";
    var bitmap = new Buffer(arr[0], 'hex');
    var jpeg = new Buffer(bitmap,'base64');
    fs.writeFileSync('Graph.jpg', jpeg);
    res.redirect('/');
   };
  });
 }else if(req.query.command == 'usmap'){
  URL = "http://blagrookheroku.herokuapp.com/custom/summarize?airports=&us_airports=xyz&carriers=";
  request(URL, function (error, response, body) {
   if (!error) {
    arr = body.split("/");
    msg = "There are " + arr[1] + " airports in the US";
    var bitmap = new Buffer(arr[0], 'hex');
    var jpeg = new Buffer(bitmap,'base64');
    fs.writeFileSync('Graph.jpg', jpeg);
    res.redirect('/');
   };
  });
 }else if(req.query.command == 'carriers'){
  URL = "http://blagrookheroku.herokuapp.com/custom/summarize?airports=&us_airports=&carriers=xyz";
  request(URL, function (error, response, body) {
   if (!error) {
    arr = body.split("/");
    msg = "" + arr[1];
    var bitmap = new Buffer(arr[0], 'hex');
    var jpeg = new Buffer(bitmap,'base64');
    fs.writeFileSync('Graph.jpg', jpeg);
    res.redirect('/');
   };
  });
 }else if(req.query.command == 'stat') {
  childProcess.execFile(binPath, childArgs, function(err, stdout, stderr){
   if(!err){
    res.redirect('/');
   };
  });
 }else if(req.query.command == 'readstat') {
  childProcess.execFile(binPath, childStats, function(err, stdout, stderr){
   if(!err){
    res.write(stdout);
    res.end();
   };
  });  
 }else if(req.query.command == 'bye'){
  if(fs.existsSync('Graph.jpg')){
   fs.unlink('Graph.jpg');
  }
  res.redirect('/');
 }
});

wss.on("connection", function(ws) {
  var id = setInterval(function() {
   
  fs.readFile('Graph.jpg', function(err, data) {
    if(!err){
    ws.send(JSON.stringify("Graph.jpg/" + msg), function() {  })
 }else{
    ws.send(JSON.stringify("Gandalf.jpg/No problem...I'm crunching your data..."), function() {  })
 }
  });
  }, 3000)

  ws.on("close", function() {
    clearInterval(id)
  })
})

Vamos a explicar un poco el código y creánme…estoy muy lejos de ser un experto en NodeJS…esta es la primera vez que lo uso para desarrollar algo tan complejo…y me tomó mucho tiempo y muchísima investigación…así que por favor traten de no criticarme mucho -:(

Vamos a crear una aplicación express que va a utilizar Web Sockets para poder refrescar el navegador y así poder mostrar los gráficos generados por el servidor R…también va a llamar a PhantomJS tánto para crear como para leer la página web generada para que así se la podamos mandar de vuelta a Alexa…

Aquí…tenemos seis opciones…map, usmap y líneas aereas…las primeras tres van a llamar a nuestro servidor R pasándole todos los parámetros pero dejándo vacios lo que no necesitamos…y solo pasándo “xyz” como parámetros…

Cuando recibimos la respuesta de R va a ser una cadena larga separada por “/”…lo cual va a ser la cadenas hexadecimal para el gráfico junto con el texto destinado a Alexa…Node va a leer el gráfico…generárlo y luego refrescar el navegador para poder mostrarlo en la pantalla…

La opción stats va a llamar a nuestro script PhantomJS para simplemente leer la página y crear un nuevo archivo con el JavaScript ya ejecutado…el readstat va a leer esta información y extraer el texto que necesitamos para Alexa…finálmente…bye va a borrar el gráfico y el web socket va a llamar al gráfico principal para que sea mostrado en pantalla.

Finálmente…el web socket va a ser constántemente revisado…cada 3 segundos para ver si hay un gráfico o no…y así poder mostrar la imagen correspondiente…

index.html
<html>
  <head>
 <title>I'm a NodeJS Page!</title> 
 <div id="container" align="center"/>
    <script>
      var host = location.origin.replace(/^http/, 'ws')
      var ws = new WebSocket(host);
      ws.onmessage = function (event) {
    var container = document.getElementById('container');
          var data = JSON.parse(event.data);
          data = data.split("/");
          var url = data[0];
          var msg = data[1];
          
          container.innerHTML = '<img src="' + url + '"></br><p><b>' + msg + '</b></p>';
      };
    </script>
  </head>
  <body>
  </body>
</html>

Esta va a ser llamado por nuestra aplicación express y simplemente va a llamar al web socket para determinar que necesitas mostrar…tiene un poco de Javascript…es por eso que necesitamos PhantomJS para que pueda interactuar con el código…

phantom.js
var page = require('webpage').create();
var fs = require('fs');
page.open('http://blagnodeheroku.herokuapp.com/', function () {
 window.setTimeout(function () {
    page.evaluate(function(){

    });

    fs.write('stats.html', page.content, 'w');
    phantom.exit();
},4000);
});

No es el mejor y más descriptivo nombre…pero a quien le importa -:P En fín…este script va a cargar la página…esto es, la aplicación express…esperar por 4 segundos para que el Javascript sea generado y luego crear una página llamada stats.html


readphantom.js
var page = require('webpage').create(),
    address = "stats.html";

    page.open(address, function (status) {
        if (status == 'success') {
                var results = page.evaluate(function() {
                    return document.querySelector('p').innerText.trim();
                });
 console.log(results);
 phantom.exit();
 }
    });

Este script simplemente va a leer la página stats.html y retornar el texto que está localizado dentro del tag “p”…totalmente simple…

CONFIGURÁNDO A ALEXA

Creándo la función Lambda


Ahora…necesitamos configurar a Alexa…para que podamos controlar todo con comándos de voz -:)

Primero…debemos ir a Amazon Lambda e ingresar si ya tenemos una cuenta…de otro modo…por favor creen una…y asegurénse de estar en la región de West Virginia…

En esta lista de funciones…busca color…


Escoje NodeJS…Python ha sido incluído también…pero no lo estaba cuando comencé a trabajar en este blog -:)


Aquí, simplemente presionamos next....


Yo ya creé la función…pero ustedes no deberías tener problemas...


Basic execution role es más que suficiente…


Esto va a llamar a una ventana pop up…simplemente presionamos el botón “Allow” y luego  “Create function”…vamos a incluir el código fuente más adelánte…pero hay que tomar en cuenta el número ARN generado…porque vamos a necesitarlo en el siguiente paso…

Creándo el Skill

Vayan a http://developer.amazon.com e ingresen…luego escojan Apps & Services --> Alexa --> Alexa Skills Set



Escogemos Alexa Skills Kit y llenámos los espacios en blanco...


Apenas presionamos el botón next un número de aplicación será generado en un nuevo campo llmado Application ID. Debemos tomar este número puesto que lo vamos a necesitar cuando hagamos el código de nuestra aplicación.

La sección de Interaction Model es muy importánte puesto que vamos definir el “Intent Schema” y “Sample Utterances”…el primero va a definir los parámetros que vamos a enviar a Alexa y el segundo es como vamos a llamar a nuestra aplicación.

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

Nuestra variable se va a llamar “command” y va a ser de tipo LITERAL…otros tipos son NUMBER, DATE, TIME y DURATION. El intent es el método que vamos a llamar en nuestro código…

Sample Utterances
GetFlightsIntent airports from {around the world|command}
GetFlightsIntent airports from {united states|command}
GetFlightsIntent flight distance from {carriers|command}
GetFlightsIntent {thank you|command}

La sección test nos ayuda a definir comándos y ver como Alexa responde…pero no vamos a hacer esto aquí…vamos a probarlo usándo un dispositivo Alexa real -;)

Olvidense de la sección Publishing Information a menos que realmente quieran publicar su aplicación…

Creamos un carpeta llamada Flights…Alexa_Party…o cualquier cosa que se les ocurra…luego creamos un carpeta llamada src y copiamos este archivo ahí…llamándolo AlexaSkills.js

Vamos a necesitar instalar solamente una librería….”request”…

sudo npm install --prefix=~/Flights/src request

Esto va a crear una carpeta llamada “node_modules” con el paquete en nuestra carpeta de proyecto…luego debemos crear un archivo llamado “index.js” y copiar y pegar el siguiente código…

index.js
var request = require("request")
  , AlexaSkill = require('./AlexaSkill')
  , APP_ID     = 'amzn1.echo-sdk-ams.app.8c0bd993-723f-4ab2-80b5-84402a7a59ce';

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

var getJsonFromFlights = function(command, callback){
 var msg = "";
 if(command == "thank you"){
 request("http://blagnodeheroku.herokuapp.com/path/?command=bye", function (error, response, body) {
  if (!error) {
   console.log("Done");
  };
 });
 setTimeout(function() {
  callback("thank you");
 },2000);
}else if (command == "around the world"){
 request("http://blagnodeheroku.herokuapp.com/path/?command=bye", function (error, response, body) {
 if (!error) {
 request("http://blagnodeheroku.herokuapp.com/path/?command=map", function (error, response, body) {
 if (!error) {
 request("http://blagnodeheroku.herokuapp.com/path/?command=stat", function (error, response, body) {
 if (!error) {
 request("http://blagnodeheroku.herokuapp.com/path/?command=readstat", function (error, response, body) {
 if (!error) {
 msg = body;
 };
 });
 };
 }); 
 };
 });
 }
 }); 
 setTimeout(function() {
  callback(msg.trim());
 },15000);
}else if (command == "united states"){
 request("http://blagnodeheroku.herokuapp.com/path/?command=bye", function (error, response, body) {
 if (!error) {
 request("http://blagnodeheroku.herokuapp.com/path/?command=usmap", function (error, response, body) {
 if (!error) {
 request("http://blagnodeheroku.herokuapp.com/path/?command=stat", function (error, response, body) {
 if (!error) {
 request("http://blagnodeheroku.herokuapp.com/path/?command=readstat", function (error, response, body) {
 if (!error) {
 msg = body;
 };
 });
 };
 }); 
 };
 });
 }
 }); 
 setTimeout(function() {
  callback(msg.trim());
 },15000);
}else if (command == "carriers"){
 request("http://blagnodeheroku.herokuapp.com/path/?command=bye", function (error, response, body) {
 if (!error) {
 request("http://blagnodeheroku.herokuapp.com/path/?command=carriers", function (error, response, body) {
 if (!error) {
 request("http://blagnodeheroku.herokuapp.com/path/?command=stat", function (error, response, body) {
 if (!error) {
 request("http://blagnodeheroku.herokuapp.com/path/?command=readstat", function (error, response, body) {
 if (!error) {
 msg = body;
 };
 });
 };
 }); 
 };
 });
 }
 }); 
 setTimeout(function() {
  callback(msg.trim());
 },15000);
 }
};
var handleFlightsRequest = function(intent, session, response){
  getJsonFromFlights(intent.slots.command.value, function(data){
 if(data != "thank you"){
  var text = data;
  var reprompt = 'Please say a command?';
  response.ask(text, reprompt);
 }else{
  response.tell("You're welcome");
 }
  });
};

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

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

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

Flights.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 Flights. ' +
    'Please, say a command.';

  var reprompt = 'Please, say a command?';

  response.ask(output, reprompt);

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

Flights.prototype.intentHandlers = {
  GetFlightsIntent: function(intent, session, response){
    handleFlightsRequest(intent, session, response);
  },

  HelpIntent: function(intent, session, response){
    var speechOutput = 'Get the information for airports and flights. ' +
      'Please say a command?';
    response.ask(speechOutput);
  }
};

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

Hora de explicar que es lo que querido hacer aquí -:P

El método handleFlightsRequest va a manejar la respuesta que Alexa va a leernos…y dentro de este método podemos encontrar el método getJsonFromFlights el cual va a tomar el comando definido en nuestro Intent Schema. Esta función va a llamar a nuestro servidor NodeJS  para los siguientes comando…”thank you” simplemente llamará al comándo bye….”around the world” va a llamar a los comandos bye, map, stat y readstats…”united states” va a llamar a los comandos bye, usmap, stat y readstat…finalmente carriers va a llamar a los comandos bye, carriers, stat y readstat…

Luego de 15 segúndos (Sip…yo sé que es bastante tiempo pero hay muchos procesos funcionándo) Alexa obtendrá el mensaje de respuesta y simplemente nos lo leerá -;)

Eso es basicamente lo que hace…ahora…puedo enseñarles algunas imágenes antes de que saltemos al video…





Ok…suficiente…veamos esto en plena acción ;)





Saludos,

Blag.
Development Culture.

Monday, December 07, 2015

LED es mi nuevo Hello World - Tiempo de Elm

Así que...como lo prometí...aquí está mi aplicación de Números LED escrita en Elm -:)

Ahora...esto me tomó más tiempo del esperado, por un par de detalle...

a) A Elm le gusta manejar valores Just y Maybe...Haskell también lo hace...pero Haskell provee funciones alternativas que manejan el Just y el Maybe...Elm no...así que tuve que crear algunas funciones adicionales para manejarlo...

b) Elm no provee una funcion para obtener elementos de una lista...así que tuve que crear la función...

c) Todavía soy un novato en Elm

Poniéndo eso de lado...Elm sigue siendo asombroso y me encanta -;)

En fín...hay que ponernos a trabajar...

Debemos crear una carpeta llamada LED_Numbers y escribir esto en el terminal...

elm package install evancz/elm-html

elm package install evancz/start-app

Luego, abre tu editor favorito y copia y pega este código...

LED_Numbers.elm
module LED_Numbers where

import Html exposing (..)
import Html.Events exposing (..)
import Html.Attributes exposing (..)
import StartApp.Simple as StartApp
import String exposing (toInt,toList)
import Dict

--MODEL
type alias Model =
  { 
    number: String,
    leds: Dict.Dict Char (List String),
    line: String
  }

initialModel: Model
initialModel = 
  {
    number = "",
    leds = Dict.fromList[('0',[" _  ","| | ","|_| "]),('1',["  ","| ","| "]),
                         ('2',[" _  "," _| ","|_  "]),('3',["_  ","_| ","_| "]),
                         ('4',["    ","|_| ","  | "]),('5',[" _  ","|_  "," _| "]),
                         ('6',[" _  ","|_  ","|_| "]),('7',["_   "," |  "," |  "]),
                         ('8',[" _  ","|_| ","|_| "]),('9',[" _  ","|_| "," _| "])],
    line = ""
  }

--UPDATE
fromJust : Maybe a -> a
fromJust x = case x of
  Just y -> y
  Nothing -> Debug.crash ""

fromMaybe : Maybe (List String) -> List String
fromMaybe x = case x of
  Just y -> y
  Nothing -> Debug.crash ""

fromMaybeChar : Maybe Char -> Char
fromMaybeChar x = case x of
  Just y -> y
  Nothing -> Debug.crash ""

get_elem : List a -> Int -> Maybe a
get_elem lst n =
  List.head (List.drop n lst)

fromMaybeListChar : Maybe (List Char) -> List Char
fromMaybeListChar x = case x of
  Just y -> y
  Nothing -> Debug.crash ""

get_list: String -> List Char
get_list str =
  String.toList str

type Action = NoOp | Submit | UpdateNumber String

update: Action -> Model -> Model
update action model =
  case action of
    NoOp ->
      model
    UpdateNumber contents ->
      { model | number = contents }  
    Submit ->
      { model | 
          line = get_led (get_list model.number) 0 model,
          number = ""
      }

get_led: List Char -> Int -> Model -> String
get_led lst n model =
  if List.length lst > 0
  then let h = fromMaybeChar(List.head lst)
           t = fromMaybeListChar(List.tail lst)
           leds = model.leds
           line = Dict.get h leds
       in fromJust(get_elem (fromMaybe line) n) ++ get_led t n model
  else if n < 2
  then "" ++ "\n" ++ get_led (get_list model.number) (n+1) model
  else if n == 2
  then "" ++ "\n"
  else ""

--VIEW
buttonStyle: Attribute
buttonStyle = 
  style
    [ ("outline", "none"),
      ("border", "none"),
      ("border-radius","4px"),
      ("margin-right","5px"),
      ("padding","4px 10px"),
      ("background","#61a1bc"),
      ("color","#fff")
    ]

divStyle: Attribute
divStyle = 
  style
    [ ("margin", "50px auto"),
      ("padding", "0px 50px"),
      ("text-align", "center")
    ]

pStyle: Attribute
pStyle = 
  style
    [ ("font-size", "30px") ]

pageHeader : Html
pageHeader = 
  h1 [ ] [text "LED Numbers"]

view: Signal.Address Action -> Model -> Html
view address model = 
  div [ divStyle ]
    [ pageHeader,
      input
        [ 
          type' "text",
          name "number",
          placeholder "Enter a number",
          value model.number,
          on "input" targetValue (\v -> Signal.message address (UpdateNumber v))
        ]
        [ ],
      button [ buttonStyle, onClick address Submit ] [ text "Submit" ],
      pre [ pStyle ]
          [ text (model.line) ]
    ]
    
main: Signal Html
main = 
  StartApp.start { model = initialModel, view = view, update = update }

Anda al terminal y escribe esto...

elm make LED_Numbers.elm --output LED_Numbers.html

Abre el archivo en tu browser y ejecutalo...



Espero que les guste -;)

Saludos,

Blag.
Development Culture.

Thursday, December 03, 2015

Mi primer post en Elm

Mirándo en mi lista de nuevos lenguajes a aprender...me encontré con Elm...programación funcional y reactiva en el browser...


No es eso impresionante? Por supuesto que lo es -:)

Bueno...Elm comenzó a existir a mediados del 2012...así que es relativamente nuevo...lo cual significa que no hay muchos tutoriales y que yo sepa ningún libro...pero...no dejes que eso te asuste...existen un par de asombrosos cursos dictados por The Pragmatic Studio que te ayudarán a estar listo y preparado -;)

Elm: Building Reactive Web Apps

Elm: Signals, Mailboxes & Ports

Ahora...para instalar Elm...si ya tienes instalado NodeJS entonces simplemente puedes utilizar npm que es yo pienso la manera más rápida y sencilla...

sudo npm install elm

De lo contrario puedes ir a la sección de download para los instaladores o para el código fuente para compilarlo...pero debes tener en cuenta que para compilarlo vas a necesitar tener Haskell instalado también...

En todo caso...vamos a ver como crear una aplicación de List Fibonacci en Elm... -:)

Crea una carpeta y llamala "Fibonacci_App" y entra en la carpeta desde el terminal...

elm package install evancz/elm-html



elm package install evancz/start-app



El primer paquete nos va a permitir generar código HTML y el segundo va a hacer nuestras vidas más sencillas...

Ahora...abre tu editor favorito y copia y pega este código...

Fibonacci.elm
module Fibonacci where

import Html exposing (..)
import Html.Events exposing (..)
import Html.Attributes exposing (..)
import StartApp.Simple as StartApp
import String exposing (toInt)

--MODEL
type alias Model =
  { 
    number: String,
    fibonacci: String
  }

initialModel: Model
initialModel = 
  {
    number = "",
    fibonacci = ""
  }

--UPDATE
parseInt : String -> Int
parseInt string =
  case String.toInt string of
    Ok value ->
      value
    Err error ->
      0

type Action = NoOp | Submit | UpdateNumber String

update: Action -> Model -> Model
update action model =
  case action of
    NoOp ->
      model
    UpdateNumber contents ->
      { model | number = contents }  
    Submit ->
      { model | 
          fibonacci = fib (parseInt model.number) 0 1,
          number = ""
      }

fib: Int -> Int -> Int -> String
fib num a b =
  if a > 0 && num > 1 then toString(a+b) ++ " " ++ fib (num-1) (a+b) a
  else if a == 0 then toString a ++ " " ++ toString b ++ " " 
                      ++ toString(a+b) ++ " " ++ fib(num-1) (a+b) b
  else ""

--VIEW
buttonStyle: Attribute
buttonStyle = 
  style
    [ ("outline", "none"),
      ("border", "none"),
      ("border-radius","4px"),
      ("margin-right","5px"),
      ("padding","4px 10px"),
      ("background","#61a1bc"),
      ("color","#fff")
    ]

divStyle: Attribute
divStyle = 
  style
    [ ("margin", "50px auto"),
      ("padding", "0px 50px"),
      ("text-align", "center")
    ]

pStyle: Attribute
pStyle = 
  style
    [ ("font-size", "30px") ]

pageHeader : Html
pageHeader = 
  h1 [ ] [text "Fibonacci List"]

view: Signal.Address Action -> Model -> Html
view address model = 
  div [ divStyle ]
    [ pageHeader,
      input
        [ 
          type' "text",
          name "number",
          placeholder "Enter a number",
          value model.number,
          on "input" targetValue (\v -> Signal.message address (UpdateNumber v))
        ]
        [ ],
      button [ buttonStyle, onClick address Submit ] [ text "Submit" ],
      p [ pStyle ]
        [ text (model.fibonacci) ]
    ]
    
main: Signal Html
main = 
  StartApp.start { model = initialModel, view = view, update = update }

Luego, solo debemos compilar nuestra aplicación -;)

elm make Fibonacci.elm --output Fibonaccci.html



Ahora, podemos abrir el archivo Fibonacci.html y probar nuestra aplicación -:D



Espero que le haya gustado -:) Y voy a tratar de tener mi aplicación de Números LED terminada pronto -;)

Saludos,

Blag.
Development Culture.

Monday, November 23, 2015

SAP HANA en la luna (con Lua)

Este post fué posteado originalmente en SAP HANA on the moon (with Lua).


Lua es un lenguaje de programación ligero diseñado como un lenguaje script con semántica extensible como primera regla. Lua es multi plataforma puesto que está escrito en ANSI C, y tiene una API de C relativamente simple.

Si están preguntándo acerca del título…bueno…Lua significa Luna en Portugués -;)


Lua es bastante potente pero sencillo de aprender y usar. Si ya saben Python o Ruby, no tendrán muchos problemas…

Antes de continuar…quiero compartir una pequeña broma…que no es especificamente única para Lua…pero aún así es graciosa -;)


Así que…ninguna demostración estaría completa si la enlazaramos con SAP HANA, so? Así que…vamos a hacerlo -;)

Primero, debemos crear un objeto Join y asociar la tabla por MANDT y CARRID. De ahí, seleccionar los siguientes campos como output MANDT, CARRID, CARRNAME, PRICE y CURRENCY.

Luego crear un objeto Aggregation seleccionándo los campos CARRNAME, PRICE (Como columnas agregadas) y CURRENCY. Debemos filtrar el campo CURRENCY por ‘USD’.

Luego, debemos crear un objeto Projection y seleccionar solo PRICE y CARRNAME.

En el objeto Semantics asegúrense de marcar  “CROSS CLIENT” como cliente por defecto.


Ahora, cambiemos a la vista SAP HANA Development y creemos un nuevo repositorio. Lo llamaremos“Flights”.

Creamos un proyecto “XS Engine” y también lo llamamos “Flights”. Lo enlazamos con el repositorio “Flights”.

Creamos un archivo vacio llamado “.xsapp”.

Creamos un archivo llamado “.xsaccess” con el siguente código.

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

Finalmente creamos un archivo llamado “flights.xsodata” con el siguiente código

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

Activamos el proyecto y lanzamos nuestro browser...deberíamos ver algo como esto…


La parte de SAP HANA está lista…así que ahora podemos pasar a la parte de Lua…

Antes de continuar…debo de recomendar que instalen un par de cosas…si usan Linux…instalen esto…

sudo apt-get install lua5.2

Y luego sigan las instrucciones para instalar LuaRocks un manejador de paquetes para Lua…

Instalen los siguientes paquetes…

sudo luarocks install luasec
sudo luarocks install luajson
sudo luarocks install luasocket

Para programar en Lua, pueden utilizar cualquier editor que les guste…copien y peguen el siguiente código…

Lua_HANA.lua
http = require("socket.http")
mime = require("mime")
ltn12 = require("ltn12")
json = require("json")

h = {Authorization = "Basic " .. (mime.b64("SYSTEM:YourPassword")), 

     ["Content-Type"] = "application/json", ["content-length"] = jsonsize }

local resp ={}

ok, code, headers = http.request{url = "http://YourServer:8000/Flights/flights.xsodata/FLIGHTS?$format=json", 
     redirect = true, method = "GET", headers = h, source = source, 
                                 sink = ltn12.sink.table(resp)}

local dec = json.decode(resp[1])
local d = dec["d"]["results"]
for i = 1, #d do
 io.write(d[i]["CARRNAME"]," : ",d[i]["PRICE"], "\n")
end
print("")


Hacer esta integración con Lua fué rápido y sencillo…Lua es un lenguaje muy interesánte con algunas características muy buenas que no se pueden encontrar en otros lenguajes...

Saludos,

Blag.
Development Culture.

Monday, November 16, 2015

SAP HANA en las garras de Falcon

Falcon es un lenguaje de programación multi-paradígma y open source. Soporta programación procedural, orientad a objetos, basada en prototipos, funcional, tabular y de intercambio de mensajes. Apareció por primera vez hace unos 12 años atrás…así que no es un lenguaje nuevo e inmaduro. Era el lenguaje script for defecto del ya desaparecido sistema operativo Auroraux.


Falcon es bastante impresionante y tiene algunas características que otros lenguajes de programación matarían por tener -:)

Así que…ninguna demostración estaría completa si la enlazaramos con SAP HANA, so? Así que…vamos a hacerlo -;)

Primero, debemos crear un objeto Join y asociar la tabla por MANDT y CARRID. De ahí, seleccionar los siguientes campos como output MANDT, CARRID, CARRNAME, PRICE y CURRENCY.

Luego crear un objeto Aggregation seleccionándo los campos CARRNAME, PRICE (Como columnas agregadas) y CURRENCY. Debemos filtrar el campo CURRENCY por ‘USD’.

Luego, debemos crear un objeto Projection y seleccionar solo PRICE y CARRNAME.

En el objeto Semantics asegúrense de marcar  “CROSS CLIENT” como cliente por defecto.


Ahora, cambiemos a la vista SAP HANA Development y creemos un nuevo repositorio. Lo llamaremos“Flights”.

Creamos un proyecto “XS Engine” y también lo llamamos “Flights”. Lo enlazamos con el repositorio “Flights”.

Creamos un archivo vacio llamado “.xsapp”.

Creamos un archivo llamado “.xsaccess” con el siguente código.

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

Finalmente creamos un archivo llamado “flights.xsodata” con el siguiente código

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

Activamos el proyecto y lanzamos nuestro browser...deberíamos ver algo como esto…


La parte de SAP HANA está lista…así que ahora podemos pasar a la parte de Erlang…

Falcon debería estar incluído en cualquier distribución de Linux…y estoy seguro de que ni siquiera se han dado cuenta -;)

En fín…también pueden instalarlo desde Falcon Releases...

Ahora…como aún soy un novato en Falcon…no estoy seguro si de verdad necesitamos esto…pero para estar seguros…instalamos esto…

apt-get install falconpl-curl

Son las libreías de Curl para Falcon…

Agarra tu editor favorito y copia y pega el siguiente código…

falcon_hana.fal
import from curl
import from json
h = curl.Handle("http://YourServer:8000/Flights/flights.xsodata/FLIGHTS?$format=json")
auth = "Authorization:Basic " + Base64.encode("SYSTEM:YourPassword")
headers = [auth]
h.setOption(curl.OPT.HTTPHEADER,headers)
h.setOption(curl.OPT.SSL_VERIFYPEER,false)
data = h.setOutString().exec().getData()

try
   raw = json.JSONdecode( data )
catch
   printl( "Can't decode the string" )
end

d = raw["d"]

results = d["results"]

for Index in [0:results.len()]
 print(results[Index]["CARRNAME"])
 print(" : ")
 printl(results[Index]["PRICE"])
end

Para ejecutarlo…simplemente abre una sesión en el terminal, anda a la carpeta donde tienes tu código y escribe...

Falcon falcon_hana.fal 



Debo admitir que esto no fué muy sencillo en un inicio…la documentación de Falcon no habla sobre curl…así que tuve que revisar el código en GitHub…hacer muchas pruebas…hasta que finalmente pude hacer que funcione…la parte de json por otro lado fué extremadamente sencilla -:D

Saludos,

Blag.
Development Culture.