Monday, October 2, 2017

OK GOOGLE on Samsung Galaxy S7 doesn’t work

To make Ok Google detection work on Galaxy S7 (Galaxy series phones) we need to perform a couple of steps.


1. As long as Samsung S voice is enabled, it interferes with Ok Google detection.


So disable S Voice first.


Goto settings -> Apps -> S Voice -> Disable. If needed Force Stop the app.


2. Make sure S voice is no longer the default app for voice commands. Otherwise the phone will start it again instead of Google assistant.


Goto settings -> Apps -> Default apps -> Device assistance app


Make sure that the device assistance app is Google.


3. Make sure “Ok Google” is turned ON.


Tap the google search bar to go to the Google Now app. Tap the big G at the top left corner and then the three bars at the top left corner and choose settings -> Voice -> OK Google detection. Make sure that Ok Google detection is turned on and Trusted voice is turned on too. Train voice model.


4. Restart the phone. This is a crucial step.

Saturday, May 20, 2017

Common questions on climate change

1.  Are renewable energy systems even viable or are they just an Utopian dream of impractical scientists? And even if they are viable wouldn’t it cost an arm and a leg to make them viable?


Among the multitude of scientific journal articles, which answers both these questions separately, one article answers both these questions succinctly in a single paper.


In 2011 Jacobson et al. proposed a 100% WWS (wind, water, solar) energy system which can supplant the current fossil fuel industry. They found that production cost of WWS is exactly same as current fossil fuel-derived energy systems and that includes costs of production, storing, and transmission (with transmission losses). Their conclusion is that “ … barriers to a 100% conversion to WWS power worldwide are primarily social and political, not technological or even economic.”


2. Which countries invest the most in renewables?


The current standing (May, 2017) is:


3. What is geothermal energy?


Geothermal Energy is a viable a source of renewable energy. A NatGeo documentary Steam Drilling (2012) explores the steamy world of geothermal energy production, its challenges, and its tremendous potential as a renewable energy source.


The only problem with geothermal energy is its location dependence. Only a few places on Earth are fortunate enough to have access to geothermal energy reserves. Krafla Power Station in Iceland is one such place. Till now it remains unique in its production of geothermal energy.


4. Many liberals claim that 97% of climate scientists agree that climate change is real and that it is man-made while conservatives say that it is a made-up number and the actual consensus is much lower. Who is right and where did this number come from?

The 97% comes from a series of surveys and meta-analysis done by climate scientists on the level of consensus in their own community. See this short video to get a quick update on how the number is arrived at or read the article at skepticalscience. However, the most convincing argument always come from a paper published in a reputed a peer-reviewed journal.  And that argument can be found in the recent article by Cook J et al 2016 Consensus on consensus: a synthesis of consensus estimates on human-caused global warming Environ. Res. Lett. 11 048002 IOPscience.

Thursday, December 15, 2016

Command-line password generator for Linux

Linux has its own cryptographic generator which can easily be harnessed by the common user to generate extremely strong passwords. This password generator can be found at /dev/random. /dev/random generates pseudorandom numbers based on the available entropy of the system (see wiki page). A derivate of /dev/random called /dev/urandom does the same thing but it is more accessible while being slightly (theoretically) less secure. So what stops us from grabbing outout from /dev/urandom using cat? An output of the content of /dev/urandom will demonstrate that it is practically gibberish with very few usable random characters. The output of

cat /dev/urandom 

should convince the user.  However, it is possible to trim out the unwanted characters and only keep alphabets, numbers, and special characters with a simple filtering by the tr command.


cat /dev/urandom | head -c 10 | tr -dc "A-Za-z0-9_!"

This command will produce the desired output but it will generate very small passwords, which are truly random but which do not meet the length criteria in most cases. Therefore, this procedure needs to be repeated a large number of times until the required length of random passwords can be generated. It is better to write a bash script which will automate this procedure.

The following bash script generates random passwords and allows the user to control the length and number of random passwords that are generated. It also allows special characters to be included or excluded with a switch (argument). Since I am always in a hurry and don't like passing too many arguments, I wrote the script so that it can accept arguments in a shorthand manner in addition to the longhand manner (Unix style) of passing arguments. Shorthand way: ./randompass.sh 10 2 1 will generate 2 random passwords of length 10 and they will all include special characters.


~$ ./randompass.sh 10 2 1

ST5%l36HpG
4Tvq%Ia1UZ

Or I could use the longhand (Unix-style) way of passing the arguments: ./randompass.sh -l 10 -n 2 -s 1


~$ ./randompass.sh -l 10 -n 2 -s 1

IofK1_qA%l
%5aw_YY1XZ


