Categories
Administration Development

How To Setup WordPress on Docker WSL For Development On A Local Directory

The main difference with other setups here is that this one is for development. This means you need to get easy access to the source code of themes and plugins. In order to do that, you only need to change one line from the official Docker guide to setup WordPress.

Original

The original is as follows. You will only need to change the volume part under wordpress to point /var/www/html to a host (local) directory like c: or d: or /home/ubuntu/temp.

version: "3.9"
    
services:
  db:
    image: mysql:5.7
    volumes:
      - db_data:/var/lib/mysql
    restart: always
    environment:
      MYSQL_ROOT_PASSWORD: somewordpress
      MYSQL_DATABASE: wordpress
      MYSQL_USER: wordpress
      MYSQL_PASSWORD: wordpress
    
  wordpress:
    depends_on:
      - db
    image: wordpress:latest
    volumes:
      - wordpress_data:/var/www/html
    ports:
      - "8000:80"
    restart: always
    environment:
      WORDPRESS_DB_HOST: db:3306
      WORDPRESS_DB_USER: wordpress
      WORDPRESS_DB_PASSWORD: wordpress
      WORDPRESS_DB_NAME: wordpress
volumes:
  db_data: {}
  wordpress_data: {}

Modified Version

The modified version changes wordpress_data to point to a local directory for example in this case to /mnt/d/temp/wordpress. You will also need to remove it from volumes: in the last line.

version: "3.9"
    
services:
  db:
    image: mysql:5.7
    volumes:
      - db_data:/var/lib/mysql
    restart: always
    environment:
      MYSQL_ROOT_PASSWORD: somewordpress
      MYSQL_DATABASE: wordpress
      MYSQL_USER: wordpress
      MYSQL_PASSWORD: wordpress
    
  wordpress:
    depends_on:
      - db
    image: wordpress:latest
    volumes:
      - /mnt/d/temp/wordpress:/var/www/html
    ports:
      - "8000:80"
    restart: always
    environment:
      WORDPRESS_DB_HOST: db:3306
      WORDPRESS_DB_USER: wordpress
      WORDPRESS_DB_PASSWORD: wordpress
      WORDPRESS_DB_NAME: wordpress
volumes:
  db_data: {}

Now if you run docker-compose up -d you should the see the following files in your directory:

If you are having trouble setting WSL on Windows feel free to check this post and if you would like to access Logs check out this post here on How To Access WordPress Logs From Docker.

Happy development! 🙂

Categories
Administration

How To Fix Couldn’t find a valid ICU package installed on the system. Set the configuration flag System.Globalization.Invariant to true if you want to run with no globalization support.

If you have run a Dotnet Core project or a packaged Dotnet Core binary on Ubuntu and you have run into Process terminated. Couldn’t find a valid ICU package installed on the system. Set the configuration flag System.Globalization.Invariant to true if you want to run with no globalization support. then you have come to the right place.

Basically this is happening because there is missing dependency for the Unicode and Globalization support.

How To Fix For Binary

You need to install the dependency on the system. If you are on Ubuntu you can do that with:

sudo apt-get install -y libicu-dev

That’s it the application should not stop complaining about the error.

How To Fix For A Dotnet Core Project: Solution 1

If the application has a runtimeconfig.json available then add the following parameters and run again:

{
    "runtimeOptions": {
        "configProperties": {
            "System.Globalization.Invariant": true
        },
    }
}

How To Fix For A Dotnet Core Project: Solution 2

If you are the one packaging the application with dotnet publish you can add the following to/or create a runtimeconfig.template.json inside the project folder:

{
    "configProperties": {
        "System.Globalization.Invariant": true
    }
}

How To Fix For A Dotnet Core csproj: Solution 3

<PropertyGroup>
    <InvariantGlobalization>true</InvariantGlobalization>
</PropertyGroup>

What does invariant do anyway?

So as from .Net Core 2, this option allows you to remove dependencies on globalization from your application. .Net Core depends on the operating system to provide this information. You can read the following document for the complete reasoning: https://github.com/dotnet/runtime/blob/main/docs/design/features/globalization-invariant-mode.md

Hopefully this will resolve the issues! If not the best place would be to check open issues at https://github.com/dotnet/core/issues or stackoverflow.

Categories
Uncategorized

Best Apex Legends Aim Assist Settings

These are the settings used by two of the most talented controller players of Apex Legends PXNDERZ and NiceWigg. Now, with all new settings you will need to give it some time to get used to.

Before moving on, if you want to check out how to enable aim assist and advanced control please check this post first: How to enable aim assist in Apex Legends PS4

Or in case you want to play with Mouse & Keyboard on ps4 check: Can you play Apex Legends with keyboard and mouse on ps4 & ps5 ?

Deadzone

Start with the first part, the Deadzone is slightly less than the default value. Deadzone is the amount you have to move your stick for it to respond. Depending on the amount of stick drift that you have you will have to adjust this differently, so take that into account.

Response Curve

The response curve is the rate at which at aim compensation is applied. If you put both the Deadzone and Response Curve to minimum you will notice your cursor moving on its own. The setting shown above is more natural.

Outer Threshold

What the description basically means is that the extra yaw setting you apply below will automatically take effect by setting the outer threshold to basically 0.

