Mostrando entradas con la etiqueta R. Mostrar todas las entradas
Mostrando entradas con la etiqueta R. Mostrar todas las entradas

miércoles, 18 de mayo de 2022

What is Nylas, why did I join and why should you care?



I joined Nylas around four months ago as their first Senior Developer Advocate. It might seem like a short amount of time, but in the startup world, time moves differently.

What is Nylas?


In a nutshell, Nylas is a set of APIs that allows you to easily connect with any email, calendar and contacts provider without having to go through a lengthy and complex configuration process.

In other words, we do the heavy work so you can focus on your business.


When it comes to Email, we offer “One Email API for Every Provider”. This means our Email API is universal and you can connect to various providers without having to write specific code for each. Also, we provide real-time, bi-directional sync, and full CRUD capabilities. If you want to learn more, just go to our Universal Email API page.

When it comes to Calendar, we offer the same capabilities as our Email API, but also conferencing sync, events metadata, and programmatic webhooks. If you want to learn more, just go to our Universal Calendar API page.

When it comes to Contacts, you can create, update or delete contacts in any supported provider. If you want to learn more, just go to our Universal Contacts API page.


With Email, Calendar, and Contacts APIs, we’re just getting started. Check out what we offer on top of these APIs to give developers even more power.

With Neural API, exploring the world of AI and ML is easy, with ready-made models that can be used to clean conversations, extract signatures, perform OCR, and run sentiment analysis. If you want to learn more, just go to our Neural API page.


Nylas Streams is our ETL solution that requires little to no code to transform and consume communications data for E-Commerce, Sales, Fintech and Customer Success. If you want to learn more, just go to our Nylas Streams page.


Scheduler, a full featured scheduler with customizable UI. If you want to learn, just go to Scheduler.


Components, ready made and fully flexible UI/UX widgets ready for immediate use. If you want to learn more, just go to Components.

Why did I join?


The first thing that caught my attention with Nylas was the fact that they provide APIs to make communications easier. Handling Email, Calendars and Contacts gives a lot of space to create amazing applications.

The second thing that attracted me to Nylas was the company culture. Everybody looked committed to each other, as I saw a lot of internal support when the Nylas account posted something on social media, and also my interviews were more like chatting with friends than actual interviews.

The third and probably most important thing for me, was going back to Developer Advocacy, which is something that I’m really passionate about. Being able to share with the community is something that makes me feel good and that makes me a better person and a better developer.

Obviously, those 3 things might not be enough to convince you, so let’s create a small example.

For this I’m going to choose one of my favorite Programming Languages– R. And while I’m not an R professional or expert, I’m very passionate about it, so bear with me, there might be better ways to do this.

What we are going to do is simply read the first three messages in my inbox and print the subjects.


The result is going to be:

A Nylas email 
Invitation: RRSP Webinar @ Tue Feb 8, 2022 1pm - 2pm (EST) (alvaro.t@nylas.com) 
Start here: Welcome to Clockwise

Obviously, while R is an awesome language used by statisticians and data scientists around the world, it is not a mainstream language.

That’s why Nylas provides us with SDKs for Python, Ruby, Node, and Java.

Let’s see how we can read our inbox using the Python SDK. If you want to learn how to install the SDK, read our Python Documentation.


The result is going to be:

A Nylas email 
Invitation: RRSP Webinar @ Tue Feb 8, 2022 1pm - 2pm (EST) (alvaro.t@nylas.com) 
Start here: Welcome to Clockwise

As you can see, using the SDK is easier, because we don’t need to traverse the JSON response or figure out where the element that we want to print is. Also, if something changes internally we can rest assured that the SDK will be updated to reflect any changes while simply calling the API will require some manual work. And the same goes for Calendar, Contacts, and the rest of our offerings.
Why should you care?

Well, to begin with, I’m your friendly Developer Advocate so you know I’m going to provide you with constant and interesting content about the Nylas APIs. Also, signing up for a Nylas account is easy, no Credit Card is required and you can get 14 days to try it out. Ready to go? Just go to https://dashboard.nylas.com/register and follow the instructions.

