BLACK CAT PROGRAMMER

python Comparison

python 提供很多的比較的方便,其中大家可能較常用 == 和 is,這個post 就講講他們的分別

is 是比較 variable 的pointer address

== 是比較 variable 的 value

簡單例子:

>>> p1 = { "name": "tom", "age": 11}
>>> p2 = { "name": "tom", "age": 11}
>>> p1 == p2
True
>>> p1 is p2
False
>>> hex(id(p1))
'0x104fdc800'
>>> hex(id(p2))
'0x104fdc840'

以上的例子都很簡單,因為 p1 同 p2 實際在memory 裡是兩個不同的 object ,不過他們有著一樣的 value,所以用 == 去比較時,會得到 True,而用 is 去比較時,會得到 False 。

我們再考慮以下的例子

>>> a = 256
>>> b = 256
>>> c = 257
>>> d = 257

>>> a == b
True
>>> c == d
True

>>> a is b
True
>>> c is d
False

為什麽 a 和 b 可以用 == 和 is 去比較,但 c 和 d 就不可以?

原來當 python 一開始是會把一常用的數值 load 入 memory ,這些數值包括 True, False, -256 to +256 ,所以他們有一樣的 memory address ,而大過256 的值,python 就會即時 allocate 新的 address

>>> hex(id(a))
'0x105b100d8'
>>> hex(id(b))
'0x105b100d8'

>>> hex(id(c))
'0x104fdffb0'
>>> hex(id(d))
'0x105047030'

所以 a b 是有一樣的 address ,而 c d 的 address 是不同

True False 在 python 世界裡都是一個 obj,他們都有各自的address,所以python 的 True 和 False 是大楷 T 和 F

>>> hex(id(True))
'0x105ad8b48'

>>> hex(id(False))
'0x105ad8b68'

Posted in notes, pythonTagged

MacBook Home and End button not work

M1 MacBook 不再支援external keyboard 的home 同end 鍵,但可以用以下方法自己改返

  1. 開啟 terminal
  2. 輸入以下command
    mkdir -p ~/Library/KeyBindings
  3. 用vim 開個新file
    vim ~/Library/KeyBindings/DefaultKeyBinding.dict
  4. paste 返下面的setting 入去
{
/* Remap Home / End keys */
/* Home Button*/
"\UF729" = "moveToBeginningOfLine:"; 
/* End Button */
"\UF72B" = "moveToEndOfLine:"; 
/* Shift + Home Button */
"$\UF729" = "moveToBeginningOfLineAndModifySelection:"; 
/* Shift + End Button */
"$\UF72B" = "moveToEndOfLineAndModifySelection:"; 
/* Ctrl + Home Button */
"^\UF729" = "moveToBeginningOfDocument:"; 
/* Ctrl + End Button */
"^\UF72B" = "moveToEndOfDocument:"; 
 /* Shift + Ctrl + Home Button */
"$^\UF729" = "moveToBeginningOfDocumentAndModifySelection:";
/* Shift + Ctrl + End Button*/
"$^\UF72B" = "moveToEndOfDocumentAndModifySelection:"; 
}

最後記得 save and exit 就完,再reboot 一次就可以了

refer: https://github.com/ttscoff/KeyBindings/blob/master/DefaultKeyBinding.dict

Posted in macbook, notesTagged ,
Install Tomcat 9 on Ubuntu 18.04

Apache Tomcat is an open-source implementation of the Java Servlet, JavaServer Pages, Java Expression Language, and Java WebSocket technologies. It is one of the most widely adopted application and web servers in the world today. Tomcat is simple to use and has a robust ecosystem of add-ons.

This tutorial explains how to install and configure Tomcat 9 on Ubuntu 18.04. The same instructions apply for Ubuntu 16.04 and any Ubuntu-based distribution, including Linux Mint and Elementary OS.

Prerequisites

To be able to install packages on your Ubuntu system, you must be logged in as a user with sudo privileges .