Normal Aim Sensitivity

I call the next settings the normal aim sensitivity because these determine the speed at which your cursor move without aiming down sight (ADS).

The speed settings above might look fast at first but they are crucial to perform good movement. Aiming alone is not enough in Apex Legends, you also need to master movement.

One note here, the settings above work well with official PS4 or XBOX controllers but if you are using crappy imitation ones their sensitivity might require you to turn them down. Because the above expects the character to move with a slight thumb push on the controller sticks.

Aim Down Sight (ADS) Settings

So the last part and important thing here is that the aim down sight speed is set to default BUT! there is a lot more Extra Yaw added. The purpose to having this is 2 fold.

The first purpose is that because the extra yaw is only applied when you are tracking by a lot, this means the normal setting is good enough to manage recoil.

Second reason is to track a moving enemy. The default settings might be to slow to track a fast moving enemy. Having this extra yaw will compensate for that.

I agree with setting no Ramp-Up time and Delay to kick the Extra Yaw as well because things go down really fast in Apex Legends.

Final Notes

It could take you one whole of week practice to get fully used to the settings but they are worth. There are some of them that you will and should be finetuning based on your playstyle.

Hopefully I have made a good explanation on why they used these settings! See you in matches! 🙂

Categories
Uncategorized

How To Relieve Carpal Tunnel Syndrome From Programming & Gaming

From Wikiepedia: https://en.wikipedia.org/wiki/Carpal_tunnel_syndrome

10 Quick tips on Carpal Tunnel Syndrome summarized if you don’t have enough time to read the entire article.

  1. Better posture, to alleviate stress on shoulders, neck and ultimately on the median nerve
  2. Appropriate table with round corners and adjustable height or at nearly the hip level
  3. Buy a gaming chair
  4. Use a keyboard and mouse wrist support
  5. Use wrist guards when sleeping
  6. Use voice recognition as much as possible
  7. Do exercises to stretch median nerve / physiotherapy
  8. Use a game pad if you can
  9. Take some holidays
  10. Seek medical assistance

What Is Carpal Tunnel Syndrome?

Carpal Tunnel Syndrome happens when the nerves at your wrist as shown in the picture above are compressed, usually after long hours of strain on the hand. This makes programmers and PC gamers particular vulnerable to Carpal Tunnel Syndrome.

Most programmers and gamers will enter a deep concentration state for long hours without realizing the harm that they are causing to their wrists, forearms and elbows.

1. Better Posture To Avoid Carpal Tunnel Syndrome

In order to understand why better posture will affect Carpal Tunnel Syndrome we need to first know that the median nerve is the main nerve in the upper limb of humans. If you take a look at the picture below you will see that the nerve stretches from the neck (not shown in illustration), shoulder, elbow, forearm and down to your fingers.

Nerves of the left upper extremity.gif
From Wikipedia: https://en.wikipedia.org/wiki/Carpal_tunnel_syndrome

With Carpal Tunnel Syndrome the nerves are are pinched/compressed at base of the wrist (or any other points). When the posture is bad or as a concrete example when someone slouches in front of the PC like below:

text neck - man in slouching position on ergonomic chair working with tablet at desk

What you are doing is stretching the median nerve both at the neck and at the shoulders which accentuates the problem. Ideally you should:

  1. Have your screen at eye level so that your neck is not strained.
  2. Have your keyboard and mouse at the hip level so a lower table or may be a table with a sliding tray or just put your keyboard on your lap. This will relieve stress on your shoulders.
  3. Have comfortable armchairs for your elbows and forearms.
Correct body alignment in sitting working with computer
Correct Posture

2. Tables Of The Future

The table in the illustration actually has one error. The edges are squared. Ideally you should look for a table which has round corners and are going to easy on your wrists if they will rest on the table.

Click here to read more about the height adjustable table

If you can afford to use a table that has adjustable height that would be really the best choice here.

Personally now that I work at home I have invested in a laptop table or lap desk? I think that’s the official name. People use it to work standing, I don’t know for you but I can’t focus when I am standing. I use it when I work from my bed or couch instead ?.

Click For More Info

3. Gaming Chair

This has changed my life. Not only for Carpal Tunnel Syndrome but I used to also have shoulder pain. My previous chair was the cheapest office chair with wheels that I had found. As programmers and gamers we need to realize we will be spending the majority of our time in front of the PC and buying a gaming chair is an investment and important for your health.

The chair that I use is an Arozzi.

VERONA JUNIOR - Arozzi Europe

I used to have shoulder pain because I used a chair with a broken wheel for a few months. Getting the Arozzi fixed my shoulder within a month. Anyway this chair will allow you to:

  1. Adjust the height so that you do not slouch and the screen is at the correct level
  2. The chair comes with comfy armchairs. You need to realize that protecting your elbows is also important. The cushion in this armchair does that really well.
  3. The seat will help you maintain the best posture. It comes with back pillows as well if that is your thing.

4. Mouse Pad and Keyboard Wrist Support

Some keyboards that you buy come with the support. By support we mean an additional part of the keyboard on which your wrists can rest while you type. This part is should 1. be present and 2. be as cushy as possible.

You should ideally also have the keyboard be in inclined position with its “legs” out. I didn’t know this before but it seems this is also available as cushy mouse pads.

