everything
5
notes/.obsidian/app.json
vendored
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"legacyEditor": false,
|
||||
"livePreview": true,
|
||||
"readableLineLength": false
|
||||
}
|
||||
4
notes/.obsidian/appearance.json
vendored
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
{
|
||||
"baseFontSize": 18,
|
||||
"accentColor": ""
|
||||
}
|
||||
7
notes/.obsidian/community-plugins.json
vendored
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
[
|
||||
"table-editor-obsidian",
|
||||
"obsidian-excalidraw-plugin",
|
||||
"obsidian-kanban",
|
||||
"obsidian-linter",
|
||||
"obsidian-tabs"
|
||||
]
|
||||
31
notes/.obsidian/core-plugins-migration.json
vendored
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
{
|
||||
"file-explorer": true,
|
||||
"global-search": true,
|
||||
"switcher": true,
|
||||
"graph": true,
|
||||
"backlink": true,
|
||||
"outgoing-link": false,
|
||||
"tag-pane": false,
|
||||
"page-preview": true,
|
||||
"daily-notes": false,
|
||||
"templates": false,
|
||||
"note-composer": true,
|
||||
"command-palette": true,
|
||||
"slash-command": false,
|
||||
"editor-status": true,
|
||||
"starred": false,
|
||||
"markdown-importer": true,
|
||||
"zk-prefixer": false,
|
||||
"random-note": false,
|
||||
"outline": false,
|
||||
"word-count": true,
|
||||
"slides": false,
|
||||
"audio-recorder": false,
|
||||
"workspaces": false,
|
||||
"file-recovery": true,
|
||||
"publish": false,
|
||||
"sync": false,
|
||||
"canvas": true,
|
||||
"bookmarks": true,
|
||||
"properties": true
|
||||
}
|
||||
17
notes/.obsidian/core-plugins.json
vendored
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
[
|
||||
"file-explorer",
|
||||
"global-search",
|
||||
"switcher",
|
||||
"graph",
|
||||
"backlink",
|
||||
"canvas",
|
||||
"properties",
|
||||
"page-preview",
|
||||
"note-composer",
|
||||
"command-palette",
|
||||
"editor-status",
|
||||
"bookmarks",
|
||||
"markdown-importer",
|
||||
"word-count",
|
||||
"file-recovery"
|
||||
]
|
||||
22
notes/.obsidian/graph.json
vendored
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
{
|
||||
"collapse-filter": true,
|
||||
"search": "",
|
||||
"showTags": false,
|
||||
"showAttachments": false,
|
||||
"hideUnresolved": false,
|
||||
"showOrphans": true,
|
||||
"collapse-color-groups": true,
|
||||
"colorGroups": [],
|
||||
"collapse-display": true,
|
||||
"showArrow": false,
|
||||
"textFadeMultiplier": 0,
|
||||
"nodeSizeMultiplier": 1,
|
||||
"lineSizeMultiplier": 1,
|
||||
"collapse-forces": true,
|
||||
"centerStrength": 0.518713248970312,
|
||||
"repelStrength": 10,
|
||||
"linkStrength": 1,
|
||||
"linkDistance": 250,
|
||||
"scale": 1,
|
||||
"close": false
|
||||
}
|
||||
3
notes/.obsidian/hotkeys.json
vendored
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
{
|
||||
"graph:open": []
|
||||
}
|
||||
323222
notes/.obsidian/plugins/obsidian-excalidraw-plugin/data.json
vendored
Normal file
24
notes/.obsidian/plugins/obsidian-excalidraw-plugin/main.js
vendored
Normal file
10
notes/.obsidian/plugins/obsidian-excalidraw-plugin/manifest.json
vendored
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
{
|
||||
"id": "obsidian-excalidraw-plugin",
|
||||
"name": "Excalidraw",
|
||||
"version": "1.7.20",
|
||||
"minAppVersion": "0.15.6",
|
||||
"description": "An Obsidian plugin to edit and view Excalidraw drawings",
|
||||
"author": "Zsolt Viczian",
|
||||
"authorUrl": "https://zsolt.blog",
|
||||
"isDesktopOnly": false
|
||||
}
|
||||
222
notes/.obsidian/plugins/obsidian-excalidraw-plugin/styles.css
vendored
Normal file
|
|
@ -0,0 +1,222 @@
|
|||
.App {
|
||||
font-family: sans-serif;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.excalidraw-wrapper {
|
||||
height: 100%;
|
||||
margin: 0px;
|
||||
background-color: white;
|
||||
}
|
||||
|
||||
.context-menu-option__shortcut {
|
||||
background-color: transparent !important;
|
||||
}
|
||||
|
||||
.block-language-excalidraw {
|
||||
text-align:center;
|
||||
}
|
||||
|
||||
.excalidraw .github-corner {
|
||||
display: none;
|
||||
}
|
||||
|
||||
img.excalidraw-svg-right-wrap {
|
||||
float: right;
|
||||
margin: 0px 0px 20px 20px;
|
||||
}
|
||||
|
||||
img.excalidraw-svg-left-wrap {
|
||||
float: left;
|
||||
margin: 0px 35px 20px 0px;
|
||||
}
|
||||
|
||||
img.excalidraw-svg-right {
|
||||
float: right;
|
||||
}
|
||||
|
||||
.excalidraw-svg-center {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
img.excalidraw-svg-left {
|
||||
float: left;
|
||||
}
|
||||
|
||||
div.excalidraw-svg-right,
|
||||
div.excalidraw-svg-left {
|
||||
display: table;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
button.ToolIcon_type_button[title="Export"] {
|
||||
display:none;
|
||||
}
|
||||
|
||||
.excalidraw-prompt-div {
|
||||
display: flex;
|
||||
max-width: 800px;
|
||||
}
|
||||
|
||||
.excalidraw-prompt-form {
|
||||
display: flex;
|
||||
flex-grow: 1;
|
||||
}
|
||||
|
||||
.excalidraw-prompt-input {
|
||||
flex-grow: 1;
|
||||
}
|
||||
|
||||
li[data-testid] {
|
||||
border: 0 !important;
|
||||
margin: 0 !important;
|
||||
padding: 0 !important;
|
||||
width: 100% !important;
|
||||
}
|
||||
|
||||
.excalidraw .context-menu-option-separator {
|
||||
margin: 4px !important;
|
||||
}
|
||||
|
||||
.excalidraw .popover {
|
||||
padding: 0 !important;
|
||||
border-color: transparent !important;
|
||||
border: 0 !important;
|
||||
box-shadow: 0 !important;
|
||||
background-color: transparent !important;
|
||||
}
|
||||
|
||||
.disable-zen-mode--visible {
|
||||
color: var(--text-primary-color);
|
||||
}
|
||||
|
||||
.disable-zen-mode {
|
||||
width: 9em !important;
|
||||
}
|
||||
|
||||
.ex-coffee-div {
|
||||
text-align: center;
|
||||
margin-bottom: 20px;
|
||||
|
||||
}
|
||||
|
||||
.excalidraw-scriptengine-install td>img {
|
||||
width: 100%;
|
||||
max-width:800px;
|
||||
}
|
||||
|
||||
.excalidraw-scriptengine-install img.coffee {
|
||||
width: 130px;
|
||||
}
|
||||
|
||||
.excalidraw-scriptengine-install tr {
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
.excalidraw-scriptengine-install table {
|
||||
max-width: 130ch;
|
||||
}
|
||||
|
||||
.excalidraw-scriptengine-install td.label {
|
||||
min-width: 11ch;
|
||||
font-weight: bold;
|
||||
padding-right: 5px;
|
||||
}
|
||||
|
||||
.excalidraw-scriptengine-install td.data {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.excalidraw-scriptengine-install .modal-content {
|
||||
max-width: 130ch;
|
||||
user-select: text;
|
||||
}
|
||||
|
||||
.excalidraw-scriptengine-install .modal {
|
||||
max-height:90%;
|
||||
width: auto;
|
||||
}
|
||||
|
||||
.excalidraw-prompt-center {
|
||||
text-align: center !important;
|
||||
}
|
||||
|
||||
.excalidraw-prompt-center button {
|
||||
margin: 0 10px;
|
||||
}
|
||||
|
||||
.excalidraw-prompt-center.filepath {
|
||||
text-align: center;
|
||||
font-weight: bold;
|
||||
margin-bottom: 2em;
|
||||
}
|
||||
|
||||
.excalidraw-dirty {
|
||||
color: red;
|
||||
}
|
||||
|
||||
.workspace-leaf-content .excalidraw-view {
|
||||
padding: 0px 1px; /*1px so on ipad swipe in from left and right still works*/
|
||||
}
|
||||
|
||||
.excalidraw-videoWrapper {
|
||||
max-width:600px
|
||||
}
|
||||
.excalidraw-videoWrapper div {
|
||||
position: relative;
|
||||
padding-bottom: 56.25%;
|
||||
height: 0;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.excalidraw-videoWrapper iframe {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.excalidraw-release .modal-content{
|
||||
padding-right: 5px;
|
||||
margin-right: -5px;
|
||||
user-select: text;
|
||||
}
|
||||
|
||||
.excalidraw-release .modal {
|
||||
max-height: 90%;
|
||||
width: auto;
|
||||
max-width: 130ch;
|
||||
}
|
||||
|
||||
.excalidraw .Island .scrollbar {
|
||||
--scrollbar-thumb-bg: silver;
|
||||
}
|
||||
|
||||
.excalidraw .ToolIcon__icon img{
|
||||
height: 1em;
|
||||
}
|
||||
|
||||
.excalidraw-scriptengine-install tbody>tr>td>div>img {
|
||||
height:20px;
|
||||
background-color: silver;
|
||||
padding: 2px;
|
||||
}
|
||||
|
||||
.excalidraw-scriptengine-install tbody>tr>td>div {
|
||||
width: 50px;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.excalidraw-release p>a>img {
|
||||
width: 100%
|
||||
}
|
||||
|
||||
.excalidraw .context-menu-option {
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
textarea.excalidraw-wysiwyg {
|
||||
border-color: transparent !important;
|
||||
border-radius: 0 !important;
|
||||
}
|
||||
114
notes/.obsidian/plugins/obsidian-kanban/main.js
vendored
Normal file
10
notes/.obsidian/plugins/obsidian-kanban/manifest.json
vendored
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
{
|
||||
"id": "obsidian-kanban",
|
||||
"name": "Kanban",
|
||||
"version": "1.3.20",
|
||||
"minAppVersion": "0.15.3",
|
||||
"description": "Create markdown-backed Kanban boards in Obsidian.",
|
||||
"author": "mgmeyers",
|
||||
"authorUrl": "https://github.com/mgmeyers/obsidian-kanban",
|
||||
"isDesktopOnly": false
|
||||
}
|
||||
1
notes/.obsidian/plugins/obsidian-kanban/styles.css
vendored
Normal file
1986
notes/.obsidian/plugins/obsidian-linter/main.js
vendored
Normal file
10
notes/.obsidian/plugins/obsidian-linter/manifest.json
vendored
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
{
|
||||
"id": "obsidian-linter",
|
||||
"name": "Linter",
|
||||
"version": "1.5.0",
|
||||
"minAppVersion": "0.15.6",
|
||||
"description": "Enforces consistent markdown styling.",
|
||||
"author": "Victor Tao",
|
||||
"authorUrl": "https://github.com/platers",
|
||||
"isDesktopOnly": false
|
||||
}
|
||||
11
notes/.obsidian/plugins/obsidian-tabs/data.json
vendored
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
{
|
||||
"tabEnabled": true,
|
||||
"rowOverflow": false,
|
||||
"horizontalToVertical": false,
|
||||
"hideButtons": true,
|
||||
"smallTitle": false,
|
||||
"compactTitle": false,
|
||||
"tabNumbering": true,
|
||||
"tabUnderline": false,
|
||||
"headerHeight": 29
|
||||
}
|
||||
257
notes/.obsidian/plugins/obsidian-tabs/main.js
vendored
Normal file
10
notes/.obsidian/plugins/obsidian-tabs/manifest.json
vendored
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
{
|
||||
"id": "obsidian-tabs",
|
||||
"name": "Obsidian Tabs",
|
||||
"version": "1.0.7",
|
||||
"minAppVersion": "0.11.13",
|
||||
"description": "Opens new leaves in tabs.",
|
||||
"author": "foreveryone",
|
||||
"authorUrl": "https://github.com/gitobsidiantutorial/obsidian-tabs",
|
||||
"isDesktopOnly": false
|
||||
}
|
||||
303
notes/.obsidian/plugins/obsidian-tabs/styles.css
vendored
Normal file
|
|
@ -0,0 +1,303 @@
|
|||
:root{
|
||||
--headerheight: 29px;
|
||||
}
|
||||
|
||||
.plugin-tabs .mod-root.workspace-split.mod-vertical .workspace-split.mod-vertical,
|
||||
.plugin-tabs .mod-root.workspace-split.mod-vertical{
|
||||
overflow-x: hidden;
|
||||
flex-direction: row;
|
||||
flex-wrap: wrap;
|
||||
align-content: flex-start;
|
||||
align-items: stretch;
|
||||
overflow-y: hidden;
|
||||
--jstabs: 0;
|
||||
--tabs: 10;
|
||||
--rowsjs: 1;
|
||||
--rows1 : 1;
|
||||
--rows : min(var(--rows1),var(--rowsjs));
|
||||
--numtabs : max(var(--jstabs),var(--tabs));
|
||||
--w1 : calc(100% * var(--rows) / var(--numtabs));
|
||||
--w2 : max(20% , 14.5rem/*alter width of tab here*/);
|
||||
}
|
||||
|
||||
.plugin-tabs.rowoverflow .mod-root.workspace-split.mod-vertical .workspace-split.mod-vertical,
|
||||
.plugin-tabs.rowoverflow .mod-root.workspace-split.mod-vertical {
|
||||
--rows1: 2;
|
||||
--rows : min(var(--rows1),var(--rowsjs));
|
||||
--w1 : calc(100% * var(--rows) / var(--numtabs));
|
||||
}
|
||||
|
||||
|
||||
.plugin-tabs .mod-root.workspace-split.mod-vertical .workspace-split.mod-vertical > div.workspace-leaf,
|
||||
.plugin-tabs .mod-root.workspace-split.mod-vertical > div.workspace-leaf {
|
||||
flex-grow: 1;
|
||||
flex-shrink: 1;
|
||||
min-width: var(--w1);
|
||||
max-width: var(--w2);
|
||||
height: var(--headerheight);
|
||||
padding-right: 0px;
|
||||
border-radius: 10px 10px 0px 0px; /* adds a slight rounding to the top corners of a pane header - NOT ESSENTIAL */
|
||||
border: 1px solid var(--background-modifier-border); /* adds a slight outline to the tab header - NOT ESSENTIAL */
|
||||
border-bottom: 0;
|
||||
}
|
||||
|
||||
.plugin-tabs .view-content {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.plugin-tabs .mod-root.workspace-split.mod-vertical > div.workspace-leaf.stayopen .view-header,
|
||||
.plugin-tabs .mod-root.workspace-split.mod-vertical > .workspace-split.mod-vertical > div.workspace-leaf .view-header,
|
||||
.plugin-tabs .mod-root.workspace-split.mod-vertical > div.workspace-leaf.stayopen .view-header{border-left: 1px solid var(--background-modifier-border) } /* adds a slight outline to the main window header - NOT ESSENTIAL */
|
||||
|
||||
.plugin-tabs .mod-root.workspace-split.mod-vertical div .view-header{
|
||||
border-top: 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
.plugin-tabs .mod-root.workspace-split.mod-vertical .workspace-split.mod-vertical > div.workspace-leaf.stayopen,
|
||||
.plugin-tabs .mod-root.workspace-split.mod-vertical > div.workspace-leaf.stayopen,
|
||||
.plugin-tabs .mod-root.workspace-split.mod-vertical .workspace-split.mod-vertical > div.workspace-leaf.stayopen,
|
||||
.plugin-tabs .mod-root.workspace-split.mod-vertical > div.workspace-leaf.stayopen {
|
||||
align-self: stretch;
|
||||
position: absolute;
|
||||
bottom: 0px;
|
||||
order: 99;
|
||||
min-width: 100%;
|
||||
max-width: 100%;
|
||||
min-height: calc(100% - var(--headerheight) * var(--rows));
|
||||
overflow-y: hidden;
|
||||
padding-right: 1px;
|
||||
border-radius: 0;
|
||||
border-left: 0;
|
||||
border-right: 0;
|
||||
border-bottom: 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
.plugin-tabs .mod-root.workspace-split.mod-vertical.maximised .workspace-split.mod-vertical > div.workspace-leaf.stayopen, .mod-root.workspace-split.mod-vertical.maximised > div.workspace-leaf.stayopen {
|
||||
height: 100%!important;
|
||||
top: 0px;
|
||||
border-radius: 10px 0px 0px 0px;
|
||||
border-top: 1px solid var(--background-modifier-border);
|
||||
}
|
||||
.plugin-tabs .maximised .view-header {height: var(--headerheight); border-left: 1px solid var(--background-modifier-border)}
|
||||
|
||||
.plugin-tabs .mod-root.workspace-split.mod-vertical .workspace-split.mod-vertical > div.workspace-leaf:only-of-type,
|
||||
.plugin-tabs .mod-root.workspace-split.mod-vertical > div.workspace-leaf:only-of-type { /*if only one pane open, maximise*/
|
||||
top: 0px;
|
||||
bottom: 0px;
|
||||
height: 100%!important;
|
||||
}
|
||||
|
||||
.plugin-tabs .mod-root.workspace-split.mod-vertical .workspace-leaf .view-header {
|
||||
height: calc(var(--headerheight) + 3px);
|
||||
}
|
||||
|
||||
.plugin-tabs .mod-root.workspace-split.mod-vertical > div.workspace-leaf:only-of-type .view-header {
|
||||
height: var(--headerheight);
|
||||
}
|
||||
|
||||
.plugin-tabs .view-header-title-container::after { /* remove pane header shadows */
|
||||
display:none;
|
||||
}
|
||||
|
||||
/* OPTIONAL */
|
||||
|
||||
/* non pane relief options */
|
||||
|
||||
/* optional feature vertical side-by-side view */
|
||||
.plugin-tabs:not(.horizontal-to-vertical) .mod-root.workspace-split.mod-vertical > .workspace-split.mod-horizontal{
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
.plugin-tabs:not(.horizontal-to-vertical) .mod-root.workspace-split.mod-vertical > .workspace-split.mod-horizontal > * {
|
||||
width: 100%;
|
||||
flex: 1 0 0;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.plugin-tabs:not(.horizontal-to-vertical) .mod-root.workspace-split.mod-vertical > .workspace-split.mod-horizontal > .workspace-leaf:nth-of-type(n+1){
|
||||
border-radius: 10px 10px 0px 0px; /* adds a slight rounding to the top corners of a pane header - NOT ESSENTIAL */
|
||||
border: 1px solid var(--background-modifier-border); /* adds a slight outline to the tab header - NOT ESSENTIAL */
|
||||
border-bottom: 0;
|
||||
border-left: 0;
|
||||
}
|
||||
|
||||
.plugin-tabs:not(.horizontal-to-vertical) .mod-root.workspace-split.mod-vertical > .workspace-split.mod-horizontal .workspace-leaf:nth-of-type(n+1) .view-header {height: var(--headerheight); }
|
||||
|
||||
.plugin-tabs:not(.horizontal-to-vertical) .mod-root.workspace-split.mod-vertical > .workspace-split.mod-horizontal hr.workspace-leaf-resize-handle{
|
||||
display: none
|
||||
}
|
||||
|
||||
/* optional feature increase room for tab title */
|
||||
|
||||
.plugin-tabs:not(.compact-title) .mod-root.workspace-split.mod-vertical .workspace-split.mod-vertical > div.workspace-leaf:not(.stayopen) .view-actions, /*decrease horizontal padding for tab actions to zero*/
|
||||
.mod-root.workspace-split.mod-vertical > div.workspace-leaf:not(.stayopen) .view-actions{
|
||||
padding: 4px 0px;
|
||||
}
|
||||
|
||||
.plugin-tabs:not(.compact-title) .workspace .mod-root.workspace-split.mod-vertical .workspace-split.mod-vertical > div.workspace-leaf.stayopen .view-actions, /*decrease horizontal padding for tab actions to zero*/
|
||||
.workspace .mod-root.workspace-split.mod-vertical > div.workspace-leaf.stayopen .view-actions{
|
||||
padding: 4px 10px;
|
||||
}
|
||||
|
||||
.plugin-tabs:not(.compact-title) .workspace .mod-root.workspace-split.mod-vertical .workspace-split.mod-vertical > div.workspace-leaf.stayopen .view-action.mod-close-leaf, /*decrease margin for close button*/
|
||||
.workspace .mod-root.workspace-split.mod-vertical > div.workspace-leaf.stayopen .view-action.mod-close-leaf{
|
||||
margin-left: 10px;
|
||||
}
|
||||
|
||||
.plugin-tabs:not(.compact-title) .mod-root.workspace-split.mod-vertical .workspace-split.mod-vertical > div.workspace-leaf:not(.stayopen) .view-action.mod-close-leaf, /*decrease margin for close button*/
|
||||
.mod-root.workspace-split.mod-vertical > div.workspace-leaf:not(.stayopen) .view-action.mod-close-leaf{
|
||||
margin-left: 0px;
|
||||
}
|
||||
|
||||
.workspace-leaf .view-header-title{cursor: context-menu}
|
||||
|
||||
div.workspace-leaf.stayopen .view-header-title,
|
||||
div.workspace-leaf.stayopen .view-header-title{cursor: text}
|
||||
|
||||
/* optional feature smaller tab titles */
|
||||
.plugin-tabs:not(.small-title) .mod-root.workspace-split.mod-vertical .workspace-split.mod-vertical > div.workspace-leaf:not(.stayopen) .view-header-title,
|
||||
.plugin-tabs:not(.small-title) .mod-root > div.workspace-leaf:not(.stayopen) .view-header-title,
|
||||
.plugin-tabs:not(.small-title) .mod-root.workspace-split.mod-vertical .workspace-split.mod-vertical > div.workspace-leaf:not(.stayopen) .view-header-title,
|
||||
.plugin-tabs:not(.small-title) .mod-root > div.workspace-leaf:not(.stayopen) .view-header-title{
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
|
||||
.plugin-tabs:not(.small-title) .mod-root.workspace-split.mod-vertical .workspace-split.mod-vertical > div.workspace-leaf.stayopen .view-header-title,
|
||||
.plugin-tabs:not(.small-title) .mod-root.workspace-split.mod-vertical > div.workspace-leaf.stayopen .view-header-title,
|
||||
.plugin-tabs:not(.small-title) .mod-root.workspace-split.mod-vertical .workspace-split.mod-vertical > div.workspace-leaf.stayopen .view-header-title,
|
||||
.plugin-tabs:not(.small-title) .mod-root.workspace-split.mod-vertical > div.workspace-leaf.stayopen .view-header-title{
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* optional feature hide header button, more options, and edit button on tabs */
|
||||
.plugin-tabs:not(.hide-buttons) .mod-root.workspace-split.mod-vertical .workspace-split.mod-vertical > div.workspace-leaf a[aria-label="Edit (Ctrl/Cmd+Click to edit in new pane)"],
|
||||
.plugin-tabs:not(.hide-buttons) .mod-root.workspace-split.mod-vertical .workspace-split.mod-vertical > div.workspace-leaf .view-header-icon,
|
||||
.plugin-tabs:not(.hide-buttons) .mod-root.workspace-split.mod-vertical .workspace-split.mod-vertical > div.workspace-leaf a[aria-label="Preview (Ctrl/Cmd+Click to open in new pane)"],
|
||||
.plugin-tabs:not(.hide-buttons) .mod-root.workspace-split.mod-vertical .workspace-split.mod-vertical > div.workspace-leaf a[aria-label="More options"],
|
||||
.plugin-tabs:not(.hide-buttons) .mod-root.workspace-split.mod-vertical > div.workspace-leaf a[aria-label="Edit (Ctrl/Cmd+Click to edit in new pane)"],
|
||||
.plugin-tabs:not(.hide-buttons) .mod-root.workspace-split.mod-vertical > div.workspace-leaf .view-header-icon,
|
||||
.plugin-tabs:not(.hide-buttons) .mod-root.workspace-split.mod-vertical > div.workspace-leaf a[aria-label="Preview (Ctrl/Cmd+Click to open in new pane)"],
|
||||
.plugin-tabs:not(.hide-buttons) .mod-root.workspace-split.mod-vertical > div.workspace-leaf a[aria-label="More options"]{
|
||||
display: none;
|
||||
}
|
||||
|
||||
.plugin-tabs:not(.hide-buttons) .mod-root.workspace-split.mod-vertical .workspace-split.mod-vertical > div.workspace-leaf.stayopen a[aria-label="Edit (Ctrl/Cmd+Click to edit in new pane)"],
|
||||
.plugin-tabs:not(.hide-buttons) .mod-root.workspace-split.mod-vertical .workspace-split.mod-vertical > div.workspace-leaf.stayopen .view-header-icon,
|
||||
.plugin-tabs:not(.hide-buttons) .mod-root.workspace-split.mod-vertical .workspace-split.mod-vertical > div.workspace-leaf.stayopen a[aria-label="Preview (Ctrl/Cmd+Click to open in new pane)"],
|
||||
.plugin-tabs:not(.hide-buttons) .mod-root.workspace-split.mod-vertical .workspace-split.mod-vertical > div.workspace-leaf.stayopen a[aria-label="More options"],
|
||||
.plugin-tabs:not(.hide-buttons) .mod-root.workspace-split.mod-vertical > div.workspace-leaf.stayopen a[aria-label="Edit (Ctrl/Cmd+Click to edit in new pane)"],
|
||||
.plugin-tabs:not(.hide-buttons) .mod-root.workspace-split.mod-vertical > div.workspace-leaf.stayopen a[aria-label="Preview (Ctrl/Cmd+Click to open in new pane)"],
|
||||
.plugin-tabs:not(.hide-buttons) .mod-root.workspace-split.mod-vertical > div.workspace-leaf.stayopen .view-header-icon,
|
||||
.plugin-tabs:not(.hide-buttons) .mod-root.workspace-split.mod-vertical > div.workspace-leaf.stayopen a[aria-label="More options"],
|
||||
.plugin-tabs:not(.hide-buttons) .mod-root.workspace-split.mod-vertical .workspace-split.mod-vertical > div.workspace-leaf.stayopen a[aria-label="Edit (Ctrl/Cmd+Click to edit in new pane)"],
|
||||
.plugin-tabs:not(.hide-buttons) .mod-root.workspace-split.mod-vertical .workspace-split.mod-vertical > div.workspace-leaf.stayopen .view-header-icon,
|
||||
.plugin-tabs:not(.hide-buttons) .mod-root.workspace-split.mod-vertical .workspace-split.mod-vertical > div.workspace-leaf.stayopen a[aria-label="Preview (Ctrl/Cmd+Click to open in new pane)"],
|
||||
.plugin-tabs:not(.hide-buttons) .mod-root.workspace-split.mod-vertical .workspace-split.mod-vertical > div.workspace-leaf.stayopen a[aria-label="More options"],
|
||||
.plugin-tabs:not(.hide-buttons) .mod-root.workspace-split.mod-vertical > div.workspace-leaf.stayopen a[aria-label="Edit (Ctrl/Cmd+Click to edit in new pane)"],
|
||||
.plugin-tabs:not(.hide-buttons) .mod-root.workspace-split.mod-vertical > div.workspace-leaf.stayopen a[aria-label="Preview (Ctrl/Cmd+Click to open in new pane)"],
|
||||
.plugin-tabs:not(.hide-buttons) .mod-root.workspace-split.mod-vertical > div.workspace-leaf.stayopen .view-header-icon,
|
||||
.plugin-tabs:not(.hide-buttons) .mod-root.workspace-split.mod-vertical > div.workspace-leaf.stayopen a[aria-label="More options"]{
|
||||
display: block;
|
||||
}
|
||||
|
||||
|
||||
/* Pane relief specific options */
|
||||
|
||||
/* optional feature underline next tab [pane relief cycle to next pane hotkey] */
|
||||
.plugin-tabs:not(.tab-underline) .mod-root.workspace-split.mod-vertical .workspace-split.mod-vertical > div.workspace-leaf.stayopen + div.workspace-leaf .view-header-title ,
|
||||
.plugin-tabs:not(.tab-underline) .mod-root.workspace-split.mod-vertical > div.workspace-leaf.stayopen + div.workspace-leaf .view-header-title {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
/* optional feature tab numbers (useful for pane relief shortcuts) */
|
||||
.plugin-tabs:not(.tab-numbering) .mod-root.workspace-split.mod-vertical .workspace-split.mod-vertical:first-of-type > div.workspace-leaf .view-header-title-container, /* first tab container gets numbered from 1-8 */
|
||||
.plugin-tabs:not(.tab-numbering) .mod-root.workspace-split.mod-vertical .workspace-split.mod-vertical:first-of-type > div.workspace-leaf:last-of-type .view-header-title-container,
|
||||
.plugin-tabs:not(.tab-numbering) .mod-root.workspace-split.mod-vertical .workspace-split.mod-vertical:only-of-type > div.workspace-leaf .view-header-title, /* alt+9 jumps to the LAST pane open, rather than the 9th, so only number if this is the only vertical split*/
|
||||
.plugin-tabs:not(.tab-numbering) .mod-root.workspace-split.mod-vertical .workspace-split.mod-vertical:only-of-type > div.workspace-leaf:last-of-type .view-header-title,
|
||||
.plugin-tabs:not(.tab-numbering) .mod-root.workspace-split.mod-vertical div.workspace-leaf .view-header-title,
|
||||
.plugin-tabs:not(.tab-numbering) .mod-root.workspace-split.mod-vertical div.workspace-leaf:last-of-type .view-header-title,
|
||||
.plugin-tabs:not(.tab-numbering) .mod-root.workspace-split.mod-vertical div.workspace-leaf .view-header-title-container,
|
||||
.plugin-tabs:not(.tab-numbering) .mod-root.workspace-split.mod-vertical div.workspace-leaf:last-of-type .view-header-title-container {padding-left: 0px}
|
||||
|
||||
.plugin-tabs:not(.tab-numbering) .mod-root.workspace-split.mod-vertical .workspace-split.mod-vertical:first-of-type > .workspace-leaf:nth-of-type(n+9) .view-header-title,
|
||||
.plugin-tabs:not(.tab-numbering) .mod-root.workspace-split.mod-vertical > .workspace-leaf:nth-of-type(n+9) .view-header-title {padding-left: 5px} /* intentionally less specific, so it gets overridden */
|
||||
|
||||
|
||||
.plugin-tabs:not(.tab-numbering) .mod-root.workspace-split.mod-vertical .workspace-split.mod-vertical:first-of-type > div.workspace-leaf > .workspace-leaf-content > .view-header .view-header-title::before,
|
||||
.plugin-tabs:not(.tab-numbering) .mod-root.workspace-split div.workspace-leaf > .workspace-leaf-content > .view-header .view-header-title::before{
|
||||
counter-reset: variable var(--pane-relief-label);
|
||||
content: counter(variable);
|
||||
padding-top: 2px;
|
||||
display: inline-block;
|
||||
height: calc(var(--headerheight) + 6px);
|
||||
margin-right: 5px;
|
||||
padding: 0 0.4em;
|
||||
width: auto; /* compatibility with mininal */
|
||||
vertical-align: baseline; /* compatibility with mininal */
|
||||
position: static; /* compatibility with mininal */
|
||||
background-color: var(--background-secondary-alt); /* change to appealing colours in your theme */
|
||||
}
|
||||
|
||||
.plugin-tabs:not(.tab-numbering) .mod-root.workspace-split.mod-vertical div.workspace-split.mod-vertical:first-of-type > div.workspace-leaf:nth-of-type(n+9) > .workspace-leaf-content > .view-header .view-header-title::before,
|
||||
.plugin-tabs:not(.tab-numbering) .mod-root.workspace-split.mod-vertical > div.workspace-leaf:nth-of-type(n+9) > .workspace-leaf-content > .view-header .view-header-title::before {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.plugin-tabs:not(.tab-numbering) .mod-root.workspace-split.mod-vertical > div.workspace-split.mod-vertical:first-of-type > div.workspace-leaf:nth-of-type(n+9):last-of-type > .workspace-leaf-content > .view-header .view-header-title::before,
|
||||
.plugin-tabs:not(.tab-numbering) .mod-root.workspace-split.mod-vertical > div.workspace-leaf:nth-of-type(n+9):last-of-type > .workspace-leaf-content > .view-header .view-header-title::before {
|
||||
display: inline-block;
|
||||
content: "9";
|
||||
}
|
||||
|
||||
.plugin-tabs:not(.tab-numbering) .mod-root.workspace-split.mod-vertical .workspace-split.mod-vertical:first-of-type > div.workspace-leaf.stayopen .view-header-title::before,
|
||||
.plugin-tabs:not(.tab-numbering) .mod-root.workspace-split.mod-vertical > div.workspace-leaf.stayopen .view-header-title::before,
|
||||
.plugin-tabs:not(.tab-numbering) .mod-root.workspace-split.mod-vertical .workspace-split.mod-vertical:first-of-type > div.workspace-leaf.stayopen .view-header-title::before,
|
||||
.plugin-tabs:not(.tab-numbering) .mod-root.workspace-split.mod-vertical > div.workspace-leaf.stayopen .view-header-title::before {
|
||||
color: var(--text-muted); /* change to appealing colour in your theme */
|
||||
background-color: var(--background-secondary-alt);
|
||||
margin-left: -0.3em;
|
||||
}
|
||||
|
||||
.plugin-tabs:not(.tab-numbering) .mod-root.workspace-split.mod-vertical .workspace-split.mod-vertical:first-of-type > div.workspace-leaf.stayopen .view-header-icon,
|
||||
.plugin-tabs:not(.tab-numbering) .mod-root.workspace-split.mod-vertical > div.workspace-leaf.stayopen .view-header-icon,
|
||||
.plugin-tabs:not(.tab-numbering) .mod-root.workspace-split.mod-vertical .workspace-split.mod-vertical:first-of-type > div.workspace-leaf.stayopen .view-header-icon,
|
||||
.plugin-tabs:not(.tab-numbering) .mod-root.workspace-split.mod-vertical > div.workspace-leaf.stayopen .view-header-icon {
|
||||
top: 0;
|
||||
padding-top: 6px;
|
||||
padding-right: 5px;
|
||||
background-color: var(--background-secondary-alt); /* make background of icon the same as the tab numbering */
|
||||
}
|
||||
|
||||
.plugin-tabs:not(.tab-numbering) .mod-root.workspace-split.mod-vertical > .workspace-split.mod-horizontal div.workspace-leaf.stayopen:nth-child(n+10) .view-header-icon,
|
||||
.plugin-tabs:not(.tab-numbering) .mod-root.workspace-split.mod-vertical .workspace-split.mod-vertical:first-of-type > div.workspace-leaf.stayopen:nth-child(n+10):not(:last-child) .view-header-icon,
|
||||
.plugin-tabs:not(.tab-numbering) .mod-root.workspace-split.mod-vertical > div.workspace-leaf.stayopen:nth-child(n+10):not(:last-child) .view-header-icon,
|
||||
.plugin-tabs:not(.tab-numbering) .mod-root.workspace-split.mod-vertical > .workspace-split.mod-horizontal div.workspace-leaf.stayopen:nth-child(n+10) .view-header-icon,
|
||||
.plugin-tabs:not(.tab-numbering) .mod-root.workspace-split.mod-vertical .workspace-split.mod-vertical:first-of-type > div.workspace-leaf.stayopen:nth-child(n+10):not(:last-child) .view-header-icon,
|
||||
.plugin-tabs:not(.tab-numbering) .mod-root.workspace-split.mod-vertical > div.workspace-leaf.stayopen:nth-child(n+10):not(:last-child) .view-header-icon {
|
||||
padding-right: 10px;
|
||||
}
|
||||
|
||||
.plugin-tabs:not(.tab-numbering) .mod-root.workspace-split.mod-vertical .workspace-split.mod-horizontal > div.workspace-leaf:first-of-type,
|
||||
.plugin-tabs:not(.tab-numbering) .mod-root.workspace-split.mod-vertical > div.workspace-leaf.stayopen:only-of-type { border-radius: 10px 10px 0px 0px; } /* don't display tab number if only one tab is open */
|
||||
.plugin-tabs:not(.tab-numbering) .mod-root.workspace-split.mod-vertical .workspace-split.mod-horizontal > div.workspace-leaf:first-of-type .view-header-icon,
|
||||
.plugin-tabs:not(.tab-numbering) .mod-root.workspace-split.mod-vertical > div.workspace-leaf.stayopen:only-of-type .view-header-icon{background-color: transparent; margin-right:0.5em;}
|
||||
.plugin-tabs:not(.tab-numbering) .mod-root.workspace-split.mod-vertical .workspace-split.mod-horizontal > div.workspace-leaf:first-of-type .view-header-title::before,
|
||||
.plugin-tabs:not(.tab-numbering) .mod-root.workspace-split.mod-vertical > div.workspace-leaf.stayopen:only-of-type .view-header-title::before { display: none!important; }
|
||||
|
||||
.plugin-tabs:not(.tab-numbering) .mod-root.workspace-split.mod-vertical .workspace-split.mod-horizontal div.workspace-leaf.stayopen .view-header,
|
||||
.plugin-tabs:not(.tab-numbering) .mod-root.workspace-split.mod-vertical.maximised > div.workspace-leaf.stayopen .view-header{
|
||||
border-left-width: 2px;
|
||||
border-top-width: 2px
|
||||
}
|
||||
|
||||
.plugin-tabs .workspace-split.mod-root > .workspace-leaf:last-of-type .workspace-leaf-content,
|
||||
.plugin-tabs .workspace-split.mod-root > .workspace-leaf:first-of-type .workspace-leaf-content {
|
||||
border-radius: 0px!important;
|
||||
}
|
||||
6
notes/.obsidian/plugins/table-editor-obsidian/data.json
vendored
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
{
|
||||
"formatType": "normal",
|
||||
"showRibbonIcon": true,
|
||||
"bindEnter": true,
|
||||
"bindTab": true
|
||||
}
|
||||
24029
notes/.obsidian/plugins/table-editor-obsidian/main.js
vendored
Normal file
11
notes/.obsidian/plugins/table-editor-obsidian/manifest.json
vendored
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
{
|
||||
"id": "table-editor-obsidian",
|
||||
"name": "Advanced Tables",
|
||||
"author": "Tony Grosinger",
|
||||
"authorUrl": "https://grosinger.net",
|
||||
"description": "Improved table navigation, formatting, manipulation, and formulas",
|
||||
"isDesktopOnly": false,
|
||||
"minAppVersion": "0.13.8",
|
||||
"version": "0.17.3",
|
||||
"js": "main.js"
|
||||
}
|
||||
28
notes/.obsidian/plugins/table-editor-obsidian/styles.css
vendored
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
.HyperMD-table-row span.cm-inline-code {
|
||||
font-size: 100%;
|
||||
}
|
||||
|
||||
.widget-icon {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
fill: var(--text-muted);
|
||||
}
|
||||
|
||||
.widget-icon:hover {
|
||||
fill: var(--text-normal);
|
||||
}
|
||||
|
||||
.advanced-tables-csv-export textarea {
|
||||
height: 200px;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.advanced-tables-donation {
|
||||
width: 70%;
|
||||
margin: 0 auto;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.advanced-tables-donate-button {
|
||||
margin: 10px;
|
||||
}
|
||||
112
notes/.obsidian/workspace
vendored
Normal file
|
|
@ -0,0 +1,112 @@
|
|||
{
|
||||
"main": {
|
||||
"id": "0ef873a90d0fc125",
|
||||
"type": "split",
|
||||
"children": [
|
||||
{
|
||||
"id": "8ff82338eb8785ab",
|
||||
"type": "leaf",
|
||||
"state": {
|
||||
"type": "markdown",
|
||||
"state": {
|
||||
"file": "Logbook.md",
|
||||
"mode": "source",
|
||||
"source": false
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"direction": "vertical"
|
||||
},
|
||||
"left": {
|
||||
"id": "08974f7ef61a9ddf",
|
||||
"type": "split",
|
||||
"children": [
|
||||
{
|
||||
"id": "97db7d746bb70a38",
|
||||
"type": "tabs",
|
||||
"children": [
|
||||
{
|
||||
"id": "5b9f6c37d038fe57",
|
||||
"type": "leaf",
|
||||
"state": {
|
||||
"type": "file-explorer",
|
||||
"state": {}
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "0c10f4c866ddee52",
|
||||
"type": "leaf",
|
||||
"state": {
|
||||
"type": "search",
|
||||
"state": {
|
||||
"query": "",
|
||||
"matchingCase": false,
|
||||
"explainSearch": false,
|
||||
"collapseAll": false,
|
||||
"extraContext": false,
|
||||
"sortOrder": "alphabetical"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"direction": "horizontal",
|
||||
"width": 300
|
||||
},
|
||||
"right": {
|
||||
"id": "f24626541fd2e064",
|
||||
"type": "split",
|
||||
"children": [
|
||||
{
|
||||
"id": "38ef544c6894dca2",
|
||||
"type": "tabs",
|
||||
"children": [
|
||||
{
|
||||
"id": "41f7b8edfcd304b6",
|
||||
"type": "leaf",
|
||||
"state": {
|
||||
"type": "backlink",
|
||||
"state": {
|
||||
"file": "Logbook.md",
|
||||
"collapseAll": true,
|
||||
"extraContext": false,
|
||||
"sortOrder": "alphabetical",
|
||||
"showSearch": false,
|
||||
"searchQuery": "",
|
||||
"backlinkCollapsed": false,
|
||||
"unlinkedCollapsed": true
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "3cb821494773a4c7",
|
||||
"type": "leaf",
|
||||
"state": {
|
||||
"type": "advanced-tables-toolbar",
|
||||
"state": {}
|
||||
}
|
||||
}
|
||||
],
|
||||
"currentTab": 1
|
||||
}
|
||||
],
|
||||
"direction": "horizontal",
|
||||
"width": 300,
|
||||
"collapsed": true
|
||||
},
|
||||
"active": "8ff82338eb8785ab",
|
||||
"lastOpenFiles": [
|
||||
"Open -.md",
|
||||
"Open.md",
|
||||
"Excalidraw/email_automatic_ingestion.excalidraw.md",
|
||||
"Excalidraw/Untitled.md",
|
||||
"Logbook.md",
|
||||
"Excalidraw/multicurrency_modeling.excalidraw.md",
|
||||
"Excalidraw/multicurrency_modeling.excalidraw.png",
|
||||
"images/Pasted image 20220929134219.png",
|
||||
"Excalidraw/Orders and users sketches.excalidraw.md",
|
||||
"Excalidraw/Drawing 2022-09-27 16.10.54.excalidraw.md"
|
||||
]
|
||||
}
|
||||
216
notes/.obsidian/workspace.json
vendored
Normal file
|
|
@ -0,0 +1,216 @@
|
|||
{
|
||||
"main": {
|
||||
"id": "0ef873a90d0fc125",
|
||||
"type": "split",
|
||||
"children": [
|
||||
{
|
||||
"id": "1dac7fcc45277d2e",
|
||||
"type": "tabs",
|
||||
"children": [
|
||||
{
|
||||
"id": "6e78bb3078b3797c",
|
||||
"type": "leaf",
|
||||
"state": {
|
||||
"type": "markdown",
|
||||
"state": {
|
||||
"file": "Logbook.md",
|
||||
"mode": "source",
|
||||
"source": false
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "f97f50561dfa9642",
|
||||
"type": "leaf",
|
||||
"state": {
|
||||
"type": "markdown",
|
||||
"state": {
|
||||
"file": "Logbook.md",
|
||||
"mode": "source",
|
||||
"source": false
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "02ee9b525153847e",
|
||||
"type": "leaf",
|
||||
"state": {
|
||||
"type": "excalidraw",
|
||||
"state": {
|
||||
"file": "Excalidraw/Drawing 2023-10-16 16.52.21.excalidraw.md"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "aefa2f87c5560653",
|
||||
"type": "leaf",
|
||||
"state": {
|
||||
"type": "markdown",
|
||||
"state": {
|
||||
"file": "Logbook.md",
|
||||
"mode": "source",
|
||||
"source": false
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "325a307d6e498ed9",
|
||||
"type": "leaf",
|
||||
"state": {
|
||||
"type": "markdown",
|
||||
"state": {
|
||||
"file": "Institut Bitcoin.md",
|
||||
"mode": "source",
|
||||
"source": false
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"currentTab": 4
|
||||
}
|
||||
],
|
||||
"direction": "vertical"
|
||||
},
|
||||
"left": {
|
||||
"id": "08974f7ef61a9ddf",
|
||||
"type": "split",
|
||||
"children": [
|
||||
{
|
||||
"id": "97db7d746bb70a38",
|
||||
"type": "tabs",
|
||||
"children": [
|
||||
{
|
||||
"id": "5b9f6c37d038fe57",
|
||||
"type": "leaf",
|
||||
"state": {
|
||||
"type": "file-explorer",
|
||||
"state": {
|
||||
"sortOrder": "alphabetical"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "0c10f4c866ddee52",
|
||||
"type": "leaf",
|
||||
"state": {
|
||||
"type": "search",
|
||||
"state": {
|
||||
"query": "",
|
||||
"matchingCase": false,
|
||||
"explainSearch": false,
|
||||
"collapseAll": false,
|
||||
"extraContext": false,
|
||||
"sortOrder": "alphabetical"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "79a08b8f22c9f300",
|
||||
"type": "leaf",
|
||||
"state": {
|
||||
"type": "bookmarks",
|
||||
"state": {}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"direction": "horizontal",
|
||||
"width": 263.5
|
||||
},
|
||||
"right": {
|
||||
"id": "f24626541fd2e064",
|
||||
"type": "split",
|
||||
"children": [
|
||||
{
|
||||
"id": "38ef544c6894dca2",
|
||||
"type": "tabs",
|
||||
"children": [
|
||||
{
|
||||
"id": "41f7b8edfcd304b6",
|
||||
"type": "leaf",
|
||||
"state": {
|
||||
"type": "backlink",
|
||||
"state": {
|
||||
"file": "Institut Bitcoin.md",
|
||||
"collapseAll": true,
|
||||
"extraContext": false,
|
||||
"sortOrder": "alphabetical",
|
||||
"showSearch": false,
|
||||
"searchQuery": "",
|
||||
"backlinkCollapsed": false,
|
||||
"unlinkedCollapsed": true
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "3cb821494773a4c7",
|
||||
"type": "leaf",
|
||||
"state": {
|
||||
"type": "advanced-tables-toolbar",
|
||||
"state": {}
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "b4e57d9fda439a58",
|
||||
"type": "leaf",
|
||||
"state": {
|
||||
"type": "all-properties",
|
||||
"state": {
|
||||
"sortOrder": "frequency"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"currentTab": 1
|
||||
}
|
||||
],
|
||||
"direction": "horizontal",
|
||||
"width": 300,
|
||||
"collapsed": true
|
||||
},
|
||||
"left-ribbon": {
|
||||
"hiddenItems": {
|
||||
"switcher:Open quick switcher": false,
|
||||
"graph:Open graph view": false,
|
||||
"canvas:Create new canvas": false,
|
||||
"command-palette:Open command palette": false,
|
||||
"markdown-importer:Open format converter": false,
|
||||
"table-editor-obsidian:Advanced Tables Toolbar": false,
|
||||
"obsidian-excalidraw-plugin:New Excalidraw drawing": false
|
||||
}
|
||||
},
|
||||
"active": "325a307d6e498ed9",
|
||||
"lastOpenFiles": [
|
||||
"Great Expectations Lifecycle.md",
|
||||
"Logbook.md",
|
||||
"Ideas.md",
|
||||
"Institut Bitcoin.md",
|
||||
"Excalidraw/Drawing 2023-10-16 16.52.21.excalidraw.md",
|
||||
"other/Order Bundling White Paper.md",
|
||||
"Excalidraw/Drawing 2023-09-29 16.09.36.excalidraw.md",
|
||||
"Excalidraw/Untitled.md",
|
||||
"Excalidraw/Drawing 2023-09-22 11.13.37.excalidraw.md",
|
||||
"Excalidraw/Drawing 2023-09-21 11.57.45.excalidraw.md",
|
||||
"images/Pasted image 20230215102943.png",
|
||||
"images/Pasted image 20230810114231.png",
|
||||
"images/Pasted image 20230809115157.png",
|
||||
"images/Pasted image 20230809113546.png",
|
||||
"images/New Office - Guidelines.pdf",
|
||||
"ChatGPT Prompts.md",
|
||||
"other/travel expenses.md",
|
||||
"Excalidraw/Drawing 2023-04-19 13.38.39.excalidraw.md",
|
||||
"Excalidraw/Drawing 2022-12-02 13.40.38.excalidraw.md",
|
||||
"other/My development.md",
|
||||
"other/Prefect Flow Checklist.md",
|
||||
"other/ideas for team meet up on sept-22.md",
|
||||
"desktop.ini",
|
||||
"Excalidraw/grid.md",
|
||||
"blog/README.md",
|
||||
"blog/trino-in-lolamarket.md",
|
||||
"images/ge_alert_example.png",
|
||||
"images/money-shop.gif",
|
||||
"blog/great-expectations-in-lolamarket.md",
|
||||
"Untitled.canvas"
|
||||
]
|
||||
}
|
||||
19
notes/ChatGPT Prompts.md
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
|
||||
**GREAT EXPECTATIONS CONFIGS**
|
||||
- Okay, we are going to work together. Here is some context for you to be aware of. We will be writing code for a Prefect 1 flow. We are using Great Expectations to evaluate some data on a MySQL database.
|
||||
Here is an example:
|
||||
ExpectationConfiguration(
|
||||
expectation_type="expect_column_values_to_be_between",
|
||||
kwargs={"column": "delivery_price", "min_value": 0},
|
||||
meta={"notes": "The delivery price should never be negative."},
|
||||
)
|
||||
|
||||
|
||||
**DOCSTRINGS**
|
||||
- You are going to help me improve some python snippets. Every time I show you a function, I want you to:
|
||||
- Add docstrings if they are missing
|
||||
- Add type hints to the function arguments and return. If you can't clearly infer what type is the right one, just leave a blank space for me to fill.
|
||||
- If the code doesn't follow the same style as the Black python formatter, modify it so it does.
|
||||
- The docstrings should be in reStructuredText format.
|
||||
- Never add the :type: entries to the reStructuredText docstrings.
|
||||
- Everytime I want you to do this for a python snippet, I will say: "fix this snippet"
|
||||
50308
notes/Excalidraw/Drawing 2022-12-02 13.40.38.excalidraw.md
Normal file
14179
notes/Excalidraw/Drawing 2023-04-19 13.38.39.excalidraw.md
Normal file
2201
notes/Excalidraw/Drawing 2023-09-21 11.57.45.excalidraw.md
Normal file
15
notes/Excalidraw/Drawing 2023-09-22 11.13.37.excalidraw.md
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
---
|
||||
|
||||
excalidraw-plugin: parsed
|
||||
tags: [excalidraw]
|
||||
|
||||
---
|
||||
==⚠ Switch to EXCALIDRAW VIEW in the MORE OPTIONS menu of this document. ⚠==
|
||||
|
||||
|
||||
%%
|
||||
# Drawing
|
||||
```json
|
||||
{"type":"excalidraw","version":2,"source":"https://excalidraw.com","elements":[],"appState":{"gridSize":null,"viewBackgroundColor":"#ffffff"}}
|
||||
```
|
||||
%%
|
||||
8513
notes/Excalidraw/Drawing 2023-09-29 16.09.36.excalidraw.md
Normal file
15
notes/Excalidraw/Drawing 2023-10-16 16.52.21.excalidraw.md
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
---
|
||||
|
||||
excalidraw-plugin: parsed
|
||||
tags: [excalidraw]
|
||||
|
||||
---
|
||||
==⚠ Switch to EXCALIDRAW VIEW in the MORE OPTIONS menu of this document. ⚠==
|
||||
|
||||
|
||||
%%
|
||||
# Drawing
|
||||
```json
|
||||
{"type":"excalidraw","version":2,"source":"https://excalidraw.com","elements":[],"appState":{"gridSize":null,"viewBackgroundColor":"#ffffff"}}
|
||||
```
|
||||
%%
|
||||
43657
notes/Excalidraw/Orders and users sketches.excalidraw.md
Normal file
0
notes/Excalidraw/Untitled.md
Normal file
5580
notes/Excalidraw/early_stages_architecture_trino.excalidraw.md
Normal file
BIN
notes/Excalidraw/early_stages_architecture_trino.excalidraw.png
Normal file
|
After Width: | Height: | Size: 1.5 MiB |
25984
notes/Excalidraw/email_automatic_ingestion.excalidraw.md
Normal file
111647
notes/Excalidraw/great_expectations_lifecycle.excalidraw.md
Normal file
65741
notes/Excalidraw/grid.md
Normal file
223558
notes/Excalidraw/multicurrency_modeling.excalidraw.md
Normal file
16
notes/Excalidraw/multicurrency_modeling.excalidraw.svg
Normal file
|
After Width: | Height: | Size: 3.6 MiB |
44485
notes/Excalidraw/mysql8-and-looker-connection-theater.md
Normal file
230183
notes/Excalidraw/order_status_refactor.excalidraw.md
Normal file
16
notes/Excalidraw/order_status_refactor.excalidraw.svg
Normal file
|
After Width: | Height: | Size: 4.2 MiB |
42
notes/Great Expectations Lifecycle.md
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
ddd
|
||||
This document explains how we tackle the different parts of the Great Expectations Lifecycle.
|
||||
|
||||
## The Lifecycle
|
||||
|
||||
The lifecycle we refer to encompasses all the steps from deciding that you need to recurrently validate data somewhere to decomissioning the validation. It encompasses three main stages:
|
||||
- The setup: deciding what is expected of the data, designing the checkpoint, testing it out and putting it into production.
|
||||
- The operation and iteration: operating your data validation and updating it across time as business and data environments change.
|
||||
- The teardown: decomissioning a data validation that is no longer needed.
|
||||
|
||||
|
||||
## Setup
|
||||
|
||||
Setting up data validation on an ETL or other automated job means creating a new Great Expectations checkpoint. Having datasources and expectations suites configured and ready to use are prerequisites to creating the checkpoint.
|
||||
|
||||
### Creating a Datasource
|
||||
|
||||
|
||||
### Creating an Expectation Suite
|
||||
|
||||
|
||||
## Creating a Checkpoint
|
||||
|
||||
## Operation and Iteration
|
||||
|
||||
### Integrating the checkpoint in a Prefect Flow
|
||||
- Staging and quarantine strategy
|
||||
- Using transactions to rollback
|
||||
- Slack alerts
|
||||
- Checking validation docs after failure
|
||||
|
||||
|
||||
###
|
||||
|
||||
|
||||
|
||||
## Glossary
|
||||
|
||||
| Term | Meaning |
|
||||
| ---------- | ---------------------------------------------------------------------------------------------------- |
|
||||
| Checkpoint | A recipe that ties together datasources, expectation suites and actions to execute after validating. |
|
||||
| | |
|
||||
7
notes/Ideas.md
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
# Ideas
|
||||
|
||||
- [ ] Partnership with buynomics to provide data for pricing engine.
|
||||
- [ ] Automate the documentation of ETL flows
|
||||
- [ ] Automate the documentation of DW schema
|
||||
- [ ] Set up a git server, pypi server and use proper packages and software re-usage to have high software quality in ETLs and prevent a collapse down the line.
|
||||
- [ ] Set up automated Data Quality checks with great-expectations on datasources and ETL staging areas
|
||||
74
notes/Institut Bitcoin.md
Normal file
|
|
@ -0,0 +1,74 @@
|
|||
|
||||
If Bitcoin is to be adopted at scale, a massive education obstacle is to be overcome. Barcelona has around 2 million inhabitants, and someone is going to have to teach them what is Bitcoin, why they need it and how to use it.
|
||||
|
||||
Institut Bitcoin is a plan to make this happen and make money along the way.
|
||||
# Case for it
|
||||
|
||||
Early adopters of Bitcoin tend to fit within a few distinctive profiles: the nerdy software engineer, the anarcocapitalist minded economist, the wealthy tax evader, etc. These profiles are not frequent at all in society. Most people in society have no clue on how a computer works, don't give a damn about the inner workings of monetary systems and surely don't spend their lives reflecting on the social and political implications of central banking and contending cryptocurrencies.
|
||||
|
||||
Normal people will adopt Bitcoin if they see a simple case for how it benefits them, and will want to use it in the most simple and effortless way.
|
||||
|
||||
Currently, learning about Bitcoin is hard. Most of the early adopters have learned through self-driven, independent research. With no one to guide them, they have spent thousands of hours consuming material and composing their own improvised content curriculums. The reward is deep knowledge, but the question is: are we expecting all the population to go through this process? The reality is this approach is not scalable at all.
|
||||
|
||||
The education and training sector in Barcelona is rotten to the core. Decades of state sponsored education systems have left us with a decaying public system and a weakened private sector. Schools and universities models are completely outdated, completely out of touch with reality and completely ineffective. Students know it, parents know it and even professors know it. There is no way on earth that this system is capable of bringing the much required Bitcoin education and training that the city needs.
|
||||
|
||||
Institut Bitcoin is a proposal to build an educational organization to onboard mainstream society to Bitcoin in the simplest and friendliest way.
|
||||
|
||||
|
||||
# Goals
|
||||
|
||||
Create a company that offers education and training services to wide audiences in Barcelona with a focus on practical Bitcoin knowledge for normal users. The company should provide basic training to 1,000 students before 2024 ends, 10,000 before 2025 ends and 50,000 students before 2026 ends.
|
||||
|
||||
|
||||
# Strategy and philosophy
|
||||
|
||||
- Complete detachment of public services and state education.
|
||||
- Innovation through the use of IT and fundamental questioning of all traditional methods.
|
||||
- Wide range of quality offerings to cater all economical and social levels of society.
|
||||
- Design value flows with generous, incentive based designs that promote high quality and effort by teachers. Shared risk, shared reward.
|
||||
- Decentralized nature to allow rapid growth, a rich and varied services offer and resilience against state attacks.
|
||||
|
||||
To avoid:
|
||||
- Imitating traditional school and university education.
|
||||
- Providing education services that has no differential case against existing options in the market.
|
||||
- Falling in the temptation of collaborating with the state and public education.
|
||||
- Generate a centralized structure
|
||||
|
||||
# Phases
|
||||
|
||||
## Phase 1
|
||||
|
||||
- Get a few workshops in place and hold them regularly.
|
||||
- Create a simple brand and web to start generating an identity and reputation.
|
||||
- Rely heavily on BBO for spaces, knowledge and teachers.
|
||||
- Work in the fiscal shadows.
|
||||
|
||||
|
||||
## Phase 2
|
||||
- Reduce dependency from BBO.
|
||||
- Improve IT infrastructure.
|
||||
- Potentially step out of the fiscal shadows and register as business.
|
||||
- Step beyond individual workshops. Create student profiles, learning paths/mini degrees.
|
||||
- Go out and market hard.
|
||||
- Work together with Prometea and other Spanish content makers to build Spanish-targeted content.
|
||||
|
||||
|
||||
## Phase 3
|
||||
|
||||
|
||||
|
||||
# Training spectrum
|
||||
|
||||
- 1-to-1 tailored training by OG
|
||||
- Small group trainings with structured curriculum and high intensity learning
|
||||
- Large scale classes, university style
|
||||
- Self-paced, unsupervised online courses
|
||||
- Curated indexes of quality content
|
||||
|
||||
|
||||
# Stakeholders
|
||||
|
||||
|
||||
- Teaching staff
|
||||
- Audit, brand and central services
|
||||
- Sales funnel owners
|
||||
4223
notes/Logbook.md
Normal file
53
notes/blog/README.md
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
|
||||
This repo stores blog entries from the Lolamarket Engineering Blog.
|
||||
|
||||
Series:
|
||||
- Prefect series
|
||||
- How we use Prefect
|
||||
- Our Prefect deployment
|
||||
- Where Prefect shines
|
||||
- Where Prefect doesn't shine
|
||||
- How to organize flows
|
||||
- DRY and our complementary toolbox
|
||||
- Great Expectations series
|
||||
- [x] GE in Lolamarket
|
||||
- Our deployment with AWS and Slack
|
||||
- Data Contracts with backend
|
||||
- Where GE shines
|
||||
- Where GE doesn't shine
|
||||
- Trino series
|
||||
- [x] Trino in Lolamarket
|
||||
- Challenges we have faced with Trino
|
||||
- Where Trino shines
|
||||
- Where Trino doesn't shine
|
||||
- Tips and tricks when working with Trino
|
||||
- Differences between Trino SQL and MySQL SQL
|
||||
- How our deployment looks like
|
||||
- Looker series
|
||||
- How we use Looker
|
||||
- Migrating from Metabase to Looker
|
||||
- Why Looker beats other visualization tools
|
||||
- Challenges we have faced with Looker
|
||||
- Interviewing series
|
||||
- How we do interviews
|
||||
- How to prepare for an interview
|
||||
- Business-oriented series
|
||||
- Year 2022 in numbers
|
||||
- Airbyte series
|
||||
- Airbyte in Lolamarket
|
||||
- Deployment of Airbyte
|
||||
- Where Airbyte shines
|
||||
- Where Airbyte does not shine
|
||||
-
|
||||
|
||||
|
||||
|
||||
---
|
||||
## ChatGPT context helper
|
||||
|
||||
A few things for you to take into account:
|
||||
- I work as a Data Engineer.
|
||||
- My company is called Lolamarket.
|
||||
- This post will be published in the our tech and engineering blog.
|
||||
- The purpose of the post is to show to the world how we use our technologies, hopefully impressing and seducing potential candidates for technical positions.
|
||||
- I want to post to showcase a great technical skill and knowledge.
|
||||
80
notes/blog/great-expectations-in-lolamarket.md
Normal file
|
|
@ -0,0 +1,80 @@
|
|||
---
|
||||
title: "Great Expectations in Lolamarket"
|
||||
slug: "great-expectations-in-lolamarket"
|
||||
tags: "stack,data,great expectations,data quality"
|
||||
author: "Pablo Martin"
|
||||
---
|
||||
|
||||
# Great Expectations in Lolamarket
|
||||
|
||||
Hi there, and welcome to the start of a new series in our blog: the Great Expectation series. In these series, we will discuss how we use Great Expectations, a data quality package.
|
||||
|
||||
|
||||
## Introducing Great Expectations
|
||||
|
||||
As a data engineer, ensuring the quality of your data is crucial to the success of your company's applications. Unfortunately, it can be challenging to make sure that your data is accurate, complete, and consistent, especially as the number of data sources grows. At Lolamarket, we have faced several problems related to data quality, such as bad data slipping into our data warehouse unnoticed, pipelines breaking due to bad data, and no centralized documentation for tables and what the data in them should look like. These challenges inspired us to seek a solution that would help us ensure the quality of our data, and that's where Great Expectations comes in.
|
||||
|
||||

|
||||
|
||||
[Great Expectations](https://greatexpectations.io/) is an open-source tool for ensuring data quality that has become increasingly popular in the data engineering and analytics communities. It comes in the form of a [Python package](https://pypi.org/project/great-expectations/). The tool is designed to help data teams set, manage, and validate expectations for their data across all of their pipelines, and ensure that their data meets those expectations. With Great Expectations, data teams can proactively monitor their data, detect issues before they become critical, and quickly respond to data-related problems.
|
||||
|
||||
Great Expectations is a flexible tool that can be used in a variety of settings, including data warehousing, ETL pipelines, and analytics workflows. It supports a wide range of data sources, including SQL databases, NoSQL databases, and data lakes. The tool is also highly customizable, with a flexible API that allows data teams to create and execute their tests, integrate with other tools in their data stack, and extend the tool's functionality.
|
||||
|
||||
## The problems that come with bad data
|
||||
|
||||
At Lolamarket, we faced a number of problems related to data quality. These are common problems that any other data team can face and will probably feel familiar if you work in the industry.
|
||||
|
||||
One of the biggest problems we faced was that bad data would sometimes slip into our data warehouse silently, without anyone noticing. This caused significant problems downstream, as the business would see incorrect data in our data products. This led to poor decisions being made and a lack of trust in our data arose. It was frustrating and caused us to waste time and resources.
|
||||
|
||||
Another challenge we faced was that bad data could also cause an ETL job to fail. This meant that our engineers had to reproduce the faulty environment, including data, to debug the problem. This was a cumbersome and time-consuming process that required a lot of data engineering firepower. We knew we had to find a way to improve our logging capabilities so that, whenever one of these failures would happen, spotting the issue would be as straightforward as possible.
|
||||
|
||||

|
||||
*My colleague trying to rubber-duck with me the ETL failure he has been debugging for 3 days straight.*
|
||||
|
||||
Finally, we realized that without documentation on what our data should look like, new joiners and other colleagues had to ask data team members about it. This added another layer of communication that was not always necessary, and it wasted valuable time that could be spent on more important tasks.
|
||||
|
||||
|
||||
## Using Great Expectations at Lolamarket
|
||||
|
||||
At Lolamarket, we are now using Great Expectations to ensure the quality of the data throughout our infrastructure.
|
||||
|
||||
First and foremost, we use Great Expectations to set expectations for our data at different stages of the ETL pipeline. This includes expectations for our data sources, the transformation logic, and the final data product. By setting these expectations, we can proactively monitor our data, detect issues before they become critical, and ensure that our data meets the criteria we've set. This has been instrumental in helping us catch issues before they impact our applications, which has been critical to the success of our business.
|
||||
|
||||
```python
|
||||
# Add an expectation to the suite that checks if the "age" column contains null values
|
||||
suite.expect_column_values_to_not_be_null("age")
|
||||
|
||||
# Add an expectation to the suite that checks if the "name" column contains any whitespace characters
|
||||
suite.expect_column_values_to_not_match_regex("name", r"\s+")
|
||||
|
||||
# Add an expectation to the suite that checks if the "email" column contains valid email addresses
|
||||
suite.expect_column_values_to_match_regex("email", r"[^@]+@[^@]+\.[^@]+")
|
||||
```
|
||||
*A simple example of how Great Expectations allows you to define what your data should be like.*
|
||||
|
||||
In addition to setting expectations for our data, we also use Great Expectations to quickly notify stakeholders when any of our tests fail. This includes owners of data sources, the owner of the ETL, or internal customers that can be impacted by the issue. By quickly notifying stakeholders, we can reduce the amount of time it takes to identify and fix issues, which ultimately helps us save time and resources.
|
||||
|
||||
Great Expectations also helps us increase the observability of issues, making debugging much easier and reducing the workload of the engineer looking into the issue. By setting up tests at different points of the ETL flow, we can quickly identify where issues are occurring and diagnose the root cause. Also, in some of the data tests we run, we will store the faulty data in a quarantine schema whenever the test fails. This way, we can easily check the data that caused the issue. This makes it easier to identify issues and quickly reach a solution, which has been instrumental in helping us maintain the reliability of our applications.
|
||||
|
||||
![[ge_alert_example.png]]
|
||||
*A example of our beloved Slack alerts bot letting us know that a data test failed.*
|
||||
|
||||
|
||||
## Why we choose Great Expectations
|
||||
|
||||
At Lolamarket, we evaluated a variety of different tools for ensuring data quality before ultimately deciding to go with Great Expectations. While there are many other comparable tools on the market, we ultimately chose Great Expectations for a variety of reasons.
|
||||
|
||||
One of the biggest reasons we chose Great Expectations is its flexibility. The tool is open source and highly customizable, with a flexible API that allows us to create and execute our tests, integrate with other tools in our data stack, and extend the tool's functionality. This has been critical to helping us tailor the tool to our specific needs and integrate it seamlessly into our existing data infrastructure. We really dislike getting locked in with tools that we can't grow if necessary, so Great Expectations had the upper-hand here against commercial alternatives.
|
||||
|
||||
The previous point also leads us to money: Great Expectations didn't come with much of a bill for our team. It played nicely out of the box with our already existing infrastructure and the resource consumption in our cloud is not enough for us to even worry about it. We can say that, besides the time and effort invested in adopting it, Great Expectations didn't really cost us anything. We like to keep things lean.
|
||||
|
||||
![[money-shop.gif]]
|
||||
*Our finance team, counting the money we didn't spend on a Data Quality tool.*
|
||||
|
||||
Another factor that played a big role in our decision to choose Great Expectations is the tool's ease of use. The tool is well-documented, with a variety of resources available that help users get up and running quickly. This has been critical in helping us get the most out of the tool while minimizing the amount of time and resources we need to invest in training our team.
|
||||
|
||||
Finally, the tool plays nicely with our stack. We can easily integrate Great Expectations checkpoints within our Prefect flows since it's just Python. Great Expectations has no trouble reading data from MySQL, which is the most frequent database server in Lolamarket. And configuring an S3 bucket to hold different metadata and logs from Great Expectations was trivial.
|
||||
|
||||
## More to come
|
||||
|
||||
In this post, we've introduced you to Great Expectations, an open-source tool for ensuring data quality, and how we're using it at Lolamarket to overcome data quality problems. In future posts, we'll dive deeper into our use of Great Expectations, including how we deploy it and how we use it to enforce data contracts with our backend teams. We'll also share tips and tricks we've learned along the way. Stay tuned!
|
||||
84
notes/blog/trino-in-lolamarket.md
Normal file
|
|
@ -0,0 +1,84 @@
|
|||
---
|
||||
title: "Trino in Lolamarket"
|
||||
slug: "trino-in-lolamarket"
|
||||
tags: "stack,data,trino"
|
||||
author: "Pablo Martin"
|
||||
---
|
||||
|
||||
# Trino in Lolamarket
|
||||
|
||||
Hi there, and welcome to the start of a new series in our blog: the Trino series. In these series, we will discuss how we use Trino, the distributed query engine, in our company.
|
||||
|
||||
## What is Trino
|
||||
|
||||
If you are familiar with Trino (also known in the past as *Presto*), you can probably skip this section. If that's not the case, stay with us and we will introduce you to it.
|
||||
|
||||

|
||||
|
||||
According to [the official Trino page](https://trino.io/):
|
||||
>Trino is a *fast distributed SQL query engine*.
|
||||
|
||||
There's a lot to unpack in there, so let's break it down:
|
||||
- **Query Engine**: Trino is basically a piece of software that can throw queries at many different databases and get the results back for you. This is an interesting concept because it decouples the storage system you are using from how you query it, allowing you to abstract away its details.
|
||||
- **Distributed**: Trino is designed to be horizontally scalable and follows a [master-slave architecture](https://trino.io/docs/current/overview/concepts.html#server-types). You can have many Trino workers who split the effort of executing your queries. This allows for interesting performance properties, since many queries allow for high degrees of parallelism. It also makes Trino play nicely with distributed storage engines like [Apache Hive](https://hive.apache.org/), which lend themselves to a highly parallelised access to data. Finally, one massive feature that comes with Trino is the ability of executing queries that fetch data across several datasources, even if they run on completely different technologies (picture joining data from MySQL, MongoDB and Hive in a single query).
|
||||
- **SQL**: Trino implements a single SQL interface for all your queries. That means that, regardless of what is the underlying database where you are fetching data from, Trino the same SQL dialect. This means that anyone with SQL knowledge can go ahead and query any database that your Trino has access to, even if the the database is NoSQL.
|
||||
- **Fast**: Trino boasts of neck-breaking query speeds. In our opinion, this claim should come with a few disclaimers since Trino is not a magic wand that will make *anything* run fast as hell. Nevertheless, it is true that Trino can enable very fast queries on large datasets with the right deployment and configuration. We will discuss this point in more detail in further posts of this series.
|
||||
|
||||
That's a lot to take in, eh? If all of this sounds great, it is because it is great. Now, just to make Trino something a bit more tangible in your mind, let us explain a bit how you connect to Trino and make queries. In Lolamarket, we generally connect to Trino in three ways:
|
||||
|
||||
**#1 Through SQL clients**
|
||||
In Lolamarket, one of our go-to SQL clients is [DBeaver](https://dbeaver.io/). In DBeaver, connecting to Trino follows the same steps as connecting to any regular database, and Trino looks and feels like such. Once this is done, you can just query it the same way you would query any other database.
|
||||
|
||||

|
||||
|
||||
**#2 With the Python client**
|
||||
Most of our ETLs are written in Python. Thus, in order to connect to Trino, we use the `trino-python-client` ([github](https://github.com/trinodb/trino-python-client)). This package is compliant with the [Python DBAPI spec](https://peps.python.org/pep-0249/), so it mostly behaves as your usual SQL connector for Python. Since a code example is worth a thousand words, this is the quickstart example from the official repo:
|
||||
|
||||
```python
|
||||
from trino.dbapi import connect
|
||||
|
||||
conn = connect(
|
||||
host="<host>",
|
||||
port=<port>,
|
||||
user="<username>",
|
||||
catalog="<catalog>",
|
||||
schema="<schema>",
|
||||
)
|
||||
cur = conn.cursor()
|
||||
cur.execute("SELECT * FROM system.runtime.nodes")
|
||||
rows = cur.fetchall()
|
||||
```
|
||||
|
||||
**#3 Through Looker**
|
||||
|
||||
[Looker](https://www.looker.com/) is our go-to solution for visualization, reports and dashboards in Lolamarket. Luckily for us, Trino is one of [Looker's supported connectors](https://cloud.google.com/looker/docs/dialects). So, by connecting our Looker instance to Trino, we can build dashboards that fetch data from any of the databases where Trino itself is connected.
|
||||
|
||||
|
||||
|
||||
## Why we chose Trino
|
||||
|
||||
Trino is a complex tool that can suit many different needs and roles. In our case, Trino came into our architecture for one very-specific need and has slowly grown to play a bigger role in our data architecture.
|
||||
|
||||
Without going into much detail on the internals of our app backend, the system behind [Mercadão](https://mercadao.pt/) uses two different databases for persistence: a MongoDB instance and a MySQL instance. All the interesting info about our business and operations (customers, orders, delivery locations, shoppers, etc.) is split between these two. This posed a problem: questions that spanned data across the two different technologies needed a way to fetch information from both and combine it.
|
||||
|
||||
In the very early days of Mercadão, this was done by manually exporting data from both sources and crossing them as needed in someone's laptop. As you can imagine, as our company and operations scaled, this became a growing headache. Plus, as we evolved into a more mature data stack, we wanted to be able to connect our main visualization tool at the time ([Metabase](https://www.metabase.com/)) to data without lousy manual exports being a critical part of the process.
|
||||
|
||||
It was then when we identified Trino as a great solution for this problem. Trino offered us the ability to act as an abstraction layer on top of our MySQL+MongoDB combination, which translated into being able to join data across both databases as if they were only one. Metabase had a connector to Trino, so we could integrate them together without further plumbing. As a result, by deploying Trino and connecting it to our datasources and Metabase, we were able to easily build queries and reports across both MySQL and MongoDB. This was great for productivity, and also enabled savvy business users to access data without having to care about the details of the underlying infrastructure, which would be confusing and bizzarre for them.
|
||||
|
||||

|
||||
|
||||
In the end, it wasn't its distributed nature nor the promises on speed that led us to Trino, but simply the ability to hide two different databases under a single SQL connector. Time has passed since this early stages and some things have changed, but this feature is still the fundamental reason for why Trino lives in our data infrastructure.
|
||||
|
||||
|
||||
## How Trino fits in our architecture
|
||||
|
||||
Today, Trino is one of the pillars of our architecture. There are three main use-cases for Trino in our company:
|
||||
1. **Act as a bridge between databases in ETL processes**: Trino is a great tool for our ETL system (which we will cover in other posts in the blog). Trino covers the gap between two different databases with something as simple as running a `INSERT INTO database_1.some_table (...) SELECT (...) FROM database2.some_table`. This way, if you can write a SQL query, you can move data between the different databases in our company, as simple as that.
|
||||
2. **Offering cross-db capabilities in Looker**: as we mentioned in the previous section, Trino enables queries across databases, which opens up a world of possibilities and convenience for our analysts who are working hard to build products in Looker to serve the business. Although not every report or dashboard in Lolamarket goes through Trino (we will cover some performance issues with Trino in future posts), a fair share of them fetch their data through Trino.
|
||||
3. **Empower analysts**: analysts and advanced users can connect to Trino through SQL clients like DBeaver to do their own research, debug data-related issues, and generally access most data within the company in a single point. This way, we simplify their lives by allowing queries across different databases, as well as access and permissions. If we spin a new database within the company, simply adding it to Trino makes it accessible to our team without requiring any action from the users themselves.
|
||||
|
||||
|
||||
|
||||
## Just the beginning
|
||||
|
||||
Today's post was a brief intro to how Trino came into Lolamarket and what role is it playing in our architecture. But there are many more details, insights and lessons learned that we can share. This post is just the beginning of our Trino series, where we will keep sharing our adventures with Trino. Stay tuned if you want to learn more!
|
||||
35
notes/books/High Performance MySQL.md
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
---
|
||||
title: "High Performance MySQL: Proven Strategies for Operating at Scale"
|
||||
author: "Silvia Botros, Jeremy Tinley"
|
||||
isbn: "978-1-492-08051-0"
|
||||
---
|
||||
|
||||
|
||||
Famously, people often used MySQL as a queue and then learned the hard way why it was bad. The most cited reasons were the overhead of polling for new queue actions, the management of locking records for process‐ ing, and the unwieldy size of queue tables as data grows over time.
|
||||
|
||||
Funny enough, this comes when I was wondering if I should it use to hold events instead of Kafka for bas just because the data will be small and I feel lazy about picking up Kafka. Guess I should listen to the experts and not use it for what it is not :)
|
||||
|
||||
|
||||
## Locks
|
||||
|
||||
Read locks on a resource are shared, or mutually nonblocking: many cli‐ ents can read from a resource at the same time and not interfere with one another. Write locks, on the other hand, are exclusive—that is, they block both read locks and other write locks—because the only safe policy is to have a single client writing to the resource at a given time and to prevent all reads when a client is writing.
|
||||
|
||||
There can be table level locks and row level locks.
|
||||
|
||||
|
||||
Table level locks:
|
||||
- Lock the entire table: nobody can read or edit anything in the table when there is a write lock
|
||||
Row level locks:
|
||||
- Are implemented in the storage engine, not the server.
|
||||
- Only lock certain rows of the table, allowing concurrent operations on the rest of the table.
|
||||
|
||||
## ACID test
|
||||
|
||||
The system is ACID complient if it satisfies:
|
||||
|
||||
1. Atomicity: transactions are all or nothing. There is no possibility of partial execution. If the whole transaction is not successful, everything is rolled back to the initial state.
|
||||
2. Consistency: ???
|
||||
3. Isolation: the results of a transaction are invisible to other transactions until the transaction is complete. In other words: transaction B is not affected in any way by transaction A when it has not started or is mid-way through execution. Only when transaction A is finished, this might impact transaction B.
|
||||
4. Durability: a committed transaction makes permanent changes. The data is persisted and won't be lost, even in the case of an ungraceful shutdown.
|
||||
|
||||
Continue on page 30.
|
||||
BIN
notes/images/1658335654251.jpg
Normal file
|
After Width: | Height: | Size: 8 MiB |
BIN
notes/images/1658335654261.jpg
Normal file
|
After Width: | Height: | Size: 327 KiB |
BIN
notes/images/1658335654273.jpg
Normal file
|
After Width: | Height: | Size: 752 KiB |
BIN
notes/images/1658335747385.jpg
Normal file
|
After Width: | Height: | Size: 332 KiB |
BIN
notes/images/1658335848404 1.jpg
Normal file
|
After Width: | Height: | Size: 259 KiB |
BIN
notes/images/1658335848404.jpg
Normal file
|
After Width: | Height: | Size: 259 KiB |
BIN
notes/images/New Office - Guidelines.pdf
Normal file
BIN
notes/images/Pasted Image 20221005152200_141.png
Normal file
|
After Width: | Height: | Size: 20 KiB |
BIN
notes/images/Pasted Image 20221021100611_126.png
Normal file
|
After Width: | Height: | Size: 404 KiB |
BIN
notes/images/Pasted Image 20221031155553_659.png
Normal file
|
After Width: | Height: | Size: 160 KiB |
BIN
notes/images/Pasted Image 20230118144318_209.png
Normal file
|
After Width: | Height: | Size: 45 KiB |
BIN
notes/images/Pasted Image 20230118144521_267.png
Normal file
|
After Width: | Height: | Size: 31 KiB |
BIN
notes/images/Pasted Image 20230118145852_224.png
Normal file
|
After Width: | Height: | Size: 47 KiB |
BIN
notes/images/Pasted Image 20230118145921_742.png
Normal file
|
After Width: | Height: | Size: 189 KiB |
BIN
notes/images/Pasted Image 20230118150009_223.png
Normal file
|
After Width: | Height: | Size: 108 KiB |
BIN
notes/images/Pasted Image 20230118152706_240.png
Normal file
|
After Width: | Height: | Size: 11 KiB |
BIN
notes/images/Pasted image 20220921124220.png
Normal file
|
After Width: | Height: | Size: 25 KiB |
BIN
notes/images/Pasted image 20220923161339.png
Normal file
|
After Width: | Height: | Size: 56 KiB |
BIN
notes/images/Pasted image 20220929134219.png
Normal file
|
After Width: | Height: | Size: 5.6 KiB |
BIN
notes/images/Pasted image 20221108123815.png
Normal file
|
After Width: | Height: | Size: 506 KiB |
BIN
notes/images/Pasted image 20221214123536.png
Normal file
|
After Width: | Height: | Size: 2.9 MiB |
BIN
notes/images/Pasted image 20221216114751.png
Normal file
|
After Width: | Height: | Size: 1.7 KiB |
BIN
notes/images/Pasted image 20230215102943.png
Normal file
|
After Width: | Height: | Size: 23 KiB |
BIN
notes/images/Pasted image 20230809113546.png
Normal file
|
After Width: | Height: | Size: 408 KiB |
BIN
notes/images/Pasted image 20230809115157.png
Normal file
|
After Width: | Height: | Size: 522 KiB |
BIN
notes/images/Pasted image 20230810114231.png
Normal file
|
After Width: | Height: | Size: 374 KiB |
BIN
notes/images/ge_alert_example.png
Normal file
|
After Width: | Height: | Size: 15 KiB |
BIN
notes/images/money-shop.gif
Normal file
|
After Width: | Height: | Size: 133 KiB |
144
notes/other/My development.md
Normal file
|
|
@ -0,0 +1,144 @@
|
|||
Hey hey. I've been thinking a bit after our last 1:1 and your proposal on discussing what kind of goals I would like to go for. I found a small writing to be the most convenient. If you have a minute to read this before our next 1:1, I think it can act as an agenda/reference. So here are few thoughts into where I would like to point myself towards to:
|
||||
|
||||
- Leadership: I have always naturally enjoyed being proactive, standing up when most people and getting things moving. I enjoy it and I think I could even say I *need* it to a certain degree. There are several areas where I think this leadership-craving can turn into applicable stuff here at Lola:
|
||||
- I enjoy leading more junior colleagues and mentoring people, as well as managing teams. I understand this is no trivial request and I'm not expecting a junior person tomorrow reporting to me, but I want you to know that you can count on me leading other colleagues in the data team when it becomes necessary. I also would enjoy taking the lead on more ephemeral, project-specific teams.
|
||||
- I enjoying partnering up with business people and becoming their technical/data go-to person. Opposite to what tends to be the case with technical profiles, I actually find this very pleasant and I guess it was one of the things that put me through consulting successfully. Overtime, I would like to play this go-to role for some area or team within Lola. Let's discuss how that fits with the bigger picture and roadmaps.
|
||||
- Technical: I enjoy the tech side of things. I am the kind of person who will code on his free time. I like best practices, building stuff and testing new tools. I think this, mixed with the previous bullet on leadership, brings me to certain ideas:
|
||||
- I enjoy being the person that has to play around with new tech to assess if it works for something (I brought Great Expectations into my unit at ACN, and have similar stories at previous companies). I think I can bring a lot with this attitude, both from the software side and the optimization/statistics/ml side for operations.
|
||||
- My values are very aligned with the open-source mindset. If some day we consider open-sourcing something we build inside Lola, I would support that strongly and would enjoy taking the lead.
|
||||
- I also enjoy participating in technical groups, events, discussions, meetups, etc. On this subject, I have to very specific proposals:
|
||||
- We could run a technical blog together with the tech team. This is large effort, so again, I understand many pieces will have to fit for this to happen. But I think it would yield value over time. And our successful competitors are doing this (https://blog.picnic.nl/).
|
||||
- A less-resourceful endeavor: there are many Python/Data Engineering/Data Science meetups in Porto, Madrid, Barcelona, Lisbon. I would love to tour around those explaining interesting things about what we build in Lola, and this could also be helpful for our PR as a tech-hiring company.
|
||||
- Others
|
||||
- My position teaching in University gets me in touch with researchers and students. I think there are opportunities to be untapped from relating with this groups that might be worth exploring. I would be happy to discuss them and lead whatever may come out of it.
|
||||
|
||||
|
||||
And to complement, a few things I would *not* like:
|
||||
- Drop all my technical work and end up in 100% business focused position
|
||||
- Stay stuck only on technical work and be miles away from business colleagues and their problems/challenges.
|
||||
- Never assume any leadership and stay at the individual contributor level.
|
||||
|
||||
## Discussion 20220907
|
||||
|
||||
- Blog: aim for early 2023 to get it started
|
||||
|
||||
GOALS:
|
||||
- Take the lead for data in polish operations
|
||||
- Blog up and running before 15/12/2022
|
||||
- Subdomain ready
|
||||
- Blogging platform ready
|
||||
- 4 articles ready
|
||||
- Explicit agreement with stakeholders on ownership and responsibilities of each of us
|
||||
- Give a talk in a meetup in at least Porto and Madrid before January
|
||||
|
||||
Liliana
|
||||
- Blog
|
||||
- PR in meetups
|
||||
- University
|
||||
|
||||
|
||||
# Discussion 20220920
|
||||
|
||||
- [x] Barcelona Meetup
|
||||
- [x] I'll talk now with Liliana
|
||||
- [ ] Berlana and the blog? Not yet
|
||||
|
||||
- [x] Feedback
|
||||
- Great feedback from the team
|
||||
- João agrees, good hire
|
||||
- [ ] Any news from Poland?
|
||||
|
||||
|
||||
|
||||
|
||||
# Discussion 20221004
|
||||
|
||||
- [x] Berlana and the blog?
|
||||
- They already tried to go for it but never followed through.
|
||||
- Berlana is happy about going for it.
|
||||
- He would like it to be a bottom-up.
|
||||
- We agree to wait until Poland is clearer and they are less overburdened.
|
||||
- We can already write material stuff.
|
||||
- [x] I discussed with Liliana, she's onboard. We just... need to do it.
|
||||
- [x] Sponsoring PyBCN day and giving talks
|
||||
|
||||
|
||||
|
||||
|
||||
# Goals for 2023
|
||||
|
||||
- Lead the junior Data Engineer
|
||||
- Keep making our systems better
|
||||
- Make the basic, foundational stuff work so well that we get plenty of time for advanced stuff
|
||||
- Keep learning
|
||||
- Swallow a few books: MySQL, AWS, Prefect, Python, Spark, Kafka
|
||||
- Fun stuff
|
||||
- Blog, Uni, Meetups
|
||||
- Come up with a few crazy engineering ideas
|
||||
|
||||
## Performance Review 2022-12-21
|
||||
|
||||
- "You do things that fall outside of your area, you never comply."
|
||||
- "You use time efficiently"
|
||||
- "One thing I like of working for you is: you have an ideal solution for a problem, but if the team wants to do something else, you adapt." Not tyrannical.
|
||||
- "Always getting new tasks"
|
||||
- Four words:
|
||||
- "Organized"
|
||||
- "Innovator" :D
|
||||
- "Efficient"
|
||||
- "Good comunicator"
|
||||
|
||||
- Start: more involved with other teams (not a critic, but a wish), some advanced data projects.
|
||||
- Stop: Nothing here. :D
|
||||
- Continue:
|
||||
- Innovating
|
||||
- Adapting to team decisions
|
||||
|
||||
- "I know you all have plenty of opportunities out there."
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# 1:1 20230110
|
||||
|
||||
- Liliana
|
||||
- Junior guy
|
||||
- I'm glad with how things are popping
|
||||
|
||||
|
||||
|
||||
# 1:1 20230207
|
||||
|
||||
- Mindmap
|
||||
- Trip to Porto? In mid march
|
||||
- Uni
|
||||
- Starting next week one hour a week
|
||||
- Will have a bit more load than expected, but I don't think it's going to be troublesome since the additional effort is on evenings
|
||||
- I'll send you a summary of my expected OOF patterns
|
||||
|
||||
|
||||
- Benefits
|
||||
- 25 days of holidays
|
||||
- Birthday off (even if one weekend)
|
||||
- Picking team day
|
||||
- Voluntary days
|
||||
|
||||
|
||||
# 1:1 20230307
|
||||
|
||||
- What happened with Ana Martins?
|
||||
- Class hours
|
||||
- Holidays
|
||||
- Trip to porto confirmed
|
||||
- Technical blog: I have a couple of articles ready
|
||||
- Multi-drop suggestion service: where do we start
|
||||
|
||||
|
||||
# 1:1 20230711
|
||||
|
||||
- Contract situation. What the hell is going on? Can't we just move my contract to a new company already?
|
||||
- Yearly review. Should we wait?
|
||||
- Morale is quite low
|
||||
- Afonso, flexibility and expectations
|
||||
73
notes/other/Order Bundling White Paper.md
Normal file
|
|
@ -0,0 +1,73 @@
|
|||
|
||||
This White Paper describes the idea of Order Bundling. It's part of a brainstorming effort, not a plan. It's purpose is to stir ideas that could lead to a more specific plan of action.
|
||||
|
||||
## TLDR
|
||||
|
||||
Order bundling consists on performing more than one delivery in a same drive. It is an opportunity to improve operational efficiency by reducing the driving time needed for the same number of orders. The improvement in efficiency mainly derives from skipping trips back to the picking location to pick the goods for the next delivery. Bundling is attractive under conditions X,Y,Z. Bundling is hard to execute under conditions X,Y,Z.
|
||||
|
||||
## What is Order Bundling
|
||||
|
||||
Order bundling is the idea of having a shopper or driver deliver two orders in a single ride. This means that, instead of:
|
||||
- Picking location -> first customer location -> picking location -> second customer location -> picking location (for next order)
|
||||
We would do:
|
||||
- Picking location -> first customer location -> second customer location -> picking location (for next order)
|
||||
|
||||
The goal of order bundling is to spend less time driving to serve the same amount of orders.
|
||||
|
||||
### Anatomy of an order
|
||||
|
||||
- Picking
|
||||
- Picking time
|
||||
- Checkout time
|
||||
- Loading time
|
||||
- Driving
|
||||
- Drive to customer location
|
||||
- Delivery
|
||||
- Drive back to picking location
|
||||
|
||||
|
||||
|
||||
|
||||
### Factors that favour bundling
|
||||
- Orders that are close in space and time.
|
||||
- High volume of orders (higher chances of multiple orders in same or adjacent timeslots)
|
||||
- Operational areas that are small in physical area (higher chances of customers being close to each other)
|
||||
- Picker + driver operating model.
|
||||
- Great temperature-control (lower chances of frozen/chill products going bad)
|
||||
|
||||
### Factors that discourage bundling
|
||||
- Orders that are far in space and time.
|
||||
- Low volume of orders (lower chances of multiple orders in same or adjacent timeslots)
|
||||
- Operational areas that are large in physical area (lower chances of customers being close to each other)
|
||||
- Single shopper operating model.
|
||||
- Poor temperature-control (higher chances of frozen/chill products going bad)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## How can Order Bundling be executed
|
||||
|
||||
## Benefits and estimated opportunity size
|
||||
|
||||
The main financial cost for Lolamarket's operation is the shopper's compensation.
|
||||
|
||||
Making shopper's significantly more productive allows at the same time cost saving for Lolamarket and an increase in hourly compensation for the shopper. An increase in efficiency basically makes the pie of each order bigger, which is independent of how this pie is split between shopper and Lolamarket. We could get greedy and hoard all the efficiency savings for ourselves. We could be selfless and let the shoppers take home all the efficiency gains. Or we could be moderate and strike a balance somewhere in between.
|
||||
|
||||
## Estimated opportunity size
|
||||
|
||||
- Pick a time frame
|
||||
- Pick a geographical area
|
||||
- Define several tiers of close-ness (<10driving-min, <20driving-min, <30driving-min)
|
||||
- Report on what percentage of orders where candidates for bundling
|
||||
- Make an assumption on the saved human time
|
||||
|
||||
|
||||
## Roadmap
|
||||
|
||||
1. Backwards looking estimation of opportunity
|
||||
2. Simple 3 day ahead bundling suggestion service
|
||||
3. Integration in shopper app and order backoffice
|
||||
4. Fine tuning
|
||||
17
notes/other/Prefect Flow Checklist.md
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
## The Flow itself
|
||||
|
||||
- [ ] **No secrets, passwords or similar in place.**
|
||||
- [ ] No unnecessary hard-codings (if some piece of data acts as constant in several flows, it's better to make it part of the `env`)
|
||||
- [ ] The right `reference_tasks` are indicated, or the defaults are good enough
|
||||
- [ ] The flow has a proper clean-up/tear-down (if something fails, finishing activities like closing connections or deleting files will still happen)
|
||||
- [ ] There is no unnecessary boilerplate imports, configs, variables, constants and functions in the script (if you can remove something and the flow will still always work properly, remove it)
|
||||
- [ ] The flow has a way to be run and tested without consequences (i.e. write to a production database)
|
||||
- [ ] You have run the flow succesfully at least once in its final state before registering
|
||||
- [ ] You have run the flow succesfully at least once from the prefect server
|
||||
|
||||
|
||||
## Scheduling
|
||||
- [ ] You have set up a slack warning so that failures are notified
|
||||
- [ ] You have intentionally made the flow fail to verify that notifications work properly
|
||||
- [ ] The right parameters are set with the scheduled run
|
||||
- [ ] You have verified manually that the first scheduled run went well and produced the expected output
|
||||
9
notes/other/ideas for team meet up on sept-22.md
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
# Ideas for Data Conclave
|
||||
|
||||
I've been thinking a bit on different things that we could do to profit from all of us being together. Sharing in no particular order:
|
||||
|
||||
- Hold a session with Gonçalo and/or Ricardo to discuss Data within Lola. It doesn't necessarily need to be about anything important, but could be a nice little boost for team morale to get in touch with team and have a few nice words. Optionally, if we have some more future-looking ideas that we thing are worth raising to them, we can leverage the opportunity.
|
||||
- North-star brainstorming: linking with the previous, we could take the chance to step away from the day-to-day work and dream awake about what could Data do for Lolamarket. If we feel like it, we could even meet with managers (Mónica, Luis, Lukasz) from different areas one by one to discuss specific ideas on their teams.
|
||||
- Meeting with the Portuguese tech team to do a bit of bonding (I guess this one is specially relevant for Dani and I mainly).
|
||||
- I would personally really like to go and do a bit of shopping, although if our stay is going to be short this might eat up too much valuable time.
|
||||
- The conclave might also be a good idea to do any internal data team training we might have in our backlog. We could even dedicate some time to have each of us bring interesting technologies/techniques/knowledge we have with the team.
|
||||
24
notes/other/travel expenses.md
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
# 27-27 Sept 2022
|
||||
|
||||
- Vueling go
|
||||
- 16€
|
||||
- Vueling return
|
||||
- 16€
|
||||
- Cabify 27/09 BCN
|
||||
- Uber 27/09 Porto
|
||||
- Uber 28/09 Porto
|
||||
- Dinner at the Porto airport
|
||||
- Cabify 28/09 BCN
|
||||
|
||||
|
||||
# 23-24 MAR23
|
||||
|
||||
- Vueling: 12,65 + 39,00 €
|
||||
- Cabify go: 23,40 €
|
||||
- Uber go: 9,35 €
|
||||
- Uber return: 9,29 €
|
||||
- Cabify return: 24,44 €
|
||||
- Francesinha:
|
||||
- Airport dinner:
|
||||
|
||||
**TOTAL**:
|
||||