notes: Linux commands sed, find, grep combination is super powerful

I needed to bulk replace some text in thousands of files, yet skip some directories. Ended up using grep / sed combination. Also used find for some other purpose. Just noting down here for my future reference.

 grep -iRl --exclude-dir={skipme1,log} FindMeInFiles .  | xargs sed -i 's/IamBad/IamGood/g'
find -L -type f -print0 |xargs -0 sed -i.bak 's/IamBad/IamGood/g’


find -L -type f -print0 |xargs -0 sed -i 's/IamBad/IamGood/g’

Speed breaker – 2 ; Mac crashing

This week the speed breaker came in the form of not code, rather hardware.

Mac is trying to upgrade to Catalina – I said yes.

But before it completes I have to be mobile. Was sitting in bus and it asked me to complete upgrade, I said yes – but I guess without internet it can not complete upgrade. So far so good.

I rebooted Mac (I do it from time to time, when I want to context switch my work – this forces to close all open windows and freshly starts everything on new work, also machine won’t be slow. True in windows more but kept the hobbit of rebooting frequently)

After reboot all I got is circle-slash!

Took couple of hours to finally reinstall and get back to work.

Also trying to learn about gRPC – seems simple but carefully reading the dcoument as I am in no rush.

vimrc backup

syntax on
set number
set lazyredraw
set showmatch
set laststatus=2
set ruler
set visualbell
colorscheme murphy ” good colorschemes: murphy, slate, molokai, badwolf, solarized
” mostly taken from https://chrisyeh96.github.io/2017/12/18/vimrc.html”
filetype plugin indent on
set tabstop=4
set expandtab
set shiftwidth=4
set softtabstop=4

set autoindent
set smartindent

set incsearch
set hlsearch

nnoremap :nohlsearch

set autoread

Speed breakers this week (a missing slash and incorrect pwd) – 1

This is first of series of posts I am going to write as and when it happens.

When trying to develop code, the first limitation is body and brain. (or heart and soul) ; But some times silly things take up all the available time wasting precious dev time. Here are two such things happened to me this week.

All I am trying to do is create a rudimentary web html page to try one of the REST API. (I know postman could be used, but I have plans to evolve this rudimentary into full blown web UI later – anyhow the REST API is already well tested with unit testing and postman)

 <form action="/restapi" method="post"> 

And it didn’t work!. Surprise, surprise!!
when I convert this to GET its working. I created so many forms in the past what the hell is happening? I check/recheck every bit by bit – deleted everything and retyped. Nothing is helping. There is no way this could go wrong. I double check, recheck my back-end code. Try different ways of doing back-end code. Is it because I am not including request.Form.Parse()? OK – no harm, let me add it. No luck. Took a break, and restarted with a fresh mind.
Finally a light bulb💡 – instead of worrying about back-end code I thought may be browser is not sending the post data, but that is not the case 😞 – anyhow, I Google searched for GET is working and POST sending empty data. Finally some result to help me 😥. If we don’t put a slash in the end it will redirect without post data.

I wrote so many forms in the past but most of them are for PHP or c#; this one is for golang. In PHP I used to give complete file name something like restapi.php so redirection didn’t came into picture. c# thanks to visual studio it is taken care.

After adding a slash it started working! Silly!!

 <form action="/restapi/" method="post"> 

Docker PWD

The second speed breaker is when trying to run ./main in docker I got incorrect permissions.

I added chmod +x ==> no luck.

I have a RUN cd main followed by CMD [“./main”] in Dockerfile ;

Expected PWD when CMD is being executed to be main directory. But that is the not the case –

so ./main ==> I assumed it will in main directory executing main exe; but docker is trying to run main directory and getting no permissions issue!

After staring at the screen for a long time, I realized what is happening. (of course did many not so useful search and reads)

Hindsight – I should never name directory and other files with same name. It adds confusion to the error messages. Making almost error message useless.

Fixed this by making WORKDIR /app/main before CMD.

Docker notes …

Basic commands:

docker image

docker image ls
(displays list of images available on this machine)
(or simply docker images instead of docker image ls)