5. Wrist Guards To Help With Carpal Tunnel Syndrome

Speaking about wrist support, have you ever thought about what happens to your wrists while sleeping? Well turns out if you are applying pressure in the wrong direction to your wrist while sleeping this can have a negative effect on your Carpal Tunnel Syndrome.

I could not find an appropriate picture for this but if you had to imagine it, it the wrist bent down supporting your chin just like the famous thinker statue.

upright=upright=1.4
From Wikipedia: The Thinker

The wrist guard will force your wrist to be in the right position while you sleep. This will help it heal faster. You can actually weird it during the way too if you are comfortable with it, it’s just that you have to remove it every time you are washing hands which can get annoying.

6. Voice Recognition

If you are on Windows 10 like me then you have the option to enable voice recognition. Your starting point will be at this link: https://support.microsoft.com/en-us/windows/use-voice-recognition-in-windows-10-83ff75bd-63eb-0b6c-18d4-6fae94050571

You should then also enable dictation: https://support.microsoft.com/en-us/windows/use-dictation-to-talk-instead-of-type-on-your-pc-fec94565-c4bd-329d-e59a-af033fa5689f

With dictation you will be able to go in any Windows App like Slack, Google Chrome or Outlook then pressing Windows Key + H to open voice to text functionality. For example part of this article has been written with dictation.

Basically the less you have to type the better. There are commands available that Cortana can listen to but I can’t get used to it, so I won’t recommend it yet.

For those who use Android there should be accessibility option that allows you to do that.

7. Stretching/Physiotherapy Exercises

This is really not my forte. What I have tried to do is from this video :

They are simple stretch exercises that you can do before the start of the day, at noon and the end of work. For me personally joining my hands together and rotating the wrists seems to work but I am no doctor so I can’t recommend that contrary to those in the video above. Check it out it was definitely helpful for me.

8. Game Pads

Buy a game pad which can be connected to your PC. For example the PS4 and Xbox controllers which in my opinion are the best bets work with Windows 10 without any hassle! You just need to connect or pair them by bluetooth. Then for example go to steam, right click on the game, properties and set the controller as input.

Click For More Info

With a controller you can rest your hands on your lap while the controller puts your hands/wrists in the correct position. Added benefits if you play Apex Legends is that you also get some aim assist when using a controller.

9. Take Some Holidays

That was the first advice that my doctor gave me. Take your some holidays before the Carpal Tunnel Syndrome gets worse. If you are only at the start where you only have some tingling this is the perfect time to take a holiday for at least 1 week. Do not use any keyboard or mouse during that time. Well also don’t go ahead and do any activity strenuous on the wrist.

This will hopefully resolve your Carpal Tunnel Syndrome.

10. Seek Medical Assistance

Don’t wait for too long to go to a doctor. The longer you wait for a diagnosis the more damage you will have done and the harder it will be to repair. The saddest thing to a programmer or gamer is probably losing the ability to do what they love the most.

To add on top of that Carpal Tunnel Syndrome is most likely already decreasing your APM (Actions per minute) or typing speed. Resolving that should be on top of your priority list.

Also this article has been written by a programmer and not a doctor, based on his own experience with Carpal Tunnel Syndrome. I never took any precaution during my 20s and started experiencing this together with other issues that I plan to write about soon.

Be smart, don’t be like me and take precautions early. Hope that this post was helpful! Thanks for reading 🙂

Categories
Administration Development

Fixing Text Too Small To Read Google Search Console WordPress

An easy way to fix Text Too Small To Read and Clickable elements too close together is by injecting the CSS below in Admin Dashboard->Appearance->Customize->Additional CSS. Then insert the following code:

@media only screen and (max-width: 1024px) {
	a {
	font-size: 1.5em !important;
	padding: 1em;
	}
	input {
		padding: 1em !important;
	}
	.meta-text {
	font-size: 3rem!important;
	}

	time {
		font-size: 1.5em!important;
	}

	.ancestor-wrapper {
		padding: 1em;
	}
	.entry-categories {
		display: none;
	}
	.wp-block-code {
	font-size: 1.5em;
	}
	p {
		font-size: 1.5em!important;
	}
}

This fixes my issues with mobile page experience for the Twenty Twenty WordPress theme. If you are using another theme then you might need to adjust the size for other elements as well.

CSS Explanation

What the CSS script first does is to only work when the screen is less than 1024px wide in order to target mobile screens/devices. Next we are select specific elements like anchor tags, inputs, time fields, a few classes which all display content/text.

We are adding !important to force a font-size of 1.5em. EM is a unit is relative to the screen size.

Quote from “The Principles of Beautiful Web Design

“An em is a CSS unit that measures the size of a font, from the top of a font’s cap height to
the bottom of its lowest descender. Originally, the em was equal to the width of the capital letter M, which is where its name originated.” Thanks to a comment from https://www.sitepoint.com/community/u/BenMore for beautifully explaining this on sitepoint.

Anyway the size we put here is 1.5em which can be big for the taste of many. You can try a different size, I actually intend to do that.

Then we have also adding a padding for input and .ancestor-wrapper to increase the space between clickable elements.