The result will be the same. I have included the full code below which is well commented. I also provide explanation and cite sources below the code.


#!/bin/bash

# generate random passwords using urandom CSPRNG.  

# randompass.sh v5.2 by Jones

# ---- SET INITIAL VALUES ----
length=16
num=4
special=1
usage="
Usage: ./randompass.sh [options ...]
  -l password length. DEFAULT=16
  -n number of passwords to generate. DEFAULT=4
  -s special characters. DEFAULT=1. Set to 0 to disable selecting _!%
  -h help
  
Example 1: ./randompass.sh -l 8 -n 2 -s 0
  
OR

./randompass.sh [password length] [number of passwords to generate] [include special characters] 

Example 2: ./randompass.sh 8 2 0   "

if [[ "$1" =~ ^[0-9]+$ ]]; then  
 # ---- SET INITIAL VALUES ----
 length=$1
 num=$2
 special=$3

 # Second and third argument might be empty which means $num and $special
 # will be empty at this point too. Set the values of $num and $special 
 #to the default values in case they are empty
 [ "$2" == "" ] && num=4
 [ "$3" == "" ] && special=1
else
 # If user uses arguments then use getopts.
 while getopts l:n:s:h option
 do
  case "${option}"
  in
          l) length=${OPTARG};;
          n) num=${OPTARG};;
          s) special=${OPTARG};;
          h) echo "$usage" ;;
  esac
 done
fi

# ---- CHECK ARG VALIDITY ----

# check if the first argument is an integer. If it is not then throw error. 
#=~ matches REGEXP ^[0-9]+$ which is one or more occurences of the numbers 0-9
if [[ !("$length" =~ ^[0-9]+$ )]]; then
 echo "Enter numbers only for the password length"
 echo "$usage"
 exit
fi

# check if the second argument is an integer. If it is not then throw error.
if [[ !("$num" =~ ^[0-9]+$) ]]; then
 echo "Enter numbers only for the number of passwords to generate"
 echo "$usage"
 exit
fi

# check if the third argument is an integer. If it is not then throw error. 
if [[ !("$special" =~ ^[0-1]+$) ]]; then
 echo "Enter only 0 or 1 for the third argument."
 echo "$usage"
 exit
fi


# ---- GENERATE THE PASSWORDS ----
if [[ $special == "1" ]]; then # if special chars needed: DEFAULT
 i="0"
# echo "first loop for 1"
 while [ $i -lt $num ] 
 # Keep looping till next password, which satisfies the required criteria, 
 # is successfully generated. May require many more passess for stricter 
 # requirements, usually smaller length passwords.
 do 
 pass=`tr -dc "A-Za-z0-9_!%" < /dev/urandom | head -c ${length} | xargs`

 if [ `echo $pass | grep "%" | grep "[0-9]" ` ]; then
   echo $pass
   i=$[$i+1]
 fi
 done
else  # if special chars are NOT needed
 i="0"
# echo "second loop for 0"
 while [ $i -lt $num ]
 do 
 pass=`tr -dc "A-Za-z0-9" < /dev/urandom | head -c ${length} | xargs`

 if [ `echo $pass | grep "[0-9]" ` ]; then
   echo $pass
   i=$[$i+1]
 fi
 done
fi



 

Parsing the command-line

The block of code which parses the command-line options using getopts is found at lifewire. The post at that link provides a clear explanation of what the block of code while getopts l:n:s:h option does. So I will only mention that the while loop parses through the command-line arguments and if it finds any matches to the options that the script expects, then it assigns the value passed to the option to the corresponding variables, defined in the script.

Checking validity of arguments passed

Since the script can only accept numeric arguments, their values need to be checked for non-numeric entries. If found an error message is displayed. To check if the values are numeric we can treat the value as a string and verify that every character lies between 0-9. This ensures that there are no non-numeric characters in that string which in turn implies that the string is a number. "$num" =~ ^[0-9]+$  does exactly that. =~ operator is used for REGEX matching of lvalue $num to rvalue ^[0-9]+$ (which is a REGEX that matches every character to characters between 0-9). A similar test is applied for the special variable which acts as a switch to include or exclude special characters. However, it only takes values 0 or 1. Hence its REGEX is ^0-1+$. For more information on regular expressions see this quick reference.




Sunday, November 27, 2016

Turning normal HDTV into Smart HDTV

