Blog Archive: June 2020

Poppy fields near Mchadijvari

| Tourism objects | 227 seen

Summers in Georgia are very beautiful, traveling around the country is a pleasure. One such travel happened at the start of June 2020, when we decided to find the real poppy field.

Let me explain, a couple of weeks ago we already started to search for a poppy field here in Georgia to make lovely family photos, we did found one little field near Marneuli, and we even took very good portrait photography,  but this time we decided to find a real, rich with flowers, good for photography, and luckily thanks to the hints on Facebook we got location details - Poppy fields near Mchadijvari

Poppy fields near Mchadijvari in Georgia

The destination is quite easy reachable from Tbilisi, in about an hour we were here, with a little stop at Tsilkani Cathedral

Using Google Maps we added following route - Tbilisi - > Tsilkani cathedral - Mchadijvari. Once in the Mchadijvari, there is a Mchadijvari cathedral, and on the right side there is road, some 500 meters and there is a little unpaved road, another 300-400 meters and our destinations was reached

Poppy fields near Mchadijvari in Georgia

It looks like a small painting. I was using macro photography here.

Poppy fields near Mchadijvari in Georgia

What a lovely afternoon spent in beautiful Georgia


Saint Dimitri Tesalonikeli Fathers Moanstery near Mtksheta

| Churches and Monasteries | 10 seen

This is a little monastery near Mtskheta, best reached via Mtskheta-Shiomghvime monastery road.

That's how we actually discovered this place at the end of May 2020 - during a random drive to the Shio-Mgvime monastery, we looked for some nice picnic areas to dine outdoors, we did a few stops here and there until noticed this place.

We didn't picnic here, but in the nearby forest after a brief trip to the monastery.

Probably not as impressive as the Jvari monastery or Svetistkhoveli cathedral in Mtshekta this place has some magic.

Little wooden roadside in Georgian 

The monastery complex is at the end of the road. Next to the monastery, there is a forest park and some horseback riding activities.

At the entrance of the entrance, we met monks, and they allowed us to come inside to take look around and take some photographs. 

A little church

There is a little church inside. What's interesting they are using solar power to generate electricity here. Very modern and sustainable. 

Wooden log houses inside the monastery

I'm not an expert on monastery living, but I have seen these loghouses around the world.

We are planing come back to this road and visit more monasteries, and they are many here.

 

 


Average Monthly Salary in European Union 2020

| Macroeconomics | 524 seen

In 2020 three were 27 member states in the European Union (EU), 19 of the 27 EU member states have adopted the euro (€) as their common currency.

In this article, I've compared the gross monthly average salary for 2020. As I have been writing these articles since 2014, I've left the United Kingdom, just for reference.

Update: Average Monthly Salary in European Union 2022

I wouldn't call the below written scientific research or take it too seriously, as most of the data in this article are taken from Wikipedia's article List of European countries by average wage. 

All calculations are done using Google Spreadsheets. The data provided below might not be 100% accurate but they should give an overall insight on average salary levels across European Union member countries.

Countries are ranked by average gross salary in 2020

    2020 2018     Rank Country Gross Gross Change EUR Change % 1 Denmark €5,179.00 €5,191.00 -€12.00 -0.23% 2 Luxembourg €5,143.00 €4,412.00 €731.00 16.57% 3 Germany €4,035.00 €3,703.00 €332.00 8.97% 4 Ireland €3,867.00 €3,133.00 €734.00 23.43% 5 Austria €3,811.00 €3,632.00 €179.00 4.93% 6 Belgium €3,401.00 €3,401.00 €0.00 0.00% 7 Finland €3,380.00 €3,380.00 €0.00 0.00% 8 Sweden €3,194.00 €3,340.00 -€146.00 -4.37% 9 United Kingdom €3,161.00 €2,498.00 €663.00 26.54% 10 France €3,097.00 €2,957.00 €140.00 4.73% 11 Netherlands €2,855.00 €2,855.00 €0.00 0.00% 12 Italy €2,442.00 €2,534.00 -€92.00 -3.63% 13 Spain €2,279.00 €2,189.00 €90.00 4.11% 14 Cyprus €1,992.00 €1,779.00 €213.00 11.97% 15 Slovenia €1,855.00 €1,626.00 €229.00 14.08% 16 Estonia €1,472.00 €1,221.00 €251.00 20.56% 17 Portugal €1,418.00 €1,158.00 €260.00 22.45% 18 Lithuania €1,381.00 €885.00 €496.00 56.05% 19 Malta €1,379.00 €1,379.00 €0.00 0.00% 20 Czechia €1,280.00 €1,149.00 €131.00 11.40% 21 Croatia €1,214.00 €1,081.00 €133.00 12.30% 22 Poland €1,191.00 €1,102.00 €89.00 8.08% 23 Hungary €1,154.00 €955.00 €199.00 20.84% 24 Latvia €1,152.00 €1,013.00 €139.00 13.72% 25 Slovakia €1,086.00 €980.00 €106.00 10.82% 26 Romania €1,075.00 €787.00 €288.00 36.59% 27 Greece €1,060.00 €1,092.00 -€32.00 -2.93% 28 Bulgaria €690.00 €586.00 €104.00 17.75%