For the last error of content wider than screen, it was actually an image of mine which was not responsive so if you have that you will have to check how to remove it or make it responsive.

That’s it let me know if it worked for you!

Categories
Administration Database

Plot JSON Stats For EventStoreDB Terminal Edition

This post covers how to plot JSON stats files generated by EventStoreDB 20.10.2 directly into the terminal. The pre-requisites are:

  1. gnuplot
  2. jq

If you are short on time then the final command looks like the following:

cat log-stats.json | jq -r '.["@t"] + " " + (.stats.sys.cpu|tostring)' | gnuplot -p -e 'set xdata time; set timefmt "%Y-%m-%dT%H:%M:%.7SZ";set format x "%d %H:%M"; set term dumb 70 35; plot "/dev/stdin" using 1:2 with linespoints'

EventStore stats contains a lot of metrics. What we want to plot is the @t field on the x-axis and a metric for example the system cpu usage on the y-axis.

This is a sample line from a random stats file of EventStoreDB. In EventStoreDB every line of the stats file is a valid JSON element. Bonus: This means that if ever you wanted to export the data to ElasticSearch you could just send that line to index it without any modification.

{
   "@t":"2021-07-10T12:40:03.1954998Z",
   "@mt":"{@stats}",
   "stats":{
      "proc":{
         "startTime":"2021-07-10T12:39:58.7025853Z",
         "id":15268,
         "mem":78970880,
         "cpu":-1,
         "threadsCount":-1,
         "contentionsRate":-1,
         "thrownExceptionsRate":-1,
         "gc":{
            "allocationSpeed":-1,
            "gen0ItemsCount":-1,
            "gen0Size":-1,
            "gen1ItemsCount":-1,
            "gen1Size":-1,
            "gen2ItemsCount":-1,
            "gen2Size":-1,
            "largeHeapSize":-1,
            "timeInGc":-1,
            "totalBytesInHeaps":-1048576
         },
         "diskIo":{
            "readBytes":1252269,
            "writtenBytes":37983,
            "readOps":488,
            "writeOps":1130
         },
         "tcp":{
            "connections":0,
            "receivingSpeed":0,
            "sendingSpeed":0,
            "inSend":0,
            "measureTime":"737980.12:40:03.1825929",
            "pendingReceived":0,
            "pendingSend":0,
            "receivedBytesSinceLastRun":0,
            "receivedBytesTotal":0,
            "sentBytesSinceLastRun":0,
            "sentBytesTotal":0
         }
      },
      "sys":{
         "cpu":0,
         "freeMem":8555593728,
         "drive":{
            "C":{
               "availableBytes":585366077440,
               "totalBytes":695771066368,
               "usage":"15%",
               "usedBytes":110404988928
            }
         }
      },
      "es":{
         "checksum":421,
         "checksumNonFlushed":421,
         "queue":{
            "Index Committer":{
               "queueName":"Index Committer",
               "groupName":"",
               "avgItemsPerSecond":0,
               "avgProcessingTime":20.6789,
               "currentIdleTime":"0:00:00:00.8203215",
               "currentItemProcessingTime":null,
               "idleTimePercent":98.01217837170631,
               "length":0,
               "lengthCurrentTryPeak":0,
               "lengthLifetimePeak":0,
               "totalItemsProcessed":1,
               "inProgressMessage":"<none>",
               "lastProcessedMessage":"CommitAck"
            },
            "MainQueue":{
               "queueName":"MainQueue",
               "groupName":"",
               "avgItemsPerSecond":41,
               "avgProcessingTime":1.8007140000000001,
               "currentIdleTime":"0:00:00:00.0019794",
               "currentItemProcessingTime":null,
               "idleTimePercent":92.46169560776302,
               "length":0,
               "lengthCurrentTryPeak":4,
               "lengthLifetimePeak":4,
               "totalItemsProcessed":50,
               "inProgressMessage":"<none>",
               "lastProcessedMessage":"Schedule"
            },
            "MonitoringQueue":{
               "queueName":"MonitoringQueue",
               "groupName":"",
               "avgItemsPerSecond":4,
               "avgProcessingTime":0.0972,
               "currentIdleTime":"0:00:00:00.8179220",
               "currentItemProcessingTime":null,
               "idleTimePercent":99.9542884369567,
               "length":0,
               "lengthCurrentTryPeak":0,
               "lengthLifetimePeak":0,
               "totalItemsProcessed":5,
               "inProgressMessage":"<none>",
               "lastProcessedMessage":"WriteEventsCompleted"
            },
            "PersistentSubscriptions":{
               "queueName":"PersistentSubscriptions",
               "groupName":"",
               "avgItemsPerSecond":4,
               "avgProcessingTime":1.0383,
               "currentIdleTime":"0:00:00:00.0020782",
               "currentItemProcessingTime":null,
               "idleTimePercent":99.4996254491069,
               "length":0,
               "lengthCurrentTryPeak":0,
               "lengthLifetimePeak":0,
               "totalItemsProcessed":5,
               "inProgressMessage":"<none>",
               "lastProcessedMessage":"PersistentSubscriptionTimerTick"
            },
            "Projection Core #0":{
               "queueName":"Projection Core #0",
               "groupName":"Projection Core",
               "avgItemsPerSecond":1,
               "avgProcessingTime":0.56005,
               "currentIdleTime":"0:00:00:01.0063733",
               "currentItemProcessingTime":null,
               "idleTimePercent":99.89183045270572,
               "length":0,
               "lengthCurrentTryPeak":0,
               "lengthLifetimePeak":0,
               "totalItemsProcessed":2,
               "inProgressMessage":"<none>",
               "lastProcessedMessage":"SubComponentStarted"
            },
            "Projections Leader":{
               "queueName":"Projections Leader",
               "groupName":"",
               "avgItemsPerSecond":9,
               "avgProcessingTime":0.46166,
               "currentIdleTime":"0:00:00:00.8931152",
               "currentItemProcessingTime":null,
               "idleTimePercent":99.55437527849736,
               "length":0,
               "lengthCurrentTryPeak":0,
               "lengthLifetimePeak":0,
               "totalItemsProcessed":10,
               "inProgressMessage":"<none>",
               "lastProcessedMessage":"EpochWritten"
            },
            "Storage Chaser":{
               "queueName":"Storage Chaser",
               "groupName":"",
               "avgItemsPerSecond":63,
               "avgProcessingTime":0.7814632352941177,
               "currentIdleTime":"0:00:00:00.0032413",
               "currentItemProcessingTime":null,
               "idleTimePercent":95.00599578181105,
               "length":0,
               "lengthCurrentTryPeak":0,
               "lengthLifetimePeak":0,
               "totalItemsProcessed":68,
               "inProgressMessage":"<none>",
               "lastProcessedMessage":"ChaserCheckpointFlush"
            },
            "StorageReaderQueue #1":{
               "queueName":"StorageReaderQueue #1",
               "groupName":"StorageReaderQueue",
               "avgItemsPerSecond":0,
               "avgProcessingTime":5.8326,
               "currentIdleTime":"0:00:00:01.0034104",
               "currentItemProcessingTime":null,
               "idleTimePercent":99.42209177905863,
               "length":0,
               "lengthCurrentTryPeak":0,
               "lengthLifetimePeak":0,
               "totalItemsProcessed":1,
               "inProgressMessage":"<none>",
               "lastProcessedMessage":"ReadStreamEventsBackward"
            },
            "StorageReaderQueue #2":{
               "queueName":"StorageReaderQueue #2",
               "groupName":"StorageReaderQueue",
               "avgItemsPerSecond":0,
               "avgProcessingTime":5.661,
               "currentIdleTime":"0:00:00:01.0033967",
               "currentItemProcessingTime":null,
               "idleTimePercent":99.43892257595347,
               "length":0,
               "lengthCurrentTryPeak":0,
               "lengthLifetimePeak":0,
               "totalItemsProcessed":1,
               "inProgressMessage":"<none>",
               "lastProcessedMessage":"ReadStreamEventsBackward"
            },
            "StorageReaderQueue #3":{
               "queueName":"StorageReaderQueue #3",
               "groupName":"StorageReaderQueue",
               "avgItemsPerSecond":0,
               "avgProcessingTime":5.6474,
               "currentIdleTime":"0:00:00:01.0034069",
               "currentItemProcessingTime":null,
               "idleTimePercent":99.44025868153523,
               "length":0,
               "lengthCurrentTryPeak":0,
               "lengthLifetimePeak":0,
               "totalItemsProcessed":1,
               "inProgressMessage":"<none>",
               "lastProcessedMessage":"ReadStreamEventsBackward"
            },
            "StorageReaderQueue #4":{
               "queueName":"StorageReaderQueue #4",
               "groupName":"StorageReaderQueue",
               "avgItemsPerSecond":0,
               "avgProcessingTime":0,
               "currentIdleTime":null,
               "currentItemProcessingTime":null,
               "idleTimePercent":100,
               "length":0,
               "lengthCurrentTryPeak":0,
               "lengthLifetimePeak":0,
               "totalItemsProcessed":0,
               "inProgressMessage":"<none>",
               "lastProcessedMessage":"<none>"
            },
            "StorageWriterQueue":{
               "queueName":"StorageWriterQueue",
               "groupName":"",
               "avgItemsPerSecond":4,
               "avgProcessingTime":24.53265,
               "currentIdleTime":"0:00:00:00.8697286",
               "currentItemProcessingTime":null,
               "idleTimePercent":88.15913918900499,
               "length":0,
               "lengthCurrentTryPeak":0,
               "lengthLifetimePeak":0,
               "totalItemsProcessed":6,
               "inProgressMessage":"<none>",
               "lastProcessedMessage":"WritePrepares"
            },
            "Subscriptions":{
               "queueName":"Subscriptions",
               "groupName":"",
               "avgItemsPerSecond":2,
               "avgProcessingTime":1.2562333333333333,
               "currentIdleTime":"0:00:00:00.0311524",
               "currentItemProcessingTime":null,
               "idleTimePercent":99.63733643093632,
               "length":0,
               "lengthCurrentTryPeak":0,
               "lengthLifetimePeak":0,
               "totalItemsProcessed":3,
               "inProgressMessage":"<none>",
               "lastProcessedMessage":"CheckPollTimeout"
            },
            "Timer":{
               "queueName":"Timer",
               "groupName":"",
               "avgItemsPerSecond":14,
               "avgProcessingTime":0.19026470588235295,
               "currentIdleTime":"0:00:00:00.0032505",
               "currentItemProcessingTime":null,
               "idleTimePercent":99.72829060690019,
               "length":5,
               "lengthCurrentTryPeak":8,
               "lengthLifetimePeak":8,
               "totalItemsProcessed":17,
               "inProgressMessage":"<none>",
               "lastProcessedMessage":"ExecuteScheduledTasks"
            },
            "Worker #1":{
               "queueName":"Worker #1",
               "groupName":"Workers",
               "avgItemsPerSecond":0,
               "avgProcessingTime":0,
               "currentIdleTime":null,
               "currentItemProcessingTime":null,
               "idleTimePercent":100,
               "length":0,
               "lengthCurrentTryPeak":0,
               "lengthLifetimePeak":0,
               "totalItemsProcessed":0,
               "inProgressMessage":"<none>",
               "lastProcessedMessage":"<none>"
            },
            "Worker #2":{
               "queueName":"Worker #2",
               "groupName":"Workers",
               "avgItemsPerSecond":0,
               "avgProcessingTime":0,
               "currentIdleTime":null,
               "currentItemProcessingTime":null,
               "idleTimePercent":100,
               "length":0,
               "lengthCurrentTryPeak":0,
               "lengthLifetimePeak":0,
               "totalItemsProcessed":0,
               "inProgressMessage":"<none>",
               "lastProcessedMessage":"<none>"
            },
            "Worker #3":{
               "queueName":"Worker #3",
               "groupName":"Workers",
               "avgItemsPerSecond":0,
               "avgProcessingTime":0,
               "currentIdleTime":null,
               "currentItemProcessingTime":null,
               "idleTimePercent":100,
               "length":0,
               "lengthCurrentTryPeak":0,
               "lengthLifetimePeak":0,
               "totalItemsProcessed":0,
               "inProgressMessage":"<none>",
               "lastProcessedMessage":"<none>"
            },
            "Worker #4":{
               "queueName":"Worker #4",
               "groupName":"Workers",
               "avgItemsPerSecond":0,
               "avgProcessingTime":0,
               "currentIdleTime":null,
               "currentItemProcessingTime":null,
               "idleTimePercent":100,
               "length":0,
               "lengthCurrentTryPeak":0,
               "lengthLifetimePeak":0,
               "totalItemsProcessed":0,
               "inProgressMessage":"<none>",
               "lastProcessedMessage":"<none>"
            },
            "Worker #5":{
               "queueName":"Worker #5",
               "groupName":"Workers",
               "avgItemsPerSecond":0,
               "avgProcessingTime":0,
               "currentIdleTime":null,
               "currentItemProcessingTime":null,
               "idleTimePercent":100,
               "length":0,
               "lengthCurrentTryPeak":0,
               "lengthLifetimePeak":0,
               "totalItemsProcessed":0,
               "inProgressMessage":"<none>",
               "lastProcessedMessage":"<none>"
            }
         },
         "writer":{
            "lastFlushSize":185,
            "lastFlushDelayMs":0.008,
            "meanFlushSize":185,
            "meanFlushDelayMs":0.008,
            "maxFlushSize":185,
            "maxFlushDelayMs":0.008,
            "queuedFlushMessages":0
         },
         "readIndex":{
            "cachedRecord":2,
            "notCachedRecord":0,
            "cachedStreamInfo":6,
            "notCachedStreamInfo":12,
            "cachedTransInfo":0,
            "notCachedTransInfo":0
         }
      },
      "timestamp":"2021-07-10T12:40:03.1929223Z"
   },
   "SourceContext":"REGULAR-STATS-LOGGER",
   "ProcessId":15268,
   "ThreadId":13
}

