Friday, November 21, 2014

Remove unwanted results and other garbage from google searches

Do I have to even explain why this is useful?  I would just assume that people shouldn't naturally enjoy having their daily tasks obstructed by the injection of useless garbage into the information they're trying to parse, but the fact that part of this solution addresses social media links tells me this is probably not the case.

As usual, YARIP comes to the rescue.  To get rid of the top, bottom, and side ads:
//div[@id='tvcap']
//div[@id='bottomads']
//div[@id='rhs_block']
To get rid of extended results boxes for local business locations:
//div/li[@id='lclbox']
To remove all listings from a particular website from the search results:
//li[child::div/div/div/div/cite[contains(., 'pinterest.com')]]
//li[child::div/div/div/div/cite[contains(., 'facebook.com')]]
//li[child::div/div/div/div/cite[contains(., 'twitter.com')]]
//li[child::div/div/div/div/cite[contains(., 'huffingtonpost.com')]]
//li[child::div/div/div/div/cite[contains(., 'pitchfork.com')]]
While it's certainly nice to be able to slap that useless trash off the visible web, there are other more useful strategies for single-site blocking.  How about getting rid of sites that just dilute the results with repeated similar pages?
//li[child::div/div/div/div/cite[contains(., 'alibaba.com')]]
Google does provide several different forms of "extended results", such as the local business listings, maps, conversion utilities, image search previews, and youtube items.  Each of these can also be blocked depending on what irks you and what your browsing habits cause you to encounter.

Exclusion through YARIP is also a quick cure for frustration on any other sites that tend to return volumes of irrelevant or unwanted results for specific searches or where available search tools don't allow exclusions.  One of my current favorite applications is dealing with poor search refinement tools on internet job boards.  For example, perform case insensitive exclusion with in the job title field on LinkedIn:
//li[child::div/h3/a[contains(translate(., 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz'),  'sales engineer')]]
//li[child::div/h3/a[contains(translate(., 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz'),  'senior')]]
//li[child::div/h3/a[contains(translate(., 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz'),  'federal government')]]
//li[child::div/h3/a[contains(translate(., 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz'),  'information systems')]]
//li[child::div/h3/a[contains(translate(., 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz'),  'information technology')]]
//li[child::div/h3/a[contains(translate(., 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz'),  'executive')]]
Of course, each site and set of search tools has its own limitations and it's the conflict between these limitations and your usage patterns that will dictate how useful any of this might be. 

Matlab: Encode images in audio spectrum

UPDATE: This sandbox script has evolved into the functions im2spectrogram() and text2spectrogram() in my aptly named Matlab Image Mangling Toolbox

A while back, I got bored and was looking for various ways to shove pictures where they didn't belong.  Among simpler ideas like concatenation, arbitrary character encoding schemes, and spreadsheet conversion, I tried my hand at conversion to audio.  Using this particular STFT/ISTFT set of tools, as well as basic parts of the image processing toolbox, I threw together this kludge:
%% simplified automatic spectrogram obfuscation

clc; clear all;
format compact;

% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

projdir='/home/assbutt/projects/imagepooper/';
inpict=imread([projdir 'test.jpg'], 'jpeg');
outwavname=[projdir 'soundpicture.wav']; 

% typical image adjustments
invert=0;           % invert if 1
flip=0;             % flip horizontal if 1
bluramt=1;          % gaussian blur amount (approx 0.5-10) (zero for no blur)
blurrad=3;          % gaussian blur radius (approx 2-5)

alteraspect=0.80;   % correct for viewer distortion
padbar=0.08;        % relative height of top padding (H=1+padwidth)
volume=1;           % adjust signal volume (will clip beyond unity)

% add blur to reduce bright edge artifacts
% use nonzero padbar to keep image below mp3 cutoff (0 for none)

% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

% desaturate color images (choose method if desired)
if (ndims(inpict) == 3); inpict=mrgb2gray(inpict,'default'); end

% invert where requested
if (invert == 1); inpict=255-inpict; end

% flip where requested
if (flip == 1); inpict=fliplr(inpict); end

inpict=flipud(inpict);      % flip image (low-f on bottom)
inpict=imadjust(inpict);    % set image contrast

magicnum=660;       
inaspect=length(inpict(1,:))/length(inpict(:,1));
inpict=padarray(inpict,[round(padbar*length(inpict(:,1))) 0],'post'); 
inpict=imresize(inpict,magicnum*[1 alteraspect*inaspect/(1+padbar)]);

if (bluramt > 0);
    h=fspecial('gaussian', blurrad*[1 1], bluramt);
    inpict=imfilter(inpict,h);
end

nft=length(inpict(:,1))*2-2;
h=nft; 
samplefreq=44100;
[x,t]=istft(inpict,h,nft,samplefreq);
[stft, f, t_stft]=stft(x, nft, h, nft, samplefreq);

