文章加密

;

2023年12月13日 星期三

Front-end Security

網站應用程式常見弱點解析
https://www.tyrc.edu.tw/data/teach/lecture/%E7%B6%B2%E7%AB%99%E6%87%89%E7%94%A8%E7%A8%8B%E5%BC%8F%E5%B8%B8%E8%A6%8B%E5%BC%B1%E9%BB%9E%E8%A7%A3%E6%9E%90.pdf


Front-end Security that Front-end developers don't know:
https://speakerdeck.com/aszx87410/front-end-security-that-front-end-developers-dont-know?slide=22
https://hackmd.io/@ouob/S1U-2_7y2?utm_source=preview-mode&utm_medium=rec


tool:
https://csp-evaluator.withgoogle.com/

2023年9月27日 星期三

chatgpt學習

aiprm

glasp

stability.ai

D-ID :  圖片ai播報

eleven lab: 念文稿的ai 可以抓別人的聲音去套用

futurepedia: the largest ai tool directory, updated daily


chatGPT: 2021前以前的資訊,有紀錄功能

Microsoft Bing: 可聯網同步,資料溯源(即提供參考來源)

Edge: 可聯網同步,資料溯源(即提供參考來源),可以閱讀pdf


2023年9月5日 星期二

2023年8月24日 星期四

版權 - 軟體授權條款

 

  • 著名的軟體授權條款有:GPL、LGPL、BSD、MIT、Apache

https://ithelp.ithome.com.tw/articles/10243402

2023年8月23日 星期三

2023年5月5日 星期五

tree shaking, webhook, restful api, aria-live: polite

1. 

tree shaking: 簡單說即"移除無用的程式" https://medium.com/starbugs/%E7%B2%BE%E6%BA%96%E7%9A%84%E6%89%93%E5%8C%85-webpack-%E7%9A%84-tree-shaking-ad39e185f284


2.

webhook:

https://pipedream.com/docs/api/rest/webhooks/#send-events-from-an-existing-event-source-to-a-webhook


3.

restful api: https://ithelp.ithome.com.tw/articles/10230223


4.

aria-live: polite

https://lepture.com/zh/2017/fe-live-regions


5.  Can JavaScript Object Keys Have Spaces? and what about hyphen case(also called kebab case or kebab-case)  and underscores (also called snake case or snake_case)?

const a = { "hi everyone":  "hello" };

const b = { "hi-everyone":  "hello" };

const c = { "hi_everyone":  "hello" };

console.log(a["hi everyone"]); // hello

console.log(b["hi-everyone"]); // hello

console.log(c.hi_everyone); // hello

html 練習題

 https://www.w3schools.com/html/exercise.asp?filename=exercise_html_formatting1

2023年5月4日 星期四

程式註解轉文件輸出

 http://wen00072.github.io/blog/2015/08/30/zhu-jie-zhong-shi-yong-javadoc-tag/

期貨???

 https://winsmart.tw/trading_knowledge/%E6%9C%9F%E8%B2%A8%E6%98%AF%E4%BB%80%E9%BA%BC/

2023年4月18日 星期二

vue3學習筆記

 快速學習課程: https://www.youtube.com/watch?v=rNQIA0Fe9KQ&list=PLbOfcOk7bN42Kzp1wQsoLuU0vPUmFBe-X



第一課:

vue-cli > create-vue

vscode擴充工具vetur > volar

vuex > pinia


vue3完全不支援ie


1. composation api寫法 > 推薦 (不用this去取得其他datas, methods)

2. options api 寫法 > 相對來說較像vue2,適合原vue2升vue3但有時程壓力時使用(要this)

不建議混合使用!



vue3底層是vite




第二課: 熟悉寫法

destory(){} > onUnmounted(()=>{})

將一個ref賦予到reactive的值裡,ref會自動被解包


<script setup>

import { computed } from "@vue/reactivity";

import {ref, onMounted, onUnmounted, watch} from "vue";

import { useRouter } from "vue-router";

const router = useRouter();

conat count = ref(1);

