Overview

Welcome to my personal wiki where I share all of the things that I know. This site is created using mdbook.

Table of Contents

NoTopicLinks
1.Rusthttps://ahmadrosid/wiki/rust.html
2.Golanghttps://ahmadrosid/wiki/go.html
3.JavaScripthttps://ahmadrosid/wiki/js.html
4.Shellhttps://ahmadrosid/wiki/shell.html

Rust

My Project

List of project I Created using rust. Most of this project I Created is because I don't know and I can not find the tool that I need.

  • hl - Github-like html Syntax highlighting.
  • tpd - Typo Detector for English words.
  • json-list - Take json list turn to striing list.
  • npr - Find and execute npm script.
  • faker-cli - Generate fake data from your terminal.
  • rep-cli - Replace text file in Bulk.

CLI - Command Line Application

Collection of comman line app written in Rust that I use.

  • bore - bore is a simple CLI tool for making tunnels to localhost
  • ripgrep - ripgrep recursively searches directories for a regex pattern while respecting your gitignore
  • bat - A cat(1) clone with wings.
  • nushell - A new type of shell.
  • Helix - A post-modern modal text editor.

GUI - Desktop application

Collection of dekstop app written in Rust.

  • Zeditor - A Capable and Fast Code Editor for macOS.
  • Warp - The terminal for the 21st century.

Golang

Learning Material

Articles

Command Line Application

  • fzf - 🌸 A command-line fuzzy finder
  • gron - Make JSON greppable!

Javascript

Javascript is my secondary programming language, I use javascript when working on frontend related things.

Opensource Project

Interesting open source project.

Full Stack

  • Outline - The fastest wiki and knowledge base for growing teams. Beautiful, feature rich, and markdown compatible.

Library/Framework

  • Lexical - Lexical is an extensible text editor framework that provides excellent reliability, accessibility and performance.

Javascript Playgound

  • RunJS - The JavaScript playground for your desktop
  • JSConsole - Javascript console on the web

Chearsheets

Generate random string.

function generate(length, password = "") {
    let letters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$%^&*()_{}/";
    Array(length).fill(0).forEach(() => {
    	 password += letters[Math.floor(Math.random() * 64)];
    })
    return password;
}

// Usage
console.log(generate(32));

Git

Git cheatsheets.

Semantic Commit Messages

Format: <type>(<scope>): <subject>

<scope> is optional

Example

feat: add hat wobble
^--^  ^------------^
|     |
|     +-> Summary in present tense.
|
+-------> Type: chore, docs, feat, fix, refactor, style, or test.

More <type> :

  • feat: (new feature for the user, not a new feature for build script)
  • fix: (bug fix for the user, not a fix to a build script)
  • docs: (changes to the documentation)
  • style: (formatting, missing semi colons, etc; no production code change)
  • refactor: (refactoring production code, eg. renaming a variable)
  • test: (adding missing tests, refactoring tests; no production code change)
  • chore: (updating grunt tasks etc; no production code change)

References:

  • https://www.conventionalcommits.org/
  • https://seesparkbox.com/foundry/semantic_commit_messages
  • http://karma-runner.github.io/1.0/dev/git-commit-msg.html

Git Conf

Turn this warning off The file will have its original line endings in your working directory

git config core.autocrlf true

git sync local repository with remote

git fetch --prune

update commit authro

git commit --amend --author="Author Name <some@mail.com>" --no-edit

# or in short
git commit --amend --reset-author

Shell Script

  • asdf - Extendable version manager with support for Ruby, Node.js, Elixir, Erlang & more

Cheatsheets

Check if command exists or not.

if !(command -v go); then
    # Do something 
fi

Check if folder exists or not.

if ! test -d "$BUILD_FOLDER"; then
  mkdir $BUILD_FOLDER
fi

Archive

Extract tar.gz

tar -xvzf filename.tar.gz

Database

MySQL Cheatsheets

Quick cheatsheat for doing mysql query for CRUD operation.

Create Database

CREATE DATABASE db_name;

Create Table

CREATE TABLE users (
    id INT(6) UNSIGNED AUTO_INCREMENT PRIMARY KEY,
    first_name VARCHAR(30) NOT NULL,
    last_name VARCHAR(30) NOT NULL,
    email VARCHAR(50),
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
)