figure(1)
subplot(1,2,1); plot(t, x);
subplot(1,2,2); imshow(flipdim(real(stft),1));
cmap=colormap('gray');
colormap(flipud(cmap))

xp=x/(max(abs(x))*1.0001)*volume;
wavwrite(xp, samplefreq, 32, outwavname)
Of course, one kind of has to guess at the transform size a person might use when configuring the script parameters, otherwise the arbitrariness of frequency-time scaling makes it basically impossible to enforce any first-view aspect ratio. Most photographs sound pretty terrible, though feeding it high-contrast images with little white content produce nicer audio sweeps.

We take this image
And the script poops out an audio file with a spectrogram like this (using foobar2000)
View your output with foobar2000, audacity, or baudline.  The behavior could probably be improved, but this script is just a novelty.  Nobody cares. I don't care anymore either.

At the time I made this, I also pooped out a version that encodes text strings as a marquee in the top end of the frequency spectrum.  The output is a sound file containing the text.  Simply mix one or more of these files with some music to obtain a song full of hidden inaudible text. I probably should've just made the core of these scripts modular, but I wasn't sure what parts would be common.
%% create text marquee for spectrogram

clc; clear all;
format compact;

% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

instring='put a whole shitload of text here';

projdir='/home/assbutt/projects/imagepooper/';
outwavname=[projdir 'soundpicture.wav']; 

% typical image adjustments
alteraspect=0.80;   % correct for viewer distortion
textheight=0.03;    % relative height of text
textlocation=19000; % frequency center of text
volume=0.1;         % adjust signal volume (will clip beyond unity)

bluramt=5;          % gaussian blur amount (approx 0.5-10) (zero for no blur)
blurrad=3;          % gaussian blur radius (approx 2-5)

% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

magicnum=660;       
samplefreq=44100;

inpict=uint8(text2im(instring));
inpict=255*(1-inpict);

toplim=samplefreq*(1-textheight/2)/2;
botlim=samplefreq/2-toplim;
if (textlocation > toplim); 
    textlocation=toplim; disp('supramaximal text center');end
if (textlocation < botlim); 
    textlocation=botlim; disp('subminimal text center');end

inaspect=length(inpict(1,:))/length(inpict(:,1));
inpict=imresize(inpict,magicnum*textheight*[1 inaspect]);
botpad=floor(magicnum*((2*textlocation/samplefreq) - textheight/2));
toppad=ceil(magicnum*(1-textheight)-botpad);

inpict=padarray(inpict,[0 10],'both'); % pad ends
inpict=padarray(inpict,[toppad 0],'pre'); % top pad
inpict=padarray(inpict,[botpad 0],'post'); % bottom pad
inaspect=length(inpict(1,:))/length(inpict(:,1)); % recalculate
inpict=imresize(inpict,magicnum*[1 alteraspect*inaspect]);
inpict=flipud(inpict);      % flip image (low-f on bottom)

if (bluramt > 0);
    h=fspecial('gaussian', blurrad*[1 1], bluramt);
    inpict=imfilter(inpict,h);
end

nft=length(inpict(:,1))*2-2;
h=nft; 
[x,t]=istft(inpict,h,nft,samplefreq);
[stft, f, t_stft]=stft(x, nft, h, nft, samplefreq);

figure(1)
subplot(1,2,1); plot(t, x);
subplot(1,2,2); imshow(flipdim(real(stft),1));
cmap=colormap('gray');
colormap(flipud(cmap))

xp=x/(max(abs(x))*1.0001)*volume;
wavwrite(xp, samplefreq, 32, outwavname)

Multiple rows of text (one is flipped) mixed into a song
Of course, I only noticed after the fact that I had reinvented the wheel.

Wednesday, November 19, 2014

Matlab: Compile all open figures as a single pdf

As part of my network status log processing script, I needed a way to export weekly overview plots in a format that could be used to convey problems to other people at a glance.  The larger body of the script is a block-mode kludge which does the actual log file processing and plotting in whatever manner I choose.  The final block is a brief bit which rolls the current figure windows into a single pdf.
%% print plots to pdfs; use pdfshuffler to cat or fix rotations

filebasename='/home/ikilledsuperman/plot_%d.pdf'
outputname='/home/ikilledsuperman/outputlogfile.pdf'

m=length(findall(0,'type','figure'));
filelist=cell(m,1);
for n=1:1:m
    figure(n);
    set(n,'PaperUnits','normalized');
    set(n,'PaperPosition', [0 0 1 1]);  %fit to page
    filelist(n)=cellstr(sprintf(filebasename,n));
    print(gcf, '-dpdf', sprintf(filebasename,n));
