Month: October 2019

Extracting the Transcript from Microsoft Stream Videos

While Microsoft does not provide a way to export the transcript from Stream videos (thus recorded Teams meetings), it is possible to get something a nicer than the select/copy/paste from the transcript box. Click the video settings and select “Show transcript”

Display the browser developer tools – In Firefox, select the “Web Developer” sub-menu from the browser menu and select “Web Console”

This console is often used for displaying errors in a website, but it can also be used to send commands to the browser. There’s a “>>” prompt – click next to it and you’ll have a flashing cursor.

Paste this into the console:

window.angular.element(window.document.querySelectorAll('.transcript-list')).scope().$ctrl.transcriptLines.map((t) => { return t.eventData.text; })

… and hit enter. Another line will appear below what you’ve entered. Right-click on that new entry and select “Copy Object”. Now paste into a text editor or Microsoft Word.

The output could use a little cleanup. You’ll see “\r\n” anywhere there’s a newline. This

Becomes “a new tip to make things quicker. So\r\nshare your knowledge” … you could replace “\r\n” with a space (I find the newlines to be superfluous) or use a regex replacement to replace “\\r\\n” (literal string, the backslash escapes the backslash to retain it) with “\n” (an actual newline)

Each time-stamped bit of the transcript is in a separate set of quotes – I’ve got a quick replacement that takes

",\n "

And replaces it with a newline … so

Becomes

Depending on the target audience … for me, that’s where I stop. To send the transcript to someone else, I manually clean up the spaces and quote before the first line and the quote-comma on the last line.

Android 10 Backup Issue

Pixel XL with Android 10 (build QP1A.191005.007.A1). Enabled Backup, selected a backup account (only one account on the device), and found the ‘Back up now’ button was grayed out. There is a strange work around — temporarily removing the security pin. The ‘Back up now’ button is active, and a backup can be performed successfully.

*But* I have to re-register my fingerprints when the pin is disabled / re-enabled. Which means I’ve got to type my long and complex banking password on the little phone keyboard. Not cool. I was able to back up my phone using ADB but needed to input a passphrase on the device to encrypt the backup. Not sure if there’s something about the screen lock security that requires the backup to be encrypted … which then precludes the magic to-the-cloud backup from proceeding?

To back up device from command line:

adb backup -apk -shared -all -f ./backup.ab

< on device, type a passphrase and approve the device backup>

 

Amazon Music

TL;DR: Lots of content, but UI/UX fail.

The user interface for Amazon Music is terrible and lacks basic functionality (and there’s a disparity of what functionality exists across platforms). The general usability is poor — it is difficult to navigate content, tool tips were not consistently displayed on mouseOver, and there’s no easy way to select a genre and see various artists/albums/releases.

There is no simple way to find and queue music. There is no way to sort albums by release date to identify the latest albums from an artist. There is minimal information about the album displayed when you ‘View album’. You cannot play music to other devices — the search/queue function on the web platform is far better than the functionality in the FireTV app, but I am then stuck streaming to my laptop.

Removing an item from ‘My Music” required too many clicks – the quick actions on the album say ‘Add to My Music’. To remove it required clicking the hamburger button, selecting ‘view album’, clicking another hamburger button, then selecting ‘Remove from My Music’.

We experienced many bugs on the web app when adding an album to ‘my music’ (the album did not appear at all. Or the album did not appear *but* the item count was incremented — so it said there were 6 albums but only five albums displayed. Or the album did not appear, the item count incremented, and one of the already-added albums was listed twice).

When searching for an artist, selecting them in the “artist” section does not list albums from the artist. You have to scroll *past* the ‘artists’ listing and select the artist under “Albums” to view their albums.

I have not been able to find a way to “train” the suggestion algorithm. While I expect the algorithm is trained as we listen to music and possibly skip songs, I would like to be able to select genres or bands that I do not like. There’s no reason to show me four different country music channels if I do not listen to country music.

On the FireTV app, a video history of Biggie Smalls was promoted. We could not find a “Video” section to see what other video content is available.

Microsoft Teams: Cross-posting to multiple channels

Click on “Post in multiple channels”

To post in additional channels, click “Select chann…”

Check off the channels into which you want the post written – this can be a channel in any Teams space where you are able to post messages. Click “Update”.