Selecting System CPU

Therefore, the first step in doing this is to select the right values. If we wanted to select the cpu stats of the system directly we could start with the following:

 cat log-stats.json | jq '.stats.sys.cpu'

The bar | means to pipe and this command will pipe everything from the Linux Concatenate command into jq and then with jq we are specifying a basic filter, the dot filter. From the dot filter we then specify starting from the highest element in the json file down to the lowest (if you think about it as a tree data structure) element which is a leaf element the cpu metric.

The above query will generate the something like the following output.

3.7089055
13.255805
9.790947
18.27493
9.216788
2.3326468
23.251188
33.470463
28.646309
25.539902
29.907745
28.43653
34.446194
36.302208
32.793518
30.899149
28.076542
36.76352
34.19705
29.917332

Selecting Time

Now let’s try to select the time field and try to concatenate the resulting time field with the system processor field. The time is easily selected alone with:

cat log-stats.json | jq '.["@t"]'

We have to add the double quotes because of the @. In cases where the fields have spaces we would also have had to add the double quotes.

Combining Time & Processor Metrics

In jq you can combine outputs with the addition + operator. But if we try to just add them as follows:

cat log-stats.json | jq '.["@t"] + .stats.sys.cpu'

We will get an error that we can’t add a string (time) with an integer (cpu):