end

delete(outputname)
append_pdfs(outputname, filelist{:});
delete(filelist{:})
As the comment says, pdfshuffler can be used to put the finishing touches on any generated pdfs.  Close any unneeded figure windows with 'close all'.  This script makes use of append_pdfs.  

Friday, November 7, 2014

Reduce risk of mains flashover on a marginal PCB assembly

Thunderstorms are probably of little concern to most people, but lightning has an absurdly strong tendency to destroy my equipment.  Despite robust grounding and protection measures, hardly a year has gone by without loss of televisions, phones, modems, motors, motherboards, or HVAC controls.  It's for this reason and the occasional phase loss on the three phase service that I was faced with a charred phase protection relay.
Kailn TG30s
The particular device was another chinese Ebay special: the Kailn TG30s.  The relay is a compact rail-mountable package and had performed suitably under test.  The internals were quite similar to a quick and dirty design I had sketched up before realizing that the autumnal comfort of my sustained apathy in purposelessness was more valuable than the $8 needed to buy the part from china.  Less than a week after installation, a storm rolled through and blew it to smithereens along with an unrelated compressor motor.

The relay is constructed from two boards soldered to each other at right angles with metal support straps on either side.  The mains sensing/power networks are combinations of resistive and reactive dividers in series with protection thermistors.  The capacitors and thermistors are through-hole devices placed in a very compact arrangement, though creepage distances do meet the IEC61010-1 minimum spec for reinforced insulation. 

Inside the case, there is nothing but black soot and the smell of burned epoxy.  After a bit of degreaser and soap, the failure sequence became apparent. A few observations led me to my conclusions:

  • Extensive charring on the top side near the mains terminals and thermistors
  • Fused traces leading to divider networks, but no caps were punctured
  • Deep burning and metallizing of case adjacent to PCB near thermistor leads
  • The device tripped a 30A thermal breaker nearly an entire second after the lightning strike
  • PCB is contaminated with flux, solder balls and stray solder from post-line hand assembly
  • Thermistor and cap leads are trimmed relatively long


Missing traces and charring down to the glass (after cleaning)

Metallization and charring of plastic case (after cleaning)
My guess is that the strike flashed over on the board near the terminal strip or thermistor leads, either between untrimmed leads or possibly along the board surface.  In a confined case, with freshly carbonized and metallized surfaces everywhere, conduction continued long after the strike impulse passed, allowing ample time for deep charring and thermal loading of the main breaker.

I should clarify that the device wasn't entirely to blame for the failure.  While inexpensive, it did get hit with a strike impulse that was also able to damage other equipment.  This venture is more about using my knowledge to add value to the inexpensive so that I can keep motors protected while not going broke (as fast).  It's a simplistic exercise in general techniques for enforcing isolation when voltages are high or when humidity or environmental contamination becomes a risk.  

  • Trim and ball component leads
  • Clean the board of residues and solder fines
  • Apply conformal coating

When the new device arrived, I immediately popped it open and looked it over.  The build finish was similar: long untrimmed leads, no-clean flux residues and solder fines.  I clipped the component leads short and added sufficient solder to ball the joints.  After thoroughly cleaning the assembly, I brushed on a couple applications of conformal coating in the board areas associated with mains-level voltages.  Attention should also be paid to keeping the coating from encroaching closer than a few mm from the board edge, as the PCB fits into a retainer groove in its case.  I wanted to make sure that the gap between the PCB edges was sealed, so I allowed the coating to flow through from the top before coating the bottom.  In this manner, air entrapment was avoided.

Coated top side (note balled terminal strips)
New board (top) after balling and coating.  Old board (bottom) showing untrimmed leads and missing traces
The coating material I used is not a product marketed for the purpose.  I used a solution of clear Dap Sidewinder sealant diluted with xylene.  Sidewinder is (as far as I know) a modified silicone.  The cured material has some excellent properties -- and no, it's not corrosive to the assembly as an acetoxy cure RTV silicone would be. With a bit of patience and stirring, the resin can be diluted to consistencies ranging from honey to warm maple syrup.  A brushed coating is relatively self-leveling and will dry to the touch in a few hours, though a day or so should be allowed for full curing. 

Monday, October 20, 2014

How to destroy a fake FOTEK SSR

In the process of developing a kiln controller on the cheap, I had opted to purchase a cheap Chinese solid state relay from ebay. I've used cheap relays for other projects, and they had worked well. I purchased a grey FOTEK branded unit, as it had nice robust barrier terminals, unlike many of the other cheap options.