One word ChromeCast. That will do it. There is no need to pay a premium for a Smart TV when Chromecast can outperform any of them for a fraction of the cost. Also, there are reports of some Smart TVs stealing user browsing behavior for commercial purposes. The worst was the claim that some TVs secretly listen to the conversation of the people in the room. I cannot verify the truthfulness of these reports but all these are viable possibilities if a malicious app has been secretly installed in the Smart TV. So I would rather play it safe and use Chromecast (since Google has all my data anyways). So we need to buy the Chromecast device and install the Chromecast app on the phone and that will transform the non-smart TV into an entertainment hub. However, just installing the Chromecast app on the phone does not satisfy a power user. Therefore, I chose to explore the possibilities of "Home entertainment".

1. Streaming movies from phone - Install Chromecast app. This is simple and most straighforward way to use it.

2. Streaming movies from the computer - Install Videostream app in Chrome and play the files straight from the local hard drive. However, one drawback of the free version is that it does not support adding a subtitle file. So the only options are to either pay for it or encode the subtitle files into the video files themselves. I will choose the latter option. We will need to create a mkv container and then embed the video and the subtitle files in that container. Videostream supports mkv files so it will stream the video to the TV along with the embedded subtitles.

The embedding can be done with a single command

mkvmerge -o output.mkv video.mp4 eng.srt

However, if there is a lag in the subtitle file and it needs to be resynced with the video file then a couple of additional steps will be required. I wrote an article about it here.

Saturday, August 13, 2016

Setting up Crafty chess engine on Linux/Ubuntu

Crafty installation is pretty simple. The command

sudo apt-get install crafty

will install crafty at /usr/games/crafty and the book files at /usr/share/crafty/books.bin.

If the book files are not installed they can be manually installed by

sudo apt-get install crafty-books-medtosmall

Sometimes the book are not automatically installed in the home folder and it will result in the following error when crafty is run from the command line.

Machine is NUMA, 1 nodes (6 cpus/node)

unable to open book file [./book.bin].
book is disabled
unable to open book file [./books.bin].
ERROR, unable to open game history file, exiting

This implies that we need to import the book.bin and books.bin which contain a vast array of opening moves into the local ~/.crafty directory. For that, we need to run the setup_crafty.sh. However, it needs to be made executable by the normal user first. As root go to the directory /usr/share/doc/crafty and do the following,

su
cd /usr/share/doc/crafty 
sudo chmod 777 setup_crafty.sh 

Then logout from root, go back to the same directory /usr/share/doc/crafty and run as user:

./setup_crafty.sh

Don't run the last command as root otherwise the .crafty directory will be created in the /root directory! It will spit out a few lines of info. Copy the lines

export CRAFTY_LOG_PATH=/home/<USERNAME>/.crafty
export CRAFTY_RC_PATH=/home/<USERNAME>/.crafty
export CRAFTY_TB_PATH=/home/<USERNAME>/.crafty
export CRAFTY_BOOK_PATH=/home/<USERNAME>/.crafty

to .bashrc file and then

source .bashrc

After that source


source /home/<USERNAME>/.crafty/env_settings

Run Crafty. It should be able to see the book files now.




Friday, September 4, 2015

Generate email filters in Gmail from list of emails

I have a lot of students from different classes who email me regularly. It is helpful to tell who belongs to which class. So I created a filter in Gmail which will sort the student's email according to their email ID. This scenario is also applicable to industry where we want to sort emails using filters. Most of the time people are able to do it by hand. However, for me it was challenging to do it by hand since I had 400 students. Therefore I fell back to Bash tools to automate the task.

The first thing is to extract all the email IDs from a CSV file and save it as a list.

cat file.csv | cut -d"," -f10

The 10th column had the email IDs in the CSV file. The fields are separated by commas in CSV files. Therefore, I have used -d"," as the delimiter in the cut command.

"rwrwfa"
"ebbra"
"rksda"
"ru57a"

But they have the " which I need to get rid off. Easy use tr.

cat file.csv | cut -d"," -f12 | sed 's/"//'

rwrwfa"
ebbra"
rksda"
ru57a"

The reason why I didn't get rid off the last " is because I am going to replace that with @aaa.edu since these email IDs do no have the @aaa.edu in them.

cat file.csv | cut -d"," -f12 | sed 's/"//' | sed 's/"/@aau.edu'

"rwrwfa@aaa.edu"
"ebbra@aaa.edu"
"rksda@aaa.edu"
"ru57a@aaa.edu"

Save this list to a file tempfile1.

cat file.csv | cut -d"," -f12 | sed 's/"//' | sed 's/"/@aau.edu' > tempfile1

The reason why I can use . (dot) inside sed is because I used  ' ' instead of " "  so .(dot) is interpreted as . (dot) and not as a wildcard. 








Thursday, August 13, 2015

Google script to generate expense spreadsheet in Google Sheets

