tag:blogger.com,1999:blog-41447043591770086922024-02-07T12:51:38.093-08:00Blag's bag of rantsMy Rants related to SAP, Scripting Languages, Technologies and everything else I wanted to talk about...Alvaro "Blag" Tejada Galindohttp://www.blogger.com/profile/12061593528820409779noreply@blogger.comBlogger305125tag:blogger.com,1999:blog-4144704359177008692.post-43218931976740837642022-05-18T03:50:00.001-07:002022-05-18T03:50:06.430-07:00What is Nylas, why did I join and why should you care?<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEixgOiVz4PdhikGGSbgeJb2Ul7FKwROnSQbAmJY4Uw05_HkQ7pi6w7XIIAqNprk4cf5mM7D6LIgT5gPpTDjgFm_UqWQGcSBsnYMinpkL0VBACrT7DL5j_GR0RQLcJTwntUJaqGbNQOhBZOwsko2WS-lBK30CArcEsrplqvvTUP6eDbuTS_RSysaYiF-7w/s2160/Office_Augmented.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1144" data-original-width="2160" height="338" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEixgOiVz4PdhikGGSbgeJb2Ul7FKwROnSQbAmJY4Uw05_HkQ7pi6w7XIIAqNprk4cf5mM7D6LIgT5gPpTDjgFm_UqWQGcSBsnYMinpkL0VBACrT7DL5j_GR0RQLcJTwntUJaqGbNQOhBZOwsko2WS-lBK30CArcEsrplqvvTUP6eDbuTS_RSysaYiF-7w/w640-h338/Office_Augmented.png" width="640" /></a></div><div><br /></div><div><br /></div>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.<div><br /><h2 style="text-align: left;">What is Nylas?</h2><br />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.<br /><br />In other words, we do the heavy work so you can focus on your business.<div><br /><div style="text-align: center;"><img height="296" src="https://media-exp1.licdn.com/dms/image/C5612AQGtdj9ryN6nHg/article-inline_image-shrink_1000_1488/0/1652866913964?e=1658361600&v=beta&t=yMVEwM6nJSptrtaYf9B24Vu_sgudqutmHisjOUxf0dI" width="400" /></div><br />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 <a href="https://www.nylas.com/products/email-api/">Universal Email API</a> page.<br /><div style="text-align: center;"><img height="258" src="https://media-exp1.licdn.com/dms/image/C5612AQGFVEl8whQaZA/article-inline_image-shrink_1500_2232/0/1652866978950?e=1658361600&v=beta&t=rViA5Fz4b4rT9K3_ITEy2fCBany3dZbf32gWRHchpH0" width="400" /></div><br />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 <a href="https://www.nylas.com/products/calendar-api/">Universal Calendar API</a> page.<br /><div style="text-align: center;"><img height="323" src="https://media-exp1.licdn.com/dms/image/C5612AQHHcb7qF2WM7w/article-inline_image-shrink_1500_2232/0/1652867010889?e=1658361600&v=beta&t=4MYwybLkCtXV1Qv1tGxVuxSwQuR8K_kJNaJladivf9c" width="400" /></div><br />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 <a href="https://www.nylas.com/products/contacts-api/">Universal Contacts API</a> page.</div><div><br /><div style="text-align: center;"><img height="323" src="https://media-exp1.licdn.com/dms/image/C5612AQEI7HJVkVGeLg/article-inline_image-shrink_1500_2232/0/1652867037867?e=1658361600&v=beta&t=S6L4ZGX6Hz07bvsReGaoNIRXXYpSr1DqskvaKMMPIC0" width="400" /></div><br />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.<br /><br />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 <a href="https://www.nylas.com/products/neural-api/">Neural API</a> page.</div><div><br /><div style="text-align: center;"><img height="323" src="https://media-exp1.licdn.com/dms/image/C5612AQGqRzS46VM4_Q/article-inline_image-shrink_1500_2232/0/1652867067736?e=1658361600&v=beta&t=TN3ECx92ve8BfBi-8byWOezxHlMa7xPld7TmRyhpP_k" width="400" /></div><br />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 <a href="https://www.nylas.com/products/nylas-streams">Nylas Streams</a> page.</div><div><br /><div style="text-align: center;"><img height="322" src="https://media-exp1.licdn.com/dms/image/C5612AQH-1EGZIvN1Yg/article-inline_image-shrink_1000_1488/0/1652867098565?e=1658361600&v=beta&t=DR474k31WZn64pMdqE_0cyHraLvGq1eg5hTXAuAO9VY" width="400" /></div><br />Scheduler, a full featured scheduler with customizable UI. If you want to learn, just go to <a href="https://www.nylas.com/products/nylas-scheduler">Scheduler</a>.</div><div><br /><div style="text-align: center;"><img height="323" src="https://media-exp1.licdn.com/dms/image/C5612AQGT-Vdiprfuqw/article-inline_image-shrink_1500_2232/0/1652867124175?e=1658361600&v=beta&t=3HZcqQ5fyaZbdqRmVhuGn3D8TOem3QtsRIbhlnN2o70" width="400" /></div><br />Components, ready made and fully flexible UI/UX widgets ready for immediate use. If you want to learn more, just go to <a href="https://www.nylas.com/products/components/">Components</a>.</div><div><br /><div style="text-align: center;"><img height="323" src="https://media-exp1.licdn.com/dms/image/C5612AQF5bgZPPVIdJQ/article-inline_image-shrink_1500_2232/0/1652867155386?e=1658361600&v=beta&t=ol27KZP4XeDBbAZ6tAWFWtrdKYzfv-GT3U1HABmXigw" width="400" /></div><h2 style="text-align: left;">Why did I join?</h2><br />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.<br /><br />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.<br /><br />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.<br /><br />Obviously, those 3 things might not be enough to convince you, so let’s create a small example.<br /><br />For this I’m going to choose one of my favorite Programming Languages– <a href="https://www.r-project.org/">R</a>. 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.<br /><br />What we are going to do is simply read the first three messages in my inbox and print the subjects.</div><div><br /><div style="text-align: center;"><img height="427" src="https://media-exp1.licdn.com/dms/image/C5612AQHnD3wGDtYoVw/article-inline_image-shrink_1000_1488/0/1652867258947?e=1658361600&v=beta&t=10HjI8mhJzp6QGmDQawIbliYrVJWYnxkK_6FjjBMXAU" width="640" /></div><br />The result is going to be:</div><div><br /></div><div><blockquote>A Nylas email </blockquote><blockquote>
Invitation: RRSP Webinar @ Tue Feb 8, 2022 1pm - 2pm (EST) (alvaro.t@nylas.com) </blockquote><blockquote>
Start here: Welcome to Clockwise</blockquote><br />Obviously, while R is an awesome language used by statisticians and data scientists around the world, it is not a mainstream language.<br /><br />That’s why Nylas provides us with SDKs for <a href="https://developer.nylas.com/docs/developer-tools/sdk/python-sdk/">Python</a>, <a href="https://developer.nylas.com/docs/developer-tools/sdk/ruby-sdk/">Ruby</a>, <a href="https://developer.nylas.com/docs/developer-tools/sdk/node-sdk/">Node</a>, and <a href="https://developer.nylas.com/docs/developer-tools/sdk/java-sdk/">Java</a>.<br /><br />Let’s see how we can read our inbox using the <a href="https://www.python.org/">Python</a> SDK. If you want to learn how to install the SDK, read our <a href="https://developer.nylas.com/docs/developer-tools/sdk/python-sdk/">Python Documentation</a>.</div><div><br /><div style="text-align: center;"><img height="445" src="https://media-exp1.licdn.com/dms/image/C5612AQGnsnXNDGZOrQ/article-inline_image-shrink_1000_1488/0/1652867385197?e=1658361600&v=beta&t=rmWtGCj1Isvefwlgt8JxedIIurLjXJzmRPkWvPvMSL8" width="640" /></div><br />The result is going to be:</div><div><br /></div><div><blockquote>A Nylas email </blockquote><blockquote>
Invitation: RRSP Webinar @ Tue Feb 8, 2022 1pm - 2pm (EST) (alvaro.t@nylas.com) </blockquote><blockquote>
Start here: Welcome to Clockwise</blockquote><br />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.<br />Why should you care?<br /><br />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 <a href="https://dashboard.nylas.com/register">https://dashboard.nylas.com/register</a> and follow the instructions.<br /><br />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.<br /><br />You can start by reading my blog <a href="https://www.nylas.com/blog/how-to-send-emails-with-the-nylas-python-sdk/">How to Send Emails with the Nylas Python SDK</a><br /><br />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.</div></div>Alvaro "Blag" Tejada Galindohttp://www.blogger.com/profile/12061593528820409779noreply@blogger.com0tag:blogger.com,1999:blog-4144704359177008692.post-27924166831104801562019-01-26T04:34:00.001-08:002019-01-26T04:34:45.679-08:00A Vector Inside<div style="text-align: justify;">
When I finished my blog called “<a href="http://blagrants.blogspot.com/2018/12/hey-vector-who-do-i-look-like.html" target="_blank">Hey Vector, who do I look like?</a>” using Anki’s Vector and SAP Leonardo’s Machine Learning APIs…I started thinking about what I should work on next…at first…I was obviously running low on ideas…but then…all of a sudden…a nice idea came to me…what if we could control Vector…from the inside? I mean…what if we could simulate that we are inside Vector and that we can see through his eyes and make him move…</div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
That’s how this project started 😉</div>
<div>
<h2 style="text-align: justify;">
<b><br /></b></h2>
<h2 style="text-align: justify;">
<b>The Idea</b></h2>
</div>
<div style="text-align: justify;">
<br />
So, I knew I wanted to be able to control Vector…I could use Amazon Alexa, but of course…that would leave the “inside” part out…so that was not a choice…then I thought about using Unreal Engine…as I used it on my blog <a href="http://blagrants.blogspot.com/2018/09/sap-leonardo-machine-learning-apis-on-go.html" target="_blank">“SAP Leonardo Machine Learning APIs on the Go”</a> where I used SAP Machine Learning APIs, Unreal Engine and Oculus Go to showcase the APIs on SAP Leonardo. Using Unreal Engine and Oculus Go seemed like the perfect combination, so I started working on it.</div>
<div style="text-align: justify;">
<h2>
<b><br /></b></h2>
<h2>
<b>What are we going to use?</b></h2>
<div>
<br />
I know that I mentioned many things…so let’s get more information about them 😉</div>
<div>
<br /></div>
<h3>
<b>Vector</b></h3>
<div>
<span style="font-family: "calibri" , sans-serif; font-size: 12.0pt; line-height: 107%;">Anki’s
next evolution of <a href="https://www.anki.com/en-ca/cozmo" target="_blank">Cozmo</a></span><span style="font-family: "calibri" , sans-serif; font-size: 12.0pt; line-height: 107%;">. <a href="https://www.anki.com/en-ca/vector" target="_blank">Vector</a> packs not only more power and more independence but also a microphone, so you
can finally talk to him </span><span style="font-family: "segoe ui emoji" , sans-serif; font-size: 12.0pt; line-height: 107%;">😉</span><span style="font-family: "calibri" , sans-serif; font-size: 12.0pt; line-height: 107%;"> and it also comes with Amazon Alexa…so it’s
just an amazing little robot…</span></div>
<div>
<span style="font-family: "calibri" , sans-serif; font-size: 12.0pt; line-height: 107%;"><br /></span></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEisSGk8x5-zah5CNt4zsiJjSGjmylsn-Hk1RbJRa6Z-HDbApL1qtNQ9iP2qmundBPAz1fUGF7ugdTIuGx_zU37UMGlo7OvgrqqJB8abiHOrHj1KaM7mE-EYXQ7LRgkKlKo-d_X7ntyEiw1M/s1600/AnkiVector.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="320" data-original-width="320" height="200" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEisSGk8x5-zah5CNt4zsiJjSGjmylsn-Hk1RbJRa6Z-HDbApL1qtNQ9iP2qmundBPAz1fUGF7ugdTIuGx_zU37UMGlo7OvgrqqJB8abiHOrHj1KaM7mE-EYXQ7LRgkKlKo-d_X7ntyEiw1M/s200/AnkiVector.jpg" width="200" /></a></div>
<h3>
<span style="font-family: "calibri" , sans-serif; font-size: 12pt; line-height: 107%;">Unreal Engine</span></h3>
<div>
<span style="line-height: 107%;"><span style="font-family: "calibri" , sans-serif;"><a href="https://www.unrealengine.com/en-US/what-is-unreal-engine-4" target="_blank">Unreal Engine</a> is without a doubt “The most powerful creating engine”. Can be programmed using C++ or Blueprints (Visual Programming) and the best of all…it’s totally free! Unless you make a commercial game that sells…then they ask only for the 5%</span></span></div>
<div>
<span style="font-family: "calibri" , sans-serif; font-size: 12.0pt; line-height: 107%;"><br /></span></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg6EkdA101yGjLifPTqlSMv5vkc3YyGT6DDBT20Lflzvj3oSXWpHFxTJSeKmzZrInUpYsQ93ApNu2izZOioH476CnIqbUXdNya-Mx3pl_3SUf-K9dNpCCwgxY53OHXHQMTzNcUWYZrbWoQ-/s1600/ue4.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="720" data-original-width="1280" height="180" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg6EkdA101yGjLifPTqlSMv5vkc3YyGT6DDBT20Lflzvj3oSXWpHFxTJSeKmzZrInUpYsQ93ApNu2izZOioH476CnIqbUXdNya-Mx3pl_3SUf-K9dNpCCwgxY53OHXHQMTzNcUWYZrbWoQ-/s320/ue4.jpg" width="320" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<h3 style="clear: both; text-align: justify;">
<b>Blender</b></h3>
<div class="separator" style="clear: both; text-align: justify;">
<a href="https://www.blender.org/" target="_blank">Blender</a> is an Open Source 3D Creation Suit. Modeling, rigging, animation, simulation, rendering and a long etcetera…bundled with version 2.8, comes EEVEE (Extra Easy Virtual Environment Engine) a real time rendering engine.</div>
<div>
<span style="font-family: "calibri" , sans-serif; font-size: 12.0pt; line-height: 107%;"><br /></span></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiZZP8Ssk8kZp0TYW79AKJyq-u4Po8Ku_le9sqjet-_F4sDJLARFxBkZOBguApufu9jLLbhq1LYjNBkWQ1v82ZlpksP89k-ZsHH1aZqBkmEUALeHTsDukZhjzhvmRqsDrowGlIXQXFngEge/s1600/Blender28Beta.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="865" data-original-width="1600" height="173" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiZZP8Ssk8kZp0TYW79AKJyq-u4Po8Ku_le9sqjet-_F4sDJLARFxBkZOBguApufu9jLLbhq1LYjNBkWQ1v82ZlpksP89k-ZsHH1aZqBkmEUALeHTsDukZhjzhvmRqsDrowGlIXQXFngEge/s320/Blender28Beta.jpg" width="320" /></a></div>
<div>
<br /></div>
<div>
<h3>
<span style="font-family: "calibri" , sans-serif; font-size: 12.0pt; line-height: 107%;"><b>HANA Cloud Platform</b></span></h3>
</div>
<div>
<span style="line-height: 107%;"><span style="font-family: "calibri" , sans-serif;">SAP’s In-Memory, column-oriented database running on the cloud. That includes Predictive Analysis, Spatial Data Processing, Text Analysis and much more. Also, it’s blazing fast 😉</span></span><br />
<span style="line-height: 107%;"><span style="font-family: "calibri" , sans-serif;"><br /></span></span>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg3lxT4RUloQ2PHEXHLD1jNiJH04lfAQgpvnpU3ZcmnRjcyS1V5DiRsoIBzHgZ0zXmV95WTld1c2UBF932DQRXayyqOKVgXi6bFDK_hGMRAgM_yTS6It4C37dbeOENT02QFJEM05RJaMMVm/s1600/SAPHANA.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="435" data-original-width="800" height="174" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg3lxT4RUloQ2PHEXHLD1jNiJH04lfAQgpvnpU3ZcmnRjcyS1V5DiRsoIBzHgZ0zXmV95WTld1c2UBF932DQRXayyqOKVgXi6bFDK_hGMRAgM_yTS6It4C37dbeOENT02QFJEM05RJaMMVm/s320/SAPHANA.png" width="320" /></a></div>
<h3>
<span style="line-height: 107%;"><span style="font-family: "calibri" , sans-serif;"><b>Python3</b></span></span></h3>
<span style="line-height: 107%;"><span style="font-family: "calibri" , sans-serif;">Interpreted, high-level, general-purpose programming language. It’s the language chosen to code Vector.</span></span><br />
<span style="line-height: 107%;"><span style="font-family: "calibri" , sans-serif;"><br /></span></span>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiEMm_LgD56X4kU0PLvCwvOsv8iVv2L4qL-eA9d4u98PeKMrEfuc-qtRkvux7kwLzJhFbJIooANxXYCncyNHwoq6W1uNNpsSy-72LKVE_Tqfru-1PRdtjB6x-OLzwqjhpdpUhPMQbK4h-y-/s1600/PythonLogo.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="203" data-original-width="601" height="108" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiEMm_LgD56X4kU0PLvCwvOsv8iVv2L4qL-eA9d4u98PeKMrEfuc-qtRkvux7kwLzJhFbJIooANxXYCncyNHwoq6W1uNNpsSy-72LKVE_Tqfru-1PRdtjB6x-OLzwqjhpdpUhPMQbK4h-y-/s320/PythonLogo.png" width="320" /></a></div>
<h2>
<span style="line-height: 107%;"><span style="font-family: "calibri" , sans-serif;"><br /></span></span></h2>
<h2>
<span style="line-height: 107%;"><span style="font-family: "calibri" , sans-serif;">The First Problem</span></span></h2>
<span style="font-family: "calibri" , sans-serif;"><br /></span>
<span style="font-family: "calibri" , sans-serif;">As I wanted to see through Vector’s eyes…I needed to display Vector’s video feed on Unreal Engine…I spend some time thinking about how to do that…but in the end I remembered that when you use Microsoft HoloLens and pair it to your laptop for “streaming”, there’s always a delay of 1 or 2 seconds…then of course I remembered that videos are just hundreds of images that are displayed in sequence in a very fast way…I didn't care too much about speed or being close to real time…having a 1 or 2 seconds delay…it’s not a bad thing at all…</span><br />
<span style="font-family: "calibri" , sans-serif;"><br /></span>
<span style="font-family: "calibri" , sans-serif;">Well…the problems continued…I knew that I wanted Vector to take a picture every 1 or 2 seconds…and then that picture should reach Unreal Engine…and despite the fact that I code in Python on my Ubuntu Virtual Machine and Unreal Engine on my regular Windows laptop…I wasn't too sure on sending the image as a file…so…I got the idea of encoding it as Base 64 (Which yes…increases the size…but at least gives you a huge string to deal with) and send it…but how? Well…SAP Cloud Platform is an in-memory database…so it’s pretty fast…why not create a table and some REST APIs to deal with the creation, view and deletion of records…</span><br />
<span style="font-family: "calibri" , sans-serif;"><br /></span>
<span style="line-height: 107%;"><span style="font-family: "calibri" , sans-serif;"></span></span><br />
<span style="font-family: "calibri" , sans-serif;">Every time Vector takes a picture...it gets converted to Base 64 and then send to the cloud, then Unreal Engine read the API, decode the Base 64 back to an image and display it…that lead to the second problem…</span></div>
<h2>
</h2>
<h2>
The Second Problem</h2>
<div>
<div>
<br />
How do I encode a Base 64 image on Unreal Engine? While I know how to use C++ very well…when it comes to Unreal Engine I mostly use Blueprints, which is visual programming and while underneath is C++ not everything is implemented…</div>
<div>
<br /></div>
<div>
Gladly, a quick visit to Unreal’s documentation gave me an answer in the form of a Base 64 encoding/decoding function…but in C++ of course…</div>
<div>
<br /></div>
<div>
But…the good thing about Unreal Engine is that you can create a C++ project…implement your Base 64 encoder class and then start creating Blueprints to consume it…another problem tackled…</div>
<div>
<br /></div>
<div>
That’s what I thought…but then I realized that it wasn’t just a matter of having the picture back as a picture…I actually needed a dynamic material where I could display the images…I browse the web and found some interesting articles…but nothing that could really helped me…in the end…I grab pieces from here and there and my own research…and managed to make it work…</div>
<div>
<br /></div>
<div>
And yes…if you’re wondering…there was another problem…</div>
</div>
<h2>
</h2>
<h2>
The Third Problem</h2>
<div>
<div>
<br />
Everything was nice and dandy…I test my solution…initial by passing some images in sequence to the cloud and then to Unreal and then using Vector…with a delay of 1 or 2 seconds…it looked like a video running on an old smartphone on a cheap Internet connection in the middle of the desert…good enough for me 😉</div>
<div>
<br /></div>
<div>
But…we were supposed to be inside Vector, right? How was I supposed to simulate that? After not too much thinking…I decided to use Blender 2.8 which is on Beta right now 😊 and that comes with EEVEE (Which is an awesome real-time renderer). I made a small “control” room…with some fancy button and panels…a chair where you can seat while controlling “Vector” and a big screen to see what Vector is seeing….</div>
<div>
<br /></div>
<div>
Baking is not working right now…or at least I’m too dumb to figure out how to use it on 2.8 so using textures on Cycles was out of the question…so…I made a test on EEVEE using just plain materials…export them as .FBX and they worked like a charm! So, I stared working and test it on Unreal…of course…I’m not a Blender expert, so while everything looks nice…not all the colors are rendered correctly ☹ At least it looks fairly decent 😉</div>
</div>
<h2>
</h2>
<h2>
No more problems</h2>
<div>
<br />
Yep…not that everything went nice and smoothly…but at least those were the most critical problems…so now we can actually start with the blog -:P </div>
<h2>
</h2>
<h2>
Blender and The Control Room</h2>
<div>
<div>
<br />
As I said…I used EEVEE rendering on Blender 2.8 Beta to create a control room that would somehow, give the impression of being inside Vector…of course…totally and completely a poetic version because a) Who know how Vector looks inside? b) I don’t think there’s enough room inside vector to fit anything else…</div>
<div>
<br /></div>
<div>
First, I started by putting some buttons, knobs and keys to a panel…then I added some sort of radars along with sliders…</div>
</div>
<div>
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiyC1vtX0K5aAl92Nh0qMXB45e5SbFc_Q3HQ4VOMcDoQJZQfO8CQN2jCkGYFFTX0YoOZF34QDC9W9r5_SfGHk0R5HHwYViMJf-m7SG1gUB4vi-bymjEN0d9TBRR1pph9-xpw4kI6CoyDpJ4/s1600/InsideCozmoPanels.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="900" data-original-width="1600" height="180" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiyC1vtX0K5aAl92Nh0qMXB45e5SbFc_Q3HQ4VOMcDoQJZQfO8CQN2jCkGYFFTX0YoOZF34QDC9W9r5_SfGHk0R5HHwYViMJf-m7SG1gUB4vi-bymjEN0d9TBRR1pph9-xpw4kI6CoyDpJ4/s320/InsideCozmoPanels.png" width="320" /></a></div>
<div>
<br /></div>
<div>
Then, I thought some switches and multi-colored buttons would make a nice addition…</div>
<div>
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhAUi5soetuuvO5IZsqTUA6TZOOoSnvM1pa05vMdjg0m3xQXuibXk6wXbdq2ZEr_DhQfcue-SadbCVePV7pjmifSYJ5CdY6TpYNjmgYB9cP6en32TkfmcmJzhc4ljU9RXMSPRLghu6jyCMv/s1600/InsideCozmoControls.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="900" data-original-width="1600" height="180" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhAUi5soetuuvO5IZsqTUA6TZOOoSnvM1pa05vMdjg0m3xQXuibXk6wXbdq2ZEr_DhQfcue-SadbCVePV7pjmifSYJ5CdY6TpYNjmgYB9cP6en32TkfmcmJzhc4ljU9RXMSPRLghu6jyCMv/s320/InsideCozmoControls.png" width="320" /></a></div>
<div>
<br /></div>
<div>
Finally, I added a chair…because you need to sit somewhere, right?</div>
<div>
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgQxOtMEXH-Z8hEHRGV73qMJMxrJwWgnm3_h97cJ37YBlUlk1bff11kpOMWFB3MjFLuw7HzLi6bZqf8o3IVluNbmuwzw9_cWF67I59oKVESKS1dSZvjoYUNMbXmFrqmi6-HZEQgfX3OSNlf/s1600/InsideCozmoChair.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="900" data-original-width="1600" height="180" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgQxOtMEXH-Z8hEHRGV73qMJMxrJwWgnm3_h97cJ37YBlUlk1bff11kpOMWFB3MjFLuw7HzLi6bZqf8o3IVluNbmuwzw9_cWF67I59oKVESKS1dSZvjoYUNMbXmFrqmi6-HZEQgfX3OSNlf/s320/InsideCozmoChair.png" width="320" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: justify;">
The screen is just a white space…pretty much like in a cinema…</div>
<div class="separator" style="clear: both; text-align: justify;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh0D0ofo5oNJzUzsdu__DTCPdvN3UtYuWERPErNsP9TTYnCnOhqQnxzvmfNnKSIIzM-nKqDQwXbW3OHSxk1Lk9gAcm04xsuje8TWjoxJ33wt1LBxqBYHsTGu-sjaCWXYhal89hg0zjzStSS/s1600/InsideCozmoScreen.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="900" data-original-width="1600" height="180" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh0D0ofo5oNJzUzsdu__DTCPdvN3UtYuWERPErNsP9TTYnCnOhqQnxzvmfNnKSIIzM-nKqDQwXbW3OHSxk1Lk9gAcm04xsuje8TWjoxJ33wt1LBxqBYHsTGu-sjaCWXYhal89hg0zjzStSS/s320/InsideCozmoScreen.png" width="320" /></a></div>
<div class="separator" style="clear: both; text-align: justify;">
<br /></div>
<div class="separator" style="clear: both; text-align: justify;">
Look, pretty cool on Blender, right? Well…not so much on Unreal…not ugly…but certainly not optimized…probably due to the fact that I merged everything together and exported as a big chunk…but that’s fine…I’m not changing that…I’m lazy 😊</div>
<div class="separator" style="clear: both; text-align: justify;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi87oJGGhvYlC8cahmRQfK-QzBQjsXMb5f9GDvDfMsGtcxbvDBjKsIGTkah-Ljhm6lFOmIT0XjR9i2mS6sIGQ3H7Zfa4d2heBMYv_eorAdIrDg9u7IxIQUP19QavYxt-zu3juy1-veHv6p0/s1600/UnrealVector.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="666" data-original-width="1287" height="165" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi87oJGGhvYlC8cahmRQfK-QzBQjsXMb5f9GDvDfMsGtcxbvDBjKsIGTkah-Ljhm6lFOmIT0XjR9i2mS6sIGQ3H7Zfa4d2heBMYv_eorAdIrDg9u7IxIQUP19QavYxt-zu3juy1-veHv6p0/s320/UnrealVector.jpg" width="320" /></a></div>
<div class="separator" style="clear: both; text-align: justify;">
<br /></div>
<div class="separator" style="clear: both;">
You see…not perfect…but not that bad either 😉</div>
<div class="separator" style="clear: both;">
<br /></div>
<div class="separator" style="clear: both;">
Here’s the <a href="http://blagarts.com/files/InsideCozmo.fbx" target="_blank">.FBX file</a></div>
<h2 style="clear: both;">
</h2>
<h2 style="clear: both;">
Creating the Tables and APIs on HANA Cloud Platform</h2>
<div class="separator" style="clear: both;">
<br /></div>
<div class="separator" style="clear: both;">
Next step…I created two tables on HANA Cloud Platform…I called the first table <b>“VECTOREYES”</b> because it’s the table that will hold the Base 64 images. Here’s the script to create it…</div>
<div class="separator" style="clear: both;">
<br /></div>
<table align="center" style="width: 600px;">
<tbody>
<tr><th bgcolor="#6690BC"></th>
</tr>
<tr>
<td><pre>CREATE COLUMN TABLE "I830502"."VECTOREYES"(
"TIMESTAMP" LONGDATE CS_LONGDATE NOT NULL,
"VECTOREYE" CLOB MEMORY THRESHOLD 3000,
PRIMARY KEY (
"TIMESTAMP"
)
) UNLOAD PRIORITY 5 AUTO MERGE;
</pre>
</td>
</tr>
<tr>
</tr>
</tbody></table>
<br />
For the primary key I used a TIMESTAMP basically because if something happens in terms of connection there would be no primary key clashes…<br />
<br />
The next table will be called <b>“VECTORCOMMAND”</b> and will hold…the commands that will send to Vector…<br />
<br />
<table align="center" style="width: 600px;">
<tbody>
<tr><th bgcolor="#6690BC"></th>
</tr>
<tr>
<td><pre>CREATE COLUMN TABLE "I830502"."VECTORCOMMAND"(
"NID" INTEGER CS_INT,
"COMMAND" NVARCHAR(50),
PRIMARY KEY (
"NID"
)
) UNLOAD PRIORITY 5 AUTO MERGE;
</pre>
</td>
</tr>
<tr>
</tr>
</tbody></table>
<br />
In this case…there’s going to be always one command…so I used a single integer primary key.<br />
<br />
With the tables created, we can generate our XS Engine package…and simply call it <b>“VectorEyes”</b>.<br />
<br />
Create the following files…<br />
<div>
<br /></div>
<table align="center" style="width: 600px;">
<tbody>
<tr><th bgcolor="#6690BC">.xsaccess</th>
</tr>
<tr>
<td><pre>{
"exposed" : true,
"authentication" :
{
"method": "Basic"
},
"cache_control" : "must-revalidate",
"cors" :
{
"enabled" : true,
"allowMethods": [
"GET",
"POST",
"HEAD",
"OPTIONS"
]
},
"enable_etags" : false,
"force_ssl" : false,
"prevent_xsrf" : false
}
</pre>
<pre></pre>
<pre></pre>
</td>
</tr>
<tr>
</tr>
</tbody></table>
<table align="center" style="width: 600px;">
<tbody>
<tr><th bgcolor="#6690BC">.xsapp</th>
</tr>
<tr>
<td><pre></pre>
</td>
</tr>
<tr>
</tr>
</tbody></table>
<br />
Yep…not a typo…this is actually totally and completely empty…
<br />
<br />
<br />
<table align="center" style="width: 600px;">
<tbody>
<tr><th bgcolor="#6690BC">AddVectorEye.xsjs</th>
</tr>
<tr>
<td><pre>$.response.contentType = "text/html";
var conn = $.db.getConnection();
var content = $.request.body.asString();
content = JSON.parse(content);
var st = conn.prepareStatement("INSERT INTO \"YourSchema\".\"VECTOREYES\" values(?,?)");
st.setString(1,content.timestamp);
st.setString(2,content.vectoreye);
st.execute();
conn.commit();
st.close();
conn.close();
</pre>
</td>
</tr>
<tr>
</tr>
</tbody></table>
<br />
<table align="center" style="width: 600px;">
<tbody>
<tr><th bgcolor="#6690BC">GetAddVectorEye.xsodata</th>
</tr>
<tr>
<td><pre>service namespace "YourSchema"{
"YourSchema"."VECTOREYES" as "vectoreye";
}
</pre>
<pre></pre>
</td>
</tr>
<tr>
</tr>
</tbody></table>
<table align="center" style="width: 600px;">
<tbody>
<tr><th bgcolor="#6690BC">DeleteVectorEye.xsjs</th>
</tr>
<tr>
<td><pre>$.response.contentType = "text/html";
var conn = $.db.getConnection();
var st = conn.prepareStatement("DELETE FROM \"YourSchema\".\"VECTOREYES\"");
st.execute();
conn.commit();
st.close();
conn.close();
</pre>
</td>
</tr>
<tr>
</tr>
</tbody></table>
<br />
With that, we can insert, read and delete the <b>VECTOREYES</b> table. Let’s continue with <b>VECTORCOMMAND</b> table files…
<br />
<br />
<table align="center" style="width: 600px;">
<tbody>
<tr><th bgcolor="#6690BC">AddVectorCommand.xsjs</th>
</tr>
<tr>
<td><pre>$.response.contentType = "text/html";
var nid = $.request.parameters.get("nid");
var command = $.request.parameters.get("command");
var conn = $.db.getConnection();
var st = conn.prepareStatement("INSERT INTO \"YourSchema\".\"VECTORCOMMAND\" values(?,?)");
st.setString(1,nid);
st.setString(2,command);
st.execute();
conn.commit();
st.close();
conn.close();
</pre>
</td>
</tr>
<tr>
</tr>
</tbody></table>
<br />
<br />
<table align="center" style="width: 600px;">
<tbody>
<tr><th bgcolor="#6690BC">GetVectorCommand.xsodata</th>
</tr>
<tr>
<td><pre>service namespace "YourSchema"{
"YourSchema"."VECTORCOMMAND" as "vectorcommand";
}
</pre>
</td>
</tr>
<tr>
</tr>
</tbody></table>
<br />
<br />
<table align="center" style="width: 600px;">
<tbody>
<tr><th bgcolor="#6690BC">DeleteVectorCommand.xsjs</th>
</tr>
<tr>
<td><pre>$.response.contentType = "text/html";
var conn = $.db.getConnection();
var st = conn.prepareStatement("DELETE FROM \"YourSchema\".\"VECTORCOMMAND\"");
st.execute();
conn.commit();
st.close();
conn.close();
</pre>
</td>
</tr>
<tr>
</tr>
</tbody></table>
<br />
That’s it 😊 We simply need to activate it and test it…for sure <a href="https://www.getpostman.com/" target="_blank">Postman</a> is the way to go 😉
<br />
<br />
<h2>
Creating our Unreal Engine project</h2>
<br />
As I mentioned earlier...I created an empty C++ Project using Mobile/Tablet, Scalable 3D or 2D and No starter content. I used Unreal Engine version 4.21.1 and called the project <b>“VectorOculusGo”</b><br />
<b><br /></b>
<br />
<div>
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiCosPxNFX-ISKfNej7wHhLZgf73XPnDAiiXmOid5ee1sBUInG2vHKbutw9jB3xAXsXK79OlIMFrc8gvW80KgEdjstF8ZkFUAfl7wG5AtKP7bMM-H6N_2RSBEVriCwGHb3ikEKt8d8_HjBn/s1600/UE_SetupProject.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="635" data-original-width="797" height="254" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiCosPxNFX-ISKfNej7wHhLZgf73XPnDAiiXmOid5ee1sBUInG2vHKbutw9jB3xAXsXK79OlIMFrc8gvW80KgEdjstF8ZkFUAfl7wG5AtKP7bMM-H6N_2RSBEVriCwGHb3ikEKt8d8_HjBn/s320/UE_SetupProject.jpg" width="320" /></a></div>
<div>
<br /></div>
<div>
When the project is open, I selected <b>“File --> New C++ Class”</b>, and chose <b>“Actor”</b>.</div>
<div>
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjOPW5b7aHx791_IE227M3ZW8swI0cxyHebBWFL50qgCd3oNhyphenhyphenhR4IRTktYUaVdQUf51D2nOaZ8gp6UyqVaqfZnZPLTvyPLSC9A8Emc7M_fSlKbLEzcofCIIQOOJ62NjrInaAutFzFjRPHC/s1600/UE_ActorClass.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="568" data-original-width="946" height="192" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjOPW5b7aHx791_IE227M3ZW8swI0cxyHebBWFL50qgCd3oNhyphenhyphenhR4IRTktYUaVdQUf51D2nOaZ8gp6UyqVaqfZnZPLTvyPLSC9A8Emc7M_fSlKbLEzcofCIIQOOJ62NjrInaAutFzFjRPHC/s320/UE_ActorClass.jpg" width="320" /></a></div>
<div>
<br /></div>
<div>
I called the class <b>“ImageParser”</b> and used the following code for <b>“ImageParser.h”</b> and <b>“ImageParser.cpp”</b></div>
<div>
<b><br /></b></div>
<table align="center" style="width: 600px;">
<tbody>
<tr><th bgcolor="#6690BC">ImageParser.h</th>
</tr>
<tr>
<td><pre>#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "ImageParser.generated.h"
UCLASS()
class VECTOROCULUSGO_API AImageParser : public AActor
{
GENERATED_BODY()
public:
// Sets default values for this actor's properties
AImageParser();
protected:
// Called when the game starts or when spawned
virtual void BeginPlay() override;
public:
// Called every frame
virtual void Tick(float DeltaTime) override;
UFUNCTION(BlueprintCallable, Category = "ImageParser")
void ParseImage(FString encoded, TArray<uint8> &decoded);
};
</uint8></pre>
</td>
</tr>
<tr>
</tr>
</tbody></table>
<br />
Here we’re creating a function that can be called via Blueprints. It will receive a String and will return an array of integers.<br />
<br />
<table align="center" style="width: 600px;">
<tbody>
<tr><th bgcolor="#6690BC">ImageParser.cpp</th>
</tr>
<tr>
<td><pre>#include "ImageParser.h"
#include "Misc/Base64.h"
// Sets default values
AImageParser::AImageParser()
{
// Set this actor to call Tick() every frame. </pre>
<pre> // You can turn this off to improve performance if you don't need it.
PrimaryActorTick.bCanEverTick = true;
}
// Called when the game starts or when spawned
void AImageParser::BeginPlay()
{
Super::BeginPlay();
}
// Called every frame
void AImageParser::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);
}
void AImageParser::ParseImage(FString encoded, TArray<uint8> &decoded)
{
FBase64::Decode(encoded, decoded);
}
</uint8></pre>
</td>
</tr>
<tr>
</tr>
</tbody></table>
<br />
Here, we simply call the Decode method from the Base64 library. This will grab the Base 64 string and converted back into an image.<br />
<br />
In order to compile, we just need to right-click on the project name and select <b>“Debug --> Start new instance”</b>.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgUwZceYVywB7TP3AmXU6vX6XEMA0Mgjsk-s1kSMQ5S0V542B8ILALTuHJkhf0wMC2Juqnmw-u9JTVdTx4a_KJGcdRiyOhHv13_nZ5UK8nNLxoZ4430AaYh8CDXnh50JlUr8t_Mo7NpvvSl/s1600/Compile.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="73" data-original-width="563" height="41" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgUwZceYVywB7TP3AmXU6vX6XEMA0Mgjsk-s1kSMQ5S0V542B8ILALTuHJkhf0wMC2Juqnmw-u9JTVdTx4a_KJGcdRiyOhHv13_nZ5UK8nNLxoZ4430AaYh8CDXnh50JlUr8t_Mo7NpvvSl/s320/Compile.jpg" width="320" /></a></div>
<br />
After the compilation is done, we can simply stop the debugging.<br />
<br />
Before we continue…we need to download a library to manage Rest APIs…it’s called <a href="https://github.com/Stefander/JSONQuery" target="_blank">JSONQuery</a> and it’s amazing!<br />
<br />
Simply close Unreal, go to the project folder and create a new folder called <b>“Plugins”</b>, then download the .zip, unzip it inside the <b>“Plugins”</b> folder file and delete the <b>Binaries</b> and <b>Intermediate</b> folders.<br />
<br />
Then, you will need to change the source code a little bit…<br />
<br />
Inside the <b>“JSONQuery”</b> folder, go to <b>“Source --> JSONQuery --> Classes --> JsonFieldData.h”</b> and look for <b>“GetRequest”</b>.<br />
<br />
After <b><i>const FString& url</i></b> add <b><i>const FString& auth</i></b><br />
<br />
Then open <b>“Source --> JSONQuery --> Private --> jsonfielddata.cpp”</b> and look for the same <b>“GetRequest”</b>.<br />
<br />
Here, add the same <b><i>const FString& auth</i></b>.<br />
<br />
After the <b><i>HttpRequest->SetURL(CreateURL(url));</i></b> add the following…<br />
<br />
<b><i>HttpRequest->SetHeader(TEXT("Authorization"), auth);</i></b><br />
<br />
Save both files and open your project. You will get a message saying that part of the code needs to be recompiled. So simply accept and wait a little bit until everything gets compiled 😊<br />
<br />
To check that everything is fine, go to <b>“Settings --> Plugins”</b> and go all the way down to find <b>“Project --> Web”</b> and <b>JSON Query</b> should be selected. 😉<br />
<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhiApcWfT5rJG8PMLZ8wKf6m7ycGG504t0wf-ooOsGyzaWbnx2M3t_-6WCrwXjh-Hq8b3yzqhIbx2rDpsPVUDGLJ42W1YU9rij9Uh_PKqupq_slvfgvUhC_1vS7b0tMtn_jn7tTpeDf7K1X/s1600/JSONQuery.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="222" data-original-width="618" height="114" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhiApcWfT5rJG8PMLZ8wKf6m7ycGG504t0wf-ooOsGyzaWbnx2M3t_-6WCrwXjh-Hq8b3yzqhIbx2rDpsPVUDGLJ42W1YU9rij9Uh_PKqupq_slvfgvUhC_1vS7b0tMtn_jn7tTpeDf7K1X/s320/JSONQuery.jpg" width="320" /></a></div>
<br />
<div>
<br /></div>
<div>
<div>
Awesome, let’s continue.</div>
<div>
<br /></div>
<div>
In order to make our project work on the Oculus Go, we need to setup a couple things.</div>
</div>
<div>
<br /></div>
<h2>
Setting up the Oculus Go</h2>
<div>
<br /></div>
<div>
You may want to setup your Oculus if you haven’t done that already 😊 Here’s a nice <a href="https://support.oculus.com/183135912238400/" target="_blank">link</a> with all the explanation you need…</div>
<div>
<br /></div>
<div>
<h2>
Setting up Unreal for Oculus Go</h2>
</div>
<div>
<div>
<br />
We need to install <b>“Code Works for Android”</b> which is actually bundled with your Unreal Installation. So, go <b>“Program Files --> Epic Games --> UE_4.21 --> Engine --> Extras --> AndroidWorks --> Win64”</b> and run <b>“CodeWorksforAndroid-1R7u1-windows.exe”</b>.</div>
<div>
<br /></div>
<div>
You will notice that you are inside the C++ Classes folder, so just click on the folder icon next to it and select <b>“Content”</b>.</div>
</div>
<div>
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjyhcFF1FxXlMwz7BB9_YCxqDgPAjlmVDKK_2QN9T-DUCAQYM4nOKK03M1Stfd7p7GkZKMZeCozdcgE515KUpultbMLnbkpijsYWQN4nmP3q69fXJrgfzcNBN4JJTOdjwPYySNzE7zPWBxf/s1600/UE_Folders.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="525" data-original-width="193" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjyhcFF1FxXlMwz7BB9_YCxqDgPAjlmVDKK_2QN9T-DUCAQYM4nOKK03M1Stfd7p7GkZKMZeCozdcgE515KUpultbMLnbkpijsYWQN4nmP3q69fXJrgfzcNBN4JJTOdjwPYySNzE7zPWBxf/s320/UE_Folders.jpg" width="117" /></a></div>
<div>
<br /></div>
<div>
<div>
<br /></div>
<div>
Don’t pay attention to the folders for now.</div>
<div>
<br /></div>
<div>
First, save the current map and call it <b>“MainMap”</b>. Then go to <b>“Edit --> Project Settings”</b>. Look for <b>“Maps & Modes”</b> and select <b>“MainMap”</b> in both <b>“Editor Startup Map”</b> and <b>“Game Default Map”</b>.</div>
</div>
<div>
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjKw88JKGnB1SVak_Ys7HRrBW7Rcpj-FFfYjPPzWVdzCY_K9P86mI0g2puD3yPJ_VufgRNVA_2DaTIi9FbRYSYv35Pw7s8pt0CVb2gHjuwYbe_LELQsENomglmStoWNPQbVwK_XxNXimChB/s1600/UE_Maps%2526Modes.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="636" data-original-width="947" height="214" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjKw88JKGnB1SVak_Ys7HRrBW7Rcpj-FFfYjPPzWVdzCY_K9P86mI0g2puD3yPJ_VufgRNVA_2DaTIi9FbRYSYv35Pw7s8pt0CVb2gHjuwYbe_LELQsENomglmStoWNPQbVwK_XxNXimChB/s320/UE_Maps%2526Modes.jpg" width="320" /></a></div>
<div>
<br /></div>
<div>
Then go down and select <b>“Engine --> Input”</b>. On the <b>“Mobile”</b> section set the <b>Default Touch Interface</b> to <b>None</b>.</div>
<div>
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhMqswFhjqxdRYqmPlFA47jIRpxpnM1M04FoUmE6L5nvU47xeMBD8KiqLQIm-zzG47kcwu3ms54wRZ9yHQ-4YK_ZQjc4dpK4qOBk40vlzNt-1MY1ib2CINSzPdqFu8tj7Gbt8besKJuDZhc/s1600/UE_TouchInterface.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="186" data-original-width="568" height="104" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhMqswFhjqxdRYqmPlFA47jIRpxpnM1M04FoUmE6L5nvU47xeMBD8KiqLQIm-zzG47kcwu3ms54wRZ9yHQ-4YK_ZQjc4dpK4qOBk40vlzNt-1MY1ib2CINSzPdqFu8tj7Gbt8besKJuDZhc/s320/UE_TouchInterface.jpg" width="320" /></a></div>
<div>
<br /></div>
<div>
<div>
<div>
Move down to <b>“Platforms”</b> and select <b>“Android”</b>. Click on <b>“Configure Now”</b>. Then move to <b>“Android”</b>. Set the minimum and target SDK version to <b>“19”</b>.</div>
<div>
<br /></div>
<div>
Also click on <b>“Enable Fullscreen Immersive on KitKat and above devices”</b> to enable it.</div>
<div>
<br /></div>
<div>
Look for <b>“Configure the AndroidManifest for Deployment to Oculus”</b> and enable it as well.</div>
<div>
<br /></div>
<div>
Now, click on <b>“Android SDK”</b> and check the configuration. If you don’t have the System Variables configured, then simply assign the folder paths.</div>
<div>
<br /></div>
<div>
Finally, go to <b>“Engine --> Rendering”</b> and make sure that <b>“Mobile HDR”</b> is not selected.</div>
<div>
<br /></div>
<div>
If something is not clear, just go to this <a href="https://developer.oculus.com/documentation/unreal/latest/concepts/unreal-quick-start-guide-go/" target="_blank">link</a> 😉 </div>
<div>
<br /></div>
<div>
Alright, now we can finally move on 😊<br />
<br /></div>
</div>
<h2>
Creating a Dynamic Material</h2>
<div>
<div class="MsoNormal">
<span style="font-size: 12pt; line-height: 17.12px;"><br /></span>Click on “<b>Add New --> Material</b>” and call it “<b>Dynamic_Mat</b>”. Once inside the material editor, right-click on an empty space and look for “<b>TextureSampleParameter2D</b>”.</div>
<div class="MsoNormal">
<br /></div>
</div>
</div>
<div>
<div class="MsoNormal">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiQ1skOQ-Wb9uTaJrSFQ7ZZBmY8IEia7UphDH3kP-NF5QluOSV4Q36Ns-KyChNO8sip5jDZjNgWXQxl3fteAm2Mu_wi_Dg1JSPDyMwZKYjRTTsoYYHpvbzZ_eI_9MgTBMEaiknWcVbiTamL/s1600/TextureSample.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="170" data-original-width="241" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiQ1skOQ-Wb9uTaJrSFQ7ZZBmY8IEia7UphDH3kP-NF5QluOSV4Q36Ns-KyChNO8sip5jDZjNgWXQxl3fteAm2Mu_wi_Dg1JSPDyMwZKYjRTTsoYYHpvbzZ_eI_9MgTBMEaiknWcVbiTamL/s1600/TextureSample.png" /></a></div>
<div align="center" class="MsoNormal" style="text-align: center;">
<br /></div>
<div class="MsoNormal">
<br /></div>
<div class="MsoNormal">
Once created, name it “<b>Texture_Sample</b>”. It will come with a default texture that you can change if you want (But doesn't matter in the end). Simply connect the first output to the “<b>Base Color</b>” of the “<b>Dynamic_Mat</b>” node.</div>
</div>
<div>
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjoeIW7aUIFBf07Gqc8eaAjFbW9U3UccugxdMJLrQjsmMiQSJMw3gGjsw4jMOzSHt4mbn8aXOVriun8wa599Ob_8n7V0vHXusOWWJXnSvDj54GnhBoPWar8DYzwSjeD5uwWrZNvzFjGNF2y/s1600/DynamicMaterial.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="508" data-original-width="475" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjoeIW7aUIFBf07Gqc8eaAjFbW9U3UccugxdMJLrQjsmMiQSJMw3gGjsw4jMOzSHt4mbn8aXOVriun8wa599Ob_8n7V0vHXusOWWJXnSvDj54GnhBoPWar8DYzwSjeD5uwWrZNvzFjGNF2y/s320/DynamicMaterial.jpg" width="299" /></a></div>
<div>
<br /></div>
<div>
Save it and it will automatically applied. The good thing about this setup is that the Param2D is dynamic 😉 </div>
<div>
<h2>
</h2>
<h2>
Creating our first Blueprint</h2>
<div>
<br />
Create a new folder and call it <b>“Blueprints”</b>. Here we’re going to create the screen where the images coming from Vector are going to be displayed.</div>
<div>
<br /></div>
<div>
Press <b>“Add New --> Blueprint Class”</b>.</div>
</div>
<div>
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjVIH9yHjYMLTOltA_kmNhw86Rrf9DINV2I8_n8fl5uQCXsCdsFHuwJwPfVOuzw7wj0HL-Dy3mI-p2ZfFgCHIdoxXt3KHJHQaVERvhKowq3WJ5gnlR78psSkbgVsL_lcHGSAsN2tI7afR8T/s1600/UE_BlueprintClass.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="667" data-original-width="218" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjVIH9yHjYMLTOltA_kmNhw86Rrf9DINV2I8_n8fl5uQCXsCdsFHuwJwPfVOuzw7wj0HL-Dy3mI-p2ZfFgCHIdoxXt3KHJHQaVERvhKowq3WJ5gnlR78psSkbgVsL_lcHGSAsN2tI7afR8T/s320/UE_BlueprintClass.jpg" width="104" /></a></div>
<div>
<br /></div>
<div>
Instead of choosing <b>“Actor”</b> as the parent class…go down to <b>“All Classes”</b> and look for <b>“Image Parser”</b> and select it as parent class.</div>
<div>
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgdQ13hL30lNnqxkhTTnXLsjSPTaHzYXuy6hc44O9O_pcdl0E01SOWSSq8DT15mGbKWK18OrvZJgROM47etH5WJSpkEO2cCw-gWNPzcy2c-cAFTZZliu1Ocd-F3zdKEn06MknJaQRmF88cS/s1600/UE_ImageParserClass.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="554" data-original-width="542" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgdQ13hL30lNnqxkhTTnXLsjSPTaHzYXuy6hc44O9O_pcdl0E01SOWSSq8DT15mGbKWK18OrvZJgROM47etH5WJSpkEO2cCw-gWNPzcy2c-cAFTZZliu1Ocd-F3zdKEn06MknJaQRmF88cS/s320/UE_ImageParserClass.jpg" width="313" /></a></div>
<div>
<br /></div>
<div>
<div>
Name it <b>“ImageRenderer”</b>.</div>
<div>
<br /></div>
<div>
Once created, go to the Viewport tab and click on <b>“Add Component --> Cube”</b>. Simply change its scale to <b>“0.01, 1.0, 1.0”</b>.</div>
</div>
<div>
<br /></div>
<div>
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEggsLYQ21XrbqRP26g3yBPw3Aou52Cc2WRkmD-qwAs_H6apu2qOHzJ3Me7-2xHSi16jgXE2xUe9MYZ5hjYx6yAY_mq59c-AC78LhoYlC3k4Txg0rRUgfB8w81gk1bz4re6jxyFP8WZUCd9q/s1600/ViewportRenderer.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="520" data-original-width="703" height="236" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEggsLYQ21XrbqRP26g3yBPw3Aou52Cc2WRkmD-qwAs_H6apu2qOHzJ3Me7-2xHSi16jgXE2xUe9MYZ5hjYx6yAY_mq59c-AC78LhoYlC3k4Txg0rRUgfB8w81gk1bz4re6jxyFP8WZUCd9q/s320/ViewportRenderer.jpg" width="320" /></a></div>
<div>
<br /></div>
<div>
<div>
Then switch to the <b>“Event Graph”</b> tab. This is where we are going to build our Blueprints.</div>
<div>
<br /></div>
<div>
But first, we need to create a couple of variables.</div>
<div>
<br /></div>
<div>
<b>CubeMaterial --> Material Instance (Object Reference)</b></div>
</div>
<div>
<b><br /></b></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjtfHYSJ20Zl8UAajhttkufB_fBzQaz2uTcytQ3C6uDhyphenhyphenkc3XxLv3HinrWYg6kmNUAawJJ2YfIHVamWXICmh1Y_2haIJyQLEHKGP8AnCbX3FkxvudvR50rVp4Oqnb63zjoa7s4BRRlfIhaF/s1600/CubeMaterial.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="321" data-original-width="490" height="209" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjtfHYSJ20Zl8UAajhttkufB_fBzQaz2uTcytQ3C6uDhyphenhyphenkc3XxLv3HinrWYg6kmNUAawJJ2YfIHVamWXICmh1Y_2haIJyQLEHKGP8AnCbX3FkxvudvR50rVp4Oqnb63zjoa7s4BRRlfIhaF/s320/CubeMaterial.png" width="320" /></a></div>
<div>
<b><br /></b></div>
<div>
<div>
This is going to be the material of the cube that we created.</div>
<div>
<b><br /></b></div>
<div>
<b>TempImg --> Texture 2D (Object Reference)</b></div>
<div>
<b><br /></b></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjy_09yEP_AyYFegjqcURPxRiFnja0VWLUN2YWjILoTA0vyTktFnQiwLIjf8CR1crwPCzSftqFtkORh3FJ_EEI32cpYnYvK0DcnvT881XmYiXEXODVGHwrlvgA3ALkfeX7zSAnvqu6Gl6M6/s1600/TempImg.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="319" data-original-width="491" height="207" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjy_09yEP_AyYFegjqcURPxRiFnja0VWLUN2YWjILoTA0vyTktFnQiwLIjf8CR1crwPCzSftqFtkORh3FJ_EEI32cpYnYvK0DcnvT881XmYiXEXODVGHwrlvgA3ALkfeX7zSAnvqu6Gl6M6/s320/TempImg.png" width="320" /></a></div>
<div>
<div>
<b><br /></b></div>
<div>
This is where we’re going to store the image after converting it from Base 64 to image.</div>
<div>
<br /></div>
<div>
<b>TempMat --> Material Instance (Object Reference)</b></div>
<div>
<br /></div>
<div>
This is the dynamic material that is going to be assign to our cube.</div>
<div>
<br /></div>
<div>
<b>ImageJSON --> String</b></div>
<div>
<br /></div>
<div>
This is the result from calling the API…the Base 64 string.</div>
<div>
<br /></div>
<div>
With the variables ready, we can start creating the first piece of the Blueprint.</div>
<div style="font-weight: bold;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjuyCkqqNVcF1bB98nCW4UtxOc2DHNhsqIJZtBhYGGDcBv0ONaPV2eytQerEu3m75f-3hqr6goY60XqoLs1oopqXJhbIiUHLIEAow3hQQ1JcU4_PpinQFnhR_eVK8JCy8UaEO-R6L-yNabp/s1600/ImageRenderer_BP_01.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="291" data-original-width="529" height="176" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjuyCkqqNVcF1bB98nCW4UtxOc2DHNhsqIJZtBhYGGDcBv0ONaPV2eytQerEu3m75f-3hqr6goY60XqoLs1oopqXJhbIiUHLIEAow3hQQ1JcU4_PpinQFnhR_eVK8JCy8UaEO-R6L-yNabp/s320/ImageRenderer_BP_01.jpg" width="320" /></a></div>
<div style="font-weight: bold;">
<br /></div>
<div>
Here, we are saying that once our application starts (<b>Event BeginPlay</b>) we’re going to call a function called <b>“Set Timer by Function Name”</b>. This function will call another function every 2.0 seconds (as we ticked the Looping value). The called function will be <b>“MyEvent”</b>.</div>
<div>
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgH-eK3WA0GKr7nwsBVi-RuXeJ0UX01FD3buszgWLvuITBZgfBALJ9c7180IyGfYAvUUW4LTs-NnuxOZKhx-kQDjvDDpUUZBuO1u-Hku42Xxsv7UW6J2_s9F1d5mCfcNuHZLgtO0PNDhMpL/s1600/RedVectorEyeTable.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="521" data-original-width="985" height="169" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgH-eK3WA0GKr7nwsBVi-RuXeJ0UX01FD3buszgWLvuITBZgfBALJ9c7180IyGfYAvUUW4LTs-NnuxOZKhx-kQDjvDDpUUZBuO1u-Hku42Xxsv7UW6J2_s9F1d5mCfcNuHZLgtO0PNDhMpL/s320/RedVectorEyeTable.jpg" width="320" /></a></div>
<div>
<br /></div>
</div>
<div style="font-weight: bold;">
<br /></div>
</div>
<div>
Here, we are calling the function <b>“MyEvent”</b>, which will call <b>“Get JSON Request”</b> by passing the URL and the Auth. This will be bound to the <b>“OnGetResult”</b> event. The result from the JSON call will be extracted by using <b>Get Object Field</b>, <b>Get Object Array Field</b>, a <b>For Loop</b> and finally a <b>Get String Field</b> in order to get the Base 64 image and store it on the <b>ImageJSON</b> variable.</div>
<div>
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgTuz-gC8It-yaM9KD_ZaeSAO1PREgUyKbUvwsomfIJ4KyEgRd0aIl94-bI46gjwnccjOdgimWR1WzeLodIRzmULrlrKd9eeHnIKi1obQv2OSgDPGxhVunV-zjjaaPg3Qe8lDfFZAwhOH2H/s1600/DeleteTableVectorEye.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="273" data-original-width="686" height="127" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgTuz-gC8It-yaM9KD_ZaeSAO1PREgUyKbUvwsomfIJ4KyEgRd0aIl94-bI46gjwnccjOdgimWR1WzeLodIRzmULrlrKd9eeHnIKi1obQv2OSgDPGxhVunV-zjjaaPg3Qe8lDfFZAwhOH2H/s320/DeleteTableVectorEye.jpg" width="320" /></a></div>
<div>
<br /></div>
<div>
After setting the ImageJSON variable, we call the API to delete the table. After this…things get interesting…</div>
<div>
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgx7lOPuG4yYoTTixcq_6LqzGuEL_KbBjMP8J_8cr-TqAq9a2HT3NzgPe6IoAqOkaupNSJuzNPpUH1d-tYd8weRadclfuXdCziFJAHMkIYjFHUfqxfryt49RQgHcJmG0IAeR-WV8ad6VXpd/s1600/LoadDynamicImage.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="292" data-original-width="1117" height="83" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgx7lOPuG4yYoTTixcq_6LqzGuEL_KbBjMP8J_8cr-TqAq9a2HT3NzgPe6IoAqOkaupNSJuzNPpUH1d-tYd8weRadclfuXdCziFJAHMkIYjFHUfqxfryt49RQgHcJmG0IAeR-WV8ad6VXpd/s320/LoadDynamicImage.jpg" width="320" /></a></div>
<div>
<br /></div>
<div>
<div>
Here we are calling our C++ Class <b>“Parse Image”</b> like another Blueprint element. We get the value stored on <b>ImageJSON</b> to be decoded as an image. The result of decoding the Base 64 string will go into <b>“Import Buffer as Texture 2D”</b>, which will go into the <b>TempImg</b> variable. After this <b>“Create Dynamic Material Instance”</b> will apply a Dynamic material to our <b>Dynamic_Mat</b> material and assign it to <b>TempMat</b> that will passed as the target of <b>Set Texture Parameter Value</b>, while <b>TempImg</b> will be pass as the value parameter. Finally, a <b>Set Material</b> node will assign the <b>TempMat</b> material to the Cube.</div>
<div>
<br /></div>
<div>
To make it simple…we grab the Base 64 string…convert it into an image…create a dynamic material, use it as the value for our dynamic material and finally we assign this to our cube. Every time we get a new Base 64 value, we will get a new image and our cube will be able to display it 😉</div>
</div>
<div>
<h2>
</h2>
<h2>
Importing our Blender model</h2>
<div>
<br />
Now, we need to simulate that we’re inside Vector…hence…we need to import our Blender .FBX model 😉</div>
<div>
<br /></div>
<div>
Simply press Import and select the .FBX file that you can get from <a href="http://blagarts.com/files/InsideCozmo.fbx" target="_blank">here</a>. Press Import All and you will have it on the screen.</div>
<div>
<br /></div>
<div>
Change the following parameters…</div>
</div>
<div>
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiyFJzBvgL5R2QHlgNNfOgf8RjgJX8FvftKmEAZQCzp9ov6x2Y2Iix6mFDaKx4HbGglEGD6fSzDN0mJSSHFYrozntMBJJuwBBv5dMpjSBsh78uU-I5uHNHQwx4SqnQcnpOVu9kzG0wolwbC/s1600/BlenderTransform.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="133" data-original-width="376" height="113" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiyFJzBvgL5R2QHlgNNfOgf8RjgJX8FvftKmEAZQCzp9ov6x2Y2Iix6mFDaKx4HbGglEGD6fSzDN0mJSSHFYrozntMBJJuwBBv5dMpjSBsh78uU-I5uHNHQwx4SqnQcnpOVu9kzG0wolwbC/s320/BlenderTransform.png" width="320" /></a></div>
<div>
<br /></div>
<div>
Now, add a Point Light with these parameters…</div>
<div>
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiqxz9F00t2s3NvsA1M9ZGVywt9ncvYZHqgB7cX5tgvvQg0dYevpeAUHhpE9JMO_Kraatl49xUgz8-Ig8hUCmLjhyT9VimJGAYmnVXIX_1kFcH2lSjxkEs0cIztf9pyljXTWQ4oIUVU00xT/s1600/PointLightTransform.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="192" data-original-width="375" height="163" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiqxz9F00t2s3NvsA1M9ZGVywt9ncvYZHqgB7cX5tgvvQg0dYevpeAUHhpE9JMO_Kraatl49xUgz8-Ig8hUCmLjhyT9VimJGAYmnVXIX_1kFcH2lSjxkEs0cIztf9pyljXTWQ4oIUVU00xT/s320/PointLightTransform.png" width="320" /></a></div>
<div>
<br /></div>
<div>
Next, grab the <b>“ImageRenderer”</b> Blueprint and drag it into the screen. Change the parameters like this…</div>
<div>
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgDwQ5dPzvfqa0jhcfM5DRLJDWGEApl6ms1PWUPGNCJj_QXh8ev0qzAvJnHu1ksjEmkU7hTKXBU_qH5baQq3UOtrXjnLvg2jS8BxQeE5SDRIY8b7UI15pJs3MlpEjvu5sHbpfNZ_S287hza/s1600/ImageRenderedTransform.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="106" data-original-width="373" height="90" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgDwQ5dPzvfqa0jhcfM5DRLJDWGEApl6ms1PWUPGNCJj_QXh8ev0qzAvJnHu1ksjEmkU7hTKXBU_qH5baQq3UOtrXjnLvg2jS8BxQeE5SDRIY8b7UI15pJs3MlpEjvu5sHbpfNZ_S287hza/s320/ImageRenderedTransform.png" width="320" /></a></div>
<div>
<br /></div>
<div>
Then, press <b>“Build”</b> and wait till everything (including the lights) get built.</div>
<div>
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj-6wwapddkPLYEyAGlVHFRqNSWmAoP1rMgb8Q32JpPqmx0ossOJLYudWgRKuNZB3xK5bhitZFVn5ImaJSP2edJ6ztRI_5Js_3UxZhrPaR44gFhjEYdxkJN67c_L5m20oysAxrBbvF_6RlG/s1600/Build.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="80" data-original-width="882" height="29" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj-6wwapddkPLYEyAGlVHFRqNSWmAoP1rMgb8Q32JpPqmx0ossOJLYudWgRKuNZB3xK5bhitZFVn5ImaJSP2edJ6ztRI_5Js_3UxZhrPaR44gFhjEYdxkJN67c_L5m20oysAxrBbvF_6RlG/s320/Build.png" width="320" /></a></div>
<div>
<br /></div>
<div>
Once the build is done…you will have this…</div>
<div>
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhvfjhlSeM-38c4a7NeJhCT4Yb3DX0UYzWzNFKNk_acb7tziDLdLgSAC0yb2nRrtOXHIxYFtmaVfiYEH6qQLsUjVxRKwzOTdAYyFjIFccy34xSRE2pSkdVIi96WVnoy3LBgJwq-OPLltu0j/s1600/BlenderModelUnreal.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="646" data-original-width="1218" height="169" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhvfjhlSeM-38c4a7NeJhCT4Yb3DX0UYzWzNFKNk_acb7tziDLdLgSAC0yb2nRrtOXHIxYFtmaVfiYEH6qQLsUjVxRKwzOTdAYyFjIFccy34xSRE2pSkdVIi96WVnoy3LBgJwq-OPLltu0j/s320/BlenderModelUnreal.png" width="320" /></a></div>
<div>
<br /></div>
<div>
Awesome! Everything is starting to take shape 😊 But now…we need to add the real Oculus Go support 😉</div>
<div>
<h2>
</h2>
<h2>
Adding Oculus Go support</h2>
<div>
<br />
So, we configured our project to work in an Oculus Go…but that’s not enough 😉 We need to do a couple of extra things…and of course…and most important…we need to add a way to control Vector using the Oculus Go controller 😊</div>
<div>
<br /></div>
<div>
Create a new folder and call it <b>“Modes”</b>. Then create a new <b>“Blueprint Class”</b> but this time choose <b>“Pawn”</b> and name it <b>“Pawn Blueprint”</b> (Smart, huh?).</div>
<div>
<br /></div>
<div>
When it opens up, go to the left section and select <b>“DefaultSceneRoot”</b>, then click on <b>“Add Component”</b> and select <b>“Scene”</b> and change its name to <b>“VRCameraRoot”</b>.</div>
<div>
<br /></div>
<div>
Select <b>“VRCameraRoot”</b> and add a <b>“Camera”</b> component, name it <b>“VRCamera”</b>.</div>
<div>
<br /></div>
<div>
Select <b>“VRCameraRoot”</b> and add a "<b>Motion Controller</b>" component, name it <b>“OculusGoController”</b>.</div>
<div>
<br /></div>
<div>
Select <b>“OculusGoController”</b> and add a "<b>Static Mesh</b>" component, name it <b>“OculusGoMesh”</b>.</div>
<div>
<br /></div>
<div>
To make clear…here’s a screenshot 😊</div>
</div>
<div>
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhsEIV2RYqoFSOHda-LmZaBaqspjmpTwpYaSf4cYCIEhRtbWN8cDVxVDVyIh0tAieMTP1FMFMVyS4k_EBjnUx9e7E3RlSuwepoFWrOMKLEqQcmOmRJUh1Mq01v_USmxtCf9pZaKUBYVhS5M/s1600/OculusController.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="195" data-original-width="280" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhsEIV2RYqoFSOHda-LmZaBaqspjmpTwpYaSf4cYCIEhRtbWN8cDVxVDVyIh0tAieMTP1FMFMVyS4k_EBjnUx9e7E3RlSuwepoFWrOMKLEqQcmOmRJUh1Mq01v_USmxtCf9pZaKUBYVhS5M/s1600/OculusController.png" /></a></div>
<div>
<br /></div>
<div>
With the <b>“OculusGoMesh”</b> selected, go to its properties and on the Static Mesh one, choose <b>“OculusGoController”</b> mesh.</div>
<div>
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjEeUANrsBqX9DSYjvh0am7Mxpp8bwnVhwIkdyFYT6F7-L4Qc7SPLHBmN3wR5d8eeXkujTpfCINiWQgt_fIWv_sewO4jgeetuGV0gWpEN1szUKQQuxOHy58902CnACsNjkBLDLKuMg_BzmV/s1600/OculusMesh.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="133" data-original-width="471" height="90" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjEeUANrsBqX9DSYjvh0am7Mxpp8bwnVhwIkdyFYT6F7-L4Qc7SPLHBmN3wR5d8eeXkujTpfCINiWQgt_fIWv_sewO4jgeetuGV0gWpEN1szUKQQuxOHy58902CnACsNjkBLDLKuMg_BzmV/s320/OculusMesh.png" width="320" /></a></div>
<div>
<br /></div>
<div>
After this, we need to create some variables…the first one will <b>“CameraHeight”</b> and will be an editable <b>“Vector”</b>.</div>
<div>
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhho_iYsmWS1BHhA6GEDegTtv3rpz66vIiK5egwVCJppKMjeTRPrNZBEureiCJ8uc9NQ4ou1WUhxLoxOOQSj7qmvkflCJiFB4q3Tyf-HSXt7qX0eO40gmYGh1vJ9uKmUM5w85GGv6ueFDns/s1600/CameraHeight.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="160" data-original-width="474" height="108" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhho_iYsmWS1BHhA6GEDegTtv3rpz66vIiK5egwVCJppKMjeTRPrNZBEureiCJ8uc9NQ4ou1WUhxLoxOOQSj7qmvkflCJiFB4q3Tyf-HSXt7qX0eO40gmYGh1vJ9uKmUM5w85GGv6ueFDns/s320/CameraHeight.png" width="320" /></a></div>
<div>
<br /></div>
<div>
<br /></div>
<div>
<div>
The second one will be called <b>“request”</b> and would be a <b>Json Field Data (Object Reference)</b>.<br />
<br /></div>
<div>
Finally, create one called <b>“Lift”</b> of type <b>Boolean</b> and a <b>String</b> variable named <b>“Var”</b>.</div>
</div>
<div>
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjCiINTSQm8bh0Gdw_OH1lsQ1iLblCvDxhwVZi-LlFJeRiPdOvm5J_qCFRumOtbhYIkZzvVql_PA39XgHXDLDIu0ilckkn0IDTOc-chTeNZbERG-DK5js6zVab_93sFcz-U7kUysguCuDJw/s1600/Variables.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="128" data-original-width="287" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjCiINTSQm8bh0Gdw_OH1lsQ1iLblCvDxhwVZi-LlFJeRiPdOvm5J_qCFRumOtbhYIkZzvVql_PA39XgHXDLDIu0ilckkn0IDTOc-chTeNZbERG-DK5js6zVab_93sFcz-U7kUysguCuDJw/s1600/Variables.png" /></a></div>
<div>
<br /></div>
<div>
<br /></div>
<div>
<div>
If you’re wondering about the open eye next to <b>“CameraHeight”</b>, that simply means that its <b>“Public”</b>, and you can change it by clicking on it.</div>
<div>
<br /></div>
<div>
Now, we can continue on the <b>“Event Graph”</b> tab.</div>
</div>
<div>
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhZf-aO0wx64VCfpLkDmGgYvyJLJW-uVPUPrI2IVHukMsffm3VfQRSzMCjZ5kGVxboC-KyFUODyRPFRrHDDYGuPIT7omhyphenhypheniPr3Q4tdk7951CvVDCKYQG5d7b8Vp5AyfTI1OtuPOhHlO3Sfo/s1600/SetTrackOrigin.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="300" data-original-width="776" height="123" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhZf-aO0wx64VCfpLkDmGgYvyJLJW-uVPUPrI2IVHukMsffm3VfQRSzMCjZ5kGVxboC-KyFUODyRPFRrHDDYGuPIT7omhyphenhypheniPr3Q4tdk7951CvVDCKYQG5d7b8Vp5AyfTI1OtuPOhHlO3Sfo/s320/SetTrackOrigin.jpg" width="320" /></a></div>
<div>
<br /></div>
<div>
Here, we want that when the applications starts (<b>Event BeginPlay</b>) the tracking origin gets set to our eyes level. The node <b>SetRelativeLocation</b> will be called where the target will be the <b>VRCameraRoot</b> and the new location would be set to the <b>CameraHeight</b>. In other word, what we see its going to be on our eyes level.</div>
<div>
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiTaNPaNROtHWk6Gl8At7dkE2ADp_j9deB5uVU77ewNWBXB9RIyefC3wPjNskfstneXURLOWOaTuKCmgnp3i6vHaITmv4-dOJdeZk3MOQwLl44ec46WAGBYRwnTXslkj4x3DxNYh1dCILMz/s1600/SendMovementCommand.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="585" data-original-width="851" height="219" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiTaNPaNROtHWk6Gl8At7dkE2ADp_j9deB5uVU77ewNWBXB9RIyefC3wPjNskfstneXURLOWOaTuKCmgnp3i6vHaITmv4-dOJdeZk3MOQwLl44ec46WAGBYRwnTXslkj4x3DxNYh1dCILMz/s320/SendMovementCommand.jpg" width="320" /></a></div>
<div>
<br /></div>
<div>
<br /></div>
<div>
When we press the Thumbstick Up or Forward, Left or Right, we assign the result to our Var variable, then we call the Get JSON Request function. The URL would be the API address plus the value of the Var variable.</div>
<div>
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh6InQ8hgnPRdo9sFuuuBHEjI2qayBO5gKAQCneYA7atB2ByTkmdyRtTJU0uflBo31WfGf33gRpW_8d-STr63CNZn3mHArFyHG-DxEfehlPnacK7FUt0MrqBWDrIfPQLXSdBQRE923LGGIk/s1600/SendLiftCommand.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="462" data-original-width="1006" height="146" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh6InQ8hgnPRdo9sFuuuBHEjI2qayBO5gKAQCneYA7atB2ByTkmdyRtTJU0uflBo31WfGf33gRpW_8d-STr63CNZn3mHArFyHG-DxEfehlPnacK7FUt0MrqBWDrIfPQLXSdBQRE923LGGIk/s320/SendLiftCommand.jpg" width="320" /></a></div>
<div>
<br /></div>
<div>
<div>
Here, we want to click on the <b>“Back”</b> button of the Oculus Controller. The first time we click the <b>“Lift”</b> variable is going to be <b>“False”</b>, so we make it <b>“True”</b>. If its <b>“True”</b> then we send the <b>“up”</b> command. If we click again, we make it <b>“False”</b> and pass the <b>“down”</b> command. This way we can control Vector’s lift handle.</div>
<div>
<br /></div>
<div>
Alright, compile, save and that’s done 😊 We simply need to add it to our scene. So, drag it and change these parameters.</div>
</div>
<div>
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi1Sc-swdajXcGX24d8Fv4d2CDrKjAWsWrp42aZ88Sd-Vn98AnHA1DcqEcXzMaKG7wxi4yfepUt1O9jSy7MTQMdhlqN8NX_nqRX55ok-AhoP3OwUp2_uj9YOKJJNw-sfRQNjZXejtJ5taa0/s1600/OculusTransform.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="105" data-original-width="369" height="91" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi1Sc-swdajXcGX24d8Fv4d2CDrKjAWsWrp42aZ88Sd-Vn98AnHA1DcqEcXzMaKG7wxi4yfepUt1O9jSy7MTQMdhlqN8NX_nqRX55ok-AhoP3OwUp2_uj9YOKJJNw-sfRQNjZXejtJ5taa0/s320/OculusTransform.png" width="320" /></a></div>
<div>
<br /></div>
<div>
Also, and this is very important…</div>
<div>
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhHt7VMZCOJSJ_jwkB4eOEm2jZsi_bB43NIAngh6-VK-rAnbnL4dCT9rVSUdx5K3y-RwnuWXZMTARrs6hzJpe_xYJRDHX7k5gdXRSfVeA3bDMAPhva81TbB0Ahu9gbN4trCNxlVTFG-6lSE/s1600/Pawn.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="210" data-original-width="382" height="175" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhHt7VMZCOJSJ_jwkB4eOEm2jZsi_bB43NIAngh6-VK-rAnbnL4dCT9rVSUdx5K3y-RwnuWXZMTARrs6hzJpe_xYJRDHX7k5gdXRSfVeA3bDMAPhva81TbB0Ahu9gbN4trCNxlVTFG-6lSE/s320/Pawn.png" width="320" /></a></div>
<div>
<br /></div>
<div>
<div>
<b>Auto Possess Player</b> should be Player <b>0</b>.</div>
<div>
<br /></div>
<div>
Now, press “<b>Build</b>” and wait till everything (including the lights) get built.</div>
<div>
<br /></div>
<div>
Then press Play…and you will see this…</div>
</div>
<div>
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgS0HM5Ys4a8QYY6AOs9BP8bi3gmV3lLYqdA9c6jerzEczDkz9IncCI0djaz0tKZ2_42Fs9hZz33nFWFWYK2aZPEdI2bJOtIS9uvK38VPpuj9NKgXpItqwPxz30DkdEGdCKXhmzfUyDH4xX/s1600/EmptyScreen.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="638" data-original-width="1206" height="169" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgS0HM5Ys4a8QYY6AOs9BP8bi3gmV3lLYqdA9c6jerzEczDkz9IncCI0djaz0tKZ2_42Fs9hZz33nFWFWYK2aZPEdI2bJOtIS9uvK38VPpuj9NKgXpItqwPxz30DkdEGdCKXhmzfUyDH4xX/s320/EmptyScreen.png" width="320" /></a></div>
<div>
<br /></div>
<div>
<br /></div>
<div>
<div>
Of course, if you try to move using your mouse…nothing will happen…so you need to send it to your Oculus Go 😉</div>
<div>
<br /></div>
<div>
To do that, simply go to Launch and select your device…it will take a long time the first time because all the shaders, Blueprints and so on need to be compiled…but after that, you will be able to put on your headset and look around 😊 Although…you’re not going to see anything on the screen because we still need to get Vector up and running 😉</div>
<h2>
</h2>
<h2>
Installing Vector’s SDK</h2>
<div>
<br />
First, make sure Vector is connected to the Internet by using the Vector app…here’s a nice <a href="https://support.anki.com/hc/en-us/articles/360010124633--VIDEO-Vector-and-Connection-How-to-set-Vector-up" target="_blank">video</a> on how to do that…</div>
<div>
<br /></div>
<div>
Once you check that, kill the app from your phone…as it might interfere with your own application taking control of Vector…</div>
<div>
<br /></div>
<div>
You can install the SDK by doing</div>
<div>
<br /></div>
<div>
<b><i>python3 -m pip install --user anki_vector</i></b></div>
<div>
<br /></div>
<div>
Then…authenticate your Vector by doing…</div>
<div>
<br /></div>
<div>
<b><i>python3 -m anki_vector.configure</i></b></div>
<div>
<br /></div>
<div>
You will be asked for Vector’s name, ip address and serial number. Also, you will be requested for your Anki Cloud credentials.</div>
<div>
<br /></div>
<div>
To get this information, simply put Vector on his charger…and press his top twice. This will give you his name, then lift up and down his handle in order to get the IP. The serial number is on Vector’s bottom.</div>
<h2>
</h2>
<h2>
Creating Vector’s script</h2>
<div>
<br />
This script is the last part of our journey 😊 Simply create a new file called VectorOculusGo.py</div>
</div>
<div>
<br /></div>
<table align="center" style="width: 600px;">
<tbody>
<tr><th bgcolor="#6690BC">VectorOculusGo.py</th>
</tr>
<tr>
<td><pre>import anki_vector #Control Vector
import requests #Use REST APIs
import json #Consume JSON
import time #Manage time
from anki_vector.util import degrees, distance_mm, speed_mmps
import base64 #Encode/Decode images
import datetime #To get time and data
#URLs to manage upload of Base 64 images and to control Vector using the
#Oculus Go controller
urlAddEye = "https://YourHANA.ondemand.com/VectorEyes/AddVectorEye.xsjs"
urlGetCommand = "https:// YourHANA.ondemand.com/VectorEyes/</pre>
<pre> GetVectorCommand.xsodata/vectorcommand"
urlDeleteCommand = "https:// YourHANA.ondemand.com/VectorEyes/</pre>
<pre> DeleteVectorCommand.xsjs"
def main():
#We stablish a connection with Vector and enable his camara
robot = anki_vector.Robot(enable_camera_feed=True)
#We connect to Vector
robot.connect()
i = 0
#We want this to loop forever…until we close the program
while i == 0:
#We instruct Vector to take a pictures
image = robot.camera.latest_image
#And save it
image.save("./img/Temp.png")
#Once saved, we open it
with open("./img/Temp.png", "rb") as imageFile:
#We get the time and create a timestamp
ts = time.time()
timestamp = datetime.datetime.fromtimestamp(ts).strftime('%Y-%m-%d %H:%M:%S')
#We enconde the picture as an Base 64 string
strImg = base64.b64encode(imageFile.read())
#The payload is the parameters that we are sending to the REST API
payload = "{\"timestamp\":\"" + timestamp + "\",\"vectoreye\":\"" + </pre>
<pre> strImg.decode('ascii') + "\"}"
#In the headers, we pass the authentication for the REST API
headers = {
'Content-Type': "application/x-www-form-urlencoded",
'Authorization': "YourAuthorization",
}
#We upload the Base 64 string of the image to the DB
response = requests.request("POST", urlAddEye, data=payload, headers=headers)
#We put the application to sleep for 2 seconds just not to overload the DB
time.sleep(2)
querystring = {"$format":"json"}
#Right after uploading the Base 64 string,
#we want to get any commands coming through
response = requests.request("GET", urlGetCommand, headers=headers, </pre>
<pre> params=querystring)
#We convert the response to JSON
json_response = json.loads(response.text)
#We need to check if there’s any information first and then extract the command
try:
json_text = json_response['d']['results'][0]['COMMAND']
except:
json_text = ""
#Depending on the command, we make Vector move forward, backward or
#lift his handle. If the lift was already up, we put it down first…
if (json_text == 'forward'):
robot.behavior.drive_straight(distance_mm(50), speed_mmps(50))
elif (json_text == 'backward'):
robot.behavior.drive_straight(distance_mm(-50), speed_mmps(50))
elif(json_text == 'right'):
robot.behavior.turn_in_place(degrees(-90))
elif(json_text == 'left'):
robot.behavior.turn_in_place(degrees(90))
elif(json_text == 'up'):
robot.behavior.set_lift_height(0.0)
robot.behavior.set_lift_height(1.0)
elif(json_text == 'down'):
robot.behavior.set_lift_height(0.0)
#After receiving the command, we simply delete it from the DB
response = requests.request("GET", urlDeleteCommand, headers=headers)
if __name__ == '__main__':
main()
</pre>
</td>
</tr>
<tr>
</tr>
</tbody></table>
<br />
Nice, the source code is self-explanatory…but still…let’s go through what is going on this application…<br />
<br />
We want Vector to take a picture every 2 seconds…once a picture is taken, we want to convert it into a Base 64 string and then along with a Timestamp (which is a date with hours, minutes and seconds) send it to the Database. Once that’s done…we rest for 2 seconds and check if there’s any command available. If there’s one, we make Vector act accordingly…and just to avoid keep repeating the same command…we simply delete it from the Database, so we can simply issue a new command.<br />
<h2>
</h2>
<h2>
Putting it all together</h2>
<br />
Great! Now we have our application running on the Oculus Go and our Vector ready to execute our script.<br />
<br />
So…get ready a Terminal or CMD window with the following line…<br />
<br />
<b><i>python3 VectorOculusGo.py</i></b><br />
<br />
Put on your Oculus Go headset, grab your controller and the hit “<b>Enter</b>” on your keyboard. Our script will start running and you will see what Vector is looking at…something like this…<br />
<div>
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiSgpVVmE5g4bEgX6XF8zfkPSbgD-eiXmvi_xyCfn3C8q-Ri-BA3PQLnXlieAKLk6Eg7eRsqa9umzskEjaDnvCAISpmX7sj_NWGhYbwiEPQxvEWbJuMc839UUIV4uBp2W6J-mRzrPHSbRKP/s1600/OculusRunning.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="891" data-original-width="1600" height="178" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiSgpVVmE5g4bEgX6XF8zfkPSbgD-eiXmvi_xyCfn3C8q-Ri-BA3PQLnXlieAKLk6Eg7eRsqa9umzskEjaDnvCAISpmX7sj_NWGhYbwiEPQxvEWbJuMc839UUIV4uBp2W6J-mRzrPHSbRKP/s320/OculusRunning.jpg" width="320" /></a></div>
<div>
<br /></div>
<div>
I know…that’s actually running on Unreal Engine and not on the Oculus…but that’s what the video is for 😉</div>
<div>
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<iframe allowfullscreen="" class="YOUTUBE-iframe-video" data-thumbnail-src="https://i.ytimg.com/vi/U5fu9C21DSs/0.jpg" frameborder="0" height="266" src="https://www.youtube.com/embed/U5fu9C21DSs?feature=player_embedded" width="320"></iframe></div>
<div>
<br /></div>
<div>
I hope you like this blog and enjoy controlling Vector from the inside! -:D</div>
<div>
<br /></div>
<div>
Greetings,</div>
<div>
<br /></div>
<div>
Blag.</div>
<div>
SAP Labs Network.</div>
</div>
Alvaro "Blag" Tejada Galindohttp://www.blogger.com/profile/12061593528820409779noreply@blogger.com0tag:blogger.com,1999:blog-4144704359177008692.post-54700327876249985692018-12-15T04:18:00.001-08:002018-12-15T04:18:54.663-08:00Hey Vector, who do I look like?<style type="text/css">
@page { size: 8.5in 11in; margin: 0.79in }
p { margin-bottom: 0.1in; line-height: 115%; background: transparent }
a:link { color: #000080; so-language: zxx; text-decoration: underline }
</style>
<br />
<div align="justify" style="line-height: 100%; margin-bottom: 0in;">
I have played with <a href="https://www.anki.com/en-us/cozmo/cozmo-learn?gclid=EAIaIQobChMI_97EvLaa3wIVSYGzCh2i8A-LEAAYASAAEgImZ_D_BwE)%20in%20the%20past,%20so%20when%20Vector%20(https://www.anki.com/en-ca/vector" target="_blank">Cozmo</a> in the past, so when <a href="https://www.anki.com/en-ca/vector" target="_blank">Vector</a> came out...I knew I needed to do something with it ;)<br />
<br />
So...what’s Vector?<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj_72RUI-97hfLP5O5973jRM7ZO8Cm3s1TY_3qw9knHVYPx3KNFDzgzE9jZYiggdxXoHvjiXGRbqoW3tA8ZWpN6YtoE6jOwKydzwn6LdtYFVbaALyX2IcVqE73gXnotcLc-Od4mCLSqxGVH/s1600/AnkiVector.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="550" data-original-width="550" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj_72RUI-97hfLP5O5973jRM7ZO8Cm3s1TY_3qw9knHVYPx3KNFDzgzE9jZYiggdxXoHvjiXGRbqoW3tA8ZWpN6YtoE6jOwKydzwn6LdtYFVbaALyX2IcVqE73gXnotcLc-Od4mCLSqxGVH/s320/AnkiVector.jpg" width="320" /></a></div>
<br />
Pretty much a black Cozmo? Well...yes and no :) Vector has a better processor, 4 cores, a microphone, almost double amount of parts, a better camera and colorful display.<br />
<br />
As you know...I’m a really big fan of <a href="https://api.sap.com/package/SAPLeonardoMLFunctionalServices?section=Artifacts" target="_blank">SAP Leonardo Machine Learning APIs</a>...as they allow you to easily consume Machine Learning services.<br />
<br />
For this blog I wanted to do something that I have always liked...take a picture of someone and then compare it with photos of famous actors and actresses and see who this person resembles the most ;)<br />
<br />
So, let’s start :D<br />
<br />
<h3>
<b>Installing the Vector SDK</b></h3>
Make sure that Vector is connected to the Internet by using Vectors app on IPhone or Android. Here’s a nice video on how to do <a href="https://support.anki.com/hc/en-us/articles/360010124633--VIDEO-Vector-and-Connection-How-to-set-Vector-up" target="_blank">that</a>.<br />
<br />
Once your Vector is connected to the Internet...make sure to simply kill the Vector's app on your phone.<br />
<br />
The Vector SDK was only available to the people who back Anki on their <a href="https://www.kickstarter.com/projects/anki/vector-by-anki-a-giant-roll-forward-for-robot-kind" target="_blank">Kickstarter campaign</a>.<br />
...but since November 11th, the SDK is on Public Alpha! :D Which means...you can finally get your hands on it ;)<br />
<br />
If by any chance you got the SDK installed before...remove it before moving forward…<br />
<br />
<b>python3 -m pip uninstall anki_vector</b><br />
<br />
Then simply install it by doing this…<br />
<br />
<b>python3 -m pip install --user anki_vector</b><br />
<br />
Then, you need to authenticate your Vector…<br />
<br />
<b>python3 -m anki_vector.configure</b><br />
<br />
You will be asked for Vector’s name, ip address and serial number. Also you will be requested for your Anki Cloud Credentials.<br />
<br />
To get this information simply put Vector on his charger...and press his top twice. This will give you his name, then lift up and down his handle in order to the IP. The serial number is on Vector’s bottom.<br />
<br />
<h3>
<b>The Learning Phase</b></h3>
<div>
<b><br /></b></div>
First things first...we need a bunch of pictures from famous people...for that I relied on <a href="https://www.themoviedb.org/person?language=en-US&page=1" target="_blank">The Movie DB</a> website...<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiJdlZ_y0pymKdmkj6wWBM2iTTqgmio5q4iWUUMWut9V0K5-IfeHKC88mfh4SS-XRZ3K2BEmlErnRknxvVdxQbCaLC2_rrdS1Lq4XhpEO9D_As5_pooUDjn0dmlIyDjds2pvkfwDtPisV31/s1600/TheMovieDB.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="644" data-original-width="1035" height="248" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiJdlZ_y0pymKdmkj6wWBM2iTTqgmio5q4iWUUMWut9V0K5-IfeHKC88mfh4SS-XRZ3K2BEmlErnRknxvVdxQbCaLC2_rrdS1Lq4XhpEO9D_As5_pooUDjn0dmlIyDjds2pvkfwDtPisV31/s400/TheMovieDB.png" width="400" /></a></div>
<br />
I went and download almost randomly 100 images of both men and woman. I didn’t went into each person but rather saved the “thumbnails”.<br />
<br />
Now, there’s an SAP Leonardo API called <a href="https://api.sap.com/api/face_feature_extraction_api/resource" target="_blank">“Inference Service for Face Feature Extraction”</a> which basically grabs and image, determine if there’s a face or not and then extracts its features...like the color of the eyes, form on the mouth, hair and so on...and that information is returned in a nice although pretty much impossible to decipher Vector of Features. I mean...they look just like numbers...and they can mean anything :P<br />
<br />
Anyway...I created a folder called “People” and drop all the 100 images. So, next step is of course get all the features for all the images...and manually its obviously not only hard but pointless...it’s way better to optimize the process ;)<br />
<br />
One programming language that I grown to love is <a href="https://crystal-lang.org/" target="_blank">Crystal</a>...<b>Fast as C, slick as Ruby</b>, yep...pretty much a better way of doing Ruby :)<br />
<br />
Installation is pretty easy and you can find instructions <a href="https://crystal-lang.org/docs/installation/" target="_blank">here</a> but I’m using Ubuntu on VMWare, so here are the instruction for it…<br />
<br />
On a terminal window copy and paste this…<br />
<br />
<b>curl -sSL https://dist.crystal-lang.org/apt/setup.sh | sudo bash</b><br />
<br />
Then simply do this…<br />
<br />
<b>sudo apt-get update</b><br />
<b><br /></b>
<b>sudo apt install crystal</b><br />
<br />
Installation of the following modules is optional but recommended…<br />
<br />
<b>sudo apt install libssl-dev # for using OpenSSL</b><br />
<b>sudo apt install libxml2-dev # for using XML</b><br />
<b>sudo apt install libyaml-dev # for using YAML</b><br />
<b>sudo apt install libgmp-dev # for using Big numbers</b><br />
<b>sudo apt install libreadline-dev # for using Readline</b><br />
<br />
Once we’re done...it’s time to write the application…first create a folder called “Features”.<br />
<br />
Call your script <b>PeopleGenerator.cr</b> and copy and paste the following code…<br />
<br /></div>
<style type="text/css">
@page { size: 8.5in 11in; margin: 0.79in }
p { margin-bottom: 0.1in; line-height: 115%; background: transparent }
a:link { color: #000080; so-language: zxx; text-decoration: underline }
</style><style type="text/css">
@page { size: 8.5in 11in; margin: 0.79in }
p { margin-bottom: 0.1in; line-height: 115%; background: transparent }
a:link { color: #000080; so-language: zxx; text-decoration: underline }
</style>
<br />
<table align="center" style="width: 600px;">
<tbody>
<tr><th bgcolor="#6690BC">PeopleGenerator.cr</th>
</tr>
<tr>
<td><pre>require "http"
require "json"
class FaceFeature
JSON.mapping({
face_feature: Array(Float64)
})
end
class Predictions
JSON.mapping({
faces: Array(FaceFeature)
})
end
class Person
JSON.mapping({
id: String,
predictions: Array(Predictions)
})
end
folder = Dir.new("#{__DIR__}/People")
while photo = folder.read
if photo != "." && photo != ".." && photo != "Features"
io = IO::Memory.new
builder = HTTP::FormData::Builder.new(io)
File.open("#{__DIR__}/People/" + photo) do |file|
metadata = HTTP::FormData::FileMetadata.new(filename: photo)
headers = HTTP::Headers{"Content-Type" => "image/jpg"}
builder.file("files", file, metadata, headers)
end
builder.finish
headers = HTTP::Headers{"Content-Type" => builder.content_type,
"APIKey" => "YourAPIKey",
"Accept" => "application/json"}
response = HTTP::Client.post("https://sandbox.api.sap.com/ml/
facefeatureextraction/
face-feature-extraction", body: io.to_s ,
headers: headers)
feature_name = "#{__DIR__}/Features/" + File.basename(photo, ".jpg") + ".txt"
puts photo
File.write(feature_name, Person.from_json(response.body).predictions[0].
faces[0].face_feature)
sleep 2.second
end
end
command = "zip -r -j features.zip #{__DIR__}/Features"
Process.run("sh", {"-c", command})
puts "Done."
</pre>
</td>
</tr>
<tr>
</tr>
</tbody></table>
<br />
Let’s explain the code before we check the results…<br />
<br />
<b>require "http"</b><br />
<b>require "json"</b><br />
<br />
We need these two libraries to be able to call the SAP Leonardo API and also to be able to read and extract the results…<br />
<br />
<b>class FaceFeature</b><br />
<b> JSON.mapping({</b><br />
<b> face_feature: Array(Float64)</b><br />
<b> })</b><br />
<b>end</b><br />
<b><br /></b>
<b>class Predictions</b><br />
<b> JSON.mapping({</b><br />
<b><span style="white-space: pre;"> </span>faces: Array(FaceFeature)</b><br />
<b> })</b><br />
<b>end</b><br />
<b><br /></b>
<b>class Person</b><br />
<b> JSON.mapping({</b><br />
<b><span style="white-space: pre;"> </span>id: String,</b><br />
<b><span style="white-space: pre;"> </span>predictions: Array(Predictions)</b><br />
<b> })</b><br />
<b>end</b><br />
<br />
This is the JSON mapping that we need to use to extract the information coming back from the API.<br />
<br />
<b>folder = Dir.new("#{__DIR__}/People")</b><br />
<b>while photo = folder.read</b><br />
<b> if photo != "." && photo != ".." && photo != "Features"</b><br />
<b><span style="white-space: pre;"> </span>io = IO::Memory.new</b><br />
<b><span style="white-space: pre;"> </span>builder = HTTP::FormData::Builder.new(io)</b><br />
<b><br /></b>
<b><span style="white-space: pre;"> </span>File.open("#{__DIR__}/People/" + photo) do |file|</b><br />
<b><span style="white-space: pre;"> </span>metadata = HTTP::FormData::FileMetadata.new(filename: photo)</b><br />
<b><span style="white-space: pre;"> </span>headers = HTTP::Headers{"Content-Type" => "image/jpg"}</b><br />
<b><span style="white-space: pre;"> </span>builder.file("files", file, metadata, headers)</b><br />
<b><span style="white-space: pre;"> </span>end</b><br />
<b><span style="white-space: pre;"> </span>builder.finish</b><br />
<b><br /></b>
<b><span style="white-space: pre;"> </span>headers = HTTP::Headers{"Content-Type" => builder.content_type, "APIKey" => "YourAPIKey,"Accept" => "application/json"}</b><br />
<b><span style="white-space: pre;"> </span>response = HTTP::Client.post("https://sandbox.api.sap.com/ml/facefeatureextraction/face-feature-extraction", body: io.to_s , headers: headers)</b><br />
<span style="white-space: pre;"><b> </b></span><br />
<b><span style="white-space: pre;"> </span>feature_name = "#{__DIR__}/Features/" + File.basename(photo, ".jpg") + ".txt"</b><br />
<span style="white-space: pre;"><b> </b></span><br />
<b><span style="white-space: pre;"> </span>puts photo<span style="white-space: pre;"> </span></b><br />
<span style="white-space: pre;"><b> </b></span><br />
<b><span style="white-space: pre;"> </span>File.write(feature_name, Person.from_json(response.body).predictions[0].faces[0].face_feature)</b><br />
<b><span style="white-space: pre;"> </span>sleep 2.second</b><br />
<b> end</b><br />
<b>end</b><br />
<b><br /></b>
<b>command = "zip -r -j features.zip #{__DIR__}"</b><br />
<b>Process.run("sh", {"-c", command})</b><br />
<b><br /></b>
<b>puts "Done."</b><br />
<b><br /></b>
This section is larger, first we specify the folder from the images will be read. Then for each image we will if it’s a picture or a folder structure...of course we want images only…<br />
<br />
Then, we create a FormData builder in order to avoid having to base64 encode the images...put them in JSON payload and so on...this way is easier and native…<br />
<br />
We open each image and feed the FormData metadata and headers.<br />
<br />
Also, we need to pass the extra “headers” required by SAP Leonardo.<br />
<br />
Once that is done, we can simply call the REST API, and then we create a “Feature Name” which is going to be the name of the generated file...basically the image name with an “.txt” extension.<br />
<br />
For each file we’re going to extract the feature vector from the JSON response, write the file and give 2 seconds delay just to not overflow the API call…<br />
<br />
Once that’s done, we simply call a “zip” command from the terminal and zip it…<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjiEoYcKoa-2IE0eRH03s6zB1Dv4SiE-oUe5hPh5xEJg4Va03YVlFiXQyVnvXcBZs379jpTqeZNc-LfYhS1JfdGE-ZSWP1WRjsQ_xFmpntBqP_TuH5P8SXe8JU9SNqXe5Eu4wjPfx6HcwjW/s1600/FeaturesFiles.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="342" data-original-width="456" height="300" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjiEoYcKoa-2IE0eRH03s6zB1Dv4SiE-oUe5hPh5xEJg4Va03YVlFiXQyVnvXcBZs379jpTqeZNc-LfYhS1JfdGE-ZSWP1WRjsQ_xFmpntBqP_TuH5P8SXe8JU9SNqXe5Eu4wjPfx6HcwjW/s400/FeaturesFiles.png" width="400" /></a></div>
<br />
Now, the zip file will contain a 100 files...each with the features of all the images that we have on our “People” folder.<br />
<br />
Simply as that...we have trained our application ;)<br />
<br />
<h3>
<b>The Testing and Execution Phase</b></h3>
<br />
I know that usually you test your model first...but for this once...we can do both at the same time ;)<br />
<br />
We’re going to create a Python script that will deal with taking our picture...call the Features API on that image and then call another API to determine who we do look like…<br />
<br />
Let’s create a script called <b>GuessWho.py</b><br />
<b><br /></b>
<br />
<table align="center" style="width: 600px;">
<tbody>
<tr><th bgcolor="#6690BC">GuessWho.py</th>
</tr>
<tr>
<td><pre>import anki_vector
import threading
import requests
import os
import json
import time
import subprocess
import re
import math
from PIL import Image
from anki_vector.events import Events
from anki_vector.util import degrees
event_done = False
said_text = False
new_width = 184
new_height = 96
def main():
args = anki_vector.util.parse_command_args()
with anki_vector.Robot(args.serial, enable_face_detection=True,
enable_camera_feed=True) as robot:
evt = threading.Event()
def on_robot_observed_face(event_type, event):
global said_text
if not said_text
said_text = True
robot.say_text("Taking Picture!")
image = robot.camera.latest_image
image.save("Temp.png")
robot.say_text("Picture Taken!")
evt.set()
robot.behavior.set_head_angle(degrees(45.0))
robot.behavior.set_lift_height(0.0)
robot.events.subscribe(on_robot_observed_face, Events.robot_observed_face)
try:
if not evt.wait(timeout=10):
print("---------------------------------")
except KeyboardInterrupt:
pass
def guess_who():
args = anki_vector.util.parse_command_args()
with anki_vector.Robot(args.serial) as robot:
url = "https://sandbox.api.sap.com/ml/facefeatureextraction/
face-feature-extraction"
img_path = "Temp.png"
files = {'files': open (img_path, 'rb')}
headers = {
'APIKey': "YourAPIKey",
'Accept': "application/json",
}
response = requests.post(url, files=files, headers=headers)
robot.say_text("I'm processing your picture!")
json_response = json.loads(response.text)
json_text = json_response['predictions'][0]['faces'][0]['face_feature']
f = open("myfile.txt", "w")
f.write(str(json_text))
f.close()
time.sleep(1)
p = subprocess.Popen('zip -u features.zip myfile.txt', shell=True)
time.sleep(1)
url = "https://sandbox.api.sap.com/ml/similarityscoring/similarity-scoring"
files = {'files': ("features.zip", open ("features.zip", 'rb'),
'application/zip')}
params = {'options': '{"numSimilarVectors":100}'}
response = requests.post(url, data=params, files=files, headers=headers)
json_response = json.loads(response.text)
robot.say_text("I'm comparing your picture with one hundred other pictures!")
for x in range(len(json_response['predictions'])):
if json_response['predictions'][x]['id'] == "myfile.txt":
name, _ = os.path.splitext(json_response['predictions'][x]
['similarVectors'][0]['id'])
name = re.findall('[A-Z][^A-Z]*', name)
full_name = " ".join(name)
pic_name = "People/" + "".join(name) + ".jpg"
avg = json_response['predictions'][x]['similarVectors'][0]['score']
robot.say_text("You look like " + full_name +
" with a confidence of " +
str(math.floor(avg * 100)) + " percent")
image_file = Image.open(pic_name)
image_file = image_file.resize((new_width, new_height),
Image.ANTIALIAS)
screen_data = anki_vector.screen.convert_image_to_screen_data(
image_file)
robot.behavior.set_head_angle(degrees(45.0))
robot.conn.release_control()
time.sleep(1)
robot.conn.request_control()
robot.screen.set_screen_with_image_data(screen_data, 0.0)
robot.screen.set_screen_with_image_data(screen_data, 25.0)
print(full_name)
print(str(math.floor(avg * 100)) + " percent")
time.sleep(5)
if __name__ == '__main__':
main()
guess_who()
</pre>
</td>
</tr>
<tr>
</tr>
</tbody></table>
<br />
This script is bigger...so let’s make sure we understand everything that is going on…<br />
<br />
<b>import anki_vector</b><br />
<b>import threading</b><br />
<b>import requests</b><br />
<b>import os</b><br />
<b>import json</b><br />
<b>import time</b><br />
<b>import subprocess</b><br />
<b>import re</b><br />
<b>import math</b><br />
<b>from PIL import Image</b><br />
<b>from anki_vector.events import Events</b><br />
<b>from anki_vector.util import degrees</b><br />
<br />
That’s a lot of libraries :) The first one is pretty obvious...is how we can connect to Vector ;)<br />
<br />
The second one is to handle “threads” as we need to do a couple of things asynchronously.<br />
<br />
The third one is to handle the call to the APIs.<br />
<br />
The fourth one is to handle folder access.<br />
<br />
The fifth one is to handle the JSON response coming back from the API.<br />
<br />
The sixth one is so that we can have a delay in the execution of the application.<br />
<br />
The seventh is to be able to call terminal commands.<br />
<br />
The eight one is to use Regular Expressions.<br />
<br />
The ninth one is to handle math operations.<br />
<br />
The tenth one is to handle image operations.<br />
<br />
The eleventh is to handle events as we want Vector to try to detect our face.<br />
<br />
The last one is to be able to move Vectors face.<br />
<br />
<b>def main():</b><br />
<b> args = anki_vector.util.parse_command_args()</b><br />
<b> with anki_vector.Robot(args.serial, enable_face_detection=True, enable_camera_feed=True) as robot:</b><br />
<b> evt = threading.Event()</b><br />
<b><br /></b>
<b> def on_robot_observed_face(event_type, event):</b><br />
<b><br /></b>
<b> global said_text</b><br />
<b> if not said_text:</b><br />
<b> said_text = True</b><br />
<b> robot.say_text("Taking Picture!")</b><br />
<b> image = robot.camera.latest_image</b><br />
<b> image.save("Temp.png")</b><br />
<b> robot.say_text("Picture Taken!")</b><br />
<b> evt.set()</b><br />
<b><br /></b>
<b> robot.behavior.set_head_angle(degrees(45.0))</b><br />
<b> robot.behavior.set_lift_height(0.0)</b><br />
<b><br /></b>
<b> robot.events.subscribe(on_robot_observed_face, Events.robot_observed_face)</b><br />
<b><br /></b>
<b> try:</b><br />
<b> if not evt.wait(timeout=5):</b><br />
<b> print("---------------------------------")</b><br />
<b> except KeyboardInterrupt:</b><br />
<b> pass</b><br />
<b><br /></b>
This one is for sure...our main event :) Here we’re going to open a connection with Vector, and as we can have multiple Vectors...we need to grab the serial number to specify which one we want to use...also we need to activate both face detection and camera feed.<br />
<br />
We’re going to start a thread as we need to call an event where Vector tries to detect our face. If he can see us, then he will say “Taking Picture!”...grab the image, save it and then say “Picture Taken!”. After that the event is done...but...while this is happening we can move his head and drop down his handle so that he can see us better.<br />
<br />
As you can see we’re subscribed to two events, one to observe our face and the other when our face is there and visible…<br />
<br />
<b>def guess_who():</b><br />
<b> args = anki_vector.util.parse_command_args()</b><br />
<b> with anki_vector.Robot(args.serial) as robot:<span style="white-space: pre;"> </span></b><br />
<b> url = "https://sandbox.api.sap.com/ml/facefeatureextraction/face-feature-extraction"</b><br />
<b> </b><br />
<b> img_path = "Temp.png"</b><br />
<b> files = {'files': open (img_path, 'rb')}</b><br />
<b><br /></b>
<b> headers = {</b><br />
<b> 'APIKey': "YourAPIKey",</b><br />
<b> 'Accept': "application/json",</b><br />
<b> }</b><br />
<span style="white-space: pre;"><b> </b></span><br />
<b> response = requests.post(url, files=files, headers=headers)</b><br />
<b><br /></b>
<b> robot.say_text("I'm processing your picture!")</b><br />
<span style="white-space: pre;"><b> </b></span><br />
<b> json_response = json.loads(response.text)</b><br />
<b> json_text = json_response['predictions'][0]['faces'][0]['face_feature']</b><br />
<span style="white-space: pre;"><b> </b></span><br />
<b> f = open("myfile.txt", "w")</b><br />
<b> f.write(str(json_text))</b><br />
<b> f.close()</b><br />
<span style="white-space: pre;"><b> </b></span><br />
<b> time.sleep(1)</b><br />
<span style="white-space: pre;"><b> </b></span><br />
<b> p = subprocess.Popen('zip -u features.zip myfile.txt', shell=True)</b><br />
<span style="white-space: pre;"><b> </b></span><br />
<b> time.sleep(1)</b><br />
<span style="white-space: pre;"><b> </b></span><br />
<b> url = "https://sandbox.api.sap.com/ml/similarityscoring/similarity-scoring"</b><br />
<span style="white-space: pre;"><b> </b></span><br />
<b> files = {'files': ("features.zip", open ("features.zip", 'rb'), 'application/zip')}</b><br />
<b> params = {'options': '{"numSimilarVectors":100}'}</b><br />
<span style="white-space: pre;"><b> </b></span><br />
<b> response = requests.post(url, data=params, files=files, headers=headers)</b><br />
<b> json_response = json.loads(response.text)</b><br />
<b><br /></b>
<b> robot.say_text("I'm comparing your picture with one hundred other pictures!")</b><br />
<b><br /></b>
<b> for x in range(len(json_response['predictions'])):</b><br />
<b> if json_response['predictions'][x]['id'] == "myfile.txt":</b><br />
<b> name, _ = os.path.splitext(json_response['predictions'][x]['similarVectors'][0]['id']) </b><br />
<b> name = re.findall('[A-Z][^A-Z]*', name)</b><br />
<b> full_name = " ".join(name)</b><br />
<b> pic_name = "People/" + "".join(name) + ".jpg"</b><br />
<b> avg = json_response['predictions'][x]['similarVectors'][0]['score']</b><br />
<b> robot.say_text("You look like " + full_name + " with a confidence of " + str(math.floor(avg * 100)) + " percent")</b><br />
<b> image_file = Image.open(pic_name)</b><br />
<b> image_file = image_file.resize((new_width, new_height), Image.ANTIALIAS) </b><br />
<b> screen_data = anki_vector.screen.convert_image_to_screen_data(image_file)</b><br />
<b> robot.behavior.set_head_angle(degrees(45.0))</b><br />
<b> robot.conn.release_control()</b><br />
<b> time.sleep(1)</b><br />
<b> robot.conn.request_control() </b><br />
<b> robot.screen.set_screen_with_image_data(screen_data, 0.0)</b><br />
<b> robot.screen.set_screen_with_image_data(screen_data, 25.0)</b><br />
<b> </b><br />
<b> print(full_name)</b><br />
<b> print(str(math.floor(avg * 100)) + " percent")</b><br />
<b><br /></b>
<b> time.sleep(5)</b><br />
<br />
This method will handle to rough parts of our application…<br />
<br />
We connect to Vector once again...although this time we don’t need to activate anything as the picture has been already taken.<br />
<br />
We pass the URL for the features API.<br />
<br />
Then we open our “Temp.png” file which is the image that Vector took from us.<br />
<br />
We need to pass the extra header for the SAP Leonardo API.<br />
<br />
We call the API and get the JSON response.<br />
<br />
Again, we need to extract the feature information from the JSON response. This time however we’re going to create a single file called “myfile.txt”. We going to make the application sleep for a second and then call a terminal process to add “myfile.txt” to our Features.zip file…<br />
<br />
Then we sleep again for another second...and this is just not to overflow the API calls…<br />
<br />
Here, we’re going to call a different API which is called <a href="https://sandbox.api.sap.com/ml/similarityscoring/similarity-scoring" target="_blank">Inference Service for Similarity Scoring</a><br />
<br />
This API will read all the 101 features files and determine the cosine distance (-1 to 1) from each file compared to one another. This way it can determine which files are closer to each other and hence to whom do we resemble the most...providing us with a percentage of confidence.<br />
<br />
This call is a little bit more complicated that the previous one as we need to upload the zip file…<br />
<br />
<b> files = {'files': ("features.zip", open ("features.zip", 'rb'), 'application/zip')}</b><br />
<b> params = {'options': '{"numSimilarVectors":100}'}</b><br />
<span style="white-space: pre;"><b> </b></span><br />
<b> response = requests.post(url, data=params, files=files, headers=headers)</b><br />
<b> json_response = json.loads(response.text)</b><br />
<br />
Take into account that while we have 101 files...we need to compare 1 file against 100 others...so we pass 100 as the “numSimilarVectors”.<br />
<br />
Once we done that, we need to read each section from the JSON response until we find the id that have the value of “myfile.txt”. Once we have that, we use a Regular Expression to extract only the name without the extension. Also, we need to have the name of the image...so in the end we need to have something like this…<br />
<br />
<b>full_name = “Nicolas Cage”</b><br />
<b>pic_name = “People/NicolasCage.jpg”</b><br />
<br />
We need to extract the percentage of confidence as well…<br />
<br />
<b>avg = json_response['predictions'][x]['similarVectors'][0]['score'] </b><br />
<br />
So, we can have Vector saying “You look like Nicolas Cage with a confidence of 75 percent”.<br />
<br />
Now...here’s come the fun part ;) We already know how do we look like...but let’s say...we don’t really remember how Nicolas Cage looks like...so let’s take advantage of Vector’s fancy screen and display it there ;) By the way...we need to release control, gain it back and display the image for zero seconds and then re-display it...this is mainly because Vector’s eyes keep blocking the image on the screen...and this a way to prevent that behavior ;)<br />
<br />
<b> <span style="white-space: pre;"> </span> image_file = Image.open(pic_name)</b><br />
<b> image_file = image_file.resize((new_width, new_height), Image.ANTIALIAS) </b><br />
<b> screen_data = anki_vector.screen.convert_image_to_screen_data(image_file)</b><br />
<b> robot.behavior.set_head_angle(degrees(45.0))</b><br />
<b> robot.conn.release_control()</b><br />
<b> time.sleep(1)</b><br />
<b> robot.conn.request_control() </b><br />
<b> robot.screen.set_screen_with_image_data(screen_data, 0.0)</b><br />
<b> robot.screen.set_screen_with_image_data(screen_data, 25.0)</b><br />
<br />
First we open the image, then we resize it so it fits on the screen, then we convert it to Vector’s format and finally we display it on the screen, specifying for how long we want it there…<br />
<br />
<b> print(full_name)</b><br />
<b> print(str(math.floor(avg * 100)) + " percent")</b><br />
<b><br /></b>
<b> time.sleep(5)</b><br />
<br />
We print some information on the screen and then sent it to sleep for 5 seconds so the image doesn’t disappear too quickly ;)<br />
<br />
Finally! The most important part of the whole script...calling the functions :P<br />
<br />
<b>if __name__ == '__main__':</b><br />
<b> main()</b><br />
<b> guess_who()</b><br />
<br />
And that’s pretty much it :) We open a terminal window and type…<br />
<br />
<b>python3 GuessWho.py</b><br />
<br />
Vector is going to try to look at us and detect our face...he will take a picture...SAP Leonardo APIs are going to be called...we will listened and see who do we look like ;)<br />
<br />
Hope you enjoyed this blog...I obviously did :D<br />
<br />
And just to wrap up things...here’s a small video…<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<iframe allowfullscreen="" class="YOUTUBE-iframe-video" data-thumbnail-src="https://i.ytimg.com/vi/QcV1FT0SS8s/0.jpg" frameborder="0" height="266" src="https://www.youtube.com/embed/QcV1FT0SS8s?feature=player_embedded" width="320"></iframe></div>
<br />
BTW...this is the picture that Vector took of me...<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgcO-fqMLgshnTMkg82RzqUYT5AzqyNUIjVm9HjTjvWmThok77fuk7Xu_hulIgfdsCmxfIcmaQ6YvClBq9YTkWubnp22h_NPAXkW_jo8Qn4od-wmB3J1UWYDvMkH95KYtdZc9I-0KNrw-ND/s1600/Temp.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="360" data-original-width="640" height="180" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgcO-fqMLgshnTMkg82RzqUYT5AzqyNUIjVm9HjTjvWmThok77fuk7Xu_hulIgfdsCmxfIcmaQ6YvClBq9YTkWubnp22h_NPAXkW_jo8Qn4od-wmB3J1UWYDvMkH95KYtdZc9I-0KNrw-ND/s320/Temp.png" width="320" /></a></div>
<br />
Greetings,<br />
<br />
Blag.<br />
SAP Labs Network.Alvaro "Blag" Tejada Galindohttp://www.blogger.com/profile/12061593528820409779noreply@blogger.com0tag:blogger.com,1999:blog-4144704359177008692.post-52377617237449710742018-09-19T11:05:00.000-07:002018-09-19T11:05:06.702-07:00SAP Leonardo Machine Learning API’s on the Go<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjSld6PFrOpgmVXAu1IlMqvDyKshoMRyzcy4BmUAbiC3XVgEEybZ-852FvdV8Lz9QlYLPEZnJ1jJDK3b1Fnyuh8VnvaKdvKsk_49J6Tmd-FpRZjDSx04qDBIG45xMuusNKXxWaLKGJP7Occ/s1600/d_shop_blog_logoToronto.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="173" data-original-width="493" height="140" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjSld6PFrOpgmVXAu1IlMqvDyKshoMRyzcy4BmUAbiC3XVgEEybZ-852FvdV8Lz9QlYLPEZnJ1jJDK3b1Fnyuh8VnvaKdvKsk_49J6Tmd-FpRZjDSx04qDBIG45xMuusNKXxWaLKGJP7Occ/s400/d_shop_blog_logoToronto.png" width="400" /></a></div>
<br />
<div style="text-align: justify;">
Working for the d-shop, first in the Silicon Valley and now in Toronto, allows me to use my creativity and grab any new gadget that hits the market.</div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
This time, it was <a href="https://www.oculus.com/go/" target="_blank">Oculus Go</a>’s turn 😉 and what’s the Oculus Go? Well, it is an Standalone VR headset, which basically means…no tangled cables 😉</div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
For this project I had the chance to work with either <a href="https://unity3d.com/" target="_blank">Unity</a> or <a href="https://www.unrealengine.com/en-US/what-is-unreal-engine-4" target="_blank">Unreal Engine</a>…I had used Unity many times to develop <a href="https://www.oculus.com/" target="_blank">Oculus Rift</a> and <a href="https://www.microsoft.com/en-CA/hololens" target="_blank">Microsoft HoloLens</a> applications…so I thought Unreal Engine would be a better choice this time…although I have never used it in a big project before…specially because nothing beats Unreal when it comes to graphics…</div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
With Unreal chosen…I needed to make another decision…C++ or Blueprints…well…while I have used C++ in the past for a couple of <a href="https://libcinder.org/" target="_blank">Cinder</a> applications…Blueprints looked better as I wanted to develop faster and without too many complications…and well…that’s half of the truth…sometimes Blueprints can become really messy 😊</div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
Just so you know, I used Unreal Engine 4.20.2 and created a Blueprints application.</div>
<div style="text-align: justify;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhS5S_bIUOjnbCiBefxG4pbeRNeE0s7yYZfajn5gQK9Nsa3Ns0WPrhyZM__3l6aZpvAoLDpZwHxxGPtwCUKaFM-3niAePcrusp8DaMl_QOdu0b3UxjdM095ZWqbkGqeVuqxMLLJ4obcvsFz/s1600/Unreal4_20_2.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="163" data-original-width="244" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhS5S_bIUOjnbCiBefxG4pbeRNeE0s7yYZfajn5gQK9Nsa3Ns0WPrhyZM__3l6aZpvAoLDpZwHxxGPtwCUKaFM-3niAePcrusp8DaMl_QOdu0b3UxjdM095ZWqbkGqeVuqxMLLJ4obcvsFz/s1600/Unreal4_20_2.jpg" /></a></div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
<div class="MsoNormal">
Since the beginning I knew that I
wanted to use <a href="https://api.sap.com/package/SAPLeonardoMLFunctionalServices?section=Artifacts" target="_blank">SAP Leonardo Machine Learning API’s</a>…as I used them before for my
blog “<a href="http://blagrants.blogspot.com/2018/07/cozmo-read-to-me.html" target="_blank">Cozmo, read to me</a>” where I used a <a href="https://www.anki.com/en-ca/cozmo" target="_blank">Cozmo</a> Robot, OpenCV and SAP Leonardo’s OCR API to read a
whiteboard with a handwritten message and have Cozmo read it out loud.<o:p></o:p></div>
<div class="MsoNormal">
<br /></div>
<div class="MsoNormal">
<b><span style="font-size: large;">The idea</span></b></div>
<div class="MsoNormal">
<br /></div>
<div class="MsoNormal">
This time, I wanted to showcase more than just one API…so I needed to choose which ones…gladly that wasn’t really hard…most API are more “Enterprise” oriented…so that left me with “Image Classification, OCR and Language Translation” …</div>
<div class="MsoNormal">
<br /></div>
<div class="MsoNormal">
With all decided…I still needed to figure out how to use those API’s…I mean…Oculus Go is Virtual Reality…so no chance of looking at something, taking a picture and send it to the API…</div>
<div class="MsoNormal">
<br /></div>
<div class="MsoNormal">
So, I thought…why don’t I use <a href="https://www.blender.org/" target="_blank">Blender</a> (which is an Open-Source 3D computer graphics software toolset) and make some models…then I can render those models…take a picture and send it to the API…and having models means…I could turn them into “.fbx” files and load them into Unreal for a nicer experience…</div>
<div class="MsoNormal">
<br /></div>
<div class="MsoNormal">
With the OCR and Language Translation API’s…it was different…as I needed images with text…so I decided to use <a href="https://inkscape.org/en/" target="_blank">InkScape</a> (which is an Open-Source Vector Graphics Editor).</div>
<div>
<br /></div>
<div>
<div>
<b><span style="font-size: large;">The implementation</span></b></div>
<div>
<br /></div>
<div>
When I first started working on the project…I knew I needed to start step by step…so I first did a Windows version of the App…then ported it to Android (Which was pretty easy BTW) and finally ported it to Oculus Go (Which was kind of painful…)</div>
<div>
<br /></div>
<div>
So, sadly I’m not going to be able to put any source code here…simply because I used Blueprints…and I’m not sure if you would like to reproduce them by hand ☹ You will see what I mean later on this blog…</div>
<div>
<br /></div>
<div>
Anyway…let’s keep going 😊</div>
<div>
<br /></div>
<div>
When I thought about this project, the first thing that came into my mind was…I want to have a d-shop room…with some desks…a sign for each API…some lights would be nice as well…</div>
</div>
<div>
<br /></div>
</div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjuGHObrpAE85X8UEXrKBo4JB5iYc5V_m1Bi_Kgij5Jy59SsYf5fam7o6oauqaE9pHKs6opCpgumWhnaejP3aUmy9r3YfGHQ8Xf_jjyg_Sx1QF-oJQlt0oQsSxLfJPAyF6SYuR9ksp3hy60/s1600/SAPLeonardoGo_ShowFloor.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="579" data-original-width="1209" height="191" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjuGHObrpAE85X8UEXrKBo4JB5iYc5V_m1Bi_Kgij5Jy59SsYf5fam7o6oauqaE9pHKs6opCpgumWhnaejP3aUmy9r3YfGHQ8Xf_jjyg_Sx1QF-oJQlt0oQsSxLfJPAyF6SYuR9ksp3hy60/s400/SAPLeonardoGo_ShowFloor.jpg" width="400" /></a></div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
<div>
So, doesn’t look that bad, huh?</div>
<div>
<br /></div>
<div>
Next, I wanted to work on the “Image Classification” API…so I wanted to be fairly similar…but with only one desk in the middle…which later turned into a pedestal…with the 3D objects rotating on top of it…the it should be a space ready to show the results back from the API…also…arrows to let the user change the 3D model…and a house icon to allow the user to go back to the “Showfloor”…</div>
<div>
<br /></div>
<div>
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjycD6xTO-7LaEGwkdTYoFaXEzoM-Mk4Q4-dxz9nLc48CXbjjBwCRpKpMZK-_ANCXgJeB4rgG7IxcBDOzUSsSB2YvsFR7mjv0u_R96uk6W2VY-rX7YTdRwxP3TL_xYX8znB5URNl59ondQV/s1600/ImageClassificationEditor.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="572" data-original-width="1204" height="190" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjycD6xTO-7LaEGwkdTYoFaXEzoM-Mk4Q4-dxz9nLc48CXbjjBwCRpKpMZK-_ANCXgJeB4rgG7IxcBDOzUSsSB2YvsFR7mjv0u_R96uk6W2VY-rX7YTdRwxP3TL_xYX8znB5URNl59ondQV/s400/ImageClassificationEditor.jpg" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div>
<div>
You will notice two things right away…first…what does that ball supposed to be? Well…that’s just a placeholder that will be replaced by the 3D Models 😊 Also…you can see a black poster that says “SAP Leonardo Output”…that’s hidden and only become available when we launch the application…</div>
<div>
<br /></div>
<div>
For the “Optical Character Recognition” and “Language Translation” scenes…it’s pretty much the same although the last one doesn't have arrows 😊</div>
</div>
<div>
<br /></div>
<div>
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiw4WM0b63Rw_fIKYCeBuN-OP-u2vITNgAEursHbaZ7bBwhyt7hzkTQK9YpJqG7kBReM4HZCf51PBx9s5ZCDmg_OAr96dMB7BXpxhPowu4_JkT8uk9odT6WIjkD-NOmK0Dc3C4cdcCLVw1M/s1600/LanguageTranslationEditor.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="573" data-original-width="1206" height="190" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiw4WM0b63Rw_fIKYCeBuN-OP-u2vITNgAEursHbaZ7bBwhyt7hzkTQK9YpJqG7kBReM4HZCf51PBx9s5ZCDmg_OAr96dMB7BXpxhPowu4_JkT8uk9odT6WIjkD-NOmK0Dc3C4cdcCLVw1M/s400/LanguageTranslationEditor.jpg" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div>
<div>
<b><span style="font-size: large;">The problems</span></b></div>
<div>
<br /></div>
<div>
So that’s pretty much how the scenes are related…but of course…I hit the first issue fast…how to call the API’s using Blueprints? I looked online and most of the plugins are paid ones…but gladly I found a free one that really surprised me…<a href="https://github.com/RVillani/UnrealJSONQuery" target="_blank">UnrealJSONQuery</a> works like a charm is not that hard to use…but of course…I needed to change a couple of things in the source code (like adding the header for the key and changing the parameter to upload files). Then I simply recompiled it and voila! I got JSON on my application 😉</div>
<div>
<br /></div>
<div>
But you want to know what I changed, right? Sure thing 😊 I simply unzip the file and went to JSONQuery --> Source --> JSONQuery --> Private and opened JsonFieldData.cpp</div>
<div>
<br /></div>
<div>
Here I added a new header with (“APIKey”, “MySAPLeonardoAPIKey”) and then I looked for PostRequestWithFile and change the “file” parameter to “files”…</div>
<div>
<br /></div>
<div>
To compile the source code, I simply created a create a new C++ project, then a “plugins” folder in the root folder of my project and put everything from the downloaded folder…open the project…let it compiled and then I re-created everything from my previous project…once that was done…everything started to work perfectly…</div>
<div>
<br /></div>
<div>
So, let’s see part of the Blueprint used to call the API…</div>
</div>
<div>
<br /></div>
<div>
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhRkI2pUILthiGkmKx7TbLqnZ4bw2d2NBITYSsPk8VvS0WIg_OGFkyZJIoSA0QOfLe0JJdPN8vaA51VlGqO8fNwzBqMHHLLAGnQd0bSJjb1hMaYXZttPNp7UBEx-1aFWaMNh9X4oyw5Rpr1/s1600/LanguageTranslationBlueprint.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="735" data-original-width="1243" height="236" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhRkI2pUILthiGkmKx7TbLqnZ4bw2d2NBITYSsPk8VvS0WIg_OGFkyZJIoSA0QOfLe0JJdPN8vaA51VlGqO8fNwzBqMHHLLAGnQd0bSJjb1hMaYXZttPNp7UBEx-1aFWaMNh9X4oyw5Rpr1/s400/LanguageTranslationBlueprint.jpg" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both;">
Basically, we need to create the JSON, call the API and then read the result and extract the information.</div>
<div class="separator" style="clear: both;">
<br /></div>
<div class="separator" style="clear: both;">
Everything was going fine and dandy…until I realized that I needed to package the 3D images generated by Blender…I had no idea how to do it…so gladly…the <a href="https://github.com/EverNewJoy/VictoryPlugin" target="_blank">Victory Plugin</a> came to the rescue 😉 Victory has some nodes that allows you to read many directories from inside the generated application…so I was all set 😊</div>
<div class="separator" style="clear: both;">
<br /></div>
<div class="separator" style="clear: both;">
This is how the Victory plugin looks like when using it in a Blueprint…</div>
<div class="separator" style="clear: both;">
<br /></div>
<div>
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi7VF5xQ7ZKb2KBwGhgczEVbpqUa3yde79MZdpmagj62vRkyn3RAQeHhhadcYYwQR9d2sIAkqWPAv8FPAWlFKOOBB1H5k0WzkSnHV3ju1YYceTleRuTA4KpvDM6IVaTKK97tquHpZ-X8WUZ/s1600/VictoryBlueprint.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="557" data-original-width="781" height="285" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi7VF5xQ7ZKb2KBwGhgczEVbpqUa3yde79MZdpmagj62vRkyn3RAQeHhhadcYYwQR9d2sIAkqWPAv8FPAWlFKOOBB1H5k0WzkSnHV3ju1YYceTleRuTA4KpvDM6IVaTKK97tquHpZ-X8WUZ/s400/VictoryBlueprint.jpg" width="400" /></a></div>
<div>
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both;">
<b><span style="font-size: large;">The Models</span></b></div>
<div class="separator" style="clear: both;">
<br /></div>
<div class="separator" style="clear: both;">
For the 3D Models as I said…I used Blender…I modeled them using “Cycles Render”, baked the materials and then render the image using “Blender Render” to be able to generate the .fbx files…</div>
<div>
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiRgQFdofmyX_4twkovKkPtUfDRzzd_2lnePUltSe9e-4iRFm2Lmz3xPleMKGJ97nSJPPXL20bcUVOHXDeJW1F5dXpKg1D1RkgevV5bYIse9UHdxDmQWutVQSrKVvXk00L29Z-WzHpqljWe/s1600/BlenderApples.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="890" data-original-width="1449" height="245" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiRgQFdofmyX_4twkovKkPtUfDRzzd_2lnePUltSe9e-4iRFm2Lmz3xPleMKGJ97nSJPPXL20bcUVOHXDeJW1F5dXpKg1D1RkgevV5bYIse9UHdxDmQWutVQSrKVvXk00L29Z-WzHpqljWe/s400/BlenderApples.jpg" width="400" /></a></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEisHy7oigAaXju2Lr9DAL2mJeFZIGPMrlx-VHL149qC0HZggiVWf5TG19RqLwP68yo1_vyxbYvT9UxdmVrC_NEsga1Hlu1rADkBYjGDQCpWDJvSsNrt3omzTn9a5IaFLxwHrXp5UuUvsigi/s1600/Bowl_Apples_BlenderRender.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="682" data-original-width="1210" height="225" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEisHy7oigAaXju2Lr9DAL2mJeFZIGPMrlx-VHL149qC0HZggiVWf5TG19RqLwP68yo1_vyxbYvT9UxdmVrC_NEsga1Hlu1rADkBYjGDQCpWDJvSsNrt3omzTn9a5IaFLxwHrXp5UuUvsigi/s400/Bowl_Apples_BlenderRender.jpg" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: justify;">
<br /></div>
<div>
<div>
If the apples look kind of metallic or wax like…blame my poor lighting skills ☹</div>
<div>
<br /></div>
<div>
When loaded into Unreal…the models look really nice…</div>
</div>
<div>
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEigfpkqLmjiPmLbZd5tgUSFEUEKekSKRkM2JPk3OwR5yktr7aOk8pI9tfHWqh0zjNKOA7YFNp_QCHTAvlLEag3prJquQuwyGlrilRmdl3CNRwOGcXJwSEZ6CiqbFMoUGcOT1ZkrQeemA1Of/s1600/DeskModel.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="703" data-original-width="1600" height="175" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEigfpkqLmjiPmLbZd5tgUSFEUEKekSKRkM2JPk3OwR5yktr7aOk8pI9tfHWqh0zjNKOA7YFNp_QCHTAvlLEag3prJquQuwyGlrilRmdl3CNRwOGcXJwSEZ6CiqbFMoUGcOT1ZkrQeemA1Of/s400/DeskModel.jpg" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: justify;">
Now…I know you want to see how a full Blueprint screen looks like…this one is for the 3D Models on the Image Classification scene…</div>
<div class="separator" style="clear: both; text-align: justify;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh7lUlROXoMkJrRtBezCFZpc6H2GfoGpy3PeKVPkmdsOm2kweoZyCSpx9RckWGp447hUUHNC7qZbWKYOfsPDEwRZv2jGl1C_VKmxPS33c3atx4xFSg2DgJdARbvMT984UqQNHamoO5L77ua/s1600/3DModel_Blueprint_Full.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="742" data-original-width="1143" height="258" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh7lUlROXoMkJrRtBezCFZpc6H2GfoGpy3PeKVPkmdsOm2kweoZyCSpx9RckWGp447hUUHNC7qZbWKYOfsPDEwRZv2jGl1C_VKmxPS33c3atx4xFSg2DgJdARbvMT984UqQNHamoO5L77ua/s400/3DModel_Blueprint_Full.jpg" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both;">
Complicated? Well...kind of…usually Blueprints are like that…but they are pretty powerful…</div>
<div class="separator" style="clear: both;">
<br /></div>
<div class="separator" style="clear: both;">
Here’s another one…this time for the “Right Arrow” which allows us to change models…</div>
<div class="separator" style="clear: both;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh7wd7eUowpKribFehVkJMK83nlyS4h-16r5RtsJk3kGe4b1lWsQ6jS082At4RmXAWh3j3yvz14qgCtIBLt5xBOkuSnYJL_OTti3wSj52ZlynefTimzAzH_gZNd1u4RD0yvfNHPmjB8xe52/s1600/ImageClassificationRightArrow.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="738" data-original-width="1143" height="257" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh7wd7eUowpKribFehVkJMK83nlyS4h-16r5RtsJk3kGe4b1lWsQ6jS082At4RmXAWh3j3yvz14qgCtIBLt5xBOkuSnYJL_OTti3wSj52ZlynefTimzAzH_gZNd1u4RD0yvfNHPmjB8xe52/s400/ImageClassificationRightArrow.jpg" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: justify;">
Looks weird…but works just fine 😉</div>
<div class="separator" style="clear: both; text-align: justify;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg9I196g9-9Dw5BGG6zNJiWtPzKMcr0BBPFZ_Gp7DZj-8zn51k-EzwvBQ90tndf24i06toPD1-fBGC4rQdLGJpVq9o6dhAjsN3xIuIHlIfb3XI5Z52783irCBGlxzYczZEqnlNhbLXUhGPG/s1600/ImageClassificationModel.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="578" data-original-width="1207" height="191" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg9I196g9-9Dw5BGG6zNJiWtPzKMcr0BBPFZ_Gp7DZj-8zn51k-EzwvBQ90tndf24i06toPD1-fBGC4rQdLGJpVq9o6dhAjsN3xIuIHlIfb3XI5Z52783irCBGlxzYczZEqnlNhbLXUhGPG/s400/ImageClassificationModel.jpg" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both;">
You may realize that both “Image Classification” and “OCR” both have Right and Left arrows…so I needed to do some reuse of variables and they needed to be shared between Blueprints…so…for that I created a “Game Instance” where I simply create a bunch of public variables that could be then shared and updated.</div>
<div class="separator" style="clear: both;">
<br /></div>
<div class="separator" style="clear: both;">
If you wonder what I used Inkscape for? Well…I wanted to have a kind of Neon Sign image and a handwritten image…</div>
<div>
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj6tby4Ai2uX-7LG_0dl0b4bNwHzE0ROCAl6JgsDOpikt8AtCWwMNurNhHn6w51qnPWgRjAxQcwqf0AjfIPnVZvLWrCAlK4Gjzu6i5jlZYAy0c72fUZ5cBQyfjaMKKYN6Bg9fEI0CZXdWil/s1600/InkscapeNeon.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1039" data-original-width="1225" height="338" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj6tby4Ai2uX-7LG_0dl0b4bNwHzE0ROCAl6JgsDOpikt8AtCWwMNurNhHn6w51qnPWgRjAxQcwqf0AjfIPnVZvLWrCAlK4Gjzu6i5jlZYAy0c72fUZ5cBQyfjaMKKYN6Bg9fEI0CZXdWil/s400/InkscapeNeon.jpg" width="400" /></a></div>
<div>
<br /></div>
<div class="separator" style="clear: both;">
<br /></div>
<div class="separator" style="clear: both;">
<b><span style="font-size: large;">From Android to Oculus Go</span></b></div>
<div class="separator" style="clear: both;">
<br /></div>
<div class="separator" style="clear: both;">
You may wonder…why does it changed from Android to the Oculus Go? Aren’t they both Android based? Well…yes…but still…thanks to personal experience…I know that things change a lot…</div>
<div class="separator" style="clear: both;">
<br /></div>
<div class="separator" style="clear: both;">
First…on Android…I created the scenes…and everything was fine…on the Oculus Go…no new scenes were loaded…when I clicked on a sign…the first level loaded itself… ☹ Why? Because I needed to include them in the arrays of scenes to be packaged…</div>
<div class="separator" style="clear: both;">
<br /></div>
<div class="separator" style="clear: both;">
And the funny thing is that the default projects folder for Unreal is “Documents”…so when I tried to add the scene it complained because the path was too long…so I need to clone the project and move it a folder on C:\</div>
<div class="separator" style="clear: both;">
<br /></div>
<div class="separator" style="clear: both;">
Also…when switching from Windows to Android…it was a simple as changing the “Click” to “Touch”…but for Oculus Go…well…I needed to create a “Pawn”…where I put a camera, a motion controller, and a pointer (acting like a laser pointer)…here I switch the “Touch” for a “Motion Controller Thumbstick”…and then from here I needed to control all the navigation details…very tricky…</div>
<div class="separator" style="clear: both;">
<br /></div>
<div class="separator" style="clear: both;">
Another thing that changed completely was the “SAP Leonardo Output”…let’s see how that looked on Android…</div>
<div>
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjDQEXG3L6EVVqHPz0edSSwudEklF08lRaLtUGJd5l2AdGfZ-do6GvNscNAZRDE2ADv_R5tmju7bgKiDbWHYZAMa7BW51m7LO5-gLePeYHfQenTnhZ9HXTTuf2rhUHkAbwdJyLsn0lVcZuk/s1600/SAPLeonardoMobile_04.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="800" data-original-width="1280" height="250" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjDQEXG3L6EVVqHPz0edSSwudEklF08lRaLtUGJd5l2AdGfZ-do6GvNscNAZRDE2ADv_R5tmju7bgKiDbWHYZAMa7BW51m7LO5-gLePeYHfQenTnhZ9HXTTuf2rhUHkAbwdJyLsn0lVcZuk/s400/SAPLeonardoMobile_04.jpg" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both;">
Here you can see that I used a “HUD”…so wherever you look…the HUD will go with you…</div>
<div class="separator" style="clear: both;">
<br /></div>
<div class="separator" style="clear: both;">
On the Oculus Go…this didn’t happen at all…first I needed to put a black image as a background…</div>
<div class="separator" style="clear: both;">
<br /></div>
<div class="separator" style="clear: both;">
Then I needed to create an actor and then put the HUD inside…turning it on a 3D HUD…</div>
<div class="separator" style="clear: both;">
<br /></div>
<div>
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi6E2Qp40fI2NgJ1FH3j2ohxBm4WDzEgHBza0_zOUvJ95BgiDz9woFUbYFlTlebJrRyf6XjfbBcmW1w-tog9hHCoHxqLYuKpCGBZq_JZfTTEQriHjLaPXXcOlzSafvycaIrq5cqtS6t7Mr-/s1600/ImageClassificationModelMsg.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="578" data-original-width="1209" height="190" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi6E2Qp40fI2NgJ1FH3j2ohxBm4WDzEgHBza0_zOUvJ95BgiDz9woFUbYFlTlebJrRyf6XjfbBcmW1w-tog9hHCoHxqLYuKpCGBZq_JZfTTEQriHjLaPXXcOlzSafvycaIrq5cqtS6t7Mr-/s400/ImageClassificationModelMsg.jpg" width="400" /></a></div>
<div>
<br /></div>
<div>
<br /></div>
<div>
<div>
<b><span style="font-size: large;">The final product</span></b></div>
<div>
<br /></div>
<div>
When everything was done…I simply packaged my app and load it into the Oculus Go…and by using <a href="https://www.vysor.io/" target="_blank">Vysor</a> I was able to record a simple session so you can see how this looks in real life 😉 Of course…the downside (Because first…I’m lazy to keep figuring out things and second because it’s too much hassle) is that you need to run this from the “Unknown Sources” section on the Oculus Go…but…it’s there and working and that’s all that matters 😉</div>
<div>
<br /></div>
<div>
Here’s the video so you can fully grasp what this application is all about 😊</div>
</div>
<div>
<br /></div>
<div class="separator" style="clear: both;">
<br /></div>
<div style="text-align: center;">
<iframe allowfullscreen="" class="YOUTUBE-iframe-video" data-thumbnail-src="https://i.ytimg.com/vi/5JonbfqF90g/0.jpg" frameborder="0" height="266" src="https://www.youtube.com/embed/5JonbfqF90g?feature=player_embedded" width="320"></iframe></div>
<br />
<div>
<br /></div>
<div class="separator" style="clear: both; text-align: justify;">
<br /></div>
<div class="separator" style="clear: both; text-align: justify;">
I hope you like it 😉</div>
<div class="separator" style="clear: both; text-align: justify;">
<br /></div>
<div class="separator" style="clear: both; text-align: justify;">
Greetings,</div>
<div class="separator" style="clear: both; text-align: justify;">
<br /></div>
<div class="separator" style="clear: both; text-align: justify;">
Blag.</div>
<div class="separator" style="clear: both; text-align: justify;">
SAP Labs Network.</div>
<div class="separator" style="clear: both; text-align: justify;">
<br /></div>
<div class="separator" style="clear: both; text-align: justify;">
<br /></div>
<div class="separator" style="clear: both; text-align: justify;">
<br /></div>
<div>
<br /></div>
</div>
Alvaro "Blag" Tejada Galindohttp://www.blogger.com/profile/12061593528820409779noreply@blogger.com0tag:blogger.com,1999:blog-4144704359177008692.post-8960614827610352492018-07-30T10:27:00.000-07:002018-07-30T10:27:35.622-07:00Cozmo, read to me<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjR_upT6e6IVMAsqdCITyd09Zh3PcwNc1rHY2jA7l45g2NrQQZPNTHITXfCYVwA6nYjqL7DOu6deYMCDSWXEGNVwklUrDynE8S8DLASVn6XJ8wB_09iu8kCklPaJ7FBqJHR0UNhhw1yNq-N/s1600/d_shop_blog_logoToronto.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="173" data-original-width="493" height="112" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjR_upT6e6IVMAsqdCITyd09Zh3PcwNc1rHY2jA7l45g2NrQQZPNTHITXfCYVwA6nYjqL7DOu6deYMCDSWXEGNVwklUrDynE8S8DLASVn6XJ8wB_09iu8kCklPaJ7FBqJHR0UNhhw1yNq-N/s320/d_shop_blog_logoToronto.png" width="320" /></a></div>
<br />
Do you know <a href="https://www.anki.com/en-ca/cozmo" target="_blank">Cozmo</a>? The friendly robot from <a href="https://www.anki.com/en-ca" target="_blank">Anki</a>? Well...here he is...<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiFJnjHXq8NNbHY4zZMlzcwn_jXnTsOu-vuBY2HSNGPDNa-jH8gygSJHz5AkumuvvAFeEcNeC3EXHs31nGBCLqCGxPgvFYzn-_Teh-BYORsZ9SfThIkmhr2WYEEdqvkA43EYCeDZreCPV7m/s1600/Cozmo.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="425" data-original-width="425" height="200" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiFJnjHXq8NNbHY4zZMlzcwn_jXnTsOu-vuBY2HSNGPDNa-jH8gygSJHz5AkumuvvAFeEcNeC3EXHs31nGBCLqCGxPgvFYzn-_Teh-BYORsZ9SfThIkmhr2WYEEdqvkA43EYCeDZreCPV7m/s200/Cozmo.jpg" width="200" /></a></div>
Cozmo is a programmable robot that has many features...and one of those includes a camera...so you can Cozmo take a picture of something...and then do something with that picture...<br />
<br />
To code for Cozmo you need to use <a href="https://www.python.org/" target="_blank">Python</a>...actually...Python 3 -;)<br />
<br />
For this blog, we're going to need a couple of things...so let's install them...<br />
<br />
<table align="center" border="1" style="width: 600px;">
<tbody>
<tr>
<td><pre>pip3 install ‘cozmo[camera]’</pre>
</td>
</tr>
<tr>
</tr>
</tbody></table>
<br />
This will install the Cozmo SDK...and you will need to install the Cozmo app in your phone as well...<br />
<br />
If you have the SDK installed already, you may want to upgrade it because if you don't have the latest version it might not work...<br />
<div>
<br /></div>
<table align="center" border="1" style="width: 600px;">
<tbody>
<tr>
<td><pre>pip3 install --upgrade cozmo</pre>
</td>
</tr>
<tr>
</tr>
</tbody></table>
<br />
<div>
Now, we need a couple of extra things...</div>
<div>
<br /></div>
<table align="center" border="1" style="width: 600px;">
<tbody>
<tr>
<td><pre>sudo apt-get install python-pygame
pip3 install pillow
pip3 install numpy
</pre>
</td>
</tr>
<tr>
</tr>
</tbody></table>
<br />
<div>
<strong>pygame</strong> is a games framework<br />
<strong>pillow</strong> is a wrapper around the PIL library and it's used to manage images.<br />
<strong>numpy</strong> allows us to manage complex numbers in Python.<br />
<br />
That was the easy part...as now we need to install <a href="https://opencv.org/" target="_blank">OpenCV</a>...which allows to manipulate images and video...<br />
<br />
This one is a little bit tricky, so if you get stuck...search on Google or just drop me a message...<br />
<br />
First, make sure that OpenCV is not installed by removing it...unless you are sure it's working properly for you...<br />
<br /></div>
<table align="center" border="1" style="width: 600px;">
<tbody>
<tr>
<td><pre>sudo apt-get uninstall opencv
</pre>
</td>
</tr>
<tr>
</tr>
</tbody></table>
<br />
Then, install the following prerequisites...<br />
<br />
<table align="center" border="1" style="width: 600px;">
<tbody>
<tr>
<td><pre>sudo apt-get install build-essential cmake pkg-config yasm python-numpy
sudo apt-get install libjpeg-dev libjpeg8-dev libtiff5-dev libjasper-dev
libpng12-dev
sudo apt-get install libavcodec-dev libavformat-dev libswscale-dev
libv4l-dev libdc1394-22-dev
sudo apt-get install libxvidcore-dev libx264-dev libxine-dev libfaac-dev
sudo apt-get install libgtk-3-dev libtbb-dev libqt4-dev libmp3lame-dev
sudo apt-get install libatlas-base-dev gfortran
sudo apt-get install libopencore-amrnb-dev libopencore-amrwb-dev
libtheora-dev libxvidcore-dev x264 v4l-utils
</pre>
</td>
</tr>
<tr>
</tr>
</tbody></table>
<br />
<div>
If by any chance, something is not available on your system, simply remove it from the list and try again...unless you're like me and want to spend hours trying to get everything...<br />
<br />
Now, we need to download the OpenCV source code so we can build it...from the source...<br />
<br /></div>
<table align="center" border="1" style="width: 600px;">
<tbody>
<tr>
<td><pre>wget https://github.com/opencv/opencv/archive/3.4.0.zip
unzip opencv-3.4.0.zip //This should produce the folder opencv-3.4.0
</pre>
</td>
</tr>
<tr>
</tr>
</tbody></table>
<br />
Then, we need to download the contributions because there are some things not bundled in OpenCV by default...and you might need them for any other project...
<br />
<br />
<table align="center" border="1" style="width: 600px;">
<tbody>
<tr>
<td><pre>wget https://github.com/opencv/opencv_contrib/archive/3.4.0.zip
unzip opencv-contrib-3.4.0.zip
//This should produce the folder opencv_contrib-3.4.0
</pre>
</td>
</tr>
<tr>
</tr>
</tbody></table>
<br />
As we have both folders, we can start compiling...
<br />
<br />
<table align="center" border="1" style="width: 600px;">
<tbody>
<tr>
<td><pre>cd opencv-3.4.0
mkdir build
cd build
cmake -D CMAKE_BUILD_TYPE=RELEASE
-D CMAKE_INSTALL_PREFIX=/usr/local
-D INSTALL_PYTHON_EXAMPLES=OFF
-D CMAKE_CXX_COMPILER=/usr/bin/g++
-D INSTALL_C_EXAMPLES=OFF
-D OPENCV_EXTRA_MODULES_PATH=/YourPath/opencv_contrib-3.4.0/modules
-D PYTHON_EXECUTABLE=/usr/bin/python3.6
-D WITH_FFMPEG=OFF
-D BUILD_OPENCV_APPS=OFF
-D BUILD_OPENCD_TS=OFF
-D WITH_LIBV4L=OFF
-D WITH_CUDA=OFF
-D WITH_V4L=ON
-D WITH_QT=ON
-D WITH_LAPACK=OFF
-D WITH_OPENCV_BIOINSPIRED=OFF
-D WITH_XFEATURES2D=ON
-D WITH_OPENCL=OFF
-D WITH_FACE=ON
-D ENABLE_PRECOMPILED_HEADERS=ON
-D WITH_OPENCL=OFF
-D WITH_OPENCL_SVM=OFF
-D WITH_OPENCLAMDFFT=OFF
-D WITH_OPENCLAMDBLAS=OFF
-D WITH_OPENCV_DNN=OFF
-D BUILD_OPENCV_APPS=ON
-D BUILD_EXAMPLES=OFF ..
</pre>
</td>
</tr>
<tr>
</tr>
</tbody></table>
<br />
<div>
Keep extra attention that you need to pass the correct path to your <strong>opencv_contrib</strong> folder...so it's better to pass the full path to avoid making errors...<br />
<br />
And yes...that's a pretty long command for a build...and it took me a long time to make it work...as you need to figure out all the parameters...<br />
<br />
Once we're done, we need to make it...as <strong>cmake</strong> will prepare the recipe...<br />
<br /></div>
<table align="center" border="1" style="width: 600px;">
<tbody>
<tr>
<td><pre>make -j2
</pre>
</td>
</tr>
<tr>
</tr>
</tbody></table>
<br />
If there's any mistake, simply do this...
<br />
<br />
<table align="center" border="1" style="width: 600px;">
<tbody>
<tr>
<td><pre>make clean
make
</pre>
</td>
</tr>
<tr>
</tr>
</tbody></table>
<br />
Then, we can finally install OpenCV by doing this...
<br />
<br />
<table align="center" border="1" style="width: 600px;">
<tbody>
<tr>
<td><pre>sudo make install
sudo ldconfig
</pre>
</td>
</tr>
<tr>
</tr>
</tbody></table>
<br />
To test that it's working properly...simply do this...
<br />
<br />
<table align="center" border="1" style="width: 600px;">
<tbody>
<tr>
<td><pre>python3
>>>import cv2
</pre>
</td>
</tr>
<tr>
</tr>
</tbody></table>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh-m-gWoVpQy3crGp7VKnuIyfhtS1jBS4P7fnQ7KEJ9nqRtocL7-i4fmMqPQHMW0MFto5dXqmZKnga5ZBl-w0xBn_jZLlcanc7ZAKBtlfafXWUYxHpMdtb1ep_Aa54vb9wdecM_TWBrxGpz/s1600/OpenCV2.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="224" data-original-width="736" height="97" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh-m-gWoVpQy3crGp7VKnuIyfhtS1jBS4P7fnQ7KEJ9nqRtocL7-i4fmMqPQHMW0MFto5dXqmZKnga5ZBl-w0xBn_jZLlcanc7ZAKBtlfafXWUYxHpMdtb1ep_Aa54vb9wdecM_TWBrxGpz/s320/OpenCV2.png" width="320" /></a></div>
<br />
If you don't have any errors...then we're good to go -;)<br />
<br />
That was quite a lot of work...anyway...we need an extra tool to make sure our image get nicely processed...<br />
<br />
Download <a href="http://www.fmwconcepts.com/imagemagick/downloadcounter.php?scriptname=textcleaner&dirname=textcleaner" target="_blank">textcleaner</a> and put in the same folder as your Python script...<br />
<br />
And...just in case you're wondering...yes...we're going to have Cozmo take a picture...we're going to process it...use SAP Leonardo's OCR API and then have Cozmo read it back to us...cool, huh?<br />
<a href="https://api.sap.com/api/ocr_api" target="_blank">SAP Leonardo's OCR API</a> is still on version 2Alpha1...but regardless of that...it works amazing well -;)<br />
<br />
Although keep in mind that if the result is not always pretty accurate that because of the lighting, the position of the image, your handwritting and the fact that the OCR API is still in Alpha...<br />
<br />
Ok...so first things first...we need a white board...<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjTqPEMewvqSqFzff8Fav0aMqc8ajefmLUok_4gkOT0hgLfqOxAyoNSkzXd4SKVAky-lrUmh5F2Gf1vn8aHqv3J7yyJ2TrTvCugfe7y3jW9ZnJWGso1R03Ld4T6U5lCjnvnREvaMmilanX5/s1600/Whiteboard.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="480" data-original-width="640" height="240" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjTqPEMewvqSqFzff8Fav0aMqc8ajefmLUok_4gkOT0hgLfqOxAyoNSkzXd4SKVAky-lrUmh5F2Gf1vn8aHqv3J7yyJ2TrTvCugfe7y3jW9ZnJWGso1R03Ld4T6U5lCjnvnREvaMmilanX5/s320/Whiteboard.JPG" width="320" /></a></div>
<br />
And yes...my hand writing is far from being good... -:(<br />
<br />
Now, let's jump into the source code...<br />
<br />
<br />
<table align="center" style="width: 600px;">
<tbody>
<tr><th bgcolor="#6690BC">CozmoOCR.py</th>
</tr>
<tr>
<td><pre>import cozmo
from cozmo.util import degrees
import PIL
import cv2
import numpy as np
import os
import requests
import json
import re
import time
import pygame
import _thread
def input_thread(L):
input()
L.append(None)
def process_image(image_name):
image = cv2.imread(image_name)
img = cv2.resize(image, (600, 600))
img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
blur = cv2.GaussianBlur(img, (5, 5), 0)
denoise = cv2.fastNlMeansDenoising(blur)
thresh = cv2.adaptiveThreshold(denoise, 255, </pre>
<pre> cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY, 11, 2)
blur1 = cv2.GaussianBlur(thresh, (5, 5), 0)
dst = cv2.GaussianBlur(blur1, (5, 5), 0)
cv2.imwrite('imggray.png', dst)
cmd = './textcleaner -g -e normalize -o 12 -t 5 -u imggray.png out.png'
os.system(cmd)
def ocr():
url = "https://sandbox.api.sap.com/ml/ocr/ocr"
img_path = "out.png"
files = {'files': open (img_path, 'rb')}
headers = {
'APIKey': "APIKey",
'Accept': "application/json",
}
response = requests.post(url, files=files, headers=headers)
json_response = json.loads(response.text)
json_text = json_response['predictions'][0]
json_text = re.sub('\n',' ',json_text)
json_text = re.sub('3','z',json_text)
json_text = re.sub('0|O','o',json_text)
return json_text
def cozmo_program(robot: cozmo.robot.Robot):
robot.camera.color_image_enabled = False
L = []
_thread.start_new_thread(input_thread, (L,))
robot.set_head_angle(degrees(20.0)).wait_for_completed()
while True:
if L:
filename = "Message" + ".png"
pic_filename = filename
latest_image = robot.world.latest_image.raw_image
latest_image.convert('L').save(pic_filename)
robot.say_text("Picture taken!").wait_for_completed()
process_image(filename)
message = ocr()
print(message)
robot.say_text(message, use_cozmo_voice=True, </pre>
<pre> duration_scalar=0.5).wait_for_completed()
break
pygame.init()
cozmo.run_program(cozmo_program, use_viewer=True, force_viewer_on_top=True)
</pre>
</td>
</tr>
<tr>
</tr>
</tbody></table>
<br />
<div>
Let's analyze the code a little bit...<br />
<br />
We're going to use threads, as we need to have a window where we can see what Cozmo is looking at and another with Pygame where we can press "Enter" as command to have Cozmo taking a picture.<br />
<br />
Basically, when we run the application, Cozmo will move his head and get into picture mode...then, if we press "Enter" (On the terminal screen) it will take a picture and then send it to our OpenCV processing function.<br />
<br />
This function will simply grab the image, scale it, make it grayscale, do a GaussianBlur to blur the image and remove the noise and reduce detail. Then we're going to apply a denoising to get rid of dust and fireflies...apply a threshold to separate the white and black pixels, and apply a couple more blurs...<br />
<br />
Finally we're to call <strong>textcleaner</strong> to further remove noise and make the image cleaner...<br />
<br />
So, here is the original picture taken by Cozmo...<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh7uRSXq67eo3tWzi2jb0mrbivJHBgx0WxXk8i8NW4W79hLBKjP8khSbrSYs3qu-gZopwKuBwng20YTtceRzcY_G0UPKYV6P5TStI9oZpWvY_GzeysfXLSv63NBxg9cVGlsvehTZ443cgUx/s1600/Message.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="240" data-original-width="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh7uRSXq67eo3tWzi2jb0mrbivJHBgx0WxXk8i8NW4W79hLBKjP8khSbrSYs3qu-gZopwKuBwng20YTtceRzcY_G0UPKYV6P5TStI9oZpWvY_GzeysfXLSv63NBxg9cVGlsvehTZ443cgUx/s1600/Message.png" /></a></div>
<br />
This is the picture after our OpenCV post-processing...<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgpT757Mvk-CVmcYMFXyX2tIsT__3EZCZd3pow01FlROTiq2iTCo8UqqVEjx70AuSsofSNmwoF4rEi4noSF0QwqX8Rq8onH-rJFwjQ9NmXV4GQJY6wIWAcVqi4EtA2OROKI35FRpSoO8wBA/s1600/imggray.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="600" data-original-width="600" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgpT757Mvk-CVmcYMFXyX2tIsT__3EZCZd3pow01FlROTiq2iTCo8UqqVEjx70AuSsofSNmwoF4rEi4noSF0QwqX8Rq8onH-rJFwjQ9NmXV4GQJY6wIWAcVqi4EtA2OROKI35FRpSoO8wBA/s320/imggray.png" width="320" /></a></div>
<br />
And finally, this is our image after using <strong>textcleaner</strong>...<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjZj_Ld36igRjw1IW6rDLcfxeetfEEnpPRNMSA-Xe2wpIZPOfnZrpp99N6vGxFTFFV-0I7Vh4y1IQ0bkzNFnViIRHxkDXIxAAymDIBURfnCXMUoz_WUwrB6UGsgoIGbt4-qjIcDgeKStsK6/s1600/out.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="633" data-original-width="633" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjZj_Ld36igRjw1IW6rDLcfxeetfEEnpPRNMSA-Xe2wpIZPOfnZrpp99N6vGxFTFFV-0I7Vh4y1IQ0bkzNFnViIRHxkDXIxAAymDIBURfnCXMUoz_WUwrB6UGsgoIGbt4-qjIcDgeKStsK6/s320/out.png" width="320" /></a></div>
Finally, once we have the image the way we wanted, we can call the OCR API which is pretty straightforward...<br />
<br />
To get the API Key, simply go to <a href="https://api.sap.com/api/ocr_api/overview">https://api.sap.com/api/ocr_api/overview</a> and log in...<br />
<br />
Once we have the response back from the API, we can do some Regular Expressions cleanup just to make sure some characters doesn't get wrongly recognized...<br />
<br />
Finally, we can have Cozmo to read the message out loud -;) And just for demonstration purposes...<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgdJF4bOpUlsKLGqiXCaxaAytlRae31WK_fGqSPKOTObjS7zZej4dkKDqi4ekgdpmpKH-SQruXSq7BAOeVvc8voNljUnElvBSx_mqE_GpmUKmZYI1zoMNOmKRn6SgoImHYphL4tD5SLvywt/s1600/CozmoWelcomeDShop.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="386" data-original-width="737" height="208" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgdJF4bOpUlsKLGqiXCaxaAytlRae31WK_fGqSPKOTObjS7zZej4dkKDqi4ekgdpmpKH-SQruXSq7BAOeVvc8voNljUnElvBSx_mqE_GpmUKmZYI1zoMNOmKRn6SgoImHYphL4tD5SLvywt/s400/CozmoWelcomeDShop.png" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
Here, I was lucky enough that the lighting and everything was perfectly setup...so it was a pretty clean response...further tests were pretty bad -:( But again...it's important to have good lighting...<br />
<br />
Of course...you wan to see a video of the process in action, right? Well...funny enough...my first try was perfect! Even better than this one...but I didn't shoot the video -:( Further tries were pretty crappy until I could get something acceptable...and this is what you're going to watch now...the sun coming through the window didn't helped me...but it's pretty good anyway...<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<iframe allowfullscreen="" class="YOUTUBE-iframe-video" data-thumbnail-src="https://i.ytimg.com/vi/UpVEC_unCyQ/0.jpg" frameborder="0" height="266" src="https://www.youtube.com/embed/UpVEC_unCyQ?feature=player_embedded" width="320"></iframe></div>
<br />
Hope you liked this blog -:)<br />
<br />
Greetings,<br />
<br />
Blag.<br />
SAP Labs Network.<br />
<br /></div>
Alvaro "Blag" Tejada Galindohttp://www.blogger.com/profile/12061593528820409779noreply@blogger.com0tag:blogger.com,1999:blog-4144704359177008692.post-42687962624011076932018-05-21T06:43:00.000-07:002018-05-21T06:43:42.075-07:00The Blagchain<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgU73yjMhF7kVTgLSGGEimtIO6h_O-IsnkzkMdBij27QG8OHLiFEHS8k8nOdAaPq7sFb9ZqHgsx7LY4dOidaUihqmPb17YkUo887vfm2iJNkmipj7U14VUU9ccKaMD4SrSymtcezuIDTCYM/s1600/Blagcoin.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="541" data-original-width="961" height="225" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgU73yjMhF7kVTgLSGGEimtIO6h_O-IsnkzkMdBij27QG8OHLiFEHS8k8nOdAaPq7sFb9ZqHgsx7LY4dOidaUihqmPb17YkUo887vfm2iJNkmipj7U14VUU9ccKaMD4SrSymtcezuIDTCYM/s400/Blagcoin.jpg" width="400" /></a></div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
Lately, I have been learning about <a href="https://en.wikipedia.org/wiki/Blockchain" target="_blank">Blockchain</a> and <a href="https://www.ethereum.org/" target="_blank">Ethereum</a>. Two really nice and interesting topics...but as they say...the best way to learn is by doing...so I put myself on working on the <b><i>Blagchain</i></b>.</div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
So, what's the Blagchain? Basically, it's a small Blockchain application that picks some things from Blockchain and some things from Ethereum and it was build as an educational thing...in the Blagchain you can get a user, post a product or buy it and everything will be stored in a chain like structure...</div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
Before we jump into the screenshots...let me tell you about the technology I chose for this little project...</div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
There are many technologies out there...so choosing the right one is always a hard thing...half the way you can realize that nope...that was not the smartest decision...some other language can do a better job in less time...or maybe that particular feature is not available and you didn't knew it because you never need it before...</div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
When I started learning about Blockchain and Ethereum...I knew I wanted to build the Blagchain using a web interface...so the first languages that came into my mind were out of the question...basically because they don't provide web interfaces or simply because it would be too painful to build the app using them...also I wanted a language with few dependencies and with easy installation and extension...I wanted an easy but fast language...and then...almost instantly I knew which one I had to use...</div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
<a href="https://crystal-lang.org/" target="_blank">Crystal</a> is similar to Ruby but faster...and nicer -;) Also...it has <a href="http://kemalcr.com/" target="_blank">Kemal</a> a <a href="http://sinatrarb.com/" target="_blank">Sinatra</a>-like web framework...</div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
When I discovered Crystal I was really impressed by how well it is designed...specially because...it's still on Alpha! How can such a young language can be so good? Beats me...but Crystal is really impressive...</div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
Anyway...let's see how the Blagchain works...</div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
For sure...it's not a dapp...but that's fine because you only use it locally...it uses two web applications that run on different ports...one working as the server and the other working as the client...</div>
<div style="text-align: justify;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiEq4OpSgZ9gVlai54GR3HQ8jPiUIGC9FEPdWpa_ZMUQagkiUV8bbPdXP2QFfu-v0pSZIKpvmDWzcJ9ee4vG1fDE4V0eBW5C7AfWV67iYurr27tgBrv1phyIF7kJ-MDcm6ju5wMeYFLE0b-/s1600/Blagchain_001.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="359" data-original-width="1600" height="140" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiEq4OpSgZ9gVlai54GR3HQ8jPiUIGC9FEPdWpa_ZMUQagkiUV8bbPdXP2QFfu-v0pSZIKpvmDWzcJ9ee4vG1fDE4V0eBW5C7AfWV67iYurr27tgBrv1phyIF7kJ-MDcm6ju5wMeYFLE0b-/s640/Blagchain_001.png" width="640" /></a></div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
You can add a new product...</div>
<div style="text-align: justify;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjs-SunXCOZwBobndAl7cjVWPNXq4IBZKFMb8Ia9xsnf5Zq8tQImP1NhX4jEfCBifw78BTEaVybSO8JX9zYLjGux7KKvIuv8fUMobZsdqpTULCdm3URpSlT1K7m9AD9sjdr-UXvMHf77suX/s1600/Blagchain_003.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="355" data-original-width="1600" height="140" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjs-SunXCOZwBobndAl7cjVWPNXq4IBZKFMb8Ia9xsnf5Zq8tQImP1NhX4jEfCBifw78BTEaVybSO8JX9zYLjGux7KKvIuv8fUMobZsdqpTULCdm3URpSlT1K7m9AD9sjdr-UXvMHf77suX/s640/Blagchain_003.png" width="640" /></a></div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
You can see here that we have our Genesis Block, a new block for the posting of a product (And they are connected via the Previous Hash) and also you can see that any transaction will cost us 0.1 Blagcoin...</div>
<div style="text-align: justify;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgIZ9mHS0Ist0Pkuih_Y19NcaLdESptfZ9qTn7D3UaTzBQdEjFi3Dn1wTBMghFlTTXA3p2LDUqUyu6uwcbEbZQt4n8YJeGqtqq2AJtTIYvcNimB18CKXOW-rQ8MDEJ3PK9q8hEFIlGQlaTw/s1600/Blagchain_004.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="530" data-original-width="1600" height="210" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgIZ9mHS0Ist0Pkuih_Y19NcaLdESptfZ9qTn7D3UaTzBQdEjFi3Dn1wTBMghFlTTXA3p2LDUqUyu6uwcbEbZQt4n8YJeGqtqq2AJtTIYvcNimB18CKXOW-rQ8MDEJ3PK9q8hEFIlGQlaTw/s640/Blagchain_004.png" width="640" /></a></div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
Now, we can use another browser to create a new user...</div>
<div style="text-align: justify;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjZwoTZvcOm41tZ-0XmMYtpBx5vo9VazZuWYB4xM9X-0q35JZuW-XUuL9vJJjs95xUUMnkuE2BrNu4C770I3lol2XJbumHyjGnxjgL1eZoLBKbnbxKglLV7myu4mlw6WbuFfi7lMwWFW4XZ/s1600/Blagchain_005.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="554" data-original-width="1600" height="220" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjZwoTZvcOm41tZ-0XmMYtpBx5vo9VazZuWYB4xM9X-0q35JZuW-XUuL9vJJjs95xUUMnkuE2BrNu4C770I3lol2XJbumHyjGnxjgL1eZoLBKbnbxKglLV7myu4mlw6WbuFfi7lMwWFW4XZ/s640/Blagchain_005.png" width="640" /></a></div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
As this user didn't create the product...he/her can buy it...and add a new transaction to the chain...</div>
<div style="text-align: justify;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgUlH0SLpif11pacVJZFT6Xebs7GSfY9KTVPLaMrlM0HZMut3ZsEVwnRnP-BM7poVHpL9E0e6zMkO__mvWeCtoVsfIaaSVXii2k-19ni4c6T07g_8GOX4esROEY9VtrgYhVypYyLQOuE6zk/s1600/Blagchain_009.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="505" data-original-width="1600" height="200" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgUlH0SLpif11pacVJZFT6Xebs7GSfY9KTVPLaMrlM0HZMut3ZsEVwnRnP-BM7poVHpL9E0e6zMkO__mvWeCtoVsfIaaSVXii2k-19ni4c6T07g_8GOX4esROEY9VtrgYhVypYyLQOuE6zk/s640/Blagchain_009.png" width="640" /></a></div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
Money (Blagcoin) goes from one account to the other. The chain grows and everything is recorded...</div>
<div style="text-align: justify;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjIQFuVxPNAcL4K7csOv59Q7oKtYrX2EkCuNEhfvj0SqTlzLF928YfVZPOG7JQTl378-rpdTMC75vgwvDlUGbdLRbPB71zSW9aD8cPXgozZykGBWHk6724rfiK6bRy9lYAZAE6Td7Tsuczq/s1600/Blagchain_011.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="640" data-original-width="1600" height="256" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjIQFuVxPNAcL4K7csOv59Q7oKtYrX2EkCuNEhfvj0SqTlzLF928YfVZPOG7JQTl378-rpdTMC75vgwvDlUGbdLRbPB71zSW9aD8cPXgozZykGBWHk6724rfiK6bRy9lYAZAE6Td7Tsuczq/s640/Blagchain_011.png" width="640" /></a></div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
What if you don't have enough Blagcoin to buy something?</div>
<div style="text-align: justify;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjAMEa3LjZaoNs0iU70Ny5LG2X4xsTv8642eDC4RqiLVRXfjxHH5G5AK4QpXpaiY4EebbQqOsmNvfblcMr8BVZUDT0VYzfgOswMbkZewZpW9nifAUrmvHSq6u5aEKLDyRIwMOKu2mvzrzMN/s1600/Blagchain_013.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="460" data-original-width="1600" height="184" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjAMEa3LjZaoNs0iU70Ny5LG2X4xsTv8642eDC4RqiLVRXfjxHH5G5AK4QpXpaiY4EebbQqOsmNvfblcMr8BVZUDT0VYzfgOswMbkZewZpW9nifAUrmvHSq6u5aEKLDyRIwMOKu2mvzrzMN/s640/Blagchain_013.png" width="640" /></a></div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
Now...if you like this kind of things...this is how many lines of codes it took me...</div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
Blagchain.cr (Server part) --> 129 lines</div>
<div style="text-align: justify;">
BlagchainClient.cr (Client part) --> 125 lines</div>
<div style="text-align: justify;">
index.ecr (HTML, Bootstrap and JQuery) --> 219 lines</div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
So not even 500 lines of codes for the whole application...that's pretty cool, huh? -;)</div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
And yes...I know you want to see a little bit of the source code, right? Well...why not -:)<br />
<br /></div>
<table align="center" style="width: 600px;">
<tbody>
<tr><th bgcolor="#6690BC">BlagchainClient.cr</th>
</tr>
<tr>
<td><pre>post "/sellArticle" do |env|
user = env.params.body["user"]
article = env.params.body["article"]
description = env.params.body["description"]
price = env.params.body["price"]
amount = (env.session.float("amount") - 0.1).round(2)
env.session.float("amount", amount)
HTTP::Client.post("http://localhost:3000/addTransaction", form: "user=" + user +
"&article=" + article + "&description=" + description + "&price=" + price)
env.session.bool("flag", true)
env.redirect "/Blagchain"
end
</pre>
</td>
</tr>
<tr>
</tr>
</tbody></table>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
Greetings,</div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
Blag.</div>
<div style="text-align: justify;">
SAP Labs Network.</div>
Alvaro "Blag" Tejada Galindohttp://www.blogger.com/profile/12061593528820409779noreply@blogger.com0tag:blogger.com,1999:blog-4144704359177008692.post-64088407421400014972018-01-17T12:17:00.000-08:002018-01-17T12:17:00.140-08:00Wooden Puzzle - My first Amazon Sumerian GameIf you read my previous blog <a href="http://blagrants.blogspot.com/2017/12/amazon-sumerian-first-impressions.html" target="_blank">Amazon Sumerian - First impressions</a> you will know that I wouldn't stop there -;)<br />
<br />
I have been able to play a lot with Sumerian and most important...to learn a lot...the <a href="https://docs.sumerian.amazonaws.com/" target="_blank">tutorials</a> are pretty good so you should read them even if you don't have access to Sumerian yet...<br />
<br />
Once thing that I always wanted to do...was to animate my Cozmo model...that I did on <a href="http://blender.org/" target="_blank">Blender</a>...<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjWVxks02vuhuHFRr-yGhM0wHQtVAXiP6QPDU6GgfnOtK5oM2sO6M_fIZUZfTQ1u3XdP3XH79BoOI0mvr2HWWjrmsmN2iIa5zjpKKlVA0Spq2Ha11CddWj7METvvLu9LpDmBZRGpvshM3zh/s1600/CozmoMirror.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="544" data-original-width="962" height="225" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjWVxks02vuhuHFRr-yGhM0wHQtVAXiP6QPDU6GgfnOtK5oM2sO6M_fIZUZfTQ1u3XdP3XH79BoOI0mvr2HWWjrmsmN2iIa5zjpKKlVA0Spq2Ha11CddWj7METvvLu9LpDmBZRGpvshM3zh/s400/CozmoMirror.jpg" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: justify;">
I tried doing it on Blender (rigging it and doing the animation but it was getting weird as it worked fine on Blender but not on Sumerian...now I know why...but at the time I got frustrated) but failed...so instead I thought on doing it on Sumerian using its tools...</div>
<div class="separator" style="clear: both; text-align: justify;">
<br /></div>
<div class="separator" style="clear: both; text-align: justify;">
I gotta admit...at first it didn't worked...but then I kept exploring and realized that the Timeline was my friend...and after many testings...I got it working -;)</div>
<div class="separator" style="clear: both; text-align: justify;">
<br /></div>
<div class="separator" style="clear: both; text-align: justify;">
Here is how it looks like...</div>
<div class="separator" style="clear: both; text-align: justify;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhV8yQ_A2IG6huZs48JJkazD-Yd03vd7-Dm3civEdDPOXoF6M8u9TmwCuX-qgVzDYX2YcnijWKYhkISwa7o_VJ-59zHLIP06VCcgTAS6r4Ge-51JVxCD3NDRUU4Tst5F-6hEuRo0wGcufP6/s1600/CozmoSumerian.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="501" data-original-width="1600" height="125" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhV8yQ_A2IG6huZs48JJkazD-Yd03vd7-Dm3civEdDPOXoF6M8u9TmwCuX-qgVzDYX2YcnijWKYhkISwa7o_VJ-59zHLIP06VCcgTAS6r4Ge-51JVxCD3NDRUU4Tst5F-6hEuRo0wGcufP6/s400/CozmoSumerian.jpg" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: justify;">
<br /></div>
<div class="separator" style="clear: both; text-align: justify;">
So just go to <a href="https://d2fzo86an1i3q6.cloudfront.net/5f116204d3aa4c6c8561cbb22972726d.scene/" target="_blank">Cozmo</a> and click on the robot to start the animation and then click on him again to restart the animation...</div>
<div class="separator" style="clear: both; text-align: justify;">
<br /></div>
<div class="separator" style="clear: both; text-align: justify;">
Simple but really cool -:)</div>
<div class="separator" style="clear: both; text-align: justify;">
<br /></div>
<div class="separator" style="clear: both; text-align: justify;">
After that...I start thinking about doing something else...something more interesting and this time involving some programming...which is actually JavaScript and not NodeJS like I though initially -:(</div>
<div class="separator" style="clear: both; text-align: justify;">
<br /></div>
<div class="separator" style="clear: both; text-align: justify;">
Anyway...I tried to do that once in <a href="https://unity3d.com/" target="_blank">Unity</a> and also in <a href="http://www.flare3d.com/" target="_blank">Flare3D</a>, but didn't had enough luck...although fair enough...by that time I didn't knew Blender...so I put myself into working on it...</div>
<div class="separator" style="clear: both; text-align: justify;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhv44B_WERSKFtzL8aPK2X7T54d4OQ3ERMkxHXD9jT5e4rEJpVhm-4pKHGsEDHlUi37fKeQIoo5OrliahZNPb793bjGL5pCsGW-RCJgFSaOBnNl5g35jIDwbgDK9b0X5anfaV18R0umkpWP/s1600/WoodenPuzzleBlender.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="844" data-original-width="1600" height="210" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhv44B_WERSKFtzL8aPK2X7T54d4OQ3ERMkxHXD9jT5e4rEJpVhm-4pKHGsEDHlUi37fKeQIoo5OrliahZNPb793bjGL5pCsGW-RCJgFSaOBnNl5g35jIDwbgDK9b0X5anfaV18R0umkpWP/s400/WoodenPuzzleBlender.jpg" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: justify;">
<br /></div>
<div class="separator" style="clear: both; text-align: justify;">
I designed a Wooden Puzzle board using Blender and then imported into Sumerian and applied a Mesh Collision to it...that way...the ball can run around the board and fall down if it gets over a hole...</div>
<div class="separator" style="clear: both; text-align: justify;">
<br /></div>
<div class="separator" style="clear: both; text-align: justify;">
Here is how it looks like...</div>
<div class="separator" style="clear: both; text-align: justify;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjMTOL7SX56hvZ39IMxZBCSwJUvAu4NI9aYGIoUGtlQo0ggSXv7md_z4bBgcj3HMX-jQDlq7HtGeoMbFOugCguNQJWagEOZ7Rp6DgRI2Grmys4ptsJxq7gF7T9euO0ap389yHZApwm92LKV/s1600/WoodenPuzzle_01.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="805" data-original-width="1600" height="201" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjMTOL7SX56hvZ39IMxZBCSwJUvAu4NI9aYGIoUGtlQo0ggSXv7md_z4bBgcj3HMX-jQDlq7HtGeoMbFOugCguNQJWagEOZ7Rp6DgRI2Grmys4ptsJxq7gF7T9euO0ap389yHZApwm92LKV/s400/WoodenPuzzle_01.jpg" width="400" /></a></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjXXQzWdaADhwbJAM2ImesFq49gUuaH-arTxoXTbkDOe5ZI0OVWllIpm7MJKIohuDKV4X_AwVZbv2044vC5XI_4fhpeYEPSMYqb5EA_WM4dS0viAp1vhUc9-7cnMo2aBtI0VJOpw5Ii0FWd/s1600/WoodenPuzzle_02.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="805" data-original-width="1600" height="201" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjXXQzWdaADhwbJAM2ImesFq49gUuaH-arTxoXTbkDOe5ZI0OVWllIpm7MJKIohuDKV4X_AwVZbv2044vC5XI_4fhpeYEPSMYqb5EA_WM4dS0viAp1vhUc9-7cnMo2aBtI0VJOpw5Ii0FWd/s400/WoodenPuzzle_02.jpg" width="400" /></a></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhEsgxZobvJSL42YO-8gkUQcDgKh_J5MYiXOdZxcsu5vV2gS4d0WYXCQdBRseJqVet9kNPFOR4eJMLOM0xnmtMCK2czjsZ9t6zt6LFssoddcK46-UBG7cqe9UyxCrAYlEtrkEU4o2DXb7ka/s1600/WoodenPuzzle_03.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="809" data-original-width="1600" height="201" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhEsgxZobvJSL42YO-8gkUQcDgKh_J5MYiXOdZxcsu5vV2gS4d0WYXCQdBRseJqVet9kNPFOR4eJMLOM0xnmtMCK2czjsZ9t6zt6LFssoddcK46-UBG7cqe9UyxCrAYlEtrkEU4o2DXb7ka/s400/WoodenPuzzle_03.jpg" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: justify;">
<br /></div>
<div class="separator" style="clear: both; text-align: justify;">
To play...simple use the cursor keys to move the board and guide the ball from "Start" to "Finish". Pressing "r" restarts the game.</div>
<div class="separator" style="clear: both; text-align: justify;">
<br /></div>
<div class="separator" style="clear: both; text-align: justify;">
Here's the link to play it "<a href="https://d2fzo86an1i3q6.cloudfront.net/864f526bc1ef433fbdafbcde7bc8b93c.scene/" target="_blank">Wooden Puzzle</a>"...</div>
<br />
Was it hard to build? Not really -:) Sumerian is very awesome and pretty powerful...on top of that...the Sumerian team is really nice and they are always more than willing to help...<br />
<br />
So far...my Sumerian experience had been nothing but joy...so I can see myself doing more and more projects...<br />
<br />
Of course...I'm already working on a couple more -;) Specially one involving using <a href="https://www.oculus.com/" target="_blank">Oculus Rift</a>...but that will take more time for sure....as I need to do a lot of Blender work..<br />
<br />
Have you tried Sumerian? Not yet? Why don't you go ahead and request <a href="https://aws.amazon.com/sumerian/" target="_blank">access</a>?<br />
<br />
Greetings,<br />
<br />
Blag.<br />
Development Culture.Alvaro "Blag" Tejada Galindohttp://www.blogger.com/profile/12061593528820409779noreply@blogger.com0tag:blogger.com,1999:blog-4144704359177008692.post-44363280399571835182017-12-22T08:51:00.000-08:002017-12-22T10:02:49.122-08:00Amazon Sumerian - First impressionsFor those who know me and for those who doesn't...as I work as a Developer Evangelist...my main job is to learn, explore and evangelize new technologies and programming languages...so of course...AR/VR had been on my plate for quite some time...<br />
<br />
I have played with <a href="https://unity3d.com/" target="_blank">Unity3D</a> and <a href="https://www.unrealengine.com/en-US/what-is-unreal-engine-4" target="_blank">Unreal Engine</a>...and of course I have developed for the <a href="https://developers.google.com/glass/" target="_blank">Google Glass</a>, <a href="https://www.microsoft.com/en-us/hololens" target="_blank">Microsoft HoloLens</a> and <a href="https://www.oculus.com/rift/" target="_blank">Oculus Rift</a>...<br />
<br />
When the good folks at Amazon announced <a href="https://aws.amazon.com/sumerian/" target="_blank">Amazon Sumerian</a> you can figure out that I completely thrilled -:D<br />
<br />
So yesterday, I finally got accepted into the Beta program, so of course I started to follow a couple of tutorials and get to know the tool -;)<br />
<br />
Please be advised that I'm starting...so I haven't tried or used everything...I want to go step by step following the tutorials and trying to understand everything in the most positive way...<br />
<br />
Have I mentioned that Sumerian runs on your browser? How crazy is that? No installation...just launch up your browser and start building AR/VR experiences...<br />
<br />
When you first launch it, you will be presented with the following screen...<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgcVLRDNSZj3BcV68u3JeO-fT74tQmBRXxU96hAdcDErnoxLlSZ48PCt2di4ncOwYF8pQCifks51_wKE_sAwi4qB_eoLVc9_fctMbrDgxzV0JMb8YeYbii4VE5tdRXjHj9H8MgJc8Birjek/s1600/AmazonSumerian_001.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="737" data-original-width="1600" height="183" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgcVLRDNSZj3BcV68u3JeO-fT74tQmBRXxU96hAdcDErnoxLlSZ48PCt2di4ncOwYF8pQCifks51_wKE_sAwi4qB_eoLVc9_fctMbrDgxzV0JMb8YeYbii4VE5tdRXjHj9H8MgJc8Birjek/s400/AmazonSumerian_001.jpg" width="400" /></a></div>
<br />
<br />
Where you can create a new screen or simply use a template.<br />
<br />
Sumerian provides many tutorials, and so far I have only made my way through the first 3...<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjrihQZQ-FMVgTyrgn_ZFT6uJs-QT04Hwo_cQ7mj_-eln4OIF5Iotp6UJAgjq1hgWc29PXEXM0Wv4jU1oHTeb_GyR85DQ7gbkIrkv7gUALt-kPo2ceK3-QXWlQFlcnrwOmxKZ8aS-BWRSUL/s1600/AmazonSumerian_Tutorials.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="524" data-original-width="1233" height="168" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjrihQZQ-FMVgTyrgn_ZFT6uJs-QT04Hwo_cQ7mj_-eln4OIF5Iotp6UJAgjq1hgWc29PXEXM0Wv4jU1oHTeb_GyR85DQ7gbkIrkv7gUALt-kPo2ceK3-QXWlQFlcnrwOmxKZ8aS-BWRSUL/s400/AmazonSumerian_Tutorials.jpg" width="400" /></a></div>
<br />
So here's how my TV room looks like...<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh3pAletef6-WG8Gimx_XBI2FBQNIqKXN1VqQAtzvao2yszs7LjPzlFqGroz9DUol65gayRKT8O3DopWzfi55rvj8JFDzjKDIyqeNHVjYztNjvhrgGfQEMHZXr3q2n0gZ1gyExdx70_EFDs/s1600/AmazonSumerian_002.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="755" data-original-width="1600" height="188" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh3pAletef6-WG8Gimx_XBI2FBQNIqKXN1VqQAtzvao2yszs7LjPzlFqGroz9DUol65gayRKT8O3DopWzfi55rvj8JFDzjKDIyqeNHVjYztNjvhrgGfQEMHZXr3q2n0gZ1gyExdx70_EFDs/s400/AmazonSumerian_002.jpg" width="400" /></a></div>
<br />
As you can see...Sumerian is a full blown editor that provides all the tools that you can find on any other editor...plus many things that I believe are brand new and exciting...<br />
<br />
Of course, you can preview your work...<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjhgwz1dD7-UT5mJ-YWyjvtqcUdCYlYu6dExJQW4OqqU79kz6PxFtpMlOk785tf4s0XiPYUJcL6t9CGolJ5eNVHDLIVBkCZDrDTpuyfcq3H93qevzGuZRw84X8cEQdsGZzSnlLoeCS0Vxt7/s1600/AmazonSumerian_003.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="756" data-original-width="1600" height="188" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjhgwz1dD7-UT5mJ-YWyjvtqcUdCYlYu6dExJQW4OqqU79kz6PxFtpMlOk785tf4s0XiPYUJcL6t9CGolJ5eNVHDLIVBkCZDrDTpuyfcq3H93qevzGuZRw84X8cEQdsGZzSnlLoeCS0Vxt7/s400/AmazonSumerian_003.jpg" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: justify;">
As for the TV Room tutorial...the idea is that below the TV Screen, there's an Amazon Echo, so you can press it to change the videos presented on the screen. For this you need to use a State Machine and also create a script that will manage the different videos. For the scripting you need to use NodeJS...which is really nice as is the language that I mainly use when developing application for Alexa...</div>
<div class="separator" style="clear: both; text-align: justify;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj35US5X5hNHxn9ZdRkoYVtxob-6KhQGXGdmI4o1YOmyKSjKP7Y91RWInIuXT0VIN6Sqe40nz63nIab9bYX3uQXTOfAQazrkF2bSi6UAxbuMdB6yzs6dxZhDk7aIpHC06e-K2AzoQybvCpd/s1600/AmazonSumerian_004.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="970" data-original-width="1595" height="242" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj35US5X5hNHxn9ZdRkoYVtxob-6KhQGXGdmI4o1YOmyKSjKP7Y91RWInIuXT0VIN6Sqe40nz63nIab9bYX3uQXTOfAQazrkF2bSi6UAxbuMdB6yzs6dxZhDk7aIpHC06e-K2AzoQybvCpd/s400/AmazonSumerian_004.jpg" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: justify;">
<br /></div>
<div class="separator" style="clear: both; text-align: justify;">
<br /></div>
This is how my TV Room looks like when playing a video on render mode -:)<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg8bYCJ23-eHfipKd0IY59MnNl5XgaEHJmjAfbu3TYcOkDTp5Hm9FftUZzzN3bK7t3EbVQMRi6p4J9_t4gGiz7cAOuRHprgGZZmjwvyd64Yv_TQZJzA8vwgMtmNnZHgMwqbSEt7dZbCrYER/s1600/AmazonSumerian_005.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="973" data-original-width="1595" height="243" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg8bYCJ23-eHfipKd0IY59MnNl5XgaEHJmjAfbu3TYcOkDTp5Hm9FftUZzzN3bK7t3EbVQMRi6p4J9_t4gGiz7cAOuRHprgGZZmjwvyd64Yv_TQZJzA8vwgMtmNnZHgMwqbSEt7dZbCrYER/s400/AmazonSumerian_005.jpg" width="400" /></a></div>
<br />
Before moving on to learn more about Sumerian...I need to say that the navigation system doesn't seem to be too good by now...you can use the mouse buttons, Tab and Shift...but control keys or AWSD doesn't seem to work like you would expect on Unity3D or Unreal Engine...I have forwarded my question to the Sumerian Team on Slack...so I will update this post as soon as I get an answer :)<br />
<br />
<b>*UPDATE* </b>By following the "Lights and Camera" tutorial I found out that while the default camera doesn't allow fine grain navigation...the FlyCam does it! -:D All good in the hood -;)<br />
<br />
Till next time,<br />
<br />
Blag.<br />
Development Culture.Alvaro "Blag" Tejada Galindohttp://www.blogger.com/profile/12061593528820409779noreply@blogger.com0tag:blogger.com,1999:blog-4144704359177008692.post-80801321939177150392017-05-02T08:56:00.000-07:002017-05-02T08:56:23.458-07:00Blender Lego Art for HoloLens<h2 style="background-color: #333333; color: #cccccc; font-family: arial, tahoma, helvetica, freesans, sans-serif; font-size: 22px; margin: 0px; position: relative; text-align: center;">
<b>This blog was originally posted on <a href="https://blogs.sap.com/2017/05/02/blender-lego-art-for-hololens/" target="_blank">Blender Lego Art for HoloLens</a>.</b></h2>
<div>
<b><br /></b></div>
<div>
<div>
Who doesn’t love Lego? And if you have used Blender before…who doesn’t love Blender? -:)</div>
<div>
<br /></div>
<div>
Combining both seemed like a great idea, so that’s what I did…Using Blender I create some pretty simple Lego pieces that can be used to build both simple and complicated models.</div>
<div>
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjmbxRcljmyXl0PhWNfu_jeSBzYpROUeP5vpEvwonU0vKBS1R7Ni9K11Gk2UdELCcLBGvfICIu5DSSdzqMhBV3f3QUVxF7aeTiBvNHJ0d5_bYb490SgK4vQ769qxJslNg9ejJhSSpGtxkiW/s1600/Lego_Set.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="225" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjmbxRcljmyXl0PhWNfu_jeSBzYpROUeP5vpEvwonU0vKBS1R7Ni9K11Gk2UdELCcLBGvfICIu5DSSdzqMhBV3f3QUVxF7aeTiBvNHJ0d5_bYb490SgK4vQ769qxJslNg9ejJhSSpGtxkiW/s400/Lego_Set.jpg" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: justify;">
A single piece is 0.25 by 0.25 and it’s made out of a single vertex. In the image, the colors are just used to give an idea of the different pieces.</div>
<div class="separator" style="clear: both; text-align: justify;">
<br /></div>
<div class="separator" style="clear: both; text-align: justify;">
The main point is simply to create a new Blender file, append the different pieces and start building.</div>
<div class="separator" style="clear: both; text-align: justify;">
<br /></div>
<div class="separator" style="clear: both; text-align: justify;">
At first it’s kind of complicate because you need to deal with the X, Y and Z positions…but once you get used to it…it’s becomes a little bit addictive -:)</div>
<div class="separator" style="clear: both; text-align: justify;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjO-EdsiMsdK88JiGAx8DvJ1nV3oipQq0FGhUUNrLZ2T2Nqh3j-XlRfjpf-JJtIOQmpbbqZan3h18Yuguf9CjgrOaYXbp8uDq4HksI6twGYVwAqxubKn4FLDXMrWThvELgpf1AMfO2b_WfY/s1600/Lego_House_Front.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="223" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjO-EdsiMsdK88JiGAx8DvJ1nV3oipQq0FGhUUNrLZ2T2Nqh3j-XlRfjpf-JJtIOQmpbbqZan3h18Yuguf9CjgrOaYXbp8uDq4HksI6twGYVwAqxubKn4FLDXMrWThvELgpf1AMfO2b_WfY/s400/Lego_House_Front.jpg" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: justify;">
Now, the name of the blog is Lego Art, right? So…if you look online for Pixel Art instead, you will find a lot of nice images…like this one…</div>
<div class="separator" style="clear: both; text-align: justify;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj4-5svQgjngX9nMl__Bj7Umg7XpJLSd6uZTE5Uhz3sK7w_ualGPDm58Wqb6foy40hEiEPNWMIOM-tnfYLXWxQz7p_M4olZJvmDwU097gzIV9xj_HMiF1R7zFTE4YkaamBtqRV1DGUaTRnb/s1600/MarioPixel.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="300" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj4-5svQgjngX9nMl__Bj7Umg7XpJLSd6uZTE5Uhz3sK7w_ualGPDm58Wqb6foy40hEiEPNWMIOM-tnfYLXWxQz7p_M4olZJvmDwU097gzIV9xj_HMiF1R7zFTE4YkaamBtqRV1DGUaTRnb/s400/MarioPixel.jpg" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: justify;">
The perfect candidate for Lego construction! By putting the pieces together and simply assign them the right material…we can get this…</div>
<div class="separator" style="clear: both; text-align: justify;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgHWVDOCnj5-pT7Bji0STO-nr_KYlr78L2PZrXgOdXRszAN7NhyphenhyphenUdyqhsk-i7Qq6uJLVGrIscvfk7RWEkdruJJdzUp-U5S9Ple9JeUS0y_Jv3G_5ZgaAfyoRDqvjTDtI5mKHT6MDg_xih2M/s1600/MarioBlog.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="225" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgHWVDOCnj5-pT7Bji0STO-nr_KYlr78L2PZrXgOdXRszAN7NhyphenhyphenUdyqhsk-i7Qq6uJLVGrIscvfk7RWEkdruJJdzUp-U5S9Ple9JeUS0y_Jv3G_5ZgaAfyoRDqvjTDtI5mKHT6MDg_xih2M/s400/MarioBlog.jpg" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: justify;">
<br /></div>
<div class="separator" style="clear: both; text-align: justify;">
And with some more time and dedication…we can get this…</div>
<div class="separator" style="clear: both; text-align: justify;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEheFCqQ8b_2KiF9RoZNMie47jnrJv00-a49qsSQBZ4uQG17rukh0aUOS9IPBGpoOKASFWoMQcyqu9EXsyHLmcsyWdesxVia2Mgu7iIiK0lC-iGKeLeqBnTvTSwQZCdHCShOWNxkkgRFTX2Z/s1600/MegaMan.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="223" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEheFCqQ8b_2KiF9RoZNMie47jnrJv00-a49qsSQBZ4uQG17rukh0aUOS9IPBGpoOKASFWoMQcyqu9EXsyHLmcsyWdesxVia2Mgu7iIiK0lC-iGKeLeqBnTvTSwQZCdHCShOWNxkkgRFTX2Z/s400/MegaMan.jpg" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiyrrmPbPrfTf9FYTuWvlbHqVyJ-AMpw1dVq07WqadNrDXhFu0TcjMHmxM5bX-HaCm5HcLFmPu4hFNGaSzuuCbPUG4cnn9TrES3XyoejMD4SPSVYuKbm4gxVMTSJpWRDG3PAeaKcEvhn58r/s1600/Pikachu.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="223" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiyrrmPbPrfTf9FYTuWvlbHqVyJ-AMpw1dVq07WqadNrDXhFu0TcjMHmxM5bX-HaCm5HcLFmPu4hFNGaSzuuCbPUG4cnn9TrES3XyoejMD4SPSVYuKbm4gxVMTSJpWRDG3PAeaKcEvhn58r/s400/Pikachu.jpg" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: justify;">
Anyway…with a collection of models…we can think up and bundle them together into a Microsoft HoloLens application -;)</div>
<div class="separator" style="clear: both; text-align: justify;">
<br /></div>
<div class="separator" style="clear: both; text-align: justify;">
The application itself is easy…you start by looking at all the models on a shelve…you can select one, make it smaller, bigger, turn it left or right or simply go back to the shelve.</div>
<div class="separator" style="clear: both; text-align: justify;">
<br /></div>
<div class="separator" style="clear: both; text-align: justify;">
Here’s a video showing how it’s look like.</div>
<div style="text-align: justify;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<iframe allowfullscreen="" class="YOUTUBE-iframe-video" data-thumbnail-src="https://i.ytimg.com/vi/FBZGJC5mlmo/0.jpg" frameborder="0" height="266" src="https://www.youtube.com/embed/FBZGJC5mlmo?feature=player_embedded" width="320"></iframe></div>
<div style="text-align: justify;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: justify;">
Greetings,</div>
<div class="separator" style="clear: both; text-align: justify;">
<br /></div>
<div class="separator" style="clear: both; text-align: justify;">
Blag.</div>
<div class="separator" style="clear: both; text-align: justify;">
Development Culture.</div>
<div class="separator" style="clear: both; text-align: justify;">
<br /></div>
<div class="separator" style="clear: both; text-align: justify;">
<br /></div>
<div class="separator" style="clear: both; text-align: justify;">
<br /></div>
<div style="text-align: justify;">
<br /></div>
<div>
<br /></div>
<div style="font-weight: bold;">
<br /></div>
</div>
Alvaro "Blag" Tejada Galindohttp://www.blogger.com/profile/12061593528820409779noreply@blogger.com0tag:blogger.com,1999:blog-4144704359177008692.post-67756647502202876212017-03-29T09:25:00.000-07:002017-03-29T09:25:25.201-07:00Room with a View – HoloLens, Unity3D and Blender<br />
<h2 style="background-color: #333333; color: #cccccc; font-family: arial, tahoma, helvetica, freesans, sans-serif; font-size: 22px; margin: 0px; position: relative; text-align: center;">
<b>This post was originally posted on <a href="https://blogs.sap.com/2017/03/29/room-with-a-view-hololens-unity3d-and-blender/" target="_blank">Room with a View – HoloLens, Unity3D and Blender</a>.</b></h2>
<span style="font-family: "calibri" , sans-serif; font-size: 12pt; line-height: 17.12px;"><br /></span>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjf0wE5oBOvlIXGPyupFE-FEOFwUgoqji9C0NSylFxW2Yk8xSlfvK2H1XZ7iAheIWyXx_7XUYBRQUdY5Mr3y9NSVJQxEGnX6J9wW6cBlq0WjSYDQth5x6V0GvhMX2l1e5v608UV3fK8TteC/s1600/d_shop_blog_logo.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="112" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjf0wE5oBOvlIXGPyupFE-FEOFwUgoqji9C0NSylFxW2Yk8xSlfvK2H1XZ7iAheIWyXx_7XUYBRQUdY5Mr3y9NSVJQxEGnX6J9wW6cBlq0WjSYDQth5x6V0GvhMX2l1e5v608UV3fK8TteC/s320/d_shop_blog_logo.jpg" width="320" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: justify;">
<br /></div>
<div class="separator" style="clear: both; text-align: justify;">
Since the last month or so I have been enlighten myself with an awesome <a href="https://www.udemy.com/blendertutorial/" target="_blank">Blender course</a>…and while I had some previous experience by reading some books…nothing could get me to the point that I’m at now as this course…so…enough said…it’s more than highly recommended 🙂</div>
<div class="separator" style="clear: both; text-align: justify;">
<br /></div>
<div class="separator" style="clear: both; text-align: justify;">
So…one of the challenges was to create something just using primitives…that means…cubes, spheres, cones and so on…nothing fancy…no modifiers…no extra knowledge…so I was able to come up with this…</div>
<div class="separator" style="clear: both; text-align: justify;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj25Lw-xq-z_2lh687txvOIWOA4uLLXMBWQu7ivGcykcY45I2TL9_b0qWTuwshVI4j9yUoBOwaUAEKMYlHqjfw1GK12l0ZP1utZDyAqLvnBhuIwUkWX3EoJJaWYPZmpUy2ZNtqJu_dwfubt/s1600/Desk_NoRender.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="226" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj25Lw-xq-z_2lh687txvOIWOA4uLLXMBWQu7ivGcykcY45I2TL9_b0qWTuwshVI4j9yUoBOwaUAEKMYlHqjfw1GK12l0ZP1utZDyAqLvnBhuIwUkWX3EoJJaWYPZmpUy2ZNtqJu_dwfubt/s400/Desk_NoRender.jpg" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: justify;">
That was a nice start…but I knew it needed something else…beside getting textures for it of course 🙂 It looked pretty plain…so next step was making it nicer…and this came along the way…</div>
<div class="separator" style="clear: both; text-align: justify;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh7rElcaQBHzPSuWcDykqtBXP1DNW92zRMcbr8VdOTAfTesRAQVHqf4SrEbSP2ox_0b8ZCxWIVfL6j6MZzC0xdgMSIoxBXLXtEXvHblTSMOnn7ffkuKtyGAfjsJay8K2rIy5iGUn3LqWdMF/s1600/Desk_Rendered.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="132" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh7rElcaQBHzPSuWcDykqtBXP1DNW92zRMcbr8VdOTAfTesRAQVHqf4SrEbSP2ox_0b8ZCxWIVfL6j6MZzC0xdgMSIoxBXLXtEXvHblTSMOnn7ffkuKtyGAfjsJay8K2rIy5iGUn3LqWdMF/s400/Desk_Rendered.jpg" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: justify;">
<br /></div>
<div class="separator" style="clear: both; text-align: justify;">
Now…it looks fancy, doesn’t it? Everything hand made created in Blender -;)</div>
<div class="separator" style="clear: both; text-align: justify;">
<br /></div>
<div class="separator" style="clear: both; text-align: justify;">
So…next step was to figure out what to do with this…it looks too nice to just leave it there on my hard drive…so I start thinking and then remembered that the Holographic Academy has a really nice demo called <a href="https://developer.microsoft.com/en-us/windows/mixed-reality/holograms_101e" target="_blank">Origami</a>…in this demo you need to select an origami ball that will drop down a paper plane and then hit a fan that will explode and in turn open a crack on the floor where a nice underground world can be seen…truly amazing if you ask me…so…I had an idea 🙂 Why not have a d-shop frame that will explode when selected and then open a hole in the wall where the room that I designed in Blender could be seen…that sound like an impressive demo to me…so that’s exactly what I did 😉</div>
<div class="separator" style="clear: both; text-align: justify;">
<br /></div>
<div class="separator" style="clear: both; text-align: justify;">
Here’s the video for your viewing pleasure…hope you like it 🙂</div>
<div class="separator" style="clear: both; text-align: justify;">
<br /></div>
<div class="separator" style="clear: both; text-align: justify;">
<br /></div>
<div style="text-align: center;">
<iframe allowfullscreen="" class="YOUTUBE-iframe-video" data-thumbnail-src="https://i.ytimg.com/vi/H952alwpxIU/0.jpg" frameborder="0" height="266" src="https://www.youtube.com/embed/H952alwpxIU?feature=player_embedded" width="320"></iframe></div>
<div style="text-align: center;">
<br /></div>
<br />
<div style="text-align: justify;">
At first I though it was going to be a lot of work…but it wasn't really like that…here are some highlights…</div>
<div style="text-align: justify;">
<div>
<br /></div>
<div>
* I enclosed the room in a black box with a hole so it be looked through…</div>
<div>
<br /></div>
<div>
* In Unity3D I simply used an Unlit shader…as black is processed as invisible on HoloLens, having the model in a black unlit box gives the same impression as being invisible…hence…it looks like a hole in the wall…</div>
<div>
<br /></div>
<div>
* I used some spatial mapping to be able to pin the frame and the room to the wall…so it didn’t float around but instead looked like the room was inside the wall…</div>
<div>
<br /></div>
<div>
* When I first imported the model from Blender into Unity3D…none of my textures were available…which seemed odd to me…as they were there and were actually assigned…it turned out that I need to choose every single piece of the model and do a smart unwrapping…so the shader knows exactly how to implement the texture…</div>
<div>
<br /></div>
<div>
* I first I tested out with the emulator…which is good…but doesn’t really implement the same measure units that the real device uses…so while it looked fine on the emulator…it looked too far away on the HoloLens…so a lot of testing was needed in order to get it into the right position…</div>
<div>
<br /></div>
<div>
* To shoot the video, at first I tried using Camtasia…but of course…the rendering wasn’t was I was expecting…one thing is to look it from the HoloLens and other thing is looking from the laptop…so instead I used a recording from the Live Streaming of the HoloLens itself…and that was the trick…</div>
<div>
<br /></div>
<div>
As you can imagine…this now brings a whole world of new possibilities and demos…</div>
<div>
<br /></div>
<div>
Now it’s your turn to show us…what can you do 😉</div>
<div>
<br /></div>
<div>
<div style="text-align: start;">
Greetings,</div>
<div style="text-align: start;">
<br /></div>
<div style="text-align: start;">
Blag.</div>
<div style="text-align: start;">
Development Culture.</div>
</div>
</div>
<div class="separator" style="clear: both; text-align: justify;">
<br /></div>
Alvaro "Blag" Tejada Galindohttp://www.blogger.com/profile/12061593528820409779noreply@blogger.com0tag:blogger.com,1999:blog-4144704359177008692.post-8581257293029382102017-02-15T13:05:00.000-08:002017-02-15T13:05:10.267-08:00SAP d-shop’s Virtual House – A journey from Physical to Virtual<span style="font-family: "calibri" , sans-serif; font-size: 12.0pt; line-height: 107%;"></span><br />
<h2 style="background-color: #333333; color: #cccccc; font-family: arial, tahoma, helvetica, freesans, sans-serif; font-size: 22px; margin: 0px; position: relative; text-align: center;">
<b>This post was originally posted on <a href="https://blogs.sap.com/2017/02/15/sap-d-shops-virtual-house-a-journey-from-physical-to-virtual/#" target="_blank">SAP d-shop’s Virtual House – A journey from Physical to Virtual</a>.</b></h2>
<span style="font-family: "calibri" , sans-serif; font-size: 12.0pt; line-height: 107%;"><br /></span>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjf0wE5oBOvlIXGPyupFE-FEOFwUgoqji9C0NSylFxW2Yk8xSlfvK2H1XZ7iAheIWyXx_7XUYBRQUdY5Mr3y9NSVJQxEGnX6J9wW6cBlq0WjSYDQth5x6V0GvhMX2l1e5v608UV3fK8TteC/s1600/d_shop_blog_logo.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="112" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjf0wE5oBOvlIXGPyupFE-FEOFwUgoqji9C0NSylFxW2Yk8xSlfvK2H1XZ7iAheIWyXx_7XUYBRQUdY5Mr3y9NSVJQxEGnX6J9wW6cBlq0WjSYDQth5x6V0GvhMX2l1e5v608UV3fK8TteC/s320/d_shop_blog_logo.jpg" width="320" /></a></div>
<span style="font-family: "calibri" , sans-serif; font-size: 12.0pt; line-height: 107%;"><br /></span>
<span style="font-family: "calibri" , sans-serif; font-size: 12.0pt; line-height: 107%;"><br /></span>
<span style="font-family: "calibri" , sans-serif; font-size: 12.0pt; line-height: 107%;">Some
time ago…our good friends from SAP d-shop Newtown Square (Namely John Astill et
all) built a IoT House for SAP Insurance. This little house (hand made by the
way) used an Arduino Nano, a bunch of sensors and LED lights…and…which is
pretty cool by the way…a 3D Printed washing machine with a water sensor…and of
course…it was and it is…IoT enabled.</span><br />
<span style="font-family: "calibri" , sans-serif; font-size: 12.0pt; line-height: 107%;"><br /></span>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiDcj1KYQG5TMCp3Od9vH9ZZQ4Xw3dMwKBfXQYeCaV-47ZZTWq0_Ul6Jtm34y75k4OTcY8wmbvMCEGIXs9ZQEkrjyE22KHDg9qlRj856Xixbonm9t_gFIJYXPBJyZJxVZjg4bKA4AFQyVPX/s1600/IotHouse.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiDcj1KYQG5TMCp3Od9vH9ZZQ4Xw3dMwKBfXQYeCaV-47ZZTWq0_Ul6Jtm34y75k4OTcY8wmbvMCEGIXs9ZQEkrjyE22KHDg9qlRj856Xixbonm9t_gFIJYXPBJyZJxVZjg4bKA4AFQyVPX/s320/IotHouse.jpg" width="320" /></a></div>
<span style="font-family: "calibri" , sans-serif; font-size: 12.0pt; line-height: 107%;"><br /></span>
<br />
<div class="MsoNormal" style="text-align: justify;">
<span style="font-size: 12.0pt; line-height: 107%;">We thought it was pretty cool…so we have one at our own SAP
d-shop at Silicon Valley and it had become a key part in all our d-shop tours.<o:p></o:p></span></div>
<div class="MsoNormal" style="text-align: justify;">
<span style="font-size: 12.0pt; line-height: 107%;"><br /></span></div>
<span style="font-family: "calibri" , sans-serif; font-size: 12.0pt; line-height: 107%;">
<span style="font-size: 12pt; line-height: 107%;">Then…some time later, our friends from HCP
Marketing (Namely Joe Binkley et all) and Intel build a Smart Building. A
really nice building…controlled by Amazon Alexa that used an Intel Galileo,
some Arduinos as well as servos, lights, a solar panel and even a
fan…everything again…IoT enabled…but also as you may have guessed…voice
controlled…so you can send the elevator up and down…open or closed the doors
and even send the whole building on emergency mode…gladly…we had keep it on the
d-shop for quite some time and it’s another of our “wow” factor demos every
time someone comes to visit…</span></span><br />
<span style="font-family: "calibri" , sans-serif; font-size: 12.0pt; line-height: 107%;"><span style="font-size: 12pt; line-height: 107%;"><br /></span></span>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjSAi12napMva793ktAifnxWJEoxxEFgvtIdT_hxXOMnIyq33URJ6Akw2L3Z6J9D2rNZyhtZR9J2CdP0LXA5o58Ij2N0gjldl6hthbhtrcRBd2LJX-NggmvZTYVUd5QV7QTL6fJqjDKlQCx/s1600/SmartBuilding.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjSAi12napMva793ktAifnxWJEoxxEFgvtIdT_hxXOMnIyq33URJ6Akw2L3Z6J9D2rNZyhtZR9J2CdP0LXA5o58Ij2N0gjldl6hthbhtrcRBd2LJX-NggmvZTYVUd5QV7QTL6fJqjDKlQCx/s320/SmartBuilding.jpg" width="311" /></a></div>
<span style="font-family: "calibri" , sans-serif; font-size: 12.0pt; line-height: 107%;"><span style="font-size: 12pt; line-height: 107%;"><br /></span></span>
<br />
<div class="MsoNormal" style="text-align: justify;">
<span style="font-size: 12.0pt; line-height: 107%;">Having these two available for us…slowly sparked the fire of
innovation and creativity…why don’t we build a Virtual House that can be used
on the Oculus Rift and it’s controlled by Alexa?<o:p></o:p></span><br />
<span style="font-size: 12.0pt; line-height: 107%;"><br /></span></div>
<span style="font-family: "calibri" , sans-serif; font-size: 12.0pt; line-height: 107%;">
</span><br />
<div class="MsoNormal" style="text-align: justify;">
<span style="font-size: 12.0pt; line-height: 107%;">Not an easy thing…but we for sure love challenges…and thanks
to our previous experience <a href="https://blogs.sap.com/2016/12/01/unity3d-and-alexa-working-together/" target="_blank">Unity3D and Alexa working together</a> </span><span style="font-size: 12.0pt; line-height: 107%;">we already knew how to start…<o:p></o:p></span></div>
<div class="MsoNormal" style="text-align: justify;">
<span style="font-size: 12.0pt; line-height: 107%;"><br /></span></div>
<div class="MsoNormal" style="text-align: justify;">
<span style="font-size: 12.0pt; line-height: 107%;"><br /></span></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjXXxKsRqNzVnZ1rjfBe6ki4GJ19EoUQrxfJoJMSvAA1OTjJqiIVS1zQWyVG4UCw9XZdX_tmGx-ygdKt049gUwB2KloJjPovfZix5S5aZwDf97tRu6ajSf5Q8Qq6O76tJXDM5p8AUO0lwQh/s1600/Unity_Diagram.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjXXxKsRqNzVnZ1rjfBe6ki4GJ19EoUQrxfJoJMSvAA1OTjJqiIVS1zQWyVG4UCw9XZdX_tmGx-ygdKt049gUwB2KloJjPovfZix5S5aZwDf97tRu6ajSf5Q8Qq6O76tJXDM5p8AUO0lwQh/s320/Unity_Diagram.jpg" width="304" /></a></div>
<div class="MsoNormal" style="text-align: justify;">
<span style="font-size: 12.0pt; line-height: 107%;"><br /></span></div>
<div class="MsoNormal" style="text-align: justify;">
<span style="font-size: 12.0pt; line-height: 107%;">The architecture is pretty simple… The Heroku server is just
an echo server, so it will repeat everything we pass to it as a JSON response.
Our Unity app is constantly checking the Heroku server to see if there’s a
message to respond to. Of course, for this to work as intended, we need to
setup a skill on Amazon Alexa just to update the server. So, when we say “open
door”, then Alexa will send a command to the Heroku server and this server then
will produce an “open door” message in JSON. Our Unity app will read the Heroku
Server, and act accordingly by opening the door…of course, we don’t want this
to happened all over…so after Unity executes the action it sent a null message
to the Heroku server, so next time the JSON response is going to be null as
well and Unity will simply wait for the next valid command.<o:p></o:p></span></div>
<div class="MsoNormal" style="text-align: justify;">
<span style="font-size: 12.0pt; line-height: 107%;"><br /></span></div>
<div class="MsoNormal" style="text-align: justify;">
<span style="font-size: 12.0pt; line-height: 107%;">
<span style="font-family: "calibri" , sans-serif; font-size: 12.0pt; line-height: 107%;">If you want to take a sneak peak of how the
Virtual House looks like…here are a couple of screenshots…but don’t forget to
watch the video, </span><span style="font-family: "wingdings"; font-size: 12.0pt; line-height: 107%;">J</span><span style="font-family: "calibri" , sans-serif; font-size: 12.0pt; line-height: 107%;"> You will get the full experience -;)</span></span></div>
<div class="MsoNormal" style="text-align: justify;">
<span style="font-size: 12.0pt; line-height: 107%;"><span style="font-family: "calibri" , sans-serif; font-size: 12.0pt; line-height: 107%;"><br /></span></span></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgvj8N6IDobU9SMzLgrvN4tQeMzDkRekJT7zEzGSZ6tBTG7cP4nqEuIV2UNl0IVxNyYtmdcfT7qDyMdNJXJxYodKmYZSE4_Ri_58CeFGHXeRz_jalCMc1vgaZivDbXZIx0SaNu5zrwATnaV/s1600/FirstFloor_Coffee_Corner.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="150" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgvj8N6IDobU9SMzLgrvN4tQeMzDkRekJT7zEzGSZ6tBTG7cP4nqEuIV2UNl0IVxNyYtmdcfT7qDyMdNJXJxYodKmYZSE4_Ri_58CeFGHXeRz_jalCMc1vgaZivDbXZIx0SaNu5zrwATnaV/s320/FirstFloor_Coffee_Corner.jpg" width="320" /></a></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEitSjDYcX4pCFGUFC5XLCfanQ9MO9n7be13vNy_sOJz1rxJsWf4k-6qfX9kab2i5O1hC6c1SQlPlDKqnqUI-TNjhZ8rGtZKujhWke0GN6PRX12QvnB9yz1ZMwzN2q67NrsArkVLpU5cduC5/s1600/FirstFloor_Disclaimer.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="150" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEitSjDYcX4pCFGUFC5XLCfanQ9MO9n7be13vNy_sOJz1rxJsWf4k-6qfX9kab2i5O1hC6c1SQlPlDKqnqUI-TNjhZ8rGtZKujhWke0GN6PRX12QvnB9yz1ZMwzN2q67NrsArkVLpU5cduC5/s320/FirstFloor_Disclaimer.jpg" width="320" /></a></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg3pUzN9ocdMb8tsPli5zfaUZsslhoD-LNUyKkK_PVz_s1Atul7-M5BotVhJnltMLo87H8pqHBdlfyLjkY08DEW8eVZZdMbc1vYO1qWDhx0wFxWr1G7CKKizMumQobiExq5gV-7Z23E73Rw/s1600/ThirdFloor_DShop_Lights.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="154" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg3pUzN9ocdMb8tsPli5zfaUZsslhoD-LNUyKkK_PVz_s1Atul7-M5BotVhJnltMLo87H8pqHBdlfyLjkY08DEW8eVZZdMbc1vYO1qWDhx0wFxWr1G7CKKizMumQobiExq5gV-7Z23E73Rw/s320/ThirdFloor_DShop_Lights.jpg" width="320" /></a></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgglZmKwj-DBgdxGWgAxgcFvdabxAiY-1flTN2u38RoXDwpcCKqVHjxqe5HClMUHLyoCSLL9u9NVsxqo1xhFqpLiF-5P7M2je1tKntbLF2JR7RdyOM5wMXOCKhrhjQng9KSRI-FjD2VV_Ow/s1600/ThirdFloor_DShop_Twiiter_No_Messages.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="150" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgglZmKwj-DBgdxGWgAxgcFvdabxAiY-1flTN2u38RoXDwpcCKqVHjxqe5HClMUHLyoCSLL9u9NVsxqo1xhFqpLiF-5P7M2je1tKntbLF2JR7RdyOM5wMXOCKhrhjQng9KSRI-FjD2VV_Ow/s320/ThirdFloor_DShop_Twiiter_No_Messages.jpg" width="320" /></a></div>
<div class="MsoNormal" style="text-align: justify;">
<span style="font-size: 12.0pt; line-height: 107%;"><span style="font-family: "calibri" , sans-serif; font-size: 12.0pt; line-height: 107%;"><br /></span></span></div>
<div class="MsoNormal" style="text-align: justify;">
<span style="font-size: 12.0pt; line-height: 107%;"><span style="font-family: "calibri" , sans-serif; font-size: 12.0pt; line-height: 107%;"></span></span></div>
<div class="MsoNormal" style="text-align: justify;">
<span style="font-size: 12.0pt; line-height: 107%;">Now…this project started as a “Project in a Box” (for
internal only…sorry about that) which means…all the source code and
explanations on how to build it from the scratch should be provided…but…for
obvious reasons…that didn’t happened </span><span style="font-family: "wingdings"; font-size: 12.0pt; line-height: 107%;">L</span><span style="font-size: 12.0pt; line-height: 107%;"> So instead…we turned this into a
“Product in a Box” meaning that (Sorry again…internals only) you can download
the compiled application and simply edit the configuration file to have it
running on your own </span><span style="font-family: "wingdings"; font-size: 12.0pt; line-height: 107%;">J</span><span style="font-size: 12.0pt; line-height: 107%;"> No source code is provided by obviously a nice email can get
you that -;)<o:p></o:p></span></div>
<div class="MsoNormal" style="text-align: justify;">
<span style="font-size: 12.0pt; line-height: 107%;"><br /></span></div>
<div class="MsoNormal" style="text-align: justify;">
<span style="font-size: 12.0pt; line-height: 107%;"></span></div>
<div class="MsoNormal" style="text-align: justify;">
<span style="font-size: 12.0pt; line-height: 107%;">Grab it from <a href="https://jam4.sapjam.com/blogs/show/jviRpc0UjVhdvmCBO3uibC" target="_blank">here</a><o:p></o:p></span></div>
<div class="MsoNormal" style="text-align: justify;">
<br /></div>
<div class="MsoNormal" style="text-align: justify;">
<span style="font-size: 12.0pt; line-height: 107%;">Now…that I got your full attention…please watch the video </span><span style="font-family: "wingdings"; font-size: 12.0pt; line-height: 107%;">J</span><span style="font-size: 12.0pt; line-height: 107%;"> It’s a nice journey from the IoT
House to the Virtual House passing by the Smart Building…<o:p></o:p></span></div>
<div class="MsoNormal" style="text-align: justify;">
<span style="font-size: 12.0pt; line-height: 107%;"><br /></span></div>
<div class="separator" style="clear: both; text-align: center;">
<iframe allowfullscreen="" class="YOUTUBE-iframe-video" data-thumbnail-src="https://i.ytimg.com/vi/0mps7dR-ZQ8/0.jpg" frameborder="0" height="266" src="https://www.youtube.com/embed/0mps7dR-ZQ8?feature=player_embedded" width="320"></iframe></div>
<div class="MsoNormal" style="text-align: justify;">
<br /></div>
<div class="MsoNormal" style="text-align: justify;">
<span style="font-size: 12.0pt; line-height: 107%;"><br /></span></div>
<div class="MsoNormal" style="text-align: justify;">
<span style="font-size: 12.0pt; line-height: 107%;">Now…you may wonder about the 3D Models used for this Virtual
House…as you can see on one of the images, most of them were downloaded but
some of them were developed in house </span><span style="font-family: "wingdings"; font-size: 12.0pt; line-height: 107%;">J</span><span style="font-size: 12.0pt; line-height: 107%;"> using Blender…Like the Amazon Echo,
the 3D Printed Robot and name tags, the Amazon Echo and obviously the house
itself </span><span style="font-family: "wingdings"; font-size: 12.0pt; line-height: 107%;">J</span><span style="font-size: 12.0pt; line-height: 107%;"> For some other things like the
plants and tables…those were imported into Blender and “hand painted” as the
textures were not available.<o:p></o:p></span><br />
<span style="font-size: 12.0pt; line-height: 107%;"><br /></span></div>
<div class="MsoNormal" style="text-align: justify;">
<span style="font-family: "calibri" , sans-serif; font-size: 12.0pt; line-height: 107%;">Now…something that we believe it’s pretty
important…is to list all the Pain Points and lessons learned while developing
this application…</span></div>
<div class="MsoNormal" style="text-align: justify;">
<span style="font-family: "calibri" , sans-serif; font-size: 12.0pt; line-height: 107%;"><br /></span></div>
<div class="MsoNormal" style="text-align: justify;">
<b><span style="font-size: 18.0pt; line-height: 107%;">Pain Points and lesson
learned:<o:p></o:p></span></b></div>
<div class="MsoNormal" style="text-align: justify;">
<b><span style="font-size: 18.0pt; line-height: 107%;"><br /></span></b></div>
<div class="MsoNormal" style="text-align: justify;">
</div>
<ul>
<li>As this is a Product in a Box and not a Project in a Box,
we’re not going to include the source code for this application, but what we’re
going to do instead is let you know the pain points and lessons learned that
came from this project.</li>
<li><span style="font-size: 12pt; line-height: 107%; text-indent: -0.25in;">Unity
uses the .NET Framework 3.5, which is already deprecated by .NET 4.0 so many
things are not going to work simply because they haven’t been implemented…and
why is that? Well…Unity uses Mono (which is .NET for Linux) and I guess they do
it to maintain uniformity in all platforms. While Mono remains on .NET 3.5,
Unity will not likely upgrade either.</span></li>
<li>When
loading scenes, the lighting gets all messed up…so you start in level one…more
to level two and suddenly it looks like nighttime…the solution to that is
simple…choose “Window <span style="font-family: "wingdings"; font-size: 12pt; line-height: 107%; text-indent: -0.25in;">à</span><span style="font-size: 12pt; line-height: 107%; text-indent: -0.25in;"> Lighting </span><span style="font-family: "wingdings"; font-size: 12pt; line-height: 107%; text-indent: -0.25in;">à</span><span style="font-size: 12pt; line-height: 107%; text-indent: -0.25in;"> Lightmaps”, uncheck the “Auto” checkbox and press
“Build” to bake the light again.</span></li>
<li>Coroutines
are simply awesome. Normally, you can’t make your application wait or sleep…but
by using Coroutines you certainly can…Coroutines are like threads.</li>
<li>When
using a light, make sure it’s turn off while the character is not in the room,
because this will save some graphic processing and because even virtually…we
need to be environment aware…</li>
<li>Unity
doesn’t have a wrap function or property for 3D Text…which is kind of problematic
especially if you want to do a Twitter Wall…so your only chance is to build you
own…although that’s not that hard…simply grab the incoming text, split it by
space into an array…concatenate each word by checking first if the length of
the string is lower than our threshold (which should be the maximum number of
characters that fit where our 3D text is), is the string is bigger than the
threshold, we simply add a carriage return (“\n”) before doing the
concatenation.</li>
<li>As
your application grows you might feel the need to duplicate some assets, which
is perfectly fine and doesn’t add too much processing (Especially if you create
a Prefab and use that prefab), but don’t forget to assign them unique names,
otherwise you’re going to have a headache if you application needs to interact
with those assets.</li>
<li>Sometimes
you will download some 3D models from the web…other times you will create them
using Blender…but don’t forget that sometimes just a simple sphere, cube or any
other Unity primitive can work just fine by just using an image attached to it
as its texture.</li>
<li>When
creating your Alexa skill…make sure not to make any spelling mistake…otherwise
you will hit you head thinking why Alexa is doing what you’re asking her to do…</li>
<li>When
testing our your application both Debug.log() and Print() will become your best
friends…nothing better than a printed value or message to realize what going
wrong.</li>
<li>When
moving an object, always make sure to record its original position and then add
the new value to that recorded position. Otherwise, something might provoke the
values to go wrong…by having the original values recorded, you avoid having to
recalculate the position but just call that variable and get things where they
belong.</li>
<li>When
using 3D Text you will notice that even if you put another object in front of
it…it will be always visible…which is not very likely…so we have two
options…either create a shader to occlude it…or the easiest one…make the
material that it’s in front of it transparent. That’s not perfect for all
situations but at least will work.</li>
<li>The
biggest problems when making Unity and Alexa speak, is that when you ask Alexa
to turn on the lights, she will respond “The lights are on” …but then if you
ask a second time her response should be “The lights are already on” …to make
this…we should need to use a Database or something to store state
information…and when closing the application, we would need to clean up the
states…while this might be doable…it’s a lot of work, and what happens if the
application crashes? Would we need to go and reset the states manually? Not
ideal…</li>
<li>That
leads me to the point of using the elevator…you can open the doors or sent it
to any of the floors…for the main part…that’s easy…each floor is a scene, so
you need to be on the first floor in order to make the elevator to floor two or
three…but…what if you’re outside the elevator? You are on floor one…ask for
floor three…and then you open the door…as your characters moves along with the
elevator floor…when you open the door everything will look bad…solution? Simply
using a cube without a mesh renderer, so it’s invisible…assign a collider with
“is trigger” enabled…and validate that the player is colliding with the cube in
order to make the elevator move…that way, even you ask for floor three and
Alexa confirms that the elevator is going up…nothing will happen…when you open
the door…we can assume that the elevator went down or up to your floor in order
for you to hop in…just an illusion…but it works…</li>
<li>Alexa
doesn’t have an option to delay the re-prompt, so when exploring the Virtual
House she will ask you “What else can I do for you?” and if we don’t respond
the skill will just die…so we will need to wake her up again…that’s kind of sad
due to the nature of the application…but nothing to be done unless Amazon
releases a way on making the re-prompt to wait longer…</li>
<li>As
the whole Alexa-Unity3D relays on Heroku…expect some downtimes or responses
from Alexa that are not actually replicated in the virtual world…might be an
internet connection glitch or just Heroku glitch…</li>
</ul>
<div>
<br /></div>
As I mentioned first…the environment gets affected by the
weather…if it’s sunny…you will see a sunny clear sky…if it’s rainy you will see
a dark and gloomy sky…and this involves using a Skybox…although not your
regular Skybox…and what is a Skybox, anyway? Well…simply put…is a cube that
covers your whole environment and has different images to simulate the
environment…the problems is that the regular Skybox only allows you to assign
six sides…which is of course not likely…you need to use a twelve side Skybox…then
you can assign sunny image and also cloudy images…that way when checking the
weather you can modify the luminosity and that will also affect the Skybox as
it will use one or the other giving that nice effect on reflecting the outside
weather…<br /><ul>
</ul>
<div>
Greetings,</div>
<div>
<br /></div>
<div>
Blag.</div>
<div>
Development Culture.</div>
Alvaro "Blag" Tejada Galindohttp://www.blogger.com/profile/12061593528820409779noreply@blogger.com0tag:blogger.com,1999:blog-4144704359177008692.post-80553243442499408342017-02-14T15:19:00.000-08:002017-02-14T15:19:41.693-08:00LED is my new Hello World - Prolog timeAs promised...here's my LED Numbers app written in Prolog...it took me a long time...a lot of research...a lot of headaches...so I hope you like it...still a complete Prolog newbie...so...no warranties at all -;)<br />
<br />
<table align="center" style="width: 600px;">
<tbody>
<tr><th bgcolor="#6690BC">LEDNumbers.pl</th>
</tr>
<tr>
<td><pre></pre>
<pre>number(0,[[' _ '],['| | '],['|_| ']]).
number(1,[[' '],['| '],['| ']]).
number(2,[[' _ '],[' _| '],['|_ ']]).
number(3,[['_ '],['_| '],['_| ']]).
number(4,[[' '],['|_| '],[' | ']]).
number(5,[[' _ '],['|_ '],[' _| ']]).
number(6,[[' _ '],['|_ '],['|_| ']]).
number(7,[['_ '],[' | '],[' | ']]).
number(8,[[' _ '],['|_| '],['|_| ']]).
number(9,[[' _ '],['|_| '],[' _| ']]).
digits(0,[]).
digits(X,[H|T]) :- (X/10 > 0 -> H1 is floor(X/10), H is X mod 10, digits(H1,T)), !.
accRev([],A,A).
accRev([H|T],A,R) :- accRev(T,[H|A],R).
getDigits(L,R) :- digits(L,Y), accRev(Y, [], R).
show_records([]).
show_records([A|B]) :-
print_records(A), nl,
show_records(B).
print_records([]).
print_records([A|B]) :-
format('~w',A),
print_records(B).
merge([L], L).
merge([H1,H2|T], R) :- maplist(append, H1, H2, H),
merge([H|T], R), !.
listnum([],[]).
listnum([H1|T1],[R|Y]) :- number(H1,R), listnum(T1,Y).
led(X) :- getDigits(X,Y), listnum(Y,Z), merge(Z,R), show_records(R).
</pre>
</td>
</tr>
<tr>
</tr>
</tbody></table>
<br />
Wanna see it in action? Me too -;)<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjLHTsht6xEGVNqXtLA3MCawGKXWpADaaaaKmBjd1A_oeSGWQ7W1A7q-sDkUEa6jGggDt95tLpx4fSqLQVndvIA7SMWTfLJernzQ-bVEX9aOAKTsLt60iWyXpmrhP1KtH9c3JE8EAH5EOSz/s1600/LEDNumbers_Prolog.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="240" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjLHTsht6xEGVNqXtLA3MCawGKXWpADaaaaKmBjd1A_oeSGWQ7W1A7q-sDkUEa6jGggDt95tLpx4fSqLQVndvIA7SMWTfLJernzQ-bVEX9aOAKTsLt60iWyXpmrhP1KtH9c3JE8EAH5EOSz/s400/LEDNumbers_Prolog.jpg" width="400" /></a></div>
<br />
Back to learning -;)<br />
<br />
Greetings,<br />
<br />
Blag.<br />
Development Culture.<br />
<br />Alvaro "Blag" Tejada Galindohttp://www.blogger.com/profile/12061593528820409779noreply@blogger.com0tag:blogger.com,1999:blog-4144704359177008692.post-68434646886509105952017-02-14T15:10:00.000-08:002017-02-14T15:10:01.622-08:00My first post on PrologAs always...I was looking for my next programming language to learn...and somehow...<a href="https://en.wikipedia.org/wiki/Prolog" target="_blank">Prolog</a> got in the way...<br />
<br />
I had played with Logic Programming in the past by learning <a href="https://mercurylang.org/" target="_blank">Mercury</a>...but really...when it comes to logic...Prolog wins the pot...<br />
<br />
Did you guys knew that the first <a href="https://www.erlang.org/" target="_blank">Erlang</a> compiler was built on Prolog? Me neither -:P<br />
<br />
For learning...I'm using <a href="http://www.swi-prolog.org/" target="_blank">SWI-Prolog</a> which seems to be the nicer and widely used...and I have to admit...it's pretty cool -;)<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhmXgI1yo4w5SwOTW8ozIVgYS_3HEzV28xkd1JY7uLMYOgJmC-8pzUTovPXgDNB0TNQvR1d6Kt837EmKqt7mxj97tlgo-OTPwmcSe2ytDa6qs5TfwuQVeRtnD2QW2cXSPbJj-x91ps6Jr1A/s1600/Prolog_Logo.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="200" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhmXgI1yo4w5SwOTW8ozIVgYS_3HEzV28xkd1JY7uLMYOgJmC-8pzUTovPXgDNB0TNQvR1d6Kt837EmKqt7mxj97tlgo-OTPwmcSe2ytDa6qs5TfwuQVeRtnD2QW2cXSPbJj-x91ps6Jr1A/s200/Prolog_Logo.png" width="200" /></a></div>
<br />
So...in a glance...Prolog reminds me of Mercury of course...but also <a href="https://www.forth.com/forth/" target="_blank">Forth</a> a little bit...and weirdly to <a href="https://www.haskell.org/" target="_blank">Haskell</a> in the sense that recursion is a key component...<br />
<br />
As happens many times when I'm learning a new programming language...I started off with my Fibonacci numbers application...so here it is...<br />
<br />
<table align="center" style="width: 600px;">
<tbody>
<tr><th bgcolor="#6690BC">fibonacci.pl</th>
</tr>
<tr>
<td><pre>fibo(NUM,A,B,[H|T]) :- (NUM > 1 -> H is A + B, X is NUM - 1,
(A =:= 0 -> fibo(X,H,B,T); fibo(X,H,A,T))).
fibo(_,_,_,[]).
fibonacci(NUM,R) :- fibo(NUM,0,1,X), !, append([0,1], X, R).
</pre>
</td>
</tr>
<tr>
</tr>
</tbody></table>
<br />
<b>.pl </b>extension? Yep...the same as <a href="https://www.perl.org/" target="_blank">Perl</a>...but as you can see...it has anything to do with Perl at all -;)<br />
<br />
Anyway...here's the output screen...<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjlf1yeRWdMsONcbCP_IL8_vvgCOZERftNKZx-achmdXftujoXaT5FDpX_WmCeSipxGcekLCcbzWULUYr07goxEC8GYToR551U7m1jvq9rMWdCOFDOP5FCvwS4p8rpOS28jz3CDrFe65h1A/s1600/Fibonacci_Prolog.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="238" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjlf1yeRWdMsONcbCP_IL8_vvgCOZERftNKZx-achmdXftujoXaT5FDpX_WmCeSipxGcekLCcbzWULUYr07goxEC8GYToR551U7m1jvq9rMWdCOFDOP5FCvwS4p8rpOS28jz3CDrFe65h1A/s400/Fibonacci_Prolog.jpg" width="400" /></a></div>
<br />
My LED Numbers applications is gladly ready and will come after this blog -;)<br />
<br />
Greetings,<br />
<br />
Blag.<br />
Development Culture.Alvaro "Blag" Tejada Galindohttp://www.blogger.com/profile/12061593528820409779noreply@blogger.com0tag:blogger.com,1999:blog-4144704359177008692.post-30428632790113907502016-12-05T10:28:00.000-08:002016-12-05T10:28:16.625-08:00LED is my new Hello World - Rust timeAs I'm currently learning <a href="https://www.rust-lang.org/en-US/" target="_blank">Rust</a>, I need to publish my LED app again -;)<br />
<br />
Please take in mind...that..."I'm learning Rust"...so my code might be buggy, long and not idiomatic...but...enough to showcase the language and allow me to learn more -;)<br />
<br />
Here's the code...
<br />
<br />
<table align="center" style="width: 600px;">
<tbody>
<tr><th bgcolor="#6690BC">led_numbers.rs</th>
</tr>
<tr>
<td><pre>use std::io;
use std::collections::HashMap;
fn main(){
let mut leds:HashMap<&str, &str> = HashMap::new();
leds.insert("0", " _ ,| | ,|_| ");
leds.insert("1", " ,| ,| ");
leds.insert("2", " _ , _| ,|_ ");
leds.insert("3", "_ ,_| ,_| ");
leds.insert("4", " ,|_| , | ");
leds.insert("5", " _ ,|_ , _| ");
leds.insert("6", " _ ,|_ ,|_| ");
leds.insert("7", "_ , | , | ");
leds.insert("8", " _ ,|_| ,|_| ");
leds.insert("9", " _ ,|_| , _| ");
println!("Enter a number : ");
let mut input_text = String::new();
io::stdin().read_line(&mut input_text)
.expect("failed to read");
let split = input_text.split("");
let vec: Vec<&str> = split.collect();
let count = &vec.len() - 2;
for i in 0..3{
for j in 0..count{
match leds.get(&vec[j]){
Some(led_line) => {
let line = led_line.split(",");
let vec_line: Vec<&str> = line.collect();
print!("{}",&vec_line[i]);
},
None => println!("")
}
}
print!("");
}
println!("");
}
</pre>
</td>
</tr>
<tr>
</tr>
</tbody></table>
<br />
And here's the result...<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhKzT8vHmfI02kSyWHSF7dSzzrOoIhbW8uQJWoCaoeH-pGd59PVrIhl0HSVM_8Jn9uz_L4DRjUn5MLWbI0gNqBehdLtKqRtgbJQeI0y2b7uV4Zass3dF9yKGN_UHjF_S2l_s-KaZZFlf65Y/s1600/LedNumbers_Rust.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="178" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhKzT8vHmfI02kSyWHSF7dSzzrOoIhbW8uQJWoCaoeH-pGd59PVrIhl0HSVM_8Jn9uz_L4DRjUn5MLWbI0gNqBehdLtKqRtgbJQeI0y2b7uV4Zass3dF9yKGN_UHjF_S2l_s-KaZZFlf65Y/s400/LedNumbers_Rust.jpg" width="400" /></a></div>
<br />
Hope you like and if you can point me in more Rusty way of doing it...please let me know -:D<br />
<br />
Greetings,<br />
<br />
Blag.<br />
Development Culture.Alvaro "Blag" Tejada Galindohttp://www.blogger.com/profile/12061593528820409779noreply@blogger.com0tag:blogger.com,1999:blog-4144704359177008692.post-89710179096130282962016-12-05T10:12:00.001-08:002016-12-05T10:12:41.553-08:00My first post on RustAgain...I'm learning a new programming language...and this time is the turn for <a href="https://www.rust-lang.org/en-US/" target="_blank">Rust</a>.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiVEUavPVTyhp6tsVJ2hPICURfahOGMeEZrl8cJjWJcU24AV4zrewQtmhEwwpZrofg54EirCe6VoR5QWO9lK3-M3Vp3U8xvEKIxm9wxvd7jt0U-wUWA_NgzcBvTEvAtZ4LTlJ9cna61UP-r/s1600/Rust_Logo.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiVEUavPVTyhp6tsVJ2hPICURfahOGMeEZrl8cJjWJcU24AV4zrewQtmhEwwpZrofg54EirCe6VoR5QWO9lK3-M3Vp3U8xvEKIxm9wxvd7jt0U-wUWA_NgzcBvTEvAtZ4LTlJ9cna61UP-r/s1600/Rust_Logo.png" /></a></div>
<br />
Rust is very nice and have some really interesting features like ownership and borrowing...and the syntax really reminds me of OCaml...which is really cool as well...<br />
<br />
Right now I'm reading the official documentation, that it's pretty well done...so of course I did my Fibonacci numbers app...<br />
<br />
<table align="center" style="width: 600px;">
<tbody>
<tr><th bgcolor="#6690BC">fibonacci.rs</th>
</tr>
<tr>
<td><pre>use std::io;
fn fib(num: i64, a: i64, b:i64) -> String{
let mut result: String = "".to_string();
let sum: i64 = a + b;
let sum_str: &str = &sum.to_string();
let a_str: &str = &a.to_string();
let b_str: &str = &b.to_string();
if a > 0 && num > 1 {
result = result + sum_str + " " + &fib((num - 1), (a + b), a);
}else if a == 0{
result = "".to_string() + a_str + " " + b_str + " " +
sum_str + " " + &fib((num - 1), (a + b), b);
}
result
}
fn main(){
println!("Enter a number : ");
let mut input_num = String::new();
io::stdin().read_line(&mut input_num)
.expect("failed to read");
let trimmed = input_num.trim();
match trimmed.parse::<i64>() {
Ok(i) => { let result: String = fib(i, 0, 1); print!("{}", result);}
Err(..) => println!("Please enter an interger, not {}", trimmed)
};
}
</i64></pre>
</td>
</tr>
<tr>
</tr>
</tbody></table>
<br />
The code is a little bit long for my taste...but that might be simply because I haven't learned enough Rust...or because their ownership/borrowing system sacrifices length to add security...which is actually a pretty good thing...<br />
<br />
Here's the result...<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiNwcR5N2PfbD_ZcwT0K1am_52KX-87CimdAkiQbTCUUzmX0H4ncESdnuftKqwi3SzRmC6DtyjqNb_jI8za5mJSyDLYVSvl4XEydjsmWDIa2O6aqA5gN4xUdq1tiFzBmtBo4RgDHqj90GmL/s1600/Fibonacci_Rust.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="133" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiNwcR5N2PfbD_ZcwT0K1am_52KX-87CimdAkiQbTCUUzmX0H4ncESdnuftKqwi3SzRmC6DtyjqNb_jI8za5mJSyDLYVSvl4XEydjsmWDIa2O6aqA5gN4xUdq1tiFzBmtBo4RgDHqj90GmL/s400/Fibonacci_Rust.jpg" width="400" /></a></div>
<br />
<br />
My LED Numbers app is ready of course...so it's coming right after this post -;)<br />
<br />
Greetings,<br />
<br />
Blag.<br />
Development Culture.Alvaro "Blag" Tejada Galindohttp://www.blogger.com/profile/12061593528820409779noreply@blogger.com0tag:blogger.com,1999:blog-4144704359177008692.post-20218159179831363542016-12-01T12:56:00.000-08:002016-12-06T11:24:01.253-08:00Unity3D and Alexa working together<div style="text-align: justify;">
<h2 style="background-color: #333333; color: #cccccc; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif; font-size: 22px; margin: 0px; position: relative; text-align: center;">
<b>This post was originally posted on <a href="https://blogs.sap.com/2016/12/01/unity3d-and-alexa-working-together/" target="_blank">Unity3D and Alexa working together</a>.</b></h2>
</div>
<br />
Since a long time...I had the idea of making Unity3D and Alexa work together...however...other project kept me away for actually doing it...so...a couple of days ago...a conversation with a friend made me remember that I actually really wanted to do this...so I did :)<br />
<br />
At first...I wasn't exactly sure how to do it...but then slowly the main idea came into my mind...what if Unity read a webservice that gets updated by Alexa? When the right command is parsed, then Unity will create the object and problems is solved...seems easy? Well...it actually is...<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjE-l-DxfmBwoGFLNQttKem90tyZWKm4iWWWsy1OxuxjieydT6HicsoRW726xP4kshb1MZG164WfdzrXl7_DRCb7WD2eDseKXetnIvgO1s1lwoywI1H3_4f4Rnbx7VXWv1gL3C2THOHubf3/s1600/Unity_Diagram.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjE-l-DxfmBwoGFLNQttKem90tyZWKm4iWWWsy1OxuxjieydT6HicsoRW726xP4kshb1MZG164WfdzrXl7_DRCb7WD2eDseKXetnIvgO1s1lwoywI1H3_4f4Rnbx7VXWv1gL3C2THOHubf3/s320/Unity_Diagram.jpg" width="304" /></a></div>
<br />
<br />
First things first...we need to create a small NodeJS webserver on <a href="https://www.hekoru.com/" target="_blank">Heroku</a>...then...we need to install the <a href="https://toolbelt.heroku.com/" target="_blank">Heroku Toolbelt</a>...<br />
<br />
Now...create a folder called <b>node_alexa</b> and inside create the following files...<br />
<div>
<br /></div>
<table align="center" style="width: 600px;">
<tbody>
<tr><th bgcolor="#6690BC">package.json</th>
</tr>
<tr>
<td><pre>{
"dependencies": {
"express": "4.13.3"
},
"engines": {
"node": "0.12.7"
}
}
</pre>
</td>
</tr>
<tr>
</tr>
</tbody></table>
<table align="center" style="width: 600px;">
<tbody>
<tr><th bgcolor="#6690BC">procfile</th>
</tr>
<tr>
<td><pre>web: node index.js
</pre>
</td>
</tr>
<tr>
</tr>
</tbody></table>
<table align="center" style="width: 600px;">
<tbody>
<tr><th bgcolor="#6690BC">index.js</th>
</tr>
<tr>
<td><pre>var express = require('express')
,app = express()
,last_value;
app.set('port', (process.env.PORT || 5000));
app.get('/', function (req, res) {
if(req.query.command == ""){
res.send("{ \"command\":\"" + last_value + "\"}");
}else{
if(req.query.command == "empty"){
last_value = "";
res.send("{}");
}else{
res.send("{ \"command\":\"" + req.query.command + "\"}");
last_value = req.query.command;
}
}
})
app.listen(app.get('port'), function () {
console.log("Node app is running on port', app.get('port')");
})
</pre>
</td>
</tr>
<tr>
</tr>
</tbody></table>
<br />
Once you have that...log into your Heroku Toolbelt and write the following...<br />
<br />
<table align="center" style="width: 600px;">
<tbody>
<tr><th bgcolor="#6690BC">Heroku Toolbelt</th>
</tr>
<tr>
<td><pre>cd node_alexa
git init .
git add .
git commit -m "Init"
heroku apps:create "yourappname"
git push heroku master
heroku ps:scale = web 0
heroku ps:scale = web 1
</pre>
</td>
</tr>
<tr>
</tr>
</tbody></table>
<br />
Your webservice is ready to rock :) You should be able to find by going to "http://yourappname.herokuapp.com/"<br />
<br />
Now...this simple NodeJS powered webservice will serve as a simple Echo server...meaning...whatever you type will be returned as a json response...of course...if you type "empty" then the response will be a empty json...so the main idea here is that we can keep the last entered value...if you pass a command it will be called again when you don't pass any commands at all...so by calling it once...we can cal it multiple times without disrupting its value...<br />
Next in line...will be to create our Unity app...<br />
<br />
Create a new app and call it "WebService" or something like that...project name doesn't matter too much...<br />
<br />
If the Hierarchy window select "Main Camera" and change the "Tranform" details like this...<br />
<div>
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEin0dWejPrBrSX2octWcSqZdjAgBYkch_DenObBtMjp1be-C6xPyx-Uoww8_ySgJetO7Z-m9WH3T1pLR6VBeSsuPg52sJOzVizw3vWcEa2OSPLgBLyqowNnk9WDA0_ui6TZk-N8gBBm9UW6/s1600/Main_Camera.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="143" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEin0dWejPrBrSX2octWcSqZdjAgBYkch_DenObBtMjp1be-C6xPyx-Uoww8_ySgJetO7Z-m9WH3T1pLR6VBeSsuPg52sJOzVizw3vWcEa2OSPLgBLyqowNnk9WDA0_ui6TZk-N8gBBm9UW6/s400/Main_Camera.jpg" width="400" /></a></div>
<div>
<br /></div>
<div>
Now, create a new "3D Object" -> "Cube" and name it "Platform" with the following "Transform" details...</div>
<div>
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhaDTVeqkQVguzp5TXaMMQq80XwPJygWu5gGdcEjQYZpEpERDYIOgud8Ylkx0IV8GNoSnu9O0wsaEZP3XAfDIxwKnihDNfk0v9yUDwfBelxtoBPYMrpNrXuaApR1zz6orwOn3r30pPV_NZn/s1600/Platform.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="140" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhaDTVeqkQVguzp5TXaMMQq80XwPJygWu5gGdcEjQYZpEpERDYIOgud8Ylkx0IV8GNoSnu9O0wsaEZP3XAfDIxwKnihDNfk0v9yUDwfBelxtoBPYMrpNrXuaApR1zz6orwOn3r30pPV_NZn/s400/Platform.jpg" width="400" /></a></div>
<div>
<br /></div>
<div>
After that, we might need to create four wall that will go around the platform...so create 4 "3D Object" -> "Cube" and name them "Wall 1", "Wall 2", "Wall 3" and "Wall 4"...</div>
<div>
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEje3YVNK1shLa3xfN4k250xxiFq-Dbfb_iS5jEsXs25dZ26tTaIe_tW6pbBAbAgrvIUZG-StxVvIl6b-vNPT-Ut_FrX_bRw6R-BkNoVpU2Uj7FpPrd5VFMyiR8UBJtPIEml6emAFi4c1GqQ/s1600/Wall1.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="138" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEje3YVNK1shLa3xfN4k250xxiFq-Dbfb_iS5jEsXs25dZ26tTaIe_tW6pbBAbAgrvIUZG-StxVvIl6b-vNPT-Ut_FrX_bRw6R-BkNoVpU2Uj7FpPrd5VFMyiR8UBJtPIEml6emAFi4c1GqQ/s400/Wall1.jpg" width="400" /></a></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhrIQw0J9qUnNF90hThoS7nT8ktQgvxlx_-DFEiQF4Ayh-qealFzPLaksB8Vf968wu3Ms5sTtlblCcpp7SU6lOhykZVew_u3JL-9Gxt4vNDNr-MI9pq9lTOKc6V1yjMnpRmDq9u5Oodah2S/s1600/Wall2.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="145" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhrIQw0J9qUnNF90hThoS7nT8ktQgvxlx_-DFEiQF4Ayh-qealFzPLaksB8Vf968wu3Ms5sTtlblCcpp7SU6lOhykZVew_u3JL-9Gxt4vNDNr-MI9pq9lTOKc6V1yjMnpRmDq9u5Oodah2S/s400/Wall2.jpg" width="400" /></a></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjjbQ2d0u7y6IYbIUg_6AS0rpoPcqkWd39qrg_oicviBJMJeWfTqgyGjFygvxHnPHNgtQbiKHLOTckQAEgdcOmioGJCKgGFSykybMLDKA6A8AzpLnqgH1R3aRhM2eegAIwlWp2R97HW0YGw/s1600/Wall3.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="140" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjjbQ2d0u7y6IYbIUg_6AS0rpoPcqkWd39qrg_oicviBJMJeWfTqgyGjFygvxHnPHNgtQbiKHLOTckQAEgdcOmioGJCKgGFSykybMLDKA6A8AzpLnqgH1R3aRhM2eegAIwlWp2R97HW0YGw/s400/Wall3.jpg" width="400" /></a></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgtRQO6dzmyoLe8oEbR_U5q7gIi3uApnt-uf-gOpd2f-F7lxpcEV91cZG5ONlXWvD-nzfrjVGWKqWxhpuClNO3rt2rAkYFBRnoGhH0_Q6DbF58lXnJqQBJP4vzvgAaVte9N7A_YOEcV6mnV/s1600/Wall4.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="141" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgtRQO6dzmyoLe8oEbR_U5q7gIi3uApnt-uf-gOpd2f-F7lxpcEV91cZG5ONlXWvD-nzfrjVGWKqWxhpuClNO3rt2rAkYFBRnoGhH0_Q6DbF58lXnJqQBJP4vzvgAaVte9N7A_YOEcV6mnV/s400/Wall4.jpg" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: justify;">
When everything is ready, your workspace should look like this...</div>
<div class="separator" style="clear: both; text-align: justify;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh9vCTng2uLSmrUOmTpGqcUtq4fL2Msh3yBWYC7aVyTXb8YYZTV6dPjphGwpPTvEPyQ-vxYbAixtkpJDjMiZD6zIdcsWPSE9MR7FY7Z_KJzwgsASmNL8feIfPmx1A_uxgfvHgz5fhMvQbOl/s1600/Workspace.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="210" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh9vCTng2uLSmrUOmTpGqcUtq4fL2Msh3yBWYC7aVyTXb8YYZTV6dPjphGwpPTvEPyQ-vxYbAixtkpJDjMiZD6zIdcsWPSE9MR7FY7Z_KJzwgsASmNL8feIfPmx1A_uxgfvHgz5fhMvQbOl/s400/Workspace.jpg" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: justify;">
<br /></div>
<div class="separator" style="clear: both; text-align: justify;">
Go to the project tab and create a new folder called "plugins" and then create a new C# file called "SimpleJSON"...inside copy the source code from <a href="http://wiki.unity3d.com/index.php/SimpleJSON" target="_blank">here</a>...this will allow us to use SimpleJSON to parse the JSON...</div>
<div class="separator" style="clear: both; text-align: justify;">
<br /></div>
<div class="separator" style="clear: both; text-align: justify;">
Now...create another folder called "Script" and inside create a new C# file called "MetaCoding"...or whatever you like...</div>
<div class="separator" style="clear: both; text-align: justify;">
<br /></div>
<div class="separator" style="clear: both; text-align: justify;">
<br /></div>
<div>
<br /></div>
<table align="center" style="width: 600px;">
<tbody>
<tr><th bgcolor="#6690BC">MetaCoding.cs</th>
</tr>
<tr>
<td><pre>using UnityEngine;
using System.Collections;
using System.Net;
using System.IO;
using SimpleJSON;
public class MetaCoding : MonoBehaviour {
int counter = 1;
IEnumerator DownloadWebService()
{
while (true) {
WWW w = new WWW("http://yourapp.herokuapp.com/?command");
yield return w;
print("Waiting for webservice\n");
yield return new WaitForSeconds(1f);
print("Received webservice\n");
ExtractCommand(w.text);
print("Extracted information");
WWW y = new WWW("http://yourapp.herokuapp.com/?command=empty");
yield return y;
print("Cleaned webservice");
yield return new WaitForSeconds(5);
}
}
void ExtractCommand(string json)
{
var jsonstring = JSON.Parse(json);
string command = jsonstring["command"];
print(command);
if (command == null) { return; }
string[] commands_array = command.Split(" "[0]);
if(commands_array.Length < 3)
{
return;
}
if (commands_array[0] == "create")
{
CreateObject(commands_array[1], commands_array[2]);
}
}
void CreateObject(string color, string shape)
{
string name = "NewObject_" + counter;
counter += 1;
GameObject NewObject = new GameObject(name);
switch (shape)
{
case "cube":
NewObject = GameObject.CreatePrimitive(PrimitiveType.Cube);
break;
case "sphere":
NewObject = GameObject.CreatePrimitive(PrimitiveType.Sphere);
break;
case "cylinder":
NewObject = GameObject.CreatePrimitive(PrimitiveType.Cylinder);
break;
case "capsule":
NewObject = GameObject.CreatePrimitive(PrimitiveType.Capsule);
break;
}
NewObject.transform.position = new Vector3(0, 5, 0);
NewObject.AddComponent<rigidbody>();
switch (color)
{
case "red":
NewObject.GetComponent<renderer>().material.color = Color.red;
break;
case "yellow":
NewObject.GetComponent<renderer>().material.color = Color.yellow;
break;
case "green":
NewObject.GetComponent<renderer>().material.color = Color.green;
break;
case "blue":
NewObject.GetComponent<renderer>().material.color = Color.blue;
break;
case "black":
NewObject.GetComponent<renderer>().material.color = Color.black;
break;
case "white":
NewObject.GetComponent<renderer>().material.color = Color.white;
break;
}
}
// Use this for initialization
void Start () {
print("Started webservice import...\n");
StartCoroutine(DownloadWebService());
}
// Update is called once per frame
void Update () {
}
}
</renderer></renderer></renderer></renderer></renderer></renderer></rigidbody></pre>
</td>
</tr>
<tr>
</tr>
</tbody></table>
<br />
Once you have the code...simply attach the script to the Main Camera...<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEihP_5B6qlwQZZaoxLeCgu0X9iHr71hBKsyb_T3YjaxtaTQcxjlH6_akrRQN_tmpuT99XpFeSODz9SgmvYnpHcinjzlw-Olk362HDn862r6i3pSVzYFcXqdhdT78YrSynutgONv_KBXDhzg/s1600/Main_Camera_Script.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="162" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEihP_5B6qlwQZZaoxLeCgu0X9iHr71hBKsyb_T3YjaxtaTQcxjlH6_akrRQN_tmpuT99XpFeSODz9SgmvYnpHcinjzlw-Olk362HDn862r6i3pSVzYFcXqdhdT78YrSynutgONv_KBXDhzg/s400/Main_Camera_Script.jpg" width="400" /></a></div>
<br />
The basic concept for this script is pretty simple...We're creating "DownloadWebService" as an IEnumerator method so we can call it as a Coroutine...and that allow us to have a sleep as we want to give some time between calls...<br />
<br />
This method will fetch our Heroku WebService looking for a "create" command...once it has it...it will parse the JSON response and split in 3...so we can have..."create", "blue" and "sphere"...this will call CreateObject which will then create a blue sphere...after we have done that...the coroutine will continue as simply send a new command to our WebService to clean the output...to make this work nicely...we want to give 5 seconds after we clean the webservice before trying to see if there's another "create" call...<br />
<br />
And this call be will be done by our Alexa skill...so basically when saying "create blue sphere" on Alexa...she will be send the command to the WebService...update the message and our Unity app will grab it...do its work...and clean up the Webservice...the wait for Alexa to provide the next command...<br />
So...to kind of wrap up...we need to create our Alexa skill...<br />
<br />
First, we're going to create a Lambda function...so log in <a href="https://www.amazon.com/ap/signin?openid.assoc_handle=aws&openid.return_to=https%3A%2F%2Fsignin.aws.amazon.com%2Foauth%3Fresponse_type%3Dcode%26client_id%3Darn%253Aaws%253Aiam%253A%253A015428540659%253Auser%252Flambda%26redirect_uri%3Dhttps%253A%252F%252Fconsole.aws.amazon.com%252Flambda%252Fhome%253Fregion%253Dus-east-1%2526state%253DhashArgs%252523%25252Ffunctions%2526isauthcode%253Dtrue%26noAuthCookie%3Dtrue&openid.mode=checkid_setup&openid.ns=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0&openid.identity=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0%2Fidentifier_select&openid.claimed_id=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0%2Fidentifier_select&action=&disableCorpSignUp=&clientContext=&marketPlaceId=&poolName=&authCookies=&pageId=aws.ssop&siteState=registered%2Cen_US&accountStatusPolicy=P1&sso=&openid.pape.preferred_auth_policies=MultifactorPhysical&openid.pape.max_auth_age=120&openid.ns.pape=http%3A%2F%2Fspecs.openid.net%2Fextensions%2Fpape%2F1.0&server=%2Fap%2Fsignin%3Fie%3DUTF8&accountPoolAlias=&forceMobileApp=0&language=en_US&forceMobileLayout=0" target="_blank">here</a>...<br />
<br />
Of course...I have everything already setup...so I'm going to create a dummy function just to show the steps...<br />
<br />
Click on "Create Lambda Function" and you will be presented with this...<br />
<div>
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEijOFSbVVQBqZrj-KdDump3ViphV27ip2FGqfw_zOuCmDLeWpWkqHaIO4YwEhMPsBksQcBHe6uN-lWpZ4VBHsb7AnCKq3l_bxVR4Yy63GvuGqjVEawbu18b8LXyW4Gw2eHaTPHK9qDdpMSj/s1600/Blueprint.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="150" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEijOFSbVVQBqZrj-KdDump3ViphV27ip2FGqfw_zOuCmDLeWpWkqHaIO4YwEhMPsBksQcBHe6uN-lWpZ4VBHsb7AnCKq3l_bxVR4Yy63GvuGqjVEawbu18b8LXyW4Gw2eHaTPHK9qDdpMSj/s400/Blueprint.jpg" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: justify;">
There's a bunch of course...so type in "Color" in the filter box...</div>
<div class="separator" style="clear: both; text-align: justify;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgFpAbNb6KoY60tPlbqNGIgQdxBvvfGXebuXhF4G5ozRj6UITczjUPIjNNObhkawfTJOqrtxFyHXFto_oMEHwUoo3e18pEE76Y1qhSQxkbI4_5afpABKgXoPUxsQ4lOEaZRN9Gt-xQzAcfC/s1600/Alexa_Color.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="158" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgFpAbNb6KoY60tPlbqNGIgQdxBvvfGXebuXhF4G5ozRj6UITczjUPIjNNObhkawfTJOqrtxFyHXFto_oMEHwUoo3e18pEE76Y1qhSQxkbI4_5afpABKgXoPUxsQ4lOEaZRN9Gt-xQzAcfC/s400/Alexa_Color.jpg" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: justify;">
Choose "alexa-skills-kit-color-expert"</div>
<div class="separator" style="clear: both; text-align: justify;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjr41uMRjcRqepsxNLjGflTk8VxR_tDdaJUjQdZq8Qsd6-N1kU5vdyTAHfcjuwYwPHvTmSEh1sY7m1V36TVKTZe5GI_2alSDLw0WrKbrtx6L2yXJ9_KeztZVgVXIgDjhk6vQOyVDwmQajHu/s1600/Trigger.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="147" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjr41uMRjcRqepsxNLjGflTk8VxR_tDdaJUjQdZq8Qsd6-N1kU5vdyTAHfcjuwYwPHvTmSEh1sY7m1V36TVKTZe5GI_2alSDLw0WrKbrtx6L2yXJ9_KeztZVgVXIgDjhk6vQOyVDwmQajHu/s400/Trigger.jpg" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: justify;">
Leave this as it is and press "Next"</div>
<div class="separator" style="clear: both; text-align: justify;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgfzt4FU2QOb_tFFZDw8OC1oaGkDRU5FroFllZdZI1bZ-CPw7jeOSSrnRd7kR4PyLxJEn9f1SZ0SM2ZYiEwjqpoY2nw_ifBHWdigP7j5xtX0ZjjK04LFD-X488_G1CjmZNfOUpYIsSN_P9L/s1600/Lambda_Name.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="140" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgfzt4FU2QOb_tFFZDw8OC1oaGkDRU5FroFllZdZI1bZ-CPw7jeOSSrnRd7kR4PyLxJEn9f1SZ0SM2ZYiEwjqpoY2nw_ifBHWdigP7j5xtX0ZjjK04LFD-X488_G1CjmZNfOUpYIsSN_P9L/s400/Lambda_Name.jpg" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: justify;">
<br /></div>
<div class="separator" style="clear: both; text-align: justify;">
Choose a name and a description...</div>
<div class="separator" style="clear: both; text-align: justify;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjlC8EhEEQVUJFaskcknw_GpbW1DmERZmQVkZyjrKx9OhkDskN4vEIxherLAFf_W3f-FScdIzRm3opYg5Z5ScB9lMtQ2-828-q146omSOVlYvbYVkYQmgDblBmhI6j894r_cvqdVD_J7KeL/s1600/Lambda_Roles.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="193" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjlC8EhEEQVUJFaskcknw_GpbW1DmERZmQVkZyjrKx9OhkDskN4vEIxherLAFf_W3f-FScdIzRm3opYg5Z5ScB9lMtQ2-828-q146omSOVlYvbYVkYQmgDblBmhI6j894r_cvqdVD_J7KeL/s400/Lambda_Roles.jpg" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: justify;">
<br /></div>
<div class="separator" style="clear: both; text-align: justify;">
Choose an existing role if you have it already...otherwise just create a lambda_basic_execution...then raise up Timeout to 10 seconds and leave everything else as it is...press "Next"...a confirmation window will appear...so just press "Create function"...</div>
<div class="separator" style="clear: both; text-align: justify;">
<br /></div>
<div class="separator" style="clear: both; text-align: justify;">
You will be presented with a screen where you can upload your source code (which will be doing later on) and an ARN number...which we need for the next step...</div>
<div style="text-align: justify;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj9ZaNOA4S9Uat9D8n7B3IEM9qLhVeVGdWjYhA9qu9r8_-byEuN03S92Na7r-cN8JkQ5aoqP-L73-EgBUGc7BVtfRYXENN7Uv-u49R9Z2y9MUseeSjE22YqOb5L0OI3Y10_rMfvZLjd-3kk/s1600/Lambda_ARN.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="25" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj9ZaNOA4S9Uat9D8n7B3IEM9qLhVeVGdWjYhA9qu9r8_-byEuN03S92Na7r-cN8JkQ5aoqP-L73-EgBUGc7BVtfRYXENN7Uv-u49R9Z2y9MUseeSjE22YqOb5L0OI3Y10_rMfvZLjd-3kk/s400/Lambda_ARN.jpg" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: justify;">
The following part deals with create the Alexa skill...so please follow along...and log in <a href="https://www.amazon.com/ap/signin?openid.return_to=https%3A%2F%2Fdeveloper.amazon.com%2Fap_login.html&openid.identity=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0%2Fidentifier_select&openid.assoc_handle=mas_dev_portal&openid.mode=checkid_setup&openid.claimed_id=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0%2Fidentifier_select&pageId=mas_dev_portal2&openid.ns=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0&language=en_US&openid.assoc_handle=mas_dev_portal&openid.claimed_id=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0%2Fidentifier_select&openid.identity=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0%2Fidentifier_select&openid.mode=logout&openid.ns=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0&openid.return_to=https%3A%2F%2Fwww.amazon.com%2Fap%2Fsignin%3Fopenid.return_to%3Dhttps%253A%252F%252Fdeveloper.amazon.com%252Fap_login.html%26openid.identity%3Dhttp%253A%252F%252Fspecs.openid.net%252Fauth%252F2.0%252Fidentifier_select%26openid.assoc_handle%3Dmas_dev_portal%26openid.mode%3Dcheckid_setup%26openid.claimed_id%3Dhttp%253A%252F%252Fspecs.openid.net%252Fauth%252F2.0%252Fidentifier_select%26pageId%3Dmas_dev_portal2%26openid.ns%3Dhttp%253A%252F%252Fspecs.openid.net%252Fauth%252F2.0%26language%3Den_US&#/skills" target="_blank">here</a>...</div>
<div class="separator" style="clear: both; text-align: justify;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgwULRDSMun2wSanjxDn5xg387LmFn3lQNoKy3HoC8c1W0d54l5llGpr4DDjc6CSdTXNVnKVG2rpxK7KgfWs1pJdRkRk8Yqwb_yI9hjRhxgMq5_wX4dV8_KgshiMOWCJBE8GF8RecZWCUt_/s1600/Alexa_Skills_Kit.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="261" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgwULRDSMun2wSanjxDn5xg387LmFn3lQNoKy3HoC8c1W0d54l5llGpr4DDjc6CSdTXNVnKVG2rpxK7KgfWs1pJdRkRk8Yqwb_yI9hjRhxgMq5_wX4dV8_KgshiMOWCJBE8GF8RecZWCUt_/s400/Alexa_Skills_Kit.jpg" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: justify;">
Choose "Alexa Skills Kit"...and create a new skill...</div>
<div class="separator" style="clear: both; text-align: justify;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
</div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg1k9giIW3vfeyCZPG7x2D5ZdXZl4HlaqiHWh8Zqes4TfLFXXgR5rAsPajSGLgsQeJtf0ewF5wHE4LVPB7F88q3pf_3WqBAaKqE8kQ3r44uYIYOBxMS40I15FlsAwQKwcZGgh1sGWxtk9M4/s1600/Alexa_Skill_Information.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="205" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg1k9giIW3vfeyCZPG7x2D5ZdXZl4HlaqiHWh8Zqes4TfLFXXgR5rAsPajSGLgsQeJtf0ewF5wHE4LVPB7F88q3pf_3WqBAaKqE8kQ3r44uYIYOBxMS40I15FlsAwQKwcZGgh1sGWxtk9M4/s400/Alexa_Skill_Information.jpg" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: justify;">
<br /></div>
<div class="separator" style="clear: both; text-align: justify;">
Choose a name for you skill and the most important...choose an "Invocation Name"...which is what you're going to use tell Alexa to open you application...something like..."Alexa, open Sandbox"...click next...</div>
<div class="separator" style="clear: both; text-align: justify;">
<br /></div>
<div class="separator" style="clear: both; text-align: justify;">
On the Interaction Model tab we have two windows...fill this on "Intent Schema"...</div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<table align="center" style="width: 600px;">
<tbody>
<tr><th bgcolor="#6690BC">Intent Schema</th>
</tr>
<tr>
<td><pre>{
"intents": [
{
"intent": "GetUnityIntent",
"slots": [
{
"name": "color",
"type": "LITERAL"
},
{
"name": "shape",
"type": "LITERAL"
}
]
},
{
"intent": "HelpIntent",
"slots": []
}
]
}
</pre>
</td>
</tr>
<tr>
</tr>
</tbody></table>
<br />
This are basically the parameters that we can use when asking Alexa to do something...<br />
<br />
And fill this on "Sample Utterances"...<br />
<br />
<table align="center" style="width: 600px;">
<tbody>
<tr><th bgcolor="#6690BC">Sample Utterances</th>
</tr>
<tr>
<td><pre>GetUnityIntent create {red|color} {sphere|shape}
GetUnityIntent create {yellow|color} {sphere|shape}
GetUnityIntent create {green|color} {sphere|shape}
GetUnityIntent create {blue|color} {sphere|shape}
GetUnityIntent create {black|color} {sphere|shape}
GetUnityIntent create {white|color} {sphere|shape}
GetUnityIntent create {red|color} {cube|shape}
GetUnityIntent create {yellow|color} {cube|shape}
GetUnityIntent create {green|color} {cube|shape}
GetUnityIntent create {blue|color} {cube|shape}
GetUnityIntent create {black|color} {cube|shape}
GetUnityIntent create {white|color} {cube|shape}
GetUnityIntent create {red|color} {cylinder|shape}
GetUnityIntent create {yellow|color} {cylinder|shape}
GetUnityIntent create {green|color} {cylinder|shape}
GetUnityIntent create {blue|color} {cylinder|shape}
GetUnityIntent create {black|color} {cylinder|shape}
GetUnityIntent create {white|color} {cylinder|shape}
GetUnityIntent create {red|color} {capsule|shape}
GetUnityIntent create {yellow|color} {capsule|shape}
GetUnityIntent create {green|color} {capsule|shape}
GetUnityIntent create {blue|color} {capsule|shape}
GetUnityIntent create {black|color} {capsule|shape}
GetUnityIntent create {white|color} {capsule|shape}
GetUnityIntent {thank you|color}
</pre>
</td>
</tr>
<tr>
</tr>
</tbody></table>
<br />
This are all the commands that Alexa can understand...and yes...we could have used "Custom Slot Types" to make the code shorter...but...I have had the problems of not working pretty well with more than one slot...simply hit next...<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg0Ce0cz26IU1CkAwn0yZHWoKurwn83efeSihHkJK-yyImEc6T1k4bC-DX30f9P_mkKvw8Qr2PwR8JLfJYlM8tW188pSwYO_kgP-mwSxU3XOsOzgMcY7OxeXElOz7fu_gYVr2j0xfi99zyL/s1600/Alexa_Global_Fields.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="235" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg0Ce0cz26IU1CkAwn0yZHWoKurwn83efeSihHkJK-yyImEc6T1k4bC-DX30f9P_mkKvw8Qr2PwR8JLfJYlM8tW188pSwYO_kgP-mwSxU3XOsOzgMcY7OxeXElOz7fu_gYVr2j0xfi99zyL/s400/Alexa_Global_Fields.jpg" width="400" /></a></div>
<br />
Here, choose AWS Lambda ARN...and pick either North America or Europe depending on your physical location...the on the text box...simply copy and paste the ARN that you received from your Lambda function...<br />
<br />
This will send you to the "Test" tab...but we don't want to and actually we can't use that yet...so go back to the "Skill Information" tab and you will find that a new field has appeared...<br />
<br />
And that should be "Application Id"...copy this number and let's move on to the final step...<br />
<br />
Create a folder called "Unity" and inside a folder called "src"...inside that folder copy this file "<a href="https://github.com/dustincoates/alexa-bus-schedule/blob/master/src/index.js" target="_blank">AlexaSkills.js</a>"<br />
<br />
We're going to use the "request" module of NodeJS...so install it locally on the Unity folder like this...<br />
<br />
<div style="text-align: center;">
<b><i>sudo npm install --prefix=~/Unity/src request </i></b></div>
<div style="text-align: center;">
<b><i><br /></i></b></div>
<div style="text-align: justify;">
This will create a node_module folder with the request module on it...</div>
<div style="text-align: justify;">
</div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
Then, create a new file called "index.js"</div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
<br /></div>
<table align="center" style="width: 600px;">
<tbody>
<tr><th bgcolor="#6690BC">index.js</th>
</tr>
<tr>
<td><pre>var request = require("request")
, AlexaSkill = require('./AlexaSkill')
, APP_ID = 'yourappid';
var error = function (err, response, body) {
console.log('ERROR [%s]', err);
};
var getJsonFromUnity = function(color, shape, callback){
var command = "create " + color + " " + shape;
if(color == "thank you"){
callback("thank you");
}
else{
var options = { method: 'GET',
url: 'http://yourapp.herokuapp.com/',
qs: { command: command },
headers:
{ 'postman-token': '230914f7-c478-4f13-32fd-e6593d8db4d1',
'cache-control': 'no-cache' } };
var error_log = "";
request(options, function (error, response, body) {
if (!error) {
error_log = color + " " + shape;
}else{
error_log = "There was a mistake";
}
callback(error_log);
});
}
}
var handleUnityRequest = function(intent, session, response){
getJsonFromUnity(intent.slots.color.value,intent.slots.shape.value, function(data){
if(data != "thank you"){
var text = 'The ' + data + ' has been created';
var reprompt = 'Which shape would you like?';
response.ask(text, reprompt);
}else{
response.tell("You're welcome");
}
});
};
var Unity = function(){
AlexaSkill.call(this, APP_ID);
};
Unity.prototype = Object.create(AlexaSkill.prototype);
Unity.prototype.constructor = Unity;
Unity.prototype.eventHandlers.onSessionStarted = function(sessionStartedRequest, session){
console.log("onSessionStarted requestId: " + sessionStartedRequest.requestId
+ ", sessionId: " + session.sessionId);
};
Unity.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 Unity. Create any color shape by saying create and providing a color and a shape';
var reprompt = 'Which shape would you like?';
response.ask(output, reprompt);
console.log("onLaunch requestId: " + launchRequest.requestId
+ ", sessionId: " + session.sessionId);
};
Unity.prototype.intentHandlers = {
GetUnityIntent: function(intent, session, response){
handleUnityRequest(intent, session, response);
},
HelpIntent: function(intent, session, response){
var speechOutput = 'Create a new colored shape. Which shape would you like?';
response.ask(speechOutput);
}
};
exports.handler = function(event, context) {
var skill = new Unity();
skill.execute(event, context);
};
</pre>
</td>
</tr>
<tr>
</tr>
</tbody></table>
This code is very simple...because it mostly a template...you simply copy it...change a couple of things and you're ready to go...<br />
<br />
Basically when you say "Alexa, open Unity"...she will listen for your requests...so you can say "create green cube"...so will call our Heroku WebService and the wait for another command...if you doesn't speak to her again...she will prompt you to say something...if you say "Thank you" she will politely deactivate herself...<br />
<br />
And that's pretty much it...once Alexa send the command to the WebServer...our Unity App will read and act accordingly...creating whatever shape and color you requested...nice, huh?<br />
<br />
But of course...you don't believe, don't you? It can't be that simple...well...yes and no...it's simple...but I took all the pain point and provide you with the nice and clean set of instructions...<br />
<br />
So...here's how it looks like when you run the Unity app...<br />
<div>
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgHpYH7VFFCmWecFMtYPksl7jpWS0fS53i-sEd_SDwlil5i4rwnSbw9XX2z5jP6sVa2yxGJe9VpPRLfMDgthiw8MRg4QR5b4TOYUxb-bVH01TW4yce4aY-pKWZT_qOywaFojIorX2v6K7dq/s1600/IMG_1563+%2528Copy%2529.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="300" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgHpYH7VFFCmWecFMtYPksl7jpWS0fS53i-sEd_SDwlil5i4rwnSbw9XX2z5jP6sVa2yxGJe9VpPRLfMDgthiw8MRg4QR5b4TOYUxb-bVH01TW4yce4aY-pKWZT_qOywaFojIorX2v6K7dq/s400/IMG_1563+%2528Copy%2529.JPG" width="400" /></a></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgZMNZoZchTxvpB6yo20OXfC-c9PCBQr7Xng2enE25Wq4vr293CmSLg-vD8nhQGjtBRS6iCPoH-kDQovjbUeiwb3U5bPXhFCHhOSHorMFnU8d28q05oVe7ztKPax5QwTo8RiOCGhyphenhyphenDp_Qkz/s1600/IMG_1564+%2528Copy%2529.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="300" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgZMNZoZchTxvpB6yo20OXfC-c9PCBQr7Xng2enE25Wq4vr293CmSLg-vD8nhQGjtBRS6iCPoH-kDQovjbUeiwb3U5bPXhFCHhOSHorMFnU8d28q05oVe7ztKPax5QwTo8RiOCGhyphenhyphenDp_Qkz/s400/IMG_1564+%2528Copy%2529.JPG" width="400" /></a></div>
<div>
<br /></div>
<div>
And here the action video...</div>
<div>
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<iframe allowfullscreen="" class="YOUTUBE-iframe-video" data-thumbnail-src="https://i.ytimg.com/vi/bWEfDRIIIRY/0.jpg" frameborder="0" height="266" src="https://www.youtube.com/embed/bWEfDRIIIRY?feature=player_embedded" width="320"></iframe></div>
<div>
<br /></div>
<div>
Hope you like it...and stay tuned...because for me this was only a proof of concept...the real thing will become my next full time project...</div>
<div>
<br /></div>
<div>
Greetings,</div>
<div>
<br /></div>
<div>
Blag.</div>
<div>
Development Culture.</div>
Alvaro "Blag" Tejada Galindohttp://www.blogger.com/profile/12061593528820409779noreply@blogger.com0tag:blogger.com,1999:blog-4144704359177008692.post-43248367096853647532016-12-01T07:52:00.000-08:002016-12-01T07:52:48.708-08:00LED is my new Hello World - Swift (for Linux) timeIt took me some time to write this post...mainly because I'm now learning <a href="https://www.rust-lang.org/en-US/" target="_blank">Rust</a> and also because I just finished my latest demo...whose blog is coming later today -;)<br />
<br />
This version of my LED Numbers app becomes the 25th language version...so...obviously...it's a pretty nice milestone for me -:D Who knows? Maybe I will do something nice if I can ever reach 50 languages -:D<br />
<br />
Anyway...like I love to say..."Enough talk...show me the source code" -;)<br />
<br />
<table align="center" style="width: 600px;">
<tbody>
<tr><th bgcolor="#6690BC">LedNumbers.swift</th>
</tr>
<tr>
<td><pre>let leds: [Character:String] = [
"0" : " _ ,| | ,|_| ",
"1" : " ,| ,| ",
"2" : " _ , _| ,|_ ",
"3" : "_ ,_| ,_| ",
"4" : " ,|_| , | ",
"5" : " _ ,|_ , _| ",
"6" : " _ ,|_ ,|_| ",
"7" : "_ , | , | ",
"8" : " _ ,|_| ,|_| ",
"9" : " _ ,|_| , _| "
];
print("Enter a number: ",terminator:"");
let num = readLine(strippingNewline: true);
var line = [String]();
var led = "";
for i in 0...2{
for character in num!.characters{
line = String(leds[character]!)!.
characters.split(separator: ",").map(String.init);
print(line[i], terminator:"");
}
print("");
}
</pre>
</td>
</tr>
<tr>
</tr>
</tbody></table>
<br />
And here's the picture of it working its magic -:)<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjkbIbZCAl7Rc41DSyzyq0tAaLKMBkSyiRe1xksILIDW9x4n7CrE5wyYKsVZymtrfuNNBs3ovUXoAZwD689qohPsD76-uF8JHxom7u84DbZKiDgHBS3ZlpKmw9DFLnEru-iYhS-0hwqDsbs/s1600/LedNumbers_Swift.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="138" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjkbIbZCAl7Rc41DSyzyq0tAaLKMBkSyiRe1xksILIDW9x4n7CrE5wyYKsVZymtrfuNNBs3ovUXoAZwD689qohPsD76-uF8JHxom7u84DbZKiDgHBS3ZlpKmw9DFLnEru-iYhS-0hwqDsbs/s400/LedNumbers_Swift.jpg" width="400" /></a></div>
<br />
Greetings,<br />
<br />
Blag.<br />
Development Culture.Alvaro "Blag" Tejada Galindohttp://www.blogger.com/profile/12061593528820409779noreply@blogger.com0tag:blogger.com,1999:blog-4144704359177008692.post-28814164538966394772016-11-28T15:06:00.000-08:002016-11-28T15:06:36.082-08:00My first post on Swift (for Linux)<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjncJLhUMZzI2GIl0yuG4483RJ_Q9rYcG6OoiDDcWyb3_-cYcijUGAoxu8qxcgy1o-D_VcuboOJpbJ5DX9_cMAMcfJBnGnhkQxuP0Alt_aL-UECu5YJ4MJpkYJFGLJyaaQras4SbCZay0Q/s1600/swiftlinux-1.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="276" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjncJLhUMZzI2GIl0yuG4483RJ_Q9rYcG6OoiDDcWyb3_-cYcijUGAoxu8qxcgy1o-D_VcuboOJpbJ5DX9_cMAMcfJBnGnhkQxuP0Alt_aL-UECu5YJ4MJpkYJFGLJyaaQras4SbCZay0Q/s400/swiftlinux-1.png" width="400" /></a></div>
<br />
As Apple kindly released <a href="https://swift.org/" target="_blank">Swift for Linux</a>...I had to learn about it -:)<br />
<br />
Of course...it's not fully implemented...so most of the things that makes Swift awesome on IOS are not here yet...but still...it's awesome! -:D<br />
<br />
Swift is kind of functional...so you can see a lot from Haskell and Erlang...but it's also imperative and Object Oriented...so that makes it a really interesting language...<br />
<br />
As usual...here's my Fibonacci numbers little app...<br />
<br />
<table align="center" style="width: 600px;">
<tbody>
<tr><th bgcolor="#6690BC">fibonacci.swift</th>
</tr>
<tr>
<td><pre>func fib(num:Int,a:Int,b:Int) -> String{
var result: String = "";
if a > 0 && num > 1{
result = result + String(a + b) + " " +
fib(num: (num - 1), a: (a + b), b: a);
}else if a == 0{
result = String(a) + " " + String(b) + " " +
String(a + b) + " " +
fib(num: (num - 1), a: (a + b), b: b);
}
return result;
}
print("Enter a number: ",terminator:"");
let number = Int(readLine(strippingNewline: true)!);
print(fib(num: number!, a: 0, b: 1));
</pre>
</td>
</tr>
<tr>
</tr>
</tbody></table>
<br />
And here's the result....<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjkQs3hhe8TODFsg1Sm5IkuVwWSf9q_GGhP2pchnXxE_Xk7NJ5rCLGQkYneKXZ37NNwn-_zgzsEUJR17m_ewzjWmFvKX1EF0ssOsqcQy2YpBme48xOCu_XA-OR058-zxSc09RHTw2MakAU/s1600/Fibonacci_Swift.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="131" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjkQs3hhe8TODFsg1Sm5IkuVwWSf9q_GGhP2pchnXxE_Xk7NJ5rCLGQkYneKXZ37NNwn-_zgzsEUJR17m_ewzjWmFvKX1EF0ssOsqcQy2YpBme48xOCu_XA-OR058-zxSc09RHTw2MakAU/s400/Fibonacci_Swift.jpg" width="400" /></a></div>
<br />
I already have the LED Numbers app ready...so just wait for it -;)<br />
<br />
Greetings,<br />
<br />
Blag.<br />
Development Culture.Alvaro "Blag" Tejada Galindohttp://www.blogger.com/profile/12061593528820409779noreply@blogger.com0tag:blogger.com,1999:blog-4144704359177008692.post-92210936425688369472016-11-15T09:50:00.001-08:002016-12-01T07:52:58.475-08:00LED is my new Hello World - Perl TimeAs promised...here's my LED Numbers a la <a href="https://www.perl.org/" target="_blank">Perl</a>...and as always...please keep in mind that I'm Perl newbie...I know that there are more efficient, short and concise way of doing this app...but...how good is an introductory code that uses some obscure and arcane code? I don't want to scare people away from Perl...I want people to say "Hey...that doesn't look hard...I want to learn Perl"...<br />
<br />
So...here it is...<br />
<br />
<table align="center" style="width: 600px;">
<tbody>
<tr><th bgcolor="#6690BC">LedNumbers.pl</th>
</tr>
<tr>
<td><pre>#!/usr/bin/perl
use strict;
use warnings;
use diagnostics;
my %leds = (
0 => ' _ ,| | ,|_| ',
1 => ' ,| ,| ',
2 => ' _ , _| ,|_ ',
3 => '_ ,_| ,_| ',
4 => ' ,|_| , | ',
5 => ' _ ,|_ , _| ',
6 => ' _ ,|_ ,|_| ',
7 => '_ , | , | ',
8 => ' _ ,|_| ,|_| ',
9 => ' _ ,|_| , _| '
);
print "Enter a number: ";
my $num = <>;
my @numbers = ( $num =~ /\d/g );
for my $i (0 .. 2){
for my $j (0 .. scalar(@numbers) - 1){
my @line = split /\,/,$leds{$numbers[$j]};
print $line[$i];
}
print "\n";
}
</pre>
</td>
</tr>
<tr>
</tr>
</tbody></table>
<br />
And here's the output...<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
</div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh41KSIVFOukxpSAbW5gk2gidLb6k-UV5Elno3ljWZKgTmtNREMwjITYqPxnl0rxEF2cmOn-831EfO5oJ5dY-Lm6G9_I-aZmMuMSE7D78MMxUFreo-aRbMMd9fstI4JVNWW0SZLomlEQmkt/s1600/LedNumbers_Perl.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="143" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh41KSIVFOukxpSAbW5gk2gidLb6k-UV5Elno3ljWZKgTmtNREMwjITYqPxnl0rxEF2cmOn-831EfO5oJ5dY-Lm6G9_I-aZmMuMSE7D78MMxUFreo-aRbMMd9fstI4JVNWW0SZLomlEQmkt/s400/LedNumbers_Perl.jpg" width="400" /></a></div>
<br />
And just so you know...this is my 24th version of this code...yep...I have written my LED Numbers app in 24 languages so far -;) What's going to be my end point? Who knows...programming is the limit -;)<br />
<br />
Greetings,<br />
<br />
Blag.<br />
Development Culture.Alvaro "Blag" Tejada Galindohttp://www.blogger.com/profile/12061593528820409779noreply@blogger.com0tag:blogger.com,1999:blog-4144704359177008692.post-58539726068930786602016-11-15T09:43:00.001-08:002016-11-15T09:43:20.997-08:00My first post on Perl<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjGTrj-jAeTZG2Bv-l6X5x-O9kir0rXeIRjysXmdKmp2n4LYuOPXpPlRXCK8JWJBhq9lB-excWMoNR0EWOPrWH_Jmk2tFfVpWrZbN0Lue-kofE00i6xKH0bQfQ5qXmDNaPC9cbfinWyxoFC/s1600/Perl.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="201" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjGTrj-jAeTZG2Bv-l6X5x-O9kir0rXeIRjysXmdKmp2n4LYuOPXpPlRXCK8JWJBhq9lB-excWMoNR0EWOPrWH_Jmk2tFfVpWrZbN0Lue-kofE00i6xKH0bQfQ5qXmDNaPC9cbfinWyxoFC/s400/Perl.jpg" width="400" /></a></div>
<br />
<br />
So yes...I started to learn <a href="https://www.perl.org/" target="_blank">Perl</a>...why? 3 simple reasons...<br />
<br />
<br />
<ol>
<li>I love programming.</li>
<li>For me...Perl belongs to the whole trinity of Scripting Languages along with Ruby and Python (Sorry PHP...you don't make the cut)</li>
<li>Because...it's Perl! Come on!</li>
</ol>
<div>
<br /></div>
<div>
So...I have been reading <a href="https://smile.amazon.com/Beginning-Perl-Curtis-Poe/dp/1118013840" target="_blank">Beginning Perl</a>...an awesome book by the way...</div>
<div>
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://smile.amazon.com/Beginning-Perl-Curtis-Poe/dp/1118013840" target="_blank"><img border="0" height="400" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg__y5NbvDbIfVgfVCGUqq5vzeIha6YAppV9HwUXAat_W1NIcDfH69YzXa3cqi1Mg4IdmL3-KoyHBdPHD197TkGb-sDx-V0S5kmrZSSUtWNm3OvQQSRLiIRhg2criWAY0dTh3wbLYfItvSU/s400/Beginning_Perl.jpg" width="315" /></a></div>
<div>
<br /></div>
<div>
<br /></div>
<div>
If you're using any flavor of Linux or Mac...you should have Perl installed already...if you're using Windows...well...you can always download it and install it -:)</div>
<div>
<br /></div>
<div>
So far...I love Perl...it's pretty amazing...and now I can see why people say that both Python and Ruby heavily borrow stuff from Perl...and sure...PHP too...</div>
<div>
<br /></div>
<div>
I don't have of course much experience...but as always...I start doing a simple and small program to get me into the right track...so here's my Fibonacci numbers app...</div>
<div>
<br /></div>
<table align="center" style="width: 600px;">
<tbody>
<tr><th bgcolor="#6690BC">fibonacci.pl</th>
</tr>
<tr>
<td><pre>#!/usr/bin/perl
use strict;
use warnings;
use diagnostics;
sub fib {
my ($num,$a,$b) = @_;
my $result = '';
if ($a>0 && $num>1){
$result = $result . ($a+$b) . " " . fib($num-1,$a+$b,$a)
}elsif($a == 0){
$result = $a . " " . $b . " " . ($a+$b) . " " . fib($num-1,$a+$b,$b)
}
return $result
}
print "Enter a number: ";
my $num = <>;
print(fib($num,0,1));
</pre>
</td>
</tr>
<tr>
</tr>
</tbody></table>
<br />
And here's the nice output...<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjzQ6E3GatQLVsEZVCoNCPxWHlxXLxsU3Ti00gRJGIxwjHkfHCkKMl72zYz4fwFoY36hZSFMZjJhml7Bv7YL3hG0gK15OcYlmzS_MFv90xQbITa6yljG8ktKoeyFowE6v8UNtrr-SDMY5D6/s1600/Fibonnaci_Perl.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="107" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjzQ6E3GatQLVsEZVCoNCPxWHlxXLxsU3Ti00gRJGIxwjHkfHCkKMl72zYz4fwFoY36hZSFMZjJhml7Bv7YL3hG0gK15OcYlmzS_MFv90xQbITa6yljG8ktKoeyFowE6v8UNtrr-SDMY5D6/s400/Fibonnaci_Perl.jpg" width="400" /></a></div>
<br />
By now...I already have my classic "LED Numbers" app ready...but that goes into another post -;)<br />
<br />
Greetings,<br />
<br />
Blag.<br />
Development Culture.Alvaro "Blag" Tejada Galindohttp://www.blogger.com/profile/12061593528820409779noreply@blogger.com0tag:blogger.com,1999:blog-4144704359177008692.post-59173825877456611372016-08-09T11:23:00.000-07:002016-08-09T11:23:15.862-07:00Microsoft HoloLens on SAP’s d-shop<h2 style="background-color: #333333; color: #cccccc; font-family: arial, tahoma, helvetica, freesans, sans-serif; font-size: 22px; margin: 0px; position: relative; text-align: center;">
<b>This post was originally posted on <a href="http://scn.sap.com/community/innovation-management/blog/2016/08/09/microsoft-hololens-on-sap-s-d-shop" target="_blank">Microsoft HoloLens on SAP’s d-shop</a>.</b></h2>
<div>
<b><br /></b></div>
<div>
<div>
One of SAP’s d-shop main goals is to gather, learn and share knowledge on the latest technologies and <a href="https://www.microsoft.com/microsoft-hololens/en-us" target="_blank">Microsoft HoloLens</a> haven’t been out of our radar -;)</div>
<div>
<br /></div>
<div>
But…what is HoloLens?</div>
<div>
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjTOzE6FHPtZV2CYaAULbGaEBqyxyvcYeON0BgMjXOngS88rroztaQW5pG0e6nwSpjXfcEOlb7UTE6WDxv-fmVMBz5fq5kEmhZR4OtENxi1j09ZpEJEvsXeY0Yvzl6BvpXU7grO4ZlIXjFp/s1600/HoloLens.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="266" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjTOzE6FHPtZV2CYaAULbGaEBqyxyvcYeON0BgMjXOngS88rroztaQW5pG0e6nwSpjXfcEOlb7UTE6WDxv-fmVMBz5fq5kEmhZR4OtENxi1j09ZpEJEvsXeY0Yvzl6BvpXU7grO4ZlIXjFp/s400/HoloLens.jpg" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: justify;">
HoloLens is a Mixed reality device…which is basically a mix of Virtual (Oculus Rift) and Augmented (Google Glass) Realities.</div>
<div class="separator" style="clear: both; text-align: justify;">
<br /></div>
<div class="separator" style="clear: both; text-align: justify;">
One of the most important features on Mixed Reality is that it allows you to create Holograms that can be blended into the real world and interact with them.</div>
<div class="separator" style="clear: both; text-align: justify;">
<br /></div>
<div class="separator" style="clear: both; text-align: justify;">
HoloLens will map your room and recognize that you have a coffee table, a sofa, a lamp, and so on…when you place your Holograms on a table or sofa, the Hologram will not go through it, but instead sit on it…and this allows to do amazing things like creating a Hologram of a lamp to be placed next the sofa and see how it looks. And that’s just one of the many uses cases that HoloLens can provide.</div>
<div class="separator" style="clear: both; text-align: justify;">
<br /></div>
<div class="separator" style="clear: both; text-align: justify;">
At the d-shop Silicon Valley, we believe that using and coding the HoloLens is an awesome experience.</div>
<div class="separator" style="clear: both; text-align: justify;">
<br /></div>
<div class="separator" style="clear: both; text-align: justify;">
So…what you do need to start coding and creating amazing experiences?</div>
<div class="separator" style="clear: both; text-align: justify;">
<br /></div>
<div class="separator" style="clear: both; text-align: justify;">
In this <a href="https://developer.microsoft.com/en-us/windows/holographic/install_the_tools" target="_blank">page</a> you will find all the tools that you need, which includes Visual Studio, a tailor made version of Unity3D and the HoloLens emulator.</div>
<div class="separator" style="clear: both; text-align: justify;">
<br /></div>
<div class="separator" style="clear: both; text-align: justify;">
Also, it would be really good for you to take a look at the <a href="https://developer.microsoft.com/en-us/windows/holographic/academy" target="_blank">Holographic Academy</a> videos…which guide you through the basics notions of HoloLens coding…</div>
<div class="separator" style="clear: both; text-align: justify;">
<br /></div>
<div class="separator" style="clear: both; text-align: justify;">
But…with this blog what we really want to show you a video with some of the demos/projects that we have created at the d-shop Silicon Valley.</div>
<div class="separator" style="clear: both; text-align: justify;">
<br /></div>
<div class="separator" style="clear: both; text-align: justify;">
<b><i>Word Clock</i></b> With this app, you can literally read the time -;) This demonstrates text usage in Unity and it was adapted from a Python application.</div>
<div class="separator" style="clear: both; text-align: justify;">
<br /></div>
<div class="separator" style="clear: both; text-align: justify;">
<b><i>d-shop Robot</i></b> This app uses a d-shop robot model built using <a href="https://www.blender.org/" target="_blank">Blender</a>. This demonstrate Spatial Mapping and simple voice commands.</div>
<div class="separator" style="clear: both; text-align: justify;">
<br /></div>
<div class="separator" style="clear: both; text-align: justify;">
<b><i>SAP Puzzle Game</i></b> This app displays a sliding puzzle game that has two modes…easy and hard…it demonstrates how to clip an image and distributed into multiple cubes, it also demonstrates basic voice commands and physics.</div>
<div class="separator" style="clear: both; text-align: justify;">
<br /></div>
<div class="separator" style="clear: both; text-align: justify;">
<b><i>HoloHouse</i></b> This app is a project built for a bank in Dubai to be used as a real state application. The models were build using <a href="http://www.autodesk.com/products/3ds-max/overview" target="_blank">3ds Max</a> by an external company. This app demonstrates how to use Unity scripting to rotate the houses, fade the lights, lift the roof and floors of the houses and display annotations.</div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<iframe allowfullscreen="" class="YOUTUBE-iframe-video" data-thumbnail-src="https://i.ytimg.com/vi/J_Fmv_MdDVg/0.jpg" frameborder="0" height="266" src="https://www.youtube.com/embed/J_Fmv_MdDVg?feature=player_embedded" width="320"></iframe></div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
<br /></div>
<div>
Now that you have seen what can be done in a couple of weeks…why don’t you join us at the d-shop and show us what you can do! -:D</div>
<div style="font-weight: bold;">
<br /></div>
</div>
<div>
Greetings,</div>
<div style="font-weight: bold;">
<br /></div>
<div>
Blag.</div>
<div>
Development Culture.</div>
Alvaro "Blag" Tejada Galindohttp://www.blogger.com/profile/12061593528820409779noreply@blogger.com0tag:blogger.com,1999:blog-4144704359177008692.post-7626734436569622132016-08-07T05:53:00.001-07:002016-08-07T05:53:54.471-07:00d-shop's very first Hololens Hackaton<h2 style="background-color: #333333; color: #cccccc; font-family: arial, tahoma, helvetica, freesans, sans-serif; font-size: 22px; margin: 0px; position: relative; text-align: center;">
<b>This post was originally posted on <a href="http://scn.sap.com/community/innovation-management/blog/2016/08/05/d-shop-s-very-first-hololens-hackaton" target="_blank">d-shop's very first Hololens Hackaton</a>.</b></h2>
<div>
<b><br /></b></div>
<div>
On August, Wednesday 3 we hosted our d-shop’s very first Hololens Hackaton. People who had never used Unity3D before and of course who had never code for the Hololens before gathered together to have a fun and exciting learning experience.</div>
<div>
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjOzKCSgc7SRSE_YLwO8l4AYranL8Ozc5X-1uynWrKLvhQ7E76TW2H3dTaRHHrZdFiMeLvTL5l-5zigtCibIknvR2PG-e8n-yLq01I1TA8rO6_pRM3UP9LQqXxzvxmAwQxTDRO654n1frZM/s1600/IMG_1138.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="300" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjOzKCSgc7SRSE_YLwO8l4AYranL8Ozc5X-1uynWrKLvhQ7E76TW2H3dTaRHHrZdFiMeLvTL5l-5zigtCibIknvR2PG-e8n-yLq01I1TA8rO6_pRM3UP9LQqXxzvxmAwQxTDRO654n1frZM/s400/IMG_1138.JPG" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: justify;">
Thanks to the hard work and organization efforts from my team partners <a href="https://scn.sap.com/people/aaron.williams2" target="_blank">Aaron Williams</a> and <a href="http://scn.sap.com/people/julia.satsuta" target="_blank">Julia Satsuta</a> we had three awesome guys from Microsoft Vlad Kolesnikov, Petri Wihelmsen and Jaime Rodriguez.</div>
<div>
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgkzGL9iqpYbyXx0lRnV0lcyckYjdrWfnQ00sWrb-rRpNYkuieaTRf1MSsWiTL3b4Qw7kPLo_YrJfZ4IlKcF_z-taWp0Cdv6YKeTDgIC5ET9iHgpQiN4THuYiY2oxq3E9d6ZhtUJxTgsqO9/s1600/IMG_1143.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="300" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgkzGL9iqpYbyXx0lRnV0lcyckYjdrWfnQ00sWrb-rRpNYkuieaTRf1MSsWiTL3b4Qw7kPLo_YrJfZ4IlKcF_z-taWp0Cdv6YKeTDgIC5ET9iHgpQiN4THuYiY2oxq3E9d6ZhtUJxTgsqO9/s400/IMG_1143.JPG" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: justify;">
The first day was spend with explanations of what Hololens is…a quick introduction to Unity3D and a design thinking / brainstorming part where the teams could develop their ideas.</div>
<div class="separator" style="clear: both; text-align: justify;">
<br /></div>
<div class="separator" style="clear: both; text-align: justify;">
The second day started with Hololens coding and coaching from our side. People were totally excited and pumped up…trying things out on the Unity3D editor…on the Hololens emulator and on the device itself.</div>
<div class="separator" style="clear: both; text-align: justify;">
<br /></div>
<div class="separator" style="clear: both; text-align: justify;">
As a way to include more people and leave the teams working without too many distractions, we had a session on Hololens on Building 7…open for anyone to join in…</div>
<div class="separator" style="clear: both; text-align: justify;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj-EFDoR4jt-cBo1KhpZJcAefPBCspuzAsjYAQtMOo622gsxVslbgVM2C-vdX6RyozalpL3yPohN3HnUb5ip91jYbZDSXL_4uBAhl4phfP7Cby6xvLyOm1q5cIRMVbJlh-QQrFvb4eAkrzR/s1600/IMG_1151.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="300" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj-EFDoR4jt-cBo1KhpZJcAefPBCspuzAsjYAQtMOo622gsxVslbgVM2C-vdX6RyozalpL3yPohN3HnUb5ip91jYbZDSXL_4uBAhl4phfP7Cby6xvLyOm1q5cIRMVbJlh-QQrFvb4eAkrzR/s400/IMG_1151.JPG" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi1bGDmOpD1lD1XwSY1TrjGkbHLyubhGUajEF0ZdHO59HSGHnZ3oWfzAt0M9QhStEj-Dv32qAvufvTQWZ6ZiBqVopHOYHXqryh4XKQafmx5IW2CxrJEG17EVKSUM4oGme3DIcjK6WkNKxcX/s1600/IMG_1154.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="300" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi1bGDmOpD1lD1XwSY1TrjGkbHLyubhGUajEF0ZdHO59HSGHnZ3oWfzAt0M9QhStEj-Dv32qAvufvTQWZ6ZiBqVopHOYHXqryh4XKQafmx5IW2CxrJEG17EVKSUM4oGme3DIcjK6WkNKxcX/s400/IMG_1154.JPG" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiDaiT603T6rDOlL_ehm-cyR592WainZMVgtoF0FTgBlBtVHfWV_0zdEL-xbDeUGRGjU8g12EvKdCJ8cCOVgp4mXg0y01lyyAK9-3mURX1fSmrfrVCW6qrLBBhjOHQpdGZ0S7p1Eh7fymHL/s1600/IMG_1163+-+Copy.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="142" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiDaiT603T6rDOlL_ehm-cyR592WainZMVgtoF0FTgBlBtVHfWV_0zdEL-xbDeUGRGjU8g12EvKdCJ8cCOVgp4mXg0y01lyyAK9-3mURX1fSmrfrVCW6qrLBBhjOHQpdGZ0S7p1Eh7fymHL/s400/IMG_1163+-+Copy.JPG" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: justify;">
After that, we went back to keep coaching and helping the teams. They needed to be fully ready by 3:30pm as we had the demo presentation at 4:00pm.</div>
<div class="separator" style="clear: both; text-align: justify;">
<br /></div>
<div class="separator" style="clear: both; text-align: justify;">
The demo presentation happened at the cafeteria on Building 8.</div>
<div style="text-align: justify;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhzMTLcypDKes52i_gtMsjEDFXNdyvozmmHwY7i7eEqmhT9-DBpDZI7YSRFxViZtAm1e7yFoXwy75gI9Jq-EU4lasAT5S1DlXBPM9Vspi216FAlSc1ZwangHSzaznT053T4rJiiJVumGm5K/s1600/IMG_1167.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="300" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhzMTLcypDKes52i_gtMsjEDFXNdyvozmmHwY7i7eEqmhT9-DBpDZI7YSRFxViZtAm1e7yFoXwy75gI9Jq-EU4lasAT5S1DlXBPM9Vspi216FAlSc1ZwangHSzaznT053T4rJiiJVumGm5K/s400/IMG_1167.JPG" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhs1x-FadQT2q2eAvoB4s36JiBNtm06OkJ1uTp9dzecHfcT1xIWtiynnTpfB7s34CsUfl7fUbhOryTqv09bhVKW_9wi2yERFRB6XiYh-el2yTsrDUHvKwMXUNEyCTt0qaa5Y3gEJRJvI6fy/s1600/IMG_1168+-+Copy.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="112" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhs1x-FadQT2q2eAvoB4s36JiBNtm06OkJ1uTp9dzecHfcT1xIWtiynnTpfB7s34CsUfl7fUbhOryTqv09bhVKW_9wi2yERFRB6XiYh-el2yTsrDUHvKwMXUNEyCTt0qaa5Y3gEJRJvI6fy/s400/IMG_1168+-+Copy.JPG" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: justify;">
We had 5 teams presenting their awesome work…</div>
<div class="separator" style="clear: both; text-align: justify;">
<br /></div>
<div class="separator" style="clear: both; text-align: justify;">
<b>Holoterior</b></div>
<div class="separator" style="clear: both; text-align: justify;">
<br /></div>
<div class="separator" style="clear: both; text-align: justify;">
Design your dream room</div>
<div class="separator" style="clear: both; text-align: justify;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgRv8uWKemsDkx29t5l5FkYRRNILPPLZxOx4O2qwUZ4E40IUX2DliJ6BAmRVmHYkQSv0DKK-jka2aLVi3GSE68tD94_OWKPhQbMVVil2ymr9GRXFMdAG5yPnE_6mA-LI0FjYwKtfQ-xgSUa/s1600/IMG_1174.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="300" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgRv8uWKemsDkx29t5l5FkYRRNILPPLZxOx4O2qwUZ4E40IUX2DliJ6BAmRVmHYkQSv0DKK-jka2aLVi3GSE68tD94_OWKPhQbMVVil2ymr9GRXFMdAG5yPnE_6mA-LI0FjYwKtfQ-xgSUa/s400/IMG_1174.JPG" width="400" /></a></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi4lUHnHxrLmy_J7uoEPNWmrcdg1EIATHlYYtl6QGr3RISiEF8dIFx9Xx6vNq-fzv_haycXPXjwyQfcgmCDEiLceYEhuIfUCbTQJn-3bEelJVrGQLPVFGUYshL-xGNTDr05mi7V-qrcnunc/s1600/IMG_1177.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="300" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi4lUHnHxrLmy_J7uoEPNWmrcdg1EIATHlYYtl6QGr3RISiEF8dIFx9Xx6vNq-fzv_haycXPXjwyQfcgmCDEiLceYEhuIfUCbTQJn-3bEelJVrGQLPVFGUYshL-xGNTDr05mi7V-qrcnunc/s400/IMG_1177.JPG" width="400" /></a></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjtAyBFrN8NTRVs2YetSMnU-21TOPTJl9u2MRHoOGCxzI4D6pAfqpg7qJ0LvcLSDAtONUkyTu_CdfqvG7kNZthaLGvG9lFi69L2ItIyIHYRQaYUPZMmMHYhwjV4FvEfp1JsEMz_W2wCi-j9/s1600/IMG_1180.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="300" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjtAyBFrN8NTRVs2YetSMnU-21TOPTJl9u2MRHoOGCxzI4D6pAfqpg7qJ0LvcLSDAtONUkyTu_CdfqvG7kNZthaLGvG9lFi69L2ItIyIHYRQaYUPZMmMHYhwjV4FvEfp1JsEMz_W2wCi-j9/s400/IMG_1180.JPG" width="400" /></a></div>
<div>
<br /></div>
<div>
<div>
<b>Mechannotate</b></div>
<div>
</div>
<div>
Order part on the go...don't waste your time filling sheets</div>
</div>
<div>
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgcID4qsXZWTQX7nQ3fx8RrD3GSb3ccoKZMADYwXdShsxF_XOl5ng4xFIpLrPidIG-882qbG7dJUjzIcOX14rb3net4H2NemEr1keGxgoLuOmhnjCERvQSAau57A7lDy4HrEvgd6LCpwXrD/s1600/IMG_1183.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="300" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgcID4qsXZWTQX7nQ3fx8RrD3GSb3ccoKZMADYwXdShsxF_XOl5ng4xFIpLrPidIG-882qbG7dJUjzIcOX14rb3net4H2NemEr1keGxgoLuOmhnjCERvQSAau57A7lDy4HrEvgd6LCpwXrD/s400/IMG_1183.JPG" width="400" /></a></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhE8B7D4hHwRcaWdY0piSHscZgNRMLONlKKgqLbgqd8vrY82TOj3Q2LJnXnHSAKyA3X62Th2A0nfWP9lP0QgYg4DjBmCvvVEoG-zqLz9LhmkutdRHbuw5fYwM0CK7mrKbpQpZyWD7ELaIaE/s1600/IMG_1184.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="300" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhE8B7D4hHwRcaWdY0piSHscZgNRMLONlKKgqLbgqd8vrY82TOj3Q2LJnXnHSAKyA3X62Th2A0nfWP9lP0QgYg4DjBmCvvVEoG-zqLz9LhmkutdRHbuw5fYwM0CK7mrKbpQpZyWD7ELaIaE/s400/IMG_1184.JPG" width="400" /></a></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj5qyQGYD6-WV0sPHi95Z7u0vxsCmmpu1hThkQDwxGUbR24SHhu_MBsU6iiockrxSd5-jCXZ1fj2wlqc0I1SqoKiFowGHD6_gfp1VsDl4OMuZ6jReFYQXRHuhMVbwFGGX4QaZCa1ynQQ1rJ/s1600/IMG_1188.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="300" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj5qyQGYD6-WV0sPHi95Z7u0vxsCmmpu1hThkQDwxGUbR24SHhu_MBsU6iiockrxSd5-jCXZ1fj2wlqc0I1SqoKiFowGHD6_gfp1VsDl4OMuZ6jReFYQXRHuhMVbwFGGX4QaZCa1ynQQ1rJ/s400/IMG_1188.JPG" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: justify;">
<b>Next Talent</b></div>
<div class="separator" style="clear: both; text-align: justify;">
<br /></div>
<div class="separator" style="clear: both; text-align: justify;">
Engage your newly hired talents by immersing them in your culture and history</div>
<div>
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjm7vJqZQ35EUYiYMY_x_Tnn2ZBV9ED7BRuzhPsMqNitWkEReaPzdRozi6JhAFLlYS9IrGxdIhZPF0JGes6zAU4Wavfvo9pLRXASaKArjCGcopULwz5VwVi0TsEcbKCqez29noIgo_EqaYu/s1600/IMG_1189.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="300" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjm7vJqZQ35EUYiYMY_x_Tnn2ZBV9ED7BRuzhPsMqNitWkEReaPzdRozi6JhAFLlYS9IrGxdIhZPF0JGes6zAU4Wavfvo9pLRXASaKArjCGcopULwz5VwVi0TsEcbKCqez29noIgo_EqaYu/s400/IMG_1189.JPG" width="400" /></a></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgSivMkvatd7Hz1Y9hqI_n0EeY1er8SHz8E0sbSGQfpGCKpnHrL9dyIHpHRcwvmKdf6WGpfMiPwFglYdYmNd6gv-NvSjFrGlGBMQrwbJD5trUia0kmGYYPGwfd0spGKXUFvjzLyd5itpFTc/s1600/IMG_1196.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="300" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgSivMkvatd7Hz1Y9hqI_n0EeY1er8SHz8E0sbSGQfpGCKpnHrL9dyIHpHRcwvmKdf6WGpfMiPwFglYdYmNd6gv-NvSjFrGlGBMQrwbJD5trUia0kmGYYPGwfd0spGKXUFvjzLyd5itpFTc/s400/IMG_1196.JPG" width="400" /></a></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEinbkiOYjD9bVHfZWm59ognTlVZPQpLoOn1UJUAWxXOiqTQRzR-rq5MhbOCqmvNbVbR1NC8AkJ6lmHuUWKJLuJJDnhSCB-wcsFUDU708zB1SM_hc12YtD2nNxa2CDeEVz_4j2xGfspvBoZC/s1600/IMG_1197.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="300" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEinbkiOYjD9bVHfZWm59ognTlVZPQpLoOn1UJUAWxXOiqTQRzR-rq5MhbOCqmvNbVbR1NC8AkJ6lmHuUWKJLuJJDnhSCB-wcsFUDU708zB1SM_hc12YtD2nNxa2CDeEVz_4j2xGfspvBoZC/s400/IMG_1197.JPG" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: justify;">
<b>TripIp</b></div>
<div class="separator" style="clear: both; text-align: justify;">
<br /></div>
<div class="separator" style="clear: both; text-align: justify;">
Planning your next trip? Get the seat that it's more comfortable for you</div>
<div>
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjk8Tskbwi9EMEKd6kEzP7VxbWcPGBETTGllqRazoeQRxxzl2YlE0uob-rSPECiKR8lK5bnh4gv2MKoQp_-XBInCS0EaGldbOYjYrWR1okVVBS8txtBnMDMvkIEJeQ-moBD3O9YTHwHctfF/s1600/IMG_1201.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="300" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjk8Tskbwi9EMEKd6kEzP7VxbWcPGBETTGllqRazoeQRxxzl2YlE0uob-rSPECiKR8lK5bnh4gv2MKoQp_-XBInCS0EaGldbOYjYrWR1okVVBS8txtBnMDMvkIEJeQ-moBD3O9YTHwHctfF/s400/IMG_1201.JPG" width="400" /></a></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhLldmObr5ugBKOS5-uLZAKfNG61qE9Wm83xio7oA5TCoVkGZ3GSSLfFFpG-pUhE6H_-v_BUB1QWRd23I0ut3I1DrJO9xk2SWtSOaH6kkpn8in7sjo08d1lc_qpZgArwaIQeON-CA4mkr20/s1600/IMG_1202.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="300" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhLldmObr5ugBKOS5-uLZAKfNG61qE9Wm83xio7oA5TCoVkGZ3GSSLfFFpG-pUhE6H_-v_BUB1QWRd23I0ut3I1DrJO9xk2SWtSOaH6kkpn8in7sjo08d1lc_qpZgArwaIQeON-CA4mkr20/s400/IMG_1202.JPG" width="400" /></a></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjuYLZGtdZR9rV4Z6ZYD4SEmWe4PDK2iRNfmbV54cEXQ-BDzEqNLUIHRSOyexeAqxgKORwMg8Tdaa5GYmy-yWvUQC0yl0nuSyE3AlqD3MKcZbkzSvxAQmlX-Y26FzAwPHjjD2fxOf9vkO15/s1600/IMG_1204.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="300" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjuYLZGtdZR9rV4Z6ZYD4SEmWe4PDK2iRNfmbV54cEXQ-BDzEqNLUIHRSOyexeAqxgKORwMg8Tdaa5GYmy-yWvUQC0yl0nuSyE3AlqD3MKcZbkzSvxAQmlX-Y26FzAwPHjjD2fxOf9vkO15/s400/IMG_1204.JPG" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: justify;">
<b>The Wesley Crushers</b></div>
<div class="separator" style="clear: both; text-align: justify;">
<br /></div>
<div class="separator" style="clear: both; text-align: justify;">
Is your pipe broken? Check it...measure it and request a replacement</div>
<div>
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjz-kum6T-CLlrNIhaAUvZqPFipnSzr-K1X70O5O95xi7NYnDG2TgfkwOAU-DpdBXX-j0ELzLdW24sYZl6iFQHHDJfLOGCJ3Nn-cARAIa8OZ-6-ShQqQyWzLPRUq-2wFPu-bHCrW2O20nbK/s1600/IMG_1206.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="300" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjz-kum6T-CLlrNIhaAUvZqPFipnSzr-K1X70O5O95xi7NYnDG2TgfkwOAU-DpdBXX-j0ELzLdW24sYZl6iFQHHDJfLOGCJ3Nn-cARAIa8OZ-6-ShQqQyWzLPRUq-2wFPu-bHCrW2O20nbK/s400/IMG_1206.JPG" width="400" /></a></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhAlIWaeqmuCCZPlOPROJCnf2kPsm5jzq046ezUzd-bGJFWTT0SqCZkfbbauQ4VBY8ZVpkLN7fEDXU_PQsXhrYOaMQRC2la7wg1ToPvnFKhfRDLIU5L5xfPEG01RJBRjgZjkzH2LIRxiBiP/s1600/IMG_1208.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="300" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhAlIWaeqmuCCZPlOPROJCnf2kPsm5jzq046ezUzd-bGJFWTT0SqCZkfbbauQ4VBY8ZVpkLN7fEDXU_PQsXhrYOaMQRC2la7wg1ToPvnFKhfRDLIU5L5xfPEG01RJBRjgZjkzH2LIRxiBiP/s400/IMG_1208.JPG" width="400" /></a></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhZqelVuKDa-emBxa8zKgd0qnDAt00bA7zd9GHwPJJlFBcW0m284ij_v2UeIHfbJZUs5LmkgOrQtyBSdWczzrrV1UX3FtbYY5x6dUgBqTsX_HbX3bOKQAaZrcFxmb7LIEQX7bvN76iUQGSm/s1600/IMG_1212.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="300" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhZqelVuKDa-emBxa8zKgd0qnDAt00bA7zd9GHwPJJlFBcW0m284ij_v2UeIHfbJZUs5LmkgOrQtyBSdWczzrrV1UX3FtbYY5x6dUgBqTsX_HbX3bOKQAaZrcFxmb7LIEQX7bvN76iUQGSm/s400/IMG_1212.JPG" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: justify;">
As you can see…all the teams put a lot of effort and created some really awesome demos…but…there’s always need to be only one winner…so the last team to present was the team who won…so…congratulations “<b>The Wesley Crushers</b>” team!</div>
<div class="separator" style="clear: both; text-align: justify;">
<br /></div>
<div class="separator" style="clear: both; text-align: justify;">
After this really nice experience…I’m sure we’re going to come back for more…Hololens is still a brand new technology, so there’s still a lot to learn, a lot to hack and a lot of possibilities.</div>
<div class="separator" style="clear: both; text-align: justify;">
<br /></div>
<div class="separator" style="clear: both; text-align: justify;">
If you’re in Palo Alto…come and visit us! Remember that the d-shop is located on the first floor of Building 9 on Deer Creek Road -;)</div>
<div>
<br /></div>
<div>
Greetings,</div>
<div>
<br /></div>
<div>
Blag.</div>
<div>
Development Culture.</div>
Alvaro "Blag" Tejada Galindohttp://www.blogger.com/profile/12061593528820409779noreply@blogger.com0tag:blogger.com,1999:blog-4144704359177008692.post-29106065601533454162016-02-06T11:34:00.001-08:002016-02-08T19:31:54.900-08:00There’s a party at Alexa’s place<div style="text-align: justify;">
<h2 style="background-color: #333333; color: #cccccc; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif; font-size: 22px; margin: 0px; position: relative; text-align: center;">
<b>This post was originally posted on <a href="http://scn.sap.com/community/innovation-management/blog/2016/02/06/there-s-a-party-at-alexa-s-place" target="_blank">There's a party at Alexa's place</a>.</b></h2>
<br />
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.</div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
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 -;)</div>
<div style="text-align: justify;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgK2aUeVOeUJXUtx2tu5_zaoOfeCaIgiU90psGzexvPczoUcJWl9mLkHqd5ROr1s1q0uJJzFfv4QbVpWXNznSk7K3i4a69K70bgOyfIEjUesE2JJCNT_FHz0D8rkkMI-2TaZk_ksaIY2eEk/s1600/Alexa_Diagram.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="348" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgK2aUeVOeUJXUtx2tu5_zaoOfeCaIgiU90psGzexvPczoUcJWl9mLkHqd5ROr1s1q0uJJzFfv4QbVpWXNznSk7K3i4a69K70bgOyfIEjUesE2JJCNT_FHz0D8rkkMI-2TaZk_ksaIY2eEk/s400/Alexa_Diagram.jpg" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: justify;">
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</div>
<div class="separator" style="clear: both; text-align: justify;">
<br /></div>
<div class="separator" style="clear: both; text-align: justify;">
So…let’s go in some simple steps…</div>
<div class="separator" style="clear: both; text-align: justify;">
<br /></div>
<div class="separator" style="clear: both; text-align: justify;">
<b><i>GET A HANA CLOUD PLATFORM ACCOUNT</i></b></div>
<div class="separator" style="clear: both; text-align: justify;">
<br /></div>
<div class="separator" style="clear: both; text-align: justify;">
You should have one already…if not…just go <a href="https://account.hanatrial.ondemand.com/" target="_blank">here</a> to create one…</div>
<div class="separator" style="clear: both; text-align: justify;">
<br /></div>
<div class="separator" style="clear: both; text-align: justify;">
Then…we need to download the <a href="https://tools.hana.ondemand.com/sdk/neo-java-web-sdk-1.95.34.zip" target="_blank">HANA Cloud Platform SDK</a> extract it and modify the file <b>tools/neo.sh</b> on line 57…</div>
<div class="separator" style="clear: both; text-align: justify;">
<br /></div>
<div class="separator" style="clear: both; text-align: justify;">
Instead of this…</div>
<div class="separator" style="clear: both; text-align: justify;">
<br /></div>
<div class="separator" style="clear: both; text-align: justify;">
<b>javaExe="$JAVA_HOME/bin/$javaCommand"</b></div>
<div class="separator" style="clear: both; text-align: justify;">
<br /></div>
<div class="separator" style="clear: both; text-align: justify;">
Use this…</div>
<div class="separator" style="clear: both; text-align: justify;">
<br /></div>
<div class="separator" style="clear: both; text-align: justify;">
<b>javaExe="$JAVA_HOME"</b></div>
<div class="separator" style="clear: both; text-align: justify;">
<br /></div>
<div class="separator" style="clear: both; text-align: justify;">
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 <a href="https://store.sap.com/sap/cpa/ui/resources/store/html/SolutionDetails.html?pid=0000012950&catID=&pcntry=US&sap-language=EN&_cp_id=id-1454559192364-0" target="_blank">here</a> take a note that will need to copy the ngdbc.jar file…</div>
<div class="separator" style="clear: both; text-align: justify;">
<br /></div>
<div class="separator" style="clear: both; text-align: justify;">
<i><b>GETTING THE DATA THAT WE'RE GOING TO USE</b></i></div>
<div class="separator" style="clear: both; text-align: justify;">
<br /></div>
<div class="separator" style="clear: both; text-align: justify;">
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…</div>
<div class="separator" style="clear: both; text-align: justify;">
<br /></div>
<div class="separator" style="clear: both; text-align: justify;">
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…</div>
<div class="separator" style="clear: both; text-align: justify;">
<br /></div>
<div class="separator" style="clear: both; text-align: justify;">
And BTW…for some weird reason my R/3 didn’t have American Airlines listen on the SCARR table…so I just added it -;)</div>
<div class="separator" style="clear: both; text-align: justify;">
<br /></div>
<div class="separator" style="clear: both; text-align: justify;">
Now…if you don’t have access to an R/3 system…then you can download the tables in CSV format from <a href="https://www.dropbox.com/s/5o1wdpst0hqfam6/R3_Tables.zip?dl=0" target="_blank">here</a></div>
<div class="separator" style="clear: both; text-align: justify;">
<br /></div>
<div class="separator" style="clear: both; text-align: justify;">
<b><i>CREATE THE R SERVER ON HEROKU</i></b></div>
<div class="separator" style="clear: both; text-align: justify;">
<br /></div>
<div class="separator" style="clear: both; text-align: justify;">
If you don’t have the <a href="https://toolbelt.heroku.com/" target="_blank">Heroku Tool Belt</a> installed…then go and grab it…</div>
<div class="separator" style="clear: both; text-align: justify;">
<br /></div>
<table align="center" style="width: 600px;">
<tbody>
<tr><th bgcolor="#6690BC">Steps to install R on Heroku with Graphic Capabilities</th>
</tr>
<tr>
<td><pre>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
</pre>
</td>
</tr>
<tr>
</tr>
</tbody></table>
<br />
<table align="center" style="width: 600px;">
<tbody>
<tr><th bgcolor="#6690BC">installR.sh</th>
</tr>
<tr>
<td><pre>#!/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
</pre>
</td>
</tr>
<tr>
</tr>
</tbody></table>
<br />
Now…we need to do a very important step -:) We need to install the totally awesome <a href="https://github.com/ddollar/heroku-buildpack-multi" target="_blank">heroku-buildpack-multi</a> from <a href="https://github.com/ddollar" target="_blank">ddollar</a>.<br />
<br />
heroku buildpacks:set https://github.com/ddollar/heroku-buildpack-multi.git<br />
<br />
After that…we need to create a couple of files…one called <b>.buildpacks</b> and the other <b>Aptfile</b>.<br />
<div>
<br /></div>
<table align="center" style="width: 600px;">
<tbody>
<tr><th bgcolor="#6690BC">.buildpacks</th>
</tr>
<tr>
<td><pre>https://github.com/ddollar/heroku-buildpack-apt
https://github.com/heroku/heroku-buildpack-ruby
</pre>
</td>
</tr>
<tr>
</tr>
</tbody></table>
<table align="center" style="width: 600px;">
<tbody>
<tr><th bgcolor="#6690BC">Aptfile</th>
</tr>
<tr>
<td><pre>gfortran
libatlas-base-dev
libatlas-dev
liblapack-dev
</pre>
</td>
</tr>
<tr>
</tr>
</tbody></table>
<br />
Now comes the interesting part…installing R -;)<br />
<br />
<table align="center" style="width: 600px;">
<tbody>
<tr><th bgcolor="#6690BC">Finally...installing R...</th>
</tr>
<tr>
<td><pre>git add . && git commit –am “message” && git push heroku master
heroku ps:scale web=0
heroku run bash
cd bin/
./installR.sh
</pre>
</td>
</tr>
<tr>
</tr>
</tbody></table>
<br />
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…<br />
<br />
<table align="center" style="width: 600px;">
<tbody>
<tr><th bgcolor="#6690BC">Installing the R Libraries</th>
</tr>
<tr>
<td><pre>#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()
</pre>
</td>
</tr>
<tr>
</tr>
</tbody></table>
<br />
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 -:(<br />
<br />
So…we need to back it up and sent it somewhere else…I used my R Server on Amazon WebServices for this…<br />
<br />
First…we need to compress the bin folder like this…<br />
<br />
<b>tar -cvzf bin.tar.gz bin</b><br />
<br />
and then we need to save this file in our external server…<br />
<br />
<b>scp -i XXX.pem bin.tar.gz ec2-user@X.X.X.X:~/Blag/bin.tar.gz</b><br />
<br />
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…<br />
<br />
<b>scp -i XXX.pem ec2-user@X.X.X.X:~/Blag/bin.tar.gz bin.tar.gz</b><br />
<br />
Once this is done…we need to something real quick…<br />
<br />
If you’re still inside the Heroku bash…simply run<br />
<br />
<b>which java</b><br />
<br />
and take note of the location…<br />
<br />
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…<br />
<br />
<table align="center" style="width: 600px;">
<tbody>
<tr><th bgcolor="#6690BC">config.ru</th>
</tr>
<tr>
<td><pre>`/app/bin/R-3.2.3/bin/R –e “source(‘/app/demo.R’)”`
</pre>
</td>
</tr>
<tr>
</tr>
</tbody></table>
<table align="center" style="width: 600px;">
<tbody>
<tr><th bgcolor="#6690BC">demo.R</th>
</tr>
<tr>
<td><pre>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)
}
</pre>
</td>
</tr>
<tr>
</tr>
</tbody></table>
<br />
<div style="text-align: justify;">
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 <b>hcp.sh</b> 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?</div>
<div style="text-align: justify;">
<br /></div>
<table align="center" style="width: 600px;">
<tbody>
<tr><th bgcolor="#6690BC">Procfile</th>
</tr>
<tr>
<td><pre>web: bundle exec rackup config.ru
</pre>
</td>
</tr>
<tr>
</tr>
</tbody></table>
<br />
We want this R Server to be able to access HANA Cloud Platform…so let’s do that before we keep going…<br />
<br />
With the location of Java…apply this command…<br />
<br />
<b>heroku config:set JAVA_HOME='/usr/bin/java'</b><br />
<br />
Now…Copy the following files into your project folder…<br />
<br />
<b>“tools”</b> folder from the HANA Cloud Platform SDK<br />
<b>ngdbc.jar</b> from SAP HANA Client<br />
<br />
Also…create this little script which is going to allow us to connect to HCP…<br />
<div>
<br /></div>
<table align="center" style="width: 600px;">
<tbody>
<tr><th bgcolor="#6690BC">hcp.sh</th>
</tr>
<tr>
<td><pre>#!/bin/bash -e
user=YourUserName
account=YourAccount
HCP_PASSWORD=YourPassword
json=$(tools/./neo.sh open-db-tunnel -i blaghanax -h hanatrial.ondemand.com -a </pre>
<pre> "$account" -u "$user" -p "$HCP_PASSWORD" --background --output json)
regex='.*"host":"([^"]*)".*"port":([^,]*),.*"instanceNumber":"([^"]*)".</pre>
<pre> *"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
</pre>
</td>
</tr>
<tr>
</tr>
</tbody></table>
<br />
Awesome…we’re almost there…please download this <a href="https://raw.githubusercontent.com/jpatokal/openflights/master/data/airports.dat" target="_blank">airports file</a> and place it on your project folder…<br />
<br />
Finally…with all files in place we can send everything back to heroku…so log into your Heroku tool belt and do the following…<br />
<br />
<table align="center" style="width: 600px;">
<tbody>
<tr><th bgcolor="#6690BC">Getting everything in place</th>
</tr>
<tr>
<td><pre>git add .
git commit –am “message”
git push heroku master
heroku ps:scale web=1
</pre>
</td>
</tr>
<tr>
</tr>
</tbody></table>
<br />
R should be installed and ready to go -;) So we should move on and continue with our NodeJS server on Heroku…<br />
<br />
<b><i>Creating NodeJS on Heroku with PhantomJS</i></b><br />
<br />
Create a folder called mynodeproject and inside create the following files…<br />
<div>
<br /></div>
<table align="center" style="width: 600px;">
<tbody>
<tr><th bgcolor="#6690BC">package.json</th>
</tr>
<tr>
<td><pre>{
"dependencies": {
"ws": "1.0.1",
"request": "2.67.0",
"express": "4.13.3",
"phantomjs-prebuilt": "2.1.3"
},
"engines": {
"node": "0.12.7"
}
}
</pre>
</td>
</tr>
<tr>
</tr>
</tbody></table>
<table align="center" style="width: 600px;">
<tbody>
<tr><th bgcolor="#6690BC">Procfile</th>
</tr>
<tr>
<td><pre>web: node index.js</pre>
</td>
</tr>
<tr>
</tr>
</tbody></table>
<table align="center" style="width: 600px;">
<tbody>
<tr><th bgcolor="#6690BC">index.js</th>
</tr>
<tr>
<td><pre>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)
})
})
</pre>
</td>
</tr>
<tr>
</tr>
</tbody></table>
<br />
<div style="text-align: justify;">
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 -:(</div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
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…</div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
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…</div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
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…</div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
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.</div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
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…</div>
<div style="text-align: justify;">
<br /></div>
<table align="center" style="width: 600px;">
<tbody>
<tr><th bgcolor="#6690BC">index.html</th>
</tr>
<tr>
<td><pre><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>
</pre>
</td>
</tr>
<tr>
</tr>
</tbody></table>
<br />
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…<br />
<br />
<table align="center" style="width: 600px;">
<tbody>
<tr><th bgcolor="#6690BC">phantom.js</th>
</tr>
<tr>
<td><pre>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);
});
</pre>
</td>
</tr>
<tr>
</tr>
</tbody></table>
<br />
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 <b>stats.html</b><br />
<b><br /></b>
<br />
<table align="center" style="width: 600px;">
<tbody>
<tr><th bgcolor="#6690BC">readphantom.js</th>
</tr>
<tr>
<td><pre>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();
}
});
</pre>
</td>
</tr>
<tr>
</tr>
</tbody></table>
<br />
<div style="text-align: justify;">
This script will simply read the stats.html page and return the text that it’s located inside the “p” tag…dead simple…</div>
<div style="text-align: justify;">
<br /></div>
<b><i>SETTING UP ALEXA</i></b><br />
<b><i><br /></i></b>
<b><i>Creating the Lambda function</i></b><br />
<b><i><br /></i></b>
<br />
<div style="text-align: justify;">
Now…we need to setup Alexa…so we can control everything via voice commands -:)</div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
First…we need to go to <a href="https://www.google.com/url?sa=t&rct=j&q=&esrc=s&source=web&cd=1&cad=rja&uact=8&ved=0ahUKEwiX1LfuoOHKAhVR4WMKHWW1B4EQFggqMAA&url=https%3A%2F%2Faws.amazon.com%2Flambda%2F&usg=AFQjCNHjO6kLR29M6rle7MjKqum-YKJfhA&sig2=Q1HIobbzxN5eTdT8_7TXUw" target="_blank">Amazon Lambda</a> and log in if you have an account…otherwise…please create one…and make sure you’re on the West Virginia region…</div>
<div style="text-align: justify;">
<br /></div>
<br />
<div style="text-align: justify;">
In the list of functions…look for color…</div>
<div style="text-align: justify;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhnNmILMoPwjD9Ww4BQrKAone14KTtLCOc1Pm56VufU3L9TpPkVm4Ef_qw0NqgTd4GgU9XikNK-BE1AERlWfkiw1VIKUerYl4tLWEtjHms0AWePVndfjtp34c9sbIiUZT4x8_ukz7uRdUS_/s1600/Alexa_Blueprint.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="172" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhnNmILMoPwjD9Ww4BQrKAone14KTtLCOc1Pm56VufU3L9TpPkVm4Ef_qw0NqgTd4GgU9XikNK-BE1AERlWfkiw1VIKUerYl4tLWEtjHms0AWePVndfjtp34c9sbIiUZT4x8_ukz7uRdUS_/s400/Alexa_Blueprint.jpg" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: justify;">
Choose the NodeJS one…Python has been included as well…but wasn’t when I started to work on this blog -:)</div>
<div class="separator" style="clear: both; text-align: justify;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhAvLCla4MLeswndImFrfY1JAbeoWxMNUHvrX4hVMgJAvcP-fBziSwq8sbLTeb65W1cZeAFKm9Kbb0T8nkoCVRRU2kLgBUw2hypa3MJtV4C0iUPZKj0FpOYb4wYpxCeMAPQfwr3l9jPgTy0/s1600/Alexa_event_source.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="96" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhAvLCla4MLeswndImFrfY1JAbeoWxMNUHvrX4hVMgJAvcP-fBziSwq8sbLTeb65W1cZeAFKm9Kbb0T8nkoCVRRU2kLgBUw2hypa3MJtV4C0iUPZKj0FpOYb4wYpxCeMAPQfwr3l9jPgTy0/s400/Alexa_event_source.jpg" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: justify;">
Here, just click next....</div>
<div class="separator" style="clear: both; text-align: justify;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhBdS-PoecMlJ0TWtHyRiCUFvUnUQ09j2fCVfJzyZeP-TzwV2JSdi1dBWfVUwqECVHJus9XhTpn23GgEjs46d9P01khWAlIg3oR0EsVYIWnn-V2zGMQ34quEZkLKGuQ4SZ-UERjNfPgJPxk/s1600/Alexa_Configure_Function.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="100" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhBdS-PoecMlJ0TWtHyRiCUFvUnUQ09j2fCVfJzyZeP-TzwV2JSdi1dBWfVUwqECVHJus9XhTpn23GgEjs46d9P01khWAlIg3oR0EsVYIWnn-V2zGMQ34quEZkLKGuQ4SZ-UERjNfPgJPxk/s400/Alexa_Configure_Function.jpg" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: justify;">
I already create the function…but you shouldn’t have a problem...</div>
<div class="separator" style="clear: both; text-align: justify;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiStQ3e3T3Ml9JvGC8G6fuRhgfB-2N_vlR4eO16YbFZNGl3Li21BIEUBlw0pmtywFBsPrJE0YvPbkuGixWK5Umb37oJJ7K_b2H1gJsjC_8sAbh5Dqo5qv-N8xN65vZLi6t8PtBYSRMAIyVc/s1600/Alexa_Role.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="111" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiStQ3e3T3Ml9JvGC8G6fuRhgfB-2N_vlR4eO16YbFZNGl3Li21BIEUBlw0pmtywFBsPrJE0YvPbkuGixWK5Umb37oJJ7K_b2H1gJsjC_8sAbh5Dqo5qv-N8xN65vZLi6t8PtBYSRMAIyVc/s400/Alexa_Role.jpg" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: justify;">
Basic execution role is more than enough…</div>
<div class="separator" style="clear: both; text-align: justify;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhCPfIB3YNvZ0lUhqxb51_tFAjncYZzLeIEj5JWU44YvRe5sPKnDM9aBwq20HAsi1aNEYc_Oq0IZ8UwFNKQim90EKAw3W9cEIQIGm2sz9J-7qQp9p4UtMzLvNxtsq0xExNACzK2njSlsW3D/s1600/Alexa_Role_Summary.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="173" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhCPfIB3YNvZ0lUhqxb51_tFAjncYZzLeIEj5JWU44YvRe5sPKnDM9aBwq20HAsi1aNEYc_Oq0IZ8UwFNKQim90EKAw3W9cEIQIGm2sz9J-7qQp9p4UtMzLvNxtsq0xExNACzK2njSlsW3D/s400/Alexa_Role_Summary.jpg" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: justify;">
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…</div>
<div class="separator" style="clear: both; text-align: justify;">
<br /></div>
<div class="separator" style="clear: both; text-align: justify;">
<b>Creating the Skill</b></div>
<div class="separator" style="clear: both; text-align: justify;">
<br /></div>
<div class="separator" style="clear: both; text-align: justify;">
Go to http://developer.amazon.com and log in…then choose Apps & Services --> Alexa --> Alexa Skills Set</div>
<div style="text-align: justify;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhOQwPMSyAWt6kdK-7HkBRMUU-5ogWmcH2GUHnvXSzOfaUFWSj4VGfuatsLlR1UVMWTYwFNZ6gyMOxnZpsY7Bpak6PTofoKfd0Y0osmYC0JmnvvgUoibE3T9Kp8cHN8K41XCYkJGSLvHO06/s1600/Alexa_Skillset.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="142" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhOQwPMSyAWt6kdK-7HkBRMUU-5ogWmcH2GUHnvXSzOfaUFWSj4VGfuatsLlR1UVMWTYwFNZ6gyMOxnZpsY7Bpak6PTofoKfd0Y0osmYC0JmnvvgUoibE3T9Kp8cHN8K41XCYkJGSLvHO06/s400/Alexa_Skillset.jpg" width="400" /></a></div>
<div style="text-align: justify;">
<br /></div>
<div class="separator" style="clear: both; text-align: justify;">
<br /></div>
<div class="separator" style="clear: both; text-align: justify;">
Choose Alexa Skills Kit and fill the blanks...</div>
<div class="separator" style="clear: both; text-align: justify;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiQTOxebgSlkZOe_MnRPl8KgW4wTiu3UXJNnGPeQb0Y_pSJdu2vCrvduksKTZQHUxPn9W1kyIDvzu18f7vETpXliy8yK2oWarSM_2yF69WhMdWG4cj02G-2CLyQEd23AYrh6-s2NVDRpPRu/s1600/Alexa_Flights_Skill.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="183" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiQTOxebgSlkZOe_MnRPl8KgW4wTiu3UXJNnGPeQb0Y_pSJdu2vCrvduksKTZQHUxPn9W1kyIDvzu18f7vETpXliy8yK2oWarSM_2yF69WhMdWG4cj02G-2CLyQEd23AYrh6-s2NVDRpPRu/s400/Alexa_Flights_Skill.jpg" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: justify;">
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.</div>
<div class="separator" style="clear: both; text-align: justify;">
<br /></div>
<div class="separator" style="clear: both; text-align: justify;">
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.</div>
<div style="text-align: justify;">
<br /></div>
<table align="center" style="width: 600px;">
<tbody>
<tr><th bgcolor="#6690BC">Intent Schema</th>
</tr>
<tr>
<td><pre>{
"intents": [
{
"intent": "GetFlightsIntent",
"slots": [
{
"name": "command",
"type": "LITERAL"
}
]
},
{
"intent": "HelpIntent",
"slots": []
}
]
}
</pre>
</td>
</tr>
<tr>
</tr>
</tbody></table>
<br />
<div style="text-align: justify;">
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…</div>
<div style="text-align: justify;">
<br /></div>
<table align="center" style="width: 600px;">
<tbody>
<tr><th bgcolor="#6690BC">Sample Utterances</th>
</tr>
<tr>
<td><pre>GetFlightsIntent airports from {around the world|command}
GetFlightsIntent airports from {united states|command}
GetFlightsIntent flight distance from {carriers|command}
GetFlightsIntent {thank you|command}
</pre>
</td>
</tr>
<tr>
</tr>
</tbody></table>
<br />
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 -;)<br />
<br />
Forget about the Publishing Information section unless you really want to publish your application…<br />
Create a folder call Flights…Alexa_Party…or whatever you fancy…then create a folder call src and copy this <a href="https://github.com/dustincoates/alexa-bus-schedule/blob/master/src/index.js" target="_blank">file</a> in there…calling it AlexaSkills.js<br />
<br />
We’re going to need to install only one library….”request”…<br />
<br />
<b>sudo npm install --prefix=~/Flights/src request</b><br />
<br />
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…<br />
<br />
<table align="center" style="width: 600px;">
<tbody>
<tr><th bgcolor="#6690BC">index.js</th>
</tr>
<tr>
<td><pre>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);
};
</pre>
</td>
</tr>
<tr>
</tr>
</tbody></table>
<br />
Time to explain what I was trying to do here -:P<br />
<br />
The <b>handleFlightsRequest</b> method will manage the response that Alexa will spell out for us…and inside this method we can find <b>getJsonFromFlights</b> which will take the command defined in the our <b>Intent Schema</b>. 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…<br />
<br />
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 -;)<br />
<br />
That’s pretty much it…now…I can show some images before we jump into the video…<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhgen_c55K6s1Jhd9JQUHC5YPFUPeV0SyXlDAPQq7fzBzLokNmIv6YBAMY_1yVel0e1yFZ90FuVKSkLRB_N4DeJu0YBETuvIr7_Wd7vJVSuVr_5C2pHPzePllD36t9DI3st6-8YSz9t1640/s1600/Gandalf.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="260" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhgen_c55K6s1Jhd9JQUHC5YPFUPeV0SyXlDAPQq7fzBzLokNmIv6YBAMY_1yVel0e1yFZ90FuVKSkLRB_N4DeJu0YBETuvIr7_Wd7vJVSuVr_5C2pHPzePllD36t9DI3st6-8YSz9t1640/s400/Gandalf.jpg" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiOI8yBDPfqMAfhDEC17QeXmsjSMn4zZNPb3iIkxzIf5d8euvLOYssUJHn6F_DTJBfnjTWlklI_cfOl3myPomelv8vZGvog-RTINpkV22sfxocwaydqzECp1LnYJmPMpZ5BW2EjKX3QMfUj/s1600/Alexa_Map.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="260" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiOI8yBDPfqMAfhDEC17QeXmsjSMn4zZNPb3iIkxzIf5d8euvLOYssUJHn6F_DTJBfnjTWlklI_cfOl3myPomelv8vZGvog-RTINpkV22sfxocwaydqzECp1LnYJmPMpZ5BW2EjKX3QMfUj/s400/Alexa_Map.jpg" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjtcBi6oTU9QbAjiBENqax1Hhoqv0lpZrJ1t_xQyabrGdMBDnbu33X49lrJiBq7ZaB45oC-46MoO1X4RDPOi4eHfrInKV_kgmmHrtoZmrL0lCg31lc6UieeYjkFtvBeP6SwUg_woAaFCNQR/s1600/Alexa_USMap.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="261" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjtcBi6oTU9QbAjiBENqax1Hhoqv0lpZrJ1t_xQyabrGdMBDnbu33X49lrJiBq7ZaB45oC-46MoO1X4RDPOi4eHfrInKV_kgmmHrtoZmrL0lCg31lc6UieeYjkFtvBeP6SwUg_woAaFCNQR/s400/Alexa_USMap.jpg" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiBB1GUQte6GqV-5oc2zK_vF7tJn-sI8O6XZ1bKK52IKiqto6NoETi1RjA8Tt9YufIpERPOszMQVLnuStRpRLX3-hJlvf4Z9dPUGTu2IBOu33ocp3CILNe4dZI2GiA_pBC9gtM-cHZ6On70/s1600/Alexa_Carriers.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="261" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiBB1GUQte6GqV-5oc2zK_vF7tJn-sI8O6XZ1bKK52IKiqto6NoETi1RjA8Tt9YufIpERPOszMQVLnuStRpRLX3-hJlvf4Z9dPUGTu2IBOu33ocp3CILNe4dZI2GiA_pBC9gtM-cHZ6On70/s400/Alexa_Carriers.jpg" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: justify;">
Ok…enough…let’s watch this in real live action ;)</div>
<div class="separator" style="clear: both; text-align: justify;">
<br /></div>
<div class="separator" style="clear: both; text-align: justify;">
<br /></div>
<div style="text-align: center;">
<iframe allowfullscreen="" class="YOUTUBE-iframe-video" data-thumbnail-src="https://i.ytimg.com/vi/JZdwE2LAMek/0.jpg" frameborder="0" height="266" src="https://www.youtube.com/embed/JZdwE2LAMek?feature=player_embedded" width="320"></iframe></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
Greetings,<br />
<br />
Blag.<br />
Development Culture.Alvaro "Blag" Tejada Galindohttp://www.blogger.com/profile/12061593528820409779noreply@blogger.com0tag:blogger.com,1999:blog-4144704359177008692.post-33476329359976760502015-12-07T11:48:00.000-08:002016-12-01T07:53:08.914-08:00LED is my new Hello World - Elm TimeSo...as promised...here's my LED Numbers app written in Elm -:)<br />
<br />
Now...this took me more time than expected, due to a couple of things...<br />
<br />
a) Elm likes to handle Just and Maybe values...Haskell does the same...but Haskell provide alternative functions that deal with Just and Maybe...Elm does not...so I need to come up with some functions for it...<br />
<br />
b) Elm doesn't provide a function to get elements from a list...so I need to build the function...<br />
<br />
c) I'm still an Elm newbie<br />
<br />
That put aside...Elm is still awesome and I love it -;)<br />
<br />
Anyway...let's get to work...<br />
<br />
Create an folder called LED_Numbers and type this into the terminal...<br />
<br />
<b>elm package install evancz/elm-html</b><br />
<b><br /></b>
<b>elm package install evancz/start-app</b><br />
<b><br /></b>
Then, open your favorite editor and copy and paste the code...<br />
<br />
<table align="center" style="width: 600px;">
<tbody>
<tr><th bgcolor="#6690BC">LED_Numbers.elm</th>
</tr>
<tr>
<td><pre>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 }
</pre>
</td>
</tr>
<tr>
</tr>
</tbody></table>
<br />
Go into the terminal again and type this...<br />
<br />
<b>elm make LED_Numbers.elm --output LED_Numbers.html</b><br />
<b><br /></b>
Open the file in your browser and run it...<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjYcDgNsRT-SBAzOYLM1_FiFKsbSSBv9opfy-BN1c6-MWuiZGCdwtsZPkbZu8OKqBHtxqXc8yv0zPk4ZrgQF7SjtkL6zIyxjM0iWiaiGRAnIJuZe1yanqYUeYEQ-dTISxO1hNzIrbIIupL7/s1600/LED_Elm_01.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="137" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjYcDgNsRT-SBAzOYLM1_FiFKsbSSBv9opfy-BN1c6-MWuiZGCdwtsZPkbZu8OKqBHtxqXc8yv0zPk4ZrgQF7SjtkL6zIyxjM0iWiaiGRAnIJuZe1yanqYUeYEQ-dTISxO1hNzIrbIIupL7/s400/LED_Elm_01.jpg" width="400" /></a></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgzc4HXobC7DSPz2z4rfGPEUWNniuSyycpRcvdmrRtVf1DwmO1WKuFUZOvP8OPn_l16qGRQhNCLeY8FbodpBEL9nVPboZO2-gN6rmkM0lVb0Bl0BIqdrdllyPg89fXihRmBBXqeyzs_jlqF/s1600/LED_Elm_02.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="140" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgzc4HXobC7DSPz2z4rfGPEUWNniuSyycpRcvdmrRtVf1DwmO1WKuFUZOvP8OPn_l16qGRQhNCLeY8FbodpBEL9nVPboZO2-gN6rmkM0lVb0Bl0BIqdrdllyPg89fXihRmBBXqeyzs_jlqF/s400/LED_Elm_02.jpg" width="400" /></a></div>
<br />
Hope you like it -;)<br />
<br />
Greetings,<br />
<br />
Blag.<br />
Development Culture.Alvaro "Blag" Tejada Galindohttp://www.blogger.com/profile/12061593528820409779noreply@blogger.com0tag:blogger.com,1999:blog-4144704359177008692.post-19007020074723750382015-12-03T11:01:00.000-08:002015-12-03T11:01:32.236-08:00My first post on ElmLooking through my list of new languages to learn...I came upon <a href="http://elm-lang.org/" target="_blank">Elm</a>...functional reactive programming in the browser...<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjD1Q6W3s_H49j3OUXHPa6lI_TNpnT2G2eCYY4FYjWpxChF277kGTldjUwMohzegzQyhDxxQU1u5PFSlP7BANy3vhsmH-u_TshaAngCXwQ8DcWY59kOeCDcbYjtCnQYhWr9PESTrZzG8r4W/s1600/Elm_Logo.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjD1Q6W3s_H49j3OUXHPa6lI_TNpnT2G2eCYY4FYjWpxChF277kGTldjUwMohzegzQyhDxxQU1u5PFSlP7BANy3vhsmH-u_TshaAngCXwQ8DcWY59kOeCDcbYjtCnQYhWr9PESTrZzG8r4W/s1600/Elm_Logo.png" /></a></div>
<br />
Isn't that cool? Of course it is -:)<br />
<br />
Now...Elm came to life around 2012...so it's fairly new...which means not some many tutorials and no books that I know of...but...don't let that scare you away...there's actually a couple of awesome courses handled by <a href="https://pragmaticstudio.com/" target="_blank">The Pragmatic Studio</a> that will help you to get up and running -;)<br />
<br />
<a href="https://pragmaticstudio.com/elm" target="_blank">Elm: Building Reactive Web Apps</a><br />
<br />
<a href="https://pragmaticstudio.com/elm-signals" target="_blank">Elm: Signals, Mailboxes & Ports</a><br />
<br />
Now...to install Elm...if you have <a href="https://nodejs.org/en/" target="_blank">NodeJS</a> already installed then you can simply use npm which is I guess the preferred and easier way...<br />
<br />
<b>sudo npm install elm</b><br />
<b><br /></b>
Otherwise just go the <a href="http://elm-lang.org/install" target="_blank">download</a> section for the installers or for the source code to build it...but keep in mind that to build it you will need to have <a href="https://www.haskell.org/" target="_blank">Haskell</a> installed as well...<br />
<br />
Anyway...we're going to see how to create a Fibonacci List app in Elm... -:)<br />
<br />
Create a folder a call it "Fibonacci_App" and the go into it from the terminal...<br />
<br />
<b>elm package install evancz/elm-html</b><br />
<b><br /></b>
<br />
<div class="separator" style="clear: both; text-align: center;">
</div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEglbPDz3z1Qx0Di8jXWR-lLbRgSTMDcIsGf_a7VtR_f39cueqK34pABkcvGY4fNHhqzT7SXRIGyx3bLqmYgwOt7O8kdS-Bmsi7QE0A4Yo6EKuOx6nd58pWd36U_7Ei4tGkjrEOxFvGxejMC/s1600/Elm_Html.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="240" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEglbPDz3z1Qx0Di8jXWR-lLbRgSTMDcIsGf_a7VtR_f39cueqK34pABkcvGY4fNHhqzT7SXRIGyx3bLqmYgwOt7O8kdS-Bmsi7QE0A4Yo6EKuOx6nd58pWd36U_7Ei4tGkjrEOxFvGxejMC/s400/Elm_Html.jpg" width="400" /></a></div>
<b><br /></b>
<b>elm package install evancz/start-app</b><br />
<b><br /></b>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhtX3_3674rBT2b2I6qyN7MslPEmP3lDEuA-OJZEFbmRuVSa1hodP6G12zhElZGLklioIpJj3asgXrJ76mSUhQ8lyt1aZoXwTHaEzKTDcI0h-fOBojpxON1Pa4y85WWB5-p00XhLUqkOkqL/s1600/Elm_Start.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="210" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhtX3_3674rBT2b2I6qyN7MslPEmP3lDEuA-OJZEFbmRuVSa1hodP6G12zhElZGLklioIpJj3asgXrJ76mSUhQ8lyt1aZoXwTHaEzKTDcI0h-fOBojpxON1Pa4y85WWB5-p00XhLUqkOkqL/s400/Elm_Start.jpg" width="400" /></a></div>
<b><br /></b>
The first package is going allow us to generate HTML code and the second one is going to make our lives easier...<br />
<br />
Now...open your favorite editor and type this away...<br />
<br />
<table align="center" style="width: 600px;">
<tbody>
<tr><th bgcolor="#6690BC">Fibonacci.elm</th>
</tr>
<tr>
<td><pre>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 }
</pre>
</td>
</tr>
<tr>
</tr>
</tbody></table>
<br />
Now, we just need to compile our application -;)<br />
<br />
<b>elm make Fibonacci.elm --output Fibonaccci.html</b><br />
<b><br /></b>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiDJnj7VIYq1aC8b60BWzlEM0txiJsGF9yhfS-Db3s9VobchvYHpSz2vPgZBjKya0tswTQ1Ppxum6Gp8fs0Nxums4znaJGmes0Ec4v5V_naEFmiqMcGo81BDtxLu7N-c0KOosNQBTapmjSH/s1600/Fibonacci_Elm.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="77" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiDJnj7VIYq1aC8b60BWzlEM0txiJsGF9yhfS-Db3s9VobchvYHpSz2vPgZBjKya0tswTQ1Ppxum6Gp8fs0Nxums4znaJGmes0Ec4v5V_naEFmiqMcGo81BDtxLu7N-c0KOosNQBTapmjSH/s400/Fibonacci_Elm.jpg" width="400" /></a></div>
<b><br /></b>
Now, we can just open that Fibonacci.html file and test our app -:D<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhbW_riXhs4tQocJuYfsaBCjLNlSc55CnZvAJL1I6vbUGCzLMMjdADNIpo2c7kBT7Qj310Kvyr2q33prQIgjwkfs3WwU92p6g5lDUfHdeK8tlPo6GLEwjWbOyxkRJS-xP13czW1D99BD0XS/s1600/Fibonacci_App_01.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="112" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhbW_riXhs4tQocJuYfsaBCjLNlSc55CnZvAJL1I6vbUGCzLMMjdADNIpo2c7kBT7Qj310Kvyr2q33prQIgjwkfs3WwU92p6g5lDUfHdeK8tlPo6GLEwjWbOyxkRJS-xP13czW1D99BD0XS/s400/Fibonacci_App_01.jpg" width="400" /></a></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhclFcjwCGfXI2K3OvYyGMVmnV3AJuBF0XWImprk4VYVJQBZVqVx3p2y5KLuzeC1wAbV3GDE7oOvU8OAbtgIhgafpSP1iKOjK4lallh3nZ7kRPvI_lETfif9yswkkkDrbskfmuyEym5NF8s/s1600/Fibonacci_App_02.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="106" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhclFcjwCGfXI2K3OvYyGMVmnV3AJuBF0XWImprk4VYVJQBZVqVx3p2y5KLuzeC1wAbV3GDE7oOvU8OAbtgIhgafpSP1iKOjK4lallh3nZ7kRPvI_lETfif9yswkkkDrbskfmuyEym5NF8s/s400/Fibonacci_App_02.jpg" width="400" /></a></div>
<br />
Hope you like it -:) I will try to get my LED_Numbers app ready soon -;)<br />
<br />
Greetings,<br />
<br />
Blag.<br />
Development Culture.Alvaro "Blag" Tejada Galindohttp://www.blogger.com/profile/12061593528820409779noreply@blogger.com0