Also, I’m already working on a series of blog posts that will help you to get started, make your first API calls and in overall, get the full Nylas experience.

You can start by reading my blog How to Send Emails with the Nylas Python SDK

Don’t think Nylas is for you? Well, recommend us to a friend then. You might know someone who could benefit from having fast, easy, and convenient access to universal communication APIs.

sábado, 6 de febrero de 2016

There’s a party at Alexa’s place

This post was originally posted on There's a party at Alexa's place.


This is my first blog of the year…so I want it to be something really nice and huge -:) You know how much I love the R Programming Language…but I also love other technologies as well…so taking a bunch of them and hooking them up together is what really brings me joy.

Now…you may be wondering about the blog title…”There’s a party at Alexa’s place”…well…I wanted it to describe the blog in a funny way…so let’s see what we’re going to build -;)


Got any idea? Basically…we’re going to use Amazon Alexa as our UI…when we ask a command…we’re going to call a NodeJS Server on Heroku (Which BTW has a PhantomJS client installed)…this NodeJS will call an R Server on Heroku (Using the Rook Server)…and this R Server is going to call HANA Cloud Platform to get some Flights information and generate nice graphics that are going to be returned to the NodeJS Server which is going to call our web browser to display the graphic generated by the R Server…of course…by using PhantomJS were going to read the generated web page on the browser and this will be sent back to Amazon Alexa so she can read out the response…interesting enough for you? I hope -:) I took me more than two weeks to get all this up and running…so you better like it -:P

So…let’s go in some simple steps…

GET A HANA CLOUD PLATFORM ACCOUNT

You should have one already…if not…just go here to create one…

Then…we need to download the HANA Cloud Platform SDK extract it and modify the file tools/neo.sh on line 57…

Instead of this…

javaExe="$JAVA_HOME/bin/$javaCommand"

Use this…

javaExe="$JAVA_HOME"

Why? Well…it will make sense later on…or maybe it will make sense now  If you have the SAP HANA Client installed…otherwise download it from here take a note that will need to copy the ngdbc.jar file…

GETTING THE DATA THAT WE'RE GOING TO USE

As always…in almost all my blogs…we’re going to use tables from the Flight model…which of course…doesn’t exist on HANA Cloud Platform…

The easiest way (at least for me) was to access an R/3 server…and simply download the tables as XLS files…convert them into CSV files and upload them into HCP…

And BTW…for some weird reason my R/3 didn’t have American Airlines listen on the SCARR table…so I just added it -;)

Now…if you don’t have access to an R/3 system…then you can download the tables in CSV format from here

CREATE THE R SERVER ON HEROKU

If you don’t have the Heroku Tool Belt installed…then go and grab it…

Steps to install R on Heroku with Graphic Capabilities
mkdkir myproject && cd myproject
mkdir bin
echo “puts ‘OK’ > config.ru
echo “source ‘http://rubygems.org’\n gem ‘rack’” > Gemfile
#Open your project folder and modify the Gemfile to replace the “\n” with an actual break line…
bundle install
git init . && git add . && git commit –m “Init”
heroku apps:create myproject –stack=cedar
git push heroku master
#Copy and paste the content of my installR.sh into the /bin folder of your project
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

Now…we need to do a very important step -:) We need to install the totally awesome heroku-buildpack-multi from ddollar.

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

After that…we need to create a couple of files…one called .buildpacks and the other 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

Now comes the interesting part…installing R -;)

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

With this done…we will have all the missing libraries needed to compile R on the new Cedar Stack on Heroku and also…we will have a nicely installed R instance with Graphic capabilities…but of course…we’re not done yet…

Installing the R Libraries
#This will open R on Heroku…
R
#This will install the libraries with their corresponding dependencies
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()