When your message is posted, an indicator will appear letting everyone know it was posted in multiple channels. No, there doesn’t appear to be a way to see which channels – that’s probably a permission / information leakage nightmare (post something into the “Mass Layoffs” channel that I shouldn’t know exists … I shouldn’t be able to see that channel name). But the glif gives you some confirmation if you think you’ve seen this info elsewhere.

Note – the posts are not linked to each other. If someone replies in one channel, the post in the other channels will not include the reply. So while this is a quick way to disseminate the same information to various teams … you’re starting multiple conversations too.

Also note — there doesn’t appear to be a way to edit cross-posted messages.

Git Log

Git log can be used to get a quick summary of the differences between two branches. The three dots between the branch names indicates you want a “symmetric difference”. That is the set of commits that are in the branch on the left or the branch on the right but not in both branches.

The –left-right option prefixes each commit with an ‘<’ or ‘>’ indicating which “side” has the commit. The –oneline option prints the abbreviated commit ID and the first line of the commit message.

Showing the differences between your local uat branch and the remote uat branch:

D:\git\gittest>git log –left-right –oneline origin/uat…uat

> 961f53a (uat) Merge branch ‘ossa-123’ into uat

> 803096b (origin/ossa-123, ossa-123) Added additional files

> cf9c419 Added initial code to branch

The top line is the most recent commit, the bottom line is the oldest commit that does not exist in both branches. I can see that the uat branch in my local repo is not missing anything from the remote (there are no commits with “<” indicating changes in the remote that do not exist in my local copy) but I have local changes which have not yet been pushed: two code commits plus the merge commit which incorporated the code commits to my local repo’s uat branch. The head of the local and remote ossa-123 branch are at the commit just prior to the merge, so on my local repo that branch has been fully merged into UAT and I just need to push uat up to the remote.

Additional options to enhance output:

–cherry-pick will omit any changes that represent the same changes in both branches (or –cherry-mark to mark those commits with an “=” flag)

–graph uses an ASCII chart to depict branch relationships.

* The three dots mean something different in git diff than in git log. In git diff, mean “what are the differences between the right-hand branch and the common ancestor shared by both the right and left-hand branches”.

Two dots in git diff mean is the differences that are in the branch on the left or the branch on the right but not in both branches.

In git log, two dots displays only commits unique to the second branch. Since commits and differences are not exactly the same thing, two and three dots don’t exactly have the opposite meaning between diff and log. But the meaning is not logically consistent.

 

Postfix IPv6 Loopback Failure

I needed to send email messages from a PHP form, and the web server at work uses Postfix. So … I’m getting Postfix set up to relay mail for the first time in a decade or two 🙂 I thought I’d just have to edit /etc/postfix/main.cf and add “relayhost = [something.example.com]”.

Nope. The service fails to start with nothing particularly indicative — just a [FAILED] status from the init script. Attempting to start Postfix outside of the init script is far more informative:

[lisa@564240601ac2 init.d]# /usr/sbin/postfix start
postfix: fatal: parameter inet_interfaces: no local interface found for ::1

Turns out I’ve got to edit /etc/postfix/main.cf and tell it to use IPv4 only:

# Enable IPv4, and IPv6 if supported
inet_protocols = ipv4

 

Roasting Pumpkin Seeds

Add enough water to fully cover seeds (2 cups, in my case)

Add a tablespoon of salt for each cup of water. Stir and let sit for a few hours (or overnight).

Preheat oven to 400 degrees F.  Boil seeds in the saltwater for ten minutes, then spread across a baking tray.

Bake for 15 minutes, stir to flip seeds over, and make for 5-10 more minutes.

Force majeure and the Township Solid Waste District

We attended a “Candidates Night” event last night where the two individuals on the ballot for a Trustee position spoke and took questions. Where most local elections don’t have much in the way of issues, this particular election may be a proxy vote for the single-hauler solid waste district because the incumbent was involved in the entire process and voted to establish a Solid Waste District that allows only one trash hauler. And indicated that she didn’t see anything wrong with the way the decision was approached.

