Carlos Castillo Passi
    • 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
    Subscribed
    • Any changes
      Be notified of any changes
    • Mention me
      Be notified of mention me
    • Unsubscribe
    Subscribe
    ![TwoCultureProblem](https://hackmd.io/_uploads/BkTMu3y2A.jpg) Credit of this fantastic figure to Matthijs Cox's blogs. --- My goal with this documents is to hopefully convey to people using languages like MATLAB, Python and R with no background in software development or computer science, **the strengths and unique elements of the Julia programming language**. While a lot of the things presented below can be done in other languages, they cannot be done as easily as in Julia :juggling:. Meaning that, I hope that more people from the left distribution (scientist/engineers) come to the center (Julia) of the figure above!! ![julia_meme](https://hackmd.io/_uploads/BJWohrf2C.png) Right now, it is not very well organized and I still need to include some topics. Feel free to contribute :smile:. TODO: - Organize information coherently - Add difference between a function and a method - Reproducibility: Project.toml, Manifest.toml, Pluto.jl - Examples in which the fastest way of doing something is in Julia (DiffEq, Tables/Data, etc) - Examples of type piracy - JULIA IS A COMPILED LANGUAGE (but interactive, REPL) - ?? help needed - fell free to add stuff # Learning Julia - Modern Julia workflows: https://modernjuliaworkflows.github.io/ - Good scientific code: - https://github.com/JuliaDynamics/GoodScientificCodeWorkshop - https://www.youtube.com/watch?v=x3swaMSCcYk - GPU kernel programming: https://pde-on-gpu.vaw.ethz.ch/lecture10/t - Matthijs Cox: - My Target Audience: https://scientificcoder.com/my-target-audience - The Art of Multiple Dispatch: https://scientificcoder.com/the-art-of-multiple-dispatch - How to solve the two language problem: https://scientificcoder.com/how-to-solve-the-two-language-problem - Automate your code quality: https://scientificcoder.com/automate-your-code-quality-in-julia - Introduction to the Julia programming language (Guillaume Dalle) - https://www.youtube.com/watch?v=O6CF-UHArMs - https://juliaepfl.github.io/Website/notebooks/intro-2024.html - https://juliaepfl.github.io/Website/notebooks/convolution_GPU_example.html - DataFrames.jl benchmarks: https://h2oai.github.io/db-benchmark/ - Why Julia - a Manifesto: https://github.com/Datseris/whyjulia-manifesto - Scientific Programming in Julia: https://juliateachingctu.github.io/Scientific-Programming-in-Julia/stable/lecture_08/lab/ - Automatic Differentiation: https://juliateachingctu.github.io/Scientific-Programming-in-Julia/stable/lecture_08/lecture/ - General code: Uncertainty Propagation https://juliateachingctu.github.io/Scientific-Programming-in-Julia/stable/lecture_12/lecture/ ```julia struct Dual{T<:Number} <: Number x::T d::T end ``` ```julia struct GNum{T} where T<:Real μ::T σ::T end ``` - MITMath: https://mitmath.github.io/18337/ # Showcasing Julia - **Pluto.jl:** - **KernelAbstractions.jl** -> CUDA.jl, AMDGPU.jl, Metal.jl, oneAPI.jl - **Enzyme.jl** - Plots (multiple backends): - Makie.jl: GPU plotting - PyPlot.jl - PlotlyJS.jl - **JuMP.jl**: Modeling language for Mathematical Optimization (linear, mixed-integer, conic, semidefinite, nonlinear) - Optimization.jl - Convex.jl: Stanford - **DifferentialEquations.jl** - Unitful.jl: adds units to type, zero overhead - Flux.jl: Deep Learning - LinearOperators.jl: https://jso.dev/tutorials/introduction-to-linear-operators/ # Benchmarks Julia is one of the most cost-effective languages in terms of the amount of necessary code to achieve high-performance. It has been shown many times that Julia can achieve C/C++ levels of performance with **a lot less effort**. ![JuliaBenchmarks](https://hackmd.io/_uploads/HJ4UKhyh0.png) ![JuliaBenchmarksZoom](https://hackmd.io/_uploads/rJB8FhknA.png) # The Unreasonable Effectiveness of Multiple Dispatch https://www.youtube.com/watch?v=kc9HwsxE1OY - There's something unusual about the Julia's ecosystem ... - there's really large amount of **code sharing** and **code reuse** ![JuliaDiffEqMeasurements](https://hackmd.io/_uploads/HyJdFhy3A.png) Generic differential equation solver -> Uncertainty measurements -> Uncertainty propagates through DiffEq solver (solution with uncertainty) -> plotting that solution shows error bars This isn't entirely surprising, multiple dispatch is good at **expressing generic algorithms**. - Generic algorithms apply to different types - Common types shared by very different packages > [!IMPORTANT] How can I explain multiple dispatch and code re-usability in practice? > Square root and dual numbers > ```julia > function mysqrt(a) # <--- My code > x = a > for k in 1:100 > x = 0.5 * (x + a / x) > end > return x > end > ``` > What if I want to compute its derivative? > $$ > f(x+\delta)=f(x)+\delta f'(x) > $$ > Let's implement a custom type for this > ```julia > struct Dual{T} # Parametric type > x::T > δ::T >end ># Extending a function coming from another package (Base) >Base.:*(m, a::Dual) = Dual(m * a.x, m * a.δ) >Base.:+(a::Dual, b::Dual) = Dual(a.x + b.x, a.δ + b.δ) >Base.:/(a::Dual, b::Dual) = Dual(a.x / b.x, (b.x * a.δ - a.x * b.δ) / b.x^2) > ``` > https://juliaepfl.github.io/Website/notebooks/intro-2024.html ![JuliaLevelsDispatch](https://hackmd.io/_uploads/HJ3KF21nA.png) - **No dispatch**: C, one code does exactly one thing `f(x₁, x₂, ...)` - **Single dispatch**: OOP ` x₁.f(x₂, ...)` (depending on the object $x_1$ the function $f$ is different) - **Multiple dispatch**: `f(x₁, x₂, ...)` depends on all the combinations of variables https://scientificcoder.com/the-art-of-multiple-dispatch ![VisualJuliaMultipleDispatch](https://hackmd.io/_uploads/H1A3Y2J2R.png) ![VisualJuliaMultipleDispatch2](https://hackmd.io/_uploads/HkAnK2knR.png) ![VisualJuliaMultipleDispatch3](https://hackmd.io/_uploads/SyR2Y31n0.png) ![VisualJuliaMultipleDispatch4](https://hackmd.io/_uploads/S103Y31nC.png) ![VisualJuliaMultipleDispatch5](https://hackmd.io/_uploads/SygRnFhk3A.png) ![JuliaGenericCode](https://hackmd.io/_uploads/ryVCY313R.png) > [!IMPORTANT] How to write generic code? > Remove all types from functions! Only specify the type for dispatch. The types go in the structs. ## Generic code ![JuliaGenericCode2](https://hackmd.io/_uploads/rk9J92khC.png) It works, but ... we can do better! ![JuliaGenericCode3](https://hackmd.io/_uploads/B1Ce93y2C.png) ![JuliaGenericCode4](https://hackmd.io/_uploads/Sk0echJnR.png) ![JuliaGenericCode5](https://hackmd.io/_uploads/HyAg5n12C.png) ![JuliaGenericCode6](https://hackmd.io/_uploads/BJRec3k20.png) ## Common Types ![JuliaTypes](https://hackmd.io/_uploads/SkNQ92ynA.png) Inheriting from RGB is ugly, I need to rename the object, and if someone defines a method for RGB, now I need to create a wrapper for MyRGB ![JuliaTypes2](https://hackmd.io/_uploads/H1NXc2k3A.png) You can give up dispatch (no generic code), or just copy paste code into your code (no code reuse) ... ![JuliaTypes3](https://hackmd.io/_uploads/S1EQ5n120.png) You can define methods outside of the type ![JuliaType4](https://hackmd.io/_uploads/r1Nmq212R.png) # The expression problem ![JuliaExpressionProblem](https://hackmd.io/_uploads/HyLs5hkn0.png) ![JuliaExpressionProblem2](https://hackmd.io/_uploads/BkY2c3J2C.png) ![JuliaExpressionProblem3](https://hackmd.io/_uploads/By9pqhy2R.png) > [!NOTE] Traits in RUST > My impression was that, while rust functions don’t have multiple dispatch, generic rust traits _can_ have multiple dispatch, which lets you accomplish pretty much the same thing (though it’s more verbose). - Jasha10 Julia Discourse > > I think one problem with multipledispatch comparing to a trait system is that the developer needs to know and fully understand the detail of a function in order to let that function use some optimized operation for calculation. E.g. in the "inner" example, one needs to read the code of the function "inner" then can he know the function "inner" uses "*" (multiplication). After that, he can write a specialized "*" for the "OneHotVector". This may be obvious for "inner" but sooner it becomes not obvious for other complicated functions. - @weiyuanwu9044 YouTube comments Why Multiple Dispatch was not used before? Trade-off with performance, In Julia this is not a problem # Code reuse https://www.youtube.com/watch?v=QTCKsqIK6nE > "I see this (telling people to reuse code) ... like us trying to get people to eat helthy ... this is something that is good for you in the long run" - Jeff Bezanson Programmers will reliably do two things: - what is easy - what runs fast In other words: people want to eat junk food. Have we made Cheetos that are good for you? **broadcast** is the same as **map** for one argument, but it repeats inputs for more arguments. # Type piracy > [!WARNING] Type piracy > You need to own either the **function** or the **type** of one of the arguments `f(arg1, arg2, ...)` to add a method to a function. # Science and wasted efforts In science, most programming languages have used this approach of OOP. For example Python. The main issue is, that if you want to solve a new problem, you need to **rewrite the whole algorithm** for your problem: - We are so used to do this, that we don't question it - So many resources have been lost in this - Wan't to do Machine Learning? rewrite your code in PyTorch, JAX or TensorFlow - TorchNUFFT - etc # Julia should be slow - All type annotations are optional, let the compiler do the magic - Multiple dispatch: specialised on concrete types - Compile time: converting code to machine code - Run time: when this machine code is actually executed ## Julia's compiler JuliaCon 2024 - Valentin Churavy ![JuliaSourcetoMachineCode](https://hackmd.io/_uploads/rkSlin1nR.png) ![JuliaMacrosIntrospectionCode](https://hackmd.io/_uploads/B1sbsnJhR.png) ## Performance pitfalls Engineering Julia for Speed | Lionel Zoubritzky | JuliaCon 2018 ![JuliaComplierPerformance](https://hackmd.io/_uploads/HJ0fi0ynC.png) **Type stability**: We can move the cost of type inference from run time to compile time (devirtualization). This is one of the most important aspects of Julia's performance. ![JuliaInlining](https://hackmd.io/_uploads/HkKEi0k3R.png) ![JuliaInlining2](https://hackmd.io/_uploads/rJmriRJ2C.png) ![JuliaInlining3](https://hackmd.io/_uploads/BJ-UoA1nR.png) ![JuliaUnboxing](https://hackmd.io/_uploads/rkSwi0knA.png) The vector can be stored in an unboxed fashion if **all types are concrete**. Specifying types in methods are good for dispatch and overloading (someone can define a method of that function of their custom type) ![JuliaUnboxing2](https://hackmd.io/_uploads/Syddo0yhC.png) ![JuliaLLVMCodeNative](https://hackmd.io/_uploads/H1OFj0yh0.png) LLVM 27k https://github.com/llvm/llvm-project CPython 61k https://github.com/python/cpython Julia 45k https://github.com/JuliaLang/julia Code: ```julia hl:2 function add(a, b) return a + b end ``` Typed code (Typed IR): ```julia hl:3 julia> @code_typed add(1,1) CodeInfo( 1 ─ %1 = Base.add_int(a, b):: Int64 └── return %1 ) => Int64 ``` LLVM IR (C++, Rust, Go, etc.) ```julia hl:7 julia> @code_llvm add(1,1) ; @ REPL[15]:1 within `add` define i64 @julia_add_428(i64 signext %0, i64 signext %1) #0 { top: ; @ REPL[15]:2 within `add` ; ┌ @ int.jl:87 within `+` %2 = add i64 %1, %0 ; └ ret i64 %2 } ``` --- CPU/GPU native code (assembly, not really useful to look at): ```julia julia> @code_native add(1, 1) .text .file "add" .globl julia_add_451 # -- Begin function julia_add_451 .p2align 4, 0x90 .type julia_add_451,@function julia_add_451: # @julia_add_451 ; ┌ @ REPL[15]:1 within `add` # %bb.0: # %top push rbp mov rbp, rsp ; │ @ REPL[15]:2 within `add` ; │┌ @ int.jl:87 within `+` lea rax, [rdi + rsi] ; │└ pop rbp ret .Lfunc_end0: .size julia_add_451, .Lfunc_end0-julia_add_451 ; └ # -- End function .section ".note.GNU-stack","",@progbits ``` > [!IMPORTANT] Static analysis > In [computer science](https://en.wikipedia.org/wiki/Computer_science "Computer science"), **static program analysis** (also known as **static analysis** or **static simulation**) is the [analysis](https://en.wikipedia.org/wiki/Program_analysis "Program analysis") of computer programs performed without executing them, in contrast with [dynamic program analysis](https://en.wikipedia.org/wiki/Dynamic_program_analysis "Dynamic program analysis"), which is performed on programs during their execution in the integrated environment. # Comparison with Python ![JuliaVsPython](https://hackmd.io/_uploads/r1p9sAJ2R.png) > You can do the same in Python ... - Anon Yes, but not as easily :wink:. In Julia you have **direct acess** to the internals, you can even check how Julia Base does something as it si written in Julia. # Julia coming from MATLAB > But in MATLAB I do it like this - Anon Sometimes people do not realize that MATLAB is sometimes the only programming language doing something in a way, it is important to enter this learning journey with an open mind :brain:. **MATLAB |> Julia JuliaCon2024**: https://pretalx.com/media/juliacon2024/submissions/NCVSZ3/resources/MATLAB2Julia_fyD0c1f.pdf - **Curiosity is key**: Tools and languages evolve, never stop asking what's new - **Respect language diversity**: Learning Julia can solidify some concepts - **Listen before prescribing**: "Julia is fast" only matters if the current approach is perceived as slow - **Don't ask how can I, ask what is the right way to**: To really get good at a new language, take your time to loose old bad habits - **Learning is an investment**: Make your peace with being less productive for a while ![EmbracingChange](https://hackmd.io/_uploads/Byh2oCJn0.png) There is a lot of challenges to change, which are not objective. Transition from Python 2 to 3 took almost 15 years. - IMPORTANT FOCUS TO: lack of SKILLS, and INCENTIVES - Older people built their whole careers using MATLAB, why change? - If we change it, suddenly their expertise goes away ... best approach is map the current methods to the new language. - How do we know is good? tell people it will not be compatible, developers can opt-out of it. - # Roadblocks - Ranges`t = 0:0.1:2pi` Just like in MATLAB! :) (not allocated! `StepRangeLen`) - **Broadcasting** `y = sin.(t)` ($\sin:\ \mathbb{R}\rightarrow\mathbb{R}$) - **Plotting**, `plot(t, y)` needs to import `using Plots` (you need to install stuff!) - `surf` -> `surface(t, t, y * y')` (In Julia most **functions use complete words**) - **Generic code can change backends**, `add UniCodoPlots`, then set`unicodeplots()` - You can define functions like `f(x) = sin.(x)` **similar to math**! - You can also **pipe** functions `y = x |> f |> f` - Pluto is **reactive**, can define cells like in Excel (we love excel right?) - Sliders can be bound to variables, `@bind x Slider(0:10)` - You can mix Markdown and code with string interpolation `mystring = "x = $x"` - Order of the cells does not matter! - For loops have their own scope ```julia for i in 1:10 print(i) end print(i) # Not like in MATLAB!! ``` - Let's do **something more complex**, use VSCode: - Ctr+Enter: Executes line and shows output inline - Docs can be seen inside VSCode - Plots appear in the plot pane ```julia using ControlSystems using Plots n, b, k = 2, 1, 1 P = tf(1, [m, b, k]) # System, mass-spring-damp C = pid(1,1,0,1) # Controler G = feedback(P * C) # Feddback loop plot(step(G, 20)) C_tuned = loopshapingPID(P, 1) G_tuned = feedback(P * C) plot!(step(G_tuned, 20)) # No hold on, fun! # More cool graphs for free res = step(G_tuned, 20) plot(stepinfo(res)) ``` # Packaging and publishing - Very well thought package environment and package manager (Pkg.jl, everything is in the CI PkgTemplates.jl) - It force you to write tests (TestItemRunner.jl) - Docstrings can be used to create automatic documentations (Documenter.jl) - Community is very helpful! Julia's Slack and Discourse are an invaluable source of information - TagBot is very useful for tagging new releases (comment`@JuliaRegister register`) - # Benefits of using all of these tools Tim Holy: ![Impacts of continuous integration](https://hackmd.io/_uploads/By_4TCynC.png) CI reduces reviewer workload to make it less of a bottleneck. "Open-source" project generally have no CI ![NoCI](https://hackmd.io/_uploads/rybmTRJ3R.png) How does it look for Julia? ![Julia strongly encourages OSI license and good coding practices](https://hackmd.io/_uploads/SkTZTAyhR.png) Julia strongly encourages good coding practices, how? because it is easy -> PkgTemplates.jl ![DocumentationJuliaStatistics](https://hackmd.io/_uploads/HkklaRkh0.png) Median number of contributors: 2 # Documentation ![Documentation - I can make it work](https://hackmd.io/_uploads/BJO03RyhC.png) Different types of documentation (David Laing) https://docs.divio.com/documentation-system/ ![Documentation types](https://hackmd.io/_uploads/ryjih0k3R.png) - Julia - NumPy - etc # Why should we use Julia coming from MATLAB? - Mathematical computations - GPUs on all architectures - High-performance computing - Unparalleled composability - Reproducible - Foments good coding practices - For scientific minded person, Julia is very attractive - For newbies MATLAB is more attractive # Take home message ![TwitJuliaYannLecun](https://hackmd.io/_uploads/Sydvn0khA.png) ![MatthijsCoxRemperatureJulia](https://hackmd.io/_uploads/Hkyt2Ak3R.png) ![PersonalityBasedOnProgrammingLanguage](https://hackmd.io/_uploads/HJk93012R.png)

    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