victor moens
    • 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 New
    • Engagement control
    • Make a copy
    • 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 Note Insights Versions and GitHub Sync Sharing URL Create Help
Create Create new note Create a note from template
Menu
Options
Engagement control Make a copy 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
    • Any changes
      Be notified of any changes
    • Mention me
      Be notified of mention me
    • Unsubscribe
    # Iteration 3 aanpak - multiple displays - resize events - event catchen en deelop() oproepen? - directory views and opening files - JSON-as-file-system # Presentatie voorbereiding - Verdeling: - Edouard: GRASP over Files, File, Cursor, Buffer + tests - Victor: GRASP over alles van tree + tests - Maxim: GRASP over Inputhandler, write, draw, terminalapp +tests - Cas: sequence diagrams + tests suites # guisseppe vragen - moeten interfaces getest worden? # guisseppe commentaar - decouple the ui and view nog meer -> remove link between view and ui -> does observer really solves problems around coupling and cohesion? ~~- viewtree: node: children moet een list worden viewnode should not have children~~ - checking type of object is not good pratice! # opgave The main part of the presentation should cover the design. The motivation of your design decisions must be explained in terms of GRASP principles. Use the appropriate design diagrams to illustrate how the most important parts of your software work. Your presentation should cover the following elements. Note that these are not necessarily all separate sections in the presentation. 1. A discussion of the high level design of the software (use GRASP patterns). Give a rationale for all the important design decisions your team has made. 2. A more detailed discussion of the parts that you think are the most interest- ing in terms of design (use GRASP patterns). Again we expect a rationale here for the important design decisions. 3. A discussion of the testing approach used in the current iteration. 4. An overview of the project management. Give an approximation of how many hours each team member worked. Use the following categories: group work, individual work, and study (excluding the classes and exercise ses- sions). In addition, insert a slide that describes the roles of the team mem- bers of the current iteration, and the roles for the next iteration. Note that these slides do not have to be presented, but we need the information. Your presentation should not consist of slides filled with text, but of slides with clear design diagrams and keywords or a few short sentences. The goal of giving a presentation is to communicate a message, not to write a novel. All design diagrams should be clearly readable and use the correct UML notation. It is therefore typically a bad idea to create a single class diagram with all information. Instead, you can for example use an overview class diagram with only the most important classes, and use more detailed class diagrams to document specific parts of the system. Similarly, use appropriate interaction diagrams to illustrate the working of the most important (or complex) parts of the system. **vragen** voor Guiseppe: //- trekken onze sequence diagrams (en klassediagram) op iets? //- wanneer gaat verdediging zijn? - inleveren: javadoc, diagrams, src-folder, **system.jar**?, (design.pdf) - moeten we kant en klare GRASP uitleg hebben? //- "*The number of files specified shall not be greater than the vertical size of the terminal text area (in characters) divided by two.*" Dees kan toch ni?! //- case 5 alternative cases active //- tereminal parser geript van Bart, is dat ok? indien ja, moet die dan in een aparte class of ni? (miss kan die mee in de algemene handler) //- wat als statusbar niet past? notes bij meeting: - user mag geen activation bar hebben - use case 4 filebuffer activation bar ends after saveinfile, how? - system seq is user system interaction - andere seq diagram is effectief met classes, we need to show everything, go more into detail, use entry point action from user as a given to start interaction - rotate functionaliteit moet aangepast worden to do: - zorgen dat ons class diagram overeenkomt met de code - sequence en class diagram fixen -> zie mail guiseppe Tegen maandag 3) onderste scrollbar (optioneel) 4) Documentatie 5) Encapsulation enz (OGP) 8) rotate layout (victor) 10) default line seperator and flags 11) starten met minstens 1 file en max size_text_area/2 13) tests + defensive approach (throwing Exceptions etc) mail Guiseppe Hi all, I will provide some tips regarding UML notation. For a discussion about your design, we can organize a meeting early next week. In the next points I will reference pages of the Larman book. - In you sequence diagrams, you are modeling both the interaction between external actors and the system, and the internal chain of events and messages exchanged by the software components following a request. You can use system sequence diagrams (page 175) to show the external actors, the events, and the generated output. So, you focus only on the dynamic behavior of the objects in the related sequence diagram of a use case (page 224). - Make sure to align the activation bars for method with the actual lifespan of the method call (usually, they do not start before a method is called, nor finish after a method returns). - Return arrows are usually dotted, while method calls are continuous, try to be consistent. Also, returning a value should not look like a method call. - Be careful when you have method calls that go back and forth in between classes. This is a sign of high coupling. In good design, method calls go typically (not always) point to the right while values are returned the opposite direction. - I assume Textr is the same as Main in your class diagram (?) Ask yourself how many responsibilities you are currently assigning to this class. - Your composite relationship between main and layout is confusing. Do you want to say that Layout can only be a part of Main? Best, Giuseppe # GRASP - **Information expert** (also expert or the expert principle) is a principle used to determine where to delegate responsibilities such as methods, computed fields, and so on. Using the principle of information expert, a general approach to assigning responsibilities is to look at a given responsibility, determine the information needed to fulfill it, and then determine where that information is stored. This will lead to placing the responsibility on the class with the most information required to fulfill it. *Related Pattern or Principle: Low Coupling, High Cohesion* - **Creator** Which class is responsible for creating objects is a fundamental property of the relationship between objects of particular classes. Problem: Who creates object A? Solution: In general, Assign class B the responsibility to create object A if one, or preferably more, of the following apply: - Instances of B contain or compositely aggregate instances of A - Instances of B record instances of A - Instances of B closely use instances of A - Instances of B have the initializing information for instances of A and pass it on creation. *Related Pattern or Principle: Low Coupling, Factory Pattern* - **Controller** The controller pattern assigns the responsibility of dealing with system events to a non-UI class that represents the overall system or a use case scenario. A controller object is a non-user interface object responsible for receiving or handling a system event. Problem: Who should be responsible for handling an input system event? Solution: A use case controller should be used to deal with all system events of a use case, and may be used for more than one use case. For instance, for the use cases Create User and Delete User, one can have a single class called UserController, instead of two separate use case controllers. Alternatively a facade controller would be used; this applies when the object with responsibility for handling the event represents the overall system or a root object. The controller is defined as the first object beyond the UI layer that receives and coordinates ("controls") a system operation. The controller should delegate the work that needs to be done to other objects; it coordinates or controls the activity. It should not do much work itself. The GRASP Controller can be thought of as being a part of the application/service layer (assuming that the application has made an explicit distinction between the application/service layer and the domain layer) in an object-oriented system with common layers in an information system logical architecture. *Related Pattern or Principle: Command, Facade, Layers, Pure Fabrication* - **Indirection** The indirection pattern supports low coupling and reuses potential between two elements by assigning the responsibility of mediation between them to an intermediate object. An example of this is the introduction of a controller component for mediation between data (model) and its representation (view) in the model-view-controller pattern. This ensures that coupling between them remains low. Problem: Where to assign responsibility, to avoid direct coupling between two (or more) things? How to de-couple objects so that low coupling is supported and reuse potential remains higher? Solution: Assign the responsibility to an intermediate object to mediate between other components or services so that they are not directly coupled. The intermediary creates an indirection between the other components. *Related Pattern or Principle: Controller* - **Low Coupling** Coupling is a measure of how strongly one element is connected to, has knowledge of, or relies on other elements. Low coupling is an evaluative pattern that dictates how to assign responsibilities for the following benefits: - lower dependency between the classes, - change in one class having a lower impact on other classes, - higher reuse potential. - **High cohesion** is an evaluative pattern that attempts to keep objects appropriately focused, manageable and understandable. High cohesion is generally used in support of low coupling. High cohesion means that the responsibilities of a given set of elements are strongly related and highly focused on a rather specific topic. Breaking programs into classes and subsystems, if correctly done, is an example of activities that increase the cohesive properties of named classes and subsystems. Alternatively, low cohesion is a situation in which a set of elements, of e.g., a subsystem, has too many unrelated responsibilities. Subsystems with low cohesion between their constituent elements often suffer from being hard to comprehend, reuse, maintain and change as a whole. - **Polymorphism** According to the polymorphism principle, responsibility for defining the variation of behaviors based on type is assigned to the type for which this variation happens. This is achieved using polymorphic operations. The user of the type should use polymorphic operations instead of explicit branching based on type. Problem: How to handle alternatives based on type? How to create pluggable software components? Solution: When related alternatives or behaviors vary by type (class), assign responsibility for the behavior—using polymorphic operations—to the types for which the behavior varies. (Polymorphism has several related meanings. In this context, it means "giving the same name to services in different objects".) - **Protected Variations** The protected variations pattern protects elements from the variations on other elements (objects, systems, subsystems) by wrapping the focus of instability with an interface and using polymorphism to create various implementations of this interface. Problem: How to design objects, subsystems, and systems so that the variations or instability in these elements do not have an undesirable impact on other elements? Solution: Identify points of predicted variation or instability; assign responsibilities to create a stable interface around them. - **Pure fabrication** A pure fabrication is a class that does not represent a concept in the problem domain, specially made up to achieve low coupling, high cohesion, and the reuse potential thereof derived (when a solution presented by the information expert pattern does not). This kind of class is called a "service" in domain-driven design. *Related Patterns and Principles: Low Coupling, High Cohesion.* # Sequence diagrams **plant uml code use case 1: hey Victor dit is klaar** MAIN @startuml actor User participant ":Terminalapp" as Terminalapp participant ":Inputhandler" as Inputhandler participant ":Files" as Files participant ":File" as FileBuffer participant ":ViewTree" as ViewTree participant ":Buffer" as Buffer User -> Terminalapp: launch(filepaths) activate Terminalapp Terminalapp -> Terminalapp: getTerminalSize() Terminalapp -> Terminalapp: check_for_flags(filepaths) Terminalapp -> Inputhandler: run(filepaths) activate Inputhandler alt valid file Inputhandler -> Files: new Files(filepaths, line separator, terminalsize) activate Files Files -> Files: inlezen(filepaths, line separator) Files -> FileBuffer: new file(file, line separator) activate FileBuffer FileBuffer -> FileBuffer: inlezen(file) FileBuffer -> Buffer: new Buffer(buffer) activate Buffer Buffer -> Buffer: setText() Buffer --> FileBuffer: return Buffer deactivate Buffer FileBuffer --> Files: return file deactivate FileBuffer Files --> Inputhandler: return files deactivate Files Inputhandler -> ViewTree: files.gettree() activate ViewTree ViewTree --> Inputhandler: return tree Inputhandler -> ViewTree: tree.getAllViewNodes().get(0).get_file(); ViewTree --> Inputhandler: return active file deactivate ViewTree Inputhandler --> User: display() else file contains forbidden bytes Inputhandler -> Files: new Files(files, line separator, terminalsize) activate Files Files --> User: exception deactivate Files deactivate Inputhandler deactivate Terminalapp end @enduml ![case1](https://hackmd.io/_uploads/SkRLTabRp.png) **plant uml code use case 2: klaar** MAIN @startuml actor User participant ":Cursor" as C participant ":inputhandler" as UI participant ":viewTree" as V participant ":viewNode" as N participant ":File" as F User -> UI: press Ctrl+P or Ctrl+N activate UI UI -> UI: controlP(index,tree) or controlN(index,tree) activate UI UI -> V: tree.getAllViewNodes() activate V V-->UI: return viewNodes deactivate V UI->N: viewNodes.get(index).get_file() activate N N-->UI: return file deactivate N UI->UI: change Active UI-->UI: return index deactivate UI UI -> F: active.getCursor().getLine() and active.getCursor().getColumn() activate F F->UI: return line and column deactivate F UI->UI: moveCursor(line,column) UI-->User: display moved cursor User -> UI: presses arrow key UI -> UI: arrowDirection(myFiles) activate UI UI->F: active.getCursor() activate F F-->UI: return cursor deactivate F UI->C: cursor.moveDirection() activate C C->F: getBuffer().getvalues() activate F F-->C: return buffer values C->F: buffer.changeValues() deactivate F C->C: modifyOwnValues() C->UI: return 0 or 1 deactivate C UI->Files: myFiles.display() deactivate UI activate Files Files-->User: shows updated screen deactivate Files deactivate UI @enduml ![case2](https://hackmd.io/_uploads/SJqB0pZAT.png) **plant uml code use case 3: klaar** MAIN @startuml actor User participant ":inputhandler" as UI participant ":viewTree" as V participant ":viewNode" as N participant ":File" as F participant ":Cursor" as C participant ":Write" as W User -> UI: press Ctrl+P or Ctrl+N activate UI UI -> UI: controlP(index,tree) or controlN(index,tree) activate UI UI -> V: tree.getAllViewNodes() activate V V-->UI: return viewNodes deactivate V UI->N: viewNodes.get(index).get_file() activate N N-->UI: return file deactivate N UI->UI: change Active UI-->UI: return index deactivate UI UI -> F: active.getCursor().getLine() and active.getCursor().getColumn() activate F F->UI: return line and column deactivate F UI->UI: moveCursor(line,column) UI-->User: display moved cursor User -> UI: presses arrow key UI -> UI: arrowDirection(myFiles) activate UI UI->F: active.getCursor() activate F F-->UI: return cursor deactivate F UI->C: cursor.moveDirection() activate C C->F: getBuffer().getvalues() activate F F-->C: return buffer values C->F: buffer.changeValues() deactivate F C->C: modifyOwnValues() C->UI: return 0 or 1 deactivate C UI->Files: myFiles.display() deactivate UI activate Files Files-->User: shows updated screen, including scrollbar deactivate Files User -> UI: presses ASCII char UI->UI: writeKey(key) activate UI UI->W: addWrite(char, active) activate W W->F: getBuffer() activate F F-->W: return buffer W->F:modifyBufferValues() W-->UI: modified buffer deactivate F deactivate W UI->Files: myFiles.display() deactivate UI activate Files Files-->User: shows updated screen, including dirty asterix deactivate Files deactivate UI @enduml ![case3](https://hackmd.io/_uploads/SJJuZR-A6.png) **plant uml code use case 4 hey dit is ook klaar Victor** @startuml actor User participant ":Inputhandler" as Inputhandler participant ":File" as FileBuffer participant ":Files" as Files participant ":ViewTree" as ViewTree participant ":ViewNode" as ViewNode participant ":Buffer" as Buffer User -> Inputhandler: Press Ctrl+P or Ctrl+N activate Inputhandler Inputhandler -> Inputhandler: ControlP(index, tree) or ControlN(index,tree) activate Inputhandler Inputhandler -> ViewTree: tree.getAllViewNodes() activate ViewTree ViewTree --> Inputhandler: return viewNodes deactivate ViewTree Inputhandler -> ViewNode: viewNodes.get(index).get_file() activate ViewNode ViewNode --> Inputhandler: return file deactivate ViewNode Inputhandler -> Inputhandler: change Active Inputhandler --> Inputhandler: return index deactivate Inputhandler User -> Inputhandler: Press(Ctrl+S) Inputhandler -> Buffer: getBuffer().getdirty() activate Buffer Buffer --> Inputhandler: dirty deactivate Buffer alt good Inputhandler -> Files: exists(file) activate Files Files --> Inputhandler: true deactivate Files Inputhandler -> FileBuffer: save() activate FileBuffer FileBuffer -> FileBuffer: write(line) FileBuffer -> Buffer: setdirty(false) activate Buffer deactivate Buffer FileBuffer -> FileBuffer: inlezen() FileBuffer --> User: display deactivate FileBuffer else bad Inputhandler -> Files: exists(file) activate Files Files --> Inputhandler: False deactivate Files Inputhandler -> Inputhandler: saveerror() Inputhandler --> User: error "Failed saving the file" end deactivate Inputhandler @enduml ![case4](https://hackmd.io/_uploads/r1_m8T-06.png) **plant uml code use case 5: final** @startuml actor User participant ":Inputhandler" as I participant ":File" as V participant ":Files" as F participant ":FileBuffer" as FB participant ":viewNode" as N participant ":Viewtree" as T User -> I: press Ctrl+P or Ctrl+N activate I I -> I: controlP(index,tree) or controlN(index,tree) activate I I -> T: tree.getAllViewNodes() activate T T-->I: return viewNodes deactivate T I->N: viewNodes.get(index).get_file() activate N N--> I: return file deactivate N I->I: change Active I-->I: return index deactivate I I -> F: active.getCursor().getLine() and active.getCursor().getColumn() activate F F->I: return line and column deactivate F I->I: moveCursor(line,column) I-->User: display moved cursor User -> I: Press F4 activate I I -> I: f4(tree, myfiles, running) activate I I -> V: Check_Dirty() activate V V --> I: dirty deactivate V alt Buffer is not dirty I -> V: close(active) activate V V -> T: removenode(active node) activate T T --> V: updated tree deactivate T V -> V: deelop() V--> User: updated view deactivate V I --> User: updated view else Buffer is dirty I --> User: ask confirmation User -> I: Press Y I-> F: exists(file) activate F F--> I: true deactivate F I-> FB: save() activate FB FB-> FB: write(line) FB-> Buffer: setdirty(false) activate Buffer deactivate Buffer FB-> FB: inlezen() FB--> User: display deactivate FB I -> V: close(active) activate V V -> T: removenode(active node) activate T T --> V: updated tree deactivate T V -> V: deelop() V--> User: updated view deactivate V I --> User: updated view else Buffer is dirty I --> User: ask confirmation User -> I: Press N I --> User: unchanged view end deactivate I deactivate User @endumlate User @enduml ![lLJ1Rjim3BthAuYU72pPgISVYZOP30GOZ1uo0piLGioqGXKfaEIqtTTFbDI4Tj8TbvD4FZu-YY--zq6wCEoraDjW7VpowCGXXjHM7QG9S5ElpM48BzBq6jqDI0_h2Q1H6bEYkvBmATDSoIo7tQumDij9_gZmhRLzfct59Dl5R72OiniXI3Gixc1Tmy6Xzx0AJdzx1ElogQNXr546ZDhN1R](https://hackmd.io/_uploads/Sy9ACa-Rp.png) **plant uml code use case 6: final** @startuml actor User participant ":inputhandler" as I participant ":viewTree" as T participant ":files" as F participant ":debug" as D participant ":viewnode" as N User -> I: press Ctrl+P or Ctrl+N activate I I -> I: controlP(index,tree) or controlN(index,tree) activate I I -> T: tree.getAllViewNodes() activate T T-->I: return viewNodes deactivate T I->N: viewNodes.get(index).get_file() activate N N--> I: return file deactivate N I->I: change Active I-->I: return index deactivate I I -> F: active.getCursor().getLine() and active.getCursor().getColumn() activate F F->I: return line and column deactivate F I->I: moveCursor(line,column) I-->User: display moved cursor User -> I: Ctrl+R/Ctrl+T activate I alt not the last view in layout I -> T: rotate_counter/clockwise(node1,node2) activate T T --> I: updated tree deactivate T I -> F: deelOp(Terminalapp.getTerminalSize()) activate F F --> User: updated view deactivate F else last view in the layout I -> D: testSound() deactivate I activate D D --> User: sound bell, unchanged view deactivate D end @end @enduml ![TLB1Rjim3BthAuYU72nPiHrz25eaC11Wy8hLsxLGBIuL9ak6HANRldwYuYoojrvacNnyVEJJNI3fAGv6o9wSXwy1lHXJIFTwb9RWfjPsZFGYhJBeRq06E2m09usldKVCoMwH_AuDXfnf5Xc5p_6OC_l_45gdpeIj42mADbiur31w305svCsx1t3-V6jPl3v9mgJjC25xPyaxyr1fg_3dcZ](https://hackmd.io/_uploads/Sy1d1CWRa.png) # Class diagram @startuml class Main { - fileBuffers: List<FileBuffer> + launchTextr(filePaths: String[]) + inspectBufferContents() + editBufferContents() + saveBuffer() + closeBuffer() + rearrangeLayout() } class FileBuffer { - filePath: String - contents: String - dirty: boolean + loadFile(filePath: String) + saveToFile() + isDirty(): boolean + closeBuffer() } class View { - buffer: FileBuffer + focus() + moveInsertionPoint() + updateScrollState() } class UserInputHandler { + handleUserInput() } class Layout { - bufferViews: List<FileBuffer> + create_layout() } Main "1" -d- "0..*" FileBuffer FileBuffer "1" -l- "0..*" View Layout –* Main View "0..*" -l- "1"Layout Main – UserInputHandler UserInputHandler –> Main @enduml ![classdiagram2](https://hackmd.io/_uploads/Hki_r93nT.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