W09Y18 – Merge images, SAPUI5 Image component, Raspberry Pi SSH over USB

Merge images

If you need to merge mutiples images in one, I’ll warmly recommend you to use this JavaScript library: https://github.com/lukechilds/merge-images.

Yes, I know what you are going to tell me: it’s possible to do it without any library but it’s more complicated, and not easy to maintain. For example, to do the same in pure JavaScript, you have to play with canvas… below a little example:

var c=document.getElementById("myCanvas");
var ctx=c.getContext("2d");
var imageObj1 = new Image();
var imageObj2 = new Image();
imageObj1.src = "1.png"
imageObj1.onload = function() {
   ctx.drawImage(imageObj1, 0, 0, 328, 526);
   imageObj2.src = "2.png";
   imageObj2.onload = function() {
      ctx.drawImage(imageObj2, 15, 85, 300, 300);
      var img = c.toDataURL("image/png");
      document.write('<img src="' + img + '" width="328" height="526"/>');
   }
};

It’s not as sexy as…

mergeImages(['/body.png', '/eyes.png', '/mouth.png']).then(b64 => document.querySelector('img').src = b64);

Agree? And you have some interesting features:

– positioning (x, y) – opacity – size (width, height)

And it’s under MIT licence.

SAPUI5, fix error 404 on sap.m.Image component

I developed some apps using the SAP UI5 frontend framework and on each app, I have the same errors in the console on each page I use the SAPUI5 Image component (sap.m.Image).

It’s not a blocking point or something really embarrassing but… if someone opens the console, it’s weird.

It’s due to retina support (good intention…) but if you haven’t your images with different densities, it will generate errors (see this article). The solution to avoid this error is to set the densityAware to false.

setDensityAware function.

By default it’s true, but I think that’s bad and should be set to false…

Raspberry Pi Zero & SSH over USB

I realized something very bad: the Raspberry Pi Zero is using a mini HDMI port (see below the HDMI vs mini HDMI)

I was very surprised and little bit blocked because it’s not a adaptor I have in my pocket. Then, I ordered one on AliExpress for less than 2$ (Mini HDMI adaptor).

If you are in the same situation then me, I have a good news, you will not be struggled because you can use your USB to ssh in few easy steps!

Step 1:

On the root of your SD card you have to add the following property at the end of the config.txt file:

dtoverlay=dwc2

Step 2:

On the root of your SD card you have to add the following property just after the rootwait parameter in the cmdline.txt file:

modules-load=dwc2,g_ether

Step 3:

Last step, you have to create a new file named “ssh” without any extension on the root of your SD card. Now connect the Raspberry Pi to your laptop and let it boot. Wait 30 seconds for the RPi to finish the boot, open your terminal and launch the command:

ssh pi@raspberrypi.local

Tadaaaaa

SAP Cloud Platform & Cloud Foundry – test, feedback, tips and tricks

After you followed all the steps to setting up Cloud Foundry in your SAP Cloud Platform Cockpit, it’s time to dig into and like all new environment you are testing, you’ll face some problems.

In this article, I’ll quickly overview the activation/installation and talk about a simple NodeJS with a MongoDB scenario. I hope it will help you to be more familiar with the tools, to implement your own needs on the platform.

Quick CF activation/installation

Install CF on your machine and follow instructions detailed here. One it’s installed, you need to test the CF CLI by typing cf in your favorite terminal.

A quota was not automatically assigned for my account because I had several sub accounts. Then, when I deployed an application, I get an error message:

Activate MongoDB / PostgreSQL and other services

Follow the path: Cloud Foundry > Services > Service Marketplace and activate the services you want to use. You can directly map the service with your app if you have already deployed it.

Create and deploy a NodeJS

First, you need to create a skeleton NodeJS project using the Nodeclipse available for free on the Eclipse Market or create your own project from scratch using the framework your like. You can simply download this project from my Github account : js-app-for-sap-cloud-foundry.

If you are not using mongodb in the scenario, you can comment the line require(‘./server/db/mongo-connect.js’)(oAppEnv);. It simplifies the workflow, you can uncomment it later. When your project is ready, be sure it compiles by running the two following commands:

npm install
node app.js

If all is OK, your project is ready to be hosted on CF.

// Logon to Could Foundry
cf login
// Enter your credentials and navigate to the space you want to host the app
// Change directory and push it!
cd js-app-for-sap-cloud-foundry
cf push

The file manifest.yml is very important for your app deployment, to specify the app information: commands, name, buildpack, etc. Below, an example of manifest.yml file

---
applications:
- name: js-app
  memory: 512M
  host: js-app
  command: node app.js

Fields you need to know for the manifest.yml file:

Key Value
name The name of the application
buildpack The name of the Node.js buildpack determined before with command cf buildpacks. (by default an auto determination of the buildpack is done if the buildpack information is missing)
command For NodeJS apps, a start command is needed to start the application. Here for example, it’s “node app.js”.
memory RAM available for the application.
disk_quota Disk space available for the application.
host Host information used in the URL which makes the application accessible.