docker image ls -a
(displays list of all images. I think it includes deleted images? intermediate images?)

docker rmi ==> will remove the image.

docker container

docker container ls
(displays all containers currently running)
(or simply docker ls)

docker container ls -a
(displays all containers including those stopped, exited)
(Question – can we restart a container?)
(Question – can we delete an image and still container be running?)

docker rm ==> will remove the container.

Image Vs Container

This link is good.
An image is an inert, immutable, file that’s essentially a snapshot of a container. Images are created with the build command, and they’ll produce a container when started with run. Images are stored in a Docker registry such as registry.hub.docker.com. Because they can become quite large, images are designed to be composed of layers of other images, allowing a miminal amount of data to be sent when transferring images over the network.

‘docker history’ is your friend

docker history command is your friend. It gives complete history of all the layers an image is built on including the size of each layer.

docker inspect is second best friend

docker inspect is awesome! It gives everything you need to know for a container.

Digging inside docker container

  1. docker attach (is one way)
    To detach try Ctrl + P / Ctrl + Q
    If it doesn’t work – try to kill the process which is attached. (pkill -9 -f 'docker.*attach')

2. docker container exec
e.g.. docker container exec 76192e17722e cd bin && ls


docker commit

This is another cool command. It makes a new docker image from running container. Take it to new machine and start running; or use it for debugging, Use the image to start container with additional options.

docker inspect

Looks like this is similar to docker history for image ;

Helpful tips for debugging container issues

  1. docker container exec <run any command like ps, top, ls>
  2. docker container exec -it <id> bash
  3. docker container exec -it -u 0 <id> bash
  4. docker container logs << Must run after you start a container>>
  5. docker container stats << view memory/CPU usage>>
  6. docker container top
  7. docker cp
  8. docker diff
  9. docker export (Gets all files as tar)

cleanup

  1. docker container prune ==> removes all stopped containers.
  2. docker image prune
  3. docker system df
  4. docker system prune (My favorite)
  5. docker rm $(docker ps -aq -f status=exited)
  6. This link is good.


Another doc link from docker to understand more about images vs containers.

Solving Sudoku like humans do

.. is not difficult, but intriguing.

Usually solved with blind back tracking. But it felt soul-less. I want to solve like humans do.

Step 1: Solve each cell which can be guessed with 100% probability.

Step 2: Pick one of the available options and move to next.

Step 3: If nothing matches, back-track and change one of previous cells done in step 2. If reached start still nothing – no solution found.

The whole program is at https://github.com/chavakiranasdev/kichavaLibrary/blob/master/leet/hard/sudoku/Sudoku/Solution.cs

It is written and tested on Leetcode, so we ended up converting input to our object and reconverted back to required format.

CellState

/// <summary>
/// Represents state of single Cell. 
/// </summary>
internal enum CellState
{
    Empty, // Not yet filled. 

    InitialValue, // This value is already given 

    SolvedWithConfidence, // We found it with 100% probability. 

    InProgress, // Currently in progress. 
}

CellLocation

/// <summary>
/// Represents a single cell location. 
/// Used during backtracking to remember path
/// </summary>
internal class CellLocation
{
    public int Row { set; get; }
    public int Column { set; get; }
}

Cell

/// <summary>
/// Represents a cell 
/// </summary>
internal class Cell
{
    public CellState State { get; set; }
    public int CurrentValue { get; set; }

    // We tried this number & it is not fit here.
    // Used during backtracking to not re-use discarded values.
    public List<int> NotFitForThisCell { get; set; }

    public Cell()
    {
        State = CellState.Empty;
        NotFitForThisCell = new List<int>();
    }

    public void Reset()
    {
        CurrentValue = 0;
        State = CellState.Empty;
    }

    public void ClearNotFitForThis()
    {
        NotFitForThisCell.Clear();
    }
}

Find a match with 100% probability

// This checks if there is only one fit for this cell. 
// If it finds more than one fit, then we return zero.
private int GetBestFit(int row, int column)
{
    var gridKey = GetGridNumber(row, column);
    var availableInAllThree = rowAvailableList[row].Intersect(columnAvailableList[column]).Intersect(gridAvailableList[gridKey]);
    if (availableInAllThree.Count() == 1)
    {
        return availableInAllThree.First();
    }
    return 0;
}