Step 1: Install OpenJDK

Tomcat requires Java to be installed. We’ll install OpenJDK , which is the default Java development and runtime in Ubuntu 18.04.

The installation of Java is pretty simple. Begin by updating the package index:

sudo apt update

Install the OpenJDK package by running:

sudo apt install default-jdk

Step 2: Create Tomcat User

For security purposes, Tomcat should not be run under the root user. We will create a new system user and group with home directory /opt/tomcat that will run the Tomcat service:

sudo useradd -r -m -U -d /opt/tomcat -s /bin/false tomcat

Step 3: Install Tomcat

We will download the latest binary release of Tomcat 9 from the Tomcat 9 downloads page .

At the time of writing, the latest version is 9.0.27. Before continuing with the next step, you should check the download page for a new version. If there is a new version, copy the link to the Core tar.gz file, which is under the Binary Distributions section.

Start by download the Tomcat archive in the /tmp directory using the following wget command:

wget http://www-eu.apache.org/dist/tomcat/tomcat-9/v9.0.27/bin/apache-tomcat-9.0.27.tar.gz -P /tmp

Once the download is complete, extract the Tomcat archive and move it to the /opt/tomcat directory:

sudo tar xf /tmp/apache-tomcat-9*.tar.gz -C /opt/tomcat

To have more control over Tomcat versions and updates, create a symbolic link called latest that points to the Tomcat installation directory:

sudo ln -s /opt/tomcat/apache-tomcat-9.0.27 /opt/tomcat/latest

Later if you want to upgrade your Tomcat instance, simply unpack the newer version and change the symlink to point to the latest version.

As we mentioned in the previous section Tomcat will run under the tomcat user. This user needs to have access to the tomcat installation directory.

The following command changes the directory ownership to user and group tomcat:

sudo chown -RH tomcat: /opt/tomcat/latest

The scripts inside bin directory must have executable flag :

sudo sh -c 'chmod +x /opt/tomcat/latest/bin/*.sh'

Step 4: Create a systemd Unit File

To run Tomcat as a service you need to create a new unit file.

Open your text editor and create a file named tomcat.service in the /etc/systemd/system/:

sudo nano /etc/systemd/system/tomcat.service

Paste the following configuration:

/etc/systemd/system/tomcat.service

[Unit]
Description=Tomcat 9 servlet container
After=network.target

[Service]
Type=forking

User=tomcat
Group=tomcat

Environment="JAVA_HOME=/usr/lib/jvm/default-java"
Environment="JAVA_OPTS=-Djava.security.egd=file:///dev/urandom -Djava.awt.headless=true"

Environment="CATALINA_BASE=/opt/tomcat/latest"
Environment="CATALINA_HOME=/opt/tomcat/latest"
Environment="CATALINA_PID=/opt/tomcat/latest/temp/tomcat.pid"
Environment="CATALINA_OPTS=-Xms512M -Xmx1024M -server -XX:+UseParallelGC"

ExecStart=/opt/tomcat/latest/bin/startup.sh
ExecStop=/opt/tomcat/latest/bin/shutdown.sh

[Install]
WantedBy=multi-user.target

CopyModify the value of JAVA_HOME if the path to your Java installation is different.

Save and close the file and notify systemd that we created a new unit file:

sudo systemctl daemon-reload

Start the Tomcat service by executing:

sudo systemctl start tomcat

Check the service status with the following command:

sudo systemctl status tomcat
* tomcat.service - Tomcat 9 servlet container
   Loaded: loaded (/etc/systemd/system/tomcat.service; disabled; vendor preset: enabled)
   Active: active (running) since Wed 2018-09-05 15:45:28 PDT; 20s ago
  Process: 1582 ExecStart=/opt/tomcat/latest/bin/startup.sh (code=exited, status=0/SUCCESS)
 Main PID: 1604 (java)
    Tasks: 47 (limit: 2319)
   CGroup: /system.slice/tomcat.service

