My current tmux config

After many years of using screen I recently started getting familiar with tmux. This is my current .tmux.conf and most of it is borrowed from IppSec’s YouTube video:

# Remap prefix to screens, easier to type, same as "screen"
set -g prefix C-a
bind C-a send-prefix
unbind C-b

# Split panes
bind | split-window -h -c "#{pane_current_path}"
bind _ split-window -v -c "#{pane_current_path}"
unbind %    # split-window -h
unbind '"'  # split-window

# Rename session and window
bind r command-prompt -I "#{window_name}" "rename-window '%%'"
bind R command-prompt -I "#{session_name}" "rename-session '%%'"
unbind "\$" # rename-session
unbind ,    # rename-window

# Quality of life stuff
set -g history-limit 20000
set -g allow-rename off

# Start index of window/pane with 1, because we're humans, not computers
set -g base-index 1
setw -g pane-base-index 1

# Enable mouse support
set -g mouse on

## Join Windows
bind-key j command-prompt -p "join pane from:"   "join-pane -s '%%'"
bind-key s command-prompt -p "send pane to:"   "join-pane -t '%%'"

## Move tabs
bind-key Right swap-window -t +1 \; next-window
bind-key Left swap-window -t -1 \; previous-window

# Search mode vi (default is emac)
set-window-option -g mode-keys vi

# Install the tmux-logging plugin via the tmux plugin manager
# To save the whole terminal session of that screen to a file, issue: prefix + Alt + Shift + p 
set -g @plugin 'tmux-plugins/tmux-logging'

# Initialize TMUX plugin manager (keep this line at the very bottom of tmux.conf)
# To install a plugin (and keep it installed) add a line like: set -g @plugin '...'
# Then while in tmux session do: prefix + I
# To update plugin(s) do: prefix + u
# To uninstall a plugin, remove its line from this file and do: prefix + Alt + u
run '~/.tmux/plugins/tpm/tpm'
Tmux Copy/Paste

With the mouse support enabled in the above config, to copy/paste text, just hold down the “Shift” key and select what you need to copy with the mouse. Then you can do one of the following:

  • Don’t let go off the “Shift” key, right-click on the selected text and pick “copy”
  • Use the regular Ctrl+Shift+C in which case you don’t have to keep holding the “Shift” key
Tmux Cheat Sheet

https://tmuxcheatsheet.com/

Note, that I have overwritten the default keybindings. So, instead of the default “Ctrl+b” I use “Ctrl+a” to initiate a Tmux command. That way it matches the screen emulator and that way I can use the same muscle memory.

PhpMyAdmin and changed MySQL data directory

Very often you would like to change the default data location of MySQL for obvious reasons. If you do that and you don’t change the phpmyadmin settings accordingly, you will not be able to login via phpmyadmin. You will constantly be getting the “Access denied” message.

Let’s say that you have added a new file system mounted under /data and you would like all MySQL data to be stored there.

Normally I set this up before I ever create new databases on the server. But in case you are moving existing databases from one data dir to another you need to copy them over to the new location first, otherwise go directly to editing the my.cnf file below.

Stop mysql:

$ sudo systemctl stop mysqld

Now that the server is shut down, we’ll copy the existing database directory to the new location with rsync. Using the -a flag preserves the permissions and other directory properties, while -v  provides verbose output so you can follow the progress.

Note: Be sure there is no trailing slash on the directory, which may be added if you use tab completion. When there’s a trailing slash, rsync will dump the contents of the directory into the mount point instead of transferring it into a containing mysql directory:

$ sudo rsync -av /var/lib/mysql /data

Now you are ready to change the MySQL configuration. To do that you need to update the /etc/my.cnf (CentOS/RHEL) /etc/mysql/my.cnf (Ubuntu) file:

$ sudo vi /etc/my.cnf

Find the datadir and socket entries under [mysql] and update them to point to the new data directory:

[mysql]
datadir=/data/mysql
socket=/data/mysql/mysql.sock

