Blogs

Paste Image in VSCode

#vscode

可以藉由設定 {專案_ROOT}/.vscode/settings.json { "markdown.copyFiles.destination": { "/docs/**/*": "images/${documentBaseName}/" } } 他會自動將所有 /docs/ 底下的圖片複製到 images/${documentBaseName}/ 底下。

Read more →

June 26, 2025

Markdown Syntax Guide

#Markdown#Example#Guide

This article offers a sample of basic Markdown syntax that can be used in Hugo content files.

Read more →

June 22, 2025

Hello World

#Blog

這是我的第一篇文章!

Read more →

June 21, 2025

自架harbor

#docker

wget https://github.com/goharbor/harbor/releases/download/v2.11.1/harbor-online-installer-v2.11.1.tgz tar xzvf harbor-online-installer-v2.11.1.tgz cd harbor Config HTTPS 使用OpenSSL 建立CA openssl genrsa -out ca.key 4096 openssl req -x509 -new -nodes -sha512 -days 3650 -subj “/C=TW/ST=Taiwan/L=Taipei/O=alanhc/OU=Personal/CN=0xfanslab.com” -key ca.key -out ca.crt openssl genrsa -out 0xfanslab.com.key 4096 openssl req -sha512 -new -subj “/C=TW/ST=Taiwan/L=Taipei/O=alanhc/OU=Personal/CN=0xfanslab.com” -key 0xfanslab.com.key -out 0xfanslab.com.csr cat > v3.ext «-EOF authorityKeyIdentifier=keyid,issuer basicConstraints=CA:FALSE keyUsage = digitalSignature, nonRepudiation, keyEncipherment, dataEncipherment extendedKeyUsage = serverAuth subjectAltName = @alt_names [alt_names] DNS.1=0xfanslab.com DNS.2=www.0xfanslab.com DNS.3=localhost EOF authorityKeyIdentifier=keyid,issuer basicConstraints=CA:FALSE keyUsage = digitalSignature, nonRepudiation, keyEncipherment, dataEncipherment extendedKeyUsage = serverAuth subjectAltName = @alt_names

Read more →

October 13, 2024

詞彙解釋

之前有感覺有時候用字如果錯會導致錯誤理解 發現台灣有人做這: https://hackmd.io/i4pWFe0fQHS7WTi10KVdEA Ref

Read more →

October 11, 2024

ubuntu wifi網卡抓不到

#driver

Ref lsusb RTL8821AU https://github.com/brektrou/rtl8821CU 找到對應的git https://github.com/gnab/rtl8812au make sudo make install TX20U 在Ubuntu 22.04 https://www.tp-link.com/tw/support/faq/3423/ 看到他是 Realtek 8832AU https://github.com/hyekalhitech/ArcherRTL8832AU

Read more →

October 11, 2024

安裝後直接進到 windows問題

#重灌

Ref Solution: 在bios裡面 boot>UEFI Hard Disk Drive BBS Priorities 設定 Boot Option 第一個要是ubuntu

Read more →

October 10, 2024

超簡單! 一文理解如何使用私有大型語言模型LLM - Ollama+Open WebUI篇

#llm

步驟 安裝 Docker Desktop 使用wsl2 使用 docker compose 2 使用WSL2 打開命令提示字元或Terminal,鍵入: wsl --install 3 使用 docker compose 安裝 3.1 安裝 NVIDIA Container Toolkit讓GPU可以使用 curl -fsSL https://nvidia.github.io/libnvidia-container/gpgkey | sudo gpg --dearmor -o /usr/share/keyrings/nvidia-container-toolkit-keyring.gpg \ && curl -s -L https://nvidia.github.io/libnvidia-container/stable/deb/nvidia-container-toolkit.list | \ sed 's#deb https://#deb [signed-by=/usr/share/keyrings/nvidia-container-toolkit-keyring.gpg] https://#g' | \ sudo tee /etc/apt/sources.list.d/nvidia-container-toolkit.list sudo apt-get update sudo apt-get install -y nvidia-container-toolkit # Configure NVIDIA Container Toolkit sudo nvidia-ctk runtime configure --runtime=docker sudo systemctl restart docker # Test GPU integration docker run --gpus all nvidia/cuda:11.5.2-base-ubuntu20.04 nvidia-smi 後續步驟有影片可以對照參考:200 秒內帶你進入私有大型語言模型LLM的世界 - Ollama + Open WebUI

Read more →

October 3, 2024

windows 下的套件管理-Chocolatey