const name = ref("mike");  // ref()才會響應在畫面,其中可放任何型別的資料,不能用watch監控其children data的改變(除非加上深度監聽的參數)

const data = reactive({  // reactive也會響應在畫面,只能用object, array型別,能用watch監控其children data的改變

  name: David

})

const plusOne = computed({

  get:() =>{

     return count.value; // 取ref的值需要.value

  },

  set:(val)=>{ 

     count.value = val;

  },

})

console.log(plusOne.value) // 1

plusOne.value = 5;

console.log(plusOne.value) // 5

console.log(count.value) // 5 (computed裡改的ref也會一起改)

const changeName = () => {

  name.value = "Jason"

}


onMounted(()=>{

})

</script>


第三課: defneProps, defineEmits

parent component:

<script setup>  // setup語法糖讓我們不用寫export default 和 return

import Children from "./xxx";

import {ref } from "vue";

const resInt = ref(0)

const callBack = (res)=> {

  resInt.value = res

}

const callBack2 = (res)=> {

  console.log(res)

}

</script>


<vImg

  alt="Vue logo"

  className="logo"

  src="xxxx"

  width="125"

  height="125"

/>

<Children @AddInt="callback" @returnName="callback2" />


children component:


<script setup>

const props = defneProps(["alt", "className", "src", "width", "height"]);

const props2 = definedProps({

  alt: {

    type: String,

    default "Img alt"

  }

  obj: {

    type: Object,

    default: () => ({})  // 官方說定義object時會希望用函式回傳的方式定義一個乾淨的obj, 這個語法糖等同()=>({return ...})

  },

  arr: {

    type:Array,

    default: () => []

  },

  testFn: {

    type: Function, // 直接把func傳下來,one way data flow

    default: () => {}

  },

}

const emit = defineEmits(["AddInt"]);

const emit2 = defineEmits({

returnName:(payload) => {

if(payload === "mike") {

  return true;

} else {

  return false

}

}

});

const handleAddClick = (a, b) => {

  emit("AddInt", a + b);

  emit("returnName", "mike");

}


</script>

<template>

<img

  :alt="props.alt"

  :className="props.className"

  :src="props.src"

  :width="props.width"

  :height="props.height"

/>

<button @click="handleAddClick(3,4)" />

</template>



第四課:

listen to change event表示輸入框還在focus狀態時但有改變就還沒觸發change

listen to input event表示輸入框還在focus狀態時但有改變就已觸發input

v-model.lazy是change行為


v-model is used on customedComponent, customedComponent內部接收如下

<script setup>

defineProps(['modelValue']) // children component固定接收到的參數名

defineEmits(['update:modelValue'])

</script>


<template>

  <input

    :value="modelValue"

    @input="$emit('update:modelValue', $event.target.value)"

  />

</template>



第五課:composables

1.

// composables folder > useWindowPosition.js  (像以前的mixins)

import { ref, onMounted, onUnmounted } from 'vue'

export function useWindowPosition() { // 建議跟檔名相同名稱

  const x = ref(0)

  const y = ref(0)


  const movePosition = (event) => {

    x.value = event.pageX

    y.value = event.pageY

  })


  onMounted(() => {

window.addEventListener("mousemove", movePosition)

  })

  onUnmounted(() => {

window.removeEventListener("mousemove", movePosition)

  })


  return { x, y }

}



// 欲使用的vue檔裡如下寫入

import { useWindowPosition } from "./composables/useWindowPosition.js";

const {x, y} = useWindowPosition();

console.log(x, y)




2.

// composables folder > useSetData.js

import {ref, readonly} from "vue";

export function useSetData(val) {

  const x = ref(val);


  const setData = (a) => {

data.value = a;

  }


  return {

    data: readonly(data),

    setData  // 這種作法讓想修改data的一定要使用setData,規範較統一

  }

}



3. 此方式也可用來拆出fetch api



第六課:pinia

// store/counter.js (mutation沒有了)

import { defineStore } from 'pinia'

import { ref } from "vue

// 以下是類似composition api的寫法