Insert

INSERT INTO users(first_name, last_name, email) 
VALUES ("Ahmad","Rosid","sample@mail.com");

Cheatsheets

Rust

Golang

JavaScript

Filter vector to unique list.

// from 
vec![1,1,2,3]
// to
vec![1,2,3]
data
    .into_iter()
    .collect::<HashSet<_>>()
    .into_iter()
    .collect::<Vec<_>>()

Read file to string in Rust.

Read to string

let file = "data.txt"
let data = std::fs::read_to_string(file).expect(&format!("Filed reading file {}", file));

Read file line by line

let file = File::open(path);
if let Ok(file) = file {
    let mut reader = BufReader::new(file);
    loop {
        let mut line = String::new();
        match reader.read_line(&mut line) {
            Ok(_) => {
                if line.is_empty() {
                    break;
                }
                // do anything with line
            }
            _ => break,
        };
    }
}

Watch file changes with inotify.

Cargo.toml

[dependencies]
notify = "4"

Code:

extern crate notify;
use notify::{DebouncedEvent, RecommendedWatcher, RecursiveMode, Watcher};
use std::sync::mpsc::channel;
use std::time::Duration;
use std::path::Path;

fn watch(file_path: &str) -> notify::Result<()> {
    let (tx, rx) = channel();
    let delay = 300;
    let mut watcher: RecommendedWatcher = Watcher::new(tx, Duration::from_millis(delay))?;
    watcher.watch(Path::new(&file_path), RecursiveMode::NonRecursive)?;

    loop {
        let event = match rx.recv() {
            Ok(event) => event,
            Err(err) => {
                println!("Config watcher channel dropped unexpectedly: {}", err);
                break;
            }
        };

        match event {
            DebouncedEvent::Rename(_, path)
            | DebouncedEvent::Write(path)
            | DebouncedEvent::Create(path)
            | DebouncedEvent::Chmod(path) => {
                // do with file changes
            }
            _ => (),
        }
    }
    Ok(())
}

Write string to file path.

use std::io::Write;

fn write_file(content: &String, file_name: &str) {
    let cwd = std::env::current_dir().unwrap();
    let mut file = std::fs::File::create(format!("{}/{}", cwd.to_str().unwrap(), file_name)).unwrap();
    write!(&mut file, "{}", content).unwrap();
}

Golang: Check if some array sting contains a given string.

package main

import "sort"

func ArrayStringContain(array []string, s string) bool {
	idx := sort.SearchStrings(array, s)
	return idx < len(array) && array[idx] == s
}

func main() {
	var data = []string{"work", "from", "home"}
	if ArrayStringContain(data, "home") {
		println("Yes it contain 'home'!")
	}
}

Convert size to bytes 1KiB to 1024.


import (
	"strings"
	"strconv"
)

func Pow(x int64, y int) int64 {
	if y == 0 {
		return 1
	}

	result := x
	for n := 1; n < y; n++ {
		result = result * x
	}
	return result
}

func ConvertSizeToBytes(s string) (string, error) {

	// make lowercase so units detection always works
	s = strings.TrimSpace(strings.ToLower(s))

	// first look for binary units
	for _, unit := range units2 {
		if strings.HasSuffix(s, unit) {
			s = strings.TrimSuffix(s, unit)
			if i, err := strconv.ParseInt(s, 10, 0); err != nil {
				return "", fmt.Errorf("invalid size value '%s': %v", s, err)
			} else {
				i = i * Pow(1024, lookupTable2[unit])
				s = strconv.FormatInt(i, 10)
				return s, nil
			}
		}
	}

	// fall back to SI units
	for _, unit := range units10 {
		if strings.HasSuffix(s, unit) {
			s = strings.TrimSuffix(s, unit)
			if i, err := strconv.ParseInt(s, 10, 0); err != nil {
				return "", fmt.Errorf("invalid size value '%s': %v", s, err)
			} else {
				i = i * Pow(1000, lookupTable10[unit])
				s = strconv.FormatInt(i, 10)
				return s, nil
			}
		}
	}

	// no valid units found, so ensure the value is a number
	if _, err := strconv.ParseUint(s, 10, 64); err != nil {
		return "", fmt.Errorf("invalid size value '%s': %v", s, err)
	}

	return s, nil
}