All right…we’re almost there -;) The problem with Heroku is that is not writable…meaning that once you get disconnected…you will lost all your work -:(

So…we need to back it up and sent it somewhere else…I used my R Server on Amazon WebServices for this…

First…we need to compress the bin folder like this…

tar -cvzf bin.tar.gz bin

and then we need to save this file in our external server…

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

and of course after that we need it on our project folder…so we need to send it from our external server to our project folder, where will simply would need to uncompressed it…

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

Once this is done…we need to something real quick…

If you’re still inside the Heroku bash…simply run

which java

and take note of the location…

Now…we can close Heroku and keep going…copy the bin.tar.gz file into your project folder and extract it…then…create the following files…

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)
}

So…let’s take some time to understand what’s going on with this code…we’re going to create a Rook server…which will allow us to host webpages from R…then, we’re going to use our hcp.sh script to get the password for our HANA Cloud Platform bridge…so we can get an JDBC connection to the database…from there we want to get a list of all the airports and also read the airports from a file detailed later (this airports file contains the geolocation of the airports). With this…we want to filter out the airports from HANA with the airports from the flight…so we don’t have any extra data…now…we have three choices…airports, US airports or carriers…the first one will generate a map of the world with all the airports as little red dots…the second one will generate a map of the US with the airports as little red dots but also showing the name of the cities…the last one will generate a geometric histogram with the details of the flights distance according to their carriers…later on…we’re going to read the information of the generated graphic to create a hexadecimal string of the graphic along with some information that Alexa should spell out…easy as cake, huh?

Procfile
web: bundle exec rackup config.ru

We want this R Server to be able to access HANA Cloud Platform…so let’s do that before we keep going…

With the location of Java…apply this command…

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

Now…Copy the following files into your project folder…

“tools” folder from the HANA Cloud Platform SDK
ngdbc.jar from SAP HANA Client

Also…create this little script which is going to allow us to connect to 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

Awesome…we’re almost there…please download this airports file and place it on your project folder…

Finally…with all files in place we can send everything back to heroku…so log into your Heroku tool belt and do the following…

Getting everything in place
git add .
git commit –am “message”
git push heroku master
heroku ps:scale web=1

R should be installed and ready to go -;) So we should move on and continue with our NodeJS server on Heroku…

Creating NodeJS on Heroku with PhantomJS

Create a folder called mynodeproject and inside create the following files…

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)
  })
})

Let’s explain the code for a little bit and believe me…I’m far from being a NodeJS expert…this is really the first time I develop something this complex…and it took me a really long time and tons of research…so please try not to criticize me too much -:(

We’re going to create a express application that uses Web Sockets in order to refresh the browser in order to show the graphics generated by our R Server…it will also call PhantomJS to both create and read the generated web page so we can send it back to Alexa…

Here…we have six choices…map, usmap and carriers…the first three are going to call our R Server passing all parameters but leaving the ones that we don’t need empty…and just passing “xyz” as parameter…

When we got the response from R it’s going to be a long string separated by an “/”…which is going to be the hexadecimal string for the graphic along with the text intended for Alexa…Node will read the graphic…generated it and then refresh the browser in order to show it on the screen…

The stats option will call our PhantomJS script to simply read the page and create a new file with the Javascript part already executed…the readstat will read this information and extract the text that we need for Alexa…finally…bye will delete the graphic and the web socket will call the main graphic to be displayed on the screen.

Finally…the web socket is going to constantly check…every 3 seconds to see if there’s a graphic or not…and the display the related image…

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>

This one is going to be called by our express application and it will simply call the web socket to determine what it needs to display…it has some Javascript…that’s why we need PhantomJS to interact with it…

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);
});

Not the best and most describing name…but who cares -:P Anyway…this script will load the page…that is the express application…wait for 4 seconds for the Javascript to get generated and then create a web page called 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();
 }
    });

This script will simply read the stats.html page and return the text that it’s located inside the “p” tag…dead simple…

SETTING UP ALEXA

Creating the Lambda function


Now…we need to setup Alexa…so we can control everything via voice commands -:)

