[{"content":"What is Vibe Coding? Vibe Coding means fully trusting AI to write code. Instead of writing code yourself, you describe your requirements in natural language and let AI do all the programming. This approach has sparked widespread discussion in the developer community recently.\nI wanted to do an experiment: Can I build a usable web application without writing a single line of code myself?\nWhat is Remote File Editor? A lightweight web IDE with VS Code-like layout. Features include code editing, file management, image viewer, and terminal panel.\nWhy Did I Build This? My original need was simple: to easily view and edit OpenClaw configuration files and working directory.\nAs a developer who frequently switches between different VPSs, I needed a way to:\nQuickly browse and edit files on the server Not have to SSH in and use vim/nano every time Have a visual interface But I didn\u0026rsquo;t want to spend too much time building a complete project from scratch—this was the perfect scenario to test Vibe Coding.\nThe 100% AI-Generated Experience Tech Stack Frontend: React + TypeScript + Vite + Monaco Editor Backend: Node.js + Express + JWT Authentication Deployment: Supports systemd and PM2 What AI Generated Almost every line of code in this project was generated by AI:\nArchitecture Design - Describe requirements, AI proposes technical solutions Frontend Code - React components, state management, styles Backend API - Express routes, file operations, JWT Deployment Config - Nginx reverse proxy, systemd service Problems Encountered Of course, it wasn\u0026rsquo;t all smooth sailing:\nInitial design wasn\u0026rsquo;t complete enough, needed multiple iterations Some edge cases weren\u0026rsquo;t fully considered Security authentication flow needed manual adjustments But all of these could be solved by continuing to chat with AI.\nKey Features File Management Tree view with refresh Read/write files under WORKSPACE_DIR (path safety enforced) Support cd to change directory Editor Monaco Editor, auto layout Auto language detection by extension Cmd/Ctrl+S to save Per-tab revert Image Editor Auto-detect image files Show dimensions Resize (optional aspect ratio lock) Grayscale conversion Terminal Panel API-driven, type command and press Enter Output appears on next line Support cd, clear commands Collapsible/expandable Authentication JWT authentication Password-protected admin access Deployment # Configure environment variables export ADMIN_PASSWORD=your-password export JWT_SECRET=your-secret export WORKSPACE_DIR=/path/to/workspace export PORT=5174 # Start npm install npm run build pm2 start server/index.js --name remote-file-editor Conclusion This experiment proves: It\u0026rsquo;s feasible to build a usable web app 100% generated by AI.\nRemote File Editor now runs on my VPS and I use it every day. It may not be the most perfect code, but it solves real problems, and it was built in a completely new way.\nVibe Coding isn\u0026rsquo;t about replacing programmers—it\u0026rsquo;s about making the path from idea to product shorter.\nIf you\u0026rsquo;re interested, check out the GitHub repo: xu4wang/remote-file-editor\nHow Was This Blog Post Created and Published? This blog post itself is a perfect example of Vibe Coding!\nWriting Process AI-assisted Writing - Describe the topic in natural language, AI generates the Chinese and English blog posts Telegram Bot - I built a Telegram bot that can receive images directly through chat Auto-upload - Send image → Bot downloads → Saves to Hugo\u0026rsquo;s static/images → Copies to Nginx → Returns URL One-click Deploy - After Git push, server automatically builds and publishes As shown above, the entire process is automated. I only need to:\nSend images to the bot on Telegram Tell AI what topic to write about Git push And the blog automatically deploys to thefreemeal.com!\nTech Stack Blog Engine: Hugo + PaperMod Theme Hosting: GitHub repository with version control Image Collection: Telegram Bot (Gram.js) Deployment: PM2 + Nginx AI Workflow Summary This blog post showcases four types of AI working together:\nLocal Vibe Coding AI (GPT-5, Claude) - Writes the code OpenClaw (MiniMax 2.5) - Running on VPS, with several agents: Image Collector Agent - Receives images from Telegram Deployment Agent - Handles blog deployment Blog Writer Agent - Writes and publishes blog posts The entire workflow is automated: just send images via Telegram, describe what to write, and the AI handles the rest!\nThis article was written with AI assistance 🤖\n","permalink":"https://blog.thefreemeal.com/en/posts/2026-02-16-remote-file-editor-vibe-coding/","summary":"\u003ch2 id=\"what-is-vibe-coding\"\u003eWhat is Vibe Coding?\u003c/h2\u003e\n\u003cp\u003eVibe Coding means fully trusting AI to write code. Instead of writing code yourself, you describe your requirements in natural language and let AI do all the programming. This approach has sparked widespread discussion in the developer community recently.\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003eI wanted to do an experiment: Can I build a usable web application without writing a single line of code myself?\u003c/p\u003e\u003c/blockquote\u003e\n\u003ch2 id=\"what-is-remote-file-editor\"\u003eWhat is Remote File Editor?\u003c/h2\u003e\n\u003cp\u003eA lightweight web IDE with VS Code-like layout. Features include code editing, file management, image viewer, and terminal panel.\u003c/p\u003e","title":"Remote File Editor: A Vibe Coding Experiment"},{"content":"What is Pip? Pip is the quoted unit for exchange rate changes. Generally the fourth decimal place. 0.0001 is one pip. Yen is an exception - for Yen, 0.01 is one pip. Because Yen is too small.\nA pip is a unit of measurement for price movements of currencies in foreign exchange (FX) markets. Pip stands for \u0026ldquo;percentage in point\u0026rdquo; or \u0026ldquo;price interest point.\u0026rdquo; It represents the smallest price variation that a particular exchange rate experiences based on typical FX market convention.\nPip represents absolute numbers, not return rates Suppose you have $10,000 USD, and USDCNY is quoted at 6.5, then you can exchange for 65,000 RMB. Assume the exchange rate increases by 100 pips (0.0001 × 100 = 0.01), becoming 6.51, then you can exchange for 65,100 RMB. A 100 pip exchange rate change caused you to gain an extra 100 RMB.\nKnowing the total transaction amount and the exchange rate change, you can determine the change in profit. But you don\u0026rsquo;t know the return rate (the proportion of profit change).\nIn the chart above, the x-axis is the original currency for exchange (e.g., USD), and the y-axis is the target currency.\nThe first curve is Baht (1 USD to 30 Baht) The second is RMB (1 USD to 6.5 RMB) The fourth is a currency with exchange rate 2 (let\u0026rsquo;s say the currency name is Silver, 1 USD to 2 Silver) The third is Silver after the exchange rate increases by 1000 pips The sixth is a currency with exchange rate 1 (let\u0026rsquo;s say the currency name is Gold, 1 USD to 1 Gold) The fifth is Gold after the exchange rate increases by 1000 pips The seventh is the target currency change when pips is 1000 Because RMB and Baht curves are too steep to observe clearly. Let\u0026rsquo;s look at Gold and Silver\u0026rsquo;s profit changes under pips. At $50,000, when pips change by 1000, both Gold and Silver increase by 5000. However, we know that 5000 Gold and 5000 Silver have different values. That is, with the same $50,000 investment, the return rate is different.\nFor Gold, 1000 pips is a relatively large fluctuation; for Silver, it\u0026rsquo;s relatively small.\nThe steeper the curve, the larger the absolute number of daily fluctuations (pips). 100 pips is a very small fluctuation for Baht, but relatively large for RMB. 100 pips = 0.01\nFor Baht, a 0.01 fluctuation is only (30.01 - 30) / 30 = 0.03% For RMB, a 0.01 fluctuation is (6.51 - 6.5) / 6.5 = 0.15% From the chart above, using pip to represent exchange rate changes is not suitable for too flat exchange rates. For example, USD/THB = 30, then THB/USD = 0.033333 (1 Baht to 3 cents). If using pips for THB/USD:\nFor a 100 pip change, it would cause (0.043333 - 0.033333) / 0.033333 = 30% exchange rate change. So in this scenario, pip\u0026rsquo;s granularity is too large.\nCurrently there are three quotation methods for exchange rates:\nDirect quotation: How much domestic currency equals one unit of foreign currency Indirect quotation: How much foreign currency equals one unit of domestic currency US Dollar quotation: How much foreign currency equals one unit of US dollar (a few currencies, for example GBP, are exceptions) ","permalink":"https://blog.thefreemeal.com/en/posts/2022-04-23-pip/","summary":"\u003ch2 id=\"what-is-pip\"\u003eWhat is Pip?\u003c/h2\u003e\n\u003cp\u003ePip is the quoted unit for exchange rate changes. Generally the fourth decimal place. 0.0001 is one pip. Yen is an exception - for Yen, 0.01 is one pip. Because Yen is too small.\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003eA pip is a unit of measurement for price movements of currencies in foreign exchange (FX) markets. Pip stands for \u0026ldquo;percentage in point\u0026rdquo; or \u0026ldquo;price interest point.\u0026rdquo; It represents the smallest price variation that a particular exchange rate experiences based on typical FX market convention.\u003c/p\u003e","title":"What is Pip in Forex Quotes"},{"content":" In the Web 3 field, what are the star applications? What are their MAU (Monthly Active Users)? For finance-related apps, what\u0026rsquo;s the monthly transaction volume in USD? Reference 1 (dappradar website) provides real-time data for analysis.\nWeb3 applications differ slightly from current web 2.0 internet applications - all user data and transaction data are transparent. You don\u0026rsquo;t need to go through the application operator; you can get real operational data from the blockchain.\nAccording to dappradar website statistics, this article looks at star dapp applications from two dimensions in the past 30 days:\nActivity: Top 10 apps by monthly active users (wallet count) Transaction Volume: Top 10 apps by transaction volume (token inflow in USD) Top 10 apps by total assets in smart contracts 1. Activity The table above shows the TOP 10 apps ranked by number of users (unique accounts) in 30 days.\nRank App Name Description 1 PancakeSwap Leading decentralized exchange on BSC 2 Primelab From the description, Primelab provides users with a blockchain ecosystem, with main features being better accessibility and usability. All Primelab dapps allow users to register via email or phone. From the data, their user count is very unstable. 3 AtomicAssets Implements NFT protocol on WAX blockchain (corresponds to common NFT standards ERC721, ERC1155 on Ethereum). 4 Alien Worlds Gaming related 5 Splinterlands Gaming related 6 OpenSea The first and largest crypto collectibles peer-to-peer market, including game items, digital art, and other virtual goods backed by blockchain. 7 Axie Marketplace Gaming related 8 Upland Gaming related 9 Katana Automated Market Maker (AMM) decentralized exchange (DEX) built on Ronin. 10 Magic Eden NFT market on Solana blockchain. Analysis from the table:\nGaming applications have more participants - 4 of the top 10 are gaming related AMM decentralized exchanges like Uniswap are also very active, e.g., Pancakeswap, Katana NFT trading related apps are active: OpenSea, Magic Eden, AtomicAssets Primelab is the only special case - its selling point is usability, making it easier for ordinary people to use blockchain services. But observing its data, it\u0026rsquo;s very unstable. Suspect it reached the top 10 by chance. 2. Transaction Volume 2.1. Top 10 by Transaction Volume 2.2. Top 10 by Asset Volume From the perspective of transaction volume (USD equivalent flowing into smart contracts in the past 30 days) and asset volume (total assets deposited in smart contracts), all top 10 applications are DeFi applications without exception. And they\u0026rsquo;re mainly decentralized exchanges on different blockchains. For example, in the current DeFi system, three AMM applications with different characteristics are all in the TOP 10 list: Uniswap, Curve, 1inch.\nETH2 Deposit Contract holds significantly higher funds than all other applications. This application serves Ethereum\u0026rsquo;s migration to 2.0, which uses POS-based consensus mechanism. Validators in the 2.0 era are similar to miners in the 1.0 era. Becoming a validator requires staking Ethereum. This smart contract is used to collect staked Ethereum.\nPolygon POS Bridge and Ronin Bridge applications that transfer assets between Ethereum and L2 sidechains also have considerable asset deposits.\nAll TOP 10 applications support one or more of the following blockchain platforms:\nLayer1 public chains: ETH, WAX, Flow, Solana, NEAR, Hive (Steem fork), EOS, Klaytn (Korean Kaokao), Waves (Russian), Avalanche, Moonbean, Fantom; Layer2 sidechains: BSC, Ronin, Polygon, Immutable X, Optimism 3. References https://dappradar.com/rankings ","permalink":"https://blog.thefreemeal.com/en/posts/2022-04-10-dapps/","summary":"\u003cblockquote\u003e\n\u003cp\u003eIn the Web 3 field, what are the star applications? What are their MAU (Monthly Active Users)? For finance-related apps, what\u0026rsquo;s the monthly transaction volume in USD? Reference 1 (dappradar website) provides real-time data for analysis.\u003c/p\u003e\u003c/blockquote\u003e\n\u003cp\u003eWeb3 applications differ slightly from current web 2.0 internet applications - all user data and transaction data are transparent. You don\u0026rsquo;t need to go through the application operator; you can get real operational data from the blockchain.\u003c/p\u003e","title":"Popular Web3 Apps Viewed from Monthly Active Users and Transaction Volume"},{"content":"Ethereum is a distributed computer composed of a large number of distributed nodes, where each node can execute bytecode (the so-called smart contracts) and store the results on the blockchain. The entire network is distributed, applications can save state information, and with state information, applications can provide rich and varied services. Ethereum has no centralized nodes - third parties cannot interfere with the entire network\u0026rsquo;s operation. It can be considered a world computer that never stops running.\n1. Ethereum - The World Computer The image above describes Ethereum\u0026rsquo;s functionality. It places a virtual computer on the blockchain. The colored blocks in the image are blocks connected by hash values. Each block contains a list of transactions, which are executed in the computer and cause changes to the computer\u0026rsquo;s state.\nIn Ethereum, this virtual computer\u0026rsquo;s state is called the \u0026ldquo;World State,\u0026rdquo; which can be considered the storage area of the \u0026ldquo;World Computer.\u0026rdquo; The World State constantly changes by executing transactions in Ethereum blocks. Each time a block is added to the chain\u0026rsquo;s tail, it causes the world\u0026rsquo;s state to change. The World State is independently maintained by each node in the database.\nFrom this perspective, this state management method is similar to Git - each block is a new version. Each block can obtain the current state of all accounts. The last block represents the current state of all accounts in the system. The World Computer runs on every Ethereum node, and the World State is the same on every node. Code triggered by transactions runs once on all nodes\u0026rsquo; virtual machines. 2. Accounts The World State consists of the states of all accounts. There are two types of accounts: Externally Owned Accounts (EOA) and Contract Accounts. Account properties include balance, nonce, code, and storage. Only contract accounts have code and storage. Externally owned accounts are controlled by private keys, while contract accounts are controlled by contract code.\nEvery internal account has its own independent storage area. Once smart contract code is deployed on Ethereum, it cannot be upgraded or modified. The codeHash ensures the code cannot be modified.\nThe image above shows only two accounts, but there are many accounts in the actual World State.\n3. Transactions Transactions in Ethereum are initiated by network users. There are two types: regular message calls and creating internal accounts (which generates a new address and initializes a smart contract).\nThe image above shows that after transaction execution, there\u0026rsquo;s a new internal account in the World State.\n4. EVM - Virtual Machine As the World Computer, there\u0026rsquo;s not only storage but also a virtual machine for executing smart contract code, called the EVM. Contract code executes in the EVM and can cause changes to storage (World State).\nSmart contract development uses high-level languages, which are compiled into binary code that the EVM can recognize when deploying to Ethereum. Once a contract is deployed, it needs to execute on all nodes that maintain the World State. Note: it\u0026rsquo;s not executed on just one node - when there are contract-related operations in the transaction list, the corresponding code for those operations must execute on all nodes. Ethereum nodes update the World State by executing contract-related code.\nUsing the World Computer is chargeable - each execution requires an advance fee (called gas), which is continuously deducted during execution. Once the advance fee is exhausted, instructions can no longer be executed, and the smart contract call fails. This mechanism also enhances system reliability. If there\u0026rsquo;s a bug in a smart contract - like writing an infinite loop - it can at least stop due to running out of fees.\n","permalink":"https://blog.thefreemeal.com/en/posts/2022-04-04-ethereum/","summary":"\u003cp\u003eEthereum is a distributed computer composed of a large number of distributed nodes, where each node can execute bytecode (the so-called smart contracts) and store the results on the blockchain. The entire network is distributed, applications can save state information, and with state information, applications can provide rich and varied services. Ethereum has no centralized nodes - third parties cannot interfere with the entire network\u0026rsquo;s operation. It can be considered a world computer that never stops running.\u003c/p\u003e","title":"Ethereum Illustrated"},{"content":"\nThe concept of Merkle tree was patented by Ralph Merkle in 1979, hence the name.\nMerkle tree is a binary tree data structure where each leaf node stores the hash value of a data block, and non-leaf nodes store the hash of their two child node values (concatenating the two hash values and then hashing). Hash trees can efficiently and securely verify the content of large data structures.\nScenario Suppose there are 1000 data blocks, each 1MB, and you need hash values (checksums) to ensure each data block hasn\u0026rsquo;t been modified during transmission. There are two approaches:\nDuring transmission, add 1000 hash values, one for each data block. The data receiver can use hash values to verify each block individually for modifications. Combine these 1000 blocks into one 1GB data block, then hash this 1GB block once. The data receiver can use the hash value to verify all 1000 blocks at once. Both approaches have drawbacks:\nApproach 1: Increases the amount of data transmitted. Using SHA256, Approach 1 needs to add 999 hash values of 32 bytes each. Approach 2: Only needs to add a 32-byte checksum (hash value), which is efficient. But the problem is when the data receiver wants to check just one data block, they must get all 1000 data blocks, combine them, and calculate together to verify. Merkle Tree provides a third approach.\nSolution Merkle Tree hashes each data block separately (similar to Approach 1 above), but doesn\u0026rsquo;t directly transmit this bunch of hash values. Instead, it concatenates pairs of hash values and hashes them again. Similar to World Cup matches, until finally getting one hash value, called the Merkle Root. Then transmit all data blocks together with the Merkle Root value.\nThe receiver gets all data blocks and the Merkle Root value. Using the algorithm above, they can recalculate to verify if the Merkle Root matches the value from Merkle hashing the data blocks.\nIf the receiver only wants to verify one data block\u0026rsquo;s integrity. For example, in the Bitcoin case shown above, if the receiver only wants to know if transaction T(D) is in the current block, they only need to get four hash values: H(C), H(AB), H(EFGH), and the Merkle Root to verify. When there are more data blocks, Merkle Tree has more levels. To verify one data block, you need the hash values of all sibling nodes on the branch from the root to the leaf node containing that block. Hash values are generally only 32 bytes, much shorter than transaction blocks.\nIn Bitcoin, SPV nodes use this property of Merkle Tree to optimize interaction with trusted nodes, greatly reducing data transmission.\nWhy don\u0026rsquo;t SPV nodes directly ask a trusted node for the H(D) value for verification? Because H(D) could be forged. But the Merkle Root value is saved in the current block\u0026rsquo;s header on the blockchain, which has integrity protection. Verifying by comparing with the Merkle Root is more reliable. Due to the one-way nature of hash functions, malicious nodes cannot forge hash values on the branch from the Merkle Root - technically impossible (would need to solve hash collision problems).\nUse Cases Merkle Tree is used in distributed systems for efficient data verification. It has been widely adopted in the industry. Here are some examples:\nVersion control tool - Git P2P browser - Tor Blockchain related: Bitcoin, Ethereum, Filecoin, etc. References Merkle Tree - Wikipedia Merkel Tree - Investopedia ","permalink":"https://blog.thefreemeal.com/en/posts/2022-04-04-merkle/","summary":"\u003cp\u003e\u003cimg alt=\"picture 32\" loading=\"lazy\" src=\"/images/1649010375043.jpg\"\u003e\u003c/p\u003e\n\u003cp\u003eThe concept of Merkle tree was patented by Ralph Merkle in 1979, hence the name.\u003c/p\u003e\n\u003cp\u003eMerkle tree is a binary tree data structure where each leaf node stores the hash value of a data block, and non-leaf nodes store the hash of their two child node values (concatenating the two hash values and then hashing). Hash trees can efficiently and securely verify the content of large data structures.\u003c/p\u003e","title":"Merkle Tree: The Data Structure Behind Git and Blockchain"},{"content":"The Bitcoin Whitepaper is a very short paper, only 12 short paragraphs. Published by Satoshi Nakamoto on October 31, 2008. The ideas contained in it later developed into blockchain. The whitepaper is definitely worth reading - it\u0026rsquo;s a classic among classics in this field. This note starts from the perspective of the Bitcoin whitepaper and adds some understanding of implementation details related to the Bitcoin network.\n1. Principles of Bitcoin and Blockchain The goal of the Bitcoin solution is to implement peer-to-peer electronic cash, allowing online payments to be sent directly from one party to another without financial institutions as intermediaries.\nIt needs to solve several problems in a peer-to-peer network, decentralized environment:\nHow to determine whose electronic cash is? You can only spend your own money, not others'. How to prevent double spending (the Double Spending mentioned above)? Your money can only be spent once; you can\u0026rsquo;t initiate two transactions at the same time while bookkeeping isn\u0026rsquo;t completed to spend the same money twice. How to issue currency and drive the network to operate spontaneously? These problems are easily solved when financial institutions act as intermediaries:\nBanks open accounts for customers, record how much money each customer has, and provide payment passwords. Customers authenticate with their passwords at the bank; after proving identity, they can pay all or part of the amount. When spending money, the bank updates the customer\u0026rsquo;s account balance in real time. As it decreases, there\u0026rsquo;s no possibility of spending money twice. Currency issuance and entire system operation are through financial institutions. In the Bitcoin system:\nFor the first problem, traditional asymmetric encryption mechanism is used. Each account in the Bitcoin system is associated with a public key; users sign their transactions with private keys. The system determines transaction legitimacy by verifying the digital signature. For the second problem, Bitcoin system proposes a new method. Pack transactions into blocks, hash them, and link blocks into a distributed continuously growing chain structure based on the hash. The chain structure allows everyone to reach consensus on the transaction sequence in the ledger (forming a Single Source of Truth). If a previous transaction has already spent money, a subsequent transaction trying to spend the same money cannot be recognized by everyone and cannot form consensus on the chain. This mechanism was first proposed in the Bitcoin whitepaper and later called blockchain. Block packaging and chaining work is done through distributed competition among all participants; Bitcoin uses POW (Proof of Work) as the consensus algorithm. For POW, there\u0026rsquo;s detailed explanation in the mining section below. For the third problem, currency issuance and entire transaction system operation are driven by miners\u0026rsquo; mining behavior. Bitcoin uses a public-private key system to solve user authentication. This solution has strong privacy protection capabilities. An extreme example: a person can generate a pair of public-private keys in a small dark room, completely offline, using pen and paper, then derive a Bitcoin address from the public key. As long as this address (e.g., 1J7mdg5rbQyUHENYdx39AWISME7fsLpEoXZy) is published, they can receive payments. After receiving, only the person in the small dark room can operate that money on the blockchain (because only they have the private key corresponding to that Bitcoin account). If deliberately concealed, money on the Bitcoin network is hard to trace to the corresponding person. Of course, privacy may be compromised during Bitcoin and fiat currency conversion.\nThe above image illustrates Bitcoin\u0026rsquo;s blockchain. In Block 2\u0026rsquo;s header, it stores the hash of Block 1\u0026rsquo;s header. The hash acts like a parent node pointer in a linked list. Based on the sequence of being added to the chain, transactions in Block 2 are later than those in Block 1, transactions in Block 3 are later than those in Block 2. Each block records transactions in the block body; a hash of all transactions in the block body is also made and stored in the block header (in the Merkle Root field).\nThrough the blockchain, transaction sequence is guaranteed, and transactions that have formed consensus on the blockchain cannot be tampered with (because transaction hashes are also stored in the block header; changing transaction content would cause the Merkle Root hash in the header to not match; if you also change the Merkle Root value, it would cause the block header hash to change, and the changed block header hash would cause the block to be removed from the linked list).\nThe network timestamps transactions by hashing them into an ongoing chain of hash-based proof-of-work, forming a record that cannot be changed without redoing the proof-of-work. The longest chain not only serves as proof of the sequence of events witnessed, but proof that it came from the largest pool of CPU power. As long as a majority of CPU power is controlled by nodes that are not cooperating to attack the network, they\u0026rsquo;ll generate the longest chain and outpace attackers. \u0026mdash; Bitcoin Whitepaper\nThat\u0026rsquo;s the theory. Below are implementation details.\n2. How Does the Bitcoin Network Operate? The steps to run the network are as follows:\nNew transactions are broadcast to all nodes. Each node collects new transactions into a block. Each node works on finding a difficult proof-of-work for its block. When a node finds a proof-of-work, it broadcasts the block to all nodes. Nodes accept the block only if all transactions in it are valid and not already spent. Nodes express their acceptance of the block by working on creating the next block in the chain, using the hash of the accepted block as the previous hash. \u0026mdash;- Bitcoin Whitepaper 2.1. Users Initiate Transactions When a user initiates a transfer transaction, they pack their public key, destination account address, amount, etc., and sign it. This creates a packaged transaction. This transaction is then broadcast to a mempool.\nThe above shows changes in the number of real-time pending transactions in the global mempool.\nIn reference material 2, you can view the current mempool situation on the Bitcoin network in real time. You can also view details of all on-chain blocks and all pending transactions.\n2.2. Miners Record Transactions Transactions in the mempool can be freely selected by each Bitcoin miner to include in a block for packaging. When selecting, they need to verify transaction legitimacy (whether the sender has enough coins, whether the signature is correct, etc.). Miners also select transactions based on transaction fees (customers giving higher tips get served first). After filling their block, miners start mining (calculating hash). Mining uses brute force, constantly trying to adjust the Nonce in the block header, then hash the block header and check if the resulting hash meets requirements.\nThe system has requirements for the block header hash (e.g., requiring several consecutive zeros at the beginning). Everyone competes; whoever finds a qualifying hash first gets their block added to the chain tail.\nThe difficulty is adjusted to probabilistically control how long it takes for the entire network to mine a block. Difficulty is proportional to the expected number of attempts needed to find a qualifying hash. Bitcoin system sets one block every 10 minutes; if blocks are being produced too fast, difficulty increases, and vice versa.\nAll miners select, package, and hash from transactions in the mempool. When a miner successfully finds a Nonce value (making the current attempt\u0026rsquo;s block header hash meet requirements), they immediately broadcast the block to the entire network. Other miners, upon receiving the new block, verify it (checking if transactions in the block are all valid, there\u0026rsquo;s no double spending, also checking block Merkle Root and other data). If valid, they add it to the end of the blockchain. At the same time, they abandon their current block that\u0026rsquo;s being calculated but not yet complete, and start calculating the next block for the next round of proof-of-work competition.\nMiners add a transaction in the block they mine. It\u0026rsquo;s the mining income (coinbase). Each block\u0026rsquo;s reward was initially 50 Bitcoin, halving every 4 years. Currently it\u0026rsquo;s 6.25 Bitcoin. In Bitcoin blockchain transactions, only mining income has no address source; there\u0026rsquo;s exactly one mining income transaction per block. Essentially, all Bitcoin\u0026rsquo;s most original source is mining income. Mining is currency issuance. Because there\u0026rsquo;s a coinbase transaction in the block, after miners find a qualifying Nonce, they can safely broadcast the block. Other miners cannot plagiarize it. 3. Main Data Structures Bitcoin system\u0026rsquo;s data structure is relatively simple; data passed between nodes is blocks. The structure of each block is as shown above. Blocks include Header and Body. Header contains:\nPrev Block: Hash of the previous block, used to link different blocks. Merkle Root: Hash of all transactions in the block. Used to ensure block body content isn\u0026rsquo;t modified. Time: Unix timestamp. Bits: Difficulty coefficient, used to control expected number of attempts needed to get target hash. Nonce: Random number, adjusted during mining to get different hash values. Body contains transactions. Each black or green horizontal bar in the above image represents a transaction. The green one is the mining income transaction.\nNote: The system uses Merkle Tree to hash all transactions in the block body. Unlike regular hash algorithms like MD5, SHA256, etc., Merkle Tree can verify if a transaction is in the block without knowing all block body information.\nBitcoin blockchain is a distributed database; its data is a one-way linked list composed of these blocks. Each node can save all these block data to get the entire Bitcoin blockchain state. The current state of the Bitcoin network is the balance corresponding to each address.\nTransactions recorded in the blockchain are similar to Redis AOF files or database binlog files. They record one transaction at a time. They don\u0026rsquo;t record state. State is obtained by replaying transactions.\n┌ │ │ │ │ │ │ │ │ │ └ ─ B ┌ │ └ ─ ─ l ─ C ─ ─ ─ o ─ B ─ ─ ─ c ┬ │ ┴ ─ ─ k ─ 5 ─ ─ ─ ─ 0 ─ ─ ─ # ─ . ─ ─ ─ 1 ─ 0 ─ ─ ─ ┬ │ ┴ ─ ─ ─ O ─ ─ ─ ─ U ─ ─ ─ ─ T ─ ─ ─ ┐ ├ ┘ ─ ┐ │ │ ┼ │ │ │ │ │ │ ┘ ─ ─ ┐ │ │ │ └ ─ ─ ┌ │ │ │ │ │ │ \u0026gt; │ │ └ ─ B ┌ │ └ ┌ │ │ │ └ ─ ─ l ─ C ─ ─ I ─ ─ ─ o ─ B ─ ─ N ─ ─ ─ c ┬ │ ┴ ┬ │ ├ │ ┴ ─ ─ k ─ 5 ─ ─ 8 ─ 4 ─ ─ ─ ─ 0 ─ ─ . ─ 1 ─ ─ ─ # ─ . ─ ─ 7 ─ . ─ ─ ─ 2 ─ 0 ─ ─ 0 ─ 3 ─ ─ ─ ┬ │ ┴ ┬ │ ┼ │ ┴ ─ ─ ─ O ─ ─ O ─ O ─ ─ ─ ─ U ─ ─ U ─ U ─ ─ ─ ─ T ─ ─ T ─ T ─ ─ ─ ┐ ├ ┘ ┐ ├ ┤ ├ ┘ ─ ┐ │ │ ┼ │ │ ┼ │ ┼ │ ┘ ─ ─ ─ ─ ─ ┐ │ │ └ ┐ │ │ ┼ │ └ ─ ─ ─ ─ ─ ─ ─ ┌ │ │ │ │ │ \u0026gt; │ \u0026gt; │ └ ─ ─ B ┌ │ └ ┌ │ ├ │ └ ─ ─ ─ l ─ C ─ ─ I ─ I ─ ─ ─ ─ o ─ B ─ ─ N ─ N ─ ─ ─ ─ c ┬ │ ┴ ┬ │ ┤ │ ┴ ─ ─ ─ k ─ 5 ─ ─ 5 ─ ─ ─ ─ ─ 0 ─ ─ 8 ─ ─ ─ ─ # ─ . ─ ─ . ─ ─ ─ ─ 3 ─ 0 ─ ─ 7 ─ ─ ─ ─ ┬ │ ┴ ┬ │ │ │ ┴ ─ ─ ─ ─ O ─ ─ O ─ ─ ─ ─ ─ U ─ ─ U ─ ─ ─ ─ ─ T ─ ─ T ─ ─ ─ ─ ┐ ├ ┘ ┐ │ │ │ ┘ ─ ─ ┐ │ │ ┼ │ │ │ │ │ │ ┘ ─ ─ ─ ─ ─ ┐ │ │ └ ┌ │ │ ┘ ─ ─ ─ ─ ┌ │ │ │ │ │ \u0026gt; │ \u0026gt; │ └ ─ B ┌ │ └ ┌ │ ├ │ └ ─ ─ l ─ C ─ ─ I ─ I ─ ─ ─ o ─ B ─ ─ N ─ N ─ ─ ─ c ┬ │ ┴ ┬ │ ┼ │ ┴ ─ ─ k ─ 5 ─ ─ 2 ─ 6 ─ ─ ─ ─ 0 ─ ─ 5 ─ 6 ─ ─ ─ # ─ . ─ ─ . ─ . ─ ─ ─ 4 ─ 0 ─ ─ 0 ─ 3 ─ ─ ─ ┬ │ ┴ ┬ │ ┼ │ ┴ ─ ─ ─ O ─ ─ O ─ O ─ ─ ─ ─ U ─ ─ U ─ U ─ ─ ─ ─ T ─ ─ T ─ T ─ ─ ─ ┐ │ ┘ ┐ │ ┤ │ ┘ ─ ┐ │ │ │ │ │ │ │ │ │ ┘ All Bitcoin transactions can also be logically串联 across blocks through account addresses. The root node is the miner reward transaction. Leaf nodes, also called UTXO (Unspent Transaction Output). Intermediate non-root non-leaf accounts represent money they once owned. This allows tracking funds through transactions. This is one of Bitcoin\u0026rsquo;s typical characteristics.\nTo calculate how much Bitcoin is in a wallet, look at which UTXO addresses the wallet\u0026rsquo;s Bitcoin addresses have, and sum the Bitcoin in those addresses.\n4. Other 4.1. POW Computing Power and 51% Attack What happens when malicious attackers appear on the Bitcoin network? Since Bitcoin\u0026rsquo;s cryptographic foundation is very secure, attackers choose to attack parts not directly protected by cryptography: transaction order. The attacker\u0026rsquo;s strategy is simple:\nSend 100 BTC to a seller to buy goods (especially digital goods that don\u0026rsquo;t need shipping). Wait until the goods are shipped. Create another transaction, sending the same 100 BTC to their own account. Make the Bitcoin network believe the transaction sending to their own account was the first one sent. Once (1) happens, after a few minutes, miners will pack this transaction into a block, let\u0026rsquo;s say block #270000. About an hour later, there will be five blocks after this block, each indirectly pointing to this transaction, confirming it. At this point, the seller receives payment and ships to the buyer. Since we assume it\u0026rsquo;s a digital good, the attacker can receive the goods immediately. Now the attacker creates another transaction sending the same 100 BTC to their account. If the attacker just broadcasts this message to the entire network, this transaction won\u0026rsquo;t be processed. Miners will run the state transition function APPLY(S,TX) and find this transaction spends a UTXO that\u0026rsquo;s no longer in the state. So, the attacker forks the blockchain, uses block #269999 as parent to regenerate block #270000, replacing the old transaction with the new one in this block. Because block data is different, this requires redoing proof of work. Also, because the attacker\u0026rsquo;s new block #270000 has a different hash, the original blocks #270001-#270005 don\u0026rsquo;t point to it, so the original blockchain and attacker\u0026rsquo;s new block are completely separate. When a fork happens, the longer blockchain branch is considered the honest one. Legitimate miners will mine after original block #270005; only the attacker mines after the new block #270000. For the attacker to have the longest blockchain, they need more computing power than the rest of the network combined (i.e., 51% attack).\n4.2. Byzantine Generals Problem This story is about a group of generals besieging Byzantium (Istanbul). Byzantium is powerful; it can only be captured if all forces attack, otherwise attacking troops will be destroyed. The generals agree to follow the majority - either all attack or retreat together. But the generals are scattered around the city, with poor communication. Among the generals are traitors who will send different false messages to different generals, causing inconsistent actions.\nModern distributed systems have similar problems - multiple server nodes on the network collaborate and ultimately need to jointly maintain a set of data. There\u0026rsquo;s no way to guarantee node honesty (a dishonest node sends different information to other nodes), nor guarantee internal system information consistency; nodes have no way to judge information authenticity.\nThe Bitcoin system\u0026rsquo;s solution based on POW: view generals as miners. Assuming each team has equal computing power, then within every 10 minutes, one general gets a chance to speak (tell others whether to attack or retreat). After several 10-minute periods, all generals\u0026rsquo; messages form a blockchain. The blockchain mechanism ensures each general can express exactly once (otherwise double spending). Generals can reach consensus through this mechanism.\n4.3. Full Nodes, Light Nodes, SPV Nodes Initially in the Bitcoin network, all nodes processed all blocks and stored all data. Later, as network scale expanded, node processing and storage capabilities continuously demanded new requirements. Light nodes and SPV nodes emerged.\nFull nodes are nodes that maintain complete blockchains with all transaction information. Full nodes can verify transaction legitimacy. Light nodes: Nodes only locally save transaction data related to themselves (especially spendable transaction data). Light nodes also process all blocks but don\u0026rsquo;t need to save all blockchain information. SPV nodes: Nodes that can only verify whether a payment is real and how many confirmations it has. SPV nodes don\u0026rsquo;t need local blockchain data to verify transactions succeeded. Verification method:\nCalculate the transaction hash of the payment to verify; Node obtains and stores all block headers of the longest chain locally from the network; Node obtains the Merkle tree hash authentication path corresponding to the payment from the blockchain; Based on the hash authentication path, calculate the Merkle tree root hash, compare with the local block header\u0026rsquo;s Merkle root, locate the block containing the payment; Based on the block header\u0026rsquo;s position, verify whether it\u0026rsquo;s in the known longest chain, determine how many confirmations the payment has; if included, prove payment is valid. Generally, mobile wallets and other devices with limited computing resources can act as SPV nodes. When someone transfers money to you, you only need to know if the transaction is on the chain and if there are enough blocks following to ensure the transaction succeeds.\n4.4. Bitcoin Network Processing Capacity Bitcoin network\u0026rsquo;s TPS (transactions per second) is about 5. This value can be calculated from three parameters:\nOne block every 10 minutes; Block size; Average transaction size. 5 TPS is a relatively small number (compare to VISA network, which processes thousands of transactions per second). Methods to improve throughput include shortening block production time, increasing block size, etc. There are also solutions using sidechains or off-chain transactions (e.g., Lightning Network) to address throughput.\n4.5. Soft Fork and Hard Fork Forks occur due to changes in consensus rules. New consensus rules may be a superset, intersection, or subset of the original rules.\nThe definition of a hard fork is to expand consensus rules, allowing something that was previously prohibited (superset or intersection case). Previously invalid transactions/blocks become valid after a hard fork. A soft fork is to tighten consensus rules, prohibiting something that was previously allowed (subset case). Previously valid transactions may become invalid after a soft fork. After a fork, some nodes in the network upgrade to support new rules.\nIn a soft fork scenario, blocks produced by new rules will also be recognized by old nodes (that haven\u0026rsquo;t upgraded). in a hard fork scenario, blocks produced by new rules may be considered illegal by old nodes. It will fork into two chains with no intersection, developing along their own paths. If you held tokens before the fork, after a hard fork, tokens become two copies, usable on both the old and new blockchains. The reason for this phenomenon is that after a hard fork, it becomes two networks. Transactions in one network only cause state changes in that network (the current state of the network, defined by the last block in the blockchain).\nWhether soft fork or hard fork, the new version of software must be able to correctly handle old block data produced by the old version of software.\n5. References Bitcoin: A Peer-to-Peer Electronic Cash System Blockchain explorer Blockchain Tutorial Ethereum Whitepaper Lightning Network ","permalink":"https://blog.thefreemeal.com/en/posts/2022-04-03-blockchain/","summary":"\u003cp\u003eThe Bitcoin Whitepaper is a very short paper, only 12 short paragraphs. Published by Satoshi Nakamoto on October 31, 2008. The ideas contained in it later developed into blockchain. The whitepaper is definitely worth reading - it\u0026rsquo;s a classic among classics in this field. This note starts from the perspective of the Bitcoin whitepaper and adds some understanding of implementation details related to the Bitcoin network.\u003c/p\u003e\n\u003cp\u003e\u003cimg alt=\"picture 24\" loading=\"lazy\" src=\"/images/1648889277551.jpg\"\u003e\u003c/p\u003e\n\u003ch2 id=\"1-principles-of-bitcoin-and-blockchain\"\u003e1. Principles of Bitcoin and Blockchain\u003c/h2\u003e\n\u003cp\u003eThe goal of the Bitcoin solution is to implement peer-to-peer electronic cash, allowing online payments to be sent directly from one party to another without financial institutions as intermediaries.\u003c/p\u003e","title":"Bitcoin and Blockchain"},{"content":" What is NFT? What is DAO? DeFi? GameFi? SocialFi? What\u0026rsquo;s in a blockchain wallet? What opportunities does Web 3 present for companies? What opportunities for programmers? Why can the US block Russian users\u0026rsquo; crypto transactions? 1. Web1, Web2, Web3 Web1: Main application is creating websites to publish information. Web2: In addition to Web1, there\u0026rsquo;s interaction. Consumers of information also create content, which is consumed by platforms (viewing ads to generate revenue for platforms). Web3: Combines the decentralization and community management of Web1 with the rich interactive features of Web2. The biggest feature is that users and developers can own content. Web3 is token-driven. According to Chris Dixon @ a16z, Web3 is a network jointly owned by developers and users, driven by tokens.\nWeb1 (roughly 1990-2005) was about open protocols that were decentralized and community-governed. Most of the value accrued to the edges of the network — users and builders. Web2 (roughly 2005-2020) was about siloed, centralized services run by corporations. Most of the value accrued to a handful of companies like Google, Apple, Amazon, and Facebook. Web3 is the internet owned by the builders and users, orchestrated with tokens. \u0026hellip; combines the decentralized, community-governed ethos of web1 with the advanced, modern functionality of web2. The above diagram describes the main problem of Web2, which is determined by the nature of central nodes (Google, Apple, Amazon, FB, etc.) pursuing profit. They give benefits to users and partners in the early stage, then consume user data later and compete with partners.\nIn terms of network structure, Web3 is peer-to-peer and decentralized.\n2. Core Concepts The above diagram compares major concepts in Web3 with major concepts in the real economy.\nIn real life, there are five types of entities that play roles in economic activities:\nMoney: Without money, exchanges have no liquidity, we\u0026rsquo;d have to rely on much less efficient barter trade. Means of production (land, factories, machines, etc.): Without means of production, there are no goods. Goods: Without goods, there\u0026rsquo;s no economy. Exchange mechanisms (e-commerce, retail stores, stock exchanges, etc.): Without exchange mechanisms, goods are hard to trade, making division of labor impossible. Institutions (governments, banks, companies, etc.): Without institutions, coordination and cooperation between different economic participants would be difficult. In internet-native economic activities (Web3), there are corresponding basic concepts:\nCryptocurrency: Token / Crypto Smart Contracts: Smart Contract Non-Fungible Tokens: NFT Exchanges: Exchanges Decentralized Autonomous Organization: DAO 2.1. Token and Crypto Token. It\u0026rsquo;s a string. A token is a record of ownership of an asset.\nThere are fungible and non-fungible types. Fungible tokens can be cryptocurrency, or money in real life. Your 1 Bitcoin and my 1 Bitcoin are equal in value, replaceable.\nNon-fungible token is NFT.\nThe above diagram classifies assets in the real and virtual worlds from two dimensions: tangible and fungible.\n2.2. Smart Contract Public contracts that everyone can see. Pre-set execution conditions that automatically execute when met. Smart contracts run on public blockchains and are open-source code natively integrated with crypto tokens. They allow developers to build complex applications across games, social, financial services, etc. Smart contract source code is public, and execution results are recorded on the blockchain.\nSmart contracts are written in Solidity, for Ethereum applications. Syntax similar to JavaScript; there are development tutorials online.\nSolidity is a statically-typed curly-braces programming language designed for developing smart contracts that run on Ethereum.\n2.3. NFT Short for Non-fungible tokens. Chinese translation is \u0026ldquo;非同质化代币\u0026rdquo; (unique token), which is ownership certification. It has the characteristics of non-fungibility, indivisibility, and transparent transaction history.\nMainly solves the problem of asset certification. Currently, in the real world, centralized organizations do asset certification. For example, the state uses property certificates to certify your property, game companies use records in databases to certify equipment you own in games. Using NFT is a decentralized way - assets can be certified and traded.\nA way to represent anything unique as an Ethereum-based asset. NFTs are giving more power to content creators than ever before. Powered by smart contracts on the Ethereum blockchain. The above definition comes from Ethereum; actually any smart contract platform can support publishing NFTs.\nNFT is certification of content. To participate in NFT, you need:\nWallet (account, owner) Cryptocurrency (to pay gas, certification fees): Can be obtained by buying ETH from exchanges Issuance and trading platforms Currently, NFT trading is mainly done on OpenSea, the largest market.\nWhy are people willing to spend money to buy ownership of a digital small image?\nAfter buying an NFT of an artwork, others who can see the artwork can also take photos or clone it digitally. NFT can\u0026rsquo;t prohibit copying. But NFT can prove you\u0026rsquo;re the owner. In the virtual world, only you are the owner of this image; only you can legally hang this image in your virtual home or use it in your own logo. With scarcity and demand, there\u0026rsquo;s buying desire. The core of buying and selling is ownership transfer. The above is an example of an NFT. The corresponding asset (image) here is stored on an external server. Some NFTs also store assets directly on the chain.\n2.5. Exchanges There are two types: centralized and decentralized. Centralized ones like Binance, Coinbase, etc. Regulated by their respective countries.\nRepresentatives of decentralized exchanges:\nUniswap (a crypto trading protocol) OpenSea (peer-to-peer market for NFTs) They are similar to the impact of stock exchanges, retail stores, or e-commerce on the traditional economy:\nAt stock exchanges you can trade traditional stocks; at Uniswap you can trade cryptocurrency (without centralized intermediaries like Coinbase or Gemini, Binance). At Walmart, Amazon, eBay you can buy physical goods; at OpenSea you can buy crypto-native digital goods. 2.5. DAO DAO is a decentralized organization, a decentralized version of traditional companies, allowing participants to own projects and make collective decisions using smart contracts. It\u0026rsquo;s a new way to finance projects, manage communities, and share value.\nTraditional companies own means of production (factories) and produce traditional economic goods (food, cars); DAO ultimately owns means of production and produces digital goods in the Web3 ecosystem.\nDAO: Decentralized Autonomous Organization - a form of organization similar to companies. More transparent than traditional companies because anyone can view all actions and fund flows in the DAO. This greatly reduces corruption and censorship risk. Listed companies must provide independent audited financial statements, but shareholders can only see a snapshot of the organization\u0026rsquo;s financial health. Since DAO balance sheets exist on public blockchains, they are completely transparent at all times, down to every transaction.\nBankless is a currently well-running DAO that provides banking services for people without bank cards. They have weekly meetings on Discord. Has goals and incentives.\nOdyssey DAO compares DAO with real-world companies:\nOrganizational structure Company: Hierarchical structure led by CEO and other executives. DAO: Flat structure led by a group of core contributors. Decision making Company: Management approves proposals and makes decisions behind closed doors. DAO: Members publicly submit proposals and vote using DAO tokens. Onboarding Company: Candidates need to apply and pass interviews to be hired. DAO: Some DAOs allow anyone to join, others require a minimum number of tokens. Tokens can be bought or earned by contributing to the DAO (e.g., taking meeting notes). Career advancement Company: Employees need to continuously grow and get promoted. DAO: Members gain trust of core contributors through contributions. Compensation Company: Most employees work full-time and get paid through salary and stock. DAO: Most contributors work part-time and get paid through DAO tokens or other cryptocurrencies (e.g., stablecoins). 3. Wallets and Accounts In Web3 practice, wallet is also an important concept, easily confused with addresses and accounts.\n3.1. Wallet, Address, and Signature A blockchain wallet is similar to a physical wallet. It can hold multiple bank cards issued by different banks (accounts on different chains). Each account (except contract accounts) is essentially protected by an asymmetric key system. Public keys are used to publicly receive information; private keys are used for authorized signatures.\nIf I use a certain account to transfer to another address, I need to sign the transfer information with the private key of the sending account, then attach the public key of the sending account. The system can use the public key and signature to determine if the transfer is approved by me (the account owner).\nMnemonic is a concept introduced to conveniently record private keys. The BIP39 specification defines how to generate private keys from mnemonics. Public keys can be calculated from private keys; addresses are a concept introduced for convenient use of public keys. Addresses are generally derived by performing hash operations on public keys.\nSo having a mnemonic is equivalent to having a private key. Having a private key means having everything. You can calculate the public key from the private key, then calculate the address from the public key.\nAddress formats may differ across chains. Ethereum starts with 0x, Bitcoin address formats have different notations (starting with 1, 3, bc1\u0026hellip;). A wallet can use the same set of mnemonics to generate different public/private keys for different chains. This way, you only need to remember one set of mnemonics to conveniently have accounts on multiple different chains.\nBlockchain Wallet Concepts Real-world Bank Account Concepts Private key Bank card password + bank card Mnemonic (simplified private key) Simplified bank card password Public key Bank account number Address Bank card number Keystore Encrypted private key Wallet Card holder Wallets can be classified in multiple ways:\nCentralized wallet (issued by exchanges, requires KYC) and decentralized wallet Cold wallet (not connected to internet) and hot wallet (app) 3.2. Accounts Bitcoin doesn\u0026rsquo;t have the concept of account balance; the blockchain records one transaction at a time. Balances are obtained by tracing historical transactions.\nEthereum has two types of accounts:\nExternally Owned Accounts (EOA), controlled by keys. Contract Accounts, controlled by smart contract code. Externally owned accounts include:\nA random number: actually a sequence number, incremented with each transaction to prevent replay attacks. Account balance Contract accounts add to external accounts:\nContract code: stores compiled EVM contract code. Once generated, it\u0026rsquo;s immutable, meaning smart contract code cannot be modified. Storage Like external accounts, contract accounts also have addresses. Full nodes in Ethereum record all account states (including balances).\nTransactions can be viewed as messages sent from one account to another, which can contain binary data (payload) and Ether. If the target account contains code, the code runs in EVM with payload as input - this is contract invocation. When contracts are triggered by transactions, instructions run on every node in the network: this requires computing cost; each instruction execution has a specific cost, gas is used to quantify this cost. Once created, each transaction prepays a certain amount of gas to limit the work required for execution and pay for transaction fees. 4. Applications Main directions:\nDeFi: Decentralized Finance GameFi: Game Finance SocialFi: Social Finance DeFi (decentFinance) refers to financial services that run on smart contracts instead of relying on middlemen such as banks or exchanges.\nIn fact, existing Web2 applications all have opportunities to evolve to Web3. For example, if we make a Web3 improved version of Zhihu (Chinese Q\u0026amp;A platform). After improvement, what\u0026rsquo;s the difference from current Web2 applications?\nAdvertising value can be shared with content creators. Display and ranking will be decided by voting, not by editors. Revenue is in platform tokens. Profit distribution and governance structure will change. For example, introducing smart contracts, after publishing, Zhihu itself cannot change them - fairer. 5. Ecosystem 5.1. Which Chain to Develop On? There are two main types of chains currently:\nEthereum: Similar to iOS, most rich ecosystem. Cosmos: Similar to Android Most activities are around Ethereum or Ethereum-compatible chains. NFT, various DAO organizations are all based on Ethereum. There are many Binance Chain (BSC) users in China; Binance Chain depends on Binance exchange. It\u0026rsquo;s a copy of Ethereum. Compatible with Ethereum language; Ethereum programs can easily port to BSC. Bitcoin originally also has a scripting language but it\u0026rsquo;s quite weak. Bitcoin\u0026rsquo;s chain is basically a decentralized ledger.\nBSC is called the Chinese \u0026ldquo;retail chain\u0026rdquo; (ponzi). Relatively cheap. Ethereum: Testing gas fees are high. 20 USD - 100+ USD. During development, you can apply for test chains on BSC/Ethereum.\nCurrently infrastructure is still early; it may not follow the pattern of mobile operating systems where iOS and Android dominate. Multiple chains may run synchronously in the future.\n5.2. Development Tools Frontend: Solidity (smart contracts) Chain, infrastructure: Mainly Golang, Rust, C++ (underlying chain algorithms), Python also used. web3.js is a collection of libraries that use HTTP or IPC to interact with local or remote Ethereum nodes.\nImplementation of smart contracts needs to consider:\nGas fees for each transaction Security 6. Opportunities and Challenges 6.1. Challenges Environment and ecosystem: Currently in China there\u0026rsquo;s no widely recognized public chain. Major giants each have their own chains, but essentially they\u0026rsquo;re all clones of Ethereum, running in their own IDCs. Not decentralized. Need a credible public blockchain that can economically, quickly, and environmentally process chain transactions. Technology: POW-based approach causes large computational volume, not environmentally friendly. Transaction speed is reduced. Laws and regulations: Since decentralization inherently conflicts with regulation, there are currently no good laws, regulations, or supervision policies. This brings uncertain risks for the future. 6.2. Opportunities for Companies Currently, Web3 is in its early stages:\nMany Web2 applications will gradually migrate to Web3 In infrastructure, it\u0026rsquo;s a fragmented landscape 6.3. Opportunities for Developers Smart contract development and blockchain-related development are hot areas. There are also many new DAO organizations that distribute rewards based on work. You can join popular open source project DAOs, have opportunities to get airdrops, and earn tokens through contributing. 6.4. Opportunities for Investors (Speculators) Investing in cryptocurrency, NFT works, stories of overnight wealth are many on YouTube.\n7. FAQ 7.1. What is mint? Minting is the act of artists or collectors (project parties and users) initially issuing NFTs on the blockchain. It\u0026rsquo;s recording a token ID and its owner\u0026rsquo;s address on the blockchain.\n7.2. What is the metaverse? Different institutions have different definitions; some see it as the ultimate version of Web3. Some just see it as enhanced virtual reality.\n7.3. Why can the US sanction Russian Bitcoin investments? Related reports:\nRecently, Coinbase, the largest US cryptocurrency exchange, said it has blocked more than 25,000 wallet addresses related to Russian individuals or entities, believing these individuals or entities engaged in illegal activities. According to 2021 data, the blocked wallet addresses represent 0.2% of Coinbase\u0026rsquo;s 1.4 million monthly trading users. Additionally, Coinbase shared these wallet addresses with the US government to help enforce sanctions, including prohibiting some Russians and companies from financial transactions.\nThe reason:\nCoinbase is a centralized exchange regulated by the US, does KYC, can block Russian users Similarly, Binance is also a centralized exchange, does KYC on customers, can block Chinese users From reports, Coinbase can identify Russian customers through its KYC data, then prohibit such customers from using Coinbase services. \u0026ldquo;Blocked wallet addresses\u0026rdquo; means cannot transfer crypto in or out of these wallet addresses through Coinbase. But the assets in those wallet addresses still exist. They can still trade in decentralized ways or on other exchanges.\n7.4. How is the total number of Bitcoin estimated? It\u0026rsquo;s calculated based on block rewards. A block is generated every 10 minutes, initially each block rewards 50 BTC, after 4 years 25 BTC, halving every 4 years. So approximately 21 million in total.\nLater in mining, each block reward decreases, but miners can still get commissions from each transaction in the block. So there\u0026rsquo;s still incentive to mine.\n","permalink":"https://blog.thefreemeal.com/en/posts/2022-03-27-web3/","summary":"\u003cblockquote\u003e\n\u003cul\u003e\n\u003cli\u003eWhat is NFT? What is DAO? DeFi? GameFi? SocialFi?\u003c/li\u003e\n\u003cli\u003eWhat\u0026rsquo;s in a blockchain wallet?\u003c/li\u003e\n\u003cli\u003eWhat opportunities does Web 3 present for companies? What opportunities for programmers?\u003c/li\u003e\n\u003cli\u003eWhy can the US block Russian users\u0026rsquo; crypto transactions?\u003c/li\u003e\n\u003c/ul\u003e\u003c/blockquote\u003e\n\u003ch2 id=\"1-web1-web2-web3\"\u003e1. Web1, Web2, Web3\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003eWeb1: Main application is creating websites to publish information.\u003c/li\u003e\n\u003cli\u003eWeb2: In addition to Web1, there\u0026rsquo;s interaction. Consumers of information also create content, which is consumed by platforms (viewing ads to generate revenue for platforms).\u003c/li\u003e\n\u003cli\u003eWeb3: Combines the decentralization and community management of Web1 with the rich interactive features of Web2. The biggest feature is that users and developers can own content. Web3 is token-driven.\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eAccording to \u003ca href=\"https://www.alexdphan.com/research/library-of-web3/web3\"\u003eChris Dixon @ a16z\u003c/a\u003e, Web3 is a network jointly owned by developers and users, driven by tokens.\u003c/p\u003e","title":"About Web 3.0"},{"content":" Diagrams extracted from the book \u0026ldquo;Underlying Logic: Seeing Through the World\u0026rsquo;s Bottom Line\u0026rdquo;. Explanations of the diagrams include my own understanding.\n1. The Underlying Logic of Right and Wrong 1.1. Don\u0026rsquo;t Dwell on It \u0026ldquo;Adults\u0026rsquo; world has no right or wrong, only interests.\u0026rdquo; When you obsess over right and wrong, you\u0026rsquo;ve already missed the point. Don\u0026rsquo;t dwell, don\u0026rsquo;t纠缠. Laugh it off.\nJurists and economists are professions; they study right and wrong for academic research.\nOrdinary people in life are the subjects of economists\u0026rsquo; research, economically rational people, merchants. It would be too pedantic for merchants to analyze problems from the perspective of jurists/economists.\n2. The Underlying Logic of Problem Solving 2.1. Elements and Relationships This diagram is about the composition of a system. It includes elements (a series of noun concepts) and relationships between elements.\nFor example, in a business system, there are elements like product, traffic, conversion, retention, profit, etc.\nCausal chain: Good product experience, increased retention Reinforcement loop: Good product experience → increased retention → increased profit → more R\u0026amp;D investment → even better product experience\u0026hellip;, or reverse reinforcement: poor product experience Regulatory loop: Traffic increases to a certain point, product experience worsens Lag effect: There\u0026rsquo;s a lag between traffic increase and retention increase (the conversion process) 2.2. Logical Deduction This diagram is about proving facts - prove existence, not non-existence; prove existence with examples. When expressing views, don\u0026rsquo;t overgeneralize. General conclusions can only be reached through proof and reasoning, not casual statements like \u0026ldquo;Isn\u0026rsquo;t this obvious?\u0026rdquo; or \u0026ldquo;Everyone thinks\u0026hellip;\u0026rdquo;\n2.3. Seeing the Essence This diagram is about grasping the essence. Restaurants near office buildings have good business - the essence is traffic; being close means more traffic. When everyone starts ordering delivery, the traffic changes. Corresponding competitive strategies need adjustment. If you can\u0026rsquo;t grasp the essence, when traffic changes, simply focusing on food taste and service won\u0026rsquo;t help much.\nThe book has an example about Microsoft managing suppliers.\nThe company provides lunch and dinner for employees. More people usually eat lunch than dinner because not everyone works overtime at night, so lunch suppliers make more profit. It\u0026rsquo;s just that sometimes lunch is terrible\u0026hellip; Imagine you\u0026rsquo;re the person in charge - how would you handle it? Send supervisors? Change chefs periodically? Ask them to update menus? Microsoft came up with a system:\nSelect 2 suppliers, one for lunch, one for dinner; Every 3 months do a satisfaction survey: do you prefer lunch or dinner? If more people prefer dinner, swap the lunch and dinner suppliers; If lunch wins for 6 consecutive months, replace the dinner supplier. The core of this system is introducing a competitive mechanism between lunch and dinner suppliers.\n3. The Underlying Logic of Individual Evolution 3.1. Ability, Efficiency, and Leverage This diagram says that success in life\u0026rsquo;s business model is determined by the product of three factors:\nAbility: Requires time and energy investment, plus good methods (deliberate practice). Efficiency: Need to manage energy, make trade-offs, and have good tools. Leverage: Use the power of teams, technology, capital, and personal influence to amplify. It particularly mentions that writing and speaking abilities are very important in personal influence.\n3.2. Lower Your Posture This diagram is about lowering your posture when communicating with others. This makes it easier to get help from others. Have an objective evaluation of yourself; don\u0026rsquo;t worry too much about others\u0026rsquo; opinions.\n4. The Underlying Logic of Understanding Others 4.1. Dopamine, Endorphins, and Serotonin This diagram explains that physiologically, humans have three sources of pleasure:\nDopamine: Comfort from satisfaction Endorphins: Exercise compensation Serotonin: Sense of security from carbohydrates and sugar Corresponding to the business world, you can design reward mechanisms:\nComparative advantage: WeChat step rankings, your boot speed beats 90% of users, giving users a sense of achievement Show off: Smart band app\u0026rsquo;s share to Moments feature, big LOGO on LV Dopamine is a reward system for humans; it doesn\u0026rsquo;t directly produce pleasure but gives humans an expectation of reward - we can also call it addiction. Once humans become addicted to something, they can\u0026rsquo;t help but replicate it to get pleasure. In products, visualizing user expectations and presenting them in various ways can stimulate users to feel pleasure. A typical example is shopping carts.\nEndorphins are substances that give you a sense of achievement; endorphin production is very stingy - it requires a lot of hard work and effort to possibly produce and give a sense of achievement. Applying this to products means building an achievement system for users, with three key points:\nSet some challenges for users; Strongly display these achievements in the product; Leverage some real-world achievements and project them into the product. Dopamine is a substance produced when people satisfy their needs, generally having significant impact on mood. Endorphins are \u0026ldquo;sweet after hardship\u0026rdquo; substances, generally produced after the body experiences pain; people who don\u0026rsquo;t exercise regularly are more likely to produce them.\nWhile both endorphins and serotonin promote mood, serotonin has a smaller impact, causing happiness and security. The pleasure from endorphins is stronger, depending on the amount of endorphins in blood flow, producing feelings similar to ecstasy and happiness. Endorphins at low levels can also produce slight relaxation and happiness, somewhat similar to serotonin\u0026rsquo;s effect.\nSerotonin secretion is greatly affected by food intake and can be induced by carbohydrate-based foods (like pasta and grains). Releasing serotonin after eating these starches produces calmness, comfort, and health. After overconsuming carbohydrates, too much serotonin is released making the eater feel sleepy. However, lack of serotonin can cause stress, anxiety, frustration, and aggression, somewhat similar to endorphin deficiency. While some drugs can induce serotonin secretion, they are easily addictive. This is also why the body craves starchy foods or drugs when serotonin levels are low.\n5. The Underlying Logic of Social Collaboration 5.1. Career and Short-term Interests This diagram is about the relationship between employees and companies. The X-axis is employees\u0026rsquo; actual views on long-term interests (career) and short-term interests. The Y-axis is the company\u0026rsquo;s expectations for employees.\nFirst quadrant: mostly startup companies; companies have dreams but hire employees who mostly focus on short-term returns. Third quadrant: companies are mature, less attractive to ambitious employees. Second quadrant: for example, housekeeping companies. \u0026ldquo;Don\u0026rsquo;t talk about beautifying the city, pay by the hour.\u0026rdquo; Fourth quadrant: employees identify with their current industry, and the company\u0026rsquo;s state has prospects, willing to struggle together with the company. Including giving up short-term interests. Different types of companies need clear positioning - whether to operate in the second or fourth quadrant.\n5.2. Sources of Profit This diagram explains the three components of profit:\nTrend dividends won\u0026rsquo;t last, gradually disappearing as followers enter. Social wages are generally thin, hard-earned money. Only innovative profit has a chance to make money. This diagram also echoes the principle of wealth distribution. The weight of wealth distribution depends on scarcity (trend dividends are because fewer companies enter; innovative profit is because only you can reduce costs through innovation).\n6. Other The book also mentions:\nExponential growth: Requires making products with zero marginal cost. Fairness and efficiency: Why does the country do redistribution, why protect vulnerable groups\u0026hellip; Long-termism: Do things that can accumulate Game theory: Decisions that affect others require considering game theory. Potential energy: To counteract the lucky element of success, follow the trend (be in an industry at the right time), grasp key directions (strategy) Contacts: Depends on people you can help, not people who can help you. \u0026ldquo;Be useful.\u0026rdquo; What, Why, How: Understanding the reason (WHY) enables unity of knowledge and action \u0026hellip; The book as a whole doesn\u0026rsquo;t have strong coherence from front to back; it\u0026rsquo;s a collection of articles. But it\u0026rsquo;s still a good points. book with many knowledge\n","permalink":"https://blog.thefreemeal.com/en/posts/2022-03-20-fundamental-logic/","summary":"\u003cblockquote\u003e\n\u003cp\u003eDiagrams extracted from the book \u0026ldquo;Underlying Logic: Seeing Through the World\u0026rsquo;s Bottom Line\u0026rdquo;. Explanations of the diagrams include my own understanding.\u003c/p\u003e\u003c/blockquote\u003e\n\u003ch2 id=\"1-the-underlying-logic-of-right-and-wrong\"\u003e1. The Underlying Logic of Right and Wrong\u003c/h2\u003e\n\u003ch3 id=\"11-dont-dwell-on-it\"\u003e1.1. Don\u0026rsquo;t Dwell on It\u003c/h3\u003e\n\u003cp\u003e\u003cimg alt=\"picture 1\" loading=\"lazy\" src=\"/images/1647794513940.jpg\"\u003e\u003c/p\u003e\n\u003cp\u003e\u0026ldquo;Adults\u0026rsquo; world has no right or wrong, only interests.\u0026rdquo; When you obsess over right and wrong, you\u0026rsquo;ve already missed the point. Don\u0026rsquo;t dwell, don\u0026rsquo;t纠缠. Laugh it off.\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003eJurists and economists are professions; they study right and wrong for academic research.\u003c/p\u003e","title":"Diagrams from 'Underlying Logic'"},{"content":" Directus APP uses Vue 3, TypeScript, built with Vite. This article records front-end related knowledge learned during the evaluation of the Directus APP.\n1. Vite Build tool, similar to webpack.\n1.1. Principle Uses the browser\u0026rsquo;s ES6 module loading function, so front-end can load JS modules on demand. During development, bundling is not needed.\n\u0026lt;script type=\u0026#34;module\u0026#34; src=\u0026#34;./foo.js\u0026#34;\u0026gt;\u0026lt;/script\u0026gt; The above module-type loaded foo.js can also import other modules and export. Browsers recognize import and export commands in JS and will send requests to the backend to load on demand.\n1.2. Application Configure dev server in vite.config.ts, for example, listening on port 8080, with API requests sent to port 8055.\nserver: { port: 8080, proxy: { \u0026#39;^/(?!admin)\u0026#39;: { target: process.env.API_URL ? process.env.API_URL : \u0026#39;http://localhost:8055/\u0026#39;, changeOrigin: true, }, }, fs: { allow: [searchForWorkspaceRoot(process.cwd()), \u0026#39;/admin/\u0026#39;], }, }, 2. Vue A way to organize JS/CSS/HTML. The runtime environment (JS library) provides data binding, changing state updates the display, making it easy for JS to update pages.\n2.1. Basic Concepts data: A function that returns the component instance\u0026rsquo;s data object. props: An array or object. These are configurable parameters when the parent component calls this component. Both data and props can be accessed in the template. The difference is:\ndata is not passed from the parent component; it\u0026rsquo;s private to the child component and is readable and writable. Data in props is all passed from parent to child and is read-only. data stores component state; components without data are stateless components.\nmixin: To be DRY (Don\u0026rsquo;t Repeat Yourself) and reduce duplication, extract common parts of component scripts (data, props, methods, etc.) into a separate object. Then mix it into the component. setup function: Used to replace mixin, implementing Composition API. Its input is props and context, and output is an object. All properties of that object can be accessed in the component. 2.2. Component Lifecycle 3. HTML 3.1. data- Custom Attributes In HTML generated by Vue, you see many divs with data-v-xxxx attributes. These are produced by scoped CSS. The same component generates the same data-v value.\nThe data-* attribute adds custom information to a \u0026lt;div\u0026gt; element. The * part is replaced with a lowercase string, such as data-id, data-source, data-category, etc. A \u0026lt;div\u0026gt; element can have any number of data-* attributes, each with their own name.\n\u0026lt;div id=\u0026#39;strawberry-plant\u0026#39; data-fruit=\u0026#39;12\u0026#39;\u0026gt;\u0026lt;/div\u0026gt; \u0026lt;script\u0026gt; // \u0026#39;Getting\u0026#39; data-attributes using getAttribute var plant = document.getElementById(\u0026#39;strawberry-plant\u0026#39;); var fruitCount = plant.getAttribute(\u0026#39;data-fruit\u0026#39;); // fruitCount = \u0026#39;12\u0026#39; // \u0026#39;Setting\u0026#39; data-attributes using setAttribute plant.setAttribute(\u0026#39;data-fruit\u0026#39;,\u0026#39;7\u0026#39;); // Pesky birds \u0026lt;/script\u0026gt; This custom attribute is defined in the HTML5 standard and can be accessed in JS.\n4. CSS 4.1. Basic Concepts Basic format is:\np { font-family: verdana; font-size: 20px; } Where p is the selector, and the following braces contain a list of properties and values.\nSelectors select HTML elements based on certain rules. Basic ones include:\nAll elements: asterisk Tag names: body, a, p, h2\u0026hellip; Class: dot ID: hash Some combinations:\nMultiple element selector: E, F - multiple selectors separated by commas Descendant selector: E F - matches all F selectors inside selector E. For example, .box h2 - all h2 inside elements with class box Child selector: E \u0026gt; F - difference from above is it only matches direct children. Only matches one level. Descendants match multiple levels. Adjacent sibling selector: E + F - E and F are siblings and are adjacent; then match F. Attribute selector: Uses brackets, selects based on element attribute name/value.\nInheritance: Styles on outer elements are automatically inherited by inner elements. If inner element styles conflict with outer, the inner takes effect.\nPositioning:\nfixed: Fixed, relative to browser window position. Followed by coordinates. Doesn\u0026rsquo;t take up standard document flow space, covers standard document flow. relative: Relative, relative to original position absolute: Absolute, coordinates are relative to positioned ancestor elements. If no ancestor is positioned, it\u0026rsquo;s the same as fixed. Doesn\u0026rsquo;t take up standard document flow space, covers standard document flow. 4.2. SCSS A new version of Sass, a language that generates CSS. Similar to CSS3, adding variables, inheritance, etc. Convenient for generating CSS.\nSee https://www.jianshu.com/p/6bb174c79172 The ampersand (\u0026amp;) symbol is the parent element selector.\n4.3. Application in Directus Below is the CSS for the left navigation bar on the main screen. On mobile screens, it\u0026rsquo;s not displayed by default; only clicking the top-left menu shows it. On PC, there\u0026rsquo;s no menu button, so it\u0026rsquo;s displayed by default. Looking at the implementation, the leftmost control moves 100% to the left to leave the screen, achieving hiding. The rightmost does the same, moving 100% to the right to hide.\n#navigation { position: fixed; top: 0; left: 0; z-index: 50; display: flex; height: 100%; font-size: 0; transform: translateX(-100%); //Hidden by default transition: transform var(--slow) var(--transition); \u0026amp;.is-open { transform: translateX(0); //Shown } \u0026amp;:not(.is-open) { .module-nav-resize-handle { display: none; } } .module-nav { position: relative; display: inline-block; width: 220px; height: 100%; font-size: 1rem; background-color: var(--background-normal); \u0026amp;-content { --v-list-item-background-color-hover: var(--background-normal-alt); --v-list-item-background-color-active: var(--background-normal-alt); height: calc(100% - 64px); overflow-x: hidden; overflow-y: auto; } } .module-nav-resize-handle { position: absolute; top: 0; right: -2px; bottom: 0; width: 4px; background-color: var(--primary); cursor: ew-resize; opacity: 0; transition: opacity var(--fast) var(--transition); transition-delay: 0; user-select: none; touch-action: none; \u0026amp;:hover, \u0026amp;:active { opacity: 1; } \u0026amp;.active { transition-delay: var(--slow); } } @media (min-width: 960px) { position: relative; transform: none; //Shows when greater than 960px \u0026amp;:not(.is-open) { .module-nav-resize-handle { display: block; } } } } 5. References https://v3.cn.vuejs.org/guide/introduction.html embedding-custom-non-visible-data-with-the-data-attributes ","permalink":"https://blog.thefreemeal.com/en/posts/2022-03-19-vue/","summary":"\u003cblockquote\u003e\n\u003cp\u003eDirectus APP uses Vue 3, TypeScript, built with Vite.\nThis article records front-end related knowledge learned during the evaluation of the Directus APP.\u003c/p\u003e\u003c/blockquote\u003e\n\u003ch2 id=\"1-vite\"\u003e1. Vite\u003c/h2\u003e\n\u003cp\u003eBuild tool, similar to webpack.\u003c/p\u003e\n\u003ch3 id=\"11-principle\"\u003e1.1. Principle\u003c/h3\u003e\n\u003cp\u003eUses the browser\u0026rsquo;s ES6 module loading function, so front-end can load JS modules on demand. During development, bundling is not needed.\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-html\" data-lang=\"html\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026lt;\u003cspan style=\"color:#f92672\"\u003escript\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003etype\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;module\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003esrc\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;./foo.js\u0026#34;\u003c/span\u003e\u0026gt;\u0026lt;/\u003cspan style=\"color:#f92672\"\u003escript\u003c/span\u003e\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cblockquote\u003e\n\u003cp\u003eThe above module-type loaded foo.js can also import other modules and export. Browsers recognize import and export commands in JS and will send requests to the backend to load on demand.\u003c/p\u003e","title":"Front End: Vue3, Vite, Css..."},{"content":"1. Collection A Collection corresponds to a table in the database. Directus collections have some unique concepts, such as alias fields and sort attributes.\n1.1. Alias Fields that do not map directly to an actual database column are called \u0026ldquo;alias\u0026rdquo; fields. For example, presentation fields (such as dividers and groups) and certain relational types that display data stored elsewhere (such as One-to-Many (O2M) and Many-to-Many (M2M)).\nO2M, M2M, M2A, etc., don\u0026rsquo;t have actual columns in the table. They are called alias fields.\nAlthough alias doesn\u0026rsquo;t have actual database table columns, they are recorded in the direct_fields table. For example, the element field of the pages collection above is an M2A type alias.\nThe direct_collections table describes all tables managed by Directus in the system, and direct_fields describes all fields of all tables. Through this non-intrusive method, the original table structure in the database can remain unchanged.\n1.2. Sort Attribute If, when creating a collection, you choose to enable sort support, a sort column will be added to the table. This column supports manually dragging to adjust the order of records in the app. The principle is simple - a number-type sort column is added to the table. When dragging, the values in this column change based on the record\u0026rsquo;s position.\n1.3. Share An app feature that can generate a link from a record in a model and send it to others for read-only access. You can set a password, expiration date, and which identity to read as.\nIn the database, Directus has a specific table, directus_shares, to manage all shares. 2. Relationship Relationships between tables. Directus supports the following four types.\n2.1. M2M Implements many-to-many relationships through a junction table. For example, between Product and Tag.\n2.2. O2M One-to-many relationship, for example between order and order row. In the order row model, there needs to be a foreign key to determine which order the order row belongs to. You can add a foreign key order in the order row, whose value is the id from the orders table.\n2.3. M2O Same as O2M, just viewed from the order row\u0026rsquo;s perspective looking at the order.\n2.4. M2A Similar to M2M, the difference is that it can represent a collection\u0026rsquo;s relationship to multiple collections. In the junction table, besides storing ids, it also stores the collection name. For example, a Page may include header, footer, and section elements. The junction table below shows that page with id 1 includes footer with id 1, header with id 1, and section with id 2.\nUsing M2A relationships, you can conveniently add different items to a page in the app. This relationship is also called a replicator.\nIf you remove the collection column from the image above, M2A degrades to an M2M relationship, which can only represent relationships between two specific collections.\nM2A stands for Many to Any. It\u0026rsquo;s called \u0026ldquo;Any\u0026rdquo; because the relationship table stores both collection name and id, so theoretically it can represent any element from any collection.\n3. Internationalization (I18N) Solutions 3.1. Multi-language for Model Names and Field Names Model names can be multi-language. Add \u0026ldquo;Collection Name Translations\u0026rdquo; in the model configuration.\nField names can be multi-language. Configure Field Name Translations in Model/Field.\nMulti-language data for model names and field names are stored in the database as JSON strings. Translations for all languages are stored together.\n3.2. Multi-language for Record Content Content elements within a model can be multi-language through a translations collection. The principle is to put all fields requiring multilingual support into a translations table. This table contains all columns requiring translations and a language code column (with values like zh-CN, en-US, etc.). This way, for each row in the original model, there will be corresponding rows in the translations model - one for Chinese, one for English, etc. - to store translated data. https://docs.directus.io/configuration/data-model/#creating-translated-multilingual-fields\nEdit the data in the Languages model and keep only Chinese and English; then in the app, only Chinese and English translations will be displayed.\nAs shown in the image, the product collection has three fields requiring multi-language support: description, longtext, and pic. From the image, images also support multi-language (different images for different languages).\nThe most intuitive approach to implement multi-language is adding columns in the table - one for Chinese, one for English, one for Spanish, etc. However, this requires changing the table structure when adding new languages, which has poor scalability. Directus\u0026rsquo;s implementation has better scalability - one structure supports all languages.\n","permalink":"https://blog.thefreemeal.com/en/posts/2022-03-13-directus/","summary":"\u003ch2 id=\"1-collection\"\u003e1. Collection\u003c/h2\u003e\n\u003cp\u003eA Collection corresponds to a table in the database. Directus collections have some unique concepts, such as alias fields and sort attributes.\u003c/p\u003e\n\u003ch3 id=\"11-alias\"\u003e1.1. Alias\u003c/h3\u003e\n\u003cblockquote\u003e\n\u003cp\u003eFields that do not map directly to an actual database column are called \u0026ldquo;alias\u0026rdquo; fields. For example, presentation fields (such as dividers and groups) and certain relational types that display data stored elsewhere (such as One-to-Many (O2M) and Many-to-Many (M2M)).\u003c/p\u003e\u003c/blockquote\u003e\n\u003cp\u003eO2M, M2M, M2A, etc., don\u0026rsquo;t have actual columns in the table. They are called alias fields.\u003c/p\u003e","title":"Directus"},{"content":" Hip drive is suitable for long distances and is relatively more energy-efficient compared to shoulder drive.\nCatch (Hold Water) Relax the shoulders, and form a resistance surface for pushing water with the inner side (the side not touched by the sun) of the entire arm. The push water resistance surface includes the inner upper arm, inner forearm, and inner palm. Keep elbows appropriately bent at about 100 degrees. Relax shoulders and armpits, but keep core (abdomen) tight, and maintain a straight body line.\nThe arm posture is similar to climbing a wall, with the elbow slightly higher. When energy is good, the catch can reach ear level; when tired, keep it lower.\nPower Transfer Hip rotation and kicking work together to drive the stroke. Hip rotation drives the kick, and the kick further provides support for the rotation (by pressing the entire thigh, calf, and instep against the water to support the same-side hip lifting).\nThe hip lifting further transmits through the torso to the upper body, driving the catching arm to swing backward.\nThe overall feeling of power transfer is similar to the image above. During power transfer:\nKeeping the abdomen (rectus abdominis, external oblique) moderately tense is critical, otherwise the rotational force gets absorbed by body twist. The joints on the power-generating side (shoulder on the catching side, hip on the kicking side) should be relaxed - relaxed to be able to swing out. During land drills, the center of gravity should be completely on the non-power-generating side. The feeling while swimming:\nHip rotates while the two legs exchange positions up and down to complete the kick. During kicking, the legs stay basically straight, with the inner thighs lightly touching to reduce drag. The upward-rotating hip, by pulling the latissimus dorsi, swings the catching arm backward, swings it out of the water, then swings it forward to form the entry position again. When swinging the arm backward, there\u0026rsquo;s also a feeling of the body rotation pulling the catching-side elbow inward. ","permalink":"https://blog.thefreemeal.com/en/posts/2022-03-12-swim-hip-driven/","summary":"\u003cblockquote\u003e\n\u003cp\u003eHip drive is suitable for long distances and is relatively more energy-efficient compared to shoulder drive.\u003c/p\u003e\u003c/blockquote\u003e\n\u003ch2 id=\"catch-hold-water\"\u003eCatch (Hold Water)\u003c/h2\u003e\n\u003cp\u003eRelax the shoulders, and form a resistance surface for pushing water with the inner side (the side not touched by the sun) of the entire arm. The push water resistance surface includes the inner upper arm, inner forearm, and inner palm. Keep elbows appropriately bent at about 100 degrees. Relax shoulders and armpits, but keep core (abdomen) tight, and maintain a straight body line.\u003c/p\u003e","title":"Hip Driven Freestyle"},{"content":"1. Docker The client operates images and containers through the docker daemon running on the host, and the registry provides image publishing and downloading (similar to npm and pip).\nA Docker image is a special read-only file system that provides programs, libraries, resources, configuration files, and other files required for container runtime. It also contains some configuration parameters prepared for runtime (such as anonymous volumes, environment variables, users, etc.). The image does not contain any dynamic data, and its content will not change after being built.\nA Container is a running instance of an image, running as a special process on the host machine. One image can have multiple containers.\nContainer adds a read-write layer on top of the Image. After doing some write operations inside the container, you can commit the read-write layer to generate a new image.\nThe above image omits the init layer that stores configuration file information. The init layer is located between the image and container layers in the above image. It stores some directories/files that need to be written when running the operating system, such as the /etc directory. The init layer is not committed. Because it\u0026rsquo;s unnecessary - the init layer content is automatically generated every time the read-only layer runs.\n1.1. Commands # d d d # d d d d d d d d d d o o o o o o o o o o o o o I c c c C c c c c c c c c c c m k k k o k k k k k k k k k k a e e e n e e e e e e e e e e g r r r t r r r r r r r r r r e a p i r i p r r s r r p c a e u m m n s u u t m m o p t x l a i e n n a r t e l g r - r \u0026lt; $ t l a c e a - - t C ( o c h s \u0026lt; i d O d \u0026lt; c h - e I t \u0026lt; N o C a i l M f c T c O l \u0026lt; t l A c l o A k N _ c o G e a n I e T f o - E n s t N r A i n d w t k a E I l t i o I o - i R c N e a r r D s h n o E _ i e l \u0026gt; e e I n R n n c d l r D t a e t l _ \u0026gt; a I m r u o n i D e s - a n \u0026gt; n - D V D V R w m e a s o i e i u o e r 4 m q w e l e n r \u0026gt; D V 9 e l n w e w l e l i f \u0026gt; i l t i d l s e 7 t o l e a n e w 9 e a o l t R t - 6 F d c a l e R e e a p 0 o / a n r u s q o e r b h l c a n t c ) r b i e i o c a o t 7 c n l i m n t i r n e o / l m a t i n t t m 4 n s o a g a v a D a : t h - g e i e b i e p / a w e , n l a n l p d i o s e y c e e i o n E r c r k r t n c e x l a s g e g k r e d n r e s c o a i r u i u u l n _ s t m s n l f f t e a e d o i a g c r l r s e j o m e t h u n a _ e f s t t n d i r t a i a n o i o m w s m t n n e i i h e t d r e r h e e s C g f o d c i i p o o s r y c n t s k t r t f e a y i r i f l n e e r e w u r i n d n / n i t s a g o t m i a e t d r d s o t c , d k i e c r r a e n c t a u t s t - a s c q h l i t t o e c o n s o l e t o v i e w o u t p u t . 1.2. Dockerfile A configuration file used to build images, starting from a base image, running a series of configuration commands to get another image\n2. Docker Compose A tool for defining, running, and managing multiple containers. After running, you can also use previous docker commands to operate containers.\nd d d d d d d d d o o o o o o o o o c c c c c c c c c k k k k k k k k k e e e e e e e e e r r r r r r r r r - - - - - - - - - c c c c c c c c c o o o o o o o o o m m m m m m m m m p p p p p p p p p o o o o o o o o o s s s s s s s s s e e e e e e e e e u u p l p s s r d p p s o o t t u o g r a o n w - s t r p n d t d d c i i c a r r a c e e c h c V c h e t S S i t e u t t e u s o a w s p r s t l 8 h a o 0 l a g 5 l n s 5 d s f e r o r u r R v n u i e n c c a S e o c e s s n h e h t a a s w o n i e h n d n r i e v c t d r i h h e s c e l e h e i o d t n s i e t r b e c a p c o c o t n k r u t g t s a r i o t s n u h e e n e r r d v s d i i c r e e ' c s t u c s o n s t e a r i v n i e c r e ' s c o n t a i n e r 8 0 5 5 i s b o u n d t o 3. Examples 3.1. Docker 3.1.1. Directus The following maps two volumes, reads environment variables, then runs directus interactively, with container name directus-sqlite.\nd o c k e r r u n - i t - e n v - f i l e = . / e n v _ s q l i t e $ P W D / : / d i r e c t u s / d a t a b a s e $ P W D / u p l o a d s : / d i r e c t u s / u p l o a d s - n a m e = \" d i r e c t u s - s q l i t e \" d i r e c t u s / d i r e c t u s : l a t e s t Where the environment variable file env_sqlite\nDB_CLIENT=\u0026#34;sqlite3\u0026#34; DB_FILENAME=\u0026#34;/directus/database/data.db\u0026#34; RATE_LIMITER_ENABLED=true RATE_LIMITER_POINTS=50 RATE_LIMITER_DURATION=1 RATE_LIMITER_STORE=memory CACHE_ENABLED=true CACHE_TTL=\u0026#34;30m\u0026#34; CACHE_NAMESPACE=\u0026#34;directus-cache\u0026#34; CACHE_AUTO_PURGE=true # memory | redis | memcache CACHE_STORE=memory ASSETS_CACHE_TTL=\u0026#34;30m\u0026#34; STORAGE_LOCATIONS=\u0026#34;local\u0026#34; STORAGE_LOCAL_DRIVER=\u0026#34;local\u0026#34; STORAGE_LOCAL_ROOT=\u0026#34;/directus/uploads\u0026#34; KEY=\u0026#34;xxxxxxx-xxxxxx-xxxxxxxx-xxxxxxxxxx\u0026#34; SECRET=\u0026#34;abcdef\u0026#34; ACCESS_TOKEN_TTL=\u0026#34;15m\u0026#34; REFRESH_TOKEN_TTL=\u0026#34;7d\u0026#34; REFRESH_TOKEN_COOKIE_SECURE=\u0026#34;false\u0026#34; REFRESH_TOKEN_COOKIE_SAME_SITE=\u0026#34;lax\u0026#34; REFRESH_TOKEN_COOKIE_NAME=\u0026#34;directus_refresh_token\u0026#34; CORS_ENABLED=\u0026#34;true\u0026#34; CORS_ORIGIN=\u0026#34;true\u0026#34; CORS_METHODS=GET,POST,PATCH,DELETE CORS_ALLOWED_HEADERS=Content-Type,Authorization CORS_EXPOSED_HEADERS=Content-Range CORS_CREDENTIALS=\u0026#34;true\u0026#34; CORS_MAX_AGE=18000 AUTH_PROVIDERS=\u0026#34;dingtalk\u0026#34; AUTH_DINGTALK_DRIVER=\u0026#34;oauth2\u0026#34; AUTH_DINGTALK_CLIENT_ID=\u0026#34;....\u0026#34; AUTH_DINGTALK_CLIENT_SECRET=\u0026#34;c6rCTM1nmIm-....\u0026#34; AUTH_DINGTALK_AUTHORIZE_URL=\u0026#34;https://fb.....cn/apipro/oauth_dingtalk/auth\u0026#34; AUTH_DINGTALK_ACCESS_URL=\u0026#34;https://fb.....cn/apipro/oauth_dingtalk/access_token\u0026#34; AUTH_DINGTALK_PROFILE_URL=\u0026#34;https://fb.....cn/apipro/oauth_dingtalk/profile\u0026#34; AUTH_DINGTALK_ALLOW_PUBLIC_REGISTRATION=\u0026#34;true\u0026#34; AUTH_DINGTALK_DEFAULT_ROLE_ID=\u0026#34;86a3338c-26a5-447d-bfbd-f938ee2c3c40\u0026#34; AUTH_DINGTALK_ICON=\u0026#34;alipay\u0026#34; EXTENSIONS_PATH=\u0026#34;./extensions\u0026#34; EMAIL_FROM=\u0026#34;austin@....com\u0026#34; EMAIL_TRANSPORT=\u0026#34;smtp\u0026#34; EMAIL_SMTP_POOL=false EMAIL_SMTP_HOST=\u0026#34;smtp........com\u0026#34; EMAIL_SMTP_PORT=465 EMAIL_SMTP_SECURE=true # Use TLS EMAIL_SMTP_IGNORE_TLS=false EMAIL_SMTP_USER=\u0026#34;austin@....com\u0026#34; EMAIL_SMTP_PASSWORD=\u0026#34;....\u0026#34; Later, you can use docker start to start directus.\nM C 7 M d M a O 8 a i a c N a c r c B T c B e B o A c o c o o I 6 o t o k N c k u k - E 4 - s - P R 6 P - P r 4 r s r o I 4 o q o - D 0 - l - 2 2 i 2 : : t : a a e a p I d p p i M i i i A r w G e w w a E c a a n t n n g u g g x s x x u / u u $ d $ $ i d r d o e o c c c k t k e u e r s r : p l s s a t t a - e r a s t t d i r C \" e O d c M o t M c u A k s N e - D r s - q e l n i t t r e y p o i n t . s … \" C 6 R E m A i T n E u D t e s a g o S E T x A i T t U e S d ( 1 ) 5 m i n u t e s a g o P O R T S N d A i M r E e S c t u s - s q l i t e 3.1.2. Basic Operations M R M U l 2 e 5 5 a e D S d M R n M / / / 1 1 / / / 2 2 2 ^ 2 2 2 2 2 2 2 2 2 2 M C 1 M 9 M C 9 1 M t M C 9 1 M t M C 9 1 M t M 9 1 M C M R n M U U D D D D D D D M R M a E a s a 7 f b 5 7 f i t o a E g a d d d 0 0 d d d 0 0 0 C 0 0 0 0 0 0 0 0 0 0 a O 2 a c a O c 2 a e a O c 2 a e a O c 2 a e a c 2 a O a E g a n n e e e e e e e a E a c P c i t 9 0 1 9 c c g a c c P i c o o o - - o o o 2 2 2 2 2 2 2 2 2 2 2 2 2 2 c N f c f c N f f c n c N f f c n c N f f c n c f f c N c P i c t t l l l l l l l c P c B O B n e a e 4 6 9 e e t k B O n B c c c l l c c c 2 2 2 0 2 2 2 2 2 2 2 2 2 2 B T 3 B b B T b 3 B d B T b 3 B d B T b 3 B d B b 3 B T B O n B a a e e e e e e e B O B o S o g s 0 4 8 0 9 2 s u e o S x o k k k i i k k k / / / 2 / / / / / / / / / / o A e o 0 o A 0 e o e o A 0 e o e o A 0 e o e o 0 e o A o S x o g g t t t t t t t o S o o I o t 2 2 f 2 6 1 t s r o I o e e e s s e e e 0 0 0 2 0 0 0 0 0 0 0 0 0 0 o I 6 o 2 o I 2 6 o r o I 2 6 o r o I 2 6 o r o 2 6 o I o I o g g e e e e e e e o I o k T k d : 0 e 4 7 3 e : : . k T k r r r t t r r r 3 3 3 / 3 3 3 3 3 3 3 3 3 3 k N e k d k N d e k _ k N d e k _ k N d e k _ k d e k N k T k e e d d d d d d d k T k - O - e 0 c 8 e 8 1 i - O - - - - e e - - - / / / 0 / / / / / / / / / / - E d - b - E b d - m - E b d - m - E b d - m - b d - E - O - d d : : : : : : : - O - P R P f P 7 d f 4 7 6 s D o P R P e e e n n e e e 0 0 0 3 0 0 0 0 0 0 0 0 0 0 P R b P 0 P R 0 b P c P R 0 b P c P R 0 b P c P 0 b P R P R P : : P R P r Y r a u 6 e 5 6 0 a h o / r Y r n n n - - n n n 8 8 8 / 8 8 8 8 8 8 8 8 8 8 r 2 r 5 r 5 2 r l r 5 2 r l r 5 2 r l r 5 2 r r Y r s s s s s s s r Y r o o u l a 9 2 9 b 5 a w l o o t t t o o t t t 0 o I b o 5 o I 5 b o a o I 5 b o a o I 5 b o a o 5 b o I o o n n h h h h h h h o o - - l l 7 6 e a 9 9 2 n i - - r r r n n r r r 0 0 0 8 0 0 0 0 0 0 0 0 0 0 - D b - e - D e b - r - D e b - r - D e b - r - e b - D - - g g a a a a a a a - - 2 2 t i : : : : : : 5 l b 2 2 y y y - - y y y 8 8 8 8 8 8 8 8 8 8 8 8 8 2 2 f 2 2 e 2 2 e 2 2 e 2 2 2 2 i i 2 2 2 2 2 2 2 2 2 : T : n 6 o r : T l : p p p i i p p p : : : 0 : : : : : : : : : : : : 4 : : n : : n : : n : : : T l : n n 5 5 5 5 5 5 5 : T : a A a t g P P P P P P : a a a A a a o o o p p o o o 5 5 5 8 5 5 5 5 5 5 5 5 5 5 a a b a a a a a a a a a A a a x x 6 6 6 6 6 6 6 a A a p G p a u u u u u u 1 d r p G t p i i i v v i i i 5 5 5 : 5 5 5 5 5 5 5 5 5 5 p I n p 0 p I n n p p I n n p p I n n p p p I p G t p : @ : : : : : : : p G p i i g f l l l l l l c e y i e i n n n 6 6 n n n : : : 5 : : : : : : : : : : i M g i 5 i M g g i i M g g i i M g g i i i M i e i l s 9 c a 0 7 1 5 i i p p : r l l l l l l 1 d / p s p t t t - - t t t 2 2 2 5 4 4 4 4 4 4 4 4 4 4 p A i p e p A i i p p A i i p p A i i p p p A p s p a h c 0 b f f f 0 p p r r o 3 n r t r . . . b b . . . 0 0 0 : 3 3 3 3 3 3 3 3 3 3 r G n r 3 r G n n r r G n n r r G n n r r r G r t r t a 1 6 e 0 d 9 8 r r o o l m c c c c c c b n g o o s s s y y s s s 4 o E x o e o E x x o o E x x o o E x x o o o E o o e 2 f 7 f c 3 0 9 o o x x a o o o o o o c e i x x h h h - - h h h [ [ [ 3 [ [ [ [ [ [ [ [ [ [ x x b x x x x x x x x x x s 5 f 2 c b f b a x x y y t l m m m m m m 6 w n y y : : : d d : : : n n n n n n n n n n n n n y y 6 y y y y y y y y y y t 6 2 b d d 1 8 a y y e i p p p p p p d e x e e o o o [ o o o o o o o o o o 0 : 0 b e c 8 1 3 w I w s b l l l l l l e r : w I 9 w / L L f f L L C t t t n t t t t t t t t t t w w e w w w w w w w w w I 9 w 1 a 6 7 c 1 0 c w I w a M a t r e e e e e e 5 l a M c a d o a a a a a o i i i o i i i i i i i i i i a a e a a a a a a a a a M c a c c f 6 b e 7 9 a M a n A n a t t t t t t d i a n A 1 n o o u u u u u n c c c t c c c c c c c c c c n C \" n d n C \" \" n n C \" \" n n C \" \" n n n C n A 1 n 1 9 0 4 3 6 0 7 n A n g G g r e e e e e e f m t g G f g c k n l l n n f e e e i e e e e e e e e e e g O / g 0 g O / / g g O / / g g O / / g g g O g G f g 3 c 0 9 8 f 3 a g G g x E x y c a e x E f x k i c t t c c i ] ] ] c ] ] ] ] ] ] ] ] ] ] x M d x a x M d d x x M d d x x M d d x x x M x E f x b 9 f b c 8 9 8 x E x u u / a g s u 2 u e n h . . h h g e u M o u 0 u M o o u u M o o u u M o o u u u M u 2 u c 4 a e 3 0 5 a u u $ I $ n 7 e t $ I 0 $ r g i s s i i u 1 1 1 ] 3 3 3 3 1 1 1 1 1 1 $ A c $ d $ A c c $ $ A c c $ $ A c c $ $ $ A $ I 0 $ 6 d b 3 5 9 a e $ I $ D g 4 D a - n h h n n r # # # 2 1 2 1 # # # # # # N k 3 N k k N k k N k k N D a d d 4 e 3 9 4 b D d d i 9 f d c d e f g : : g g a 1 1 1 1 # # # # 1 1 1 1 1 1 d D e d f d D e e d d D e e d d D e e d d d D d c d e 5 1 1 6 e 7 e d o o n c o o 9 o n o t : : : # 3 3 3 3 : : : : : : o r o 4 o r r o o r r o o r r o o o o 9 o 5 1 5 c f 4 9 a o c c x 3 r c c c t r / i i / / i 1 2 1 2 1 c - c d c - - c c - - c c - - c c c c c c d 7 0 8 3 d 9 c c k C k 7 k 9 k r d n n d d o u n b : : : : : s w s s w e k e k d k e e k k e e k k e e k k k k 9 k f 5 4 2 d d 5 8 k C e R e 7 n e e y s o f f o o n s g u i o i i o x e n e 8 e n n e e n n e e n n e e e C e e c e c 1 c 6 d a e R r E r 9 g r r p h c o o c c i i i s s s e e g r g g r i r t r 4 r t t r r t t r r t t r r r R r r a a 9 7 b 3 f d r E A 7 i o e k : : k k c n n l i i i x x n k n n k t r 6 r r r r r r E 7 7 3 e 5 1 e 0 A i T p 4 n i C 6 r i l e e e o g x t g g g i i a e a a e p y r f p y y s p y y s p y y s r p A i C 6 r 4 3 f b 0 d e c i T m E u 1 x m R u n l r G E r r m / n n n t t l r l l r s p u 8 s p p t s p p t s p p t m s T m R m 9 9 f 1 0 1 2 b m E a D l 4 : a E d n t - e n - - p t 1 b a a a i i o n a o o o o o a o o o E a E d i c 5 2 b 1 7 a 2 a D g l 6 l g A a . s e t a e e l h . y l l l n n 1 p 2 1 p - i e - i i p - i i r - i i p $ - D g A a 3 e b 6 7 f 8 d g e a a e T y - d c n t b n n e e 2 g g 7 r 9 7 r a n - d a n n a n n t a n n ( a e T y 7 d f 5 1 e e 0 e s n c t s E s i / r t i l t t t 1 g 2 2 2 o o t d f t t t t t t t t d s E s 9 7 9 5 c e 3 0 8 s S g 0 e D t i r n e r r e \" . c ( c ( ( c . 5 . . e … … t … … e o D c 9 4 d f f 7 5 9 S I i 5 s a i p y g d y y ; e 6 c ( ( ( S e S S e … n 9 … … n \" \" e \" \" n c S a 7 f 0 0 9 1 5 f I Z n 2 t g n s t p p p p S S S I s I I s \" g 7 \" \" d n d k T g 4 2 3 5 e 8 d 8 Z E x 5 o g s o t l o o r o 1 I I I G s G G s i 3 e d e e A o 1 5 0 4 e 0 a e E 6 i n i h i i i e l 0 G G G C I C n a r e r r T 4 9 c 6 0 1 3 7 7 n o i n e s n n a l . I I I H 3 O H 3 x 9 _ 5 A r A 2 _ U 6 f b d e 6 8 e 9 x t n t t t t d \" 2 N N N L 1 ) L 2 C 4 e C 6 A m C 2 b _ C b m c S a 7 3 a 5 9 7 4 1 S 1 . c e . . y . T T T D D R 4 c R b c R o m R o m c o S 1 c a 2 5 5 1 1 8 c I 3 e d h n d d e 1 ) ) ) ) e r ) e E f E s o l E s u c E u i l n I 3 0 9 4 1 e d d 7 a Z 4 m d e / f v x e x A s 2 A e u a A e t l A t n a t Z 4 5 c 2 c 8 4 e f 2 E M p 1 c 2 3 o e 2 r r r r i c r i T e 6 T c t r T c a T u r a E M 2 8 2 b 6 6 d 0 f B t c 0 k n 0 0 r n 0 e e e e t e e t E c b E o e E o a r E a t e i P B 5 0 b 7 9 a 2 2 e y k - s - - t 2 c c c c e i c e D o 3 D n a n D n e D e n n O 6 4 b e f 9 f 9 1 , e l u I e t s 1 e e e e d v e d n a d d m n m s e R 7 a d 3 8 4 a 9 9 r i m P n u t m 0 i i i i e i d d s m s i i r T 9 f 4 2 d 9 b a 7 w - s v v n a e 1 v v v v w d v w s 6 i n n a S 1 9 a d b 5 0 2 9 i e t o 6 s e r t 1 e e e e i e i 3 a n a u u g l c 3 4 b 8 5 3 4 f l n e f u - t h 0 d d d d t d t a c g u g t t o s a 1 4 1 b 1 7 8 c l t n i b w o , , , h h g 9 o t o e e 2 2 7 7 5 f 1 f 8 r - n s o u d ( f f o 1 e - f 0 0 a 1 c 2 3 e a y e t r p D e e e r c r c a a a e 2 4 0 a b 9 4 8 t p n t / - k e x x x o o o o a g g q N 1 2 6 c 7 a b c 2 t o - c e o e b i i i m d m d g o o ) A 9 c e 4 9 4 4 f 7 e i i / t n r i t t t e e S E o M 7 b b f 2 c 0 4 8 m n p n c - - a i i i 3 3 T x E 9 9 b 0 a 8 4 6 b p t v g / t p n n n n 1 0 2 0 A i S f 5 9 a b 6 4 a f t . 6 i n e r g g g T t E E U E c b a 6 7 6 2 b 0 d - n g m o 1 U e S U E S x x S p x 8 2 6 a b b d 8 1 t b x i p c 0 S d T p x T i i T i e f 6 3 3 8 4 6 2 y / n l e . A i A t t A 4 t 8 c 1 c 9 5 6 a 1 - c x a s 2 ( T 5 t T e e T e 2 f 5 0 8 4 6 1 d p d o / t s . 0 U e U d d U s d 7 3 0 c a d 7 a 2 e e n c e e 1 ) S s d S S e 8 6 e 6 9 f 8 3 8 r f f o s s - e ( ( c ( b 3 c 9 e b c 5 5 f a . n . . 6 2 c ( 0 0 o 0 f 6 8 1 0 f 4 6 o u d f s s ) 0 o 0 ) ) n ) 0 7 a 8 1 b b d r l / . h h n ) d 1 m t d d s d 7 A s 2 2 . e / e s 4 b 1 c s f d c 5 s o m d o h a e o e u i 2 n u f n s c t n 8 f l a d e o u 5 i t u s c n a t g . l o d e u c t a n s m s r o . g d i a n c o s a n a t f o g u g i n a o t o o f g e n P o O a R g 8 T o P 0 S P 8 O / O 0 R t R / T c T t S p S c P p O N o R A b T M j S t o E e N e b S c N t o A n j t A e b M d e i M n j E e c v E d e t o S r t e S e c N e b _ i _ r t A n j m v g _ i M d e c e o m v E e c l _ o c e S r t a g d l _ _ i r o a a g m v e o l r o c e n d l e o l _ a n d a g l a r o l l e o l n d a l l 3.2. Docker Compose 3.2.1. directus docker-compose.yaml v s n e e e r r d c d t d s v a a i w i i i t c i n e c c i n r c i p n d e o r o c a o m o e n h o m e e o m o o e e n r e n e b n a l t - v P P P e n a t - c n a r - l # # # # # # # t - p - - v K S D D D D D D C C C A A # # # k c : s a t g u w i O O O : t g w t t g t u w e i E E B B B B B B A A A D D s t : s a e m d r S S S a e o d u a e s 8 m B A l M - I - o d n c d r Y C _ _ _ _ _ _ C C C M M M ( P : u ' e i : e r i o T T T i : r i s i : : 0 e y l o / a f r i d a a o : R C H P D U P H H H I I a s U s 3 : n s d k r n G G G n k r : n 5 s w c u k k r s c t n E L O O A S A E E E N N k e B : ' e p : a s e m R R R e r s e e d 5 : d a a p e / y s e _ h a m ' T I S R T E S _ _ _ _ _ e e L r o t : c e E E E r e : c r i : e y l l d e : c o e b e 2 : E T T A R S E S R E P I _ s a t n S S S _ d t _ r 8 f s o s a u x t n a n 5 N : : B : W N T E M A s h C n t / u t _ _ _ n i u n e 0 a d a u t t u : s t 5 ' T A O A O D A S u t _ a g d s : U P D a s s a c 5 u m r d r a w e s e : d 6 : ' ' S ' R B R I I S r t U m i a S A B m : m t 5 l a i s e b a n 8 1 d 5 E d D L E S L W e p R e s t E S : e 6 e u t k v : a n s 6 1 ' a 4 : i : E : : : O s L : / a R S : : s , e e / t s t i 1 6 p t 3 r D R t : : p b : W ' / r d o e o b 4 g a 2 ' e ' : ' ' ' D o / d o a O d c d d u s i : t n - 8 ' b ' d c d r r a : / ' a s s ' R i a i i p u r a / o s 5 7 a i t i ' e e d s d h t t e d D r c r r l r e l d : e b s r u r t d d m ' e o t a g : i : e h e e o e c s i l a - e e s e r i i i d t c t b i / r c e c c a t o r d 1 c ' c ' c u s s n 1 s p a s v e ' t t t d y u e a i - d t t e ' : @ r t . s s : a c d u u u s o s m c d r 5 a u u ' / e 3 h d : e 1 r t i s s s u / o t e 9 1 s s / x c i i / 3 / u r ' : a r u u u e c 9 - ' ' c a t s r / - l s e l r p n s x t 6 5 a m u e d m i ' c a e l t / t u - 2 c p 5 i c i a b t t o o d e s 9 c h l ' n t r s / u e s l a t a n / a 2 e e u e t p s s t u d h t s e a - : . p s c e o ' t o m s e a i x 3 b 6 c r . t r s r e b o t - 5 3 o o i u t e s a n e 9 b 7 m d o s g d o s s n 2 5 9 ' u / . r m l e s 2 - ' c c e e i a u f i 5 c t o x s n t m r o 3 8 i n a q c e o n 0 0 o f m l / h m s e 2 n i p / d e w c 2 g l d i s h t 4 c u e a r e h 0 4 r . t e t n e b 5 a c a c h 1 e t o t e u h ' 2 i m u s o 6 o ' s s i s 3 n / t n t ' / u o g c p r o l a S n o g Q f a e L i d i g s r t - o e o o p t t i w o h n e s n / # u g s e i n n e g r a l ) 3.2.2. Basic Operations M D C C C C M C 8 d 5 M S S S R R R R M C M a o r r r r a O 4 e 6 a t t t e e e e a O a c c e e e e c N 0 6 6 c o o o m m m m c N c B k a a a a B T 6 b 0 B p p p o o o o B T B o e t t t t o A 4 9 1 o p p p v v v v o A o o r i i i i o I 1 7 3 o i i i i i i i o I o k n n n n k N 4 6 d k n n n n n n n k N k - C g g g g - E e 6 a - g g g g g g g - E - P o P R 4 0 3 P P R P r m n d c d r 6 8 d r d d c d d c n r r o p e a a i o I e a 6 o i a a i a a e o I o - o t t c r - D e 6 c - r t c r t c t - D - 2 s w a h e 2 2 e a h e a h w 2 2 : e o b e c : : c b e c b e o : : d r a t d d t a t a r d d o i k s u o I d p r o u s u s k o I o c s e s c M i o e c s e s e c M c k \" k A r s d k d k A k e n d e G e t i e o e G e r o o r E c g s r c r E r w c t i : k w k w u s 6 w e w w a i e d d d a s a d d d d d d r a a n n r o o o n p n o o o o o o _ n n g _ n n n g d o g n n n n n n d g g x t d e e e x i s x e e e e e e i x C x u h i u r t u r u O u $ e r $ e g $ e $ M $ e c i c M d D c d t s d t d A o o t o u : o u o N c c u c s 1 c s c D k k s k : 3 k k e e \" e l - e e r r r a m r r - w t a - C c C i p e s c p R o L t s s t o s E m I h t e m A p , - r p - T o t a o a E s t h s D e r e e y C \" \" \" u d O d d d d p ` e M o o o o S d f M c c c w T - o a A k k k n A d c u N e e e T k l D r r r U e t - - - S r e e e d n n n c r t t t o i r r r m v y y y P p e p p p O o r o o o R s i i i T e n n n S t t t u . . . p s s s ` … … … \" \" \" N A M C 1 1 1 E R 3 6 6 S E A s s s T e e e E c c c D o o o n n n d d d s s s a a a g g g o o o S U U U T p p p A T 1 1 1 U 0 3 3 S s s s e e e c c c o o o n n n d d d s s s P 0 5 6 O . 4 3 R 0 3 7 T . 2 9 S 0 / . t t 0 c c : p p 8 0 5 5 - \u0026gt; 8 0 5 5 / t c p , : : : 8 0 5 5 - \u0026gt; 8 0 5 5 / t c p N d d c A i a a M r t c E e a h S c b e t a u s s e ","permalink":"https://blog.thefreemeal.com/en/posts/2022-03-06-docker-directus/","summary":"\u003ch2 id=\"1-docker\"\u003e1. Docker\u003c/h2\u003e\n\u003cp\u003e\u003cimg alt=\"picture 1\" loading=\"lazy\" src=\"/images/1646728842198.png\"\u003e\u003c/p\u003e\n\u003cp\u003eThe client operates images and containers through the docker daemon running on the host, and the registry provides image publishing and downloading (similar to npm and pip).\u003c/p\u003e\n\u003cp\u003eA Docker image is a special read-only file system that provides programs, libraries, resources, configuration files, and other files required for container runtime. It also contains some configuration parameters prepared for runtime (such as anonymous volumes, environment variables, users, etc.). The image does not contain any dynamic data, and its content will not change after being built.\u003c/p\u003e","title":"Docker"},{"content":"1. Introduction The diagram below comes from Learning Curves (for different programming languages). Although the article is primarily humorous, it shows the author\u0026rsquo;s attitude towards unit testing.\nFor Python programmers, as experience grows, after mastering unit testing, personal productivity gets a sudden boost (as for mastering decorators, one might feel inflated, but the efficiency improvement is not obvious).\nMany years ago, just out of school, in the C++ era. A Java expert from former Nortel evangelized to the development team, recommending cpp-unit, saying unit testing \u0026ldquo;can significantly improve individual combat capability.\u0026rdquo; Time passes, through many battles, I\u0026rsquo;ve lost contact with Eddie from Nortel, but his evangelism was clearly successful. I\u0026rsquo;ve practiced unit testing in different projects:\ncpp unit junit luaunit python unittest jest Although the languages are different, the unit testing concept is the same, with concepts like setup, teardown, testcase, assert/expect, and mock.\nI \u0026ldquo;cannot agree more\u0026rdquo; with the statement that unit testing \u0026ldquo;improves individual combat capability\u0026rdquo;.\n2. Benefits of Unit Testing The benefits of unittest are mainly in two aspects.\n2.1. Encourages Designing Interfaces First To do test-driven development, you have to think about how to test first, which promotes considering issues from the perspective of interface definition at an early stage. It also promotes low coupling and high cohesion in modules. Additionally, it brings an extra benefit: TDD also deposits test cases similar to documentation. Years later, when reviewing software, looking at the test cases basically explains the thinking at that time.\n2.2. Low Cost to Run Tests With standardized test case writing and test framework support for convenient execution and feedback, running tests has no time or effort burden, and can be run anytime. Running tests frequently and continuous integration exposes problems early. After interfaces stabilize, having test cases for quality assurance makes refactoring convenient.\n3. Example Suppose you\u0026rsquo;re developing an API server. Unit testing at different levels of granularity can be:\nFrom the API level, using HTTP client to simulate requests, then assert whether the returned results meet expectations From the Handler level, simulate HTTP request headers, params, body, etc., then feed to the Handler, see if the returned structure meets expectations At the module level, if there are other business logic modules below the Handler, you can do unit testing against the module interface The above 1 can already be considered system testing (end-to-end testing).\n2 has some additional benefits compared to 1: In general, for handling a request, besides the Handler, there are some middleware for preprocessing. For 1, you must test the middleware functions and the Handler itself as a whole. It\u0026rsquo;s not flexible enough.\n2 also has some disadvantages compared to 1: It requires mocking. Depending on the framework used, you need to mock the input and output data structures. Fortunately, mocking is generally simple, and many frameworks have third-party mock libraries. For example, below is a test for JS express Handler:\nimport { posthandler } from \u0026#39;../src/handlers/post\u0026#39;; import { getMockReq, getMockRes } from \u0026#39;@jest-mock/express\u0026#39;; // generate a mocked response and next function, with provided values const { res, next } = getMockRes({ }) test(\u0026#39;check post handler returns token in JSON body\u0026#39;, async () =\u0026gt; { // generate a mock request with params const req = getMockReq({ params: { id: \u0026#39;abc-def\u0026#39; }, headers:{authorization:\u0026#39;this is my token\u0026#39;} }) // provide the mock req, res, and next to assert await posthandler(req, res) expect(res.json).toHaveBeenCalledWith( expect.objectContaining({ authorization: \u0026#39;this is my token\u0026#39;, }), ) }) The introduced third-party jest-mock/express helps generate input data and check output data. See? Easy.\n4. Conclusion For most projects of any scale, as long as you introduce a few simple concepts, developers can get started in an hour or two. Organizing asserts for different modules into test cases, making it convenient to run test cases, is enough. Small investment, high return. Essential for junior programmers to advance.\n5. References Learning Curves (for different programming languages) ","permalink":"https://blog.thefreemeal.com/en/posts/2022-03-06-unittest/","summary":"\u003ch2 id=\"1-introduction\"\u003e1. Introduction\u003c/h2\u003e\n\u003cp\u003eThe diagram below comes from \u003ca href=\"https://github.com/Dobiasd/articles/blob/master/programming_language_learning_curves.md\"\u003eLearning Curves (for different programming languages)\u003c/a\u003e. Although the article is primarily humorous, it shows the author\u0026rsquo;s attitude towards unit testing.\u003c/p\u003e\n\u003cp\u003e\u003cimg alt=\"picture 7\" loading=\"lazy\" src=\"/images/1646395927979.png\"\u003e\u003c/p\u003e\n\u003cp\u003eFor Python programmers, as experience grows, after mastering unit testing, personal productivity gets a sudden boost (as for mastering decorators, one might feel inflated, but the efficiency improvement is not obvious).\u003c/p\u003e\n\u003cp\u003eMany years ago, just out of school, in the C++ era. A Java expert from former Nortel evangelized to the development team, recommending cpp-unit, saying unit testing \u0026ldquo;can significantly improve individual combat capability.\u0026rdquo; Time passes, through many battles, I\u0026rsquo;ve lost contact with Eddie from Nortel, but his evangelism was clearly successful. I\u0026rsquo;ve practiced unit testing in different projects:\u003c/p\u003e","title":"Unit Testing, Test Driven Development"},{"content":"1. Background When configuring Directus to use DingTalk QR code login, I found that DingTalk\u0026rsquo;s password-free login (OAuth 2) is not consistent with the RFC specification. Protocol conversion is needed before it can communicate with Directus normally. This is a relatively niche requirement, and there was no existing software available, so I had to build it myself.\n2. Main Functions Can act as a middleware for API communication, forwarding communication between clients and API servers, recording LOGs for convenient protocol analysis; As a middleware, it can modify request content and response content; it can do protocol adaptation and conversion. APIPROXY is a RESTFUL API proxy, monitor and adaptor.\nForward RESTFUL API to another host. It\u0026rsquo;s man in the middle who can monitor and modify the header and body of the API Request \u0026amp; Response. Good for protocol study and adaptation.\nFeatures\nAPI proxy: forward any incoming API to remote sever and return the response back to client. API monitor: you can get detailed log of the API req and res in the log file. API adpator: modify the request and response on the fly while forwarding, including parameters, body, http headers etc. API mock server: you can add your own API for testing purpose easily. 3. Current Status Initially implemented RFC6749-compatible wrapper for DingTalk\u0026rsquo;s OAuth2 protocol. Currently, Directus can support DingTalk password-free login through its translation.\n4. References APIPROXY ","permalink":"https://blog.thefreemeal.com/en/posts/2022-03-05-api-proxy/","summary":"\u003ch2 id=\"1-background\"\u003e1. Background\u003c/h2\u003e\n\u003cp\u003eWhen configuring Directus to use DingTalk QR code login, I found that DingTalk\u0026rsquo;s password-free login (OAuth 2) is not consistent with the RFC specification. Protocol conversion is needed before it can communicate with Directus normally. This is a relatively niche requirement, and there was no existing software available, so I had to build it myself.\u003c/p\u003e\n\u003ch2 id=\"2-main-functions\"\u003e2. Main Functions\u003c/h2\u003e\n\u003col\u003e\n\u003cli\u003eCan act as a middleware for API communication, forwarding communication between clients and API servers, recording LOGs for convenient protocol analysis;\u003c/li\u003e\n\u003cli\u003eAs a middleware, it can modify request content and response content; it can do protocol adaptation and conversion.\u003c/li\u003e\n\u003c/ol\u003e\n\u003cblockquote\u003e\n\u003cp\u003eAPIPROXY is a RESTFUL API proxy, monitor and adaptor.\u003c/p\u003e","title":"A Simple API Proxy"},{"content":"Unlike Python, TypeScript/JavaScript has a wide variety of module import and export methods.\nCurrently, ES6 has been standardized, so using import/export is recommended. Due to historical legacy and the huge number of npm libraries, require/exports will continue to coexist for a long time.\n1. ES6 Module Import and Export 1.1. Syntax Three export methods, two import methods\nexport import export var; import {var} from module export {var}; import {var} from module export default var import var from module You can also use:\nimport * as module_alias from module This imports all exported variables from the module into an object called module_alias.\n1.2. Examples 1.2.1. testEs6Export.ts \u0026#39;use strict\u0026#39; //Export variable export const a = \u0026#39;100\u0026#39;; //Export function export const dogSay = function(){ console.log(\u0026#39;wang wang\u0026#39;); } //Export function - second way function catSay(){ console.log(\u0026#39;miao miao\u0026#39;); } export { catSay }; //export default export const m = 100; export default m; //export defult const m = 100;// This format cannot be written here. 1.2.2. index.ts import { dogSay, catSay } from \u0026#39;./testEs6Export\u0026#39;; //Imported exported methods import m from \u0026#39;./testEs6Export\u0026#39;; //Imported export default import * as testModule from \u0026#39;./testEs6Export\u0026#39;; //As aggregated object export 2. CommonJS Module Import and Export 2.1. Syntax The module has a module.exports object, which contains the exported variables.\nexports = module.exports = {}; Additionally, there is exports, which is a reference to module.exports.\nUse require to retrieve the variables exported by the module.\nNote: The actual export is the variable that module.exports points to.\n2.2. Example //utils.js let a = 100; console.log(module.exports); //Can print result: {} console.log(exports); //Can print result: {} exports.a = 200; //Here, the hard work changes module.exports content to {a : 200} exports = \u0026#39;point to other memory area\u0026#39;; //Here, exports is pointed elsewhere //test.js var a = require(\u0026#39;/utils\u0026#39;); console.log(a) // Prints {a : 200} 3. References https://segmentfault.com/a/1190000010426778 ","permalink":"https://blog.thefreemeal.com/en/posts/2022-03-04-typescript-modules/","summary":"\u003cp\u003eUnlike Python, TypeScript/JavaScript has a wide variety of module import and export methods.\u003c/p\u003e\n\u003cp\u003eCurrently, ES6 has been standardized, so using import/export is recommended.\nDue to historical legacy and the huge number of npm libraries, require/exports will continue to coexist for a long time.\u003c/p\u003e\n\u003ch2 id=\"1-es6-module-import-and-export\"\u003e1. ES6 Module Import and Export\u003c/h2\u003e\n\u003ch3 id=\"11-syntax\"\u003e1.1. Syntax\u003c/h3\u003e\n\u003cp\u003eThree export methods, two import methods\u003c/p\u003e\n\u003ctable\u003e\n  \u003cthead\u003e\n      \u003ctr\u003e\n          \u003cth\u003eexport\u003c/th\u003e\n          \u003cth\u003eimport\u003c/th\u003e\n      \u003c/tr\u003e\n  \u003c/thead\u003e\n  \u003ctbody\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eexport var;\u003c/td\u003e\n          \u003ctd\u003eimport {var} from module\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eexport {var};\u003c/td\u003e\n          \u003ctd\u003eimport {var} from module\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eexport default var\u003c/td\u003e\n          \u003ctd\u003eimport var from module\u003c/td\u003e\n      \u003c/tr\u003e\n  \u003c/tbody\u003e\n\u003c/table\u003e\n\u003cp\u003eYou can also use:\u003c/p\u003e","title":"Modules in TypeScript"},{"content":" TypeScript learning notes. From zero to hero.\n1. Array, Tuple, Union, Enum // Basic Types let id: number = 5 //Add type after variable, separated by colon let company: string = \u0026#39;Traversy Media\u0026#39; let isPublished: boolean = true let x: any = \u0026#39;Hello\u0026#39; //any type variable can hold any type of data let ids: number[] = [1, 2, 3, 4, 5] //Variable-length array; different from traditional static language int a[4]; let arr: any[] = [1, true, \u0026#39;Hello\u0026#39;] //any array, can mix various values // Tuple let person: [number, string, boolean] = [1, \u0026#39;Brad\u0026#39;, true] //Tuple: array with known number of elements and types; element types need not be the same. // Tuple Array let employees: [number, string][] //Array where each element is a tuple employee = [ [1, \u0026#39;Brad\u0026#39;], [2, \u0026#39;John\u0026#39;], [3, \u0026#39;Jill\u0026#39;], ] // Union let pid: string | number //Union /* Below is C language union - a variable that can store several different types of data union data{ int n; char ch; double f; }; */ pid = \u0026#39;22\u0026#39; // Enum enum Direction1 { Up = 1, Down, Left, Right, } enum Direction2 { Up = \u0026#39;Up\u0026#39;, Down = \u0026#39;Down\u0026#39;, Left = \u0026#39;Left\u0026#39;, Right = \u0026#39;Right\u0026#39;, } 2. Map // Definition type MapType = { [id: string]: string; } // Instantiation const map: MapType = {}; map[\u0026#39;a\u0026#39;] = \u0026#39;b\u0026#39;; map[\u0026#39;c\u0026#39;] = \u0026#39;d\u0026#39;; // Deletion delete map[\u0026#39;c\u0026#39;]; // Enumeration for (let i in map) { console.log(map[i]); } // Get array containing all keys console.log(Object.keys(map)); // Another implementation using Record const map: Record\u0026lt;string, string\u0026gt; = {}; map[\u0026#39;a\u0026#39;] = \u0026#39;b\u0026#39;; map[\u0026#39;c\u0026#39;] = \u0026#39;d\u0026#39;; 3. Object // Objects type User = { id: number name: string } const user: User = { id: 1, name: \u0026#39;John\u0026#39;, } // Type Assertion - type casting let cid: any = 1 // let customerId = \u0026lt;number\u0026gt;cid Casting from any to number let customerId = cid as number 4. Function // Functions function addNum(x: number, y: number): number { return x + y } // Void function log(message: string | number): void { console.log(message) } 5. Interface, Class // Interfaces interface UserInterface { readonly id: number name: string age?: number } const user1: UserInterface = { id: 1, name: \u0026#39;John\u0026#39;, } interface MathFunc { (x: number, y: number): number } const add: MathFunc = (x: number, y: number): number =\u0026gt; x + y const sub: MathFunc = (x: number, y: number): number =\u0026gt; x - y interface PersonInterface { id: number name: string register(): string } // Classes class Person implements PersonInterface { id: number name: string constructor(id: number, name: string) { this.id = id this.name = name } register() { return `${this.name} is now registered` } } const brad = new Person(1, \u0026#39;Brad Traversy\u0026#39;) const mike = new Person(2, \u0026#39;Mike Jordan\u0026#39;) // Subclasses class Employee extends Person { position: string constructor(id: number, name: string, position: string) { super(id, name) this.position = position } } const emp = new Employee(3, \u0026#39;Shawn\u0026#39;, \u0026#39;Developer\u0026#39;) 6. Generics // Generics =\u0026gt; Similar to C++ templates function getArray\u0026lt;T\u0026gt;(items: T[]): T[] { return new Array().concat(items) } let numArray = getArray\u0026lt;number\u0026gt;([1, 2, 3, 4]) let strArray = getArray\u0026lt;string\u0026gt;([\u0026#39;brad\u0026#39;, \u0026#39;John\u0026#39;, \u0026#39;Jill\u0026#39;]) strArray.push(1) // Throws error 7. FAQ 7.1. type alias or interface https://www.typescriptlang.org/docs/handbook/2/everyday-types.html#differences-between-type-aliases-and-interfaces\nNot much difference; generally prefer using interface type is an alias for simple types. Commonly used to give a name to enum types for easier use later. For example: type ID = number | string; type ABC = \u0026#39;a\u0026#39; | \u0026#39;b\u0026#39; | \u0026#39;c\u0026#39; 8. d.ts Files This is similar to header files in C language. They contain type definitions. With these, you can know how to use a JavaScript library in TypeScript. DefinitelyTyped is a header file library maintained by the TypeScript community. Types for third-party JavaScript can all be found there.\n9. References https://www.youtube.com/watch?v=BCg4U1FzODs https://github.com/DefinitelyTyped/DefinitelyTyped ","permalink":"https://blog.thefreemeal.com/en/posts/2022-03-04-tyepscript-in-30-mins/","summary":"\u003cblockquote\u003e\n\u003cp\u003eTypeScript learning notes. From zero to hero.\u003c/p\u003e\u003c/blockquote\u003e\n\u003ch2 id=\"1-array-tuple-union-enum\"\u003e1. Array, Tuple, Union, Enum\u003c/h2\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-js\" data-lang=\"js\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e// Basic Types\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003elet\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003eid\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e:\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003enumber\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e5\u003c/span\u003e         \u003cspan style=\"color:#75715e\"\u003e//Add type after variable, separated by colon\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003elet\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003ecompany\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e:\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003estring\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;Traversy Media\u0026#39;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003elet\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003eisPublished\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e:\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003eboolean\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003etrue\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003elet\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003ex\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e:\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003eany\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;Hello\u0026#39;\u003c/span\u003e       \u003cspan style=\"color:#75715e\"\u003e//any type variable can hold any type of data\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003elet\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003eids\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e:\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003enumber\u003c/span\u003e[] \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e [\u003cspan style=\"color:#ae81ff\"\u003e1\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e2\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e3\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e4\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e5\u003c/span\u003e]  \u003cspan style=\"color:#75715e\"\u003e//Variable-length array; different from traditional static language int a[4];\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003elet\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003earr\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e:\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003eany\u003c/span\u003e[] \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e [\u003cspan style=\"color:#ae81ff\"\u003e1\u003c/span\u003e, \u003cspan style=\"color:#66d9ef\"\u003etrue\u003c/span\u003e, \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;Hello\u0026#39;\u003c/span\u003e]  \u003cspan style=\"color:#75715e\"\u003e//any array, can mix various values\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e// Tuple\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003elet\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003eperson\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e:\u003c/span\u003e [\u003cspan style=\"color:#a6e22e\"\u003enumber\u003c/span\u003e, \u003cspan style=\"color:#a6e22e\"\u003estring\u003c/span\u003e, \u003cspan style=\"color:#66d9ef\"\u003eboolean\u003c/span\u003e] \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e [\u003cspan style=\"color:#ae81ff\"\u003e1\u003c/span\u003e, \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;Brad\u0026#39;\u003c/span\u003e, \u003cspan style=\"color:#66d9ef\"\u003etrue\u003c/span\u003e]  \u003cspan style=\"color:#75715e\"\u003e//Tuple: array with known number of elements and types; element types need not be the same.\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e// Tuple Array\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003elet\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003eemployees\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e:\u003c/span\u003e [\u003cspan style=\"color:#a6e22e\"\u003enumber\u003c/span\u003e, \u003cspan style=\"color:#a6e22e\"\u003estring\u003c/span\u003e][]  \u003cspan style=\"color:#75715e\"\u003e//Array where each element is a tuple\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#a6e22e\"\u003eemployee\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e [\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  [\u003cspan style=\"color:#ae81ff\"\u003e1\u003c/span\u003e, \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;Brad\u0026#39;\u003c/span\u003e],\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  [\u003cspan style=\"color:#ae81ff\"\u003e2\u003c/span\u003e, \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;John\u0026#39;\u003c/span\u003e],\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  [\u003cspan style=\"color:#ae81ff\"\u003e3\u003c/span\u003e, \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;Jill\u0026#39;\u003c/span\u003e],\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e]\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e// Union\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003elet\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003epid\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e:\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003estring\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003e|\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003enumber\u003c/span\u003e    \u003cspan style=\"color:#75715e\"\u003e//Union\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e/*  Below is C language union - a variable that can store several different types of data\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003eunion data{\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e    int n;\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e    char ch;\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e    double f;\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e};\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e*/\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#a6e22e\"\u003epid\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;22\u0026#39;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e// Enum\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003eenum\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003eDirection1\u003c/span\u003e {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#a6e22e\"\u003eUp\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e1\u003c/span\u003e,\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#a6e22e\"\u003eDown\u003c/span\u003e,\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#a6e22e\"\u003eLeft\u003c/span\u003e,\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#a6e22e\"\u003eRight\u003c/span\u003e,\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e}\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003eenum\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003eDirection2\u003c/span\u003e {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#a6e22e\"\u003eUp\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;Up\u0026#39;\u003c/span\u003e,\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#a6e22e\"\u003eDown\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;Down\u0026#39;\u003c/span\u003e,\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#a6e22e\"\u003eLeft\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;Left\u0026#39;\u003c/span\u003e,\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#a6e22e\"\u003eRight\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;Right\u0026#39;\u003c/span\u003e,\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e}\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch2 id=\"2-map\"\u003e2. Map\u003c/h2\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-javascript\" data-lang=\"javascript\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e// Definition\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e\u003c/span\u003e\u003cspan style=\"color:#a6e22e\"\u003etype\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003eMapType\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e { \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    [\u003cspan style=\"color:#a6e22e\"\u003eid\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e:\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003estring\u003c/span\u003e]\u003cspan style=\"color:#f92672\"\u003e:\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003estring\u003c/span\u003e; \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e}\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e// Instantiation\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003econst\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003emap\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e:\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003eMapType\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e {};\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#a6e22e\"\u003emap\u003c/span\u003e[\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;a\u0026#39;\u003c/span\u003e] \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;b\u0026#39;\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#a6e22e\"\u003emap\u003c/span\u003e[\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;c\u0026#39;\u003c/span\u003e] \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;d\u0026#39;\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e// Deletion\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003edelete\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003emap\u003c/span\u003e[\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;c\u0026#39;\u003c/span\u003e];\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e// Enumeration\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003efor\u003c/span\u003e (\u003cspan style=\"color:#66d9ef\"\u003elet\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003ei\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003ein\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003emap\u003c/span\u003e) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#a6e22e\"\u003econsole\u003c/span\u003e.\u003cspan style=\"color:#a6e22e\"\u003elog\u003c/span\u003e(\u003cspan style=\"color:#a6e22e\"\u003emap\u003c/span\u003e[\u003cspan style=\"color:#a6e22e\"\u003ei\u003c/span\u003e]);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e}\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e// Get array containing all keys\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e\u003c/span\u003e\u003cspan style=\"color:#a6e22e\"\u003econsole\u003c/span\u003e.\u003cspan style=\"color:#a6e22e\"\u003elog\u003c/span\u003e(Object.\u003cspan style=\"color:#a6e22e\"\u003ekeys\u003c/span\u003e(\u003cspan style=\"color:#a6e22e\"\u003emap\u003c/span\u003e));\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e// Another implementation using Record\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003econst\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003emap\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e:\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003eRecord\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e\u0026lt;\u003c/span\u003e\u003cspan style=\"color:#a6e22e\"\u003estring\u003c/span\u003e, \u003cspan style=\"color:#a6e22e\"\u003estring\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e\u0026gt;\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e {};\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#a6e22e\"\u003emap\u003c/span\u003e[\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;a\u0026#39;\u003c/span\u003e] \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;b\u0026#39;\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#a6e22e\"\u003emap\u003c/span\u003e[\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;c\u0026#39;\u003c/span\u003e] \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;d\u0026#39;\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch2 id=\"3-object\"\u003e3. Object\u003c/h2\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-javascript\" data-lang=\"javascript\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e// Objects\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e\u003c/span\u003e\u003cspan style=\"color:#a6e22e\"\u003etype\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003eUser\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#a6e22e\"\u003eid\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e:\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003enumber\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#a6e22e\"\u003ename\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e:\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003estring\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e}\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003econst\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003euser\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e:\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003eUser\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#a6e22e\"\u003eid\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e:\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e1\u003c/span\u003e,\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#a6e22e\"\u003ename\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e:\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;John\u0026#39;\u003c/span\u003e,\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e}\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e// Type Assertion - type casting\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003elet\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003ecid\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e:\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003eany\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e1\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e// let customerId = \u0026lt;number\u0026gt;cid  Casting from any to number\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003elet\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003ecustomerId\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003ecid\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003eas\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003enumber\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch2 id=\"4-function\"\u003e4. Function\u003c/h2\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-js\" data-lang=\"js\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e// Functions\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003efunction\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003eaddNum\u003c/span\u003e(\u003cspan style=\"color:#a6e22e\"\u003ex\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e:\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003enumber\u003c/span\u003e, \u003cspan style=\"color:#a6e22e\"\u003ey\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e:\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003enumber\u003c/span\u003e)\u003cspan style=\"color:#f92672\"\u003e:\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003enumber\u003c/span\u003e {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#66d9ef\"\u003ereturn\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003ex\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003e+\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003ey\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e}\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e// Void\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003efunction\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003elog\u003c/span\u003e(\u003cspan style=\"color:#a6e22e\"\u003emessage\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e:\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003estring\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003e|\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003enumber\u003c/span\u003e)\u003cspan style=\"color:#f92672\"\u003e:\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003evoid\u003c/span\u003e {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#a6e22e\"\u003econsole\u003c/span\u003e.\u003cspan style=\"color:#a6e22e\"\u003elog\u003c/span\u003e(\u003cspan style=\"color:#a6e22e\"\u003emessage\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e}\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch2 id=\"5-interface-class\"\u003e5. Interface, Class\u003c/h2\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-js\" data-lang=\"js\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e// Interfaces\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003einterface\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003eUserInterface\u003c/span\u003e {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#a6e22e\"\u003ereadonly\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003eid\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e:\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003enumber\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#a6e22e\"\u003ename\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e:\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003estring\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#a6e22e\"\u003eage\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e?:\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003enumber\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e}\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003econst\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003euser1\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e:\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003eUserInterface\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#a6e22e\"\u003eid\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e:\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e1\u003c/span\u003e,\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#a6e22e\"\u003ename\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e:\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;John\u0026#39;\u003c/span\u003e,\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e}\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003einterface\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003eMathFunc\u003c/span\u003e {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  (\u003cspan style=\"color:#a6e22e\"\u003ex\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e:\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003enumber\u003c/span\u003e, \u003cspan style=\"color:#a6e22e\"\u003ey\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e:\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003enumber\u003c/span\u003e)\u003cspan style=\"color:#f92672\"\u003e:\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003enumber\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e}\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003econst\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003eadd\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e:\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003eMathFunc\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e (\u003cspan style=\"color:#a6e22e\"\u003ex\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e:\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003enumber\u003c/span\u003e, \u003cspan style=\"color:#a6e22e\"\u003ey\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e:\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003enumber\u003c/span\u003e)\u003cspan style=\"color:#f92672\"\u003e:\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003enumber\u003c/span\u003e =\u0026gt; \u003cspan style=\"color:#a6e22e\"\u003ex\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003e+\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003ey\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003econst\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003esub\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e:\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003eMathFunc\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e (\u003cspan style=\"color:#a6e22e\"\u003ex\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e:\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003enumber\u003c/span\u003e, \u003cspan style=\"color:#a6e22e\"\u003ey\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e:\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003enumber\u003c/span\u003e)\u003cspan style=\"color:#f92672\"\u003e:\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003enumber\u003c/span\u003e =\u0026gt; \u003cspan style=\"color:#a6e22e\"\u003ex\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003e-\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003ey\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003einterface\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003ePersonInterface\u003c/span\u003e {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#a6e22e\"\u003eid\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e:\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003enumber\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#a6e22e\"\u003ename\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e:\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003estring\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#a6e22e\"\u003eregister\u003c/span\u003e()\u003cspan style=\"color:#f92672\"\u003e:\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003estring\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e}\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e// Classes\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003eclass\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003ePerson\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003eimplements\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003ePersonInterface\u003c/span\u003e {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#a6e22e\"\u003eid\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e:\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003enumber\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#a6e22e\"\u003ename\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e:\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003estring\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#a6e22e\"\u003econstructor\u003c/span\u003e(\u003cspan style=\"color:#a6e22e\"\u003eid\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e:\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003enumber\u003c/span\u003e, \u003cspan style=\"color:#a6e22e\"\u003ename\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e:\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003estring\u003c/span\u003e) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003ethis\u003c/span\u003e.\u003cspan style=\"color:#a6e22e\"\u003eid\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003eid\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003ethis\u003c/span\u003e.\u003cspan style=\"color:#a6e22e\"\u003ename\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003ename\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#a6e22e\"\u003eregister\u003c/span\u003e() {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003ereturn\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e`\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e${\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003ethis\u003c/span\u003e.\u003cspan style=\"color:#a6e22e\"\u003ename\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e is now registered`\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e}\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003econst\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003ebrad\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003enew\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003ePerson\u003c/span\u003e(\u003cspan style=\"color:#ae81ff\"\u003e1\u003c/span\u003e, \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;Brad Traversy\u0026#39;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003econst\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003emike\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003enew\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003ePerson\u003c/span\u003e(\u003cspan style=\"color:#ae81ff\"\u003e2\u003c/span\u003e, \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;Mike Jordan\u0026#39;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e// Subclasses\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003eclass\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003eEmployee\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003eextends\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003ePerson\u003c/span\u003e {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#a6e22e\"\u003eposition\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e:\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003estring\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#a6e22e\"\u003econstructor\u003c/span\u003e(\u003cspan style=\"color:#a6e22e\"\u003eid\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e:\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003enumber\u003c/span\u003e, \u003cspan style=\"color:#a6e22e\"\u003ename\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e:\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003estring\u003c/span\u003e, \u003cspan style=\"color:#a6e22e\"\u003eposition\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e:\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003estring\u003c/span\u003e) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003esuper\u003c/span\u003e(\u003cspan style=\"color:#a6e22e\"\u003eid\u003c/span\u003e, \u003cspan style=\"color:#a6e22e\"\u003ename\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003ethis\u003c/span\u003e.\u003cspan style=\"color:#a6e22e\"\u003eposition\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003eposition\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e}\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003econst\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003eemp\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003enew\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003eEmployee\u003c/span\u003e(\u003cspan style=\"color:#ae81ff\"\u003e3\u003c/span\u003e, \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;Shawn\u0026#39;\u003c/span\u003e, \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;Developer\u0026#39;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch2 id=\"6-generics\"\u003e6. Generics\u003c/h2\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-js\" data-lang=\"js\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e// Generics =\u0026gt; Similar to C++ templates\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003efunction\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003egetArray\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e\u0026lt;\u003c/span\u003e\u003cspan style=\"color:#a6e22e\"\u003eT\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e\u0026gt;\u003c/span\u003e(\u003cspan style=\"color:#a6e22e\"\u003eitems\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e:\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003eT\u003c/span\u003e[])\u003cspan style=\"color:#f92672\"\u003e:\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003eT\u003c/span\u003e[] {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#66d9ef\"\u003ereturn\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003enew\u003c/span\u003e Array().\u003cspan style=\"color:#a6e22e\"\u003econcat\u003c/span\u003e(\u003cspan style=\"color:#a6e22e\"\u003eitems\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e}\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003elet\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003enumArray\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003egetArray\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e\u0026lt;\u003c/span\u003e\u003cspan style=\"color:#a6e22e\"\u003enumber\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e\u0026gt;\u003c/span\u003e([\u003cspan style=\"color:#ae81ff\"\u003e1\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e2\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e3\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e4\u003c/span\u003e])\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003elet\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003estrArray\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003egetArray\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e\u0026lt;\u003c/span\u003e\u003cspan style=\"color:#a6e22e\"\u003estring\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e\u0026gt;\u003c/span\u003e([\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;brad\u0026#39;\u003c/span\u003e, \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;John\u0026#39;\u003c/span\u003e, \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;Jill\u0026#39;\u003c/span\u003e])\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#a6e22e\"\u003estrArray\u003c/span\u003e.\u003cspan style=\"color:#a6e22e\"\u003epush\u003c/span\u003e(\u003cspan style=\"color:#ae81ff\"\u003e1\u003c/span\u003e) \u003cspan style=\"color:#75715e\"\u003e// Throws error\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch2 id=\"7-faq\"\u003e7. FAQ\u003c/h2\u003e\n\u003ch3 id=\"71-type-alias-or-interface\"\u003e7.1. type alias or interface\u003c/h3\u003e\n\u003cp\u003e\u003ca href=\"https://www.typescriptlang.org/docs/handbook/2/everyday-types.html#differences-between-type-aliases-and-interfaces\"\u003ehttps://www.typescriptlang.org/docs/handbook/2/everyday-types.html#differences-between-type-aliases-and-interfaces\u003c/a\u003e\u003c/p\u003e","title":"Typescript"},{"content":"What is bps? BP (or bps) stands for Basis Point. In Chinese, it\u0026rsquo;s translated to \u0026ldquo;基点\u0026rdquo; (jī diǎn). It\u0026rsquo;s a ratio, meaning one ten-thousandth, which is one hundredth of one percent.\nWhy Do We Need This Concept? Why not just say \u0026ldquo;one ten-thousandth\u0026rdquo; and introduce a new term instead?\nBasis points are convenient and steady. Basis points are less ambiguous than percentages as they represent an absolute, set figure instead of a ratio.\nFor example, a 1 percent increase on a 5 percent interest rate could be interpreted as either 5.05 percent or 6 percent.\nConversely, if the rate increases by 100 basis points, the result is constant. The rate updates to 6 percent.\nThe introduction of bps is to make expression clearer and avoid ambiguity.\nFor example, suppose the central bank announces today that the LPR (Loan Prime Rate) increases by 1 percent. There are two different interpretations:\nThe new LPR is 5% + 1% = 6% The new LPR is 5% + 5% * 1% = 5.05% After introducing bps, when the central bank says add 100 basis points, everyone unambiguously knows the new LPR is 6%.\n","permalink":"https://blog.thefreemeal.com/en/posts/2022-03-03-bps/","summary":"\u003ch2 id=\"what-is-bps\"\u003eWhat is bps?\u003c/h2\u003e\n\u003cp\u003eBP (or bps) stands for Basis Point. In Chinese, it\u0026rsquo;s translated to \u0026ldquo;基点\u0026rdquo; (jī diǎn). It\u0026rsquo;s a ratio, meaning one ten-thousandth, which is one hundredth of one percent.\u003c/p\u003e\n\u003ch2 id=\"why-do-we-need-this-concept\"\u003eWhy Do We Need This Concept?\u003c/h2\u003e\n\u003cp\u003eWhy not just say \u0026ldquo;one ten-thousandth\u0026rdquo; and introduce a new term instead?\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003eBasis points are convenient and steady. Basis points are less ambiguous than percentages as they represent an absolute, set figure instead of a ratio.\u003c/p\u003e","title":"What is Basis Point (bps)?"},{"content":"Directus itself is a NodeJS-based API server. The TPS it can support depends on multiple factors such as the database system and API query design. This article provides some architectural considerations to enable Directus applications to scale with business growth by adding hardware, thereby improving system processing capacity and achieving good scalability in performance.\n1. How to Plan a Scalable Directus Application Directus focuses on two aspects for handling high load scenarios:\nHorizontally scaling application servers (deploying multiple Directus instances) Using high-performance database solutions, such as Amazon Aurora or CockroachDB Rijk van Zanten: That being said, I do highly recommend horizontally scaling your Directus instance if you\u0026rsquo;re planning on running it at scale. Make sure you use Redis for caches / rate limiter, and S3 or another shared file storage for the file storage. At that point, the bottleneck will become the amount of allowed connections and the overall server performance of the database. That being said, there\u0026rsquo;s a lot of database services nowadays that scale virtually endless, like Amazon Aurora or CockroachDB.\n2. Horizontal Scaling of Application Servers For horizontal scaling, it\u0026rsquo;s important to note that data shared between all instances cannot be stored locally. Instead, use high-performance solutions like CDN or Redis. Shared data across instances includes: images, files, caches, etc.\nDirectus uses JWT, so there\u0026rsquo;s no session sharing issue. It doesn\u0026rsquo;t matter which instance handles each API request since instances don\u0026rsquo;t store user state information.\n3. Database Scalability Currently, Directus version 9.5 supports CockroachDB using the PostgreSQL driver. CockroachDB, a fully distributed database, is a revolutionary product that greatly enhances system scalability.\nFor example, deploying CockroachDB nodes in multiple countries\u0026rsquo; IDCs, after networking, each country can access separately. This can:\nIncrease database processing bandwidth Introduce multi-city, multi-IDC to improve disaster recovery and backup capabilities Overseas users can access the database locally, and API servers deployed in overseas data centers reduce access latency We will continue to monitor the production usage and testing of Directus and CockroachDB.\n4. References performance discussion Implement CockroachDB support ","permalink":"https://blog.thefreemeal.com/en/posts/2022-03-02-directus-performance/","summary":"\u003cp\u003eDirectus itself is a NodeJS-based API server. The TPS it can support depends on multiple factors such as the database system and API query design. This article provides some architectural considerations to enable Directus applications to scale with business growth by adding hardware, thereby improving system processing capacity and achieving good scalability in performance.\u003c/p\u003e\n\u003ch2 id=\"1-how-to-plan-a-scalable-directus-application\"\u003e1. How to Plan a Scalable Directus Application\u003c/h2\u003e\n\u003cp\u003eDirectus focuses on two aspects for handling high load scenarios:\u003c/p\u003e","title":"Designing High-Performance and Scalable API Services"},{"content":"1. Project Overview The expected outcome of this small project is to allow Directus to support logging in with DingTalk accounts. After understanding the OAuth2 protocol (see the previous blog post, reference 1), we have enough knowledge to implement this. Directus natively supports GitHub login, so the approach is to start with GitHub. Follow these steps:\nConfigure Directus to use GitHub account login to get familiar with Directus\u0026rsquo;s standard OAuth support Configure Directus to use DingTalk account login; since DingTalk\u0026rsquo;s protocol implementation differs from RFC6749/GitHub, we may need to handle issues as they arise Deploy Directus to the server environment and verify on both DingTalk PC and mobile versions 2. Environment Configuration Use ngrok locally to expose a service to receive OAuth server redirects.\nngrok http 8055 Get https://445a-240e-47c-30b0-3b10-600e-ea25-cde5-2334.ngrok.io/ as the public domain to access the local port 8055 where directus is running.\n3. Directus GitHub Login Configure parameters according to reference material 2. In the following configuration, for each new GitHub authorized user, Directus will automatically create a Directus user using the user\u0026rsquo;s email during the login process and assign it the role AUTH_GITHUB_DEFAULT_ROLE_ID.\nA A A A A A A A A A # # U U U U U U U U U U T T T T T T T T T T A A H H H H H H H H H H U U _ _ _ _ _ _ _ _ _ _ T T P G G G G G G G G G H H R I I I I I I I I I _ _ O T T T T T T T T T G G V H H H H H H H H H I I I U U U U U U U U U T T D B B B B B B B B B H H E _ _ _ _ _ _ _ _ _ U U R D C C A A P A D I B B S R L L U C R L E C _ _ = I I I T C O L F O E I \" V E E H E F O A N M D g E N N O S I W U = A E i R T T R S L _ L \" I N t = _ _ I _ E P T g L T h \" I S Z U _ U _ i _ I u o D E E R U B R t K F b a = C _ L R L O h E I \" u \" R U = L I L u Y E t 7 E R \" = C E b = R h e T L h \" _ _ \" \" _ 2 . = = t h R I e K \" . \" \" t t E D m E . d h p t G = a Y . 5 t s p I \" i = a . t : s S 0 l \" e . p / : T f \" e \" . s / / R 5 m . : g / A f a . i a T 1 i . t p I b l . g h i O 5 \" d i u . N a 9 t b g = - \" h . i \" 1 u c t t 0 b o h r 6 . m u u f c b e - l . \" 4 m c e g o c l i m 7 o n - g u a i o s 8 n a e b / u r 8 o t \" - a h 6 u / f t a 1 h c 1 / c 4 a e 8 u s 2 t s a h _ 0 o t 6 r o 0 i k f z e \" e n \" \" After restarting Directus to apply the configuration, you can see the GitHub option on the login page. After selecting and authorizing, you can successfully log in to Directus. Check that the newly generated user and permissions in Directus are normal. 4. Attempting Directus DingTalk Login First, try to configure it similar to GitHub.\nA A A A A A A A A A # # U U U U U U U U U U A A T T T T T T T T T T U U H H H H H H H H H H T T _ _ _ _ _ _ _ _ _ _ H H P D D D D D D D D D _ _ R I I I I I I I I I D D O N N N N N N N N N I I V G G G G G G G G G N N I T T T T T T T T T G G D A A A A A A A A A T T E L L L L L L L L L A A R K K K K K K K K K L L S _ _ _ _ _ _ _ _ _ K K = D C C A A P A D I _ _ \" R L L U C R L E C E I g I I I T C O L F O M D i V E E H E F O A N A E t E N N O S I W U = I N h R T T R S L _ L \" L T u = _ _ I _ E P T a _ I b \" I S Z U _ U _ l K F , o D E E R U B R i E I a = C _ L R L O p Y E d u \" R U = L I L a = R i t d E R \" = C E y \" _ n h i T L h \" _ _ \" e K g 2 n = = t h R I m E t \" g \" \" t t E D a Y a . c h p t G = i = l . 6 t s p I \" l \" k . r t : s S 0 \" e \" t C p / : T f m x T s / / R 5 a t . : a / A f i \" . p a T 1 l . / i p I b \" h l . i O 5 4 o d . N a o g i d = - h i n i \" 1 K n g n t 0 l . t g r 6 q d a t u f 5 i l a e - o n k l \" 4 z g . k e \" t c . c a o c 7 l m - k m a . v / 8 c 1 v b o . 1 8 m 0 . - / 0 6 o / f a a c 1 u u o 1 t t n 4 h h t 8 2 2 a 2 / / c a a u t 0 u s / 6 t e u 0 h r s f \" A e \" c r c s e / s m s e T \" o k e n \" Clicking Log In with DingTalk authorizes normally, but after authorization it redirects to:\n/ a d m i n / l o g i n ? r e a s o n = I N V A L I D _ U S E R Suspect that the URL redirected back from DingTalk doesn\u0026rsquo;t have a code parameter (refer to the previous article about protocol analysis - DingTalk uses authCode parameter). First, I opened an issue in the community to see if anyone else has encountered this.\nAt the same time, I made a temporary patch to the oauth2 driver. When there\u0026rsquo;s an authCode, assign it to code.\ntry { res.clearCookie(`oauth2.${providerName}`); if ( req.query.authCode) { req.query.code = req.query.authCode } if (!req.query.code || !req.query.state) { logger.warn(`[OAuth2] Couldn\u0026#39;t extract OAuth2 code or state from query: ${JSON.stringify(req.query)}`); } authResponse = await authenticationService.login(providerName, { code: req.query.code, codeVerifier: verifier, state: req.query.state, }); } catch (error: any) { ... After restarting directus again, the patch seemed to work. This time it redirected to:\n/ a d m i n / l o g i n ? r e a s o n = S E R V I C E _ U N A V A I L A B L E The first step of the OAuth2 protocol (getting the code) has passed. Is SERVICE_UNAVAILABLE a problem with getting the token or getting the profile?\nI noticed that in the request to get the token from DingTalk, the parameter names are clientId, clientSecret. While GitHub uses client_id, client_secret. Additionally, DingTalk requires an extra grantType.\n{ } \" \" \" \" c c c g l l o r i i d a e e e n n n \" t t t T I S : y d e p \" c \" e r 6 \" : e b t 4 : \" \" 2 d 7 \" i : e a n 8 u g \" b t y f h y o a o o u b r u r 8 i r 3 z s e a i e 9 t d c 3 i \" r b o , e e n t d _ \" d c , 1 o 3 d f e 1 \" 6 a 4 3 0 7 0 2 \" , Configure clientId, clientSecret, and grantType as parameters in the directus request.\nA U T H _ D I N G T A L K _ P A R A M S = \" { \\ \" c l i e n t I d \\ \" : \\ \" d i n . . . t x t \\ \" , \\ \" c l i e n t S e c r e t \\ \" : \\ \" d 5 6 . . . . 5 8 b d 9 \\ \" , \\ \" g r a n t T y p e \\ \" : \\ \" a u t h o r i z a t i o n _ c o d e \\ \" } \" Still getting SERVICE_UNAVAILABLE. After checking the driver, the problem is in the following:\ntry { tokenSet = await this.client.oauthCallback( this.redirectUrl, { code: payload.code, state: payload.state }, { code_verifier: payload.codeVerifier, state: generators.codeChallenge(payload.codeVerifier) } ); userInfo = await this.client.userinfo(tokenSet.access_token!); } catch (e) { throw handleError(e); } The above code throws an exception because the HTTP response is 400. It should be that the DingTalk OAuth server doesn\u0026rsquo;t recognize the message sent by Directus.\nThe context of the above code execution:\nIn the oauth2 driver, the express route is configured to handle the code redirected from DingTalk. During processing, the user needs to be authenticated (successful authentication completes login and issues JWT token); User authentication is independent of the driver, handled by a general AuthenticationService.login service, which calls the driver\u0026rsquo;s getUserID method to get userId; For the oauth2 driver, no username/password is passed from the web page. Its only input is the code redirected from DingTalk. It needs to convert the code to a token through the OAuth interface, then read the user information to know the userID. The OAuth2 Driver uses openid-client to communicate with the server. The client is also initialized in the driver:\nconst issuer = new Issuer({ authorization_endpoint: authorizeUrl, token_endpoint: accessUrl, userinfo_endpoint: profileUrl, issuer: additionalConfig.provider, }); this.client = new issuer.Client({ client_id: clientId, client_secret: clientSecret, redirect_uris: [this.redirectUrl], response_types: [\u0026#39;code\u0026#39;], }); So the problem becomes compatibility between openid-client and DingTalk. More specifically, how to use the oauthCallback function to get tokens from DingTalk.\nLooking at the implementation of openid-client, when interacting with OAuth servers, the POST form data uses parameter names hardcoded according to RFC6749. These inevitably don\u0026rsquo;t match DingTalk\u0026rsquo;s requirements. Using openid-client cannot be compatible with DingTalk. I discussed the research results in detail with the Directus OAuth Driver author in Integrating Dingtalk as OAuth2 server.\n5. Conclusion The original plan cannot be achieved. The reason is that DingTalk\u0026rsquo;s OAuth implementation is not compatible with the standard. Directus uses a third-party OAuth library to communicate with OAuth servers. The standard openid-client cannot communicate with DingTalk\u0026rsquo;s OAuth server that speaks a different \u0026ldquo;dialect\u0026rdquo;.\nTwo solutions are considered:\nInherit from Directus\u0026rsquo;s standard oauth2 driver and implement a DingTalk dialect version of the oauth2-dingtalk driver, or Implement a proxy to translate DingTalk\u0026rsquo;s OAuth dialect to the standard OAuth2 protocol I prefer solution 2, which is equivalent to creating a protocol wrapper for DingTalk, converting parameter formats according to the standard. This way, other systems that need to integrate DingTalk login in the future can also use it.\nI will add more notes after completion.\n6. Additional Notes Refer to apiproxy which implemented password-free DingTalk login using solution 2 above.\n7. References OAuth2 Protocol Illustrated Directus Authentication Configuration node openid client 钉钉Nodejs SDK 钉钉开放平台开发文档中获得token的示例 Integrating Dingtalk as OAuth2 server apiproxy ","permalink":"https://blog.thefreemeal.com/en/posts/2022-02-27-oauth-directus-dingtalk/","summary":"\u003ch2 id=\"1-project-overview\"\u003e1. Project Overview\u003c/h2\u003e\n\u003cp\u003eThe expected outcome of this small project is to allow Directus to support logging in with DingTalk accounts. After understanding the OAuth2 protocol (see the previous blog post, reference 1), we have enough knowledge to implement this. Directus natively supports GitHub login, so the approach is to start with GitHub. Follow these steps:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eConfigure Directus to use GitHub account login to get familiar with Directus\u0026rsquo;s standard OAuth support\u003c/li\u003e\n\u003cli\u003eConfigure Directus to use DingTalk account login; since DingTalk\u0026rsquo;s protocol implementation differs from RFC6749/GitHub, we may need to handle issues as they arise\u003c/li\u003e\n\u003cli\u003eDeploy Directus to the server environment and verify on both DingTalk PC and mobile versions\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"2-environment-configuration\"\u003e2. Environment Configuration\u003c/h2\u003e\n\u003cp\u003eUse ngrok locally to expose a service to receive OAuth server redirects.\u003c/p\u003e","title":"OAuth2 Application Practice: Attempting to Integrate DingTalk Login with Directus"},{"content":"1. Principle Suppose there\u0026rsquo;s an APP that wants me to use GitHub for authorized login. In this login scenario:\nI, as the data owner, tell the system (GitHub) that I agree to authorize a third-party application (App) to enter the system and obtain certain data (my ID, avatar, etc.). The system then generates a short-term access token to replace the password for the third-party application (APP) to access the data.\nThe token is valid for a short time, and I can revoke it through GitHub at any time, making the APP unable to access my ID/avatar and other information.\nThere are four roles: user, application, system, and resource.\nThe user is the resource owner, the application is the resource consumer, and the system is the resource manager. In real life, the application and system each have one instance, while users have multiple instances. The application and system communicate through the OAuth2 protocol, with the user participating in the process (authorization).\nMapping the sequence diagram above to a real-life scenario, where an owner authorizes a courier company to enter the community to deliver packages:\nClient Req Auth: The SF Express courier calls the owner, there\u0026rsquo;s a package for you, needs to be delivered in, let\u0026rsquo;s get a pass Resource Owner Grant Auth: Owner contacts the property management: I\u0026rsquo;m the owner, here\u0026rsquo;s my proof, I allow SF Express to enter the community to deliver packages for me in the next two days Property tells owner: OK, have SF Express contact me for the temporary pass, room 201 building 3, authorization code: nucleic acid test benefits the country Client Sends Auth Grant Courier company contacts property: I\u0026rsquo;m SF Express, here\u0026rsquo;s my proof, need to deliver to room 201 building 3, owner\u0026rsquo;s authorization code is nucleic acid test benefits the country Auth Server Sends Access Token Property says: authorization code is good, here\u0026rsquo;s the temporary pass, valid for two days Clients Sends Access Token Courier uses temporary pass to open the community gate Protected Resource sends resource Courier enters the community Note:\nIn step 2, when owner contacts property, must prove they\u0026rsquo;re actually the owner (via community app login) In step 3, when SF Express contacts property, needs to prove they\u0026rsquo;re actually SF Express (report the client_secret pre-assigned by property). Property also needs to check that the owner of room 201 building 3 actually allowed it (via authorization code check). If the courier goes directly to the guard and says \u0026ldquo;nucleic acid test benefits the country,\u0026rdquo; it won\u0026rsquo;t work. The information carried by \u0026ldquo;nucleic acid test benefits the country\u0026rdquo; is that the owner of room 201 building 3 allowed SF Express to enter the community within 2 days. The courier reporting this authorization code to the guard is useless - the guard only recognizes the pass. Besides, the guard doesn\u0026rsquo;t know if the courier is from SF Express. The authorization code is only useful after the courier company exchanges it for a temporary pass. Exchanging for a temporary pass requires verifying SF Express\u0026rsquo;s identity. The information carried by \u0026ldquo;nucleic acid test benefits the country\u0026rdquo; can be public - if others hear it, there\u0026rsquo;s no security risk because others don\u0026rsquo;t have the client_secret that SF Express registered with the property, so they can\u0026rsquo;t exchange the authorization code for a temporary pass. The temporary pass must be kept safe - anyone with it can enter the community.\nThe OAuth2 process is: when there\u0026rsquo;s a package, the owner authorizes the property to assign a temporary pass to the courier company, which can enter the community within a certain time. At the same time, there will be many valid temporary passes authorized by different owners, but for one owner to one courier company, there\u0026rsquo;s only one valid temporary pass at any given time.\nChinese Term Sequence Diagram Concept GitHub Login APP Scenario Owner Authorizes SF Express to Enter Community User Resource Owner GitHub User Owner Application Client GitHub OAuth APP SF Express System Authorization Server GitHub Property Management Resource Protected Resource GitHub username, avatar Community roads Authorization Authorization Grant code Nucleic acid test Token Access Token token Temporary pass The diagram below is from RFC6750. For actual implementation, Client is the APP, Auth Server/Resource Server are on the same domain (GitHub, DingTalk, Facebook\u0026hellip;), and Resource Owner also completes authorization (Auth Grant) on that domain.\nC l i e n t ( ( ( ( ( ( A B C D E F ) ) ) ) ) ) - - - - - - - - - - - A - - - u A A - - t u u - - P h t t r o h h A A o r o o c c t i r r c c e z i i e e c a z z s s t t a a s s e i t t d o i i T T n o o o o R n n k k e R e e s e G G n n o q r r u u a a r e n n c s t t e t A u R t e h R s O o S e S o w r e s e u n i r o r r e z v u v c r a e r e e t r c r i e o n For discussion convenience, \u0026ldquo;obtaining user authorization\u0026rdquo; is abbreviated as \u0026ldquo;getting code,\u0026rdquo; and \u0026ldquo;obtaining access token\u0026rdquo; is abbreviated as \u0026ldquo;getting token.\u0026rdquo;\nNext, using GitHub and DingTalk as OAuth servers, we\u0026rsquo;ll analyze the message formats in the process of getting code, getting token, and reading user info. No coding needed - just need a browser and REST Client (POSTMAN, CURL, or VSCode plugin).\nThere are two types of OAuth clients:\nPublic: Clients that don\u0026rsquo;t have the ability to store secret keys securely - like desktop software, mobile apps, single-page applications (SPA). Confidential: The step of exchanging code for access_token is done on the backend. Generally protected with client_secret. We\u0026rsquo;ll mainly discuss confidential clients. 2. GitHub OAuth Interaction Analysis The following four steps demonstrate:\nCreating a new OAuth app on GitHub Getting authorization code through GitHub\u0026rsquo;s API Getting token through GitHub\u0026rsquo;s API Getting authorized user data through GitHub\u0026rsquo;s API Recording key input/output parameters for each step.\n2.1. Create OAuth APP After logging into GitHub, create a new OAuth APP in the development options. For testing convenience, I set Redirect URL to https://www.baidu.com/. The new APP configuration is:\nc c l l i i e e n n t t _ _ i s d e c : r e 7 t e : c e 5 5 9 c 2 c f 7 6 8 f e 0 4 f f 1 d 9 d e 3 2 2 1 6 c 0 d a 7 e 0 6 d 6 b f 4 c 4 d c f 6 f e 9 a 0 a d 0 9 9 c 2.2. Get code In browser, initiate:\nh t t p s : / / g i t h u b . c o m / l o g i n / o a u t h / a u t h o r i z e ? c l i e n t _ i d = 7 e c e 5 c c 7 8 e 4 f d d 3 2 6 0 a e \u0026amp; r e d i r e c t _ u r i = h t t p s : / / w w w . b a i d u . c o m / You\u0026rsquo;ll see: After selecting authorize, you can see the Code in the callback:\nh t t p s : / / w w w . b a i d u . c o m / ? c o d e = 8 7 1 f 7 4 a 9 d 1 2 9 e f 1 9 8 b 4 3 2.3. Get token p o s t h t t p s : / / g i t h u b . c o m / l o g i n / o a u t h / a c c e s s _ t o k e n ? c l i e n t _ i d = 7 e c e 5 c c 7 8 e 4 f d d 3 2 6 0 a e \u0026amp; c l i e n t _ s e c r e t = 5 9 2 f 6 f 0 f 1 9 e 2 1 c d 7 0 6 d 6 b f 4 c 4 d c f 6 f e 9 a 0 a d 0 9 9 c \u0026amp; c o d e = 8 7 1 f 7 4 a 9 d 1 2 9 e f 1 9 8 b 4 3 The request has three parameters:\nclient_id: obtained from creating the app on GitHub client_secret: obtained from creating the app on GitHub code: obtained from previous Authorization step In the response:\na c c e s s _ t o k e n = g h o _ Q V E s K 2 p l K h 6 T 6 0 A 4 h M E D J d d E n R 2 y 4 D 3 7 s C P x \u0026amp; s c o p e = \u0026amp; t o k e n _ t y p e = b e a r e r Now in the GitHub app configuration, you can see that the app has one user. And I can Revoke All user tokens.\n2.4. Read User Info g a A e c u t c t e h h p o t t r t : i p z s ' a : a t / p i / p o a l n p i : i c . a t g t o i i k t o e h n n u / b j g . s h c o o o n _ m ' Q V u E s s e K r 2 p l K h 6 T 6 0 A 4 h M E D J d d E n R 2 y 4 D 3 7 s C P x In the response:\n{ \u0026#34;login\u0026#34;: \u0026#34;xu4wang\u0026#34;, \u0026#34;id\u0026#34;: 311397, \u0026#34;node_id\u0026#34;: \u0026#34;MDQ6VXNlcjMxMTM5Nw==\u0026#34;, \u0026#34;avatar_url\u0026#34;: \u0026#34;https://avatars.githubusercontent.com/u/311397?v=4\u0026#34;, \u0026#34;gravatar_id\u0026#34;: \u0026#34;\u0026#34;, \u0026#34;url\u0026#34;: \u0026#34;https://api.github.com/users/xu4wang\u0026#34;, \u0026#34;html_url\u0026#34;: \u0026#34;https://github.com/xu4wang\u0026#34;, \u0026#34;followers_url\u0026#34;: \u0026#34;https://api.github.com/users/xu4wang/followers\u0026#34;, \u0026#34;following_url\u0026#34;: \u0026#34;https://api.github.com/users/xu4wang/following{/other_user}\u0026#34;, \u0026#34;gists_url\u0026#34;: \u0026#34;https://api.github.com/users/xu4wang/gists{/gist_id}\u0026#34;, \u0026#34;starred_url\u0026#34;: \u0026#34;https://api.github.com/users/xu4wang/starred{/owner}{/repo}\u0026#34;, \u0026#34;subscriptions_url\u0026#34;: \u0026#34;https://api.github.com/users/xu4wang/subscriptions\u0026#34;, \u0026#34;organizations_url\u0026#34;: \u0026#34;https://api.github.com/users/xu4wang/orgs\u0026#34;, \u0026#34;repos_url\u0026#34;: \u0026#34;https://api.github.com/users/xu4wang/repos\u0026#34;, \u0026#34;events_url\u0026#34;: \u0026#34;https://api.github.com/users/xu4wang/events{/privacy}\u0026#34;, \u0026#34;received_events_url\u0026#34;: \u0026#34;https://api.github.com/users/xu4wang/received_events\u0026#34;, \u0026#34;type\u0026#34;: \u0026#34;User\u0026#34;, \u0026#34;site_admin\u0026#34;: false, \u0026#34;name\u0026#34;: \u0026#34;Austin\u0026#34;, \u0026#34;company\u0026#34;: null, \u0026#34;blog\u0026#34;: \u0026#34;https://awis.me\u0026#34;, \u0026#34;location\u0026#34;: \u0026#34;Shenzhen, China\u0026#34;, \u0026#34;email\u0026#34;: \u0026#34;xu4wang@gmail.com\u0026#34;, \u0026#34;hireable\u0026#34;: null, \u0026#34;bio\u0026#34;: \u0026#34;Working @ Bangkok , Beijing and Shenzhen\u0026#34;, \u0026#34;twitter_username\u0026#34;: null, \u0026#34;public_repos\u0026#34;: 26, \u0026#34;public_gists\u0026#34;: 1, \u0026#34;followers\u0026#34;: 10, \u0026#34;following\u0026#34;: 17, \u0026#34;created_at\u0026#34;: \u0026#34;2010-06-22T05:35:32Z\u0026#34;, \u0026#34;updated_at\u0026#34;: \u0026#34;2022-02-25T18:51:48Z\u0026#34; } From a security implementation perspective, applying for Token can be done between the backend and GitHub. This way, the final Token won\u0026rsquo;t appear on the frontend.\nAuthorization Request happens between browser and GitHub, getting Access Code (authorization code) is redirected by GitHub, which the browser gets. Client Secret can be stored only on the backend, so even if the frontend gets the Access Code, it can\u0026rsquo;t call the API to get the Token from GitHub. The frontend uses client_id to request an access code that the app can use, then the backend uses client_secret and access code together to apply for a token. This two-step design satisfies the requirement of using frontend for user authorization while also keeping the token hidden from the frontend, enhancing security.\n3. DingTalk OAuth Interaction Analysis On DingTalk, except for needing to configure OAuth app and add two permissions for reading personal info, other processes are similar to GitHub.\n3.1. Create OAuth APP In DingTalk Developer Center, create an H5 internal enterprise app. And authorize it to read personal phone number and contact info.\n3.2. Get code h r G h t e e t t d t t p i s p s r : s : e : / c / / t / l _ w o u w g r w i i . n = b . h a d t i i t d n p u g s . t % c a 3 o l A m k % / . 2 ? c F a o % u m 2 t / F h o w C a w o u w d t . e h b = 2 a 6 / i b a d 4 u u 2 t . 7 h c e ? o 8 m b % f 2 a F b \u0026amp; 8 r 3 e e s 9 p 3 o b n e s d e d _ 1 t 3 y f p 1 e 6 = a c 4 o 3 d 0 e 7 \u0026amp; 0 c 2 l i e n t _ i d = d i n g y o u r c l i e n t i d \u0026amp; s c o p e = o p e n i d \u0026amp; p r o m p t = c o n s e n t When getting code on DingTalk, there can be a corpId parameter to specify which organization\u0026rsquo;s user.\n3.3. Get token POST https://api.dingtalk.com/v1.0/oauth2/userAccessToken Content-Type:application/json { \u0026#34;clientId\u0026#34; : \u0026#34;ding your id\u0026#34;, \u0026#34;clientSecret\u0026#34; : \u0026#34;your secret\u0026#34;, \u0026#34;code\u0026#34; : \u0026#34;6b427e8bfab83e93bedd13f16a430702\u0026#34;, \u0026#34;grantType\u0026#34; : \u0026#34;authorization_code\u0026#34; } Gets: { \u0026#34;expireIn\u0026#34;: 7200, \u0026#34;accessToken\u0026#34;: \u0026#34;a8f4e3215a703ce9a7164e91dbab53c0\u0026#34;, \u0026#34;refreshToken\u0026#34;: \u0026#34;b13e5a61b421342d95d86c9e64c275c6\u0026#34; } 3.4. Read User Info GET https://api.dingtalk.com/v1.0/contact/users/me x-acs-dingtalk-access-token:a8f4e3215a703ce9a7164e91dbab53c0 Content-Type:application/json Gets: { \u0026#34;nick\u0026#34;: \u0026#34;AWIS ME\u0026#34;, \u0026#34;unionId\u0026#34;: \u0026#34;D578iS5hxxxx\u0026#34;, \u0026#34;avatarUrl\u0026#34;: \u0026#34;https://static-legacy.dingtalk.com/media/lADPGT5i9m5ZyXDNA4LNAtA_720.jpg\u0026#34;, \u0026#34;openId\u0026#34;: \u0026#34;WySPOpXqxE\u0026#34;, \u0026#34;mobile\u0026#34;: \u0026#34;1350xxxxxxxx\u0026#34;, \u0026#34;stateCode\u0026#34;: \u0026#34;86\u0026#34;, \u0026#34;email\u0026#34;: \u0026#34;xxxu@xxx.com\u0026#34; } 3.5. About Standard Compatibility In DingTalk\u0026rsquo;s OAuth 2 implementation, many parameter names differ from RFC6749 definitions. For example, code is called authCode in DingTalk, client_id is called clientId, grant_type is renamed to grantType, etc. Incompatibility with the standard means generic OAuth libraries (like openid-client) can\u0026rsquo;t directly integrate with DingTalk. This non-standard protocol design causes software to be non-reusable, wasting social resources, and should be despised.\n4. PKCE OAuth 2.0 public clients utilizing the Authorization Code Grant are susceptible to the authorization code interception attack. This specification describes the attack as well as a technique to mitigate against the threat through the use of Proof Key for Code Exchange (PKCE, pronounced \u0026ldquo;pixy\u0026rdquo;).\nPKCE is an extension of OAUTH2, originally intended to solve security issues for public clients (like browsers or app apps). But later recommended for the confidential clients described above.\nThe basic principle is when getting code in the first step, additionally pass two more parameters to the auth server:\ncode challenge code challenge method P c \u0026amp; \u0026amp; \u0026amp; \u0026amp; \u0026amp; \u0026amp; r l r s r s c c o i e c e t o o v e d o s a d d i n i p p t e e d t r e o e _ _ e _ e = n = c c r i c { s { h h d t S e r a a + = _ c _ a l l { u o t n l l c r p y d e e o l i e p o n n a i = } e m g g u e { = e e t n C c l = _ h t a o o { m / _ l d n c e r i l e g o t e d b d h d } a s e o i c t d r k r c = e i h S c U n a H t R g l A ? L } l 2 } e 5 n 6 g e } Where:\nc o d e c h a l l e n g e = c o d e _ c h a l l e n g e _ m e t h o d ( c o d e v e r i f i e r ) And code verifier is a random string.\nAfter receiving the request, the server saves code challenge and code_challenge_method, then issues the code.\nNext, when exchanging code for token, the client gives the code verifier and code to the server together. This allows the server to verify if the client exchanging for token is the same as the one that originally requested the code.\nThis way, even if malicious program intercepts the authorization code, without code_verifier, they can\u0026rsquo;t get the access token.\nPKCE can also be used for confidential (confidential) clients - that\u0026rsquo;s client_secret + code_verifier double key.\nIf OAuth2 only has client_secret without PKCE, there\u0026rsquo;s also a risk of user identity impersonation.\nThe attack principle is: a third party uses a browser plugin to get the code, then makes the victim\u0026rsquo;s OAuth flow fail, while using the stolen code to impersonate the victim to log in. With PKCE, the victim\u0026rsquo;s browser has code_verifier, which won\u0026rsquo;t be stolen along with the code (it\u0026rsquo;s not transmitted over the network before exchanging for token), so the attacker can\u0026rsquo;t impersonate the victim on the API server even with the code.\n5. References OAuth 2 Protocol Introduction RFC6750 OAuth 2 Framework Bearer Token Usage RFC6749 OAuth 2 Framework DingTalk Documentation https://datatracker.ietf.org/doc/html/rfc7636 ","permalink":"https://blog.thefreemeal.com/en/posts/2022-02-26-oauth/","summary":"\u003ch2 id=\"1-principle\"\u003e1. Principle\u003c/h2\u003e\n\u003cp\u003eSuppose there\u0026rsquo;s an APP that wants me to use GitHub for authorized login. In this login scenario:\u003c/p\u003e\n\u003cp\u003eI, as the data owner, tell the system (GitHub) that I agree to authorize a third-party application (App) to enter the system and obtain certain data (my ID, avatar, etc.). The system then generates a short-term access token to replace the password for the third-party application (APP) to access the data.\u003c/p\u003e","title":"OAuth2 Protocol Analysis: GitHub and DingTalk Examples"},{"content":"1. Introduction Open source software is the foundation of the information society.\nThere are many types of software on GitHub, with different market positioning and maturity levels.\nFor mature general-purpose software like Linux and NGINX, there are few concerns about introducing them into your own projects. Because they\u0026rsquo;re general-purpose, many people use them. You can find numerous success stories and many developers to maintain them. When problems arise, it\u0026rsquo;s easy to find answers online.\nBut there\u0026rsquo;s another category of open source software that is relatively less general-purpose. Although they\u0026rsquo;ve done well in their niche areas, due to the smaller ecosystem, there are many factors to consider when introducing them into projects:\nDo the existing developers have the ability to master and take over continued development? If problems occur during use, are there suitable developers to fix them or do secondary development? After the system goes live, are there suitable people for long-term maintenance? For this type of software, there are two ways to increase confidence before introducing it into a project:\nFind the right people Become a member of the software\u0026rsquo;s open source community 2. Find Experts Here are several methods:\nSearch for Chinese developers among the software\u0026rsquo;s developers and try to establish contact. Search for discussion forums and QQ groups related to the software on Baidu. Join and listen to identify experts. Find and participate in training related to the software. Find software related to this software on GitHub - for example, software that references it, plugins, etc. And establish contact with collaborators. The purpose of all the above is to establish real-world connections with experts. Then through phone calls, emails, meals, and other communications with experts, further understand the software\u0026rsquo;s domestic ecosystem and its pros and cons. Lay the foundation for future introduction. After establishing contact with experts, it\u0026rsquo;s convenient to cooperate with them on projects for win-win results.\n3. Become Part of the Open Source Community If you can\u0026rsquo;t find experts domestically, you have to roll up your sleeves and become an expert yourself.\n3.1. Learn to Use Mainly focus on these areas:\nOfficial documentation of the software Introduction videos on YouTube and third-party tutorials Unit tests of the software Combined with coarse-grained source code analysis, you can master the software\u0026rsquo;s general outline.\n3.2. Discuss with Peers General open source software communities have these places:\nGitHub Project Issues GitHub Project Discussions Discord or Slack discussion groups Email mailing lists By joining and seeing what people are discussing, you can learn some usage details and applicable scenarios of the software. While learning, also think more, ask more questions, and answer community questions.\nAnswering community questions can focus on areas related to your project. Actively answering questions has two benefits:\nDrive yourself to think deeply - if I encounter this problem in my project, how should I handle it? Build connections with other community users and software developers/maintainers This is the discussion community for Headless CMS Directus. I\u0026rsquo;ve been researching using Directus as an API middleware recently, and watched the project\u0026rsquo;s discussion area. GitHub sends all discussions to a specific email of mine in real-time. Through reading everyone\u0026rsquo;s discussions, I\u0026rsquo;ve gained a lot. I also summarized my learned experiences to help other users - I\u0026rsquo;m ranked 5th on the \u0026ldquo;Most Helpful\u0026rdquo; list.\n3.3. Small-Scale MVP Verification On the basis of reading, you also need to do hands-on work.\nBased on your project\u0026rsquo;s characteristics, define a minimum MVP process related to the software and try to introduce the open source software to implement it.\nThese three points complement each other and can be carried out simultaneously. The ideal result is:\nYou become an expert and introduce it in the project During research, discover the software isn\u0026rsquo;t suitable and decisively give up ","permalink":"https://blog.thefreemeal.com/en/posts/2022-02-25-how-to-learn-a-foss/","summary":"\u003ch2 id=\"1-introduction\"\u003e1. Introduction\u003c/h2\u003e\n\u003cp\u003eOpen source software is the foundation of the information society.\u003c/p\u003e\n\u003cp\u003eThere are many types of software on GitHub, with different market positioning and maturity levels.\u003c/p\u003e\n\u003cp\u003eFor mature general-purpose software like Linux and NGINX, there are few concerns about introducing them into your own projects. Because they\u0026rsquo;re general-purpose, many people use them. You can find numerous success stories and many developers to maintain them. When problems arise, it\u0026rsquo;s easy to find answers online.\u003c/p\u003e","title":"Introducing Niche Open Source Software into Your Project"},{"content":"Using Core to Push Water There are two land-based auxiliary exercises:\nRolling-Driven Push Extend the lead arm into the catch position, keeping the elbow and both shoulders in a straight line. Through shoulder rotation, create extension on the side of the entering hand. At the same time, keep the catch side\u0026rsquo;s elbow and shoulders in a straight line for as long as possible. The focus is on the catch elbow and both shoulders in a straight line. The elbow tip pushes forward and upward along the shoulder extension line, with the forearm naturally hanging down. Through this focus, experience completing the push through shoulder rotation and retraction. The arm only needs to maintain the catch shape - don\u0026rsquo;t actively push. Especially in the first half of the push. In the second half, after the shoulder retracts enough and the scapula is in a good position for power generation, you can actively push.\nUsing Waist Power Based on the previous exercise, when catching, feel the waist extension on the catch side. As you rotate and retract the shoulder, also intentionally tighten the same-side waist. Through this, catch more water through waist extension, and drive the latissimus dorsi to push water through waist movement.\n2022 PB Today the pool was not crowded, and I swam my 2022 PB (Personal Best).\n","permalink":"https://blog.thefreemeal.com/en/posts/2022-02-20-swim-catch-and-pull/","summary":"\u003ch2 id=\"using-core-to-push-water\"\u003eUsing Core to Push Water\u003c/h2\u003e\n\u003cp\u003eThere are two land-based auxiliary exercises:\u003c/p\u003e\n\u003ch3 id=\"rolling-driven-push\"\u003eRolling-Driven Push\u003c/h3\u003e\n\u003col\u003e\n\u003cli\u003eExtend the lead arm into the catch position, keeping the elbow and both shoulders in a straight line.\u003c/li\u003e\n\u003cli\u003eThrough shoulder rotation, create extension on the side of the entering hand. At the same time, keep the catch side\u0026rsquo;s elbow and shoulders in a straight line for as long as possible.\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003eThe focus is on the catch elbow and both shoulders in a straight line. The elbow tip pushes forward and upward along the shoulder extension line, with the forearm naturally hanging down.\nThrough this focus, experience completing the push through shoulder rotation and retraction. The arm only needs to maintain the catch shape - don\u0026rsquo;t actively push. Especially in the first half of the push. In the second half, after the shoulder retracts enough and the scapula is in a good position for power generation, you can actively push.\u003c/p\u003e","title":"Feelings About Catch and Push in Freestyle Swimming"},{"content":"Leo is Stopping Development This morning I read a message from EKR on the mailing list:\nLeo 6.6 may be the last substantial release in Leo\u0026rsquo;s history. At present, the 6.6 to-do list contains five items. There are no items at present on the 6.7 to-do list. Many open items remain, but I have little desire to do any of them. Expect 6.6 final in a month or so.\nThe leojs project now seems like the future of Leo. Indeed, it melds Leo with vs code, an unbeatable combination imo.\nAs a long-time user of Leo Editor, I\u0026rsquo;d like to pay tribute here. EKR also promoted leojs in the email, which reminds me of:\nAnything that can be Written in JavaScript, will Eventually be Written in JavaScript\nLeo Memories I used Leo for knowledge management for a period of time. I recorded project information of all sizes, wrote documents, meeting notes, and took notes.\nI also made some extensions for it:\nAdded keyboard shortcuts for Git Add, Commit, and GitHub Push - one button to automatically commit to local git and push to a private GitHub repository for backup. The save-push button in the image above does this. Read xmpp messages sent from phone and generated image files and text info under specific Leo nodes. Added encryption/decryption for certain node information. Added bi-directional sync with simpletask todo.txt files. Could manage a todo list on both phone and computer simultaneously. Later, after switching to Foam in VS Code, I used Leo less and less. Leo itself is an Outliner that displays knowledge in a tree structure. Each node has a topic and content. Nodes have different types with different display methods.\nIn the community, some people use it for code development - Leo itself is a large Python project developed within Leo. Many non-software professionals also use it for writing documents and notes.\nClone Operation, Leo\u0026rsquo;s Soul Leo has one characteristic that\u0026rsquo;s impressive. It can create Views of knowledge. For example, if you save many small knowledge fragments, each paragraph is a Node. When you have a new project, you can create a node and clone other system nodes into this project.\n\u0026ldquo;Clone\u0026rdquo; is the term used in the Leo community, but \u0026ldquo;reference\u0026rdquo; would be more accurate. The information isn\u0026rsquo;t copied - it\u0026rsquo;s referenced in the view.\nIf each subtree is treated as a project view, the same paragraph can appear in different views. Change one place, and others change too. Deleting one view doesn\u0026rsquo;t affect others. Only when the paragraph itself and all its clones are deleted does the information truly get removed from the system.\nThis allows creating multiple views of knowledge for different scenarios and projects.\nFor work that needs focused attention for a period of time, you can easily create a view, clone the nodes you need into it. After the work is done, just delete the view node. The work results are already reflected in other system nodes.\nLeo internally uses a Directed Acyclic Graph (DAG) data structure to store nodes, supporting the clone operation.\nIn the image above, you can see Node D under both Node A and C. The reason for using an acyclic graph is that Leo has many commands that traverse all child nodes. For example, generating a PDF from a node - all child nodes become chapters. An acyclic graph supports this scenario well.\nFuture Leo is powerful with great extensibility and a friendly development community. The problem is that as an editor, its ecosystem isn\u0026rsquo;t good enough - the community is too small.\nBelieving in embracing VS Code is the right choice. Using leojs to bring Leo\u0026rsquo;s essence into VS Code as an extension, combining with other extensions, will bring richer features to users.\n","permalink":"https://blog.thefreemeal.com/en/posts/2022-02-19-leo-end-development/","summary":"\u003ch2 id=\"leo-is-stopping-development\"\u003eLeo is Stopping Development\u003c/h2\u003e\n\u003cp\u003eThis morning I read a message from EKR on the mailing list:\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003eLeo 6.6 may be the last substantial release in Leo\u0026rsquo;s history. At present, the 6.6 to-do list contains five items. There are no items at present on the 6.7 to-do list. Many open items remain, but I have little desire to do any of them. Expect 6.6 final in a month or so.\u003c/p\u003e\n\u003cp\u003eThe leojs project now seems like the future of Leo. Indeed, it melds Leo with vs code, an unbeatable combination imo.\u003c/p\u003e","title":"Leo Editor Python Development Coming to an End"},{"content":" Review:\nJavaScript language-defined callbacks, promises, await, async JavaScript/NodeJS engine (libuv) OS IO multiplexing (epoll) Understanding how async functions work and are implemented makes it easier to read and debug JavaScript code.\n1. Introduction For programmers accustomed to thread pools, multi-processes, and message queues, there are a few concepts to understand when using JavaScript/NodeJS:\nCallbacks, Promises, Async Await IO multiplexing and async access 2. Callbacks, Promises, Async Await There\u0026rsquo;s a YouTube video Async JS Crash Course - Callbacks, Promises, Async Await that explains these concepts clearly in 24 minutes.\nCallbacks are the most basic, but they have a problem: when writing async functions, you need to pass a callback function as a parameter. If that function itself is async and also has a callback parameter, and there are many layers, you get \u0026ldquo;callback hell\u0026rdquo; - the code becomes very hard to read.\nTo solve this, Promise adds a layer of abstraction. When defining an async function, you no longer need to specify the callback function. Instead, you can:\nUse .then() to define callbacks for successful execution Use .catch() to define callbacks for errors Async Await is a further abstraction over Promise. It makes async functions look like synchronous functions (no more explicit .then() for callbacks).\nHere\u0026rsquo;s an example from Google\u0026rsquo;s official documentation:\nasync function myFirstAsyncFunction() { try { const fulfilledValue = await promise; } catch (rejectedValue) { // … } } When you use the async keyword before a function definition, you can use await inside that function. When you await a Promise, the function pauses execution until the Promise resolves, and this pause doesn\u0026rsquo;t block the main thread. If the Promise resolves, it returns the value. If it rejects, it throws the rejection value.\nWhen a JavaScript program executes, it first runs each statement synchronously line by line. When it encounters a callback, it puts that callback in a queue and continues to the next statement. After all statements are executed, it checks which callbacks in the queue are ready to run and executes them. See the NodeJS Event Loop section below.\ndoA(function() { doB(); doC(function() { doD(); }); doE(); }); doF(); The execution order is: A, F, B, C, E, D. All of ABCDEF don\u0026rsquo;t depend on external events. When a function is a callback of an async function, its execution also depends on whether the corresponding event has occurred.\nFor example:\n\u0026lt;p id=\u0026#34;content\u0026#34;\u0026gt; Please wait three seconds!\u0026lt;/p\u0026gt; \u0026lt;script\u0026gt; setTimeout(\u0026#34;changeState()\u0026#34;,3000 ); function changeState(){ let content=document.getElementById(\u0026#39;content\u0026#39;); content.innerHTML=\u0026#34;\u0026lt;div style=\u0026#39;color:red\u0026#39;\u0026gt;I appear after 3 seconds!\u0026lt;/div\u0026gt;\u0026#34;; } \u0026lt;/script\u0026gt; The changeState function above only executes after the timer fires. See the Timers section in the event loop description below.\nThe callback is configured through setTimeout, which is a built-in async function of the JS engine. Calling it returns immediately, but the callback will be invoked when the specific event occurs.\nA JavaScript program has various callback functions, triggered through timers or network/file access functions provided by JS. The internal callback implementation uses IO multiplexing and async mechanisms.\n3. IO Multiplexing and Async Access IO multiplexing (event-driven IO) is not unique to JavaScript/NodeJS - it\u0026rsquo;s a general IO access pattern used by most high-performance web servers (e.g., nginx).\nJavaScript is famous for async IO access because it only supports this IO method. It forces programmers to use this less intuitive but high-performance design pattern, which is great for IO-intensive applications.\nPython also supports async IO, but due to historical reasons, most applications use multi-process/multi-thread approaches with synchronous IO processing within processes.\nlibevent, libev, libuv are third-party libraries for building IO multiplexing applications. Their main purpose is to shield differences in OS APIs and provide a unified interface for applications.\nThese libraries can support large concurrent connections in network server applications because they can delegate the scanning of thousands of IO states to the operating system with minimal memory consumption. For new network requests:\nNo new process/thread is needed, reducing resource consumption No additional async polling is needed at the application layer - just use epoll_ctl to tell the OS Both browser JS and backend NodeJS have async mechanisms. Fundamentally, they access OS-provided async IO APIs within the OS process (Chrome process or NodeJS process). Let\u0026rsquo;s analyze primarily with NodeJS as the example.\nNodeJS uses libuv to implement IO multiplexing and async IO. libuv started as part of the NodeJS project but has been adopted by other projects, for example Python\u0026rsquo;s Fastapi also uses libuv.\nNote: UNP: Unix Network Programming divides IO access into 5 categories:\nblocking I/O nonblocking I/O I/O multiplexing (select and poll) signal driven I/O (SIGIO) asynchronous I/O (the POSIX aio_ functions) The third category uses epoll, which is an enhanced version of select/poll.\nThe fifth category in UNP refers to async IO where the OS handles data reading/writing and the application only cares about completion events (similar to DMA).\nThis differs from JavaScript\u0026rsquo;s async IO, which more precisely refers to non-blocking IO under IO multiplexing.\n3.1. NodeJS Event Loop timers: this phase executes callbacks scheduled by setTimeout() and setInterval(). pending callbacks: executes I/O callbacks deferred to the next loop iteration. idle, prepare: only used internally. poll: retrieve new I/O events; execute I/O related callbacks (almost all with the exception of close callbacks, the ones scheduled by timers, and setImmediate()); node will block here when appropriate. check: setImmediate() callbacks are invoked here. close callbacks: some close callbacks, e.g. socket.on(\u0026lsquo;close\u0026rsquo;, \u0026hellip;). As shown in the NodeJS official documentation, the event loop\u0026rsquo;s main thread continuously polls (on Linux, through libuv calling epoll_wait) to check which events have occurred, then calls the corresponding user-registered callbacks.\n3.2. libuv The libuv documentation introduces it as:\nAnother important dependency is libuv, a C library that is used to abstract non-blocking I/O operations to a consistent interface across all supported platforms. It provides mechanisms to handle file system, DNS, network, child processes, pipes, signal handling, polling and streaming. It also includes a thread pool for offloading work for some things that can\u0026rsquo;t be done asynchronously at the operating system level.\nAs you can see in libuv:\nNetwork IO: uses OS-provided async IO implementations File operations: uses thread pools to provide async event interfaces 3.3. OS Calls in Network IO For network data sending/receiving, libuv wraps different operating systems. On Linux, it uses the async IO API epoll, which provides three APIs:\nint epoll_create(int size); int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event); int epoll_wait(int epfd, struct epoll_event *events, int maxevents, int timeout); Applications configure which events to listen for via epoll_ctl, and query which events have occurred via epoll_wait.\nNote:\nepoll_ctl can configure events like file descriptor readability, writability, etc. epoll_wait may not block - the timeout parameter can be very short to check events and return immediately. NodeJS works this way. If it blocked forever, the event loop wouldn\u0026rsquo;t turn. 4. Summary JavaScript uses async methods to access IO. For code readability, it has made several abstractions on top of callbacks. Async Await now looks very similar to synchronous functions.\nJavaScript\u0026rsquo;s async events are supported by the underlying operating system. Events are triggered by the OS and read by JavaScript\u0026rsquo;s internal event loop, which then calls the corresponding event handler callbacks.\nJavaScript code cannot independently generate events. JavaScript async functions are implementations of callbacks required by engine APIs, and further abstractions over those engine APIs.\n","permalink":"https://blog.thefreemeal.com/en/posts/2022-02-12-node-sync/","summary":"\u003cblockquote\u003e\n\u003cp\u003eReview:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eJavaScript language-defined callbacks, promises, await, async\u003c/li\u003e\n\u003cli\u003eJavaScript/NodeJS engine (libuv)\u003c/li\u003e\n\u003cli\u003eOS IO multiplexing (epoll)\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eUnderstanding how async functions work and are implemented makes it easier to read and debug JavaScript code.\u003c/p\u003e\u003c/blockquote\u003e\n\u003ch2 id=\"1-introduction\"\u003e1. Introduction\u003c/h2\u003e\n\u003cp\u003eFor programmers accustomed to thread pools, multi-processes, and message queues, there are a few concepts to understand when using JavaScript/NodeJS:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eCallbacks, Promises, Async Await\u003c/li\u003e\n\u003cli\u003eIO multiplexing and async access\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"2-callbacks-promises-async-await\"\u003e2. Callbacks, Promises, Async Await\u003c/h2\u003e\n\u003cp\u003eThere\u0026rsquo;s a YouTube video \u003ca href=\"https://www.youtube.com/watch?v=PoRJizFvM7s\u0026amp;list=PLz-wA1QEiaA4bqejYQGjfhHhqc21CYV0w\u0026amp;index=4\"\u003eAsync JS Crash Course - Callbacks, Promises, Async Await\u003c/a\u003e that explains these concepts clearly in 24 minutes.\u003c/p\u003e","title":"JavaScript Asynchronous Execution Mechanism"}]