Saturday, December 31, 2022

kex_exchange_identification: Connection closed by remote host error with ssh

When trying to connect with ssh to our internal server, I was seeing such errors intermittently -
kex_exchange_identification: Connection closed by remote host

When I would try again, it would connect.

Of the many possible reasons, I think in our case the cause might have been a busy router or a busy server. 

Edit: A restart or something like that seems to have solved it now, a couple of days later.

Wednesday, December 28, 2022

private file sharing solutions

Copy-pasting from an email discussion regarding solutions for sharing large files with multiple remote teams - 

1. Shared Drive - This seems to be the easiest and simplest solution, at least to start with. Most probably you cannot increase individual users beyond 30 GB, but you can use Shared Drives -  https://www.googlecloudcommunity.com/gc/Workspace-Q-A/Trying-to-change-storage-limit-for-members-of-a-group/m-p/421866

Shared Drives currently have no limit, as far as I could see.

2. Single file size limits - With google drive, even shared drives, you have a limit of a few MB for uploading files from the web interface. If you use the Google Drive Sync desktop app, you apparently can go up to 5 TB for individual files. But limited to 750 GB per day. This page also has the explanation for the 100 GB added, "no longer available for new customers"

3. If more than 5 TB is needed - Advantage of separate server for file-sharing - would be cheaper than google drive or other cloud storage. Disadvantage - would need to choose a server in India or else uploads might be quite slow. After that, if we have https downloads, we could use cloudflare caching to speed up downloads. This apparently works even if the content is behind some login/pw authentication, for example session based auth.

Tuesday, December 27, 2022

getting form response in an iframe

I've used the target attribute earlier in forms in order to get a form's response in an iframe, like

<form action="rightpage.php" method="get" target="result_frame">

....

<iframe name="result_frame" width="100%" height="900">


Apparently, we can also use formtarget instead, which goes into the submit button - 

<input type="submit" formtarget="result_frame" value="Submit to frame">

Monday, December 26, 2022

how to delete EFI system partition on Windows

If we want to repartition a former system drive, Windows doesn't allow us to delete the EFI system partition from the GUI. Can be done from the terminal - How to Delete the EFI System Partition in Windows 10 or 11 | Tom's Hardware (tomshardware.com)

diskpart
list disk
sel disk 2
list partition
sel partition 2
delete partition override

Notes on building release apk using Github Actions - cordova commandline build

  1. The working workflow file for building the modified version of the Moodle app version 4.1.0 is at buildSSSVV.yml

  2. Though the main idea was to clone a private repo similar to this post, one difference was that I used my user's private key instead of adding a separate key-pair as deployment key - that also worked, but I should be careful to remove my private key from the destination repo as soon as I finish my builds.

  3. We must clone the private repo and build the public repo as part of the same job in the github workflow, or else the file would be cleaned up and not available (unless stored as an artifact.) 

  4. One stumbling block preventing builds on the first attempt was to find the correct syntax for the release build using cordova build. Turns out it needs several points which were not clearly discussed at cordova's documentation example, but was mentioned in ionic's documentation example. (Edit - all the flags required are mentioned at https://cordova.apache.org/docs/en/11.x/guide/platforms/android/index.html#using-flags - I had not seen this page earlier.) I did not create a build.json since the commandline switches worked for me. "failed to read key from store" was because I missed the --password parameter, I had put in only the --storePassword parameter. The error was not due to requiring escaping of special characters in the password.

  5. We also need -- -- twice in order to get an apk instead of an aab as the output file, Cordova generate release apk instead of aab - Stack Overflow.

  6. The final correct command to build (at least for this version of cordova android) was
    npx ionic cordova build android --release -- -- --packageType=apk --keystore="~/sssvv_mobile-release-key.keystore" --password=$KEY_PW --storePassword=$KEY_PW --alias=$KEY_ALIAS

  7. Before trying all this, I tried building just an unsigned apk - but jarsigner signing of the unsigned release apk didn't work. I wonder why.
    jarsigner -keystore <keystore_file>  -storepass <storepass> -keypass <keypass> <unsigned_apk_file> <alias_name>
    The apk was not showing the correct icon, and "problem parsing file" when try to install. Maybe this problem is due to some version difference between the java / SDK / build tools on the build machine and the signing machine? No idea.

  8. The technique of using this GUI tool to avoid typing out all the paths - Android APK Signer & Aligner - Luke Alderton - also failed, probably due to the same issue as in the above point, whatever that is. Which is why I went ahead with trying to generate the signed release apk from the workflow itself, as above.

Saturday, December 24, 2022

HP 1020 printer on USB instead

Printing to the HP 1020 printer over Wifi, as noted in an earlier post, was working. But it had some issues. Multiple copies were not printing. On some days, the printer would not get detected - once it got detected after I tried something with the Android app, but on another day nothing would help. So, I got fed up and connected it via USB instead.

To get it to print over USB, 
led to
sudo apt-get install hplip-gui

(it was version 3.21.8 for current linux mint 20.3 kernel 5.15)

Deleted and installed after turning off wifi = worked.

Tuesday, December 20, 2022

initializing a 2D array in google apps script

Trying code like:
var resultasarray = [];  
  
  while (TableData.next()) {
    for (var j = 0; j < numberOfColumns; j++) {
       resultasarray[i][j] = TableData.getString(j+1));
  }
  i++;
       
    }