First…we need to go to Amazon Lambda and log in if you have an account…otherwise…please create one…and make sure you’re on the West Virginia region…


In the list of functions…look for color…


Choose the NodeJS one…Python has been included as well…but wasn’t when I started to work on this blog -:)


Here, just click next....


I already create the function…but you shouldn’t have a problem...


Basic execution role is more than enough…


This will provide a pop up window…simply press the “Allow” button and then “Create function”…we will include the source code later on…but notice the ARN generated number…because we’re going to need it on the next step…

Creating the Skill

Go to http://developer.amazon.com and log in…then choose Apps & Services --> Alexa --> Alexa Skills Set



Choose Alexa Skills Kit and fill the blanks...


As soon as we hit next an application number will be generated on a new field called Application ID. Grab this number as we’re going to need it for our application code.

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": "GetFlightsIntent",
      "slots": [
        {
          "name": "command",
          "type": "LITERAL"
        }
      ]
    },
    {
      "intent": "HelpIntent",
      "slots": []
    }
  ]
}

Our variable is going to be called “command” 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
GetFlightsIntent airports from {around the world|command}
GetFlightsIntent airports from {united states|command}
GetFlightsIntent flight distance from {carriers|command}
GetFlightsIntent {thank you|command}

The test section help us to say commands and see how Alexa responds…but we’re not going to do that here…we’re going to test it using a real Alexa device -;)

Forget about the Publishing Information section unless you really want to publish your application…
Create a folder call Flights…Alexa_Party…or whatever you fancy…then create a folder call src and copy this file in there…calling it AlexaSkills.js

We’re going to need to install only one library….”request”…

sudo npm install --prefix=~/Flights/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     = '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);
};

Time to explain what I was trying to do here -:P

The handleFlightsRequest method will manage the response that Alexa will spell out for us…and inside this method we can find getJsonFromFlights which will take the command defined in the our Intent Schema. This function will call our NodeJS server for the following commands…”thank you” will simply call the bye command….”around the world” will call the bye, map, stat and readstat commands…”united states” will call the bye, usmap, stat and readstat commands…finally carriers will call the bye, carriers, stat and readstat commands…

After 15 seconds (Yep…I know it’s too much but there are a lot of processes going on) Alexa will get the response message and simply speak it to us -;)

That’s pretty much it…now…I can show some images before we jump into the video…





Ok…enough…let’s watch this in real live action ;)





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.

miércoles, 9 de septiembre de 2015

Nest Thermostat and R - Creating a Shiny dashboard

This post was originally posted on Nest Thermostat and R - Creating a Shiny dashboard.



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

At the d-shop we're always looking forward to play with the latest technologies...a while the Nest Thermostat is not really "new", we're in the process of getting one.

For now, we are happy to be able to play a little bit with Nest Home Simulator available on the Google Chrome Store.

In this blog, we're going to use the Nest Home Simulator, the Statistics Programming Language R and the Shiny package, which allows us to create awesome web interfaces to manage data. Also, we're going to need the RJson package.

First step will be to create an account on the Nest Developer Program and the install the Nest Home Simulator.


Wen we log into the Simulator, we are going to be able to create a Thermostat to start playing around with the current and target temperatures...


The second important thing, is that when we are log into the Nest Developer Program we're going to be able to create a client which will access our thermostat and also, we will going to able to generate a unique number to communicate with it.


We need to just copy and paste the URL from the Authorization URL and after accepting the conditions a number will be presented...we need this number for our R code...but keep in mind that once the connection is closed, we will need to generate a new number...


Now, we're ready to add some code to the mix...when working with R, is always better to use RStudio...so copy and paste this code...and remember to replace the code variable with your own number...also you will need to replace the Client ID and Client Secret with the information from your Nest Developer Program Client code...

Nest_Dashboard.R
library("shiny")
library("rjson")

