Mechanical keyboard on Mac OS. When the right command key does not work properly.

Recetly I decided to switch from an Apple magic keyboard to the on of the mechanical keyboard I bought the other day on the Aliexpress. It's the GK85 one with red switches. Despite the fact this keyboard wasn't expensive the typing felt pretty good. Although the keyboard was compatible with the Mac OS, I faced that the right command key did not work as expected. Then the Karabiner Elements app came to my aid. In Karabiner-EventViwer I was able to determine the correct key-code that was associated with this key. In my case it was {"key_code": "application"}. So, there was just one thing left to do - map this key_code to the key_code I needed - right_command:
Simple Modifications ->
  For your device (select it) ->
    Add item -> application (Keys in pc keybords) ->
      right_command (Modifier keys)
There you go - it started functioning well.

Golang. Working with go module dependencies

In order to initialize go modules in our project just run the next command

go mod init github.com/<user>/<project>
As a result, go.mod and go.sum will be created. go.mod file describes all the dependencies in the project, as well as the current version of the language and initialized module name.

This file also contains the following elements:

require includes all dependency modules and the associated version that we are going to use in our project.

replace points to the local version of the dependency in Go, not git-web. It will create a local copy of the provider with available versions, so there is no need to install every time we want to refer to the provider.

//indirect implies that we do not use these dependencies inside our project, but there is some module that imports them.

go.sum maintains a checksum, so when we run the project again, it won't install all the packages again. It uses the cache, which is stored in the $GOPATH/pkg/mod directory (module cache directory).

It is possible to create a separate catalog of vendors with available versions. This copies all third-party dependencies to the vendor folder at the root of your project. This adds all the transitive dependencies needed to run the vendor’s package. When vendoring is enabled, the go command will download packages from the vendor directory instead of downloading modules from their sources into the module cache and using the already downloaded packages.

go mod vendor

There is a command to remove installed packages. This command is used to clear the mod cache, which is stored in $GOPATH/pkg/mod. The -modcache flag removes the entire module load cache, including unpacked dependency version source code.

go clean -modcache

To view a list of available package versions

go list -m -versions github.com/pkg/math

To view a list of available versions of all packages that are used in your project

go list -m all

The list of available versions will only be displayed if the package has a release version. In this case, if a package is used that does not have a release version, then go.mod will display an entry in the following format instead of the version - v0.0.0-<timestamp>-<commit-hash> In fact, the availability of a release version can also be found through git commands:

git ls-remote —tags git://github.com/.git | less
git ls-remote —heads git://github.com/.git | less

Upgrading dependency to the latest version

go get example.com/pkg

Upgrading dependency and all its dependencies to the latest version

go get -u example.com/pkg

Viewing available dependency upgrades. It will show you available minor and patch upgrades for all direct and indirect dependencies

go list -u -m all

Upgrading all dependencies at once. To upgrade all dependencies at once for a given module, just run the following from the root of your module. This upgrades to the latest or minor patch release

go get -u ./...

Or we can upgrade test dependencies

go get -t -u ./...

To also upgrade to a specific version using Go modules

go get foo@v1.2.3
go get github.com/pkg/math@v0.3.0

or specifying a commit hash

go get foo@f5801deq7

We can update the package to the latest available version and thus

go get github.com/pkg/math@latest

Thus, given the required version, we can perform downgrading and upgrading. After all such updates and changes in the project code, it is recommended to run the command

go mod tidy

This will then link the current imports in the project and packages listed in go.mod go mod tidy ensures that the go.mod file matches the source code of the module. It adds any missing module requirements needed to build the current module's packages and dependencies, if there are any unused dependencies, go mod tidy will remove them from go.mod accordingly. It also adds any missing entries to go.sum and removes unnecessary entries.

Golang. Encapsulation via interfaces

How we can use all power of encapsulation in golang?
To achieve that we can use so-called interfaces. Below you can see one example of that approach. Our Notifier interface is public and the notifier struct is private. It means that all external clients will be able to use notifiers package publicly only via public interface while other things are hidden. So it’s the power of using encapsulation.

package notifiers

import "fmt"

type Notifier interface {
	Send()
}

type notifier struct {
	client string
}

func NewNotifier(client string) Notifier {
	return &notifier{client: client}
}

func (n *notifier) Send() {
	fmt.Printf("Notifier sent notification via client: %v\n", n.client)
}