Ref [Chocolatey Software | Trial](https://chocolatey.org/contact/trial) configuration = Configuration(access_token='') handler = WebhookHandler('')

Read more →

September 4, 2024

更快的影片學習方法

#學習

ytd get youtube video whisper video -> text video -> 關鍵影格 (變動threshold>0.2) learn-fast/ import sys import os import subprocess from yt_dlp import YoutubeDL from mlx_whisper import transcribe import cv2 import numpy as np import json from slugify import slugify # create mp.json if not exist if not os.path.exists("mp.json"): with open("mp.json", "w") as f: json.dump({}, f) def download_youtube_video(url, output_path='./videos'): mp={} ydl_opts = { 'verbose': True, 'format': 'bestvideo+bestaudio/best', 'outtmpl': os.path.join(output_path, '%(id)s.%(ext)s'), 'merge_output_format': 'mp4', 'quiet': False, 'writesubtitles': True, 'writeautomaticsub': True, } info_save = None with YoutubeDL(ydl_opts) as ydl: info = ydl.extract_info(url, download=True) video_title = info['title'] info_save = info video_file = os.path.join(output_path, f"{id}.mp4") try: with open("mp.json", "r") as f: mp = json.load(f) except json.JSONDecodeError as e: print(f"Error reading mp.json: {e}") print(f"Error position: {e.pos}") with open("mp.json", "r") as f: json_data = f.read() print(f"JSON content up to error position: {json_data[:e.pos]}") # mp = {} mp[url] = info_save with open("mp.json", "w") as f: json.dump(mp, f) return f'{output_path}/{mp[url]['id']}.mp4' def video_to_text(output_folder, audio_file): print("==", audio_file) output = transcribe(audio_file, word_timestamps=True) with open(f"{audio_file}.transcription.json", "w") as f: json.dump(output, f, default=lambda x: x.item() if isinstance(x, np.float16) else print(x)) return output def extract_key_frames(video_path, output_folder, threshold=0.2): cap = cv2.VideoCapture(video_path) path = os.path.join(output_folder, os.path.splitext(os.path.basename(video_path))[0]) basename = os.path.basename(path) os.makedirs(output_folder, exist_ok=True) os.makedirs(f"{output_folder}/{basename}", exist_ok=True) success, prev_frame = cap.read() if success: cv2.imwrite(f"{output_folder}/{basename}/frame_0.jpg", prev_frame) count = 0 ans = [] while success: success, curr_frame = cap.read() if not success: break diff = cv2.absdiff(cv2.cvtColor(prev_frame, cv2.COLOR_BGR2GRAY), cv2.cvtColor(curr_frame, cv2.COLOR_BGR2GRAY)) non_zero_count = np.count_nonzero(diff) non_zero_ratio = non_zero_count / diff.size if non_zero_ratio > threshold: frame_time = cap.get(cv2.CAP_PROP_POS_MSEC) / 1000.0 frame_name = f"{output_folder}/{basename}/frame_{int(frame_time)}.jpg" cv2.imwrite(frame_name, curr_frame) print(f"Saved frame at {frame_time:.2f} seconds as {frame_name}") ans.append( { "frame": frame_name, "time": frame_time } ) prev_frame = curr_frame count += 1 cap.release() with open(f"{output_folder}/{basename}/keyframes.json", "w") as f: json.dump(ans, f) print(f"Extracted frames saved in {output_folder}") def video_to_audio(video_file=""): audio_file = f"{video_file}.wav" subprocess.run(["ffmpeg", "-i", video_file, audio_file], check=True) return audio_file def main(): if len(sys.argv) != 2: print("Usage: python pt.py <YouTube URL>") return youtube_url = sys.argv[1] video_output_path = './videos' frames_output_folder = './frames' threshold = 0.2 # 畫面變動的閾值 video_file = download_youtube_video(youtube_url, video_output_path) audio_file = video_to_audio(video_file) transcription = video_to_text("videos", audio_file) # extract_key_frames(video_file, frames_output_folder, threshold) if __name__ == "__main__": main()

Read more →

August 14, 2024

llm-k8s

https://microk8s.io/docs/install-macos https://sarinsuriyakoon.medium.com/deploy-ollama-on-local-kubernetes-microk8s-6ca22bfb7fa3 multipass 是甚麼?? Ref

Read more →

July 17, 2024

fastapi-k8s

#kubernetes

![[Pasted image 20240717010914.png]] FROM tiangolo/uvicorn-gunicorn-fastapi:python3.9 COPY ./main.py /app/main.py fastapi-deployment.yaml apiVersion: apps/v1 kind: Deployment metadata: name: fastapi-deployment spec: replicas: 1 selector: matchLabels: app: fastapi template: metadata: labels: app: fastapi spec: containers: - name: fastapi-container image: alanhc/test:latest ports: - containerPort: 80 fastapi-service.yaml apiVersion: v1 kind: Service metadata: name: fastapi-service spec: selector: app: fastapi ports: - protocol: TCP port: 80 targetPort: 80 type: NodePort from fastapi import FastAPI app = FastAPI() @app.get("/") def read_root(): return {"Hello": "World"} kubectl apply -f

Read more →

July 17, 2024

Building Your Own Database Agent

#llm

Building Your Own Database Agent https://learn.deeplearning.ai/courses/building-your-own-database-agent/lesson/1/introduction ![[Database Agent 1.png]] ![[Artificial Intelligence.png]] ![[Fine tuning.png]] ![[Database Agents.png]] from langchain.agents.agent_types import AgentType from langchain_experimental.agents.agent_toolkits import create_pandas_dataframe_agent agent = create_pandas_dataframe_agent(llm=model,df=df,verbose=True) agent.invoke(“how many rows are there?”) > Entering new AgentExecutor chain… Thought: To find out the number of rows in a pandas DataFrame, I can use the shape attribute which returns a tuple with the number of rows and columns. The first element of the tuple will give me the number of rows.

Read more →

July 16, 2024

Hugging Face LLM

確認有 Hugging face token,記得要有read權限 run.py access_token = "hf_..." # 這裡放 Hugging face token # pip install accelerate from transformers import AutoTokenizer, AutoModelForCausalLM import torch tokenizer = AutoTokenizer.from_pretrained("google/gemma-2b-it", token=access_token) model = AutoModelForCausalLM.from_pretrained( "google/gemma-2b-it", device_map="auto", torch_dtype=torch.bfloat16 , token=access_token ) input_text = "Write me a poem about Machine Learning." input_ids = tokenizer(input_text, return_tensors="pt").to("cuda") outputs = model.generate(**input_ids) print(tokenizer.decode(outputs[0])) <bos>Write me a poem about Machine Learning. Machines, they weave and they learn, From Ref https://huggingface.co/google/gemma-2b/discussions/28 https://huggingface.co/google/gemma-2b-it

Read more →

July 10, 2024

inferencing-llm

#llm

## mac 安裝 pip install mlx-lm 使用 mac cli python -m mlx_lm.generate --model mlx-community/Phi-3-mini-4k-instruct-4bit --prompt "how are you" import bs4 from langchain import hub from langchain_community.document_loaders import WebBaseLoader from langchain_chroma import Chroma from langchain_core.output_parsers import StrOutputParser from langchain_core.runnables import RunnablePassthrough from langchain_openai import OpenAIEmbeddings from langchain_text_splitters import RecursiveCharacterTextSplitter import getpass import os os.environ["OPENAI_API_KEY"] = "sk-proj-"#getpass.getpass() from langchain_community.document_loaders import PyPDFLoader loader = PyPDFLoader("files/替代役管理作業規定.pdf") pages = loader.load_and_split() from langchain_community.llms.mlx_pipeline import MLXPipeline llm = MLXPipeline.from_model_id( "mlx-community/quantized-gemma-2b-it", # pipeline_kwargs={"max_tokens": 512, "temp": 0.1}, pipeline_kwargs={"temp": 0.1}, ) from huggingface_hub import login login(token="") import os docs = loader.load() text_splitter = RecursiveCharacterTextSplitter(chunk_size=1000, chunk_overlap=200) splits = text_splitter.split_documents(docs) vectorstore = Chroma.from_documents(documents=splits, embedding=OpenAIEmbeddings()) # Retrieve and generate using the relevant snippets of the blog. retriever = vectorstore.as_retriever() prompt = hub.pull("rlm/rag-prompt") def format_docs(docs): return "\n\n".join(doc.page_content for doc in docs) rag_chain = ( {"context": retriever | format_docs, "question": RunnablePassthrough()} | prompt | llm | StrOutputParser() ) question = "替代役管理作業規定是依據甚麼法律?" rag_chain.invoke(f"{question} ") # ' 根據上述法律,替代役管理作業規定主要依據兵役法第 26條。' Ollama 使用 Ollama 執行 TAIDE 的 TAIDE-LX-7B-Chat-4bit 大語言模型 ollama create taide-lx-7b-chat-4bit:latest -f Modelfile 介紹好用工具:Ollama 快速在本地啟動並執行大型語言模型 透過Ollama在本機電腦執行大型語言模型(LLM):Windows與VS Code篇 Ref

Read more →

July 4, 2024

python使用pyinstaller製作桌面應用程式

#python#pyinstaller

先看 File structure: # app.py import streamlit as st st.title('Hello World') # hooks/hook-streamlit.py from PyInstaller.utils.hooks import copy_metadata datas = copy_metadata("streamlit") # run_app.py import streamlit import streamlit.web.cli as stcli import os, sys if __name__ == "__main__": os.chdir(os.path.dirname(__file__)) sys.argv = [ "streamlit", "run", "./src/app.py", "--global.developmentMode=false", ] sys.exit(stcli.main()) method 1: 第一次打包 pyinstaller --onefile --additional-hooks-dir=./hooks run_app.py --clean 第二次打包

Read more →

June 26, 2024

20240621-公雲學習筆記

概覽公共雲服務 (11:45)Top 50+ AWS Services Explained in 10 Minutes Elastic Compute Cloud (EC2) -> -> 有 擴展問題 -> LB -> Cloud Watch -> Auto Scaling -> 太麻煩 -> Elastic Beanstalk (PAAS) -> 其實不用伺服器 -> Lambda (FAAS aka ServerLess) OutPosts: 可以跑 AWS 在自己基礎建設 SNOW: 自架 docker: 可以跑不同公雲環境 需要更多可以擴展 -> EKS -> 可以自動擴展?-> FARGATE 既然有 Container,使用App Runner最簡單 儲存? s3: 可以存任何格式 -> 是否有成本低、高延遲的? -> Glacier ,速度要快? Block Storage,要更多權限、可控 > Elastic File System

Read more →

June 21, 2024

20240409-你要如何衡量你的人生

#書

人生方向 樂在工作、挑戰、個人成長、有意義 家庭 婚姻 孩子:學做困難事、價值觀 家庭文化、行為準則 個人:道德原則、不妥協 職涯發展 5特質 Spiritual Heart Abilities Personality Experience 作者是 Rhodes Scholar 牛津讀博 運動、政治、寫作、社區 股市大盜:Dan of thieves 如何知道工作生涯何以成功、快樂 如何知道自己與配偶、兒女、朋友可以快樂 如何知道一生堅守原則,免於牢獄 破壞性創新 - Andy Grove 創新的兩難 理論的Value:從經驗學cost大 每天一睜眼可以為自己喜歡社情欣喜 誘因理論 Michael Jemsem Agent Theory Willian Meckling Two-Factor Theory 動機(發自內心)vs 應因 動機理論 Frederiok Herzberg hygrene factor 保健 e.g. 地位穩定 motivation factor 動機 e.g. 有挑戰性 策略 Hery Mintzberg deliberate strategy 審慎策略 (可預期) emergement strategy 應急策略(不可預期) Walmart 只在小鎮,支援方便,避免削價競爭 發現導向(計畫)- 檢驗哪一比的收穫大 -> 哪些假設新證明為真 重要不確定 vs 不重要但確定 創新的困難 e.g. SonoSite 資源分配的重要 投資困境:為什麼雪球滾不大 (書) 好資金 (少、慢、考慮獲利)、壞資金(大、急於成功) 孩子溝通時要使用:如果…、你還記得… 30個月多說話 公司能力:資源、流程、企業優先順序 Ship of Theseus 人才『書』展翅高飛:培養下一代領導者 經驗的重要 文化的制定 Ref

Read more →

June 16, 2024

閱讀筆記-建中 2021 暑假資讀投影片-謝一

#competitive_programming

https://slides.com/thanksone/deck Bubble sort Merge sort Quick sort Ref

Read more →

April 6, 2024

閱讀筆記

https://tioj.ck.tp.edu.tw/articles/22 9/15 演算法初探 https://slides.com/justinlai2003/deck-5fc968 9/22 貪婪、分治與動態規劃: https://slides.com/fhvirus/greedy-dq-dp Greedy DQ DP DP 經典題 ![[截圖 2024-04-06 晚上9.21.15 2.png]] ![[截圖 2024-04-06 晚上9.21.32 2.png]]

Read more →

April 6, 2024

競技程式路線圖

#competitive_programming#roadmap

Competitive Programming Roadmap (target: [gray, blue]) Competitive programming roadmap here. 如何擅長? 想什麼? 快速瞭解問題成標準問題 簡化問題 如何思考 分析敘述、數學方程式、觀察結果 如何練習? Codeforces problemset :適合有經驗,網路找不到答案 CSES 150: 標準問題 AtCoder problemset: 初學者友善 Competitive programming roadmap abc240_a - Edge Checker abc220_a - Find Muliple Time complex Python可以跑4秒,C可以2秒,大約10^8 2. Loops and arrays Time Complexity $O(1)$: 數學解 $O(logn)$: Binary Search, Sorted set/map, priority queue per operation $O(\sqrt{n})$: 質因數分解 $O(n)$: two pointer $O(nlogn)$: Sorting(merge sort) $O(n^2)$: Quick sort (worst case) $O(n^k)$: iter subset of size k, e.g. iter all triplets $O(n^3)$ $O(2^n)$: iter all subsets $O(n!)$: iter all permutations 透過下表看演算法會不會超過時間 abc204_b - Nuts abc205_b - Permutation Check abc206_c - Swappable abc220_c - Long Sequence abc196_c - Doubled abc194_c - Squared Error Ref

Read more →

April 6, 2024

20240324-learn-go

#backend#go#grpc

quickstart golang in 100 secoonds package main import ( "fmt" ) func main() { fmt.Println("Hello, world!") } 編譯可執行檔案:go build hello.go 執行:go run hello.go 初始化 dependancy: go mod init alanhc/school 下載:go install OOO,會出現在go.mod

Read more →

March 24, 2024

20240321-interview-warmup

#llm#chatgpt#rag

Backgrounds I just got rejected by a big tech company. In order to improve my ability to explain interview questions effectively in English, I’m designing an interview warmup tool using LLM and RAG technologies. Design So, I start design a system that could help me practice: User Story As a recruiter, I want to disguise the user’s answer is correct or not based on the QA dataset so that I could filter potential candidates. Scope the Problem Recruiter can build his/her QA datasets. LLM will provide some technical advice to the recruiter Main component Storage: JSON file Advice: ChatGPT+RAG This project consists of two main components: Retriever and Advisor. Retriever focuses on managing the dataset. Initially, I use Gemini to generate the correct answers, which are then saved in a JSON file. Subsequently, questions and answers are stored in a JSON file due to its advantages:

Read more →

March 21, 2024

20240303-save-password-python

#python#security

使用 AES(對稱加密) + base64 加密 from Crypto.Cipher import AES from Crypto.Util.Padding import pad, unpad from Crypto.Protocol.KDF import PBKDF2 from Crypto.Random import get_random_bytes salt = get_random_bytes(16) key_enc = PBKDF2(password, salt, dkLen=32) cipher = AES.new(key_enc, AES.MODE_ECB) ciphertext = cipher.encrypt(pad(plaintext.encode(), BLOCK_SIZE)) data[k] = base64.b64encode(ciphertext).decode() with open("password.txt", "w") as f: json.dump(data, f) Ref

Read more →

March 3, 2024

國外工作

#job#移民#國外工作

歐洲 根據 歐洲資訊科技產業協會: 的資料,歐洲軟體工程師最需要的領域包括: 雲端計算和分散式系統 人工智慧和機器學習 網路安全 大數據和資料分析 軟體開發和工程 行動應用程式開發 遊戲開發 嵌入式系統 這些領域的軟體工程師都比較容易獲得歐洲簽證,因為這些領域的職缺很多,而且這些職缺通常需要高技能的員工。 以下是歐洲一些提供軟體工程師簽證的國家: 德國:德國的藍卡計畫讓高技能的非歐盟公民可以獲得工作簽證。藍卡的申請人必須有大學學歷,並有至少 56,400 歐元的年薪。 Opens in a new windowwww.germany-visa.org Germany visa 荷蘭:荷蘭的知識型移民計畫讓高技能的非歐盟公民可以獲得工作簽證。知識型移民計畫的申請人必須有大學學歷,並有至少 48,000 歐元的年薪。 Opens in a new windowen.siu.com.cn Netherlands visa 英國:英國的全球人才簽證計畫讓高技能的非歐盟公民可以獲得工作簽證。全球人才簽證的申請人必須有大學學歷,並有至少 25,600 英鎊的年薪。 Opens in a new windowwww.gov.uk UK visa 法國:法國的科技人才簽證計畫讓高技能的非歐盟公民可以獲得工作簽證。科技人才簽證的申請人必須有大學學歷,並有至少 30,000 歐元的年薪。 Opens in a new windowrjfmac.com

Read more →

February 27, 2024

20240227-warp-terminal

#terminal

發現一個有趣的東西 brew install –cask warp Ref

Read more →

February 27, 2024

20240227-huggingface-nlp

#course#nlp

transformers models NLP challenge 人可以很快知道詞相似 Transformers, what can they do? Working with pipelines https://huggingface.co/models from transformers import pipeline classifier = pipeline("sentiment-analysis") classifier("I've been waiting for a HuggingFace course my whole life.") # [{'label': 'POSITIVE', 'score': 0.9598047137260437}] available pipelines

Read more →

February 27, 2024

20240227-Hash-Table-ood

#object_oriented_design

Question 設計一個使用chaining(Link List)處理碰撞問題的hash table Solution O(1) 可以使用array但浪費空間 可以使用binary search但就不會是O(1) Ref

Read more →

February 27, 2024

20240227-File-Systems-ood

#object_oriented_design

Question 解釋如何設計in-memory的DS 及 演算法,請可能舉例 Solution 最簡單就分成有File及Directory他們各自extend Entry Ref

Read more →

February 27, 2024

20240226-minesweeper-ood

#object_oriented_design

Question 踩地雷遊戲,玩家直到整個盤都探索完畢,玩家點選後如果是炸彈就輸掉,若是空白,消除所有鄰近空白及數字 Solution focus key idea+structure out Design:Cell enum Design:Board init, flip Design: Game host game state Algorithm placing the bomb setting number cells expanding a Blank Region Ref

Read more →

February 26, 2024

20240226-Circular-array-ood

#object_oriented_design

Question 實作CircularArray class可以有效翻轉array like data structure,這個class需使用generic type(template),且支援iter notaion(obj o: circularArray) Solution 拆解問題:實作CircularArray class、支援iteration Implementing the CircularArray class 注意負數在mod後的使用 Implementing the Iterator Interface 這邊參考p330 Ref

Read more →

February 26, 2024

20240222-content-analysis

#nlp#text_network_analysis

文字清理(去除符號、轉小寫) 依據詞頻拆分關鍵字網路 邊/連結厚度代表關鍵字的相依頻率 節點大小代表專見字的頻率 Ref

Read more →

February 22, 2024

20240221-othello-ood

#object_oriented_design

Question 設計黑白棋的OOD,黑白棋是如果周遭(上下左右)被圍起來就更換中間(被包圍)顏色,到一方無法下任何棋結束。 Solution core object: game, board, pieces, players Shold BlackPiece and WhitePiece be classes? 因為棋會一直被翻轉,有一個統一Piece Class可能比較好 Do we need separate Board and Game classes? Pros 邏輯上分開board跟game Cons 需要額外layer Who keeps Score? 可能可以使用Group、Piece、Board group 我們暫時使用board存,這樣分數可以由Board分組 Should Game be a Singleton class? Singleton 好處是所有人可呼叫,而不用每次都pass ref,但只能被初始化一次,與interviewer討論是否可以這樣做 Ref

Read more →

February 21, 2024

20240219-chat-server-ood

#object_oriented_design

Question 請解釋你會怎麼設計一個chat server,請說明你會怎麼設計Backend Component的細節、Class及Method,可能需要解決最困難的問題是什麼 Solution 這問題很大,一開始要scope problem,一開始建議從廣下手,但focus可以再inerview完成的部分 focus 使用者管理(新增、建立對話、更新狀態) 先不管網路、資料怎麼傳送給client等問題 要加入聯絡人,要兩方都是才是,支援群組聊天、一對一私人對話,不考慮語、音通話或檔案傳輸 What specific action does it need to support? 與interviewer討論,for example: singing online and offline 加入request(sending, accepting and rejeccting) 更新狀態 建立private 及群組訊息 在private及群組對話加入訊息 What can we learn about these requirements? 我們需要有使用者、新增request狀態、線上狀態、訊息 What are the core components of the system? 使用database永久儲存資料,SQL很好,如果要scalability,可以使用BigTable之類 client-server溝通可以使用XML,因為人跟機器可讀,但他不是最好壓縮過的格式 資料可能被切分在不同機器,為了避免single point of failure,資料會複製好幾份在不同機器 What are the key objects and methods key objects, includes users, conversations, status message UserManager userById: map(int=>User) userByAccountName: map(string=>User) onlineUsers: map(int=>User) addUser() approveAddRequest() rejectAddRequest() iserSignedOn() iserSignedOff() What problems would be the hardest to solve(or the most interesting)? 可能會interviewer討論以下問題 Q1: How do we know If someone is online–I mean, really know? 有可能使用者忘記登出,定時去ping client看是否還在 Q2: How do we deal with conflicting information 有些存databse,有些存電腦的memory,如果有些out of sync怎麼辦?哪個才正確? Q3: How do we make our server scale? 如何設計可以擴展的系統,真實世界資料可能要拆分在不同機器,怎麼處理不同步資料 Ref

Read more →

February 19, 2024

20240217-parking-lot-ood

#object_oriented_design

Question 設計一個根據object-oriented principles的parking lot(停車場) Solution 跟interviewer討論支援什麼類別的車 假設 停車場有多個level,每個level有多個spots 停車長可以停摩托車、汽車及公車 有摩托車停車、小客車停車場及大型停車場 摩托車可以停在任何停車場 小客車可以停在小客車、大型停車場 公車只能停在大型停車場 建立一個車輛的abstract類別可以讓其他extend ParkingLot是多個Level的warpper 摩托車停車、小客車停車場及大型停車場可以繼承自ParkingLot Ref

Read more →

February 17, 2024

20240217-online-book-reader-ood

#object_oriented_design

Question 設計線上書本閱讀器的資料結構 Solution 因為問題沒解釋很清楚,我們假設提供以下功能 用戶帳戶建立、擴增 搜尋資料庫的書 看書 同一時間只可以有一個線上使用者 這個使用者指只會有一本acitve的書 有可能會有 User/Book/Library get/set/update Ref

Read more →

February 17, 2024

20240217-jukebox-ood

#object_oriented_design

Question 使用object-oriented principles設計jukebox musical(點唱機) Solution 問interviewer釐清設計限制 播放CD/錄影/MP3? 在PC/實體點唱機? 假設 for example 電腦模擬,要接近實體點唱機 basic component Jukebox CD Song Artist Playlist Display breakdown to find possible actions Playlist creation(add/delete/shuffle) CD selector Song selector Queuing up a song get next song from playlist 使用者可以: add delete credit infomation Ref

Read more →

February 17, 2024

20240217-jigsaw-ood

#object_oriented_design

Question 打造一個拼圖遊戲,設計資料結構以及解釋如何破解這個拼圖的演算法。你可以假設有一個fitsWith(),他可以檢查兩個拼圖是否可以拼在一起。 Solution 我們需要針對每一片拼圖儲存位置,可能有兩種儲存情況 絕對位置:(x,y) 相對位置:還不知道在哪,但知道A在B旁邊 主要Class: Puzzle, Piece, Edge 形狀(shape): inner, outer, flat edge的方向: left, right, top, down Puzzle 會有個很多piece的list Piece 會有個hashtable(orientation=>edge),有可能會rotate piece,所以hash有可能會變 Algorithm to Solve the Puzzle 要可以rotate嘗試是否可以塞到角落 Ref

Read more →

February 17, 2024

20240217-call-center-ood

#object_oriented_design

Question 有一個有三種level員工的call center,respondent, manager, director。當電話進來時,要assign給空閒的respondent,如果他不能回答,必須轉介給manager,也不行就往上給director,設計一個給這問題的class及資料結構,實作一個dispathchCall()指派電話給低一個可用的員工 solution OOD有很多方式可以實作,跟面試官討論,trade off,保持彈性、可維護性設計。 Call代表一則通話,並且call有最小的rank而且被指定給可以處理的第一個員工 Employee 是superclass,且是一個abstract類別,不應該直接實例化 respondent, manager, director可以extend Employee類別 Ref

Read more →

February 17, 2024

20240216-levelsfyi-crawler

#web_scraping

Background from a stack overflow question , level.fyi encrypt its response request GET https://api.levels.fyi/v3/salary/search?countryIds[]=197&offset=10&limit=50&sortBy=offer_date&sortOrder=DESC&jobFamilySlug=software-engineer response { "payload": "EofXi7jF2t63a..." } solution Go to levels.fyi> Inspect>Network>JS tab>commonUtils.js>CryptoJS.AES.decrypt I wrote a python script : from Crypto.Cipher import AES from Crypto.Hash import MD5 from base64 import b64encode, b64decode import zlib class ResponseUtil: def __init__(self): self.key = "levelstothemoon!!" self.n = 16 def parse(self, t): if "payload" not in t: return t r = t["payload"] a = MD5.new(self.key.encode()).digest() a_base64 = b64encode(a)[: self.n] cipher = AES.new(a_base64, AES.MODE_ECB) decrypted_data = cipher.decrypt(b64decode(r)) decompressed_data = zlib.decompress(decrxypted_data) return json.loads(decompressed_data.decode()) # Example usage: response_util = ResponseUtil() parsed_data = response_util.parse(ans) print(parsed_data) { "total": 1000, "hidden": 2, "rows": [ { "uuid": "079fb0cf-d9ff-4b58-bb08-70f3a8447521", "title": "Software Engineer", "jobFamily": "Software Engineer", "level": "E7", "focusTag": "General", "yearsOfExperience": 5, "yearsAtCompany": 2, "yearsAtLevel": 2, "offerDate": "2024-01-27T02:02:19.682Z", "location": "Hsin-chu, TP, Taiwan", "workArrangement": "office", "compPerspective": "employee", "cityId": 17410, "dmaId": 10064, "countryId": 236, "exchangeRate": 31.2881, "baseSalary": 42188.5583, "baseSalaryCurrency": "TWD", "totalCompensation": 67757.3815, "avgAnnualStockGrantValue": null, "stockGrantCurrency": null, "avgAnnualBonusValue": 25568.8232, "bonusCurrency": "TWD", "salesComp": null, "negotiatedAmount": null, "gender": null, "ethnicity": null, "education": null, "otherDetails": null, "companyInfo": { "registered": true, "icon": "https://logo.clearbit.com/mediatek.com", "name": "MediaTek", "slug": "mediatek" }, "vestingSchedule": null, "tags": null, "stockType": null }, ... https://hackmd.io/DXNwbKGJRWamrYYFv6LT_Q contract If you have any questions or needs, please contract me at alan.tseng.cs@gmail.com

Read more →

February 17, 2024

20240205-Deck-of-cards

#object_oriented_design

Question Deck of cards:設計一個給一副牌的generic資料結構,解釋如何設計black-jack(21點)資料結構的子類別 Solution 首先跟面試關確認generic的定義,給Uno、pocker-like還是? 假設是poker card: Suit club, diamond, heart, spade value getValue() getSuitFromValue() Deck cards=[] shuffle() remainintCards() dealHand() dealCard() Card faceValue suit isAvaliable() setAvaliable(state) Hand cards=[] score() addCard() BlackJackHand extends Hand 備註:這邊我除了看書內容,可以問bard: 21點遊戲規則是什麼,請解釋並說明如何使用OOP方式實作 Ref

Read more →

February 15, 2024

20240212-linkedin-private-api

#linkedin#web_scraping

思路:先用playwright 取得cookies,觀察network直接打API 先取得 geoid (地點id) q_keywords = "software engineer" q_location = "taiwan" r = requests.get(f"https://www.linkedin.com/jobs/search?keywords={q_keywords}&location={q_location}&trk=public_jobs_jobs-search-bar_search-submit") soup = BeautifulSoup(r.text, "html.parser") geo_id_inputs = soup.select("input[name='geoId']") geoid = geo_id_inputs[0].get("value") start_n = 0 job_search_link = f"https://www.linkedin.com/voyager/api/voyagerJobsDashJobCards?decorationId=com.linkedin.voyager.dash.deco.jobs.search.JobSearchCardsCollection-192&count=25&q=jobSearch&query=(origin:JOB_SEARCH_PAGE_SEARCH_BUTTON,keywords:software%20engineer,locationUnion:(geoId:{geoid}),spellCorrectionEnabled:true)&start={start_n}" headers = [{ 'Authority': 'www.linkedin.com', 'Method': 'GET', 'Scheme': 'https', 'Accept': 'application/vnd.linkedin.normalized+json+2.1', 'Accept-Encoding': 'gzip, deflate, br', 'Accept-Language': 'en-US,en;q=0.9', 'Cookie': "; ".join([f"{key}={value}" for key, value in session.cookies.items()]), 'Csrf-Token': session.cookies.get('JSESSIONID').strip('"'), 'User-Agent': 'OOOO', 'X-Li-Track': 'OOOO' } for session in [s]] r = s.get(job_search_link,headers=headers[0]) 後記:結果發現github有人做了 linkedin apiQQ,當作練習吧 - https://github.com/tomquirk/linkedin-api -

Read more →

February 12, 2024

20240211-taiwan-job-insights

#job

網頁互動版 資料來源:Levels Fyi 台灣 在台灣 軟體工程師 做什麼最賺錢? Android先猜應該是因為Google的關係拉高平均,Testing有點意外,Backend也是常常被提到成長幅度較大的,Networking先猜應該是網通廠MTK之類的。 AI 天花板高一點,但整體比做產品、嵌入式系統低。 在台灣 軟體工程師 做什麼底薪最好? 起薪最高Android,但成長幅度最高是Backend,但只有很少一部分 在台灣 Android 去哪間? 果然Google最高,但起薪是MTK比較高,之前不知道MTK也有Android,以前以為只有網通 從看到一些強者從Google跳槽到NV後,這張圖好像不會很意外。 這個問我爸後,原來Android不只有手機,許多如smart TV等底層很多都是Android 在台灣 Testing 去哪間? 原來Testing是被Apple拉高,大部分頂級外商也都有Testing職位 在台灣 ML/AI 去哪間? 在台灣ML給最高是Amazon,意外的是街口竟然比外商及半導體公司高 在台灣 Production 去哪間?

Read more →

February 11, 2024

20240211-pastebin-design

#system_design

Question 設計像是『Pastebin』,一個可以讓使用者輸入文字並且取得分享鏈結的系統 Solutions Step 1: Scope the Problem 系統不需要有帳戶功能及編輯檔案 系統需要追蹤頁面存取次數 過舊的檔案要定時刪除 使用者不應該很容易猜到網址 除了frontend 還有api 統計資料會顯示在stats分頁 Step 2: Make Reasonable Assumptions 系統的traffic十分繁重且包含數以百萬的document traffic不是平均分散在不同document Step 3: Draw the Major Components 如何儲存doc? db file: 因為檔案可能很大,搜尋要比較快的話存檔案比較好 簡單設計方式: graph TD A(URL to File Database) --> B(server with files) A(URL to File Database) --> C(server with files) A(URL to File Database) --> D(server with files) db 用來存file location db存traffic anlysis(timestamp, IP, address and location) Step 4: Identify the Key Issue 有部分資料會被頻繁讀取,若存在檔案系統,存取會較花時間,因此可能需要cache,由於不會有更新doc,所以cache不會有資料不合法問題 考慮從URL建立hash map的 database sharding 問題:如果要新增server,如何redistribute doc? Generating URLs 鏈結要比較難被猜到 使用GUID,缺點:太長 10碼英數混合,容易有碰撞問題 可以搭配資料庫查詢是否碰撞 Analytics 有兩個選擇

Read more →

February 11, 2024

20240209-job-insights

#job#linkedin#level_fyi

system design1. Scope the problem 可以知道現在有什麼工作機會、該公司位於總體的薪水級距 可以知道最近就業市場中需要的工作技能 如何讓自己更搶手、薪水更高? 技能vs薪水級距 2. Reasonable Assumptions 雇主資料每天會更新一次 刪除大於半年以上的 job 高價值產業、薪水頻繁更新,其餘不一定 3. Key Component 探索資料 Taiwan 資料:[[20240211-taiwan-job-insights]] 全球 找地區 (reddit) Do most software engineers eventually make $200K+ Occupational Employment and Wages, May 2022 (bls.gov) (reddit) Aren’t EU salaries are too low compared to Eastern European? 全球公司產業排名

Read more →

February 9, 2024

20240207-dcard-crawler

#web_scraping#dcard#反爬蟲#selenium#jieba#playright#DrissionPage

https://github.com/alanhc/dcard_crawler.git Backgorund 有些反爬蟲會針對selenium偵測,因此使用 undetected-chromedriver 先去 chrome://settings/help 確定chrome是最新版本 playwright 比 seleium 快 DrissionPage vs playwright DrissionPage 比較快 0.844653 秒 vs 3.023822 秒 不會觸發一些反爬蟲措施 斷詞 https://www.fontpalace.com/font-download/SimHei/ 文字雲 ckip-transformers 文字雲 jieba 比較 ckip-transformers ckip-transformers jieba Result 爬蟲時間:DrissionPage < Playwright < seleium 段詞: ckip-transformers > jieba Ref # jieba分词过滤停顿词、标点符号及统计词频 https://github.com/alanhc/dcard_crawler.git https://github.com/ckiplab/ckip-transformers https://www.w3schools.com/cssref/css_selectors.php https://www.zenrows.com/blog/playwright-scraping#step-five-taking-screenshots-with-playwright

Read more →

February 7, 2024

20240205-salesrank-design

#system_design

Question 設計一個有多類別的產品ranking網站 Solutions Step 1 Scope the problem 只跟問題相關、而不是整個系統,包含前端及購買component 定義什麼是salesrank,包含前天、上週、上個月 假設有多個類別,且不會有子類別 Step 2 Make Reasonable Assumptions 假設不用更新全部資料 熱門商品數字要精確、不熱門的可以不用那麼精確 熱門資料要每小時更新,其餘的超過7天不用很精確 Step 3 Draw the Major Component graph LR A(Purchase System) --> |orders added to db| B(Database) B(Database) --> |sort| C(Salesrank Data) C(Salesrank Data) --> D(Frontend) A(Purchase System) --> B(Database) C(Salesrank Data) --> D(Frontend) Step 4 Identity the Key Issues 分析非常昂貴 若把資料全部存在一個表,每天會區要更新,所以可以拆分成ID+日期 example Prod ID Total Sun Mon Prod ID Cat ID 資料庫被頻繁寫入 可能會需要batch write,在之前可能先cache在某種memory,但要考慮是否能放進hash table,假設有1000萬筆資料… 注意更新sales rank與資料寫入的時間,確保不會有偏差 join 查詢非常貴 與其先將資料裡每個類別sort過再join,會花很多時間,不如一開始使用資料格式 Prod ID Cat Total Sun Mon 資料庫查詢很昂貴 如果write/search很昂貴可以使用類似log file像是map reduce 每個query使用檔案及資料夾分類 Follower up 你如何會碰到接下來的bottleneck,如何解釋? 如果有子類別? 如果資料要很準確,達到30min內都是精確的

Read more →

February 5, 2024

20240203-trading-bot

#fintech#trading_bot

Python自動化交易 https://www.xq.com.tw/XQlite-Download.aspx https://ithelp.ithome.com.tw/users/20129306/ironman/3071?page=2 Ref

Read more →

February 3, 2024

quotes

#quotes

Elizabeth Sloane : Lobbying is about foresight. About anticipating your opponent’s moves and devising counter measures. The winner plots one step ahead of the opposition. And plays her trump card just after they play theirs. It’s about making sure you surprise them. And they don’t surprise you. Cynthia : That is so cynical Elizabeth Sloane : Cynical is a word used by Pollyannas to denote an absence of the naiveté they so keenly exhibit. Ref

Read more →

January 28, 2024

20240125-web_srawler_design

#system_design

Question 再設計爬蟲時,如何避免無限迴圈 Solutions 問題:無限迴圈何時發生?因為我們將鏈結化作graph,所以有可能有無限迴圈,有可能使用hashtable[v]=true及BFS ,但v怎麼設定? 但遇到URL parameters可能會有問題,比如example.com?pid=google及example.com?pid=apple可能是不同,但example.com?foo=hi 跟example.com是相同網頁 根據內容?使用 相似度,首先爬取children,計算子頁相似度極優先度,如下 開啟網頁、建立page signature根據 頁面、url query database看簽名是否最近被爬取過 如果有,新增到db到low priority 如果沒有,爬取網頁並新增資料庫

Read more →

January 25, 2024

20240125-duplicate-url-design

#system_design

Question 如何儲存1000萬的url,每個字4 byte、頁面平均100字,這樣大約會有4TB Solutions Solution 1: Disk Storage 使用two pass first pass: 將URL hash 儲存,分成 每個1G,共4000chunk,儲存URL u到<x>.txt <x>.txt where x = hash(u%4000) second pass: 讀入memory、建立hash table、尋找重複 Solution 2: Multiple Machines 跟two pass一樣,只是在不同機器 Pros 可以平行處理,對大型資料效率佳 Cons 複雜、維護多個機器困難

Read more →

January 25, 2024

20240125-cache-design

#system_design

Question 設計一個簡單搜尋引擎的webserver,假設系統有100台機器負責回應queries,有個昂貴的function,processSearch(string query),機器的選擇是隨機的,同一台機器回應可能會不一樣,請設計最相關queries的caching機制,請解釋當資料改變時如何更新cache Solutions 與面試官討論假設 Assumptions 沒有最正確的答案 所有的query 發生在機器最初呼叫時 cache的queries要有百萬等級 在機器間呼叫要相對快 結果是order list,並且有50字以內title及200字summary 最熱門的會極端熱門,而且隨時都應該在cache System Requirements 根據key有效檢索 過期舊資料應該被刪除 Step 1 design a cache for a single system 如何有效根據key新增及刪除資料? lined list 可以有效快速刪除特定節點、限制長度 hashtable可以有效找尋data 使用hashmap map query 到特定node Step 2 Expand to many machines Option 1: Each machine has its own cache Pros 相對快、因為沒有machine-to-machine call Cons 如果有很多重複的query會很沒有效率 Option 2: Each machine has a copy of the cache Pros 在cache一定會找得到 Cons 更新、佔用空間大、cache總數會較小 Option 3: Each machine stores a segment of the cache 根據 hash(query)%N

Read more →

January 25, 2024

20240124-social-network-design

#system_design

Question 如何設計給Linkedin、Facebook等公司可以處理非常大量資料的data structure?請說明如何設計計算兩個人的最短距離的 (e.g. src->B-C->dst) 演算法 Solutions Step 1 Simplify the problem - forget about the millions of users 首先使用簡單方法,先從BFS,為何不是DFS,因為DFS會非常沒有效率 另一種方式是bidirectional BFS,也就是從source跟target同時進行BFS,碰撞到即找到最短路徑 使用visited hash table避免走已經走過的路徑 程式 people: A->B->C def findPathBid(people, src, dst): while True: # search from src collision = searchLevel(people, src, dst) if collision: return mergePaths(src, dst, collision) # search from dst collision = searchLevel(people, dst, src) if collision: return mergePaths(dst, src, collision) return None 數學證明 假設每個人有k的朋友,路徑q BFS: $k+kk$ , O($k^q$) Bi BFS: $2k$, O($k^{\frac{q}{2}})$ e.g. A->B->C->D->E BFS: $100^4$ Bi BFS: $2100^2$

Read more →

January 24, 2024

20240124-break-cloudflare-bot-prevention

#web_scraping#反爬蟲

今日看到好玩的東西,改天有時間來玩 Ref https://github.com/g1879/DrissionPage

Read more →

January 24, 2024

20240123-scalper

#ticketing#web_scraping

論文研究如何避免黃牛的賣票策略,其實也順便研究了黃牛 黃牛訪談影片 【紀錄片】黃牛末日?直擊台灣黃牛產業鏈 - 第九人稱 【國昌直播】看看上週立法院在做什麼_0410 |連線前黃牛 bot https://github.com/max32002/tixcraft_bot?tab=readme-ov-file Ref

Read more →

January 23, 2024

沒環境講英文?如何跟 ChatGPT 對話,快速加強口說

#學習#english

Voice Control for ChatGPT Ref https://youtu.be/UPh0iQbg4iU?si=WVHhbe66odXGZaUK

Read more →

January 22, 2024

20240122-stock-data

#system_design

Question 設計一個可以有1000 client 可以取得最後的開高收低,已經有資料、可以自行決定儲存,要怎麼設計client說明幾種不同的方法及為甚麼使用,可以用任意技術及可以選擇任意分散機制 Solutions 先考慮以下幾點 Client Ease of use: 對顧客使用簡單且有用 Ease for Our selves: 對我們來說好實作且好維護 Flexibility for future demand: 如何根據真實世界需求彈性調整 Scalability and Efficiency: 注意解決有效性 Propsal 1 file 使用簡單text file,且讓顧客透過FTP下載 Pros 簡單好維護、方便閱讀、備份 Cons 搜尋、排序困難 新增資料會break paring mechanism Propsal 2 SQL Pros 方便查詢且有效率 rolling back, backing up, security 已經有,不用重新造輪子 方便整合現有應用,因為SQL幾乎是軟體開發標準 Cons 笨重,會複雜化系統 人類難閱讀 對於client要注意、不該給的權限、使否執行昂貴、沒效率的queries Propsal 3 XML Pros easy to distirbute, 對機器、人類好閱讀 大部分程式都支援XML 很好新增 插入 有很多工具可以back up Cons 執行query 需要取得全部data client 會有全部資料,會沒有效率 沒有正確的答案,雖然看起來file的做法最不好,每種方法都有trade off Ref

Read more →

January 22, 2024

20240122-ntu-cool-video-download

#video#ntu

Ref https://www.youtube.com/watch?v=hT6A8zRn0Ck&t=31s&ab_channel=%E9%82%8A%E7%B7%A3%E4%BA%BA%E7%9A%84%E5%9E%83%E5%9C%BE%E6%A1%B6

Read more →

January 22, 2024

20240121-Web-Scraping-Instagram-with-Selenium

#crawler#web_scraping#instagram

https://github.com/alanhc/bot/blob/main/instagram.ipynb Ref https://youtu.be/iJGvYBH9mcY?si=lVPMP3EG68ppn5y_

Read more →

January 21, 2024

20240119-OSINT

#security#instagram#twitter

一開始看到 The KK Show - 187 中共網軍的敵人 - 沈伯洋 【賀瓏夜夜秀】沈伯洋 被攻擊炎上是榮幸 The KK Show - 34 小粉紅殺手 - 沈伯洋(助理)教授 攻敵必救、遊說、關鍵人物、 網軍常見手法全面解析,製造網路恐懼效應,應立法管制嗎?【時事評判】 相關文章 【滲透測試LAB】如何使用OSINT - SpiderFoot 執行情蒐 肉搜神器theHarvester 學APT攻擊找開源情資 https://www.nss.com.tw/socialmarketing/product/ptt%E9%96%8B%E6%96%87%E4%B8%80%E9%96%8B%E4%BA%94%E5%9B%9E%E6%AF%8F%E7%AF%87/ https://sectools.tw/sherlock/ 簡單操作 Facebook 爬蟲:Facebook scraper 套件介紹 https://github.com/kevinzg/facebook-scraper https://github.com/topics/osint https://github.com/topics/osint-tools https://github.com/jivoi/awesome-osint https://github.com/alishahlakhani/Facebook-comments-exporter-chrome-extension/blob/master/src/scripts/background.js: 擷取facebook comments https://www.youtube.com/watch?v=2MJt1dTqbPk&ab_channel=%E5%B0%8FLin%E8%AF%B4: 擷取facebook comments sherlock (從帳號名稱找註冊網站) 可以使用 https://github.com/sherlock-project/sherlock Twint (從twitter找貼文) 不確定是否可以使用 Analyzing Tweets with NLP in minutes with Spark, Optimus and Twint How to use Twint as an OSINT tool Osintagram (Instagram osint工具) 可以使用 https://github.com/Datalux/Osintgram?tab=readme-ov-file Ref

Read more →

January 19, 2024

20240113-data-pay

#salary#mindset

以下內容為該影片的筆記: 中國經濟變差 政府監管 員工信心 全球資產配置 美股 賺美元全權資產配置 大廠 推行要一年 大廠大家做得跟核心業務沒關 數據 有博士會有加成、做得好不需要博士、性價比不高 有用的DS? 第一份工作很重要 拿到最好的工作 儘早感受真實世界在想什麼比較重要 面試 business sense 統計、SQL、python、analyical、business(商業問題化成數據可解決)、product sense(找重點) 有沒有思考足夠多的trade-off 有沒有把東西推到落地 這個方法的理解是否是本質的理解 DS學徒制學習 統計理論很重要 Scientist:用科學方法論理解世界、data & model 只是輔助 ML scientist pay 會多一些 很多聰明人擠 apply跟發揮價值很少 懂業務的analytics非常少 Ref https://youtu.be/A8GWS00nYDQ?si=mv4ORUgu4cxO45d1

Read more →

January 13, 2024

20240108-attention

#學習

公司 → 搶奪注意力 太多分心事 克服 決心、自我反省 why? 手機成癮 多巴安 → 採取行動獲得獎勵 看手機→獎勵→空虛 (重複)久了會疲乏 →思考力下降 高度專注任務難以進行 因為需要相同刺激 多巴安排毒 = 減少外在刺激 (激烈)24-48 小時內 斷絕 網路 社群媒體 手機遊戲 ,使用散步 冥想替代 部分排毒:找出最容易分心刺激來源,有意識限制,減少使用時間 找出最容易成癮的 逛網購、短影音 找出想分析原因 戒掉衝動 想為什麼想滑?吸引?當下事情太困難 解決可以解決當前問題的替換事項 找到有停止點的替換事項 e.g. 書 拉筋 放鬆 保持客觀、不批判 感受情緒 延遲享樂 自我控制 現代 太習慣立即性獎賞 滑手機 太習慣立即性想法 影響人際 思考現在的事情對長遠影響 好的留不好的改 有意識計劃每一天:減少分心 早晨看 計畫 e.g. notion ,而不是看email等 → 都在處理別人事情的陷阱 明確的目標、計畫 把零碎時間填滿 Ref https://youtu.be/gvOOgqcpbvU?si=GVwLMdc0DqtdpWC2

Read more →

January 8, 2024

20240107-notion-websire

#notion

使用這套件可以讓notion嵌入到網站 因為不能使用iframe 將notion嵌入,而大多數的solution都要付費 Ref https://github.com/NotionX/react-notion-x https://github.com/NotionX/react-notion-x/tree/master/examples/minimal

Read more →

January 7, 2024

20231222-socket-io

#socket#socketio

https://signal.org/blog/facebook-messenger/ https://github.com/signalapp/libsignal-protocol-javascript Ref https://socket.io/docs/v4/tutorial/ending-notes

Read more →

December 22, 2023

20231217-ntu-matches

#vector_database#select

先請AI生成資料 prompt 請生成三組男女,各有各的自我介紹,僅說明自己,這個叫做content 請將這三組男女配對 用第一個使用者去敘述他配對的對象,這叫做mate 生成以上敘述的json資料,共會有六筆,有mate, content, gender, wish_gender欄位 回傳 { "mate":"我心目中的理想伴侶是一個善良、聰明、有趣的人。她應該是一個有自己興趣愛好,能夠獨立思考和行動的人。她應該也是一個幽默風趣的人,能夠讓我的生活充滿樂趣。", "content":"我是一名 25 歲的男性軟體工程師。我喜歡閱讀、寫作和旅行。我是一個善良、聰明、有趣的人,希望找到一個和我一樣的人。", "gender":"male", "wish_gender":"female" }, { "mate":"我心目中的理想伴侶是一個陽光、幽默、有責任心的人。他應該是一個熱愛生活,積極向上的人。他應該也是一個有責任心的人,能夠照顧好我和家庭。", "content":"我是一名 24 歲的女性護士。我喜歡烹飪、看電影和逛街。我是一個陽光、幽默、有責任心的人,希望找到一個和我一樣的人。", "gender":"female", "wish_gender":"male" }, { "mate":"我心目中的理想伴侶是一個溫柔、體貼、有愛心的女性。她應該是一個善解人意,能夠包容我的人。她應該也是一個有愛心的女性,能夠與我一起去關愛他人。", "content":"我是一名 26 歲的男性律師。我喜歡運動、打球和聽音樂。我是一個溫柔、體貼、有愛心的人,希望找到一個和我一樣的人。", "gender":"male", "wish_gender":"female" }, { "mate":"我心目中的理想伴侶是一個善良、聰明、有趣的人。她應該是一個有自己興趣愛好,能夠獨立思考和行動的人。她應該也是一個幽默風趣的人,能夠讓我的生活充滿樂趣。", "content":"我是一名 25 歲的女性護士。我喜歡烹飪、看電影和逛街。我是一個善良、聰明、有趣的人,希望找到一個和我一樣的人。", "gender":"female", "wish_gender":"male" }, { "mate":"我心目中的理想伴侶是一個陽光、幽默、有責任心的人。他應該是一個熱愛生活,積極向上的人。他應該也是一個有責任心的人,能夠照顧好我和家庭。", "content":"我是一名 26 歲的男性軟體工程師。我喜歡運動、打球和聽音樂。我是一個陽光、幽默、有責任心的人,希望找到一個和我一樣的人。", "gender":"male", "wish_gender":"female" } Vector Database %load_ext dotenv %dotenv import weaviate, os # Connect with Weaviate Embedded client = weaviate.connect_to_embedded( version="1.22.4", headers={ "X-OpenAI-Api-Key": os.environ[ "OPENAI_API_KEY" ], # Replace with your inference API key }, ) client.is_ready() import weaviate.classes as wvc if client.collections.exists("Dating"): client.collections.delete("Dating") client.collections.create( name="Dating", vectorizer_config=wvc.Configure.Vectorizer.text2vec_openai(), # wvc.Configure.Vectorizer.text2vec_cohere() ) Insert questions = client.collections.get("Dating") questions.data.insert_many(data) search print(data[0]["mate"]) from weaviate.classes import Filter response = questions.query.hybrid( data[0]["mate"], alpha=0.7, filters=( Filter("gender").equal(data[0]["wish_gender"]) & ( Filter("wish_gender").equal(data[0]["gender"]) | Filter("wish_gender").equal("others") ) ), limit=2, ) for item in response.objects: print(item.properties) 我心目中的理想伴侶是一個善良、聰明、有趣的人。她應該是一個有自己興趣愛好,能夠獨立思考和行動的人。她應該也是一個幽默風趣的人,能夠讓我的生活充滿樂趣。 {'mate': '我心目中的理想伴侶是一個善良、聰明、有趣的人。她應該是一個有自己興趣愛好,能夠獨立思考和行動的人。她應該也是一個幽默風趣的人,能夠讓我的生活充滿樂趣。', 'wish_gender': 'others', 'gender': 'female', 'content': '我是一名 25 歲的女性護士。我喜歡烹飪、看電影和逛街。我是一個善良、聰明、有趣的人,希望找到一個和我一樣的人。'} {'content': '我是一名 24 歲的女性護士。我喜歡烹飪、看電影和逛街。我是一個陽光、幽默、有責任心的人,希望找到一個和我一樣的人。', 'wish_gender': 'male', 'gender': 'female', 'mate': '我心目中的理想伴侶是一個陽光、幽默、有責任心的人。他應該是一個熱愛生活,積極向上的人。他應該也是一個有責任心的人,能夠照顧好我和家庭。'} Ref

Read more →

December 17, 2023

20231217-google-gemini

#genai#llm#google

Ref https://www.kaggle.com/code/alanhc/gemini-api-starter-notebook https://makersuite.google.com/app/library

Read more →

December 17, 2023

20231213-pyspark

#pyspark#pandas#polars

Ref https://learn.microsoft.com/en-us/azure/databricks/pandas/pyspark-pandas-conversion https://s3.amazonaws.com/assets.datacamp.com/blog_assets/PySpark_Cheat_Sheet_Python.pdf Pandas vs PySpark..! Data Processing: Pandas vs PySpark vs Polars Polars vs. pandas: What’s the Difference?

Read more →

December 13, 2023

20231210-convert-post-markdown

#markdown

medium https://github.com/dtesler/medium-to-markdown Blogger https://codebeautify.org/html-to-markdown https://github.com/cheshrkat/blogger-archive-converter Ref

Read more →

December 10, 2023

20231209-docker-machine-learning

#docker#machine_learning

Docker docker search tensorflow docker pull jupyter/tensorflow-notebook docker run jupyter/tensorflow-notebook -p 8000:8888 -p out:in Transformers from transformers import pipeline pip install transformers docker compose services: transformers-notebook: build: ./Dockerfile | image: jupyter/tensorflow-notebook - 8000:8888 environment - JUPYTER_TOKEN=token volumes - ./:/home/{user} FROM jupyter/tensorflow-notebook USER $NB_UID //user | USER root RUN pip install --upgrade pip &&\ pip install transformers && \ pip install pysrt && \ fix-permissions "/home/${NB_USER}" COPY file.srt Translate.ipynb ./ docker-compose up

Read more →

December 9, 2023

20231209-AI-music-example

#ai#music

AI 音樂風格轉換太酷了 Frank Sinatra - A Cruel Angel’s Thesis Careless Whisper - Frank Sinatra AI Cover Ref

Read more →

December 9, 2023

20231202-twitter-bot

#bot#twitter#api

1. 使用 twitter API 先去 dashboard建立App,並在User authentication settings > 設定 複製 Keys and tokens 建立tweet import tweepy bearer_token = "" consumer_key = "" consumer_secret = "" access_token = "" access_token_secret = "" client = tweepy.Client( consumer_key=consumer_key, consumer_secret=consumer_secret, access_token=access_token, access_token_secret=access_token_secret ) response = client.create_tweet( text="This Tweet was Tweeted using Tweepy and Twitter API v2!" ) print(f"https://twitter.com/user/status/{response.data['id']}") # return # Response(data={'edit_history_tweet_ids': ['1730651881314414696'], 'id': '1730651881314414696', 'text': 'This Tweet was Tweeted using Tweepy and Twitter API v2!1'}, includes={}, errors=[], meta={}) # get me response = client.get_me() response 免費版只有幾個 API https://developer.twitter.com/en/docs/twitter-api/getting-started/about-twitter-api

Read more →

December 2, 2023

20231130-Building-and-Evaluating-Advanced-RAG (未完)

#llm#not_finish

Advance RAG Pipeline RAG Triad of metrics 看到13:01 Ref https://learn.deeplearning.ai/building-evaluating-advanced-rag

Read more →

November 30, 2023

Should You Use Open Source Large Language Models?

#llm

Ref https://www.youtube.com/watch?v=y9k-U9AuDeM

Read more →

November 29, 2023

20231125-cloudflare-tunnel

#self-host#cloudflare

方式一 使用 GUIrun service e.g. docker run -p 80:80 -d nginx cloudflare 設定 https://dash.cloudflare.com/ dash > Zerotrust 機器下載 註:windows 需要使用msi,用wsl 使用 docker會有問題 設定service位址 結果 訪問 前一個步驟設定的網址,成功🎉 方式2 使用 docker composeTOKEN 為 version: "3.9" services: nginx: image: nginx:latest expose: - 80 cloudflared: image: cloudflare/cloudflared:latest command: tunnel run environment: - TUNNEL_TOKEN={TOKEN} public host 設定 docker-compose up -d

Read more →

November 25, 2023

20231124-terraform-vercel

#terraform#vercel

vercel token: https://vercel.com/guides/how-do-i-use-a-vercel-api-access-token npx create-next-app nextjs-terraform-demo main.tf terraform { required_providers { vercel = { source = "vercel/vercel" version = "~> 0.3" } } } terraform init terraform { required_providers { vercel = { source = "vercel/vercel" version = "~> 0.3" } } } resource "vercel_project" "example" { name = "terraform-test-project" framework = "nextjs" git_repository = { type = "github" repo = "alanhc/nextjs-terraform-demo" } } terraform apply

Read more →

November 24, 2023

20231117-Large Language Models with Semantic Search

#llm#ai

keyword-search Setup Load needed API keys and relevant Python libaries. # !pip install cohere # !pip install weaviate-client import os from dotenv import load_dotenv, find_dotenv _ = load_dotenv(find_dotenv()) # read local .env file Let’s start by imporing Weaviate to access the Wikipedia database.

Read more →

November 17, 2023

20231116-Vector-Databases-from-Embeddings-to-Applications

#llm#vector_database

RAG -> vector database how-to-obtain-vector-representations-of-data ![[L1_Embeddings]] search-for-similar-vectors ![[L2_kNN (1)]] approximate-nearest-neighbours ![[L3_approximate_nearest_neighbours]] vector-databases ![[L4_Objects_Vectors]] sparse,-dense,-and-hybrid-search

Read more →

November 16, 2023

20231115-How-to-Build-An-MVP-Startup-School

#創業#mvp

16:52 twich 創辦人(Michael Seibel) 1. 從使用者學習 不要害怕失去客戶,因為才剛開始 Fake steve jobs 不要執著打造完美產品 e.g. 第一次的iphone 沒有app store的iphone 都是 經過時間迭代的產品 第一代 Airbnb 解決問題是你的責任,不是客戶的 從市場中學習 一個MVP是最快從客戶學習的方法 Ref https://youtu.be/QRZ_l7cVzzU?si=oGWmErG3cp8hxwtq

Read more →

November 15, 2023

20211115-LIVEBuilding-Multi-Modal-Search-with-Vector-Databases

#ai#llm#vector_database

problem? 關鍵字搜尋 vector embeding https://github.com/weaviate-tutorials/multimodal-workshop 可以直接使用openai 提供 或 self host 1.1 1.2 alpha: 1: 使用100%vector search 0.7:70% vector 0.3: keyword 2 Ref https://www.youtube.com/watch?v=3WUobZryyok https://github.com/weaviate-tutorials/multimodal-workshop https://github.com/alanhc/multimodal-workshop https://docs.google.com/presentation/d/1sS-bxJ-k9EuESH2VhpwnybY3QyV_9FdxHLmZLCSpuSM/edit#slide=id.g29ae64ebf98_0_5

Read more →

November 15, 2023

20210922-fintech

#fintech#course

Links http://mirlab.org/jang/courses/fintech/schedule.asp w2 ROI是什麼意思?股票投資的年化報酬率怎麼算(附EXCEL) 投資報酬率 Return of Investment 簡稱ROI:投資獲利比率 投資報酬率(%) = 投資淨損益 / 總投入資金 年化報酬率 Internal Rate of Return,縮寫:IRR:可用於比較投資方案 年化報酬率(%) = (總報酬率+1)^(1/年數) -1 總報酬率 :幾年後賺多少 (1+年化報酬率)^(年數) -1 股票投資報酬率 股票損益 = 1. 資本利得:也就是股價的漲跌 + 2. 股息配發:拿到手中的現金股利、股票股利會影響股價 複利 IRR 綠角財經筆記 股票怎麼買?600秒學完股票交易基礎 | 夯翻鼠FQ30 投資理財(9:32) 開戶 證券戶、交割戶(最好同一個,可共用網銀) 手續費:電子下單6折 < 23300以20元算 流程 委託 > 搓合 > 交割(T+2) 違約交割:T+2 還沒有入金到交割戶 交易 台股 一~五 0830-0900:試搓合 0900-1330:交易時間(盤中) 1330-1430:(盤後) 零股買賣、定價交易 單位 張(1000股) 價格 平盤:前天收盤價 台股:+/- 10% 漲跌 成本 手續費:成交金額 * 0.1425% 手機下單 有6折 不滿20以20算 證交稅:0.3% 要聽懂股票國語言~先學會金字塔這四面 (基本/籌碼/技術/消息) | 夯翻鼠FQ24 股票入門(7:32) 基本:年報、季報、獲利營收、商品報價、年度淡旺季

Read more →

November 13, 2023

2021112-upload-large-file

#nextjs#file#frontend

upload api import { connectToDb, fileExists } from "@/lib/mongodb"; import { NextResponse } from "next/server"; import { Readable } from "stream"; import formidable, { errors as formidableErrors } from 'formidable'; var fs = require('fs'); var md5 = require('md5'); export const config = { api: { bodyParser: false, } }; type ProcessedFiles = Array<[string, File]>; export default async function handler(req: any, res: any) { const { bucket } = await connectToDb(); // get the form data // const data = await req.formData(); // Access uploaded files directly using req.files //const files = Array.from(req.files.entries()); let status = 200, resultBody = { status: 'ok', message: 'Files were uploaded successfully' }; const form = formidable({ uploadDir: "/tmp" }); let fields; let files; try { form.parse(req, async (err, fields, files) => { console.log('fields:', fields); console.log('files:', files); for (const [key, value] of Object.entries(files)) { const isFile = typeof value == "object"; if (isFile) { let file: any = value[0] let filename = file.originalFilename let type = file.mimetype let buffer = fs.readFileSync(file.filepath); const stream = Readable.from(buffer); const hash = md5(buffer) const existing = await fileExists(hash); if (existing) { // If file already exists, let's skip it. // If you want a different behavior such as override, modify this part. continue; } const uploadStream = bucket.openUploadStream(filename, { // make sure to add content type so that it will be easier to set later. contentType: type, metadata: { hash:hash }, //add your metadata here if any }); // pipe the readable stream to a writeable stream to save it to the database await stream.pipe(uploadStream); res.status(200).json({ hash: hash }) } } }); } catch (err: any) { // example to check for a very specific error if (err.code === formidableErrors.maxFieldsExceeded) { } console.error(err); res.writeHead(err.httpCode || 400, { 'Content-Type': 'text/plain' }); res.end(String(err)); return; } return res.json({ success: true }); } response image import { MongoClient, ObjectId, GridFSBucket } from 'mongodb'; import clientPromise, { connectToDb } from "@/lib/mongodb"; export default async function handler(req:any, res:any) { const client = await clientPromise; const {hash} = req.query; const db = client.db("fanstick"); const metadata:any = await db .collection('media.files') .find({"metadata.hash":hash}) .toArray() console.log(metadata) const {bucket}= await connectToDb() res.writeHead(200, { 'Content-Type': metadata[0].contentType }); bucket.openDownloadStream(metadata[0]._id) .on('data', (chunk) => { res.write(chunk); }) .on('end', () => { res.end(); }) .on('error', (err) => { res.status(500).json({ error: err.message }); }); // const file:any = await db // .collection('media.chunks') // .find({"files_id":metadata[0]._id}) // .toArray() // console.log(file[0].data) // res.setHeader('Content-Type', metadata[0].contentType) // res.send(file[0].data) } Frontend fetch(`/backend/upload/file`, { method: "POST", body: formData }).then((res) => res.json()) .then(({hash}) => { const image_url = `${process.env.Deploy_URL}/api/file/${hash}` setImage(image_url) form.setFieldValue(field.name,image_url) }) Ref https://github.com/gapon2401/upload-files-nextjs/blob/master/pages/api/upload.ts https://reacthustle.com/blog/how-to-upload-retrieve-images-to-mongodb-using-nextjs-13-app-router

Read more →

November 12, 2023

filebase

#ipfs

Ref https://docs.filebase.com/getting-started/ipfs-getting-started-guide

Read more →

November 11, 2023

80分鐘快速了解大型語言模型-5-30有咒術迴戰雷

#llm#ai

客製化GPT https://openai.com/blog/introducing-gpts 串接dalle 自動生成頭像 GPT: Generative Pre-trained Transformer others Google Bard anthropic Claude GPT 訓練:文字接龍 e.g. 台灣大->chatGPT-> 學 台灣大->chatGPT-> (機率)學10% 歌、6% https://platform.openai.com/docs/tokenizer ChatGPT目前可以讀300頁pdt chatgpt可能跟 Instruct gpt有關 gpt 3.5 人類去調整

Read more →

November 10, 2023

20231110-生成式AI淺談圖像生成模型-Diffusion-Model-原理

#ai

Ref https://www.youtube.com/watch?v=azBugJzmz-o

Read more →

November 10, 2023

20231108-How-Diffusion-Models-Work

#ai

Intuition Sampling from typing import Dict, Tuple from tqdm import tqdm import torch import torch.nn as nn import torch.nn.functional as F from torch.utils.data import DataLoader from torchvision import models, transforms from torchvision.utils import save_image, make_grid import matplotlib.pyplot as plt from matplotlib.animation import FuncAnimation, PillowWriter import numpy as np from IPython.display import HTML from diffusion_utilities import * # Setting Things Up class ContextUnet(nn.Module): def __init__(self, in_channels, n_feat=256, n_cfeat=10, height=28): # cfeat - context features super(ContextUnet, self).__init__() # number of input channels, number of intermediate feature maps and number of classes self.in_channels = in_channels self.n_feat = n_feat self.n_cfeat = n_cfeat self.h = height #assume h == w. must be divisible by 4, so 28,24,20,16... # Initialize the initial convolutional layer self.init_conv = ResidualConvBlock(in_channels, n_feat, is_res=True) # Initialize the down-sampling path of the U-Net with two levels self.down1 = UnetDown(n_feat, n_feat) # down1 #[10, 256, 8, 8] self.down2 = UnetDown(n_feat, 2 * n_feat) # down2 #[10, 256, 4, 4] # original: self.to_vec = nn.Sequential(nn.AvgPool2d(7), nn.GELU()) self.to_vec = nn.Sequential(nn.AvgPool2d((4)), nn.GELU()) # Embed the timestep and context labels with a one-layer fully connected neural network self.timeembed1 = EmbedFC(1, 2*n_feat) self.timeembed2 = EmbedFC(1, 1*n_feat) self.contextembed1 = EmbedFC(n_cfeat, 2*n_feat) self.contextembed2 = EmbedFC(n_cfeat, 1*n_feat) # Initialize the up-sampling path of the U-Net with three levels self.up0 = nn.Sequential( nn.ConvTranspose2d(2 * n_feat, 2 * n_feat, self.h//4, self.h//4), # up-sample nn.GroupNorm(8, 2 * n_feat), # normalize nn.ReLU(), ) self.up1 = UnetUp(4 * n_feat, n_feat) self.up2 = UnetUp(2 * n_feat, n_feat) # Initialize the final convolutional layers to map to the same number of channels as the input image self.out = nn.Sequential( nn.Conv2d(2 * n_feat, n_feat, 3, 1, 1), # reduce number of feature maps #in_channels, out_channels, kernel_size, stride=1, padding=0 nn.GroupNorm(8, n_feat), # normalize nn.ReLU(), nn.Conv2d(n_feat, self.in_channels, 3, 1, 1), # map to same number of channels as input ) def forward(self, x, t, c=None): """ x : (batch, n_feat, h, w) : input image t : (batch, n_cfeat) : time step c : (batch, n_classes) : context label """ # x is the input image, c is the context label, t is the timestep, context_mask says which samples to block the context on # pass the input image through the initial convolutional layer x = self.init_conv(x) # pass the result through the down-sampling path down1 = self.down1(x) #[10, 256, 8, 8] down2 = self.down2(down1) #[10, 256, 4, 4] # convert the feature maps to a vector and apply an activation hiddenvec = self.to_vec(down2) # mask out context if context_mask == 1 if c is None: c = torch.zeros(x.shape[0], self.n_cfeat).to(x) # embed context and timestep cemb1 = self.contextembed1(c).view(-1, self.n_feat * 2, 1, 1) # (batch, 2*n_feat, 1,1) temb1 = self.timeembed1(t).view(-1, self.n_feat * 2, 1, 1) cemb2 = self.contextembed2(c).view(-1, self.n_feat, 1, 1) temb2 = self.timeembed2(t).view(-1, self.n_feat, 1, 1) #print(f"uunet forward: cemb1 {cemb1.shape}. temb1 {temb1.shape}, cemb2 {cemb2.shape}. temb2 {temb2.shape}") up1 = self.up0(hiddenvec) up2 = self.up1(cemb1*up1 + temb1, down2) # add and multiply embeddings up3 = self.up2(cemb2*up2 + temb2, down1) out = self.out(torch.cat((up3, x), 1)) return out # hyperparameters # diffusion hyperparameters timesteps = 500 beta1 = 1e-4 beta2 = 0.02 # network hyperparameters device = torch.device("cuda:0" if torch.cuda.is_available() else torch.device('cpu')) n_feat = 64 # 64 hidden dimension feature n_cfeat = 5 # context vector is of size 5 height = 16 # 16x16 image save_dir = './weights/' # construct DDPM noise schedule b_t = (beta2 - beta1) * torch.linspace(0, 1, timesteps + 1, device=device) + beta1 a_t = 1 - b_t ab_t = torch.cumsum(a_t.log(), dim=0).exp() ab_t[0] = 1 # construct model nn_model = ContextUnet(in_channels=3, n_feat=n_feat, n_cfeat=n_cfeat, height=height).to(device) # Sampling # helper function; removes the predicted noise (but adds some noise back in to avoid collapse) def denoise_add_noise(x, t, pred_noise, z=None): if z is None: z = torch.randn_like(x) noise = b_t.sqrt()[t] * z mean = (x - pred_noise * ((1 - a_t[t]) / (1 - ab_t[t]).sqrt())) / a_t[t].sqrt() return mean + noise # load in model weights and set to eval mode nn_model.load_state_dict(torch.load(f"{save_dir}/model_trained.pth", map_location=device)) nn_model.eval() print("Loaded in Model") # sample using standard algorithm @torch.no_grad() def sample_ddpm(n_sample, save_rate=20): # x_T ~ N(0, 1), sample initial noise samples = torch.randn(n_sample, 3, height, height).to(device) # array to keep track of generated steps for plotting intermediate = [] for i in range(timesteps, 0, -1): print(f'sampling timestep {i:3d}', end='\r') # reshape time tensor t = torch.tensor([i / timesteps])[:, None, None, None].to(device) # sample some random noise to inject back in. For i = 1, don't add back in noise z = torch.randn_like(samples) if i > 1 else 0 eps = nn_model(samples, t) # predict noise e_(x_t,t) samples = denoise_add_noise(samples, i, eps, z) if i % save_rate ==0 or i==timesteps or i<8: intermediate.append(samples.detach().cpu().numpy()) intermediate = np.stack(intermediate) return samples, intermediate # visualize samples plt.clf() samples, intermediate_ddpm = sample_ddpm(32) animation_ddpm = plot_sample(intermediate_ddpm,32,4,save_dir, "ani_run", None, save=False) HTML(animation_ddpm.to_jshtml()) #### Demonstrate incorrectly sample without adding the 'extra noise' # incorrectly sample without adding in noise @torch.no_grad() def sample_ddpm_incorrect(n_sample): # x_T ~ N(0, 1), sample initial noise samples = torch.randn(n_sample, 3, height, height).to(device) # array to keep track of generated steps for plotting intermediate = [] for i in range(timesteps, 0, -1): print(f'sampling timestep {i:3d}', end='\r') # reshape time tensor t = torch.tensor([i / timesteps])[:, None, None, None].to(device) # don't add back in noise z = 0 eps = nn_model(samples, t) # predict noise e_(x_t,t) samples = denoise_add_noise(samples, i, eps, z) if i%20==0 or i==timesteps or i<8: intermediate.append(samples.detach().cpu().numpy()) intermediate = np.stack(intermediate) return samples, intermediate # visualize samples plt.clf() samples, intermediate = sample_ddpm_incorrect(32) animation = plot_sample(intermediate,32,4,save_dir, "ani_run", None, save=False) HTML(animation.to_jshtml())

Read more →

November 8, 2023

20231107-MUI-toolpad

#frontend#mui

很好做prototype的前端網站 Ref https://mui.com/toolpad/getting-started/first-app/

Read more →

November 7, 2023

20231107-imgbb

#upload#image

免費圖片上傳api const onDrop = useCallback((acceptedFiles: any) => { acceptedFiles.forEach((file: any) => { const reader:any = new FileReader() reader.onabort = () => console.log('file reading was aborted') reader.onerror = () => console.log('file reading has failed') reader.onload = async () => { const base64String:any = reader.result.split(',')[1]; console.log(base64String); let data = new FormData() data.append("image", base64String) fetch(`https://api.imgbb.com/1/upload?expiration=600&key=${api_key}`, { method: "POST", body:data }).then((res)=>console.log(res)) } reader.readAsDataURL(file) }) }, []) Ref https://api.imgbb.com/

Read more →

November 7, 2023

20231104-learn-cosmos

#cosmos#blockchain

Ignite CLI: 它是Cosmos SDK的開發人員友善介面 https://docs.ignite.com/guide 建立區塊鏈 ignite scaffold chain mars cd mars ignite chain serve ignite scaffold chain hello 查詢 nft marketplace https://www.stargaze.zone/marketplace Ref

Read more →

November 4, 2023

20231103-linklist

#DSA

c++ #include <iostream> using namespace std; struct Node { int data; Node* next; }; Node* head = nullptr; void insertNode(int data) { Node* newNode = new Node(); newNode->data = data; newNode->next = nullptr; //head沒有東西 if (head == nullptr) { head = newNode; return; } //head有東西 Node* now = head; //找到 ->next 是空的接上去 while (now->next!=nullptr) { now = now->next; } now->next = newNode; } void deleteNode(int data) { if (head==nullptr) return; //找到要刪除的節點 Node* to_delete = head; Node* prev = nullptr; while (to_delete->data != data) { prev = to_delete; to_delete = to_delete->next; } if (to_delete!=nullptr) { if(prev == nullptr) head = to_delete->next; else prev->next = to_delete->next; delete to_delete; } } void printList() { Node* now = head; while (now!=nullptr) { cout << now->data << " "; now = now-> next; } cout << endl; } int main() { insertNode(1); insertNode(2); insertNode(3); insertNode(4); insertNode(5); printList(); // 刪除首節點 deleteNode(1); printList(); // 刪除中間 deleteNode(3); printList(); return 0; } Ref

Read more →

November 3, 2023

20231103-Finetuning-Large-Language-Models

#llm

Introduction why? 要學某種語氣等等要使用 Why finetune from llama import BasicModelRunner # Try Non-Finetuned models non_finetuned = BasicModelRunner("meta-llama/Llama-2-7b-hf") non_finetuned_output = non_finetuned("Tell me how to train my dog to sit") print(non_finetuned_output) print(non_finetuned("What do you think of Mars?")) print(non_finetuned("taylor swift's best friend")) print(non_finetuned("""Agent: I'm here to help you with your Amazon deliver order. Customer: I didn't get my item Agent: I'm sorry to hear that. Which item was it? Customer: the blanket Agent:""")) # Compare to finetuned models finetuned_model = BasicModelRunner("meta-llama/Llama-2-7b-chat-hf") finetuned_output = finetuned_model("Tell me how to train my dog to sit") print(finetuned_output) print(finetuned_model("[INST]Tell me how to train my dog to sit[/INST]")) print(non_finetuned("[INST]Tell me how to train my dog to sit[/INST]")) print(finetuned_model("What do you think of Mars?")) print(finetuned_model("taylor swift's best friend")) print(finetuned_model("""Agent: I'm here to help you with your Amazon deliver order. Customer: I didn't get my item Agent: I'm sorry to hear that. Which item was it? Customer: the blanket Agent:""")) # Compare to ChatGPT chatgpt = BasicModelRunner("chat-gpt") print(chatgpt("Tell me how to train my dog to sit")) where fineturning fits in

Read more →

November 3, 2023

20231101-generative-ai-for-everyone

#ai#llm

What is Generative AI Supervised learning (labeling things) 2010 - 2020: Large scale supervised learning LLM How? supervised learning (A->B) 重複預測下一個word 例子 寫作:rewrite for clarity 閱讀:有沒有在抱怨、情緒分析 聊天:聊天機器人 web search or LLM? LLM可能會錯,但回答比較精簡 web search有時會得到比較好的答案,但要花時間找到你要的資訊 Generative AI Applications setup import openai import os openai.api_key = os.getenv("OPENAI_API_KEY") def llm_response(prompt): response = openai.ChatCompletion.create( model='gpt-3.5-turbo', messages=[{'role':'user','content':prompt}], temperature=0 ) return response.choices[0].message['content'] classify prompt = ''' Classify the following review as having either a positive or negative sentiment: The banana pudding was really tasty! ''' response = llm_response(prompt) print(response) all_reviews = [ 'The mochi is excellent!', 'Best soup dumplings I have ever eaten.', 'Not worth the 3 month wait for a reservation.', 'The colorful tablecloths made me smile!', 'The pasta was cold.' ] all_reviews classifications = [] for review in all_reviews: prompt = f''' Classify the following review as having either a positive or negative sentiment. State your answer as a single word, either "positive" or "negative": {review} ''' response = llm_response(prompt) classifications.append(response) classifications

Read more →

November 2, 2023

Andrew-Ng-Opportunities-in-AI-2023

#ai#llm

兩個很重要的領域 監督式學習及生成式AI 生成式AI 怎麼訓練? 使用很大的資料集用監督式學習方法訓練 過去監督式學習 生成式AI會給workflow很大的改變 未來三年的價值比較 機會 1. 長期價值? Lensa 一個數位網紅的App 隨著時間熱度減退 下一個Uber、Airbnb、Tinder 這種有“長期”價值的公司在哪? 2. 客製化及不用程式碼的解決方案 雖然廣告及搜尋價值最大,但也有一些專精特定領域的機會 e.g. 500億美元 pizza 專案、稻作生長等等

Read more →

October 31, 2023

Building Systems with the ChatGPT API

#llm#course

Introduction Language Models, the Chat Format and Tokens LLM How? 使用 監督式學習 預測下一個word type Base LLM: 訓練時是去預測下一個字的訓練方式 Instruction Turned LLM:使用教學QA 如何讓BaseLLM更好? -> Instruction Turned 使用 QA Fine tune 人類評分 e.g. helpful? harmless 使用 RLHF, Reimforcelearning Human Feedback Tune LLM 限制 token: e.g. gpt3.5 turbo 只能有4000 token import os import openai import tiktoken from dotenv import load_dotenv, find_dotenv _ = load_dotenv(find_dotenv()) # read local .env file openai.api_key = os.environ['OPENAI_API_KEY'] def get_completion(prompt, model="gpt-3.5-turbo"): messages = [{"role": "user", "content": prompt}] response = openai.ChatCompletion.create( model=model, messages=messages, temperature=0, ) return response.choices[0].message["content"] response = get_completion("What is the capital of France?") print(response) def get_completion_from_messages(messages, model="gpt-3.5-turbo", temperature=0, max_tokens=500): response = openai.ChatCompletion.create( model=model, messages=messages, temperature=temperature, # this is the degree of randomness of the model's output max_tokens=max_tokens, # the maximum number of tokens the model can ouptut ) return response.choices[0].message["content"] 注意 LLM 內部是使用token # wrong prompt response = get_completion("Take the letters in lollipop \ and reverse them") print(response) # output # "lollipop" in reverse should be "popillol" # correct prompt 使用 - 隔開 response = get_completion("""Take the letters in \ l-o-l-l-i-p-o-p and reverse them""") # output 'p-o-p-i-l-l-o-l' helper function (chat) def get_completion_from_messages(messages, model="gpt-3.5-turbo", temperature=0, max_tokens=500): response = openai.ChatCompletion.create( model=model, messages=messages, temperature=temperature, # this is the degree of randomness of the model's output max_tokens=max_tokens, # the maximum number of tokens the model can ouptut ) return response.choices[0].message["content"] 使用角色定 messages = [ {'role':'system', 'content':"""You are an assistant who\ responds in the style of Dr Seuss."""}, {'role':'user', 'content':"""write me a very short poem\ about a happy carrot"""}, ] response = get_completion_from_messages(messages, temperature=1) print(response)

Read more →

October 28, 2023

20231028-mozilla-ai

#ai#llm#guide

有涵蓋LLM,由淺入深,有colab實作,還不錯 IntroductionSummarization - [colab introduction](https://colab.research.google.com/drive/1cpdhABVmqmjLfJr-qQIlOOM0Yonc_xFY#scrollTo=Jd2i2959FP3L) Ref https://share.goodnotes.com/s/bXUxVzvrKQjpNVfT9gtLSt https://ai-guide.future.mozilla.org/ colab

Read more →

October 27, 2023

20231026-ChatGPT-Prompt-Engineering-for-Developers

#llm#course

Introduction 兩種LLM模型 1. base:由訓練資料預測下一個word 2. instruction based :由指令Fine-turn / RLHF(強化學習、人類回饋) Guidelines Setup import openai import os from dotenv import load_dotenv, find_dotenv _ = load_dotenv(find_dotenv()) openai.api_key = os.getenv('OPENAI_API_KEY') helper function def get_completion(prompt, model="gpt-3.5-turbo"): messages = [{"role": "user", "content": prompt}] response = openai.ChatCompletion.create( model=model, messages=messages, temperature=0, # this is the degree of randomness of the model's output ) return response.choices[0].message["content"] Prompting Principles P1 寫具體且清晰的指令 1. 使用分隔符號 Triple quotes: ''''' Triple backticks: Triple dashes: ---, Angle brackets: ‹>, XML tags: ‹ tag> </tag> e.g.

Read more →

October 26, 2023

20231023-Pair-Programming-with-a-Large-Language-Model

#ai#llm#software_engineer#course

TL;DR LLM 可以幫助程式設計師包含:改進現有程式碼、簡化code、寫測試、優化程式除錯及解釋程式碼,使用流程為(1)建立prompt (2)取得結果 (3) 輸出結果,為了程式重複使用,會使用template機制讓呼叫比較簡單。 Palm - google 的llm模型 有三個組成 API Key GEN AI library model裡面選擇 chat bison vs text bison 差別是多次對話跟一次對話 大致上使用流程 create a prompt completion output result Getting start from utils import get_api_key import os import google.generativeai as palm from google.api_core import client_options as client_options_lib palm.configure( api_key=get_api_key(), transport="rest", client_options=client_options_lib.ClientOptions( api_endpoint=os.getenv("GOOGLE_API_BASE"), ) ) models = [m for m in palm.list_models() if 'generateText' in m.supported_generation_methods] model_bison = models[0] model_bison from google.api_core import retry @retry.Retry() def generate_text(prompt, model=model_bison, temperature=0.0): return palm.generate_text(prompt=prompt, model=model, temperature=temperature) process create a prompt prompt = "Show me how to iterate across a list in Python." completion completion = generate_text(prompt) output print(completion.result) String template import os from utils import get_api_key import google.generativeai as palm from google.api_core import client_options as client_options_lib palm.configure( api_key=get_api_key(), transport="rest", client_options=client_options_lib.ClientOptions( api_endpoint=os.getenv("GOOGLE_API_BASE"), ) ) models = [m for m in palm.list_models() if 'generateText' in m.supported_generation_methods] model_bison = models[0] model_bison from google.api_core import retry @retry.Retry() def generate_text(prompt, model=model_bison, temperature=0.0): return palm.generate_text(prompt=prompt, model=model, temperature=temperature) prompt_template = """ {priming} {question} {decorator} Your solution: """ priming_text = "You are an expert at writing clear, concise, Python code." question = "create a doubly linked list" decorator = "Insert comments for each line of code." prompt = prompt_template.format(priming=priming_text, question=question, decorator=decorator) prompt_template priming: 類似前情提要/背景 question: 要問的問題 decorator: 修飾回答樣式 Pair Progaming scenarios 1. improve existing code prompt_template = """ I don't think this code is the best way to do it in Python, can you help me? {question} Please explain, in detail, what you did to improve it. """ question = """ def func_x(array) for i in range(len(array)): print(array[i]) """ completion = generate_text( prompt = prompt_template.format(question=question) ) print(completion.result) prompt_template = """ I don't think this code is the best way to do it in Python, can you help me? {question} Please explore ***multiple ways*** of solving the problem, and explain each. """ completion = generate_text( prompt = prompt_template.format(question=question) ) print(completion.result) prompt_template = """ I don't think this code is the best way to do it in Python, can you help me? {question} Please explore multiple ways of solving the problem, and tell me which is ***the most Pythonic*** """ completion = generate_text( prompt = prompt_template.format(question=question) ) print(completion.result) 2. simplify code prompt_template = """ Can you please simplify this code for a linked list in Python? {question} Explain in detail what you did to modify it, and why. """ question = """ class Node: def __init__(self, dataval=None): self.dataval = dataval self.nextval = None class SLinkedList: def __init__(self): self.headval = None list1 = SLinkedList() list1.headval = Node("Mon") e2 = Node("Tue") e3 = Node("Wed") list1.headval.nextval = e2 e2.nextval = e3 """ completion = generate_text( prompt = prompt_template.format(question=question) ) print(completion.result) 3. write test cases prompt_template = """ Can you please create test cases in code for this Python code? {question} Explain in detail what these test cases are designed to achieve. """ # Note that the code I'm using here was output in the previous # section. Your output code may be different. question = """ class Node: def __init__(self, dataval=None): self.dataval = dataval self.nextval = None class SLinkedList: def __init__(self): self.head = None def create_linked_list(data): head = Node(data[0]) for i in range(1, len(data)): node = Node(data[i]) node.nextval = head head = node return head list1 = create_linked_list(["Mon", "Tue", "Wed"]) """ completion = generate_text( prompt = prompt_template.format(question=question) ) print(completion.result) 4. Make code more efficient prompt_template = """ Can you please make this code more efficient? {question} Explain in detail what you changed and why. """ question = """ # Returns index of x in arr if present, else -1 def binary_search(arr, low, high, x): # Check base case if high >= low: mid = (high + low) // 2 if arr[mid] == x: return mid elif arr[mid] > x: return binary_search(arr, low, mid - 1, x) else: return binary_search(arr, mid + 1, high, x) else: return -1 # Test array arr = [ 2, 3, 4, 10, 40 ] x = 10 # Function call result = binary_search(arr, 0, len(arr)-1, x) if result != -1: print("Element is present at index", str(result)) else: print("Element is not present in array") """ completion = generate_text( prompt = prompt_template.format(question=question) ) print(completion.result) 有時候輸出有可能會錯

Read more →

October 23, 2023

20231023-learning

#學習

小林說:分享有關於金融背景的ytr,分享得很棒 我是如何快速学习一个领域的 (15:49) Sumary 結構化思維可以幫助記憶,How? 方法 可信、簡短、品質好的來源,一文理解XX、八分鐘釐清 問ChatGPT 如何梳裡架構 多問為什麼:思維的捷徑 -> 帶目的搜索 沿著時間線:一個東西發展很複雜,剛起步開始講,挖掘中間怎麼發展 從結果導向的數據e.g. 股價,反應看哪個時間的事件重要 重要 找一手訊息:從底層挖掘 國家:基礎CPI、就業率 公司:年報、訪談 流程化思維 記憶大師 記52章牌:聯想法 > 找到結構 search 搜尋 問題:資料太多 整理框架 < 結構化思維 參考別人的框架 看書目錄、框架 可信來源 + 一文讀懂OOO AI (chatgpt) 會錯 > 不斷交互問 省略細節、注重重點 製作影片有樹枝 > 塞細節 一直問為什麼 帶目的搜尋,忽略不重要的部分 時間線 起源 太多資訊? 找重點=> 結果導向數據 e.g. 大波動、市場真實反映=>股價 一手訊息 流程化思維 大神有框架 有知識樹,問知識樹 整理 長文 讀兩次 第一次忽略所有細節,找關鍵性框架訊息 整理: 根據問題 想知道什麼細節 補充進去 輸出 複習 蓋起來重劃 這概念有點類似覆盤

Read more →

October 23, 2023

20231010-webauthn

#web

web 生物辨識api Ref

Read more →

October 10, 2023

20231006-fastapi-streaming

#python

main.py from fastapi import FastAPI from fastapi.responses import StreamingResponse import time app = FastAPI() def fake_data_streamer(): for i in range(10): yield b'some fake data\n\n' time.sleep(0.5) @app.get('/') async def main(): return StreamingResponse(fake_data_streamer(), media_type='text/event-stream') @app.get("/video") def main(): def iterfile(): # with open("rick_roll.mp4", mode="rb") as file_like: # yield from file_like # return StreamingResponse(iterfile(), media_type="video/mp4") test.py import httpx url = 'http://127.0.0.1:8000/' with httpx.stream('GET', url) as r: for chunk in r.iter_raw(): # or, for line in r.iter_lines(): print(chunk) Ref

Read more →

October 6, 2023

20230929-rn-qrcode

#react-native

snack Podfile def node_require(script) # Resolve script with node to allow for hoisting require Pod::Executable.execute_command('node', ['-p', "require.resolve( '#{script}', {paths: [process.argv[1]]}, )", __dir__]).strip end node_require('react-native/scripts/react_native_pods.rb') node_require('react-native-permissions/scripts/setup.rb') ... platform :ios, min_ios_version_supported prepare_react_native_project! ... setup_permissions([ # 'AppTrackingTransparency', # 'BluetoothPeripheral', # 'Calendars', 'Camera', # 'Contacts', # 'FaceID', # 'LocationAccuracy', # 'LocationAlways', # 'LocationWhenInUse', # 'MediaLibrary', # 'Microphone', # 'Motion', # 'Notifications', 'PhotoLibrary', # 'PhotoLibraryAddOnly', # 'Reminders', # 'SpeechRecognition', # 'StoreKit' ]) ... target 'verifier' do ... pod 'RNPermissions', :path => '../node_modules/react-native-permissions' ios/{}/Info.plist <key>NSCameraUsageDescription</key> <string>Your message to user when the camera is accessed for the first time</string> <!-- Include this only if you are planning to use the camera roll --> <key>NSPhotoLibraryUsageDescription</key> <string>Your message to user when the photo library is accessed for the first time</string> package.json 加上 ... "resolutions": { "react-native-permissions": "^3.8.0" }, "overrides": { "react-native-qrcode-scanner": { "react-native-permissions": "^3.8.0" } } Ref https://www.npmjs.com/package/react-native-qrcode-scanner https://stackoverflow.com/questions/75772965/error-react-native-permissions-nativemodule-rnpermissions-is-null < 這要記得

Read more →

September 29, 2023

20230926-21-things-before-21

#share

Ref https://mrjamie.cc/2023/03/27/21-things-you-need-to-know-before-21/?fbclid=IwAR3QDSeABMFLomEetK8o_6izjB-B42bcQMGiQRY2nMP6ICJi724-1jwenH8

Read more →

September 26, 2023

20230924-wagami

#web3#frontend

import { EthereumClient, w3mConnectors, w3mProvider } from '@web3modal/ethereum' _app.tsx: const chains = [sepolia,polygonMumbai, goerli,arbitrum, mainnet, polygon,localhost] const projectId = '' const { publicClient } = configureChains(chains, [w3mProvider({ projectId })]) const wagmiConfig = createConfig({ autoConnect: true, connectors: w3mConnectors({ projectId, chains }), publicClient }) export default function App({ Component, pageProps }: AppProps) { return ( <WagmiConfig config={wagmiConfig}> <Component {...pageProps} /> import { usePrepareContractWrite, useContractWrite } from "wagmi"; const { data:max_tickets, isError, isLoading } = useContractRead({ address: router.query.contract as `0x${string}`, abi: Event_data.abi, functionName: 'max_tickets', }) const { data: data1, write: set_tickets } = useContractWrite({ address: router.query.contract as `0x${string}`, abi: Event_data.abi, functionName: 'set_tickets' }); const { data, write, isSuccess } = useContractWrite({ address: contract_addr.event_factory as `0x${string}`, abi: Event_data.abi, functionName: 'createEvent', }) const { isError, isLoading } = useWaitForTransaction({ hash: data?.hash, }) Ref

Read more →

September 25, 2023

20230924-QR-Code

#frontend

<QRCode size={256} style={{ height: "auto", maxWidth: "100%", width: "100%" }} value={JSON.stringify(url)} viewBox={`0 0 256 256`} /> @/components/Html5QrcodePlugin import { Html5QrcodeScanner } from 'html5-qrcode'; import { useEffect } from 'react'; const qrcodeRegionId = "html5qr-code-full-region"; // Creates the configuration object for Html5QrcodeScanner. const createConfig = (props) => { let config = {}; if (props.fps) { config.fps = props.fps; } if (props.qrbox) { config.qrbox = props.qrbox; } if (props.aspectRatio) { config.aspectRatio = props.aspectRatio; } if (props.disableFlip !== undefined) { config.disableFlip = props.disableFlip; } return config; }; const Html5QrcodePlugin = (props) => { useEffect(() => { // when component mounts const config = createConfig(props); const verbose = props.verbose === true; // Suceess callback is required. if (!(props.qrCodeSuccessCallback)) { throw "qrCodeSuccessCallback is required callback."; } const html5QrcodeScanner = new Html5QrcodeScanner(qrcodeRegionId, config, verbose); html5QrcodeScanner.render(props.qrCodeSuccessCallback, props.qrCodeErrorCallback); // cleanup function when component will unmount return () => { html5QrcodeScanner.clear().catch(error => { console.error("Failed to clear html5QrcodeScanner. ", error); }); }; }, []); return ( <div id={qrcodeRegionId} /> ); }; export default Html5QrcodePlugin; import Html5QrcodePlugin from "@/components/Html5QrcodePlugin" <Html5QrcodePlugin fps={10} qrbox={256} disableFlip={false} qrCodeSuccessCallback={(_results: string) => onScanSuccess(_results)} /> Ref

Read more →

September 25, 2023

20230924-cmd-copy

#cmd

for i in {0..100}; cp ticket.png "./images/$i.png" Ref

Read more →

September 24, 2023

20230920-nx

#frontend

Ref https://nx.dev/getting-started/intro https://nx.dev/getting-started/installation

Read more →

September 20, 2023

hardhat

#solidity

npx hardhat pnpm add -D @nomicfoundation/hardhat-toolbox @nomicfoundation/hardhat-network-helpers @nomicfoundation/hardhat-chai-matchers @nomicfoundation/hardhat-ethers @nomicfoundation/hardhat-verify chai ethers hardhat-gas-reporter solidity-coverage @typechain/hardhat typechain @typechain/ethers-v6 npx hardhat compile npx hardhat test 跑hardhat測試網:npx hardhat node 部署:npx hardhat run scripts/deploy.ts –network localhost npx hardhat –network localhost faucet 0x028bfd960e7f43f856c74d33d9e9a5af4b6bdece test coverage https://hardhat.org/hardhat-runner/docs/guides/test-contracts npx Ref https://hardhat.org/ https://hardhat.org/tutorial/creating-a-new-hardhat-project

Read more →

September 19, 2023

初探 react native

#mobile#react-native

網路編輯器:https://snack.expo.dev/ CocoaPods:ios 的套件管理 npx react-native@latest init AwesomeProject https://reactnativepaper.com/: UI mui https://callstack.github.io/react-native-paper/ https://callstack.github.io/react-native-paper/docs/guides/getting-started/ https://snyk.io/advisor/npm-package/react-native-qrcode-scanner: QR Code 在螢幕間切換:https://reactnative.dev/docs/navigation https://blog.logrocket.com/using-mui-react-native/ 這也是使用 react-native-paper https://callstack.github.io/react-native-paper/docs/components/Badge https://stackoverflow.com/questions/61398426/is-it-possible-to-use-material-ui-library-with-react-native UI React Native Elements React Native Paper Native Base Native base https://docs.nativebase.io/install-rn /Users/alanhc/workspace/ticketing/components/hero/index.tsx Ref https://reactnative.dev/docs/getting-started https://reactnative.dev/docs/environment-setup?guide=quickstart https://reactnative.dev/docs/environment-setup https://roadmap.sh/react-native

Read more →

September 7, 2023

在部落格中使用mdx

Ref https://nextjs.org/docs/pages/building-your-application/configuring/mdx

Read more →

September 1, 2023

在mongodb裡面將兩個group merge成一個結果

#mongodb#python

結果 { "results": [ { "path": "/mcu/course/2D動畫實務", "id": "2D動畫實務" }, ... { "path": "/mcu/professor/楊健貴", "id": "楊健貴" }, ... } 原本資料 使用facet+project Col_course.aggregate([ { $facet: { teacher_subject: [ { $group: { _id: { teacher: "$teacher", subject: "$subject" } } }, { $project: { _id: 0, path: { $concat: ["/mcu/ratings/", "$_id.teacher", "/", "$_id.subject"], }, id: { $concat: ["$_id.teacher", " ", "$_id.subject"], }, }, }, ], teacher: [ { $group: { _id: { teacher: "$teacher" } } }, { $project: { _id: 0, path: { $concat: ["/mcu/professor/", "$_id.teacher"], }, id: { $concat: ["$_id.teacher"], }, }, }, ], subject: [ { $group: { _id: { subject: "$subject" } } }, { $project: { _id: 0, path: { $concat: ["/mcu/course/", "$_id.subject"], }, id: { $concat: "$_id.subject", }, }, }, ], }, }, { $project: { results: { $setUnion: ["$teacher_subject", "$teacher", "$subject"] }, }, }, { $unwind: "$results" }, { $replaceRoot: { newRoot: "$results" } }, ]); Ref

Read more →

August 31, 2023

(未完)加入kbar讓搜尋更便利

_app.tsx // app.tsx import { KBarProvider } from "kbar"; function MyApp() { return ( <KBarProvider> // ... </KBarProvider> ); } Ref https://www.npmjs.com/package/kbar

Read more →

August 31, 2023

加入GA

https://analytics.google.com/analytics/web/ 裡面 拿到GA_MEASUREMENT_ID應該會是G-{...} 在_app.tsx 加入 const GA_MEASUREMENT_ID = process.env.NEXT_PUBLIC_GOOGLE_ANALYTICS; return ( <> <Script src={`https://www.googletagmanager.com/gtag/js?id=${GA_MEASUREMENT_ID}`} strategy="afterInteractive" /> <Script id="google-analytics" strategy="afterInteractive"> {` window.dataLayer = window.dataLayer || []; function gtag(){window.dataLayer.push(arguments);} gtag('js', new Date()); gtag('config', '${GA_MEASUREMENT_ID}'); `} </Script> Ref

Read more →

August 30, 2023

20230829-peerjs

簡化wwebrtc的使用方法 https://developer.mozilla.org/en-US/docs/Web/API/WebRTC_API/Build_a_phone_with_peerjs https://github.com/peers/peerjs Ref

Read more →

August 29, 2023

20230829-orbit-chat

嘗試使用chatui及orbitdb製作一個去中心化的chat聊天 https://github.com/alanhc/orbit-chat Ref

Read more →

August 29, 2023

20230829-chakra-ui

pnpm add @chakra-ui/react @chakra-ui/next-js @emotion/react @emotion/styled framer-motion // pages/_app.tsx import type { AppProps } from 'next/app' import { ChakraProvider } from '@chakra-ui/react' export default function App({ Component, pageProps }: AppProps) { return ( <ChakraProvider> <Component {...pageProps} /> </ChakraProvider> ) } Ref https://chakra-ui.com/getting-started/nextjs-guide

Read more →

August 29, 2023

初探libp2p

建立signal 節點 import { sigServer } from '@libp2p/webrtc-star-signalling-server' const server = await sigServer({ port: 24642, host: '0.0.0.0', metrics: false }) 到127.0.0.1:24642訪問即可看到 Ref https://github.com/libp2p/js-libp2p-webrtc-star/tree/master/packages/webrtc-star-signalling-server#hosted-rendezvous-server https://github.com/libp2p/js-libp2p-webrtc-star/blob/master/packages/webrtc-star-signalling-server/DEPLOYMENT.md

Read more →

August 28, 2023

初探ipfs

下載 brew install ipfs ipfs init import { create } from 'ipfs-http-client' const ipfs = create(new URL('http://127.0.0.1:5001')) const { cid } = await ipfs.add('Hello world!') //CID(QmQzCQn4puG4qu8PVysxZmscmQ5vT1ZXpqo7f58Uh9QfyY) 更新 https://github.com/ipfs-examples/helia-examples/tree/main/examples/helia-101 Ref https://docs.ipfs.tech/install/command-line/#install-official-binary-distributions https://github.com/ipfs/js-ipfs/blob/master/packages/ipfs-http-client/README.md

Read more →

August 28, 2023

安裝動漫vscode主題

去 下載doki-theme 使用方法 瀏覽主題 cmd+shift+p install {}'s wallpaper/sticker ref https://github.com/doki-theme/doki-theme-vscode https://marketplace.visualstudio.com/items?itemName=unthrottled.doki-theme

Read more →

August 27, 2023

加入PWA功能

前置 先準備 service worker、manifacts.json、logo.png 引入套件:pnpm add next-pwa 修改 next.config.js const withPWA = require('next-pwa')({ dest: 'public' }) ... module.exports = withPWA(nextConfig); 產生icon 到public/,新增logo.png,並下:npx pwa-asset-generator logo.png icons 或 pwa online generator 產生manifest 到public/,新增 manifest.json { "display": "standalone", "scope": "/", "start_url": "/", "name": "Alan Tseng", "short_name": "alanhc", "display": "minimal-ui", "icons": [ { "src": "icons/manifest-icon-192.maskable.png", "sizes": "192x192", "type": "image/png", "purpose": "any" }, { "src": "icons/manifest-icon-192.maskable.png", "sizes": "192x192", "type": "image/png", "purpose": "maskable" }, { "src": "icons/manifest-icon-512.maskable.png", "sizes": "512x512", "type": "image/png", "purpose": "any" }, { "src": "icons/manifest-icon-512.maskable.png", "sizes": "512x512", "type": "image/png", "purpose": "maskable" } ] } 加入link、meta tag 到 next-seo.config.js export default { ... additionalMetaTags:{ { name: "apple-mobile-web-app-capable", content: "yes" } }, additionalLinkTags: [ ... { rel: 'manifest', href: "/manifest.json" }, { rel: "apple-touch-icon", href: "icons/apple-icon-180.png" }, 看到右上角有下載就成功了🎉

Read more →

August 27, 2023

初探orbitdb

orbitdb npm init -y package.json 加入:"type": "module" pnpm add @orbitdb/core@next pnpm add ipfs-core import { createOrbitDB } from '@orbitdb/core' import { create } from 'ipfs-core' // Create an IPFS instance with defaults. const ipfs = await create() const orbitdb = await createOrbitDB({ ipfs }) const db = await orbitdb.open('my-db') console.log('my-db address', db.address) // my-db address /orbitdb/zdpuAvAG3zG4zF3E2s5KVS3pcrqXFK2ky6fMiyi6TsU2mb9qo 加入資料

Read more →

August 27, 2023

notion的替代品 - AFFiNE

替代notion的酷炫東西,github上目前有21.8k stars,而且是rust寫的,,而且也有類似miro的功能,但好像目前沒有發現ios版本,但有線上版目前還是beta。 ref https://affine.pro/ https://github.com/toeverything/AFFiNE

Read more →

August 27, 2023

chat聊天界面初探

chat npx create-next-app chat pnpm add @chatscope/chat-ui-kit-react pnpm add @chatscope/chat-ui-kit-styles import styles from '@chatscope/chat-ui-kit-styles/dist/default/styles.min.css'; import { MainContainer, ChatContainer, MessageList, Message, MessageInput } from '@chatscope/chat-ui-kit-react'; render: <MainContainer> <ChatContainer> <MessageList> <Message model={{ message: "Hello my friend", sentTime: "just now", sender: "Joe" }} /> </MessageList> <MessageInput placeholder="Type message here" /> </ChatContainer> </MainContainer> 另外azure也有自己的UI庫:https://azure.github.io/communication-ui-library/?path=/docs/overview–page 看功能怎麼使用: https://chatscope.io/storybook/react/?path=/story/documentation-introduction--page

Read more →

August 27, 2023

統整markdown的使用方法

資料在本地 使用unified 資料在雲端 使用 MDX 相關posts https://alanhc.github.io/next-blog/posts/20230812-react-syntax-clipboard

Read more →

August 26, 2023

加入next-seo

使用 https://www.favicon.cc/ 從logo.png製作 favicon.ico 加入環境變數 在next.config.js新增 const nextConfig = { ... env: { baseUrl: isProd ? "https://alanhc.github.io" : "http://localhost:3000", NEXT_PUBLIC_GOOGLE_ANALYTICS: "G-L5Z3CY454S", config: { title: "Alan Tseng title", titleShort:"alanhc", description: "description", fqdn: isProd ? "https://alanhc.github.io" : "http://localhost:3000", social: { twitterID:"@alanhc316" }, image: { logo: "/favicon.ico" } } }, ... 設定next-seo變數 新增 next-seo.config.js export default { titleTemplate: `%s | ${process.env.config.titleShort}`, defaultTitle: process.env.config.title, canonical: process.env.config.fdqn, openGraph: { type: process.env.config.title, url: process.env.config.fdqn, siteName: process.env.config.title, }, twitter: { handle: process.env.config.social.twitterID, site: process.env.config.social.twitterID, cardType: 'summary_large_image', }, additionalLinkTags: [ {rel: 'icon', href: process.env.config.image.logo} ] }; 新增到頁面 在 _app.tsx import SEO from '../../next-seo.config'; import { DefaultSeo } from "next-seo"; <DefaultSeo {...SEO} /> 其他頁面:index.tsx import { NextSeo } from 'next-seo'; import SEO from "../../../../next-seo.config"; <NextSeo title={postData.title} description={postData.content} {...SEO} /> 加入 rss additionalLinkTags: [ ... { rel: "alternate", type: "application/rss+xml",href: "/feed.xml"}, { rel: "alternate", type: "application/atom+xml", href: "/atom.xml"}, ] ref https://www.npmjs.com/package/next-seo

Read more →

August 26, 2023

加入import別名讓import更好看

設定 tsconfig.json { "compilerOptions": { ... "baseUrl": ".", "paths": { "@/components/*": ["src/components/*"], ... } } 使用 import Profile from "@/components/partial/Profile"; ref https://nextjs.org/docs/app/building-your-application/configuring/absolute-imports-and-module-aliases

Read more →

August 26, 2023

nextjs 相關文章

markdown相關資料在本地 使用unified 資料在雲端 使用 MDX remote 相關posts https://alanhc.github.io/next-blog/posts/20230812-react-syntax-clipboard

Read more →

August 26, 2023

imgur上傳

註冊:https://api.imgur.com/oauth2/addclient ref https://apidocs.imgur.com/

Read more →

August 26, 2023

添加rss功能到nextjs部落格

下載 npm feed pnpm add feed 新增 generateRSS() 新增 lib/generateRSS.js import { Feed } from "feed"; import { writeFileSync } from "fs"; import { getSortedPostsData } from "./posts"; export default function generateRSS() { const feed = new Feed({ title: "Alan Tseng", description: "This is my personal feed!", id: process.env.baseUrl, link: process.env.baseUrl, //language: "en", // optional, used only in RSS 2.0, possible values: http://www.w3.org/TR/REC-html40/struct/dirlang.html#langcodes image: `${process.env.baseUrl}/image/me.jpeg`, favicon: `${process.env.baseUrl}/favicon.ico`, copyright: "All rights reserved 2013, John Doe", //updated: new Date(2013, 6, 14), // optional, default = today generator: "awesome", // optional, default = 'Feed for Node.js' feedLinks: { json: `${process.env.baseUrl}/json`, atom: `${process.env.baseUrl}/atom`, }, author: { name: "alanhc", email: "alanhc.tseng1999@gmail.com", link: `${process.env.baseUrl}`, }, }); const Blog_URL = `${process.env.baseUrl}/next-blog/posts`; getSortedPostsData().forEach((post) => { console.log(post); feed.addItem({ title: post.title, id: post.id, link: `${Blog_URL}/${post.id}`, description: post.content.slice(0, 100), content: post.content, author: "alanhc", date: new Date(post.date), //image: "" }); writeFileSync("./public/feed.xml", feed.rss2()); writeFileSync("./public/atom.xml", feed.atom1()); writeFileSync("./public/feed.json", feed.json1()); }); } load 時產生 在 pages/index.tsx 的 getStaticProps 裡,新增 generateRSS(); 打開 localhost/feed.xml 使用 chrome extension - RSS Feed Reader 可以看到東西就成功了 🎉

Read more →

August 25, 2023

部落格暗黑模式

新增 theme.ts import { extendTheme, type ThemeConfig } from "@chakra-ui/react"; // 2. Add your color mode config const config: ThemeConfig = { initialColorMode: "light", useSystemColorMode: false, }; // 3. extend the theme const theme = extendTheme({ config }); export default theme; 新增_document.tsx import { ColorModeScript } from "@chakra-ui/react"; import theme from "./theme"; render的部分:

Read more →

August 24, 2023

初探bigchaindb

設定bigchaindb本地節點 使用docker pull image:docker pull bigchaindb/bigchaindb:all-in-one run image: docker run \ --detach \ --name bigchaindb \ --publish 9984:9984 \ --publish 9985:9985 \ --publish 27017:27017 \ --publish 26657:26657 \ --volume $HOME/bigchaindb_docker/mongodb/data/db:/data/db \ --volume $HOME/bigchaindb_docker/mongodb/data/configdb:/data/configdb \ --volume $HOME/bigchaindb_docker/tendermint:/tendermint \ bigchaindb/bigchaindb:all-in-one` python 程式 設定節點 from bigchaindb_driver import BigchainDB bdb_root_url = 'http://localhost:9984' bdb = BigchainDB(bdb_root_url) 定義asset(資產) game_boy_token = { 'data': { 'token_for': { 'game_boy': { 'serial_number': 'LR1235' } }, 'description': 'Time share token. Each token equals one hour of usage.', }, } 建立交易 prepared_token_tx = bdb.transactions.prepare( operation='CREATE', signers=alice.public_key, recipients=[([bob.public_key], 10)], asset=game_boy_token) 簽署交易 fulfilled_token_tx = bdb.transactions.fulfill( prepared_token_tx, private_keys=alice.private_key) 送出交易 txn_id = bdb.transactions.send_commit(fulfilled_token_tx) txn_id 應該會看到以下

Read more →

August 24, 2023

更新nextjs到13

升級nextjs版本:pnpm up next react react-dom eslint-config-next --latest 自動更新image import:npx @next/codemod@latest next-image-to-legacy-image . 會更新 next/image -> next/legacy/image 更新link:npx @next/codemod@latest new-link . 記錄一下目前部落格的樣貌 Ref https://chakra-ui.com/docs/components/link/usage#usage-with-nextjs https://nextjs.org/docs/pages/building-your-application/upgrading/codemods#new-link https://nextjs.org/docs/pages/building-your-application/upgrading/version-13 https://nextjs.org/docs/pages/building-your-application/upgrading/codemods#next-image-to-legacy-image

Read more →

August 20, 2023

讓部落格可以顯示markdown的流程圖

code如下 mermaid graph TD; A-->B; A-->C; B-->D; C-->D; 修改CodeBlock function CodeBlock({ language, node, inline, className, children, ...props }: any) { const { onCopy, value, setValue, hasCopied } = useClipboard(children); const match = /language-(\w+)/.exec(className || ''); if (inline || !match) { //只有一行的code return (<Flex mb={2}> <Code {...props} colorScheme="blackAlpha"> {children} </Code> <Button ml={2} onClick={onCopy} colorScheme='blue' variant='outline'>{hasCopied ? "Copied!" : "Copy"}</Button> </Flex>) } else if (match![1] ==='mermaid') { return (<Box className='mermaid'>{children}</Box>) } else { return ( <Flex mb={2}> <SyntaxHighlighter style={darcula as { [key: string]: CSSProperties }} language={match![1] } PreTag="div" {...props} > {String(children).replace(/\n$/, '')} </SyntaxHighlighter> <Button ml={2} onClick={onCopy} colorScheme='blue' variant='outline'>{hasCopied ? "Copied!" : "Copy"}</Button> </Flex> ) } } render新增 <Script id="mermaidjs" type="module" strategy="afterInteractive" dangerouslySetInnerHTML={{ __html: ` import mermaid from 'https://cdn.jsdelivr.net/npm/mermaid@10/dist/mermaid.esm.min.mjs'; mermaid.initialize({ startOnLoad: true }); mermaid.contentLoaded(); `, }} /> 成功 以下圖是使用 mermaidjs渲染出來的

Read more →

August 19, 2023

實作markdown section link

Toc部分 import markdownToc from 'markdown-toc'; const tocMarkdown = await markdownToc(markdownContent); <UnorderedList> {postData.tocMarkdown.json.map((heading: any) => ( <ListItem key={heading.content}> <Link href={`#${heading.content}`}> {heading.content} </Link> </ListItem> ))} </UnorderedList> 修改react markdown所需要的component function SectionBlock({ node, inline, className, children, id, ...props }: any) { const router = useRouter() const origin = typeof window !== 'undefined' && window.location.origin ? window.location.origin : ''; const URL = `${origin}${router.asPath}`; const { onCopy, value, setValue, hasCopied } = useClipboard(URL + "#" + children); const [isHovering, setIsHovering] = useState(false); return ( <Link href={`#${children}`} id={children} onClick={onCopy} onMouseEnter={() => setIsHovering(true)} onMouseLeave={() => setIsHovering(false)}> <Heading {...props}> {children} {isHovering && "🔗"} </Heading> </Link> ); } const components = { code: CodeBlock, h1: ({ node, ...props }: any) => <SectionBlock as="h1" size='xl' {...props} />, h2: ({ node, ...props }: any) => <SectionBlock as="h2" size='lg' {...props} />, h3: ({ node, ...props }: any) => <SectionBlock as="h3" size='md' {...props} />, h4: ({ node, ...props }: any) => <SectionBlock as="h4" size='sm' {...props} />, h5: ({ node, ...props }: any) => <SectionBlock as="h5" size='xs' {...props} />, a: ({ node, ...props }: any) => <Link {...props} />, };

Read more →

August 18, 2023

將部落格加入sitemap功能

指令下:pnpm add -D next-sitemap next.config.js新增 SITE_URL=“https://example.com” 新增 next-sitemap.config.js /** @type {import('next-sitemap').IConfig} */ module.exports = { siteUrl: 'https://example.com', generateRobotsTxt: true, // (optional) // ...other options } 在package.json > script 新增 "postbuild": "next-sitemap" 使用pnpm需要新增 .npmrc enable-pre-post-scripts=true 在public/看到 sitemap.xml 、robots.txt、sitemap-0.xml成功🎉

Read more →

August 17, 2023

新增page loading的進度條

pnpm add nprogress pnpm add -D @types/nprogress 在pages/_app.tsx新增 import 'nprogress/nprogress.css'; import { useRouter } from 'next/router'; import NProgress from 'nprogress'; import { useEffect } from 'react'; function MyApp({ Component, pageProps }: AppProps) { const router = useRouter(); // Integrate nprogress useEffect(() => { router.events.on('routeChangeStart', () => NProgress.start()); router.events.on('routeChangeComplete', () => NProgress.done()); router.events.on('routeChangeError', () => NProgress.done()); ... // eslint-disable-next-line react-hooks/exhaustive-deps }, []); 這樣就可以在等待的時候看到藍色進度條了🎉

Read more →

August 16, 2023

三種使用Python爬取網頁的方法

第一版: 使用session慢慢爬 s = requests.Session() 第二版: 使用python的並行處理功能 import requests import concurrent.futures results = [] # 定義爬蟲任務 def fetch_url(url, session): try: response = session.get(url) try: return url, response.status_code, response.json() except: return url, response.status_code, {} except requests.RequestException as e: return url, None def fetch(urls): with requests.Session() as session: with concurrent.futures.ThreadPoolExecutor() as executor: # 使用 map 函式來同時執行多個爬蟲任務 results = executor.map(fetch_url, urls, [session] * len(urls)) return results 第三版: 直接使用異步處理方式 import asyncio import aiohttp async def fetch_url(session, url): try: async with session.get(url) as response: # 在這裡你可以對回應進行任何處理,例如解析HTML,提取資料等。 # 這裡我們只回傳回應的狀態碼作為範例。 try: data = await response.json() return url, response.status, data except: print("=======================================", url, response.status) return url, response.status, {} except aiohttp.ClientError as e: return url, None, {} async def fetch_all(urls): async with aiohttp.ClientSession() as session: tasks = [fetch_url(session, url) for url in urls] return await asyncio.gather(*tasks) urls_courses = [ "https://up.mcuosc.dev/courses/json?page="+str(i) for i in range(200) ] loop = asyncio.get_event_loop() results = loop.run_until_complete(fetch_all(urls_courses)) link https://github.com/alanhc/back-up

Read more →

August 13, 2023

使用react syntax highlighter及useClipboard強化程式碼區塊

react syntax highlighter + clipboard 先去讀 postsDirectory 的markdownfile交給matter將markdown轉成object --- title: Hello slug: home --- # Hello world! 結果 { content: '# Hello world!', data: { title: 'Hello', slug: 'home' } } const fullPath = path.join(postsDirectory, `${id}.md`); const fileContents = fs.readFileSync(fullPath, 'utf8'); const matterResult = matter(fileContents); ... 將matterResult的markdown語法顯示出來 註:remarkGfm 讓他可以接受github的神奇markdown語法 import remarkGfm from 'remark-gfm' import ReactMarkdown from "react-markdown"; ... <ReactMarkdown components={components} remarkPlugins={[remarkGfm]}> {postData.contentHtml} </ReactMarkdown> 讓產生出來的程式需要有顏色的語法提示及複製功能 註:這裡是透過指定ReactMarkdown的components及使用chakra ui的useClipboard hook,如果codeblock有指定的程式語言就使用react-syntax-highlighter將他顯示語法提示 import { Container, Heading, Link, Code, useClipboard, Flex, Button } from "@chakra-ui/react"; import { PrismAsync as SyntaxHighlighter } from "react-syntax-highlighter"; function CodeBlock({ node, inline, className, children, ...props }: any) { const { onCopy, value, setValue, hasCopied } = useClipboard(children); const match = /language-(\w+)/.exec(className || ''); return !inline && match ? ( <Flex mb={2}> <SyntaxHighlighter style={darcula as { [key: string]: CSSProperties }} language={match[1]} PreTag="div" {...props} > {String(children).replace(/\n$/, '')} </SyntaxHighlighter> <Button ml={2} onClick={onCopy}colorScheme='blue' variant='outline'>{hasCopied ? "Copied!" : "Copy"}</Button> </Flex> ) : ( <Flex mb={2}> <Code {...props} colorScheme="blackAlpha"> {children} </Code> <Button ml={2} onClick={onCopy} colorScheme='blue' variant='outline'>{hasCopied ? "Copied!" : "Copy"}</Button> </Flex> ); } const components = { code: CodeBlock, };

Read more →

August 12, 2023

實作ipfs上傳的前端

import package import { NFTStorage, File, Blob } from 'nft.storage' const API_KEY = process.env.NFT_STORAGE_API_KEY const client = new NFTStorage({ token: API_KEY }) function dataURItoBlob(dataURI) { // convert base64 to raw binary data held in a string // doesn't handle URLEncoded DataURIs - see SO answer #6850276 for code that does this var byteString = atob(dataURI.split(',')[1]); // separate out the mime component var mimeString = dataURI.split(',')[0].split(':')[1].split(';')[0] // write the bytes of the string to an ArrayBuffer var ab = new ArrayBuffer(byteString.length); // create a view into the buffer var ia = new Uint8Array(ab); // set the bytes of the buffer to the correct values for (var i = 0; i < byteString.length; i++) { ia[i] = byteString.charCodeAt(i); } // write the ArrayBuffer to a blob, and you're done var blob = new Blob([ab], {type: mimeString}); return blob; } ... const [dataUri, setDataUri] = useState("") const [ipfs, setIpfs] = useState("") const onChange = (file) => { if (!file) { setDataUri(''); return; } fileToDataUri(file) .then(dataUri => { setDataUri(dataUri) }) } const handle_mint = () => { const upload_ipfs = async() => { const img_blob = await dataURItoBlob(dataUri) //const img_cid = await client.storeBlob(img_blob) const metadata = await client.store({ name: 'My sweet NFT', description: 'Just try to funge it. You can\'t do it.', image: img_blob }) console.log(metadata.url) setIpfs(metadata.url) } upload_ipfs() } return ( <Layout> ... <img width="100" height="100" src={dataUri} alt="avatar"/> <input type="file" onChange={(event) => onChange(event.target.files[0] || null)} ></input> <Button onClick={handle_mint}>Create</Button> {ipfs} </Layout> ) https://github.com/alanhc/aka-ticket/blob/main/frontend/pages/event/index.js

Read more →

January 9, 2023

erc 1155 合約

ERC 721 // SPDX-License-Identifier: MIT pragma solidity ^0.8.9; import "@openzeppelin/contracts/token/ERC721/ERC721.sol"; import "@openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol"; import "@openzeppelin/contracts/access/Ownable.sol"; import "@openzeppelin/contracts/utils/Counters.sol"; contract MyToken is ERC721, ERC721URIStorage, Ownable { using Counters for Counters.Counter; Counters.Counter private _tokenIdCounter; constructor() ERC721("MyToken", "MTK") {} function safeMint(address to, string memory uri) public onlyOwner { uint256 tokenId = _tokenIdCounter.current(); _tokenIdCounter.increment(); _safeMint(to, tokenId); _setTokenURI(tokenId, uri); } // The following functions are overrides required by Solidity. function _burn(uint256 tokenId) internal override(ERC721, ERC721URIStorage) { super._burn(tokenId); } function tokenURI(uint256 tokenId) public view override(ERC721, ERC721URIStorage) returns (string memory) { return super.tokenURI(tokenId); } function supportsInterface(bytes4 interfaceId) public view override(ERC721, ERC721URIStorage) returns (bool) { return super.supportsInterface(interfaceId); } } safemint to:自己address, uri: https://alanhc.github.io/nft/opensea-example.json 就可以在 testnet opensea看到 其實也可以不用一個一個設置:可以直接設置baseuri :https://ethereum.stackexchange.com/questions/122404/best-way-to-set-metadata-in-erc721-contract-on-production erc 1155 // SPDX-License-Identifier: MIT pragma solidity ^0.8.9; import "@openzeppelin/contracts/token/ERC1155/ERC1155.sol"; import "@openzeppelin/contracts/access/Ownable.sol"; contract MyToken is ERC1155, Ownable { uint256 public constant Rock = 1; uint256 public constant Paper = 2; uint256 public constant Scissors = 3; constructor() ERC1155("https://alanhc.github.io/nft/erc-1155/{id}.json") { _mint(msg.sender, Rock, 1, ""); _mint(msg.sender, Paper, 1, ""); _mint(msg.sender, Scissors, 1, ""); } function setURI(string memory newuri) public onlyOwner { _setURI(newuri); } function mint(address account, uint256 id, uint256 amount, bytes memory data) public onlyOwner { _mint(account, id, amount, data); } function mintBatch(address to, uint256[] memory ids, uint256[] memory amounts, bytes memory data) public onlyOwner { _mintBatch(to, ids, amounts, data); } } 註記:mint data要設定 0x0000000000000000000000000000000000000000000000000000000000000000

Read more →

January 8, 2023

部署我的網站到k8s上

1. 在專案根目錄新增以下檔案 FROM node:16-alpine ARG NODE_ENV="production" ENV NODE_ENV=${NODE_ENV} WORKDIR /app COPY package*.json ./ RUN yarn install COPY . . ENV PORT=3000 EXPOSE 3000 CMD [ "yarn", "start" ] 2. build image docker build . -t alanhc/alanhc.github.io:latest

Read more →

December 31, 2022

使用smartpy撰寫tezos的nft程式

撰寫nft合約 到 smartpy ide 輸入 import smartpy as sp FA2 = sp.io.import_template("FA2.py") class NFT(FA2.FA2): pass @sp.add_test(name="tests") def test(): jerry = sp.test_account("Jerry") tom = sp.test_account("Tom") admin = sp.address("tz1aV2DuPYXEK2mEVc4VBhP9o4gguFGxBky4") scenario = sp.test_scenario() scenario.h1("tutorial tests") nft = NFT(FA2.FA2_config(non_fungible=True), admin=admin, metadata= sp.utils.metadata_of_url("https://alanhc.github.io/nft/tezos-contract-example.json") scenario += nft 部署合約 更改admin為自己的地址、按下執行(左上),並按下deploy contract 選擇測試鏈(ghostnet),並選擇estimate gas 將 token metadata (hex) 輸入,可使用 string2hex 範例:(hex)697066733a2f2f6261666b7265696833366d336434796662707974656c75766e7475706835787962777467786476796b736267796736366573343464726b34687179,原文(string):ipfs://bafkreih36m3d4yfbpyteluvntuph5xybwtgxdvyksbgyg66es44drk4hqy 查看nft 到 tzkt >balance 查看是否有nft 參考 https://learn.figment.io/tutorials/mint-nfts-on-tezos

Read more →

December 30, 2022

在solana上mint NFT

下載 solana cli: sh -c "$(curl -sSfL https://release.solana.com/v1.14.11/install)" 新增帳號 solana-keygen new --outfile ~/.config/solana/devnet.json 設定 devnet solana config set --url <https://metaplex.devnet.rpcpool.com/> 檢查設定 solana config get Config File: ~/.config/solana/cli/config.yml RPC URL: https://metaplex.devnet.rpcpool.com/ WebSocket URL: wss://metaplex.devnet.rpcpool.com/ (computed) Keypair Path: ~/.config/solana/devnet.json Commitment: confirmed 拿測試token: solana airdrop 2

Read more →

December 28, 2022

Hello World

Hi! 😃hello world!

Read more →

December 22, 2022

20220811-monorepo-development

#frontend#monorepo#select

Ref 前言 LINE台灣用戶有2100萬 LINE 跨國公司 正文 時間:2000年初 共享code,scale build system 及 version control 使用公司:Google Facebook Microsoft Uber Airbnb Twitter Pros code reuse:透過共享lib共享code 簡化相依性管理:單一package.json,不容易造成版本衝突 簡單重構:單一repo看得到整個架構 跨團隊協作:靈活掌握,可以修改其他團隊code Cons 權限控管:不能根據repo設定訪問權限 預設設定會佔用空間:預設會下載整個專案,專案龐大會佔用開發者空間 障礙 Google monorepo 幾萬筆commit及80TB的monorepo scale 版本控制軟體:2005年Google建構服務要10min. 2010年改進30s-1min Scaling build software: 執行build及CI test會有問題 前言 許多網頁都有共用component,這些component不盡相同。 為何要用monorepo? 現代的專案愈來愈龐大,一個品牌底下可能有很多不同的服務,然而服務間及服務間有許多功能是相似的,以前端來說,網頁組成大部分會寫成component的形式讓不同頁面可以共用,但不同服務呢,Monorepo就是解決這問題的好方法。 Monorepo的歷史可以追溯到2000年初期,為了解決不同專案間reuse code的概念誕生了讓專案維持在同一個codebase底下,不僅如此,單一的套件管理方式不易造成版本衝突,重構時也可以看到專案全貌針對問題彈性修改等好處,然而,這些好處同時,也可能違背最小權限原則的管理模式,較難根據repo設定訪問權限,由於專案建構時會一次建構整個專案,會造成時間及空間上的問題,對於版本控制也是一大問題,如Google的Monorepo每天處理上萬筆的commit及幾十TB的儲存空間,好的monorepo選擇也變得十分重要。 單一codebase,共用component,單一共用的相依性 有哪些選擇? nx turborepo rush bazel

Read more →

August 11, 2022

20220811-LINE-Blockchain-Developer-Intern

#blockchain#LINE#select

為何想去實習? 知道業界缺乏什麼樣的人才? 了解學界、業界差異 累積實戰經驗 同學都有好幾段實習經歷 看看自己的市場價值 我怎麼準備? 目標 Blockchain、雲端相關、Application 當時準備 ALG、DS、Behavior 檢討 但可能比較重要還是 Side Project及你準備一下有多想進你申請公司的一些準備 雖然我沒花啥時間準備Side Project的面試,原本想說都我寫的問不倒,但其實很多問題不是當下你的Project做了什麼,而是面試官會希望你講一下你可以怎麼優化你的Side Project跟旁敲側擊技術難度 我很幸運因為那時剛好是Blockchain牛市,Blockchain人才非常稀缺,我剛好很幸運拿到趨勢及LINE的Offer 投遞 Intern 目標:選可以學到最多的,讓自己成為很厲害的工程師 指標 實習時間 成長性 未來發展 機會 趨勢Web3 Team(暑期2 month) vs. LINE Blockchain Dev (一年期) 最後選擇 LINE,因為我爸在美商從小嚮往像我爸公司的外商文化及實習時間長(預期可以學到比較多東西),但如果可以重新選我可能會選趨勢,因為那個比較偏分析交易+點一些Infra技能。 其她 中研院:放棄 一階過後放棄 台灣微軟:未錄取 4/28電話面試,BQ > 5/6 說明演算法、中英自我介紹(萬寶華) 大概面到第四輪,應該是沒有Team match被刷,當時偏向找AR/VR。 其實我不太喜歡他們委託給其他人力公司,很難從面試官獲得反饋,面試很像在跟沒靈魂的機器人對答。 群暉 iOS/Android:無聲 3/18 投遞 > 4/12 一面線上考 Link List > 4/21 二面考Tree 樹遍歷,不用queue等資料結構 面到第三輪,考很細,都考DS的問題,因為是面Application所以LeetCode沒有很難,問很多OS、OOD及記憶體管理問題,無聲。 Garmin:無聲 我實驗室同學(博翔)很早就上了,所以沒有機會QQ Amazon:沒上 Coding沒寫完。 Intel:放棄 原本有TME(Technical Marketing Engineer)機會,但因為LINE先上+我爸覺得年輕人做這沒有很好(他之前幹過這),所以婉拒。 ASUS:5/19 二面沒上 趨勢:放棄 3/25 Codility (120min) > 4/15通知二面 > 4/21 主管聊天(專案) 緯創:放棄 LINE Blockchain:錄取 3/19 投遞 > 4/28面試(聊履歷) > 5/11 確認錄取 結論 感覺有什麼機會還是看當時就業市場需要什麼 關於 LINE Blockchain Dev Background LINE的組織架構很複雜…,從上到下都是,因為避稅關係,好像設立地點是在某太平洋小島,總之我算是在LINE做Blockchain的子公司LINE Next,底下的DOSI Store產品,主要就是NFT交易市場Team。 因為我們的Product Owner是KR,所以Deadline很死、很操、沒辦法negotiate。 Pros 學習資源很多,LINE的Engineer文化就是分享(尤其是日本),Global Dev Relation很活躍會一直去邀請大佬來分享,有很多讀書會,裡面的人也熱愛分享。 主管級很有Business的Sense,也會在讀書會跟員工討論分享,也不會有主管架子,新人意見可以很有效傳達到上面。 Cons 組織很扁平,可能會一直被skip(大主管)敲,Context Switch要很好。 會議很多,跟KR、讀書會、自己Team,我感覺大概工作有一半時間都在開會 @@ 總結 LINE 是一間很大的新創公司,相對其他大公司變動很快,無時不刻在創新。 想比較多產品參與感可能要去比較在地化的Team,LINE Today、Travel、Music之類,否則還是去LINE Fukuoka(福岡)、LINE Tokyo(東京)、LINE Global(韓國)比較好 我學到了什麼? 使用 Monorepo Development 打造 Scalable Frontend [[20220811-monorepo-development]] Why? Re-use Code How? 由很像JSON結構去生前端,其實美商很多都這樣,這邊可能用graphql比較好 Web2 公司如何做、進入Blockchain/web3 公司私鏈、COSMOS(LINE Blockchain底層使用) 公司運作 Business 避稅 各國文化差異 日本:嚴謹,重Testing 韓國:做事很快、嚴格 軟體開發 Dev Flow: 開發流程 增進Frontend (Alvin推薦) clean code: design clean architecture: refactor clean architecture white_check_mark eyes raised_hands You Don’t know JS https://github.com/getify/You-Dont-Know-JS https://medium.com/%E6%89%8B%E5%AF%AB%E7%AD%86%E8%A8%98/react-swr-485b8e41ef78 https://medium.com/starbugs/%E9%96%8B%E6%BA%90%E5%B0%88%E6%A1%88%E8%AE%80%E8%B5%B7[…]1%E4%B8%8D%E8%A6%81%E6%9B%B4%E6%96%B0%E7%9A%84-swr-d02dadc1116b https://medium.com/hulis-blog/frontend-engineer-guide-297821512f4e https://roadmap.sh/frontend https://www.tenlong.com.tw/products/9786263332577 https://en.wikipedia.org/wiki/Multitier_architecture https://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93viewmodel https://www.guru99.com/mvc-vs-mvvm.html https://www.tutorialspoint.com/What-is-the-difference-between-session-and-cookies 我在實習做了什麼? 升級project workspace to React 18 [[20220721-upgrade-nx-repo-to-react-18]] 認知反直覺的事 景氣不好因為招聘放緩所以不太會裁員(台廠思維) 廣告的收益並不好 管理學第一步是要從自身利益開始 認識/厲害的人 George (UIT Eng manager) 中央資管 (Skip) 半導體pm > LINE日本UIT > LINE TW 以前是LINE日本的,後來來台灣是UIT的頭,我很常被他抓去討論Blockchain的事情😂。 Coke (UIT Team Lead) 中央資管碩畢 我的直屬主管,常常在開會的時候分享Code怎麼寫比較安全、我覺得他蠻棒ㄉ,資源也很Support,我那時說想去碰K8s他也給我一個K8s Task,也會跟我講要做哪些Task可以讓自己未來比較值錢,講話很好笑。 Eric (Mentor) 交大資工實務組,yoe~1y 交大實務組碩畢業,實作很強,但講話有點太直接。好像同時也在創業,很厲害的人。 Alvin (UIT Senior) 輔大資工,YOE 5+ 算蠻資深UIT,以前在趨勢,他之前推薦我很多FE的學習資源,以及講解整個Project的架構、歷史,真的很抱歉打擾他很多時間XD Evan (Dev Rel Lead) 東吳資管(?),yoe 10+ 應該軟體開發圈沒人不認識他,Golang社群很活躍,以前在DSC也常常聽他分享學生該怎麼樣讓自己更有競爭力! Tom (DOSI ServerSide) 黑客松夥伴,很Carry,也指出了我一些Project的 Water (Travel Team ServerSide Intern) 台大資工所 我學姊XD 實驗室也很近,之前常常和她請教BE的一些技術、該學哪些之類,還有叫我不要延畢XD TU (Mobile Team Intern) 北科資工 -> 英國碩 可能因為他實習時間待比較長?跟他聊蠻多Mobile方面還有業界比較看什麼 Cipto (UIT) 北科互動,yoe 10+ 之前是Designer後來轉FE,之前有關UI問題都問他XD Steve (UIT Intern) 雲科電機 有很多我不知道問題可以找誰的時候都是直接問他 Jerry (QA Intern) 政大資管 沒有很熟,之前Intern月會有小聊Blockchain,以前他在OurSong,但後來去日本露天 Jonny (SRE Team Lead) 之前K8s不知道怎用的時候都是去請教他,很厲害的人,人也很好,以前在騰訊 Steve (SRE Intern) 只有吃過幾次飯,sitcon 裡大神,貌似是大一休學 Kyle (UIT Lead) 政大資管學 yoe 3-5y FE 大佬,有出書很厲害,但後來貌似也不在LINE了 Brian (Staff Engineer (?), Platform) DevOps大佬,之前在IBM,上過他的內部training學到很多DevOps知識 Penny (ML Team Lead) 外國碩->TSMC->LINE 之前在TSMC,很厲害 Tom (UIT Infra) UIT 優化、Infra很厲害 Joey (Strategy) 黑客松夥伴,對於Presentation 很厲害,很Carry YiHan TW Intern -> LFK(福岡) OO (Blockchain) ?? 從幣安跳來LINE Ref

Read more →

August 11, 2022

Upgrade nx repo to react 18

#nextjs#nx#job#select

更新@nrwl/react 到14會自動更新React到18 https://nx.dev/guides/react-18#react-18-migration npx 指令:暫時使用,不global下載 更新nx npx nx migrate latest : 尋找更新的dependencies,還沒更新任何東西 更新package.json 產生migrations.json npx nx migrate --run-migrations: 開始執行下載,包含npm i https://nx.dev/using-nx/updating-nx 更新chakra-ui 查版本https://www.npmjs.com/package/@chakra-ui/react https://chakra-ui.com/getting-started/migration 改package.json到最新版 (目前2.2.4) 更新 Typescript 查版本https://www.npmjs.com/package/typescript 改package.json到最新版 (目前4.7.4) 檢查 npx nx run app:lint npx nx run app:build:production 遇到問題 chakra裡面的csstype下npm i沒有被下載到 @chakra-ui/styled-system/node_modules/csstype 改path: @chakra-ui/styled-system/node_modules/csstype ~> csstype Warning: ReactDOM.hydrate is no longer supported in React 18 next在版本12.1.7有解掉, https://github.com/vercel/next.js/issues/37378

Read more →

July 21, 2022

Decentral Showroom — NTU DApp Term project

#medium#select

photo by Hsiang Hsu, model: Cute Ubi Decentral Showroom,屬於你的Metaverse展場空間 期末我和實驗室同學Leo Chen、Jack Hsieh、Hsiang Hsu及Ubi Tsai製作了 一個基於Tezos鍊上的NFT展場空間,拉近您與作品的距離,先來看我們做了甚麼👉 [65s] 策展 == 策展人可以透過 DSR網站,建立您的展場空間,並透過編輯器擺放您所擁有的NFT(non fungible tokens),展場建立後會產生一個可以被分享的Id。 DSR Editor: https://dsr-team.github.io/DSR-Editor 使用VR與NFT作品互動戴上頭盔、輸入展場ID即可進入沈浸式的虛擬展間體驗各式各樣的作品,DSR支援的作品類型包含聲音、影片、模型及GIF,您可以在DSR的元宇宙裡與作品近距離互動,更可以將模型直接拿下來仔細研究不必擔心會損壞作品。 進入DSR虛擬展間 將3D作品拿下來觀看 系統設計DSR系統分為三個部分,VR互動、前端Editor及後端的API services,我們使用FARM(FastAPI, React, MongoDB)的技術來完成此系統。 系統架構圖 DSR Showroom在VR沈浸式展場中,模擬美術館、博物館呈現作品的方式來擺放NFT作品,支援teleport、snapturn等操作功能。為了避免不同作品的聲音干擾影響觀展體驗,DSR設計了“作品泡泡”讓您可以安心的體驗作品不被干擾。 DSR 展場空間 DSR Editor策展人首先必須簽署一個payload用於登入,並回傳server取得登入憑證。 簽署登入payload 使用DSR Editor可以建立虛擬展間,建立完成後會取得展間ID。 建立虛擬展場 接下來就是佈置您的展場了~~ 擺設NFT

Read more →

May 31, 2022

web3 世界裡的驗證機制,以Tezos為例

#tezos#medium#select

在web3的世界裡面,區塊鏈錢包取代了過去綁定社交帳號登入的功能,以下面在Tezos上的NFT交易平台objkt為例,可以看到sync取代login的按鈕。 objkt 如下圖,點選sync後,objkt會與您的錢包(temple wallet)互動,然後請您簽署一份payload: temple wallet 點選簽名完後即可登入頁面,但他到底是怎麼做的,首先我們要來複習一下數位簽章的一些基礎。 數位簽章 (Digital signature)數位簽章被廣泛應用在許多領域如證書、email、blockchain等等。簡單來說我們需要驗證東西『是否為某人所發』,可以使用數位簽章來達成此事。如下圖,假這今天Bob要證明某個訊息是否為Alice所發出,首先Alice使用私鑰(private key/secret key)來對message做簽章,然後將簽完的message(簽章,signature)送給Bob,此時Bob只要使用Alice的Public key及收到signature,去驗證訊息是否為Alice所發。 https://en.wikipedia.org/wiki/Digital_signature 若我們要知道前端使用者是誰,可以利用上面概念及wallet本身的簽署功能,如下圖,首先frontend(React)會將從server送來的payload利用私鑰做簽名,產生signature,然後送給server,此時server只要檢查送過來的signature是不是當初發的即可,這樣就可以知到這『確實是某人』所簽。 簡單邏輯 了解上面後,由於我們需要做登入,這邊是以確認使用者後即發JWT(json web token)來做例子,其實就很間單的三個步驟:encode、sign、verify,他的登入流程如下: frontend對server發請求,告訴server誰要登入(address)。 server將使用者資訊encode成錢包可接受的資料格式payload。 server將payload(0501…為SigningType)回傳。 frontend與wallet互動,利用wallet簽署(sign)payload。 frontend將signature回傳。 server接收到signature後,利用公鑰vk verify使用者資訊。 通過後server發送JWT給前端。 詳細流程 由於這是NTU DApp的期末作業,因尚未公開參考code的部分之後再公開~ 最後感謝實驗室大神同學陳冠廷給我一些驗證的建議。 參考 https://docs.walletbeacon.io/guides/sign-payload/ https://en.wikipedia.org/wiki/Digital_signature Ref https://medium.com/@alanhc/web3-%E4%B8%96%E7%95%8C%E8%A3%A1%E7%9A%84%E9%A9%97%E8%AD%89%E6%A9%9F%E5%88%B6-5e0d05b6f735

Read more →

May 18, 2022

使用Bloom Filter及web3.py來做疫苗認證 — NTU DApp 期中prototype

#algorithm#medium#select

前言剛好最近看到一篇blockchain-based的疫苗認證系統提到他們使用Bloom Filter來快速查找疫苗批號,因此就萌生了想自己來實作一下這篇的其中一個功能-使用Bloom Filter來追蹤疫苗批號,先來看一下我做了什麼👉 [53s] 為什麼使用Bloom Filter? ================== 在區塊鏈應用裡面,如何節省storage fee(使用空間)及快速找到資料(快速搜尋)是非常重要的,而Bloom Filter是個在大量資料可以快速搜尋又省空間的方法,相較於其他的演算法他的搜尋只需要O(k),k取決於用多少hash function,而且他佔用的空間也非常少,因此被利用在許多應用上,從惡意名單的找尋等等。簡單理解的話,如下圖,一開始會有兩個參數,分別整個需要查找的元素個數n及可以接受的false positive(誤報),Bloom Filter會根據n,p,計算出總共需要的storage空間m及需要用到的hash function數目k,可以經由下面的鏈結簡單計算。 [ Bloom filter calculator Calculate the optimal size for your bloom filter, see how many items a given filter can hold, or just admire the curvy… hur.st ](https://hur.st/bloomfilter/?source=post_page-----4493ba5425e9--------------------------------) 以下面為例,有一個數列{x,y,z},假設使用到m的bit及k的hash func 新增 新增元素x,把元素做 hash(x),做k次,把結果設為1,因此bitarray裡第1,5,13個bit被設為1。 搜尋 搜尋元素w,把元素做 hash(w),做k次,檢查第4,13,15對應的bit是否全為1,任一bit為0此w不再集合中。

Read more →

April 6, 2022

20211028-虛擬人課堂筆記4-vroid

#VR#medium#select

vroid (註冊&下載) 調整模型到你喜歡的 Face Editor>Generate Bone 調整完 Camera/Export>Export Info> Material Reduction>設定2 Camera/Export>Export Info> Texture Altas Resolution>最小 Camera/Export>Export Info> Polygons Resolution>Editor Hair Cross Section、Delete Transparent Mashes打勾 點選下面Export 開啟cluster,點右上頭像>Avatar>upload avatar 點選剛剛下載的cluster,選擇活動 可以進去活動的虛擬世界拉🎉 製作自己的模型 — PIFuHD code 點複製,檔案>複製副本到自己的雲端 點連線 找自己喜歡的接近T pose照片,取名girl上傳 點開旁邊資料夾確認檔案已經上傳 並將下面程式片段改成剛剛上取的名字 接下來一直往下執行,直到: 沒有錯誤,點開旁邊資料夾>pifuhd>results>pifu_final>recon裡面檔案下載 把下載下來的模型丟到creator3d檢視,我找的這張轉完效果好像有點不好QQ 打開Blender > File>import OBJ 點選上方UV Editing

Read more →

October 28, 2021

20211027-虛擬人課堂筆記3-unity-facecapture

#unity#medium#select

去上禮拜ReadyPlayerMe下載glb模型檔 打開Blender,按右鍵刪除方塊 2. File>import>.glb 3. 選擇角色跟骨架 3. 全選模型> File>Export>照著下面紅框做>Export(匯出) 打開Unity(2020.3.20以上)>選擇3D project window>package manager>+>Add package by name>com.unity.live-capture 點開sample>import 到project區域>Assets>Samples>Live Camera>1.0.1>ARKit Face Sample>FaceCaptureSample.unity 拖曳剛剛下載的模型.fbx到中間檔案區 把人物丟到Scene 點場景SampleHead>Inspector>SampleHead旁邊勾勾取消 點場景Camera>Inspector>Camera旁邊勾勾取消 Hierarchy>右鍵>Live Capture>Virtual Camera Actor 調整Camera視角 Hierarchy>我的模型>Incepetor>Add component>ARkit Face Actor 在Project>Create>Live Capture>ARKit Face Capture>Mapper 改名成myMapper 拖曳Hierarchy>我的模型拖曳到Project>點選Original Prefab 點一下myMapper,再點myMapper>拖曳Rig Prefab 拖曳模型的左眼右眼頭等等(參考下圖) Inspector>Add Render 然後點選Hierarchy>TakeRecorder>NewFaceDevice,照下面設定 點選我的模型,把myMapper加入Inspector>Mapper 點選上面tab window>Live Capture>connections>Create Server>按下start 打開Iphone/Ipad,使用剛剛下載的Unity Face Capture

Read more →

October 27, 2021

虛擬人課堂筆記2 —Mozilla Hub

#mozilla_hub#medium#select

在Mozilla Hub裡面使用虛擬角色新建一個room: https://hubs.mozilla.com 掛載虛擬人 https://readyplayer.me create avatar之後開始調整模型 調整完點選claim my avatar 到右側My avatars 點選Copy .glb URL 回到Mozilla Hub 登入,點選People>change Avatar 按右上頭像 GLB URL 貼上去就可以發現我們的頭貼改成模型~別人看到你就是這個模型了🎉 也可以自己架虛擬世界~~ https://hubs.mozilla.com/cloud 場景編輯器 https://hubs.mozilla.com/spoke 在Mozilla Hub裡面使用會動的虛擬角色在https://readyplayer.me 裡面My Avatars>Download avatar glb 打開blender File>import>glTF2.0(.glb/.gltf) 2. 把右上方泡泡圖案打開才會讀入貼圖 3. File>export>FBX,並照下面第二張圖設定 去Mixamo 選取右側upload character,可以點選左側animations 手機下載 Adobe Areo 點選下面+然後選擇Adobe Creative Cloud 點選下面 Action(動作)進去選取tab

Read more →

October 18, 2021

虛擬人課堂筆記 — SparkAR

#AR#medium#select

讀完這篇,將學會可在FB嵌入的濾鏡👇 先下載 SparkAR 開啟 SparkAR 選擇 Create new > Backgroun 在左上相機選取FaceTime HD Cameras 底下Assets>Textures>replace按下右鍵 左下角點一下 Test on device>選則send 可以去手機 FB App點開會顯示(preview.arexport特效已可供測試) 3D眼鏡 Create new > Face Decoration 尋找3D模型 左下 Add Asset>import>from computer 拖曳到上面 dragHere 調整一下Position, Rotation, Scale Cyberpunk面具 Add Asset>Search AR Library>3D object>搜尋cyberpunk>import Free 拖曳到 draghere 結合前面背景與特效 開啟背景專案>Focal Distance>Add>Face Tracker 把模型拖曳到Face Tracker

Read more →

October 11, 2021

20210820-開發mcu-up-銘傳金手指3-0-的那些事兒

#medium#select

請參考:銘傳金手指 Photo by joanna, from upMCU MCU-up,一個專屬銘傳人的選課評價網站。 為甚麼會想做此專案?大學四年邁向尾聲時,我開始思考做過的事情。從 創立MCU開源社 把校內對資訊有興趣的同學可以有個地方聚在一起討論進步。那我是否可以藉由自身的資訊專長造福更多人,於是 MCU-up 這個專案就此誕生了😆 from Dcard — 金手指…他回來了? 我如何開發這個專案?首先,我找了社團對於改善學校選課系統有興趣的社團幹部-徐友笙,組織了MCU-up讀書會,並藉由讀書會的時間去閱讀許多學校如NCTU+、NTU Sweety Course、CLASSIN等使用的技術,嘗試找出他們使用的技術、及遇到的問題,同時也透過謝育平老師得知了之前的金手指作者-曾信傑,學長也熱心提供了之前的2000筆評論資料。 銘傳金手指 BY 曾信傑 from dcard 為了保持彈性及希望使其網站可以永續經營,我們使用了最多人且歷史悠久 NodeJS+Express+MongoDB的技術,並依照最小可行性產品的原則做出了初版MCU-up網站。 初版MCU-up(銘傳金手指3.0)網站 基本的網站功能(使用者驗證、留言)完成後,由於需要將此專案推行到一般使用者及使團隊背景更多元,我找了2nd社員(現3rd副社長,資工系)-張智仁來一同改善前端顯示的部分、何靖嫻(1th 社員,設計學院) 來討論及設計前端介面。組別也增編了設計組讀書會,來討論此網站想帶給同學的功能,及頁面顯示的強化。此時 view engine也從原本的EJS改成PUG。並且找了幾個對資安比較有興趣的子軒(3rd社長)、龍成(2nd社長)來討論改善資安問題,並找到同屆DSC — 楊毅(中興 GDSC Lead 2019)Flutter開發手機端程式。 MCU-up(銘傳金手指3.0) v0.1.1-alpha 總結此專案最終在7/30正式上線,很高興開發組(張智仁、徐友笙、子軒、龍成)、設計組(何靖嫻)、謝育平老師、學長(曾信傑、小喵) 的各位來支持一同完成這項任務,沒有你們就沒有今天的MCU-up。從此專案磨練並學習到很多不僅是技術或開發方面的知識,更多是如何將不同領域背景的人聚在一同完成專案。接下來此專案將由MCU開源社共同維護所以看到這篇文的銘傳學弟妹,想學背後的相關技術就加 MCU開源社吧! 社團會在下學期社課教導背後的相關技術,如果你是其他學校想一起合作也歡迎留言或者直接私訊粉專(Link在下面),讓我們一起來讓這個開源專案更好! 特別感謝 謝育平老師:分享他在CPE瘋狂程設剛開始的開發故事,並鼓勵我們勇於嘗試及討論此專案的一些方向。 曾信傑學長(金手指作者):提供了金手指過去的2000筆資料,及教導過往金手指的技術實作細節。 小喵學長:教導了我們一些比較業界方面在專案管理上的一些知識、工具及方法。 鏈結 銘傳金手指 為什我會成為DSC Lead及怎麼申請 Ref https://medium.com/@alanhc/%E9%96%8B%E7%99%BCmcu-up-%E9%8A%98%E5%82%B3%E9%87%91%E6%89%8B%E6%8C%873-0-%E7%9A%84%E9%82%A3%E4%BA%9B%E4%BA%8B%E5%85%92-5214e62aca80

Read more →

August 20, 2021

alanhc 互動技術-week17 [final]

#interactive_programming

回顧這學期的作品:  期中作業:LANDING:PLANET 賣點&特點: 炫麗的特效 物理(星球重力及降落)及粒子系統(噴射) 世界地圖可根據視角縮放 困難點: 重寫3次最終改寫成物件導向的CLASS寫法 攝影機的座標 粒子系統噴射 期末作業:drum.io 說明你做了什麼 學javascript es6的語法規則、p5.js與processing的不同,了解socket網路通訊程式原理, 花最多時間在多人連線的部分,需要畫出狀態圖及流程圖,與一般程式思考邏輯不太一樣 分為host與play兩個階段,當某個client在host階段 其他就負責檢查是否有與打一樣,有點像請你跟我這樣做 再花點時間debug 深度學習是否要多層訓練比較好等等 如何操作 1. 將瀏覽器的自動播放功能打開 ,設定 > 進階設定 > 隱私 > 音效 > 允許 {server ip} 2. 進資料夾,在小黑下 node server.js(必須有nodejs在電腦上 3. 接上開發版即可開始玩 賣點是什麼 可以多人遊玩及對戰 深度學習訓練自己的Air drum 困難點是什麼 * 多人連線(寫好協定讓彼此可以跑一樣的視窗及不會打架 使用nodejs socket io * 深度學習(訓練使準確率提升 ml5 library (base on tensorflow js) * 互動裝置(Arduino及三軸感測器... 雖然由於serial的原理也是使用nodejs,因此若兩者同時跑會導致我的程式會不同步,若以後可以的話可以再試試用其他的方法解決ex. 直接寫tensorflow.js原生碼之類

Read more →

January 16, 2020

alanhc 互動技術-week16

#interactive_programming

多人遊戲的電子鼓v1 server 端程式  處理socket及routing(express) serverjs.js let express = require('express'); let app = express(); let server = app.listen(3000); app.use(express.static('public')) console.log("My socket server is running"); let socket = require('socket.io'); let io = socket(server); io.sockets.on('connection', newConnection); let player=0; let playerList=[]; let nowHost=0; function newConnection(socket) {     playerList.push(socket.id);     player++;         socket.broadcast.emit('players',player);     socket.broadcast.emit('hoster name',playerList[nowHost]);     socket.on('disconnect', ()=>{         --player;         socket.broadcast.emit('players',player);         playerList = playerList.filter( (value, index, arr)=> value!=socket.id );     });     socket.on('send pattern', (patternIn)=>{         socket.broadcast.emit('answer pattern',patternIn);     });     //console.log(playerList.length); } setInterval(function() {     io.local.emit('players',player);     io.local.emit('hoster name',playerList[nowHost]);         //console.log(nowHost); }, 100); setInterval(function() {     if (nowHost>playerList.length-2) nowHost=0;     else nowHost++; }, 4*4*1000); let nowBeat=0; setInterval(function() {     nowBeat++;     nowBeat%=8;     io.local.emit('beat',nowBeat);     }, 500); client端 public資料夾 index.html 處理首頁配置 player.js 處理播放音樂(Tone.js) sketch.js主程式 index.html <html> <head>   <meta charset="UTF-8">   <meta name="viewport" content="width=device-width, initial-scale=1.0">       <script language="javascript" type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.10.2/p5.min.js"></script>   <script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.10.2/addons/p5.sound.min.js"></script>   <script src="https://cdnjs.cloudflare.com/ajax/libs/tone/13.0.1/Tone.min.js" type="text/javascript"></script>   <script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/2.3.0/socket.io.js"> </script>   <script src="https://unpkg.com/p5.touchgui@0.5.2/lib/p5.touchgui.js"></script>     <script language="javascript" type="text/javascript" src="sketch.js"></script>   <script language="javascript" type="text/javascript" src="player.js"></script>   <script language="javascript" type="text/javascript" src="serial.js"></script>   <script >       </script>       <style> body { padding: 0; margin: 0; } </style> </head> <body> </body> </html> player.js let myPattern = [     [0,0,0,0,0,0,0,0], //bd     [0,0,0,0,0,0,0,0], //cr     [0,0,0,0,0,0,0,0], //hh     [0,0,0,0,0,0,0,0], //t1     [0,0,0,0,0,0,0,0], //t2 ] let ansPattern = [     [0,0,0,0,0,0,0,0], //bd     [0,0,0,0,0,0,0,0], //cr     [0,0,0,0,0,0,0,0], //hh     [0,0,0,0,0,0,0,0], //t1     [0,0,0,0,0,0,0,0], //t2 ] let bdrum; let crash; let hh_c; let tom1; let tom2; //let totalBeat=0; //Tone.Transport.scheduleRepeat(playBeat, "0.5s"); Tone.Buffer.on('load', play); let img_bdrum; let img_cymbals; let img_drum; function preload() {     bdrum = new Tone.Player('assets/80s-Bdrum1.mp3');     crash = new Tone.Player('assets/80s-CRASH1.mp3');     hh_c = new Tone.Player('assets/80s-HHCLOSE1.mp3');     tom1 = new Tone.Player('assets/80s-TOM1.mp3');     tom2 = new Tone.Player('assets/80s-TOM2.mp3');     bdrum.toMaster();     crash.toMaster();     hh_c.toMaster();     tom1.toMaster();     tom2.toMaster();     img_bdrum = loadImage('assets/bdrum.png');     img_cymbals = loadImage('assets/cymbals.png');     img_drum = loadImage('assets/drum.png'); } function play() {     Tone.Transport.start(); } function keyTyped() {   if (key>0&&key<6) ansPattern[key-1][steps]=1;   } function playBeat(steps, pattern) {               if (pattern[0][steps] == 1) {         bdrum.start();     }     if (pattern[1][steps] == 1) {         crash.start();     }     if (pattern[2][steps] == 1) {         hh_c.start();     }     if (pattern[3][steps] == 1) {         tom1.start();     }     if (pattern[4][steps] == 1) {         tom2.start();     } } sketch.js let socket; let players; let host; let myId; let serverIp='192.168.1.109:3000'; let state; function setup() {             createCanvas(windowWidth,windowHeight);     background(220);     socket = io('http://'+serverIp); //change server ip here     socket.on('players', (num)=>{  players=num; });     socket.on('hoster name', (hostInput)=>{          host=hostInput;         if (host==myId) {             socket.emit('send pattern', myPattern);         }     });     socket.on('answer pattern', (patternIn)=>{         ansPattern=patternIn;     });     let init_myPattern=false;     let init_ansPattern=false;         socket.on('beat', (stepsIn)=>{         havePlayed=false;         playBeat(steps, ansPattern);         steps=stepsIn;               if (host!=myId) { // now is play mode             state='play';                         myPattern= [                 [0,0,0,0,0,0,0,0], //bd                 [0,0,0,0,0,0,0,0], //cr                 [0,0,0,0,0,0,0,0], //hh                 [0,0,0,0,0,0,0,0], //t1                 [0,0,0,0,0,0,0,0], //t2             ]             init_myPattern=false;                                 } else {         // now is host mode             state='host';             playBeat(steps, myPattern);             ansPattern= [                 [0,0,0,0,0,0,0,0], //bd                 [0,0,0,0,0,0,0,0], //cr                 [0,0,0,0,0,0,0,0], //hh                 [0,0,0,0,0,0,0,0], //t1                 [0,0,0,0,0,0,0,0], //t2             ]             if (!init_myPattern) {                 myPattern= [                     [0,0,0,0,0,0,0,0], //bd                     [0,0,0,0,0,0,0,0], //cr                     [0,0,0,0,0,0,0,0], //hh                     [0,0,0,0,0,0,0,0], //t1                     [0,0,0,0,0,0,0,0], //t2                 ]                 init_myPattern=true;             }                                 }         //console.log(state);             }); } let steps; let havePlayed; function draw() {     myId=socket.id;         if (key>0 && key<6 && keyIsPressed && state=='host') {         myPattern[key-1][steps]=1;         if (!havePlayed) {             playBeat(steps, myPattern);             havePlayed=true;         }     }     if (state=='host') background(255,0,0,10);     else background(0,128,220);     let spaceW=windowWidth/9;     let spaceH=windowHeight/7;     let shW=spaceW/2;     let shH=spaceH;     fill(0);     textSize(16);     text('online: '+players, shW, shH/3);     text('Host  : '+host, shW, shH/2);     text('state: '+ state, shW, shH/1.5);             for (let i=0; i<8; i++) {         for (let j=0; j<5; j++) {             if (myPattern[j][i]==1) {                                 let minW=Math.min(spaceH,spaceW);                 switch(j) {                     default:                     break; case 0:                     image(img_bdrum, shW+spaceW*i, shH+spaceH*j, minW,minW);                     break; case 1:case 2:                     image(img_cymbals, shW+spaceW*i, shH+spaceH*j, minW,minW);                     break; case 3: case 4:                     image(img_drum, shW+spaceW*i, shH+spaceH*j, minW,minW);                 }                                 fill(0,30);             } else if (ansPattern[j][i]==1) {                                 fill(150);                 let minW=Math.min(spaceH,spaceW);                 switch(j) {                     default:                     break; case 0:                     image(img_bdrum, shW+spaceW*i, shH+spaceH*j, minW,minW);                     break; case 1:case 2:                     image(img_cymbals, shW+spaceW*i, shH+spaceH*j, minW,minW);                     break; case 3: case 4:                     image(img_drum, shW+spaceW*i, shH+spaceH*j, minW,minW);                 }                             }             else {                 fill(255);             }                         //rect(shW+spaceW*i, shH+spaceH*j, spaceW,spaceH); //draw player                     }         fill(255,255,0,10);         rect(shW+steps*spaceW,shH,spaceW,spaceH*5);         stroke(0);     } } device #include "CurieIMU.h" void setup() {   Serial.begin(9600); // initialize Serial communication   while (!Serial);    // wait for the serial port to open   // initialize device   Serial.println("Initializing IMU device...");   CurieIMU.begin();   // Set the accelerometer range to 2G   CurieIMU.setAccelerometerRange(2); } void loop() {   float ax, ay, az;   CurieIMU.readAccelerometerScaled(ax, ay, az);     Serial.print("a:\t");   Serial.print(ax);   Serial.print("\t");   Serial.print(ay);   Serial.print("\t");   Serial.print(az);   Serial.println(); } 後記:目前還在整合serial 及GUI聲音調整,未來會有更多 目前實驗到: serial連線 https://editor.p5js.org/alanhc/sketches/ILrZMsoO7 深度學習訓練 https://editor.p5js.org/alanhc/sketches/FmNlDsPjv 介面調整及測試 https://editor.p5js.org/alanhc/sketches/Tpc-lw1Xi 可至15週筆記看實驗

Read more →

December 26, 2019

alanhc 互動技術-week15

#interactive_programming

 我實在不知道期末作業做什麼比較好,而且我也想做到期末作品人家可以投我的作品,找了很久有沒有一些有趣的應用 我發現有人做一個使用arduino與tensorflow.js的應用 參考文章 但這可能有點進階,在還沒有任何web開發經驗的我來說有點早,因此我找了幾個影片學怎麼寫node跟javascript等等 然後socket的寫法我大部分是跟著這影片學,再加上一些其他文章的參考 發現其實google有個叫做chrome music lab的地方,也很有趣,也讓我確定要做的東西 chrome music lab 實在想做一點機器學習的東西,剛好有個函式庫叫做ml5.js他是基於tensorflow.js的一個簡單容易上手的函示庫 直接看文件就好,因為他也很好上手 [ 文件 ] 等等會有更詳細的解說 p5.js serial的寫法 [ doc ] 簡述 index.html > 網頁進入點 沒有特別的,不多加論述 p5.serialport.js > 要匯入的library 請參照 [ doc ] main.js > 裡面有setup()跟draw() serial.js > 直接把一些重要函式包再一起放在這 執行前需要先把整個repository clone下來,執行node startserver.js,由於它是由node去做的 serial.js initSerial() 會放在到時候彙整的setup() 或在此實驗是在main.js呼叫 let serial="/dev/ttyACM0"; let latestData = "waiting for data"; function initSerial() {   serial = new p5.SerialPort();   serial.list();   serial.open("/dev/ttyACM0");   serial.on('connected', serverConnected);   serial.on('list', gotList);   serial.on('data', gotData);   serial.on('error', gotError);   serial.on('open', gotOpen);   serial.on('close', gotClose); } function serverConnected() {   print("Connected to Server"); } function gotList(thelist) {   print("List of Serial Ports:");   for (let i = 0; i < thelist.length; i++) {     print(i + " " + thelist[i]);   } } function gotOpen() {   print("Serial Port is Open"); } function gotClose(){     print("Serial Port is Closed");     latestData = "Serial Port is Closed"; } function gotError(theerror) {   print(theerror); } let ax,ay,az; function gotData() {   let currentString = serial.readLine();    trim(currentString);                      if (!currentString) return;              let splitString = split(currentString, '\t');   ax=float(splitString[1]);   ay=float(splitString[2]);   az=float(splitString[3]);       latestData = currentString; } function gotRawData(thedata) {   } p5.js的介面函式庫 [ doc ] 由於在期中作業時發現有人使用gui的函式庫,我也找了一個是p5.touchgui,節省一點時間   簡述 index.html > 網頁進入點 沒有特別的,不多加論述 g_m.js > 做場景切換等環境變數的設定 gui.js > 直接在此畫gui gui.js let b_go, t_set, s_volume; let pre_stage; function init_gui_layout() {   pre_stage=0;     gui = createGui();   gui.loadStyle("Blue");   b_go = createButton("start", cx-50,cy,100,50);   t_set = createToggle("▽", cx/10, cy/10, 50,50);   s_volume = createSlider("volume", cx,cy-75);     b_go.onPress = function() {     if (stage==0) stage++;   }   t_set.onPress = function() {     if (stage!=-1) pre_stage=stage;     if (t_set.val) stage=-1;     else stage=pre_stage;   }       t_set.labelOn  = "△";   t_set.labelOff = "▽"; } function gui_layout() {   drawGui();     switch(stage) {     default:     break; case -1:       b_go.visible = false;     break; case 0:       b_go.visible = true;     break; case 1:       b_go.visible = false;     break; case 2:         }   s_volume.visible = t_set.val;     if (s_volume.isChanged) {     volume = s_volume.val;   }   s_volume.val = volume;   } ml5.js [ doc ] 簡述 index.html > 網頁進入點  sketch.js > 裡面有setup()跟draw() 做主要控制 ml5.js > 把ml5.js分為初始的函式跟loop serial.js p5.serialport.js index.html <head>   <meta charset="UTF-8">   <title>XY Classifier</title>   <script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.9.0/p5.min.js"></script>   <script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.9.0/addons/p5.dom.min.js"></script>   <script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.9.0/addons/p5.sound.min.js"></script>   <script src="https://unpkg.com/ml5@0.4.3/dist/ml5.min.js" type="text/javascript"></script> </head> <body>   <h1>Teachable Air Drum</h1>   <script src="sketch.js"></script>   <script src="ml5.js"></script>   <script src="serial.js"></script>   <script src="p5.serialport.js"></script>   <p>     Label: <select id="label">       <option value="bdrum">bdrum</option>       <option value="crash">crash</option>       <option value="hh_c">hh_c</option>       <option value="tom1">tom1</option>       <option value="tom2">tom2</option>       <option value="up">up</option>     </select>     <button id="train">train</button>   </p>   <p>     Classification: <span id="classification"></span>   </p>   <p>     Click in canvas to add training data.  <span id="device_data"></span>   </p> </body> </html> sketch.js let brain; function setup() {   let canvas = createCanvas(400, 400);     canvas.mousePressed(addData);   init_ml5js();     // Train Model button   select('#train').mousePressed(trainModel);   background(0);   initSerial();   } function draw() {     textAlign(LEFT);   select('#device_data').html("acc is "+ax+","+ay+","+az);   } ml5.js function init_ml5js() {     // Create ethe model   const options = {     inputs: ['x', 'y'],      outputs: ['label'],     layers: [         ml5.tf.layers.dense({             units: 50,             inputShape: [3],             activation: 'relu',         }),         ml5.tf.layers.dense({             units: 25,             activation: 'relu',         }),                 ml5.tf.layers.dense({             units: 6,             activation: 'sigmoid',         })     ],     debug: true,     task: 'classification'   }   brain = ml5.neuralNetwork(options);   } // Add a data record function addData() {   let label = select('#label').value();   // Add data   brain.addData({x:ax, y:ay, z:az}, {label});   stroke(255);   noFill();   ellipse(mouseX, mouseY, 32);   fill(255);   textSize(16);   textAlign(CENTER, CENTER);   text(label, mouseX, mouseY); } // Train the model function trainModel() {   brain.normalizeData();     brain.train({ epochs: 200 }, finishedTraining); } // When the model is trained function finishedTraining() {   brain.classify([ax, ay, az], gotResults); } // Got a result function gotResults(error, results) {   if (error) {     console.error(error);     return;   } // Show classification   select('#classification').html(results[0].label);   // Predict again   brain.classify([ax, ay, az], gotResults); } serial.js 請參考前一部分的serial

Read more →

December 19, 2019

alanhc 互動技術-week14

#interactive_programming

連線小畫家 先可以傳資料 Server(開啟port 5204作為服務端口) import processing.net.*; Server server; Client client; void setup() {   size(300,300);   server = new Server(this, 5204); } void draw() {     Client temp = server.available();     if (temp != null) {         client = temp;         String msg = client.readString();         println(msg);            } } Client(送訊息到server) import processing.net.*; Client client; void setup() {   size(300,300);    client = new Client(this, "127.0.0.1", 5204); } void draw() {   if (mousePressed) {     line(mouseX, mouseY, pmouseX, pmouseY);     client.write(mouseX+" "+mouseY+" "+pmouseX+" "+pmouseY+"\n");   } } 使用字串切割 splitTokens(now); 在Server程式把 println(msg)底下加上 String pos[] = splitTokens(msg); int mpos[]= new int[4]; for (int i=0; i<4; i++) { mpos[i] = int(pos[i]); } line(mpos[0],mpos[1],mpos[2],mpos[3]); 大功告成~         完整程式碼 server import processing.net.*; Server server; Client client; void setup() {   size(300,300);   server = new Server(this, 5204); } void draw() {     Client temp = server.available();     if (temp != null) {         client = temp;         String msg = client.readString();         String pos[] = splitTokens(msg);         int mpos[]= new int[4];         for (int i=0; i<4; i++) {           mpos[i] = int(pos[i]);         }         line(mpos[0],mpos[1],mpos[2],mpos[3]);     } } client import processing.net.*; Client client; void setup() {   size(300,300);    client = new Client(this, "127.0.0.1", 5204); } void draw() {   if (mousePressed) {     line(mouseX, mouseY, pmouseX, pmouseY);     client.write(mouseX+" "+mouseY+" "+pmouseX+" "+pmouseY+"\n");   } } 網路畫完可以undo ArrayList儲存 宣告 ArrayList points; setup() >      points = new ArrayList();  存取 points.add() points.remove() Client import processing.net.*; Client client; ArrayList<PVector> points; void setup() {   size(300,300);    client = new Client(this, "127.0.0.1", 5204);   points = new ArrayList<PVector>(); } void draw() {   background(0);   for (int i=0; isize(); i++) {     circle(points.get(i).x, points.get(i).y, 10);    } } void mouseDragged() {   if (mouseButton==LEFT) {     points.add(new PVector(mouseX, mouseY));     client.write(mouseX+" "+mouseY+" "+0);   }   else if (mouseButton==RIGHT&&points.size()>0) {     points.remove(points.size()-1);     client.write(mouseX+" "+mouseY+" "+1);   } } Server import processing.net.*; Server server; Client client; ArrayList<PVector> points; void setup() {   size(300,300);   server = new Server(this, 5204);   points = new ArrayList<PVector>(); } void draw() {     background(0);     background(0);     for (int i=0; isize(); i++) {       circle(points.get(i).x, points.get(i).y, 10);      }         Client temp = server.available();     if (temp != null) {         client = temp;         String msg = client.readString();                 String pos[] = splitTokens(msg);         int mpos[]= new int[3];         for (int i=0; i<3; i++) {           mpos[i] = int(pos[i]);          }         if (mpos[2]==0) {           points.add(new PVector(mpos[0], mpos[1]));         }         else if (mpos[2]==1 &&points.size()>0 ) {           points.remove(points.size()-1);         }     } } 處理不要掉字串 client import processing.net.*; Client client; ArrayList<PVector> points; void setup() {   size(300,300);    client = new Client(this, "127.0.0.1", 5204);   points = new ArrayList<PVector>(); } void draw() {   background(0);   for (int i=0; isize(); i++) {     circle(points.get(i).x, points.get(i).y, 10);    } } void mouseDragged() {   if (mouseButton==LEFT) {     points.add(new PVector(mouseX, mouseY));     client.write(mouseX+" "+mouseY+" "+0+"\n");   }   else if (mouseButton==RIGHT&&points.size()>0) {     points.remove(points.size()-1);     client.write(mouseX+" "+mouseY+" "+1+"\n");   } } server import processing.net.*; Server server; Client client; ArrayList<PVector> points; void setup() {   size(300,300);   server = new Server(this, 5204);   points = new ArrayList<PVector>(); } void draw() {     background(0);       for (int i=0; isize(); i++) {       circle(points.get(i).x, points.get(i).y, 10);      }         Client temp = server.available();     if (temp != null) {         client = temp;         String msg = client.readString();         if (msg!=null) {           println(msg);           String pos[] = splitTokens(msg);                     for (int t=0; t3) {             int mpos[]= new int[3*4];                         for (int i=0; i<3; i++) {               mpos[i] = int(pos[i+t]);              }                         if (mpos[2]==0) {               points.add(new PVector(mpos[0], mpos[1]));             }             else if (mpos[2]==1 &&points.size()>0 ) {               points.remove(points.size()-1);             }           }         }     } }

Read more →

December 12, 2019

alanhc 互動技術-week13

#interactive_programming

連到老師電腦(Server) 運用上禮拜教的 net library Client 端 //Client 可以是任何人 import processing.net.*; Client client; void setup(){ size(100,100);///老師的serverIP:120.125.70.53 client = new Client(this, "120.125.70.53", 6666); } void draw(){ } void mousePressed(){ client.write("Hello你好帥"); } *先宣告 寫入 Hello你好帥 老師會檢查字串 Server joystick 根據滑桿值發出聲音 f:512~1024 void setup() { pinMode(2,INPUT); pinMode(8, OUTPUT); } void loop() {     int x=analogRead(A0);   tone(8,x);   analogRead(A1);   digitalRead(2); } A0、A1 分別代表X軸與Y軸上的數值(PWM) 使用joystick控制processing程式: Arduino: 透過Serial傳輸 Serial.println(s); void setup() { pinMode(2,INPUT); pinMode(8, OUTPUT); Serial.begin(9600); } void loop() {   // put your main code here, to run repeatedly:   int x=analogRead(A0);   int y=analogRead(A1);     tone(8,x);     String s=String(x)+" "+String(y);   Serial.println(s);   digitalRead(2); } Processing import processing.serial.*; Serial myPort; void setup() {   printArray(Serial.list());   myPort = new Serial(this, "/dev/cu.usbserial-14120",9600);  } void draw() {   while (myPort.available() > 0) {     println(myPort.readString());   } } 使用arduino透過serial控制會動的球球 Arduino void setup() { pinMode(2,INPUT); pinMode(8, OUTPUT); Serial.begin(9600); } void loop() {   // put your main code here, to run repeatedly:   int x=analogRead(A0);   int y=analogRead(A1);   String s=String(x)+" "+String(y);   tone(8,x);     Serial.println(s);   digitalRead(2);   delay(100); } processing 使用 splitTokens() 分割xy字串 import processing.serial.*; Serial myPort; void setup() {   size(1024, 1024);   printArray(Serial.list());   myPort = new Serial(this, "/dev/cu.usbserial-14120",9600);  } int x=512; int y=512; void draw() {   background(0);     while (myPort.available() > 0) {     String now = myPort.readString();     String[] xy = splitTokens(now);     x= int(xy[0]);     y= int(xy[1]);   }     println(x,",",y);   fill(255,0,0);   circle(x,y, 20);   }

Read more →

December 5, 2019

alanhc 互動技術-week11

#interactive_programming

Hello MAKER UNO! 寫腳: digitalWrite(pin, 輸出); pin:要寫的腳位 輸出:HIGH, LOW void setup() {   pinMode(13, OUTPUT);   digitalWrite(13,HIGH); } void loop() {  } LED輪流亮 void setup() {   for (int i=2; i<=13; i++) {     pinMode(i, OUTPUT);   }   digitalWrite(13,0); } int digit[] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0}; int i=0; void loop() {   for (int i=2; i<=13; i++) {     digitalWrite(i,digit[i]);     delay(100);     if (digit[i]==0) digit[i]=1;     else digit[i]=0;       } } 加分:小蜜蜂 int sheet[]={0,261,294,329,349,392,440,493,523}; #define BUTTON 2 #define BUZZER 8 int melody[] = {   5,3,3,0,4,2,2,0,1,2,3,4,5,5,5,0 }; int noteDurations[] = {   10, 10, 10, 10, 10, 10, 10, 10, 10,10, 10, 10, 10, 10, 10, 10 }; int pin; int ledArrayHigh; int ledArrayLow; boolean mode = false; boolean buttonPressed = false; void setup() {   delay(1000);     pinMode(BUTTON, INPUT_PULLUP);   for (pin = 3; pin < 14; pin++) {     pinMode(pin, OUTPUT);   }   for (int thisNote = 0; thisNote < 16; thisNote++) {     int noteDuration = 1000 / noteDurations[thisNote];     tone(BUZZER, sheet[melody[thisNote]], noteDuration);     int pauseBetweenNotes = noteDuration * 1.30;     delay(pauseBetweenNotes);     noTone(BUZZER);   } } 按鈕~ pinMode(pin, 模式); 模式: pullup 預設要拉高 再使用 digitalRead(2) 讀取數值 digitalRead(2) void setup() {   for (int i=3; i<=13; i++) {     pinMode(i, OUTPUT);     digitalWrite(i, HIGH);   }   pinMode(2, INPUT_PULLUP); } bool sw=false; void loop() {   if (digitalRead(2)==HIGH) sw=HIGH;   else sw=LOW;     for (int i=3; i<=13; i++) {       digitalWrite(i, sw);   } } 寫Serial Arduino int f[]={0,261,294,329,349,392,440,493,523}; void setup() {   pinMode(8,OUTPUT);   Serial.begin(9600); } void loop() {   if (Serial.available()) {     char now = Serial.read();     Serial.println(now);     if (now=='1') tone(8,f[1], 300);     if (now=='2') tone(8,f[2], 300);     if (now=='3') tone(8,f[3], 300);     if (now=='4') tone(8,f[4], 300);     if (now=='5') tone(8,f[5], 300);       }   } Processing 先匯入  import processing.serial.*; 宣告 Serial myPort; 指定port myPort = new Serial(this, "/dev/cu.usbserial-14220",9600);  寫入 myPort.write(key); 完整Code import processing.serial.*; Serial myPort; void setup() {   printArray(Serial.list());   myPort = new Serial(this, "/dev/cu.usbserial-14220",9600);  } void draw() {   } void keyPressed() {     myPort.write(key); }

Read more →

November 21, 2019

alanhc 互動技術-week10

#interactive_programming

Maker UNO 0. 下載 [ CH341 Driver for Mac ]. 設定port 聽到 馬里奧的聲音就完成了

Read more →

November 14, 2019

alanhc 互動技術-week8

#interactive_programming

猜杯子 物件導向 改寫上方為物件導向寫法 1. 寫好Class class Cup{     PVector pos;     PVector v;     boolean coin=false;     Cup(float x, float y) { ///建構子        pos = new PVector(x,y);        v = new PVector(random(4), random(3));     }     void draw() {        pos.add(v);        if (pos.x<0 || pos.x>400) v.x *= -1;        if (pos.y<0 || pos.y>300) v.y *= -1;        fill(255);        ellipse(pos.x, pos.y, 90,60);     } } *其中,Cup(float x, float y)<為建構子 2. 宣告:Cup[] cup= new Cup[3]; 3. 實體化:cup[i] =new Cup(100+i*100, 100); 函式 簡化 ex. playerDraw() 切換場景 ex. 開始、贏、輸了 使用stage來做場景切換 滾動 電腦圖學的pushMatrix()、popMatrix()裡的rotate()去處理

Read more →

October 31, 2019

alanhc 互動技術-week7

#interactive_programming

小畫家著作半透明貼圖,做好丟入ppt 移動小星星練習 優秀學姊作品 1. 使用 keyPressed() 、 keyReleased() 控制變數 2. 在draw()改圖 一次讀很多圖 1. 宣告物件:PImage[] img = new PImage[3]; 2. 讀檔:for (int i=0; i<3; i++) img[i] = loadImage("star"+i+".png"); QUEUE 排隊產生10以內的閃電 if (thunderN==10) {     for (int i=0; i<9; i++) {         thunderX[i]=thunderX[i+1];         thunderY[i]=thunderY[i+1];         thunderDir[i]=thunderDir[i+1];     }     thunderN--; } * 往前挪 thunderX[i]=thunderX[i+1]; 移動小星星程式 位置:draw() background(mouseX); image(img[run],starX,starY,50,50); starX+=run-1; 位置:keyPressed()、keyReleased() run=0 or 1 or 2 閃電程式 控制閃電:thunderDir、thunderX、thunderY 1. 產生閃電 位置:draw() if (frameCount%60==0) genThunder();   每60frame產生一個閃電 2. 畫閃電 位置:draw() drawThunder() PVector練習 物件的移動方法 宣告 PVector user, userV; 給定值 user = new PVector(200,200); 兩個向量 user+userV   user = new PVector(200,200);   userV = new PVector(1,1); user.add(userV); 完整程式碼 電流急急棒 判斷如果碰到邊 準備圖片   imgMap=loadImage("map.png");   imgMap.loadPixels(); 判斷滑鼠點顏色   imgMap.pixels[ mouseX+mouseY*360 ]==color(0,0,0) 完整程式: 彈幕 使用前面的PVector小技巧 小問題:曲率?

Read more →

October 24, 2019

alanhc 互動技術-week6

#interactive_programming

打殭屍小遊戲 [ 連結 ] 生成10個殭屍位置 for (int i=0; i<10; i++) {     zombiePos[i] = int( random(3) );      print(zombiePos[i]+" "); } 畫殭屍 for (int i=9; i>=0; i--) {     rect(zombiePos[i]*100, 200-i*30,100,100);  } 判斷殭屍是否被按否則視窗變紅 if ( (key=='1'&&zombiePos[0]==0) || (key=='2'&&zombiePos[0]==1) ||   (key=='3'&&zombiePos[0]==2) ) {     println("correct");     for (int i=0; i<9; i++) zombiePos[i]=zombiePos[i+1];//move zombie     zombiePos[9]=int( random(3) ); } else {     fill(255,0,0);     rect(0,0,width,height); } key:按對了更新螢幕且要新增一個新的     for (int i=0; i<9; i++) zombiePos[i]=zombiePos[i+1];//move zombie     zombiePos[9]=int( random(3) ); 小提醒: zombiePos[i] 的範圍 [0,2] 所以殭屍的X為 zombiePos[i]*100 聲音 youtubeto import processing.sound.*; SoundFile player; player = new SoundFile(this, "rain.wav"); player.play(); 不能播QQ Minim 0. 查範例 1. 匯入及宣告 import ddf.minim.effects.*; import ddf.minim.signals.*; import ddf.minim.spi.*; import ddf.minim.ugens.*; Minim minim; AudioPlayer player; 2. 實體化及讀音樂檔 minim = new Minim(this); player = minim.loadFile("cymbal.wav"); 3. 播放 * rewind() 是倒帶 player.rewind(); player.play(); 完整程式碼 import ddf.minim.*; import ddf.minim.analysis.*; import ddf.minim.effects.*; import ddf.minim.signals.*; import ddf.minim.spi.*; import ddf.minim.ugens.*; Minim minim; AudioPlayer player; AudioInput input; void setup() {   minim = new Minim(this);   player = minim.loadFile("cymbal.wav"); } void mousePressed() {   player.rewind();    player.play(); } 氣球 使用陣列使其氣球可以一直生成 void mousePressed() {   balloonSize[nowN]=10;   balloonX[nowN] = mouseX-balloonSize[nowN]/2;   balloonY[nowN] = mouseY-balloonSize[nowN]/2*3;   nowN++;   bigger=1; } void mouseReleased() {   bigger=0; } 畫畫面 void draw() {   background(255);   for (int i=0; i          image(imgBalloon, balloonX[i], balloonY[i], balloonSize[i], balloonSize[i]);     if (balloonY[i]>0) {       balloonY[i]--;     }    }   if (bigger==1) balloonSize[nowN-1]+=1;   println(bigger+" "+nowN); } 氣球可以充氣 if (mousePressed) balloonSize[nowN-1]+=1; 小技巧:解決氣球充氣後偏移 void setBalloon(int size, int i) {   balloonSize[nowN]=10;   balloonX[nowN] = mouseX-balloonSize[nowN]/2;   balloonY[nowN] = mouseY-balloonSize[nowN]/2*3; } void mousePressed() {   setBalloon(10, nowN); 組別: 曾宏鈞 想做的遊戲:

Read more →

October 17, 2019

alanhc 互動技術-week4

#interactive_programming

打字遊戲 先用一個code的陣列,使用查表 String []code = {  "qwertyuiop",  "asdfghjkl",  "zxcvbnm", }; 使用上週的技巧,陣列儲存 滑鼠按下,格子打勾 void keyPressed() {   for (int i=0; i<3; i++) {     int j = code[i].indexOf(key);     if (j>=0) {       table[i][j] = 1;       println(j);     }   }  } 滑鼠放開,格子歸零 void keyReleased() {   for (int i=0; i<3; i++) {     int j = code[i].indexOf(key);     if (j>=0) {       table[i][j] = 0;       println(j);     }   }  } 打字上去 text(哪一個字元 , X座標, Y座標); text(code[i].charAt(j) , 100+j*size+(size/1.5), i*size+150+(size/4)); textSize(16);  速度與加速度 速度 vx ballX = +vx; if (ballX<0) vx=+2; if (ballX>700) vx=-2; 球不會在邊線消失 +15 if (ballX<0+15) vx = +2; 重力加速度 加一點重力加速度 vy+=0.98 void draw() {   ellipse(ballX, ballY, 30,30);   ballX+=vx; ballY+=vy;   vy+=0.98; 怕跳太高 *0.7 if (ballY<0+15) vy = -vy*0.7; void draw() {   //background(255);   ellipse(ballX, ballY, 30,30);   ballX += vx;    ballY += vy;   vy += 0.98;   if (ballX<0+15)   vx = -vx*0.9;   if (ballX>600-15) vx = -vx*0.9;   if (ballY<0+15)   vy = -vy*0.9;   if (ballY>400-15) vy = -vy*0.9;   println(vy); } Q. 解決球不會一直重複彈跳 A. 解決:float ballX=100, ballY=100; 球的型別要是float 跳跳馬力歐 有力的變化,位置: draw()   marioX += marioVX;   marioY += marioVY; 重力,位置: draw() marioVY += 0.9; 往上跳後會掉下來 位置: keyPressed() if (keyCode==UP&&flying==0) {   marioVY-=30;   flying=1; } 位置: draw() if (marioY<100) marioVY += 0.9; else  { ///hold on floor   marioY=100;   flying=0; } 左右跑的摩擦力 位置: keyPressed() if (keyCode==LEFT) {   marioVX-=3;   softBrake=0; } if (keyCode==RIGHT) {   marioVX+=3;   softBrake=0; } 位置: keyReleased() if (keyCode==RIGHT) softBrake=1; if (keyCode==LEFT) softBrake=1; 位置: draw() if (softBrake==1) marioVX *=0.9; *=0.9 慢慢減少 馬力歐跳方塊 位置: draw() if (marioY<100) {     if (flying==1)marioVY += 0.9;     if (marioVY>0 && marioY>50 && (marioX>100&&marioX<400)) {  flying=0; marioY=50;}  } else {      if (marioY<=50 && (marioX>100&&marioX<400)) marioY=50;     else marioY=100;     flying=0; } 重點: 如果開始往下掉(marioVY>0),才判斷位置才會比較順 座標系統是向下

Read more →

October 3, 2019

alanhc 互動技術-week3

#interactive_programming

筆記 background() 比image()快10倍 一筆成形 void draw() {   line(mouseX, mouseY, pmouseX, pmouseY);  } 按下左鍵才畫圖 if (mousePressed == true && mouseButton == LEFT) void setup() {     size(600, 400); }  void draw() {     if (mousePressed == true && mouseButton == LEFT) line(mouseX, mouseY, pmouseX, pmouseY);  } 畫粗細及輕重 調粗細 strokeWeight(lw); 調顏色 stroke(colorV); 1. 按下方向鍵處理 keyPressed() 2. 變數調整 colorV += 20;、lw-=1; int colorV=0; int lw=1; void draw() {   if (mousePressed == true && mouseButton == LEFT) {     ellipse(mouseX, mouseY, 3, 3);     line(mouseX, mouseY, pmouseX, pmouseY);     stroke(colorV);     strokeWeight(lw);   } } void keyPressed() {   if (keyCode == UP) {      colorV += 20;   } else if (keyCode == DOWN) {      colorV -= 20;   }    if (keyCode == LEFT) {      lw-=1;   } else if (keyCode == RIGHT) {      lw+=1;   }    if (colorV<0) colorV=0;   if (lw<1) lw=1; } 小畫家 座標系統 void setup() {     size(600, 400);     fill(255,0,0); rect(0,0,50,50);     fill(0,255,0); rect(0,50,50,50);     fill(0,0,255); rect(0,100,50,50);     fill(255,0,255); rect(0,150,50,50);     fill(0,255,255); rect(0,200,50,50);     line(50,0,50,400);     line(25,250,25-7,400);     line(25,250,25+7,400);     }    void draw() {    if (mousePressed && mouseX<50) {       if (mouseY<50) stroke(255,0,0);       else if (mouseY<100) stroke(0,255,0);       else if (mouseY<150) stroke(0,0,255);       else if (mouseY<200)  stroke(255,0,255);       else if (mouseY<250)  stroke(0,255,255);       else {         strokeWeight( (mouseY-250)/10 );      }    }    if (mousePressed && mouseX>50) {      line(pmouseX, pmouseY, mouseX, mouseY);    } } 特殊鍵用keyCode,一般用key 按下滑鼠瞬間 void mousePressed() 按下滑鼠拖曳 void mouseDragged() 畫線用 mouseDragged() 選顏色用 mousePressed()

Read more →

September 26, 2019

alanhc 互動技術-week1

#interactive_programming

下載 IDE視窗 色彩選擇小工具 Tools > Color Selector... #AA5151為16進位的RGB顏色碼 畫布(繪圖視窗) size(X座標, Y座標); 畫圖指令 Reference > 2D Primitives ellipse(X座標, Y座標, 寬, 高); rect(X座標, Y座標, 寬, 高);            line(X1, Y1, X2, Y2);                小企鵝~~~

Read more →

September 25, 2019

alanhc 互動技術-week2

#interactive_programming

觀念 Processing 陣列宣告 int [][] table = new int [786][357]; ///宣告786*357的陣列 滑鼠事件 void mousePressed() *KEY 打洞洞 mouseX/16*16, mouseY/30*30 mouseX/16 除掉奇怪的值 mouseX/16*16 乘回來就可以歸零到左上角! 打洞洞程式 void mousePressed() {     fill(0); rect(mouseX/16*16, mouseY/30*30,16,30); } 小觀念:畫洞洞 > rect(X位置, Y位置, 寬, 高); 任務:古老洞洞卡體驗 讀圖! 1. 設定圖片參考路徑 Sketch > Add File 2. 寫程式! 宣告物件:PImage photo; 讀圖片到物件:hoto = loadImage("run03.png"); 畫圖: background(imgBG); 左鍵打洞洞,右鍵還原 位置:draw() 小技巧:使用陣列記洞洞位置 int nowI=mouseX/bx, nowJ=mouseY/by; if (mousePressed) {   if (mouseButton==LEFT) {     table[nowI][nowJ]=1;   } else {     table[nowI][nowJ]=0;   } } 畫洞洞 for (int i=0; i<49; i++) {     for (int j=0; j<10; j++) {       fill(0);       if (table[i][j]==1) rect(i*bx, j*by,bx,by);     } } 大功告成! 今日程式碼:

Read more →

September 19, 2019

20190614-CGfinal

#blogger

alanhc/張牧之 電腦圖學-week17 [final] 張貼者: alanhc 於 上午11:13 以電子郵件傳送這篇文章BlogThis!分享至 Twitter分享至 Facebook分享到 Pinterest 標籤: 06160485_曾宏鈞, Week17 Ref https://2019graphicsa.blogspot.com/2019/06/alanhc-week17.html

Read more →

June 14, 2019

alanhc/張牧之 電腦圖學-week15

#computer_graphics

投影法 Perspective Ortho Frustum glu 進階函式 glm.h 裡面包含 glmReadOBJ(), glmDraw(), glmUnitized() glEnable(GL_DEPTH_TEST); ///有立體功能 GLfloat light_pos[] = { 0.0, 0.0, 1.0, 0.0 }; glEnable(GL_LIGHT0); ///NOW2 打光後變立體的彩色的 glEnable(GL_LIGHTING); ///NOW2 打光後變立體的彩色的 glLightfv(GL_LIGHT0, GL_POSITION, light_pos);///NOW2 打光的位置 Michael bay rotating camera https://www.youtube.com/watch?v=DPtHPgZmZdA projection矩陣 glMatrixMode(GL_PROJECTION);///NOW4 glLoadIdentity();///NOW4 glOrtho(-1,+1, -1,+1, -10,+10);///NOW4 可以看到範圍比較大的投影法 modelview矩陣 glMatrixMode(GL_MODELVIEW);///NOW3 glLoadIdentity();///NOW3 gluLookAt(eyeX, eyeY, eyeZ, ///NOW3 LookAt的 eye 0.0, 0.6, 0.0, ///NOW3 LookAt的 center 0, 1, 0);///NOW3 LookAt的 up 草食性動物 >眼睛長在旁邊 肉食性動物 >眼睛長在前面 小葉閒聊 learning pyramid http://www.cmlab.csie.ntu.edu.tw/~jsyeh/3dcg10/ 裡 source glm.c glm.h 印度人 搖頭 https://www.youtube.com/watch?v=ZK1KdMU10pg

Read more →

May 31, 2019

alanhc/張牧之 電腦圖學-week14

#computer_graphics

0. 計時器 1. 影格 2. 內插 / 插值(Interpolation) 3. 改預設路徑(美麗的錯誤) 4. Dancing Time!!! 5. 小葉閒聊 0. 計時器 解釋 glutTimerFunc(持續時間, 呼叫的timer函式, 在第幾秒); 實作 1. include #include 2. 放音樂在 freeglut/bin 3. 寫程式 main() 放入 glutTimerFunc(1000, timer, 0); 新憎程式 void timer(int t) { PlaySoundA("carhn[1].wav", NULL, SND_ASYNC); } Q 如果要馬上播呢? A. 加入這行 void timer(int t) { glutTimerFunc(1000, timer, t+1); ///馬上播 < 就是這行 printf("%d \n", t); PlaySoundA("carhn[1].wav", NULL, SND_ASYNC); } 1.影格 [ 參考&圖片 ] 介紹 FPS 一般來我們是30fps 因此每秒會有30張 recall 大一flash設計 重要概念:關鍵影格 因此,重要個部份來了 這背後到底怎麼做的????? > 數學!!! 內插法(Interpolation) 2.內插 / 插值(Interpolation) 看張圖理解 公式 [ 參考資料1wiki ] [ 參考資料2 stackexchange ] [ 超詳細! ] 口訣: 座標  = alpha * 新+ (1-alpha) * 舊 alpha 是 0~1的數字 新 配 alpha 舊 配 (1-alpha) 舊的是0 新的是1 用 Excel 算下去就對啦 alpha = t/30 內插: alpha*新+(1-alpha)*舊 這樣就可以算出來拉哈哈哈 程式 void display() { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glPushMatrix(); glTranslatef(nowX, 0,0); glutSolidTeapot( 0.3 ); glPopMatrix(); glutSwapBuffers(); } void timer(int t) { glutTimerFunc(30, timer, t+1); ///馬上播 printf("%d \n", t); float alpha = (t%30) / 30.0; nowX = alpha*1.0+(1-alpha) * -1.0; glutPostRedisplay(); } display() 的glTranslatef(nowX, 0,0);負責畫圖 由timer裡的nowX = alpha*1.0+(1-alpha) * -1.0算座標 3.改預設路徑(美麗的錯誤) 在專案資料夾會有個 "C:/Users/alant/Desktop/freeglut/bin" />改working_dir="." 所以會變這樣 "." />然後 會出現這 因為路徑改掉了!!!去freeglut\bin下載回來即可 4.Dancing Time!!! 1. 移動模型 (擺好pose) 2. 紀錄 (recall 前面觀念的 關鍵影格) 3. 貼很多次 (變成動畫) 好像是 poping 還是 locking Next > 使用Alpha compositing 筆記 影格的概念 讀檔 if (key=='t') {     ///啟動timer   } 捕間動畫 > timer  mlt材質 obj點 Q&A glutPostRedisplay 跟glutMainLoop()講我需要一直檢查 5.小葉閒聊 14 now 15 X 17 imagine cup https://www.geekwire.com/2019/microsoft-imagine-cup-winner-aims-transform-blood-glucose-monitoring-eye-testing-app/ 今天的程式碼

Read more →

May 24, 2019

alanhc/張牧之 電腦圖學-week13

#computer_graphics

寫檔 1. 新增指標 fout FILE * fout=NULL; 2. 指定指標 fopen("檔名", 方式)  方式是 "w+" 3. 印到檔案 fprintf(指標, "要寫的東西") 1. File * fout=NULL 2. fout = fopen("filename.txt", "w+"); 3. fprintf(fout, "hello world"); 讀檔 1. 新增指標 fin FILE * fin =NULL; 2. 指定指標 fopen("檔名", 方式)  方式是 "r" 3. 讀檔案 fscanf(指標, "%s", line); 1. File * fin=NULL 2. fin = fopen("filename.txt", "r"); 3. fscanf(fin, "hello world"); 控制獨立關節轉動 1. main() 宣告 glutKeyboardFunc(keyboard); 2. 程式撰寫 > 使用一個 變數 angleID, 使 motion() 裡,陣列 angle[angleID]  可以控制 display() 裡的 angle[] void motion(int x, int y) { angle[angleID] += (x-oldX); oldX = x; display(); } void keyboard(unsigned char key, int x, int y) { if(key=='1') angleID=1; if(key=='2') angleID=2; if(key=='3') angleID=3; if(key=='4') angleID=4; } 圖示 紀錄/播放動作 紀錄 講解 > 使用寫檔 (參見前一章) > 按下w開始 記錄(write) > fprintf( 指標, "要印的東西" )  keyboard() 裡,加入以下程式 if (key=='w') { if (fout==NULL) fout=fopen("motion.txt", "w+"); for (int i=0; i<5; i++) { printf( "%.1f ", angle[i] ); fprintf( fout, "%.1f ", angle[i]); } printf("\n"); fprintf(fout, "\n"); } if (fout==NULL) 檢查是否有開檔 for () 一次寫5個關節 在motion()裡面也加 if(fin==NULL) fin = fopen("motion.txt", "r"); for(int i=0; i<20;i++){ fscanf(fin, "%f", &angle[i]); } printf("\n"); fprintf(fout, "\n"); 在freeglut\bin資料夾底下找 motion.txt 就可以找到剛剛紀錄的座標 播放 講解 > 使用讀檔 (參見前一章) > 按下r開始 記錄(write) > fscanf( 指標, "要讀的東西" )  if(key=='r'){ if(fin==NULL) fin = fopen("motion.txt", "r"); for(int i=0; i<20;i++){ fscanf(fin, "%f", &angle[i]); } } glutPostRedisplay(); *glutPostRedisplay(); 加上這 就會重新畫,否則只有按下鍵盤才畫 終於大功告成拉拉拉拉拉拉拉拉拉哈哈哈哈哈哈哈哈哈哈哈哈哈!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 小葉閒聊time  規劃的重要性 unitize 轉成單位 分開存,才能分開畫

Read more →

May 17, 2019

alanhc/張牧之 電腦圖學-week12

#computer_graphics

windows mmsystem.h有些需要 mmsystem   multimedia system可播聲音 PlaySoundA("英文ASCII檔名", NULL, SND_SYNC) (windows物件,windows物件,windows物件 ) wav檔下載 播放音樂 1. include  2. 路徑正確 3. 寫程式 1. include Debug Time Q: A: build option > Linker setting > add library "winmm" SND_ASYNC 聲音不等待同步 小工具 windows內建 小葉很炫技巧 dir *winmm* /s (搜尋所有子目錄) 小葉閒聊 總統盃黑客松 細心 耐心、不甘心 問問題 小葉酷炫技巧 dir *winmm* path  小葉cpe密技 每次讀兩行 片語 英文題目 task 小階段解決 白紙

Read more →

May 10, 2019

alanhc/張牧之 電腦圖學-week11

#computer_graphics

0. 小觀念:機器人&階層性關節轉動 1. Codding Time!!! 1-1.鏡射 1-2.滑鼠 1-3.小技巧-更新座標: 1-4.鍵盤 2.小葉閒聊Time 0. 小觀念:機器人&階層性關節轉動 >那是甚麼??? 0-1 機器人 機器人是由許多的 關節 連接 骨頭 組成 0-2 階層性關節 一層一層 的放入 stack 使其可以一起旋轉 TRT旋轉是關鍵!!! >參考下圖TRT [ 小提示 ] 不知道在講甚麼? [ 傳送門 ] TRT TRT旋轉 1. Codding Time!!! 1-1鏡射 反轉 x座標 反轉 角度 glRotatef(-angle, 0,0,1); glTranslatef(-x, 0,0); 乾坤大挪移~~~ 1-2滑鼠 Past: glutMotionFunc() Now: glutMotionFunc() + glutMouseFunc() motion 與 mouse差別: 1-3小技巧-更新座標: 原理圖 程式觀點 void motion(int x, int y) ///new { angle += (x-oldX); oldX=x; ///old 數字觀點 1-4鍵盤 void keyboard(unsigned char key, int x, int y) key:按鍵 x:按下時滑鼠x座標 y:按下時滑鼠y座標 why unsigned? [ doc ]  [ ref2 ] >回家任務 使用陣列 2小葉閒聊Time 星星的孩子 天賦 好的coding特質 細膩的眼神   觀察細微 龜毛   排版    偏執   死纏爛打 問問題   不恥下問 大學教授 > 內向 > 專注 

Read more →

May 3, 2019

alanhc/張牧之 電腦圖學-week10

#computer_graphics

0. 觀念 1. 不同觀點看RT 2. 動動手寫程式 3. step by step 理解程式 4. 小葉閒聊Time 0. 觀念 看圖理解: R-T                                                                        T-R 1. 不同觀點看RT 1-1 線性代數觀點: 超圖解! 複習線性代數(發現數學QQ): Transformation [ 參考資料Transformation ]           講幾個有趣的 Stretching (拉) (沿著x軸拉) Squeezing (擠) (擠壓) Rotate (後面更詳細) Rotation [ 參考資料 Rotation ] 2D 3D [ 參考資料push matrix ] 1-2 程式觀點 程式:(   display()裡   ) glPushMatrix();         glRotatef(90, 0,1,0);    ///step 3         glTranslatef(0,0.5,0);   ///step 2         glutSolidTeapot(0.3);   ///step 1 glPopMatrix(); 1-3 OpenGL觀點 [ 參考 ] - 4*4矩陣 基本運算規則 translation Matrix  Scaling  2. 動動手寫程式 程式 glPushMatrix();         glTranslatef(0.5,0.45,0);            //step5         glRotatef(angle+=0.1,0,0,1);     //step4         glTranslatef(0.6,0,0);                 //step3         glRotatef(-90,0,1,0);                  //step2         glutWireCone(0.3, 0.6, 10, 10); //step1   glPopMatrix(); 3. step by step 理解程式  glutWireCone(0.3, 0.6, 10, 10); glRotatef(-90,0,1,0); glTranslatef(0.6,0,0);   glRotatef(angle+=0.1,0,0,1); glTranslatef(0.5,0.45,0); 4. 小葉閒聊Time: 學習率: 看 5 % 看+課本 15% 看+課本+demo 25% 看+課本+demo+動手 30% 多媒體互動 40% 教別人 90% 95% 今天的程式

Read more →

April 26, 2019

alanhc/張牧之 電腦圖學-week08

#computer_graphics

貼圖概念 / Concept 貼圖的手把手教學 / Step by step Turtorial 1.Concepts: glTexCoord2f()  >小提示:打錯面會顯示不出來 小歷史: SGI > 早期做圖形的電腦,現在已被其他公司收購 OpenCV  > intel 發起的 圖像處理、電腦視覺、圖形辨識函式庫 ipl (intel performance library) GL_POLYGON為何會壞掉? >黃色區域被填滿 2. 貼圖的step by step教學 (1) 下載opencv (2) 寫helloworld!!! (3) 綜合OpenCV與OpenGL (4) 開始貼圖 (1) 下載 [opencv] (2) 寫Helloworld!!! 新增貝殼(console)專案 但在開始之前...我們必須先了解 使用外部函式庫三步驟 1. include .h file 2. link       .lib檔 3. 執行     bin dll檔 因此我們要先設定一些東西 1. search include  > opencv<版本>\include search link > opencv\lib 2.link cv210.lib、cxcore210.lib、highgui210.lib 3.執行dll 將要的照片丟入freeglut/bin裡 丟入程式[HelloWorld 程式碼],並且執行 大功告成~~~慶祝~~~ (3) 綜合OpenCV與OpenGL (1)匯入OpenCV(請參考前面段落2的Helloworld) (2)10行GLUT程式,並加入OpenCV的Helloworld裡的程式[HelloWorld 程式碼] (3)執行小慶祝~ (4) 開始貼圖 Quick start > 改寫 [ 小葉程式碼 ] 1.改myInit()裡的 id = myTexture("image.png"); 裡面 image.png 改成你在freeglut\bin裡面放的圖片位置 > 裡面的myTexture()函式,是在處理貼圖的程式 參數:檔案的名子 IplImage的ipl就是前面提到的 Intel Performance Library 程式碼就改寫自小葉程式碼 11~17行 及 貼圖檔名 glPushMatrix();///利用matrix可以轉 //glRotatef(0, 1,0,0); glRotatef(angle, 0,1,0);///自動轉很帥 ///gluQuadricTexture(quad, 1); glutSolidTeapot( 0.5 ); ///gluSphere(quad, 1, 30, 30);///glutSolidTeapot(0.3); glPopMatrix();/// 地球會轉,很帥XDDD。茶壺會轉,也很帥XDDD glm (OpenGL Mathematics),其實就是一個數學的函式庫

Read more →

April 12, 2019

alanhc/張牧之 電腦圖學-week06

#06160485_曾宏鈞#Week06

0329 如何使GLUT可讀入MAYA模型檔? 1. 準備好環境 2. 修改程式 3. Debug 4. 上課筆記 5. 功課 1. 準備好環境 先準備下載好 [source] (1) windows 裡的 [data] 資料夾丟到 freeglut/bin 所在位置 (2) [source] 裡的 glm.h、glm.c、transformation.c丟到 專案資料夾 (3) 改 transformation.c 為 transformation.cpp 2.修改程式 (1) 加入#include "glm.h"  ///匯入 (2) link glm.cpp file ///在codeblocks左邊workspace 地方點選專案名字按右鍵add file (3) 宣告 GLMmodel* pmodel = NULL;  ///宣告指標 (4) 加程式到display裡面 ********************************************************* if (!pmodel) { pmodel = glmReadOBJ("data/AL.obj");///讀模型 if (!pmodel) exit(0);///讀不到離開 glmUnitize(pmodel); ///調整大小 glmFacetNormals(pmodel);///調法向量 glmVertexNormals(pmodel, 90.0);///調法向量 } glmDraw(pmodel, GLM_SMOOTH | GLM_MATERIAL);///畫模型 } ********************************************************* 成功~~~ 3. Debug Q1 如果人物很暗 A1 代表光線位置有問題,改light_position[] 裡的z即可 Q2 如果嘴巴曲線炸掉 A2 應該是不小心複製到glEnable(GL_CULL_FACE) 理由在這: cull face 解釋 4. 上課筆記 TD thechnical director 技術 TA Technical Artist notepad++ 存成cpp >  有顏色 notepad++ 外掛 > NppExport > Export to html lightMaterial.c 搜尋glm 找第一個、第二個、第三個 lightMaterial.c 讀入3D模型 include glm.h GLMmodel* pmodel= NULL "glm.h" 要放在專案目錄 glm.c放入 codeblocks 新增檔案> drawmodel() 裡面城市複製到display freeglut     bin     include     lib 丟之前的data到 bin裡 Debug ||=== Build: Debug in class0329 (compiler: GNU GCC Compiler) ===| C:\Users\alant\Desktop\class0329\main.cpp||In function 'void display()':| C:\Users\alant\Desktop\class0329\main.cpp|20|warning: deprecated conversion from string constant to 'char*' [-Wwrite-strings]| obj\Debug\main.o||In function `Z7displayv':| C:\Users\alant\Desktop\class0329\main.cpp|20|undefined reference to `glmReadOBJ(char*)'| C:\Users\alant\Desktop\class0329\main.cpp|22|undefined reference to `glmUnitize(_GLMmodel*)'| C:\Users\alant\Desktop\class0329\main.cpp|23|undefined reference to `glmFacetNormals(_GLMmodel*)'| C:\Users\alant\Desktop\class0329\main.cpp|24|undefined reference to `glmVertexNormals(_GLMmodel*, float)'| C:\Users\alant\Desktop\class0329\main.cpp|27|undefined reference to `glmDraw(_GLMmodel*, unsigned int)'| ||error: ld returned 1 exit status| ||=== Build failed: 6 error(s), 1 warning(s) (0 minute(s), 0 second(s)) ===| 三步驟 (1) include .h檔案 (2) link lib (3) 執行 bin .dll .obj黨裡面都是點 名詞解釋: Normal :法向量 v vn vertex normal f: facet t:很小的小 f 1802//1690  1690:法向量 OBJ > Maya出生的格式 Maya小歷史 縮放大小:glScale 作業 File > export  5. 功課 (1) 畫好MAYA模型 (2) File > Export ALL (3) 另存成OBJ (4) 參考上課步驟,改成讀入自己模型 今天的程式:

Read more →

March 29, 2019

alanhc/張牧之 電腦圖學-week05

#06160485_曾宏鈞#Week05#精選5

要有光 0. 介紹 1. 如何設定材質及燈光 2. 筆記 3. 小技巧 4. 小思考 0. 介紹 按右鍵 黃色區塊 > 選 模型 紅色區塊 > 選 材質 藍色區塊 > 一些 程式設定 1. 如何設定材質及燈光? 從小葉資料夾(參考week02 (1) 設定     glLightfv( p1, p2, p3 )         -> 光的設定方法     glMaterialfv( p1, p2, p3 )   -> 物體材質的設定方法 (2) 怎麼寫     燈光:     glLightfv(p1, p2, p3);         p1:哪一個燈         P2:設定甚麼 ( GL_AMBIENT、                                    GL_DIFFUSE                                    GL_SPECULAR                                    GL_POSITION  )         P3:設定值 [ 陣列 ] (請參考下圖)          示意圖 陣列設定方法:     GLfloat light_pos[] = { x, y, z, d }         x : 沿 x 軸         y : 沿 y軸         z : 沿z軸         d : 距離     GLfloat material_Kd[] = { R, G, B, alpha } 2.筆記: kd:打甚麼顏色光 英文單字: pos 位置 Ka: Kd: Ks: K:係數 a:ambient > 周圍漫射 d:diffuse > 隨著角度,直接照較亮,側著照較暗 s:specular >  特別亮的點 e:emission > 自體發光 Se: shininese emission 自體發亮 更多有關於 Ka、Kd、Ks https://cg2010studio.com/2011/03/27/specular/ 學習步驟: (1) notepad++複製程式碼 (2) 剪貼程式碼 (3) 改程式碼 todo:把茶壺打光 (1) file>new>project (2) cp 177行 到notepad (3) 寫10行GLUT茶壺 (4) 把 Light (打光)     (a) 8行陣列     (b) glutMainLoop() 第三堂 glutIdleDisplay(display) > 閒閒沒事時執行 3.小技巧: 知其然知其所以然:     小技巧:http://pythontutor.com/     小工具:cTour 程式上色:notepad++ NPPexport,丟到瀏覽器複製 4.小思考: Q為何要用GLfloat而不是float ? A根據compiler不同,不同 compiler 的 float Q. 轉太快 > 因為電腦跑的速度不同 A. 計時器調整 今天的課堂程式碼:

Read more →

March 22, 2019

alanhc/張牧之 電腦圖學-week04

#computer_graphics

0. 講解 1.體驗 2. Codingggg 3. 小葉額外補充     (1) silhouette optical illusion     (2) Ivan Sutherland     (3) 神奇學姊 - 林郁珊 4. 小葉酷炫技巧XDDD     regular expression + batch script 本周大綱:glrotate() 0.講解     > 原理圖                                          > 語法 void glRotatef(GLfloat angle, GLfloat x, GLfloat y, GLfloat z); angle : 旋轉角度 x,y,z : 數值代表以哪個為軸 其實x,y,z是指一個三度空間的向量 [ doc ] [ 原理 ] 1.體驗 > 安裝方法請參考 [ Week02 ] (1) 觀察這張圖 (2)與 右手定則 有關~  > α 為旋轉角度 > z 為軸心 2. 開始Codingggggg (1)基本茶壺動動語法 [ 動動程式碼 ] (2) 轉轉語法 位置 :  display() >  glPushMatrix() > glPopMatrix() >  語法: float rotateAngle = x * 100.0; glRotatef(rotateAngle,0,1,0); 解釋: 100.0 是因為我 滑鼠座標x (透過 motion() 處理) 介於-1和1之間,我乘上一個倍數做轉換。 0,1,0 代表我以y軸為旋轉軸 以 Y 軸選轉 | 參數(0,1,0) 以 X 軸旋轉 | 參數(1,0,0) (3) 小補充 glClear( ): 清buffer用,把舊畫面清掉[ 參考更多 ]     > GL_COLOR_BUFFER_BIT 清 顏色     > GL_DEPTH_BUFFER_BIT  清 深度 glPushMatrix( )、glPopMatrix( ):讓 Transform Matrix 不要亂掉     Transform Matrix &gt; 計算頂點在移動、旋轉、縮放後,會到哪裡。 3. 小葉的額外補充: (1) silhouette optical illusion            ( 茶壺搞不清楚往哪邊轉)                                     > 跟第一眼印象有關 (2) Ivan Sutherland - 電腦圖學的小歷史                 原本博士寫論文                                                                   沒有對應的學科 > 研討會結束發表                                 > 電腦圖學誕生                                                                    影響 物件導向 計算機圖學 等發展                                       [ 1963 Sketch Pad Demo ]                                                [ Wiki ]  (3) 神奇學姊 - 林郁珊  [ blog ] [ 作品Youtube ]  科技部計畫 - 棉花糖 選題目選很久 > 從生活觀察       看雲 > 打工經驗 >上 stanford 課程 > 論文 變成專研題目                  "興趣" 重要                                      ** 2018 互動技術概論 期末作品** 4. 神奇小技巧 下載資料夾 notepad開啟 ctrl+F 在取代裡面輸入 ". copy " .bat檔 Google:regular expression + batch script 今天的程式碼 --------------------------------------------------- Operation Neptune  [ 厲害學姊 ] [ 去年FB ] [ 國旗 ] [ 動動摩天輪 ] 滑鼠 用法: (1) main() > 加上 glutMouseFunc(mouse); (2)寫 mouse 函式 參數: void mouse(int button,int state,int x,int y)   畫圓弧麻煩 -> 挑戰:[ 貝茲曲線 ] (1) 公式    (2) 四個點固定寫死的寫法 [ Code1 ] (3) 讀檔不固定點數 嘗試: codeblocks project add files -> failed 加在display() -> failed 加在main() -> failed 遇到問題: Q. 讀不到檔案 A. 改成問題出在絕對路徑& \跳脫符號 路徑 進階技巧 寫絕對路徑 > C:\Users\alant\Desktop\PracticeBezier 預設路徑 > 方法: 使用 codeblocks檔案開啟  .cbp 查看 <Add directory="C:/Users/alant/Desktop/freeglut/lib" /> 代表 C:/Users/alant/Desktop/freeglut/lib 小額外補充: 一般應用程式會去path底下找對應的.dll檔(應用程式擴充檔)

Read more →

March 15, 2019

alanhc/張牧之 電腦圖學-week03

#computer_graphics

0.講解 1.體驗     (1)小葉程式 2.開始     (1)translate     (2)碰到的問題     (3)滑鼠移動 3.成品 4.檢討作業     (1) 小畫家算點 5.小撇步 0.講解 移動、滑鼠 glTranslatef(par1,par2,par3) translate:移動 f:float par1:x, par1:y, par1:z 模型檔位置:\windows\data\ 1.體驗 (1)先準備 (2)開始玩~ 左鍵調數值 2.開始 (1)基本程式架構 (2)加入第4行 glTranslate要glutSolidTeapot前面!!! (3) But!但一移動一下視窗會跑掉!!! sol:加上      glPushMatrix     glPopMatrix (4) GG好可怕的畫面... Sol: 加入19行 glclear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ),清掉 (5) 滑鼠: glutMotionFunc(motion); motion(int x, int y) 函式:滑鼠移動會呼叫此函式,並且pass兩個參數滑鼠x跟y *記得在最後一行加上display()這樣才會更新物體的位置! 3.成品~~~~~~~ 4.檢討作業: (1)開小畫家 座標上下顛倒>調整座標負號 (2)複製圖片到小畫家 紅線為x軸與y軸 5.小撇步 (1)winrar中文檔名解壓縮會有問題>下載 7zip (2)使用小葉的圖學範例shape再開始寫程式 今天的程式碼 Homework 挑戰3D空間+滑鼠移動 [ Code ] 挑戰:畫3D圖形 目標:DNA 步驟: (1)先畫旁邊螺旋(GL_LINE_STRIP) (2)畫梯子透過兩個螺旋頂點連線,並使用(GL_LINES) (3)加入還沒教的glRotate使其看起來較3D (4)實驗motion->改變鬆緊程度及選轉速度 遇到問題:y軸上升座標> 解決:a/PI,從週期看,每次上升1/PI

Read more →

March 8, 2019

alanhc/張牧之 電腦圖學-week02

#computer_graphics

秘笈 0. 講解 1. 體驗 2. 開始 3. 整理 4. Q&A 0. 講解 圖學基本:點、線、面 point:點 Vertex:頂點 / Vertices (複) glVertexf(幾個參數) 幾維 Ex.     glVertex2f glColor<數字>f <數字> 3:RGB 4:RGBA glBegin();     glVertex2f lEnd(); 1. 體驗 (1) 下載 [秘笈]中, win32 (Windows資料夾) data glut32.dll (2)點選執行Shapes.exe 使用方法: 按右鍵>改設定 按左鍵>上下拖曳改數字 2. 開始! (0) 準備GLUT project [week01] (1) 點選 main.cpp,刪除裡面程式碼 (2) 開始codingggggggg!!!!!!          3. 整理 基本架構 幾個sample 4. Q&A Q.遇到codeblocks黑掉 A.View>Manager Q.不能Build A.檢查 C:\Program Files(x86)\CodeBlocks\MinGW 不見: 安裝codeblocks_MinGW Setting>Compiler>ToolchainExecutable Setting>Compiler>ToolchainExecutable ,要有正確目錄 "C:\Program Files(x86)\CodeBlocks\MinGW" Q.GLUT是甚麼 A.下載 freeglut windows MinGW版本 放到桌面 Q.為甚麼找不到GLUT A.參見 week01 Homework [ Code ] 作法: (1) 先畫橢圓 (2) 分函式(eye、blush等等 (3) 找每個部位位置 (4)上色 彎月形作法:GL_TRIANGLE_FAN 看這張圖了解更多,數字為畫點順序

Read more →

February 23, 2019

alanhc/張牧之 電腦圖學-week01

#computer_graphics

1. Helloworld-openGL project 2.安裝GLUT 2/22 [課堂講解] 範例:webGL-water [系上課程安排] Maya、Unity 底層 OpenGL(C/C++) G:Graphic L:Language Hello World! 新增專案 File > New > Project  選 OpenGL project     Folder:C:\Users\ \Desktop     Title:week01_opengl 建置 F9 Q.不見 A:View > Management 安裝GLUT [提示] cbp codeblocks project (1) 新增專案 File > New > Project  選 GLUT project 遇到 Wait!!! (2) 安裝 Google:freeglut windows Download freeglut 3.0.0 for MinGW  下載完後先不要解壓縮,把裡面freeglut直接抓到桌面 (3) 新增libglut32.a檔案 (4) 更改路徑為freeglut路徑 Mission: accomplish!!!

Read more →

February 22, 2019

20190409-uva409

#uva

#心得 #解題 #Excuses_Excuses #Uva409 #str 這題真的是集結了str的精華XD Ref https://www.facebook.com/groups/363494050740833/permalink/427464177677153/

Read more →

April 9, 2018

20180405-uva630

#uva

#心得 #解題 #Anagrams_II #Uva630 #str 這題我寫出來後,程式當掉了一陣子,後來丟到command line後,原來是segmentation fault,後來找到是6,7行的多維陣列寫反了,導致我沒辦法儲存那麼多資料。 基本上我是先把key跟輸入sort過,這樣就可以輸出不同排列的字。 圖片:https://keydifferences.com/difference-between-rows-and… Ref https://www.facebook.com/groups/363494050740833/permalink/425606714529566/

Read more →

April 5, 2018

20180317-uva10409

#uva

#心得 #解題 #Die_Game #Uva10409 #模擬 我覺得這題難的是題目字好多XD 註:我一開始宣告的地方在第10行導致她沒有重設成一開始的狀態,難怪我想說怎麼一直錯XD。 Ref https://www.facebook.com/groups/363494050740833/permalink/418124398611131/

Read more →

March 17, 2018

20180314-uva105

#uva

#心得 #解題 #The_Skyline_Problem #Uva105 這題我原先是不想開一個超大陣列(10000個元素), 原本是寫了個結構去存他每一段,找每一段的左界和右界,但我後來發現這個方法卡有點久,因此後來還是用直接用陣列存高度的方法。不過我覺得或許有更好執行更少次的方法,可以改天再寫寫看。 Ref https://www.facebook.com/groups/363494050740833/permalink/416953388728232/

Read more →

March 14, 2018

20180312-uva10190

#uva

#更 #心得 #解題 #Divide_But_Not_Quite_Conquer #分治法 #更 這題瘋狂程設的測資可能不夠多, 所以我一開始寫的碰巧在瘋狂程設有過, 照片是補齊的版本。 這題是cpe歷屆題目,其實我之前就寫過了哈哈 我覺得這次寫的時候還蠻快的。 我覺得試試了上次看老師直播分段測試的方法, 再寫的時候也比較有信心, 只不過有個問題有卡一下,當n==1的時候, 我會有無窮迴圈的問題RE了一下。 不過後來還是解決了 —–我是分隔線—– 瘋狂程設 通過 uva TLE uva RE uva AC Ref https://www.facebook.com/groups/363494050740833/permalink/416074128816158/

Read more →

March 12, 2018

20180309-uva141

#uva

#續 #解題 #The_Spot_Game #Uva141 #模擬 這題我後來去看看別人寫的程式碼, 找了一下找到覺得這個寫法感覺還不錯, 使用string來建立map的key這個方法還蠻聰明的 flag的用法解決了找到後還要繼續讀資料的問題, 看懂了之後試著寫一次, 順便了解像string及map的好用的工具。 也發現其實在旋轉的時候,其實找要寫個函式讓他一直轉90,這個方法也可以,這樣可以避免直接想3次怎麼找陣列的index。 Ref https://www.facebook.com/groups/363494050740833/permalink/414548145635423/

Read more →

March 9, 2018

20180228-hash-table

#hash_table

#Data_Structure_and_Algorithms #hash_table hash table 是一種可以很快搜索到東西的一種方法,只要hash function有寫好,複雜度幾乎是O(1),比線性搜的O(n)及二分搜得O(logn)還快上許多。 Ref https://www.facebook.com/groups/363494050740833/permalink/410898522667052/

Read more →

February 28, 2018

20180222-uva401

#uva

#心得 #解題 #Palindromes #Uva401 #回文 #鏡像 題意:判斷是否為鏡像或回文 原本是用switch case 寫,但覺得這樣寫會要寫很多行case,因此改用一個陣列去存鏡像的字元 注意: for那邊是檢查到i <= len/2 (奇數時沒有等於會錯) -‘1’+26這邊就是依照ascii表+題目給的鏡像表來做查詢的index, 這題瘋狂程設的測資怪怪的, 瘋狂程設的測資會有小寫, 我的程式會錯。 Ref https://www.facebook.com/groups/363494050740833/permalink/408337622923142/

Read more →

February 22, 2018

20180212-uva10611

#uva

Ref https://www.facebook.com/groups/363494050740833/permalink/404391153317789/

Read more →

February 12, 2018

20180210-NCTU-PCCA-winter-notes

#competitive_programming

NCTU PCCA winter快速索引 活動網頁 | 水題大賽 | 課程網頁 演算法筆記 一般組 Day 1: 二分搜尋法 (pdf) (上機練習) (題解) Day 2: 資料結構&STL (slide) (上機練習) (題解) Day 3: 暴力法 (slide) (上機練習) (題解) (影片) Day 4: 貪心法 & 分治法 (slide) (上機練習) (題解) (影片) Day 5: 動態規劃 (slide) (上機練習) (題解) (影片) 進階組 Day 6: 貪心法 (pdf) (上機練習) (題解) (影片) 練習套題 [日常的日常 ] Day 7: 數學工具 (slide) (上機練習) (題解) Day 8: 自動機與字串們 (slide) (上機練習) (題解) 練習套題 [無盡的日常] Day 9: 高級的 DP (slide) (上機練習) (題解) Day 10: 高級的圖論 (slide) 二分搜 Day1 PDF 上機練習 題解 整理筆記 演算法 Big O 時間複雜度

Read more →

February 10, 2018

20180209-uva406

#uva

#心得 #Prime_Cuts #Uva406 #解題 其實在寫這題的時候一開始寫出來的東西會TLE, 後來改一改又變成RA,我就丟到瘋狂程設, 原來是到超大數會錯,我就把建表的範圍在加大,就AC了 這題應該就是要先建表, 然後再找他的上界跟下界在哪裡~依照題目印出來就好 不過我覺得我寫得有點不是很精簡, 可能看之後有沒有想法再改吧~ 有人有想法也可以討論~ Ref https://www.facebook.com/groups/363494050740833/permalink/403197643437140/

Read more →

February 9, 2018

20180209-linked-list

#linked_list

#練習 #Linked_List #鏈結陣列 雖然這比賽應該很難用到,用個vector應該可以解決很多事? 但還是實作了一下鏈結陣列,練習一下。 其實鏈結陣列比較麻煩的地方是在頭。 註:我把它分成幾個不同的小函式來處理。 Ref

Read more →

February 9, 2018

20180206-uva10162

#uva

#心得 #Last_Digit #Uva10162 #解題 這題我覺得有點麻煩,因為數字超級大( N (1 ≤ n ≤ 2 ∗ 10^100) ),所以一定要用字串(因為long long int 只到0 到 18,446,744,073,709,551,615),然後再觀察n^n最後一位的規律及序列S的規律,然後再查表,我寫了兩個查表,一個是n^n一個是 Σ(i^i)的 好久沒碰到二項式定理了,好像之前有聽過 哈哈 註: Σ(i^i)那張表 是每20個他的數值會多4,所以其實是100個一循環,但方便寫其實寫20個再去用差補就好了~ 但我覺得找規律好賭運氣, 或許這題是要靠數學吧(笑 整數儲存範圍:https://msdn.microsoft.com/zh-tw/library/s3f49ktz.aspx 找規律解法參考:http://diadoacm.blogspot.tw/…/02/acm-10162-last-digit.html 數學證明參考解法:http://blog.csdn.net/mobius_strip/article/details/37757287 不過或許會有更簡單的解法? Ref https://www.facebook.com/groups/363494050740833/permalink/402095146880723/

Read more →

February 6, 2018

20180205-uva10405

#uva

#心得 #Longest_Common_Subsequence #LCS #DP #Uva10405 #解題 心得: 這題其實看懂題目+用陣列來填真的蠻簡單,但是我debug了一天,因為我圖表陣列的型別弄錯QQ 要注意這個陣列是int 題目:找最長的共同子集合 分析: 先了解甚麼是共同子集合 以 { a,b,c,d} 來說 { b, c } 是他的子集合 { c, b } 就不是 假設兩個序列 c1,c2 假設c1中存在一個a 你就是要去c2中找有沒有a, 找到了之後再找c1中的下一個字母 而DP其實就是 把大問題切成很多很多重複的小問題 也可以用特定計算(遞迴)求出來 把算過的答案計算下來 以這題來講, 我們用lcs[i+1][j+1]來記下算過的答案。 我們最後的答案會在lcs[m][n],因為此時我們已經掃完c1與c2的所有元素 每當我在c2裡找到原本c1的下一個子元素, 我就會把值+1,來代表他的子元素的長度。 如果我還沒有在c2中找到c1中我要找的元素,就把我之前找到的和我之前記下來的答案取最大值(max),這個步驟我覺得其實講成白話文就是記下我之前找到的最長子集合長度 為甚麼我填值是從lcs[i+1][j+1]是因為我要讓 第i行 與 第j列保持都是0,這樣讓我在找max的時候會比較好算 這題要畫圖比較好理解 Ref https://www.facebook.com/groups/363494050740833/permalink/401726533584251/

Read more →

February 5, 2018

20180131-uva11917

#uva

#心得 #解題 #討論 #Uva11917 #Do_Your_Own_Homework 上次問完老師之後, 今天在自己從寫一遍, 不過我是用一個struct來整理科目和天數~ 我今天在營隊, 我的室友好像說也可以用map這個function來處理? 好像是類似python的字典型別的功能? 有時間研究看看~ 我覺得後來看了一下,我的變數命名有待加強~哈哈 Ref https://www.facebook.com/groups/363494050740833/permalink/399428737147364/

Read more →

January 31, 2018

20180128-uva10931

#uva

#心得 #Uva10931 #Parity #解題 #討論 一開始解這題的時候, 因為輸入數字可能會很大, 而且後來發現itoa函式也不能用, 因為有些compiler看不懂。 於是我發現有其他人用遞迴的方法(只不過他寫得有點怪?, 於是我就用遞迴法想了一次, 改成我覺得可以的程式。 寫完覺得,我怎麼寫了個這麼難懂的程式碼。 我後來想想, 阿原來還可以位元運算哈哈 ———-我是分隔線———- 先講一開始為甚麼要用遞迴法: 因為我們要把十進位轉二進位時,其實就是一直除2找餘數。 但數字是從後面寫回去, 遞迴剛好可以讓我可以不用去處理反過來的問題, 只不過想的時候會有點難想, 但比原本想的另一個方法(準備超大陣列然後反轉)還要好, 但我覺得這題用位元運算會比較好, 比較稍微難的地方是要把前面的0給去掉。 比如 0100 要變成 100 Ref https://www.facebook.com/groups/363494050740833/permalink/398522603904644/

Read more →

January 28, 2018

20180124-gets-puts

#string

#心得 #緩衝區溢位 #gets_puts #string 語法: char *gets(char *string); int puts(const char *string); ——–我是分隔線——– 其實puts(string),就是fputs(string, stdout)更簡潔的語法。 但是fgets(string, 128, stdin),不等於gets,因為gets沒有參數可以限制讀進string的字元數,因此在現在的compiler會建議不要使用gets函式,因為可能會發生buffer overrun(緩衝區溢位)的問題。 另外,C語言中也有一些標準函式庫裡函式的使用也需要特別注意,如:gets, scanf, strtok, strcpy。 然後後來我找到一篇講解概念的: https://medium.com/…/%E7%B7%A9%E8%A1%9D%E5%8D%80%E6%BA… https://zh.wikipedia.org/…/C%E6%A8%99%E6%BA%96%E5%87%BD… Ref https://www.facebook.com/groups/363494050740833/permalink/396732620750309/

Read more →

January 24, 2018

20180123-int2str

#string

#心得 #int_to_str #ascii 如果函式要回傳string (return str),函式的前面必須寫成char *() {}。 圖片中 str[i++] = (num % 10) + ‘0’; 後面要有+‘0’,因為0在ascii裡面是代表30(16進位),若沒有寫會變成ascii前面10個的特殊指令。 不過我這樣寫數字會反轉。 ————我是分隔線———— 如果看到這邊覺得很複雜的話其實還有更簡單的方法: 就是使用sprintf 例如: int n; char buffer[100]; sprintf(buffer,"%d", n); 這樣就可以把n(int)轉成buffer(character array) 可以參考:http://www.cplusplus.com/reference/cstdio/sprintf/ Ref https://www.facebook.com/groups/363494050740833/permalink/396463824110522/

Read more →

January 23, 2018

20180119-hackmd

#markdown

#分享 #HackMD 最近找到個蠻有趣的東西 - “HackMD” 這可以寫共同筆記之類的。我覺得有時我們資訊一直丟上來有天可能會太雜,除了丟新想法或解題外,整理也是很重要的。因此我建了個HackMD 讓大家可以來共同做筆記。 網址:https://hackmd.io/s/rkkRiKyrf 註:右上角有個鉛筆符號,點下去可以編輯。 Ref https://www.facebook.com/groups/363494050740833/permalink/394817457608492/

Read more →

January 19, 2018

20171230-recursion

#recursion

#心得 #遞迴 #無限呼叫 最近在寫遞迴的時候,發現常常會寫到當機(終止條件沒有設好) 最近想到個方法, 解決方法: 設一個變數去計算我到底呼叫他幾次, 若呼叫次數大於某個值,就回傳error,可避免無限呼叫。 Ref https://www.facebook.com/groups/363494050740833/permalink/387029151720656/

Read more →

December 30, 2017

20171221-uva10190

#uva

#Debug #遞迴 #等比數列 #除錯 #PART2 #10190 接續上次找等比級數的程式 情況: 我後來發現瘋狂程設會當機, 因此我再去開命令列檢查錯誤訊息 出現:Floating point exception 問題: 當我輸入的y是0時,x%y不能計算,因此出現此錯誤 解決方法: 一開始要判斷輸入值是否可作計算(紅色那行) Ref https://www.facebook.com/groups/363494050740833/permalink/383438732079698/

Read more →

December 21, 2017

20171219-recursion

#recursion

#心得 #除錯 #遞迴 #等比數列 #PART1 情況: 想試著用遞迴的方式來檢查是否輸入兩數可以寫成等比數列。 Ex: input: 125 5 output:true 125 25 5 1 input: 10 3 output:false 敘述: 原本一直出現 segmentation fault,後來加上紅色註解的下一行就過。 原因: 1234 / 321 = 3 3 / 321 = 0 0 /321 = 0 … 他會一直呼叫自己,導致無限呼叫(沒有回傳) 導致記憶體超出配置範圍 結論: 寫遞迴真的條件要想的很清楚,要不然會發生很可怕的結果 Ref https://www.facebook.com/groups/363494050740833/permalink/382582158832022/

Read more →

December 19, 2017

20171217-DP

#DP

#心得 #Dynamic_Programming 關於DP: 1.大問題切成小問題 ( Divide and Conquer ) 最佳子結構(大問題解決的小問題基礎) 轉換成遞迴關係 2.記下同個問題計算過的答案 最近在學遞迴影片中整理的重點 Ref https://www.facebook.com/groups/363494050740833/permalink/381892755567629/

Read more →

December 17, 2017

20171210-vector

#vector

#心得 #vector #class 最近發現了一個蠻好玩的東西, Vector,他屬於一個C++的一個Class。 優點:可以任意改變陣列的大小 備註:需要 #include<vector> 有興趣可以參考: http://www.cplusplus.com/reference/vector/vector/ 中文概念參考: https://zh.wikipedia.org/wiki/Vector_(STL) 用法參考: http://mropengate.blogspot.tw/2015/07/cc-vector-stl.html Ref

Read more →

December 10, 2017

20171202-styleguide

#coding_style

#文章分享 #styleguide https://tw-google-styleguide.readthedocs.io/en/lates Ref https://www.facebook.com/groups/363494050740833/permalink/376399396116965/

Read more →

December 2, 2017

20171106-gcd

#math

#程式分享 #GCD #Greatest_Common_Divisor 前陣子看到個很簡潔的找最大公數方法 Ref https://www.facebook.com/groups/363494050740833/permalink/367341390356099/

Read more →

November 6, 2017

20171105-makerfair

#makerfair

前情提要: 今天去MakerFaire有個攤位是做智慧家電的, 我覺得有個還蠻適合拿來討論的, 簡單來說一般做物聯網都是用網路來做, 但他們很特別是靠電力系統來做資料傳輸, 我覺得方式還蠻有趣的, 但我問了兩個問題: 問題: Q1. 所有的電力系統都會連到同一條通往台電的線,那不是代表駭客只要在家插插頭就可以開始去散播寫的病毒程式,或直接在變壓站值入竊聽程式? A1. 他的回答是,因為兩個頻率不一樣,基本上到家裡的電會有個濾波的功能,所以無法從外部直接攻入。(這應該算物理上的防護) Q2. 那假設這套被大量應用在我們的生活中,駭客是不是只要駭進一台裝置,同時我就可以藉由這台透過電力系統去駭進其他台裝置? A2. 他的說法是,假設你已經被駭,基本上也無法防護。 我的想法: 其實我覺得他們點子很創新很有意思, 但或許實際應用層面上, 安全的部分還是需要加強? https是用加密金鑰的方式來處理因為他有金鑰跟一些標準來加密, 我覺得應該不至於到無法防護拉, 各位覺得呢 或有任何想法也可以一起討論~ Ref https://www.facebook.com/groups/363494050740833/permalink/366898140400424/

Read more →

November 5, 2017

20171102-computer-virus

#security

#心得 #debug #電腦中毒 這幾天遇到的問題, 我把問 葉正聖 (Jeng-Sheng Yeh)老師教的做個簡單的小整理: 遇到的問題: Codeblocks 無法compile 思考過程: codeblocks按F9 compile ( fail ) error: cannot open the output file 以cmd檢查是否可以用gcc直接compile檔案 存取被拒 以系統參數更改output檔名的方式 ( succeed ) 代表有人把untitle.exe 1 鎖住了 以 系統管理員 進入 procexp 找 " 沒有公司名子的檔案 " 找到有個Arduino_的檔案 常駐 ,進去propreties找 TCP/IP 找是否有對外的2 通道( 有發現 ) 結論:電腦中毒 有可能是這個電腦病毒看到Untitle的檔名就去保護他導致我檔案被鎖,無法存取(刪除、修改)。 解決方法:追查問題檔案目錄及檢查登入目錄程式是否有相關檔案存在,若有,直接在登入目錄修改檔名,使電腦病毒無法呼叫他需要的檔案。 1:原本的檔案叫untitle.c,codeblocks會自己把執行檔編譯成 your_name.exe 2:因為電腦病毒的特性可能有 常駐在背景 檔案很小 藏在很隱密的地方 名子跟正常很像但目錄不對 開通道傳資料( TCP/IP ) Ref https://www.facebook.com/groups/363494050740833/permalink/365709920519246/

Read more →

November 2, 2017

20171027-refactor

#refactor

https://www.ithome.com.tw/node/46046 Ref https://www.facebook.com/groups/363494050740833/permalink/363567360733502/

Read more →

October 27, 2017

20171027-bnf

#programing

#心得 前幾個禮拜的時候,我寫程式有時都會碰到一些問題,例如: int a = b = 0; // error : 沒宣告b for迴圈的寫法 for ( ; i < 0 ; ) 等同於 while( i < 0 ) 今天剛好發現一個很有趣的東西 “ Backus Normal Form ” 雖然我還沒有全部看得懂,但好像可以了解 一個程式語言可以怎麼寫~ 今天的心得 ps 以後我應該會一個禮拜打一篇心得哈哈哈 我覺得這樣互相分享除了可以知道觀念有沒有錯, 也可以不是只有在解題上,我的想法拉哈哈哈哈哈 ![](data:image/svg+xml,%3Csvg fill=‘none’ xmlns=‘http://www.w3.org/2000/svg' viewBox=‘0 0 16 16’%3E%3Cpath d=‘M16.0001 7.9996c0 4.418-3.5815 7.9996-7.9995 7.9996S.001 12.4176.001 7.9996 3.5825 0 8.0006 0C12.4186 0 16 3.5815 16 7.9996Z’ fill=‘url(%23paint0_linear_15251_63610)’/%3E%3Cpath d=‘M16.0001 7.9996c0 4.418-3.5815 7.9996-7.9995 7.9996S.001 12.4176.001 7.9996 3.5825 0 8.0006 0C12.4186 0 16 3.5815 16 7.9996Z’ fill=‘url(%23paint1_radial_15251_63610)’/%3E%3Cpath d=‘M16.0001 7.9996c0 4.418-3.5815 7.9996-7.9995 7.9996S.001 12.4176.001 7.9996 3.5825 0 8.0006 0C12.4186 0 16 3.5815 16 7.9996Z’ fill=‘url(%23paint2_radial_15251_63610)’ fill-opacity=’.5’/%3E%3Cpath d=‘M7.3014 3.8662a.6974.6974 0 0 1 .6974-.6977c.6742 0 1.2207.5465 1.2207 1.2206v1.7464a.101.101 0 0 0 .101.101h1.7953c.992 0 1.7232.9273 1.4917 1.892l-.4572 1.9047a2.301 2.301 0 0 1-2.2374 1.764H6.9185a.5752.5752 0 0 1-.5752-.5752V7.7384c0-.4168.097-.8278.2834-1.2005l.2856-.5712a3.6878 3.6878 0 0 0 .3893-1.6509l-.0002-.4496ZM4.367 7a.767.767 0 0 0-.7669.767v3.2598a.767.767 0 0 0 .767.767h.767a.3835.3835 0 0 0 .3835-.3835V7.3835A.3835.3835 0 0 0 5.134 7h-.767Z’ fill=’%23fff’/%3E%3Cdefs%3E%3CradialGradient id=‘paint1_radial_15251_63610’ cx=‘0’ cy=‘0’ r=‘1’ gradientUnits=‘userSpaceOnUse’ gradientTransform=‘rotate(90 .0005 8) scale(7.99958)’%3E%3Cstop offset=’.5618’ stop-color=’%230866FF’ stop-opacity=‘0’/%3E%3Cstop offset=‘1’ stop-color=’%230866FF’ stop-opacity=’.1’/%3E%3C/radialGradient%3E%3CradialGradient id=‘paint2_radial_15251_63610’ cx=‘0’ cy=‘0’ r=‘1’ gradientUnits=‘userSpaceOnUse’ gradientTransform=‘rotate(45 -4.5257 10.9237) scale(10.1818)’%3E%3Cstop offset=’.3143’ stop-color=’%2302ADFC’/%3E%3Cstop offset=‘1’ stop-color=’%2302ADFC’ stop-opacity=‘0’/%3E%3C/radialGradient%3E%3ClinearGradient id=‘paint0_linear_15251_63610’ x1=‘2.3989’ y1=‘2.3999’ x2=‘13.5983’ y2=‘13.5993’ gradientUnits=‘userSpaceOnUse’%3E%3Cstop stop-color=’%2302ADFC’/%3E%3Cstop offset=’.5’ stop-color=’%230866FF’/%3E%3Cstop offset=‘1’ stop-color=’%232B7EFF’/%3E%3C/linearGradient%3E%3C/defs%3E%3C/svg%3E)

Read more →

October 27, 2017

test

h1text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text h2 h3 abc abc abc + abc code hello

Read more →

January 1, 2000

#excalidraw

==⚠ Switch to EXCALIDRAW VIEW in the MORE OPTIONS menu of this document. ⚠== You can decompress Drawing data with the command palette: ‘Decompress current Excalidraw file’. For more info check in plugin settings under ‘Saving’ Drawing N4IgLgngDgpiBcIYA8DGBDANgSwCYCd0B3EAGhADcZ8BnbAewDsEAmcm+gV31TkQAswYKDXgB6MQHNsYfpwBGAOlT0AtmIBeNCtlQbs6RmPry6uA4wC0KDDgLFLUTJ2lH8MTDHQ0YNMWHRJMRZFAFZFAEYyJE9VGEYwGgQAbQBdcnQoKABlALA+UEl8PGzsDT5GTkxMch0YIgAhdFQAayKuRlwAYXpMenwEEABiADMx8ZAAX0mgA %%

Read more →