How to use?

var k = "1KiB"
s, err := ConvertSizeToBytes(k)
// s = 1024

Golang: Format byte size to human readable text.

import "fmt"

var sizes = []string{"B", "kB", "MB", "GB", "TB", "PB", "EB"}

func FormatFileSize(s float64, base float64) string {
	unitsLimit := len(sizes)
	i := 0
	for s >= base && i < unitsLimit {
		s = s / base
		i++
	}

	f := "%.0f %s"
	if i > 1 {
		f = "%.2f %s"
	}

	return fmt.Sprintf(f, s, sizes[i])
}

How to use:

var size = 452984832
fmt.Printf("%s\n", FormatFileSize(float64(size), 1024.0)) // 432.00 MB

Run it here

Golang: Get current working direactory path.

import (
    "os"
    "fmt"
)

func GetCurrentDir() string {
	dir, err := os.Getwd()
	if err != nil {
		fmt.Println(err)
		os.Exit(-1)
	}

	return dir
}

Golang: Get directory size recursively.

import (
    "path/filepath"
    "os"
)

const notRegularFileMode os.FileMode = os.ModeDir | os.ModeSymlink | os.ModeNamedPipe | os.ModeSocket | os.ModeDevice | os.ModeCharDevice | os.ModeIrregular

func GetDirectorySize(path string) (int64, error) {
	var size int64
	err := filepath.Walk(path, func(_ string, info os.FileInfo, err error) error {
		if info != nil && (info.Mode()&notRegularFileMode) == 0 {
			size += info.Size()
		}
		return err
	})
	return size, err
}

Most of the time we will parse JSON data to struct.

type User struct {
    Username string `json:"username"`
    Email string `json:"email"`
}

But if you have JSON data like this, you can not parse that directly to the struct.

{
    "0": {
        "username":"ahmad",
        "email":"ahmad@mail.com",
    },
    "1": {
        "username":"ahmad1",
        "email":"ahmad1@mail.com",
    }
}

So to solve this you can create map to user.

type Response map[string]User

So you can parse it like this.

import (
    "strings"
    "encoding/json"
)

func Parse(data string) {
    dec := json.NewDecoder(strings.NewReader(data))
    var response Response
    dec.Decode(&response)
    response["0"].username // ahmad
    response["1"].username // ahmad1
}

Golang: Convert interface{} to float64.

import (
	"fmt"
	"math"
)

func parseFloat64(unk interface{}) (float64, error) {
	switch i := unk.(type) {
	case float64:
		return i, nil
	case float32:
		return float64(i), nil
	case int64:
		return float64(i), nil
	case int32:
		return float64(i), nil
	case int:
		return float64(i), nil
	case uint64:
		return float64(i), nil
	case uint32:
		return float64(i), nil
	case uint:
		return float64(i), nil
	default:
		return math.NaN(), fmt.Errorf("failed to parse to float")
	}
}

Collect all gorilla mux routes and print to stdout.


import (
	"fmt"
	"log"
	"net/http"
	"strings"

	"github.com/gorilla/mux"
)

func PrintRoute(router *mux.Router) {
	router.Walk(func(route *mux.Route, router *mux.Router, ancestors []*mux.Route) error {
		t, err := route.GetPathTemplate()
		if err != nil {
			log.Println(err)
			return err
		}
		fmt.Println(strings.Repeat("| ", len(ancestors)), t)
		return nil
	})
}

Usage :

func handler(w http.ResponseWriter, r *http.Request) {
	return
}

func main() {
	r := mux.NewRouter()
	r.HandleFunc("/", handler)
	r.HandleFunc("/products", handler)
	r.HandleFunc("/articles", handler)
	r.HandleFunc("/blog", handler)
	r.HandleFunc("/blog/post", handler)
	r.HandleFunc("/blog/post/{slug}", handler)
	r.HandleFunc("/articles/{id}", handler)
	PrintRoute(r)
}

Golang: Read file line by line and return string.

import (
    "os"
    "bufio"
)