Google has started scripting support for all its products. So Google docs now supports scripting which will allow end users to automate routine tasks. Google Scripts is a Javascript cloud scripting language (as opposed to Javascript being client-side only) which can make life easier for most of us (Or at least the tech savvy ones). But if you are not a programmer, don't despair -- this tutorial does not assume coding experience but the ability to copy and paste in the right places.

Now all Google products support scripting and this includes Google Maps. So for example, if you want to write a script which will import the restaurant data from Google Maps, then make it into a list in Google Sheets, and then sort the list by distance from home and email that list to colleagues, it is now possible to achieve all of this due to the support of Google Scripts. This means that now many things can be automated and the end result is an increased level of productivity. So I decided to give it a try.

I have an expense spreadsheet of my monthly expenses which I copy over every month and start from scratch. This means I had to manually delete all the data and the notes and align the dates with the days again (my spreadsheet is broken into weeks running from Sun-Sat and does not go from 1-31 of the month, which would have been easier but not insightful). So I wrote a Goggle Script to automate this mundane task. It turns out to be a little more complex than I thought. The script had to figure out the dates when each week ends and then append a row of Weekly Total and at the end of the month there is some days extra which needs to be summed again for a Final Total. Then just for fun I added a gross total of each individual category (I have 4 categories - Grocery, Gas, Restaurant, Misc.). For a customized set of categories another script needs to be written. Currently, I am working on a script which will take user input on the types of categories and prepare the spreadsheet accordingly but I decided to publish this bit of work first.

In order to run the Google Script, open up the scripts browser and copy paste the code below. The Script Browser can be accessed from Tools -> Script Editor. The first time the script is run, Google will ask for authorization. Once accepted (no malicious codes here, check it!!) you will need to run it again to actually execute it. I am usually very careful about running scripts because it is easy for a malicious user to embed codes in them. So I do not expect the user to direct copy paste and run the code. I expect the user to read the code and understand its function. Google script is essentially Javascript hence it should be easy to comprehend for anyone with a decent programming background.