jq: error (at :0): string (“2021-07-10…) and number (9.457963) cannot be added

Let’s convert cpu to a string and then add both of the strings together with a space in the middle. This is possible with jq using the tostring operator as follows:

cat log-stats.json | jq '.["@t"] + " " + (.stats.sys.cpu|tostring)'

The output should then something as the following:

"2021-07-10T12:50:20.8773244Z 40.122253"
"2021-07-10T12:50:21.8840932Z 30.23657"
"2021-07-10T12:50:22.8923130Z 34.853474"
"2021-07-10T12:50:23.9067622Z 15.039631"
"2021-07-10T12:50:24.9231023Z 13.266266"
"2021-07-10T12:50:25.9354628Z 9.457963"

Removing Double Quotes

You will notice that there are double quotes around our output. We don’t want that because gnuplot will confuse the output to a single field. Removing the double is easy, we can provide jq with an additional parameter -r to provide raw output.

cat log-stats.json | jq -r '.["@t"] + " " + (.stats.sys.cpu|tostring)'

Which will give us:

2021-07-10T12:50:20.8773244Z 40.122253
2021-07-10T12:50:21.8840932Z 30.23657
2021-07-10T12:50:22.8923130Z 34.853474
2021-07-10T12:50:23.9067622Z 15.039631
2021-07-10T12:50:24.9231023Z 13.266266
2021-07-10T12:50:25.9354628Z 9.457963

