So, after a period of not using John’s Adventures Desktop Background Switcher for a few years, I started using it again. With 3 screens. I realized there are a lot pictures that I don’t really need to remember anymore.  I want to keep them on my harddrive, but I don’t want to see them.

So I rename them from .jpg, but keep the file.  The way I do this in my system is to “deprecate” the file, renaming it from whatever.jpg to whatever.jpg.deprecated.  The file is still on my harddrive, but no longer viewable because it doesn’t have the correct extension anymore.  This is the archivist’s way of deleting.  Some people use the .bak extension, but I tend to delete those automatically sometimes, so I want something different.

I knew I would be doing this many times in my life. I wanted an easy way to do this. Minimal keystrokes.  3 key presses to activate. 1 keypress to choose which of my 3 screens I am referring to. I would settle for nothing less.  The command I use is “pd.bat” for “picdep” or “picture deprecate” or “picture delete”, if you want to think of that way.  P, D, Enter.  Three key strokes. Then you pick a number for which screen it is on That’s what I want.

SETUP REQUIREMENTS

So here is the necessary scripts. You have to run TakeCommand / TCMD to run these, and have some implementation of perl such that you can run perl scripts at the commandline without prefixing them with “perl”. Otherwise, you’ve got one line to edit in my script.  If you’re using Windows, use Strawberry Perl. Cygwin’s perl should be fine, too. These are the only setup requirements.  If you’re not under windows, how the hell are you running TakeCommand scripts? Contact me immediately!

It’s one file, picdep.bat, which you would need to edit one part of: The SOURCE. It must point to your John’s Adventures Status.xml file.  The other 10 BAT files are just variou utility BAT files that I already use in my environment.

Also – my screens are in reverse order. There’s this whole perverse internal mapping that makes it so that when I have 3 screens, 1=3, 2=2, 3=1, and when I have 2 screens, 1=2, and 2=1. It was handy that TakeCommand had an internal automatic environment variable to tell me how many monitors I have. DisplayPort monitors disappear when you turn them off, which is VERY annoying.

Also, you can type “oops” or “undo” to undo what you’ve done when you do this.  Just a handy thing I do. I set an UNDOCOMMAND in the environment, if one can be generated automatically. It’s very handy for when you move things to an incorrect place. Just type “oops”.

It all looks like this:

20150626 - picdep.bat example with undo
picdep.bat:

@Echo OFF

::::: CONFIG:
 set DEBUG=0
 set STATUS_FILE=c:\Users\oh\AppData\Roaming\johnsadventures.com\Background Switcher\Status.xml
 call validate-environment-variable STATUS_FILE

::::: CREATE TEMP SCRIPT FILE:
 :: prepare
 call setTmpFile
 set TEMP_SCRIPT=%TMPFILE%.bat
 set WIDTH=%@EVAL[%_COLUMNS-1]

 :: tell
 call debugprint * STATUS_FILE=%STATUS_FILE%
 call debugprint * TEMP_SCRIPT=%TEMP_SCRIPT%

 :: do
 convert-background-switcher-log-to-env-vars.pl <"%STATUS_FILE%" >"%TEMP_SCRIPT%"
 call validate-environment-variable TEMP_SCRIPT
 type "%TEMP_SCRIPT%"
 call "%TEMP_SCRIPT%"

 :: validate variables for total pics, first pic filename, last pic filename (rest are too much work):
 call validate-environment-variable BGPIC_NUM_PICS_FOUND
 SET NUM_MONITORS=%BGPIC_NUM_PICS_FOUND%
 call validate-environment-variable BGPIC_%BGPIC_NUM_PICS_FOUND%
 call validate-environment-variable BGPIC_1