Data source: List of European countries by average wage

This is a list of countries containing monthly (annual divided by 12 months) gross (before taxes) and net income (after taxes) average wages in Europe in EUR currency.The table above reflects the average (mean) wage as reported by various data providers. In less developed markets, actual incomes may exceed those listed in the table due to the existence of grey economies.

The average salary in the European Union in 2020

The gap (in terms of monthly gross salary) between the richest (Denmark) and the poorest (Bulgaria) is 7.5. Which actually is increasing, as in 2018 the gap between Denmark and Bulgaria was more 7.15 times.

There is one thing that should be kept in mind, not all countries in this list have adopted EUR currency, in fact, there are 8 out of 27 countries in the EU using their national currencies instead of EUR. ( Bulgaria, Croatia, Czechia, Denmark, Hungary, Poland, Romania, Sweden)


Oskars Kalpaks Museum and Memorial Place "Airītes"

| Museums | 16 seen

Oskars Kalpaks Museum and Memorial Place "Airītes" is a branch of the Latvian War Museum established in memory of the hero of the Latvian War of Independence Colonel Oskars Kalpaks in "Airītes", Zirņi Parish, Saldus Region.

On March 6, 1919 during the liberation battles of Latvia, colonel Oskars Kalpaks, commander of the First Latvian Special Battalion; Nikolajs Grundmanis, the First Commander of the Battalion's Special Company; Peteris Krievs, Lieutenant-General of the Cavalry Squad and Johans-Hans Srinders, Lieutenant of the Baltic Home Guard Artillery died near Airites.

Airītes

From 1922-1933 monuments in remembrance of the four heroes were unveiled here, and the Oskars Kalpaks Memorial was opened in 1936. During the Soviet occupation, the Airites Museum and memorial ensemble were closed down. The memorial was reopened in 1988, and the renovated museum opened its doors in 1990. The museum's exhibition shows the role of Oskars Kalpaks and his battalion during the liberation battles


Church of the Archangels of Mchadijvari

| Churches and Monasteries | 14 seen

Mchadijvari Archangels Church is an architectural and historical monument in Georgia,  in the center of the village of Mchadijvari. 

