Initial commit :

Last change made - Inserted Flask API section
This commit is contained in:
Nikola
2026-07-11 19:33:44 +02:00
commit 9bc7ba9166
63 changed files with 18740 additions and 0 deletions
+13
View File
@@ -0,0 +1,13 @@
{
"alwaysUpdateLinks": true,
"attachmentFolderPath": "/Attachments",
"livePreview": true,
"defaultViewMode": "source",
"pdfExportSettings": {
"pageSize": "Letter",
"landscape": false,
"margin": "0",
"downscalePercent": 100
},
"readableLineLength": true
}
+7
View File
@@ -0,0 +1,7 @@
{
"enabledCssSnippets": [
"pdf-export",
"editor"
],
"nativeMenus": false
}
+7
View File
@@ -0,0 +1,7 @@
[
"editing-toolbar",
"obsidian-excalidraw-plugin",
"translate",
"obsidian-git",
"obsidian-pandoc"
]
+33
View File
@@ -0,0 +1,33 @@
{
"file-explorer": true,
"global-search": true,
"switcher": true,
"graph": true,
"backlink": true,
"canvas": true,
"outgoing-link": true,
"tag-pane": true,
"footnotes": false,
"properties": true,
"page-preview": true,
"daily-notes": true,
"templates": true,
"note-composer": true,
"command-palette": true,
"slash-command": false,
"editor-status": true,
"bookmarks": true,
"markdown-importer": false,
"zk-prefixer": false,
"random-note": false,
"outline": true,
"word-count": true,
"slides": false,
"audio-recorder": false,
"workspaces": false,
"file-recovery": true,
"publish": false,
"sync": true,
"bases": true,
"webviewer": false
}
+22
View File
@@ -0,0 +1,22 @@
{
"collapse-filter": true,
"search": "",
"showTags": false,
"showAttachments": false,
"hideUnresolved": false,
"showOrphans": true,
"collapse-color-groups": true,
"colorGroups": [],
"collapse-display": false,
"showArrow": false,
"textFadeMultiplier": 0,
"nodeSizeMultiplier": 1,
"lineSizeMultiplier": 1,
"collapse-forces": true,
"centerStrength": 0.518713248970312,
"repelStrength": 10,
"linkStrength": 1,
"linkDistance": 250,
"scale": 1.1447142425533312,
"close": true
}
+18
View File
@@ -0,0 +1,18 @@
{
"editing-toolbar:subscript": [
{
"modifiers": [
"Mod"
],
"key": "-"
}
],
"editing-toolbar:superscript": [
{
"modifiers": [
"Mod"
],
"key": "="
}
]
}
+541
View File
@@ -0,0 +1,541 @@
{
"lastVersion": "4.0.10",
"aestheticStyle": "default",
"positionStyle": "top",
"menuCommands": [
{
"id": "editing-toolbar:editor-undo",
"name": "Undo Edit",
"icon": "undo-glyph"
},
{
"id": "editing-toolbar:editor-redo",
"name": "Redo Edit",
"icon": "redo-glyph"
},
{
"id": "editing-toolbar:toggle-format-brush",
"name": "Format Brush",
"icon": "paintbrush"
},
{
"id": "editing-toolbar:format-eraser",
"name": "Clear Text Formatting",
"icon": "eraser"
},
{
"id": "editing-toolbar:header2-text",
"name": "Header 2",
"icon": "header-2"
},
{
"id": "editing-toolbar:header3-text",
"name": "Header 3",
"icon": "header-3"
},
{
"id": "SubmenuCommands-header",
"name": "submenu",
"icon": "header-n",
"SubmenuCommands": [
{
"id": "editing-toolbar:header1-text",
"name": "Header 1",
"icon": "header-1"
},
{
"id": "editing-toolbar:header4-text",
"name": "Header 4",
"icon": "header-4"
},
{
"id": "editing-toolbar:header5-text",
"name": "Header 5",
"icon": "header-5"
},
{
"id": "editing-toolbar:header6-text",
"name": "Header 6",
"icon": "header-6"
}
]
},
{
"id": "editing-toolbar:toggle-bold",
"name": "Bold",
"icon": "bold-glyph"
},
{
"id": "editing-toolbar:toggle-italics",
"name": "Italic",
"icon": "italic-glyph"
},
{
"id": "editing-toolbar:toggle-strikethrough",
"name": "Strikethrough",
"icon": "strikethrough-glyph"
},
{
"id": "editing-toolbar:underline",
"name": "Underline",
"icon": "underline-glyph"
},
{
"id": "editing-toolbar:toggle-highlight",
"name": "Highlight",
"icon": "highlight-glyph"
},
{
"id": "SubmenuCommands-text-tools",
"name": "Text Tools",
"icon": "box",
"menuType": "dropdown",
"SubmenuCommands": [
{
"id": "editing-toolbar:get-plain-text",
"name": "Get Plain Text",
"icon": "lucide-file-text"
},
{
"id": "editing-toolbar:smart-symbols",
"name": "Full Half Converter",
"icon": "lucide-at-sign"
},
{
"id": "editingToolbar-Divider-Line",
"name": "Line Operations",
"icon": "vertical-split"
},
{
"id": "editing-toolbar:insert-blank-lines",
"name": "Insert Blank Lines",
"icon": "lucide-space"
},
{
"id": "editing-toolbar:remove-blank-lines",
"name": "Remove Blank Lines",
"icon": "lucide-minimize-2"
},
{
"id": "editing-toolbar:split-lines",
"name": "Split Lines",
"icon": "lucide-split"
},
{
"id": "editing-toolbar:merge-lines",
"name": "Merge Lines",
"icon": "lucide-merge"
},
{
"id": "editing-toolbar:dedupe-lines",
"name": "Dedupe Lines",
"icon": "lucide-filter"
},
{
"id": "editingToolbar-Divider-Line",
"name": "Text Processing",
"icon": "vertical-split"
},
{
"id": "editing-toolbar:add-wrap",
"name": "Add Prefix/Suffix",
"icon": "lucide-wrap-text"
},
{
"id": "editing-toolbar:number-lines",
"name": "Number Lines (Custom)",
"icon": "lucide-list-ordered"
},
{
"id": "editing-toolbar:remove-whitespace-trim",
"name": "Trim Line Ends",
"icon": "lucide-scissors"
},
{
"id": "editing-toolbar:remove-whitespace-compress",
"name": "Shrink Extra Spaces",
"icon": "lucide-minimize"
},
{
"id": "editing-toolbar:remove-whitespace-all",
"name": "Remove All Whitespace",
"icon": "lucide-eraser"
},
{
"id": "editingToolbar-Divider-Line",
"name": "Advanced Tools",
"icon": "vertical-split"
},
{
"id": "editing-toolbar:list-to-table",
"name": "List to Table",
"icon": "lucide-table"
},
{
"id": "editing-toolbar:table-to-list",
"name": "Table to List",
"icon": "lucide-list"
},
{
"id": "editing-toolbar:extract-between",
"name": "Extract Between Strings",
"icon": "lucide-brackets"
}
]
},
{
"id": "SubmenuCommands-lucdf3en5",
"name": "submenu",
"icon": "edit",
"SubmenuCommands": [
{
"id": "editing-toolbar:editor-cut",
"name": "Cut",
"icon": "lucide-scissors"
},
{
"id": "editing-toolbar:editor-copy",
"name": "Copy",
"icon": "lucide-copy"
},
{
"id": "editing-toolbar:editor-paste",
"name": "Paste",
"icon": "lucide-clipboard-type"
},
{
"id": "editing-toolbar:editor:swap-line-down",
"name": "Swap Line Down",
"icon": "lucide-corner-right-down"
},
{
"id": "editing-toolbar:editor:swap-line-up",
"name": "Swap Line Up",
"icon": "lucide-corner-right-up"
}
]
},
{
"id": "editing-toolbar:editor:attach-file",
"name": "Attach File",
"icon": "lucide-paperclip"
},
{
"id": "editing-toolbar:editor:insert-table",
"name": "Insert Table",
"icon": "lucide-table"
},
{
"id": "editing-toolbar:editor:cycle-list-checklist",
"name": "Cycle List and Checklist",
"icon": "check-circle"
},
{
"id": "SubmenuCommands-luc8efull",
"name": "submenu",
"icon": "message-square",
"SubmenuCommands": [
{
"id": "editing-toolbar:editor:toggle-blockquote",
"name": "Blockquote",
"icon": "lucide-text-quote"
},
{
"id": "editing-toolbar:insert-callout",
"name": "Callout",
"icon": "lucide-quote"
}
]
},
{
"id": "SubmenuCommands-mdcmder",
"name": "submenu",
"icon": "<svg width=\"18\" height=\"18\" focusable=\"false\" fill=\"currentColor\" viewBox=\"0 0 1024 1024\"><g transform=\"scale(1, -1) translate(0, -896) scale(0.9, 0.9) \"><path class=\"path\" d=\"M464 608 l0 -568 q0 -3 -2.5 -5.5 q-2.5 -2.5 -5.5 -2.5 l-80 0 q-3 0 -5.5 2.5 q-2.5 2.5 -2.5 5.5 l0 568 l-232 0 q-3 0 -5.5 2.5 q-2.5 2.5 -2.5 5.5 l0 80 q0 3 2.5 5.5 q2.5 2.5 5.5 2.5 l560 0 q3 0 5.5 -2.5 q2.5 -2.5 2.5 -5.5 l0 -80 q0 -3 -2.5 -5.5 q-2.5 -2.5 -5.5 -2.5 l-232 0 ZM864 696 q17 0 28.5 11.5 q11.5 11.5 11.5 28.5 q0 17 -11.5 28.5 q-11.5 11.5 -28.5 11.5 q-17 0 -28.5 -11.5 q-11.5 -11.5 -11.5 -28.5 q0 -17 11.5 -28.5 q11.5 -11.5 28.5 -11.5 ZM864 640 q-40 0 -68 28 q-28 28 -28 68 q0 40 28 68 q28 28 68 28 q40 0 68 -28 q28 -28 28 -68 q0 -40 -28 -68 q-28 -28 -68 -28 ZM576 322 l0 -63 q0 -3 2 -5 l89 -70 l-89 -70 q-2 -2 -2 -5 l0 -63 q0 -4 3.5 -5.5 q3.5 -1.5 6.5 0.5 l170 133 q4 3 4.5 8.5 q0.5 5.5 -2.5 9.5 l-2 2 l-170 133 q-3 2 -6.5 0.5 q-3.5 -1.5 -3.5 -5.5 ZM256 322 l0 -63 q0 -3 -2 -5 l-89 -70 l89 -70 q2 -2 2 -5 l0 -63 q0 -4 -3.5 -5.5 q-3.5 -1.5 -6.5 0.5 l-170 133 q-4 3 -4.5 8.5 q-0.5 5.5 2.5 9.5 l2 2 l170 133 q3 2 6.5 0.5 q3.5 -1.5 3.5 -5.5 Z\"></path></g></svg>",
"SubmenuCommands": [
{
"id": "editing-toolbar:superscript",
"name": "Superscript",
"icon": "superscript-glyph"
},
{
"id": "editing-toolbar:subscript",
"name": "Subscript",
"icon": "subscript-glyph"
},
{
"id": "editing-toolbar:editor:toggle-code",
"name": "Inline Code",
"icon": "code-glyph"
},
{
"id": "editing-toolbar:codeblock",
"name": "Code Block",
"icon": "codeblock-glyph"
},
{
"id": "editing-toolbar:editor:insert-wikilink",
"name": "Wikilink",
"icon": "<svg width=\"15\" height=\"15\" focusable=\"false\" fill=\"currentColor\" viewBox=\"0 0 1024 1024\"><g transform=\"scale(1, -1) translate(0, -896) scale(0.9, 0.9) \"><path class=\"path\" d=\"M306 134 l91 0 q1 0 1 -8 l0 -80 q0 -8 -1 -8 l-91 0 q-1 0 -1 7 q0 -8 -5 -8 l-45 0 q-5 0 -5 8 l0 784 q0 8 5 8 l45 0 q5 0 5 -8 q0 8 1 8 l91 0 q1 0 1 -8 l0 -80 q0 -8 -1 -8 l-91 0 q-1 0 -1 8 l0 -623 q0 8 1 8 ZM139 134 l91 0 q1 0 1 -8 l0 -80 q0 -8 -1 -8 l-91 0 q-1 0 -1 7 q0 -8 -5 -8 l-45 0 q-5 0 -5 8 l0 784 q0 8 5 8 l45 0 q5 0 5 -8 q0 8 1 8 l91 0 q1 0 1 -8 l0 -80 q0 -8 -1 -8 l-91 0 q-1 0 -1 8 l0 -623 q0 8 1 8 ZM711 134 q1 0 1 -8 l0 623 q0 -8 -1 -8 l-91 0 q-1 0 -1 8 l0 80 q0 8 1 8 l91 0 q1 0 1 -8 q0 8 4 8 l46 0 q4 0 4 -8 l0 -784 q0 -8 -4 -8 l-46 0 q-4 0 -4 8 q0 -7 -1 -7 l-91 0 q-1 0 -1 8 l0 80 q0 8 1 8 l91 0 ZM878 134 q1 0 1 -8 l0 623 q0 -8 -1 -8 l-91 0 q-1 0 -1 8 l0 80 q0 8 1 8 l91 0 q1 0 1 -8 q0 8 5 8 l45 0 q4 0 4 -8 l0 -784 q0 -8 -4 -8 l-45 0 q-5 0 -5 8 q0 -7 -1 -7 l-91 0 q-1 0 -1 8 l0 80 q0 8 1 8 l91 0 Z\"></path></g></svg>"
},
{
"id": "editing-toolbar:editor:insert-embed",
"name": "Embed",
"icon": "note-glyph"
},
{
"id": "editing-toolbar:insert-link",
"name": "Link",
"icon": "link-glyph"
},
{
"id": "editing-toolbar:hrline",
"name": "Horizontal Divider",
"icon": "<svg width=\"18\" height=\"18\" focusable=\"false\" fill=\"currentColor\" viewBox=\"0 0 1024 1024\"><g transform=\"scale(1, -1) translate(0, -896) scale(0.9, 0.9) \"><path class=\"path\" d=\"M912 424 l0 -80 q0 -3 -2.5 -5.5 q-2.5 -2.5 -5.5 -2.5 l-784 0 q-3 0 -5.5 2.5 q-2.5 2.5 -2.5 5.5 l0 80 q0 3 2.5 5.5 q2.5 2.5 5.5 2.5 l784 0 q3 0 5.5 -2.5 q2.5 -2.5 2.5 -5.5 Z\"></path></g></svg>"
},
{
"id": "editing-toolbar:toggle-inline-math",
"name": "Inline Math",
"icon": "lucide-sigma"
},
{
"id": "editing-toolbar:editor:insert-mathblock",
"name": "MathBlock",
"icon": "lucide-sigma-square"
}
]
},
{
"id": "SubmenuCommands-list",
"name": "submenu-list",
"icon": "bullet-list-glyph",
"SubmenuCommands": [
{
"id": "editing-toolbar:editor:toggle-checklist-status",
"name": "Checklist",
"icon": "checkbox-glyph"
},
{
"id": "editing-toolbar:renumber-ordered-list",
"name": "Renumber Ordered List",
"icon": "list-restart"
},
{
"id": "editing-toolbar:toggle-numbered-list",
"name": "Ordered List",
"icon": "<svg width=\"18\" height=\"18\" focusable=\"false\" fill=\"currentColor\" viewBox=\"0 0 1024 1024\"><g transform=\"scale(1, -1) translate(0, -896) scale(0.9, 0.9) \"><path class=\"path\" d=\"M860 424 q17 0 28.5 -11.5 q11.5 -11.5 11.5 -28 q0 -16.5 -11.5 -28.5 q-11.5 -12 -27.5 -12 l-457 0 q-17 0 -28.5 11.5 q-11.5 11.5 -11.5 28 q0 16.5 11.5 28.5 q11.5 12 27.5 12 l457 0 ZM860 756 q17 0 28.5 -11.5 q11.5 -11.5 11.5 -28 q0 -16.5 -11.5 -28.5 q-11.5 -12 -27.5 -12 l-457 0 q-17 0 -28.5 11.5 q-11.5 11.5 -11.5 28 q0 16.5 11.5 28.5 q11.5 12 27.5 12 l457 0 ZM860 92 q17 0 28.5 -11.5 q11.5 -11.5 11.5 -28 q0 -16.5 -11.5 -28.5 q-11.5 -12 -27.5 -12 l-457 0 q-17 0 -28.5 11.5 q-11.5 11.5 -11.5 28 q0 16.5 11.5 28.5 q11.5 12 27.5 12 l457 0 ZM264 136 l-3 -3 l-51 -57 l56 0 q14 0 24.5 -10 q10.5 -10 11.5 -25 l0 -1 q0 -15 -10.5 -25.5 q-10.5 -10.5 -24.5 -10.5 l-137 0 q-15 0 -25 10 q-10 10 -11 24.5 q-1 14.5 9 25.5 l63 70 l49 54 q7 7 7 16.5 q0 9.5 -7.5 16.5 q-7.5 7 -18.5 7 q-11 0 -18.5 -6.5 q-7.5 -6.5 -8.5 -16.5 l0 0 q0 -15 -10.5 -25.5 q-10.5 -10.5 -25.5 -10.5 q-15 0 -25.5 10.5 q-10.5 10.5 -10.5 25.5 q0 26 13.5 47.5 q13.5 21.5 36 34.5 q22.5 13 49 13 q26.5 0 49.5 -13 q23 -13 36 -34.5 q13 -21.5 13 -47.5 q0 -20 -7.5 -37.5 q-7.5 -17.5 -21.5 -30.5 l-1 -1 ZM173 794 q11 11 25 10.5 q14 -0.5 24.5 -10.5 q10.5 -10 10.5 -25 l0 -293 q0 -15 -10 -25.5 q-10 -10.5 -25 -10.5 q-15 0 -25.5 10 q-10.5 10 -11.5 25 l0 211 q-10 -8 -23.5 -7 q-13.5 1 -22.5 11 l-1 0 q-10 11 -9.5 25.5 q0.5 14.5 10.5 24.5 l58 54 Z\"></path></g></svg>"
},
{
"id": "editing-toolbar:toggle-bullet-list",
"name": "Unordered List",
"icon": "<svg width=\"18\" height=\"18\" focusable=\"false\" fill=\"currentColor\" viewBox=\"0 0 1024 1024\"><g transform=\"scale(1, -1) translate(0, -896) scale(0.9, 0.9) \"><path class=\"path\" d=\"M860 424 q17 0 28.5 -11.5 q11.5 -11.5 11.5 -28 q0 -16.5 -11.5 -28.5 q-11.5 -12 -27.5 -12 l-477 0 q-17 0 -28.5 11.5 q-11.5 11.5 -11.5 28 q0 16.5 11.5 28.5 q11.5 12 27.5 12 l477 0 ZM860 756 q17 0 28.5 -11.5 q11.5 -11.5 11.5 -28 q0 -16.5 -11.5 -28.5 q-11.5 -12 -27.5 -12 l-477 0 q-17 0 -28.5 11.5 q-11.5 11.5 -11.5 28 q0 16.5 11.5 28.5 q11.5 12 27.5 12 l477 0 ZM860 92 q17 0 28.5 -11.5 q11.5 -11.5 11.5 -28 q0 -16.5 -11.5 -28.5 q-11.5 -12 -27.5 -12 l-477 0 q-17 0 -28.5 11.5 q-11.5 11.5 -11.5 28 q0 16.5 11.5 28.5 q11.5 12 27.5 12 l477 0 ZM176 716 l0 0 ZM112 716 q0 -27 18.5 -45.5 q18.5 -18.5 45.5 -18.5 q27 0 45.5 18.5 q18.5 18.5 18.5 45.5 q0 27 -18.5 45.5 q-18.5 18.5 -45.5 18.5 q-27 0 -45.5 -18.5 q-18.5 -18.5 -18.5 -45.5 ZM176 384 l0 0 ZM112 384 q0 -27 18.5 -45.5 q18.5 -18.5 45.5 -18.5 q27 0 45.5 18.5 q18.5 18.5 18.5 45.5 q0 27 -18.5 45.5 q-18.5 18.5 -45.5 18.5 q-27 0 -45.5 -18.5 q-18.5 -18.5 -18.5 -45.5 ZM176 52 l0 0 ZM112 52 q0 -27 18.5 -45.5 q18.5 -18.5 45.5 -18.5 q27 0 45.5 18.5 q18.5 18.5 18.5 45.5 q0 27 -18.5 45.5 q-18.5 18.5 -45.5 18.5 q-27 0 -45.5 -18.5 q-18.5 -18.5 -18.5 -45.5 Z\"></path></g></svg>"
},
{
"id": "editing-toolbar:undent-list",
"name": "Unindent List",
"icon": "<svg width=\"18\" height=\"18\" focusable=\"false\" fill=\"currentColor\" viewBox=\"0 0 1024 1024\"><g transform=\"scale(1, -1) translate(0, -896) scale(0.9, 0.9) \"><path class=\"path\" d=\"M872 302 q17 0 28.5 -11.5 q11.5 -11.5 11.5 -28 q0 -16.5 -11.5 -28.5 q-11.5 -12 -27.5 -12 l-429 0 q-17 0 -28.5 11.5 q-11.5 11.5 -11.5 28 q0 16.5 11.5 28.5 q11.5 12 27.5 12 l429 0 ZM872 542 q17 0 28.5 -11.5 q11.5 -11.5 11.5 -28 q0 -16.5 -11.5 -28.5 q-11.5 -12 -27.5 -12 l-429 0 q-17 0 -28.5 11.5 q-11.5 11.5 -11.5 28 q0 16.5 11.5 28.5 q11.5 12 27.5 12 l429 0 ZM872 784 q17 0 28.5 -11.5 q11.5 -11.5 11.5 -28 q0 -16.5 -11.5 -28.5 q-11.5 -12 -27.5 -12 l-721 0 q-17 0 -28.5 11.5 q-11.5 11.5 -11.5 28 q0 16.5 11.5 28.5 q11.5 12 27.5 12 l721 0 ZM872 62 q17 0 28.5 -11.5 q11.5 -11.5 11.5 -28 q0 -16.5 -11.5 -28.5 q-11.5 -12 -27.5 -12 l-721 0 q-17 0 -28.5 11.5 q-11.5 11.5 -11.5 28 q0 16.5 11.5 28.5 q11.5 12 27.5 12 l721 0 ZM244 534 l-123 -122 q-8 -7 -8 -18 q0 -11 8 -18 l123 -122 q8 -7 19 -7 q11 0 18.5 7.5 q7.5 7.5 7.5 18.5 l0 242 q0 11 -7.5 18.5 q-7.5 7.5 -18.5 7.5 q-11 0 -19 -7 Z\"></path></g></svg>"
},
{
"id": "editing-toolbar:indent-list",
"name": "Indent list",
"icon": "<svg width=\"18\" height=\"18\" focusable=\"false\" fill=\"currentColor\" viewBox=\"0 0 1024 1024\"><g transform=\"scale(1, -1) translate(0, -896) scale(0.9, 0.9) \"><path class=\"path\" d=\"M872 302 q17 0 28.5 -11.5 q11.5 -11.5 11.5 -28 q0 -16.5 -11.5 -28.5 q-11.5 -12 -27.5 -12 l-429 0 q-17 0 -28.5 11.5 q-11.5 11.5 -11.5 28 q0 16.5 11.5 28.5 q11.5 12 27.5 12 l429 0 ZM872 542 q17 0 28.5 -11.5 q11.5 -11.5 11.5 -28 q0 -16.5 -11.5 -28.5 q-11.5 -12 -27.5 -12 l-429 0 q-17 0 -28.5 11.5 q-11.5 11.5 -11.5 28 q0 16.5 11.5 28.5 q11.5 12 27.5 12 l429 0 ZM872 784 q17 0 28.5 -11.5 q11.5 -11.5 11.5 -28 q0 -16.5 -11.5 -28.5 q-11.5 -12 -27.5 -12 l-721 0 q-17 0 -28.5 11.5 q-11.5 11.5 -11.5 28 q0 16.5 11.5 28.5 q11.5 12 27.5 12 l721 0 ZM872 62 q17 0 28.5 -11.5 q11.5 -11.5 11.5 -28 q0 -16.5 -11.5 -28.5 q-11.5 -12 -27.5 -12 l-721 0 q-17 0 -28.5 11.5 q-11.5 11.5 -11.5 28 q0 16.5 11.5 28.5 q11.5 12 27.5 12 l721 0 ZM158 534 l124 -122 q7 -7 7 -18 q0 -11 -7 -18 l-124 -122 q-7 -7 -18 -7 q-11 0 -19 7.5 q-8 7.5 -8 18.5 l0 242 q0 11 8 18.5 q8 7.5 19 7.5 q11 0 18 -7 Z\"></path></g></svg>"
}
]
},
{
"id": "SubmenuCommands-aligin",
"name": "submenu-aligin",
"icon": "<svg width=\"18\" height=\"18\" focusable=\"false\" fill=\"currentColor\" viewBox=\"0 0 1024 1024\"><g transform=\"scale(1, -1) translate(0, -896) scale(0.9, 0.9) \"><path class=\"path\" d=\"M724 304 q17 0 28.5 -11.5 q11.5 -11.5 11.5 -28 q0 -16.5 -11.5 -28.5 q-11.5 -12 -27.5 -12 l-421 0 q-17 0 -28.5 11.5 q-11.5 11.5 -11.5 28 q0 16.5 11.5 28.5 q11.5 12 27.5 12 l421 0 ZM872 540 q17 0 28.5 -11.5 q11.5 -11.5 11.5 -28 q0 -16.5 -11.5 -28.5 q-11.5 -12 -27.5 -12 l-721 0 q-17 0 -28.5 11.5 q-11.5 11.5 -11.5 28 q0 16.5 11.5 28.5 q11.5 12 27.5 12 l721 0 ZM724 776 q17 0 28.5 -11.5 q11.5 -11.5 11.5 -28 q0 -16.5 -11.5 -28.5 q-11.5 -12 -27.5 -12 l-421 0 q-17 0 -28.5 11.5 q-11.5 11.5 -11.5 28 q0 16.5 11.5 28.5 q11.5 12 27.5 12 l421 0 ZM872 68 q17 0 28.5 -11.5 q11.5 -11.5 11.5 -28 q0 -16.5 -11.5 -28.5 q-11.5 -12 -27.5 -12 l-721 0 q-17 0 -28.5 11.5 q-11.5 11.5 -11.5 28 q0 16.5 11.5 28.5 q11.5 12 27.5 12 l721 0 Z\"></path></g></svg>",
"SubmenuCommands": [
{
"id": "editing-toolbar:justify",
"name": "Justify Text",
"icon": "<svg width=\"18\" height=\"18\" focusable=\"false\" fill=\"currentColor\" viewBox=\"0 0 1024 1024\"><g transform=\"scale(1, -1) translate(0, -896) scale(0.9, 0.9) \"><path class=\"path\" d=\"M112 736 l0 0 ZM120 736 l784 0 q8 0 8 -8 l0 -80 q0 -8 -8 -8 l-784 0 q-8 0 -8 8 l0 80 q0 8 8 8 ZM112 331 l0 0 ZM120 331 l784 0 q8 0 8 -8 l0 -80 q0 -8 -8 -8 l-784 0 q-8 0 -8 8 l0 80 q0 8 8 8 ZM112 128 l0 0 ZM120 128 l784 0 q8 0 8 -8 l0 -80 q0 -8 -8 -8 l-784 0 q-8 0 -8 8 l0 80 q0 8 8 8 ZM112 533 l0 0 ZM120 533 l784 0 q8 0 8 -8 l0 -80 q0 -8 -8 -8 l-784 0 q-8 0 -8 8 l0 80 q0 8 8 8 Z\"></path></g></svg>"
},
{
"id": "editing-toolbar:left",
"name": "Align Text Left",
"icon": "<svg width=\"18\" height=\"18\" focusable=\"false\" fill=\"currentColor\" viewBox=\"0 0 1024 1024\"><g transform=\"scale(1, -1) translate(0, -896) scale(0.9, 0.9) \"><path class=\"path\" d=\"M572 304 q17 0 28.5 -11.5 q11.5 -11.5 11.5 -28 q0 -16.5 -11.5 -28.5 q-11.5 -12 -27.5 -12 l-421 0 q-17 0 -28.5 11.5 q-11.5 11.5 -11.5 28 q0 16.5 11.5 28.5 q11.5 12 27.5 12 l421 0 ZM872 540 q17 0 28.5 -11.5 q11.5 -11.5 11.5 -28 q0 -16.5 -11.5 -28.5 q-11.5 -12 -27.5 -12 l-721 0 q-17 0 -28.5 11.5 q-11.5 11.5 -11.5 28 q0 16.5 11.5 28.5 q11.5 12 27.5 12 l721 0 ZM572 776 q17 0 28.5 -11.5 q11.5 -11.5 11.5 -28 q0 -16.5 -11.5 -28.5 q-11.5 -12 -27.5 -12 l-421 0 q-17 0 -28.5 11.5 q-11.5 11.5 -11.5 28 q0 16.5 11.5 28.5 q11.5 12 27.5 12 l421 0 ZM872 68 q17 0 28.5 -11.5 q11.5 -11.5 11.5 -28 q0 -16.5 -11.5 -28.5 q-11.5 -12 -27.5 -12 l-721 0 q-17 0 -28.5 11.5 q-11.5 11.5 -11.5 28 q0 16.5 11.5 28.5 q11.5 12 27.5 12 l721 0 Z\"></path></g></svg>"
},
{
"id": "editing-toolbar:center",
"name": "Center Text",
"icon": "<svg width=\"18\" height=\"18\" focusable=\"false\" fill=\"currentColor\" viewBox=\"0 0 1024 1024\"><g transform=\"scale(1, -1) translate(0, -896) scale(0.9, 0.9) \"><path class=\"path\" d=\"M724 304 q17 0 28.5 -11.5 q11.5 -11.5 11.5 -28 q0 -16.5 -11.5 -28.5 q-11.5 -12 -27.5 -12 l-421 0 q-17 0 -28.5 11.5 q-11.5 11.5 -11.5 28 q0 16.5 11.5 28.5 q11.5 12 27.5 12 l421 0 ZM872 540 q17 0 28.5 -11.5 q11.5 -11.5 11.5 -28 q0 -16.5 -11.5 -28.5 q-11.5 -12 -27.5 -12 l-721 0 q-17 0 -28.5 11.5 q-11.5 11.5 -11.5 28 q0 16.5 11.5 28.5 q11.5 12 27.5 12 l721 0 ZM724 776 q17 0 28.5 -11.5 q11.5 -11.5 11.5 -28 q0 -16.5 -11.5 -28.5 q-11.5 -12 -27.5 -12 l-421 0 q-17 0 -28.5 11.5 q-11.5 11.5 -11.5 28 q0 16.5 11.5 28.5 q11.5 12 27.5 12 l421 0 ZM872 68 q17 0 28.5 -11.5 q11.5 -11.5 11.5 -28 q0 -16.5 -11.5 -28.5 q-11.5 -12 -27.5 -12 l-721 0 q-17 0 -28.5 11.5 q-11.5 11.5 -11.5 28 q0 16.5 11.5 28.5 q11.5 12 27.5 12 l721 0 Z\"></path></g></svg>"
},
{
"id": "editing-toolbar:right",
"name": "Align Text Right",
"icon": "<svg width=\"18\" height=\"18\" focusable=\"false\" fill=\"currentColor\" viewBox=\"0 0 1024 1024\"><g transform=\"scale(1, -1) translate(0, -896) scale(0.9, 0.9) \"><path class=\"path\" d=\"M872 304 q17 0 28.5 -11.5 q11.5 -11.5 11.5 -28 q0 -16.5 -11.5 -28.5 q-11.5 -12 -27.5 -12 l-421 0 q-17 0 -28.5 11.5 q-11.5 11.5 -11.5 28 q0 16.5 11.5 28.5 q11.5 12 27.5 12 l421 0 ZM872 540 q17 0 28.5 -11.5 q11.5 -11.5 11.5 -28 q0 -16.5 -11.5 -28.5 q-11.5 -12 -27.5 -12 l-721 0 q-17 0 -28.5 11.5 q-11.5 11.5 -11.5 28 q0 16.5 11.5 28.5 q11.5 12 27.5 12 l721 0 ZM872 776 q17 0 28.5 -11.5 q11.5 -11.5 11.5 -28 q0 -16.5 -11.5 -28.5 q-11.5 -12 -27.5 -12 l-421 0 q-17 0 -28.5 11.5 q-11.5 11.5 -11.5 28 q0 16.5 11.5 28.5 q11.5 12 27.5 12 l421 0 ZM872 68 q17 0 28.5 -11.5 q11.5 -11.5 11.5 -28 q0 -16.5 -11.5 -28.5 q-11.5 -12 -27.5 -12 l-721 0 q-17 0 -28.5 11.5 q-11.5 11.5 -11.5 28 q0 16.5 11.5 28.5 q11.5 12 27.5 12 l721 0 Z\"></path></g></svg>"
}
]
},
{
"id": "editing-toolbar:change-font-color",
"name": "Change Font Color",
"icon": "<svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" focusable=\"false\" fill=\"currentColor\"><g fill-rule=\"evenodd\"><path id=\"change-font-color-icon\" d=\"M3 18h18v3H3z\" style=\"fill:#2DC26B\"></path><path d=\"M8.7 16h-.8a.5.5 0 01-.5-.6l2.7-9c.1-.3.3-.4.5-.4h2.8c.2 0 .4.1.5.4l2.7 9a.5.5 0 01-.5.6h-.8a.5.5 0 01-.4-.4l-.7-2.2c0-.3-.3-.4-.5-.4h-3.4c-.2 0-.4.1-.5.4l-.7 2.2c0 .3-.2.4-.4.4zm2.6-7.6l-.6 2a.5.5 0 00.5.6h1.6a.5.5 0 00.5-.6l-.6-2c0-.3-.3-.4-.5-.4h-.4c-.2 0-.4.1-.5.4z\"></path></g></svg>"
},
{
"id": "editing-toolbar:change-background-color",
"name": "Change Background Color",
"icon": "<svg width=\"18\" height=\"24\" viewBox=\"0 0 256 256\" version=\"1.1\" xmlns=\"http://www.w3.org/2000/svg\"><g stroke=\"none\" stroke-width=\"1\" fill=\"currentColor\" fill-rule=\"evenodd\"><g ><g fill=\"currentColor\"><g transform=\"translate(119.502295, 137.878331) rotate(-135.000000) translate(-119.502295, -137.878331) translate(48.002295, 31.757731)\" ><path d=\"M100.946943,60.8084699 L43.7469427,60.8084699 C37.2852111,60.8084699 32.0469427,66.0467383 32.0469427,72.5084699 L32.0469427,118.70847 C32.0469427,125.170201 37.2852111,130.40847 43.7469427,130.40847 L100.946943,130.40847 C107.408674,130.40847 112.646943,125.170201 112.646943,118.70847 L112.646943,72.5084699 C112.646943,66.0467383 107.408674,60.8084699 100.946943,60.8084699 Z M93.646,79.808 L93.646,111.408 L51.046,111.408 L51.046,79.808 L93.646,79.808 Z\" fill-rule=\"nonzero\"></path><path d=\"M87.9366521,16.90916 L87.9194966,68.2000001 C87.9183543,69.4147389 86.9334998,70.399264 85.7187607,70.4 L56.9423078,70.4 C55.7272813,70.4 54.7423078,69.4150264 54.7423078,68.2 L54.7423078,39.4621057 C54.7423078,37.2523513 55.5736632,35.1234748 57.0711706,33.4985176 L76.4832996,12.4342613 C78.9534987,9.75382857 83.1289108,9.5834005 85.8093436,12.0535996 C87.1658473,13.303709 87.9372691,15.0644715 87.9366521,16.90916 Z\" fill-rule=\"evenodd\"></path><path d=\"M131.3,111.241199 L11.7,111.241199 C5.23826843,111.241199 0,116.479467 0,122.941199 L0,200.541199 C0,207.002931 5.23826843,212.241199 11.7,212.241199 L131.3,212.241199 C137.761732,212.241199 143,207.002931 143,200.541199 L143,122.941199 C143,116.479467 137.761732,111.241199 131.3,111.241199 Z M124,130.241 L124,193.241 L19,193.241 L19,130.241 L124,130.241 Z\" fill-rule=\"nonzero\"></path></g></g><path d=\"M51,218 L205,218 C211.075132,218 216,222.924868 216,229 C216,235.075132 211.075132,240 205,240 L51,240 C44.9248678,240 40,235.075132 40,229 C40,222.924868 44.9248678,218 51,218 Z\" id=\"change-background-color-icon\" style=\"fill:#FA541C\"></path></g></g></svg>"
},
{
"id": "editing-toolbar:fullscreen-focus",
"name": "Fullscreen Focus Mode",
"icon": "fullscreen"
},
{
"id": "editing-toolbar:workplace-fullscreen-focus",
"name": "Workplace Fullscreen",
"icon": "exit-fullscreen"
}
],
"followingCommands": [],
"topCommands": [],
"fixedCommands": [],
"mobileCommands": [],
"enableMultipleConfig": false,
"enableTopToolbar": true,
"enableFollowingToolbar": false,
"enableFixedToolbar": false,
"appendMethod": "workspace",
"shouldShowMenuOnSelect": false,
"cMenuVisibility": true,
"cMenuBottomValue": 4.25,
"cMenuNumRows": 12,
"cMenuWidth": 610,
"cMenuFontColor": "#c00000",
"cMenuBackgroundColor": "#d3f8b6",
"autohide": false,
"Iscentered": false,
"custom_bg1": "#FFB78B8C",
"custom_bg2": "#CDF4698C",
"custom_bg3": "#A0CCF68C",
"custom_bg4": "#F0A7D88C",
"custom_bg5": "#ADEFEF8C",
"custom_fc1": "#D83931",
"custom_fc2": "#DE7802",
"custom_fc3": "#245BDB",
"custom_fc4": "#6425D0",
"custom_fc5": "#646A73",
"isLoadOnMobile": false,
"horizontalPosition": 0,
"verticalPosition": 0,
"formatBrushes": {},
"customCommands": [],
"viewTypeSettings": {},
"appearanceByStyle": {
"top": {
"toolbarBackgroundColor": "rgba(var(--background-secondary-rgb), 0.7)",
"toolbarIconColor": "var(--text-normal)",
"toolbarIconSize": 18,
"aestheticStyle": "default"
},
"following": {
"toolbarBackgroundColor": "rgba(var(--background-secondary-rgb), 0.7)",
"toolbarIconColor": "var(--text-normal)",
"toolbarIconSize": 18,
"aestheticStyle": "default"
},
"fixed": {
"toolbarBackgroundColor": "rgba(var(--background-secondary-rgb), 0.7)",
"toolbarIconColor": "var(--text-normal)",
"toolbarIconSize": 18,
"aestheticStyle": "default"
},
"mobile": {
"toolbarBackgroundColor": "rgba(var(--background-secondary-rgb), 0.7)",
"toolbarIconColor": "var(--text-normal)",
"toolbarIconSize": 18,
"aestheticStyle": "default"
}
},
"toolbarBackgroundColor": "rgba(var(--background-secondary-rgb), 0.7)",
"toolbarIconColor": "var(--text-normal)",
"toolbarIconSize": 18,
"useCurrentLineForRegex": false,
"ai": {
"enabled": false,
"consentAccepted": false,
"onboardingShown": true,
"providerMode": "pkmer-first",
"enableInlineCompletion": true,
"inlineCompletionHintLearned": false,
"completionTrigger": "manual",
"completionDelay": 500,
"enableRewrite": true,
"showRewriteToolbarOnSelection": false,
"rewriteMinSelectionLength": 1,
"pkmerApiBaseUrl": "https://newapi.pkmer.cn",
"pkmerModel": "04-fast",
"pkmerModelRouting": {
"mode": "smart",
"completion": "04-fast",
"rewrite": "04-fast",
"reasoning": "03-agent",
"artifact": "03-agent"
},
"pkmer": {
"tokenExpiresAt": 0,
"userInfo": null
},
"enableCustomModel": false,
"customModel": {
"apiFormat": "openai-compatible",
"baseUrl": "",
"apiKey": "",
"model": "",
"temperature": 0.2
},
"frontmatterPrompt": {
"mode": "auto",
"properties": "title: concise, one-line note title\nsummary: 1-3 sentence note summary\ntags: YAML list of relevant keywords\ncreated: YYYY-MM-DD date when appropriate\ncategory: broad content category",
"language": "auto",
"prompt": "Generate YAML frontmatter for the current Obsidian note using the requested properties below.\n\nRequested properties:\n{properties}\n\nOutput language for generated values: {language}\n\nRules:\n- Return only one complete YAML frontmatter block wrapped in --- delimiters.\n- Use the target text as the note content.\n- Follow current and sibling-note frontmatter conventions from context when provided.\n- Keep values concise, practical, and useful for filtering or browsing.\n- Do not add explanations or markdown fences outside the YAML block."
},
"customPromptHistory": [],
"customPromptTemplates": [
{
"id": "template-demo-variables",
"name": "📝 Summarize Key Points",
"prompt": "Analyze the structure of {{file:content}} and focus on:\n{{selection}}\n\nPlease provide:\n1. A concise overview\n2. The key points\n3. Suggestions for improvement",
"icon": "lucide-sparkles"
},
{
"id": "template-task-variables",
"name": "Extract Tasks",
"prompt": "Today's date is {{date}}. Extract all actionable tasks from {{file:content}}, with special attention to:\n{{selection}}\n\nPlease output strictly in Obsidian Tasks plugin format, one task per line:\n\n- [ ] Task description ⏫/🔼/🔽/⏬ priority\n- [ ] Task description 📅 YYYY-MM-DD due date\n- [ ] Task description ⏰ YYYY-MM-DD HH:mm reminder\n- [ ] Task description 🛫 YYYY-MM-DD start date\n- [ ] Task description 🔁 every day/week/month recurrence\n- [ ] Task description #tag #project\n\nExtraction rules:\n1. If the text implies urgency such as urgent, ASAP, immediately, or today, add ⏫.\n2. If it implies near-term timing such as tomorrow, this week, or soon, add 🔼.\n3. Convert explicit dates to 📅 YYYY-MM-DD.\n4. Convert explicit times to ⏰ YYYY-MM-DD HH:mm when possible.\n5. Add recurrence for repeated work such as 🔁 every week/month.\n6. Add practical tags for each task.\n\nExample output:\n- [ ] Finish project report ⏫ 📅 2026-04-25 #work\n- [ ] Weekly team sync 🔁 every week on Monday ⏰ 09:00 #meeting\n- [ ] Follow up on client request 🔼 📅 2026-04-23 #follow-up",
"icon": "lucide-sparkles"
},
{
"id": "template-dataview",
"name": "Generate Dataview",
"prompt": "Help me generate an Obsidian Dataview query block based on my requirement. Requirements:\n1. Use DataviewJS or DQL syntax.\n2. Include the necessary filters and sorting.\n3. Add short comments explaining each part.\n4. Use DataviewJS if the logic is complex.\n\nMy requirement:",
"icon": "lucide-database"
},
{
"id": "template-templater",
"name": "Design Templater Template",
"prompt": "Help me design an Obsidian Templater template. Requirements:\n1. Use Templater syntax (<% %>).\n2. Include dynamic date, time, and similar variables.\n3. Support user input prompts.\n4. Add necessary conditionals and loops.\n5. Comment the purpose of each section.\n\nTemplate purpose:",
"icon": "lucide-file-code"
},
{
"id": "template-mermaid",
"name": "Create Mermaid Diagram",
"prompt": "Based on my selected text {{selection}}, generate Mermaid diagram code. Requirements:\n1. Choose an appropriate diagram type such as flowchart, sequence, class, or gantt.\n2. Use clear node names.\n3. Add useful styling and comments when needed.\n4. Ensure the syntax is valid and renderable.\n",
"icon": "lucide-workflow"
},
{
"id": "template-metadata",
"name": "Design YAML",
"prompt": "Based on the current note content {{file:content}}, help me design a suitable YAML Frontmatter structure for this note. Requirements:\n1. Recommend fields that fit the note content.\n2. Include common fields such as tags, aliases, and date.\n3. Suggest useful custom fields.\n4. Briefly explain the purpose of each field.\n\nNote type:",
"icon": "lucide-file-json"
},
{
"id": "template-callout",
"name": "Wrap with Callout",
"prompt": "Based on my selected text {{selection}}, wrap it using an Obsidian Callout block. Requirements:\n1. Choose an appropriate callout type such as note, tip, warning, or danger.\n2. Support nesting and folding when helpful.\n3. Include a title and content.\n4. Allow code blocks or lists when needed.\n\nContent requirement:",
"icon": "lucide-message-square"
}
]
}
}
+12
View File
File diff suppressed because one or more lines are too long
+10
View File
@@ -0,0 +1,10 @@
{
"id": "editing-toolbar",
"name": "Editing Toolbar",
"version": "4.0.10",
"minAppVersion": "0.14.0",
"description": "The Obsidian Editing Toolbar is modified from cmenu, which provides more powerful customization settings and has many built-in editing commands to be a MS Word-like toolbar editing experience.",
"author": "Cuman",
"authorUrl": "https://github.com/cumany/obsidian-editing-toolbar",
"isDesktopOnly": false
}
File diff suppressed because it is too large Load Diff
+8
View File
File diff suppressed because one or more lines are too long
+9
View File
@@ -0,0 +1,9 @@
{
"id": "immersive-translate",
"name": "Immersive Translate",
"version": "0.0.2",
"minAppVersion": "0.15.0",
"description": "A free-to-use translatation service for foreign language markdown file.",
"author": "imfenghuang",
"isDesktopOnly": true
}
+15
View File
@@ -0,0 +1,15 @@
#immersiveTranslate-translation-button-wrapper {
position: fixed;
bottom: 10%;
right: 10px;
background-color: rgb(253, 242, 248);
border: 1px solid rgb(251, 207, 232);
padding: 10px;
border-radius: 5px;
cursor: pointer;
z-index: var(--layer-status-bar);
}
#immersiveTranslate-translation-button {
margin-bottom: -20px;
}
File diff suppressed because it is too large Load Diff
File diff suppressed because one or more lines are too long
@@ -0,0 +1,12 @@
{
"id": "obsidian-excalidraw-plugin",
"name": "Excalidraw",
"version": "2.25.2",
"minAppVersion": "1.8.7",
"description": "Sketch Your Mind. Edit and view Excalidraw drawings. Enter the world of 4D Visual PKM.",
"author": "Zsolt Viczian",
"authorUrl": "https://excalidraw-obsidian.online",
"fundingUrl": "https://ko-fi.com/zsolt",
"helpUrl": "https://github.com/zsviczian/obsidian-excalidraw-plugin#readme",
"isDesktopOnly": false
}
File diff suppressed because one or more lines are too long
+67
View File
@@ -0,0 +1,67 @@
{
"commitMessage": "vault backup: {{date}}",
"autoCommitMessage": "vault backup: {{date}}",
"commitMessageScript": "",
"commitDateFormat": "YYYY-MM-DD HH:mm:ss",
"autoSaveInterval": 0,
"autoPushInterval": 0,
"autoPullInterval": 0,
"autoPullOnBoot": false,
"autoCommitOnlyStaged": false,
"disablePush": false,
"pullBeforePush": true,
"disablePopups": false,
"showErrorNotices": true,
"disablePopupsForNoChanges": false,
"listChangedFilesInMessageBody": false,
"showStatusBar": true,
"updateSubmodules": false,
"syncMethod": "merge",
"mergeStrategy": "none",
"customMessageOnAutoBackup": false,
"autoBackupAfterFileChange": false,
"treeStructure": true,
"refreshSourceControl": true,
"basePath": "",
"differentIntervalCommitAndPush": false,
"changedFilesInStatusBar": false,
"showedMobileNotice": true,
"refreshSourceControlTimer": 7000,
"showBranchStatusBar": true,
"setLastSaveToLastCommit": false,
"submoduleRecurseCheckout": false,
"gitDir": "",
"showFileMenu": true,
"authorInHistoryView": "hide",
"dateInHistoryView": false,
"diffStyle": "split",
"hunks": {
"showSigns": false,
"hunkCommands": false,
"statusBar": "disabled"
},
"lineAuthor": {
"show": false,
"followMovement": "inactive",
"authorDisplay": "initials",
"showCommitHash": false,
"dateTimeFormatOptions": "date",
"dateTimeFormatCustomString": "YYYY-MM-DD HH:mm",
"dateTimeTimezone": "viewer-local",
"coloringMaxAge": "1y",
"colorNew": {
"r": 255,
"g": 150,
"b": 150
},
"colorOld": {
"r": 120,
"g": 160,
"b": 255
},
"textColorCss": "var(--text-muted)",
"ignoreWhitespace": false,
"lastShownAuthorDisplay": "initials",
"lastShownDateTimeFormatOptions": "date"
}
}
File diff suppressed because one or more lines are too long
+10
View File
@@ -0,0 +1,10 @@
{
"author": "Vinzent",
"authorUrl": "https://github.com/Vinzent03",
"id": "obsidian-git",
"name": "Git",
"description": "Integrate Git version control with automatic backup and other advanced features.",
"isDesktopOnly": false,
"fundingUrl": "https://ko-fi.com/vinzent",
"version": "2.38.6"
}
+23
View File
@@ -0,0 +1,23 @@
#!/bin/sh
PROMPT="$1"
TEMP_FILE="$OBSIDIAN_GIT_CREDENTIALS_INPUT"
cleanup() {
rm -f "$TEMP_FILE" "$TEMP_FILE.response"
}
trap cleanup EXIT
echo "$PROMPT" > "$TEMP_FILE"
while [ ! -e "$TEMP_FILE.response" ]; do
if [ ! -e "$TEMP_FILE" ]; then
echo "Trigger file got removed: Abort" >&2
exit 1
fi
sleep 0.1
done
RESPONSE=$(cat "$TEMP_FILE.response")
echo "$RESPONSE"
+705
View File
@@ -0,0 +1,705 @@
@keyframes loading {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}
.workspace-leaf-content[data-type="git-view"] .button-border {
border: 2px solid var(--interactive-accent);
border-radius: var(--radius-s);
}
.workspace-leaf-content[data-type="git-view"] .view-content {
padding-left: 0;
padding-top: 0;
padding-right: 0;
}
.workspace-leaf-content[data-type="git-history-view"] .view-content {
padding-left: 0;
padding-top: 0;
padding-right: 0;
}
.loading {
overflow: hidden;
}
.loading > svg {
animation: 2s linear infinite loading;
transform-origin: 50% 50%;
display: inline-block;
}
.obsidian-git-center {
margin: auto;
text-align: center;
width: 50%;
}
.obsidian-git-textarea {
display: block;
margin-left: auto;
margin-right: auto;
}
.obsidian-git-disabled {
opacity: 0.5;
}
.obsidian-git-center-button {
display: block;
margin: 20px auto;
}
.tooltip.mod-left {
overflow-wrap: break-word;
}
.tooltip.mod-right {
overflow-wrap: break-word;
}
/* Limits the scrollbar to the view body */
.git-view {
display: flex;
flex-direction: column;
position: relative;
height: 100%;
}
/* Re-enable wrapping of nav buttns to prevent overflow on smaller screens #*/
.workspace-drawer .git-view .nav-buttons-container {
flex-wrap: wrap;
}
.git-tools {
display: flex;
margin-left: auto;
}
.git-tools .type {
padding-left: var(--size-2-1);
display: flex;
align-items: center;
justify-content: center;
width: 11px;
}
.git-tools .type[data-type="M"] {
color: orange;
}
.git-tools .type[data-type="D"] {
color: red;
}
.git-tools .buttons {
display: flex;
}
.git-tools .buttons > * {
padding: 0;
height: auto;
}
.workspace-leaf-content[data-type="git-view"] .tree-item-self,
.workspace-leaf-content[data-type="git-history-view"] .tree-item-self {
align-items: center;
}
.workspace-leaf-content[data-type="git-view"]
.tree-item-self:hover
.clickable-icon,
.workspace-leaf-content[data-type="git-history-view"]
.tree-item-self:hover
.clickable-icon {
color: var(--icon-color-hover);
}
/* Highlight an item as active if it's diff is currently opened */
.is-active .git-tools .buttons > * {
color: var(--nav-item-color-active);
}
.git-author {
color: var(--text-accent);
}
.git-date {
color: var(--text-accent);
}
.git-ref {
color: var(--text-accent);
}
/* ====== diff2html ======
The following styles are adapted from the obsidian-version-history plugin by
@kometenstaub https://github.com/kometenstaub/obsidian-version-history-diff/blob/main/src/styles.scss
which itself is adapted from the diff2html library with the following original license:
https://github.com/rtfpessoa/diff2html/blob/master/LICENSE.md
Copyright 2014-2016 Rodrigo Fernandes https://rtfpessoa.github.io/
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
documentation files (the "Software"), to deal in the Software without restriction, including without limitation the
rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit
persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the
Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
.theme-dark,
.theme-light {
--git-delete-bg: #ff475040;
--git-delete-hl: #96050a75;
--git-insert-bg: #68d36840;
--git-insert-hl: #23c02350;
--git-change-bg: #ffd55840;
--git-selected: #3572b0;
--git-delete: #cc3333;
--git-insert: #399839;
--git-change: #d0b44c;
--git-move: #3572b0;
}
.git-diff {
.d2h-d-none {
display: none;
}
.d2h-wrapper {
text-align: left;
border-radius: 0.25em;
overflow: auto;
}
.d2h-file-header.d2h-file-header {
background-color: var(--background-secondary);
border-bottom: 1px solid var(--background-modifier-border);
font-family:
Source Sans Pro,
Helvetica Neue,
Helvetica,
Arial,
sans-serif;
height: 35px;
padding: 5px 10px;
}
.d2h-file-header,
.d2h-file-stats {
display: -webkit-box;
display: -ms-flexbox;
display: flex;
}
.d2h-file-header {
display: none;
}
.d2h-file-stats {
font-size: 14px;
margin-left: auto;
}
.d2h-lines-added {
border: 1px solid var(--color-green);
border-radius: 5px 0 0 5px;
color: var(--color-green);
padding: 2px;
text-align: right;
vertical-align: middle;
}
.d2h-lines-deleted {
border: 1px solid var(--color-red);
border-radius: 0 5px 5px 0;
color: var(--color-red);
margin-left: 1px;
padding: 2px;
text-align: left;
vertical-align: middle;
}
.d2h-file-name-wrapper {
-webkit-box-align: center;
-ms-flex-align: center;
align-items: center;
display: -webkit-box;
display: -ms-flexbox;
display: flex;
font-size: 15px;
width: 100%;
}
.d2h-file-name {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
color: var(--text-normal);
font-size: var(--h5-size);
}
.d2h-file-wrapper {
border: 1px solid var(--background-secondary-alt);
border-radius: 3px;
margin-bottom: 1em;
max-height: 100%;
}
.d2h-file-collapse {
-webkit-box-pack: end;
-ms-flex-pack: end;
-webkit-box-align: center;
-ms-flex-align: center;
align-items: center;
border: 1px solid var(--background-secondary-alt);
border-radius: 3px;
cursor: pointer;
display: none;
font-size: 12px;
justify-content: flex-end;
padding: 4px 8px;
}
.d2h-file-collapse.d2h-selected {
background-color: var(--git-selected);
}
.d2h-file-collapse-input {
margin: 0 4px 0 0;
}
.d2h-diff-table {
border-collapse: collapse;
font-family: var(--font-monospace);
font-size: var(--code-size);
width: 100%;
}
.d2h-files-diff {
width: 100%;
}
.d2h-file-diff {
/*
overflow-y: scroll;
*/
border-radius: 5px;
font-size: var(--font-text-size);
line-height: var(--line-height-normal);
}
.d2h-file-side-diff {
display: inline-block;
margin-bottom: -8px;
margin-right: -4px;
overflow-x: scroll;
overflow-y: hidden;
width: 50%;
}
.d2h-code-line {
padding-left: 6em;
padding-right: 1.5em;
}
.d2h-code-line,
.d2h-code-side-line {
display: inline-block;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
white-space: nowrap;
width: 100%;
}
.d2h-code-side-line {
/* needed to be changed */
padding-left: 0.5em;
padding-right: 0.5em;
}
.d2h-code-line-ctn {
word-wrap: normal;
background: none;
display: inline-block;
padding: 0;
-webkit-user-select: text;
-moz-user-select: text;
-ms-user-select: text;
user-select: text;
vertical-align: middle;
width: 100%;
/* only works for line-by-line */
white-space: pre-wrap;
}
.d2h-code-line del,
.d2h-code-side-line del {
background-color: var(--git-delete-hl);
color: var(--text-normal);
}
.d2h-code-line del,
.d2h-code-line ins,
.d2h-code-side-line del,
.d2h-code-side-line ins {
border-radius: 0.2em;
display: inline-block;
margin-top: -1px;
text-decoration: none;
vertical-align: middle;
}
.d2h-code-line ins,
.d2h-code-side-line ins {
background-color: var(--git-insert-hl);
text-align: left;
}
.d2h-code-line-prefix {
word-wrap: normal;
background: none;
display: inline;
padding: 0;
white-space: pre;
}
.line-num1 {
float: left;
}
.line-num1,
.line-num2 {
-webkit-box-sizing: border-box;
box-sizing: border-box;
overflow: hidden;
/*
padding: 0 0.5em;
*/
text-overflow: ellipsis;
width: 2.5em;
padding-left: 0;
}
.line-num2 {
float: right;
}
.d2h-code-linenumber {
background-color: var(--background-primary);
border: solid var(--background-modifier-border);
border-width: 0 1px;
-webkit-box-sizing: border-box;
box-sizing: border-box;
color: var(--text-faint);
cursor: pointer;
display: inline-block;
position: absolute;
text-align: right;
width: 5.5em;
}
.d2h-code-linenumber:after {
content: "\200b";
}
.d2h-code-side-linenumber {
background-color: var(--background-primary);
border: solid var(--background-modifier-border);
border-width: 0 1px;
-webkit-box-sizing: border-box;
box-sizing: border-box;
color: var(--text-faint);
cursor: pointer;
overflow: hidden;
padding: 0 0.5em;
text-align: right;
text-overflow: ellipsis;
width: 4em;
/* needed to be changed */
display: table-cell;
position: relative;
}
.d2h-code-side-linenumber:after {
content: "\200b";
}
.d2h-code-side-emptyplaceholder,
.d2h-emptyplaceholder {
background-color: var(--background-primary);
border-color: var(--background-modifier-border);
}
.d2h-code-line-prefix,
.d2h-code-linenumber,
.d2h-code-side-linenumber,
.d2h-emptyplaceholder {
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
.d2h-code-linenumber,
.d2h-code-side-linenumber {
direction: rtl;
}
.d2h-del {
background-color: var(--git-delete-bg);
border-color: var(--git-delete-hl);
}
.d2h-ins {
background-color: var(--git-insert-bg);
border-color: var(--git-insert-hl);
}
.d2h-info {
background-color: var(--background-primary);
border-color: var(--background-modifier-border);
color: var(--text-faint);
}
.d2h-del,
.d2h-ins,
.d2h-file-diff .d2h-change {
color: var(--text-normal);
}
.d2h-file-diff .d2h-del.d2h-change {
background-color: var(--git-change-bg);
}
.d2h-file-diff .d2h-ins.d2h-change {
background-color: var(--git-insert-bg);
}
.d2h-file-list-wrapper {
a {
text-decoration: none;
cursor: default;
-webkit-user-drag: none;
}
svg {
display: none;
}
}
.d2h-file-list-header {
text-align: left;
}
.d2h-file-list-title {
display: none;
}
.d2h-file-list-line {
display: -webkit-box;
display: -ms-flexbox;
display: flex;
text-align: left;
}
.d2h-file-list {
}
.d2h-file-list > li {
border-bottom: 1px solid var(--background-modifier-border);
margin: 0;
padding: 5px 10px;
}
.d2h-file-list > li:last-child {
border-bottom: none;
}
.d2h-file-switch {
cursor: pointer;
display: none;
font-size: 10px;
}
.d2h-icon {
fill: currentColor;
margin-right: 10px;
vertical-align: middle;
}
.d2h-deleted {
color: var(--git-delete);
}
.d2h-added {
color: var(--git-insert);
}
.d2h-changed {
color: var(--git-change);
}
.d2h-moved {
color: var(--git-move);
}
.d2h-tag {
background-color: var(--background-secondary);
display: -webkit-box;
display: -ms-flexbox;
display: flex;
font-size: 10px;
margin-left: 5px;
padding: 0 2px;
}
.d2h-deleted-tag {
border: 1px solid var(--git-delete);
}
.d2h-added-tag {
border: 1px solid var(--git-insert);
}
.d2h-changed-tag {
border: 1px solid var(--git-change);
}
.d2h-moved-tag {
border: 1px solid var(--git-move);
}
/* needed for line-by-line*/
.d2h-diff-tbody {
position: relative;
}
/* My additions */
.cm-merge-revert {
width: 4em;
}
/* Ensure that merge revert markers are positioned correctly */
.cm-merge-revert > * {
position: absolute;
background-color: var(--background-secondary);
display: flex;
}
}
/* ====================== Line Authoring Information ====================== */
.cm-gutterElement.obs-git-blame-gutter {
/* Add background color to spacing inbetween and around the gutter for better aesthetics */
border-width: 0px 2px 0.2px;
border-style: solid;
border-color: var(--background-secondary);
background-color: var(--background-secondary);
}
.cm-gutterElement.obs-git-blame-gutter > div,
.line-author-settings-preview {
/* delegate text color to settings */
color: var(--obs-git-gutter-text);
font-family: monospace;
height: 100%; /* ensure, that age-based background color occupies entire parent */
text-align: right;
padding: 0px 6px;
white-space: pre; /* Keep spaces and do not collapse them. */
}
@media (max-width: 800px) {
/* hide git blame gutter not to superpose text */
.cm-gutterElement.obs-git-blame-gutter {
display: none;
}
}
.git-unified-diff-view,
.git-split-diff-view .cm-deletedLine .cm-changedText {
background-color: #ee443330;
}
.git-unified-diff-view,
.git-split-diff-view .cm-insertedLine .cm-changedText {
background-color: #22bb2230;
}
.git-obscure-prompt[git-is-obscured="true"] #git-show-password:after {
-webkit-mask-image: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="svg-icon lucide-eye"><path d="M2.062 12.348a1 1 0 0 1 0-.696 10.75 10.75 0 0 1 19.876 0 1 1 0 0 1 0 .696 10.75 10.75 0 0 1-19.876 0"></path><circle cx="12" cy="12" r="3"></circle></svg>');
}
.git-obscure-prompt[git-is-obscured="false"] #git-show-password:after {
-webkit-mask-image: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="svg-icon lucide-eye-off"><path d="M10.733 5.076a10.744 10.744 0 0 1 11.205 6.575 1 1 0 0 1 0 .696 10.747 10.747 0 0 1-1.444 2.49"></path><path d="M14.084 14.158a3 3 0 0 1-4.242-4.242"></path><path d="M17.479 17.499a10.75 10.75 0 0 1-15.417-5.151 1 1 0 0 1 0-.696 10.75 10.75 0 0 1 4.446-5.143"></path><path d="m2 2 20 20"></path></svg>');
}
/* Override styling of Codemirror merge view "collapsed lines" indicator */
.git-split-diff-view .ͼ2 .cm-collapsedLines {
background: var(--interactive-normal);
border-radius: var(--radius-m);
color: var(--text-accent);
font-size: var(--font-small);
padding: var(--size-4-1) var(--size-4-1);
}
.git-split-diff-view .ͼ2 .cm-collapsedLines:hover {
background: var(--interactive-hover);
color: var(--text-accent-hover);
}
.git-signs-gutter {
.cm-gutterElement {
display: grid;
/* Needed to align the sign properly for different line heigts. Such as
* when having a heading or list item.
*/
padding-top: 0 !important;
}
}
.git-gutter-marker:hover {
border-radius: 2px;
}
.git-gutter-marker.git-add {
background-color: var(--color-green);
justify-self: center;
height: inherit;
width: 0.2rem;
}
.git-gutter-marker.git-change {
background-color: var(--color-yellow);
justify-self: center;
height: inherit;
width: 0.2rem;
}
.git-gutter-marker.git-changedelete {
color: var(--color-yellow);
font-weight: var(--font-bold);
font-size: 1rem;
justify-self: center;
height: inherit;
}
.git-gutter-marker.git-delete {
background-color: var(--color-red);
height: 0.2rem;
width: 0.8rem;
align-self: end;
}
.git-gutter-marker.git-topdelete {
background-color: var(--color-red);
height: 0.2rem;
width: 0.8rem;
align-self: start;
}
div:hover > .git-gutter-marker.git-change {
width: 0.6rem;
}
div:hover > .git-gutter-marker.git-add {
width: 0.6rem;
}
div:hover > .git-gutter-marker.git-delete {
height: 0.6rem;
}
div:hover > .git-gutter-marker.git-topdelete {
height: 0.6rem;
}
div:hover > .git-gutter-marker.git-changedelete {
font-weight: var(--font-bold);
}
.git-gutter-marker.staged {
opacity: 0.5;
}
/* Prevent shifting of the editor when git signs gutter is the only gutter present */
.cm-gutters.cm-gutters-before:has(> .git-signs-gutter:only-child) {
margin-inline-end: 0;
.git-signs-gutter {
margin-inline-start: -1rem;
}
}
.git-changes-status-bar-colored {
.git-add {
color: var(--color-green);
}
.git-change {
color: var(--color-yellow);
}
.git-delete {
color: var(--color-red);
}
}
.git-changes-status-bar .git-add {
margin-right: 0.3em;
}
.git-changes-status-bar .git-change {
margin-right: 0.3em;
}
File diff suppressed because it is too large Load Diff
+10
View File
@@ -0,0 +1,10 @@
{
"id": "obsidian-pandoc",
"name": "Pandoc Plugin",
"version": "0.4.1",
"minAppVersion": "0.12.5",
"description": "This is a Pandoc export plugin for Obsidian. It provides commands to export to formats like DOCX, ePub and PDF.",
"author": "Oliver Balfour",
"authorUrl": "https://github.com/OliverBalfour/obsidian-pandoc",
"isDesktopOnly": true
}
+4
View File
@@ -0,0 +1,4 @@
.pandoc-plugin-error {
color: red;
}
+165
View File
File diff suppressed because one or more lines are too long
+10
View File
@@ -0,0 +1,10 @@
{
"id": "obsidian-style-settings",
"name": "Style Settings",
"version": "1.0.9",
"minAppVersion": "0.11.5",
"description": "Offers controls for adjusting theme, plugin, and snippet CSS variables.",
"author": "mgmeyers",
"authorUrl": "https://github.com/mgmeyers/obsidian-style-settings",
"isDesktopOnly": false
}
File diff suppressed because one or more lines are too long
+226
View File
@@ -0,0 +1,226 @@
{
"version": "1.4.5",
"display_language": "display",
"filter_mode": "0",
"translation_service": "google_translate",
"security_setting": "none",
"switch_button_action": "switch-both",
"translation_command_action": "replace",
"apply_glossary": false,
"local_glossary": false,
"glossary_preference": "online",
"case_insensitive_glossary": false,
"enable_animations": true,
"glossary_bidirectional": false,
"quicksettings_default": [
"change-service",
"automatic-translation",
"change-layout",
"apply-filter",
"open-settings"
],
"layout_default": 0,
"left_quickactions_default": [
"paste",
"clear"
],
"right_quickactions_default": [
"copy"
],
"hide_attribution_default": false,
"default_source_language": "auto",
"target_language_preference": "specific",
"last_used_target_languages": [],
"default_target_language": "en",
"filtered_services": [],
"hotkeys": [
{
"id": "view-translate",
"modifiers": [
"Mod"
],
"key": "Enter"
},
{
"id": "view-language-switch",
"modifiers": [
"Mod"
],
"key": "S"
},
{
"id": "view-action-copy",
"modifiers": [],
"key": ""
},
{
"id": "view-action-clear",
"modifiers": [],
"key": ""
},
{
"id": "view-action-paste",
"modifiers": [],
"key": ""
},
{
"id": "view-clear-fields",
"modifiers": [],
"key": ""
}
],
"service_settings": {
"fasttext": {
"default_usage": false,
"version": "1.0.0"
},
"google_translate": {
"selected_languages": [
"en"
],
"api_key": "",
"auto_translate": false,
"auto_translate_interval": 500,
"validated": null,
"available_languages": [
"af",
"ak",
"am",
"ar",
"as",
"ay",
"az",
"be",
"bg",
"bho",
"bm",
"bn",
"bs",
"ca",
"ceb",
"ckb",
"co",
"cs",
"cy",
"da",
"de",
"doi",
"dv",
"ee",
"el",
"en",
"eo",
"es",
"et",
"eu",
"fa",
"fi",
"fr",
"fy",
"ga",
"gd",
"gl",
"gn",
"gom",
"gu",
"ha",
"haw",
"he",
"hi",
"hmn",
"hr",
"ht",
"hu",
"hy",
"id",
"ig",
"ilo",
"is",
"it",
"iw",
"ja",
"jv",
"jw",
"ka",
"kk",
"km",
"kn",
"ko",
"kri",
"ku",
"ky",
"la",
"lb",
"lg",
"ln",
"lo",
"lt",
"lus",
"lv",
"mai",
"mg",
"mi",
"mk",
"ml",
"mn",
"mni-Mtei",
"mr",
"ms",
"mt",
"my",
"ne",
"nl",
"no",
"nso",
"ny",
"om",
"or",
"pa",
"pl",
"ps",
"pt",
"qu",
"ro",
"ru",
"rw",
"sa",
"sd",
"si",
"sk",
"sl",
"sm",
"sn",
"so",
"sq",
"sr",
"st",
"su",
"sv",
"sw",
"ta",
"te",
"tg",
"th",
"ti",
"tk",
"tl",
"tr",
"ts",
"tt",
"ug",
"uk",
"ur",
"uz",
"vi",
"xh",
"yi",
"yo",
"zh",
"zh-CN",
"zh-TW",
"zu"
],
"version": "1.1.0"
}
}
}
+169
View File
File diff suppressed because one or more lines are too long
+11
View File
@@ -0,0 +1,11 @@
{
"id": "translate",
"name": "Translate",
"version": "1.4.9",
"minAppVersion": "1.0.0",
"description": "Translate text and notes with Google Translate, DeepL, Azure, and more.",
"author": "Fevol",
"authorUrl": "https://github.com/Fevol/",
"isDesktopOnly": false,
"fundingUrl": "https://ko-fi.com/fevol"
}
File diff suppressed because one or more lines are too long
+3
View File
@@ -0,0 +1,3 @@
body {
--file-line-width: 1500px;
}
+92
View File
@@ -0,0 +1,92 @@
/* shared palette */
body {
--code-keyword: #c678dd;
--code-string: #98c379;
--code-function: #61afef;
--code-type: #e5c07b;
}
/* .cm-keyword { color: var(--code-keyword) !important; }
.cm-string { color: var(--code-string) !important; }
.cm-def { color: var(--code-function) !important; }
.cm-type { color: var(--code-type) !important; }
.token.keyword { color: var(--code-keyword) !important; }
.token.string { color: var(--code-string) !important; }
.token.function { color: var(--code-function) !important; }
.token.class-name { color: var(--code-type) !important; } */
/* Targets code blocks and inline code */
/* Editing and reading mode */
.markdown-rendered pre,
.markdown-rendered pre code,
.cm-s-obsidian .HyperMD-codeblock,
pre, code {
font-size: 11px !important; /* Adjust this number up or down as needed */
white-space: pre-wrap !important; /* Forces text to wrap if it's still too long, rather than cutting off */
}
@media screen {
.markdown-rendered pre {
}
.markdown-rendered pre code {
}
}
/* PDF / Print view */
@media print {
.markdown-rendered h1,
.markdown-rendered h2,
.markdown-rendered h3,
.markdown-rendered h4,
.markdown-rendered h5,
.markdown-rendered h6,
.markdown-rendered p {
break-after: avoid !important;
page-break-after: avoid !important;
}
.markdown-rendered pre {
background: #1e222a !important;
color: #e6e6e6 !important;
font-size: 8px !important; /* Adjust this number up or down as needed */
white-space: pre-wrap !important; /* Forces text to wrap if it's still too long, rather than cutting off */
background-color:#1e222a !important;
border-radius: 10px !important;
break-inside: avoid !important;
page-break-inside: avoid !important;
-webkit-break-inside: avoid;
-webkit-column-break-inside: avoid;
}
.markdown-rendered pre code {
color: inherit !important;
font-size: 8px !important; /* Adjust this number up or down as needed */
white-space: pre-wrap !important; /* Forces text to wrap if it's still too long, rather than cutting off */
background-color:#1e222a !important;
border-radius: 10px !important;
break-inside: avoid !important;
page-break-inside: avoid !important;
-webkit-break-inside: avoid;
-webkit-column-break-inside: avoid;
}
.page-break {
display: block;
height: 0;
break-before: page;
page-break-before: always;
}
}
/* Live Preview / Source mode */
.cm-s-obsidian .HyperMD-codeblock {
font-size: 12px;
background-color:#1e222a !important;
/* background-color: blue !important; */
}
+210
View File
@@ -0,0 +1,210 @@
{
"main": {
"id": "6d06477fc8fa2e5e",
"type": "split",
"children": [
{
"id": "567dae9a01eaef2f",
"type": "tabs",
"children": [
{
"id": "127ce2a147446e39",
"type": "leaf",
"state": {
"type": "pdf",
"state": {
"file": "Semester 2/EIST/EIST CHEATSHEET.pdf"
},
"icon": "lucide-file-text",
"title": "EIST CHEATSHEET"
}
},
{
"id": "37f018f4ea886da2",
"type": "leaf",
"state": {
"type": "markdown",
"state": {
"file": "EIDI/JVM.md",
"mode": "source",
"source": false
},
"icon": "lucide-file",
"title": "JVM"
}
}
]
}
],
"direction": "vertical"
},
"left": {
"id": "50f530f1517d25bf",
"type": "mobile-drawer",
"children": [
{
"id": "c5c1e060d2a82497",
"type": "leaf",
"state": {
"type": "file-explorer",
"state": {
"sortOrder": "alphabetical",
"autoReveal": false
},
"icon": "lucide-folder-closed",
"title": "Files"
}
},
{
"id": "83b74d0ae36b68d5",
"type": "leaf",
"state": {
"type": "search",
"state": {
"query": "",
"matchingCase": false,
"explainSearch": false,
"collapseAll": false,
"extraContext": false,
"sortOrder": "alphabetical"
},
"icon": "lucide-search",
"title": "Search"
}
},
{
"id": "85b2fbfde733fc4f",
"type": "leaf",
"state": {
"type": "tag",
"state": {
"sortOrder": "frequency",
"useHierarchy": true,
"showSearch": false,
"searchQuery": ""
},
"icon": "lucide-tags",
"title": "Tags"
}
},
{
"id": "794f0bcdbac35b97",
"type": "leaf",
"state": {
"type": "all-properties",
"state": {
"sortOrder": "frequency",
"showSearch": false,
"searchQuery": ""
},
"icon": "lucide-archive",
"title": "All properties"
}
},
{
"id": "beb7bbf0715d4ce1",
"type": "leaf",
"state": {
"type": "bookmarks",
"state": {},
"icon": "lucide-bookmark",
"title": "Bookmarks"
}
}
],
"currentTab": 0
},
"right": {
"id": "fd1ec1eafeaf0734",
"type": "mobile-drawer",
"children": [
{
"id": "819f75ef367a28d1",
"type": "leaf",
"state": {
"type": "backlink",
"state": {
"file": "ERA/Progress.md",
"collapseAll": false,
"extraContext": false,
"sortOrder": "alphabetical",
"showSearch": false,
"searchQuery": "",
"backlinkCollapsed": false,
"unlinkedCollapsed": true
},
"icon": "links-coming-in",
"title": "Backlinks"
}
},
{
"id": "1902bcf43ba91ab8",
"type": "leaf",
"state": {
"type": "outgoing-link",
"state": {
"linksCollapsed": false,
"unlinkedCollapsed": true
},
"icon": "links-going-out",
"title": "Outgoing links"
}
},
{
"id": "b949dda5e967cb77",
"type": "leaf",
"state": {
"type": "outline",
"state": {
"followCursor": false,
"showSearch": false,
"searchQuery": ""
},
"icon": "lucide-list",
"title": "Outline"
}
}
],
"currentTab": 0
},
"left-ribbon": {
"hiddenItems": {
"obsidian-git:Open Git source control": false,
"translate:Open translation view": false,
"obsidian-excalidraw-plugin:New drawing": false,
"switcher:Open quick switcher": false,
"graph:Open graph view": false,
"canvas:Create new canvas": false,
"daily-notes:Open today's daily note": false,
"templates:Insert template": false,
"command-palette:Open command palette": false,
"bases:Create new base": false
}
},
"active": "127ce2a147446e39",
"lastOpenFiles": [
"Semester 2/EIST/EIST CHEATSHEET.md",
"Semester 2/EIST/EIST CHEATSHEET.pdf",
"ERA/Progress.md",
"GAD/gad26e01-go38coz/build/classes",
"EIST/eist26l02pe01-go38coz/page-microservice/build/resources/main",
"EIST/eist26l02pe01-go38coz/page-microservice/build/resources",
"EIST/eist26l02p01-go38coz/build/classes/java/main/org/spotify/grpc",
"EIST/eist26l02p02-go38coz/tweet-microservice/src/main/java/eist24l03pb01",
"EIST/eist26l02p02-go38coz/tweet-microservice/src/main/java",
"EIST/eist26l02p02-go38coz/tweet-microservice/src/main",
"GAD/gad26e01-go38coz/build/tmp/compileJava/compileTransaction/header-output",
"GAD/gad26e01-go38coz/build/tmp/compileJava/compileTransaction",
"EIDI/JVM.md",
"EIDI/Progress.md",
"DS/Progress.md",
"ERA/Vorlesung 24 - K-Maps.md",
"Attachments/20260119_kmaps_260129_183719.jpg",
"Woche 1 - Datendarstellungen und Zahlensysteme.md",
"Zahlensysteme.md",
"Attachments/Pasted image 20260126012909.png",
"Vorlesung 1.md",
"Woche 1 - Zahlensysteme.md",
"Welcome.md"
]
}
+228
View File
@@ -0,0 +1,228 @@
{
"main": {
"id": "ac47054851f43cf2",
"type": "split",
"children": [
{
"id": "844a1764731992eb",
"type": "tabs",
"children": [
{
"id": "3ba46ad009838dd8",
"type": "leaf",
"state": {
"type": "markdown",
"state": {
"file": "Semester 2/EIST/EIST CHEATSHEET.md",
"mode": "source",
"source": false
},
"icon": "lucide-file",
"title": "EIST CHEATSHEET"
}
}
]
}
],
"direction": "vertical"
},
"left": {
"id": "68eacf2b1519b145",
"type": "split",
"children": [
{
"id": "07280441c202dd46",
"type": "tabs",
"children": [
{
"id": "35ef490cc049101e",
"type": "leaf",
"state": {
"type": "file-explorer",
"state": {
"sortOrder": "alphabetical",
"autoReveal": false
},
"icon": "lucide-folder-closed",
"title": "Files"
}
},
{
"id": "1007da8058a4cbd3",
"type": "leaf",
"state": {
"type": "search",
"state": {
"query": " ",
"matchingCase": false,
"explainSearch": false,
"collapseAll": false,
"extraContext": false,
"sortOrder": "alphabetical"
},
"icon": "lucide-search",
"title": "Search"
}
},
{
"id": "92c3c7845aeb3a8c",
"type": "leaf",
"state": {
"type": "bookmarks",
"state": {},
"icon": "lucide-bookmark",
"title": "Bookmarks"
}
}
]
}
],
"direction": "horizontal",
"width": 300
},
"right": {
"id": "5c4898baa11e4100",
"type": "split",
"children": [
{
"id": "a7fb8b4fa8dbc433",
"type": "tabs",
"children": [
{
"id": "44e9c2900a01d539",
"type": "leaf",
"state": {
"type": "backlink",
"state": {
"file": "Semester 2/EIST/EIST CHEATSHEET.md",
"collapseAll": false,
"extraContext": false,
"sortOrder": "alphabetical",
"showSearch": false,
"searchQuery": "",
"backlinkCollapsed": false,
"unlinkedCollapsed": true
},
"icon": "links-coming-in",
"title": "Backlinks for EIST CHEATSHEET"
}
},
{
"id": "d444bebd3a64ee18",
"type": "leaf",
"state": {
"type": "outgoing-link",
"state": {
"file": "Semester 2/EIST/EIST CHEATSHEET.md",
"linksCollapsed": false,
"unlinkedCollapsed": true
},
"icon": "links-going-out",
"title": "Outgoing links from EIST CHEATSHEET"
}
},
{
"id": "16ccfa01ac890dee",
"type": "leaf",
"state": {
"type": "tag",
"state": {
"sortOrder": "frequency",
"useHierarchy": true,
"showSearch": false,
"searchQuery": ""
},
"icon": "lucide-tags",
"title": "Tags"
}
},
{
"id": "ccc8d8c3eba80e25",
"type": "leaf",
"state": {
"type": "all-properties",
"state": {
"sortOrder": "frequency",
"showSearch": false,
"searchQuery": ""
},
"icon": "lucide-archive",
"title": "All properties"
}
},
{
"id": "d23db6412871c788",
"type": "leaf",
"state": {
"type": "outline",
"state": {
"file": "Semester 2/EIST/EIST CHEATSHEET.md",
"followCursor": false,
"showSearch": false,
"searchQuery": ""
},
"icon": "lucide-list",
"title": "Outline of EIST CHEATSHEET"
}
},
{
"id": "1221778bf93051e6",
"type": "leaf",
"state": {
"type": "git-view",
"state": {},
"icon": "git-pull-request",
"title": "Source Control"
}
}
],
"currentTab": 5
}
],
"direction": "horizontal",
"width": 300
},
"left-ribbon": {
"hiddenItems": {
"obsidian-excalidraw-plugin:New drawing": false,
"translate:Open translation view": false,
"obsidian-git:Open Git source control": false,
"switcher:Open quick switcher": false,
"graph:Open graph view": false,
"canvas:Create new canvas": false,
"daily-notes:Open today's daily note": false,
"templates:Insert template": false,
"command-palette:Open command palette": false,
"bases:Create new base": false
}
},
"active": "3ba46ad009838dd8",
"lastOpenFiles": [
"Semester 2/EIST/Progress.md",
"Semester 2/EIST/EIST CHEATSHEET.pdf",
"Semester 2/EIST/EIST CHEATSHEET.md",
"2026-07-10.md",
"Semester 2/EIST/lu280859klubr.tmp",
"Semester 2/EIST/lu280859klubn.tmp",
"Semester 2/EIST/EIST CHEATSHEET.odg",
"Semester 2/EIST/lu280859klubk.tmp",
"Semester 2/EIST/test.html",
"Semester 2/EIST/test.pdf",
"Semester 2/EIST/EIST CHEATSHEET.docx",
"Excalidraw/Drawing 2026-07-09 18.02.17.excalidraw.md",
"Excalidraw/Drawing 2026-07-09 18.02.06.excalidraw.md",
"Excalidraw",
"home/nikola/Documents/EIST/eist26l09p01-go38coz.md",
"home/nikola/Documents/EIST",
"file/home/nikola/Documents/EIST/eist26l09p01-go38coz 3.md",
"file/home/nikola/Documents/EIST/eist26l09p01-go38coz 2.md",
"file/home/nikola/Documents/EIST/eist26l09p01-go38coz 1.md",
"file/home/nikola/Documents/EIST/eist26l09p01-go38coz.md",
"2026-07-09.md",
"Semester 1/ERA/Vorlesung 24 - K-Maps.md",
"Semester 1/ERA/Progress.md",
"Semester 1/DS/Progress.md",
"Semester 2/Untitled.md",
"Untitled.md"
]
}
+5
View File
@@ -0,0 +1,5 @@
# This directory is a Syncthing folder marker.
# Do not delete.
folderID: ern3y-p95qk
created: 2026-05-28T21:37:52+02:00
View File
View File
View File
View File
View File
+1
View File
@@ -0,0 +1 @@
,nikola,fedora,06.07.2026 02:18,file:///home/nikola/.config/libreoffice/4;
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 148 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 56 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