::::: CHOICE TIME:
 :: create set of valid keys to answer with
 unset /q INKEYMASK
 for /l %key in (1, 1,%BGPIC_NUM_PICS_FOUND%) gosub PrepareInputKeys %key%

 :: prompt
 cls %+ echo. %+ echo. %+ echos `` 
 color bright yellow on yellow %+ echo ***** CHOOSE ONE TO DEP: ***** 
 color white on black %+ echo.
 for /l %pic in (%BGPIC_NUM_PICS_FOUND%,-1,1) gosub PreparePic %pic%
 echos ``
 color bright yellow on yellow %+ echos ***** CHOOSE FROM:
 color bright red on black %+ echos %INKEYMASK ``
 color bright yellow on yellow %+ echo !!!!!!! ***** 
 color white on black %+ echos ``
 color bright green on black 
 
 :: deal with answer
 if "%1" eq "" goto :AnswerNotProvided
 if "%@REGEX[%1,%INKEYMASK]" eq "1" .and. "%@LEN[%1]" eq "1" (set CHOICE=%1 %+ goto :AnswerProvidedAlready)
 :AnswerNotProvided
 inkey /c /k"%INKEYMASK%" %%CHOICE 
 goto :AnswerNowRetrieved
 :AnswerProvidedAlready
 echos %1
 :AnswerNowRetrieved

::::: DO IT!!!:
 gosub processChoice %CHOICE%
 keystack Ctrl-Alt-N %+ REM Makes JohnsAdventures go to the next picture

::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
goto :END


 ::::::::::::::::::::::::::::::::::::::::::::::::::
 :PrepareInputKeys [picNum]
 :: add the filenum to our valid choices
 set INKEYMASK=%INKEYMASK% %picNum%
 return
 ::::::::::::::::::::::::::::::::::::::::::::::::::

 ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
 :adjustPicNumToUse
 :::: This is mostly a multi-monitor-numbred-incorrectly kludge.
 if "%DEBUG%" eq "1" echo * picNumToUse[0]=%picNumToUse [picnum=%picnum]
 goto :Adjust_%NUM_MONITORS%
 goto :PicNumChangeDone

 :Adjust_2
 if %picNumToUse%==1 (set picNumToUse=2 %+ goto :PicNumChangeDone)
 if %picNumToUse%==2 (set picNumToUse=1 %+ goto :PicNumChangeDone)
 goto :PicNumChangeDone

 :Adjust_3
 if %picNumToUse%==1 (set picNumToUse=3 %+ goto :PicNumChangeDone)
 if %picNumToUse%==3 (set picNumToUse=1 %+ goto :PicNumChangeDone)
 goto :PicNumChangeDone

 :Admitttedly, adjust_2 and adjust_3 are both the same thing, but with 2 and 3 substituted, and that's just num_monitors,
 :so they could be refactored into a single thingy. Sigh.

 :PicNumChangeDone
 if "%DEBUG%" eq "1" echo * picNumToUse[1]=%picNumToUse 
 return
 ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::

 ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
 :PreparePic [picNum]
 :: fork parameter
 set picNumToUse=%picNum%
 gosub adjustPicNumToUse

 :: color to display filename in:
 set fg=%picNumToUse%
 set bg=0
 if "%picNumToUse%" eq "1" (set fg=3)
 if "%picNumToUse%" eq "2" (set fg=7)
 if "%picNumToUse%" eq "3" (set fg=6)

 :: display the filename
 color 0 on %fg% %+ echos ``
 color %@EVAL[%fg%+8] on %bg% %+ echo %picNumToUse%: %@NAME[%[BGPIC_%picNum%]]
 color %fg% on %bg% %+ echo %@REPLACE[%PICTURES%,,%[BGPIC_%picNum%]]|cut -c1-%WIDTH
 echo.
 return
 ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::

 ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
 :processChoice [choice]
 color white on black 
 echo.
 set picNumToUse=%choice%
 gosub adjustPicNumToUse
 set filename=%[BGPIC_%picNumToUse%]
 set command=call dep "%filename%" 
 if "%DEBUG%" eq "1" set command=echo * IF NOT IN DEBUG MODE, WOULD HAVE DONE: %COMMAND%
 color bright blue on black 
 echo. %+ echo.
 echo - Your selected %choice%
 echo - PicNumToUse is %picNumToUse%
 echo - Filename is %filename%
 echo - Command is %command% 
 echo. %+ echo.
 color white on black

 %COMMAND%
 return
 ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::