If there are no errors enable the Tomcat service to be automatically started at boot time:

sudo systemctl enable tomcat

Step 5: Adjust the Firewall

If your server is protected by a firewall and you want to access Tomcat from the outside of your local network, you need to open port 8080.

To allow traffic on port 8080 type the following command:

sudo ufw allow 8080/tcp

Usually when running a Tomcat application in a production environment you will have a load balancer or reverse proxy . It’s a best practice to restrict access to port 8080 only to your internal network.

Step 6: Configure Tomcat Web Management Interface

Now that Tomcat is installed and running, the next step is to create a user with access the web management interface.

Tomcat users and roles are defined in the tomcat-users.xml file. This file is a template with comments and examples describing how to configure user or role.

sudo nano /opt/tomcat/latest/conf/tomcat-users.xml

To add a new user with access to the Tomcat web interface (manager-gui and admin-gui) we need to define the user in the tomcat-users.xml file, as shown below. Make sure you change the username and password to something more secure:/opt/tomcat/latest/conf/tomcat-users.xml

<tomcat-users>
<!--
    Comments
-->
   <role rolename="admin-gui"/>
   <role rolename="manager-gui"/>
   <user username="admin" password="admin_password" roles="admin-gui,manager-gui"/>
</tomcat-users>

Copy

By default Tomcat web management interface is configured to restrict access to the Manager and Host Manager apps only from the localhost.

If you want to be able to access the web interface from a remote IP, you will have to remove these restrictions. This may have various security implications, and it is not recommended for production systems.

To enable access to the web interface from anywhere open the following two files and comment or remove the lines highlighted in yellow.

For the Manager app, open the following file:

sudo nano /opt/tomcat/latest/webapps/manager/META-INF/context.xml

For the Host Manager app, open the following file:

sudo nano /opt/tomcat/latest/webapps/host-manager/META-INF/context.xml

context.xml

<Context antiResourceLocking="false" privileged="true" >
<!--
  <Valve className="org.apache.catalina.valves.RemoteAddrValve"
         allow="127\.\d+\.\d+\.\d+|::1|0:0:0:0:0:0:0:1" />
-->
</Context>

Copy

Another option is to allow access to the to the Manager and Host Manager apps only from a specific IP. Instead of commenting the blocks you can simply add your IP address to the list.

For example if your public IP is 45.45.45.45 you would make the following change:context.xml

<Context antiResourceLocking="false" privileged="true" >
  <Valve className="org.apache.catalina.valves.RemoteAddrValve"
         allow="127\.\d+\.\d+\.\d+|::1|0:0:0:0:0:0:0:1|45.45.45.45" />
</Context>

Copy

The list of allowed IP addresses is a list separated with vertical bar |. You can add single IP addresses or use a regular expressions.

Remember to restart the Tomcat service each time you edit Tomcat configuration files for changes to take effect:

sudo systemctl restart tomcat

Step 6: Test the Tomcat Installation

Open your browser and type: http://<your_domain_or_IP_address>:8080

Assuming the installation is successful, a screen similar to the following should appear:

Tomcat 8.5

Tomcat web application manager dashboard is available at http://<your_domain_or_IP_address>:8080/manager/html. From here, you can deploy, undeploy, start, stop, and reload your applications.

You can sign in with the user you have created in Step 6.

Tomcat web application manager

Tomcat virtual host manager dashboard is available at http://<your_domain_or_IP_address>:8080/host-manager/html. From here, you can create, delete and manage Tomcat virtual hosts.

Tomcat virtual host manager

Conclusion

You have successfully installed Tomcat 9 on your Ubuntu 18.04 system. You can now visit the official Apache Tomcat 9 Documentation and learn more about the Apache Tomcat features.

Refer: https://linuxize.com/post/how-to-install-tomcat-9-on-ubuntu-18-04/

Posted in notes

python virtual environment