Bewaaaaare
After finding out that the absolute minimum input voltage was closer to 5.0-5.3 volts than the stated 3 volts, the doubts began to surface -- but what could go wrong?  The use case was marginal, but not unreasonable.  The system operates at 208V; the relay is rated for 380V.  The operating current is less than 48A, with a cold current less than 53A.  The relay is rated for 60A.  That's less than a conservative 75% derating, but why stick to arbitrary derating factors when an upper boundary on the cold current is known?

All started well in the first cycle test.  The unit ramped up to a test setpoint and we observed the overshoot.  Either the time constant in the feedback path was three times what I'd estimated, or the relay thyristors were still partially conducting... POP.  What was that? Soon the PV fell below the setpoint and the relay driver came on once more... POP.

A bit embarrassed and reluctant to spend a (relatively) lot of money for a Crydom or Gavazzi, I headed back to the internet for options.  Somewhere along the way, a chisel and bandsaw attacked the failed SSR and a few interesting details dripped onto the pavement around its body.

Fused leads and torn trace; melted solder blown through vias

Exploded via and opto, stray solder flash and char
The PCB traces carrying the main current path are 1mil thick, 150 mil wide.  To some degree, the solder from hand-assembly does serve to increase sectional area, but I can't imagine anything more than 25A wouldn't start melting things. The side of the relay case had been blistered from the heat, and liquid solder had been forced between the PCB and the potting, spraying out through cracks and likely shorting the output at least momentarily.

Part of one of the triacs
The output stage is composed of discrete thyristor packages screwed to the backplate.  I could tell this much from the screws visible externally.  I haven't gutted many SSR's, but I imagine a more reliable approach for high-current units would be direct-bonded chips.  Still, my first guess when seeing two screws was to think it was two antiparallel SCR's.  Nope.  It's two CTA24-800 clones (triacs) in parallel without any means of enforcing current sharing (other than a common heat sink).  I should point out that even in the ideal scenario, that only amounts to 25Ax2=50A worth of current capacity, not 60A.  Curiously, the FOTEK product pdf for SSR50DA has transient current capacity curves strikingly similar to twice that of a mounted CTA24-800.  I'm curious to know if they also use paralleled discrete output triacs or if that's just a consequence of a coincidentally similar thermal impedance.

The remnant internals of the triacs can be inspected and tested to clearly indicate that they are the insulated-tab variant.  Considering a junction-case thermal resistance of 1.7 K/W (from STmicro BTA24) and an interface thermal resistance of about 0.20-0.25 K/W for the TO220 insulated tab packages, the overall junction-case thermal resistance for the SSR could be as much as 0.975 K/W -- let's just say 1 K/W.  This is significantly higher than the thermal resistances listed for other SSR's in the 50A class -- by as much as a factor of two.  With an input of 1.2 W/A at 40°C, one needs a 0.3 K/W heat sink to keep the junction temperature safely below 125°C at the limiting current of 50A.  When it's the thermal resistances internal to the assembly that are so significant, it may be difficult to notice an excessive operational condition; the heat sink temps would remain relatively low. Overheating would indeed contribute to the likelihood of a stuck relay.

My casual guess at what happened was that one of the triacs remained on after the input went low, a condition made more likely if one had been hogging current.  This resulted in the failure of the stuck triac.  When the input signal reappeared, the remaining device destroyed itself, blowing out the optocoupler in the process.

Note position of R5 and suggested alternate location
Interpreting the schematic from the board is trivial, though a few curiosities appear.  The series input circuit ensures that the device will not trigger at 3v input.  At the rated 5mA threshold current for the MOC3063, the input voltage would indeed need to be higher than 5v.  The FOTEK device pdf shows a parallel input structure and specifies a minimum ON transition voltage of 2.4v.

I found the location of R5 to be curious.  Its manner of connection to the snubber network seems a bit odd.  The resistor actually looks as if it were improperly installed through a via in this node, as the pad spacing is too small for the device to properly fit.  There is a stub trace with an unpopulated PTH nearby which connects to the AC2 node.  The spacing is more appropriate in this location, so this may be an alternate or a defect.  It may also be that the PCB is used for multiple layouts.

It's also worth noting that the trace spacing reduces the input-output isolation distance to roughly 20 mil.  I haven't checked, but even under thin coating of epoxy, I doubt that meets the 2.5kV isolation spec.

So what are the actual capabilities of this thing?  If one is able to trust that the components (triacs, optocoupler) meet their individual specifications, I would still feel reluctant to trust this relay above about 20A at 240V.  I don't trust the configuration to share current reliably between triacs, so I'd derate it to the capacity of a single component.  Even still, one needs to consider the added thermal resistance caused by the packaging as mentioned before.  The signal voltage range would be limited to an inconvenient 5.5v to 12v, as restricted by the series input structure.  The extra indicator LED increases the minimum voltage to reach a reliable trigger current, and it also restricts the maximum allowable current.  While the optocoupler can accept up to 60mA forward current, the indicator won't likely be reliable at 300% of its absolute maximum current.  For people wanting to drive it directly from a microcontroller IO pin, this would probably cause problems as it did for me.  At 5v, the relay may trigger unreliably because the opto would be operating near or below its specified trigger current.  Operating at voltages slightly above 12v would probably be okay, but 32v is asking for trouble in my opinion.

