Software developer2023-09-10T20:31:08+00:00https://alex-alekseichuk.github.ioAlex Alekseichukalex.alekseichuk@yandex.comPlinko game on the Phaser 3 framework2023-09-10T00:00:00+00:00https://alex-alekseichuk.github.io/2023/09/10/phaser-plinko-game<p>I designed and implemented <a href="https://alex-alekseichuk.github.io/projects/plinko/">plinko</a> game 2 months ago.
Plinko is a kind of gambling game.
A small ball is dropping to go through the set of barriers to finish its path in one of the buckets.
It’s not a final version and there is no graphics.
On the other hand, the physics looks like real one with the gravity and correct collisions.</p>
<p>I used <a href="https://phaser.io/">phaser</a> framework.</p>
<div id="plinko-game"></div>
<script src="//cdn.jsdelivr.net/npm/phaser@3.55.1/dist/phaser.js"></script>
<script type="text/javascript">
const model = {
nBuckets: 12,
launch: function() {
let iBucket;
while (iBucket === undefined)
iBucket = this.getRandomBucket();
return iBucket;
},
getRandomBucket: function() {
const rand = Math.random();
for (let i = 0; i < this.nBuckets; i++) {
if (rand <= this.randMax[i]) return i;
}
},
probs: [
0.0004882,
0.0053710,
0.0268554,
0.0805664,
0.1611328,
0.2255859,
0.2255859,
0.1611328,
0.0805664,
0.0268554,
0.0053710,
0.0004882,
],
prizes: [
136,
6.4,
3.2,
1.6,
0.6,
0.3,
0.3,
0.6,
1.6,
3.2,
6.4,
136,
],
init: function() {
this.randMax = [];
let accProb = 0;
this.probs.forEach(prob => {
this.randMax.push(prob + accProb);
accProb += prob;
});
},
};
model.init();
var config = {
type: Phaser.AUTO,
backgroundColor: '#eee',
parent: 'plinko-game',
width: 660,
height: 495,
scene: {
preload: preload,
create: create,
update: update,
},
scale: {
mode: Phaser.Scale.FIT,
autoCenter: Phaser.Scale.CENTER_BOTH
},
physics: {
default: 'arcade',
arcade: {
gravity: { y: 500 },
debug: false
}
},
};
const game = new Phaser.Game(config);
function preload ()
{
}
const xStart = 0;
let dx;
let rb;
let statics;
let buckets;
let dynamics;
let ball;
function create ()
{
dx = Math.floor(game.config.width / (model.nBuckets * 2 + 2));
const dy = dx;
const r = dx / 2 - 3;
rb = r - 4;
const yStart = 3 * dy;
statics = this.physics.add.staticGroup();
buckets = this.physics.add.staticGroup();
dynamics = this.physics.add.group();
for (let iy = 0; iy < model.nBuckets; iy++) {
const xRowStart = xStart + (model.nBuckets - iy) * dx;
for (let ix = 0; ix < iy+2; ix++) {
const x = ix * dx * 2 + xRowStart;
const y = iy * dy + yStart;
const circle = this.add.circle(x, y, r, 0x101010);
circle.bucket = model.nBuckets / 2 - 1 - iy/2 + ix;
circle.xx = model.nBuckets - 2 - iy + 2*ix;
circle.yy = iy;
if (ix > 0) circle.canLeft = true;
if (ix < iy+1) circle.canRight = true;
statics.add(circle);
circle.body.setCircle(r);
}
}
for (let ix = 0; ix < model.nBuckets; ix++) {
const x = ix * dx * 2 + (2*dx) + xStart;
const y = model.nBuckets * dy + yStart;
const bucket = this.add.rectangle(x, y, dx + dx/2, dy, 0x009900);
bucket.i = ix;
buckets.add(bucket);
}
launch(this);
}
function launch(scene) {
const x = xStart + (model.nBuckets + 1) * dx;
ball = scene.add.circle(x, 0, rb, 0xEE1010);
ball.iBucket = model.launch();
ball.xBucket = 2 * ball.iBucket;
ball.yBucket = model.nBuckets - 1;
ball.level = -1;
console.log(`target bucket: ${ball.iBucket}`);
dynamics.add(ball);
ball.body.setCircle(rb);
ball.body.setBounce(1.0, 0.3);
ball.body.setCollideWorldBounds(true);
scene.physics.add.collider(ball, statics, (ball, circle) => {
if (ball.level < circle.yy) {
ball.level = circle.yy;
} else if (ball.level === circle.yy) {
return;
} else {
ball.body.setVelocityY(30);
return;
}
let v;
let leftRightBoth = 2; // 0,1,2
const h = ball.yBucket - (circle.yy - 1);
if (ball.xBucket < circle.xx && circle.xx - ball.xBucket >= h) {
leftRightBoth = 0;
}
if (ball.xBucket > circle.xx && ball.xBucket - circle.xx >= h) {
leftRightBoth = 1;
}
switch (leftRightBoth) {
case 0:
v = -30;
break;
case 1:
v = 30;
break;
case 2:
if (Math.abs(ball.x - circle.x) < 10.0)
v = (Math.random() - 0.5) * 60;
break;
}
console.log(`v: ${v}`);
if (v)
ball.body.setVelocityX(v);
});
scene.physics.add.collider(ball, buckets, (ball, bucket) => {
dynamics.remove(ball, true, true);
console.log(`result bucket: ${bucket.i}`);
launch(scene);
});
}
function update ()
{
}
</script>
Vim mode in VS Code2023-01-05T00:00:00+00:00https://alex-alekseichuk.github.io/2023/01/05/vscode-vim-mode<p>I use the vim/vi editor in the Linux terminal.
But Vim is not a single plain text editor.
VS Code is widely used as an ID.
Working with text is absolutely different in these 2 editors.
To switch from one editor to another, it needs to rearrange the brain.
To avoid such frustration, it’s better to use a special Vim extension in VS Code,
to use the same normal/insert/visual modes and the same keys as in vim.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Vim emulation for Visual Studio Code
</code></pre></div></div>
<p>Add in VS Code Settings (JSON):</p>
<div class="language-json highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">{</span><span class="w">
</span><span class="nl">"vim.easymotion"</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span><span class="p">,</span><span class="w">
</span><span class="nl">"vim.incsearch"</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span><span class="p">,</span><span class="w">
</span><span class="nl">"vim.useSystemClipboard"</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span><span class="p">,</span><span class="w">
</span><span class="nl">"vim.useCtrlKeys"</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span><span class="p">,</span><span class="w">
</span><span class="nl">"vim.hlsearch"</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span><span class="p">,</span><span class="w">
</span><span class="nl">"vim.insertModeKeyBindings"</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="w">
</span><span class="p">{</span><span class="w">
</span><span class="nl">"before"</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="s2">"j"</span><span class="p">,</span><span class="w"> </span><span class="s2">"j"</span><span class="p">],</span><span class="w">
</span><span class="nl">"after"</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="s2">"<Esc>"</span><span class="p">]</span><span class="w">
</span><span class="p">}</span><span class="w">
</span><span class="p">],</span><span class="w">
</span><span class="nl">"vim.normalModeKeyBindingsNonRecursive"</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="w">
</span><span class="p">{</span><span class="w">
</span><span class="nl">"before"</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="s2">"<leader>"</span><span class="p">,</span><span class="w"> </span><span class="s2">"d"</span><span class="p">],</span><span class="w">
</span><span class="nl">"after"</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="s2">"d"</span><span class="p">,</span><span class="w"> </span><span class="s2">"d"</span><span class="p">]</span><span class="w">
</span><span class="p">},</span><span class="w">
</span><span class="p">{</span><span class="w">
</span><span class="nl">"before"</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="s2">"<C-n>"</span><span class="p">],</span><span class="w">
</span><span class="nl">"commands"</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="s2">":nohl"</span><span class="p">]</span><span class="w">
</span><span class="p">},</span><span class="w">
</span><span class="p">{</span><span class="w">
</span><span class="nl">"before"</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="s2">"K"</span><span class="p">],</span><span class="w">
</span><span class="nl">"commands"</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="s2">"lineBreakInsert"</span><span class="p">],</span><span class="w">
</span><span class="nl">"silent"</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span><span class="w">
</span><span class="p">},</span><span class="w">
</span><span class="p">{</span><span class="w">
</span><span class="nl">"before"</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="s2">"u"</span><span class="p">],</span><span class="w">
</span><span class="nl">"commands"</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="s2">"undo"</span><span class="p">]</span><span class="w">
</span><span class="p">},</span><span class="w">
</span><span class="p">{</span><span class="w">
</span><span class="nl">"before"</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="s2">"<C-r>"</span><span class="p">],</span><span class="w">
</span><span class="nl">"commands"</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="s2">"redo"</span><span class="p">]</span><span class="w">
</span><span class="p">}</span><span class="w">
</span><span class="p">],</span><span class="w">
</span><span class="nl">"vim.leader"</span><span class="p">:</span><span class="w"> </span><span class="s2">"<space>"</span><span class="p">,</span><span class="w">
</span><span class="nl">"vim.handleKeys"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
</span><span class="nl">"<C-a>"</span><span class="p">:</span><span class="w"> </span><span class="kc">false</span><span class="p">,</span><span class="w">
</span><span class="nl">"<C-w>"</span><span class="p">:</span><span class="w"> </span><span class="kc">false</span><span class="p">,</span><span class="w">
</span><span class="nl">"<C-o>"</span><span class="p">:</span><span class="w"> </span><span class="kc">false</span><span class="p">,</span><span class="w">
</span><span class="nl">"<C-f>"</span><span class="p">:</span><span class="w"> </span><span class="kc">false</span><span class="w">
</span><span class="p">}</span><span class="w">
</span><span class="p">}</span><span class="w">
</span></code></pre></div></div>
<p>Features:</p>
<ul>
<li>double <code class="language-plaintext highlighter-rouge">jj</code> to switch to normal mode from insert, as Esc.</li>
<li>leader key is <code class="language-plaintext highlighter-rouge">space</code> instead of default one</li>
<li>^n new file/tab</li>
<li>^a select all</li>
<li>^w close tab</li>
<li>^o open file</li>
<li>^f find via VS Code find interface</li>
<li>^s save</li>
</ul>
The Zebra Puzzle brute force solution in golang2021-10-17T00:00:00+00:00https://alex-alekseichuk.github.io/2021/10/17/zebra-puzzle-brute-force-solution-in-golang<p>In CS theory book I found the link on interesting Boolean Algebra task.
<a href="https://code.energy/solving-zebra-puzzle/">The Zebra Puzzle</a>
It’s a sort of Boolean Algebra exercise.</p>
<p>I wrote simple <a href="https://gist.github.com/alex-alekseichuk/8baa02973787db972c35cd8777ac6e3d?ts=4">golang program</a> to solve the puzzle.</p>
<p>It’s a kind of pure brute force iterator of all possible combinations.
Generator pattern is used to provide the combinations and implemented by goroutine and channel. It looks like standard approach in golang.
It’s optimized to cut false combinations as soon as possible.
There is also a DSL to describe a set of rules.</p>
<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c">// Brute-force solution of the Zebra Puzzle</span>
<span class="c">// https://code.energy/solving-zebra-puzzle/</span>
<span class="c">//</span>
<span class="c">// Result:</span>
<span class="c">// Norwegian from 1 house drinks water.</span>
<span class="c">// Japanese from 5 house owns zebra.</span>
<span class="k">package</span> <span class="n">main</span>
<span class="k">import</span> <span class="p">(</span>
<span class="s">"fmt"</span>
<span class="p">)</span>
<span class="k">func</span> <span class="n">contains</span><span class="p">(</span><span class="n">values</span> <span class="p">[]</span><span class="kt">int</span><span class="p">,</span> <span class="n">value</span> <span class="kt">int</span><span class="p">)</span> <span class="kt">bool</span> <span class="p">{</span>
<span class="k">for</span> <span class="n">_</span><span class="p">,</span> <span class="n">n</span> <span class="o">:=</span> <span class="k">range</span> <span class="n">values</span> <span class="p">{</span>
<span class="k">if</span> <span class="n">n</span> <span class="o">==</span> <span class="n">value</span> <span class="p">{</span>
<span class="k">return</span> <span class="no">true</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="k">return</span> <span class="no">false</span>
<span class="p">}</span>
<span class="k">func</span> <span class="n">addIndexRecursive</span><span class="p">(</span><span class="n">indexes</span> <span class="p">[]</span><span class="kt">int</span><span class="p">,</span> <span class="n">ch</span> <span class="k">chan</span> <span class="p">[]</span><span class="kt">int</span><span class="p">,</span> <span class="n">n</span> <span class="kt">int</span><span class="p">)</span> <span class="p">{</span>
<span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">indexes</span><span class="p">)</span> <span class="o">==</span> <span class="m">5</span> <span class="p">{</span>
<span class="n">ch</span> <span class="o"><-</span> <span class="n">indexes</span>
<span class="k">return</span>
<span class="p">}</span>
<span class="k">for</span> <span class="n">i</span> <span class="o">:=</span> <span class="m">0</span><span class="p">;</span> <span class="n">i</span> <span class="o"><</span> <span class="n">n</span> <span class="p">;</span> <span class="n">i</span><span class="o">++</span> <span class="p">{</span>
<span class="k">if</span> <span class="n">contains</span><span class="p">(</span><span class="n">indexes</span><span class="p">,</span> <span class="n">i</span><span class="p">)</span> <span class="p">{</span>
<span class="k">continue</span>
<span class="p">}</span>
<span class="n">indexes</span> <span class="o">=</span> <span class="nb">append</span><span class="p">(</span><span class="n">indexes</span><span class="p">,</span> <span class="n">i</span><span class="p">)</span>
<span class="n">addIndexRecursive</span><span class="p">(</span><span class="n">indexes</span><span class="p">,</span> <span class="n">ch</span><span class="p">,</span> <span class="n">n</span><span class="p">)</span>
<span class="n">indexes</span> <span class="o">=</span> <span class="n">indexes</span><span class="p">[</span><span class="o">:</span><span class="nb">len</span><span class="p">(</span><span class="n">indexes</span><span class="p">)</span><span class="o">-</span><span class="m">1</span><span class="p">]</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="k">func</span> <span class="n">allCombinations</span><span class="p">(</span><span class="n">n</span> <span class="kt">int</span><span class="p">)</span> <span class="k">chan</span> <span class="p">[]</span><span class="kt">int</span> <span class="p">{</span>
<span class="n">ch</span> <span class="o">:=</span> <span class="nb">make</span><span class="p">(</span><span class="k">chan</span> <span class="p">[]</span><span class="kt">int</span><span class="p">)</span>
<span class="k">go</span> <span class="k">func</span><span class="p">(</span><span class="n">ch</span> <span class="k">chan</span> <span class="p">[]</span><span class="kt">int</span><span class="p">)</span> <span class="p">{</span>
<span class="n">indexes</span> <span class="o">:=</span> <span class="p">[]</span><span class="kt">int</span> <span class="p">{}</span>
<span class="n">addIndexRecursive</span><span class="p">(</span><span class="n">indexes</span><span class="p">,</span> <span class="n">ch</span><span class="p">,</span> <span class="n">n</span><span class="p">)</span>
<span class="nb">close</span><span class="p">(</span><span class="n">ch</span><span class="p">)</span>
<span class="p">}(</span><span class="n">ch</span><span class="p">)</span>
<span class="k">return</span> <span class="n">ch</span>
<span class="p">}</span>
<span class="k">func</span> <span class="n">match</span><span class="p">(</span><span class="n">indexes1</span> <span class="p">[]</span><span class="kt">int</span><span class="p">,</span> <span class="n">value1</span> <span class="kt">int</span><span class="p">,</span> <span class="n">indexes2</span><span class="p">[]</span><span class="kt">int</span><span class="p">,</span> <span class="n">value2</span> <span class="kt">int</span><span class="p">)</span> <span class="kt">bool</span> <span class="p">{</span>
<span class="k">if</span> <span class="p">(</span><span class="n">indexes1</span><span class="p">[</span><span class="m">0</span><span class="p">]</span> <span class="o">!=</span> <span class="n">value1</span> <span class="o">||</span> <span class="n">indexes2</span><span class="p">[</span><span class="m">0</span><span class="p">]</span> <span class="o">!=</span> <span class="n">value2</span><span class="p">)</span> <span class="o">&&</span>
<span class="p">(</span><span class="n">indexes1</span><span class="p">[</span><span class="m">1</span><span class="p">]</span> <span class="o">!=</span> <span class="n">value1</span> <span class="o">||</span> <span class="n">indexes2</span><span class="p">[</span><span class="m">1</span><span class="p">]</span> <span class="o">!=</span> <span class="n">value2</span><span class="p">)</span> <span class="o">&&</span>
<span class="p">(</span><span class="n">indexes1</span><span class="p">[</span><span class="m">2</span><span class="p">]</span> <span class="o">!=</span> <span class="n">value1</span> <span class="o">||</span> <span class="n">indexes2</span><span class="p">[</span><span class="m">2</span><span class="p">]</span> <span class="o">!=</span> <span class="n">value2</span><span class="p">)</span> <span class="o">&&</span>
<span class="p">(</span><span class="n">indexes1</span><span class="p">[</span><span class="m">3</span><span class="p">]</span> <span class="o">!=</span> <span class="n">value1</span> <span class="o">||</span> <span class="n">indexes2</span><span class="p">[</span><span class="m">3</span><span class="p">]</span> <span class="o">!=</span> <span class="n">value2</span><span class="p">)</span> <span class="o">&&</span>
<span class="p">(</span><span class="n">indexes1</span><span class="p">[</span><span class="m">4</span><span class="p">]</span> <span class="o">!=</span> <span class="n">value1</span> <span class="o">||</span> <span class="n">indexes2</span><span class="p">[</span><span class="m">4</span><span class="p">]</span> <span class="o">!=</span> <span class="n">value2</span><span class="p">)</span> <span class="p">{</span>
<span class="k">return</span> <span class="no">false</span>
<span class="p">}</span>
<span class="k">return</span> <span class="no">true</span>
<span class="p">}</span>
<span class="k">func</span> <span class="n">rightOf</span><span class="p">(</span><span class="n">indexes1</span> <span class="p">[]</span><span class="kt">int</span><span class="p">,</span> <span class="n">value1</span> <span class="kt">int</span><span class="p">,</span> <span class="n">indexes2</span><span class="p">[]</span><span class="kt">int</span><span class="p">,</span> <span class="n">value2</span> <span class="kt">int</span><span class="p">)</span> <span class="kt">bool</span> <span class="p">{</span>
<span class="k">if</span> <span class="p">(</span><span class="n">indexes1</span><span class="p">[</span><span class="m">1</span><span class="p">]</span> <span class="o">!=</span> <span class="n">value1</span> <span class="o">||</span> <span class="n">indexes2</span><span class="p">[</span><span class="m">0</span><span class="p">]</span> <span class="o">!=</span> <span class="n">value2</span><span class="p">)</span> <span class="o">&&</span>
<span class="p">(</span><span class="n">indexes1</span><span class="p">[</span><span class="m">2</span><span class="p">]</span> <span class="o">!=</span> <span class="n">value1</span> <span class="o">||</span> <span class="n">indexes2</span><span class="p">[</span><span class="m">1</span><span class="p">]</span> <span class="o">!=</span> <span class="n">value2</span><span class="p">)</span> <span class="o">&&</span>
<span class="p">(</span><span class="n">indexes1</span><span class="p">[</span><span class="m">3</span><span class="p">]</span> <span class="o">!=</span> <span class="n">value1</span> <span class="o">||</span> <span class="n">indexes2</span><span class="p">[</span><span class="m">2</span><span class="p">]</span> <span class="o">!=</span> <span class="n">value2</span><span class="p">)</span> <span class="o">&&</span>
<span class="p">(</span><span class="n">indexes1</span><span class="p">[</span><span class="m">4</span><span class="p">]</span> <span class="o">!=</span> <span class="n">value1</span> <span class="o">||</span> <span class="n">indexes2</span><span class="p">[</span><span class="m">3</span><span class="p">]</span> <span class="o">!=</span> <span class="n">value2</span><span class="p">)</span> <span class="p">{</span>
<span class="k">return</span> <span class="no">false</span>
<span class="p">}</span>
<span class="k">return</span> <span class="no">true</span>
<span class="p">}</span>
<span class="k">func</span> <span class="n">nextTo</span><span class="p">(</span><span class="n">indexes1</span> <span class="p">[]</span><span class="kt">int</span><span class="p">,</span> <span class="n">value1</span> <span class="kt">int</span><span class="p">,</span> <span class="n">indexes2</span><span class="p">[]</span><span class="kt">int</span><span class="p">,</span> <span class="n">value2</span> <span class="kt">int</span><span class="p">)</span> <span class="kt">bool</span> <span class="p">{</span>
<span class="k">if</span> <span class="p">(</span><span class="n">indexes1</span><span class="p">[</span><span class="m">0</span><span class="p">]</span> <span class="o">!=</span> <span class="n">value1</span> <span class="o">||</span> <span class="n">indexes2</span><span class="p">[</span><span class="m">1</span><span class="p">]</span> <span class="o">!=</span> <span class="n">value2</span><span class="p">)</span> <span class="o">&&</span>
<span class="p">(</span><span class="n">indexes1</span><span class="p">[</span><span class="m">1</span><span class="p">]</span> <span class="o">!=</span> <span class="n">value1</span> <span class="o">||</span> <span class="n">indexes2</span><span class="p">[</span><span class="m">0</span><span class="p">]</span> <span class="o">!=</span> <span class="n">value2</span> <span class="o">&&</span> <span class="n">indexes2</span><span class="p">[</span><span class="m">2</span><span class="p">]</span> <span class="o">!=</span> <span class="n">value2</span><span class="p">)</span> <span class="o">&&</span>
<span class="p">(</span><span class="n">indexes1</span><span class="p">[</span><span class="m">2</span><span class="p">]</span> <span class="o">!=</span> <span class="n">value1</span> <span class="o">||</span> <span class="n">indexes2</span><span class="p">[</span><span class="m">1</span><span class="p">]</span> <span class="o">!=</span> <span class="n">value2</span> <span class="o">&&</span> <span class="n">indexes2</span><span class="p">[</span><span class="m">3</span><span class="p">]</span> <span class="o">!=</span> <span class="n">value2</span><span class="p">)</span> <span class="o">&&</span>
<span class="p">(</span><span class="n">indexes1</span><span class="p">[</span><span class="m">3</span><span class="p">]</span> <span class="o">!=</span> <span class="n">value1</span> <span class="o">||</span> <span class="n">indexes2</span><span class="p">[</span><span class="m">2</span><span class="p">]</span> <span class="o">!=</span> <span class="n">value2</span> <span class="o">&&</span> <span class="n">indexes2</span><span class="p">[</span><span class="m">4</span><span class="p">]</span> <span class="o">!=</span> <span class="n">value2</span><span class="p">)</span> <span class="o">&&</span>
<span class="p">(</span><span class="n">indexes1</span><span class="p">[</span><span class="m">4</span><span class="p">]</span> <span class="o">!=</span> <span class="n">value1</span> <span class="o">||</span> <span class="n">indexes2</span><span class="p">[</span><span class="m">3</span><span class="p">]</span> <span class="o">!=</span> <span class="n">value2</span><span class="p">)</span> <span class="p">{</span>
<span class="k">return</span> <span class="no">false</span>
<span class="p">}</span>
<span class="k">return</span> <span class="no">true</span>
<span class="p">}</span>
<span class="k">const</span> <span class="p">(</span>
<span class="n">englishman</span> <span class="o">=</span> <span class="no">iota</span>
<span class="n">ukrainian</span>
<span class="n">norwegian</span>
<span class="n">japanese</span>
<span class="n">spaniard</span>
<span class="p">)</span>
<span class="k">const</span> <span class="p">(</span>
<span class="n">red</span> <span class="o">=</span> <span class="no">iota</span>
<span class="n">green</span>
<span class="n">ivory</span>
<span class="n">blue</span>
<span class="n">yellow</span>
<span class="p">)</span>
<span class="k">const</span> <span class="p">(</span>
<span class="n">milk</span> <span class="o">=</span> <span class="no">iota</span>
<span class="n">orange</span>
<span class="n">water</span>
<span class="n">tea</span>
<span class="n">coffee</span>
<span class="p">)</span>
<span class="k">const</span> <span class="p">(</span>
<span class="n">oldGold</span> <span class="o">=</span> <span class="no">iota</span>
<span class="n">kools</span>
<span class="n">chesterfields</span>
<span class="n">luckyStrike</span>
<span class="n">parliaments</span>
<span class="p">)</span>
<span class="k">const</span> <span class="p">(</span>
<span class="n">dog</span> <span class="o">=</span> <span class="no">iota</span>
<span class="n">snails</span>
<span class="n">horse</span>
<span class="n">zebra</span>
<span class="n">fox</span>
<span class="p">)</span>
<span class="k">func</span> <span class="n">main</span><span class="p">()</span> <span class="p">{</span>
<span class="n">nationsTitles</span> <span class="o">:=</span> <span class="p">[</span><span class="m">5</span><span class="p">]</span><span class="kt">string</span> <span class="p">{</span><span class="s">"Englishman"</span><span class="p">,</span> <span class="s">"Ukrainian"</span><span class="p">,</span> <span class="s">"Norwegian"</span><span class="p">,</span> <span class="s">"Japanese"</span><span class="p">,</span> <span class="s">"Spaniard"</span><span class="p">}</span>
<span class="k">for</span> <span class="n">iNations</span> <span class="o">:=</span> <span class="k">range</span> <span class="n">allCombinations</span><span class="p">(</span><span class="m">5</span><span class="p">)</span> <span class="p">{</span>
<span class="k">if</span> <span class="o">!</span><span class="p">(</span><span class="n">iNations</span><span class="p">[</span><span class="m">0</span><span class="p">]</span> <span class="o">==</span> <span class="n">norwegian</span><span class="p">)</span> <span class="p">{</span>
<span class="k">continue</span>
<span class="p">}</span>
<span class="k">for</span> <span class="n">iSmokes</span> <span class="o">:=</span> <span class="k">range</span> <span class="n">allCombinations</span><span class="p">(</span><span class="m">5</span><span class="p">)</span> <span class="p">{</span>
<span class="k">if</span> <span class="o">!</span><span class="n">match</span><span class="p">(</span><span class="n">iNations</span><span class="p">,</span> <span class="n">japanese</span><span class="p">,</span> <span class="n">iSmokes</span><span class="p">,</span> <span class="n">parliaments</span><span class="p">)</span> <span class="p">{</span>
<span class="k">continue</span>
<span class="p">}</span>
<span class="k">for</span> <span class="n">iColors</span> <span class="o">:=</span> <span class="k">range</span> <span class="n">allCombinations</span><span class="p">(</span><span class="m">5</span><span class="p">)</span> <span class="p">{</span>
<span class="k">if</span> <span class="o">!</span><span class="n">match</span><span class="p">(</span><span class="n">iNations</span><span class="p">,</span> <span class="n">englishman</span><span class="p">,</span> <span class="n">iColors</span><span class="p">,</span> <span class="n">red</span><span class="p">)</span> <span class="o">||</span>
<span class="o">!</span><span class="n">match</span><span class="p">(</span><span class="n">iSmokes</span><span class="p">,</span> <span class="n">kools</span><span class="p">,</span> <span class="n">iColors</span><span class="p">,</span> <span class="n">yellow</span><span class="p">)</span> <span class="o">||</span>
<span class="o">!</span><span class="n">rightOf</span><span class="p">(</span><span class="n">iColors</span><span class="p">,</span> <span class="n">green</span><span class="p">,</span> <span class="n">iColors</span><span class="p">,</span> <span class="n">ivory</span><span class="p">)</span> <span class="o">||</span>
<span class="o">!</span><span class="n">nextTo</span><span class="p">(</span><span class="n">iNations</span><span class="p">,</span> <span class="n">norwegian</span><span class="p">,</span> <span class="n">iColors</span><span class="p">,</span> <span class="n">blue</span><span class="p">)</span> <span class="p">{</span>
<span class="k">continue</span>
<span class="p">}</span>
<span class="k">for</span> <span class="n">iDrinks</span> <span class="o">:=</span> <span class="k">range</span> <span class="n">allCombinations</span><span class="p">(</span><span class="m">5</span><span class="p">)</span> <span class="p">{</span>
<span class="k">if</span> <span class="o">!</span><span class="p">(</span><span class="n">iDrinks</span><span class="p">[</span><span class="m">2</span><span class="p">]</span> <span class="o">==</span> <span class="m">0</span><span class="p">)</span> <span class="o">||</span>
<span class="o">!</span><span class="n">match</span><span class="p">(</span><span class="n">iDrinks</span><span class="p">,</span> <span class="n">coffee</span><span class="p">,</span> <span class="n">iColors</span><span class="p">,</span> <span class="n">green</span><span class="p">)</span> <span class="o">||</span>
<span class="o">!</span><span class="n">match</span><span class="p">(</span><span class="n">iNations</span><span class="p">,</span> <span class="n">ukrainian</span><span class="p">,</span> <span class="n">iDrinks</span><span class="p">,</span> <span class="n">tea</span><span class="p">)</span> <span class="o">||</span>
<span class="o">!</span><span class="n">match</span><span class="p">(</span><span class="n">iSmokes</span><span class="p">,</span> <span class="n">luckyStrike</span><span class="p">,</span> <span class="n">iDrinks</span><span class="p">,</span> <span class="n">orange</span><span class="p">)</span> <span class="p">{</span>
<span class="k">continue</span>
<span class="p">}</span>
<span class="k">for</span> <span class="n">iPets</span> <span class="o">:=</span> <span class="k">range</span> <span class="n">allCombinations</span><span class="p">(</span><span class="m">5</span><span class="p">)</span> <span class="p">{</span>
<span class="k">if</span> <span class="o">!</span><span class="n">match</span><span class="p">(</span><span class="n">iNations</span><span class="p">,</span> <span class="n">spaniard</span><span class="p">,</span> <span class="n">iPets</span><span class="p">,</span> <span class="n">dog</span><span class="p">)</span> <span class="o">||</span>
<span class="o">!</span><span class="n">match</span><span class="p">(</span><span class="n">iSmokes</span><span class="p">,</span> <span class="n">oldGold</span><span class="p">,</span> <span class="n">iPets</span><span class="p">,</span> <span class="n">snails</span><span class="p">)</span> <span class="o">||</span>
<span class="o">!</span><span class="n">nextTo</span><span class="p">(</span><span class="n">iSmokes</span><span class="p">,</span> <span class="n">chesterfields</span><span class="p">,</span> <span class="n">iPets</span><span class="p">,</span> <span class="n">fox</span><span class="p">)</span> <span class="o">||</span>
<span class="o">!</span><span class="n">nextTo</span><span class="p">(</span><span class="n">iSmokes</span><span class="p">,</span> <span class="n">kools</span><span class="p">,</span> <span class="n">iPets</span><span class="p">,</span> <span class="n">horse</span><span class="p">)</span> <span class="p">{</span>
<span class="k">continue</span>
<span class="p">}</span>
<span class="k">for</span> <span class="n">i</span><span class="p">,</span> <span class="n">iDrink</span> <span class="o">:=</span> <span class="k">range</span> <span class="n">iDrinks</span> <span class="p">{</span>
<span class="k">if</span> <span class="n">iDrink</span> <span class="o">==</span> <span class="n">water</span> <span class="p">{</span>
<span class="n">fmt</span><span class="o">.</span><span class="n">Println</span><span class="p">(</span><span class="n">nationsTitles</span><span class="p">[</span><span class="n">iNations</span><span class="p">[</span><span class="n">i</span><span class="p">]],</span> <span class="s">"from"</span><span class="p">,</span> <span class="n">i</span> <span class="o">+</span> <span class="m">1</span><span class="p">,</span> <span class="s">"house drinks water."</span><span class="p">)</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="k">for</span> <span class="n">i</span><span class="p">,</span> <span class="n">iPet</span> <span class="o">:=</span> <span class="k">range</span> <span class="n">iPets</span> <span class="p">{</span>
<span class="k">if</span> <span class="n">iPet</span> <span class="o">==</span> <span class="n">zebra</span> <span class="p">{</span>
<span class="n">fmt</span><span class="o">.</span><span class="n">Println</span><span class="p">(</span><span class="n">nationsTitles</span><span class="p">[</span><span class="n">iNations</span><span class="p">[</span><span class="n">i</span><span class="p">]],</span> <span class="s">"from"</span><span class="p">,</span> <span class="n">i</span> <span class="o">+</span> <span class="m">1</span><span class="p">,</span> <span class="s">"house owns zebra."</span><span class="p">)</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>
Brieif descriptions of the tools by parsing their man pages2021-10-09T00:00:00+00:00https://alex-alekseichuk.github.io/2021/10/09/brief-descriptions-of-the-tools-by-their-man-pages<p>I found nice series of lectures online.
<a href="https://www.youtube.com/watch?v=sz_dsktIjt4">One of them</a>
is about unix/linux CLI tools to process files.</p>
<p>I wrote simple <a href="https://gist.github.com/alex-alekseichuk/68f8565d65c61d5260ac22cd0b3e8005">bash script</a>:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>#!/bin/bash
cmds=(cat tac head tail tee more less echo wc grep find sort comm tr cut split sed awk seq)
for cmd in $cmds; do
man $cmd|sed -n '4p'|sed -E 's/^\s+//;s/ - /\n /'
done
</code></pre></div></div>
<p>It gets 4-th line of the man page of each tool and compose the list of tools and their brief descriptions.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>cat
concatenate files and print on the standard output
tac
concatenate and print files in reverse
head
output the first part of files
tail
output the last part of files
tee
read from standard input and write to standard output and files
more
file perusal filter for crt viewing
less
opposite of more
echo
display a line of text
wc
print newline, word, and byte counts for each file
grep, egrep, fgrep, rgrep
print lines that match patterns
find
search for files in a directory hierarchy
sort
sort lines of text files
uniq
report or omit repeated lines
comm
compare two sorted files line by line
tr
translate or delete characters
cut
remove sections from each line of files
split
split a file into pieces
sed
stream editor for filtering and transforming text
gawk
pattern scanning and processing language
seq
print a sequence of numbers
</code></pre></div></div>
<p>Happy hacking!</p>
Code sample in the book2020-11-18T00:00:00+00:00https://alex-alekseichuk.github.io/2020/11/18/code-sample-in-the-book<p>I read the book called like Modern Development using TypeScript and blah-blah-blah.
Well, you can find a lot of books like that.</p>
<p>I spot an example:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>getMailboxes().then(function() {
async function getContacts() {
const contactsWorker: Contacts.Worker = new Contacts.Worker();
const contacts: Contacts.IContact[] = await contactsWorker.listContacts();
contacts.forEach((inContact) => {
baseComponent.state.addContactToList(inContact);
});
}
getContacts().then(() =>
baseComponent.state.showHidePleaseWait(false));
});
</code></pre></div></div>
<p>which I would re-write like</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>getMailboxes().then(() => {
const contactsWorker: Contacts.Worker = new Contacts.Worker();
return contactsWorker.listContacts();
}).then((contacts: Contacts.IContact[]) => {
contacts.forEach(inContact =>
baseComponent.state.addContactToList(inContact));
}).then(() =>
baseComponent.state.showHidePleaseWait(false));
});
</code></pre></div></div>
<p>or even better</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>await getMailboxes();
const contactsWorker: Contacts.Worker = new Contacts.Worker();
const contacts: Contacts.IContact[] = await contactsWorker.listContacts();
contacts.forEach(inContact =>
baseComponent.state.addContactToList(inContact));
baseComponent.state.showHidePleaseWait(false));
</code></pre></div></div>
<p>There would be compact, good code instead of something copy-pasted from the project of the author.
Anybody can code something, but it’s not so easy to write really good code and good book, as well.</p>
<p>Happy reading!</p>
JavaScript Test Tasks2020-08-10T00:00:00+00:00https://alex-alekseichuk.github.io/2020/08/10/js-test<p>I passed the simple coding test during registration on the web site few days ago.
There are 3 tasks:</p>
<h3 id="1-sort-the-numbers-by-frequency-and-leave-original-order-for-equal-frequency-numbers">1. Sort the numbers by frequency and leave original order for equal frequency numbers</h3>
<p>I implemented modified bubble-sort for both the sorting and the saving original order</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>const input = '1 1 3 5 8 8 4 8 9';
var output = countSort(input);
console.log(output);
function countSort(s) {
const a = s.split(' ').map(ch => +ch);
const counters = {};
a.forEach(x => {
if (!counters[x])
counters[x] = 1;
else
counters[x] += 1;
});
let process = true;
while (process) {
process = false;
for (let i = 0, n = a.length; i < n - 1; i++)
if (counters[a[i]] < counters[a[i+1]]) {
const c = a[i];
a[i] = a[i+1];
a[i+1] = c;
process = true;
}
}
return a.join(' ');
}
</code></pre></div></div>
<h3 id="2-perfect-numbers">2. Perfect numbers</h3>
<p>6, 28, 496, …</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>for (let i = 0; i < 500; i++) {
if (isPerfect(i))
console.log(i);
}
function isPerfect(n) {
if (n < 6)
return false;
let s = 0;
for (let i = 1, count = n / 2; i <= count; i++) {
if (n % i === 0)
s += i;
}
return s === n;
}
</code></pre></div></div>
<h3 id="3-string-rank">3. String rank</h3>
<p>I’m afraid there is be some more elegant pure regex solution.
But I’ve done dummy straightforward solution.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>console.log(stringRank('onion')); // on - 2
console.log(stringRank('codenrock')); // 0
console.log(stringRank('undergrounder')); // under - 5
function stringRank(s) {
const a = s.toLowerCase().split('');
if (a.length <= 1)
return 0;
let result = 0;
for (let i = 1, n = a.length; i < n; i++) {
let j;
for (j = 0; j < i; j++)
if (a[j] !== a[n-i+j])
break;
if (j === i)
result = i;
}
return result;
}
</code></pre></div></div>
<p>Happy coding!</p>
JS1024 2020 Schulte Tables2020-08-07T00:00:00+00:00https://alex-alekseichuk.github.io/2020/08/07/js1024-2020-schulte-tables<p>I took a part in JS1024 contest several weeks ago.
The goal is to implement some JavaScript application in 1kB.
I implemented the simplest version of <a href="https://js1024.fun/results/2020#36">Schulte Tables</a> application.</p>
<p>Happy js’ing!</p>
Lazydocker is a handy Docker tool2020-08-06T00:00:00+00:00https://alex-alekseichuk.github.io/2020/08/06/lazydocker-is-a-handy-docker-tool<p>Just try <a href="https://github.com/jesseduffield/lazydocker">lazydocker</a>.
It’s a handy console tool for both the speedup your regular docker routines in command line
and the visual picture of your images and containers.</p>
<h3 id="to-install">To Install</h3>
<ol>
<li>make sure you have <code class="language-plaintext highlighter-rouge">go</code> environment installed</li>
<li>run
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>go get github.com/jesseduffield/lazydocker
</code></pre></div> </div>
</li>
</ol>
<p>In ``~/.zshrc`</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>PATH=$PATH:$HOME/go/bin
alias lzd='lazydocker'
</code></pre></div></div>
<p>Some hot-keys:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>[] - prev/next tab
x - menu
PgUp/PgDown - scroll
d remove
s stop
r restart
a attach
D prune existed containers
m view logs
</code></pre></div></div>
<p>Happy hacking!</p>
Best JavaScript minifier2020-07-12T00:00:00+00:00https://alex-alekseichuk.github.io/2020/07/12/best-JavaScript-minifier<p>I took a part in the JS1024 contest last weekend.
The idea is to design and implement something interesting or valuable in 1024 bytes JS code.
I’ve done the <em><a href="https://en.wikipedia.org/wiki/Schulte_table">Schulte Tables</a></em> application.
<em><a href="/projects/schulte-tables-js1024.html">Try it online</a></em>.
To have it as less size as possible,
I minimized the code by <em><a href="https://www.npmjs.com/package/uglify-js">UglifyJS 3</a></em>.
There is <em><a href="https://skalman.github.io/UglifyJS-online/">online tool</a></em>.</p>
<p>Happy coding!</p>
Best comments for source code2020-06-26T00:00:00+00:00https://alex-alekseichuk.github.io/2020/06/26/best-comments-for-source-code<p>We write source code and the comments for better understanding the ideas and patterns used.
It needs to just writing, but the reading the comments, as well.
Ideally, you should write the code, then leave it for some time to jump out of the context.
Next step is to read it one more time.</p>
<p>If you spent just little time to understand it,
then you are lucky to have correct coding patterns and style guides.
So, you don’t need to put anything extra like comments.</p>
<p>On the other hand, if you are thinking about some function or even variable usage/purpose,
then it needs to add extra comments to help/speed up the understanding process.</p>
<p>Happy coding!</p>
.nojekyll file to host Nuxt project on GitHub2020-06-10T00:00:00+00:00https://alex-alekseichuk.github.io/2020/06/10/nojekyll-file-to-host-nuxt-on-github<p>I was taking part in the awesome hackathon last weekend.
For the demonstration of the SPA web UI, I’ve done, I used GitHub.io pages free hosting.
I used Vue, Vuex, Vuetify, and Nuxt to implement the application.
But the Nuxt places some files into <code class="language-plaintext highlighter-rouge">_nuxt/</code> directory,
which is ignored by Jekyll engine on GitHub.io side.</p>
<p>To avoid such a conflict, it’s enough to place <code class="language-plaintext highlighter-rouge">.nojekyll</code> empty file in the root of the repo.
So, the Jekyll engine would be turned off, and you can host your Nuxt based solution.</p>
<p>Happy hosting!</p>
Non-blocking node.js exit on key press2020-06-04T00:00:00+00:00https://alex-alekseichuk.github.io/2020/06/04/nodejs-exit-on-key-press<p>From time to time it needs to implement some CLI tool.
There is the approach to wait for any key press, then exit the process.
The feature doesn’t block your process.
So, there is some listener or other useful logic can still be in progress.</p>
<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nx">process</span><span class="p">.</span><span class="nx">stdin</span><span class="p">.</span><span class="nx">setRawMode</span><span class="p">(</span><span class="kc">true</span><span class="p">);</span>
<span class="nx">process</span><span class="p">.</span><span class="nx">stdin</span><span class="p">.</span><span class="nx">resume</span><span class="p">();</span>
<span class="nx">process</span><span class="p">.</span><span class="nx">stdin</span><span class="p">.</span><span class="nx">on</span><span class="p">(</span><span class="dl">'</span><span class="s1">data</span><span class="dl">'</span><span class="p">,</span> <span class="nx">process</span><span class="p">.</span><span class="nx">exit</span><span class="p">.</span><span class="nx">bind</span><span class="p">(</span><span class="nx">process</span><span class="p">,</span> <span class="mi">0</span><span class="p">));</span>
</code></pre></div></div>
<p>Happy coding!</p>
Exclude in Babel2020-06-03T00:00:00+00:00https://alex-alekseichuk.github.io/2020/06/03/exclude-in-babel<p>I build complicated application by webpack+babel.
Obviously, it uses some well-known libraries as dependencies.
Usually, those libraries are already packed, so we don’t need to process them,
just import/require and use.</p>
<p>That’s why it’s handy to exclude such a dependency from processing by babel.
See a rule below. We just exclude all files from <code class="language-plaintext highlighter-rouge">node_modules</code>.</p>
<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="p">{</span>
<span class="nl">test</span><span class="p">:</span> <span class="sr">/</span><span class="se">\.</span><span class="sr">jsx</span><span class="se">?</span><span class="sr">$/</span><span class="p">,</span>
<span class="nx">exclude</span><span class="p">:</span> <span class="o">/</span><span class="nx">node_modules</span><span class="o">/</span><span class="p">,</span>
<span class="nx">loaders</span><span class="p">:</span> <span class="p">[</span>
<span class="dl">'</span><span class="s1">babel-loader</span><span class="dl">'</span>
<span class="p">]</span>
<span class="p">}</span>
</code></pre></div></div>
<p>There would be more complicated configuration. E.g., we use our own common library as dependency.
In this case we need to include files from such a source into loader.
One of approaches is to add exception for the module into regexp.</p>
<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="p">{</span>
<span class="nl">test</span><span class="p">:</span> <span class="sr">/</span><span class="se">\.</span><span class="sr">jsx</span><span class="se">?</span><span class="sr">$/</span><span class="p">,</span>
<span class="nx">exclude</span><span class="p">:</span> <span class="o">/</span><span class="nx">node_modules</span><span class="p">[</span><span class="err">\\\</span><span class="o">/</span><span class="p">](?</span><span class="o">!</span><span class="nx">common</span><span class="p">[</span><span class="err">\\\</span><span class="o">/</span><span class="p">])</span><span class="o">/</span><span class="p">,</span>
<span class="nx">loaders</span><span class="p">:</span> <span class="p">[</span>
<span class="dl">'</span><span class="s1">babel-loader</span><span class="dl">'</span><span class="p">,</span>
<span class="p">]</span>
<span class="p">}</span>
</code></pre></div></div>
<p>It looks too messy and weired. Regexp becomes unreadable.
There is better approach below.</p>
<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="nx">exclude</span><span class="p">:</span> <span class="p">{</span>
<span class="nl">test</span><span class="p">:</span> <span class="nx">path</span><span class="p">.</span><span class="nx">resolve</span><span class="p">(</span><span class="nx">__dirname</span><span class="p">,</span> <span class="dl">"</span><span class="s2">node_modules</span><span class="dl">"</span><span class="p">),</span>
<span class="nx">exclude</span><span class="p">:</span> <span class="nx">path</span><span class="p">.</span><span class="nx">resolve</span><span class="p">(</span><span class="nx">__dirname</span><span class="p">,</span> <span class="dl">"</span><span class="s2">node_modules/common</span><span class="dl">"</span><span class="p">)</span>
<span class="p">},</span>
</code></pre></div></div>
<p>Happy building!</p>
Tabs in Vim editor2020-05-29T00:00:00+00:00https://alex-alekseichuk.github.io/2020/05/29/vim-tabs<p>It doesn’t need to explain the role of Vi/Vim text editor in our life.
I tend to call it default console editor, or even just default text editor.
Usually, I use buffers or cool window manager provided by the plugin to switch virtual screen,
when I edit several files in Vim. But today I found for myself regular built-in Tabs feature
provided in my current Vim version out of the box. It’s like in other text editors/IDE’s.
So, I don’t need all those buffers, etc., as there are tabs.</p>
<p>For records:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>When starting Vim, the
-p
option opens each specified file in a separate tab
vim -p first.txt second.txt
:tabe file open file in new tab
:tabc close tab
:tabc {i}
:tabonly class all other tabs
gt go to next tab
gT go to previous tab
{i}gt go to tab in position i
# do something through all the
:tabdo %s/foo/bar/g
:tabs list all tabs including their displayed windows
:tabm 0 move current tab to first
:tabm move current tab to last
:tabm {i} move current tab to position i+1
:tabn go to next tab
:tabp go to previous tab
:tabfirst go to first tab
:tablast go to last tab
:tab ball show each buffer in a tab (up to 'tabpagemax' tabs)
:tab help open a new help window in its own tab page
:tab drop {file} open {file} in a new tab, or jump to a window/tab containing the file if there is one
:tab split copy the current window to a new tab of its own
.vimrc
set showtabline=2
imap ,t <Esc>:tabnew<CR>
</code></pre></div></div>
<p>Happy editing!</p>
UML diagrams in GitLab2020-05-29T00:00:00+00:00https://alex-alekseichuk.github.io/2020/05/29/uml-diagrams-in-gitlab<p>We use GitLab in our team. It’s handy to use UML in the process on any stage.
But drawing takes too much time. That’s why it’s better to use plain text online editor
<a href="http://www.plantuml.com/plantuml/uml/">PlantUML</a> to compose in pure declarative way the UML diagram or ER-diagram schema.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>@startuml
' hide the spot
hide circle
' avoid problems with angled crows feet
skinparam linetype ortho
entity "Entity01" as e01 {
*e1_id : number <<generated>>
--
*name : text
description : text
}
entity "Entity02" as e02 {
*e2_id : number <<generated>>
--
*e1_id : number <<FK>>
other_details : text
}
entity "Entity03" as e03 {
*e3_id : number <<generated>>
--
e1_id : number <<FK>>
other_details : text
}
e01 ||..o{ e02
e01 |o..o{ e03
@enduml
</code></pre></div></div>
<p>The tool can generate PNG file, that we can attach to a description or a comment in GitLab.</p>
<p><img src="/assets/images/2020-05-29-er-diagram.png" alt="ER-diagram example" title="ER-diagram example" /></p>
<p>Besides, we can save plain-text source of diagram to the file and commit it.
Later, correct it and even check by <em>git diff</em>, which is not possible with diagram in the form of a PNG image.</p>
<p>More examples:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>@startuml
participant User
User -> A: DoWork
activate A
A -> B: << createRequest >>
activate B
B -> C: DoWork
activate C
C --> B: WorkDone
destroy C
B --> A: RequestCreated
deactivate B
A -> User: Done
deactivate A
@enduml
</code></pre></div></div>
<p><img src="/assets/images/2020-05-29-sequence-diagram.png" alt="Sequence Diagram example" title="Sequence Diagram example" /></p>
Express framework: Common error handler2020-05-26T00:00:00+00:00https://alex-alekseichuk.github.io/2020/05/26/express-framework-common-error-handler<p>The Express framework doesn’t allow us to set up a global error handler before assign route handlers.
It’s not handy, because we do all common settings before all concrete application stuff, usually.</p>
<p>There is a workaround in the case of the express framework.
Create and assign <code class="language-plaintext highlighter-rouge">express.Router</code> on the root URL, then register a global error handler.</p>
<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">const</span> <span class="nx">router</span> <span class="o">=</span> <span class="nx">express</span><span class="p">.</span><span class="nx">Router</span><span class="p">();</span>
<span class="nx">httpServer</span><span class="p">.</span><span class="nx">use</span><span class="p">(</span><span class="dl">'</span><span class="s1">/</span><span class="dl">'</span><span class="p">,</span> <span class="nx">router</span><span class="p">);</span>
<span class="nx">httpServer</span><span class="p">.</span><span class="nx">use</span><span class="p">(</span><span class="nx">errorHandler</span><span class="p">);</span>
</code></pre></div></div>
<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">function</span> <span class="nx">errorHandler</span><span class="p">(</span><span class="nx">err</span><span class="p">,</span> <span class="nx">req</span><span class="p">,</span> <span class="nx">res</span><span class="p">,</span> <span class="nx">next</span><span class="p">)</span> <span class="p">{</span>
<span class="nx">_logger</span><span class="p">.</span><span class="nx">error</span><span class="p">(</span><span class="nx">err</span><span class="p">.</span><span class="nx">stack</span><span class="p">);</span>
<span class="k">if</span> <span class="p">(</span><span class="nx">res</span><span class="p">.</span><span class="nx">headersSent</span><span class="p">)</span> <span class="p">{</span>
<span class="k">return</span> <span class="nx">next</span><span class="p">(</span><span class="nx">err</span><span class="p">)</span>
<span class="p">}</span>
<span class="k">if</span> <span class="p">(</span><span class="nx">req</span><span class="p">.</span><span class="nx">xhr</span> <span class="o">||</span> <span class="nx">req</span><span class="p">.</span><span class="nx">headers</span><span class="p">.</span><span class="nx">accept</span><span class="p">.</span><span class="nx">indexOf</span><span class="p">(</span><span class="dl">'</span><span class="s1">json</span><span class="dl">'</span><span class="p">)</span> <span class="o">></span> <span class="o">-</span><span class="mi">1</span><span class="p">)</span> <span class="p">{</span>
<span class="nx">res</span><span class="p">.</span><span class="nx">status</span><span class="p">(</span><span class="mi">500</span><span class="p">).</span><span class="nx">send</span><span class="p">({</span> <span class="na">error</span><span class="p">:</span> <span class="nx">err</span><span class="p">.</span><span class="nx">message</span> <span class="o">||</span> <span class="dl">'</span><span class="s1">Server error</span><span class="dl">'</span> <span class="p">})</span>
<span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
<span class="nx">res</span><span class="p">.</span><span class="nx">status</span><span class="p">(</span><span class="mi">500</span><span class="p">).</span><span class="nx">send</span><span class="p">(</span><span class="nx">err</span><span class="p">.</span><span class="nx">message</span> <span class="o">||</span> <span class="dl">'</span><span class="s1">Server Error</span><span class="dl">'</span><span class="p">)</span>
<span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>
<p>All following route handlers should be registered within the Router object instead of the main express instance.
Now it’s ok to register route handlers after a common error handler.</p>
<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="nx">router</span><span class="p">.</span><span class="kd">get</span><span class="p">(</span><span class="dl">'</span><span class="s1">/some/url</span><span class="dl">'</span><span class="p">,</span> <span class="k">async</span> <span class="p">(</span><span class="nx">req</span><span class="p">,</span> <span class="nx">res</span><span class="p">,</span> <span class="nx">next</span><span class="p">)</span> <span class="o">=></span> <span class="p">{</span>
<span class="k">try</span> <span class="p">{</span>
<span class="c1">// ...</span>
<span class="nx">next</span><span class="p">();</span>
<span class="p">}</span> <span class="k">catch</span> <span class="p">(</span><span class="nx">err</span><span class="p">)</span> <span class="p">{</span>
<span class="nx">next</span><span class="p">(</span><span class="nx">err</span><span class="p">);</span>
<span class="p">}</span>
<span class="p">});</span>
</code></pre></div></div>
Enums in JavaScript2020-05-25T00:00:00+00:00https://alex-alekseichuk.github.io/2020/05/25/enum-in-javascript<p>In multi-layer application it needs to pass error/result codes from provider to the service, or from the service to upper layer.
The best approach to deal with error codes are enums. But there are no enums in JavaScript.</p>
<p>I use such utility function to create an object which provides the set of constants like enum does:</p>
<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">function</span> <span class="nx">createEnum</span><span class="p">(</span><span class="nx">labels</span><span class="p">,</span> <span class="nx">startIndex</span> <span class="o">=</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span>
<span class="k">return</span> <span class="nb">Object</span><span class="p">.</span><span class="nx">freeze</span><span class="p">(</span><span class="nx">labels</span><span class="p">.</span><span class="nx">reduce</span><span class="p">((</span><span class="nx">enu</span><span class="p">,</span> <span class="nx">label</span><span class="p">,</span> <span class="nx">i</span><span class="p">)</span> <span class="o">=></span> <span class="p">{</span><span class="nx">enu</span><span class="p">[</span><span class="nx">label</span><span class="p">]</span> <span class="o">=</span> <span class="nx">i</span> <span class="o">+</span> <span class="nx">startIndex</span><span class="p">;</span> <span class="k">return</span> <span class="nx">enu</span><span class="p">;},</span> <span class="p">{}));</span>
<span class="p">}</span>
</code></pre></div></div>
<p>Define enum in the service to be called:</p>
<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">const</span> <span class="nx">ERRORS</span> <span class="o">=</span> <span class="nx">util</span><span class="p">.</span><span class="nx">createEnum</span><span class="p">([</span><span class="dl">'</span><span class="s1">OK</span><span class="dl">'</span><span class="p">,</span> <span class="dl">'</span><span class="s1">UNKNOWN_ERROR</span><span class="dl">'</span><span class="p">,</span> <span class="dl">'</span><span class="s1">SERVER_ERROR</span><span class="dl">'</span><span class="p">]);</span>
</code></pre></div></div>
<p>Then use those codes on both sides the client and the service:</p>
<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">const</span> <span class="nx">result</span> <span class="o">=</span> <span class="k">await</span> <span class="nx">someApi</span><span class="p">.</span><span class="nx">method</span><span class="p">();</span>
<span class="k">if</span> <span class="p">(</span><span class="nx">result</span> <span class="o">===</span> <span class="nx">someApi</span><span class="p">.</span><span class="nx">ERRORS</span><span class="p">.</span><span class="nx">OK</span><span class="p">)</span>
<span class="p">...</span>
</code></pre></div></div>
Get port mapping in kubernetes cluster2019-11-08T00:00:00+00:00https://alex-alekseichuk.github.io/2019/11/08/get-port-mapping-in-kubernetes-cluster<p>A few days ago I was asked for a way to get external port of the service hosted under kubernetes.
Internal listening port inside the container is mapped to outside world.</p>
<h3 id="how-to-get-kubernetes-ports-mappings">How to get kubernetes ports mappings.</h3>
<p>1) install <code class="language-plaintext highlighter-rouge">kubectl</code> tool</p>
<p>2) get <code class="language-plaintext highlighter-rouge">kubeconfig</code> file for specific kubernetes cluster</p>
<p>3) use specific config as default one</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>cp kubeconfig ~/.kube/config
</code></pre></div></div>
<p>As alternative, we can specify the config via arg. <code class="language-plaintext highlighter-rouge">--kubeconfig</code></p>
<p>4) be sure it’s used now</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>kubectl config view
</code></pre></div></div>
<p>5) list namespaces</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>kubectl get namespace
</code></pre></div></div>
<p>6) list services with port mappings in the namespace</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>kubectl get services -n some-namespace
</code></pre></div></div>
Jekyll + GitHub Pages: looking for the perfect blog platform2019-10-29T00:00:00+00:00https://alex-alekseichuk.github.io/2019/10/29/jekyll-and-github-pages<p>I don’t remember when I started blogging. Probably 10-12 years ago.
I used several online systems. Last one was Wordpress.
It has several cons.:</p>
<ul>
<li>It’s not easy to switch/jump from wordpress.com to another hosting.</li>
<li>It’s not easy to backup all posts/content as a set of source files/records.</li>
<li>There are some limitations of layout and visual editor.</li>
<li>It puts some ads right into my content. Generally, it’s a cost of free hosting/service, but I don’t like it anyway.</li>
</ul>
<p>I don’t need a lot of features, just regular posts publishing with SEO.
<a href="https://jekyllrb.com/">Jekyll</a>, <a href="https://www.gatsbyjs.org/">Gatsby</a> or <a href="https://gohugo.io/">Hugo</a> provides static blogging cases out of the box.
As <a href="https://pages.github.com/">GitHub Pages</a> already provides Jekyll as a service, and even for free,
so, it looks like the best way.</p>
<p>I found simple theme and compose <a href="https://jekyllrb.com/">Jekyll</a> project based on it.
Jekyll is the system to create and maintain static web sites.
It’s implemented by ruby and has a lot of plugins as ruby gems.
Text content is composed and saved in source files. I use markdown format.
There is powerful styles and layout systems.
Transform your plain text into static websites and blogs:</p>
<ul>
<li>Markdown for content</li>
<li>YAML for data</li>
<li>Liquid for templating</li>
</ul>