Switch from Snap to DEB Firefox on Kubuntu

Steps may change in the future.

  • sudo snap remove firefox

  • Follow https://support.mozilla.org/en-US/kb/install-firefox-linux#w_install-firefox-deb-package-for-debian-based-distributions
    • However, in step 5: onfigure APT to prioritize packages from the Mozilla repository, use the command below:
      echo '
      Package: *
      Pin: origin packages.mozilla.org
      Pin-Priority: 1001
      
      Package: firefox
      Pin: version 1:1snap*
      Pin-Priority: -1
      ' | sudo tee /etc/apt/preferences.d/mozilla-firefox
      
  • sudo apt install firefox

  • To ensure that unattended upgrades do not reinstall the snap version of Firefox:
    echo 'Unattended-Upgrade::Allowed-Origins:: "namespaces/moz-fx-productdelivery-pr-38b5/repositories/mozilla:mozilla";' | sudo tee /etc/apt/apt.conf.d/51unattended-upgrades-firefox
    

Some Minimal API patterns

Minimal API is a fairly new way to implement Web APIs, introduced in .NET 6.
I initially thought it was only suitable for small projects, as its name suggests. Recently, I read some articles and watched videos about how to organize Minimal API projects, and I have changed my mind.
The main reason I believed Minimal API was only for small projects is that most demos are quite small and put all APIs in Program.cs, which is obviously not scalable and somewhat messy.
By using extension methods, it is quite convenient to group APIs into different files, making them much easier to manage.
A third-party library Carter also seems useful in grouping APIs.

Below are some articles and videos I found useful regarding organizing Minimal API applications:
Milan Jovanović’s video
Milan Jovanović’s blog Tess Ferrandez’s article about organizing ASP.NET Core Minimal APIs

Milan uses extension methods for IEndpointRouteBuilder while Tess using WebApplication. I prefer the IEndpointRouteBuilder approach because MS official document says so.

In my previous experience with Spring Boot, I was used to a more MVC style when implementing Web APIs. However, I am glad to see a new way to develop them. I’m not sure if Minimal API is suitable for “large” projects, but it really looks promising to me for many Web API applications.

Some C# notes

  1. Use escape sequences for special signs such as \n. Or use a verbatim statement
    // Escape sequences example
    Console.WriteLine("I need to use escape sequences for special signs such as \\ here.");
    // Verbatim statement example
    Console.WriteLine(
      @"
      My name is ""SilMOON"" and this is a verbatim statement.
      I can use special signs such as \ here.
      "
      );
    

    Noted that C#11 introduced raw string literals which is more convenient. I’m actually suprised that they didn’t add this feature earlier. :)