:END
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::

validate-environment-variable.bat:

@echo off

::::: USAGE:
    :: call validate-environment-variable VARNAME_NO_PERCENT [option]
    ::      where option can be "skip_validation_existence" to skip existence validation

::::: SEE IF IT IS DEFINED:
          set         VARNAME=%1
    :echo if defined %VARNAME% goto :Defined_YES
          if defined %VARNAME% goto :Defined_YES
          if ""  eq  %VARNAME% goto :Defined_NO

::::: REPOND IF IT IS NOT:
    :Defined_NO
        echo *** Environment variable %1 is not defined, and needs to be!!
        call alarm-beep
        set ERROR=1
        pause
        goto :END

::::: ADDITIONALLY, VALIDATE THAT IT EXISTS, IF IT SEEMS TO BE POINTING TO A FOLDER/FILE:
    :Defined_YES
    set VARVALUE=%[%VARNAME%]
                                                     set IS_FILE_LOCATION=0
    call   car>nul                                   %+ rem Lets us use carrot in next line
    if "1" eq "%@REGEX[^[A-Z]:,%@UPPER[%VARVALUE%]]" set IS_FILE_LOCATION=1
    call nocar>nul                                   %+ rem Restores original state
    if "0" eq "%IS_FILE_LOCATION%"                   (goto :DontValidateIfExists  %+ set  VARVALUEDRIVE=%@INSTR[0,1,%VARVALUE%])
    if "0" eq "%@READY[%VARVALUEDRIVE%]"             (goto :DontValidateIfExists)
    if "%@UPPER[%2]" eq "skip_validation_existence"  (goto :DontValidateIfExists)
    if exist "%VARVALUE%"                            (                         goto :ItExistsAfterall)
    if isdir "%VARVALUE%"                            (                         goto :ItExistsAfterall)
    if exist "%VARVALUE%.dep"                        (gosub :ItIsDeprecated %+ goto :ItExistsAfterall)
    if isdir "%VARVALUE%.dep"                        (gosub :ItIsDeprecated %+ goto :ItExistsAfterall)
    if exist "%VARVALUE%.deprecated"                 (gosub :ItIsDeprecated %+ goto :ItExistsAfterall)
    if isdir "%VARVALUE%.deprecated"                 (gosub :ItIsDeprecated %+ goto :ItExistsAfterall)
    call alarm-beep * Environment variable %@UPPER[%VARNAME%] appears to be a file location that does not exist: %VARVALUE%       


:::::::::::::::::::::::::::::::::::::::::::::::::::::::
goto :Past_The_End_Of_The_Sub-Routines
        ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
        :ItIsDeprecated 
            echo. %+ echo. %+ echo.
            color bright magenta on black
                echo * Environment variable %@UPPER[%VARNAME%] points deprecated file: 
                echo            "%VARVALUE%"
            color white on black
            beep 73 3
            beep 73 2
            beep 73 1
            pause
        return
        ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
:Past_The_End_Of_The_Sub-Routines
:::::::::::::::::::::::::::::::::::::::::::::::::::::::

:ItExistsAfterall
:DontValidateIfExists
:END

convert-background-switcher-log-to-env-vars.pl

use strict;