In the end, the device design is a functioning SSR, but it is not capable of performing to the specified capacity.  I'm curious to know how the 100A or 600V units are constructed.  As I mentioned, I've used cheap chinese SSR's before; perhaps for a 25A relay, all this gimmickry doesn't impact the performance as much.  Without knowing the details of construction or being able to trust the specifications, there is no reliable method to use these devices within their actual range of functionality.  There are other stories online of fake FOTEK SSR's sticking on or melting.  Hopefully I can contribute a little bit of information to explain the failure beyond "it was cheap". 

Kill internet trolls with fire

Well maybe it's not actual fire, but it certainly gives me a warm feeling inside.

Do you frequent any sites where the user comment section is overrun with trolls, plants, and paid shills? Are you sick of their comments reminding you that they remain capable of breathing? Use YARIP to eliminate all their comments from view. Just use Firefox's element inspector (use the right-click menu) to take a peek at the local structure and put together an appropriate XPATH to use in YARIP.

For example, delete entire posts based on a partial name match on reason.com:
//li[child::p/strong[contains(., 'Viagra')]]
Or delete just the post content based on a full name match on zerohedge.com:
//div[child::div/b/a[@href="/users/bangalore-equity-trader"]]/div[@class='comment-content']
Adapt to suit your browsing habits.

Always expand YouTube video descriptions

I never understood the point of creating website content and then persistently hiding it from users. Do stores put their merchandise on top of tall greased poles to improve sales?  With Google continually finding ways to obfuscate interfaces for no clear reason, I'm reluctantly conditioned to lose hope in the suspicion that the defining characteristic of the modern web is waste without reason -- but masturbatory social media should have made that conclusion obvious long ago.  It's a world of greased poles either way. 

Today's drop in the sea, the pinprick distracting from a thousand knife wounds, is the YouTube video watch page.  Why hide the video description? Fix that fucking shit with YARIP.  The following ugly attribute deletion expands the description, and the second XPATH removes the more/less buttons.
//div[@id='action-panel-details']/attribute::class
//div[@id='action-panel-details']/button
As an alternative and more appropriate approach, instead of using the first line to delete the class attribute for 'action-panel-details', YARIP can be configured to perform an attribute substitution.  From the YARIP's page manager, under the attribute tab, the class attribute for the 'action-panel-details' element can be simply set to
'action-panel-content yt-card yt-card-has-padding yt-uix-expander'
As a bonus, try this in YARIP to get rid of a fraction of the unrelated garbage in the sidebar. 
//li[child::a/span[text()="Recommended for you"]]
I'd like to find a way to fix the comment sorting, but I haven't had much luck so far.  It's not exactly as if I know what I'm doing.

Alternatively, the expansion itself can be accomplished using a userscript.   I use Scriptish, but Greasemonkey may also work. 
// ==UserScript==
// @name          YouTube Show Description
// @description   show the full description for fucks sake
// @namespace     http://www.stopbreakingyoutubeyouassholes.com
// @include       https://www.youtube.com/watch?*
// ==/UserScript==

document.getElementById('action-panel-details').className = 'action-panel-content yt-card yt-card-has-padding yt-uix-expander';

Monday, September 22, 2014

Make sorting media files marginally easier

If you're like me, you have a hard drive with little scattered oxbow directories filled with the varied sediment of entertainment media strata.  These dark swamplands occasionally need draining and the value of each soggy log and bog frog within must be appraised.  The trick is to minimize the time required to hold one's breath.

The dominant populations one may find in such a data-wallow may include:
  • product pdf's and datasheets
  • books and reference documents
  • videos of things exploding into flames
  • good old-fashioned porn
  • music videos from YouTube
  • bad old-fashioned porn 
  • esoteric music files from atypical sources
  • graphs documenting the aggrandizement of a veiled fascism
  • cat pictures
Whether it's by lack of self-discipline or because you have a good excuse, these things tend to collect and need occasional sorting and cleanup.   Some things like video and audio tend to be tedious to sort, not only because the files take time to review, but often because their sources leave them poorly named.

Recently I felt the need to abuse myself by sorting a folder full of shit video files I wasn't in the mood to watch.  It so happened that they were mostly rips from various flash players and all had meaningless hash salads for filenames.  Because of this, manually picking through each one becomes tedious.  Tab-completion is defeated; it's difficult to even remember which filename you're trying to target.  I put together a crude script to automate the review, renaming, and categorization of the ~200 files.

