Category Archives: Technology

Your Own Cheap VPN for $1/mo

People are (rightfully) freaking out about their privacy as the Senate voted the law S.J. 34 to let internet providers share your private data with advertisers. While it’s important to protect your privacy, it doesn’t mean that you need it at all times. Also, VPN is a service that is not free, but I found you the CHEAPEST DEAL AVAILABLE TODAY: therefore, let’s create a VPN in 15mn for $1/mo!

Read more: Your Own Cheap VPN for $1/mo

This guide will show you step by step how to do it with Virmach but this is valid for any other brand, provided you accept the price. The whole point is to use a script that does it for you, so you don’t have to spend a whole day doing it. Yes, setting up a VPN Server by hand is very complicated.

 

1. Get a KVM Server for $1/mo at Virmach

This is the crapiest, cheapest KVM provider I could find as of March 2020. Unfortunately they do not offer $1/mo plans anymore, because it depends on availability. I highly doubt they ever offered these plans in large quantities but you know how business work, yeah?

Select the cheapest KVM from the Virmach plans available here.

virMarch-cheapest-server
You may have a warning saying they are out of stock but they promise to charge you only $1/mo.
Option 2 would be a slightly better bandwidth at $1.25:

virMarch-cheapest-server-2

 

2. Create a RedHat, Debian, Ubuntu or CentOS server

Versions required for the script to work: Supported distros are Ubuntu, Debian, AlmaLinux, Rocky Linux, CentOS and Fedora

  • Ubuntu 18.04 or higher
  • Debian 9 or higher
  • CentOS 7 or higher
  • Fedora any version

virmach-distro-compatibles

The script that will create the OpenVPN server for you needs to be run on the major versions above. Among the limited options that Virmach offers you for that price, as of September 2021, choose one of these:

The versions shown above are the lowest versions compatible with the script. The rest of the setup in straightforward. Take note of the root password they give you and that’s it.

3. Initial Setup (optional)

Virmach will provide you a root access with a password. All the steps below are optional, especially if you already own an IaaS Cloud server access.

A. Update the System (advised)

The commands below are for Debian/Ubuntu systems:

apt update -y
apt upgrade -y
apt autoremove -y
apt clean -y

That’s it. Most systems are already configured for IPv4 Forwarding so you should be good to go.

B. Setup SSH (optional)

You can change the remote SSH access to RSA key access only instead of using a password, by setting up your identity and the SSHd daemon.

First you need to create your SSH identity (you could also force copy your own from another server):

ssh-keygen -f ~/.ssh/id_rsa

Next, add your public RSA key in ~/.ssh/authorized_keys (there are 3 ways to do that but this one is straightforward):

echo ssh-rsa AAAAB3Nza...IsFA0eGz name>~/.ssh/authorized_keys
chmod 600 ~/.ssh/authorized_keys

Next, tweak the SSHd config file:

sed -i -e "s/^#PasswordAuthentication yes/PasswordAuthentication no/g" /etc/ssh/sshd_config || sed -i -e "s/^PasswordAuthentication yes/PasswordAuthentication no/g" /etc/ssh/sshd_config

4. Install OpenVPN

To install OpenVPN and all the dependencies including EasyRSA, simply execute this command:

wget https://git.io/vpn -O openvpn-install.sh && bash openvpn-install.sh

If using Ubuntu 16.04, another script is necessary:

wget https://git.io/vpn1604 -O openvpn-install.sh && bash openvpn-install.sh

That’s it. Now, get the content of the OVPN file generated for your clients:

cat /root/virmach1.ovpn

5. Setup the Clients

Windows Client

With the OVPN file you got, simply import it in OpenVPN GUI and you’re good to go!

DD-wrt Client

This guide will show you how to setup this OpenVPN connection on your home Dd-wrt router so the Wi-Fi is VPN-ized!

 

Wrapping Up

Let me know in the comments how long it actually took you. It took me much more than 15mn because I was writing the guide at the same time, but I think that 15mn altogether is a fair guess.

As of today, March 2020, Virmach let you pay $1 for a $1.25/mo plan because they “ran out” of cheap plans, but you are limited to 1 only. Also, no other location than within the USA are available, which defeats the purpose of a VPN when you live in the USA. What you really want is an access point in Europe.

CenturyLink is Garbage

CenturyLink blocks Kodi. Centurylink blocks Kodi repositories. CenturyLink filters internet without telling you. CenturyLink caps your bandwidth after 6 months. CenturyLink blocks random websites. CenturyLink is BAD.

After moving, I thought that using any competitor to Comcast would be a good idea. After all, it’s one of these ISP that still provide ADSL. It cannot be that bad? 

Read more: CenturyLink is Garbage

CenturyLink First Impressions

Well, ADSL is not fast, you know that. Do you? ADSL is a branch of DSL that’s provided through existing phone lines. It is therefore sensitive to electromagnetic noise. And the ping is attrocious: 21ms+

Noise can be emited by crappy electric devices such as dishwashers, washing machines, microwave ovens and whatever chinessium crap is connected close to your home.

It is also sensitive to radio signals on the 1400Mhz band. Chinesium crap devices can also emit on this band and hinder your bandwidth.

I also noticed a drop in bandwidth after 6 months. 

CenturyLink Caps your Bandwidth

At the beginning, speedtest.net reported a whooping 80MB download speed. Living less than 1 mile away from the DSLAM, it made a lot of sense. 10MB upload speed was honorable for this kind of connection.

Here we are, 6 months later. Speedtest now reports between 20 and 30MB download speed at Any time.

century-link-speedtest-202109

And This is what you get by living 1 mile away from the DSLAM. Imagine if you live further away…

It’s down from 80MB to 30MB after 6 months, permanently and for no reason. Also, Kodi servers are blocked from time to time. 

CenturyLink Blocks Kodi Repos

This post is coincidental with me trying to reinstall a new Kodi build on my Rbox pro set-top box. The previous build refused to update most repos and I was not surprised, since it happened in the past with other builds.

It’s a catch-me-if-you-can game between pirated stream providers and the media Majors, we all know that. Still, I could not even configure new 2020 builds I knew that were working.

I could not even access xanax or slamious home site from my desktop. Only from my phone via Verizon. Isn’t that odd??

Setting up a VPN on the router solved the issue: Kodi works again!

Edit: as of April 2020, they re-opened the access to most build repos. Maybe it was an internal network issue on their side? 

Conclusion: Comcast Is a Monopoly, but CenturyLink Is Worst

CenturyLink can block Kodi repos without warning you. CenturyLink also cap your bandwidth after some time with no reason. Maybe they think you won’t notice?

CenturyLink is hindering your freedom of surfing and therefore your freedom of speech. CenturyLink is not a good alternative to these monopolies that are Comcast, Verizon and AT&T. It’s not even cheaper.

CenturyLink plan, including their crappy modem is worth $60/mo and it’s not worth it. CenturyLink is bad, period.

Des batteries quasi éternelles fabriquées à partir de déchets nucléaires

Des batteries nucléaires, quasi éternelles fabriquées à partir de déchets nucléaires sont une enieme FAKE NEWS, merci ouest france. Aussi sur que le fiasco des Solar Freakin Roadways que Segolene Royal a voulu tester malgre tout avec votre argent.

Read more: Des batteries quasi éternelles fabriquées à partir de déchets nucléaires

@Thunderf00t a debunk cette idiotie depuis le 30 Janvier 2020:

NUCLEAR Diamond Battery: BUSTED!!
NUCLEAR Diamond Battery: BUSTED!!

Je ne reviendrais pas sur les calculs effectues, suivez la video et refaite-les vous meme si vous doutez.

Ouest France et le reste des media Francais, en termes de qualite editoriale scientifique, sont tous completement a l’ouest.