成日都忘記virtual environment 的用法,所以記下來,不用每一次都去睇doc

每一個project 所需的 library 的版本的要求都不同,virtual environment 就是替每一個project 開一個environment,而家每個environment 都可以有自己的所要的library。

實際操作亦很簡單,

去創造一個新的environment,我自己個人就喜歡將新的environment 叫venv 放在project 的root folder。記住要將.venv 放到git ignore 的file 裡。

python -m venv ./venv

使用剛剛新創建的virtual environment

# On Windows, run:

.venv\Scripts\activate.bat

# On Unix or MacOS, run:

source .venv/bin/activate

然後 python xxx.py 就可以使用新的environment,如果要安裝新的library,可以用pip 正常咁安裝

# list current install packages
pip list

# install packages with requirements.txt
pip install -r requirements.txt

離開virtural environment

# On Windows, run:

.venv\Scripts\deactivate.bat

# On Unix or MacOS, run:

source .venv/bin/deactivate

Posted in notesTagged ,

Virtualbox ubuntu copy and paste problem

Virtualbox ubuntu copy and paste problem
Oracle’s VirtualBox allows you copy and paste from the host machine to the guest virtual machine and vice versa. Unfortunately, this feature sometimes does not work properly.

Firstly, be sure you have install the Guest Addition

If it still does not work, you may restart the vboxclient by following commands in terminal

sudo killall BVBoxClient
sudo VBoxClient-all

Posted in notesTagged

Connecting to OpenSwan VPN in Windows

Environment

A ipsec VPN was setup in a raspberry pi with OpenSwan.

Steps

Adding Server CA Certificate

  1. Download the server CA
  2. Import the server CA
    Start -> run -> enter “mmc”
  3. Add new snap
  4. Select Certificate on left menu and then click the Add button on the middle
  5. Select computer account**
    1. The popup may not appear and the cert will be imported to current user by default. The cert must be imported to local computer
    2. to do so. Start -> enter cmd
    3. Run the cmd with administrator
    4. enter certlm.msc
    5. go to step 8
  6. Select Local computer, them click finish button
  7. After clicking finish button, the popup window will be closed
  8. Back mmc Console window, there will be a new item Certificates on left menu
  9. Unfold Certificates -> Trusted Root Certification Authorities
  10. Right click on Certificates and click on All Tasks -> Import …
  11. A new window will be popped up. Select Local Machine if required
  12. Select the CA certificate just downloaded
  13. Once the CA certificate is added, it will appear under Trusted Root Certification Authorities
  14. Close mmc window without save
  15. Done

Adding VPN

  1. Open VPN setting by entering “vpn settings” start
  2. Click on “Add a VPN connection”
  3. Enter the form

    – Connection name is the name for you to identify the VPN
    – Server name or address: enter the domain or IP of the VPN server
    – VPN type: select IKEv2
    – Type of sign-in info: Select the appropriate sign in info
    – User name: VPN account name
    – Password: VPN account password
  4. Then back to VPN setting windows, click on “Change adapter options”
  5. On the new window, right click on the newly created VPN icon. Then click on “Properties”
  6. On security tab, config as following
  7. The other settings can be kept untouched
  8. Click Ok to close the window
  9. Done

Connect to VPN

  1. On VPN settings page, select the VPN
  2. Click on the Connect button

Common problems

parameter is incorrect

Solution: Reset and clear networking caches
Run windows cmd window (click windows start menu, type ‘cmd’, right click on ‘Command Prompt’ and select “Run as Administrator”).

type command below
netsh int ip reset
netsh int ipv6 reset
netsh winsock reset

Restart your computer.

Reset Device Manager adaptors
1. Open Device Manager
2. Find Network Adapters
3. Uninstall WAN Miniport drivers (IKEv2, IP, IPv6, etc)
4. Click Action > Scan for hardware changes
5. The adapters you just uninstalled should come back

Posted in notes, vpnTagged , ,