We discovered this church when searching for the poppy fields in Georgia, at the start of June 2020 (hint poppy fields are next to the church, some 5000 meters on the right.

Church of the Archangels of Mchadijvari

The above picture is made from the Dusheti - Mchadijvari-Odzisi highway site. This time we actually didn't visited the cathedral, but here is what I was able to find out from Georgian Wikipedia

There is a construction inscription on the church. According to the inscription, the church was built in 1668 by Domenti Catholicos, and the castle-fence by Constantine Mukhranbaton in 1746 .

Shortly after the construction of the church, during one of the raids on Kartli, the Leks surrounded the village of Mchadijvari, but the church survived the demolition. In 1746, Constantine Mukhranbaton rebuilt the village and built a fortress around the church of Mchadijvari: "to be built and built without harm from men and enemies and the Marbies."

View towards Mchadijvari from the poppy fields

The view looks like from some medieval painting, kind of Johan Brotze works (I'm not sure if he ever has been to Georgia, but if we had, he would most probably paint this place)


Khatsiri Forest Park

| Tourism objects | 22 seen

Khatsiri Forest park is a nice recreational area next to the town of Tianeti in Georgia. 

We discovered this place by accident after spending a day at Kuzh Park in Tianeti (sometimes we love to drive to the Tianeti town to walk in the Kuzh park with our baby girl).

Way back home to Tbilisi we decided to make a stop here at Khatsiri Forest Park - let me say in one word - WOW. I was impressed.

Picnic area at Khatsiri Forest park

We are planning to come here often and make a picnic quite often. Also this is yet another addition to our picnic places around Georgia.

View to the town of Tianeti

Local farmers are grazings cows and sheep in these meadows.

There is a little church a top of the hill

i didn't find much information online about this place, but if you happen be around town of Tianeti, give it a try.

Pine trees at Khatsiri forest park


Minimum Wages in European Union 2020

| Macroeconomics | 16 seen

In 2020 there were 21 out of 27 European Union member states with an official minimum wage set by the government.

In this article I've listed them all, also this is the first year I'm not including data for the UK in this table

Turns out this is already the seventh (#7) article about minimum wages in European Union featured on the blog.

    Gross 2020 Gross 2019 Change Change % 1 Luxembourg €2,142.00 €2,071.00 €71.00 3.31% 2 Netherlands €1,636.00 €1,615.00 €21.00 1.28% 3 Ireland €1,616.00 €1,563.00 €53.00 3.28% 4 Belgium €1,594.00 €1,563.00 €31.00 1.94% 5 Germany €1,584.00 €1,599.00 -€15.00 -0.95% 6 France €1,539.00 €1,521.00 €18.00 1.17% 7 Spain €1,108.00 €1,050.00 €58.00 5.23% 8 Slovenia €941.00 €886.00 €55.00 5.84% 9 Malta €777.00 €747.00 €30.00 3.86% 10 Greece €758.00 €758.00 €0.00 0.00% 11 Portugal €741.00 €700.00 €41.00 5.53% 12 Poland €611.00 €524.00 €87.00 14.24% 13 Lithuania €607.00 €555.00 €52.00 8.57% 14 Estonia €584.00 €540.00 €44.00 7.53% 15 Slovakia €580.00 €520.00 €60.00 10.34% 16 Czech Republic €575.00 €514.00 €61.00 10.61% 17 Croatia €546.00 €505.00 €41.00 7.51% 18 Hungary €487.00 €464.00 €23.00 4.72% 19 Romania €466.00 €449.00 €17.00 3.65% 20 Latvia €430.00 €430.00 €0.00 0.00% 21 Bulgaria €312.00 €286.00 €26.00 8.33%   Average EU €934.95 €898.10 €36.86 3.94%

Data source: List of European countries by minimum wage

It should be noted: The calculations are based on the assumption of a 40-hour working week and a 52-week year, with the exceptions of France (35 hours), Belgium (38 hours), United Kingdom (38.1 hours), Ireland (39 hours), and Germany (39.1 hours). Most of the minimum wages are fixed at a monthly rate, but there are countries where the minimum wage is fixed at an hourly rate or weekly rate.

As it already happened for the previous years, there are no changes in the country with the highest and lowest minimum wage. Luxembourg as usual ranks #1 with more than EUR 2,000 gross minimum wage in 2020, while Bulgaria takes the last spot with minimum wage EUR 312 Making a gap between highest and lowest salary in European Union 6.63 times. That's huge, but shrinking (for 2018, the gap was 7.62 times)

Minimum wage map in European Union 2020

When visualizing data on the map, its' clearly visible that higher minimum wages are set in the Western European countries, despite the higher growth rates are found in Eastern European countries.


Eat For Fit - Healty Food Home Delivery in Tbilisi

| Living in Georgia | 159 seen

Eat for fit is my favorite healthy food home delivery service here in Tbilisi.

Recently these loss-weight / dietary food delivery companies have started to pop up like mushrooms in the forest after the rain here in Tbilisi. We have tried a dietary menu from Eat for fit twice - and both times the result has been excellent. 

One thing should be added - we are the gym goers - and the great weight-loss results comes both from the physical activities and well-balanced food. Eat for Fit are great with calories counting and they cook really delicious food. There has not been a day I felt starvation. All was well calculated and prepared individually. 

We paid about GEL 32 (February 2020) for 5 meals for a day, meals were delivered using Glovo courier service every evening for the next day.

Eat for Fit packaging

Each day there were 5 items, like for breakfast, dinner, snacks, and supper. For snacks, there were fruits and dietary fitness snacks.

Cottage cheese with dills

When the meal plan was made - Eat For Fit asked is there some food I don't like and if there were, these foods were removed from the menu.   So no surprises here. 

Dessert from Eat for Fit

I'm ready to order more these lovely desserts.

Dinner from Eat For Fit

 


Tsilkani cathedral

| Churches and Monasteries | 37 seen

The Tsilkani cathedral of the Mother of God is a Georgian Orthodox church in the village of Tsilkani, Mtskheta Municipality, in Georgia's eastern region of Mtskheta-Mtianeti.

Originally built in the 4th century, the church was repeatedly remodeled in the Middle Ages. The extant edifice is a domed cross-in-square design, contained in a walled enclosure with corner towers. It is inscribed on the list of the Immovable Cultural Monuments of National Significance.

We discovered this church in early June 2020, when traveling the Natkhtari - Tsilkani - Mukhrani highway (we were in the searches for poppy fields, which we later found some 10 km from this church)

Tsilkani Cathedral

The Tsilkani cathedral stands in the centre of the eponymous village—northwest of the ancient city of Mtskheta—on the left bank of the Narekvavi, a tributary of the Aragvi River. The village, home to a Late Bronze Age burial mound and other archaeological finds, is also notable for a 4th–5th-century Christian crypt, with a Greek inscription on its wall

Church cupola at Tsilkani Cathedral

The Tsilkani church is credited by the medieval Georgian chronicles to King Bakar (r. c. 365–380), son of Mirian III, the first Christian king of Kartli—Iberia of the Classical sources. Originally a hall church, the cathedral was remade into a three-nave basilica in the 5th or 6th century and, eventually, reconstructed as a domed church in the 12th or 13th century. The church was further renovated in the 16th–17th century. The church was also associated in medieval Georgian tradition—elaborated in the hymns by the 13th-century cleric Arsen Bulmaisimisdze—with the monk Jesse from Antioch who came as part of the Thirteen Assyrian Fathers in Kartli around 545. It is maintained that Jesse's tomb is still preserved in the church. The cathedral was the seat of bishops of Tsilkani, first heard of in 506.

The cathedral was home to the venerated Virgin Hodegetria of Tsilkani, a 9th-century icon of the Virgin and the Child attended by the archangels. The icon was repainted and refurbished at the turn of the 12th century, but the faces painted in encaustic tempera were left untouched. In 1926, the icon was moved for preservation to the Georgian National Museum in Tbilisi.

Outer walls of the cathedral complex

The extant church, measuring 28 × 24 m and built largely of dressed sandstone blocks, is a cross-in-square building, with a semicircular apse and a central dome held up on four free-standing piers. The base of the dome is pierced with 12 windows. The interior is additionally lit with 10 windows cut in the walls. The church has three entrances. To the south porch is attached a small hall church with a semicircular apse and two niches, connected via a doorway to the cathedral's south nave. The church bears remnants of the coarse wall paintings, dated from the 15th century to the 18th.

The cathedral is enclosed in a late-18th-century stone curtain wall, measuring 58 × 72 m. The wall is pierced by an arched brick gate on the southwest and a number of embrasures and contain rounded corner towers, one of which, on the southeast, is topped by a 19th-century hexagonal belfry.


How to Install Drupal with Nginx, PHP-FPM 7.4, MySQL, phpMyAdmin on Ubuntu 20.04 - Linode Guide

| Servers | 130 seen

In this article, you will learn how to setup webserver for serving  Drupal  websites running with Nginx, PHP-FPM 7.4, MySQL and phpMyAdmin on Ubuntu 20.04

For the following tutorial, I used very much the information from my previous guide with Ubuntu 18.04, but I decided to rewrite it for Ubuntu 20.04 version as it is shipped with php7.4 version and will work for Drupal 7, Drupal 8 and most probably for Drupal 9

Prerequisites

  • Ubuntu 20.04 
  • Root privileges.

You can get a cheap VPS starting just $5/mo from Linode. That's what I did - bought a new nanode from Linode

Deploying server with Linode

Literally in a couple of seconds, the new server was up and running - that's what I love sticking with Linode for years

Follow basic security guide, see: Securing Your Server

I will use Putty for Windows to access SSH

Secure your server

Create the user, replacing example_user with your desired username. You’ll then be asked to assign the user a password:

adduser example_user


Add the user to the sudo group so you’ll have administrative privileges:

adduser example_user sudo

Disallow root logins over SSH. This requires all SSH connections to be by non-root users. Once a limited user account is connected, administrative privileges are accessible either by using sudo or changing to a root shell using su -.

sudo nano /etc/ssh/sshd_config

Under # Authetification section change to

# Authentication: ... PermitRootLogin no

Update the Ubuntu system

sudo apt-get update

Install Nginx and PHP-FPM

Install Nginx with the following apt command:

sudo apt-get install nginx -y

Next, install php7.4-fpm with php-gd extension that is required by Drupal core:

sudo apt-get install php7.4-fpm php7.4-cli php7.4-gd php7.4-mysql php7.4-xml -y

Configure Nginx and PHP-FPM

In this step, we will configure Nginx to use php-fpm to serve HTTP requests for PHP pages. Go to the php-fpm directory "/etc/php/7.4/fpm" and edit the "php.ini" file:

sudo nano /etc/php/7.4/fpm/php.ini

Un-comment the cgi.fix_pathinfo line and change the value to "0"

When using nano command you can use CTRL+W to locate that line. Once changed press CTRL+O to save changes and CTRL+X to exit from nano editor

Now we should modify the default Nginx virtual host configuration. Edit the "default" file and enable the php-fpm directive.

sudo nano /etc/nginx/sites-available/default

Un-comment  location ~ \.php$ section, so it look like this

location ~ \.php$ { include snippets/fastcgi-php.conf; # With php7.4-cgi alone: #fastcgi_pass 127.0.0.1:9000; # With php7.4-fpm: fastcgi_pass unix:/run/php/php7.4-fpm.sock; }

CTRL+O and CTRL+X

Then test the Nginx configuration with the command "nginx -t" to ensure that it is valid:

nginx -t

If there is no error, restart nginx and the php-fpm service:

systemctl restart nginx systemctl restart php7.4-fpm

PHP Info file (Optional)

Next, test that php-fpm is working properly with Nginx by creating new PHP info file in the web directory "/var/www/html"

cd /var/www/html/ echo "<?php phpinfo(); ?>" > info.php

Visit the info.php file at the server IP  in a web browser.

Configure the VirtualHost for Drupal

We will install Drupal 8 in the directory "/srv/www/0dtespxtrading.com". Please replace my domain name in your installation with the domain name of the website that you want to use this Drupal installation for. So let's create the directory:

sudo mkdir -p /srv/www/0dtespxtrading.com/{public_html,logs} sudo usermod -a -G www-data admin sudo chown -R www-data:www-data /srv/www sudo chmod -R 775 /srv/www sudo nano /etc/nginx/sites-available/0dtespxtrading.com

Paste the Nginx configuration for Drupal 8:

server { server_name 0dtespxtrading.com; root /srv/www/0dtespxtrading.com/public_html; ## <-- Your only path $ access_log /srv/www/0dtespxtrading.com/logs/access.log; error_log /srv/www/0dtespxtrading.com/logs/error.log; listen 80; listen [::]:80; location = /favicon.ico { log_not_found off; access_log off; } location = /robots.txt { allow all; log_not_found off; access_log off; } # Very rarely should these ever be accessed outside of your lan location ~* \.(txt|log)$ { allow 192.168.0.0/16; deny all; } location ~ \..*/.*\.php$ { return 403; } location ~ ^/sites/.*/private/ { return 403; } # Block access to "hidden" files and directories whose names begin with a # period. This includes directories used by version control systems such # as Subversion or Git to store control files. location ~ (^|/)\. { return 403; } location / { # try_files $uri @rewrite; # For Drupal <= 6 try_files $uri /index.php?$query_string; # For Drupal >= 7 } location @rewrite { rewrite ^/(.*)$ /index.php?q=$1; } # In Drupal 8, we must also match new paths where the '.php' appears in the middle, # such as update.php/selection. The rule we use is strict, and only allows this pattern # with the update.php front controller. This allows legacy path aliases in the form of # blog/index.php/legacy-path to continue to route to Drupal nodes. If you do not have # any paths like that, then you might prefer to use a laxer rule, such as: # location ~ \.php(/|$) { # The laxer rule will continue to work if Drupal uses this new URL pattern with front # controllers other than update.php in a future release. location ~ '\.php$|^/update.php' { fastcgi_split_path_info ^(.+?\.php)(|/.*)$; #NOTE: You should have "cgi.fix_pathinfo = 0;" in php.ini include fastcgi_params; include snippets/fastcgi-php.conf; fastcgi_param SCRIPT_FILENAME $request_filename; fastcgi_intercept_errors on; fastcgi_pass unix:/run/php/php7.4-fpm.sock; } # Fighting with Styles? This little gem is amazing. # location ~ ^/sites/.*/files/imagecache/ { # For Drupal <= 6 location ~ ^/sites/.*/files/styles/ { # For Drpal >= 7 try_files $uri @rewrite; } location ~* \.(js|css|png|jpg|jpeg|gif|ico)$ { expires max; log_not_found off; } }

CTRL+O and CTRL + X

The Drupal virtual host file has been created, now we have to activate it by creating a symlink to the file in the "sites-enabled" directory:

ln -s /etc/nginx/sites-available/0dtespxtrading.com /etc/nginx/sites-enabled/

Test the Nginx configuration and if there are no errors restart Nginx:

nginx -t systemctl restart nginx

Install MySQL

sudo apt-get install mysql-server ​sudo mysql_secure_installation

Install phpMyAdmin

sudo apt-get install phpmyadmin

Hit ESC when the installation prompts you for auto-configuration because there is no option for Nginx.

Make an easily accessible symlink

sudo ln -s /usr/share/phpmyadmin/ /srv/www/0dtespxtrading.com/public_html/phpmyadmin

Install and Configure Drupal

Enter the directory that we created earlier and download Drupal with wget. I'm using the latest Drupal 8.8.6. release as of May 20, 2020, make sure you are downloading latest version by visiting Drupal 8 download page and writing down the last numbers (version)

cd /srv/www/0dtespxtrading.com sudo wget https://ftp.drupal.org/files/projects/drupal-8.8.6.tar.gz sudo tar -xvzf drupal-8.8.6.tar.gz sudo cp drupal-8.8.6/* public_html/ -R sudo chown www-data:www-data public_html -R

Now visit your Drupal site in the web Browser, you should see the following screen

Drupal 8 welcome screen

Now, it's just time to connect the database and set up your Drupal 8 website


File Permissions for gmap_markers.js

| Drupal Development | 12 seen

Time after time I'm facing this issue with gmap markers. As mostly this happens when I'm doing something on the server side with file permissions, I decided to keep the notes

here is the problem

GMap is unable to save the marker bundle, so the markers will not work. Please check file system permissions of the public://js/gmap_markers.js!

Here is the solution

sudo chmod 755 /sites/all/files/js/gmap_markers.js

Simple CSS trick to Make Table Responsive

| Drupal Development | 51 seen

Working on the OptionsBrew.com project (website is powered by Drupal 8) I faced the following responsive table issue while browsing content with a table on smaller screens (phone)

Broken Table on a smaller screen

Luckily there is a simple CSS workaround:

in the .css file add the following to table properties:

display: block; overflow-x: auto;

like this:

table{ border-collapse: separate; border-spacing: 0; width:100%; margin: 25px 0 40px; display: block; overflow-x: auto; }

here is how it looks now

Responsive table

You can see a live example here: Top 20 Most Active Stock Options May 2020


Poppy fields near Marneuli

| | 94 seen

We love poppy fields, we have featured them a couple of times here at the Piece of Life series

  • Beautiful Poppy Field Near P104 (Jaunpils-Tukums) Road (Latvia)
  • Railroad crossing in Skrunda municipality, Latvia

Today we are going to share a brief photo story with poppy field near Marneuli, next to the Милена Оптовый Магазин (Milena mall)

It was one of the first days when travel restrictions between Georgia's inner cities were lifted and we decided to head to the Marneuli side looking for poppy fields (my partner have seen online some beautiful photos of poppies the day before). I love these wandering around days.

We didn't find the special poppy field, instead we found poppies. Surprisingly we made a lot of great family portraits here rich with poppies  in the background.

Poppy fields next to the Milena Shopping mall near Marneuli

Quite an interesting stop here, we spent about an hour in this flower field.

Poppy field

That was a nice day at the end of May 2020.


Drupal 7 Fix: SQLSTATE[42000]: Syntax error or access violation: 1231 Variable 'sql_mode' can't be set to the value of 'NO_AUTO_CREATE_USER'.

| Drupal Development | 1,125 seen

I was migrating Drupal 7 website to a newer infrastructure (PHP 7.4) and during the migration process when tried to connect to the MySQL database  I faced following error - SQLSTATE[42000]: Syntax error or access violation: 1231 Variable 'sql_mode' can't be set to the value of 'NO_AUTO_CREATE_USER'.

Here is the error code:

Resolve all issues below to continue the installation. For help configuring your database server, see the installation handbook, or contact your hosting provider. Failed to connect to your database server. The server reports the following message: SQLSTATE[42000]: Syntax error or access violation: 1231 Variable 'sql_mode' can't be set to the value of 'NO_AUTO_CREATE_USER'. Is the database server running? Does the database exist, and have you entered the correct database name? Have you entered the correct username and password? Have you entered the correct database hostname?

No_auto_create_user

After quick research I was able to find a patch (Mysql 8 Support on Drupal 7 #24)  which involves overwriting core database.inc file (inclues/database/mysql - > database.inc)

here I'm pasting full working example (for a patch see here)

<?php /** * @file * Database interface code for MySQL database servers. */ /** * @addtogroup database * @{ */ class DatabaseConnection_mysql extends DatabaseConnection { /** * Flag to indicate if the cleanup function in __destruct() should run. * * @var boolean */ protected $needsCleanup = FALSE; public function __construct(array $connection_options = array()) { // This driver defaults to transaction support, except if explicitly passed FALSE. $this->transactionSupport = !isset($connection_options['transactions']) || ($connection_options['transactions'] !== FALSE); // MySQL never supports transactional DDL. $this->transactionalDDLSupport = FALSE; $this->connectionOptions = $connection_options; $charset = 'utf8'; // Check if the charset is overridden to utf8mb4 in settings.php. if ($this->utf8mb4IsActive()) { $charset = 'utf8mb4'; } // The DSN should use either a socket or a host/port. if (isset($connection_options['unix_socket'])) { $dsn = 'mysql:unix_socket=' . $connection_options['unix_socket']; } else { // Default to TCP connection on port 3306. $dsn = 'mysql:host=' . $connection_options['host'] . ';port=' . (empty($connection_options['port']) ? 3306 : $connection_options['port']); } // Character set is added to dsn to ensure PDO uses the proper character // set when escaping. This has security implications. See // https://www.drupal.org/node/1201452 for further discussion. $dsn .= ';charset=' . $charset; $dsn .= ';dbname=' . $connection_options['database']; // Allow PDO options to be overridden. $connection_options += array( 'pdo' => array(), ); $connection_options['pdo'] += array( // So we don't have to mess around with cursors and unbuffered queries by default. PDO::MYSQL_ATTR_USE_BUFFERED_QUERY => TRUE, // Because MySQL's prepared statements skip the query cache, because it's dumb. PDO::ATTR_EMULATE_PREPARES => TRUE, ); if (defined('PDO::MYSQL_ATTR_MULTI_STATEMENTS')) { // An added connection option in PHP 5.5.21+ to optionally limit SQL to a // single statement like mysqli. $connection_options['pdo'] += array(PDO::MYSQL_ATTR_MULTI_STATEMENTS => FALSE); } parent::__construct($dsn, $connection_options['username'], $connection_options['password'], $connection_options['pdo']); // Force MySQL to use the UTF-8 character set. Also set the collation, if a // certain one has been set; otherwise, MySQL defaults to 'utf8_general_ci' // for UTF-8. if (!empty($connection_options['collation'])) { $this->exec('SET NAMES ' . $charset . ' COLLATE ' . $connection_options['collation']); } else { $this->exec('SET NAMES ' . $charset); } // Set MySQL init_commands if not already defined. Default Drupal's MySQL // behavior to conform more closely to SQL standards. This allows Drupal // to run almost seamlessly on many different kinds of database systems. // These settings force MySQL to behave the same as postgresql, or sqlite // in regards to syntax interpretation and invalid data handling. See // http://drupal.org/node/344575 for further discussion. Also, as MySQL 5.5 // changed the meaning of TRADITIONAL we need to spell out the modes one by // one. $connection_options += array( 'init_commands' => array(), ); $connection_options['init_commands'] += array( 'sql_mode' => "SET sql_mode = 'REAL_AS_FLOAT,PIPES_AS_CONCAT,ANSI_QUOTES,IGNORE_SPACE,STRICT_TRANS_TABLES,STRICT_ALL_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO'", ); // Execute initial commands. foreach ($connection_options['init_commands'] as $sql) { $this->exec($sql); } } public function __destruct() { if ($this->needsCleanup) { $this->nextIdDelete(); } } public function query($query, array $args = array(), $options = array()) { $query = preg_replace('/{([^}]+)}/', '`\1`', $query); // This to make Drush work $query = str_replace(' system.', ' `system`.', $query); $query = str_replace('`system` system', '`system` `system`', $query); return parent::query($query, $args, $options); } public function queryRange($query, $from, $count, array $args = array(), array $options = array()) { return $this->query($query . ' LIMIT ' . (int) $from . ', ' . (int) $count, $args, $options); } public function queryTemporary($query, array $args = array(), array $options = array()) { $tablename = $this->generateTemporaryTableName(); $this->query('CREATE TEMPORARY TABLE {' . $tablename . '} Engine=MEMORY ' . $query, $args, $options); return $tablename; } public function driver() { return 'mysql'; } public function databaseType() { return 'mysql'; } public function mapConditionOperator($operator) { // We don't want to override any of the defaults. return NULL; } public function nextId($existing_id = 0) { $new_id = $this->query('INSERT INTO {sequences} () VALUES ()', array(), array('return' => Database::RETURN_INSERT_ID)); // This should only happen after an import or similar event. if ($existing_id >= $new_id) { // If we INSERT a value manually into the sequences table, on the next // INSERT, MySQL will generate a larger value. However, there is no way // of knowing whether this value already exists in the table. MySQL // provides an INSERT IGNORE which would work, but that can mask problems // other than duplicate keys. Instead, we use INSERT ... ON DUPLICATE KEY // UPDATE in such a way that the UPDATE does not do anything. This way, // duplicate keys do not generate errors but everything else does. $this->query('INSERT INTO {sequences} (value) VALUES (:value) ON DUPLICATE KEY UPDATE value = value', array(':value' => $existing_id)); $new_id = $this->query('INSERT INTO {sequences} () VALUES ()', array(), array('return' => Database::RETURN_INSERT_ID)); } $this->needsCleanup = TRUE; return $new_id; } public function nextIdDelete() { // While we want to clean up the table to keep it up from occupying too // much storage and memory, we must keep the highest value in the table // because InnoDB uses an in-memory auto-increment counter as long as the // server runs. When the server is stopped and restarted, InnoDB // reinitializes the counter for each table for the first INSERT to the // table based solely on values from the table so deleting all values would // be a problem in this case. Also, TRUNCATE resets the auto increment // counter. try { $max_id = $this->query('SELECT MAX(value) FROM {sequences}')->fetchField(); // We know we are using MySQL here, no need for the slower db_delete(). $this->query('DELETE FROM {sequences} WHERE value < :value', array(':value' => $max_id)); } // During testing, this function is called from shutdown with the // simpletest prefix stored in $this->connection, and those tables are gone // by the time shutdown is called so we need to ignore the database // errors. There is no problem with completely ignoring errors here: if // these queries fail, the sequence will work just fine, just use a bit // more database storage and memory. catch (PDOException $e) { } } /** * Overridden to work around issues to MySQL not supporting transactional DDL. */ protected function popCommittableTransactions() { // Commit all the committable layers. foreach (array_reverse($this->transactionLayers) as $name => $active) { // Stop once we found an active transaction. if ($active) { break; } // If there are no more layers left then we should commit. unset($this->transactionLayers[$name]); if (empty($this->transactionLayers)) { if (!PDO::commit()) { throw new DatabaseTransactionCommitFailedException(); } } else { // Attempt to release this savepoint in the standard way. try { $this->query('RELEASE SAVEPOINT ' . $name); } catch (PDOException $e) { // However, in MySQL (InnoDB), savepoints are automatically committed // when tables are altered or created (DDL transactions are not // supported). This can cause exceptions due to trying to release // savepoints which no longer exist. // // To avoid exceptions when no actual error has occurred, we silently // succeed for MySQL error code 1305 ("SAVEPOINT does not exist"). if ($e->errorInfo[1] == '1305') { // If one SAVEPOINT was released automatically, then all were. // Therefore, clean the transaction stack. $this->transactionLayers = array(); // We also have to explain to PDO that the transaction stack has // been cleaned-up. PDO::commit(); } else { throw $e; } } } } } public function utf8mb4IsConfigurable() { return TRUE; } public function utf8mb4IsActive() { return isset($this->connectionOptions['charset']) && $this->connectionOptions['charset'] === 'utf8mb4'; } public function utf8mb4IsSupported() { // Ensure that the MySQL driver supports utf8mb4 encoding. $version = $this->getAttribute(PDO::ATTR_CLIENT_VERSION); if (strpos($version, 'mysqlnd') !== FALSE) { // The mysqlnd driver supports utf8mb4 starting at version 5.0.9. $version = preg_replace('/^\D+([\d.]+).*/', '$1', $version); if (version_compare($version, '5.0.9', '<')) { return FALSE; } } else { // The libmysqlclient driver supports utf8mb4 starting at version 5.5.3. if (version_compare($version, '5.5.3', '<')) { return FALSE; } } // Ensure that the MySQL server supports large prefixes and utf8mb4. try { $this->query("CREATE TABLE {drupal_utf8mb4_test} (id VARCHAR(255), PRIMARY KEY(id(255))) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci ROW_FORMAT=DYNAMIC ENGINE=INNODB"); } catch (Exception $e) { return FALSE; } $this->query("DROP TABLE {drupal_utf8mb4_test}"); return TRUE; } } /** * @} End of "addtogroup database". */

May 2020 Dividend Income Report - $225.17

| Investments | 16 seen

Welcome to the thirty-seventh (#37) dividend income report, covering earnings I've made from dividend-paying stocks and peer to peer lending in May 2020.

Just like the previous month of April, in May we also spent in a self-isolation (because of Covid-19) here in Georgia. Some of the strict lockdown measurements were lifted (like using a private vehicle and going from city to city)  we did a few road trips here in Georgia.  Baby girl is doing her online class, learning about animals, shapes, continents, and even planets. Quite fascinating what a 22-month-old can do. Development is very rapid.

Saint Dimitri Tesalonikeli Fathers Moanstery near Mtksheta

May come with very sad news - my dad passed away, some 11 days before his 66 year birthday. My dad was like a best buddy to me, we talked a lot about investments, stocks, politics, we argued, disagreed, we had opinions  - most of our conversations were on WhatsApp chat, he was very tech guy, into gadgets.. dad I miss you. Everything's gonna be alright - this was his favorite phrase. His last message on WhatsApp was on May 8:

Last message from Dad on May 8, 2020

The loss of dad will leave a space in my life that can never get filled.

From the perspective of dividend income -  last May was very good, we were able to take $225.17, despite most of our dividends are trimmed by half and more. Back in March's market panic, we bought for a cheap a lot of FGB stock, this stock helped to boost this May's dividend income. FGB is not the stock we would like to keep for life, but I feel happy I bought it back in March.

Compared to the previous May in 2019, our monthly dividend has increased by a mere 4.16%  (+$9.00). Despite I was looking at a $300-$350 dividend this month a year ago, I will say the overall result is very good, taking into account the market downturn.

An additional $595.43 was made from options trading.   As options trading is not a passive form of making money while you are sleeping it wouldn't be fair to include them in dividend income reports. As we love selling options a lot, during the month of May I launched a separate website -  Investing with covered calls - OptionsBrew.com You can read our first options income review here: May 2020 Options Income Report - $595.43

If counted all together (dividends + options) it seems we have made $820.6 in total last month. 

Effective income yield last May was 4.36% (about 52.32% annually) Which is great. One of my monthly goals is to generate at least 2.5% income yield from the portfolio. As longs it's above to it - it's awesome.

From dividends + active trading taking 30% year seems quite doable. The first five months of 2020 have been a bumpy road, but we have been able to take more than 2.5% from the market in 3 out of the 5 months. 

Interest income in May 2020

From the stocks and peer to peer lending I got following income last month:

Ticker

Earnings

FGB

€75.23

BGLF

€36.30

XIN

€17.52

EDI

€14.04

Mintos

€11.26

EDF

€9.77

NRZ

€9.54

KNF1L

€9.05

RA

€7.60

NCV

€6.48

ET

€5.44

AWP

€3.66

Total EUR 206.58 / USD 225.17

In total there were 12 companies paying us dividend in May 2020 that is 3 companies less than in May 2019

Monthly income

I've been tracking my journey towards million dollars in a savings account since January 2017. More than three years already. The result, so far, looks quite good. Dividends are growing (even when they are not)

Monthly dividend Income chart as of May 2020

The cumulative earnings for 2020 now are $882.72  which is exactly 24.52% from my goal of 2020 ($3,600). On average, it would ask us to generate $388.89 every month for the next 7 months to reach this goal. Right, now the goal looks unattainable, as for now, I cannot see even a single $300 month for 2020, but this could change later, during the year as we are trying to add more quality stock to the portfolio. 

2019 in Review and Financial Goals for 2020

Goals for May 2021

This is my favorite part of the reports - trying to forecast/set goals for the next year. But before setting a goal for 2020, let's see what I forecasted/said a year ago (May 2019)

When setting goals for May 2020, I will say $300 seems a good number to work with, but I want more - at least $350 for May 2020

None of the numbers were reached. Taking into account the downturn in the markets and many dividend trims. I will say that it is quite acceptable. 

For May 2021 I have a goal to crack finally that $300 milestone, to get there will add more quarterly stocks paying dividends in May (like FBG, PBCT, and T). From today's perspective looks quite possible.