GNUPLOT

Our input is now ready to be processed by gnuplot. The tricky part here actually is to process the time field. In order to do that there a few commands that you need to provide gnuplot with regarding the time value.

  1. You need to tell gnuplot that the first column is a datetime format. You can do this with: set xdata time;
  2. Then you need to provide gnuplot with the exact time format of the data: set timefmt “%Y-%m-%dT%H:%M:%.7SZ”; You can read more about the time format in the official gnuplot docs: http://gnuplot.sourceforge.net/docs_4.2/node274.html
  3. Then you need to provide the format of the output in your x-axis: set format x “%d %H:%M”;
  4. We need to the tell gnuplot to output the graph in terminal: set term dumb 70 35; There are many other types of outputs possible like saving directly to a png on disk that you might want to look into.
  5. Finally we need to tell gnuplot to take the input from the standard input directly, then we need to tell gnuplot which fields to use and which of kind plot to draw: plot “/dev/stdin” using 1:2 with linespoints

Combining the whole gnuplot and jq commands will look as follows:

cat log-stats.json | jq -r '.["@t"] + " " + (.stats.sys.cpu|tostring)' | gnuplot -p -e 'set xdata time; set timefmt "%Y-%m-%dT%H:%M:%.7SZ";set format x "%d %H:%M"; set term dumb 70 35; plot "/dev/stdin" using 1:2 with linespoints'

This command will generate the graph in the terminal. For example the screenshot below is on a Ubuntu 20.04 WSL 2.0 terminal on Windows.

We hope that this was useful, please comment if you are stuck or want another guide!

Categories
Administration Database

Top 10 Reasons To Upgrade EventStoreDB to Version 20.10.2 LTS

EventStoreDB has recently had many improvements due to their growth in team size and the future looks promising for the product. The company has recently announced a new versioning strategy to a date based strategy to make the length of support more intuitive to customers. You can read more at https://www.eventstore.com/blog/new-version-strategy.

Below are 10 reasons on why you should think about upgrading to the latest LTS(long term support) version 20.10.2 (at the time of writing of course).

Information detailed below have been compiled from the release notes at https://www.eventstore.com/blog/release-notes

1. Backport Of Fixes

The October releases are now going to be long term support releases and to be supported for the next 2 years (from the release date). This means that bug fixes will be backported to those versions. As an example, version 20.10.2 contains bug fixes that were backported from 21.2 to improve the product.

2. Cluster Stability Improvements

Cluster stability depends on the nodes’ ability to talk to each other correctly. There are scenarios where an overloaded node can take too long to reply to a gossip message, for example when that message is backed up in the send queue. This has now greatly improved in the latest 20.10.2 with a proactive heartbeat logic implemented which will reduce the number of heartbeat timeouts on busy servers.

Fewer false positives of dead nodes results in fewer fake cluster changes and better cluster stability.

3. Server-Side Filtering

Server side filtering allows you to request events from the server by passing a filter. The advantage in letting the server do the filtering compared to just reading from $all is that you will have significantly less events to receive (less network cost) and filter (less computation) on the client side. You can read more about it here: https://www.eventstore.com/blog/server-side-filtering

4. gRPC Interface

The new gRPC interface allows for easier implementation of clients. So far clients officially(I mean by EventStore) released are the NodeJS, Java, Rust, Golang and DotNet gRPC clients.

5. Read Only Replica

Previously on version 5 we used to have only Masters and Slaves. With version 20.10.2 firstly the terminology has changed from Master to Leader and from Slave to Follower.

In addition to this, it is possible for a node to be to a Read Only Replica. As the name suggests, this node is to used for reads only and the node itself does not take part in the quorum for elections.

Read Only Replica allows you to scale up on reads for catchup subscriptions, although, persistent subscriptions still only run on the Leader node.

6. Improvement In Memory Usage

There have been many memory usage improvements regarding index merges, specially in cases where the index cache depth values had been changed to higher values. Index merges are an essential part of letting a server keep up good performance as it grows and the memory improvements to index merges means that the cluster health is better.