+9
View File
@@ -0,0 +1,9 @@
- [x] VL1: Einführung, Logik
- [x] VL2: Beweise
- [ ] Übungsblatt 1
- [x] VL3: Mengen
- [x] Übungsblatt 2
- [ ] Übungsblatt 3
- [ ] VL4
- [ ]
+30
View File
@@ -0,0 +1,30 @@
## Struktur von Program
Programme sind hierarchisch aus Komponenten aufgebaut. Für jede
Komponente geben wir Regeln an, wie sie aus anderen
Komponenten zusammengesetzt sein können.
program = decl* stmt*
decl = type name ( , name)*
type = int
#### Statements
stmt ::= ; | { stmt* } |
name = expr; | name = read(); | write( expr ); |
if ( cond ) stmt |
if ( cond ) stmt else stmt |
while ( cond ) stmt
- Ein Statement ist entweder leer (d.h. gleich ;) oder eine
geklammerte Folge von Statements;
- Oder eine Zuweisung, eine Lese- oder Schreib-Operation;
- Eine (einseitige oder zweiseitige) bedingte Verzweigung;
- Oder eine Schleife.
#### Expressions
expr ::= number | name | ( expr ) |
unop expr | expr binop expr
unop ::= -
binop ::= - | + | * | / | %
- Ein Ausdruck ist eine Konstante, eine Variable oder ein geklammerter Ausdruck
- Oder ein unärer Operator (unop), angewandt auf einen Ausdruck,
- Oder ein binärer Operator(binop), angewandt auf zwei Argument-Ausdrücke.
- Einziger unärer Operator ist (bisher) die Negation.
- Mögliche binäre Operatoren sind Addition, Subtraktion, Multiplikation, (ganz-zahlige) Division und Modulo.
+10
View File
@@ -0,0 +1,10 @@
- [x] Folien: Einführung und Objektbasiertes Programmieren
- [x] Folien: Testen
- [x] Folien: Kontrollstrukturen und Felder
- [x] Folien: Abstrakte Datentypen
- [x] Folien: Objektorientierung
- [x] Folien: Rekursion
- [x] Folien: Fortgeschrittene Programmierkonstrukte
- [x] Folien: Nebenläufigkeit
- [x] Folien: GUIs
- [x] Folien: Rekursion Revisited
+49
View File
@@ -0,0 +1,49 @@
- [x] Vorlesung 1: Einführung und Datendarstellungen
- [x] Zentralübung 1: Zahlensysteme
- [x] Übungsblatt 1: Zahlensysteme
- [x] Vorlesung 2/3: Assemblersprachen
- [x] Zentralübung 2: Einführung in RISC-V Assembly
- [x] Übungsblatt 2: RISC-V Assembly
- [x] Vorlesung 4/5: Assembler Beispiel und von Neumann Architektur
- [x] Zentralübung 3: RISC-V Deep Dive
- [x] Übungsblatt 3: RISC-V Teil 2 - Sprünge und Pointer
- [x] Vorlesung 6: Andere ISAs zum Vergleich
- [x] Vorlesung 7: Systemarchitektur
- [x] Zentralübung 4: RISC-V Calling Convention and Rekursion
- [x] Übungsblatt 4: RISC-V Teil 3 - Rekursion und Calling Convention
- [x] Vorlesung 8/9: Speicherverwaltung und Caches
- [x] Zentralübung 5: Caches
- [x] Übungsblatt 5: Caches
- [ ] Vorlesung 10: Boolesche Algebra
- [x] Vorlesung 11: Addierer/Subtrahierer
- [x] Zentralübung 6: Boolesche Algebra
- [x] Übungsblatt 6: Kombinatorische Schaltungen
- [ ] Vorlesung 12: Multiplizierer
- [x] Vorlesung 13: Speicher
- [x] Zentralübung 7: Sequenzielle Schaltungen
- [x] Übungsblatt 7: Multiplizierer und Sequenzielle Logik
- [x] Vorlesung 14/15: Single-Cycle Prozessor
- [x] Zentralübung 8: Single-Cycle Prozessor
- [ ] Übungsblatt 8: Single-Cycle Prozessor
- [ ] Vorlesung 16: Endliche Automaten
- [ ] Vorlesung 17: Multi-Cycle Prozessor
- [ ] Zentralübung 9: Multi-Cycle Prozessor
- [ ] Übungsblatt 9: Multi-Cycle Prozessor
- [ ] Vorlesung 18/19: Moderne Systeme und Parallität
- [ ] Zentralübung 10: Caches & Parallelität
- [ ] Übungsblatt 10: Altklausur
- [ ] Vorlesung 20: Das E/A Werk
- [ ] Vorlesung 21: Implementierung auf das Physikalischen Schicht
- [ ] Zentralübung 11: Modern RISC-V
- [ ] Übungsblatt 11: Parallelisierung und Caches
- [ ] Vorlesung 22/23: Pipelined Prozessor
- [ ] Zentralübung 12: Pipelining
- [ ] Übungsblatt 12: Pipelining
- [x] Vorlesung 24: K-Maps
- [x] Vorlesung 25: BDDs
- [ ] Zentralübung 13: K-Maps und BDDs
- [ ] Übungsblatt 13: K-Maps und BDDs
- [ ] Vorlesung 26: SATs
- [ ] Vorlesung 27: Physical Design
- [ ] Zentralübung 14: SAT und Physical Design
- [ ] Übungsblatt 14: SAT und Physical Design
@@ -0,0 +1,37 @@
# Datendarstellung
#### Rechner arbeiten meistens im Binarsystem:
- Beschreiben durch 0/1
- "Strom an" / "Strom aus"
#### Darstellung von Daten:
- Reihen von "0" und "1"
- Representierung von allen "Daten"
- Eingaben/Ausgaben
- Code
# Zahlensysteme
### Dezimalsystem:
- $2019 = 2 * 10^3 + 0 * 10^2 + 1 * 10^1 + 9 * 10^0$
- **10 Zahlensymbole:** 0,1, 2, 3, 4, 5, 6, 7 ,8 ,9, 0
- Basis: 10
### Andere Kulturen haben andere Basen
- **Beispiel**: Maya - Basis: 20
- **Konsequenz**: 20 Zahlensymbole
## Systemen für Rechner
### Binärsystem:
- $1101\ 1001_2 = 1 * 2^7 + 1 * 2^6 + 0 * 2^5 + 1 * 2^4 + 1 * 2^3 + 0 * 2^0 + 0 * 2^2 + 0 * 2^1 + 1*2^0$
- **Zahlensymbole**: 0, 1
- Basis: 2
**Beispiel**: 2019 = 111 1110 0011<sub>b</sub>
### Hexadezimalsystem(Basis 16)
- 217 = D9<sub>h</sub> = 13\*16<sup>1</sup> + 9\*16<sup>0</sup> =1101 1001<sub>b</sub>
- **Zahlensymbole**: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, A, B, C, D, E, F
- **!!! Vorteil**: 1 Hex-Symbol = 4 Binär-Symbole **!!!**
## Binär- und Hexadezimal-Arithmetik
### Addition:
- Ähnlich zu Arithmetik im Dezimalsystem
- Überlauf wird an die nächste Stelle weitergereicht
- Beispiel:
- System mit max. 5 Ziffern.
- a = 01001<sub>2</sub> = 1 · 810 + 0 · 410 + 0 · 210 + 1 · 110 = 910
- b = 00111<sub>2</sub> = 0 · 810 + 1 · 410 + 1 · 210 + 1 · 110 = 710
- Ergebnis: 1610
![[Pasted image 20260126042053.png]]
+58
View File
@@ -0,0 +1,58 @@
## Logiksynthese und -minimierung
- #### **Deduzierte Schaltungen lassen sich nicht effizient "von Hand entwickeln"**
-> Wir brauchen Methodik für Schaltkreissynthese
- #### **Logiksynthese und -minimierung: Versuch, Logik der Schaltung:**
- zu generieren bzw.
- zu minimieren
- #### **Unterscheidung zwischen:**
- **kombinatorischer Synthese** (Realisierung einer Booleschen Funktion)
- **sequentieller Synthese** (Realisierung eines endlichen **Automaten**; kann als Boolesche Funktion repräsentiert werden)
- #### Ausgangspunkt: Funktionsbeschreibung (Wahrheitstabelle, Boolescher Ausdruck, ... )
## Wdhlg. : Synthese (simpel)
- #### Realisierung beliebiger Wahrheitstabellen durch **<font color="#00b0f0">Grundgatter</font> möglich
- #### Vorgehen:
- Für jede Zeile mit Ausgabewert 1:
Und-Gatter mit passender Eingangsbeschaltung
- Oder-Verknüpfung aller Und-Gatter
- ### Funktioniert für alle Tabellen, aber
- <font color="#c00000">teuer</font>
- <font color="#c00000">nicht skalierbar</font>
![[20260119_kmaps_260129_183719.jpg]]
## Weitere Grundlagen
- #### Die Booleschen Ausdrücke <font color="#ff0000">x<sub>i</sub></font> und <font color="#ff0000">x<sub>i</sub>' </font>heißen <font color="#00b0f0">Literale</font>
- x<sub>i</sub> ist <font color="#00b0f0">positives Literal</font>
- x<sub>i</sub>' ist <font color="#00b0f0">negatives Literal</font>
- #### Eine Konjunktion von Literalen heißt <font color="#00b0f0">Monom</font>, wenn:
- jedes Literal kommt höchstens einmal vor
- es kommt nicht sowohl das <font color="#00b0f0">positive</font> als auch das <font color="#00b0f0">negative</font> <font color="#00b0f0">Literal</font> einer Variable vor
- Monome: **x<sub>1</sub>x<sub>2</sub>x<sub>3</sub>, x<sub>1</sub>x<sub>2</sub>x<sub>3</sub>'
- #### Ein Monom heißt <font color="#00b0f0">vollständig</font> oder <font color="#00b0f0">Minterm</font>, wenn <font color="#ff0000">jede Variable</font> entweder als <font color="#00b0f0">positives</font> oder als <font color="#00b0f0">negatives</font> <font color="#00b0f0">Literal</font> vorkommt
- #### Eine Disjunktion von paarweise verschiedenen Monomen heißt <font color="#00b0f0">Polynom</font>. Sind alle <font color="#00b0f0">Monome</font> des <font color="#00b0f0">Polynoms</font> <font color="#00b0f0">vollständig</font>, so heißt das Polynom <font color="#00b0f0">vollständig</font>
- #### Eine Boolesche <font color="#00b0f0">Funktion</font> ist von ihrer Darstellung als Formel zu unterschieden
- Die <font color="#00b0f0">Interpretationsfunktion</font> $\psi$ weist einer Formel die entsprechende Funktion zu
- $f = (a+b) * c$ und $g = a * c + b * c$ sind unterschiedliche Formeln aber $\psi(f) = \psi(g)$
## Logiktoptimierung
- #### Gegeben: Eine Boolesche Funktion $f$
- #### Ziel: Darstellung von $f$ als <font color="#00b0f0">Minimalpolynom</font> $p$, das heißt ein Polynom sodass gilt:
- $\psi(p) = f$
- Die Anzahl an <font color="#00b0f0">Monomen</font> in $p$ ist **minimal**
- Die Anzahl der <font color="#00b0f0">Literale</font> in $p$ ist **minimal**
- #### Idee: $x_1x_2x_3 + x_1x_2\bar{x_3} = x_1x_2$
- Die Belegung von $x_3$ hate keinen Einfluss auf den Wahrheitswert des Polynoms
- $x_1x_2$ ist ein sogenannter <font color="#00b0f0">Implikant</font> von $x_1x_2x_3 + x_1x_2\bar{x_3}$
- #### Allgemein: Ein Monom(!) $q$ ist ein Implikant der Funktion $f$ falls $\psi(q) \leq f$
Das bedeutet das der Implikant kleiner oder optimierter als der Funktion ist
- #### <font color="#00b0f0">Ein Primimplikant von f</font> ist ein maximaler Implikant $q$ von $f$, d.h. es gibt keinen Implikanten $s(s \neq q)$
-
Binary file not shown.
+718
View File
@@ -0,0 +1,718 @@
# List of contents
1. [[#REST API with Spring]]
2. [[#DOCKER]]
3. [[#gRPC]]
4.
<div class="page-break"></div>
# REST API in Java with Spring
## Making REST API Requests
### With ***WebClient*** object:
(e.g Spring WebFlux)
#### GET
```java
public void getAllPersons(CustomerSortingOptions sortingOptions, Consumer<List<Customer>> customerConsumer) {
webClient.get()
.uri(uriBuilder -> uriBuilder
.path("customers")
.queryParam("sortField", sortingOptions.getSortField())
.queryParam("sortingOrder", sortingOptions.getSortingOrder())
.build())
.retrieve()
.bodyToMono(new ParameterizedTypeReference<List<Customer>>() {
})
.onErrorStop()
.subscribe(newPersons -> {
customers.clear();
customers.addAll(newPersons);
customerConsumer.accept(customers);
});
}
```
#### POST
```java
public void addPerson(Customer customer, Consumer<List<Customer>> customerConsumer) {
// TODO Part 2: Complete the http post request to the server
webClient.post()
.uri("customers")
.bodyValue(customer)
.retrieve()
.bodyToMono(Customer.class)
.onErrorStop()
.subscribe(newCustomer -> {
customers.add(newCustomer);
customerConsumer.accept(customers);
});
}
```
#### PUT
```java
public void updatePerson(Customer customer, Consumer<List<Customer>> customerConsumer) {
// TODO Part 2: Complete the http put request to the server
webClient.put()
.uri("customers/" + customer.getId())
.bodyValue(customer)
.retrieve()
.bodyToMono(Customer.class)
.onErrorStop()
.subscribe(newCustomer -> {
customers.replaceAll(x -> x.getId().equals(customer.getId()) ? newCustomer : x);
customerConsumer.accept(customers);
});
}
```
#### DELETE
```java
public void deletePerson(Customer customer, Consumer<List<Customer>> customerConsumer) {
// TODO Part 2: Make an http delete request to the server
webClient.delete()
.uri("customers/" + customer.getId())
.retrieve()
.toBodilessEntity()
.onErrorStop()
.subscribe(deletedCustomer -> {
customers.remove(customer);
customerConsumer.accept(customers);
});
}
```
#### Just in case: webClient Constructor
```java
public CustomerController() {
this.webClient = WebClient.builder()
.baseUrl("http://localhost:8080/")
.defaultHeader(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON_VALUE)
.defaultHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)
.build();
this.customers = new ArrayList<>();
}
```
#### With Request Parameters:
Endpoint:
```java
@GetMapping("persons")
public ResponseEntity<List<Person>> getAllPersons(PersonSortingOptions sortingOptions) { // Don't use @RequestParams unless object is simple(for example String), for more complex objects Spring parses the object by itself
List<Person> persons = personService.getAllPersons(sortingOptions);
return ResponseEntity.ok(persons);
}
```
Request:
```java
public void getAllPersons(PersonSortingOptions sortingOptions, Consumer<List<Person>> personsConsumer) {
this.webClient.get()
.uri(uriBuilder -> uriBuilder // Use uriBuilder to build the path
.path("persons")
.queryParam("sortingOrder",sortingOptions.getSortingOrder()) // The fields are passed separately
.queryParam("sortField",sortingOptions.getSortField()) // In the format: ("Name",value)
.build()
)
.retrieve()
.bodyToMono(new ParameterizedTypeReference<List<Person>>() {
})
.onErrorStop()
.subscribe(persons -> {
this.persons = persons;
personsConsumer.accept(this.persons);
});
}
```
### With *RestTemplate*:
```java
GetMapping("/getTimeLine/{id}")
public List<Tweet> getTimeLine(@PathVariable("id") int userID) {
headers.setContentType(MediaType.APPLICATION_JSON);
ResponseEntity<List<Tweet>> response = restTemplate.exchange(
getActivityURL + userID, // Set the uri HttpMethod.GET,
null, // requestEntity = null as there is no body,
new ParameterizedTypeReference<List<Tweet>>(){} // response body type );
return response.getBody();
}
```
## REST API Endpoints
Example Java class:
```java
@RestController
@RequestMapping("/activity")
public class ActivityController {
private Map<Integer, List<Tweet>> userActivityMap = new HashMap<>();
private Map<Integer, List<User>> userFollowedMap = new HashMap<>();
@GetMapping("/getActivity/{id}")
public List<Tweet> getActivity(@PathVariable("id") int userID) {
List<Tweet> userTweets = userActivityMap.get(userID);
if(userTweets == null) return new ArrayList<>();
return userTweets;
}
@PostMapping("/addActivity")
public void addActivity(@RequestBody Tweet tweet) {
userActivityMap.computeIfAbsent(tweet.getUser().getUserID(), x -> new LinkedList<>());
userActivityMap.get(tweet.getUser().getUserID()).add(tweet);
}
@PostMapping("/addFollower")
public void addFollower(@RequestBody FollowRequest followRequest) {
User follower = followRequest.getFollower();
User followed = followRequest.getFollowed();
userFollowedMap.computeIfAbsent(follower.getUserID(),x -> new LinkedList<>())
.add(followed);
}
@DeleteMapping("/deleteActivity")
public void deleteActivity(@RequestBody Tweet tweet) {
List<Tweet> userTweets = userActivityMap.get(tweet.getUser().getUserID());
if(userTweets == null) return;
userTweets.remove(tweet);
}
@DeleteMapping("/deleteFollower")
public void deleteFollower(@RequestBody FollowRequest followRequest) {
User follower = followRequest.getFollower();
User followed = followRequest.getFollowed();
List<User> followedUsers = userFollowedMap.get(follower.getUserID());
if(followedUsers == null) return;
followedUsers.remove(followed);
}
@GetMapping("/getFollowedList/{id}")
public List<User> getFollowedList(@PathVariable("id") int userID) {
// TODO: this method is also not complete, so you have to implement it accordingly :)
List<User> followed = userFollowedMap.get(userID);
if(followed == null) return new ArrayList<>();
return followed;
}
}
```
<div class="page-break"></div>
# Flask API in Python
## *Server side* endpoints
#### GET
```python
@api.route("/<key>", methods=["GET"])
def get(key: str) -> Response:
"""
Retrieve the file-content associated with the given key owned by the user.
If there is no user-id `uid` given in the request body or the user-id does not match, return error message and status.
Otherwise, return the file-content and success status.
"""
request_body: dict = request.json
ff: FileFolder = current_app.ff # type: ignore
user_id = request_body.get("uid")
if user_id is None:
return Response(NO_UID_IN_REQUEST_BODY,BAD_REQUEST)
file = ff.get(key)
if file is None:
return Response(response=KEY_DOES_NOT_EXIST % key, status=NOT_FOUND)
if file.uid != user_id:
return Response(response=NO_ACCESS_TO_ENTRY % key, status=BAD_REQUEST)
return Response(response=file.content,status=OK)
pass
```
#### PUT
```python
@api.route("/<key>", methods=["PUT"])
def put(key: str) -> Response:
"""
Upsert a file-content associated with the given key owned by the user.
If there is no user-id `uid` or file-content `content` given in the request body, return error message and status.
Otherwise, return the success message and success status
"""
request_body: dict = request.json
ff: FileFolder = current_app.ff
if "uid" not in request_body:
return Response(NO_UID_IN_REQUEST_BODY,BAD_REQUEST)
if "content" not in request_body:
return Response(NO_CONTENT_IN_REQUEST_BODY,BAD_REQUEST)
uid = request_body["uid"]
file_content = request_body["content"]
old_entry = ff.get(key)
if old_entry is None:
entry = Entry(uid,file_content)
success = ff.put(key,entry)
if success:
return Response(PUT_SUCCESS,OK)
else:
return Response(NO_SPACE_IN_FILE_FOLDER,BAD_REQUEST)
if uid != old_entry.uid:
return Response(NO_ACCESS_TO_ENTRY % key,status=BAD_REQUEST)
entry = Entry(uid,file_content)
ff.put(key,entry)
return Response(PUT_SUCCESS,OK)
pass
```
#### DELETE
```python
@api.route("/<key>", methods=["DELETE"])
def remove(key: str) -> Response:
"""
Remove the file-content associated with the given key owned by the user.
If there is no user-id `uid` given in the request body or the user-id does not match, return error message and status.
Otherwise, return the removed file-content and success status
"""
request_body: dict = request.json
ff: FileFolder = current_app.ff
if "uid" not in request_body:
return Response(NO_UID_IN_REQUEST_BODY,BAD_REQUEST)
uid = request_body["uid"]
entry = ff.get(key)
if entry is None:
return Response(KEY_DOES_NOT_EXIST % key,NOT_FOUND)
if entry.uid != uid:
return Response(NO_ACCESS_TO_ENTRY % key,BAD_REQUEST)
ff.remove(key)
return Response(entry.content,OK)
pass
```
#### GET - all
```python
@api.route("/", methods=["GET"])
def list() -> Response:
"""
List all (key, file-content) tuples owned by the user.
If there is no user-id `uid` given in the request body, return error message and status.
Otherwise, return the list of file-content and success status.
"""
request_body: dict = request.json
ff: FileFolder = current_app.ff
if "uid" not in request_body:
return Response(NO_UID_IN_REQUEST_BODY,BAD_REQUEST)
uid = request_body["uid"]
items = ff.items()
output = []
for key, entry in items:
output.append(f"{key}:{entry.content}")
output_string = ".".join(output)
return Response(output_string,OK)
pass
```
## Making requests on the *client side*
#### Helper method
```python
# make json request to server
def json_request(self, method: str, path: str, body: dict):
self.conn.request(method, path, json.dumps(body), headers={"Content-Type": "application/json"})
flask_response = self.conn.getresponse()
return flask_response.read().decode()
```
#### PUT
```python
def put(self, key, content):
"""
Upsert (key, content) tuple into the file folder.
Return the server response
"""
request_body = {"uid": self.user_id, "content": content}
return self.json_request("PUT", f"/{key}",request_body)
pass
```
#### GET
```python
def read(self, key):
"""
Retrieve the file-content associated with the given key owned by the user.
Return the server response
"""
request_body = {"uid": self.user_id}
return self.json_request("GET",f"/{key}",request_body)
pass
```
#### DELETE
```python
def remove(self, key):
"""
Remove the file-content associated with the given key owned by the user.
Return the server response
"""
request_body = {"uid": self.user_id}
return self.json_request("DELETE",f"/{key}",request_body)
pass
```
#### GET - ALL
```python
def list(self):
"""
List all file-content owned by the user.
Return the server response
"""
request_body = {"uid": self.user_id}
return self.json_request("GET","/",request_body)
pass
```
# DOCKER
**Docker reference: https://docs.docker.com/**
### Dockerfiles
https://docs.docker.com/get-started/docker-concepts/building-images/writing-a-dockerfile/
https://docs.docker.com/reference/dockerfile/
```dockerfile
FROM python:3.13
WORKDIR /usr/local/app
# Install the application dependencies
COPY requirements.txt ./
RUN pip install --no-cache-dir -r requirements.txt
# Copy in the source code
COPY src ./src
EXPOSE 8080
# Setup an app user so the container doesn't run as the root user
RUN useradd app
USER app
CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8080"]
```
### Building docker
```bash
docker build -t <tag>
```
### Docker processes
```bash
docker ps
```
#### Exercises
- [L09P01 - Registry Office Service Deployment](file:///home/nikola/Documents/EIST/eist26l09p01-go38coz)
- [L09P02 - Garching Best Software](file:///home/nikola/Documents/EIST/eist26l09p02-go38coz)
- [L08PE04 - Spaceship](file:///home/nikola/Documents/EIST/eist26l0pe04-go38coz)
<div class="page-break"></div>
# gRPC
**gRPC reference: https://grpc.io/docs/**
**gRPC Java basics: https://grpc.io/docs/languages/java/basics/**
## Protobuf files
#### Defining classes:
Important tips:
* Array in protobuf means ```repeated``` field
```protobuf
message Date {
int32 day = 1; // Number specifies order
int32 month = 2;
int32 year = 3;
}
message Location {
string city = 1;
string country = 2;
}
message LocationDate {
Location location = 1;
Date date = 2;
}
```
#### Defining services:
```protobuf
service WeatherReporter {
//Returning one object
rpc GetCityWeatherSingleDay(LocationDate) returns (CityWeatherData) {}
// Returning a stream of objects
rpc GetCityWeatherMultipleDays(LocationDatePeriod) returns (stream CityWeatherData) {}
}
```
#### Example of services and objects with **repeated** fields
This will be utilized by some of the client side examples underneath
```protobuf
service MetadataService {
rpc getTrackMetadata(EntitiesRequest) returns (Tracks) {}
rpc getAlbumMetadata(EntitiesRequest) returns (Albums) {}
}
message EntitiesRequest {
repeated uint32 id = 1;
}
message Track {
uint64 id = 1;
string name = 2;
string album = 3;
string artist = 4;
uint32 duration = 5;
}
message Tracks {
repeated Track track = 1;
}
message Album {
uint64 id = 1;
string name = 2;
string artist = 3;
repeated uint32 tracks = 4;
}
message Albums {
repeated Album album = 1;
}
```
#### Generating classes from *.proto* files
1. Gradle tab in IDE and press "Tasks > other > generateProto")
2. The generated classes from the proto file should be in build/generated/source/proto/main folder
## Server side
In practice can be done with streams or with simple iteration
```java
public void getCityWeatherSingleDay(LocationDate request, StreamObserver<CityWeatherData> responseObserver) {
var data = allWeatherData.stream().filter(cityWeatherData -> cityWeatherData.getLocationDate().equals(request)).findFirst().orElse(null);
if(data != null)responseObserver.onNext(data);
responseObserver.onCompleted();
}
```
#### For returning a *stream* of data just call onNext multiple times
With iteration:
```Java
public void getCityWeatherMultipleDays(LocationDatePeriod request, StreamObserver<CityWeatherData> responseObserver) {
for(CityWeatherData data : allWeatherData) {
if(data.getLocationDate().getLocation().equals(request.getLocation())) {
if(compareDate(data.getLocationDate().getDate(), request.getStartDate()) >= 0 && compareDate(data.getLocationDate().getDate(), request.getEndDate()) <= 0)
{
responseObserver.onNext(data);
}
}
}
responseObserver.onCompleted();
}
```
With streams:
```java
public void getCityWeatherMultipleDays(LocationDatePeriod request, StreamObserver<CityWeatherData> responseObserver) {
var startDate = request.getStartDate();
var endDate = request.getEndDate();
allWeatherData.stream()
.filter(cityWeatherData -> cityWeatherData.getLocationDate().getLocation().equals(request.getLocation()))
.filter(cityWeatherData -> compareDate(cityWeatherData.getLocationDate().getDate(),startDate) >= 0)
.filter(cityWeatherData -> compareDate(cityWeatherData.getLocationDate().getDate(),endDate) <= 0)
.forEach(responseObserver::onNext);
responseObserver.onCompleted();
}
```
#### For returning an object which contains array of other objects (stupid???)
```java
public void getAlbumMetadata(EntitiesRequest request, StreamObserver<Albums> responseObserver) {
Albums.Builder albumsBuilder = Albums.newBuilder();
for(int i = 0; i < request.getIdCount();i++) {
// Find the album by its id
Album album = database.findAlbumById(request.getId(i));
if(album != null) {
albumsBuilder.addAlbum(album);
}
}
// In case that an album isn't found builder builds empty list
Albums albums = albumsBuilder.build();
responseObserver.onNext(albums);
responseObserver.onCompleted();
}
```
## Client Side
#### Setup
The **blocking stub** is a placeholder on which the functions are called. It needs to be received from the gRPC object in some way.
```java
public WeatherClient(Channel channel) {
// Get blocking stub from the gRPC object
blockingStub = WeatherReporterGrpc.newBlockingStub(channel);
}
```
or
```java
public SpotifyClient(Channel channel) {
// spotifyConnection is a wrapper defined in the excercise
// this is just an example that there can be other ways to get the stub
this.spotifyConnection = new SpotifyConnection(channel);
this.blockingStub = spotifyConnection.getStub();
}
```
#### Calling method with ***single object*** return value
```java
public void getCityWeatherSingleDay(int day, int month, int year, String city, String country) {
// Need to use builders to create the objects for the request
Date date = Date.newBuilder().setDay(day).setMonth(month).setYear(year).build();
Location location = Location.newBuilder().setCity(city).setCountry(country).build();
// Building the locationDate which will be passed as a parameter
LocationDate locationDate = LocationDate.newBuilder().setDate(date).setLocation(location).build();
// Getting the returned object from calling the method on the stub
CityWeatherData cityWeatherData = blockingStub.getCityWeatherSingleDay(locationDate);
System.out.println(cityWeatherData.toString());
}
```
#### Calling method which returns ***stream***
```java
public void getCityWeatherMultipleDays(int startDay, int startMonth, int startYear, int endDay, int endMonth, int endYear, String city, String country) {
// Building objects for the request
Date startDate = Date.newBuilder()
.setDay(startDay)
.setMonth(startMonth)
.setYear(startYear)
.build();
Date endDate = Date.newBuilder()
.setDay(endDay)
.setMonth(endMonth)
.setYear(endYear)
.build();
Location location = Location.newBuilder().setCity(city).setCountry(country).build();
// Building LocationDatePeriod object to be passed as parameter
LocationDatePeriod locationDatePeriod = LocationDatePeriod.newBuilder()
.setStartDate(startDate)
.setEndDate(endDate)
.setLocation(location)
.build();
// Method call returns Iterator<CityWeatherData> for the stream of CityWeatherData
Iterator<CityWeatherData> iterator = blockingStub.getCityWeatherMultipleDays(locationDatePeriod);
// Iterating over the objects
while (iterator.hasNext()) {
CityWeatherData cityWeatherData = iterator.next();
System.out.println(cityWeatherData.toString());
}
}
```
#### Calling method which has *parameter with **repeated** field*
```java
public String displayPlaylist(int[] playlist) throws SpotifyClientException {
StringBuilder stringBuilder = new StringBuilder();
EntitiesRequest.Builder builder = EntitiesRequest.newBuilder();
// IMPORTANT for REPEATED fields
// Add all id's to request
for(int id : playlist) {
builder.addId(id);
}
EntitiesRequest request = builder.build();
// Unlike in earlier examplese returns OBJECT which contains multiple Tracks
Tracks tracks;
tracks = blockingStub.getTrackMetadata(request);
if(tracks.getTrackCount() != playlist.length) throw new SpotifyClientException("Failed to get track metadata");
for(int i = 0; i < tracks.getTrackCount();i++) {
Track track = tracks.getTrack(i);
int durationInSeconds = track.getDuration();
int durationInMinutes = durationInSeconds / 60;
durationInSeconds = durationInSeconds % 60;
stringBuilder.append(String.format("%d. %s - %s (%d:%02d)%n", i+1,track.getName(), track.getArtist(), durationInMinutes, durationInSeconds));
}
return stringBuilder.toString();
}
```
<div class="page-break"></div>
## ALL RESOURCE LINKS:
- **Lecture slides (PDF)**
- **Your own homework solutions (cloned)**
- **Cheat-sheets/self-written notes (printed/on paper/PDF)**
- **C reference:** https://en.cppreference.com/w/c/language
- **Python reference:** https://docs.python.org/3/reference/index.html
- **Java reference:** https://www.baeldung.com/get-started-with-java-series
- **Java reference:** https://docs.oracle.com/en/java/javase/22/
- **gRPC reference:** https://grpc.io/docs/
- **Spotbugs**: https://spotbugs.readthedocs.io
- **AddressSanitizer**: https://gcc.gnu.org/onlinedocs/gcc/Instrumentation-Options.html
- **Spring Boot:** https://www.baeldung.com/spring-boot
- **Spring Boot:** https://spring.io/projects/spring-boot
- **Docker:** https://docs.docker.com/
- **JavaFX:** https://openjfx.io/openjfx-docs
- **Gradle:** https://docs.gradle.org/current/userguide/userguide.html
- **Git:** https://git-scm.com/docs
- **JUnit:** https://junit.org/junit5/docs/current/user-guide/
- **Mockito:** https://javadoc.io/doc/org.mockito/mockito-core/latest/org/mockito/Mockito.html
- **EasyMock:** https://easymock.org/user-guide.html
- **man pages (command line, not online)**
<div class="page-break"></div>
Binary file not shown.
Binary file not shown.
+79
View File
@@ -0,0 +1,79 @@
- [ ] **Lecture 1:**
- [x] L01PE01
- [ ] **Lecture 2:**
- [x] L02PB01
- [x] L02PB02
- [x] L02P01
- [x] L02P02
- [x] L02PE01
- [x] L02PE02
- [x] L02PE03
- [ ] **Lecture 3:**
- [x] L03PB01
- [x] L03PB02
- [x] L03P01
- [ ] L03P02
- [ ] L03PE01
- [ ] L03PE02
- [ ] L03PE03
- [ ] L03PE04
- [ ] **Lecture 4:**
- [ ] L04PB01
- [ ] L04PB02
- [ ] L04P01
- [ ] L04P02
- [ ] L04PE01
- [ ] L04PE02
- [ ] L04PE03
- [ ] L04PE04
- [ ] L04PE05
- [ ] **Lecture 5:**
- [ ] L05PB01
- [ ] L05PB02
- [ ] L05P01
- [ ] L05P02
- [ ] L05P03
- [ ] L05PE01
- [ ] L05PE02
- [ ] L05PE03
- [ ] Lecture 6:
- [ ] L06PB01
- [ ] L06PB02
- [ ] L06P01
- [ ] L06P02
- [ ] L06PE01
- [ ] L06PE02
- [ ] L06PE03
- [ ] Lecture 7:
- [ ] L07PB01
- [ ] L07PB02
- [ ] L07P01
- [ ] L07P02
- [ ] L07PE01
- [ ] L07PE02
- [ ] L07PE03
- [ ] Lecture 8:
- [ ] L08PB01
- [ ] L08PB02
- [ ] L08P01
- [ ] L08P02
- [ ] L08PE01
- [ ] L08PE02
- [ ] L08PE03
- [ ] L08PE04
- [ ] Lecture 9:
- [ ] L09PB01
- [ ] L09PB02
- [ ] L09P01
- [ ] L09P02
- [ ] L09PE01
- [ ] L09PE02
- [ ] L09PE03
- [ ] Lecture 10:
- [ ] L10PE01
+366
View File
@@ -0,0 +1,366 @@
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" lang="" xml:lang="">
<head>
<meta charset="utf-8" />
<meta name="generator" content="pandoc" />
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes" />
<title>EIST CHEATSHEET</title>
<style>
code{white-space: pre-wrap;}
span.smallcaps{font-variant: small-caps;}
div.columns{display: flex; gap: min(4vw, 1.5em);}
div.column{flex: auto; overflow-x: auto;}
div.hanging-indent{margin-left: 1.5em; text-indent: -1.5em;}
/* The extra [class] is a hack that increases specificity enough to
override a similar rule in reveal.js */
ul.task-list[class]{list-style: none;}
ul.task-list li input[type="checkbox"] {
font-size: inherit;
width: 0.8em;
margin: 0 0.8em 0.2em -1.6em;
vertical-align: middle;
}
.display.math{display: block; text-align: center; margin: 0.5rem auto;}
/* CSS for syntax highlighting */
html { -webkit-text-size-adjust: 100%; }
pre > code.sourceCode { white-space: pre; position: relative; }
pre > code.sourceCode > span { display: inline-block; line-height: 1.25; }
pre > code.sourceCode > span:empty { height: 1.2em; }
.sourceCode { overflow: visible; }
code.sourceCode > span { color: inherit; text-decoration: inherit; }
div.sourceCode { margin: 1em 0; }
pre.sourceCode { margin: 0; }
@media screen {
div.sourceCode { overflow: auto; }
}
@media print {
pre > code.sourceCode { white-space: pre-wrap; }
pre > code.sourceCode > span { text-indent: -5em; padding-left: 5em; }
}
pre.numberSource code
{ counter-reset: source-line 0; }
pre.numberSource code > span
{ position: relative; left: -4em; counter-increment: source-line; }
pre.numberSource code > span > a:first-child::before
{ content: counter(source-line);
position: relative; left: -1em; text-align: right; vertical-align: baseline;
border: none; display: inline-block;
-webkit-touch-callout: none; -webkit-user-select: none;
-khtml-user-select: none; -moz-user-select: none;
-ms-user-select: none; user-select: none;
padding: 0 4px; width: 4em;
color: #aaaaaa;
}
pre.numberSource { margin-left: 3em; border-left: 1px solid #aaaaaa; padding-left: 4px; }
div.sourceCode
{ }
@media screen {
pre > code.sourceCode > span > a:first-child::before { text-decoration: underline; }
}
code span.al { color: #ff0000; font-weight: bold; } /* Alert */
code span.an { color: #60a0b0; font-weight: bold; font-style: italic; } /* Annotation */
code span.at { color: #7d9029; } /* Attribute */
code span.bn { color: #40a070; } /* BaseN */
code span.bu { color: #008000; } /* BuiltIn */
code span.cf { color: #007020; font-weight: bold; } /* ControlFlow */
code span.ch { color: #4070a0; } /* Char */
code span.cn { color: #880000; } /* Constant */
code span.co { color: #60a0b0; font-style: italic; } /* Comment */
code span.cv { color: #60a0b0; font-weight: bold; font-style: italic; } /* CommentVar */
code span.do { color: #ba2121; font-style: italic; } /* Documentation */
code span.dt { color: #902000; } /* DataType */
code span.dv { color: #40a070; } /* DecVal */
code span.er { color: #ff0000; font-weight: bold; } /* Error */
code span.ex { } /* Extension */
code span.fl { color: #40a070; } /* Float */
code span.fu { color: #06287e; } /* Function */
code span.im { color: #008000; font-weight: bold; } /* Import */
code span.in { color: #60a0b0; font-weight: bold; font-style: italic; } /* Information */
code span.kw { color: #007020; font-weight: bold; } /* Keyword */
code span.op { color: #666666; } /* Operator */
code span.ot { color: #007020; } /* Other */
code span.pp { color: #bc7a00; } /* Preprocessor */
code span.sc { color: #4070a0; } /* SpecialChar */
code span.ss { color: #bb6688; } /* SpecialString */
code span.st { color: #4070a0; } /* String */
code span.va { color: #19177c; } /* Variable */
code span.vs { color: #4070a0; } /* VerbatimString */
code span.wa { color: #60a0b0; font-weight: bold; font-style: italic; } /* Warning */
</style>
<link rel="stylesheet" href="obsidian.css" />
</head>
<body>
<nav id="TOC" role="doc-toc">
<ul>
<li><a href="#list-of-contents" id="toc-list-of-contents">List of
contents</a>
<ul>
<li><a href="#making-rest-api-requests"
id="toc-making-rest-api-requests">Making REST API Requests</a>
<ul>
<li><a href="#just-in-case-webclient-constructor"
id="toc-just-in-case-webclient-constructor">Just in case: webClient
Constructor</a></li>
</ul></li>
</ul></li>
<li><a href="#docker" id="toc-docker">DOCKER</a>
<ul>
<li><a href="#dockerfiles" id="toc-dockerfiles">Dockerfiles</a></li>
<li><a href="#building-docker" id="toc-building-docker">Building
docker</a></li>
<li><a href="#docker-processes" id="toc-docker-processes">Docker
processes</a></li>
</ul></li>
<li><a href="#grpc" id="toc-grpc">gRPC</a>
<ul>
<li><a href="#implementing-grpc-server-methods"
id="toc-implementing-grpc-server-methods">Implementing gRPC server
methods</a></li>
<li><a href="#all-resource-links" id="toc-all-resource-links">ALL
RESOURCE LINKS:</a></li>
</ul></li>
</ul>
</nav>
<h1 id="list-of-contents">List of contents</h1>
<ol type="1">
<li>[[#Making REST API Requests]]</li>
<li>[[#DOCKER]]</li>
<li>[[#gRPC]]</li>
</ol>
<h2 id="making-rest-api-requests">Making REST API Requests</h2>
<h4 id="get">GET</h4>
<div class="sourceCode" id="cb1"><pre
class="sourceCode java"><code class="sourceCode java"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a><span class="kw">public</span> <span class="dt">void</span> <span class="fu">getAllPersons</span><span class="op">(</span>CustomerSortingOptions sortingOptions<span class="op">,</span> Consumer<span class="op">&lt;</span><span class="bu">List</span><span class="op">&lt;</span>Customer<span class="op">&gt;&gt;</span> customerConsumer<span class="op">)</span> <span class="op">{</span></span>
<span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a> webClient<span class="op">.</span><span class="fu">get</span><span class="op">()</span></span>
<span id="cb1-3"><a href="#cb1-3" aria-hidden="true" tabindex="-1"></a> <span class="op">.</span><span class="fu">uri</span><span class="op">(</span>uriBuilder <span class="op">-&gt;</span> uriBuilder</span>
<span id="cb1-4"><a href="#cb1-4" aria-hidden="true" tabindex="-1"></a> <span class="op">.</span><span class="fu">path</span><span class="op">(</span><span class="st">&quot;customers&quot;</span><span class="op">)</span></span>
<span id="cb1-5"><a href="#cb1-5" aria-hidden="true" tabindex="-1"></a> <span class="op">.</span><span class="fu">queryParam</span><span class="op">(</span><span class="st">&quot;sortField&quot;</span><span class="op">,</span> sortingOptions<span class="op">.</span><span class="fu">getSortField</span><span class="op">())</span></span>
<span id="cb1-6"><a href="#cb1-6" aria-hidden="true" tabindex="-1"></a> <span class="op">.</span><span class="fu">queryParam</span><span class="op">(</span><span class="st">&quot;sortingOrder&quot;</span><span class="op">,</span> sortingOptions<span class="op">.</span><span class="fu">getSortingOrder</span><span class="op">())</span></span>
<span id="cb1-7"><a href="#cb1-7" aria-hidden="true" tabindex="-1"></a> <span class="op">.</span><span class="fu">build</span><span class="op">())</span></span>
<span id="cb1-8"><a href="#cb1-8" aria-hidden="true" tabindex="-1"></a> <span class="op">.</span><span class="fu">retrieve</span><span class="op">()</span></span>
<span id="cb1-9"><a href="#cb1-9" aria-hidden="true" tabindex="-1"></a> <span class="op">.</span><span class="fu">bodyToMono</span><span class="op">(</span><span class="kw">new</span> ParameterizedTypeReference<span class="op">&lt;</span><span class="bu">List</span><span class="op">&lt;</span>Customer<span class="op">&gt;&gt;()</span> <span class="op">{</span></span>
<span id="cb1-10"><a href="#cb1-10" aria-hidden="true" tabindex="-1"></a> <span class="op">})</span></span>
<span id="cb1-11"><a href="#cb1-11" aria-hidden="true" tabindex="-1"></a> <span class="op">.</span><span class="fu">onErrorStop</span><span class="op">()</span></span>
<span id="cb1-12"><a href="#cb1-12" aria-hidden="true" tabindex="-1"></a> <span class="op">.</span><span class="fu">subscribe</span><span class="op">(</span>newPersons <span class="op">-&gt;</span> <span class="op">{</span></span>
<span id="cb1-13"><a href="#cb1-13" aria-hidden="true" tabindex="-1"></a> customers<span class="op">.</span><span class="fu">clear</span><span class="op">();</span></span>
<span id="cb1-14"><a href="#cb1-14" aria-hidden="true" tabindex="-1"></a> customers<span class="op">.</span><span class="fu">addAll</span><span class="op">(</span>newPersons<span class="op">);</span></span>
<span id="cb1-15"><a href="#cb1-15" aria-hidden="true" tabindex="-1"></a> customerConsumer<span class="op">.</span><span class="fu">accept</span><span class="op">(</span>customers<span class="op">);</span></span>
<span id="cb1-16"><a href="#cb1-16" aria-hidden="true" tabindex="-1"></a> <span class="op">});</span></span>
<span id="cb1-17"><a href="#cb1-17" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span></code></pre></div>
<h4 id="post">POST</h4>
<div class="sourceCode" id="cb2"><pre
class="sourceCode java"><code class="sourceCode java"><span id="cb2-1"><a href="#cb2-1" aria-hidden="true" tabindex="-1"></a><span class="kw">public</span> <span class="dt">void</span> <span class="fu">addPerson</span><span class="op">(</span>Customer customer<span class="op">,</span> Consumer<span class="op">&lt;</span><span class="bu">List</span><span class="op">&lt;</span>Customer<span class="op">&gt;&gt;</span> customerConsumer<span class="op">)</span> <span class="op">{</span></span>
<span id="cb2-2"><a href="#cb2-2" aria-hidden="true" tabindex="-1"></a> <span class="co">// </span><span class="al">TODO</span><span class="co"> Part 2: Complete the http post request to the server</span></span>
<span id="cb2-3"><a href="#cb2-3" aria-hidden="true" tabindex="-1"></a> webClient<span class="op">.</span><span class="fu">post</span><span class="op">()</span></span>
<span id="cb2-4"><a href="#cb2-4" aria-hidden="true" tabindex="-1"></a> <span class="op">.</span><span class="fu">uri</span><span class="op">(</span><span class="st">&quot;customers&quot;</span><span class="op">)</span></span>
<span id="cb2-5"><a href="#cb2-5" aria-hidden="true" tabindex="-1"></a> <span class="op">.</span><span class="fu">bodyValue</span><span class="op">(</span>customer<span class="op">)</span></span>
<span id="cb2-6"><a href="#cb2-6" aria-hidden="true" tabindex="-1"></a> <span class="op">.</span><span class="fu">retrieve</span><span class="op">()</span></span>
<span id="cb2-7"><a href="#cb2-7" aria-hidden="true" tabindex="-1"></a> <span class="op">.</span><span class="fu">bodyToMono</span><span class="op">(</span>Customer<span class="op">.</span><span class="fu">class</span><span class="op">)</span></span>
<span id="cb2-8"><a href="#cb2-8" aria-hidden="true" tabindex="-1"></a> <span class="op">.</span><span class="fu">onErrorStop</span><span class="op">()</span></span>
<span id="cb2-9"><a href="#cb2-9" aria-hidden="true" tabindex="-1"></a> <span class="op">.</span><span class="fu">subscribe</span><span class="op">(</span>newCustomer <span class="op">-&gt;</span> <span class="op">{</span></span>
<span id="cb2-10"><a href="#cb2-10" aria-hidden="true" tabindex="-1"></a> customers<span class="op">.</span><span class="fu">add</span><span class="op">(</span>newCustomer<span class="op">);</span></span>
<span id="cb2-11"><a href="#cb2-11" aria-hidden="true" tabindex="-1"></a> customerConsumer<span class="op">.</span><span class="fu">accept</span><span class="op">(</span>customers<span class="op">);</span></span>
<span id="cb2-12"><a href="#cb2-12" aria-hidden="true" tabindex="-1"></a> <span class="op">});</span></span>
<span id="cb2-13"><a href="#cb2-13" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<h4 id="put">PUT</h4>
<div class="sourceCode" id="cb3"><pre
class="sourceCode java"><code class="sourceCode java"><span id="cb3-1"><a href="#cb3-1" aria-hidden="true" tabindex="-1"></a><span class="kw">public</span> <span class="dt">void</span> <span class="fu">updatePerson</span><span class="op">(</span>Customer customer<span class="op">,</span> Consumer<span class="op">&lt;</span><span class="bu">List</span><span class="op">&lt;</span>Customer<span class="op">&gt;&gt;</span> customerConsumer<span class="op">)</span> <span class="op">{</span></span>
<span id="cb3-2"><a href="#cb3-2" aria-hidden="true" tabindex="-1"></a> <span class="co">// </span><span class="al">TODO</span><span class="co"> Part 2: Complete the http put request to the server</span></span>
<span id="cb3-3"><a href="#cb3-3" aria-hidden="true" tabindex="-1"></a> webClient<span class="op">.</span><span class="fu">put</span><span class="op">()</span></span>
<span id="cb3-4"><a href="#cb3-4" aria-hidden="true" tabindex="-1"></a> <span class="op">.</span><span class="fu">uri</span><span class="op">(</span><span class="st">&quot;customers/&quot;</span> <span class="op">+</span> customer<span class="op">.</span><span class="fu">getId</span><span class="op">())</span></span>
<span id="cb3-5"><a href="#cb3-5" aria-hidden="true" tabindex="-1"></a> <span class="op">.</span><span class="fu">bodyValue</span><span class="op">(</span>customer<span class="op">)</span></span>
<span id="cb3-6"><a href="#cb3-6" aria-hidden="true" tabindex="-1"></a> <span class="op">.</span><span class="fu">retrieve</span><span class="op">()</span></span>
<span id="cb3-7"><a href="#cb3-7" aria-hidden="true" tabindex="-1"></a> <span class="op">.</span><span class="fu">bodyToMono</span><span class="op">(</span>Customer<span class="op">.</span><span class="fu">class</span><span class="op">)</span></span>
<span id="cb3-8"><a href="#cb3-8" aria-hidden="true" tabindex="-1"></a> <span class="op">.</span><span class="fu">onErrorStop</span><span class="op">()</span></span>
<span id="cb3-9"><a href="#cb3-9" aria-hidden="true" tabindex="-1"></a> <span class="op">.</span><span class="fu">subscribe</span><span class="op">(</span>newCustomer <span class="op">-&gt;</span> <span class="op">{</span></span>
<span id="cb3-10"><a href="#cb3-10" aria-hidden="true" tabindex="-1"></a> customers<span class="op">.</span><span class="fu">replaceAll</span><span class="op">(</span>x <span class="op">-&gt;</span> x<span class="op">.</span><span class="fu">getId</span><span class="op">().</span><span class="fu">equals</span><span class="op">(</span>customer<span class="op">.</span><span class="fu">getId</span><span class="op">())</span> <span class="op">?</span> newCustomer <span class="op">:</span> x<span class="op">);</span></span>
<span id="cb3-11"><a href="#cb3-11" aria-hidden="true" tabindex="-1"></a> customerConsumer<span class="op">.</span><span class="fu">accept</span><span class="op">(</span>customers<span class="op">);</span></span>
<span id="cb3-12"><a href="#cb3-12" aria-hidden="true" tabindex="-1"></a> <span class="op">});</span></span>
<span id="cb3-13"><a href="#cb3-13" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<h4 id="delete">DELETE</h4>
<div class="sourceCode" id="cb4"><pre
class="sourceCode java"><code class="sourceCode java"><span id="cb4-1"><a href="#cb4-1" aria-hidden="true" tabindex="-1"></a><span class="kw">public</span> <span class="dt">void</span> <span class="fu">deletePerson</span><span class="op">(</span>Customer customer<span class="op">,</span> Consumer<span class="op">&lt;</span><span class="bu">List</span><span class="op">&lt;</span>Customer<span class="op">&gt;&gt;</span> customerConsumer<span class="op">)</span> <span class="op">{</span></span>
<span id="cb4-2"><a href="#cb4-2" aria-hidden="true" tabindex="-1"></a> <span class="co">// </span><span class="al">TODO</span><span class="co"> Part 2: Make an http delete request to the server</span></span>
<span id="cb4-3"><a href="#cb4-3" aria-hidden="true" tabindex="-1"></a> webClient<span class="op">.</span><span class="fu">delete</span><span class="op">()</span></span>
<span id="cb4-4"><a href="#cb4-4" aria-hidden="true" tabindex="-1"></a> <span class="op">.</span><span class="fu">uri</span><span class="op">(</span><span class="st">&quot;customers/&quot;</span> <span class="op">+</span> customer<span class="op">.</span><span class="fu">getId</span><span class="op">())</span></span>
<span id="cb4-5"><a href="#cb4-5" aria-hidden="true" tabindex="-1"></a> <span class="op">.</span><span class="fu">retrieve</span><span class="op">()</span></span>
<span id="cb4-6"><a href="#cb4-6" aria-hidden="true" tabindex="-1"></a> <span class="op">.</span><span class="fu">toBodilessEntity</span><span class="op">()</span></span>
<span id="cb4-7"><a href="#cb4-7" aria-hidden="true" tabindex="-1"></a> <span class="op">.</span><span class="fu">onErrorStop</span><span class="op">()</span></span>
<span id="cb4-8"><a href="#cb4-8" aria-hidden="true" tabindex="-1"></a> <span class="op">.</span><span class="fu">subscribe</span><span class="op">(</span>deletedCustomer <span class="op">-&gt;</span> <span class="op">{</span></span>
<span id="cb4-9"><a href="#cb4-9" aria-hidden="true" tabindex="-1"></a> customers<span class="op">.</span><span class="fu">remove</span><span class="op">(</span>customer<span class="op">);</span></span>
<span id="cb4-10"><a href="#cb4-10" aria-hidden="true" tabindex="-1"></a> customerConsumer<span class="op">.</span><span class="fu">accept</span><span class="op">(</span>customers<span class="op">);</span></span>
<span id="cb4-11"><a href="#cb4-11" aria-hidden="true" tabindex="-1"></a> <span class="op">});</span></span>
<span id="cb4-12"><a href="#cb4-12" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<h3 id="just-in-case-webclient-constructor">Just in case: webClient
Constructor</h3>
<div class="sourceCode" id="cb5"><pre
class="sourceCode java"><code class="sourceCode java"><span id="cb5-1"><a href="#cb5-1" aria-hidden="true" tabindex="-1"></a><span class="kw">public</span> <span class="fu">CustomerController</span><span class="op">()</span> <span class="op">{</span></span>
<span id="cb5-2"><a href="#cb5-2" aria-hidden="true" tabindex="-1"></a> <span class="kw">this</span><span class="op">.</span><span class="fu">webClient</span> <span class="op">=</span> WebClient<span class="op">.</span><span class="fu">builder</span><span class="op">()</span></span>
<span id="cb5-3"><a href="#cb5-3" aria-hidden="true" tabindex="-1"></a> <span class="op">.</span><span class="fu">baseUrl</span><span class="op">(</span><span class="st">&quot;http://localhost:8080/&quot;</span><span class="op">)</span></span>
<span id="cb5-4"><a href="#cb5-4" aria-hidden="true" tabindex="-1"></a> <span class="op">.</span><span class="fu">defaultHeader</span><span class="op">(</span>HttpHeaders<span class="op">.</span><span class="fu">ACCEPT</span><span class="op">,</span> MediaType<span class="op">.</span><span class="fu">APPLICATION_JSON_VALUE</span><span class="op">)</span></span>
<span id="cb5-5"><a href="#cb5-5" aria-hidden="true" tabindex="-1"></a> <span class="op">.</span><span class="fu">defaultHeader</span><span class="op">(</span>HttpHeaders<span class="op">.</span><span class="fu">CONTENT_TYPE</span><span class="op">,</span> MediaType<span class="op">.</span><span class="fu">APPLICATION_JSON_VALUE</span><span class="op">)</span></span>
<span id="cb5-6"><a href="#cb5-6" aria-hidden="true" tabindex="-1"></a> <span class="op">.</span><span class="fu">build</span><span class="op">();</span></span>
<span id="cb5-7"><a href="#cb5-7" aria-hidden="true" tabindex="-1"></a> <span class="kw">this</span><span class="op">.</span><span class="fu">customers</span> <span class="op">=</span> <span class="kw">new</span> <span class="bu">ArrayList</span><span class="op">&lt;&gt;();</span></span>
<span id="cb5-8"><a href="#cb5-8" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<div class="page-break">
</div>
<h1 id="docker">DOCKER</h1>
<p><strong>Docker reference: https://docs.docker.com/</strong></p>
<h3 id="dockerfiles">Dockerfiles</h3>
<p>https://docs.docker.com/get-started/docker-concepts/building-images/writing-a-dockerfile/
https://docs.docker.com/reference/dockerfile/</p>
<div class="sourceCode" id="cb6"><pre
class="sourceCode dockerfile"><code class="sourceCode dockerfile"><span id="cb6-1"><a href="#cb6-1" aria-hidden="true" tabindex="-1"></a><span class="kw">FROM</span> python:3.13</span>
<span id="cb6-2"><a href="#cb6-2" aria-hidden="true" tabindex="-1"></a><span class="kw">WORKDIR</span> /usr/local/app</span>
<span id="cb6-3"><a href="#cb6-3" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-4"><a href="#cb6-4" aria-hidden="true" tabindex="-1"></a><span class="co"># Install the application dependencies</span></span>
<span id="cb6-5"><a href="#cb6-5" aria-hidden="true" tabindex="-1"></a><span class="kw">COPY</span> requirements.txt ./</span>
<span id="cb6-6"><a href="#cb6-6" aria-hidden="true" tabindex="-1"></a><span class="kw">RUN</span> <span class="ex">pip</span> install <span class="at">--no-cache-dir</span> <span class="at">-r</span> requirements.txt</span>
<span id="cb6-7"><a href="#cb6-7" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-8"><a href="#cb6-8" aria-hidden="true" tabindex="-1"></a><span class="co"># Copy in the source code</span></span>
<span id="cb6-9"><a href="#cb6-9" aria-hidden="true" tabindex="-1"></a><span class="kw">COPY</span> src ./src</span>
<span id="cb6-10"><a href="#cb6-10" aria-hidden="true" tabindex="-1"></a><span class="kw">EXPOSE</span> 8080</span>
<span id="cb6-11"><a href="#cb6-11" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-12"><a href="#cb6-12" aria-hidden="true" tabindex="-1"></a><span class="co"># Setup an app user so the container doesn&#39;t run as the root user</span></span>
<span id="cb6-13"><a href="#cb6-13" aria-hidden="true" tabindex="-1"></a><span class="kw">RUN</span> <span class="ex">useradd</span> app</span>
<span id="cb6-14"><a href="#cb6-14" aria-hidden="true" tabindex="-1"></a><span class="kw">USER</span> app</span>
<span id="cb6-15"><a href="#cb6-15" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-16"><a href="#cb6-16" aria-hidden="true" tabindex="-1"></a><span class="kw">CMD</span> [<span class="st">&quot;uvicorn&quot;</span>, <span class="st">&quot;app.main:app&quot;</span>, <span class="st">&quot;--host&quot;</span>, <span class="st">&quot;0.0.0.0&quot;</span>, <span class="st">&quot;--port&quot;</span>, <span class="st">&quot;8080&quot;</span>]</span></code></pre></div>
<h3 id="building-docker">Building docker</h3>
<div class="sourceCode" id="cb7"><pre
class="sourceCode bash"><code class="sourceCode bash"><span id="cb7-1"><a href="#cb7-1" aria-hidden="true" tabindex="-1"></a><span class="ex">docker</span> build <span class="at">-t</span> <span class="op">&lt;</span>tag<span class="op">&gt;</span></span></code></pre></div>
<h3 id="docker-processes">Docker processes</h3>
<div class="sourceCode" id="cb8"><pre
class="sourceCode bash"><code class="sourceCode bash"><span id="cb8-1"><a href="#cb8-1" aria-hidden="true" tabindex="-1"></a><span class="ex">docker</span> ps</span></code></pre></div>
<h4 id="exercises">Exercises</h4>
<ul>
<li><a
href="file:///home/nikola/Documents/EIST/eist26l09p01-go38coz">L09P01 -
Registry Office Service Deployment</a></li>
<li><a
href="file:///home/nikola/Documents/EIST/eist26l09p02-go38coz">L09P02 -
Garching Best Software</a></li>
<li><a
href="file:///home/nikola/Documents/EIST/eist26l0pe04-go38coz">L08PE04 -
Spaceship</a></li>
</ul>
<div class="page-break">
</div>
<h1 id="grpc">gRPC</h1>
<p><strong>gRPC reference: https://grpc.io/docs/</strong> <strong>gRPC
Java basics: https://grpc.io/docs/languages/java/basics/</strong></p>
<h4 id="defining-classes">Defining classes:</h4>
<div class="sourceCode" id="cb9"><pre
class="sourceCode protobuf"><code class="sourceCode protobuf"><span id="cb9-1"><a href="#cb9-1" aria-hidden="true" tabindex="-1"></a><span class="kw">message</span> Date {</span>
<span id="cb9-2"><a href="#cb9-2" aria-hidden="true" tabindex="-1"></a> <span class="dt">int32</span> day <span class="op">=</span> <span class="dv">1</span>; <span class="co">// Number specifies order</span></span>
<span id="cb9-3"><a href="#cb9-3" aria-hidden="true" tabindex="-1"></a> <span class="dt">int32</span> month <span class="op">=</span> <span class="dv">2</span>;</span>
<span id="cb9-4"><a href="#cb9-4" aria-hidden="true" tabindex="-1"></a> <span class="dt">int32</span> year <span class="op">=</span> <span class="dv">3</span>;</span>
<span id="cb9-5"><a href="#cb9-5" aria-hidden="true" tabindex="-1"></a>}</span>
<span id="cb9-6"><a href="#cb9-6" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb9-7"><a href="#cb9-7" aria-hidden="true" tabindex="-1"></a><span class="kw">message</span> Location {</span>
<span id="cb9-8"><a href="#cb9-8" aria-hidden="true" tabindex="-1"></a> <span class="dt">string</span> city <span class="op">=</span> <span class="dv">1</span>;</span>
<span id="cb9-9"><a href="#cb9-9" aria-hidden="true" tabindex="-1"></a> <span class="dt">string</span> country <span class="op">=</span> <span class="dv">2</span>;</span>
<span id="cb9-10"><a href="#cb9-10" aria-hidden="true" tabindex="-1"></a>}</span>
<span id="cb9-11"><a href="#cb9-11" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb9-12"><a href="#cb9-12" aria-hidden="true" tabindex="-1"></a><span class="kw">message</span> LocationDate {</span>
<span id="cb9-13"><a href="#cb9-13" aria-hidden="true" tabindex="-1"></a> Location location <span class="op">=</span> <span class="dv">1</span>;</span>
<span id="cb9-14"><a href="#cb9-14" aria-hidden="true" tabindex="-1"></a> Date date <span class="op">=</span> <span class="dv">2</span>;</span>
<span id="cb9-15"><a href="#cb9-15" aria-hidden="true" tabindex="-1"></a>}</span></code></pre></div>
<h4 id="defining-services">Defining services:</h4>
<div class="sourceCode" id="cb10"><pre
class="sourceCode protobuf"><code class="sourceCode protobuf"><span id="cb10-1"><a href="#cb10-1" aria-hidden="true" tabindex="-1"></a><span class="kw">service</span> WeatherReporter {</span>
<span id="cb10-2"><a href="#cb10-2" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb10-3"><a href="#cb10-3" aria-hidden="true" tabindex="-1"></a> <span class="co">//Returning one object</span></span>
<span id="cb10-4"><a href="#cb10-4" aria-hidden="true" tabindex="-1"></a> <span class="kw">rpc</span> GetCityWeatherSingleDay(LocationDate) <span class="kw">returns</span> (CityWeatherData) {}</span>
<span id="cb10-5"><a href="#cb10-5" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb10-6"><a href="#cb10-6" aria-hidden="true" tabindex="-1"></a> <span class="co">// Returning a stream of objects</span></span>
<span id="cb10-7"><a href="#cb10-7" aria-hidden="true" tabindex="-1"></a> <span class="kw">rpc</span> GetCityWeatherMultipleDays(LocationDatePeriod) <span class="kw">returns</span> (stream CityWeatherData) {}</span>
<span id="cb10-8"><a href="#cb10-8" aria-hidden="true" tabindex="-1"></a>}</span></code></pre></div>
<h4 id="generating-classes-from-.proto-files">Generating classes from
<em>.proto</em> files</h4>
<ol type="1">
<li>Gradle tab in IDE and press “Tasks &gt; other &gt;
generateProto”)</li>
<li>The generated classes from the proto file should be in
build/generated/source/proto/main folder</li>
</ol>
<h3 id="implementing-grpc-server-methods">Implementing gRPC server
methods</h3>
<p>In practice can be done with streams or with simple iteration</p>
<div class="sourceCode" id="cb11"><pre
class="sourceCode java"><code class="sourceCode java"><span id="cb11-1"><a href="#cb11-1" aria-hidden="true" tabindex="-1"></a><span class="kw">public</span> <span class="dt">void</span> <span class="fu">getCityWeatherSingleDay</span><span class="op">(</span>LocationDate request<span class="op">,</span> StreamObserver<span class="op">&lt;</span>CityWeatherData<span class="op">&gt;</span> responseObserver<span class="op">)</span> <span class="op">{</span></span>
<span id="cb11-2"><a href="#cb11-2" aria-hidden="true" tabindex="-1"></a> <span class="dt">var</span> data <span class="op">=</span> allWeatherData<span class="op">.</span><span class="fu">stream</span><span class="op">().</span><span class="fu">filter</span><span class="op">(</span>cityWeatherData <span class="op">-&gt;</span> cityWeatherData<span class="op">.</span><span class="fu">getLocationDate</span><span class="op">().</span><span class="fu">equals</span><span class="op">(</span>request<span class="op">)).</span><span class="fu">findFirst</span><span class="op">().</span><span class="fu">orElse</span><span class="op">(</span><span class="kw">null</span><span class="op">);</span></span>
<span id="cb11-3"><a href="#cb11-3" aria-hidden="true" tabindex="-1"></a> <span class="cf">if</span><span class="op">(</span>data <span class="op">!=</span> <span class="kw">null</span><span class="op">)</span>responseObserver<span class="op">.</span><span class="fu">onNext</span><span class="op">(</span>data<span class="op">);</span></span>
<span id="cb11-4"><a href="#cb11-4" aria-hidden="true" tabindex="-1"></a> responseObserver<span class="op">.</span><span class="fu">onCompleted</span><span class="op">();</span></span>
<span id="cb11-5"><a href="#cb11-5" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<p>For returning a <em>stream</em> of data just call onNext multiple
times:</p>
<h5 id="with-iteration">With iteration</h5>
<div class="sourceCode" id="cb12"><pre
class="sourceCode java"><code class="sourceCode java"><span id="cb12-1"><a href="#cb12-1" aria-hidden="true" tabindex="-1"></a><span class="kw">public</span> <span class="dt">void</span> <span class="fu">getCityWeatherMultipleDays</span><span class="op">(</span>LocationDatePeriod request<span class="op">,</span> StreamObserver<span class="op">&lt;</span>CityWeatherData<span class="op">&gt;</span> responseObserver<span class="op">)</span> <span class="op">{</span></span>
<span id="cb12-2"><a href="#cb12-2" aria-hidden="true" tabindex="-1"></a> <span class="cf">for</span><span class="op">(</span>CityWeatherData data <span class="op">:</span> allWeatherData<span class="op">)</span> <span class="op">{</span></span>
<span id="cb12-3"><a href="#cb12-3" aria-hidden="true" tabindex="-1"></a> <span class="cf">if</span><span class="op">(</span>data<span class="op">.</span><span class="fu">getLocationDate</span><span class="op">().</span><span class="fu">getLocation</span><span class="op">().</span><span class="fu">equals</span><span class="op">(</span>request<span class="op">.</span><span class="fu">getLocation</span><span class="op">()))</span> <span class="op">{</span></span>
<span id="cb12-4"><a href="#cb12-4" aria-hidden="true" tabindex="-1"></a> <span class="cf">if</span><span class="op">(</span><span class="fu">compareDate</span><span class="op">(</span>data<span class="op">.</span><span class="fu">getLocationDate</span><span class="op">().</span><span class="fu">getDate</span><span class="op">(),</span> request<span class="op">.</span><span class="fu">getStartDate</span><span class="op">())</span> <span class="op">&gt;=</span> <span class="dv">0</span> <span class="op">&amp;&amp;</span> <span class="fu">compareDate</span><span class="op">(</span>data<span class="op">.</span><span class="fu">getLocationDate</span><span class="op">().</span><span class="fu">getDate</span><span class="op">(),</span> request<span class="op">.</span><span class="fu">getEndDate</span><span class="op">())</span> <span class="op">&lt;=</span> <span class="dv">0</span><span class="op">)</span></span>
<span id="cb12-5"><a href="#cb12-5" aria-hidden="true" tabindex="-1"></a> <span class="op">{</span></span>
<span id="cb12-6"><a href="#cb12-6" aria-hidden="true" tabindex="-1"></a> responseObserver<span class="op">.</span><span class="fu">onNext</span><span class="op">(</span>data<span class="op">);</span></span>
<span id="cb12-7"><a href="#cb12-7" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span>
<span id="cb12-8"><a href="#cb12-8" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span>
<span id="cb12-9"><a href="#cb12-9" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span>
<span id="cb12-10"><a href="#cb12-10" aria-hidden="true" tabindex="-1"></a> responseObserver<span class="op">.</span><span class="fu">onCompleted</span><span class="op">();</span></span>
<span id="cb12-11"><a href="#cb12-11" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<h5 id="with-streams">With streams</h5>
<div class="sourceCode" id="cb13"><pre
class="sourceCode java"><code class="sourceCode java"><span id="cb13-1"><a href="#cb13-1" aria-hidden="true" tabindex="-1"></a><span class="kw">public</span> <span class="dt">void</span> <span class="fu">getCityWeatherMultipleDays</span><span class="op">(</span>LocationDatePeriod request<span class="op">,</span> StreamObserver<span class="op">&lt;</span>CityWeatherData<span class="op">&gt;</span> responseObserver<span class="op">)</span> <span class="op">{</span></span>
<span id="cb13-2"><a href="#cb13-2" aria-hidden="true" tabindex="-1"></a> <span class="dt">var</span> startDate <span class="op">=</span> request<span class="op">.</span><span class="fu">getStartDate</span><span class="op">();</span></span>
<span id="cb13-3"><a href="#cb13-3" aria-hidden="true" tabindex="-1"></a> <span class="dt">var</span> endDate <span class="op">=</span> request<span class="op">.</span><span class="fu">getEndDate</span><span class="op">();</span></span>
<span id="cb13-4"><a href="#cb13-4" aria-hidden="true" tabindex="-1"></a> allWeatherData<span class="op">.</span><span class="fu">stream</span><span class="op">()</span></span>
<span id="cb13-5"><a href="#cb13-5" aria-hidden="true" tabindex="-1"></a> <span class="op">.</span><span class="fu">filter</span><span class="op">(</span>cityWeatherData <span class="op">-&gt;</span> cityWeatherData<span class="op">.</span><span class="fu">getLocationDate</span><span class="op">().</span><span class="fu">getLocation</span><span class="op">().</span><span class="fu">equals</span><span class="op">(</span>request<span class="op">.</span><span class="fu">getLocation</span><span class="op">()))</span></span>
<span id="cb13-6"><a href="#cb13-6" aria-hidden="true" tabindex="-1"></a> <span class="op">.</span><span class="fu">filter</span><span class="op">(</span>cityWeatherData <span class="op">-&gt;</span> <span class="fu">compareDate</span><span class="op">(</span>cityWeatherData<span class="op">.</span><span class="fu">getLocationDate</span><span class="op">().</span><span class="fu">getDate</span><span class="op">(),</span>startDate<span class="op">)</span> <span class="op">&gt;=</span> <span class="dv">0</span><span class="op">)</span></span>
<span id="cb13-7"><a href="#cb13-7" aria-hidden="true" tabindex="-1"></a> <span class="op">.</span><span class="fu">filter</span><span class="op">(</span>cityWeatherData <span class="op">-&gt;</span> <span class="fu">compareDate</span><span class="op">(</span>cityWeatherData<span class="op">.</span><span class="fu">getLocationDate</span><span class="op">().</span><span class="fu">getDate</span><span class="op">(),</span>endDate<span class="op">)</span> <span class="op">&lt;=</span> <span class="dv">0</span><span class="op">)</span></span>
<span id="cb13-8"><a href="#cb13-8" aria-hidden="true" tabindex="-1"></a> <span class="op">.</span><span class="fu">forEach</span><span class="op">(</span>responseObserver<span class="op">::</span>onNext<span class="op">);</span></span>
<span id="cb13-9"><a href="#cb13-9" aria-hidden="true" tabindex="-1"></a> responseObserver<span class="op">.</span><span class="fu">onCompleted</span><span class="op">();</span></span>
<span id="cb13-10"><a href="#cb13-10" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<div class="page-break">
</div>
<h2 id="all-resource-links">ALL RESOURCE LINKS:</h2>
<ul>
<li><strong>Lecture slides (PDF)</strong></li>
<li><strong>Your own homework solutions (cloned)</strong></li>
<li><strong>Cheat-sheets/self-written notes (printed/on
paper/PDF)</strong></li>
<li><strong>C reference:</strong>
https://en.cppreference.com/w/c/language</li>
<li><strong>Python reference:</strong>
https://docs.python.org/3/reference/index.html</li>
<li><strong>Java reference:</strong>
https://www.baeldung.com/get-started-with-java-series</li>
<li><strong>Java reference:</strong>
https://docs.oracle.com/en/java/javase/22/</li>
<li><strong>gRPC reference:</strong> https://grpc.io/docs/</li>
<li><strong>Spotbugs</strong>: https://spotbugs.readthedocs.io</li>
<li><strong>AddressSanitizer</strong>:
https://gcc.gnu.org/onlinedocs/gcc/Instrumentation-Options.html</li>
<li><strong>Spring Boot:</strong>
https://www.baeldung.com/spring-boot</li>
<li><strong>Spring Boot:</strong>
https://spring.io/projects/spring-boot</li>
<li><strong>Docker:</strong> https://docs.docker.com/</li>
<li><strong>JavaFX:</strong> https://openjfx.io/openjfx-docs</li>
<li><strong>Gradle:</strong>
https://docs.gradle.org/current/userguide/userguide.html</li>
<li><strong>Git:</strong> https://git-scm.com/docs</li>
<li><strong>JUnit:</strong>
https://junit.org/junit5/docs/current/user-guide/</li>
<li><strong>Mockito:</strong>
https://javadoc.io/doc/org.mockito/mockito-core/latest/org/mockito/Mockito.html</li>
<li><strong>EasyMock:</strong> https://easymock.org/user-guide.html</li>
<li><strong>man pages (command line, not online)</strong>
<div class="page-break">
</div></li>
</ul>
</body>
</html>
Binary file not shown.