After updating the existing lines, we’ll need to add configuration for the mysql client. Add the following three lines at the end of that file, right above the !includedir /etc/mysql/conf.d/ line and the comment above it:

[client]
port=3306
socket=/data/mysql/mysql.sock

We are all set with the MySQL configuration and we can start db the server:

$ sudo systemctl start mysqld

If you have phpMyAdmin installed you need to reconfigure it to use socket authentication and point to the new location of the mysql socket. If you don’t do this, you will not be able to login via phpMyAdmin.

Edit the /etc/phpMyAdmin/config.inc.php (CentOS/RHEL) /etc/phpmyadmin/config.inc.php (Ubuntu) file:

$ sudo vi /etc/phpMyAdmin/config.inc.php

Change the socket and data_type. Normally the data_type would be set to ‘tcp’. Change it to ‘socket’ instead. Then set the new location of the socket:

$cfg['Servers'][$i]['socket'] = '/data/mysql/mysql.sock';          // Path to the socket - leave blank for default socket
$cfg['Servers'][$i]['connect_type'] = 'socket';       // How to connect to MySQL server ('tcp' or 'socket')

You are all set. Restart Apache and you should be good to go.

How to export/import gnome-terminal profiles

You only need dconf to export/import gnome-terminal profiles.

To export all gnome-terminal profiles run:

$ dconf dump /org/gnome/terminal/legacy/profiles:/ > gnome-terminal-profiles.dconf

To import the exported profiles above, run:

$ dconf load /org/gnome/terminal/legacy/profiles:/ < gnome-terminal-profiles.dconf

If you want to export and then import only a particular profile, you need to find out the profile’s id first. To list all profiles available:

$ dconf dump /org/gnome/terminal/legacy/profiles:/ | grep -e "\[\:\|visible-name"

You get an output like this one:

[:2afe8ac6-b873-4843-94e1-df6efbb8368d]
visible-name='Default'
[:c20ee9bb-547e-4e42-9865-ec27748eec5f]
visible-name='server1'
[:bd255b93-a970-45fe-aab6-4c3b969f3b9e]
visible-name='server2'

Let’s say I would like to export the server1 profile, the id for it is c20ee9bb-547e-4e42-9865-ec27748eec5f

To back it up:

$ dconf dump /org/gnome/terminal/legacy/profiles:/:c20ee9bb-547e-4e42-9865-ec27748eec5f/ > server1-gnome-terminal-profile.dconf

To load it:

$ dconf load /org/gnome/terminal/legacy/profiles:/:c20ee9bb-547e-4e42-9865-ec27748eec5f/ < server1-gnome-terminal-profile.dconf

Gradle fails after upgrading Android Studio to 3.2.1 with “Could not find aapt2-proto.jar”

Almost every other time I go through an Android Studio upgrade, my projects no longer compile and I spend an hour or so trying to figure out what was wrong or what I need to change.

Due to this reason very often I will postpone upgrading as much as possible, especially if I have an upcoming application update that I am trying to release on time.

The latest Android Studio upgrade was not an exception. After the upgrade to v. 3.2.1, Gradle failed to compile my project with the following error:

Could not find aapt2-proto.jar (com.android.tools.build:aapt2-proto:0.3.1)

It turns out that it the issue was with the order of the repositories in the build.gradle file. For some reason the google repo had to be moved at the top (above the maven repo), otherwise the appt2-proto library could not be found. Here is how it looks after I fixed it:

repositories {
google()
jcenter()
maven {
url 'https://maven.google.com/'
name 'Google'
}
}

PHP.ini settings to increase file size and number of uploads

Update: Please checkout the later post with a better approach before reading further.

In addition to changing your code, you also need to change the setting on the server to accommodate uploading larger file sizes.

The settings that need to be changed are in the php.ini file:

sudo vi /etc/php/7.0/apache2/php.ini

(the path here is for PHP ver 7.0)

The following settings need to be checked:

