cmd
for macOS is the ctrl
for windows.
Keyboard Shortcuts | Description | VSCode (macOS) | Intellij (macOS) | VSCode (windows) |
---|---|---|---|---|
cmd + c | copy | default | default | ctrl + c |
cmd + x | cut | default | default | ctrl + x |
cmd + v | paste | default | default | ctrl + v |
cmd + z | undo | default | default | ctrl + z |
cmd + s | save | default | default | ctrl + s |
cmd + / | toggle line comment | default | default | ctrl + / |
back/del | delete | default | default | default |
cmd + a | select all | default | default | ctrl + a |
cmd + shift + → | select to line end | default | default | => ctrl + shift + → |
cmd + shift + ← | select to line start | default | default | => ctrl + shift + ← |
shift + arrow | select to arrow direction | default | default | default |
cmd + → | move to line end | default | default | => ctrl + → |
cmd + ← | move to line start | default | default | => ctrl + ← |
cmd + ↑ | move to top | default | default | => ctrl + ↑ |
cmd + ↓ | move to bottom | default | default | => ctrl + ↓ |
cmd + [ | go back | => cmd + [ |
default | => ctrl + [ |
cmd + ] | go forward | => cmd + ] |
default | => ctrl + ] |
cmd + shift + f | find in files | default | default | ctrl + shift + f |
cmd + f | find in file | default | default | ctrl + f |
cmd + b | toggle side panel | default | => cmd + b |
ctrl + b |
cmd + shift + p | open command pallete | default | double shift | ctrl + shift + p |
cmd + p | go to file | default | double shift | ctrl + p |
ctrl + ` | toggle terminal panel | default | => ctrl + ` |
default |
cmd + w | close tab | default | default | ctrl + w |
Redis
as a simple distribution lock solution, which is already available in our application and needs zero extra setup, and it is a single instance therefore no replication sync concern. Redis
is single-threaded architecture so no matter how many concurrent clients try to write to it, it is guaranteed to be in sequential and atomic. I figure out I could make use of this nature to fix the issue faced.
namespace :main do
task :hello do
sleep 1 # simulate long-running task
puts '***hello, world***'
end
end
$ bundle exec rake main:hello & bundle exec rake main:hello &
[1] 38358
[2] 38359
***hello, world***
***hello, world***
[2] + done bundle exec rake main:hello
[1] + done bundle exec rake main:hello
Two processes run it simultaneously, and it runs twice.
namespace :lock do
redis = Redis.new
task :before do
task_name = Rake.application.top_level_tasks[0]
lock_obtained = redis.set task_name, '1', ex: 60, nx: true
abort "Another process is already running #{task_name}" unless lock_obtained
end
task :after do
task_name = Rake.application.top_level_tasks[0]
redis.del task_name
end
end
Rake::Task['main:hello'].enhance(['lock:before']) do
Rake::Task['lock:after'].execute
end
$ bundle exec rake main:hello & bundle exec rake main:hello &
[1] 38560
[2] 38561
Another process is already running main:hello
[1] - exit 1 bundle exec rake main:hello
***hello, world***
[2] + done bundle exec rake main:hello
Two processes run it simultaneously, but it runs only once.
The point is to make use of the nx: true
option of the set
command, which means only set the key if it does not already exist
. With redis single-threaded design, we can be sure that only one process will successfully set the key, denoting that only one process obtains the lock.
For referencee, Distributed Locks with Redis has more details on implementing more reliable and safer algorithem based locks such as Redlock
for more complicated cases.
$ tmux ls
$ tmux new -s <session-name>
# hold ctrl, press b, release both, and then press d
$ ctrl+b d
# in case of nested session - not recommended
# hold ctrl, press b, release both; repeat, and then press d
$ ctrl+b ctrl+b d
$ tmux attach -t <session-name>
$ tmux kill-session -t <session-name>
Ensure shebang is set like: #!/usr/bin/env java --source 17
, note the --source
is important
Ensure the first top-level class in the source code file contains the psvm
method as the execution entrance
Ensure file name does not have .java
extension and file is executable with chmod +x ./filename
fib
and make it executable#!/usr/bin/env java --source 17
public class Fib {
public static void main(String[] args) {
long num = Long.parseLong(args[0]);
System.out.println(fib(num));
}
private static long fib(long n) {
if (n < 2) return n;
return fib(n - 2) + fib(n - 1);
}
}
~$ ./fib 10
55
It can also be run without setting shebang line #!/usr/bin/env java --source 17
in ways of java filename.java
, in which case the file doesn’t need be set executable and the filename doesn’t need match the first top-level class name in source code file (like regular java code), but the .java
file extension is required.
If the single-file executable uses external dependency outside JDK, it can be passed with the usual -cp
parameter like: java -cp /path/to/3rd-party.jar filename.java
.
new Date().getTime()
, however, as a human we just can not quickly tell what date and time it represents. There is a convenient website named Epoch Converter that can help convert it to human-readable format easily but most of the time for developers, there are even quicker ways than opening the website, which is by using the interactive shell
that comes with many programming languages.
// node or browser console
> new Date(1685506340672)
2023-05-31T04:12:20.672Z
// jshell jdk 9+
import java.time.*;
jshell> Instant.ofEpochMilli(1685506340672L).atZone(ZoneId.of("Asia/Tokyo"))
//$1 ==> 2023-05-31T13:12:20.672+09:00[Asia/Tokyo]
# irb
irb(main):001:0> Time.at(0, 1685506340672, :millisecond)
=> 2023-05-31 13:12:20.672 +0900
>>> from datetime import datetime
>>> d = datetime.fromtimestamp(1685506340672/1000)
>>> str(d)
'2023-05-31 13:12:20.672000'
URI.escape
method.
irb(main):001:0> RUBY_VERSION
=> "2.7.6"
irb(main):002:1* def add(a: 1, b: 2)
irb(main):003:1* sum = a + b
irb(main):004:1* puts "#{a} + #{b} = #{sum}"
irb(main):005:0> end
=> :add
irb(main):006:0> add({a: 10, b: 20})
10 + 20 = 30
=> nil
irb(main):001:0> RUBY_VERSION
=> "3.0.5"
irb(main):002:1* def add(a: 1, b: 2)
irb(main):003:1* sum = a + b
irb(main):004:1* puts "#{a} + #{b} = #{sum}"
irb(main):005:0> end
=> :add
irb(main):006:0> add({a: 10, b: 20})
# (irb):2:in `add': wrong number of arguments (given 1, expected 0) (ArgumentError)
# from (irb):6:in `<main>'
# from /Users/andy/.rbenv/versions/3.0.5/lib/ruby/gems/3.0.0/gems/irb-1.3.5/exe/irb:11:in `<top (required)>'
# from /Users/andy/.rbenv/versions/3.0.5/bin/irb:23:in `load'
# from /Users/andy/.rbenv/versions/3.0.5/bin/irb:23:in `<main>'
irb(main):007:0> add(**{a: 10, b: 20})
10 + 20 = 30
=> nil
URI.escape
method and solutionirb(main):001:0> RUBY_VERSION
=> "3.0.5"
irb(main):002:0> require 'uri'
=> true
irb(main):003:0> url = 'http://www.google.com/?q=ruby 3'
=> "http://www.google.com/?q=ruby 3"
irb(main):004:0> URI.escape url
# (irb):4:in `<main>': undefined method `escape' for URI:Module (NoMethodError)
# from /Users/andy/.rbenv/versions/3.0.5/lib/ruby/gems/3.0.0/gems/irb-1.3.5/exe/irb:11:in `<top (required)>'
# from /Users/andy/.rbenv/versions/3.0.5/bin/irb:23:in `load'
# from /Users/andy/.rbenv/versions/3.0.5/bin/irb:23:in `<main>'
irb(main):005:0> URI.encode_www_form_component url
=> "http%3A%2F%2Fwww.google.com%2F%3Fq%3Druby+3"
irb(main):006:0> require 'cgi'
=> true
irb(main):007:0> CGI.escape url
=> "http%3A%2F%2Fwww.google.com%2F%3Fq%3Druby+3"
link
element with rel="stylesheet"
and href
set to a css file location, or creating a style
element with css definitions as its content. Now there is a 3rd way: importing css directly from within an ESM script tag, similarly to the way of importing JavaScript resources, via a feature called CSS Module scripts
.
<div id="app" class="has-text-success">{{ message }}</div>
<script type="module">
import { createApp } from 'https://unpkg.com/vue@3/dist/vue.esm-browser.js';
import bulma from 'https://cdn.jsdelivr.net/npm/bulma@0.9.4/css/bulma.min.css' assert { type: 'css' };
document.adoptedStyleSheets.push(bulma);
createApp({
data() {
return {
message: 'Hello World!'
}
}
}).mount('#app');
</script>
v18.11.0
, there is now FileHandle.prototype.readLines
builtin which makes it very convenient to use.
import fs from 'node:fs';
import readline from 'node:readline';
const fileStream = fs.createReadStream('input.txt');
const rl = readline.createInterface({
input: fileStream,
crlfDelay: Infinity
});
for await (const line of rl) {
console.log(`Line from file: ${line}`);
}
import { open } from 'node:fs/promises';
const file = await open('input.txt');
for await (const line of file.readLines()) {
console.log(`Line from file: ${line}`);
}
PS: There were some debates and discussions on whether this method should land on the core nodejs libraries from the PR. From an end-user perspective, I think it is a great addition and it makes using nodejs more convenient for handling large text files and reduces mental burden needed to remember the way from the readline
module as well as reduces lines of code by 50%, even though it’s just a wrapper method on top of readline
.
Thread.sleep()
, sleep
, and time.sleep()
methods to pause the execution of the current thread and wait after specified time to continue the execution, and when used together with loops, it can help address race condition issues for example. In node.js, and generally JavaScript, the way to pause and wait may not seem very obvious and frequently seen due to the nature of single-threaded, event-driven, and asyncronous architecture. However, since the use of wait
and retry
is still needed and helpful under certain circumstances, it is possible to simulate similar functions and effects in nodejs or JavaScript.
sleep
/wait
with setTimeout
new Promise
const wait = ms => new Promise(resolve => setTimeout(resolve, ms));
util.promisify
import util from 'node:util';
const wait = util.promisify(setTimeout);
retry
with back-offrecursive
functionsconst retry = async (fn, depth = 0, numRetries = 3) => {
try {
return await fn();
} catch (e) {
if (depth === numRetries) {
throw e;
}
console.log('retry...');
await wait(2 ** depth * 10);
return retry(fn, depth + 1, numRetries);
}
}
for
loopsconst retry = async (fn, retryDelayMs = 100, numRetries = 3) => {
for (let attempt = 0; attempt <= numRetries; attempt++) {
try {
return await fn();
} catch (e) {
if (attempt === numRetries) {
throw e;
}
console.log('retry...');
await wait(retryDelayMs);
retryDelayMs *= 2;
}
}
}
truthy
valueconst retry = async (fn, retryDelayMs = 100, numRetries = 3) => {
let result;
for(let i = 0; i < numRetries; i++) {
try {
result = await fn();
} catch (e) {
// ignore errors
}
if(result) {
return result;
}
console.log('retry...');
await wait(retryDelayMs);
retryDelayMs *= 2;
}
return result;
};
Open and edit the /etc/ssh/sshd_config
on the ssh server
ClientAliveInterval 60
ClientAliveCountMax 0
where ClientAliveInterval
can be set to a value greater than 0
, meaning the interval seconds to request client messages from the server and setting to 0
means doing nothing and disabling the requests; and ClientAliveCountMax
can be set to a value greater than 0
, meaning maximum counts of intervals without receiving client messages and setting to 0
means no maximum count limit and the server does not terminate the connection even without receiving any messages from the client.
For example, below combination will keep the connection alive for at least 60 * 3 = 180
seconds before server terminates the session.
ClientAliveInterval 60
ClientAliveCountMax 3
after the change, restart the sshd
service to make it take effect
service sshd restart
Create a ~/.ssh/config
on the ssh client machine (e.g. laptops)
HOST *
ServerAliveInterval 60
ServerAliveCountMax 0
The meaning of the config options is similar to the ones from the server side, varying in that who is the side that is trying to keep the connection alive.
Alternatively pass the options via command line during connection
ssh -o ServerAliveInterval=60 user@instance-1