7. Improvement To Projection Subsystem

If you take a look at the public repository and the number of projection fixes that been done over the years, you will realise that the projection subsystem is not much more stable. The likelyhood for projections to fault is now decreased with many corner cases fixed.

https://github.com/EventStore/EventStore/pulls?q=is%3Apr+is%3Aclosed+projection

8. Improvement To Facilitate Maintenance

Version 20.10.2 has the ability to resign a Leader node. What this means is that a new election is triggered with an attempt to elect a new Leader. This is extremely useful for performing maintenance work. By maintenance work we mean scavenging and manual index merges. Both of the those operations are resource intensive and it is recommended that they are performed on the Follower Nodes as the Leader Node is usually busier.

In addition to the above, you can also restart projections and persistent subscriptions subsystems.

9. Performance Improvements

A new option is now available to increase Read Index Cache Capacity. With this option you can increase the amount metadata that is cached by EventStore and increase both read and write performance.

Index memory improvement also mean that index cache depth can now safely be raised to a higher level. This can bring about better performance but it is a value to be used carefully and to be tested first in a development environment.

There is also a commercial option available to bypass check stream access which will also increase both read and write performance (because every write in EventStore has to perform a check on stream access first).

10. DotNet Core 5.0

EventStore has moved from Mono 4.6.2 to Mono 5.16.0.220 in version 5. Then to DotNet Core 3.0 in version 20.6.0. Finally, in version 20.10.2 EventStore has moved to DotNet 5. This brings various overall improvements to the runtime that can be found on the official website at https://dotnet.microsoft.com/download/dotnet/5.0

We hope that all of the above has convinced you to upgrade to the latest EventStoreDB.

Categories
Ideas

How To Enable Bots In Firing Range In Apex Legends

Step 1: Pick Pathfinder

Step 2: Go to Firing Range and Drop P2020 and ammo

Spawn at Firing Range
After dropping P2020 and Ammo

Step 3: Go to the right most entrance (if step 10 does not work go to the left most and try again)

Right most entrance

Step 4: Go inside and view the up there should be a ledge as seen in the screenshot below.

The ledge that you need to jump on

Step 5: Grapple onto the ledge. I usually grapple at the corner to make sure I don’t jump off the ledge when I land.

View after grappling onto the ledge.

Step 6: Crouch down around the center.

View after crouching down.

Step 7: Now look down completely until you can’t look further down.

Looking down completely.

Step 8: Now choose another legend.

Open the menu to change legends

Step 9: Pick any hero, for example I have picked Octane here.

Step 10: You should now here a metal clanking sound. When you go back to the training area the bots should now be active and shooting you as seen below.

If you are still having trouble enabling the bots, comment below and I will try to get back to you ASAP.

Categories
Administration

How To Extract XZ files on Windows 7, Vista, XP, 2008, 2003, 2000, NT, ME, and 98

Quick tip is to just install 7z https://sourceforge.net/projects/sevenzip/

The reason why I am writing this is that if you just Google how to do that you will probably go to https://tukaani.org/xz/ which is a great product but it is harder to use than 7z on Windows.

They have the same backward compatibility up to Windows 98 but xz.exe has to be run from the command line:

Screenshot of xz.exe –help from Windows Terminal

Anyway I will leave you with a fun fact that XZ utils can compress certain files 30% better than gzip. Hope that this post has saved you some time 🙂

Categories
Ideas

5 Tips For Networking Online

Networking opens up opportunities that can lead to anything from a new partner, a new job, friends or even investment. With the advent of Covid-19, new protocols of communications and safety practices have been adopted.

With the rules of the game now changed, networking is harder than it previously was. The networking game has moved from the physical to the digital.

This post provides a few tips on how to network online.

Online Communities

There are many online communities using anything from Facebook Groups, Meetup, Reddit or Discord. Finding them is easy as well. Most of the groups are public or if they are private they will usually contain information/instructions on how to join them. For example, if you are interested in bug bounty you can join Hackerone’s discord community.

Join Volunteer Organisations

There many organisations like Junior Chamber International or Rotary which have moved online. They do meetings and planning online with actions done physically but they are very much active. The way to join then is to find a local chapter near you. Usually Facebook or a Google Search will be your best bet.

MMO(RPGs)

MMOs are games that have been designed with interaction of a large number players in mind. It is inevitable that you will be making new friends there, which can translate to longer friendships with social media. Usually there is a clan or guild system in the games which will make this even easier.

Attend Online Conferences

Most of the online conferences are paid ones but there still are a few free ones. If not you can also look for webinars which are usually free. The important thing here is that you register for a conference around your area of interest. In most cases, the conferences are going to be done either in public on Youtube, Twitch or in private on Zoom. Either way attend sessions and ask questions. Later on try to get in touch with the speaker or anyone that caught your attention. This can be on Linkedin or Twitter or any means.

Chatroulette or Omegle

If you are not familiar with these two names, they are platforms built for you to meet strangers. I have put this last because with these platforms you have the risk to meet weird people. If you are in college then Omegle also has the option to chat with other college students. You will need to provide your college student email address as confirmation.

Anyway, just prepare yourself mentally beforehand 😀

That’s it! I have personally used those 3 tips and can vouch that they work!