ThinkPad P52s charging/Thunderbolt issues

Aug. 3, 2019, 10:55 p.m.

This morning after waking my ThinkPad P52s (Windows 10 x64) from sleep the following happened:

  1. The "A Thunderbolt controller has experienced a problem and cannot connect to devices or other computers until new firmware is installed" dialog box popped up several times. However, it no longer shows up. I believe (after some googling) this means the controller went into "safe mode" for some reason and will only accept firmware updates now.
  2. Both USB-C ports stopped working properly (peripherals connected to either of those ports are not functioning). I was able to use those ports just fine few days ago.
  3. The 65W Lenovo power adapter is now detected as "15W USB-C power" instead of "AC power". This results in batteries charging only when power consumption does not exceed 15W (i.e. when laptop is powered off or idle). Most likely due to the same reason the following message is now shown during every reboot: "The connected AC adapter has a lower wattage than the recommended model which was shipped with the system. To boot with the AC adapter, please connect the AC adapter which was shipped with the system. Press Esc to continue."

Thunderbolt controller is enabled in BIOS. "Thunderbolt in BIOS Assist Mode" is disabled.

It looks like Power Delivery is not being negotiated between the power adapter and the laptop due to (malfunctioning?) Thunderbolt controller.

What I've tried so far:

  • Plugging power adapter to both USB-C ports with the same result (see 3. above)
  • Updating OS to the latest version using Windows Update
  • Applying all the updates in Lenovo Vantage (including BIOS update to 1.22)
  • Re-installing the latest available version of Thunderbolt Software (
  • Re-installing and running the latest version of the Thunderbolt Firmware Update Tool ( The tool is not able to detect any Thunderbolt controllers and exits with the following message: "No active Thunderbolt(TM) controller found in the system or Thunderbolt(TM) software is not present in the system. Make sure you have Thunderbolt(TM) software installed. Then connect Thunderbolt(TM) device and retry." I can see it tries to use the "force power" feature to wake the controller without any success.
  • Tried booting into Ubuntu Linux and triggering "force power" myself with echo 1 >/sys/bus/wmi/devices/86CCFD48-205E-4A77-9C48-2021CBEDE341/force_power, but the controller does not show up under /sys/bus/thunderbolt. lspci just hangs for an unknown reason.
  • Disconnected the power source, took out the removable battery and disabled the internal battery in BIOS. Also tried disconnecting the internal battery by inserting a paperclip into the emergency-reset hole on the bottom of the laptop.

Unfortunately I do not have any true Thunderbolt peripherals (only USB 1.0/2.0 with USB-C adapter cables) to plug in an see if that will wake the Thunderbolt controller up.

It is unclear whether it is a hardware issue or some catch 22 with controller not waking up because it wants the firmware update and firmware update not being applied because the controller is not waking up.

UPD: Had the motherboard replaced few days ago which fixed the issue for myself. But it looks like Lenovo has acknowledged the issue and the fix for P52s is pending:

ICS stops working after a reboot

Dec. 29, 2018, 12:43 a.m.

There are numerous reports (first, second, third results on Google) on the Internet about an issue with Internet Connection Sharing in Windows 10. Since the 1607 release (or 1703 for some people) ICS stops working after a reboot. The only way to get it working again for me was to disable and then re-enable the sharing. Resetting Windows Firewall settings, suggested by some people, didn't work.

You can automate the disable/enable steps with a simple Powershell script run as a scheduled task on system startup, like this one:

$m = New-Object -ComObject HNetCfg.HNetShare

$private = $m.EnumEveryConnection |? { $m.NetConnectionProps.Invoke($_).Name -eq "Loopback0" }
$private_config = $m.INetSharingConfigurationForINetConnection.Invoke($private)

$public = $m.EnumEveryConnection |? { $m.NetConnectionProps.Invoke($_).Name -eq "Wi-Fi" }
$public_config = $m.INetSharingConfigurationForINetConnection.Invoke($public)


Start-Sleep 1


if you're after a quick and easy fix. Some users reported Windows Firewall filling up with duplicate rules created on every enable/disable of the ICS though.

There is a better fix, however.

Dissatisfied with all proposed workarounds I've tried searching for the reports on this issue on Microsoft TechNet directly. The issue has been there for years, so there are plenty.

One thread mentioned creating the DWORD HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\SharedAccess\EnableRebootPersistConnection registry key, setting it to 1 and setting the Internet Connection Sharing service startup type to "Automatic". This fixed the problem!

The mentioned registry key was introduced with the 1709 release in KB4054517. See KB4055559 for more information.

Synchronizing multiple subshells in Bash

Nov. 15, 2018, 9:23 p.m.

Let's suppose you want to diff outputs of two scripts which operate on the same resource (file). Compare contents of the file before and after a transformation in a single pass, for example.

With process substitution, like diff <(cat myfile) <(reformat myfile; cat myfile) both substitutions are started in separate subshells at the same time, so you would need a semaphore, to ensure the second process substitution is started after after the first one - otherwise you might hit a race condition.

One option is to use a named pipe for that, but it involves the creation (and cleanup) of the pipe device file.

Another option is to use a co-process (Bash 4+) for that. cat command running as the co-process would basically act as an anonymous pipe!

echo BEFORE >data.txt

    coproc cat

    diff -du \
        <(sleep 5; cat data.txt; echo >&"${COPROC[1]}") \
        <(read <&"${COPROC[0]}"; echo AFTER >data.txt; cat data.txt)

(sleep is for demonstration purposes only)

will output

--- /dev/fd/62  2018-11-15 21:41:17.771271807 +0000
+++ /dev/fd/61  2018-11-15 21:41:17.771271807 +0000
@@ -1 +1 @@

An exit code of a compound command and errexit

Sept. 25, 2018, 8:10 p.m.

Sometimes you may need to capture an exit code of a command while keeping the errexit option enabled during execution of that command.

|| rc=$? or wrapping the command in an if statement, does not work correctly for compound commands and functions as ||, if, while, etc. will completely disable the errexit option for that command, therefore failures in the middle of a function will not cause that function to fail.


set -euo pipefail

failing_fn () {
    return 5

complex_fn () {
    echo 'Should not see me'
complex_fn || rc=$?
echo "$rc"


Should not see me

One could use the PIPESTATUS trick, like complex_fn | cat; rc=${PIPESTATUS[0]} but it does not work with -o pipefail

Here's one of the ways to handle this:

set +e
(set -e; complex_fn)
set -e
echo "$rc"

outputs 5

This method also works with pipes and -o pipefail:

set +e
(set -e; true | complex_fn | true)
set -e
echo "$rc"

also outputs 5

Indirect variable references in Bash 4.3

Sept. 5, 2018, 7:58 a.m.

There is a way to declare (-n) a variable in Bash as a reference to another variable (kind of pointer). This allows us to pass multiple arrays to functions or create utility functions like:

# Check if variable is set. Will return true even when the value is an empty string.
# Usage: is_set VAR_NAME
is_set () {
    declare -n __var="$1"
    [[ "${__var+set}" = 'set' ]]


# Translate characters in a string
# Usage: translate STR FROM_CHARS TO_CHARS
translate () {
    declare str="$1"
    declare -n __from="$2"
    declare -n __to="$3"
    declare i

    [[ "${#__from[@]}" = "${#__to[@]}" ]] || return 1

    for i in "${!__from[@]}"; do

    printf '%s\n' "$str"
$ declare -a from=(a b)
$ declare -a to=(c d)

$ translate "abc" from to


pushopts () {
    declare -n __opts="$1"
    readarray -t __opts < <(shopt -po)

popopts () {
    declare -n __opts="$1"
    declare cmd
    for cmd in "${__opts[@]}"; do
        eval "$cmd"
$ set -e
$ pushopts BACKUP
$ set +e
$ popopts BACKUP
$ shopt -po errexit
set -o errexit

Backup/restore Bash options including errexit

Sept. 1, 2018, 11:49 p.m.

errexit is not propagated into command substitutions, so you cannot do this:

set -e
OPTS=$(shopt -po)

set +e

eval "$OPTS"

but it is propagated into process substitutions.

set -e

# Backup restore commands into an array
declare -a OPTS
readarray -t OPTS < <(shopt -po)

set +e

# Restore options
declare cmd
for cmd in "${OPTS[@]}"; do
    eval "$cmd"


$  shopt -po errexit
set -o errexit

BUG in the "time" Bash built-in?

Aug. 27, 2018, 12:55 a.m.

In Bash, time is a built-in reserved word you can prepend to a pipeline to measure the duration of executed commands. It implements a subset of features of the original time binary, but does not involve shelling-out. time built-in will output the measurements to STDERR. Under some circumstances (time is used to measure a failing function executed in a subshell with errexit enabled), the STDERR of time will leak into the executed command.


Let's define a couple of functions first

$ failing_fn () { false; }

$ successful_fn () { true; }

The following will result in measurements written into testfile (while it shouldn't, redirect happens in the subshell)

$  time (set -e; failing_fn 2>./testfile)
$  cat testfile

real    0m0.000s
user    0m0.000s
sys 0m0.000s

This does not happen if the subshell command is not a function

$  time (set -e; false 2>./testfile)

real    0m0.000s
user    0m0.000s
sys 0m0.000s
$  cat testfile

it also doesn't happen when the failing function does not fail the pipeline (errexit is not enabled)

$  time (set +e; failing_fn 2>./testfile)

real    0m0.000s
user    0m0.000s
sys 0m0.000s
$  cat testfile

or if the function is successful

$  time (set -e; successful_fn 2>./testfile)

real    0m0.000s
user    0m0.000s
sys 0m0.000s
$  cat testfile

or when we do not use time with the subshell syntax directly

$  time eval '(set -e; failing_fn 2>./testfile)'

real    0m0.001s
user    0m0.001s
sys 0m0.000s
$  cat testfile

Oddly enough, simply adding | cat to the pipeline inside the subshell will result in measurements output being duplicated into both STDERR of the current shell and STDERR of the subshell function

$  time (set -e; failing_fn 2>./testfile | cat)

real    0m0.001s
user    0m0.001s
sys 0m0.001s
$  cat testfile

real    0m0.001s
user    0m0.000s
sys 0m0.000s

and it works properly in case | cat and eval are present in the subshell (found this one by trial-and-error)

$  time (set -e; eval failing_fn 2>./testfile | cat)

real    0m0.001s
user    0m0.001s
sys 0m0.001s
$  cat testfile

Dynamic allocation of file descriptors in Bash

Aug. 26, 2018, 1:30 p.m.

Since Bash version 4.1 it is possible to dynamically allocate file descriptors greater than 10. Useful for redirections


$ testfn () { 
    echo "This is STDOUT"
    echo "This is STDERR" 1>&2

$ (
    # Annotate output of the current subshell so it is visible
    # which file descriptor it comes from
    exec 2> >(sed -e "s/^/STDERR:/") > >(sed -e "s/^/STDOUT:/")

    # Unmodified output

    # The folowing command will swap STDOUT and STDERR from testfn()
    { testfn 2>&${stderrfd} >&${stdoutfd}; } {stderrfd}>&1 {stdoutfd}>&2

    # Need to manually close the created descriptors after use
    exec {stderrfd}>&- {stdoutfd}>&-

Output is out of order because annotating processes run in async subshells

Arduino-based DIY DJ MIDI controller

July 25, 2018, 6:07 p.m.
Controller outside Controller inside

A while ago my daughter asked me to show her how beat-matching is done. Unfortunately we had no DJing equipment and even the entry-level MIDI controllers on Amazon are quite expensive. After some googling we've discovered projects like Fliper DJ and Traktorino, but the former wasn't quite what I've wanted and the later wasn't available at the time, so we've decided to build one ourselves.

Few knobs, buttons, wires, Arduino Uno (+ CD74HC4067 multiplexer) and here we go:

Project repository on GitHub contains the code and Traktor 2 mappings.

Portable one-liner to enable the Puppet noop mode

April 29, 2018, 2:08 a.m.
puppet resource augeas setnoop \
  "context=/files/etc/puppetlabs/puppet/puppet.conf/agent" \
  "changes=set noop true" \
&& { systemctl try-restart puppet || service puppet condrestart; }

Required variables in Makefile

April 26, 2018, 10:01 p.m.

Lazy set combined with $(error) will fail a recipe nicely if the user hasn't provided the value for the var

REQUIRED_VAR = $(error Please supply a value for REQUIRED_VAR)


April 13, 2018, 11:02 p.m.
  • powerline-shell is awesome!
  • Apparently oVirt supports CEPH via the Cinder integration and (since 4.2) via the Ceph iSCSI gateway
  • Libvirt network XML does support static routes on the host, but does not any exceptions to the automatic iptables firewall rules, which probably renders it useles for routing to isolated subnets (like Kubernetes cluster networks) via the VMs
  • Hashidays. Amsterdam, June 25-27


March 30, 2018, 12:26 p.m.


Puppet 4+, Foreman 1.14, and Fedora 27

March 22, 2018, 10:55 p.m.

Kickstart default template tries to install puppet-agent package in the %packages section, but the repo which is set up in the kickstart file only contains puppetlabs-release-pc1.

It looks like only Puppet 5 is supported on FC27. Puppet 5 repo package is available via different URL: and name: puppet-release


March 11, 2018, 2:06 p.m.

There is no right or wrong, just preferences

Concourse CLI

March 7, 2018, 10:41 p.m.

Well designed CLI interface: ./concourse web --help

Warmth - Dopamine

March 5, 2018, 12:12 a.m.

Testing in clojure

Feb. 9, 2018, 9:18 p.m.
  1. Unit-test pure functions only
  2. When dealing with impure functions - extract to pure ones as much as possible. Use dependency injection - this will allow you to use different back-ends later.
  3. Use external integration-testing (Robot, Cucumber, scripts, etc) for testing impure functions in your application

NetworkManager slave connections

Nov. 19, 2017, 3:07 a.m.

Do not use bond-slave, team-slave or bridge-slave as values for the connection.type property. These always default to to 802-3-ethernet connection types. Set specific type (802-3-ethernet or wifi, etc) and the connection.master and connection.slave-type properties instead.

Idempotent redirect to a file

July 6, 2017, 11:33 p.m.

Let's say you want to redirect the STDOUT of some command to a file (a config file for example) using the (bash) shell. In ideal case destination file should not be touched if it already has exactly the same content you are going to write into it. How to do that in a single pipe?

Here's how:

echo "New contents" | diff -duaN "$target_path" - | patch --binary -s -p0 "$target_path"

Full example

#!/usr/bin/env bash

set -eu -o pipefail

to_stderr () {
  >&2 cat

printable_only () {
  tr -cd '\11\12\15\40-\176'

pipe_debug () {
  tee >(printable_only | to_stderr)

to_file () {
  local target_path="$1"
  local restore_pipefail

  # diff will return non-zero exit code if file differs, therefore
  # pipefail shell attribute should be disabled for this
  # special case
  restore_pipefail=$(shopt -p -o pipefail)
  set +o pipefail

  diff -duaN "$target_path" - | pipe_debug | patch --binary -s -p0 "$target_path"

  eval "$restore_pipefail"

md5 () {
  md5sum -b | cut -f 1 -d ' '

sample_binary_data () {
  local i

  for (( i=0; i<=255; i++ )); do
    printf "\x$(printf %x "$i")"

sample_text_data () {
  cat <<EOF
Here be dragons


echo "Binary data MD5 $(sample_binary_data | md5)"
echo "Text data MD5: $(sample_text_data | md5)"

sample_text_data >"$testfile"

echo "$testfile is going to be modified"
sample_binary_data | to_file "$testfile"

echo "$testfile is NOT going to be modified"
sample_binary_data | to_file "$testfile"

echo "$testfile MD5: $(md5 <"$testfile")"

echo "$testfile is going to be modified"
sample_text_data | to_file "$testfile"

echo "$testfile is NOT going to be modified"
sample_text_data | to_file "$testfile"

echo "$testfile MD5: $(md5 <"$testfile")"

Sample output

Binary data MD5 e2c865db4162bed963bfaa9ef6ac18f0
Text data MD5: 890923a3ff411987e645531cc33548f6
./testfile is going to be modified
--- ./testfile  2017-07-07 07:21:39.853604436 +0100
+++ -   2017-07-07 07:21:39.856596473 +0100
@@ -1 +1,2 @@
-Here be dragons
\ No newline at end of file
./testfile is NOT going to be modified
./testfile MD5: e2c865db4162bed963bfaa9ef6ac18f0
./testfile is going to be modified
--- ./testfile  2017-07-07 07:21:39.994605593 +0100
+++ -   2017-07-07 07:21:40.146792083 +0100
@@ -1,2 +1 @@
\ No newline at end of file
+Here be dragons
./testfile is NOT going to be modified
./testfile MD5: 890923a3ff411987e645531cc33548f6

We need to go deeper

July 1, 2017, 9:48 p.m.

I'm an oldfag. I love playing old games "Baldur's Gate" series or "Heroes of Might & Magic II". I happen to own the original Gold Edition CD of the latter one which I enjoy playing with my daughters occasionally. The CD contains the state of the art soundtrack which is an essential part of the game.

Unfortunately, this version of the game doesn't run well on the latest build of the Windows 10. Even with some workarounds applied game tends to crash now and then.

Y U do dis Microsoft

The version distributed by GOG (which is basically a repackaged DOS version of it) works, but it lacks network play and has some audio tracks replaced with the different ones for some reason.

My primary operating system, for the time being, is Windows 10 and I do not have plans to change this in the near future, therefore the obvious choice is to run the game in a VM. Windows XP/7 require an additional license, so I've decided to give Linux/Wine a shot. VirtualBox was used for the hypervisor as I use it for the other things anyway.

The tricky part was to get the CD audio working. By passing the host CD drive to the VM I was able to access the data track, but not the audio tracks. Passing the CD as ISO image wouldn't work either, as the ISO format does not support the audio tracks. The solution was to create BIN/CUE/CCD image and load it into the emulated CD drive inside of the VM.

The result? Well, see for yourself :)

Libvirt SR-IOV pools on a Cisco UCS in the CentOS7

March 30, 2017, 9:14 p.m.

Libvirt allows you to create a network definition with all the virtual functions (VF) from the specified SR-IOV physical function (PF). It will assign one of the available VFs to the guest VM connected to such network automatically when it's powered on. This allows you to avoid hardcoding of the VF PCI addresses into the configuration of the guest.

To enable SR-IOV for the static vNIC on the Cisco UCS You need to create a Dynamic vNIC Connection Policy with the desired number of the dynamic vNICs and assign it to the static vNIC.

You will also need to enable VT-d in the BIOS policy of the service profile (by selecting the predefined SRIOV BIOS policy for example) and enable the IOMMU support for your Linux kernel (see the " Using SR-IOV" section of the "Guest virtual machine device configuration" chapter from the RH Virtualization Deployment and Administration Guide)

Typical example, like the one from the section " Setting PCI device assignment from a pool of SR-IOV virtual functions" of the mentioned chapter might not work on the UCS:

   <name>passthrough</name> <!-- This is the name of the file you created -->
   <forward mode='hostdev' managed='yes'>
     <pf dev='enpXs0f0'/>  <!-- Use the netdev name of your SR-IOV devices PF here -->

In my case I was getting the internal error: missing IFLA_VF_INFO in netlink response error after trying to power on the VM connected to the "passthrough" network.

In order to work properly, the SR-IOV VF needs the Port Profile and the Port Profile Client created on the UCS (VM tab in the GUI, see the Cisco UCS Manager VM-FEX for KVM GUI Configuration Guide for more details on configuring port profiles on the UCS) and specified in the Libvirt network or interface definition. This allows you to specify the allowed VLANs for the VM configured to use that port profile.

Working Libvirt network definition looks like this (notice the <driver name='vfio'/> I've had to add as well):

   <forward mode='hostdev' managed='yes'>
     <pf dev='enpXs0f0'/>
     <driver name='vfio'/>
  <portgroup name='libvirt_port_group1' default='yes'>
    <virtualport type='802.1Qbh'>
      <parameters profileid='UCS_Port_Profile'/>

And the network interface for the VM can be defined like:

<interface type='network'>
  <mac address='52:54:00:ec:24:f1'/>
  <source network='passthrough' portgroup='libvirt_port_group1'/>

One of the enpXs0f0 virtual functions (total number depends on the Dynamic vNIC Connection Policy assigned to the static vNIC) will be consumed by that VM as soon as you power it on.

Successful assignment of the VF from the pool

Body weight

Feb. 18, 2017, 4:54 p.m.

The energy lifecycle

Combine water and carbon dioxide. If you use some energy take a part of oxygen out - you will be left with the glucose - a simple sugar. Plants use the energy of the sun to run this process all over the planet every day.

Photosynthesis equation

Our bodies revert that reaction by adding oxygen back to the glucose (that's the reason you have to breathe :) ) to release the stored energy (water and exhaled carbon dioxide are the waste products). The actual process of converting that energy into muscular(mechanical) one is a bit more complicated, involving the conversion of glucose into the more suitable fuel by the mitochondria.

1 gram of glucose contains 4 calories of energy. You burn that much energy by running for the 40 meters.

The Fat

Fat is the conserved fuel our body is able to store in a practically infinite amount.

Why and how do we accumulate the fat? Our bodies burn energy at some rate. This rate is higher during the exercise and lowers during the rest. Consumed carbohydrates are broken down into the glucose and used as the primary energy source by the organs (except for the heart, which mainly uses fatty acids for fuel). An insignificant amount of sugar is stored in the muscles in the form of glycogen for quick access, Some glycogen is stored in the liver and released on demand, but not much (enough to sustain a few hour exercise).

If the glycogen stores in your body are already full, and the sugar enters your bloodstream at a higher rate than your body is able to burn it - any excess will be stored as fat for the later consumption.

Some sugars you eat are simple (like glucose, fructose) and easy to digest. Simple sugars combined into complex chains (starches for example) are harder to digest, as they need to be broken down first. Some sugar chains, cellulose, for example, cannot be broken down by the human body at all, therefore pass through it and do not contribute to the overall calory intake.

The simpler sugar is - the quicker it will reach your bloodstream - the greater chance it will be converted into fat.

On the other hand - a can of Coke (33 grams of table sugar) consumed after a 10km run would be used to replenish the glycogen stores and won't end up as a fat.

For both simple and complex carbohydrates 1 gram contains 4 calories of energy, Dietary fiber (cellulose for example) is a carbohydrate as well, but, as mentioned before, it is not absorbed by the humans, as our bodies lack the enzymes which are needed to break it down.

While protein also provides 4 calories per 1 gram - it's primary function is to provide building blocks for the body. Protein will be converted into glucose when glycogen stores in the muscles and the liver are exhausted. While there is a pathway for the excess protein to turn into fat - it is very unlikely to happen. This doesn't mean one can safely replace carbohydrates with protein in the diet - consuming too much of it may overload liver and kidneys,

Another source of energy is the fat we eat. It contains approximately 9 calories per 1 gram. Consumed fat is broken into fatty acids first. Some of the consumed fat is used as the fuel, the rest is used for the different purposes (like an insulator for the nerves and organs or hormone production for example). Fat will slow down the digestion of the carbohydrates and/or proteins when consumed together.

Body weight, BMI, and fat percentage

Body Mass Index is simple but useless. It doesn't differentiate between muscle mass and fat mass.

Arnold Schwarzenegger in 1974

The person above is the Arnold Schwarzenegger. According to the BMI (height 188cm, weight 106kg) he was obese in 1974, the year this photo was taken :)

There are few variables we can change to affect body mass - muscle mass, fat tissue, and water. Changing the amount of water in your body is neither effective nor healthy way to affect the body weight, therefore we are left with only two variables.

Fitness is rarely about losing weight. Usually, it's about changing the body composition. Being big boned doesn't make you look fat. Being muscular doesn't make you look fat. Fat makes you look fat.

Making the change

Basal Metabolic Rate tells us the amount of energy we burn during the rest per day. Your liver, brain, muscle, kidneys, heart and other organs constantly require energy supply just to keep you alive. Even if you stay completely idle throughout the day - you will still burn 1000-2500 calories (actual amount depends on the lean body mass of the individual). BMR is the bulk of the daily energy expenditure even for many athletes.

You can find out your approximate body fat percentage by comparing yourself with the sample pictures from this article

Your approximate BMR is calories per day.

You can reduce your body fat percentage in a number of ways. The most obvious one - simply reduce your daily calory intake to the amount which is less than your BMR combined with any additional calories spent (like during exercise). In other words - eat less - weigh less.

While the diet is the primary way of changing the body composition - it can lead to the undesired result when used as the only way.

Reducing the calory intake below the amount spent will eventually switch the body into the starvation mode. This will trigger the release and use of the stored fat for fuel. It will also trigger the gluconeogenesis - the process of converting proteins and fats into glucose. Not all organs can use fats as the fuel - our brain requires at least 10g of glucose per day, the remaining energy requirements of the brain are satisfied by the alternative fuel produced by the liver from the fat. The body may break down the muscle tissues, which are made of protein in case there is not enough of it in the bloodstream to convert into glucose. In other words - you may end up losing both fat and a significant amount of the muscle mass as a result - depends on how extreme the diet is.

Increased protein intake can mitigate the muscle mass loss problem to some extent, but it's not a silver bullet and you can't consume a lot of it due to the reasons explained earlier.

It's hard to spot muscle mass loss if you are overweight - a layer of fat may mask it.

The consequence of losing the muscle mass is the daily energy expenditure (BMR) decrease (as it directly depends on the lean body mass). Lower BMR means the energy demand is now lower than it was before, therefore calory intake should be reduced or the amount of exercise has to be increased. Ever heard of the yo-yo weight cycling effect? Decreased BMR is one of the reasons people start gaining, even more, weight when they complete the diet and return to their usual eating habits.

When diet is combined with an aerobic exercise like running, cycling, swimming - energy consumption is accelerated. A lot of calories are burned during the aerobic exercise - approximately 100 calories per 1km of running or 5km of cycling for example (it depends on your weight and age and exercise conditions).

Human body prefers fat as the fuel source during the low-intensity exercise, such as aerobic one, therefore it's a good choice to lose fat. The duration is important - 40 minutes or more is the way to go.

Fat is very energy dense - with 9 calories per 1 gram, it's 9000 calories per 1 kilogram of fat. That's 90 kilometers of running alone! Think of it this next time you eat your 200 calory snack :)

The best way to affect your body composition is to grow muscle mass while keeping slight calory deficit and doing occasional aerobic exercise. Increased muscle mass will result in higher BMR. As the baseline energy demand will grow - you'll have to eat more, simply to keep slight calory deficit constant. That's where the "to lose weight you have to eat more, not less" expression stems from. It takes a longer time to achieve the goal, but the result is much more sustainable.


So, how do you become more muscular? The answer is simple - you lift. You lift heavy weights. How heavy? Think weight, which you can lift 8-12 times max. The weight will be different for different types of exercise. Lifting heavy weights will:

  • Increase the production of the testosterone in the body.
  • Do some damage to the muscle fibers. Combined with the increased muscle protein synthesis due to the raised testosterone level this will promote the muscle growth.

Lifting light weights will not result in testosterone production increase. Muscle will not grow if testosterone level does not increase. No pain - no gain. You have to overload the body to trigger the response.

Testosterone is only produced when you rest(sleep), therefore you will experience the boost on the day following the strength exercise. The heavier the weight you lift and the more joints are involved in the exercise - the stronger effect it will have on the testosterone production.

If you are a beginner - don't waste your time on weight machines. Most of those are isolation (single-joint) oriented and won't affect hormone production much. Dedicate first years of your training to the compound (multi-joint) exercises. The following are the classics:

Each of the mentioned above will result in a huge boost in testosterone production, but beware all three are the high-risk exercises and will result in injury if performed improperly. A proper warm-up before lifting heavy weights is essential. Please learn about proper form and common mistakes (see deadlift, squat and bench press mistakes for example) before starting. Start with lighter weights, only go heavier if you are completely confident and comfortable with the exercise.

Proper rest is required to allow full muscle recovery between workouts. Too frequent exercise may lead to overtraining.

Due to the physiological differences, it's easier for the males to gain muscle mass compared to the females. It's nearly impossible for the most females to become as muscular as the Arnie on the photo above, simply because testosterone production volume is lower in females than males.

The human body needs amino acids to repair and grow the muscle tissue. There are 20 common amino acids, nine of which are essential (our body cannot synthesize those from other common amino acids). We get amino acids from the protein we consume. Different proteins contain different sets and amounts of the mentioned common amino acids. Complete proteins contain all nine essential amino acids. Meat, dairy, eggs, soy, and fish are sources of the complete protein.

You'll have to adjust your protein intake after starting the weight training, but don't go crazy about it. 1.5 grams of protein per one kilogram of the desired body mass is enough in most cases (for an 80kg person - that's 120 grams of protein per day). For the reference - 100 grams of chicken breast contain 31 gram of complete protein, one egg (one of the best protein sources) has 6 grams of protein.

It's easier than you think

Eat clean. High-calory fast carbohydrates are too expensive - think in terms of kilometers of running needed to burn those.

Run a few km twice a week - that's extra several hundred of calories burned.

Do 40 minutes of weight lifting two-three times a week. Spend those 40 minutes working out, not looking at your phone.


And sleep well.

bashrc Git and history improvements

Jan. 15, 2017, 12:31 a.m.

Finally replaced old crappy git prompt with the vanilla one from the contrib and did some tuning to the Bash history

# git
if [[ -f ~/.git-completion.bash ]]; then
    . ~/.git-completion.bash

if [[ -f ~/ ]]; then
    . ~/

PS1='[\u@\h \W$(__git_ps1 " (\[\033[1;34m\]%s\[\033[0m\])")]\$ '

# History (see
HISTFILE="${HOME}/.bash_history.$(hostnamectl --static)"
shopt -s histappend
shopt -s cmdhist
PROMPT_COMMAND='history -a'


Jan. 14, 2017, 9:55 a.m.

Yet another hello world