func ReadFileToString(filename string) {
	fs, err := os.Open(filename)
	if err != nil {
		log.Fatalf("Failed to open file %s\n", filename)
	}
	defer fs.Close()
	scanner := bufio.NewScanner(fs)
	var data string
	for scanner.Scan() {
		data += scanner.Text() + "\n"
	}
    return data
}

Or if you want to use shorter version.

import (
	"op/ioutil"
	"log"
	"fmt"
)

func main() {
    result, err := ioutil.ReadFile("thermopylae.txt")
	if err != nil {
		log.Fatal(err)
	}

    fmt.Println(string(result))
}

For scaning string word by word.


import (
    "fmt"
    "os"
    "bufio"
)

func main() {
    file, err := os.Open("thermopylae.txt")
    if err != nil {
		fmt.Println(err)
	}

    defer file.Close()

    scanner := bufio.NewScanner(file)
    scanner.Split(bufio.ScanWords)

    for scanner.Scan() {
        fmt.Println(scanner.Text())
    }

    if err := scanner.Err(); err != nil {
        fmt.Println(err)
    }
}

Repeat executes f every interval seconds until stopc is closed. It executes f once right after being called.

import (
	"time"
)

func RepeatExecute(interval time.Duration, stopc <-chan struct{}, f func() error) error {
	tick := time.NewTicker(interval)
	defer tick.Stop()

	for {
		if err := f(); err != nil {
			return err
		}
		select {
		case <-stopc:
			return nil
		case <-tick.C:
		}
	}
}

How to use?

func Run(ctx context.Context, interval time.Duration) error {
	return RepeatExecute(interval, ctx.Done(), func() error {
		 err := someOperation()
		if err != nil {
			return err
		}
		return nil
	})
}

Javascript: Create directory recursively if not exists.

function createFileIfNotExists(dirName) {
    if (!fs.existsSync(dirName)) {
        fs.mkdirSync(dirName, {
            recursive: true,
        });
    }
}

Convert a date to a relative time string, such as "a minute ago", "in 2 hours", "yesterday", "3 months ago", etc.

function getRelativeTimeString(date, lang) {
    const minute = 60;
    const hour = minute * 60;
    const day = hour * 24;
    const week = day * 7;
    const month = day * 30;
    const year = day * 365;

    const time = date instanceof Date ? date.getTime() : date;
    const delta = Math.round((time - Date.now()) / 1000);
    const absoluteDelta = Math.abs(delta);
    const times = [
        [minute, "second", 1],
        [hour, "minute", minute],
        [day, "hour", hour],
        [week, "day", day],
        [month, "week", week],
        [year, "month", month],
        [Infinity, "year", year],
    ];
    
    let divider = year;
    let timeType = "year";
    for (const [num, timeInterval, div] of times) {
        if (absoluteDelta < num) {
            divider = div;
            timeType = timeInterval;
            break;
        }
    }
    const rtf = new Intl.RelativeTimeFormat(lang, { numeric: "auto" });

    return rtf.format(Math.floor(delta / divider), timeType);
}

Usage:

getRelativeTimeString(Date.now() + 1000) // in 1 second
getRelativeTimeString(Date.now() + 100000000) // tomorrow

Next.js: Use this to catch all routes inside sub directory, so don't need to create sub directory for each slashed URL.

File:

pages/blog/[...slug].js

Url will be:

/blog/post
/blog/post/one
/blog/post/two/three.xyz

Code:

export async function getStaticPaths() {
    return {
        paths: [
            { params: { slug: ["post"] } },
            { params: { slug: ["post", "one"] } },
            { params: { slug: ["post", "two", "three.xyz"] } }
        ],
        fallback: false
    };
}

export async function getStaticProps({ params }) {
    const postData = await getDataBySlug(params.slug)
    return {
        props: {
            postData
        }
    }
}

export default function Post({ postData }) {
    return (...)
}

Javascript: Walk directory recursively.

const fs = require("fs");
const path = require("path");

async function* walk(dir) {
    for await (const d of await fs.promises.opendir(dir)) {
        const entry = path.join(dir, d.name);
        if (d.isDirectory()) yield* walk(entry);
        else if (d.isFile()) yield entry;
    }
}

// Then, use it with a simple async for loop
async function main() {
    const dir = "."
    for await (const p of walk(dir))
        console.log(p)
}