#!/bin/bash

SAVEIFS=$IFS
IFS=$(echo -en "\n\b")

if [ ! -d "funnyshit" ]; then mkdir funnyshit; fi
if [ ! -d "depressingshit" ]; then mkdir depressingshit; fi
if [ ! -d "infuriatingshit" ]; then mkdir infuriatingshit; fi
if [ ! -d "junk" ]; then mkdir junk; fi

for file in $(ls -1); do 
    echo -e "\033[0;36mPlaying: $file\033[0m " 
    mplayer $file --really-quiet
    sleep 1

    whiptail --inputbox "Filename Editor\nESC to skip this file" 8 60 "$file" 2>tname
    if [ $? != 0 ]; then 
        rm tname 
        echo -e "\033[0;36mSkipping $file\033[0m" 
        continue
    fi 
    newname=$(cat tname); rm tname

    if [ $newname != $file ]; then 
        mv $file $newname
        echo -e "\033[0;36mChanged $file to $newname\033[0m" 
        file=$newname
    else
        echo -e "\033[0;36mDid not change file name\033[0m"
    fi

    whiptail --radiolist "where to put it" 15 50 8 "funnyshit" "" on "depressingshit" "" off "infuriatingshit" "" off "junk" "" off 2>tdir
    if [ $? != 0 ]; then rm tdir; break; fi
    destination=$(cat tdir); rm tdir

    echo -e "\033[0;36mMoving $file to $destination\033[0m"
    mv $file $destination/
done

IFS=$SAVEIFS

The script just blindly picks up every file in the directory and plays it.  Non-video files can be manually skipped or sorted if they're identifiable.  Video files are played with Mplayer.  Once an evaluation is made, user hits escape to terminate Mplayer, and a dialog prompts for an optional new name and a choice of output directory bins.

There are a lot of ways to make this more flexible and useful in other tasks or with other filetypes, but I hope it's obvious by now that i don't really care any more.

Monday, September 15, 2014

The mysterious shrinking terminal window

Terminator is a nice little tool for managing multiple gterm sessions within a single window.  I find the use of split screens very comfortable.  Terminator allows the creation of layout profiles to automate the setup of a particular tab/split configuration.  These can be selected with the --layout option when launching Terminator.  The problem with this is that at least under my current environment (Mint 14/XFCE), the resultant window spawns and then shrinks down as small as possible.  It's hard to describe, so maybe i should include a graphic. 

Whaaaaaat
I recall having read about this phenomenon elsewhere, though i don't recall if a solution or workaround had been revealed at the time.  Since i was issuing these commands primarily via a long, ugly session recovery script, my first hack-around solution was to use wmctrl to subsequently restore the window geometry.  This was fun to watch, but the better workaround is to just use the gnome geometry options from the start.
terminator --layout="yourlayoutname" --geometry=1280x977 
That was a pretty simple solution to a rather comical problem.

Saturday, September 13, 2014

The foolproof way to do screen capture

Years ago, i did my first screen capture experiment. I put together an ugly pair of scripts to take screenshots at infrequent intervals, capturing the essence of a slow and boring bit of work in GIMP. I surmised at the time that there are probably lots of better ways.

Fast forward to recent months. I was trying to demonstrate the use of Matlab to encode images and text into audio spectra. I needed more typical framerates and i wanted companion audio, so i figured that it was the time to search for that "better way". In Mint 14, i had a lot of options suggested by forums and by software sources:
  • Istanbul -- Ogg video desktop recorder 
  • RecordMyDesktop -- Another desktop recorder 
  • Kazam -- Yet another 
  • VLC -- has a mode for capturing the desktop 
Unfortunately, none of these programs actually worked properly. Kazam crashes and often produces corrupted output. Istanbul produces choppy output if it actually saves anything at all. RMD and VLC are similarly broken on my system. IIRC, parts of the bugginess comes from particular ogg or python library versions, and perhaps things work differently on a more up-to-date system. I don't care. They're broken on mine.

Since none of these tools capture audio correctly anyway, i cut my losses and decided to capture video only.
ffmpeg -f x11grab -r 25 -s 1280x1024 -i :0.0 -sameq bullshit.mp4
... of course, you can do it with avconv instead of ffmpeg:
avconv -f x11grab -r 25 -s 1280x1024 -i :0.0 -same_quant bullshit.mp4
It's simple, it works, and it's faster and more flexible than some of the other options.

Friday, September 12, 2014

Open documents in an application on a different X display

When running multihead with separate servers for each screen (Zaphod mode, not Xinerama), there comes occasional need to launch applications on a display other than the one currently in use.  This comes up in various tasks:
  • Launch an app on screen A from a panel launcher on screen B
  • Place application windows on various screens with a session recovery script
  • Open a URL in a web browser from an application on a different screen