if(!exists("access_code")){
  code<-"XXX"
  info_data<-data.frame(Humidity=integer(),
  Current_Temperature=integer(),Target_Temperature=integer(),Times=character())
  access_code<-system(sprintf('curl -X POST 
  "https://api.home.nest.com/oauth2/access_token?client_id=XXX&code=%s&
  client_secret=XXX&grant_type=authorization_code"',code),intern=T)
  document<-fromJSON(access_code)
  access<-document$access_token
  devices<-paste("https://developer-api.nest.com/devices?auth=",access,sep="")
  all_devices<-system(sprintf('curl -L -X GET -H "Accept: application/json" "%s"',devices),intern=T)
  device<-gsub("thermostats|:|{|\"|humidity.*","",all_devices,perl=T)
  themostat_code<-paste("https://developer-api.nest.com/devices/thermostats/",device,"?auth=",access,sep="")
}

get_nest_info = function(info_data){
    thermostat<-system(sprintf('curl -L -X GET -H "Accept: application/json" "%s"',themostat_code),intern=T)
    info<-fromJSON(thermostat)
    timeframe<-Sys.time()
    timeframe<-gsub("\\d+-\\d+-\\d+\\s","",timeframe)
    new_data<-data.frame(Humidity=info$humidity,Current_Temperature=info$ambient_temperature_f,
    Target_Temperature=info$target_temperature_f,Times=timeframe,stringsAsFactors = F)
    if(nrow(info_data)==10){
      info_data<-info_data[-1,]
    }
    info_data<-rbind(info_data,new_data)
  return(info_data)
}

runApp(list(
  ui = pageWithSidebar(    
    
    headerPanel("Nest Dashboard"),
    
    sidebarPanel(
    ),
    
    mainPanel(
      plotOutput("nestPlot")
    )
  ),
  server =function(input, output, session) {
    autoInvalidate <- reactiveTimer(10000, session)
      output$nestPlot <- renderPlot({
        autoInvalidate()
        info_data<<-get_nest_info(info_data) 
        plot(info_data$Current_Temperature,type="n",axes=F,ann=F)
        lines(info_data$Current_Temperature,col="blue")
        lines(info_data$Target_Temperature,col="red")
        points(info_data$Current_Temperature, pch=21, bg="lightcyan", cex=1.25)
        points(info_data$Target_Temperature, pch=21, bg="lightcyan", cex=1.25)
        box()
        xy<-length(info_data$Times)
        axis(2, col.axis="blue", las=1)
        axis(1, at=1:xy, lab=info_data$Times, col.axis="purple")
        legend("topright",c("Current Temp","Target Temp"),lty=c(1,1),col=c("blue","red"),bty="n")
    })
  }
))

This code will get 10 readings until it refreshes itself to get 10 new ones. So we can update the Current and Target Temperature values in order to see the Dashboard changing...



Greetings,

Blag.
Development Culture.

lunes, 29 de junio de 2015

Exploring SparkR

A colleague from work, asked me to investigate about Spark and R. So the most obvious thing to was to investigate about SparkR -;)

I installed Scala, Hadoop, Spark and SparkR...not sure Hadoop is needed for this...but I wanted to have the full picture -:)

Anyway...I came across a piece of code that reads lines from a file and count how many lines have a "a" and how many lines have a "b"...

For this code I used the lyrics of Girls Not Grey by AFI...

SparkR.R
library(SparkR)

start.time <- Sys.time()
sc <- sparkR.init(master="local")
logFile <- "/home/blag/R_Codes/Girls_Not_Grey"
logData <- SparkR:::textFile(sc, logFile)
numAs <- count(SparkR:::filterRDD(logData, function(s) { grepl("a", s) }))
numBs <- count(SparkR:::filterRDD(logData, function(s) { grepl("b", s) }))
paste("Lines with a: ", numAs, ", Lines with b: ", numBs, sep="")
end.time <- Sys.time()
time.taken <- end.time - start.time
time.taken



0.3167355 seconds...pretty fast...I wonder how regular R will behave?

PlainR.R
library("stringr")

