Max Wu
    • Create new note
    • Create a note from template
      • Sharing URL Link copied
      • /edit
      • View mode
        • Edit mode
        • View mode
        • Book mode
        • Slide mode
        Edit mode View mode Book mode Slide mode
      • Customize slides
      • Note Permission
      • Read
        • Only me
        • Signed-in users
        • Everyone
        Only me Signed-in users Everyone
      • Write
        • Only me
        • Signed-in users
        • Everyone
        Only me Signed-in users Everyone
      • Engagement control Commenting, Suggest edit, Emoji Reply
    • Invite by email
      Invitee

      This note has no invitees

    • Publish Note

      Share your work with the world Congratulations! 🎉 Your note is out in the world Publish Note

      Your note will be visible on your profile and discoverable by anyone.
      Your note is now live.
      This note is visible on your profile and discoverable online.
      Everyone on the web can find and read all notes of this public team.
      See published notes
      Unpublish note
      Please check the box to agree to the Community Guidelines.
      View profile
    • Commenting
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
      • Everyone
    • Suggest edit
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
    • Emoji Reply
    • Enable
    • Versions and GitHub Sync
    • Note settings
    • Note Insights
    • Engagement control
    • Transfer ownership
    • Delete this note
    • Save as template
    • Insert from template
    • Import from
      • Dropbox
      • Google Drive
      • Gist
      • Clipboard
    • Export to
      • Dropbox
      • Google Drive
      • Gist
    • Download
      • Markdown
      • HTML
      • Raw HTML
Menu Note settings Versions and GitHub Sync Note Insights Sharing URL Create Help
Create Create new note Create a note from template
Menu
Options
Engagement control Transfer ownership Delete this note
Import from
Dropbox Google Drive Gist Clipboard
Export to
Dropbox Google Drive Gist
Download
Markdown HTML Raw HTML
Back
Sharing URL Link copied
/edit
View mode
  • Edit mode
  • View mode
  • Book mode
  • Slide mode
Edit mode View mode Book mode Slide mode
Customize slides
Note Permission
Read
Only me
  • Only me
  • Signed-in users
  • Everyone
Only me Signed-in users Everyone
Write
Only me
  • Only me
  • Signed-in users
  • Everyone