Connect with a MongoDB

The first step is to create a new MongoDB instance. You have to go to your SAP CP CF sub account > Services > Service Marketplace and select MongoDB. Now in your left panel you can select Instances and create a new one (see below)

Now you are able to map your instance with the app you deployed before. The manifest.yml will change a little bit and the service will be mapped like this:

---
applications:
- name: js-app
  memory: 512M
  host: js-app
  command: node app.js
  services:
  - mongodb-service 

/!\ “mongodb-service” is the name of you instance, you need to adapt /!\

Useful links

Github | SAP/hcp-cloud-foundry-tutorials
SAP CP | Cloud Foundry Tutorials
Github | Cloud Foundry CLI
Cloud Foundry CLI Reference Guide

Useful CLI commands

cf
cf apps
cf login
cf logout
cf push
cf buildpacks
cf marketplace
cf api api.cf.<host information>
cf create-service mongodb v3.0-dev mongo-service

Google Apps Script: Get current user email from a spreadsheet Add-On

Retrieve the current user email using App Script in your Spreadsheet Add-On is a little bit tricky. You can easily use the Session object to get it but in some cases, this object will return undefined.

Current user email using Session object

var userEmail = Session.getActiveUser().getEmail();

So, you need to find a workaround. The workaround could be to use the PropertyService object.

Current user email using PropertiesService object

var userEmail = PropertiesService.getUserProperties().getProperty('userEmail');

Why not, that’s another way to get it but not 100% too. If you want to secure it and combine another way to get it, you need to work with the sheet protection.

Current user email using spreadsheet protection

var protection = SpreadsheetApp.getActive().getRange('A1').protect();
protection.removeEditors(protection.getEditors());
var editors = protection.getEditors();
if (editors.length === 2) {
    var owner = SpreadsheetApp.getActive().getOwner();
    editors.splice(editors.indexOf(owner), 1);
}
userEmail = editors[0];
protection.remove();
PropertiesService.getUserProperties().setProperty('userEmail', userEmail);

Free to play

The full method, ready to use, capy-paste in your code and have fun:

function getCurrentUserEmail() {
    var userEmail = Session.getActiveUser().getEmail();
    if (userEmail === '' || !userEmail || userEmail === undefined) {
        userEmail = PropertiesService.getUserProperties().getProperty('userEmail');
        if (!userEmail) {
            var protection = SpreadsheetApp.getActive().getRange('A1').protect();
            protection.removeEditors(protection.getEditors());
            var editors = protection.getEditors();
            if (editors.length === 2) {
                var owner = SpreadsheetApp.getActive().getOwner();
                editors.splice(editors.indexOf(owner), 1);
            }
            userEmail = editors[0];
            protection.remove();
            PropertiesService.getUserProperties().setProperty('userEmail', userEmail);
        }
    }
    return userEmail;
}

Dynamic port & Bower + Grunt scripts with Heroku host

I use Heroku to host some project like Osprey, and I need to admit that this is really a nice platform to host your personal projects for free. It’s really easy to start with but you need to know a few of things…

First of all, check the Node tutorial provided by Heroku.

Bower & Grunt

If you have some bower or grunt scripts to launch after the npm install and before the npm start, you need to add a bash script reference in your package.json file. Your package.json file will contain a postinstall command:

"scripts": {
  "test": "echo \"Error: no test specified\" && exit 1",
  "start": "node server.js",
  "postinstall": "bash ./build.sh"
},

And your build.sh file should contain all the commands to build the rest of your project (copy, move files, etc…)

#!/bin/bash
./node_modules/bower/bin/bower install
./node_modules/grunt-cli/bin/grunt

Dynamic port

Heroku assigns dynamically a port to your app. So, if you have set a fixed port in your server.js file, it will not work with the heroku deployment. The port is added to the process.env.PORT variable so you need to pull it from there. You app.listen method should look something like this:

var port = process.env.PORT;
app.listen(port || 3000);

Google Photos, bring back your filters (Deimos, Ariel, Triton, Phobos, etc…)

Since Novembre 2016, Google has “improved” the Google Photos app, but they simply removed all filters for something that is not equal… I’ve sent a feedback through the Google Photos contact form (https://photos.google.com/ > left menu > give feedback).

The workaround is to download an old version of Google Photos and install to a simulator or on your phone. You can find all APK versions on the APKMirror website.

If you don’t know which version is needed for your phone, check on Google your phone architecture version and dpi. For example, for a Nexus 5X, it’s arm64 – dpi 420 (default), so you need to download the 540717 (October 31, 2016) version which corresponds to: arm64, Android 4.1+, 400-480dpi

Forum posts

Google Forum – Is there way to use the previous filter?

Google, bring back your filters! They were good!