package main

import "notifiers"

func main() {
	notifiers.NewNotifier("html client").Send()
}
But what if we need to get access to the state of returning struct instance from the package instead of being able to work only with the public interface? In that case, we can change the return type in the signature of the public constructor NewNotifier.

func NewNotifier(client string) *notifier {
	return &notifier{client: client}
}
And it will be workable. But if you try to run golint then you will get the next error message:

exported func NewNotifier returns unexported type *notifier, which can be annoying to use (golint)


There is only one thing we can do to fix it. This is to make the return struct public.

package notifiers

import "fmt"

type Notifier struct {
	client string
}

func NewNotifier(client string) *Notifier {
	return &Notifier{client: client}
}

func (n *Notifier) Send() {
	fmt.Printf("Notifier sent notification via client: %v\n", n.client)
}
As you can see, the Notifier interface had to be removed. Thus, we threw more details out. In my opinion, it’s a less abstract approach. Despite this, we can still use encapsulation both at the package and at the level of public structure (by using private fields).

Ruby. Working with PostGIS extension

Postgres is well known as a modern and powerful database. One of the possibilities is support for working with geospatial data. Initially, this requires the installation of the PostGIS extension. Next, in your rails application, you need to use gems such as:
  • gem 'activerecord-postgis-adapter'
  • gem 'rgeo'
  • gem 'geocoder'