SexTape de Benjamin Griveaux

Les site relayant la sex tape de Benjamin Griveaux n’etaient pas assez nombreux, Ils sont tous down! La France a toujours assez de courage et d’abnegation pour couvrir les deboirs de ses chers hommes politiques. Impossible d’acceder aux photos ou aux videos, apres seulement 3 jours!!

 

Summary (English)

picture of benjamin griveaux
You didn’t see that one coming, did you?

Source: AFP

EDIT 2024

Let’s face it… I was hacked. Weeks after, with the duplicity of Amazon (AWS) which I left since then. I buried my head in the sand for the past 4 years trying to ignore it, improving security, resilience, swaping Clouds, thinking that it was a File System error… But no, there are evidences.

What I can tell when I realized:

  • recent nginx logs were missing
  • *all* images uploaded for the past 2 months were missing
  • database not corrupt but… all media references removed.
    • normally, when you delete a picture from the file system, it stays in your media page and shows as missing
    • in this case, the media attachments were also missing. Someone indeed did some cleanup
    • the post is still there. They left it intact as a warning.
  • nothing relevant in system log
  • a server reboot was recorded

Who other then Amazon would give access to my disk space? Why is the post still in place and no visible database alteration other then missing pictures? Why only the last 2 months of pictures uploaded were missing? Only the last 2 months, really? Why wasn’t my site entirely wiped?

This makes no sense, the more I think about it. Hackers or whoever that was, carefully deleted ONLY the pictures under wp-content/uploads, and ONLY the last 2 months. It’s been carefully done: just enough damage, looking like it was Amazon’s fault. I suspected a file system restore as they sometimes do, without telling their customers. But the tempering evidences in the database are too strong.

To top it off, it also happened at a time where I frantically started pasting stuff directly to the site, not having local backups. Lesson learned!

Now I have to fix all those posts for which the pictures were deleted:

  • How To Install Pi-Hole DNS Ad blocker
  • Your Own Cheap VPN for $1/mo
  • CenturyLink is Bad
  • Des batteries quasi éternelles fabriquées à partir de déchets nucléaires
  • Let’s start calling the novel coronavirus the CCP virus
  • WHO: 70% of sick in China have recovered
  • DUTCH RESEARCHERS FIRST TO FIND COVID-19 ANTIBODIES!
  • We Found Out Where All Of The Toilet Paper Went!
  • Coronavirus Cure: Best Treatments
  • There Are Only 2 Genders
  • Voir La SexTape de Benjamin Griveaux

Being hacked, or bare-back doored by your own Cloud provider is not a pleasant feeling. What do you think happened? If I was hacked, why did they delete only 2 months of pictures? Why not the database and the whole uploads folder? Why not the post itself?

I’d love to have your thoughts, maybe I’m just overthinking it…?

 

Images and traces que j’ai pu sauvegarder avant que la Republique ne fasse le menage:

pornopolitique.com

pornopolitique.com downLa premiere source a avoir offert les videos du ruskof (a qui on avait rien demande) est down.

Ce site a clairement ete cree pour cette occasion, et cela ne date pas d’hier: le whois montre un enregistrement au Canada, qui date de Novembre 2019!

waybackmachine.com

La France a meme reussi a bloquer le contenu de waybackmachine,org! Jugez plutot: ce lien liste les snapshots du site pornopolitique.com:

wayback machine archive down

Quand on clique la page se charge mais apres 2 secondes est remplacee par ceci:

wayback machine downEt impossible de recharger la page bien sur. Meme resultat avec les autres snapshots. Comment ont-ils fait?

Il est interessant de noter qu’il n’y a de snapshots QUE pour les journees du 13 et 14 Fevrier:

wayback machine last snapshotCe site a visiblement ete cree de toute piece pour cette affaire. Vous aurez un peu plus de chance avec les “archives” du site, mais toujours pas acces aux videos

jeuxvideo.com

Curieusement, jeuxvideo.com avait aussi une page sur le sujet:

La page est bien sure bloquee:

jeuxvideo.com down
twitter.com

Pas besoin de mentionner que Twitter a bien sur supprime les comptes de ceux qui relayaient l’information. Ils ont aussi supprime mon compte parceque ces wokes de Californie n’aimaient pas ma pic de profile.

twitter down

pornhub.com

Certain forums and facebook proposent d’aller fureter sur pornhub… La encore la machine gouvernementale a fait le menage:

pornhub down

boursier.com

Meme des commentaires plutot serieux sur l’affaire sont retires! Jugez plutot:

boursier.com moderated

youtube.com

Aura-t-on plus de chances avec Youtube? Il y a bien un moyen pour retrouver des videos supprimees, mais cela ne fonctionne que si queulqu’un a uploade la video sur un site alternatif…

youtube private

delutube Dtube Peertube etc

On avait plusieurs sites qui permettaient d’uploader des videos Youtube supprimmees. Non seulement ils n’apparaissent plus dans les recherches Google et Duckduckgo, mais ils sont soit down eux aussi, soit personne n’a eu le temps d’uploader! Sale temps pour la liberte d’expression.

delutube.com downFallouts

La carriere de ce pourri est peut etre finie, mais pour le russe qui a leaked la video, c’est une autre histoire.

russian performance artist pyotr pavlensky in november 2015. photo by sergei savostyanov via getty images.
Russian performance artist Pyotr Pavlensky in November 2015. Photo by Sergei Savostyanov via Getty Images.

Aparement, ce ruskov est un arsonist. Il fout le feu partout ou il va pour raisons diverses et variees, et se fait prendre en photo devant. Apres avoir gracieusement ete accepte avec sa demande d’asile, il met le feu a la Banque de France en 2017. C’est comme ca qu’il remercie le pays qui lui a donne asile. Et il appelle ca de l’Art. Celui la aussi c’est un sacre fils de pute.

Tous des fils de pute dans cette affaire degueulasse.

Conclusions

MrHand

J’ai eu plus de chance pour trouver la video de Mr Hand que les photos minables de Benjamin Griveaux.

Qui l’eu cru? Rien sur Google, rien sur Duckduckgo, rien sur Youtube, rien sur Bing, rien sur Yahoo, rien sur Yandex, and meme la wayback machine a ete nettoyee!

Benjamin Griveaux sextape,i was hacked,Benjamin Griveaux,pornopolitique

Sale temps pour la liberte d’expression sur Internet. Depuis sa “Declaration of the Independence of Cyberspace” en 1996, ni Barlow lui-meme, ni sa fondation EFF n’ont pas permit d’ameliorer la situation.

La France est toujours une grande puissance, que vous le vouliez ou non. Elle a des allies partout, le rapide cleanup de wayback machine en est la preuve. Essayez vous-meme d’effacer vos propre archives, vous allez comprendre comme c’est long et difficile.

Appel aux dons

Vous avez sauvegarde la video? Les photos? Vous avez des liens qui marchent? Envoyez moi ca! Je suis curieux de voir comment la France va me bloquer une seconde fois.

 

 

Cloud Backup Strategy on AWS

Cloud Backup

Always have a Cloud Backup plan.

Mila Kunis

So, you moved to the Cloud and you got yourself one or more server? You host your own data and potentially even client data? What if you got hacked today? Database corruption, File corruption, accidental deletion, all these nice things happen all the time.

Cloud Backup Its Not a Matter “If” but “When”

IRS Criminal Investigation

Hopefully, AWS offers lots of options when it comes to Cloud Backup and data redundancy. On the other hand, Online Cloud Backup is not free. EBS Snapshots and S3 Buckets are darn cheap, but costs accumulate since you pay by the GB.

What Are My Cloud Backup Options?

EBS Snapshots

