2020年12月27日 星期日

限制不能使用最近三次的历史密码

 https://www.cnblogs.com/insus/archive/2012/01/30/2332013.html


https://dotblogs.com.tw/mis2000lab/2014/08/14/member_login_out-of-time_and_new-password

2020年12月8日 星期二

如何截取完整網頁畫面?Chrome快捷鍵讓你輕鬆取得高畫質長截圖

 https://www.bnext.com.tw/article/47401/chrome-screenshot


Windows為F12

Windows為Ctrl + Shift + P

輸入命令Capture full size screenshot(只輸前幾個字母就能找到),敲下Enter, Chrome就會自動截取整個網頁內容並保存至本機

2020年12月1日 星期二

C# 鎖USB

 https://blog.miniasp.com/post/2008/01/18/How-to-disable-the-use-of-USB-storage-devices

https://blog.xuite.net/kenny.pro2/blog/212310907

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Diagnostics;

namespace WindowsFormsApplication1
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e)  //"禁用USB隨身碟"那個Button
        {
            if (textBox1.Text == "1qaz")  //每次都要先輸入此密碼 ,Button才能按
            {
                if (MessageBox.Show("是否確定要禁用隨身碟!!", "禁用!!", MessageBoxButtons.YesNo) == DialogResult.Yes)   // YES/NO 確認
                {
                    Reg_Method(@" ADD HKEY_LOCAL_MACHINESYSTEMCurrentControlSetServicesUSBSTOR /v Start /t REG_DWORD /d 4 /f");
                    MessageBox.Show("已禁用隨身碟 !!   隨身碟重拔插後生效");
                } 
            }
            else
                MessageBox.Show("密碼錯誤");
        }

        private void button2_Click(object sender, EventArgs e)  //"開放USB隨身碟"那個Button
        {
            if (textBox1.Text == "1qaz")
            {
                if (MessageBox.Show("是否確定要開放隨身碟!!", "開放!!", MessageBoxButtons.YesNo) == DialogResult.Yes)    // YES/NO 確認
                {
                    Reg_Method(@" ADD HKEY_LOCAL_MACHINESYSTEMCurrentControlSetServicesUSBSTOR /v Start /t REG_DWORD /d 3 /f");
                    MessageBox.Show("已開放隨身碟 !!   隨身碟重拔插後生效");
                }
            }
            else
                MessageBox.Show("密碼錯誤");
        }

        private void button3_Click(object sender, EventArgs e)  //"唯讀USB隨身碟"那個Button
        {
            if (textBox1.Text == "1qaz")
            {
                if (MessageBox.Show("是否確定要"唯讀"USB隨身碟!!", "唯讀!!", MessageBoxButtons.YesNo) == DialogResult.Yes)   // YES/NO 確認
                {
                    Reg_Method(@" ADD HKEY_LOCAL_MACHINESYSTEMCurrentControlSetControlStorageDevicePolicies /v WriteProtect /t REG_DWORD /d 1 /f");
                    MessageBox.Show("已唯讀隨身碟 !!   隨身碟重拔插後生效");
                }
            }
            else
                MessageBox.Show("密碼錯誤");
        }

        private void button4_Click(object sender, EventArgs e)  //"可寫入USB隨身碟"那個Button
        {
            if (textBox1.Text == "1qaz")
            {
                if (MessageBox.Show("是否確定要讓隨身碟可寫入!!", "可寫入!!", MessageBoxButtons.YesNo) == DialogResult.Yes)   // YES/NO 確認
                {
                    Reg_Method(@" ADD HKEY_LOCAL_MACHINESYSTEMCurrentControlSetControlStorageDevicePolicies /v WriteProtect /t REG_DWORD /d 0 /f");
                    MessageBox.Show("隨身碟已可寫入 !!   隨身碟重拔插後生效");
                }
            }
            else
                MessageBox.Show("密碼錯誤");
        }

        private void button5_Click(object sender, EventArgs e)  //說明那個Button
        {
            MessageBox.Show("禁用USB隨身碟 : 禁用所有Windows認定的USB儲存裝置"
                + Environment.NewLine + "開放USB隨身碟 : 開放所有Windows認定的USB儲存裝置"
                + Environment.NewLine + "唯讀USB隨身碟 : USB儲存裝置,只能讀取無法寫入(限此台電腦)"
                + Environment.NewLine + "可寫入USB隨身碟 : USB儲存裝置,只能讀取可讀可寫(限此台電腦)");
        }

        // --------------------------------  Register Method  ---------------------------------------------------
        private static void Reg_Method(string x)
        {
            ProcessStartInfo reg = new ProcessStartInfo("reg.exe", x);
            reg.WindowStyle = ProcessWindowStyle.Hidden;
            Process.Start(reg);
        }
    }
}