function generateExpenseSheet() {
  
  // written by Jones to create an expense spreadsheet v3.0 09/04/15 v2.0 08/12/15
  
  var sheet = SpreadsheetApp.getActiveSheet();

  var yesno = Browser.msgBox('Alert', 'Clear sheet?', Browser.Buttons.YES_NO);
  
  if (yesno === 'yes') {
    sheet.clear();
    sheet.clearNotes();
  } else {
    return;
  }
  
  sheet.clear();
  sheet.clearNotes();
  
  var weekday = ["Sun","Mon","Tue","Wed","Thu","Fri","Sat"];
  
// Create toady's date. Use it to extract the month and year info. Then use that info to create the first date of the month. 
// Then use getDay() method to get the day of the week on which this first date of the month falls.
  var d = new Date();
  var d2 = new Date(d.getFullYear(),d.getMonth(),1);
  var firstdayofmonth = d2.getDay();
  
// Create the last date of the month and then use it to extract the days of month.
// Using 0 in the day field of next month chooses the last day of previous month.
  var d1 = new Date(d.getFullYear(),d.getMonth()+1,0);
  var daysinMonth = d1.getDate();
  
//  Logger.log(firstdayofmonth);
  
  var currentrowno = 1;
  
// Fill column heading
  sheet.appendRow(['day', 'date','grocery','gas','restaurant','misc.','total','','TOTAL']);
  currentrowno++;
  
// start from Sun but fill with empty rows till first day of the month  
  
  for ( i = 0 ; i < firstdayofmonth ; i++,currentrowno++) 
    sheet.appendRow([weekday[(i)%7],'','','','','','' ]);
     
// start filling rows with info starting from first day of month  
  for ( j = 0 ; j < daysinMonth ; j++) {
    
    
    // after every one week then insert a 'TOTAL FOR THE WEEK' row
    if ( (j + firstdayofmonth) % 7 === 0) {    
      // generate SUM formula for each column 3-8, save the formulas in an array 
      var weekrange = [];
      for ( k = 0 ; k < 4 ; k++) {
        weekrange[k] = sheet.getRange(((j + firstdayofmonth)/7-1)*8+2, k+3,7,1).getA1Notation();
      }
      // insert formulas as a single row
      var rownoTotal = ((j + firstdayofmonth)/7 )*8 + 1 ;
      sheet.appendRow(['','','=SUM('+weekrange[0]+')','=SUM('+weekrange[1]+')','=SUM('+weekrange[2]+')', '=SUM('+weekrange[3]+')','=SUM(C'+ rownoTotal +':F'+ rownoTotal +')' ]);
      // make the sum row BOLDso that it is easy to differentiate from the other rows of the week
      sheet.getRange(currentrowno,3,1,5).setFontWeight("Bold");
 
      // increase row no after each appendRow
      currentrowno++;

    }
    
    // add blank rows with day of week and date and the total of the day
    var rowno =  (parseInt((j + firstdayofmonth)/7) +  1)*8 + 1 ;
    sheet.appendRow([weekday[(j + firstdayofmonth)%7],j+1,'','','','','=SUM(C'+ currentrowno +':F'+ currentrowno +')' ]);
   // increase row no after each appendRow
   currentrowno++;
    
  }
  
 // if there are extra days which are not totaled then total them
 // start at the row next to the last WEEKLY TOTAL ROW. find the date of that day. 
 // then subtract it from the total days in the month. that will give the row where the list ends. 
  var dateOfLastTotalRow = sheet.getRange((parseInt((j + firstdayofmonth)/7))*8,2).getValue();
  
  var rowNoOfLastTotalRow = (parseInt((j + firstdayofmonth)/7))*8 + 2 ;
  
 // generate SUM formula for each column 3-8, save the formulas in an array 
 for ( k = 0 ; k < 4 ; k++) {
   weekrange[k] = sheet.getRange(rowNoOfLastTotalRow, k+3,daysinMonth -  dateOfLastTotalRow,1).getA1Notation();
   }
  
  // get final row no. use it to calc. the sum at the lower right corner of the table and then use it in the MASTER TOTAL of the Month formula
  var finalRow = currentrowno;
  
  // insert SUM formulas as a single row in the FINAL ROW
   var sumrow = sheet.appendRow(['','','=SUM('+weekrange[0]+')','=SUM('+weekrange[1]+')','=SUM('+weekrange[2]+')','=SUM('+weekrange[3]+')','=SUM(C'+finalRow+':F'+finalRow+')' ]);
    sheet.getRange(currentrowno,3,1,5).setFontWeight("Bold");

 if ( finalRow == 41  )
  {
    var MasterSUM = '=G9+G17+G25+G33+G41';
    var grocerySUM = '=C9+C17+C25+C33+C41';
    var restaurantSUM = '=E9+E17+E25+E33+E41';
    var gasSUM = '=D9+D17+D25+D33+D41';
    var miscSUM = '=F9+F17+F25+F33+F41';
  }
  else if ( finalRow > 41 ) {
    var MasterSUM = '=G9+G17+G25+G33+G41+G'+finalRow;
    var grocerySUM = '=C9+C17+C25+C33+C41+C'+finalRow;
    var restaurantSUM = '=E9+E17+E25+E33+E41+E'+finalRow;
    var gasSUM = '=D9+D17+D25+D33+D41+D'+finalRow;
    var miscSUM = '=F9+F17+F25+F33+F41+F'+finalRow;
  }
 else 
  {
    var MasterSUM = '=G9+G17+G25+G33+G'+finalRow;
    var grocerySUM = '=C9+C17+C25+C33+C'+finalRow;
    var restaurantSUM = '=E9+E17+E25+E33+E'+finalRow;
    var gasSUM = '=D9+D17+D25+D33+D'+finalRow;
    var miscSUM = '=F9+F17+F25+F33+F'+finalRow;
  }
  
  sheet.getRange(1,10).setValue(MasterSUM);
  
  //make table for 
  sheet.getRange(5,9).setValue("Grocery");
  sheet.getRange(5,10).setValue(grocerySUM);
  
  sheet.getRange(6,9).setValue("Restaurant");
  sheet.getRange(6,10).setValue(restaurantSUM);

  sheet.getRange(7,9).setValue("Gas");
  sheet.getRange(7,10).setValue(gasSUM);

  sheet.getRange(8,9).setValue("Misc");
  sheet.getRange(8,10).setValue(miscSUM);
  
  // Make sure the cell is updated right away in case the script is interrupted
  SpreadsheetApp.flush();
 
}

Before running the script the user needs to save it under a project name. The choice of the name of the project doesn't matter at this stage so go ahead and name it what you wish to. Then click the small play button to run the script. When executing the script for the first time the user will receive an authorization window like this

Select Accept and run it again. Go back to your Google Sheet. There is a small message box waiting asking permission to clear the sheet. Click yes and watch the script generate the entire expense spreadsheet.

Need : Google Drive, Google Sheet, Google script (provided), Javascript knowledge (optional).


OK GOOGLE on Samsung Galaxy S7 doesn’t work

To make Ok Google detection work on Galaxy S7 (Galaxy series phones) we need to perform a couple of steps. 1. As long as Samsung S vo...