Tortoise and Hare

'''

This implements simple tortoise and hare algorithm which is a cycle detection algorithm

input:
number of nodes
<source node id> <destination ndoe id>
<source node id> <destination ndoe id>
...


'''

import sys

class Node:
  def __init__(self, pos):
    self.cur_pos = pos
    self.next_node = None

def find_cyclic(start_node):
  tortoise = start_node
  hare = start_node
  while tortoise.next_node and hare.next_node.next_node:
    tortoise = tortoise.next_node
    hare = hare.next_node.next_node

    if tortoise.cur_pos == hare.cur_pos:
      tortoise = start_node
      while tortoise.cur_pos != hare.cur_pos:
        tortoise = tortoise.next_node
        hare = hare.next_node

      return tortoise
  return False

node_count = int(input())
node_list = [Node(i) for i in range(node_count)]

for _ in range(node_count):
  line = input()
  line_arr = line.strip().split(" ")
  src = int(line_arr[0])
  dest = int(line_arr[1])
  node_list[src].next_node = node_list[dest]


# debug
node = node_list[0]
print("{} -> {}".format(node.cur_pos, node.next_node.cur_pos))
count = 0
while node.next_node and count < len(line):
  node = node.next_node
  print("{} -> {}".format(node.cur_pos, node.next_node.cur_pos))
  count+=1
  
meetup = find_cyclic(node_list[0])
print("meet up: {}".format(meetup.cur_pos))
          

Ref: https://medium.com/@tuvo1106/the-tortoise-and-the-hare-floyds-algorithm-87badf5f7d41

Posted in coding, notes

Angular safe

Angular adds the word unsafe in front of an iOS app download link. ie the link turns from itms-services://?action=download-manifest&url=https://…manifest.plist into unsafe:itms-services://?action=download-manifest&url=https://...manifest.plist

As a result, the download link does not work. To solve it, we have to use DomSanitizer either in html or in .ts

<a [attr.href]="{{ linkVariable | safe: 'resourceUrl' }}">click me</a>

Be reminded to user attr.href instead of href=..., using href will throw a warning WARNING: sanitizing unsafe URL value SafeValue must use [property]=binding: itms-services://?action=download....

safe.pip.ts

import { Pipe, PipeTransform } from '@angular/core';
import { DomSanitizer, SafeHtml, SafeStyle, SafeScript, SafeUrl, SafeResourceUrl } from '@angular/platform-browser';

@Pipe({
  name: 'safe'
})
export class SafePipe implements PipeTransform {

  constructor(protected sanitizer: DomSanitizer) {}
 
 public transform(value: any, type: string): SafeHtml | SafeStyle | SafeScript | SafeUrl | SafeResourceUrl {
    switch (type) {
      case 'html': return this.sanitizer.bypassSecurityTrustHtml(value);
      case 'style': return this.sanitizer.bypassSecurityTrustStyle(value);
      case 'script': return this.sanitizer.bypassSecurityTrustScript(value);
      case 'url': return this.sanitizer.bypassSecurityTrustUrl(value);
      case 'resourceUrl': return this.sanitizer.bypassSecurityTrustResourceUrl(value);
      default: throw new Error(`Invalid safe type specified: ${type}`);
    }
  }
}

Ref: https://angular.io/api/platform-browser/DomSanitizer

Posted in notesTagged , ,

Google Sheet script

因為疫情,同事都係一齊訂外賣,之後係公司食,之前大家都係用Whatsapp group 到send 出黎,但成日出事,互overwrite 大家d 野。

所以之前有同事就google sheet 去入data,但我今日竟然無聊到去整靚佢…

有好多無聊functionsssss,睇黎我真係悶到傻了。

function sheetName() {
  return SpreadsheetApp.getActiveSpreadsheet().getActiveSheet().getName();
}

// update the title
function onOpen() {
  setTitle();
}