upload_max_filesize – controls the maximum size of each file
max_file_uploads – sets the maximum number of files that can be uploaded at a time
post_max_size – max size of POST data that PHP will accept. This value should be at least as big as upload_max_filesize * max_file_uploads
memory_limit – max amount of memory a script may consume. This value should be at least as big as post_max_size

Possibly you might want to increase these as well:

max_execution_time – max execution time of each script, in seconds
max_input_time – max amount of time each script may spend parsing request data

For example if you would like to be able to upload 20 files at a time, each of which could be up to 10MB in size:

upload_max_filesize = 10M
max_file_uploads = 20
post_max_size = 208M
memory_limit = 216M

Once the the changes to the php.ini file are made, you need to restart Apache:

sudo service apache2 restart

How to connect your Android phone to Ubuntu to do development, testing, installations or tethering – Updated

All the way back in 2010 I wrote a post how to connect your Android device to your Ubuntu computer in order to develop on it. There have been a few changes since then, so here is the updated version of that post.

Recently, out of the blue I had permission issues accessing the my phone via adb. When I ran “adb devices” I got a “no permissions” message:

$ adb devices
List of devices attached
8XV7N18328713317	no permissions (verify udev rules); see [http://developer.android.com/tools/device.html]

It gives you a link to a Google article that addresses the issue, but their solution did not work for me.

So, here are the steps you need to take to be able to connect your Android device:

  1. Enable Unknown sources and USB debugging on your device
  2. Settings -> Developer Options -> USB debugging
    Settings -> Security -> Unknown sources

    The unknown sources in needed only if you will be developing on your device and you will be installing dev apk files.

  3. Find out the vendor id and product id of your device
  4. Run “lsusb”. This will list all of the devices connected to the USB ports of your computer- mouse, keyboard, camera, etc. including your phone or tablet. Each device will have a description, so it will be easy to identify.

    In my case the phone is a Nexus 6P, identified here as a Google device:

    $ lsusb
    Bus 002 Device 008: ID 18d1:4ee7 Google Inc. 

    This device is number 008 on bus number 002.

    You can see the device object created by udev. It is a fileL /dev/bus/usb//
    In this case it would be: /dev/bus/usb/002/008

    18d1:4ee7 represents VendorID:ProductID. In this case the vendor id is 18d1 and the product id is 4ee7. The vendor id and product id are different for each device manufacturer.

  5. Set up udev rules
  6. Now that we have all the info we need, we can set up the rules.

    Create a 51-android.rules file in /etc/udev/rules.d

    $ sudo gedit /etc/udev/rules.d/51-android.rules

    In this file you should create a rule for each device you want to connect.

    ATTR{idProduct}=="4ee7", SYMLINK+="android_adb", MODE="0660", GROUP="plugdev", TAG+="uaccess", SYMLINK+="android"

    Here, replace “4ee7” with your device’s product id from step #2.

    Note the GROUP=”plugdev” entry. This will create the device object file with the plugdev group as an owner. You need to make sure that your user is part of this group. This is done in the next step.

  7. Add your user to the plugdev group
  8. sudo usermod -a -G plugdev $(id -u -n)
  9. Activate the new udev rule and restart adb
  10. $ sudo udevadm control --reload-rules
    $ sudo service udev restart
    $ sudo udevadm trigger
    

    Now if we list the object files we should see that our device has a group of plugdev:

    $ ls -l /dev/bus/usb/002/
    total 0
    crw-rw----+ 1 root plugdev 189, 135 May  7 21:48 008

    Also, we should have two symlinks in /dev pointing to our device object:

    $ ll /dev | grep android
    lrwxrwxrwx   1 root root          15 May  7 21:48 android -> bus/usb/002/008
    lrwxrwxrwx   1 root root          15 May  7 21:48 android_adb -> bus/usb/002/008
  11. Restart adb and check the result
  12. $ adb kill-server
    $ adb start-server
    * daemon not running. starting it now at tcp:5037 *
    * daemon started successfully *
    $ adb devices
    List of devices attached
    8XV7N18328713317	device

    As you can see, we now have access to the connected device and can begin work.

I found a github project where the community is maintaining a rules file with the most widely used Android devices. You can just copy this rules file:
https://github.com/M0Rf30/android-udev-rules/blob/master/51-android.rules

Make sure to change the group from adbusers to plugdev. The line is towards the end of the file. GROUP=”adbusers” should be changed to GROUP=”plugdev”.

Then do steps 4, 5 and 6 above.

Gradle – Automatically rename the .apk file and copy the ProGuard mapping.txt file

ProGuard writes the mapping file under the build directory of the project. Under normal circumstances all files and directories under the build dirs are excluded from version control. That is a bit of an issue if you want to be able to save that file with every release build. I always forget to this manually. So, let’s do that at build time with Gradle and while we are at it, we might as well rename our apk file, so we don’t have to do that manually either.

Here is the relevant code to put in our build.gradle file:


import java.util.regex.Matcher
import java.util.regex.Pattern

buildTypes {
        release {
        debuggable false
        minifyEnabled true
        proguardFiles 'proguard.cfg'

        // Rename the apk file and copy the ProGuard mapping file to the root of the project
        applicationVariants.all { variant ->
            if (variant.getBuildType().name.equals("release")) {
                def formattedDate = new Date().format('yyyyMMddHHmmss')
                def projectName = ""
                variant.outputs.all { output ->
                        def fullName = output.outputFile.name
                        projectName = fullName.substring(0, fullName.indexOf('-'))
                        // ${variant.name} has the value of "paidRelease"
                        outputFileName = new File((String) output.outputFile.parent, (String) outputFileName.replace(".apk", "-v${variant.versionName}-${formattedDate}.apk"))
                    }
                def mappingFile = "${rootDir}/${projectName}/build/outputs/mapping/${getCurrentFlavor()}/release/mapping.txt"
                println("mappingFile:  ${mappingFile}")
                if (variant.getBuildType().isMinifyEnabled()) {
                    variant.assemble.doLast {
                        copy {
                            from "${mappingFile}"
                            into "${rootDir}"
                            rename { String fileName ->
                                "mapping-${variant.name}.txt"
                            }
                        }
                    }
                }
            }
        }
    }

    debug {
        debuggable true
    }
}

def getCurrentFlavor() {
    Gradle gradle = getGradle()
    String  tskReqStr = gradle.getStartParameter().getTaskRequests().toString()
    Pattern pattern;

    if( tskReqStr.contains( "assemble" ) )
        pattern = Pattern.compile("assemble(\\w+)(Release|Debug)")
    else
        pattern = Pattern.compile("generate(\\w+)(Release|Debug)")

    Matcher matcher = pattern.matcher( tskReqStr )

    if( matcher.find() )
        return matcher.group(1).toLowerCase()
    else {
        println "NO MATCH FOUND"
        return "";
    }
}

The above code was updated for the new Android Studio 3.0 and Gradle 3.0.

The new Gradle introduces some changes and the output.outputFile is now a read only property. So, you cannot change it starting with Gradle 3. You will get the following error:

“Cannot set the value of read-only property ‘outputFile’ for ApkVariantOutputImpl_Decorated{apkData=Main{type=MAIN, fullName=release, filters=[]}}…”

Here are the changes:

old:


variant.outputs.each { output ->
                    def fullName = output.outputFile.name
                    projectName = fullName.substring(0, fullName.indexOf('-'))
                    // ${variant.name} has the value of "paidRelease"
                    output.outputFile = new File((String) output.outputFile.parent, (String) output.outputFile.name.replace(".apk", "-v${variant.versionName}-${formattedDate}.apk"))
                }

new:


variant.outputs.all { output ->
                        def fullName = output.outputFile.name
                        projectName = fullName.substring(0, fullName.indexOf('-'))
                        // ${variant.name} has the value of "paidRelease"
                        outputFileName = new File((String) output.outputFile.parent, (String) outputFileName.replace(".apk", "-v${variant.versionName}-${formattedDate}.apk"))
                    }

The Android SDK Manager fails to fetch the platform and tools list from Google

If you get the following error message when launching the Android SDK Manager:

Failed to fetch URL https://dl.google.com/android/repository/addons_list-2.xml, reason: File not found

most likely the owner/permissions are not set correctly for the ~/.android directory.

This error message is very confusing and it took me while to find the issue.

In my case the owner of this directory and all the files and directories in it was root.

There are numerous “solutions” given to this in many forums. Most of them recommend launching Android Studio as root. That is definitely the wrong approach. It will get rid of the error, since you will no longer be faced with permissions issues, but running Android Studio as root is a vary bad idea.

Instead, you should change the owner of the ~/.android directory to your user id.

So, find the .android directory (most likely it is in your home directory). Then change the ownership recursively to your user:


cd ~
sudo chown -R myuser: .android/

You should be now good to go.

Find out what DNS requests are made in real time via command line

Since all DNS requests are over port 53, we can use the raw tcpdump utility and just look at the packets on that port:

tcpdump -vvv -s 0 -l -n port 53

Someone took the extra step to write a php script to massage that data, so that it is easier to read as well as focusing on those queries that either do not resolve or take a long time to resolve:

http://jontai.me/blog/2011/11/monitoring-dns-queries-with-tcpdump/

Android Studio- What files and directories to exclude when importing into Subversion (or Git)

Update Oct. 17, 2019:
———————
This is the official .gitignore file maintained by JetBrains:

https://github.com/github/gitignore/blob/master/Global/JetBrains.gitignore

———————

List of directories and files to be excluded when importing into a version control (relative to the root of the project):

.gradle (directory)
build (directory)
local.properties (file)
app/build (directory)
.idea/libraries (directory)
.idea/gradle.xml (file)
.idea/workspace.xml (file)

There are a couple of different ways to have the above directories and files not present in the version control:

1. Exclude them from the initial import
2. Delete them after the import


svn delete -m "Delete .gradle dir" http://server/path/to/repository/.gradle
svn delete -m "Delete build dir" http://server/path/to/repository/build
svn delete -m "Delete app/build dir" http://server/path/to/repository/app/build
svn delete -m "Delete local.properties" http://server/path/to/repository/local.properties
svn delete -m "Delete .idea/libraries dir" http://server/path/to/repository/.idea/libraries
svn delete -m "Delete gradle.xml" http://server/path/to/repository/.idea/gradle.xml
svn delete -m "Delete workspace.xml" http://server/path/to/repository/.idea/workspace.xml

Now that we have gone through that, the version control does not have these directories and files, but locally, the project on your computer has these (if not they will be automatically generated when you first open the project in Android Studio or you build the project).

That means that we need to delete them from svn locally and tell svn locally to ignore them:


svn ps svn:ignore '.gradle local.properties build' .
svn ps svn:ignore build app
svn ps svn:ignore 'libraries gradle.xml workspace.xml' .idea

Update Oct. 23, 2018: Here is a .gitignore file that I use for all my Android Studio projects:


# Built application files
*.apk
*.ap_
*.aab

# Files for the ART/Dalvik VM
*.dex

# Java class files
*.class

# Generated files
bin/
gen/
out/

# Gradle files
.gradle/
build/
app/build/
# Here depending on your project you might need to include more build direcories

# Local configuration file (sdk path, etc)
local.properties

# Log Files
*.log

# Android Studio Navigation editor temp files
.navigation/

# Android Studio captures folder
captures/

# IntelliJ
*.iml
.idea/workspace.xml
.idea/tasks.xml
.idea/gradle.xml
.idea/assetWizardSettings.xml
.idea/dictionaries
.idea/libraries
.idea/caches

# Keystore files
*.jks
*.keystore

# External native build folder generated in Android Studio 2.2 and later
.externalNativeBuild

# OSX_files
.DS_Store