It's the third task which is the solution to a problem I encountered when setting up Thunderbird.  Unless Thunderbird is on the same X display as the browser, It will fail with the error

Firefox is already running, but is not responding. To open a new window, you must first close the existing Firefox process, or restart your system.
YOU BROKE IT, MILLIE!

I mention Thunderbird, but this could be Evolution or some other app. The target application doesn't have to be a web browser either.  In fact, if your browser and mail client are on different screens, the browser won't be able to open mailto links in the mail client either.  In these cases, the core of the solution is to temporarily change the $DISPLAY environment variable.
#!/bin/bash
# allows thunderbird to pass URLs to a browser on a different $DISPLAY

cdisp=$DISPLAY
DISPLAY=:0
palemoon $1
DISPLAY=$cdisp
Change the executable name and display numbers to suit. 

For Thunderbird specifically, enabling the use of this script requires changing the attachment handler settings.  Since there is no way to add new entries in the Attachments section of the Preferences dialog (on TB 24), open about:config and set network.protocol-handler.warn-external.http and network.protocol-handler.warn-external.https to TRUE. This forces a user dialog when a link of either type is clicked. Select the new script in both cases. Once successful, the dialog shouldn't pop up again. The resultant settings generated by these actions are visible/editable in the Attachments section of the Preferences dialog. 

It's worth noting that applying these methods to Firefox will open the URL in the existing Firefox session. If you expect to open a new Firefox window on another screen, you're pretty much shit out of luck as far as i know. There are certainly some dodgy workarounds, though.

Thursday, September 11, 2014

Selectively Invert workspaces for readability

UPDATE October 2019: The script has been updated for multirow operation, better window identification, and reduced execution time.

In my recent experiences dealing with the rapid progression of cataracts and vision loss, I had to make a lot of adjustments to my computing environment to accommodate for the diffusion.  In my sight, bright regions in the field of view bleed over dark areas and obscure them extremely effectively.  The diffusion averages the brightness of the entire visual field, nearly eliminating local contrast.  This pretty much means that the thin black lines of text on a white background disappear.  White characters on a dark background bleed as well, but the impact on readability is much smaller.

OH GOD THE BRIGHTNESS

I do understand that other individuals with cataracts claim different experiences regarding contrast preference; perhaps it is the differences in the types of cataract structure that explains those things.  Regardless, my overall goal is to control bright areas of my workspace and enforce a relatively high contrast light-on-dark regime. 

This new quest covered the normal bases:
  • GTK 2/3 theme
  • QT4 color settings
  • Desktop wallpaper
  • Custom user styles for Firefox/Stylish
... but still, there are things that can't be properly themed.  Wine applications, as well as certain things like virtual machines and Matlab/Simulink all appear as horrible fuzzy bright rectangles of pain.  What the hell does one do about those?

If i could invert an individual window's colors, that would be sufficient.  The only method i can recall to do this is with Compiz, and that's not going to happen for various reasons.  Under Mint 14/XFCE, the only thing i could think to do is invert the entire X display.  Since i normally run these offending applications maximized, the amount of remaining bright area is mostly restricted to the xfce4-panel area at the top.  Inverting the entire display can be done with xcalib, but unless one wants to get blinded every time the workspace is switched, the application of the screen inversion should be automated.

#!/bin/bash

# This is an ad-hoc replacement for wm-specific workspace switching (ctrl-alt-left, ctrl-alt-right, ctrl-alt-number)
# Script conditionally inverts X display on workspaces containing offending windows
# Helps to enforce dark, hi-contrast UI despite unthemeable windows (virtual machines, wine apps, etc)
# Works best when applications are run full-screen
# directional usage: switchworkspace left|right|up|down
# explicit usage: switchworkspace workspacenumber

# this version is about 5% faster than the old 1-D version
# and does not invoke gamma enforcement and inversion checks at endpoints

# specify the workspace/pager layout
nwsx=3 # number of columns
nwsy=3 # number of rows


current=$(wmctrl -d | sed -n 's/^\([0-9]\+\) *\*.*/\1/p')