# SAMPLE INPUT:
#  <current_pictures>
#    <BackgroundSwitcherSettingsPicture position="scale" Info="20101125 - Thanksgiving - group picture - (by Chris) - 5215610791_4815d44cf2_o
Thursday, November 25, 2010" Name="20101125 - Thanksgiving - group picture - (by Chris) - 5215610791_4815d44cf2_o" Identifier="S:\WWWPICS\2010-2019\2010\2010_11_25_Thanksgiving at Britt's\20101125 - Thanksgiving - group picture - (by Chris) - 5215610791_4815d44cf2_o.jpg">S:\WWWPICS\2010-2019\2010\2010_11_25_Thanksgiving at Britt's\20101125 - Thanksgiving - group picture - (by Chris) - 5215610791_4815d44cf2_o.jpg</BackgroundSwitcherSettingsPicture>
#    <BackgroundSwitcherSettingsPicture position="scale" Info="20070324 - Chili Cook-off at Mandy &amp; Brad's - 116-1604 - Christian, dog
Saturday, March 24, 2007" Name="20070324 - Chili Cook-off at Mandy &amp; Brad's - 116-1604 - Christian, dog" Identifier="S:\WWWPICS\2000-2009\2007\2007_03_24_Chili Cook-off at Mandy &amp; Brad's\20070324 - Chili Cook-off at Mandy &amp; Brad's - 116-1604 - Christian, dog.jpg">S:\WWWPICS\2000-2009\2007\2007_03_24_Chili Cook-off at Mandy &amp; Brad's\20070324 - Chili Cook-off at Mandy &amp; Brad's - 116-1604 - Christian, dog.jpg</BackgroundSwitcherSettingsPicture>
#    <BackgroundSwitcherSettingsPicture position="scale" Info="20100803 1220 - Cape Cod - North Beach Island - there's nowhere safe from scrutiny - helicopter - IMG_1708
Tuesday, August 03, 2010" Name="20100803 1220 - Cape Cod - North Beach Island - there's nowhere safe from scrutiny - helicopter - IMG_1708" Identifier="S:\WWWPICS\2010-2019\2010\2010_07_30-2010_08_07_Cape Cod\2010_08_03\1_North Island part 1\20100803 1220 - Cape Cod - North Beach Island - there's nowhere safe from scrutiny - helicopter - IMG_1708.jpg">S:\WWWPICS\2010-2019\2010\2010_07_30-2010_08_07_Cape Cod\2010_08_03\1_North Island part 1\20100803 1220 - Cape Cod - North Beach Island - there's nowhere safe from scrutiny - helicopter - IMG_1708.jpg</BackgroundSwitcherSettingsPicture>
#  </current_pictures>

# NEEDED OUTPUT:
#	1) Environment variable sequence for each  filename  (BGPIC_1, BGPIC_2,etc)
#   2) Environment variable value    for total filenames (BGPIC_NUM_PICS_FOUND)

my $num_pics_found=0;
my $line;
my $picture_directory;
my $picture_filename;
my $NUM_PICS_FOUND=0;
my $VARNAME1;
my $VARNAME2;
my $IT;
while ($line=<STDIN>) {
	if ($line =~   /<current_pictures>/) { $IT="on" ; }
	if ($line =~ /<\/current_pictures>/) { $IT="off"; }
	chomp $line;

	if (($IT eq "on") && ($line=~/BackgroundSwitcherSettingsPicture/)) {
			    $picture_filename = $line;
			    $picture_filename =~ s/^(.*)(Identifier=")([^"]*)(".*)$/$3/;
			    $picture_filename =~ s/&amp;/&/g;
			if ($picture_filename eq "") { die("pic is empty"); }
				if ($ENV{DEBUG} > 0) { print "echo picture_dir[0] = $picture_directory \n"; }
				$picture_directory = $picture_filename;
				if ($ENV{DEBUG} > 0) { print "echo picture_dir[1] = $picture_directory \n"; }
				$picture_directory =~ s/[\\\/][^\\\/]*$//;	#remove the last slash and ever every non-slash after it, until the end of the line

			$NUM_PICS_FOUND++;
			$VARNAME1 = "BGPIC_" . $NUM_PICS_FOUND;
			$VARNAME2 = "BGDIR_" . $NUM_PICS_FOUND;

			print "set $VARNAME1=$picture_filename"    . "\n";
			print "set $VARNAME2=$picture_directory"   . "\n";
			print  "pushd      \"$picture_directory\"" . "\n";
			print "call validate-environment-variable $VARNAME1\n";
			print "call validate-environment-variable $VARNAME2\n\n\n\n";
	}
}
print "\nset BGPIC_NUM_PICS_FOUND=$NUM_PICS_FOUND\n";
print "call validate-environment-variable BGPIC_NUM_PICS_FOUND\n";