執行起來Form的樣子:



2020年11月10日 星期二

產品行銷規劃

 1.發新聞稿

2.line face

3.blog

4.youtube

5.EDM

6.google analysis

7.電子雜誌

8.行銷通路

9.策略聯盟


1.電子型錄

2.網站產品介紹

3.使用情境

4.使用方法,操作手冊

5.錄製使用影片


市調

分析

TA

定位

手段

費用

績效評估

PKI

2020年11月8日 星期日

2020年11月5日 星期四

Winform啟動時隱藏不顯示

 https://www.itread01.com/content/1536044185.html

http://blueweite.blogspot.com/2014/06/c-winform-hide-winform.html

2020年10月26日 星期一

c#錄音和放音,超簡單!不用DirectX

 https://www.itdaan.com/tw/e7d5e5f305ed


https://www.codeproject.com/Articles/31356/C-MP3-Sound-Capturing-Recording-Component

2020年10月23日 星期五

禁用格式化磁碟操作 保護電腦文件安全防止刪除

 禁用格式化磁碟操作 保護電腦文件安全防止刪除

https://kknews.cc/zh-tw/news/y5958ek.html

對於磁碟格式化的操作,是通過Format.exe程序來實現,因此我們也有必要對可以實現磁碟格式化的軟體進行限制運行操作,從而 實現更徹底的防止格式化磁碟操作


2020年10月21日 星期三

1 20使用asp net core必须会依赖注入

 https://www.youtube.com/watch?v=I6cevbG6aSs

https://www.youtube.com/watch?v=ToUut_LBZbs&list=PL_ejO7vn7l2358FsVgNZI944kEIn4NNJ8

2020年10月20日 星期二

IHttpClientFactory要安裝的原件

 



webapi jwt 實作

 

=====================================================================

瀏覽器會有WEB API 跨域請求


傳統作法

1.btn_1登入後,取得帳號

2.btn_2 在前端驗證帳號

3.如果有帳號,將帳號傳送出去

4.取得該帳號個資


有風險

1.直接在前端避掉驗證帳號

2.可以在前端將帳號變更(明碼)

3.可以直接取得帳號個資


jwt

1.在後端做驗證帳號

2.btn_1登入後,將帳號比對後,做jwt加密,回傳token

3.btn_2 將token加入headers回傳,申請取得資料

4.在後端將token解密比對帳號,如果帳號ok

5.將帳號個資回傳


如果將token用工具解密,在Payload內容變更帳號,然後直接線上產生一組新的token

將token回傳,申請取得資料,會無法解密。

(因為必須透過jwt開始時透過key加密方法產生的token才有辦法解密時,透過key來解密)



2020年10月14日 星期三

依赖注入

https://www.bilibili.com/video/BV1QZ4y1u72y/?spm_id_from=333.788.videocard.4 

https://www.youtube.com/watch?v=B76TOeGad6M

https://www.bilibili.com/video/BV1ck4y1r79C/?spm_id_from=333.788.videocard.7

https://www.bilibili.com/video/BV1Bf4y1278A/?spm_id_from=333.788.videocard.1

==========================================================

https://haokan.baidu.com/v?vid=9126350290334122060&pd=bjh&fr=bjhauthor&type=video

https://www.facebook.com/will.fans/videos/711522182929613/

https://www.facebook.com/watch/?v=271242413931518