start.time <- Sys.time()
logFile <- "/home/blag/R_Codes/Girls_Not_Grey"
logfile<-read.table(logFile,header = F, fill = T)
logfile<-apply(logfile[,], 1, function(x) paste(x, collapse=" "))
df<-data.frame(lines=logfile)
a<-sum(apply(df,1,function(x) grepl("a",x)))
b<-sum(apply(df,1,function(x) grepl("b",x)))
paste("Lines with a: ", a, ", Lines with b: ", b, sep="")
end.time <- Sys.time()
time.taken <- end.time - start.time
time.taken


Nice...0.01522398 seconds...wait...what? Isn't Spark supposed to be pretty fast? Well...I remembered that I read somewhere that Spark shines with big files...

Well...I prepared a file with 5 columns and 1 million records...let's see how that goes...

SparkR.R
library(SparkR)

start.time <- Sys.time()
sc <- sparkR.init(master="local")
logFile <- "/home/blag/R_Codes/Doc_Header.csv"
logData <- SparkR:::textFile(sc, logFile)
numAs <- count(SparkR:::filterRDD(logData, function(s) { grepl("a", s) }))
numBs <- count(SparkR:::filterRDD(logData, function(s) { grepl("b", s) }))
paste("Lines with a: ", numAs, ", Lines with b: ", numBs, sep="")
end.time <- Sys.time()
time.taken <- end.time - start.time
time.taken



26.45734 seconds for a million records? Nice job -:) Let's see if plain R wins again...

PlainR.R
library("stringr")

start.time <- Sys.time()
logFile <- "/home/blag/R_Codes/Doc_Header.csv"
logfile<-read.csv(logFile,header = F)
logfile<-apply(logfile[,], 1, function(x) paste(x, collapse=" "))
df<-data.frame(lines=logfile)
a<-sum(apply(df,1,function(x) grepl("a",x)))
b<-sum(apply(df,1,function(x) grepl("b",x)))
paste("Lines with a: ", a, ", Lines with b: ", b, sep="")
end.time <- Sys.time()
time.taken <- end.time - start.time
time.taken


48.31641 seconds? Look like Spark was almost twice as fast this time...and this is a pretty simple example...I'm sure that when complexity arises...the gap is even bigger...

And sure...I know that a lot of people can take my plain R code and make it even faster than Spark...but...this is my blog...not theirs -;)

I will come back as soon as I learn more about SparkR -:D

UPDATE

So...I got a couple of comments claiming that read.csv() is too slow...and I should measuring the process not the loading of an csv file...while I don't agree...because everything is included in the process...I did something as simple as moving the start.time after the csv file is done...let's see how much of a change this brings...

SparkR

Around 1 second faster...which means that reading the csv was really efficient...


Plain R

Around 6 seconds faster...read.csv is not that good...but...SparkR is almost 50% faster...

HOLLY CRAP UPDATE!

 Markus from Spain gave me this code on the comments...I just added a couple of things to make complaint...but...damn...I wish I could code like that in R! -:D Thanks Markus!!!

Markus's code
logFile <- "/home/blag/R_Codes/Doc_Header.csv"
lines <- readLines(logFile)
start.time <- Sys.time()
a<-sum(grepl("a", lines, fixed=TRUE))
b<-sum(grepl("b", lines, fixed=TRUE))
paste("Lines with a: ", a, ", Lines with b: ", b, sep="")
end.time <- Sys.time()
time.taken <- end.time - start.time
time.taken


Simply...superb! -:)

Greetings,

Blag.
Development Culture.

viernes, 29 de agosto de 2014

LED is my new Hello World - R Time

Yep...as I have said many times before, the LED Number application has become my new Hello World...whenever I learn a new programming language I try to build this, because it compromises several language constructs and makes you learn more by trying to figure out how to build it again...

Yesterday I blog about how to build it using Haskell...and...I'm still learning Haskell...so I thought..."It's cool that I'm using this for my new programming languages...but what about the old ones?"

I suddenly realized that I had never wrote this using R...and that's really sad...I love R -:)