export const useCounterStore = defineStore("counter", ()=>{

  const counter = ref(0);  // state


  const doubleCount = computed(() => { // getter

    return counter.value * 2;

  }


  const addCount = () => { // action

    counter.value++;

  }

  

  return {

counter, doubleCount, addCount

  }

})


// 以下是類似options api的寫法,相對來說不推

export const useCounterStore = defineStore({

  id:"counter", // 每個store都需要給id

  state: () => ({

counter: 0

  }),

  getters: {

doubleCount: (state) => state.counter * 2

  },

  actions: {

    addCount() {

      this.counter++;

    },

  },

})


// App.vue

<script setup>

import { useCounterStore } from "./store/counter.js";

const store = useCounterStore();

const clickAdd = () => {

  store.addCount();

}

<script>

<template>

<h1>{{ store.counter }}</h1>

<button @click="clickAdd">click</button>

</template>



或是想解構寫的簡潔則如下

<script setup>

import { storeToRefs } from "pinia";

import { useCounterStore } from "./store/counter.js";

const store = useCounterStore();

const { addCount } = store; // 解構,不能用在資料如state, getter

const { counter, doubleCount } = storeToRefs(store); // 用在資料如state, getter

const clickAdd = () => {

  addCount();

}


watch(doubleCount, (newVal, oldVal) => { // 如果要深度watch要加上deep

console.log(newVal);

console.log(oldVal);

})

store.$subscribe((mutation, state) => { // .$subscribe直接就是深度watch

  // import { MutationType } from 'pinia'

  mutation.type // 'direct' | 'patch object' | 'patch function'

  // same as cartStore.$id

  mutation.storeId // 'cart'

  // only available with mutation.type === 'patch object'

  mutation.payload // patch object passed to cartStore.$patch()

})

<script>

<template>

<h1>{{ counter }}</h1>

<button @click="clickAdd">click</button>

</template>


P.S.可以在./store/counter.js import另一個store去做處理



第七課

naive ui


第八課:router

import { createWebHistory, createRouter } from "vue-router";

import HomePage "@pages/HomePage.vue";


Vue.use(VueRouter) 

const router = createRouter({

  history: createWebHistory(), // 需要主機配置https://router.vuejs.org/zh/guide/essentials/history-mode.html#nginx,否則丟上主機router.push會壞掉。如果主機無法配合,可用createWebHashHistory(),但網址上會有#。

  routes: [

    {

        path: '/', 

        component: HomePage,

        name: 'HomePage',

    },

    {

        path: '/about', 

        component: () => import("@pages/HomePage.vue"), // 直接用函式載入,是動態的載入方式,只有在要切換時才會載入,適合用在靜態檔等確定載入時間不長的頁面

        name: 'About',

    },

    {

        path: '/:id', // 記得這個放最後面

        component: () => import("../views/[id].vue"), // [id].vue 是一種動態網址的命名方式

        name: 'userData',

    },

    {

        path: '/:domain(.*)*', // 記得這個放最後面

        component: import("../views/404.vue"),

        name: 'NotFound',

    },

})


// App.vue

<script setup>

import { RouterLink, RouterView, useRouter } from "vue-router";


const router = useRouter();  // route是參數,router是動作

setTimeout(()=>{

router.push("/about");

},3000)

</script>


<template>

  <RouterLink to="/">Home</RouterLink>

  <RouterView>

</template>


第九課

nuxt 3 前導


1.

在App.vue加入<NuxtPage />就可以把在pages folder下的 有其相對route設定,如下

index.vue 對應 /

about.vue 對應 /about

[id].vue 對應 /:id 


2.

const route = useRoute(); 即可,不用import route相關的東西,nuxt3自動引入


P.S. ref也自動引入,不用import

P.S. component也自動引入,不用import

P.S. composables也自動引入,不用import

P.S. 應該都可自動引入,有疑問再查文件


3.

npx nuxi add component TheHeader  // 用指令創建components folder 及其下TheHeader.vue


4. 

asyncData => useAsyncData // 只能在page裡用

axios => ohmyfetch (axios在server端好像不能用了)


// index.vue

<script setup>

const {data} = await useAsyncData("idName".() => { // 不用async了

$fetch("api url") // nuxt3整合了ohmyfetch, https://www.npmjs.com/package/ohmyfetch

})




參考網站:

https://vuejs.org/

https://pinia.vuejs.org/

https://router.vuejs.org/

https://nuxt.com/



2023年3月17日 星期五

Fix: ssh connection refused port 22

 https://itslinuxfoss.com/fix-ssh-connection-refused-port-22/


Reason 1: OpenSSH is not installed

Solution: Install OpenSSH in System

Reason 2: SSH Server Not Active

Solution: Check the Active Status of SSH

Reason 3: SSH Service is Running on a Different Port

Solution: Check the SSH Port Number

Reason 4: Firewall is Blocking Port 22

Solution: Configure Firewall Through UFW Utility


2023年3月8日 星期三

.bat .ps1 .sh

.bat  run by cmd run on windows =>batch language  

.ps1 run by powershell CLI on windows =>powershell script

.sh  run by bash shell run in linux =>Bourne-Again Shell script (bash script)


Shell is a general term including both .bat, .bash script, as well as other types of scripts such as csh, tcsh, zsh, and others.


reference: https://www.youtube.com/watch?v=mUw58ogYufY

2023年3月7日 星期二

為你自己學 GitLab CI/CD - 高見龍




merge 兩個分支,不管如何B的蓋過A: 

git merge B

git checkout --theirs *<conflict file>




實作上我在runner server上裝了docker 

ubuntu默認上沒有ssh: https://linuxhint.com/configure-authorized-keys-ssh-ubuntu/


林彥成: https://linyencheng.github.io/2022/05/30/devops-gitlab-ci-and-gitlab-runner/

高見龍yt: https://www.youtube.com/watch?v=zCFFot5HnEw&list=PLBd8JGCAcUAEwyH2kT1wW2BUmcSPQzGcu&index=2

gitlab: https://gitlab.com/kaochenlong/shopping-cat-v2 (已有fork到自己的repo)

doc.gitlab variables: https://docs.gitlab.com/ee/ci/variables/predefined_variables.html


cloud server:  aws / gcp / digitalOcean

ssh username@ip   // 連線到遠端機

uname -a // 印出當前機器的環境(ex: darwin, ubuntu...),是linux指令


用自己的runner設定:

1. install gitlab runner on server (maybe cloud server)

2. use "gitlab runner register" cmd to register it to gitlab project

3. add runner tag in gitlab-ci.yml

接著

4. testing: 先在runner環境上裝docker,根據test code使用的技術安裝相關的image,例如deno

5.built(built image) 

用Dockerfile打包,寫法參考https://philipzheng.gitbook.io/docker_practice/dockerfile/instructions,可配合.dockerignore忽略不用打包的檔案

FROM node:lts-alpine3.17 (我猜這樣寫)
WORKDIR /app  (表示希望在image裡面建立一個/app的資料夾)
COPY . /app (表示複製當前位置全部到/app的資料夾,全部但不包含.dockerignore所提及的)
EXPOSE 8000 (application開起來時的port)
RUN npm i (我猜這樣寫)
RUN npm run build (我猜這樣寫)

寫好Dockerfile後

docker build -t <生成的image_name> .   // -t表示要命名,.表示在當前目錄(尋找dockerfile)


** runner沒有權限執行docker,可以在runner機器上用usermod -aG docker gitlab-runer


6.publish(push image to gitlab registry)(optional)

7.deploy_to_dev

利用ssh-keygen指令建立一組public key-private key,連線到正式機,在authorized_keys檔案裡加入公鑰=>  vi authorized_keys

在gitlab 平台>設定>cicd>變數 加入 1.私鑰  2.正式機ip  3.連線的usernae

before_script:
    - eval $(ssh-agent -s)  
    - ssh-add <(echo "$SERVER_PRIVATE_KEY") //把echo出來的內容家到ssh-add裡
script:
    - scp -o StrictHostKeyChecking=no ./docker-compose.yml $SERVER_USER@$SERVER_URL:$HOME
    - ssh -o StrictHostKeyChecking=no $SERVER_USER@$SERVER_URL 
      "
      docker compose down &&
      docker compose up -d
      " // ""裡是成功連線後要執行的指令

// 有了公私鑰的關係才能進行連線
// ssh-agent: 進行公鑰驗證時,讓遠端主機可以存取儲存您的私人鑰匙(啟動ssh-agent)
// ssh-agent — OpenSSH authentication agent
// ssh-add — adds private key identities to the OpenSSH authentication
     agent
// -o StrictHostKeyChecking=no 這段是避免第一次連線時跳出詢問"是否確定要連線到那台機器"
// scp: Secure Copy主機間進行加密安全的複製

8.deploy_to_staging
9.environment 這個寫法可以把deploy的網址跟名稱存在gitlab > Deployments > Environments裡,如下
environment:
    name: dev
    url: http://localhost:3000


10.用樣板繼承方式讓deploy_to_dev和deploy_to_staging看起來更簡潔
樣板job名稱前面通常會加.,表示為樣板,不能單獨執行會壞掉
寫法如下
.deploy:
  variables:
    SERVER_PRIVATE_KEY: ""
    SERVER_USER: ""
    SERVER_URL: ""
    HOME: ""
    ENV: ""
    APP_PORT: ""

  before_script:
    - eval $(ssh-agent -s)
    - ssh-add <(echo "$SERVER_PRIVATE_KEY")
  script:
    - scp -o StrictHostKeyChecking=no ./docker-compose.yml $SERVER_USER@$SERVER_URL:$HOME
    - ssh -o StrictHostKeyChecking=no $SERVER_USER@$SERVER_URL "
      export COMPOSE_PROJECT_NAME=$ENV
      export APP_PORT=$APP_PORT
      docker compose down &&
      docker compose up -d
      "

  environment:
    name: $ENV
    url: http://$SERVER_URL:$APP_PORT

deploy-to-dev:
  stage: deploy_to_dev
  extends: .deploy
  variables:
    SERVER_PRIVATE_KEY: $DEV_SERVER_PRIVATE_KEY
    SERVER_USER: $DEV_SERVER_USER
    SERVER_URL: $DEV_SERVER_URL
    ENV: dev
    HOME: /root
    APP_PORT: 3000 
11. 手動執行job: 加上when:manual
如下
deploy-to-do:
  stage: deploy_to_production
  needs:
    - run-test-on-staging
  extends: .deploy
  when: manual
  variables:
    SERVER_PRIVATE_KEY: $DEV_SERVER_PRIVATE_KEY
    SERVER_USER: $DEV_SERVER_USER
    SERVER_URL: $DEV_SERVER_URL
    ENV: production-do
    HOME: /root
    APP_PORT: 80

12. artifacts 
例如:
run-tests:
  stage: testing
  image: denoland/deno:latest
  script:
    - deno test > test-report.txt
  artifacts:
    paths:
      - test-report.txt
    expire_in: "30 days"




Dockerfile vs docker-compose: What's the difference?

The contents of a Dockerfile describe how to create and build a Docker image, while docker-compose is a command that runs Docker containers based on settings described in a docker-compose.yaml file.

https://www.theserverside.com/blog/Coffee-Talk-Java-News-Stories-and-Opinions/Dockerfile-vs-docker-compose-Whats-the-difference


Dockerfile 寫好這個才能用docker

docker-compose.yml 把原本的docker相關指令寫在這裡面,然後用docker-compose up 一起執行

關閉時用docker-compose down,要背景執行的話加 -d

example: https://docs.docker.com/compose/gettingstarted/



docker run -p 80:8000 -d registry.gitlab.com/xxx/xxx (image path)  

// -d: 背景執行

// 我的本地3000對到遠端機的8000

這個指令改寫成 docker-compose.yml 如下

version: "3.9"  (意義就像package.json裡會有的版號)

services:
  cat:
    image: registry.gitlab.com/xxx/xxx
    ports:
      - 80:8000
    restart: always


linux的指令: 

cat $abc > test.txt // 把變數abc的內容寫入test.txt裡


pm2

https://pm2.keymetrics.io/

https://s103071049.coderbridge.io/2021/08/12/nginx-pm2/


選用 Executor :

  • Shell:即是 Runner 直接在自己的 Local 環境執行 CI Job,因此如果你的 CI Job 要執行各種指令,例如 make、npm、composer⋯⋯,則需要事先確定在此 Runner 的 Local 環境是否已具備執行 CI Job 所需的一切相依程式與套件。

ref: https://chengweichen.com/2021/03/gitlab-ci-executor.html


How to use if-else condition on gitlabci

https://stackoverflow.com/questions/54761464/how-to-use-if-else-condition-on-gitlabci/55464100#55464100

https://docs.gitlab.com/ee/ci/yaml/#rules


shell (script)教程

业界所说的 shell 通常都是指 shell 脚本,但读者朋友要知道,shell 和 shell script 是两个不同的概念。

在一般情况下,人们并不区分 Bourne Shell 和 Bourne Again Shell,所以,像 #!/bin/sh,它同样也可以改为 #!/bin/bash

https://www.runoob.com/linux/linux-shell.html


command prompt (use shell scripting language, like bash, sh, or csh)

  • If you're unsure of what commands to use, you can type "Help" into Command Prompt. This makes a list appear with different common commands you can use.
  • Get more information about a command by typing "/?" at the end. This gives you additional information about changing how that command works. ex: cd/?
  • Keep your computer clean and issue-free by running "sfc/ scannow" in the Command Prompt window. This System File Checker tool can help you identify and fix issues by scanning all your protected files. It also repairs broken files to improve performance on your computer.

Common commands to use in Command Prompt

  • systeminfo: This displays specific properties and configurations for your computer.
  • tasklist: This displays all active tasks and services.
  • taskkill: This stops a process or application.
  • time: This sets the computer's time.
  • type: This displays all the contents within a text file.
  • ver: This shows the Windows version on your computer.
  • verify: This tells Windows whether your files are written correctly to a disk.
  • xcopy: This copies files and directory trees.


Gitlab CI/CD for npm packages: 

https://dev.to/kristijankanalas/gitlab-ci-cd-for-npm-packages-4ncj

[有空看看] 資料庫 my migration tool

讓資料庫修改不用從my admin介面進入去修改,而是merge後直接上雲(大概,總之進化了,有空可以看看)

2023年2月24日 星期五

singleNumber , ex: [4,1,2,1,2]

var singleNumber = function(nums) {

    var ans = 0;

    for (var i = 0; i < nums.length; i++) {

        ans = ans ^ nums[i];

    }

    return ans;

};


example1:

Input: nums = [4,1,2,1,2]

Output: 4

2023年2月23日 星期四

containsDuplicate 利用arr-key取代第二個for-loop

 var containsDuplicate = function(nums) {

    const arr=[]

     for(let i=0;i<nums.length;i++) {

        

        if(arr[nums[i]]) {

            return true

        }else {

            arr[nums[i]]= true

         }  

    }

    return false

};



Example 1:

Input: nums = [1,2,3,1]

Output: true


Example 2:

Input: nums = [1,2,3,4]

Output: false

時間字符串被格式化為hh:mm:ss並基於 24 小時制,字符串比較的默認行為就足夠了

 https://bobbyhadz.com/blog/javascript-compare-two-time-strings


const time1 = '07:30:24';
const time2 = '10:45:33';

if (time1 > time2) {
  console.log('time1 is greater than time2');
} else if (time2 > time1) {
  // ✅ this runs
  console.log('time2 is greater than time1');
} else {
  console.log('time1 is equal to time2');
}

2023年2月7日 星期二

why-is-my-css3-transition-delaying-before-it-starts

 https://stackoverflow.com/questions/30627250/why-is-my-css3-transition-delaying-before-it-starts


可試試這個文章 https://css-tricks.com/using-css-transitions-auto-dimensions/ 看能不能解