Below is an example of working with a truck model, in which one of the fields (let's call it waypoints) has a special data type - geometry(linestring).


# app/lib/geo.rb
class Geo
  SRID = 4326
  
  METHODS = %i[point line_string]
  
  class << self
    delegate *METHODS, prefix: 'cartesian', to: :cartesian_factory
    delegate *METHODS, prefix: 'spherical', to: :spherical_factory

    def cartesian_factory
      @cartesian_factory ||= RGeo::Cartesian.factory
    end

    def spherical_factory
      @spherical_factory ||= RGeo::Geographic.spherical_factory(srid: SRID)
    end

    def pairs_to_points(pairs)
      pairs.map { |pair| point(pair[0], pair[1]) }
    end
    
    def pairs_to_line_string(pairs)
      points = pairs_to_points(pairs)
      cartesian_line_string(points)
    end
  end
end


# app/models/concerns/geo_workable.rb
module GeoWorkable
  extend ActiveSupport::Concern

  METHODS = %i[pairs_to_points pairs_to_line_string].freeze

  included do
    delegate *METHODS, to: Geo
  end

  class_methods do
    delegate *METHODS, to: Geo
  end
end


# app/models/track.rb
class Track < ActiveRecord::Base
  include GeoWorkable
  
  def coordinates
    self.waypoints.coordinates
  end
  
  def update_waypoints(coordinates)
    self.waypoints = pairs_to_line_string(coordinates)
    self.save
  end
end


track = Track.find(...)
coordinates = track.coordinates # [[longitude, latitude], [longitude, latitude], ...]
# do some transformations on that coordinates
track.update_waypoints(coordinates)

Golang. A simple concept of a constructor

In Go it does not exist the concept of a constructor like in other languages. A struct is a very flexible construct that can be defined in many ways. When working with structs it is very important to take into consideration fields zero values and how these values may impact the code. In many cases, it is a good practice to define constructors, especially when certain values are not valid.

package main

type Box struct {
	Height int
	Width  int
}

// It's a kind of constructor
func NewBox(height int, width int) (*Box, error) {
	if height <= 0 || width <= 0 {
		return nil, errors.New("params must be greater than zero")
	}

	return &Box{height, width}, nil
}

func main() {
	b, err := NewBox(1, 2)
	if err != nil {
		...
	}
}

JavaEE/WildFly/vscode. Debugging a web application in the vscode in conjunction with the WildFly server

As an experiment, I tried to debug a simple web application running on the WildFly server in vscode. Of course, vscode does not have the same completeness as IntelliJ IDEA in terms of features, but it can be considered as a kind of alternative. So, in order to debug your application, start the WildFly server in debug mode, specifying the port to which vscode will connect (in my case, port 8787 is specified):

standalone.sh --debug 8787
After that add the configuration:

{
    "version": "0.2.0",
    "configurations": [
        {
            "type": "java",
            "name": "Debug (Attach)",
            "projectName": "your_project_name",
            "request": "attach",
            "hostName": "your_host_name",
            "port": "debugging_port"
        }
    ]
}
In my case the configuration looks like this:

{
    "version": "0.2.0",
    "configurations": [
        {
            "type": "java",
            "name": "Debug (Attach)",
            "projectName": "webapp",
            "request": "attach",
            "hostName": "localhost",
            "port": 8787
        }
    ]
}
Next, start debugging by pressing F5 Now everything is ready, so you can set breakpoints and debug your application. Happy debugging 🖖

Ruby. Iterating through a collection within specified a window

Rust has a method - windows (or equivalent - chunks)

  fn main() {
    let ints = [0, 1, 2, 3, 4, 5, 6, 7, 8];
    let slice = &ints;

    for el in slice.windows(3) {
      println!("window {:?}", el)
    }
  }
that allows you to iterate through a slice and read elements within specified a window. Below is the implementation of similar functionality in Ruby:

module Enumerable
  def windows(n)
    raise ArgumentError.new("Expected a value greater than 0") if n <= 0

    return to_enum(:windows, n) unless block_given?
    return nil if self.size == 0

    (0..(self.size/n)).each do |i|
      l = i * n
      yield self[l...(l + n)]
    end
  end
  
  alias_method :chunks, :windows
end

irb(main):014:0> [0, 1, 2, 3, 4, 5, 6, 7, 8].windows(3).each { |el| puts el.join(',') }
0,1,2
3,4,5
6,7,8

irb(main):015:0> [0, 1, 2, 3, 4, 5, 6, 7, 8].windows(0).each { |el| puts el.join(',') }
(irb):3:in `windows': Expected a value greater than 0 (ArgumentError)

irb(main):016:0> windows = [0, 1, 2, 3, 4, 5, 6, 7, 8].windows(5)
=> #
irb(main):017:0> windows.each { |el| puts el.join(',') }
0,1,2,3,4
5,6,7,8

Why algorithms (in particular, I/O algorithms) are important

Suppose we have a two-dimensional array, which is a map with given heights at different points. Let's calculate the average elevation. To do this, you can go through either each row:
sum = 0
for i = 0 to m - 1 do
  for j = 0 to m - 1 do
    sum = sum + A[i, j]
avg = sum / m^2
or each column:
sum = 0
for j = 0 to m - 1 do
  for i = 0 to m - 1 do
    sum = sum + A[i, j]
avg = sum / m^2
Then summarize all heights and divide by the number of points on the map. Do you think there is any difference between these methods? It would seem not, but in fact, there is. The first method (traversing all rows) turns out to be more productive than the second method (traversing the columns). The whole thing is related to the organization of the array in memory and access to each cell. I tried to compare on Java. That's what I did.

// Computing the average elevation
class Avg {
  public static void main(String[] argv) {
    int n = 1000; // 1000 * 1000 = 10^6
    int[][] matrix = new int[n][n];

    fillMatrix(matrix, n, 1);

    long start = System.nanoTime();
    int avg = avgRowByRow(matrix);
    System.out.println(String.format(
      "avg (Row By Row) = %s,
      it takes %s nano-seconds",
      avg,
      System.nanoTime() - start
    ));

    start = System.nanoTime();
    avg = avgColumnByColumn(matrix);
    System.out.println(String.format(
      "avg (Column By Column) = %s
      it takes %s nano-seconds",
      avg,
      System.nanoTime() - start
    ));
  }

  private static void fillMatrix(int[][] matrix, int n, int default_value) {
    for (int i = 0; i < n; i++) {
      for (int j = 0; j < n; j++) {
        matrix[i][j] = default_value;
      }
    }
  }

  private static int avgRowByRow(int[][] matrix) {
    int sum = 0, m = matrix.length;

    for (int i = 0; i < m; i++) {
      for (int j = 0; j < m; j++) {
        sum = sum + matrix[i][j];
      }
    }

    return sum / m / m; // sum / (m * m)
  }

  private static int avgColumnByColumn(int[][] matrix) {
    int sum = 0, m = matrix.length;

    for (int j = 0; j < m; j++) {
      for (int i = 0; i < m; i++) {
        sum = sum + matrix[i][j];
      }
    }

    return sum / m / m; // sum / (m * m)
  }
}
Then I tried to run it a couple of times and got the following result. The result can be said to be obvious:
avg (Row By Row)       = 1, it takes 3822568 nano-seconds
avg (Column By Column) = 1, it takes 5646746 nano-seconds

avg (Row By Row)       = 1, it takes 3902352 nano-seconds
avg (Column By Column) = 1, it takes 5467638 nano-seconds

avg (Row By Row)       = 1, it takes 3939734 nano-seconds
avg (Column By Column) = 1, it takes 5077092 nano-seconds

avg (Row By Row)       = 1, it takes 3736544 nano-seconds
avg (Column By Column) = 1, it takes 4950847 nano-seconds

avg (Row By Row)       = 1, it takes 3900019 nano-seconds
avg (Column By Column) = 1, it takes 5009578 nano-seconds

avg (Row By Row)       = 1, it takes 3954720 nano-seconds
avg (Column By Column) = 1, it takes 5109380 nano-seconds

avg (Row By Row)       = 1, it takes 3824056 nano-seconds
avg (Column By Column) = 1, it takes 5276105 nano-seconds

API Documentation. Multiple examples in Swagger

When describing the API documentation, sometimes there is a need to add several examples of responses. This is necessary for the possibility of a more complete description of the API documentation, since this API documentation is a kind of contract between the backend and the frontend. If you still use Swagger v.2.0 then you face the limitation - adding multiple examples is not supported. To get around this limitation, you need to go to the OpenAPI v. 3.0.0 specification. Then you will be able to add examples as follows.

- One example:

responses:
  "200":
    description: user creation successful
    content:
      application/json:
        example:
          token: fEt4IouUyRrqlx80treEWwq8
- A few examples:

responses:
  "422":
    description: user creation failed
    content:
      application/json:
        schema:
          properties:
            response:
              $ref: "#/components/schemas/ErrorResponse"
        examples:
          "Missing parameters":
            value:
              error: 'error-1'
              message: 'error-message-1'
          "Validation failed":
            value:
              error: 'error-2'
              message: 'error-message-2'


The differences between Swagger v.2.0 and the OpenAPI v. 3.0.0 specification are generally not so big:

    Swagger v.2.0     |  OpenAPI v.3.0.0
----------------------|-------------------
    info              |    info
----------------------|-------------------
   host               |
   basePath           |    servers
   schemes            |
----------------------|-------------------
   security           |    security
----------------------|-------------------
   paths              |   paths
----------------------|-------------------
   externalDocs       |   externalDocs
----------------------|-------------------
   tags               |   tags
----------------------|-------------------
                      |
  securityDefinitions |
                      |  components:
----------------------|    parameters
   produces           |    responses
----------------------|    examples
   consumes           |    requestBodies
----------------------|    headers
   definitions        |    links
   parameters         |    callbacks
   responses          |    securitySchemes
                      |

So the transition itself should not be difficult.

Rspec. When hashes are used inside arrays

I'm always amazed at the flexibility of unit testing when working with Ruby projects. Below are examples of such flexibility in which you can check the contents of hashes nested in an array.

context 'when hashes in array' do
  let(:hash_set) do
    [
      { attr1: 1, attr2: 2 },
      { attr1: 3, attr2: 4 }
    ]
  end

  let(:attribute_keys) { %i[attr1 attr2] }

  it 'contains a set of attribute keys' do
    expect(hash_set).to all(include(*attribute_keys))
  end
end

context 'when hashes in nested array' do
  let(:hash_set) do
    [
      { attr1: 1, attr2: [{ attr3: 3, attr4: 4 }] },
      { attr1: 5, attr2: [{ attr3: 6, attr4: 7 }] }
    ]
  end

  let(:first_attribute_keys) { %i[attr1 attr2] }
  let(:second_attribute_keys) { %i[attr3 attr4] }

  it 'contains a set of first attribute keys' do
    expect(hash_set).to all(include(*first_attribute_keys))
  end

  it 'contains a set of second attribute keys' do
    expect(hash_set).to all(
      include(attr2: all(include(*second_attribute_keys)))
    )
  end
end

# Some class for testing
class Tester
  def exec(options)
    # some work
  end
end

context 'when hashes are passed as parameters' do
  subject(:tester) { Tester.new }

  let(:options) do
    {
      attr1: 1,
      attr2: { attr4: 2 },
      attr3: [
        { attr5: 3 },
        { attr6: 4 }
      ]
    }
  end

  it 'contains a set of attribute keys with values' do
    expect(tester).to receive(:exec).with(
      hash_including(
        attr1: 1,
        attr2: hash_including(attr4: 2),
        attr3: [hash_including(attr5: 3), hash_including(attr6: 4)]
      )
    )

    tester.exec(options)
  end

  it 'contains a set of attribute keys' do
    expect(tester).to receive(:exec).with(
      hash_including(
        :attr1,
        attr2: hash_including(:attr4),
        attr3: array_including(hash_including(:attr5), hash_including(:attr6))
      )
    )

    tester.exec(options)
  end
end

Ruby. Messages from RuboCop about using predefined variables

Ruby has a lot of predefined variables. The one of them is $/. It is used as a universal substitution of newline symbol:

> numbers = ['one', 'two', 'three']
=> ["one", "two", "three"]

> numbers.join($/)
=> "one\ntwo\nthree"

> puts numbers.join($/)
one
two
three
=> nil
RuboCop is a Ruby code style checker (linter) and formatter based on the community-driven Ruby Style Guide. If you use it in your project, then it is possible that you will face with the next problem when using $/:
Prefer `$INPUT_RECORD_SEPARATOR` or `$RS` from the stdlib 'English' module
(don't forget to require it) over `$/`.(convention:Style/SpecialGlobalVars)
To fix it you can do like this:

# readable global var aliases
require 'English'

...
def log_error(error)
  backtrace_cleaner = ActiveSupport::BacktraceCleaner.new
  backtrace_cleaner.add_filter { |line| line.gsub(Rails.root.to_s, '') }
  backtrace_cleaner.add_silencer { |line| line =~ /puma|rubygems/ }

  Rails.logger.error(
    [
      "#{error.class}: #{error.message}",
      *backtrace_cleaner.clean(error.backtrace)
    ].join($RS)
  )
end
...

As you can see I have used the $RS. Instead, you can use $INPUT_RECORD_SEPARATOR.

Mathematical equivalence of bit shifts

a << b <=> a * (2 ^ b)
a >> b <=> a / (2 ^ b)

Apache Bench

The Apache software foundation offers a lot of cool tools. The one of them is Apache Bench. It gives you ability to test and get benchmarks of handling http requests by your web service. I currently use Ubuntu so to play around I ran next command:

sudo apt-get install apache2-utils
And fed my service to it:

ab -n 100 -c 10 http://127.0.0.1/greet
As a result, you'll get next output:

This is ApacheBench, Version 2.3 <$Revision: 1807734 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/

Benchmarking 127.0.0.1 (be patient).....done


Server Software:        nginx/1.17.6
Server Hostname:        127.0.0.1
Server Port:            80

Document Path:          /greet
Document Length:        10 bytes

Concurrency Level:      10
Time taken for tests:   0.004 seconds
Complete requests:      100
Failed requests:        0
Total transferred:      15300 bytes
HTML transferred:       1000 bytes
Requests per second:    27956.39 [#/sec] (mean)
Time per request:       0.358 [ms] (mean)
Time per request:       0.036 [ms] (mean, across all concurrent requests)
Transfer rate:          4177.08 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        0    0   0.0      0       0
Processing:     0    0   0.0      0       0
Waiting:        0    0   0.0      0       0
Total:          0    0   0.0      0       0

Percentage of the requests served within a certain time (ms)
  50%      0
  66%      0
  75%      0
  80%      0
  90%      0
  95%      0
  98%      0
  99%      0
 100%      0 (longest request)

Ruby/Haskell. Left and right folds

Haskell has ample opportunities to work with lists, in particular - left and right fold. For this in the Prelude module there are functions such as foldr - for the right fold and foldl - for the left fold:

foldr :: (a -> b -> b) -> b -> [a] -> b
foldr f ini []     = ini
foldr f ini (x:xs) = f x (foldr f ini xs)

foldl :: (b -> a -> b) -> b -> [a] -> b
foldl f ini []     = ini
foldl f ini (x:xs) = foldl f (f ini x) xs
For an example of their use let's implement the function evenOnly, which throws out elements from the list that stand in odd places, leaving only even ones. One of the implementations is as follows:

evenOnly :: [a] -> [a]
evenOnly = fst . foldr (\x (y1, y2) -> (y2, x:y1)) ([],[])
To do this, we used the right fold. Consider how Haskell will step by step perform the reductions with the fold of the list [1, 2, 3, 4].
Denote the anonymous function (\ x (y1, y2) -> (y2, x: y1)) by f

{- Right fold of list (steps of reductions):
foldr f ([],[]) 1:2:3:4:[]
~> f 1 (foldr f ([],[]) 2:3:4:[])
~> f 1 (f 2 (foldr f ([],[]) 3:4:[]))
~> f 1 (f 2 (f 3 (foldr f ([],[]) 4:[])))
~> f 1 (f 2 (f 3 (f 4 (foldr f ([],[]) []))))
~> f 1 (f 2 (f 3 (f 4 ([],[]))))
~> f 1 (f 2 (f 3 ([],4:[])))
~> f 1 (f 2 (4:[], 3:[]))
~> f 1 (3:[], 2:4:[])
~> (2:4:[], 1:3:[])
([2,4], [1,3])
-}
Let's change the right fold to the left in this implementation:

evenOnly :: [a] -> [a]
evenOnly = fst . foldl (\(y1, y2) x -> (y2, x:y1)) ([],[])
And also let's look how reductions will be executed step by step.

{- Left fold of list (steps of reductions):
foldl f ([],[]) 1:2:3:4:[]
~> foldl f (f ([],[]) 1) (2:3:4:[])
~> foldl f (f (f ([],[]) 1) 2) (3:4:[])
~> foldl f (f (f (f ([],[]) 1) 2) 3) (4:[])
~> foldl f (f (f (f (f ([],[]) 1) 2) 3) 4) []
~> f (f (f (f ([],[]) 1) 2) 3) 4
~> f (f (f ([],1:[]) 2) 3) 4
~> f (f (1:[],2:[]) 3) 4
~> f (2:[], 3:1:[]) 4
~> (3:1:[], 4:2:[])
([3,1], [4,2])
-}
From these examples we can see how the right and left folds differ. Also note that the implementation of evenOnly through left fold certainly behaves incorrectly, because the order of the "even" values becomes incorrect. Also pay attention to the difference of signatures of anonymous functions passed to the functions foldr and foldl. Now we will try to implement similar functionality on Ruby. First, let's implement the functions foldr and foldl:

def foldr(f, ini, list)
  return ini if list.length == 0
  *xs, x = list
  foldr(f, f.call(x, ini), xs)
end

def foldl(f, ini, list)
  return ini if list.length == 0
  x, *xs = list
  foldl(f, f.call(ini, x), xs)
end
Based on the right fold:

evenOnly = ->(list) { foldr(->(x, ini) { xs, ys = ini; [ys, [x, *xs]] }, [[], []], list).first }
Based on the left fold:

evenOnly = ->(list) { foldl(->(ini, x) { xs, ys = ini; [ys, [x, *xs]] }, [[], []], list).first }
Since the left fold is incorrect (given only for demonstration), we take the right fold as the basis and run our implementation for the test a couple of times:

evenOnly.call([])                              # []
evenOnly.call([1])                             # []
evenOnly.call([1, 2, 3, 4])                    # [2, 4]
evenOnly.call([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]) # [2, 4, 6, 8, 10]

Ruby/Haskell. Hoare's partition sort or quick sort. Imperative or functional approach?

Some of these days I had fun with Haskell. I tried to write Hoare's sort in Haskell. For my implementation I used list's filtering by the element that was in the middle of the list:

qsort :: Ord a => [a] -> [a]
qsort [] = []
qsort xs = partitions (xs !! (div ((length xs) - 1) 2)) xs where
  partitions x' xs' =
    qsort (filter (< x') xs') ++ (filter (== x') xs') ++ qsort (filter (> x') xs')
What is the most interesting that using of this kind of filtering allows to write a more intuitive algorithm than a variant with an imperative implementation. For comparison, below we can see implementations in Ruby.

This is a variant of imperative implementation:

def hoaresort(array, first, last)
  i, j = first, last
  x  = array[(i + j) / 2]

  begin
    i += 1 while array[i] < x
    j -= 1 while array[j] > x

    if i <= j
      array[i], array[j] = array[j], array[i] if i < j
      i += 1
      j -= 1
    end
  end while (i <= j)

  hoaresort(array, i, last) if i < last
  hoaresort(array, first, j) if first < j

  # Uncomment next line if you want to return sorted array as result
  # array
end
And next is a variant of functional implementation:

def hoaresort(array)
  return [] if array.length == 0
  
  x = array[(0 + (array.length - 1)) / 2]
  
  hoaresort(array.filter { |v| v < x }) +
    array.filter { |v| v == x } +
      hoaresort(array.filter { |v| v > x })
end
In my opinion the comparison obviously shows us that the functional approach is more clear and understandable.

curl. Basic authentication

Specify the user name and password to use for server authentication:

curl --user <name>:<password> http://www.test.com
If you simply specify the user name, curl will prompt for a password:

curl --user <name> http://www.test.com
Also you can encrypt name and password before sending your curl request:

curl -H "Authorization: Basic <your_token>" http://www.test.com
where <your_token> is being generated like that:

-ne "<name>:<password>" | base64 --wrap 0

Git. Often used command set

Shows git tree of all commits

git log

Moving around in Git: - destination by:

HEAD^
HEAD^^^
HEAD~
HEAD~3
<branch>^
<branch>~2
<branch>
- or by hash of commit:

fed2da64c0efc5293610bdd892f82a58e8cbc5d8
- commands:

git checkout <destination>
git checkout HEAD~;
git checkout HEAD^2;
git checkout HEAD~2;
git checkout HEAD~^2~2
git branch -f <branch> <destination>
git branch <branch> master^~2
- feature in merge commit

git checkout master^1 # goes to the first ancesstor
git checkout master^2 # goes to the second ancesstor

Creates new feature branch without checking out

git branch <feature-branch-name>
git branch <feature-branch-name> HEAD~

Creates new feature branch and check out

git checkout -b branch <feature-branch-name> HEAD~

Rebasing (target branch ia a current branch)

git rebase <source-branch>
- with hash of commit

git rebase <Commit>
- with interactive mode

git rebase -i HEAD~4
- for rebasing target branch with source branch

git rebase <source-branch> <target-branch>

Reversing changes: - only local

git reset HEAD~1
- for share with remote

git revert HEAD
- only for changing last commit message

git commit --amend

Adds commits (copies) to current branch in given order

git cherry-pick <Commit1>, <Commit2>, ...

Tagging commits

git tag <tag-name>
git describe <place>
OUTPUT: <tag>_<numCommits>_g<hash>

Merging changes (target branch ia a current branch)

git merge <source-branch>

Pulling changes from remote
- in merging way
git pull is equal to git fetch; git merge origin/master

git pull
git push

git fetch
git merge origin/master
git push
- in rebase way
git pull --rebase is equal to git fetch; git rebase origin/master

git pull --rebase
git push

git fetch
git rebase origin/master
git push
- when source is related to remote and destination to local (if branch doesn't exist it will be created)

git pull origin <source>:<destination>
git pull origin foo is equal to git fetch origin foo; git merge origin/foo
git pull origin bar~1:bugFix is equal to git fetch origin bar~1:bugFix; git merge bugFix

- Remote tracking (when some branches can be linked by origin/master independently of master branch)

git checkout -b foo origin/master
git pull

git checkout -b foo origin/master
git commit
git push
- when branch exists

git branch -u origin/master foo
git branch -u origin/master

git branch -u foo o/master
git commit
git push

Pushing changes to remote

git push origin <place>
- source is related to local and destination to remote (if branch doesn't exist it will be created)

git push origin <source>:<destination>
git push origin master^^:foo
git push origin foo:master

Removes foo branch in remote

git push origin :foo

Adds bar branch in local

git fetch origin :bar

openssh. Problem with connection to servers via ssh

One of these days I faced the following problem. I needed to organize the ability to work on two computers with servers via ssh. On one machine a public and private key was generated, a config file was configured, everything worked well. Next, I copied the keys to another machine, also set up config file and verified that the key was added ($ ssh-add -l), but when I was trying to connect to any server I was failing. Both machines were on Ubuntu OS (17.10 and 16.04 LTS).
Next, I tried to test connection:
$ ssh -v your-useful.server.com
Output was next:
...
debug1: kex: server->client cipher: chacha20-poly1305@openssh.com MAC:
 compression: none
debug1: kex: client->server cipher: chacha20-poly1305@openssh.com MAC:
 compression: none
debug1: expecting SSH2_MSG_KEX_ECDH_REPLY
On the last line, the check was froze and ended after a while. After a short searching based on the last line of output, it turned out that problem was associated with a bug in the openssh package. The bug was revealed in the fact that each connection was required to refine the cipher via the -c key.
$ ssh -c aes256-ctr your-useful.server.com
After that, everything began to work. To exclude redundancy, you need to add either in /etc/ssh/ssh_config or in ~/.ssh/config (I chose this option) the following line:
Ciphers aes128-ctr,aes192-ctr,aes256-ctr

Ruby. Null-aware operators

1. The safe navigation operator

There are some languages that support object-oriented programming that have support for the so-called the safe navigation operator (SNO). Also it's known as optional chaining operator, safe call operator or null-conditional operator. The SNO is a binary operator that returns null if its first argument is null;
otherwise it returns the second argument.

It's used to avoid sequential explicit null checks and assignments and replace them with method/property chaining. In programming languages where the navigation operator (e.g. ".") leads to an error if applied to a null object, the safe navigation operator stops the evaluation of a method/field chain and returns null as the value of the chain expression. It's currently supported in languages such as Apache Groovy, Ruby, Swift, C#, Kotlin, CoffeeScript and others. There is currently no common naming convention for this operator, but SNO is the most widely used term.

The main advantage of using this operator is that it solves a problem commonly known as pyramid of doom. Instead of writing multiple nested ifs, programmers can just use usual chaining, but put question mark symbols before dots (or other characters used for chaining).

Ruby supports the &. safe navigation operator (also known as the lonely operator) since version 2.3.0

Let's consider concrete example of using safe navigation operator on Ruby. My current version of Ruby is 2.5.1

Let's say that we have two classes: Owner and Account:

class Owner
  attr_accessor :first_name, :last_name, :age

  def initialize(first_name:, last_name:, age:)
    self.first_name = first_name
    self.last_name = last_name
    self.age = age
  end

  def summary
    "Owner: first name: #{first_name}, last name: #{last_name}, age: #{age}"
  end
end

module Roles
  GUEST = 1
  USER = 2
  ADMIN = 4
end

class Account
  include Roles

  attr_accessor :owner, :role

  def initialize(owner, role = GUEST)
    self.owner = owner
    self.role = role
  end
end

Create instances of these classes like that

owner = Owner.new(
  first_name: 'John',
  last_name: 'Smith',
  age: 30
)

account = Account.new(owner, Roles::USER)

Now we can get a full information about owner from account by the following way

puts account.owner.summary

But what if, while creating instances of our classes, something goes wrong? Then when you try to get the full information about owner from account you won't have guarantees that this operation will be successful. Moreover, we can get an error and our system may fall. Here is an example of such a situation

account = Account.new(nil)
puts account.owner.summary

As result we get next error:

undefined method `summary' for nil:NilClass (NoMethodError)

So, to avoid this, you can use safe navigation operator &.

puts account&.owner&.summary

And instead of an error, we get nil (it's a null in Ruby)

2. The null coalescing operator

The null coalescing operator (called the Logical Defined-Or operator in Perl) is a binary operator that is part of the syntax for a basic conditional expression in several programming languages. While its behavior differs between implementations, the null coalescing operator generally returns the result of its first operand if it exists and isn't null.

In contrast to the ternary conditional if operator used as x ? x : y, but like the binary Elvis operator used as x ?: y, the null coalescing operator is a binary operator and thus evaluates its operands at most once, which is significant if the evaluation of x has side-effects.

In the ruby for these purposes, we can use the operator ||

some_variable = nil || 'default_value'

Git. Work with Bitbucket/GitHub repositories without username/password

Initially, you should have two generated keys: private - id_rsa and public - id_rsa.pub.

To do this, you need to run the command:

$ ssh-keygen -t rsa -b 4096 -f $HOME/.ssh/id_rsa


Next, you need to add your public key (its contents) via the web interface.
After that, you can work with your repositories without having to enter a password for every action you take.
But it's important to remember that you must work through ssh:// not through https://

If initially you cloned your repository like this

$ git clone https://git@REPOSITORY.git


then you need to change the remote URL to ssh://
To do this, run the command:

$ git remote set-url origin ssh://git@REPOSITORY.git


To look at current remote URL it's possible either that

$ git remote -v


or that

$ git config remote.origin.url