Server hosting tips

  1. Add non-root user.
    I. # useradd -m USERNAME
    II. # passwd USERNAME
    III. Add your user to the wheel or sudo group:
    • DEB based distros: # usermod -aG sudo USERNAME
    • RPM based distros: # usermod -aG wheel USERNAME
  2. Disable root logins.
    I. # vim /etc/ssh/sshd_config
    II. Set PermitRootLogin=no

  3. Change SSH port

  4. Use non-root user

  5. (Just my preference) Install zsh & oh-my-zsh

  6. Set up SSH keys
    • If no exsisting key, generate one first
    • On local machine: $ ssh-copy-id USERNAME@IP_ADDRESS (If SSH port changed: $ ssh-copy-id -p PORT USERNAME@IP_ADDRESS)
  7. Configure ufw firewall

  8. Install Fail2Ban

  9. (If possible) Use Docker rootless

  10. (From: https://docs.docker.com/engine/install/linux-postinstall/) If using regular Docker, don’t forget:
    • $ sudo groupadd docker
    • $ sudo usermod -aG docker $USER
    • Reboot
  11. (Optional) Disable SMTP port

Some Kotlin notes

  1. Use vararg for variable arguments:
    fun printLetters(vararg letters: String, count: Int): Unit {
     print("$count letters are ")
     for (letter in letters) print(letter)
     println()
    }
    

    Then we can use it by calling:

    printLetters("a", "c", "q", count = 3)
    

    Or use * to pass an array as parameters:

    val argArray = arrayOf("q","e","w")
    printLetters(*argArray, count = 3)
    

Check the usage of ports in Linux

We can use the netstat -anp command to check active connections and port usage.

-a shows all active connections.

-n shows applications an port number in numbers.

-p lists processes(pid) which occupied the port. And we can simply kill them using the pid if we need.

Some Java notes

  1. The this keyword has two meanings: to refer a field of the implicit parameter and to call another defined constructor in the same class. The super keyword also has two meanings: to call a superclass constructor and call a superclass method. Like using this keyword to call a constructor, the constructor call must be the first statement in the new constructor. In the following example, Manager is the subclass of Employee, the Employee class which is hidden for simplicity does not have the field bonus:
    public Manager(String name, double salary, int year, int month, int day)
    {
     super(name, salary, year, month, day); //is the same as Employee(name, salary, year, month, day)
     bonus = 0;
    }
    

    Likewise, the this keyword can be used in a similar way.

Fix DNS resolution issue for my domain

Yesterday I found that my domain name for my Mastodon instance couldn’t be resolved. So I check my Whois information on ICANN Lookup and found that my status became “serverHold”. Generally this code means your domain name potentially have risks of spam or other illegal matters, but I only use this domain for my small Mastodon instance and the email service it runs is simply for sending verification email to new users. But I still had to email to the registry of my domain and when they reactivate my domain name, I was told that my domain was also blacklisted by another anti-spam organization. As a result, I had to contact that organization in order to get my domain out of their blacklist. I was told that the reason I was blacklisted is that I ran an outgoing email service without setting verified rDNS. To solve this problem, I firstly set rDNS of my server, this step is quite easy thanks to Vultr’s easy to use interface. Next I need to apply for a delist key from their delist tool. In order to get the key, the anti-spam website need a postmaster email address with my domain name, so I create it using the email-forwarding tool provided by my domain name provider. And then I simply get the key and get my domain out of the blacklist successfully.

Some Rust notes II

  1. A simple example of the syntax of specifying generic type parameters, trait bounds, and lifetimes:
    use std::fmt::Display;
    fn longest_with_an_announcement<'a, T>(x: &'a str, y: &'a str, ann: T) -> &'a str
     where T: Display
    {
     println!("Announcement! {}", ann);
     if x.len() > y.len() {
         x
     } else {
         y
     }
    }
    
  2. We can put expected panic information in the expected parameter of #[should_panic]:
    #[should_panic(expected = "Guess value must be less than or equal to 100")]
    
  3. FnOnce consumes the variables it captures from the closure’s environment. To consume the captured variables, the closure must take ownership of these variables and move them into the closure when it is defined. The Once part of the name represents the fact that the closure can’t take ownership of the same variables more than once, so it can be called only once. FnMut can change the environment because it mutably borrows values. Fn borrows values from the environment immutably.
  4. An example of using a closure function as a element in a struct:
    struct Cacher<T>
     where T: Fn(u32) -> u32 
    {
     calculation: T,
     value: HashMap<u32, u32>,
    }
    impl<T> Cacher<T>
     where T: Fn(u32) -> u32 
    {
     fn new(calculation: T) -> Cacher<T> {
         Cacher {
             calculation,
             value: HashMap::new(),
         }
     }
     fn value(&mut self, arg: u32) -> u32 {
         match self.value.get(&arg) {
             Some(v)     => *v,
             None        => {
                 let v = (self.calculation)(arg);
                 self.value.insert(arg, v);
                 v
             }
         }
     }
    }
    
  5. Using sum method for iterator will take ownership so that if this statement is called:
    let v1 = vec![1, 2, 3];
    let v1_iter = v1.iter();
    let total: i32 = v1_iter.sum();
    

    we cannot use v1_iter after the call because of the reason stated above.

  6. The default value for the opt-level setting for the dev profile is 0 and the one for the release profile is 3. Add these two lines in Cargo.toml will override the default optimization level for dev profile:
    [profile.dev]
    opt-level = 1
    
  7. A cons list example written using Box<T>:
    enum List {
     Cons(i32, Box<List>),
     Nil,
    }
    use self::List::{Cons, Nil};
    fn main() {
     let test = Cons(1, 
                     Box::new(Cons(2,
                     Box::new(Cons(3, 
                     Box::new(Nil))))));
    }
    
  8. An example of creating a simple smart pointer implementing Deref and Drop traits:
    struct MyBox<T>(T);
    impl<T> MyBox<T> {
     fn new(x: T) -> MyBox<T> {
         MyBox(x)
     }
    }
    impl<T> Deref for MyBox<T> {
     type Target = T;
     fn deref(&self) -> &T {
         &self.0
     }
    }
    impl<T> Drop for MyBox<T> {
     fn drop(&mut self) {
         println!("Dropping MyBox!");
     }
    }
    
  9. Comparing with regular reference, with Rc we can create things with shared ownership and do not need to specify lifetime parameters.
  10. An example of combination of Rc and RefCell:
    use std::rc::Rc;
    use std::cell::RefCell;
    #[derive(Debug)]
    enum List {
    Cons(Rc<RefCell<i32>>, Rc<List>),
    Nil,
    }
    use crate::List::{Cons, Nil};
    fn main() {
    let value = Rc::new(RefCell::new(5));
    let a = Rc::new(Cons(Rc::clone(&value), Rc::new(Nil)));
    let b = Cons(Rc::new(RefCell::new(6)), Rc::clone(&a));
    let c = Cons(Rc::new(RefCell::new(12)), Rc::clone(&a));
    *value.borrow_mut() += 10;
    println!("{:?}\n{:?}\n{:?}\n", a, b, c);
    }
    
  11. By using Rc<T> and RefCell<T>, it’s possible to create reference cycles which creates memory leaks because the reference count of each item in the cycle will never reach 0, and the values will never be dropped.
  12. An example of using Weak<T> to avoid reference cycle and create a simple node structure: ```rust struct Node { value: i32, parent: RefCell<Weak>, children: RefCell<Vec<Rc>>, } fn main() { let root = Rc::new(Node { value: 0, parent: RefCell::new(Weak::new()), children: RefCell::new(vec![]), });

Comment system is added now

Just added a comment system using Utterances. Welcome to leave your thoughts about my blogs!