alarm-beep.bat:

@echo off

::::: SETUP:
    if not defined USERNAME (echo *** FATAL ERROR: USERNAME NOT DEFINED! %+ pause +% goto :END)

::::: FLASH WINDOW AND DISPLAY ERROR:
    window flash=2,8
    :window flash=4
    if "%1" eq "" goto :NoErrorToDisplay
        color bright white on red   %+ echos *** ERROR: %* *** 
        color        white on black %+ echo.
    :NoErrorToDisplay

::::: DON'T MAKE AUDIBLE ALARM IF SOMEONE IS NAPPING:
    if "%SLEEPING%" eq "1" goto :done_klaxoning
        gosub klaxon
        gosub klaxon
        gosub klaxon
        gosub klaxon
    :done_klaxoning





goto :END

::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
:klaxon
goto :klaxon%USERNAME%

    :klaxon
    :klaxonClint
        beep  2000 10
        beep  1000 10
        call sleep 1
    return

    :klaxonCarolyn
        beep  2666 2
        beep  1333 2
        beep  2666 2
        call sleep 1
    return

    :klaxonCarolynRejected
        beep  1333 2
        beep  2666 1
        beep  1333 1
        beep  2666 1
        beep  1333 1
        call sleep 1
    return
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::

:END
    :stop continuous flashing:
    :window flash=0
    :start non-continuous flashing that, in theory, goes until the window is in the foreground again, but, in reality, doesn't always if new commands are issued in a BAT file:
    window flash=2,8
    window flash=2,2
    pause


car.bat (this one is stupid but sometimesnecessary, leftover from 1990s laziness):

@echo off
setdos /C~
color bright blue on black
echo You can now use the carrot key for things other than command stacking.
color white on black

nocar.bat (this one is stupid but sometimesnecessary, leftover from 1990s laziness):

@echo off
setdos /c%=^
color bright blue on black
echo You now must use the carrot key for command stacking only.
color white on black

alarmbeep.bat:

call alarm-beep %*

settmpfile.bat:

call validate-environment-variable TEMP
call validate-environment-variable USERNAME
SET TMPFILE=%TEMP%\%_DATETIME.%USERNAME%.%_PID.%@NAME[%@UNIQUE[%TEMP]]
:DEBUG:  echo - TMPFILE is %TMPFILE

debugprint.bat:

if "%DEBUG%" ne "1" goto :END

        color green on black 

            echo %&amp;

        color white on black

:END

dep.bat:

