<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:cc="http://cyber.law.harvard.edu/rss/creativeCommonsRssModule.html">
    <channel>
        <title><![CDATA[Stories by zhaoolee on Medium]]></title>
        <description><![CDATA[Stories by zhaoolee on Medium]]></description>
        <link>https://medium.com/@zhaoolee?source=rss-1744b6bf3efb------2</link>
        <image>
            <url>https://cdn-images-1.medium.com/fit/c/150/150/1*eQH_8_KDn7_45254WQfdUg.jpeg</url>
            <title>Stories by zhaoolee on Medium</title>
            <link>https://medium.com/@zhaoolee?source=rss-1744b6bf3efb------2</link>
        </image>
        <generator>Medium</generator>
        <lastBuildDate>Sat, 30 May 2026 12:14:51 GMT</lastBuildDate>
        <atom:link href="https://medium.com/@zhaoolee/feed" rel="self" type="application/rss+xml"/>
        <webMaster><![CDATA[yourfriends@medium.com]]></webMaster>
        <atom:link href="http://medium.superfeedr.com" rel="hub"/>
        <item>
            <title><![CDATA[From Google Maps to Lazy Bars: How Hacker News Is Inspiring the Next Wave of Tech Innovation]]></title>
            <link>https://medium.com/@zhaoolee/from-google-maps-to-lazy-bars-how-hacker-news-is-inspiring-the-next-wave-of-tech-innovation-01f0f2952183?source=rss-1744b6bf3efb------2</link>
            <guid isPermaLink="false">https://medium.com/p/01f0f2952183</guid>
            <dc:creator><![CDATA[zhaoolee]]></dc:creator>
            <pubDate>Wed, 16 Oct 2024 10:07:06 GMT</pubDate>
            <atom:updated>2024-10-16T10:07:06.048Z</atom:updated>
            <content:encoded><![CDATA[<p>Today, while reading Hacker News, I found a very interesting view. The author suggests using Google to help you decide when moving to a new house.</p><p>For example, if I’m considering a house at 005 A Street, I should input the address into Google Maps and analyze the results. If I can find good results, it means the address can easily receive shopping packages. It also indicates that I can vote in elections using this address, apply for a credit card, and enjoy convenient traffic and lifestyle options. An address easily found on Google often signifies a well-connected location.</p><p>Google is a tool containing vast amounts of data, providing users with needed information. Almost all open-source human knowledge can be found on Google, and more importantly, this knowledge gateway is free!</p><p>I love Hacker News; it always provides amazing information. High-quality products drive world progress. Recently, I discovered a product called “Busy Bar” on Hacker News. It’s a small computer with a 30cm x 8cm screen that displays “busy” as its default status.</p><p>We can control the screen content via an Android app. The content can be text, an image, or a website. It can request information via API, such as displaying “a word every day.” The product includes a button that, when pressed, can trigger a 15-minute event and show the remaining time. The “Busy Bar” is priced at $189, which I think offers good value.</p><p>As a Raspberry Pi enthusiast, I want to create a product called “Lazy Bar.” Similar to the “Busy Bar,” it would consist of a screen and a Raspberry Pi 3B, designed for hackers. The screen could display a web page showing brief information like Linux server health status or typical phrases like “I’m lazy, don’t call me.”</p><p>The web page would receive information via MQTT, which offers real-time updates with fewer limitations.</p><p>I plan to create a shell for the “Lazy Bar” using 3D printing, which costs about $5/kg in 2024 — a price I find acceptable.</p><p>I have another idea: the “Lazy Bar” could be developed as a project to engage Raspberry Pi fans. If sold for $99, it might generate some profit and create job opportunities.</p><p>I believe the “Lazy Bar” is well-suited for digital enthusiasts who want to check their self-server status, such as CPU usage, NAS operations, disk read/write rates, and real-time network speeds. The “Lazy Bar” can display various statuses in an easy-to-read format.</p><p>What makes a good product? I think it must be interesting, something people want to use. Users should find it intriguing just by looking at it and feel that interacting with it will provide an even more enjoyable experience.</p><p>The “Lazy Bar” is a tool running Android, similar to a Kindle or smartphone. Unlike a Kindle, it can auto-run and support our lives once set up, operating for extended periods like a clock. Unlike a smartphone, the “Lazy Bar” displays important information in its main area without requiring constant user interaction.</p><p>As technology advances, ChatGPT continues to provide knowledge based on our prompts. The “Lazy Bar” doesn’t need prompts; it always shows real-time information to users. This could include RSS updates we’ve subscribed to, reminders to drink water for our health, or suggestions to take a break from the computer screen and look at nature.</p><p>In summary, Hacker News is a valuable website that can broaden our perspectives and provide interesting ideas that may make the world more enjoyable.</p><p>I’m a professional front-end programmer, developing web, Android, and Electron applications. I’ve published many open-source projects on GitHub, such as Chrome extension tutorials, auto-management of WordPress posts using Markdown, and GitHub Actions to collect the best information via RSS. If you want to find more interesting open-source projects, you can visit <a href="https://github.com/zhaoolee">https://github.com/zhaoolee</a>.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=01f0f2952183" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[1 trick of auto Update New Medium Blog Feed to Github]]></title>
            <link>https://medium.com/@zhaoolee/automatically-updating-new-medium-blog-feed-to-github-homepage-via-github-actions-05a942fbfe4e?source=rss-1744b6bf3efb------2</link>
            <guid isPermaLink="false">https://medium.com/p/05a942fbfe4e</guid>
            <dc:creator><![CDATA[zhaoolee]]></dc:creator>
            <pubDate>Sun, 22 Sep 2024 05:03:34 GMT</pubDate>
            <atom:updated>2024-10-12T05:02:10.845Z</atom:updated>
            <content:encoded><![CDATA[<p>Medium allows you to subscribe to an author’s articles and images via Feed. For example, if my username is @zhaoolee</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*U-H59R4k0CjaM_ZvphTbdQ.png" /></figure><p>then my dedicated feed link would be <a href="https://medium.com/feed/@zhaoolee">https://medium.com/feed/@zhaoolee</a></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*kccuKd74OWwMg4quZueSxw.png" /></figure><p>My Github username is also zhaoolee, so I just need to create a repository named zhaoolee <a href="https://github.com/zhaoolee/zhaoolee">https://github.com/zhaoolee/zhaoolee</a>, and write the following code in main.py :</p><pre>import feedparser<br>import time<br>import os<br>import re<br>from datetime import datetime<br>import pytz<br><br>def get_link_info(feed_url, num):<br>    feed = feedparser.parse(feed_url)<br>    entries = feed.entries[:num]<br>    return &quot;\n&quot;.join(f&quot;- [{entry.title}]({entry.link})&quot; for entry in entries)<br><br>def update_readme(insert_info):<br>    readme_path = os.path.join(os.getcwd(), &quot;README.md&quot;)<br>    with open(readme_path, &#39;r&#39;, encoding=&#39;utf-8&#39;) as f:<br>        content = f.read()<br>    <br>    update_time = datetime.now(pytz.timezone(&#39;Asia/Shanghai&#39;)).strftime(&#39;%Y-%m-%d %H:%M:%S&#39;)<br>    insert_info = f&quot;&quot;&quot;---start---<br><br>## zhaoolee（老法师昭昭）的每日更新<br><br>&gt; 更新时间: {update_time} | 本部分通过Github Actions抓取RSS自动更新，无意中实现了自动刷绿墙...<br><br>{insert_info}<br><br>---end---&quot;&quot;&quot;<br><br>    new_content = re.sub(r&#39;---start---(.|\n)*---end---&#39;, insert_info, content)<br>    <br>    with open(readme_path, &#39;w&#39;, encoding=&#39;utf-8&#39;) as f:<br>        f.write(new_content)<br>    <br>    return insert_info<br><br>def main():<br>    feeds = [<br>        (&quot;https://medium.com/feed/@zhaoolee&quot;, 3)<br>    ]<br>    <br>    all_info = []<br>    for url, num in feeds:<br>        feed_info = get_link_info(url, num)<br>        all_info.append(feed_info)<br>        print(f&quot;\n获取到的 {url} 的信息：\n{feed_info}\n&quot;)<br><br>    insert_info = &quot;\n\n&quot;.join(all_info)<br>    <br>    final_result = update_readme(insert_info)<br>    print(&quot;\n最终更新到 README.md 的内容：\n&quot;)<br>    print(final_result)<br><br>if __name__ == &quot;__main__&quot;:<br>    main()</pre><p>Write a Github Actions scheduled task at <a href="https://github.com/zhaoolee/zhaoolee/blob/main/.github/workflows/main.yml">https://github.com/zhaoolee/zhaoolee/blob/main/.github/workflows/main.yml</a> to automatically run every 15 minutes, and you can synchronize my feed to the Github homepage.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*nEiPZHkWXg6WEjzpRkqfHA.png" /><figcaption>x</figcaption></figure><p>After updating the article links to the Github homepage, you just need to click on the title in the red box to enter the Medium article page. If your Github open-source project is good enough, it can even bring better search engine SEO for Medium articles!</p><p>If you also want to have a similar effect, you just need to fork my repository <a href="https://github.com/zhaoolee/zhaoolee">https://github.com/zhaoolee/zhaoolee</a> and modify the feed link in main.py. If you really don’t understand the code, you can ask AI for help with modifications.</p><h3>Summary</h3><p>I used to be a fanatic of Jianshu, which is a product similar to Medium in the Chinese internet. Unfortunately, Jianshu doesn’t make money in China and was sold, so I had to find a similar product as a substitute. Eventually, I chose Medium. From <a href="https://www.jianshu.com/u/c5d047065c42">https://www.jianshu.com/u/c5d047065c42</a> to <a href="https://medium.com/@zhaoolee">https://medium.com/@zhaoolee</a>, original high-quality content is scarce on any platform. I hope to receive good creative feedback on Medium as well.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*hFnyDs8fKLmbHKLaX6WCwg.png" /></figure><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=05a942fbfe4e" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Enhancing Docker Usage Experience: Elegantly Setting Docker Restart Policies for ZenTao]]></title>
            <link>https://medium.com/@zhaoolee/enhancing-docker-usage-experience-elegantly-setting-docker-restart-policies-for-zentao-2709ecd00a9e?source=rss-1744b6bf3efb------2</link>
            <guid isPermaLink="false">https://medium.com/p/2709ecd00a9e</guid>
            <dc:creator><![CDATA[zhaoolee]]></dc:creator>
            <pubDate>Sat, 21 Sep 2024 10:21:33 GMT</pubDate>
            <atom:updated>2024-09-21T10:21:33.107Z</atom:updated>
            <content:encoded><![CDATA[<h4>Encountering a Minor Issue with Unexpected Service Stoppage</h4><p>Recently, I set up two PostGIS databases using Docker, one for the testing environment and another for the production environment. Later, when adjusting the Docker configuration and restarting Docker, I discovered that the database in the testing environment had crashed, while the production environment database was running normally.</p><p>Upon investigation, I found that the two services had different restart policies.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*hlV_7LRT78D_LHn5J9aWrg.png" /></figure><p>To check the current restart policy of a container, use the following command:</p><pre>docker inspect --format=&#39;{{.HostConfig.RestartPolicy.Name}}&#39; container_name_or_id</pre><p>Consequently, I set the restart policy of the testing environment container <strong>testpostgis</strong> to <strong>unless-stopped</strong>:</p><pre>docker update --restart unless-stopped container_name_or_id</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*yN0lfnkCqQVDf4nYwK4zVA.png" /></figure><p>Problem solved perfectly!</p><h4>Improving the Running Method: Elegant Use of the Open-Source Project ZenTao</h4><p>If you also use ZenTao for requirement management, you’ll find that with the official running command, ZenTao needs to be manually restarted if Docker restarts. By using the unless-stopped parameter, you can make ZenTao automatically resume service after restarting Docker or the server.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*2oRgXVgPuR0_WBR0NGWbzg.png" /></figure><p>ZenTao Docker startup documentation:</p><p><a href="https://www.zentao.net/book/zentaopms/docker-1111.html">https://www.zentao.net/book/zentaopms/docker-1111.html</a></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*0iy1bsYnLhYyMDO0lHCyxw.png" /></figure><p>Using unless-stop in conjunction with Docker’s auto-start on boot can significantly reduce operational risks.</p><h4>There are four restart policies:</h4><ul><li>no (no restart): This is the default restart policy, suitable for data analysis scripts. For example, a Python script that runs nightly to process log files and generate reports. The script exits naturally after running and doesn&#39;t need to restart.</li><li>on-failure (restart on failure): Suitable for scheduled task services. For instance, a cron job scheduler is expected to run normally and exit, but if it crashes due to an unexpected error, it needs to restart to ensure subsequent tasks can be executed.</li><li>always (always restart): Suitable for web servers. For example, Nginx needs to run 24/7 without interruption to serve website visits.</li><li>unless-stopped (always restart unless stopped): Suitable for databases in development environments. Developers may need to frequently modify configurations or data and can manually stop the container instead of deleting it each time.</li></ul><h4>Summary</h4><p>Mastering these restart policies can make us more adept at using Docker to run services. Even when encountering events like Docker restarts or server reboots, we can methodically restore various services.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=2709ecd00a9e" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[A Peculiar Experience of Being Schooled by Windows Server! Why Don’t More People Use Linux?]]></title>
            <link>https://medium.com/@zhaoolee/a-peculiar-experience-of-being-schooled-by-windows-server-why-dont-more-people-use-linux-0c2b9e96e559?source=rss-1744b6bf3efb------2</link>
            <guid isPermaLink="false">https://medium.com/p/0c2b9e96e559</guid>
            <dc:creator><![CDATA[zhaoolee]]></dc:creator>
            <pubDate>Sat, 21 Sep 2024 07:47:37 GMT</pubDate>
            <atom:updated>2024-09-21T07:47:37.951Z</atom:updated>
            <content:encoded><![CDATA[<p>Today, I encountered a rather amusing situation. I planned to deploy a local large language model on a Windows Server 2019 using Docker.</p><p>However, I discovered that Windows Server 2019 couldn’t directly install Docker Desktop. After researching various sources, I found out that I needed to enable containerization technology (Hyper-V And Containers).</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*bXZNlWWV6XhOswLbksnwQw.png" /></figure><p>After enabling it, Windows Server 2019 prompted that a restart was necessary to complete the installation process. To finish the installation, I had no choice but to restart, and that’s when things got interesting.</p><p>After restarting, I found that I couldn’t connect through Microsoft Remote Desktop no matter what. At first, I thought Windows was just slow to reboot, so I waited for half an hour, but still couldn’t connect. So, I contacted the on-duty administrator at the server room to investigate the issue. The final conclusion was: Blue Screen of Death!</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*b5a_qR8xfMILarO-nYsppw.png" /></figure><p>Windows Server 2019, as a server operating system, had actually blue-screened, causing the service to become completely unavailable, with no remote recovery options. The only solution was to have someone physically restart it at the server room.</p><p>After a round of investigation, I initially thought it might be due to Hyper-V not being enabled on the BIOS. So, I remotely guided the server room administrator to enable Hyper-V and disable BIOS security. Then I asked the admin to save the BIOS settings and restart!</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*oz4UwIyEGUxmGQh2SEC_fQ.png" /></figure><p>Windows Server 2019 surprised me even more. After saving the BIOS settings, it still blue-screened on restart. However, when they unplugged the power and restarted, it booted successfully. At this point, I could only describe it as a miracle.</p><p>At that moment, I was infected by a disease called curiosity. I tried to understand the underlying principle, so I issued another restart command through Microsoft Remote Desktop to see if the problem was completely resolved.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*PZfCog9cszoJg_FoODRFKg.png" /></figure><p>Microsoft, as a company, always manages to give the right kind of despair to arrogant people. Yes! After restarting, Windows Server 2019 blue-screened again. At this moment, two words simultaneously appeared in my mind: first, “Fascinating,” and second, “Damn Microsoft.”</p><p>Then I told the server room administrator to try restarting multiple times. We found that “only unplugging the power and restarting could avoid the blue screen” and allow entry into the system. Truly, there are learning points everywhere.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*bzy8uJLfWuO9I2t21k2jdA.png" /></figure><p>This article can contribute a few meaningless but life-quality-improving pieces of knowledge:</p><ol><li>Don’t mess with Windows Server 2019 if you don’t have to, and especially don’t restart it randomly.</li><li>If Windows Server 2019 blue screens, try unplugging the power and then turning it on again.</li><li>If you want to play with containerization, please choose a Linux operating system. It can avoid a lot of unnecessary trouble.</li></ol><p>I have a guess about the source of these problems. This machine has been used by too many people and has various software and drivers installed. There’s even an Epic Games pop-up appearing on Windows Server 2019. These drivers likely have issues, causing Windows restart commands to always fail, resulting in blue screens. In the end, the only way to start the machine is by cutting power and then turning it on again. But since the machine isn’t nearby, it’s hard to investigate. We’ll have to move the machine out of the server room at some future time to check the drivers.</p><p>Recently, there was an article titled: “Why don’t more people use Linux?”</p><p><a href="https://world.hey.com/dhh/why-don-t-more-people-use-linux-33b75f53">https://world.hey.com/dhh/why-don-t-more-people-use-linux-33b75f53</a></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*Chg5cv_jk_c68Fmchl4pdQ.png" /></figure><p>The article’s viewpoint is that few people use Linux because Linux has a high learning curve, not because Linux isn’t good enough. Exercise is beneficial to the body, but few people do it; reading elevates the spirit, but few people do it; junk food is harmful to the body, but many people love to eat it.</p><p>For computer enthusiasts, Linux can provide long-term value, allowing people to gain a deeper understanding of computers and enter a higher realm.</p><p>In the server domain, Linux is a dominant presence. The primary requirement for servers is security and stability. It’s precisely because Linux has a certain learning curve that people unfamiliar with Linux don’t have the ability to mess around with Linux servers. And it’s because no one messes around that Linux servers remain stable and secure.</p><p>In contrast, almost anyone can randomly double-click to install drivers on Windows Server 2019, leading to situations where Windows Server 2019 directly restarts and blue screens.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*3gVWQPRMLy-27RsKrC6INg.png" /></figure><p>I believe if Microsoft really wants to make a good server system, the simplest method would be to provide a mini version image for Windows Server. This mini image wouldn’t include a desktop environment, which could greatly improve the system’s stability and security.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=0c2b9e96e559" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[“Raspberry Pi Doesn’t Gather Dust” Issue 1: Flashing Ubuntu Server 20.04,]]></title>
            <link>https://medium.com/@zhaoolee/raspberry-pi-doesnt-gather-dust-issue-1-flashing-ubuntu-server-20-04-c1849340c8f4?source=rss-1744b6bf3efb------2</link>
            <guid isPermaLink="false">https://medium.com/p/c1849340c8f4</guid>
            <dc:creator><![CDATA[zhaoolee]]></dc:creator>
            <pubDate>Thu, 18 Jan 2024 09:04:22 GMT</pubDate>
            <atom:updated>2024-01-18T09:04:22.934Z</atom:updated>
            <content:encoded><![CDATA[<h3>“Raspberry Pi Doesn’t Gather Dust” Issue 1: Flashing Ubuntu Server 20.04, Binding a Public Domain Name, Providing HTTP Services to the Public Network, and SSH Login Service</h3><p>Flashing Ubuntu Server 20.04, Binding a Public Domain Name, Providing HTTP Services to the Public Network, and SSH Login Service</p><p>A while ago, I bought an 8GB RAM Raspberry Pi 4B and used a USB wireless card to turn it into a soft router Turning a Raspberry Pi 4B with an OpenWrt image into a portable router that transforms standard wifi into magic wifi https://v2fy.com/p/2021-07-04-openwrt-4b-1625383754000/, but later I felt that it was a waste to use an 8GB Raspberry Pi as a soft router. So this time, I transformed the Raspberry Pi 4B into a server accessible from the public network to run some memory-intensive tasks.</p><p>The native system of Raspberry Pi is not as rich in packages as Ubuntu, so this time I chose to flash Ubuntu Server 20.04 LTS.</p><p>To ensure that the Raspberry Pi server at home could be accessed from the public network, I used the open-source FRP technology for internal network penetration to bind the domain name frp.v2fy.com to the Raspberry Pi. Accessing the HTTP service on the Raspberry Pi is as simple as visiting <a href="https://frp.v2fy.com/">https://frp.v2fy.com</a>. I also set up SSH mapping so that the Raspberry Pi can be accessed via SSH by connecting to port 6000 of frp.v2fy.com on the public network.</p><h3>Principle Structure Diagram</h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*kYBNHZGgdsWNq15r.jpeg" /></figure><p><strong>About the Architecture of Internal Network Penetration</strong></p><p>The browser’s default requests to a domain name point to ports 80 (HTTP) and 443 (HTTPS). I installed Nginx on the server end to occupy ports 80 and 443 for receiving HTTP and HTTPS requests. Then I wrote a set of rules to forward all requests targeting frp.v2fy.com to port 8080. Part of the HTTPS rules also include configuration of an HTTPS certificate for frp.v2fy.com (Nginx automatic certificate renewal operation can be referred to Independence! Using acme.sh to set up multiple HTTPS certificates for nginx to automatically update, and indefinitely renew HTTPS certificates https://v2fy.com/p/2021-06-27-nginx-https-1624774964000/), and port 8080 is occupied by the FRP server process frps, which sends requests to the FRP client frpc on the Raspberry Pi. FRPC then forwards requests from FRP to the http-server service running on 8080 on the Raspberry Pi; the SSH forwarding rule is similar to the HTTP forwarding rule, forwarding from the server&#39;s port 6000 to the Raspberry Pi&#39;s port 22.</p><h3>Preliminary Preparation</h3><ol><li>Indispensable Raspberry Pi kit: A Raspberry Pi (generations 2, 3, 4 are all suitable, I chose the Raspberry Pi 4B), Raspberry Pi power supply, an SD card of at least 8GB (16GB or above recommended).</li><li>One good network cable with RJ45 connectors on both ends.</li><li>A router with internet access and one available LAN port.</li><li>A public network server with a fixed IP.</li><li>One domain name.</li><li>A 32GB or larger flash drive or high-capacity hard drive for expanding the server storage of the Raspberry Pi (optional).</li></ol><p>The main content starts next…</p><h3>Using SD Card Formatter to Format SD Card</h3><p>SD Card Formatter download link <a href="https://www.sdcard.org/downloads/formatter/">https://www.sdcard.org/downloads/formatter/</a></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/950/0*hp9--cs_MWwEMaw-.png" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/920/0*YFPXHRD-i0Lk5oRc.png" /></figure><h3>Download Image</h3><p>Download the image from <a href="https://ubuntu.com/download/raspberry-pi/thank-you?version=20.04.3&amp;architecture=server-arm64+raspi">https://ubuntu.com/download/raspberry-pi/thank-you?version=20.04.3&amp;architecture=server-arm64+raspi</a></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*pRPnyLtobGkzft_g.png" /></figure><p>After clicking download now on the page, you will get the file ubuntu-20.04.3-preinstalled-server-arm64+raspi.img.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/534/0*nlb2mOL0-Egv8Lzc.png" /></figure><p>If your browser often fails to download, I suggest putting https://cdimage.ubuntu.com/releases/20.04.3/release/ubuntu-20.04.3-preinstalled-server-arm64+raspi.img.xz directly into Free Download Manager for downloading (Free Download Manager is a free download tool with free cloud acceleration download function, which is friendly for downloading overseas resources).</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/908/0*pB6CIWXJGYmQE7u4.png" /></figure><h3>Using balenaEtcher to Flash the Image onto the SD Card</h3><p>balenaEtcher download link <a href="https://www.balena.io/etcher/">https://www.balena.io/etcher/</a></p><p>Select the version you need to download according to your own system. If you’re on Windows, you can directly download the first one shown below.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*vfnlSiRwUytz21Mt.png" /></figure><p>Open Etcher, select the image file, choose the SD card, and start burning.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/839/0*MVNG3kZah91DLuiK.png" /></figure><p>Here in the image it’s an 8GB SD card, but after a few failed attempts, I switched to a 16GB memory card and succeeded on the first try. If your burning fails repeatedly, I suggest trying with another SD card.</p><p>Insert the burned SD card into the Raspberry Pi, connect the Raspberry Pi to the router’s LAN port with a network cable, and power on the device.</p><h3>Log into the Router Backend to Check the IP Assigned to the Raspberry Pi with Ubuntu Installed</h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*TkSj_KHFJczjrmyx.png" /></figure><h3>Use SSH to Log in to the Raspberry Pi Server</h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/800/0*Mfztn9fRHwohnLc0.png" /></figure><p>The initial username and password are both ubuntu</p><h3>After the first login, you will be forced to change the default password</h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/785/0*bvQDe-Mn6a--PjhW.png" /></figure><p><strong>Below, we use FRP internal network penetration to give the Raspberry Pi home server an external domain name</strong></p><h3>Internal Network Penetration: Server Setup</h3><p>First, resolve your domain name to your server IP. The following steps will involve four server ports. To facilitate subsequent debugging runs, please open up the security policies for the following ports: 80 (for Nginx to receive HTTP requests), 443 (for Nginx to receive HTTPS requests), 6000 (for forwarding SSH services), and 8080 (for forwarding HTTP services) ports.</p><ul><li>Configure Nginx to forward requests for the frp.v2fy.com domain to the 8080 port (before doing this step, please install Nginx according to your server’s operating system).</li></ul><p>Set /etc/nginx/nginx.conf</p><pre>#user  nginx;<br>worker_processes  1;<br>load_module /usr/lib64/nginx/modules/ngx_stream_module.so;</pre><pre>error_log  /var/log/nginx/error.log warn;<br>pid        /var/run/nginx.pid;</pre><pre>stream {<br>    map $ssl_preread_server_name $backend_name {<br>        frp.v2fy.com        frp_v2fy_com;<br>        default web;<br>    }<br></pre><pre>   upstream frp_v2fy_com {<br>        server 127.0.0.1:8081;<br>   }</pre><pre>   upstream web {<br>        server 127.0.0.1:80;<br>   }</pre><pre>   server {<br>        listen       443 reuseport;<br>        listen  [::]:443 reuseport;<br>        proxy_pass   $backend_name;<br>        ssl_preread  on;<br>   }</pre><pre>}</pre><pre>events {<br>    worker_connections  1024;<br>}</pre><pre>http {</pre><pre>    include       /etc/nginx/mime.types;<br>    default_type  application/octet-stream;<br>    charset utf-8,gbk;<br>    client_max_body_size 20m;</pre><pre>    set_real_ip_from 127.0.0.1;<br>    real_ip_header X-Forwarded-For;<br></pre><pre>    log_format  main  &#39;$remote_addr  - $remote_user [$time_local] &quot;$request&quot; &#39;<br>                      &#39;$status $body_bytes_sent &quot;$http_referer&quot; &#39;<br>                      &#39;&quot;$http_user_agent&quot; &quot;$http_x_forwarded_for&quot;&#39;;<br>    access_log  /var/log/nginx/access.log  main;</pre><pre>    sendfile        on;<br>    #tcp_nopush     on;<br>    keepalive_timeout  65;<br>    gzip  on;<br>    include /etc/nginx/conf.d/*.conf;<br>}</pre><p>Create /etc/nginx/conf.d/frp.v2fy.com.conf, and write the following content into /etc/nginx/conf.d/frp.v2fy.com.conf (frp.v2fy.com is my domain, please replace it with your own domain name)</p><pre>server {<br>    server_name      frp.v2fy.com;<br>    listen           80;</pre><pre>    location / {<br>        proxy_pass <a href="http://127.0.0.1:8080;">http://127.0.0.1:8080;</a><br>        proxy_set_header Host $host:80;<br>        proxy_set_header X-Real-IP $remote_addr;<br>        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;<br>    }<br>}<br></pre><pre>server {<br>    listen       8081 ssl http2;<br>    listen       [::]:8081 ssl http2;<br>    server_name  frp.v2fy.com;</pre><pre>    location / {<br>        proxy_pass <a href="http://127.0.0.1:8080;">http://127.0.0.1:8080;</a><br>        proxy_set_header Host $host:443;<br>        proxy_set_header X-Real-IP $remote_addr;<br>        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;<br>    }</pre><pre>    ssl_certificate &quot;/etc/nginx/ssl/frp.v2fy.com/fullchain.cer&quot;;<br>    ssl_certificate_key &quot;/etc/nginx/ssl/frp.v2fy.com/frp.v2fy.com.key&quot;;<br>    ssl_session_cache shared:SSL:1m;<br>    ssl_session_timeout  10m;<br>    ssl_ciphers HIGH:!aNULL:!MD5;<br>    ssl_prefer_server_ciphers on;</pre><pre>    # Load configuration files for the default server block.<br>    include /etc/nginx/default.d/*.conf;</pre><p>Here is the translation of the provided Simplified Chinese Markdown documentation into English:</p><pre>error_page 404 /404.html;<br>    location = /40x.html {<br>}</pre><pre>error_page 500 502 503 504 /50x.html;<br>    location = /50x.html {<br>}</pre><p>Restart nginx</p><pre>nginx -t<br>nginx -s reload</pre><ul><li>Download frp and set up the server side</li></ul><p>Frp software is divided into two parts, the client is frpc, the server is frps</p><pre>cd /opt/<br>wget https://github.com/fatedier/frp/releases/download/v0.37.0/frp_0.37.0_linux_386.tar.gz<br>tar zxvf https://github.com/fatedier/frp/releases/download/v0.37.0/frp_0.37.0_linux_386.tar.gz</pre><p>The server side’s frpc configuration file is frpc.ini</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/631/0*bKp_w7l1KO6utRkT.png" /></figure><p>We need to modify the server-side configuration file frps.ini</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/892/0*5yTx1GDyNcJ44X9t.png" /></figure><pre>[common]<br>bind_port = 7000<br>vhost_http_port = 8080</pre><p>The above configuration means that the server side of frp named frps is running on port 7000, and it will forward requests targeting port 8080 to the client side;</p><ul><li>Run the following command to start the frp server-side program</li></ul><pre>./frps -c frps.ini</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/794/0*x-w60yCAy59sKCEu.png" /></figure><p>frps runs in the foreground by default. If you want to run it as a background daemon process, you can use the Node.JS version of pm2 to keep it running.</p><ul><li>Global installation method for pm2</li></ul><p>First, install Node.js (please choose the appropriate Node.js version for your server OS), npm is installed by default with Node.js, then use npm to install pm2</p><pre>npm i pm2 -g</pre><p>pm2 is also simple to use</p><p>First, save ./frps -c frps.ini in a file named start_frps.sh</p><p>Then run</p><pre>pm2 start /opt/frp_0.37.0_linux_arm64/start_frps.sh<br>pm2 save</pre><p>This way you can run frps as a daemon process!</p><p>At this point, running pm2 list, you can see that the script is running...</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*GP4K23s7b02N6fsX.png" /></figure><h3>Intranet Penetration: Client Setup</h3><ul><li>Execute the following command on the Raspberry Pi to download and extract frp</li></ul><pre>cd /opt/<br>sudo wget https://github.com/fatedier/frp/releases/download/v0.37.0/frp_0.37.0_linux_arm64.tar.gz<br>sudo tar zxvf frp_0.37.0_linux_arm64.tar.gz</pre><p>Enter /opt/frp_0.37.0_linux_arm64</p><p>Backup the client-side frpc’s configuration file frpc.ini</p><pre>sudo cp frpc.ini frpc.ini_backup</pre><ul><li>Edit frpc.ini</li></ul><pre>sudo vim frpc.ini</pre><ul><li>Insert the following configuration into frpc.ini</li></ul><pre>[common]<br>server_addr = (your server public IP)<br>server_port = 7000</pre><pre>[web]<br>type = http<br>local_port = 8080<br>custom_domains = frp.v2fy.com</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/486/0*mB6xSWT4F7ytnfiL.png" /></figure><ul><li>Use a web browser to access the Raspberry Pi from the public network to verify if the intranet penetration is successful</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*esENs8MpyW2OjBN-.png" /></figure><h4>Install Node.js (using the ARMv8 version of the stable Node.js)</h4><p>(Updated January 14, 2024) If you want to install Node.js automatically, it’s recommended to use nvm <a href="https://github.com/nvm-sh/nvm">https://github.com/nvm-sh/nvm</a></p><pre>curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.7/install.sh | bash<br>nvm install 20.11.0<br>nvm alias default 20.11.0</pre><p>After checking the wiki for Raspberry Pi CPU architecture, it seems that Raspberry Pi Series 3 and later versions are ARMv8 architecture</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*ShYWKTLHQKcobX2i.png" /></figure><p>Use the ARMv8 version of the stable Node.js</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*4fkpI3WGhrJxN77I.png" /></figure><pre>cd /opt/<br>sudo wget https://nodejs.org/dist/v14.18.0/node-v14.18.0-linux-arm64.tar.xz<br>sudo tar xvf node-v14.18.0-linux-arm64.tar.xz</pre><ul><li>Add Node.js to system variables</li></ul><pre>sudo echo &quot;export NODE_HOME=/opt/node-v14.18.0-linux-arm64&quot; &gt;&gt; ~/.bashrc<br>sudo echo &quot;export PATH=\$NODE_HOME/bin:\$PATH&quot; &gt;&gt; ~/.bashrc<br>source ~/.bashrc</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/957/0*gVhrSHesoQu1k_Jo.png" /></figure><ul><li>Install the http-server service</li></ul><pre>npm install http-server -g</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*_rpnVLhUopwruj0r.png" /></figure><ul><li>Create a frp.v2fy.com folder in the /opt directory and create a hello.txt file</li></ul><pre>sudo mkdir /opt/frp.v2fy.com<br>sudo chmod 777 -R  /opt/frp.v2fy.com<br>sudo touch /opt/frp.v2fy.com/hello.txt<br>sudo echo &quot;Hello World! Success! &quot; &gt; /opt/frp.v2fy.com/hello.txt</pre><ul><li>Install pm2</li></ul><pre>npm install pm2 -g</pre><ul><li>Use pm2 to daemonize the http-server service</li></ul><pre>cd /opt/frp_0.37.0_linux_arm64 <br>sudo chmod 777 start_http_server.sh<br>sudo echo &quot;http-server /opt/frp.v2fy.com -p 8080&quot; &gt; start_http_server.sh<br>pm2 start /opt/frp_0.37.0_linux_arm64/start_http_server.sh<br>pm2 save</pre><ul><li>Use pm2 to daemonize the frpc service</li></ul><pre>sudo touch /opt/frp_0.37.0_linux_arm64/start_frpc.sh<br>sudo chmod 777 /opt/frp_0.37.0_linux_arm64/start_frpc.sh<br>sudo echo &quot;/opt/frp_0.37.0_linux_arm64/frpc -c /opt/frp_0.37.0_linux_arm64/frpc.ini&quot; &gt; /opt/frp_0.37.0_linux_arm64/start_frpc.sh<br>cd /opt/frp_0.37.0_linux_arm64/<br>pm2 start  /opt/frp_0.37.0_linux_arm64/start_frpc.sh<br>pm2 save</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*hl2tXpXeDO3dcOJX.png" /></figure><p>Visit <a href="https://frp.v2fy.com/">https://frp.v2fy.com</a></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/631/0*E6R16HZ1cKl2Y_5S.png" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/469/0*b-MTZH3XgsL6MPu5.png" /></figure><p>Here you can successfully access the HTTPS services of a home server via the public network.</p><h3>Add SSH service</h3><ul><li>Add configuration</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/955/0*f-DZhewctZdkRY6S.png" /></figure><pre>[ssh]<br>type = tcp<br>local_ip = 127.0.0.1<br>local_port = 22<br>remote_port = 6000</pre><p>The configuration means to map the default ssh port 22 of the Raspberry Pi to port 6000 of frp.v2fy.com</p><ul><li>Restart the frpc service</li></ul><pre>cd /opt/frp_0.37.0_linux_arm64<br>pm2 restart start_frpc.sh</pre><ul><li>Log in through the ssh of the public network frp.v2fy.com at port 6000</li></ul><pre>ssh ubuntu@frp.v2fy.com -p 6000</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*XRadhRxNnuqYqp-3.png" /></figure><p>Thus, we can access our home Raspberry Pi server via ssh from any computer on the internet.</p><h3>Set pm2 to start on boot, so that after an accidental power loss and restart of the Raspberry Pi, it can automatically start the intranet penetration</h3><pre>ubuntu@ubuntu:/opt/frp_0.37.0_linux_arm64$ pm2 startup<br>[PM2] Init System found: systemd<br>[PM2] To setup the Startup Script, copy/paste the following command:<br>sudo env PATH=$PATH:/opt/node-v14.18.0-linux-arm64/bin /opt/node-v14.18.0-linux-arm64/lib/node_modules/pm2/bin/pm2 startup systemd -u ubuntu --hp /home/ubuntu<br>ubuntu@ubuntu:/opt/frp_0.37.0_linux_arm64$ sudo env PATH=$PATH:/opt/node-v14.18.0-linux-arm64/bin /opt/node-v14.18.0-linux-arm64/lib/node_modules/pm2/bin/pm2 startup systemd -u ubuntu --hp /home/ubuntu<br>[PM2] Init System found: systemd<br>Platform systemd<br>Template<br>[Unit]<br>Description=PM2 process manager<br>Documentation=https://pm2.keymetrics.io/<br>After=network.target</pre><pre>[Service]<br>Type=forking<br>User=ubuntu<br>LimitNOFILE=infinity<br>LimitNPROC=infinity<br>LimitCORE=infinity<br>Environment=PATH=/opt/node-v14.18.0-linux-arm64/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin:/opt/node-v14.18.0-linux-arm64/bin:/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin<br>Environment=PM2_HOME=/home/ubuntu/.pm2<br>PIDFile=/home/ubuntu/.pm2/pm2.pid<br>Restart=on-failure</pre><p>ExecStart=/opt/node-v14.18.0-linux-arm64/lib/node_modules/pm2/bin/pm2 resurrect ExecReload=/opt/node-v14.18.0-linux-arm64/lib/node_modules/pm2/bin/pm2 reload all ExecStop=/opt/node-v14.18.0-linux-arm64/lib/node_modules/pm2/bin/pm2 kill</p><p>[Install] WantedBy=multi-user.target</p><p>Target path: /etc/systemd/system/pm2-ubuntu.service Command list:</p><ul><li>‘systemctl enable pm2-ubuntu’ [PM2] Writing init configuration in /etc/systemd/system/pm2-ubuntu.service [PM2] Making script booting at startup… [PM2] [-] Executing: systemctl enable pm2-ubuntu… [PM2] [v] Command successfully executed. + — — — — — — — — — — — — — — — — — — — -+ [PM2] Freeze a process list on reboot via: $ pm2 save</li></ul><p>[PM2] Remove init script via: $ pm2 unstartup systemd ubuntu@ubuntu:/opt/frp_0.37.0_linux_arm64$</p><p>Run pm2 startup, then run the command that pops up sudo env PATH=$PATH:/opt/node-v14.18.0-linux-arm64/bin /opt/node-v14.18.0-linux-arm64/lib/node_modules/pm2/bin/pm2 startup systemd -u ubuntu --hp /home/ubuntu</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*7njW2knvUHa4ePcu.png" /></figure><p>To verify that the automatic startup is set correctly, I pulled the power from the Raspberry Pi, and indeed the HTTP service was unavailable</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*xhYXNqa779xMgO-F.png" /></figure><p>Powering the Raspberry Pi on, frp.v2fy.com can be accessed again</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/716/0*inmW_p1OS-8XAx0Q.png" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*XGIvgl8i3riG_OoY.png" /></figure><h3>Adding More Capacity to Raspberry Pi (with a 32GB USB Drive)</h3><p>The SD card I am using is only 16GB, which is too small, so I plugged a 32GB USB drive into the Raspberry Pi for expanded capacity. After inserting the USB drive into the Raspberry Pi, enter the following command to see if the USB drive is recognized:</p><pre>sudo fdisk -l</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/758/0*4fhOYd9tjPD_ZHOR.png" /></figure><p>The USB drive is located at /dev/sda1.</p><ul><li>Mount /dev/sda1 to /mnt/sda1:</li></ul><pre>sudo mkdir /mnt/sda1<br>sudo mount /dev/sda1 /mnt/sda1</pre><p>Enter /mnt/sda1, and you can read and write files to the USB drive.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/467/0*Px9fhpJHJBNA-lx1.png" /></figure><p>We can also mount the USB drive to the web service folder:</p><pre>sudo mkdir /opt/frp.v2fy.com/sda1<br>sudo mount /dev/sda1 /opt/frp.v2fy.com/sda1</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/663/0*lV0JZ9Zpa8-Vme4n.png" /></figure><p>Once again, visit https://frp.v2fy.com, and you can access all the files on the USB drive via <a href="https://frp.v2fy.com/sda1.">https://frp.v2fy.com/sda1.</a></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/804/0*zN-laS-htpwx-ru0.png" /></figure><h3>What Can You Do with a Server?</h3><ul><li>Unlock greyed-out songs on NetEase Cloud Music for free Use a private server to brighten up NetEase Cloud Music songs and share with friends around you <a href="https://v2fy.com/p/2021-07-07-net-server-1625654857000/">https://v2fy.com/p/2021-07-07-net-server-1625654857000/</a></li><li>Create a free image hosting service for the popular Markdown editor Typora Coding at home on New Year&#39;s Day, I completed a private image hosting tool for the Markdown artifact Typora~ Can be run on Windows, macOS, Linux <a href="https://v2fy.com/p/2021-01-02-easytypora-1609587043000/">https://v2fy.com/p/2021-01-02-easytypora-1609587043000/</a></li><li>Build a full-featured website with a database for free 《Nginx WordPress Site Building Guide》Build a highly playable website <a href="https://v2fy.com/p/tips-000003-nginx-wordpress/">https://v2fy.com/p/tips-000003-nginx-wordpress/</a></li><li>Establish a BBS forum for free Setting up a new generation BBS forum site with Discourse in 30 minutes in 2021 <a href="https://v2fy.com/p/2021-06-12-discourse-2021-1623477573000/">https://v2fy.com/p/2021-06-12-discourse-2021-1623477573000/</a></li><li>Create a free VScode cloud development environment, available anytime, anywhere Deploy VSCode to server tutorial, log in the game on the web! Start &quot;cloud coding&quot;! Can be used as an SSH client~ <a href="https://v2fy.com/p/2021-07-12-vscode-1626075074000/">https://v2fy.com/p/2021-07-12-vscode-1626075074000/</a></li><li>Deploy your own RSS crawler server for free The full record of privately deploying RSSHub <a href="https://v2fy.com/p/2021-09-07-rsshub-1631018903000/">https://v2fy.com/p/2021-09-07-rsshub-1631018903000/</a></li></ul><h3>Conclusion</h3><p>Through this operation, I provided a domain name frp.v2fy.com for the home-use Raspberry Pi by using internal network penetration, which can be accessed via the public network; by configuring ssh, it is possible to remotely log in using ssh to the frp.v2fy.com port 6000 from anywhere on the internet.</p><p>Recently zhaoolee has been researching K8S clusters and needed a few high-performance hosts, but memory and hard drives are too expensive, so he put the Raspberry Pi 4B to use. With internal network penetration, it can serve like a real server on the internet.</p><p>Setting up your own server at home is every boy’s dream. As long as there are no power outages, no internet disconnections, and the Raspberry Pi board doesn’t explode, we can have an extremely cost-effective server at a very low cost.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=c1849340c8f4" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[To deeply experience Hades, I wrote an open-source program that reads all NPC dialogues in English…]]></title>
            <link>https://medium.com/@zhaoolee/to-deeply-experience-hades-i-wrote-an-open-source-program-that-reads-all-npc-dialogues-in-english-03578fb92e40?source=rss-1744b6bf3efb------2</link>
            <guid isPermaLink="false">https://medium.com/p/03578fb92e40</guid>
            <dc:creator><![CDATA[zhaoolee]]></dc:creator>
            <pubDate>Wed, 17 Jan 2024 10:39:55 GMT</pubDate>
            <atom:updated>2024-01-17T10:39:55.452Z</atom:updated>
            <content:encoded><![CDATA[<h3>To deeply experience Hades, I wrote an open-source program that reads all NPC dialogues in English and Chinese</h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*8kGzIC0JwO31Mivo.png" /></figure><p><a href="https://www.supergiantgames.com/games/hades/">Hades</a> embraces fragmented storytelling. Each time players embark on a challenge, NPCs engage in different dialogues filled with clever banter. According to bilibili users, these dialogues are hilariously entertaining 🤣.</p><p>These dialogues are stored in the Subtitles folder within the game&#39;s directory. To delve deeper into this game, I wrote a script to deduplicate the dialogues from various NPCs. I then created a table displaying these dialogues in a bilingual format, with both English and Chinese versions. This table can be found in the README.md of the open-source project hosted at <a href="https://github.com/zhaoolee/hades">https://github.com/zhaoolee/hades</a>.</p><p>By reading the repository’s README, you can gain a deep understanding of each NPC and uncover various hidden plots within the game. It’s also an opportunity to learn English by comparing translations and to appreciate the unique artistic style of Hades’ posters.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/648/0*eahUl-1_Yve_OPcK.png" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*5mM8ZWpuhv5reXhN.jpeg" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*NOoTbzV4jBxd_Nki.jpeg" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*fFrnjxIEEfEFAT-6.png" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*LtczAg2m1kdVF_YL.png" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/953/0*O-JX4WnuVg9VHL8O.png" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*gOwZgGvdfnFiYzYu.png" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*yjzxdYk1RkG5-IfV.png" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*-64lP4MK4QmLb8aG.png" /></figure><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=03578fb92e40" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[2 Way to Solve macOS Network Problems]]></title>
            <link>https://medium.com/@zhaoolee/2-way-to-solve-macos-network-problems-72a463be475b?source=rss-1744b6bf3efb------2</link>
            <guid isPermaLink="false">https://medium.com/p/72a463be475b</guid>
            <dc:creator><![CDATA[zhaoolee]]></dc:creator>
            <pubDate>Wed, 03 Jan 2024 12:05:35 GMT</pubDate>
            <atom:updated>2024-01-03T12:05:35.825Z</atom:updated>
            <content:encoded><![CDATA[<h3>The First Way: Switch Off IPv6</h3><p>I encountered an issue where Chrome display the message Your connection was interrupted A network change was detected. ERR_NETWORK_CHANGED I tried many solutions, such as <strong>reinstall Chrome</strong> , <strong>Closing VPNs, and clearing the cache , </strong>but I could not resolve problem</p><p>I could not stand the persistent Your connection was interrupted message, so I did not give up on finding a way to fix it.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*QLFKu_DWKNL3CbMb.png" /></figure><p>Finally, I found the answer at <a href="https://github.com/brave/brave-browser/issues/5958">https://github.com/brave/brave-browser/issues/5958</a></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*fYhwyONpgKFehfyb.png" /></figure><p>In short, display IPv6, by running the following command in Terminal</p><pre>networksetup -setv6off &quot;Wi-Fi&quot;</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/599/0*tbn0I6sJ3Ej57njo.png" /></figure><p>After running the command, you can find that Configure IPv6 is set to <strong>Off</strong></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/704/0*4TqUIINNDLEv9DF9.png" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/691/0*q7ep3t59h0Qn1YMb.png" /></figure><p>Restart macOS, and the <strong>ERR_NETWORK_CHANGED </strong>should no longer appear!</p><h3>The Second Way: Create New Locations</h3><p>Recently，I discovered that when I visited some HTTP websites, I was redirected to an anti-fraud website after using the bookstore’s Wi-Fi. The reason is that my DNS is polluted.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/720/0*0p9WftnlF5qyKDeL.png" /></figure><p>I find a way to clean my DNS by reading <a href="https://support.apple.com/en-us/105129">https://support.apple.com/en-us/105129</a></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*3vmVBvrffzfCpvPg.png" /></figure><p>The specifict method to create a new location:</p><ul><li>Open <strong>System Settings</strong></li><li>Select <strong>Network</strong>, you will find a button at the bottom of the pane</li><li>Click the Button, and a menu will appear</li><li>Select <strong>Location</strong>, click <strong>Edit</strong>, and create a new location, set a name for new location(such as the current date)</li><li>Final, choose the new location, and I should work!</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*KnAyfF3t7wZPh7CNCUGkJw.gif" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*vC-gR1Bbzp4x_98k.png" /></figure><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=72a463be475b" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[The meaning of life is learning and try]]></title>
            <link>https://medium.com/@zhaoolee/the-meaning-of-life-is-learning-and-try-979fa08856a1?source=rss-1744b6bf3efb------2</link>
            <guid isPermaLink="false">https://medium.com/p/979fa08856a1</guid>
            <dc:creator><![CDATA[zhaoolee]]></dc:creator>
            <pubDate>Sat, 23 Dec 2023 13:43:26 GMT</pubDate>
            <atom:updated>2024-01-04T02:34:03.015Z</atom:updated>
            <content:encoded><![CDATA[<h2>The meaning of life is learning and trying</h2><p>How can one enjoy life?</p><p>I believe the best way to enjoy life is by acquiring new knowledge. In the past two weeks, I have finished two books and a series of video lessons.</p><p>By learning new skills and trying to improve existing ones, I have become really happy.</p><p>If you feel bored with life, try reading a book or watching a video course. By learning a new skill or gaining new knowledge, you will find more color in the world.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=979fa08856a1" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Utilizing a Raspberry Pi: A Guide for Programmers and Enthusiasts]]></title>
            <link>https://medium.com/@zhaoolee/utilizing-a-raspberry-pi-a-guide-for-programmers-and-enthusiasts-e1bd0ec4ecba?source=rss-1744b6bf3efb------2</link>
            <guid isPermaLink="false">https://medium.com/p/e1bd0ec4ecba</guid>
            <dc:creator><![CDATA[zhaoolee]]></dc:creator>
            <pubDate>Tue, 19 Dec 2023 10:43:16 GMT</pubDate>
            <atom:updated>2023-12-19T10:43:16.582Z</atom:updated>
            <content:encoded><![CDATA[<p>Utilizing a Raspberry Pi: A Guide for Programmers and Enthusiasts</p><p>The Raspberry Pi, a compact computer roughly the size of a credit card, is often underestimated. While some may dismiss it as nothing more than a dust collector, I see its potential.</p><p>To illustrate its capabilities, I’ve established a GitHub project which serves as a practical guide:</p><p><a href="https://github.com/zhaoolee/pi">GitHub - zhaoolee/pi: 树莓派教程，树莓派防吃灰小分队，让树莓派不再吃灰~</a></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1000/0*jNLgrVxBfVj3TIT9" /></figure><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=e1bd0ec4ecba" width="1" height="1" alt="">]]></content:encoded>
        </item>
    </channel>
</rss>