if [ $1 ]; then
 ex='^[0-9]+$'
 if ! [[ $1 =~ $ex ]]; then
  # argument is not a number
  if [ $1 == "right" ] || [ $1 == "left" ]; then
   if [ $1 == "right" ]; then
    if [ $(($current % $nwsx)) == $(($nwsx-1)) ]; then
     exit
    else
     target=$(($current+1))
    fi
   elif [ $1 == "left" ]; then
    if [ $(($current % $nwsx)) == 0 ]; then
     exit
    else
     target=$(($current-1))
    fi
   fi
  elif [ $1 == "up" ] || [ $1 == "down" ]; then
   if [ $1 == "down" ]; then
    if [ $(($current / $nwsx)) == $(($nwsy-1)) ]; then
     exit
    else
     target=$(($current+$nwsx))
    fi
   elif [ $1 == "up" ]; then
    if [ $(($current / $nwsx)) == 0 ]; then
     exit
    else
     target=$(($current-$nwsx))
    fi
   fi
  else
   echo "unknown direction"
   exit
  fi
 else
  # argument is numeric
  total=$(wmctrl -d | wc -l)
  if [ $1 -gt $total ]; then
   target=$(($total-1))
  elif [ $1 -lt 1 ]; then
   target=0
  else
   target=$(($1-1))
  fi
  
  if [ $current == $target ]; then exit; fi
 fi 
else
 echo "must specify a workspace number or direction (right/left/up/down)"
 exit
fi


# add other applications by window title keyword or window class
# if multiple windows match, all corresponding desktops will be affected
winlist=$(wmctrl -lx)
inv[0]=$(echo "$winlist" | grep "XFramePeer.com-mathworks-util-PostVMInit" | cut -d \  -f 3)
inv[1]=$(echo "$winlist" | grep "XFramePeer.MATLAB" | cut -d \  -f 3)
inv[2]=$(echo "$winlist" | grep "eagle.exe." | cut -d \  -f 3)
inv[3]=$(echo "$winlist" | grep "scad3.exe." | cut -d \  -f 3)
inv[4]=$(echo "$winlist" | grep "femm.exe." | cut -d \  -f 3)


function contains {
 case "${inv[@]}" in  *"$1"*) 
  echo 1 
  return 1 ;; 
 esac
 echo 0
}

wmctrl -s $target

A=$(contains $target)
B=$(contains $current)

#echo $current $target $A $B

if [ $A == 1 ] && [ $B != 1 ]; then

 xcalib -i -a
elif  [ $A == 1 ] && [ $B == 1 ]; then
 return
else
 xcalib -clear

 # i have gamma presets for each of my two monitors
 # issuing 'xcalib -clear' will reset the gamma to 1.00
 # so i'll need to reassert my preference depending on the active display
 # you might not need this
 # when running this from a terminal, $DISPLAY may be ":0" depending on what's happened during its session
 thisdisp=$(echo $DISPLAY)
 #echo $thisdisp
 if [ "$thisdisp" == ":0.0" ]; then
  xgamma -quiet -gamma 0.87
 else
  xgamma -quiet -gamma 1.2
 fi
fi


The script is relatively simple and a bit of effort did go into making it quick.  An array of workspace numbers is created by searching for specific WM_CLASS strings in the window list.  When switching workspaces with this script, the inversion state of the display is altered to correspond to the workspace contents.

Two workspaces: Terminator (normal), Matlab/Simulink (inverted)

Just add appropriate window title keywords and set your preferred wrapping behavior in the script.  Reassign the appropriate keybindings (Ctrl-Alt-Left, Ctrl-Alt-Right) so they execute this script instead of the inbuilt window manager functions.  Script accepts one parameter, either "prev" or "next".

Wednesday, September 10, 2014

Get rid of all YouTube annotations

YouTube annotations can be disabled through a user's account settings, but what if you don't want an account?  What if i don't want to keep logging in?  Kill that annoying shit with a single AdBlock filter:
 s.ytimg.com/yts/swfbin/*
and an exception rule:
 @@||s.ytimg.com/yts/swfbin/*/endscreen.swf
This blocks any annotations, but without blocking the endscreen thumbnails.

Thunderbird: Quick Filter background color

To terminate a long and frustrating exploration of Evolution Mail and its utter brokenness, I installed the last Australis-free Thunderbird (24) and began to set it up to my liking.  Perhaps the one obstacle to the application's compatibility with dark gtk themes is the Quick Filter view.

When the quick filter is active and shows results, the folder view appears with a bluish-white background.  For dark themes with light foreground colors, this makes it impossible to read the results.  Some forums had mentioned that this was part of an explicit definition made in an attempt to highlight the active status of the filter.  With that idea in hand, i simply took a screenshot of the window, extracted the background color, and cross-searched #F2F9FC against relevant keywords until i found an appropriate stylesheet to modify.



Using Stylish, i crammed this up Thunderbird's ass:
#threadTree[filterActive="matches"] {
  background-color: rgba(0,255,0,0.1);
}

#threadTree[filterActive="nomatches"] {
  background: -moz-repeating-linear-gradient(top left -45deg, #ff4444,
              #ff4444 5px, #882222 5px, #882222 10px);
}



 I used a transparent green when successful and red when no matches are found.  In this sense, a highlight effect is still available.  Adjust to suit your needs.