threw errors, TypeError: Cannot read properties of undefined (reading '0')

Using push() instead, worked.

var resultasarray = [];  
  
  while (TableData.next()) {
    var rowvals = [];

    for (var j = 0j < numberOfColumnsj++) {
        rowvals.push(TableData.getString(j+1));
        //Logger.log(TableData.getString(j+1))
    }
    resultasarray.push(rowvals)
    i++;
  }

ad-hoc reports - device information

Copy-pasting from an email exchange regarding the addition of device information to files downloaded ad-hoc report on Moodle:

the device used by the user whether tablets supplied by us or smartphones

This information is not directly captured in the logs, so we cannot put this directly in the files downloaded per user report.

But we do have the
prefix_user_devices table,
which logs which mobile device a user has logged in from, including the time-stamp of when they first logged in from that device.

So, we could write a separate queries for things like:
1. How many users are using the tablets provided by us
2. How many users are using mobile phones or other tablets
3. Which devices a particular user has used, including the time periods

and so on. 

Also, we must note:
This table would not have entries if the user has logged in using a web browser - even if it was a tablet or mobile. Only those devices which use the Moodle app or our mobile app would be logged in this table.

Saturday, December 17, 2022

mailchimp-like free services without the banner, sendinblue and curl

Mailchimp's free plan nowadays has quite an intrusive banner. "Grow your business with Mailchimp". This makes it quite inappropriate for non-commercial emails. Older methods like this one, to make the banner less intrusive, don't seem to work. Looking around for alternatives, one of the top search results was sendinblue, with 300 free emails per day, including transactional emails also. Added bonus - the transactional emails don't even have an unsubscribe link by default, we can add it though. My test implementation is at https://github.com/hn-88/Google-Apps-Script-mailing-list/blob/main/Mailing%20List/Test%20sendinblue%20API.gs

While testing the sendinblue api and the mailchimp api, found some points by trial and error. Just related to curl, syntax of multi-line strings and so on.

  1. curl's --user parameter can be translated to the following snippet -
    'headers': {
            "Authorization": "Basic " + Utilities.base64Encode("anystring" + ":" + mailchimpApiKey)
        }

    for use in Google Apps scripts.

  2. curl's --header parameters should be used as such - just take care to escape double-quotes and single quotes inside the strings like \' or \\\' as needed.
    'headers': {
            "accept": "application/json",
            "content-type": "application/json",
            "api-key" :  sibApiKey
        }
  3. Sendinblue's transactional emails don't include unsubscribe links by default, but we can add them by including the placeholder {{ unsubscribe }}
    <a href={{ unsubscribe }}>To unsubscribe, click here</a>

  4. Multi-line data needs to be handled with care. In Bash, for curl, we put \ at the end of lines for line breaks between parameters, but for a single parameter (like --data) which has a multi-line parameter, we can use single quotes in Bash+curl and single back-ticks in GAS for json objects as can be seen at the following lines of code here. But for JSON to be valid, there should be no line-breaks within the key-value pairs - so, the htmlContent has to be entered in a single line with no breaks. Even adding \n inside the string causes the API to complain about invalid JSON.

 

Wednesday, December 14, 2022

batch conversion of canon raw files

There were some photos in Canon Raw .CR2 format which were to be uploaded to shutterfly.com which accepts only JPG, JPEG, BMP, PNG, HEIC and HEIF - not CR2 or RAW. So I looked at batch conversions. Most probably it would have been possible to do it in Irfanview, but for Linux, I found this - https://askubuntu.com/questions/483379/how-to-convert-cr2-to-jpg-or-png

In my case, I used

sudo apt install darktable 

for pic in *.CR2
do
     darktable-cli "$pic" "$(basename ${pic%.CR2}.jpg)";
done 

It took nearly 10 seconds per file, but it did the job.

PPF information