Cloud Backup

Convenient, easy to generate, easy to automate, EBS Snapshots are however the most expensive Cloud Backup option from AWS.

EBS Snapshots = $0.05 per GB-month of data stored
50GB = $2.5 per month

Snapshots are critical for fast data recovery though, they are therefore necessary for your system volumes. Convenient, easy to generate, easy to automate, EBS Snapshots however can become quite expensive in the long run.

AWS-Snapshot-Policy-Schedule
AWS-Snapshot-Policy-Schedule

Conclusion: You can live with only one snapshot in rotation every 24h per system volume, but for data volumes you certainly do not want that. Also, indeed Snapshots can be automated by aws cli, it makes the Snapshots console neither fish nor fowl. You don’t have this issue with S3 Buckets since you are forced to build scripts from the start.


What are these aws cli scripts you are mentioning?

Check this AWS documentation out. 

S3 Buckets

S3 Buckets are a much cheaper Cloud Backup alternative. Pretty much everything to know is said on AWS’ own wiki, but it’s a bit more complex. Depending on how frequently you want to access your data, you can go as low as $0.00099, as of 2020. Look at the prices below

 Storage pricing
   S3 Standard – General purpose storage for any type of data, typically used for frequently accessed data  
 First 50 TB / Month That’s already half the cost of Snapshots$0.023 per GB 
 Next 450 TB / Month $0.022 per GB 
 Over 500 TB / Month $0.021 per GB 
 S3 Intelligent – Tiering * – Automatic cost savings for data with unknown or changing access patterns  
 Frequent Access Tier, First 50 TB / Month $0.023 per GB 
 Frequent Access Tier, Next 450 TB / Month $0.022 per GB 
 Frequent Access Tier, Over 500 TB / Month $0.021 per GB 
 Infrequent Access Tier, All Storage / Month $0.0125 per GB 
 Monitoring and Automation, All Storage / Month $0.0025 per 1,000 objects 
  
 S3 Standard – Infrequent Access * – For long lived but infrequently accessed data that needs millisecond access $0.0125 per GB 
  
 S3 One Zone – Infrequent Access * – For re-createable infrequently accessed data that needs millisecond access $0.01 per GB 
  
   S3 Glacier ** – For long-term backups and archives with retrieval option from 1 minute to 12 hours $0.004 per GB 
  
 S3 Glacier Deep Archive ** – For long-term data archiving that is accessed once or twice in a year and can be restored within 12 hours $0.00099 per GB 

S3 Buckets are clearly cheaper. By default, my 50GB volume backup now costs me only $1.15, that’s 53% LESS than Snapshots. However, you cannot upload a Snapshot to S3. Even though they are hosted on S3, that’s in a separate network administered by AWS. All you can do is upload files. Remember dd? This smells like you need scripts!

How much do S3 Buckets cost?

It’s per GB.
Standard = $0.023 (50GB = $1.15/mo)
Standard _IA = $0.0125 (50GB = 62 cents/mo!)
Glacier = $0.004 (50GB = 20 cents/mo!!)
Glacier Deep = $0.00099 (50GB = 5 cents/mo!!!)

Can you automate them?

Yes. With scripts in bash, using the aws cli commands and a bit of cron.

How far back in time can you go for your $$$?

Since you can automate backup files expiration with scripts, it’s easy to keep the few you need and pay only for those.

What if I want to restore last month backup?

Restore the monthly or the weekly that you have setup. You could also retain 30 snapshots in rotation.

Wait a minute. 30 Snapshots?

Yes, for the price of an S3 Glacier, your 30 snapshots at $12/mo now cost less than a dollar! Access costs are negligible.

How much costs 30 Snapshots?

Standard: 30 * 8GB * $0.023 = $5.52/mo
Glacier: 30 * 8GB * $0.004 = $0.96/mo

Can you backup each week instead?

Why not.

Can you automate the snapshots deletion?

Yes.

What scripting language to use?

Scripts with bash or zsh for loafs like me (rely on the aws cli binaries), and Python for the courageous, or Ruby for the smart. Python and Ruby come with ssl and POST capabilities, which is needed to use the S3 API.

Wrapping up

More on S3 automation and its drawbacks in the next post! The goal being to sleep with your deaf ear up, a bit more efforts and challenge is needed the reach the Graal of the ultimate bargain price possible.

If you prefer convenience and money is not an issue, be my guest and go for hand-managed Snapshots in the console.

Ultimate MSDOS interactive dynamic menu

This is the Ultimate MSDOS interactive dynamic menu with Powershell quirk. Vertical menu controlled by cursor keys via Powershell quirk + Horizontal carousel to select each option’s value.

Linus Tech Tips

Purpose of vertimenu

Presentation of vertimenu

This batch is a compilation of all the crazy interactive menu examples
by Antonio Perez Ayala from https://www.dostips.com/forum/viewtopic.php?f=3&t=6936

  • By selecting options in the menu, obtain a list of variables install{product} and version{product}.
  • {product} can be anything you like: AA, BB etc
  • Then you process these in your own routines

Usage for vertimenu

Usage:

  • The batch below is used in a modified way to download stuff from FTP or OneDrive.
  • Drop it on some server, then it’s using a preset of versions to choose from
  • Then it is supposed to download formated ini files names: install-{product}-{version}-platform|product.ini that contain the actual files to download
  • Use it for whatever your like!

Features of vertimenu

  • Vertical menu controlled by cursor keys via Powershell quirk
  • Horizontal carousel to select each option’s value (we call it version)
  • Win10 compatible colors with colorless selector fallback for Vista/2012 – findstr trick is disabled
  • Tabbed indentation with parent and children
  • Jump over spacers and disabled options!
  • Multicolumns for selected version and highest detected version
  • Windows like children options toggle when Parent options are toggled
  • Auto attribution of version value to Menu option children without version
  • Dynamic indentation and menu resize
  • (Un)limited number of tab levels
  • CSV-like controlled options
  • Includes _PS_Resize trick to fit the content of the menu
  • Includes comments! How unusual…
  • Maximum 30 options

Source Code & Git for vertimenu

https://github.com/audioscavenger/vertimenu-msdos-dynamic-menu

@echo OFF
if "%~1" equ "vmenu_OptionSelection" goto :%~1
pushd %~dp0
setlocal enabledelayedexpansion

:top 
set DEMO=
set DEBUG=
set VERBOSE=
...

@echo OFF
if "%~1" equ "vmenu_OptionSelection" goto :%~1
pushd %~dp0
setlocal enabledelayedexpansion

:top
set DEMO=
set DEBUG=
set VERBOSE=
set PAUSE=echo.
:: enable the line below to debug and pause at places of your choice
REM set PAUSE=pause
set POPUP=false
IF DEFINED DEBUG set VERBOSE=true
verify on

:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
set author=audioscavenger@it-cooking.com
set version=5.1.10
:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
:: Purpose
::        This batch is a compilation of all the crazy interactive menu examples
::        by Antonio Perez Ayala on https://www.dostips.com/forum/viewtopic.php?f=3&t=6936
::
::        By selecting options in the menu, obtain a list of variables install{product} and version{product}
::        {product} can be anything you like: AA, BB etc
::        Then you process these in your own routines
:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
:: Features
::        Vertical menu controlled by cursor keys via Powershell quirk
::        Horizontal carousel to select each option's value (we call it version)
::        Win10 compatible colors with colorless selector fallback for Vista/2012 - findstr trick is disabled
::        Tabbed indentation with parent and children
::        Jump over spacers and disabled options!
::        Multicolumns for selected version and highest detected version
::        Windows like children options toggle when Parent options are toggled
::        Auto attribution of version value to Menu option children without version
::        Dynamic indentation and menu resize
::        (Un)limited number of tab levels
::        CSV-like controlled options
::        Includes _PS_Resize trick to fit the content of the menu
::        Includes comments! How unusual...
::        Maximum 30 options
:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
:: * TODO
::     1. actually include hidden tools choice in the list because selector menu thinks nothing selected if only that
::     1. add -r to arguments to REFRESH remoteVersionsAvailable
::     1. evolve :arguments to getopt
:: 5.1 enhancements and bug-fixes:
::     1. added local versions detection!
::     2. finally a version flip-switch that's blocked at the edges
::     5. bug fix: deselect a tabbed option would disable the next ones
::     7. protect all [x] comparisons between quotes
::    10. introduce export[%%i] to include or not selected products (used for menu parents)
:: 5.0 enhancements and bug-fixes:
::     1. integrated magic vmenu from https://www.dostips.com/forum/viewtopic.php?f=3&t=6936
::     2. added powershell winsize to resize window
::     3. simplified labels definition, format and colors
::     4. unset PAUSE on DEBUG, one may want DEBUG REMOTE
::     5. auto jump disabled option with DO WHILE emulation
::     7. enable disabled sub-options when selecting top option
:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::

:: set local folders
set rootDir=%CD%
set LOGS=%rootDir%\logs
md %LOGS% 2>NUL
set LOG=%LOGS%\%~n0.log
set EXAMPLE_LocalFolder=%rootDir%\install-product-files

:: TMP files management - RANDOM everytime because of file lock by our friend cmd.exe
set TMPFILE=%LOGS%\%~n0.%RANDOM%.tmp.txt
set TMPWARN=%LOGS%\%~n0.warning.%RANDOM%.tmp.log
set TMPERR=%LOGS%\%~n0.error.%RANDOM%.tmp.log
set remoteVersionsAvailable=%LOGS%\%~n0.remoteVersionsAvailable.txt
set versionsSelected=%LOGS%\%~n0.versionsSelected.tmp.txt

:start
IF DEFINED DEBUG echo %TIME% :start

:: when connected remotely via a LocalSystem agent, USERNAME=COMPUTERNAME$
IF [%USERNAME:~-1%]==[$] set AUTOMATED=true
IF NOT [%1]==[] (set AUTOMATED=true) ELSE (title %~n0 %version% - %COMPUTERNAME% - %USERNAME%@%USERDNSDOMAIN% %USERDOMAIN%)
IF DEFINED AUTOMATED call :arguments %*
IF %ERRORLEVEL% EQU 99 exit /b 0
call :detect_winVersion
IF NOT DEFINED AUTOMATED call :set_colors
call :prechecks

:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: defaults - set your defaults here
:: include your default values here
:defaults
:: Windows Vista / 2012 and below: fallback for absence of colors
IF "%RC%"=="" (set "cursor=^>") ELSE set "cursor= "

:: width of your menu labels
set labelWidth=40

:: width of your indentations
set tabWidth=2

:: how many levels for your sub-menus?
set maxLevels=5

:: comment the line below to always export every options so the "export" column won't be used
set alwaysExportAll=alwaysExportAll

:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: defaults

:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: menu content
:menuContent

:::::::::::::::::::::::::::::::::::::::::::::::::::::::::
:: pre-selections: 1st field, chose what is pre-selected at start;
:: Each variable 'installXX' is a selector in the menu
:: No field can be NULL because for loop considers multiple separators as a single one
:: field 5 = set of versions available for each option in the nenu
:: It is good practice to set field 3 = product codes all the same length
:: field 4 = color includes a space as first char for color backward compatibility with previous versions of Windows
:::::::::::::::::::::::::::::::::::::::::::::::::::::::::
:: in this example, we also have submenu parents which won't be used, 
:: it all depends on what you want to do after the options are passed back to main.
:::::::::::::::::::::::::::::::::::::::::::::::::::::::::
set "switch="
set "endHeader="
REM ::                    1=b ;  2=c   ;  4=d   ;   3=e    4=f  ;   5=g    ;  6=h
REM :: labelLine format = tab ; select ; export ; product color ; versions ; label
REM set options=1;x;Tools;   ;tools + Rkit ^(cannot remove^)
set           options=1;x;Y;AA; %y%;3.3.0.12 3.2.4.0;AA label             
set options=%options%/2; ;Y;AA1; %y%;3.5.5.3-US;AA1              
set options=%options%/1; ;Y;BB; %y%;1.6.2.11 1.6.2.8;BB label             
set options=%options%/1; ;Y;CC; %y%;5.1.0.67 5.1.0.52 5.1.0.49;CC label             
set options=%options%/2; ;Y;CC1; %y%;5.1.2.30-US 5.1.1.1-US;CC1              
set options=%options%/0; ;Y;spacer; %w%; ; This line is a spacer
set options=%options%/1; ;Y;PA; %y%;5.0.1.34;PA label             
set options=%options%/2; ;Y;PA1; %w%;UFRII_v2.10 PCL6_v2.00;PA1 Submenu 1 xyz         
set options=%options%/2; ;N;PA2ParentWontBeUsed; %w%; ;PA2 Submenu Parent       
set options=%options%/3;x;Y;PA3; %w%;PCL6;PA3 Submenu 2-1 xyz      
set options=%options%/3;x;Y;PA4; %w%;UFRII;PA4 Submenu 2-2 xyz      
set options=%options%/2; ;Y;PB; %w%;1 2 3;xPB label                
set options=%options%/1; ;N;SQLParentWontBeUsed; %w%;2017 2016 2014;SQL Parent menu                
set options=%options%/2;x;Y;SQL1; %w%; ;SQL1                           
set options=%options%/2;x;Y;SQL2; %w%; ;SQL2                           
set options=%options%/0; ;Y;spacer; %w%; ; This line is a spacer
set options=%options%/1; ;Y;EXAMPLEsmthAndReloadMenu; %w%; ;Update available remote versions     

:: calculate number of options here
REM for %%a in ("%options:/=" "%") do set /A lastOption+=1
for %%a in ("%options:/=" "%") do set /A totalOptions+=1

:: :detect_local_installs must be done before options definition and after options defaults
call :detect_local_installs %*

:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: menu content
IF NOT DEFINED AUTOMATED call :winsize 120 40 120 9997
REM IF NOT DEFINED DEMO call :EXAMPLE_setupSomeStuff
REM IF DEFINED AUTOMATED call :EXAMPLE_alterVersionsAvailableInMenu & goto :main


:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: menu loop
:menu
:: you could alter the menu options before loading it, here:
REM call :EXAMPLE_alterVersionsAvailableInMenu

:: define tabbed indentations spaces here:
call :vmenu_setTabbedSpaces

:: menu needs to be redrawn with a goto
goto :vmenu_header
REM IF /I NOT [%choice%]==[n] goto :menu
:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: menu loop


:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: main program
:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: main program
:: from here, no user interaction no more
:main
IF DEFINED VERBOSE echo %TIME% :main

IF DEFINED DEBUG echo call :vmenu_decodeOptions %select%
:: STEP 1: decode binary shift encoded options + setup install{product} and version{product} variables
call :vmenu_decodeOptions %select%

:: STEP 2: (optional) copyParentVersions from Parent menu items into their children
:: the EXAMPLE below will for example, copy the Parent submenu version into its children with empty version.
call :vmenu_copyParentVersions-EXAMPLE

:: EXAMPLE: (optional) menu loop after alteration
:: if installEXAMPLEsmthAndReloadMenu is chosen as an option, 
:: it will call a routine that will alter the menu/versions and then reload the menu
IF "%installEXAMPLEsmthAndReloadMenu%"=="x" call :installsmthAndReloadMenu-EXAMPLE & goto :menu