.NET Core(C#) 使用IHttpClientFactory实现爬虫执行GET和POST请求






2020年10月4日 星期日

LINQ

 https://www.youtube.com/watch?v=g1EU9gnZKOg&list=PLZX6sKChTg8GQxnABqxYGX2zLs4Hfa4Ca&index=33

===============================================================

using System;

using System.Collections.Generic;

using System.ComponentModel;

using System.Data;

using System.Drawing;

using System.Linq;

using System.Text;

using System.Threading.Tasks;

using System.Windows.Forms;


namespace pt

{

    public partial class Form1 : Form

    {

        weberpEntities db = new weberpEntities();

        public Form1()

        {

            InitializeComponent();

        }

        private void button1_Click(object sender, EventArgs e)

        {

            label1.Text = "";

            var allitem = db.bas_item.ToList();

            foreach (var item in allitem)

            {

                label1.Text += item.mname + "\r\n";

            }

        }


        private void button2_Click(object sender, EventArgs e)

        {

            label1.Text = "";

            var item = db.bas_item.Select(p => p.mname).ToList();

            foreach (var fn in item)

            {

                label1.Text += fn + "\r\n";

            }

        }


        private void button3_Click(object sender, EventArgs e)

        {

            label1.Text = "";

            var item = db.bas_item.Where(p=>p.price_sale==500).Select(p => p.mname+":費用"+p.price_sale).ToList();

            foreach (var fn in item)

            {

                label1.Text += fn + "\r\n";

            }

        }


        private void button4_Click(object sender, EventArgs e)

        {

            label1.Text = "";

            var YesOrNo= db.bas_item.All(p => p.price_sale == 500);

            label1.Text = YesOrNo.ToString();

        }


        private void button5_Click(object sender, EventArgs e)

        {

            label1.Text = "";

            var YesOrNo = db.bas_item.Any(p => p.price_sale == 500);

            label1.Text = YesOrNo.ToString();

        }

        private void button6_Click(object sender, EventArgs e)

        {

            label1.Text = "";

            var groups = db.bas_item.GroupBy(p => p.mname).ToList();

            foreach (var g in groups)

            {

                label1.Text += g.Key + ":" + g.Count() + "\r\n";

            }          

        }

        private void button7_Click(object sender, EventArgs e)

        {

            label1.Text = "";

            var count = db.bas_item.Count(p => p.placeid == 1);

            label1.Text = count.ToString();       

        }

    }

}


2020年9月24日 星期四

[C#.NET] 如何列舉輸入法

 https://dotblogs.com.tw/yc421206/2009/08/09/9966


https://www.twblogs.net/a/5c46a628bd9eee35b21efde4

2020年9月22日 星期二

C# - 實作載入外部 DLL 外並使用 Method

 https://blog.xuite.net/f8789/DCLoveEP/36480071-C%23+-+%E5%AF%A6%E4%BD%9C%E8%BC%89%E5%85%A5%E5%A4%96%E9%83%A8+DLL+%E5%A4%96%E4%B8%A6%E4%BD%BF%E7%94%A8+Method

2020年9月19日 星期六

c# 檢測作業系統版本

 https://www.prugg.at/2019/09/09/properly-detect-windows-version-in-c-net-even-windows-10/


https://kknews.cc/zh-tw/code/xyvjxq.html


https://docs.microsoft.com/zh-tw/windows/win32/api/winnt/ns-winnt-osversioninfoa?redirectedfrom=MSDN

2020年9月18日 星期五

如何使用VirtualBox虛擬機軟件

 https://www.youtube.com/watch?v=uE6EHy_hgng

07 VirtualBox快照備份與還原


https://www.youtube.com/watch?v=7PkGXhDp7_s


2020年9月16日 星期三

C# 系統集合泛型(System.Collections.Generic) Queue, Stack

 

C# 系統集合泛型(System.Collections.Generic) Queue, Stack



https://adon988.logdown.com/posts/1209582-c-generic-systems-collection-system-collections-generic-queue-stack-teaching-notes-using-visual-studio

過濾方法改寫

 


namespace WindowsFormsApp1

{

    public partial class Form1 : Form

    {

        public Form1()

        {

            InitializeComponent();

        }


        private void button1_Click(object sender, EventArgs e)

        {

            List<string> ary = new List<string>()

            {

                "tony",

                "mary",

                "c:"

            };

            string var = @"tony\sss\ee";

            //ary.ForEach(x => x = var);

            label1.Text = ary.FirstOrDefault(x => var.Contains(x));

        }


        bool flag = false;


        private void _watch_Created(object sender, FileSystemEventArgs e)

        {

            先非同步過濾

            

            下面放在非同步裡面

            

            存入 Queue(e.FullPath);

            if (!flag)

            {

                flag = true;

                用非同步的方法 handleQueue();

            }

        }


        public asyc void handleQueue()

        {

            //逐筆處理 Queue集合的東西

            flag = flase;

        }

    }



}

2020年9月14日 星期一

ASP.NET Core 3.x 入门视频

 https://www.bilibili.com/video/BV1c441167KQ/?spm_id_from=333.788.videocard.0

https://www.bilibili.com/video/av92363688/

https://www.bilibili.com/video/BV1XJ411q7yy/?spm_id_from=333.788.videocard.0

市场调查

 https://www.bilibili.com/video/BV1sV411f7KS

https://space.bilibili.com/88225156/channel/detail?cid=117664

https://search.bilibili.com/all?keyword=%E5%B8%82%E5%9C%BA%E8%B0%83%E7%A0%94%E5%92%8C%E4%BA%A7%E5%93%81%E8%A7%84%E5%88%92&from_source=nav_search_new

https://www.bilibili.com/video/BV1Z64y1F7Ah/?spm_id_from=333.788.videocard.2

https://www.bilibili.com/video/BV19J411R7Pc?from=search&seid=5540238887719149637

2020年9月9日 星期三

c#進階

 https://www.youtube.com/watch?v=XrH6q5_VkwQ

https://www.youtube.com/watch?v=RGewr2UuWmk

https://www.youtube.com/watch?v=ZxW9v0CflH4

2020年9月8日 星期二

序列化

https://blog.xuite.net/grimmslaw/78/52048294-%E5%BA%8F%E5%88%97%E5%8C%96%EF%BC%88Serialization%EF%BC%89

 

序列化(Serialization)是.NET平臺最酷的特性之一。

1、為什麼要序列化:

首先你應該明白序列化的目的就不難理解他了。序列化的目的就是能在網路上傳輸物件,否則就無法實現面向物件的分散式計算。比如你的用戶端要調用伺服器上的一個方法獲得一個產品物件,比如方法為:public   Product   findProduct(int   product_id);   

  注意該方法返回一個Product物件,如果沒有序列化技術,用戶端就收不到返回的物件Product。而序列化的實現就是把物件變成一個可在網路上傳輸的位元組流。

2、利用序列化技術,可以實現物件的備份和還原。序列化可以將記憶體中的物件(或物件圖)序列化為資料流程,並保存到磁片上進行持久化;還可以將資料流程反序列化為物件,實現物件的還原。序列化技術在分散式系統的資料傳輸中得到充分的利用,如:XML Web Service 利用XML序列化實現跨平臺,.NET Remoting 則用到了二進位序列化和SOAP序列化。

.NET Compact Framework 2.0 支援XML序列化,不支援二進位序列化和SOAP序列化。而 .NET Compact Framework 1.0 XML序列化都不支持。不過 OpenNETCF 1.x  .NET CF 1.0 實現了一個XML序列化的類,這個類在 OpenNETCF.Xml.dll 程式集中可以找到。

序列化和反序列化用於將一個物件保存到檔,和從檔讀取。

View Source------------------------------------------------------------------------------

using   System.IO;   
using   System.Runtime.Serialization.Formatters.Binary;   
[Serializable()]//可以序列化的類需要用這個屬性標記   
 
public   class   ToBeSerialized   
{   
      public   int   a;   
      public   string   b;   
      public   ToBeSerialized(int   a,string   b)   
     {   
         this.a=a;   
         this.b=b;   
      }   
}   
 
public   class   Test   
{   
    
  public   void   Serialize()//序列化   
  {   
      ToBeSerialized   tbs = new   ToBeSerialized(22,"SOM");   
      Stream   fs   =   File.Create("Serialized.txt");   
      BinaryFormatter   serializer   =   new   BinaryFormatter();   
      serializer.Serialize(fs,   tbs);   
      fs.Close();   
  }   
  
public   void   DeSerialize()//反序列化   
  {   
     ToBeSerialized   restore;   
      Stream   fs   =   File.OpenRead("Serialized.txt");   
      BinaryFormatter   deserializer   =   new   BinaryFormatter();   
     restore   =   (ToBeSerialized)(deserializer.Deserialize(fs));//反序列化得到的物件   
     fs.Close();   
  }   
}

2020年9月7日 星期一

C#基础之反射及線上版本更新 特性

 https://www.bilibili.com/video/BV1Sk4y1m7av

https://www.youtube.com/watch?v=RGewr2UuWmk

https://www.youtube.com/watch?v=ZxW9v0CflH4


2020年9月3日 星期四

[C#]換行、連接符號

 

[C#]換行、連接符號


https://dotblogs.com.tw/yypass2002/2013/08/13/114391

C# webapi 解析 json字串包

 https://www.itread01.com/content/1544714307.html


[Web API] WinForm 使用 HttpClient 呼叫 Web API


https://dotblogs.com.tw/joysdw12/2013/06/03/web-api-httpclient-windows-form

2020年8月26日 星期三

【转】Task Scheduler Managed Wrapper: 由程式來排程工作

 https://www.cnblogs.com/tigerjacky/archive/2010/05/07/1729684.html


https://suntargets.com/c-%E5%B0%87%E7%A8%8B%E5%BC%8F%E5%8A%A0%E5%85%A5-task-scheduler/

Creating a Task and Running with Highest Privileges from Another Task,

https://stackoverflow.com/questions/60851150/creating-a-task-and-running-with-highest-privileges-from-another-task

https://social.msdn.microsoft.com/Forums/vstudio/en-US/a6f288c1-5257-44b3-93f2-21f127181e05/task-scheduler-taskrunlevel?forum=csharpgeneral

https://stackoom.com/question/2FB2h/%E5%A6%82%E4%BD%95%E4%BB%A5%E7%BC%96%E7%A8%8B%E6%96%B9%E5%BC%8F%E8%AE%BE%E7%BD%AETask-Scheduler%E5%AE%89%E5%85%A8%E9%80%89%E9%A1%B9


Task Scheduler Managed Wrapper: 由程式來排程工作

https://docs.microsoft.com/zh-tw/previous-versions/ee922578(v=msdn.10)?redirectedfrom=MSDN

[C#] 攔截並阻擋系統關機程序

 取自:

https://notes.andywu.tw/2018/c-sharp-%E6%94%94%E6%88%AA%E4%B8%A6%E9%98%BB%E6%93%8B%E7%B3%BB%E7%B5%B1%E9%97%9C%E6%A9%9F%E7%A8%8B%E5%BA%8F/

[C#] 攔截並阻擋系統關機程序

前言

會研究這個主題是因為最近在用系上電腦教室挖礦XDD (噓~


但是大約下午沒課後一小時就會有專門的人來一台台關機 (凸 - -" 我才剛開好的說


幸運的是負責關機的人都是按一下電源鍵然後關螢幕就換下一台去了


所以我就想說如果可以攔截開機訊號,阻斷關機繼續進行,我的挖礦程式就不會被關閉了 (太邪惡了lol...

 


以下是效果圖,explorer.exe是我寫的阻止關機程式(故意取這樣的名字,才不會讓人起疑


它會卡著系統不讓系統關閉所有程式

原理解說

在程式實作之前,我們必須先了解一下windows的關機順序


系統在接收到使用者發出的關機訊號後(不管是從開始選單的還是按一下電源鍵),會逐一對所有應用程式發出WM_QUERYENDSESSION訊息,來詢問應用程式在現階段是否可以被關閉


至於WM_QUERYENDSESSION是什麼,以下是MSDN對WM_QUERYENDSESSION的解釋

The WM_QUERYENDSESSION message is sent when the user chooses to end the session or when an application calls one of the system shutdown functions. If any application returns zero, the session is not ended. The system stops sending WM_QUERYENDSESSION messages as soon as one application returns zero.


After processing this message, the system sends the WM_ENDSESSION message with the wParam parameter set to the results of the WM_QUERYENDSESSION message.


翻成中文的意思就是說:


如果有一個應用程式對WM_QUERYENDSESSION回傳0,則系統就不會繼續發送WM_QUERYENDSESSION,關機的程序也就因為那個應用程式而宣告暫停(就會卡在上面那張圖)


p.s. 如果這時按Force Quit,則關閉應用程式就會變成系統主動去kill,完全不會理會應用程式的回應


當送完WM_QUERYENDSESSION,那麼系統就會再接著發送WM_ENDSESSION訊息,來「通知」應用程式是否會關機


注意,WM_ENDSESSION在這邊只有通知用喔,應用程式在這個階段已經沒有決定權了


淺略了解windows關機前的程序後,我們要做的就是在WM_QUERYENDSESSION時給它回傳0,讓系統因為我們而暫時停止關機程序

程式實作

首先先開一個新的專案,類型是視窗應用程式(Windows Forms App)


Layout要怎麼設計隨便,甚至我把它Opacity設0%,隱藏起來


接下來切換到該Form的程式碼頁

 


在創建的class新增下列程式碼,override掉原本的WndProc方法

protected override void WndProc(ref Message aMessage)

{

    const int WM_QUERYENDSESSION = 0x0011;

    const int WM_ENDSESSION = 0x0016;

 

    if (aMessage.Msg == WM_QUERYENDSESSION || aMessage.Msg == WM_ENDSESSION)

        return;

 

    base.WndProc(ref aMessage);

}



這個方法是用來讓系統或硬體跟應用程式溝通的,原本在被override前裡面也已經寫好遇到WM_QUERYENDSESSION及WM_ENDSESSION等等的訊息時要執行的動作


我們現在override後讓他遇到WM_QUERYENDSESSION跟WM_ENDSESSION訊息時直接return,啥都不要做;如果是其他則執行原本被override前的WndProc方法


如果有做到這一步其實就已經算完成了


編譯並執行程式後測試看看,按下登出、關機、重新開機,會發現系統的關機程序卡在像上圖一樣的地方。

 


如果還想要進一步更改提示訊息,我們需要使用ShutdownBlockReasonCreate這個方法


這個方法的用途就跟它名字一樣,應該不用多解釋吧:))


把以下程式碼新增在這個Form的建構子裡面,也就是InitializeComponent();下面,讓Form一初始化完就執行

ShutdownBlockReasonCreate(this.Handle, "這邊填要顯示的提示");


這時Visual Studio應該會報錯,說不認得這個方法


於是我們要告訴程式這個方法的實作已經在user32.dll完成了,去user32.dll裡面找

[DllImport("user32.dll")]

public extern static bool ShutdownBlockReasonCreate(IntPtr hWnd, [MarshalAs(UnmanagedType.LPWStr)] string pwszReason);

新增完後記得把動態載入dll所依賴的System.Runtime.InteropServices給補上

using System.Runtime.InteropServices;

到這邊算是第二階段的完成了。

如果想要把該Form從工作管理員隱藏,就把下列程式碼也加進去

protected override CreateParams CreateParams

{

    get

    {

        var cp = base.CreateParams;

        cp.ExStyle |= 0x80;

        return cp;

    }

}

最後附上完整程式碼

using System;

using System.Windows.Forms;

using System.Runtime.InteropServices;

 

namespace NoShutdown

{

    public partial class NoShutdown : Form

    {

        [DllImport("user32.dll")]

        public extern static bool ShutdownBlockReasonCreate(IntPtr hWnd, [MarshalAs(UnmanagedType.LPWStr)] string pwszReason);

         

        public NoShutdown()

        {

            InitializeComponent();

            ShutdownBlockReasonCreate(this.Handle, "這邊填要顯示的提示");

        }

         

        protected override void WndProc(ref Message aMessage)

        {

            const int WM_QUERYENDSESSION = 0x0011;

            const int WM_ENDSESSION = 0x0016;

 

            if (aMessage.Msg == WM_QUERYENDSESSION || aMessage.Msg == WM_ENDSESSION)

                return;

 

            base.WndProc(ref aMessage);

        }

 

        protected override CreateParams CreateParams //Hide from Task Manager

        {

            get

            {

                var cp = base.CreateParams;

                cp.ExStyle |= 0x80;

                return cp;

            }

        }

    }

}

小提醒:如果曾經使用過一些工具去優化關機速度的可能就不會被阻擋在那個畫面。因為那些優化為了減少關機時間,不管WM_QUERYENDSESSION回傳什麼會直接kill掉。


WPF聊天室应用(ASP.NET Core SignalR)

  WPF聊天室应用(ASP.NET Core SignalR) https://www.bilibili.com/video/BV1Q741187Si?p=2 https://www.bilibili.com/video/BV1UV411e75T?from=search&...