There were two justifications provided for this decision — both financial. Individuals who have rubbish service will pay less for their service because the Township is essentially facilitating a bulk-purchase agreement. The company is going to drive the same number of miles but 100% of the houses will be their customer. The other stated motivation is reducing road repair costs. Not because the Trustees provided any evidence that rubbish trucks cause a significant amount of damage to roads (although I’ve been told it’s common sense that big trucks cause a lot of damage … there are four, I think, companies that collect rubbish in the area. Commercial rubbish collection is out of scope, so those companies are still going to be driving on some of the roads. What percentage of road damage is done by three rubbish trucks a week compared to vehicle traffic, delivery trucks, snow plows, freeze/thaw cycles? And that’s assuming the single hauler doesn’t need to increase the number of trucks/trips to collect all residential waste — which I doubt is true. We’re more likely to net remove one or two large trucks a week from the roads.). But when I asked what metrics would be provided to show that this cost savings would be realized, the incumbent candidate replied “I don’t think residents want to fund an expensive study about what roads needed repairs and how much it costs”. Which is a senseless non-answer — they’ve got a projected service department budget for next year. And hopefully the year after that. They’ve got historic actual numbers for decades. Take next year’s actual and compare it to the budget. How’s that compare to, say, the difference between last year’s actual and forecasted budgets?

But the oddest part of the night was when a resident asked about people whose existing contracts are a problem — either their current rubbish service will stop collecting trash a month before this single-hauler contract begins, their annual contract is up a month or three before the single-hauler contract begins and they’re not going to be able to renew, or their contract extends beyond the single-hauler start date. The first two scenarios are answered easily enough — the company that’s been chosen as the rubbish collector has agreed to start collecting “early” at rack-rate. So you “get” to buy service from the company you didn’t want at the price you didn’t want. The incumbent indicated that people whose contracts extend beyond the single-hauler start date won’t have to pay early termination penalties because of force majeure. Now maybe she’s actually seen residential contracts from each of the rubbish collectors that operate in this Township. We haven’t had rubbish service for years because we compost & recycle. The remaining trash (generally Styrofoam), we can drop off once a year at the county dump for like 1.50$. But in the contract we did have, force majeure was specifically protection for the trash hauler — they are not in breach for failing to collect rubbish in the middle of a hurricane, during a strike, etc. Courts tend to interpret force majeure clauses narrowly. If the hauler wants to push the issue … I doubt there’s a clause about government action freeing the resident from fulfilling their contractual duties. You’d be making an argument under common law contract doctrine.

But there’s no need to put yourself in a defensive position. The hauler will elect either to cease operation in the Township or incur penalties for continued residential rubbish collection. As a customer, you aren’t the one seeking to breach the contract. The hauler’s failure to act on their contractual duties may fall under a specific item within a force majeure clause. Or they may consider their duty voided under “frustration of purpose”. Call it “impracticability” because of the fines. It’s not like a resident needs to fight to compel their old hauler to continue their contractually-obligated duties that the hauler needs to defend their withdraw as a specifically permitted action. A resident needs the hauler to be the one who withdraws from the contract.

Testing Procedural Code with PHPUnit

You can use PHPUnit to test procedural code — in this case, I’m testing the output of a website. I have some Selenium tests for UI components but wanted to use the shell executor for functional testing. In the test code, you can populate the _SERVER and _POST (or _GET) arrays and simulate the web environment.

<?php
    namespace phpUnitTests\CircuitSearch;
    class CircuitExportTest extends \PHPUnit_Framework_TestCase{
        private function _execute(array $paramsPost = array(), array $paramsServer = array() ) {
            $_POST = $paramsPost;
            $_SERVER = $paramsServer;
            ob_start();
            include "../../myWebSitePage.php";
            return ob_get_clean();
        }
        public function testUsageLogging(){
            $argsPost = array('strInput'=>'SearchValue', 'strReportFormat'=>'JSON');
            $argsServer = array("DOCUMENT_ROOT" => '/path/to/website/code/html/', "HOSTNAME" => getHostByName(),
                                "SERVER_ADDR" => getHostByName(php_uname('n')), "PWD" => '/path/to/website/code/html/subcomponent/path');
            $this->assertEquals('{}', $this->_execute($argsPost, $argsServer));
        }
    }
?>

Running the test, my web output is compared to the static string in assertEquals. In this case, I am searching for a non-existent item, nothing is returned, and I expect to get empty braces. I could use AssertsRegExp or or AssertsStringContainsString to verify the specifics of a real result set.