:: STEP 3: (optional) visualize the options finally selected with their version
call :vmenu_listOptions %select%

:: STEP 4: (optional) validate each version
:: EXAMPLE: :select_versions routine will ask user to post-modify/validate each version selected
call :select_versions

echo menu selection is over. Call your routines here...
REM call :routine1
REM call :routine2
REM call :routine3

pause
goto :end
:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: main program
:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: main program



:installsmthAndReloadMenu-EXAMPLE
echo do something here to alter the menu options
goto :EOF

:arguments %*
IF DEFINED DEBUG echo %HIGH%%c% %~0 %END%%c% %* %END%

IF /I [%1]==[version]           echo version=%version% & exit /b 99

call :USAGE & exit /b 99
goto :EOF

:USAGE
echo Usage:    %~n0 [ help ^| version ^| whatever you like]
goto :EOF


::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
:: start of magic vmenu
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
:vmenu_header
  cls
  IF DEFINED DEBUG echo %TIME% %~0
  REM echo(%nbsp%
  call :your-logo-here
  REM echo/
  REM echo Example of Check List / Radio Button
  REM echo/
  echo Move selection lightbar with these cursor keys:
  echo Home/End = First/Last, Up/Down = Prev/Next, or via option's first letter, Left/Right = set Version
  echo                                                     selected     local
  echo      [x] tools + Rkit ^(cannot remove^)             ----------- + ----------
  %endHeader%

  if defined switch set "switch=/R"
  call :vmenu_CheckList select="%options%" %switch%
  echo/
  echo/
  if "%select%" equ "0" goto :vmenu_endProg
  if DEFINED DEBUG echo   DEBUG: Binary Options sum: %select%
  
:: example loop
goto :main
:vmenu_endProg
goto :EOF


:vmenu_CheckList select= "option1/option2/..." [/R]
setlocal EnableDelayedExpansion
:: vmenu subroutine activates a CheckList/RadioButton form controlled by cursor control keys
:: RadioButton is now certainly broken but I keep its original code for history purpose

:: %1 = Variable that receive the selection
:: %2 = Options list separated by slash
:: %3 = /R (switch) = Radio Button (instead of Check List)

:: Process /R switch
if /I "%~3" equ "/R" (
  set "Radio=1"
  set "unmark=( )" & set "mark=(o)"
) else (
  set "Radio="
  set "unmark=[ ]" & set "mark=[x]"
)

:: Separate options
set "options=%~2"
set "lastOption=0"
for %%a in ("%options:/=" "%") do (
  set /A lastOption+=1
  set labelLine=%%~a

  REM ::                    1=b ;  2=c   ;  4=d   ;   3=e    4=f  ;   5=g    ;  6=h
  REM :: labelLine format = tab ; select ; export ; product color ; versions ; label
  for /F "tokens=1-6* delims=;" %%b in ("!labelLine!") do (
    set "tab[!lastOption!]=%%~b"
    set "tabs[!lastOption!]=!tabSpaces[%%~b]!"

    REM :: grab selected products and options: an "x" marks the bounty
    set "select[!lastOption!]=[%%~c]"
    set "install%%e=%%~c"
    
    REM :: compatibility with Vista/Server 2012 and below: no colors available
    set export[!lastOption!]=%%~d
    
    REM :: compatibility with Vista/Server 2012 and below: no colors available
    set color=%%~f
    set labelColor[!lastOption!]=!color:~1!
    
    REM :: versions used in the right column carousel
    set "versions=%%~g"
    set "versions[!lastOption!]=%%~g"
    REM :: IMPORTANT: this is where we get the local detected versions found by :detect_local_installs
    call set "versionsFound[!lastOption!]=%%versionsFound%%~e%%"

    set numVersions=0
    set firstVersion=
    set move2Version[!lastOption!]=0
    for %%v in (!versions!) DO (
      set /A numVersions+=1
      IF "!firstVersion!"=="" (
        set firstVersion=done
        set "version[!lastOption!]=%%v"
        set move2Version[!lastOption!]=1
      )
    )
    set numVersions[!lastOption!]=!numVersions!
    REM set labelVersions[!lastOption!]=!thisLabelVersions!
    
    REM :: add spaces after label to LEFT trim it after
    set label=%%~h                                             
    REM :: calculate the label width and setup toggles
    IF %%~b EQU 0 (
      set "toggle[!lastOption!]=off"
    ) ELSE (
      set "toggle[!lastOption!]=on"
      
      REM :: auto-calculate label width based on tabbing
      call set "option[!lastOption!]=%%label:~0,!labelWidth[%%~b]!%%"
    )
  )

  REM :: Below we setup selected menu item with 
  REM :: the line below is real genius as it's a Unix like command expansion in a variable!
  call set "moveSel[%%option[!lastOption!]:~0,1%%]=set sel=!lastOption!"
)
for /L %%j in (1,1,%totalOptions%) DO IF !tab[%%j]! EQU 1 call :vmenu_toggleColor %%j %totalOptions%

if defined Radio set "select[1]=%mark%"

:: Define powershell vmenu working variables
for %%a in ("Enter=13" "Esc=27" "Space=32" "Endd=35" "Home=36" "LeftArrow=37" "RightArrow=39" "UpArrow=38" "DownArrow=40" "LetterA=65" "LetterZ=90") do set %%a
set "letter=ABCDEFGHIJKLMNOPQRSTUVWXYZ"

:: findstr trick - for Server 2012 and under
REM for /F %%a in ('echo prompt $H ^| cmd') do set "BS=%%a"
REM echo %BS%%BS%%BS%%BS%%BS%%BS%      >_

:: Define movements for standard keys
:: Also define left/right options for versions
set "sel=1"
set "moveSel[%Home%]=set sel=1"
set "moveSel[%Endd%]=set sel=%lastOption%"
set "moveSel[%UpArrow%]=set /A sel-=^!^!(sel-1)"
set "moveSel[%DownArrow%]=set /A sel+=^!^!(sel-lastOption)"

:: Read keys via PowerShell  ->  Process keys in Batch
set /P "=Loading vmenu..." < NUL
PowerShell -executionPolicy bypass -Command ^
  Write-Host 0;  ^
  $validKeys = %Endd%..%Home%+%LeftArrow%+%RightArrow%+%UpArrow%+%DownArrow%+%Space%+%Enter%+%Esc%+%LetterA%..%LetterZ%;  ^
  while ($key -ne %Enter% -and $key -ne %Esc%) {  ^
    $key = $Host.UI.RawUI.ReadKey('NoEcho,IncludeKeyDown').VirtualKeyCode;  ^
    if ($validKeys.contains($key)) {Write-Host $key}  ^
  }  ^
%End PowerShell%  |  "%~F0" vmenu_OptionSelection

:::::::::::::::::::::::::::::::::::::::::::::::::::::::::
:::::::::::::::::::::::::::::::::::::::::::::::::::::::::
:: THIS IS WHERE WE PASS SELECTED OPTIONS BACK TO :MAIN
:: %1 is actually "select" passed as 1st arg to this routine, since '=' sign counts as MSDOS separator
:: The trick below is called Passing variables from one routine to another: https://ss64.com/nt/endlocal.html
:: By attaching '&' to endlocal, we are able to SET a (group of) variables just before the localisation is ended
:::::::::::::::::::::::::::::::::::::::::::::::::::::::::
endlocal & set "%~1=%errorlevel%"

:: another way of passing more variables to the parent shell:
REM Endlocal&(
REM set "%~1=%errorlevel%"
REM set "versions=%version[1]% %version[2]% %version[3]%")
:::::::::::::::::::::::::::::::::::::::::::::::::::::::::
:::::::::::::::::::::::::::::::::::::::::::::::::::::::::

:: findstr trick
REM del _
exit /B


:vmenu_toggle sel maxSel
if defined Radio (
  set "select[%Radio%]=%unmark%"
  set "select[%1]=%mark%"
  set "Radio=%1"
) else (
  if "!select[%1]!" equ "%unmark%" (
    set "select[%1]=%mark%"
  ) else (
    set "select[%1]=%unmark%"
  )
  
  call :vmenu_toggleColor %1 %2
)
exit /B


:vmenu_toggleColor sel maxSel
REM :: below we en(dis)able sub-options based on their tab[%%j] value
set lastOne=0
set /A "nextSel=%1+1"
IF "!select[%1]!"=="%mark%" (set toggleNext=on) ELSE set toggleNext=off

for /L %%j in (%nextSel%,1,%2) DO (
  REM :: stop processing if %%j < lastOne
  IF NOT %%j LEQ !lastOne! (
    REM :: stop processing if next tab is ==root
    IF !tab[%%j]! EQU !tab[%1]! exit /b
    REM :: stop processing if next tab is root==1 or ==itself
    IF !tab[%%j]! LSS 2 exit /b
    
    :: at this point, %%j tab is 100% > sel tab
    set "toggle[%%j]=%toggleNext%"
    set lastOne=%%j
    IF "!select[%%j]!%toggleNext%"=="%unmark%on" call :vmenu_toggleColor %%j %2
  )
)
exit /B


:vmenu_OptionSelection
setlocal EnableDelayedExpansion

rem Wait for PS code start signal
set /P "keyCode="
set /P "="

set "endHeader=exit /B"
:vmenu_ReDraw
:: vmenu_ReDraw draws every line after each key press
:: Clear the screen and show the list:
call :vmenu_header

  REM :: anti flicker trick: doesn't work
  REM echo(%nbsp%
  < NUL (for /L %%i in (1,1,%lastOption%) do (
      set "num=  %%i"
      set "labelVersion=!version[%%i]!                    "
      set "labelversionsFound=!versionsFound[%%i]!                    "
      IF DEFINED DEBUG (
        set ddebug=!toggle[%%i]!    !move2Version[%%i]!
        set ddebugToggle=!toggle[%%i]!    !move2Version[%%i]!
        echo !ddebugToggle!>>ggg
      )
      if !tab[%%i]! EQU 0 (
        REM :: spacer
        echo.!ddebug!
      ) ELSE (
        if "!toggle[%%i]!" equ "off" (
          REM :: this line is disabled:
          echo  !num:~-2!!tabs[%%i]!%HIGH%%k%!select[%%i]! !option[%%i]! !labelVersion:~0,11!%END% ^| !labelversionsFound:~0,20!!ddebug!
          ) ELSE (
          if "%%i" equ "%sel%" (
            REM :: this line is active AND highlighted
            
            REM :: findstr trick
            REM set /P "=%k%!tab[%%i]!%END%!num:~-2! !select[%%i]!  "
            REM findstr /A:17 . "!option[%%i]!\..\_" NUL
            
            REM :: We show horizontal carousel only if there is more than one version available;
            REM :: also we want to show the direction where the other versions are
            IF !numVersions[%%i]! GTR 1 (
              IF !move2Version[%%i]! EQU !numVersions[%%i]! (
                REM :: last version is shown
                echo %cursor%!num:~-2!!tabs[%%i]!!select[%%i]!%cursor%%RC%%k%!option[%%i]!%END%^<%RB%%w%!labelVersion:~0,11!%END%]^| !labelversionsFound:~0,20!!ddebug!
              ) ELSE (
                IF !move2Version[%%i]! EQU 1 (
                  REM :: first version is shown
                  echo %cursor%!num:~-2!!tabs[%%i]!!select[%%i]!%cursor%%RC%%k%!option[%%i]!%END%[%RB%%w%!labelVersion:~0,11!%END%^>^| !labelversionsFound:~0,20!!ddebug!
                ) ELSE (
                  REM :: middle versions are shown
                  echo %cursor%!num:~-2!!tabs[%%i]!!select[%%i]!%cursor%%RC%%k%!option[%%i]!%END%^<%RB%%w%!labelVersion:~0,11!%END%^>^| !labelversionsFound:~0,20!!ddebug!
                )
              )
            ) ELSE (
              REM :: only one version is shown
              echo %cursor%!num:~-2!!tabs[%%i]!!select[%%i]!%cursor%%RC%%k%!option[%%i]!%END%[!labelVersion:~0,11!%END%]^| !labelversionsFound:~0,20!!ddebug!
            )
          ) else (
            REM :: this line is active but not highlighted
            IF "!select[%%i]!"=="%unmark%" (set versionColor=) ELSE set versionColor=%HIGH%
            echo  !num:~-2!!tabs[%%i]!!select[%%i]! !labelColor[%%i]!!versionColor!!option[%%i]! !labelVersion:~0,11!%END% ^| !labelversionsFound:~0,20!!ddebug!
          )
        )
      )
    )
  )
  echo/
  set /P "=Space=(De)Select, Enter=Continue, Esc=Cancel" < NUL

  REM :: Get a keycode from PowerShell
  set /P "keyCode="
  set /P "="

  REM :: Process it: check for action keys
  if %keyCode% equ %Enter% goto :vmenu_encodeSelection
  if %keyCode% equ %Esc% exit 0
  
  REM :: we process Left/Right only if numVersions > 1
  IF !numVersions[%sel%]! GTR 1 (
    set lastVersion=0
    if %keyCode% equ %LeftArrow% (
      for %%v in (!versions[%sel%]!) DO (
        set /A lastVersion+=1
        IF "!version[%sel%]!"=="%%v" IF !lastVersion! GTR 1 set /A "move2Version[%sel%]-=1"
      )
    )
    if %keyCode% equ %RightArrow% (
      for %%v in (!versions[%sel%]!) DO (
        set /A lastVersion+=1
        IF "!version[%sel%]!"=="%%v" IF !lastVersion! LSS !numVersions[%sel%]! set /A "move2Version[%sel%]+=1"
      )
    )
    
    REM :: below we flip-switch the version after Left/Right is pressed
    IF !lastVersion! GTR 0 (
      REM :: The trick below can be used to rotate versions indefinitely back and forth:
      REM IF !move2Version! GTR !lastVersion! set move2Version=1
      REM IF !move2Version! LEQ 0 set move2Version=!lastVersion!
      set lastVersion=0
      
      REM :: Cannot use '!' in the tokens= part, that's too bad:
      REM for /f "tokens=%move2Version[!sel!]%" %%v in ("!versions[%sel%]!") DO set "version[%sel%]=%%v" & set "versionsFound[%sel%]=%%v"
      
      REM :: Using ! for the calculated token doesn't work, you need a full-fledge loop with increment
      for %%v in (!versions[%sel%]!) DO (
        set /A lastVersion+=1
        IF !lastVersion! EQU !move2Version[%sel%]! set "version[%sel%]=%%v"
      )
    )
  )
  
  REM :: below we (un)mark options after space is pressed
  if %keyCode% equ %Space% (
    call :vmenu_toggle %sel% %lastOption%
    goto :vmenu_ReDraw
  )

  REM :: Process it: check for move keys
  if %keyCode% lss %LetterA% goto :vmenu_jumpSelection
  REM :: Below we process pressed key from A-Z
  REM :: Last Letter option wins when multiple labels start with same Letter
  set /A keyCode-=LetterA
  set "keyCode=!letter:~%keyCode%,1!"
  :vmenu_jumpSelection
  !moveSel[%keyCode%]!
  REM :: jump next one if this is a spacer - first and last options cannot be a spacer
  REM :: BUG: this works only for Arrows Up/Down, for Letters you actually can end on a disabled option
  if "!toggle[%sel%]!"=="off" !moveSel[%keyCode%]!

  REM :: jump next one if this is disabled - DO WHILE emulation
  REM :: This cannot work if first or last option is disabled
  :vmenu_whileDisabled
  IF DEFINED DEBUG call echo toggle[%sel%]=!toggle[%sel%]! %lastOption%   moveSel[%keyCode%]=!moveSel[%keyCode%]!>>ggg
  REM :: the loop below will jump to next selection that's enabled when pressing a Letter,
  REM :: if the letter leads to a disabled option, by forcing using an Arrow instead
  if "!toggle[%sel%]!" equ "off" (
    if %keyCode% GEQ %LetterA% (
      if %sel% lss %lastOption% (set keyCode=38) ELSE set keyCode=40
      !moveSel[%keyCode%]!
    )
  ) ELSE goto :vmenu_whileEnd
  REM keyCode 40 = up, 38 = down
  if %keyCode% equ 38 (set /A "sel-=1") ELSE set /A "sel+=1"
  goto :vmenu_whileDisabled
  :vmenu_whileEnd

  REM :loop_antiflicker
  REM if "%time:~-1%"=="!time:~-1!" goto :loop_antiflicker
goto :vmenu_ReDraw

:::::::::::::::::::::::::::::::::::::::::::::::::::::::::
:: :vmenu_encodeSelection will create the binary encoded errorlevel used by :vmenu_decodeOptions
:::::::::::::::::::::::::::::::::::::::::::::::::::::::::
:vmenu_encodeSelection
set "sel="
del /f /q %versionsSelected% >NUL 2>NUL
:: We need to process options in reverse order because that's how we'll pop then out of the errorlevel
for /L %%i in (1,1,%lastOption%) do (
  REM :: we always export all versions because we process every options in reverse order
  echo "!version[%%i]!">>%versionsSelected%
  
  REM :: 1<<x = 2 power x
  REM :: To get the original selections, just for loop in reverse and substract each power values of 2
  REM :: We also make sure we select only those which are not disabled by checking for !toggle[%%i]!
  if "!select[%%i]!!toggle[%%i]!" equ "%mark%on" (
    REM :: We also export only the products tagged "Y" for export unless alwaysExportAll is set
    REM :: Beware: by doing so, you do not export Parent menu items and cannot copy their version into their children in :vmenu_copyParentVersions
    if /I "%alwaysExportAll%"=="alwaysExportAll" (
      set /A "sel+=1<<%%i"
    ) ELSE (
      if /I "!export[%%i]!"=="Y" (
        set /A "sel+=1<<%%i"
      )
    )
  )
)

if NOT DEFINED sel set "sel=0"
:: BUG: there is a MAX value for %sel%: ERRORLEVEL cannot be higher than 1357508192 > 2^30 = 30 options maximum
exit %sel%
:::::::::::::::::::::::::::::::::::::::::::::::::::::::::
:::::::::::::::::::::::::::::::::::::::::::::::::::::::::

:vmenu_decodeOptions %select%
IF DEFINED DEBUG echo %~0 %1 with lastOption=%lastOption%
:: %binarySum% is a binary addition: sum of all selected options as power of 2
:: BUG: there is a MAX value for binarySum: ERRORLEVEL cannot be higher than 1357508192 > 2^30 = 30 options maximum
set binarySum=%1

:: Separate options
:: TODO: this could be exported as a separate routine since we need that to reverse option selections
set "lastOption=0"
for %%a in ("%options:/=" "%") do (
  REM ::                    1=b ;  2=c   ;  4=d   ;   3=e    4=f  ;   5=g    ;  6=h
  REM :: labelLine format = tab ; select ; export ; product color ; versions ; label
  set /A lastOption+=1
  set labelLine=%%~a
  for /f "tokens=1-6* delims=;" %%b in ("!labelLine!") do (
    set product[!lastOption!]=%%~e
  )
)

:: decode each option
:: %select% is a binary addition: sum of all selected options as power of 2
for /L %%i in (%lastOption%,-1,1) do (
  REM :: overwrite whatever install is detected first:
  call set install!product[%%i]!= 
  set /A "thisOne=1<<%%i"
  REM :: (sign bit -> 0) An arithmetic shift: https://ss64.com/nt/set.html
  REM :: { 1 Lsh 1 = binary 01 Lsh 1 = binary 010   = decimal 2 }
  REM :: { 1 Lsh 2 = binary 01 Lsh 2 = binary 0100  = decimal 4 }
  REM :: { 1 Lsh 3 = binary 01 Lsh 3 = binary 01000 = decimal 8 }
  REM :: etc
  IF !binarySum! GEQ !thisOne! (
    REM :: substract arithmetic shift from binarySum and continue
    REM :: by doing so, we extract each selected option. There is a limit tho:
    set /A "binarySum-=1<<%%i"
    call set install!product[%%i]!=x
  
    REM :: grab selectedVersion for product[%%i]
    set line=0
    for /F %%v in (%versionsSelected%) do set /A line+=1 && IF !line! EQU %%i call set "version!product[%%i]!=%%~v"
    IF DEFINED DEBUG call echo   DEBUG1: Now we can execute option %%i = install!product[%%i]! with version version!product[%%i]!=%%version!product[%%i]!%%
  )
)
goto :EOF

:vmenu_copyParentVersions-EXAMPLE
IF DEFINED DEBUG echo %~0 %1 with lastOption=%lastOption%
:: EXAMPLE: post-process options 
:: This example will attribute parent selection version to its children with empty version.
:: Don't use it if you are OK with products with empty versions
echo.
for /L %%n in (1,1,%lastOption%) do (
  call set "install=%%install!product[%%n]!%%"
  IF "!install!"=="x" (
    call set "thisVersion=%%version!product[%%n]!%%"
    IF NOT "!thisVersion!"=="" (
      set lastVersion=!thisVersion!
    ) ELSE (
      call set "version!product[%%n]!=!lastVersion!"
    )
    IF DEFINED DEBUG call echo   DEBUG2: Now we can execute option %%n = install!product[%%n]! with version version!product[%%n]!=%%version!product[%%n]!%%
  )
)
goto :EOF

:vmenu_setTabbedSpaces
for /L %%L in (1,1,%maxLevels%) DO (
  for /L %%s in (1,1,%tabWidth%) DO (
    set "tabSpaces=!tabSpaces! "
  )
  set "tabSpaces[%%L]=!tabSpaces!"
  set /A "labelWidth[%%L]=labelWidth-thisTabWidth"
  set /A thisTabWidth=thisTabWidth+tabWidth
)

goto :EOF

:vmenu_listOptions %select%
IF DEFINED DEBUG echo %~0 %1 with lastOption=%lastOption%
set binarySum=%1

:: %select% is a binary addition: sum of all selected options as power of 2
echo.
for /L %%i in (%lastOption%,-1,1) do (
  set /A "thisOne=1<<%%i"
  IF !binarySum! GEQ !thisOne! (
    set /A "binarySum-=1<<%%i"
    IF DEFINED DEBUG call echo   DEBUG3: Now we can execute option %%i = install!product[%%i]! with version version!product[%%i]!=%%version!product[%%i]!%%
  )
)
goto :EOF

::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
:: end of magic menu
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::


:prechecks
IF DEFINED DEBUG echo %HIGH%%c% %~0 %END%%c% %* %END%
del /f /q %LOGS%\%~n0.*.tmp.* 2>NUL

for %%x in (powershell.exe) do (set powershell=%%~$PATH:x)
IF NOT DEFINED powershell call :error %~0: powershell NOT FOUND

:: test %TMP% exist and write access, i've seen cases where %TMP% is set but actually don't exist
echo]>%TMPFILE%
IF %ERRORLEVEL% NEQ 0 call :error %~0: NO writeable folder found, please logoff to reload environment... EXIT & %PAUSE% & exit

goto :EOF



:::::::::::::::::::::::::::::::::::::::::::::::: technical functions
:detect_winVersion
IF DEFINED DEBUG echo %HIGH%%c% %~0 %END%%c% %* %END%
set osType=workstation
wmic os get Caption /value | findstr Server >%TMPFILE%
IF %ERRORLEVEL% EQU 0 set osType=server

:: https://www.lifewire.com/windows-version-numbers-2625171
IF [%osType%]==[workstation] (
  ver | findstr /C:"Version 10.0" && set WindowsVersion=10& goto :EOF
  ver | findstr /C:"Version 6.3" && set WindowsVersion=8.1& goto :EOF
  ver | findstr /C:"Version 6.2" && set WindowsVersion=8& goto :EOF
  ver | findstr /C:"Version 6.1" && set WindowsVersion=7& goto :EOF
  ver | findstr /C:"Version 6.0" && set WindowsVersion=Vista& goto :EOF
  ver | findstr /C:"Version 5.1" && set WindowsVersion=XP& goto :EOF
) ELSE (
  for /f "tokens=4" %%a in (%TMPFILE%) do set WindowsVersion=%%a
)
goto :EOF

:set_colors
set colorCompatibleVersions=-8-8.1-10-2016-2019-
IF DEFINED WindowsVersion IF "!colorCompatibleVersions:-%WindowsVersion%-=_!"=="%colorCompatibleVersions%" goto :EOF


goto :EOF
:: BUG: some space are needed after :set_colors


:your-logo-here
echo.
echo.
echo    %y%                    __   __                  __        __   ___  __  tm
echo    %y%                   ^|  \ /  \ ^|  ^| ^|\ ^| ^|    /  \  /\  ^|  \ ^|__  ^|__) 
echo    %y%                   ^|__/ \__/ ^|/\^| ^| \^| ^|___ \__/ /~~\ ^|__/ ^|___ ^|  \ 
echo    %c%   ,;            
echo    %c% `7MMpMMMb.pMMMb.
echo    %c%   MM    MM    MM
echo    %c%   MM    MM    MM
echo    %c%   MM    MM    MM
echo    %c% .JMML  JMML  JMML
echo.%END%
goto :EOF


:error "msg"
echo.%r%
echo ==============================================================
echo %HIGH%%r%  ERROR:%END%%r% %*
IF /I [%2]==[powershell] echo %y%Consider install Management Framework at https://support.microsoft.com/en-us/help/968929/ %r% 1>&2
echo ==============================================================
echo.%END%
IF NOT DEFINED AUTOMATED pause
exit
goto :EOF
:::::::::::::::::::::::::::::::::::::::::::::::: technical functions


:select_versions
IF DEFINED DEBUG echo %HIGH%%c% %~0 %END%%c% %* %END%

:: manually re-validate each version:
set choice=n
set /P choice=Would you like to manually validate each version? [%HIGH%%y%%choice%%END%] 
IF /I NOT "%choice%"=="n" (
  for /L %%n in (1,1,%lastOption%) do (
    call set "install=%%install!product[%%n]!%%"
    IF "!install!"=="x" (
      call set "thisVersion=%%version!product[%%n]!%%"
      set /P version!product[%%n]!=version!product[%%n]!? [%HIGH%%m%!thisVersion!%END%] 
    )
  )
)

:: manually re-validate each product's download file:
IF %POPUP%==true (set havePOPUP=y) ELSE (set havePOPUP=n)
set /P havePOPUP=POPUP files list before download? [%HIGH%%y%%havePOPUP%%END%] 
IF /I "[%havePOPUP%]"=="[y]" (set POPUP=true) ELSE (set POPUP=false)

:: EXAMPLE: post-process some product's versions to shorten them for some reason:
:: PRODUCTx short versions are used in main download section for platform.ini files: !%%ax%!
for %%P in (BB CC PA) DO call set %%Px=%%%%Pversion:~0,1%%

:: EXAMPLE: special cases for some other products:
set SQL1x=%SQL1version%
set SQL2x=%SQL1version%
set AAx=%AAversion:~0,3%

echo.
goto :EOF



:detect_local_installs %*
IF DEFINED DEBUG echo %HIGH%%c% %~0 %END%%c% %* %END%

:: detect what's present to pre-check options
:: 3 different detection patterns: your needs, your choice!
for %%P in (AA BB CC PA AA1 CC1) DO (
  for /f "tokens=3 delims=-" %%v in ('dir /b install-%%P-*-product.ini 2^>NUL') DO (
    CALL set install%%P=x
    CALL set versionsFound%%P=%%v
  )
)
for %%P in (PA1 PA2 PA3 PA4) DO (
  IF EXIST %EXAMPLE_LocalFolder%\PA\%%P\ (
    CALL set install%%P=x
    CALL set versionsFound%%P=%%v
  )
)
for %%P in (SQL1 SQL2) DO (
  for /f "tokens=3 delims=-" %%v in ('dir /b install-%%P-*-platform.ini 2^>NUL') DO (
    CALL set install%%P=x
    CALL set versionsFound%%P=%%v
  )
)
goto :EOF



:: :winsize  winWidth  winHeight  bufWidth  bufHeight
:winsize
:: Console Resize values via PowerShell (changeable)
SET "_PSResize=100 54 100 9997"
IF NOT [%4]==[] SET "_PSResize=%1 %2 %3 %4"

:: Check for powershell via PATH variable
REM POWERSHELL "Exit" >NUL 2>&1 && SET "_PS=1"
REM IF NOT DEFINED _PS (ECHO No&do something) ELSE (ECHO Yes&do something)
 
:: PS-Console Resizing
REM IF DEFINED _PS CALL:_PS_ReSize %_PSRESIZE%
CALL :_PS_ReSize %_PSRESIZE%
goto :EOF

:: :_PS_Resize  winWidth  winHeight  bufWidth  bufHeight
:_PS_Resize
:: Mode sets buffer size-not window size
MODE %1,%2

:: resize
powershell -executionPolicy bypass -Command "&{$H=get-host;$W=$H.ui.rawui;$B=$W.buffersize;$B.width=%3;$B.height=%4;$W.buffersize=$B;}"
goto :EOF

:end
IF DEFINED DEBUG echo :end
echo %DATE% %TIME% %HIGH%%c% %~0 %END%%c% %* %END% ------- THE END

pause
del /f /q %LOGS%\%~n0.*.tmp.* 2>NUL

Licence: GNU GPL3, share it or leave it

 

Bitcoin Wallet Security Is A Lie


 

So, you have decided to ignore that Bitcoin and cryptocurrencies are a Ponzi scheme? You decided to succumb to the sirens’ song and want a share of the virtual pie for your retirement? Creating a Bitcoin wallet is the first step to pour more money in the system and maintain the scheme alive, your are right.

Continue reading Bitcoin Wallet Security Is A Lie

My Talking Tom Hack Unlimited Diamonds


My Talking Tom Hack Unlimited Diamonds, Unlimited Coins, Unlimited Potions, Unlimited Tickets! No survey, no payment, no ads, totally FREE! Jailbreak hack!

Difficulty: 3/5

Jailbreak your iPhone, download some software, find out your iPhone IP address, connect via SSH, have changed the root password… If the a-b-c’s of jail-breaking didn’t scare the hell out of you, you can achieve this hack fingers in the nose!

Continue reading My Talking Tom Hack Unlimited Diamonds