My PPF (Public Provident Fund) account was with SBI's main branch in Calicut, while my savings bank account with SBI is in Puttaparthi. So, when I got an email from SBI Trivandrum asking if I wanted to enable standing instructions, I did not find my PPF account directly linked in my SBI netbanking, nor did I know my account number off-hand. Asking a bank employee in Calicut, got the account number. Then, found that the account number and balance are available in two places:

  1. SBI's Netbanking --> Other links --> My SBI World - shows the "net worth", which includes PPF. Also supposed to show transactions if any. The account number is shown in full here.

  2. The monthly statement from cbssbi.cas@sbi.co.in has the PPF info also in the statement. The account number is partially blanked out here. 

In my case, trying UPI payments to the account did not work. A colleague who works in finance said that this was probably due to the account being inactive for the last few years - we need to call them, make the account active, and then close it or deposit more etc. The toll-free lines did not work, of course. And nobody answers the landline number of the branch. Probably will have to contact some bank employee and get this done. There is time - one more year till maturity as per the statement.

Saturday, December 10, 2022

log out all users from php sessions based website - and superuser shell for shell wildcard expansions

There was a request to log out all users from the website based on this code. At first I thought just restarting the server after applying some updates would do it. But no. 

Since our site was based on php sessions and nothing was being saved to the database for user sessions, here is what worked:
First found the path using a small php page which had the line 
php echo session_save_path()
(or phpinfo would have worked?)

then just 
sudo sh -c 'rm -v /var/lib/php/sessions/sess*'

About why just 
sudo rm sess* 

Friday, December 09, 2022

Notes on a simple mailing list written in Google Apps Script

There are lots of examples about mail-merge with Google Apps Script. 

Using Mailchimp for blog updates by email had the problem that only the default feed would work, and not a custom feed as mentioned in my earlier post

So, I've attempted to create a mailing list manager in Google Apps Script. Subscribe and unsubscribe forms are to be done (TBD). Some notes, in addition to the references in the inline comments - 

Thursday, December 08, 2022

concatenating mp4 files without re-encoding with ffmpeg

Following https://ottverse.com/3-easy-ways-to-concatenate-mp4-files-using-ffmpeg/ and https://finance.uw.edu/recmgt/resources/list-your-folder-structure-windows
  • dir *.mp4 /B > filelist.txt
  • In notepad, find/replace VIDEO_ with file VIDEO_
  • ffmpeg -f concat -safe 0 -i filelist.txt -c copy mergedVideo.mp4
After that, speeding up the video 10x using Avisynth to open the file in VirtualDub - the two videos below. The second video's last part seems to have some missing segments, probably because the dashcam's power adapter came out of the 12V socket. I've now replaced it with one which I had purchased earlier, which has a better grip. 




The camera-generated timelapse and other info is at this post.

Saturday, December 03, 2022

preventing related videos on embedded youtube videos

If a youtube video is embedded with the default embed code, after the video plays, youtube shows a selection of "related content" which is usually not from the same channel. According to this thread, we can now only prevent other channel content from being displayed - by adding ?rel=0 to the embed code. Like youtube.com/embed/idOfVideo?rel=0

some Reaper audio cleanup ideas

Use the Ripple Delete tool to enable Ripple Delete either for a single track or for all tracks -


https://www.youtube.com/watch?v=AW5G-60jH34
describes a useful click pop removal using trim tool - we can change the fade-in-out lengths for the trim tool at
Preferences -> Media Item defaults for new items from 10 ms to 50 ms.

And in using this for click-pop removal, we can pinpoint the correct location to use the trim tool by using the Spectrograph view - Spectral Edit -> View Spectrograph. In the track image below, the orange vertical line is the click - 


Some cleaning up tips
https://www.youtube.com/watch?v=Ar4hIbqTzAY
NR etc.

Screenshots from my current settings for audio cleanup and sweetening for voice-overs (VO) - 

1. Noise reduction with ReaFir to remove the background hiss,


2. Gating out background noises


3. Some compression


4. Followed by a little bit of reverb for the vocals.

This earlier post gives the method I have used to do RMS normalization for audio clips, using the limiter and manual control of the limiter threshold by watching the RMS levels on the Master track. 





Thursday, December 01, 2022

adding copyright statement to Moodle footer - Moove theme

There was a request to add a custom content copyright statement to the footer of one of our Moodle sites which used the Moove theme.

The easiest way to add the copyright footer seems to be via the custom CSS box at
https://moodlesite.tld/admin/settings.php?section=themesettingmoove#theme_moove_advanced

Using the technique at

So, in this case, the css added was:

footer#page-footer .supportemail::before {content: "© 2010 - 2022 Our custom copyright statement."} 
 
All the raw SCSS added currently:

footer#page-footer .supportemail::before {content: "© 2010 - 2022 Our custom copyright statement. All rights reserved."}

.card-body {
min-height: 100%;
}
footer#page-footer .copyright  {display:none;}

nav.navbar .navbar-brand .logo img{

max-width:100%;

height:auto;

}

nav.navbar .navbar-brand .logo{

display:inline!important;}