Thomie29
    • 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
    # Team Meeting 1 * Kennismaking * Lezen en overlopen van de opdracht * Uitvoeren van de voorbeeldcode en oplossen van technische problemen * Overzicht van de grote opdrachten * Database: * Hoe? Werken met liberaries -> JSON * Opmerking: bestanden best steeds eerst nieuw maken en nadien en hernoemen * Comprimeren -> Huffman * Server * Algemene opmerking * Keuze om de complexiteit stap per stap op te bouwen en te starten met een basis implementatie. Er wordt wel ruimte gelaten, zodat optimalisaties makkelijk codeerbaar zijn. * Wie doet wat * Deze week: focus op database en de connectie client-server * Team database: geleid door Robbe, samen met Tom, Thomas en Florian * Team server: geleid door Briek, samen met Alec, Jens, Kobus en Laurens * Extra opdeling wordt gemaakt binnen deze 2 teams naargelang de aanpak 1. Database: aanpak * Keuze voor 1 grote klasse database, die alle operaties implementeert * User, channel, message krijgen elk een eigen klasse, die constructor en getters implementeert * Wie doet wat? Klasse Channel door Tom, Message door Thomas, User door Florian en Database door Robbe * Opmerking: opletten voor bidirectionele relaties tussen channel-user en message-channel 2. Server: overzicht * createJSONMessage D * Maak een json message van de vorm: * Vb. ChannelJoin: { "command": "ChannelJoin", "email": "me@foo.be", "mode": 4, "channelId": "#a00d200b" } * basis ZOD-schema implementeren D [Briek] * design dat makkelijk uitbreidbaar is * channelJoin/channelJoined [Jens] * Stuur request naar de server om een bepaalde channel te joinen. (De user is nog geen deelnemer van deze channel) * channelSwitch/channelSwitched * Verander de huidige channel waarin de user aan het typen is. * isChannelAlive/channelIsAlive * Server moet checken of channel ID bestaat en dat de email overeenkomt met de geconnecteerde client * channelCheck/channelchecked * Kijkt in welke channel de user aan het typen is. * channelLeave/channelLeft * Verlaat de actieve channel waarin de user aan het typen is. * login [Laurens] * Log in in een bestaand account, kijkt na of client bestaat en kijkt wachtwoord na of wachtwoord overeenkomt (past termination datum aan) * loggedIn * Reply van de server op een login * loginRefused * Indien login niet voldoet * passwordVerification * Nakijken of wachtwoord overeenkomt * signup * Aanmaken van nieuw account, kijkt na of gebruiker gegevens legaal zijn * signedUp * Reply van de server op een login * signupFailed * Indien signup niet lukt * sendFile / fileSent * Verzendt een file door compressie met huffmanbomen en decompressie bij de eindgebruiker * CompressFile * DecompressFile * ConstructHuffmanTree -> Frequency analysis * removeUser * Indien de user te lang niet actief is/ user data delete request indient, data van de user verwijderen * removeChannel * Verwijdert bepaalde channel en bijhorende files (check if all users left the channel) * createChannel * Creëert een nieuwe channel * sendReminder * Stuurt een mail naar iemand die een reminder heeft ingesteld [Revised] * [Revision]: hier is nog volledig vrije keuze van de implementatie * updateSelfDestructTimestamp * Update de self destruct timestamp on user activity * sendMessage D [kobus] * Verstuurt een bericht (een string van utf-8 characters, client moet al in een channel zitten) * onClientMessage [kobus] * Stuurt bericht van SendMessage door naar andere gebruikers * ServerPersistence (database) * (Passief deel): bij server sluiten geen dataverlies * MessageLookup (database) * Geeft timestamp, geeft bericht terug dat het dichtst in de buurt komt * PasswordHashing D * hash passwords met argon2id ```sequence Note over Client: Read Client input Client->Server: Request Note over Server: Sort request Server->Client: Response Server-->Other: Response announcement ``` # Team Meeting 2 * Overlopen werk van vorige week * Bespreking tussen team database en team server * Overlopen welke functies nodig zijn en hoe deze zullen heten, zodat het server team deze kan gebruiken bij het aanspreken van de database * Server: vooruitgang * Basisprotocol tussen server en client * Voor log in nog extra functies nodig * Interface voor channelchange gemaakt * Provisioneel message versturingssysteem gemaakt * Database: in het team van 4 werd de keuze gemaakt om de groep op te delen in 2, aangezien de implementatie al goed is geëvalueerd. Tom en Robbe focussen zich verder op het implementeren van de functies in de database-module. Florian en Thomas starten met de implementatie van een compressie-algoritme. Vooruitgang database: * Lichte refactoring * Afwerken van load functionaliteit * Implementeren van save functionaliteit * Gestart met schrijven van testen * Gedeeltelijk implementeren van database methodes (zie hieronder) * Werken deze week * Input van de client inlezen * Afwerken delen van week 1 Hieronder de huidige progressie (Server-Client), Checkmark betekend afgewerkt, C,S of D betekend dat er respectievelijk nog werk is aan het client, server of communicatie met database deel van de opdracht * [X] CreateJSONMessage * [X] Basis ZOD-schema implementeren * [ ] Channel... S,D * [ ] Login/Signup C,S,D * [ ] PasswordVerification D * [ ] SendFile C,S,D * [ ] Messages S * [ ] SendReminder C,S * [ ] UpdateSelfdestructTimestamp C,S,D * Mock versie maken van de database ? * Implementeren functies Database: (= Interface) * [X] functie die nakijkt of een channel ID bestaat (channelExists) * [X] toevoegen van een user (addUser) * [X] Bestaat een User? (userExists) * [X] paswoord ophalen (getHashedPass) * [X] user toevoegen aan channel (addUserToChannel) * [X] nakijken of user in een channel zit (getPermissions) * [X] een user uit een channel verwijderen (removeUserFromChannel) * [X] termination datum aanpassen/instellen (getTerminationDate / setTerminationDate) * [X] user verwijderen (removeUser) * [ ] messages van een user verwijderen * [X] channel verwijderen (removeChannel) * [X] channel aanmaken (addChannel) * [X] message toevoegen (sendFile / sendMessage) * [ ] message opvragen op basis van * Compressie-algoritme: het basisidee werd gehaald van de voorgestelde website in de opgave, maar werd wel op een eigen manier verwerkt. * Stap 1: opstellen van een frequency table, gebruik makende van een dictionary. * Stap 2: deze tabel sorteren en zo een array maken van tuples, om later gemakkelijk te kunnen itereren * Stap 3: opstellen van een klasse Node, die alle informatie van een node kan opslaan en operaties als setParent en setChildren + getters heeft * Stap 4: mbv de klasse Node een de gesorteerde frequency table omzetten naar een gesorteerde array van nodes * Stap 5: mbv de gesorteerde array van nodes een compression tree maken. We hebben gesorteerd om nu slechts 1 maal de lijst te moeten overlopen en zo alle nodes te vormen. Wanneer een node alle nodige informatie bevat, wordt hij verwijderd uit de gesorteerde array en toegevoegd aan een set die alle nodes bijhoudt. * Stap 6: compressie -> volgende week * Stap 7: decompressie -> volgende week # Team Meeting 3 * Vooruitgang deze week * Begin mock database * Huffmanboom maken van de tree mee bezig geweest * Deze week * Huffman codering afwerken (karakters omzetten tot bits + bitstream maken en decompressie algoritme schrijven ) * Afwerken check list team meeting 2 * Unit test cases maken + documentatie schrijven * Database Interface * Afwerken Thuis * ~~Database Subklassen aanpassen om te voldoen aan de vereisten voor Database~~ * Database Implementatie * ~~loadDB()~~ * Hieronder de huidige progressie (Server-Client), Checkmark betekend afgewerkt, C,S of D betekend dat er respectievelijk nog werk is aan het client, server of communicatie met database deel van de opdracht * [X] CreateJSONMessage * [X] Basis ZOD-schema implementeren * [ ] Channel... S * [ ] Login C * [X] Signup * [ ] PasswordVerification D * [ ] SendFile C,S,D * [ ] Messages S * [ ] SendReminder C,S * [ ] UpdateSelfdestructTimestamp C,S,D * Database: Er werd een interface DatabaseInterface gedefinieerd met de gevraagde functie-headers en bijhorende documentatie (op vraag van Briek). Hierdoor kunnen al mock-functie-oproepen naar de Database gedaan worden in Server, terwijl de back-end implementatie in Database nog niet volledig moet zijn. De klasse Database zal deze interface aan het einde van de week implementeren. * Database II: Channel en User gebruiken nu terug Sets, aanpassing is doorgevoerd naar Database. We werken met Sets omdat de volgorde van Users of Channels niet uitmaakt, en sneller zijn om op te zoeken. Voor Messages behouden we wel de Array, gezien we dan makkelijker in volgorde kunnen teruggeven. De Database Interface is uitgebreid (op vraag van Jens) met getChannel(), getUser(), getActiveChannel(), etc, en is gepusht naar *database-interface* * Compression: (Florian en Thomas) * Schrijven van testen voor de reeds gemaakte functies die nog geen testcase hadden * assignBits: functie die elke value een bitrepresentatie toekent * Gekozen voor een recursieve methode om zo op een efficiënte manier over de knopen te kunnen gaan. * Deze methode leek heel lang niet te werken, maar het bleek dat de versie wel juist was. Er was echter wel een fout in MakeTree en hulpfunctie InsertNode, die de testcase nog niet coverde. * Aangezien de eerste versie niet werkte, werd ook een tweede implementatie gemaakt, vooraleer het echte probleem werd gevonden. Deze tweede versie is een kortere en meer effiënte versie en wordt daarom ook gekozen. * MakeTree + InsertNode (thuis, Thomas): * fouten werden verbeterd. Het doorschuiven van een element naar het verste punt (0-de element in de array) gebeurde niet, waardoor elementen in bepaalde gevallen op de verkeerde plek konden staan en verkeerde Nodes + tree werden aangemaakt. * createBitStream (thuis, Thomas) * Eenvoudige implementatie die een map gebruikt om de bit representaties van de values te verkrijgen * createMessage (thuis, Thomas) * Deze versie doet eigenlijk het omgekeerde van createBitStream * Oorspronkelijk werd geen rekening gehouden voor een implementatie die de omgekeerde beweging van bit representatie -> karakter doet. Daarom werd een twee map in alle nodige functies een extra map gecreëerd die de omgekeerde beweging kan uitvoeren. Op die manier moet niet steeds over alle keys gezocht worden om een value op te zoeken en de translatie te doen. * Toevoegen van testen voor de nieuwe implementaties (thuis, Thomas) * assignBits, makeTree (deel 2), insertNode, createBitStream, createMessage * Maken van extra module die zorgt voor een interface (thuis, Thomas) * DoCompression * DoDecompression * voert de algoritmes uit zonder dat iemand iets moet weten over de verdere implementatie * Maken van testen voor DoCompression en DoDecompression (thuis, Thomas) * Implementatie van de bitstream met het opvullen van bytes (thuis, Thomas) * Extra gemaakte modules: bit+byte-operations * Implementatie die het mogelijk maakt om de compression rate te bepalen (thuis, Thomas) * Database III: De klasse Message werd opgesplitst in subklassen TextMessage en FileMessage aan de hand van Polymorfisme (door Robbe). Deze types kunnen nu ook aangemaakt worden via de Database Interface. Andere triviale methoden werden toegevoed aan Database Interface, zoals updateLastSeenDate(), etc... De Database zal geimplementeerd worden in de branch *feature/database/implementation*. Binnenkort volgt een beschrijving van de Database Interface indien nodig * Database IV: Het grote deel van de Interface werd geimplementeerd in de klasse Database *(in database_bis.mts)*. Er ontbreken nog enkele test-cases en de implementatie van MessageLookup(). De Interface werd licht gewijzigd (voornamelijk veranderen naar async Promise<> return-types). Enkel nog mergen met *database* en *main*, en verder implementeren... # Team Meeting 4 **Mogelijke vergaderpunten:** * Het verwijderen van een User: Wat met Messages? Moeten lege Channels verwijderd worden? * Hoe worden berichten opgeslagen? * Mogelijkheden * Buckets: berichten worden gegroepeerd op basis van de tijdsperiode waarin ze gestuurd zijn * Implementatie verwijderen gebruikers * Guidelines moeten nog bekeken worden Overlopen vooruitgang Robbe: Berichten bijhouden op verschillende manieren (filemessage en textmessage) (database) Jens: Channelfuncies worden verder uitgewerkt (Server-Channel), Schrijven van testen en beginnen aan userinterface te maken. Laurens: functies voor in te loggen gemaakt & tests (Server-Login) Kobus: functies voor sign up (Server-SignUp) Florian + Thomas: (De)compression is volledig geïmplementeerd en gemerged naar de main branch. Alec: functies voor doorsturen bestand serverside Briek: new Almessage modifications, zou moeten werken Tom: zoeken doorheen database sneller gemaakt, door gebruik maken van maps * Wat moet er nog gebeuren * User can sign up and log in with account * Kobus, Laurens, Robbe, moet nog getest worden * Users can join and leave channels * Jens, moet nog getest worden. Wachten op db interface. * All members of the channel can send messages * All members of the channel can read messages * Users can send messages in the channel * Not yet in channel, just on server * Shutdown of the server can't lead to data loss * Tom, Robbe, ok * Na elke operatie wordt de database opgeslagen * Login with password * Laurens, ok, nog te testen * Compression functies werken, nog te implementeren aan de server side * Alec, moet nog verder geïmplementeerd worden * Automatich verwijderen van inactieve users * Tom, functies moeten nog opgeroepen worden * Robbe ging kijken om een Schedular aan te maken TO DO: * [X] Database loadDB() geeft soms ERROR -> Gefixt door try-catch-loop * [x] RemoveUser() anders implementeren -> Optioneel argument *purge* toegevoegd dat Messages ook verwijderd -> Default op false, dus enkel anonymizeSender() op Messages * [x] Database Interface aanpassen naar Promise<> -> Code van Server moet aangepast worden met 'await' -> ERRORs opgelost tijdens Merge-request * [x] MessageLookup() Interface aanpassen en Implementeren -> Geimplementeerd aan de hand van Binair Zoeken * [x] Verder Test-cases voor Database schrijven -> We hebben 95% function-coverage, dus voldoende * [x] sendReminder() toevoegen aan Database (-> Robbe) -> Merged op 27/11 * [x] Bestand opslaan in Database (bitstream als Uint8Array of number[]) -> sendFileMessage() en getFileFromDatabase() -> Bestanden opgeslagen als *DB.filePath/attachments/messageID.json* * [x] Message-klasse moet bit-lengte opslaan -> Bitlengte wordt opgeslagen in messageID.txt indien FileMessage * [ ] Beginnen schrijven aan het Verslag * [x] askFile nog afwerken (-> Alec) * [x] Mergen van *main* en *feature/database/implementation2* zal errors veroorzaken in andere bestanden wegens de aanpassingen aan de Interface. * [x] Verander Database Getters van naam -> .users naar .GetUsersArray(), analoog voor Messages en Channels -> getUsersAmount() toegevoegd om efficienter het aantal te berekenen * [ ] ~~User to User messages~~ # Team Meeting 5 TO DO: - [x] ReadMe file (Tom) - [x] Add Missing Unit Tests - [x] Add Server Start-up Alias (op branch askfile2) - [x] AskFile (Alec) - [x] SendReminder (Robbe) - [ ] User to User Messages: extra, niet voor nu - [x] GitLab stale Branches verwijderen - [ ] Groepsfoto :D - [x] Assets correct in .gitignore (Tom) - [ ] Verslag * Missing unit tests * [x] ws-mock * Dit is file geschreven door Dirk Nuyens * [x] gives error, when 2 mockwss share URL 124-125 * [X] read-file * [X] read input from files with multiple lines 16-19 * [x] write-file * [x] gives error, when unable to write 20-21, not really sure how we can test this one * [x] node * [x] toString() method 33-46 * [x] equals() method 53-59 * [ ] equals() (this.bitRepresentation[i] === otherNode.bitRepresentation[i])) return false; 59 * [x] channel * [x] addUser returns false if user is already in channel 82 * [x] add message, when message does not exist returns false 104 * [x] delete message, when message does not exist returns false 117 * [x] user * [x] Changes the activeChannel to NULL if it is missing from the new Set 105-106 * [x] add user to channel that he is already a part of returns false 119 * [ ] client-connection * [x] Heel veel functies hiervan * [X] Login * [X] Logout * [X] Signup * [X] DeleteUser * [X] Client close * [X] Clientsendfile * [X] Clientaskfile * [ ] onClientLookupRequest * [X] onClientChannelAliveRequest -> invalid channel ID * [X] onClientChannelAliveRequest -> login required * onClientChannelAliveRequest -> default case never accesible 361-363 * [X] onClientActiveChannelRequest -> 'active_success', null * [X] onClientActiveChannelRequest -> login required * onClientChannelSwitchRequest -> default case never accesible 311-312 * [X] onClientChannelSwitchRequest -> login required * [X] onClientChannelLeaveRequest -> login required * [X] Redundancy verwijderd bij onClientJoinrequest 255 * [X] onClientChannelJoinRequest -> login required * [X] onClientCreateChannelRequest -> channel already exists (this always times out for some reason) **For some reason this function was programmed to have a never resolving promise** * [X] onClientCreateChannelRequest -> invalid channel ID (this always times out for some reason)**For some reason this function was programmed to have a never resolving promise** * [X] onClientCreateChannelRequest -> login required * [X] onClientLogoutRequest -> login required * [X] onClientLoginRequest -> account logging in does not exist * Removed ClientLogoutRequest and ClientLoginRequest relying on signup * [X] onClientLoginRequest -> already logged in * [ ] onClientMessage * [ ] onClientRawMessage * [x] chat-client * Niet echt testbaar * [ ] server-connection (Briek) * [ ] No test cases yet * [x] Database * Geeft bij vitest coverage veel delen aan die nog niet gecovered zijn, maar deze zijn (bijna) altijd clauses die een error geven als er toch inconsistency zou voorkomen, wat normaal gezien niet kan gebeuren, hier kan dus ook niet echt op getest **Vandaag:** * Laatste functies afmaken: * Bijhouden van data aan de client-side * UserInterface afwerken * Schrijven van een README * Mergen van alle branches en samenvoegen tot 1 geheel!! * Schrijven van unit testen voor laatste functies die vandaag zijn toegevoegd * Verdeling van het verslag: * Introduction: Florian * Description of the app: Florian * Overview Progress: Jens * Technical Description features: Thomas, Florian, Alec, Laurens * Evaluation of teamwork * Dividing of tasks: Robbe * Testing: Kobus, Tom * Improvements: Briek * Conclusion: Thomas * Appendix Git: Individueel tabel aanvullen # Team Meeting 6 **Thuis Afwerken:** * Werken aan het verslag **Volgende Week groepsfoto!** :D **Uitgestelde Taken:** * Channel ID: number → string * DB.getChannelMessages() reverse order? **TODO:** * Branches van alle testen toevoegen - normaal alleen nog mergen * Moeten er nog testen geschreven worden? * Andere branches mogen weg? * Zelf in de terminal alles nog eens uitvoeren om te kijken of we niets over het hoofd hebben gezien * Verslag: * Tabellen aanvullen * Groepsfoto - moet toch een beetje origineel zijn he * Figuren een naam geven en ernaar verwijzen vanuit tekst * Alle blauwe tekst eruit halen * Nalezen + spellingscheck + layout + check paginalimiet **Vragen** * Wat is de bedoeling van de demo/presentatie? * Alles tonen/in powerpoint * Deel presenteren + deel vragen beantwoorden? * ... * Wat is de bedoeling voor volgend semester wat betreft dit project ### Vergaderverslag Originele Groepsfoto :D → ASAP Hoe zit het? Branches op GitLab mergen of verwijderen of uitstellen. Verslag: * Kleine verbeteringen * Nalezen (voor Consistentie) * Feedback van Vorig Verslag toepassen * Referenties en Captions toevoegen * Tabellen Vervolledigen Unit tests uitwerken # De Presentatie De "Feedback": * Concurrency van de Database * Changes cachen, niet meteen write-through. * Queues van Requests? * UI QoL Changes: Wat bij receiven van Messages tijdens het typen? * Moderators die Channels leaven? * Mogelijke CronJob-crash *'oplossen'* naar het midden van de nacht ;) * Voorgestelde verbeteringen wel degelijk toepassen Genieten van de 'Kerstvakantie' :D # Team Meeting 7 - Lezen van de Feedback op het Verslag - Opdracht herlezen

    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