// reload the whatsapp message when any cell was updated
function onEdit(e) {
  var outputRange = SpreadsheetApp.getActiveSpreadsheet().getRange('B21');
  outputRange.setValue(generateWhatsappMsg('A3:D17', 'B21'));
}

function setTitle() {
  var titleRange = SpreadsheetApp.getActiveSpreadsheet().getRange('A1');
  var date = Utilities.formatDate(new Date(), "GMT+8:00", "yyyyMMdd");
  titleRange.setValue("今日終於食日本野 " + date);
}

function generateNewSheet() {
  var date = Utilities.formatDate(new Date(), "GMT+8:00", "yyyyMMdd");
  var todaySheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(date);
  if (!todaySheet) {
    SpreadsheetApp.getActiveSpreadsheet().duplicateActiveSheet();
    SpreadsheetApp.getActiveSpreadsheet().renameActiveSheet(date);
    todaySheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(date);  
  } 
  SpreadsheetApp.setActiveSheet(todaySheet);
  setTitle();
}

function generateWhatsappMsg(range, outRange) {
  var inputRange = SpreadsheetApp.getActiveSpreadsheet().getRange(range);
  var rangeValues = inputRange.getValues();
  var lastRow = inputRange.getLastRow() - 3;
  var tel = SpreadsheetApp.getActiveSpreadsheet().getRange('B19').getValue();
  var msg = '送餐地點:XXXX\n送餐時間:12:00\n電話:'+tel+'\n\n';
  var errorMsg = '';
  var foodDict = {}; // key: set (sideDish); val: order count
  var drinkDict = {}; // key: drinkId; val: order count
  
  for ( i = 0; i < lastRow; i++){
    let name = rangeValues[i][0];
    let set = rangeValues[i][1];
    let sideDish = rangeValues[i][2];
    let drink = rangeValues[i][3];

    if (set) {
      var foodKey = sideDish? set + '(' + sideDish + ')': set;
      if (foodKey in foodDict) {
        foodDict[foodKey] = foodDict[foodKey] + 1;
      } else {
        foodDict[foodKey] = 1;
      }
      if (!drink) {
        errorMsg += name + ' 未選揀飲品\n';
      }
    }
    if (drink) { // if selected drink
      if (drink in drinkDict) {
        drinkDict[drink] = drinkDict[drink] + 1;
      } else {
        drinkDict[drink] = 1;
      }
      if (!set) {
        errorMsg += name + ' 未選揀飯餐\n';
      }
    }
  };
  
  // no one eat :(
  if (Object.keys(foodDict).length == 0) {
    errorMsg = "今日無人食 :(";
  }
  
  // looped all people, now generate the message
  for ( var foodKey in foodDict) {
    msg += foodKey + ": " + foodDict[foodKey] + "\n";
  }
  msg += '\n';
  for ( var drinkKey in drinkDict) {
    msg += drinkKey + ": " + drinkDict[drinkKey] + "\n";
  }
  
  msg += '\n唔要餐具/糖,謝謝';
  
  if (errorMsg.length>0) {
    SpreadsheetApp.getActiveSpreadsheet().getRange(outRange).setBackground('#E6B8AF');
    return errorMsg;
  } else {
    SpreadsheetApp.getActiveSpreadsheet().getRange(outRange).setBackground('white');
    return msg;
  }
}

Posted in UncategorizedTagged

Ubuntu disable ctrl+alt+e

iBus binds ctrl + alt + e to enter emoji, but it is quite annoying actually. I did not enter emoji on Ubuntu. More importantly, it collides with the vscode shortcut.

So, how to disable it.

Method 1

In terminal type ibus-setup, go to the emoji tab, and delete the keybindings.

But for some reason, it may not work in VSCode.


https://github.com/Microsoft/vscode/issues/48480

Method 2

  1. Open terminal
  2. enter
    gsettings set org.freedesktop.ibus.panel.emoji hotkey []
  3. Done
Posted in notesTagged ,