Docker Commands Cheatsheet

 

Reminder: A Container is a running instance of an Image

Docker CLI commands

Command Meaning
docker pull download an image from dockerhub
docker images show list of locally available docker image
docker start start container
docker stop stop container
docker run pulls image, make a container from image and runs it
docker run -d running in detached mode
docker run -p: port binding e.g. -p6000:6379
docker ps show a list of running containers
docker ps -a show a list of running and stopped containers
docker logs gets the log from the running container
docker exec -it /bin/bash interactive terminal
docker rename rename a container

How I learned to love the Bash

My tale of woe

When I started to write my first ebook I decided to use pandoc to transform markdown into pdf.
It basically looked like this

pandoc metadata_de.yaml -o ./level_up_de.pdf --from markdown -V lang=de-DE level_up_de.md

This simple command can be pasted into the command line everytime I want to build a new version of the ebook.
But: I have to keep in mind the command which is tedious. I could write it into a text file and copy it everytime I use it.
There is a more elegant way: let’s make a script!

Make a script

A shell script is basically a file with the extension “.sh”
When You want to specify which shell shall be used, you put

#!/bin/bash

in the first line of your script.

Echo

To put some text on the command line for e.g. displaying the start of your script, you can use the command echo like this

echo "Start generating PDF"

The script now looks like that

#!/bin/bash
echo "Start generating PDF"
pandoc metadata_de.yaml -o ./level_up_de.pdf --from markdown -V lang=de-DE level_up_de.md

Variables

After finishing the German version I also wanted to create an English version,
so the “de” strings should be replaced by a variable to switch between languages.

To declare a variable, you write down the name and assign it a value with the equal sign.
You use a variable by using thew $ sign to access its content.

language="en"
echo "Language: $language"

Caveat: whitespaces are not allowed around the equal sign!

language = "en" # this won't work

Let’s have a look at our script now:

#!/bin/bash
echo "Start generating PDF"
lang="en"
echo "Language: $lang"
pandoc metadata_$lang.yaml -o ./level_up_$lang.pdf --from markdown -V lang=de-DE level_up_$lang.md

Pretty neat!

But we need to get rid of the “de-DE” as well

Conditions

When we get “en” as language we want to use en-US as language subtag. When “de” is used we want de-DE
Let’s write some conditions.

if [[ $lang = "en" ]]
then
  lang_subtag="$lang-US"
elif [[ $lang = "de" ]]
then
  lang_subtag="$lang-DE"
else
  echo "Wrong language"
fi

Now we can replace the de-DE with $lang_subtag

pandoc metadata_$lang.yaml -o ./level_up_$lang.pdf --from markdown -V lang=$lang_subtag level_up_$lang.md

Command Line Arguments

Now that we can generate the ebook for english and german we could introduce a command line parameter.
In bash every argument provided to the script is stored in variables $1 .. $n

lang="$1"

Arrays and loops

I wanted to break down the big markdown file into individual chapters.
To make an array variable in bash you can do the following:

chapters=(
./de/chapter_01.txt
./de/chapter_02.txt
./de/chapter_03.txt
)

Looping over an array looks like this:

for chapter in ${chapters[*]}
do
  cat "$chapter"
  printf "\n"
done

So now we can pass the chapters array to pandoc

pandoc metadata_$lang.yaml -o ./level_up_$lang.pdf --from markdown -V lang=$lang_subtag ${chapters[*]}

To be continued …

You can find the source code here: https://github.com/jboegeholz/shell_tutorial

How to use an AVAudioPlayer in iOS with Swift 5

import AVFoundation

var player: AVAudioPlayer?


let url = Bundle.main.path(forResource: "richtig", ofType: "wav")
do {
    try AVAudioSession.sharedInstance().setMode(.default)
    try AVAudioSession.sharedInstance().setActive(true, options: .notifyOthersOnDeactivation)
    guard let url = url else {
        return
    }
    player = try AVAudioPlayer(contentsOf: URL(fileURLWithPath: url))
} catch {
    print("Something went wrong")
}

@IBAction func playButton(_ sender: Any) {
    guard let player = player else {
    return
    }
    if player.isPlaying {
        player.stop()
    }
    else {
        player.play()
    }
}

Create an iOS 12 compatible app with Xcode 12

To make an app downwards compatible do the follwing

  • Change deployment target to iOS 12
  • Remove the methods in AppDelegate.swift
  • Add var window: UIWindow?
  • Remove SceneDelegate.swift
  • Remove the entry Application Scene Manifest in the info.plist.

Use github with tokens

I got an error accessing github from Android Studio

It seems that github disabled the usage of user/pw authentification.

To fix it you have to

  • Go to https://github.com/settings/tokens
  • Generate new token
  • enable “repo”, “admin:org”, “gist”

Now you can use the token from within Android Studio

Developing for iOS 14 with Xcode 12.4

Oh boy, Apple….

I’m still running macOS 10.15.7 Catalina on my Mac due to different reasons. My iPhone is already up to date on iOS 14.5.

That means my Mac can only run Xcode 12.4 which makes it incompatible with my iPhone for development. But there is a way.

DeviceSupport files

You need an additional DeviceSupport file. Do the following:

  • Close Xcode
  • Go to https://github.com/filsv/iPhoneOSDeviceSupport
  • Download the matching zip in my case 14.5
  • Unzip the archive
  • Copy the folder to
    • /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/DeviceSupport/
  • Start Xcode

 

Generating SHA-1 for Google API

When you want to interface with any Google API e.g. YouTube from within your Android App, you need to register your app in the developer console.

You have to provide a SHA-1 key which can be generated as following:

Command line

$ chmod u+x gradlew
$ ./gradlew signingReport

Play sound on Android

Resource files shall be placed under app\src\main\res\raw

import android.media.AudioManager
import android.media.SoundPool
import android.os.Build
import android.os.Bundle
import android.util.Log
import android.view.View
import androidx.appcompat.app.AppCompatActivity


class MainActivity : AppCompatActivity() {
    private var mCSoundOne: Int = 0
    private lateinit var mSoundPool: SoundPool
    private var mLoaded = false

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        mSoundPool = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            Log.d("SoundPoolTest", "Building Soundpool")
            SoundPool.Builder().setMaxStreams(1).build()
        } else {
            SoundPool(1, AudioManager.STREAM_MUSIC, 1)
        }
        mSoundPool.setOnLoadCompleteListener(SoundPool.OnLoadCompleteListener { soundPool, sampleId, status ->
            Log.d("SoundPoolTest", "Load Completed")
            mLoaded = true
        })
        Log.d("SoundPoolTest", "Loading wav")
        mCSoundOne = mSoundPool.load(applicationContext, R.raw.eins, 1)

    }

    fun play_one(view: View?) {
        Log.d("SoundPoolTest", "Button Clicked")
        if (mLoaded) {
            Log.d("SoundPoolTest", "Playing wav")
            mSoundPool.play(mCSoundOne, 1.0f, 1.0f, 0, 0, 1.0f)
        }
    }
}