@echo off
set                              NOQUOTES=%@STRIP[%=",%1]
set        LAST_FILE_DEPPED_OLD=%NOQUOTES%
set        LAST_FILE_DEPPED_NEW=%NOQUOTES.deprecated
if exist "%LAST_FILE_DEPPED_NEW%" call alarm-beep LAST_FILE_DEPPED_NEW of %LAST_FILE_DEPPED_NEW% already exists and should not! Why could that be, hmmmmmm??
ren      "%LAST_FILE_DEPPED_OLD%" "%LAST_FILE_DEPPED_NEW%"
if exist "%LAST_FILE_DEPPED_OLD%" call alarm-beep LAST_FILE_DEPPED_OLD of %LAST_FILE_DEPPED_OLD% *still* exists and should not! Might want to run 'handles'.
:: add this command to eligibility for undo/oops.bat:
set        UNDOCOMMAND=call undep
unset  /q  NOQUOTES

undo.bat:

@Echo OFF

if not defined UNDOCOMMAND goto :nothing

    :::::::::::::::::::::::::::::::::::
    :something
        :: If this pattern seems weird, it's because I want to unset UNDOCOMMAND *before* running it,
        :: in case we Ctrl-Break out of the command.  If we don't want it, it needs to go away. 
        :: Undo commands should only be run once. They should never be run twice.
        :: Therefore, we must unset UNCOMMAND *before* running it.
        :: Which neccesitates saving the value to a separate variable...
            set TMPCOMMAND=%UNDOCOMMAND%
            unset /q UNDOCOMMAND
                color bright red on black
            echos * Undo command is: ``
                color bright green on black
            echo %TMPCOMMAND%
                color white on black
            %TMPCOMMAND%
    goto :END
    :::::::::::::::::::::::::::::::::::

    :::::::::::::::::::::::::::::::::::::::
    :nothing
        echo. 
        color bright magenta on black 
        echo   * Nothing to undo!
    goto :END
    :::::::::::::::::::::::::::::::::::::::

:END

oops.bat:

@call undo %*

deprecate.bat:

@call dep %*

undep.bat:

call validate-environment-variable LAST_FILE_DEPPED_NEW
call validate-environment-variable LAST_FILE_DEPPED_OLD skip_validation_existence
ren  "%LAST_FILE_DEPPED_NEW%" "%LAST_FILE_DEPPED_OLD%" 

pd.bat:

@call picdep %*

UNNECESSARY BONUS: DP.BAT OVERLOAD TRICK. I have a dp.bat, and I kept running it instead of pd.bat. Sine I pre-load the number of the image i use (“dp 1” for monitor 1, “dp 2” for monitor 2, etc), I check if a number between 1 and NUM_MONITORS is entere, and then pass control over to pd.bat, the one I meant to use. I basically had to out-program my own brain’s frequent mistake. I do it insanely tightly, even checking %_MONITORS, so it will only work up to the number of monitors I have. “dp 3” will only transfer control to pd.bat if my 3rd screen on i :)

(from dp.bat)

::::: IF WE PASS A SINGLE-DIGIT NUMBER, WE ARE PROBABLY TRYING TO CALL DP.BAT INSTEAD OF PD.BAT, SO LET'S JUST ALLOW THAT:
    SET ARGV=%1
    if "%ARGV%" eq "" goto :NoOverload
        :Overload
        if "%ARGV%" ne "" .and. "%@LEN[%ARGV%]" eq "1" .and. "%2" eq "" .and. "%@REGEX[[0-%_MONITORS],%ARGV%]" eq "1" (pd.bat %*)
    :NoOverload

Anyway. I just wanted to go through the motions of publishing some kind of functionality of mine, to start thinking about if I want to publish things, and how to do that in a more automated fashion as well — but without unveiling private information accidentally, and decoupling it from some of my more interesting anti-maintenance scripts. For instance, above, I gave one line that is:

SET STATUS_FILE=c:\Users\oh\AppData\Roaming\johnsadventures.com\Background Switcher\Status.xml

In reality, the code I use internally is much more complicated:

::::: FIND STATUS FILE: 
    call validate-environment-variable   APPDATA
    call validate-environment-variable   SERVER_OF_SCREEN_BACKGROUNDS
    call validate-environment-variable   DRIVE_C_%SERVER_OF_SCREEN_BACKGROUNDS%_VAR
    call validate-environment-variable %[DRIVE_C_%SERVER_OF_SCREEN_BACKGROUNDS%_VAR]
    set STATUS_FILE=%[%[DRIVE_C_%[SERVER_OF_SCREEN_BACKGROUNDS]_VAR]]:\Users\oh\AppData\Roaming\johnsadventures.com\Background Switcher\Status.xml
    call validate-environment-variable STATUS_FILE

But it assumes a certain kind of environment that only I have defined.

%[%[DRIVE_C_%[SERVER_OF_SCREEN_BACKGROUNDS]_VAR]] evaluates to
%[%[DRIVE_C_THAILOG_VAR]] which eventually evaluates to 
%HD240G                   which            evaluates to
C

…. This is all abstracted in such a way that works on every machine in my house regardless of what the actual drive letter ends up being (definitely NOT C for all the machines except 1).  Ask me about my harddrive driveletter environment and reverse-lookup variables sometime.  I even have an environment variable called %THE_ALPHABET% which I use frequently.