Anyway...here it goes -;)

LED.R
line<-c(1,2,3,1,2,3,1,2,3,1,2,3,1,2,3,1,2,3,1,2,3,1,2,3,1,2,3,1,2,3)
index<-c(0,0,0,1,1,1,2,2,2,3,3,3,4,4,4,5,5,5,6,6,6,7,7,7,8,8,8,9,9,9)
map<-c("  _ ","| | ","|_| ","  ","| ","| ","  _ "," _| ","|_  ",
       " _","_| ","_| ","    ","|_| ","  | ","  _ ","|_  "," _| ",
       "  _ ","|_  ","|_| "," _  "," |  "," |  ","  _ ","|_| ","|_| ",
       "  _ ","|_| "," _| ")

Lines<-cbind(line,index,map)
DF_Lines<-data.frame(Lines,stringsAsFactors=F)

line1<-""
line2<-""
line3<-""

p_number<-readline("Enter a number?: ")
l_number<-strsplit(p_number,"")
for(i in 1:nchar(p_number)){
  num_map<-DF_Lines[DF_Lines$index == as.numeric(l_number[[1]][i]),]
  line1<-paste(line1,num_map$map[1])
  line2<-paste(line2,num_map$map[2])
  line3<-paste(line3,num_map$map[3])
}
lines = paste(line1,"\n",line2,"\n",line3,"\n")
cat(lines)

Check the picture -;)


Greetings,

Blag.
Development Culture.

viernes, 8 de agosto de 2014

Bioinformatics with R Cookbook - Book Review

I just finished reading Bioinformatics with R Cookbook...so here's my review -:)



I was excited to read this book, because it's been a while since I read any R book...but...I gotta admit...this is not my kind of book...as I discovered that obviously I had minus one experience in Bioinformatics...

The book is not short but not long either...340 pages...and it's full of recipes...

It starts with a basic introduction to R, which should be appreciated by newbies...but for more season developers that just can be skipped out...

The are chapters dedicated to Sequence Analysis, Protein Structure Analysis and even Machine Learning in Bioinformatics...

Of course there's a lot of new packages that are used for the recipes and well as many interesting graphics...




If you have some knowledge of Bioinformatics...then you should for sure get this book...if you're not...well...you can buy it anyway...even if you don't understand anything...it is still a book about R and it's full of interesting codes...so you might end learning a bunch of new things -;)

The recipes are well explained and the result is always shown...which is good so we can know exactly what to expect...

Greetings,

Blag.
Development Culture.



viernes, 16 de mayo de 2014

Julia versus R - Playing around

So...as time goes by, I'm getting more proficient with Julia...which is something fairly easy as the learning curve is pretty fast...

I decided to load a file with 590,209 records that I got from Freebase...the file in question contains Actors and Actresses from movies...you can have a quick look here...


For this test, I'm using my Linux box on VMWare running on 2 GB of RAM...running Ubuntu 12.04.4 (Precise)

For R, I'm not using any special package...just plain R...version 2.14.1 and for Julia version 0.2.1, I'm using the DataFrames package...

Let's take a look at the R source code first along with its runtime processing...

Actors_Info.R
start.time <- Sys.time()
if(!exists("Actors")){
Actors<-read.csv("Actors_Table.csv", header=TRUE, 
                     stringsAsFactors=FALSE, colClasses="character", na.strings = "")
}
Actors<-unique(Actors)
Actors<-Actors[complete.cases(Actors),]
Actor_Info<-data.frame(Actor_Id=Actors$Actor_Id,Name=Actors$Name,Gender=Actors$Gender)
Actor_Info<-Actor_Info[order(Actor_Info$Gender),]
write.csv(Actor_Info,"Actor_Info_R.csv",row.names=TRUE)
end.time <- Sys.time()
time.taken <- end.time - start.time
time.taken