Datastructures

// Constants 
// we can generally solve sudoku of any size. 
// So far, tested only for size 9
private int SizeOfSudoku { get; set; }

// Private variables. 
// Later, we create a board of given size (e.g.. 9X9)
private Cell[,] cellBoard;

// Next three dictionaries (hash's) represent each row, column, grid and still available values at any instance. 
// For example, once we initialize with input values, we remove them from corresponding row, column, grid. 
// Instead of three hashe's we could use 9X9 hashes to do same for each cell. That should be good for perf, for now this what I used.
Dictionary<int, List<int>> rowAvailableList = new Dictionary<int, List<int>>();
Dictionary<int, List<int>> columnAvailableList = new Dictionary<int, List<int>>();
Dictionary<int, List<int>> gridAvailableList = new Dictionary<int, List<int>>();

Constructor

public Solution(int sizeOfSudoku = 9)
{
    SizeOfSudoku = sizeOfSudoku;
    cellBoard = new Cell[SizeOfSudoku, SizeOfSudoku];
}

Solution

public void SolveSudoku(char[][] board)
{
    Console.WriteLine("Start...");
    InitializeAllAvailableLiistsWithEverything();
    // Initialize given char array into our cell array. 
    InitializeCellArray(board);

    // First round - find all those which doesn't need guessing.
    bool isAtleastOneBestFitFound;
    int currentRow;
    int currentColumn;
    do
    {
        isAtleastOneBestFitFound = false;
        // Solve each row. 
        currentRow = 0;
        while (currentRow < SizeOfSudoku)
        {
            currentColumn = 0;
            while (currentColumn < SizeOfSudoku)
            {
                if (cellBoard[currentRow, currentColumn].CurrentValue == 0)
                {
                    var bestFit = GetBestFit(currentRow, currentColumn);
                    if (bestFit != 0)
                    {
                        // We have a match. Update the cell with this value.
                        isAtleastOneBestFitFound = true;
                        UpdateCellValue(currentRow, currentColumn, bestFit, CellState.SolvedWithConfidence);
                    }
                }
                currentColumn++;
            }
            currentRow++;
        }
    } while (isAtleastOneBestFitFound);

    // Second round - Try to do best guess
    bool response = true;
    response = SolveByRow();
    if (response == false)
    {
        Console.WriteLine("Bug: Unable to solve given Sudoku");
    }

    // we should be done now. 
    // Just put final result into char array instead of cell object array
    for (int i = 0; i < SizeOfSudoku; i++)
    {
        for (int j = 0; j < SizeOfSudoku; j++)
        {
            board[i][j] = Convert.ToChar(cellBoard[i, j].CurrentValue + 48);
        }
    }
}

SovleByRow

 private bool SolveByRow()
    {
        bool response = true;
        if (!SolveGivenSubBlock(rowStart: 0, rowEnd: SizeOfSudoku - 1, columnStart: 0, columnEnd: SizeOfSudoku - 1))
        {
            response = false;
            Console.WriteLine("Bug? Unable to solve some of the grid");
        }
        return response;
    }

SolveGivenSubBlock

 private bool SolveGivenSubBlock(int rowStart, int rowEnd, int columnStart, int columnEnd)
    {
        bool response = true;
        for (int currentRow = rowStart; currentRow <= rowEnd; currentRow++)
        {
            for (int currentColumn = columnStart; currentColumn <= columnEnd; currentColumn++)
            {
                if (!SolveGivenCell(currentRow, currentColumn))
                {
                    response = false; // do not overwrite this value for next cell's success, and thus above if
                }
            }
        }
        return response;
    }

SolveGivenCell

  private bool SolveGivenCell(int currentRow, int currentColumn)
    {
        bool response = true;
        var currentCell = cellBoard[currentRow, currentColumn];
        if (currentCell.CurrentValue == 0)
        {
            // go back tracking. 
            // This will first attempt to find best guess if not found then back tracks.
            if (!BackTrackRealThisTime(currentRow, currentColumn))
            {
                response = false;
                Console.WriteLine($"Bug? Unable to solve {currentRow} :: {currentColumn}");
            }
        }
        return response;
    }