Only me Signed-in users Everyone
Engagement control Commenting, Suggest edit, Emoji Reply
  • Invite by email
    Invitee

    This note has no invitees

  • Publish Note

    Share your work with the world Congratulations! 🎉 Your note is out in the world Publish Note

    Your note will be visible on your profile and discoverable by anyone.
    Your note is now live.
    This note is visible on your profile and discoverable online.
    Everyone on the web can find and read all notes of this public team.
    See published notes
    Unpublish note
    Please check the box to agree to the Community Guidelines.
    View profile
    Engagement control
    Commenting
    Permission
    Disabled Forbidden Owners Signed-in users Everyone
    Enable
    Permission
    • Forbidden
    • Owners
    • Signed-in users
    • Everyone
    Suggest edit
    Permission
    Disabled Forbidden Owners Signed-in users Everyone
    Enable
    Permission
    • Forbidden
    • Owners
    • Signed-in users
    Emoji Reply
    Enable
    Import from Dropbox Google Drive Gist Clipboard
       owned this note    owned this note      
    Published Linked with GitHub
    9
    Subscribed
    • Any changes
      Be notified of any changes
    • Mention me
      Be notified of mention me
    • Unsubscribe
    Subscribe
    --- title: HackMD - Markdown 協作筆記 @ 2016 MOPCON lang: zh-tw disqus: hackmd slideOptions: width: 1200 --- <style> .reveal, .reveal h1, .reveal h2, .reveal h3, .reveal h4, .reveal h5, .reveal h6 { font-family: -apple-system, BlinkMacSystemFont, Roboto, "Helvetica Neue", Helvetica, Arial, PingFangTC-Light, "Microsoft JhengHei", "微軟正黑", sans-serif, "Apple Color Emoji" } </style> # <i class="fa fa-file-text"></i> HackMD ## Markdown 協作筆記 **jackycute @ 2016 MOPCON** --- <img src="https://i.imgur.com/PTbB46S.jpg" style="width:300px;height:300px;border-radius:50%"/> # 吳承翰 Max Wu #### 北科大 資訊工程所 ### 我喜歡好的產品,也開發好的產品;<br>我寫的不是程式,是理想。 --- # <i class="fa fa-file-text"></i> HackMD ## Realtime collaborative markdown notes on all platforms ---- ## 工程師看到的時候想: - Realtime;那就是很快就可以看到結果的意思 - Collaborative;就是可以跟別人一起同時工作 - Markdown;就是 GitHub 還有 堆疊溢出 在用的語法嘛 - Notes;喔 Evernote 還是 Quip 都用過啦 - Platforms;阿不就跨平台好棒棒 ---- ## 一般人看到的時候想: - Realtime;即時?阿是有多即時?FB 那樣嗎? - Collaborative;協作?Google Doc 我聽過 - Markdown;你給我解釋解釋,解釋解釋 - Notes;我們公司都用 Word 作筆記傳 FTP - Platforms;不懂你的意思,可以說清楚一點嗎? ---- # Hack + MD ---- # Hack ## 用聰明的方法來完成事情<!-- .element: class="fragment" data-fragment-index="1" --> ---- # Markdown # 輕量的視覺化標記語言<!-- .element: class="fragment" data-fragment-index="1" --> # 「蛤?」<!-- .element: class="fragment" data-fragment-index="2" --> ---- # 文字就可以排版的語法 感謝 @clkao 貢獻此麻瓜咒語 --- # <i class="fa fa-file-text"></i> HackMD - 靈感來自 Hackpad - 更注重速度與靈活度 - 跨平台的筆記服務 ---- # <i class="fa fa-file-text"></i> 用途 - 製作筆記 - 撰寫文件 - 快速簡報 ---- # <i class="fa fa-file-text"></i> 功能 - 自動上傳圖片 - 支援嵌入影片 - 支援數學公式 - 支援各式圖表 - 自動修訂紀錄 - 自動作者標記 ---- # <i class="fa fa-file-text"></i> 採用 - PyCon TW 2016 - g0v - CTF write-ups - Debater - 成大 進階電腦系統理論與實作 (Fall 2016) ---- # <i class="fa fa-file-text"></i> 現況 - 2015 年 3 月開始上線服務 - 累計超過 5.2 萬份筆記 - 每月超過 3.4 萬的活躍使用者 - 會員超過 7,500 名 - 使用者來自 台灣、日本、美國、歐洲、南美洲 - 支援超過 15 種介面語言 ---- # <i class="fa fa-github"></i> 開源 - 被星星超過 1,000 次 - 擁有超過 24 名貢獻者 - 被 Fork 超過 130 次 ---- # <i class="fa fa-file-text"></i> 架構 - 前端使用 jQuery - 後端使用 Node.js - 資料庫使用 PostgreSQL --- ## 一個人怎麼實踐理想? # 「組合肉」<!-- .element: class="fragment" data-fragment-index="1" --> ---- # 起源 ## 資訊安全 期末專案 <!-- .element: class="fragment" data-fragment-index="1" --> ### 好奇即時協作的原理與其中的安全問題<!-- .element: class="fragment" data-fragment-index="2" --> ### 因為我很懶所以愛上優雅的 Markdown<!-- .element: class="fragment" data-fragment-index="3" --> ---- # 做法: 1. 上網餵狗搜尋 Collaborate Editor 2. 找最容易看得懂的範例開始改起 3. 找可以用的 Open Source 套件加料 4. 研究原始碼填補接縫 5. 測試功能正常,美化外皮 ---- ## 結論:兩天完成的夜市牛排 - 可以多使用者同時協作文字 - 實作對稱式加解密 (AES) - 其實就是實踐 MVP (最小可行產品) 的過程 ---- # 劇終 - 這個專案拿到 99 分 - 做完就去放寒假了 XD - 沒有人愛你 :heart: --- ## Re: 從零開始的協作筆記 - 既然用了 Markdown 就要渲染成 HTML 啊! - 既然都是網頁了不如支援一下 RWD (響應式網頁設計) - 先來場大亂鬥看看會發生甚麼事情?! --- ## 選擇 Markdown renderer - chjj / marked <i class="fa fa-star"></i> 10766 <i class="fa fa-exclamation-circle"></i> 298 - jonschlinkert / remarkable <i class="fa fa-star"></i> 2881 <i class="fa fa-exclamation-circle"></i> 53 - markdown-it / markdown-it <i class="fa fa-star"></i> 2656 <i class="fa fa-exclamation-circle"></i> 2 - wooorm / remark <i class="fa fa-star"></i> 715 <i class="fa fa-exclamation-circle"></i> 5 ---- # chjj / marked - 輕量、效能最好 - 沒有遵循任何標準 - 自訂語法較困難 ---- ## markdown-it / markdown-it - 效能佳 - 遵循 CommonMark - 容易自訂語法 - 外掛多 ~~jonschlinkert / remarkable~~ 基本上已棄用,markdown-it 的前身 <!-- .element: class="fragment" data-fragment-index="1" --> ---- # wooorm / remark - 效能好 - 遵循 CommonMark - 有制定一套 AST (虛擬結構樹) - 外掛多 - 明日之星 :star: ---- # CommonMark 因為 Markdown 是開放格式 所以各自制定的語法有非常多種 目前 CommonMark 為大多數人遵循的標準 --- # 跨平台介面設計 - 使用 Bootstrap,內建 RWD - 無論整合什麼都要看起來像 Bootstrap - 盡量讓所有功能可用,不能用的直接藏起來 ---- ## 跨平台也能保持良好的使用者體驗 ### 了解瀏覽器的設計,盡量保留原生功能<!-- .element: class="fragment" data-fragment-index="1" --> - body scrolling 的時候工具列會縮小 - 輸入的時候虛擬鍵盤會彈出來 - #hash 是拿來定位 id anchor 的 :anger: <!-- .element: class="fragment" data-fragment-index="2" --> ---- ## 跨平台介面開發與除錯 - 善用響應式設計模式預覽 (Safari) - 善用 Remote 除錯 (Chrome, Safari) - 實機測試最準確 - 為不同螢幕裝置做更詳細的最佳化 ---- ## 使用者總能挑戰裝置的極限! - 這麼小的螢幕上還是要用 IDE! - 超小的元素還是被點到了! - 行動網路很慢,但是硬要用! :anguished: --- # 社群推廣大亂鬥 - 分享到 FB 的幾個較大的資訊相關社團 - 自己分享到 Hacker News - 造成空前的流量,很多人一起測試輸入 ---- # 大爆炸 :bomb: - 有人嘗試輸入 40 萬字,造成 CPU 負載過重 - 有人嘗試輸入 不安全的語法 - 多人一起輸入會搶字 ---- # 適當且無感的限制 - 限制最大輸入字數,超過會提醒 - 自動過濾所有渲染出來的 HTML --- # 如何協作同步? - 輸入拼字也需要同步 - 網路延遲造成同步錯亂 ---- # 拼字問題 - 輸入需要拼字的還有 日文、韓文 等 - 拼字的時候瀏覽器有事件 (compositionStart 等) - 但是會因為裝置、瀏覽器而實作有所不同 - 總之不要忽略拼字,ㄅㄆㄇㄈ也需要同步 ---- ### Operational Transformation 操作轉換 ### 無法避免因為網路延遲所導致的資料不同步<!-- .element: class="fragment" data-fragment-index="1" --> 多人協作的時候需要將輸入的操作結構化 然後按照順序轉換成相對應的操作並同步 <!-- .element: class="fragment" data-fragment-index="2" --> ---- # 共有三種操作 - Retain 多少字元不更動 - Insert 插入字元 - Delete 刪除字元 ---- # 如何轉換? ## 以「PPAP」為例<!-- .element: class="fragment" data-fragment-index="1" --> ---- # PP→PPAP ```mermaid sequenceDiagram Client A->>Server: O1: Insert[1, 'P', 1] Client B->>Server: O2: Insert[1, 'A', 1] Server-->>Client B: O1': Insert[1, 'P', 2] Server-->>Client A: O2': Insert[2, 'A', 1] ``` ---- # PAAP→PPAP ```mermaid sequenceDiagram Client A->>Server: O1: Delete[1, 'A', 2] Client B->>Server: O2: Insert[1, 'P', 3] Server-->>Client B: O1': Delete[2, 'A', 2] Server-->>Client A: O2': Insert[1, 'P', 2] ``` --- # 資料儲存架構 - 將具有即時性的資料暫存在記憶體 - 變更資料的同時標記此筆資料變更 - 使用非同步 Workers 掃描變更資料並存回資料庫 ---- ### Worker 的工作流程 <div style="width: 80vmin; display: inline-block;"> ```flow st=>start: 資料存取 e=>end: 刪除暫存 op1=>operation: 暫存資料至記憶體 cond1=>condition: 資料是否被變更? cond2=>condition: 資料是否逾時未變更? op2=>operation: 儲存變更資料回資料庫 st->op1->cond1 cond1(yes)->op2->e cond1(no)->cond2->op1 cond2(yes)->e cond2(no)->cond1->sub1 ``` </div> --- # 如何記錄修訂版本? - google-diff-match-patch - 只記錄 patch 減少重複內容 ---- ## google-diff-match-patch - 基於 Myer's diff algorithm - 加上預處理 (加速) - 加上後處理 (減少多餘的結構) ---- # diff 範例 - old: 假的業障重, new: 假的暫時的 - diff 得到:假的~~業障重~~==暫時的== - 轉成 GNU unified format patch ```= @@ -1,5 +1,5 @@ 假的 -業障重 +暫時的 ``` ---- ## 只儲存 patch 減少資料量 - 只有最新與最舊的版本會完整儲存 - 當拿取中間版本時,由最靠近的完整版本 patch 回來 - 從舊版本計算出較新版本 → patch - 從新版本計算到較舊版本 → inverse patch --- # 如何整合套件 - 要整合的無縫 - 要能發揮它的力量 - 了解它、修正它、Fork 它 - 不吝給予回饋 (開 Issue、發 PR) ---- # 目前已整合的重要套件 - CodeMirror - socket.io - OT - textcomplete - bootstrap - markdown-it - reveal.js - google-diff-match-patch ---- # 為何不重造輪子 - 因為沒那麼多資源 - 因為沒有那麼專業 ---- # 為何重造輪子 - 因為可以完全自訂 - 因為可以知道細節 --- # 設計與核心思想 # 「懶」<!-- .element: class="fragment" data-fragment-index="1" --> ## 懶得優雅<!-- .element: class="fragment" data-fragment-index="2" --> ## 懶得簡潔<!-- .element: class="fragment" data-fragment-index="3" --> ---- # 實踐方法 - 只出現必要的元件 - 注重微小的細節 - 好的體驗是由無數個細節構成 ---- # 自己吃吃看狗糧 - 最好的電影是連導演都感動 - 最棒的服務是連自己都驚嘆 --- # 社群是你最好的導師 - 自己的痛點可能也是別人的痛點 - 用 open source 實踐 MVP ---- ## 別想單打獨鬥解決所有困難 - 勇者,不要跟他拼拳,嘗試切他中路! :facepunch: - 嘗試創造不存在那些痛點的世界 (但是有 tradeoffs) - 想法 → 課程專案 → Issue DD → Community DD ---- # 樂於與社群互動 - 關心使用者,提供管道並傾聽他們的聲音 :ear: - 與敬佩的對手聯誼,市場夠大不要小氣 - 研究 → 設計 → 實作 → 驗證 → 回饋 ---- ## 最好是免錢又大碗又好吃 - 這是不可能的 :cry: - 必須在設計、開發、營運之間嘗試平衡 - 將所有功能都集合的不一定是好產品 --- # 感謝貢獻與推廣 @clkao @neil @BlueT @ETblue @EvanWu @yukai @PeterDaveHello @ttcat @BobbyTung @xnum @au @g0v and more... --- # 感謝贊助 ## 已收到超過 250 美元的捐贈! --- ## <i class="fa fa-facebook-square"></i> 搜尋並加入 # Markdown 台灣 --- # Q&A --- # <i class="fa fa-github"></i> ⨯ <i class="fa fa-file-text"></i> ## HackMD<br>已列入<br>GitHub Integrations List --- # 謝謝大家! 這份簡報使用 HackMD 製作 https://hackmd.io/p/Bk9X2eJT

    Import from clipboard

    Paste your markdown or webpage here...

    Advanced permission required

    Your current role can only read. Ask the system administrator to acquire write and comment permission.

    This team is disabled

    Sorry, this team is disabled. You can't edit this note.

    This note is locked

    Sorry, only owner can edit this note.

    Reach the limit

    Sorry, you've reached the max length this note can be.
    Please reduce the content or divide it to more notes, thank you!

    Import from Gist

    Import from Snippet

    or

    Export to Snippet

    Are you sure?

    Do you really want to delete this note?
    All users will lose their connection.

    Create a note from template

    Create a note from template

    Oops...
    This template has been removed or transferred.
    Upgrade
    All
    • All
    • Team
    No template.

    Create a template

    Upgrade

    Delete template

    Do you really want to delete this template?
    Turn this template into a regular note and keep its content, versions, and comments.

    This page need refresh

    You have an incompatible client version.
    Refresh to update.
    New version available!
    See releases notes here
    Refresh to enjoy new features.
    Your user state has changed.
    Refresh to load new user state.

    Sign in

    Forgot password

    or

    By clicking below, you agree to our terms of service.

    Sign in via Facebook Sign in via Twitter Sign in via GitHub Sign in via Dropbox Sign in with Wallet
    Wallet ( )
    Connect another wallet

    New to HackMD? Sign up

    Help

    • English
    • 中文
    • Français
    • Deutsch
    • 日本語
    • Español
    • Català
    • Ελληνικά
    • Português
    • italiano
    • Türkçe
    • Русский
    • Nederlands
    • hrvatski jezik
    • język polski
    • Українська
    • हिन्दी
    • svenska
    • Esperanto
    • dansk

    Documents

    Help & Tutorial

    How to use Book mode

    Slide Example

    API Docs

    Edit in VSCode

    Install browser extension

    Contacts

    Feedback

    Discord

    Send us email

    Resources

    Releases

    Pricing

    Blog

    Policy

    Terms

    Privacy

    Cheatsheet

    Syntax Example Reference
    # Header Header 基本排版
    - Unordered List
    • Unordered List
    1. Ordered List
    1. Ordered List
    - [ ] Todo List
    • Todo List
    > Blockquote
    Blockquote
    **Bold font** Bold font
    *Italics font* Italics font
    ~~Strikethrough~~ Strikethrough
    19^th^ 19th
    H~2~O H2O
    ++Inserted text++ Inserted text
    ==Marked text== Marked text
    [link text](https:// "title") Link
    ![image alt](https:// "title") Image
    `Code` Code 在筆記中貼入程式碼
    ```javascript
    var i = 0;
    ```
    var i = 0;
    :smile: :smile: Emoji list
    {%youtube youtube_id %} Externals
    $L^aT_eX$ LaTeX
    :::info
    This is a alert area.
    :::

    This is a alert area.

    Versions and GitHub Sync
    Get Full History Access

    • Edit version name
    • Delete

    revision author avatar     named on  

    More Less

    Note content is identical to the latest version.
    Compare
      Choose a version
      No search result
      Version not found
    Sign in to link this note to GitHub
    Learn more
    This note is not linked with GitHub
     

    Feedback

    Submission failed, please try again

    Thanks for your support.

    On a scale of 0-10, how likely is it that you would recommend HackMD to your friends, family or business associates?

    Please give us some advice and help us improve HackMD.

     

    Thanks for your feedback

    Remove version name

    Do you want to remove this version name and description?

    Transfer ownership

    Transfer to
      Warning: is a public team. If you transfer note to this team, everyone on the web can find and read this note.

        Link with GitHub

        Please authorize HackMD on GitHub
        • Please sign in to GitHub and install the HackMD app on your GitHub repo.
        • HackMD links with GitHub through a GitHub App. You can choose which repo to install our App.
        Learn more  Sign in to GitHub

        Push the note to GitHub Push to GitHub Pull a file from GitHub

          Authorize again
         

        Choose which file to push to

        Select repo
        Refresh Authorize more repos
        Select branch
        Select file
        Select branch
        Choose version(s) to push
        • Save a new version and push
        • Choose from existing versions
        Include title and tags
        Available push count

        Pull from GitHub

         
        File from GitHub
        File from HackMD

        GitHub Link Settings

        File linked

        Linked by
        File path
        Last synced branch
        Available push count

        Danger Zone

        Unlink
        You will no longer receive notification when GitHub file changes after unlink.

        Syncing

        Push failed

        Push successfully