This source will first ask if the file was loaded already, if not...it will load it...then, it will eliminate the repeated records, delete all the null or NA's and the create a new Data Frame, sort it by "Gender" and then write a new CSV file...time will be taken to measure its speed...we will run it twice...first time the file is not loaded...second time it will...and that should improve greatly the execution time...



As we can see...the times are really good...and the different between the first and second run are pretty obvious...for the record...the generated file contains 105874 records...

Now...let's see the Julia version of the code...

Actors_Info.jl
using DataFrames
start = time()
isdefined(:Actors) || (Actors = readtable("Actors_Table.csv", header=true, nastrings=["","NA"]))
drop_duplicates!(Actors)
complete_cases!(Actors)
Actor_Info = DataFrame(Actor_Id=Actors["Actor_Id"],Name=Actors["Name"],Gender=Actors["Gender"])
sortby!(Actor_Info, [:Gender])
writetable("Actor_Info_Julia.csv", Actor_Info)
finish = time()
println("Time: ", finish-start)


Here...we're doing the same...we load the DataFrames package (But exclude that from the execution time), check if the file is loaded so we don't load it again on the second run...eliminate duplicates, delete all null or NA, create a new DataFrame, sort it by "Gender" and finally write a new CVS file...


Well...the difference between the second and first run is very significative...but of course...way slower than R...

But...let me tell you one simple thing...Julia is still a brand new language...the DataFrames package is not part of the core Julia language, which means...that its even newer...and optimizations are being performed as we speak...I would say that for a young language...18 seconds to process 590,209 records is pretty awesome...and of course...my R experience surpasses greatly my Julia experience...

So...I don't really want to leave you with the impression that Julia is not good or not fast enough...because believe me...it is...and you going to love my next experiment -;)

Let's take a look at the R source code first...

Random_Names.R
start.time <- Sys.time()
names<-c("Anne","Gigi","Blag","Juergen","Marek","Ingo","Lars","Julia",
         "Danielle","Rocky","Julien","Uwe","Myles","Mike", "Steven")

last_names<-c("Hardy","Read","Tejada","Schmerder","Kowalkiewicz","Sauerzapf",
              "Karg","Satsuta","Keene","Ongkowidjojo","Vayssiere","Kylau",
              "Fenlon","Flynn","Taylor")
full_names<-c()
for(i in 1:100000){
  name<-sample(1:15, 1)
  last_name<-sample(1:15, 1)
  full_name<-paste(names[name],last_names[last_name],sep=" ")
  full_names<-append(full_names,full_name)
}
end.time <- Sys.time()
time.taken <- end.time - start.time
time.taken

So this code is fairly simple...we have a couple of vectors with names and last names...then we loop 100000 times and then generate a couple of random numbers simply to read the vectors, create a full name and populate a new vector... with some random funny name combinations...



Well....the different between both runs is not really good...second time was a little bit higher...and 1 minute is kind of a lot...let's see how Julia behaves...

Here's the Julia source code...

Random_Numbers.jl
start = time()
names=["Anne","Gigi","Blag","Juergen","Marek","Ingo","Lars","Julia",
       "Danielle","Rocky","Julien","Uwe","Myles","Mike", "Steven"]
last_names=["Hardy","Read","Tejada","Schmerder","Kowalkiewicz","Sauerzapf",
            "Karg","Satsuta","Keene","Ongkowidjojo","Vayssiere","Kylau","Fenlon","Flynn","Taylor"]
full_names=String[]
full_name = ""
for i = 1:100000
        name=rand(1:15)
        last_name=rand(1:15)
        full_name = names[name] * " " * last_names[last_name]
        push!(full_names,full_name)
end
finish = time()
println("Time: ", finish-start)

So this code as well, creates two arrays with names and last names, do a loop 100000 times, generate a couple of random numbers, mix a name with a last name and then populate a new array with some mixed full names...


Just like in the R code...the second time took Julia a little bit more...but...less than a second?! That's something like...amazingly fast and really took R by storm...

Now...I believe you will start to take Julia more seriously -:D

Hope you liked this blog...

Greetings,

Blag.
Development Culture.