Backtracking

 private bool BackTrackRealThisTime(int currentRow, int currentColumn)
    {
        var stack = new Stack<CellLocation>();
        // clear not fit for this, if any from prevous attempts.
        cellBoard[currentRow, currentColumn].ClearNotFitForThis();
        stack.Push(new CellLocation() { Row = currentRow, Column = currentColumn });

        while (stack.Count != 0)
        {
            var currentTopOfStack = stack.Peek();
            var bestGuess = GetBestGuess(currentTopOfStack.Row, currentTopOfStack.Column);
            if (bestGuess != 0)
            {
                // We have a guess. Update the cell with this value.
                UpdateCellValue(currentTopOfStack.Row, currentTopOfStack.Column, bestGuess, CellState.InProgress);
                stack.Pop(); // Remove this from stack.
                continue;
            }
            var previousCellLocation = GetPreviousInProgressCellLocation(currentTopOfStack);
            // Push this cell onto stack after emptying it.;
            var previousCell = cellBoard[previousCellLocation.Row, previousCellLocation.Column];
            previousCell.NotFitForThisCell.Add(previousCell.CurrentValue);
            RemoveCellValue(previousCellLocation.Row, previousCellLocation.Column);
            // Now that we are moving further back, current cell's notfit is no longer valid.
            cellBoard[currentTopOfStack.Row, currentTopOfStack.Column].ClearNotFitForThis();
            stack.Push(previousCellLocation);
        }
        return true; // stack is empty
    }

Conclusion

I tried to be lazy and backtrack in random, without remembering path – but on my machine it works, leetcode always timed out. Forcing me to be a better 🙂

Get rest of the code from above github link.

Notes while becoming a Gopher (aka learning Go language)

  1. Functions returning multiple values is taken to next level.  
  2. Golang’s documentation to get started is very well designed and implemented. Other languages can learn a bit from here to not make their complex-language learning extra-complex.  
  3. I thought I have seen last of pointers for major use cases, alas, I am mistaken.  
  4. “for” is new ‘while’.  
  5. Switch is all powerful.  (Good. I still remember how I suffered with switch in Java6 days)
  6. Methods are c# extension methods. (Or the otherway)  
  7. Go is C.Redefined. (Or C.Redesigned or C.Improved)  
  8. Go is not OOPS but Go is OOPS (Or Go is only a bit of OOPS and lot of Procedural)  
  9. Copy is actually CopyTo as destination is first argument and source is second argument.  
  10. Defer will do finally’s job, in more human way. Defer + Recover is catch; panic is throw exception. But the documentation says they don’t have try catch – I am a bit confused. It feels panic-defer-recover are more human friendly design of try-catch-finally.
  11. I may miss c#’s $_ string interpolation. 
  12. Loved separate name for rune. Makes conversing in Unicode characters more straightforward. 

An idea to save Twitter from itself : InDoor

Twitter is great – for celebrities, media and folks inside media.

But for common-man twitter is chaos. Nothing much to offer for them other than keeping up to date which also not possible due to its infinite chaos. Even if one follows ten people, it is impossible to feel satisfied. It is always unfinished – forcing people to run away to other social networking sites or moving on with life.

One idea to save Twitter from this self destructing nature. InDoor

Allow people to make their own twitter.

  1. Anybody can create an indoor twitter.
  2. Example twitter.com/indoor/myFamily or twitter.com/indoor/myTeam
  3. Tweets inside indoor are for members only.
  4. Every member follows every other member by default this setting can be changed either globally or per member by moderator.
  5. One can unfollow any member.
  6. One can retweet public tweets to indoor only.
  7. Once on indoor there won’t be any confusion whole twitter interface remains same, except everything now applies to indoor account. Users can easily exit indoor and go to public twitter.

This should make twitter more useful to common members who are not celebrities. This will put twitter in direct competition with What’sapp for family/friend groups + slack/teams for office groups.

Once basic structure is there – we could go on innovating much more.