Merge remote-tracking branch 'origin/main'

This commit is contained in:
2026-03-12 17:43:14 -04:00
390 changed files with 7509 additions and 19042 deletions
+1 -1
View File
@@ -2,5 +2,5 @@
/.obsidian/workspace-mobile.json
/.obsidian/plugins/recent-files-obsidian/data.json
/.obsidian/plugins/novel-word-count/data.json
/out/
/.out/
/ref/
+1 -1
View File
@@ -4,7 +4,7 @@
"interfaceFontFamily": "",
"cssTheme": "Typewriter",
"theme": "moonstone",
"baseFontSize": 16,
"baseFontSize": 15,
"enabledCssSnippets": [
"tables"
]
-1
View File
@@ -16,7 +16,6 @@
"lilypond",
"novel-word-count",
"easy-copy",
"anchor-display-text",
"calendar",
"periodic-notes",
"spellcheck-toggler",
+13 -5
View File
@@ -1,14 +1,22 @@
{
"collapse-filter": true,
"search": "path:/*.md",
"collapse-filter": false,
"search": "tag:#type/periodic ",
"showTags": false,
"showAttachments": false,
"hideUnresolved": false,
"showOrphans": true,
"collapse-color-groups": false,
"colorGroups": [],
"colorGroups": [
{
"query": "tag:#occupational ",
"color": {
"a": 1,
"rgb": 14048348
}
}
],
"collapse-display": false,
"showArrow": true,
"showArrow": false,
"textFadeMultiplier": 0,
"nodeSizeMultiplier": 1,
"lineSizeMultiplier": 1,
@@ -17,6 +25,6 @@
"repelStrength": 10,
"linkStrength": 1,
"linkDistance": 250,
"scale": 0.18454855383603447,
"scale": 0.18454855383603405,
"close": false
}
-9
View File
@@ -1,9 +0,0 @@
{
"includeNoteName": "headersOnly",
"titleProperty": "title",
"whichHeadings": "allHeaders",
"includeNotice": false,
"sep": " ",
"suggest": true,
"ignoreEmbedded": true
}
-306
View File
@@ -1,306 +0,0 @@
/*
THIS IS A GENERATED/BUNDLED FILE BY ESBUILD
if you want to view the source, please visit the github repository of this plugin
*/
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
// main.ts
var main_exports = {};
__export(main_exports, {
default: () => AnchorDisplayText
});
module.exports = __toCommonJS(main_exports);
var import_obsidian = require("obsidian");
var RE_ANCHOR_NO_DISPLAY = /!?\[\[([^\]]+#[^|\n\r\]]+)\]\]$/;
var RE_ANCHOR_DISPLAY = /(\[\[([^\]]+#[^\n\r\]]+)\]\])$/;
var RE_DISPLAY = /\|([^\]]+)/;
var DEFAULT_SETTINGS = {
includeNoteName: "headersOnly",
titleProperty: "",
whichHeadings: "allHeaders",
includeNotice: false,
sep: " ",
suggest: true,
ignoreEmbedded: true
};
var AnchorDisplayText = class extends import_obsidian.Plugin {
constructor() {
super(...arguments);
this.suggestionsRegistered = false;
}
async onload() {
await this.loadSettings();
this.addSettingTab(new AnchorDisplayTextSettingTab(this.app, this));
if (this.settings.suggest) {
this.registerEditorSuggest(new AnchorDisplaySuggest(this));
this.suggestionsRegistered = true;
}
this.registerEvent(
this.app.workspace.on("editor-change", (editor) => {
var _a;
const cursor = editor.getCursor();
const currentLine = editor.getLine(cursor.line);
const lastChars = currentLine.slice(cursor.ch - 2, cursor.ch);
if (lastChars !== "]]")
return;
const match = currentLine.slice(0, cursor.ch).match(RE_ANCHOR_NO_DISPLAY);
if (match) {
if (this.settings.ignoreEmbedded && match[0].charAt(0) === "!")
return;
const headings = match[1].split("#");
let notename = headings[0];
if (this.settings.titleProperty) {
notename = this.getTitleFromFile(notename);
}
let displayText = "";
if (this.settings.whichHeadings === "lastHeader") {
displayText = headings[headings.length - 1];
} else {
displayText = headings[1];
if (this.settings.whichHeadings === "allHeaders") {
for (let i = 2; i < headings.length; i++) {
displayText += this.settings.sep + headings[i];
}
}
}
const startIndex = ((_a = match.index) != null ? _a : 0) + match[0].length - 2;
if (this.settings.includeNoteName === "noteNameFirst") {
displayText = `${notename}${this.settings.sep}${displayText}`;
} else if (this.settings.includeNoteName === "noteNameLast") {
displayText = `${displayText}${this.settings.sep}${notename}`;
}
if (displayText.startsWith("^")) {
displayText = displayText.slice(1);
}
editor.replaceRange(`|${displayText}`, { line: cursor.line, ch: startIndex }, void 0, "headerDisplayText");
if (this.settings.includeNotice) {
new import_obsidian.Notice(`Updated anchor link display text.`);
}
}
})
);
}
onunload() {
}
/**
* Get title property value from file's frontmatter
* @param filename - The filename to look up
* @returns The title property value if found, otherwise returns the original filename
*/
getTitleFromFile(filename) {
if (this.settings.titleProperty) {
const file = this.app.metadataCache.getFirstLinkpathDest(filename, "");
if (file) {
const cache = this.app.metadataCache.getFileCache(file);
if (cache && cache.frontmatter && cache.frontmatter[this.settings.titleProperty]) {
return String(cache.frontmatter[this.settings.titleProperty]);
}
}
}
return filename;
}
async loadSettings() {
this.settings = Object.assign({}, DEFAULT_SETTINGS, await this.loadData());
}
async saveSettings() {
await this.saveData(this.settings);
}
};
var AnchorDisplaySuggest = class extends import_obsidian.EditorSuggest {
constructor(plugin) {
super(plugin.app);
this.suggestionSelected = null;
this.plugin = plugin;
}
onTrigger(cursor, editor) {
if (!this.plugin.settings.suggest)
return null;
if (this.suggestionSelected) {
if (this.suggestionSelected.ch === cursor.ch && this.suggestionSelected.line === cursor.line)
return null;
this.suggestionSelected = null;
return null;
}
const currentLine = editor.getLine(cursor.line);
const lastChars = currentLine.slice(cursor.ch - 2, cursor.ch);
if (lastChars !== "]]")
return null;
const slice = currentLine.slice(0, cursor.ch);
const match = slice.match(RE_ANCHOR_DISPLAY);
if (!match)
return null;
if (this.plugin.settings.ignoreEmbedded && slice.charAt(match.index - 1) === "!")
return null;
return {
start: {
line: cursor.line,
ch: match.index + match[1].length - 2
// 2 less to keep closing brackets
},
end: {
line: cursor.line,
ch: match.index + match[1].length - 2
},
query: match[2]
};
}
getSuggestions(context) {
const headings = context.query.split("|")[0].split("#");
let notename = headings[0];
if (this.plugin.settings.titleProperty) {
notename = this.plugin.getTitleFromFile(notename);
}
let displayText = headings[1];
if (displayText.startsWith("^")) {
displayText = displayText.slice(1);
}
for (let i = 2; i < headings.length; i++) {
displayText += this.plugin.settings.sep + headings[i];
}
const suggestion1 = {
displayText,
source: "Don't include note name"
};
const suggestion2 = {
displayText: `${notename}${this.plugin.settings.sep}${displayText}`,
source: "Note name and than heading(s)"
};
const suggestion3 = {
displayText: `${displayText}${this.plugin.settings.sep}${notename}`,
source: "Heading(s) and than note name"
};
return [suggestion1, suggestion2, suggestion3];
}
renderSuggestion(value, el) {
const suggestionEl = el.parentElement;
const suggestionContainerEl = suggestionEl.parentElement;
if (suggestionContainerEl.childElementCount < 2) {
const promptInstructionsEl = suggestionContainerEl.createDiv({ cls: "prompt-instructions" });
const instructionEl = promptInstructionsEl.createDiv({ cls: "prompt-instruction" });
instructionEl.createEl("span", { cls: "prompt-instruction-command", text: "\u21B5" });
instructionEl.createEl("span", { text: "to accept" });
}
el.setAttribute("class", "suggestion-item mod-complex");
const suggestionContentEl = el.createDiv({ cls: "suggestion-content" });
suggestionContentEl.createDiv({ cls: "suggestion-title", text: value.displayText });
suggestionContentEl.createDiv({ cls: "suggestion-note", text: value.source });
}
selectSuggestion(value, evt) {
const editor = this.context.editor;
const match = this.context.query.match(RE_DISPLAY);
if (match) {
this.context.start.ch = this.context.start.ch - match[0].length;
}
editor.replaceRange(`|${value.displayText}`, this.context.start, this.context.end, "headerDisplayText");
this.suggestionSelected = this.context.end;
}
};
var AnchorDisplayTextSettingTab = class extends import_obsidian.PluginSettingTab {
constructor(app, plugin) {
super(app, plugin);
this.sepWarning = null;
this.plugin = plugin;
}
validateSep(value) {
let validValue = value;
for (const c of value) {
if ("[]#^|".includes(c)) {
validValue = validValue.replace(c, "");
}
}
if (validValue != value) {
if (!this.sepWarning) {
this.sepWarning = new import_obsidian.Notice(`Separators cannot contain any of the following characters: []#^|`, 0);
}
} else {
if (this.sepWarning) {
this.sepWarning.hide();
this.sepWarning = null;
}
}
return validValue;
}
display() {
const { containerEl } = this;
containerEl.empty();
new import_obsidian.Setting(containerEl).setName("Include note name").setDesc("Include the title of the note in the display text.").addDropdown((dropdown) => {
dropdown.addOption("headersOnly", "Don't include note name");
dropdown.addOption("noteNameFirst", "Note name and then heading(s)");
dropdown.addOption("noteNameLast", "Heading(s) and then note name");
dropdown.setValue(this.plugin.settings.includeNoteName);
dropdown.onChange((value) => {
this.plugin.settings.includeNoteName = value;
this.plugin.saveSettings();
});
});
new import_obsidian.Setting(containerEl).setName("Title property").setDesc("If set, use the value of this property as the note name. (Leave blank to use file name)").addText((text) => {
text.setValue(this.plugin.settings.titleProperty);
text.onChange((value) => {
this.plugin.settings.titleProperty = value;
this.plugin.saveSettings();
});
});
new import_obsidian.Setting(containerEl).setName("Include subheadings").setDesc("Change which headings and subheadings are in the display text.").addDropdown((dropdown) => {
dropdown.addOption("allHeaders", "All linked headings");
dropdown.addOption("lastHeader", "Last heading only");
dropdown.addOption("firstHeader", "First heading only");
dropdown.setValue(this.plugin.settings.whichHeadings);
dropdown.onChange((value) => {
this.plugin.settings.whichHeadings = value;
this.plugin.saveSettings();
});
});
new import_obsidian.Setting(containerEl).setName("Separator").setDesc("Choose what to insert between headings instead of #.").addText((text) => {
text.setValue(this.plugin.settings.sep);
text.onChange((value) => {
this.plugin.settings.sep = this.validateSep(value);
this.plugin.saveSettings();
});
});
new import_obsidian.Setting(containerEl).setName("Enable notifications").setDesc("Have a notice pop up whenever an anchor link is automatically changed.").addToggle((toggle) => {
toggle.setValue(this.plugin.settings.includeNotice);
toggle.onChange((value) => {
this.plugin.settings.includeNotice = value;
this.plugin.saveSettings();
});
});
new import_obsidian.Setting(containerEl).setName("Suggest alternatives").setDesc("Have a suggestion window to present alternative display text options when the cursor is directly after an anchor link.").addToggle((toggle) => {
toggle.setValue(this.plugin.settings.suggest);
toggle.onChange((value) => {
this.plugin.settings.suggest = value;
this.plugin.saveSettings();
if (!this.plugin.suggestionsRegistered) {
this.plugin.registerEditorSuggest(new AnchorDisplaySuggest(this.plugin));
this.plugin.suggestionsRegistered = true;
}
});
});
new import_obsidian.Setting(containerEl).setName("Ignore embedded files").setDesc("Don't add or change display text for embedded files.").addToggle((toggle) => {
toggle.setValue(this.plugin.settings.ignoreEmbedded);
toggle.onChange((value) => {
this.plugin.settings.ignoreEmbedded = value;
this.plugin.saveSettings();
});
});
}
};
/* nosourcemap */
-10
View File
@@ -1,10 +0,0 @@
{
"id": "anchor-display-text",
"name": "Anchor Link Display Text",
"version": "1.4.0",
"minAppVersion": "0.15.0",
"description": "Automatically uses the linked heading as the display text for anchor links.",
"author": "Robert C Arsenault",
"authorUrl": "https://github.com/rca-umb",
"isDesktopOnly": false
}
+622 -45
View File
@@ -10732,6 +10732,48 @@ var import_obsidian2 = require("obsidian");
// src/repositoryConnection/RepositoryConnection.ts
var import_js_logger = __toESM(require_logger());
// src/forestry/LimitReachedError.ts
var LimitReachedError = class extends Error {
constructor(errorType, responseData) {
var _a2;
const message = (_a2 = responseData.message) != null ? _a2 : "Usage limit reached";
super(message);
this.name = "LimitReachedError";
this.errorType = errorType;
this.buildsUsed = responseData.builds_used;
this.monthlyLimit = responseData.monthly_limit;
this.starterCreditsRemaining = responseData.starter_credits_remaining;
}
};
function throwIfLimitError(error) {
if (error && typeof error === "object" && "status" in error && error.status === 403) {
const responseData = extractResponseData(error);
if (!responseData) return;
const errorType = responseData.error;
if (errorType === "build_limit_reached" || errorType === "storage_limit_exceeded") {
throw new LimitReachedError(errorType, responseData);
}
}
}
function extractResponseData(error) {
const err = error;
if (err.response && typeof err.response === "object") {
const response = err.response;
if (response.data && typeof response.data === "object") {
return response.data;
}
}
if (err.response && typeof err.response === "object") {
const resp = err.response;
if (resp.data && typeof resp.data === "object") {
return resp.data;
}
}
return null;
}
// src/repositoryConnection/RepositoryConnection.ts
var logger = import_js_logger.default.get("repository-connection");
var IMAGE_PATH_BASE = "src/site/";
var NOTE_PATH_BASE = "src/site/notes/";
@@ -10823,6 +10865,7 @@ var RepositoryConnection = class {
);
return result;
} catch (error) {
throwIfLimitError(error);
logger.error(error);
return false;
}
@@ -10875,6 +10918,7 @@ var RepositoryConnection = class {
payload
);
} catch (error) {
throwIfLimitError(error);
logger.error(error);
}
});
@@ -10973,6 +11017,7 @@ var RepositoryConnection = class {
sha: blob.data.sha
};
} catch (error) {
throwIfLimitError(error);
logger.error(error);
}
}));
@@ -11002,6 +11047,7 @@ var RepositoryConnection = class {
sha: blob.data.sha
};
} catch (error) {
throwIfLimitError(error);
logger.error(error);
}
}));
@@ -12902,7 +12948,8 @@ var CanvasCompiler = class {
node,
baseStyle,
colorClass,
file
file,
assets
);
case "file":
return yield this.buildFileNode(
@@ -12927,7 +12974,7 @@ var CanvasCompiler = class {
}
});
}
buildTextNode(node, baseStyle, colorClass, file) {
buildTextNode(node, baseStyle, colorClass, file, assets) {
return __async(this, null, function* () {
var _a2;
let processedText = node.text;
@@ -12935,7 +12982,8 @@ var CanvasCompiler = class {
try {
processedText = yield this.textNodeProcessor.processTextNodeContent(
file,
node.text
node.text,
assets
);
} catch (e) {
console.error("Error processing canvas text node:", e);
@@ -12955,6 +13003,45 @@ var CanvasCompiler = class {
}
buildFileNode(node, baseStyle, colorClass, file, assets) {
return __async(this, null, function* () {
const isPdf = /\.pdf$/i.test(node.file);
if (isPdf) {
const linkedFile = this.metadataCache.getFirstLinkpathDest(
(0, import_obsidian4.getLinkpath)(node.file),
file.getPath()
);
if (linkedFile) {
try {
const pdfData = yield this.vault.readBinary(linkedFile);
const pdfBase64 = arrayBufferToBase64(pdfData);
const pdfPath2 = `/img/user/${linkedFile.path}`;
assets.push({
path: pdfPath2,
content: pdfBase64,
localHash: generateBlobHashFromBase64(pdfBase64)
});
return `<div class="canvas-node canvas-node-file canvas-node-pdf ${colorClass}" data-node-id="${node.id}" style="${baseStyle}">
<div class="canvas-node-container">
<div class="canvas-node-content">
<iframe src="${encodeURI(
pdfPath2
)}" class="canvas-pdf-iframe" loading="lazy" style="width:100%;height:100%;border:none;"></iframe>
</div>
</div>
</div>`;
} catch (e) {
console.error("Error reading canvas PDF:", e);
}
}
const resolvedPath = (linkedFile == null ? void 0 : linkedFile.path) || node.file;
const pdfPath = encodeURI(`/img/user/${resolvedPath}`);
return `<div class="canvas-node canvas-node-file canvas-node-pdf ${colorClass}" data-node-id="${node.id}" style="${baseStyle}">
<div class="canvas-node-container">
<div class="canvas-node-content">
<iframe src="${pdfPath}" class="canvas-pdf-iframe" loading="lazy" style="width:100%;height:100%;border:none;"></iframe>
</div>
</div>
</div>`;
}
const isImage = /\.(png|jpg|jpeg|gif|webp|svg)$/i.test(node.file);
if (isImage) {
const linkedFile = this.metadataCache.getFirstLinkpathDest(
@@ -19415,6 +19502,18 @@ var GardenPageCompiler = class {
linkedFileName = headerSplit[0];
headerPath = headerSplit.length > 1 ? `#${headerSplit[1]}` : "";
}
if (linkedFileName === "" && headerPath !== "") {
const currentFilePath = file.getPath();
const currentExtensionlessPath = currentFilePath.substring(
0,
currentFilePath.lastIndexOf(".")
);
convertedText = convertedText.replace(
linkMatch,
`[[${currentExtensionlessPath}${headerPath}\\|${linkDisplayName}]]`
);
continue;
}
const fullLinkedFilePath = (0, import_obsidian5.getLinkpath)(linkedFileName);
if (fullLinkedFilePath === "") {
continue;
@@ -20122,7 +20221,7 @@ ${headerSection}
* Process text content from canvas text nodes through the same pipeline as notes.
* This enables wiki-links, transclusions, dataview, etc. in canvas text nodes.
*/
processTextNodeContent(file, text2) {
processTextNodeContent(file, text2, assets) {
return __async(this, null, function* () {
const CANVAS_TEXT_COMPILE_STEPS = [
this.convertCustomFilters,
@@ -20130,12 +20229,18 @@ ${headerSection}
this.createTranscludedText(0),
this.convertDataViews,
this.convertLinksToFullPath,
this.removeObsidianComments
this.removeObsidianComments,
this.createSvgEmbeds
];
return yield this.runCompilerSteps(
const compiledText = yield this.runCompilerSteps(
file,
CANVAS_TEXT_COMPILE_STEPS
)(text2);
const [processedText, collectedAssets] = yield this.convertEmbeddedAssets(file)(compiledText);
if (assets) {
assets.push(...collectedAssets);
}
return processedText;
});
}
generateMarkdown(file) {
@@ -20371,6 +20476,9 @@ var Publisher = class {
yield this.uploadAssets(assets, remoteImageHashes);
return true;
} catch (error) {
if (error instanceof LimitReachedError) {
throw error;
}
console.error(error);
return false;
}
@@ -20416,6 +20524,9 @@ var Publisher = class {
);
return true;
} catch (error) {
if (error instanceof LimitReachedError) {
throw error;
}
console.error(error);
return false;
}
@@ -30017,6 +30128,22 @@ var ForestryApi = class {
}
});
}
getUserLimits() {
return __async(this, null, function* () {
try {
const response = yield this.client.get(
"user/limits"
);
if (response.status !== 200) {
return null;
}
return response.data;
} catch (e) {
import_js_logger8.default.error(e);
return null;
}
});
}
};
// src/views/SettingsView/ForestrySettings.svelte
@@ -30033,11 +30160,11 @@ function create_else_block5(ctx) {
pending: create_pending_block,
then: create_then_block,
catch: create_catch_block,
value: 9,
value: 12,
blocks: [, , ,]
};
handle_promise(promise = /*getPageInfo*/
ctx[5](), info);
ctx[7](), info);
return {
c() {
await_block_anchor = empty();
@@ -30125,13 +30252,13 @@ function create_if_block6(ctx) {
input,
"input",
/*input_input_handler*/
ctx[8]
ctx[10]
),
listen(
button,
"click",
/*connect*/
ctx[3]
ctx[5]
)
];
mounted = true;
@@ -30191,7 +30318,7 @@ function create_catch_block(ctx) {
button,
"click",
/*disconnect*/
ctx[4]
ctx[6]
);
mounted = true;
}
@@ -30218,7 +30345,7 @@ function create_then_block(ctx) {
function select_block_type_1(ctx2, dirty) {
if (
/*pageInfo*/
ctx2[9]
ctx2[12]
) return 0;
return 1;
}
@@ -30287,7 +30414,7 @@ function create_else_block_12(ctx) {
button,
"click",
/*disconnect*/
ctx[4]
ctx[6]
);
mounted = true;
}
@@ -30313,7 +30440,7 @@ function create_if_block_15(ctx) {
let t0;
let t1_value = (
/*pageInfo*/
((_a2 = ctx[9].value.pageName) != null ? _a2 : "Unknown") + ""
((_a2 = ctx[12].value.pageName) != null ? _a2 : "Unknown") + ""
);
let t1;
let t2;
@@ -30326,11 +30453,25 @@ function create_if_block_15(ctx) {
let a;
let icon1;
let t7;
let t8;
let if_block_anchor;
let current;
let mounted;
let dispose;
icon0 = new Icon_default({ props: { name: "check-circle" } });
icon1 = new Icon_default({ props: { name: "external-link" } });
function select_block_type_2(ctx2, dirty) {
if (
/*limitsLoading*/
ctx2[4]
) return create_if_block_25;
if (
/*limits*/
ctx2[3]
) return create_if_block_33;
}
let current_block_type = select_block_type_2(ctx, -1);
let if_block = current_block_type && current_block_type(ctx);
return {
c() {
div4 = element("div");
@@ -30351,6 +30492,9 @@ function create_if_block_15(ctx) {
a = element("a");
create_component(icon1.$$.fragment);
t7 = text(" Open Forestry.md Dashboard");
t8 = space();
if (if_block) if_block.c();
if_block_anchor = empty();
attr(div0, "class", "setting-item-name");
set_style(div0, "display", "flex");
set_style(div0, "align-items", "center");
@@ -30384,18 +30528,32 @@ function create_if_block_15(ctx) {
append(div5, a);
mount_component(icon1, a, null);
append(a, t7);
insert(target, t8, anchor);
if (if_block) if_block.m(target, anchor);
insert(target, if_block_anchor, anchor);
current = true;
if (!mounted) {
dispose = listen(
button,
"click",
/*disconnect*/
ctx[4]
ctx[6]
);
mounted = true;
}
},
p: noop,
p(ctx2, dirty) {
if (current_block_type === (current_block_type = select_block_type_2(ctx2, dirty)) && if_block) {
if_block.p(ctx2, dirty);
} else {
if (if_block) if_block.d(1);
if_block = current_block_type && current_block_type(ctx2);
if (if_block) {
if_block.c();
if_block.m(if_block_anchor.parentNode, if_block_anchor);
}
}
},
i(local) {
if (current) return;
transition_in(icon0.$$.fragment, local);
@@ -30412,14 +30570,362 @@ function create_if_block_15(ctx) {
detach(div4);
detach(t6);
detach(div5);
detach(t8);
detach(if_block_anchor);
}
destroy_component(icon0);
destroy_component(icon1);
if (if_block) {
if_block.d(detaching);
}
mounted = false;
dispose();
}
};
}
function create_if_block_33(ctx) {
let div5;
let div0;
let t0;
let t1_value = (
/*limits*/
ctx[3].plan + ""
);
let t1;
let t2;
let t3;
let div4;
let div1;
let span0;
let t5;
let span1;
let t6_value = (
/*limits*/
ctx[3].builds.monthlyLimit - /*limits*/
ctx[3].builds.monthlyRemaining + ""
);
let t6;
let t7;
let t8_value = (
/*limits*/
ctx[3].builds.monthlyLimit + ""
);
let t8;
let t9;
let t10;
let div2;
let span2;
let t12;
let span3;
let t13_value = (
/*limits*/
ctx[3].storage.usedFormatted + ""
);
let t13;
let t14;
let t15_value = (
/*limits*/
ctx[3].storage.limitFormatted + ""
);
let t15;
let t16;
let div3;
let span4;
let t18;
let span5;
let t19_value = (
/*limits*/
ctx[3].sites.current + ""
);
let t19;
let t20;
let t21_value = (
/*limits*/
ctx[3].sites.limit + ""
);
let t21;
let t22;
let if_block0 = (
/*limits*/
ctx[3].builds.starterCreditsRemaining > 0 && create_if_block_53(ctx)
);
let if_block1 = (
/*limits*/
(ctx[3].builds.monthlyRemaining === 0 || /*limits*/
ctx[3].storage.usedBytes >= /*limits*/
ctx[3].storage.limitBytes) && create_if_block_43(ctx)
);
return {
c() {
div5 = element("div");
div0 = element("div");
t0 = text("Usage \u2014 ");
t1 = text(t1_value);
t2 = text(" plan");
t3 = space();
div4 = element("div");
div1 = element("div");
span0 = element("span");
span0.textContent = "Builds this month";
t5 = space();
span1 = element("span");
t6 = text(t6_value);
t7 = text(" / ");
t8 = text(t8_value);
t9 = space();
if (if_block0) if_block0.c();
t10 = space();
div2 = element("div");
span2 = element("span");
span2.textContent = "Storage";
t12 = space();
span3 = element("span");
t13 = text(t13_value);
t14 = text(" / ");
t15 = text(t15_value);
t16 = space();
div3 = element("div");
span4 = element("span");
span4.textContent = "Sites";
t18 = space();
span5 = element("span");
t19 = text(t19_value);
t20 = text(" / ");
t21 = text(t21_value);
t22 = space();
if (if_block1) if_block1.c();
set_style(div0, "font-weight", "600");
set_style(div0, "margin-bottom", "8px");
set_style(
span1,
"color",
/*limits*/
ctx[3].builds.monthlyRemaining === 0 ? "var(--text-error)" : "var(--text-normal)"
);
set_style(div1, "display", "flex");
set_style(div1, "justify-content", "space-between");
set_style(
span3,
"color",
/*limits*/
ctx[3].storage.usedBytes >= /*limits*/
ctx[3].storage.limitBytes ? "var(--text-error)" : "var(--text-normal)"
);
set_style(div2, "display", "flex");
set_style(div2, "justify-content", "space-between");
set_style(div3, "display", "flex");
set_style(div3, "justify-content", "space-between");
set_style(div4, "display", "flex");
set_style(div4, "flex-direction", "column");
set_style(div4, "gap", "6px");
set_style(div4, "font-size", "0.9em");
set_style(div4, "color", "var(--text-muted)");
set_style(div5, "margin-top", "16px");
set_style(div5, "padding", "12px");
set_style(div5, "background", "var(--background-secondary)");
set_style(div5, "border-radius", "8px");
},
m(target, anchor) {
insert(target, div5, anchor);
append(div5, div0);
append(div0, t0);
append(div0, t1);
append(div0, t2);
append(div5, t3);
append(div5, div4);
append(div4, div1);
append(div1, span0);
append(div1, t5);
append(div1, span1);
append(span1, t6);
append(span1, t7);
append(span1, t8);
append(div4, t9);
if (if_block0) if_block0.m(div4, null);
append(div4, t10);
append(div4, div2);
append(div2, span2);
append(div2, t12);
append(div2, span3);
append(span3, t13);
append(span3, t14);
append(span3, t15);
append(div4, t16);
append(div4, div3);
append(div3, span4);
append(div3, t18);
append(div3, span5);
append(span5, t19);
append(span5, t20);
append(span5, t21);
append(div5, t22);
if (if_block1) if_block1.m(div5, null);
},
p(ctx2, dirty) {
if (dirty & /*limits*/
8 && t1_value !== (t1_value = /*limits*/
ctx2[3].plan + "")) set_data(t1, t1_value);
if (dirty & /*limits*/
8 && t6_value !== (t6_value = /*limits*/
ctx2[3].builds.monthlyLimit - /*limits*/
ctx2[3].builds.monthlyRemaining + "")) set_data(t6, t6_value);
if (dirty & /*limits*/
8 && t8_value !== (t8_value = /*limits*/
ctx2[3].builds.monthlyLimit + "")) set_data(t8, t8_value);
if (dirty & /*limits*/
8) {
set_style(
span1,
"color",
/*limits*/
ctx2[3].builds.monthlyRemaining === 0 ? "var(--text-error)" : "var(--text-normal)"
);
}
if (
/*limits*/
ctx2[3].builds.starterCreditsRemaining > 0
) {
if (if_block0) {
if_block0.p(ctx2, dirty);
} else {
if_block0 = create_if_block_53(ctx2);
if_block0.c();
if_block0.m(div4, t10);
}
} else if (if_block0) {
if_block0.d(1);
if_block0 = null;
}
if (dirty & /*limits*/
8 && t13_value !== (t13_value = /*limits*/
ctx2[3].storage.usedFormatted + "")) set_data(t13, t13_value);
if (dirty & /*limits*/
8 && t15_value !== (t15_value = /*limits*/
ctx2[3].storage.limitFormatted + "")) set_data(t15, t15_value);
if (dirty & /*limits*/
8) {
set_style(
span3,
"color",
/*limits*/
ctx2[3].storage.usedBytes >= /*limits*/
ctx2[3].storage.limitBytes ? "var(--text-error)" : "var(--text-normal)"
);
}
if (dirty & /*limits*/
8 && t19_value !== (t19_value = /*limits*/
ctx2[3].sites.current + "")) set_data(t19, t19_value);
if (dirty & /*limits*/
8 && t21_value !== (t21_value = /*limits*/
ctx2[3].sites.limit + "")) set_data(t21, t21_value);
if (
/*limits*/
ctx2[3].builds.monthlyRemaining === 0 || /*limits*/
ctx2[3].storage.usedBytes >= /*limits*/
ctx2[3].storage.limitBytes
) {
if (if_block1) {
} else {
if_block1 = create_if_block_43(ctx2);
if_block1.c();
if_block1.m(div5, null);
}
} else if (if_block1) {
if_block1.d(1);
if_block1 = null;
}
},
d(detaching) {
if (detaching) {
detach(div5);
}
if (if_block0) if_block0.d();
if (if_block1) if_block1.d();
}
};
}
function create_if_block_25(ctx) {
let div2;
return {
c() {
div2 = element("div");
div2.innerHTML = `<div class="setting-item-info"><div class="setting-item-name">Loading usage info...</div></div>`;
attr(div2, "class", "setting-item");
set_style(div2, "margin-top", "12px");
},
m(target, anchor) {
insert(target, div2, anchor);
},
p: noop,
d(detaching) {
if (detaching) {
detach(div2);
}
}
};
}
function create_if_block_53(ctx) {
let div;
let span0;
let t1;
let span1;
let t2_value = (
/*limits*/
ctx[3].builds.starterCreditsRemaining + ""
);
let t2;
return {
c() {
div = element("div");
span0 = element("span");
span0.textContent = "Starter credits remaining";
t1 = space();
span1 = element("span");
t2 = text(t2_value);
set_style(div, "display", "flex");
set_style(div, "justify-content", "space-between");
},
m(target, anchor) {
insert(target, div, anchor);
append(div, span0);
append(div, t1);
append(div, span1);
append(span1, t2);
},
p(ctx2, dirty) {
if (dirty & /*limits*/
8 && t2_value !== (t2_value = /*limits*/
ctx2[3].builds.starterCreditsRemaining + "")) set_data(t2, t2_value);
},
d(detaching) {
if (detaching) {
detach(div);
}
}
};
}
function create_if_block_43(ctx) {
let div;
return {
c() {
div = element("div");
div.innerHTML = `You&#39;ve reached your usage limit. <a href="https://dashboard.forestry.md/settings" target="_blank">Upgrade your plan</a> to continue publishing.`;
set_style(div, "margin-top", "8px");
set_style(div, "padding", "8px");
set_style(div, "background", "var(--background-modifier-error)");
set_style(div, "border-radius", "4px");
set_style(div, "font-size", "0.85em");
},
m(target, anchor) {
insert(target, div, anchor);
},
d(detaching) {
if (detaching) {
detach(div);
}
}
};
}
function create_pending_block(ctx) {
let div2;
return {
@@ -30576,6 +31082,8 @@ function instance8($$self, $$props, $$invalidate) {
let { saveSettings } = $$props;
let { onConnect } = $$props;
let apiKey = settings.forestrySettings.apiKey;
let limits = null;
let limitsLoading = false;
const connect = () => __awaiter(void 0, void 0, void 0, function* () {
let pageInfo = yield getPageInfo();
if (!pageInfo) {
@@ -30594,24 +31102,45 @@ function instance8($$self, $$props, $$invalidate) {
$$invalidate(0, settings.forestrySettings.forestryPageName = "", settings);
yield saveSettings();
$$invalidate(2, apiKey = "");
$$invalidate(3, limits = null);
});
const getPageInfo = () => __awaiter(void 0, void 0, void 0, function* () {
let pageInfo = yield new ForestryApi(apiKey).getPageInfo();
return pageInfo;
});
const fetchLimits = () => __awaiter(void 0, void 0, void 0, function* () {
if (!settings.forestrySettings.apiKey) return;
$$invalidate(4, limitsLoading = true);
try {
$$invalidate(3, limits = yield new ForestryApi(settings.forestrySettings.apiKey).getUserLimits());
} catch (_a2) {
$$invalidate(3, limits = null);
}
$$invalidate(4, limitsLoading = false);
});
function input_input_handler() {
apiKey = this.value;
$$invalidate(2, apiKey);
}
$$self.$$set = ($$props2) => {
if ("settings" in $$props2) $$invalidate(0, settings = $$props2.settings);
if ("saveSettings" in $$props2) $$invalidate(6, saveSettings = $$props2.saveSettings);
if ("onConnect" in $$props2) $$invalidate(7, onConnect = $$props2.onConnect);
if ("saveSettings" in $$props2) $$invalidate(8, saveSettings = $$props2.saveSettings);
if ("onConnect" in $$props2) $$invalidate(9, onConnect = $$props2.onConnect);
};
$$self.$$.update = () => {
if ($$self.$$.dirty & /*settings*/
1) {
$: if (settings.forestrySettings.apiKey) {
fetchLimits();
}
}
};
return [
settings,
unique,
apiKey,
limits,
limitsLoading,
connect,
disconnect,
getPageInfo,
@@ -30625,8 +31154,8 @@ var ForestrySettings = class extends SvelteComponent {
super();
init(this, options, instance8, create_fragment8, safe_not_equal, {
settings: 0,
saveSettings: 6,
onConnect: 7
saveSettings: 8,
onConnect: 9
});
}
};
@@ -30699,7 +31228,7 @@ var SettingView = class {
const publishPlatformSettings = this.settingsRootElement.createEl(
"div",
{
cls: "connection-status"
cls: "publish-platform-settings"
}
);
this.initializePublishPlatformSettings(publishPlatformSettings);
@@ -31313,13 +31842,31 @@ var SettingView = class {
cb.setButtonText("Apply settings to site");
cb.setCta();
cb.onClick((_ev) => __async(this, null, function* () {
const octokit = new Octokit({
auth: this.settings.githubToken
});
new import_obsidian15.Notice("Applying settings to site...");
yield this.saveSettingsAndUpdateEnv();
yield this.addFavicon(octokit);
yield this.addLogo(octokit);
const connection = yield PublishPlatformConnectionFactory.createPublishPlatformConnection(
this.settings
);
const octokit = connection.octoKit;
const owner = connection.userName;
const repo = connection.pageName;
try {
yield this.addFavicon(octokit, owner, repo);
} catch (error) {
import_js_logger9.default.error("Failed to update favicon", error);
new import_obsidian15.Notice(
"Failed to update favicon. Check the developer console for details."
);
}
try {
yield this.addLogo(octokit, owner, repo);
} catch (error) {
import_js_logger9.default.error("Failed to update logo", error);
new import_obsidian15.Notice(
"Failed to update logo. Check the developer console for details."
);
}
new import_obsidian15.Notice("Settings applied to site!");
}));
};
new import_obsidian15.Setting(this.settingsRootElement).setName("Appearance").setDesc("Manage themes, sitename and styling on your site").addButton((cb) => {
@@ -31724,7 +32271,7 @@ var SettingView = class {
}
return settings;
}
addFavicon(octokit) {
addFavicon(octokit, owner, repo) {
return __async(this, null, function* () {
let base64SettingsFaviconContent = "";
if (this.settings.faviconPath) {
@@ -31738,11 +32285,12 @@ var SettingView = class {
const faviconContent = yield this.app.vault.readBinary(faviconFile);
base64SettingsFaviconContent = arrayBufferToBase64(faviconContent);
} else {
const defaultFavicon = yield octokit.request(
const baseConnection = PublishPlatformConnectionFactory.createBaseGardenConnection();
const defaultFavicon = yield baseConnection.octoKit.request(
"GET /repos/{owner}/{repo}/contents/{path}",
{
owner: "oleeskild",
repo: "digitalgarden",
owner: baseConnection.userName,
repo: baseConnection.pageName,
path: "src/site/favicon.svg"
}
);
@@ -31755,13 +32303,13 @@ var SettingView = class {
currentFaviconOnSite = yield octokit.request(
"GET /repos/{owner}/{repo}/contents/{path}",
{
owner: this.settings.githubUserName,
repo: this.settings.githubRepo,
owner,
repo,
path: "src/site/favicon.svg"
}
);
faviconsAreIdentical = // @ts-expect-error TODO: abstract octokit response
currentFaviconOnSite.data.content === base64SettingsFaviconContent;
currentFaviconOnSite.data.content.replace(/\n/g, "") === base64SettingsFaviconContent;
if (faviconsAreIdentical) {
import_js_logger9.default.info("Favicons are identical, skipping update");
return;
@@ -31771,8 +32319,8 @@ var SettingView = class {
}
if (!faviconExists || !faviconsAreIdentical) {
yield octokit.request("PUT /repos/{owner}/{repo}/contents/{path}", {
owner: this.settings.githubUserName,
repo: this.settings.githubRepo,
owner,
repo,
path: "src/site/favicon.svg",
message: `Update favicon.svg`,
content: base64SettingsFaviconContent,
@@ -31782,9 +32330,12 @@ var SettingView = class {
}
});
}
addLogo(octokit) {
addLogo(octokit, owner, repo) {
return __async(this, null, function* () {
var _a2;
import_js_logger9.default.info(
`addLogo called, logoPath setting: "${this.settings.logoPath}", owner: "${owner}", repo: "${repo}"`
);
const logoBasePath = "src/site/logo";
const logoExtensions = ["png", "jpg", "jpeg", "gif", "svg", "webp"];
for (const ext of logoExtensions) {
@@ -31792,8 +32343,8 @@ var SettingView = class {
const existingLogo = yield octokit.request(
"GET /repos/{owner}/{repo}/contents/{path}",
{
owner: this.settings.githubUserName,
repo: this.settings.githubRepo,
owner,
repo,
path: `${logoBasePath}.${ext}`
}
);
@@ -31804,8 +32355,8 @@ var SettingView = class {
yield octokit.request(
"DELETE /repos/{owner}/{repo}/contents/{path}",
{
owner: this.settings.githubUserName,
repo: this.settings.githubRepo,
owner,
repo,
path: `${logoBasePath}.${ext}`,
message: `Remove logo.${ext}`,
// @ts-expect-error TODO: abstract octokit response
@@ -31841,13 +32392,13 @@ var SettingView = class {
currentLogoOnSite = yield octokit.request(
"GET /repos/{owner}/{repo}/contents/{path}",
{
owner: this.settings.githubUserName,
repo: this.settings.githubRepo,
owner,
repo,
path: logoPath
}
);
logosAreIdentical = // @ts-expect-error TODO: abstract octokit response
currentLogoOnSite.data.content === base64LogoContent;
currentLogoOnSite.data.content.replace(/\n/g, "") === base64LogoContent;
if (logosAreIdentical) {
import_js_logger9.default.info("Logos are identical, skipping update");
return;
@@ -31858,8 +32409,8 @@ var SettingView = class {
if (!logoExists || !logosAreIdentical) {
try {
const requestPayload = __spreadValues({
owner: this.settings.githubUserName,
repo: this.settings.githubRepo,
owner,
repo,
path: logoPath,
message: `Update logo.${logoExtension}`,
content: base64LogoContent
@@ -32550,6 +33101,10 @@ var DigitalGarden = class extends import_obsidian19.Plugin {
} catch (e) {
statusBarItem.remove();
this.isPublishing = false;
if (e instanceof LimitReachedError) {
this.showLimitNotice(e);
return;
}
console.error(e);
new import_obsidian19.Notice(
"Unable to publish multiple notes, something went wrong."
@@ -32666,9 +33221,15 @@ var DigitalGarden = class extends import_obsidian19.Plugin {
const publishSuccessful = yield publisher.publish(publishFile);
if (publishSuccessful) {
new import_obsidian19.Notice(`Successfully published note to your garden.`);
} else {
new import_obsidian19.Notice("Unable to publish note, something went wrong.");
}
return publishSuccessful;
} catch (e) {
if (e instanceof LimitReachedError) {
this.showLimitNotice(e);
return false;
}
console.error(e);
new import_obsidian19.Notice("Unable to publish note, something went wrong.");
return false;
@@ -32762,6 +33323,22 @@ var DigitalGarden = class extends import_obsidian19.Plugin {
}
});
}
showLimitNotice(error) {
var _a2, _b;
if (error.errorType === "build_limit_reached") {
const used = (_a2 = error.buildsUsed) != null ? _a2 : 0;
const limit = (_b = error.monthlyLimit) != null ? _b : 0;
new import_obsidian19.Notice(
`Publishing blocked: You've used all ${used}/${limit} builds this month. Upgrade to Pro for 1000 builds/month at dashboard.forestry.md/settings`,
1e4
);
} else {
new import_obsidian19.Notice(
`Publishing blocked: Storage limit exceeded. Free up space or upgrade at dashboard.forestry.md/settings`,
1e4
);
}
}
openPublishModal() {
const siteManager = new DigitalGardenSiteManager(
this.app.metadataCache,
+1 -1
View File
@@ -1,7 +1,7 @@
{
"id": "digitalgarden",
"name": "Digital Garden",
"version": "2.69.0",
"version": "2.72.0",
"minAppVersion": "1.10.0",
"description": "Publish your notes to the web for others to enjoy. For free.",
"author": "Ole Eskild Steensen",
File diff suppressed because one or more lines are too long
+1 -1
View File
@@ -1,7 +1,7 @@
{
"id": "obsidian-excalidraw-plugin",
"name": "Excalidraw",
"version": "2.20.2",
"version": "2.20.6",
"minAppVersion": "1.5.7",
"description": "Sketch Your Mind. An Obsidian plugin to edit and view Excalidraw drawings. Enter the world of 4D Visual PKM.",
"author": "Zsolt Viczian",
File diff suppressed because one or more lines are too long
+281 -271
View File
File diff suppressed because one or more lines are too long
+1 -1
View File
@@ -6,5 +6,5 @@
"description": "Integrate Git version control with automatic backup and other advanced features.",
"isDesktopOnly": false,
"fundingUrl": "https://ko-fi.com/vinzent",
"version": "2.36.1"
"version": "2.38.0"
}
+5
View File
@@ -81,6 +81,11 @@
height: 100%;
}
/* Re-enable wrapping of nav buttns to prevent overflow on smaller screens #*/
.workspace-drawer .git-view .nav-buttons-container {
flex-wrap: wrap;
}
.git-tools {
display: flex;
margin-left: auto;
File diff suppressed because one or more lines are too long
+2 -2
View File
@@ -1,11 +1,11 @@
{
"id": "obsidian-latex-suite",
"name": "Latex Suite",
"version": "1.9.8",
"version": "1.11.0",
"minAppVersion": "1.0.0",
"description": "Make typesetting LaTeX math as fast as handwriting through snippets, text expansion, and editor enhancements",
"author": "artisticat",
"authorUrl": "https://github.com/artisticat1",
"fundingUrl": "https://ko-fi.com/artisticat",
"isDesktopOnly": false
}
}
+29
View File
@@ -192,8 +192,25 @@ sup.cm-math, sub.cm-math {
0px 3.4px 6.7px rgba(0, 0, 0, 0.15),
0px 0px 30px rgba(0, 0, 0, 0.27);
}
/* CM6 puts the top of the tooltip higher than what's viewable (negative top value),
so to compensate for this, we align the content to the bottom of the tooltip container,
and limit the height.
*/
.cm-tooltip.cm-tooltip-cursor.cm-tooltip-above {
display: flex;
}
.cm-tooltip.cm-tooltip-cursor.cm-tooltip-above > .MathJax {
overflow-y: auto;
max-height: 70%;
display: inline-block;
align-self: flex-end;
}
.cm-tooltip.cm-tooltip-cursor.cm-tooltip-below > .MathJax {
overflow-y: auto;
max-height: 90%;
}
/* Highlight brackets */
.theme-light .latex-suite-highlighted-bracket, .theme-light .latex-suite-highlighted-bracket [class^="latex-suite-color-bracket-"] {
background-color: hsl(var(--accent-h), var(--accent-s), 40%, 0.3);
@@ -233,3 +250,15 @@ sup.cm-math, sub.cm-math {
/* .latex-suite-color-bracket-3 {
color: #8de15c;
} */
.latex-suite-math-preview-highlight {
background-color: var(--text-selection);
}
.cm-snippetFieldPosition {
vertical-align: text-top;
width: 0;
height: 1.15em;
display: inline-block;
margin: 0 -0.7px -.7em;
border-left: 1.4px dotted #888;
}
+4 -1
View File
@@ -106,7 +106,8 @@
"enabled": false
},
"move-footnotes-to-the-bottom": {
"enabled": false
"enabled": false,
"include-blank-line-between-footnotes": false
},
"re-index-footnotes": {
"enabled": false
@@ -273,9 +274,11 @@
"lintOnSave": true,
"recordLintOnSaveLogs": false,
"displayChanged": true,
"suppressMessageWhenNoChange": false,
"lintOnFileChange": false,
"displayLintOnFileChangeNotice": false,
"settingsConvertedToConfigKeyValues": true,
"additionalFileExtensions": [],
"foldersToIgnore": [],
"filesToIgnore": [],
"linterLocale": "system-default",
File diff suppressed because one or more lines are too long
+2 -2
View File
@@ -1,8 +1,8 @@
{
"id": "obsidian-linter",
"name": "Linter",
"version": "1.30.0",
"minAppVersion": "1.9.0",
"version": "1.31.2",
"minAppVersion": "1.12.0",
"description": "Formats and styles your notes. It can be used to format YAML tags, aliases, arrays, and metadata; footnotes; headings; spacing; math blocks; regular markdown contents like list, italics, and bold styles; and more with the use of custom rule options as well.",
"author": "Victor Tao",
"authorUrl": "https://github.com/platers",
+2 -2
View File
@@ -14,7 +14,7 @@
"targetFolders": "",
"scanDelay": 250,
"useTitle": true,
"reduceNestedParent": true,
"reduceNestedParent": false,
"frontmatterKey": "title",
"useTagInfo": false,
"tagInfo": "pininfo.md",
@@ -26,7 +26,7 @@
"useMultiPaneList": false,
"archiveTags": "",
"disableNarrowingDown": true,
"expandUntaggedToRoot": false,
"expandUntaggedToRoot": true,
"disableDragging": false,
"linkConfig": {
"incoming": {
File diff suppressed because one or more lines are too long
+1 -1
View File
@@ -1,7 +1,7 @@
{
"id": "obsidian-tasks-plugin",
"name": "Tasks",
"version": "7.22.0",
"version": "7.23.1",
"minAppVersion": "1.4.0",
"description": "Track tasks across your vault. Supports due dates, recurring tasks, done dates, sub-set of checklist items, and filtering.",
"helpUrl": "https://publish.obsidian.md/tasks/",
File diff suppressed because one or more lines are too long
+1 -1
View File
@@ -6,7 +6,7 @@
"devMode": false,
"templateFolderPath": "",
"announceUpdates": "none",
"version": "2.10.0",
"version": "2.12.0",
"globalVariables": {},
"onePageInputEnabled": false,
"disableOnlineFeatures": true,
+67 -61
View File
File diff suppressed because one or more lines are too long
+1 -1
View File
@@ -1,7 +1,7 @@
{
"id": "quickadd",
"name": "QuickAdd",
"version": "2.10.0",
"version": "2.12.0",
"minAppVersion": "1.11.4",
"description": "Quickly add new pages or content to your vault.",
"author": "Christian B. B. Houmann",
File diff suppressed because one or more lines are too long
+1 -2
View File
@@ -562,8 +562,7 @@ var SpellcheckTogglerPlugin = class extends import_obsidian2.Plugin {
const editor = (_a2 = this.app.workspace.activeEditor) == null ? void 0 : _a2.editor;
if (!editor)
return;
editor.replaceRange(" ", editor.getCursor());
editor.undo();
editor.refresh();
})();
}
async onload() {
+1 -1
View File
@@ -1,7 +1,7 @@
{
"id": "spellcheck-toggler",
"name": "Spellcheck Toggler",
"version": "1.4.3",
"version": "1.4.4",
"minAppVersion": "1.5.3",
"description": "Toggle spellchecking for types of text blocks in the editing view.",
"author": "Julian Szachowicz",
+2 -1
View File
@@ -25,6 +25,7 @@
"TQ_show_tree": "checkbox",
"TQ_show_urgency": "checkbox",
"dg-publish": "checkbox",
"id": "datetime"
"id": "datetime",
"TQ_show_toolbar": "checkbox"
}
}
+5 -3
View File
@@ -1,10 +1,12 @@
---
id:
aliases: []
title:
title: 107 Morgan Street
tags:
- authorship/original
- destiny/permanent
- status/not-started
- occupational/project
---
- status/not-started
dg-publish: true
---
# 107 Morgan Street
+1
View File
@@ -22,6 +22,7 @@ year: 1960
description: |
Frontpage newspaper article noting the accidental death
of Rev. Dr. William Hamilton Bill Alexander and his wife Marylouise.
dg-publish: false
---
# Rev. William Alexander And Wife Killed In Airplane Crash
+5 -3
View File
@@ -1,10 +1,12 @@
---
id:
aliases: []
title:
title: 1990 K Street
tags:
- authorship/original
- destiny/permanent
- status/not-started
- occupational/project
---
- status/not-started
dg-publish: true
---
# 1990 K Street
+1
View File
@@ -6,6 +6,7 @@ tags:
- authorship/original
- destiny/permanent
- status/incomplete
dg-publish: true
---
# 2009 Honda Civic
+14
View File
@@ -0,0 +1,14 @@
---
id:
aliases: []
title: 2026-W07
tags:
- authorship/original
- destiny/permanent
- status/draft
- type/periodic/weekly
dg-publish: true
date-created: 2026-03-06T10:45:40-05:00
yearly: "[[2026]]"
---
# 2026-W07
+1
View File
@@ -7,5 +7,6 @@ tags:
- destiny/permanent
- occupational/project
- status/not-started
dg-publish: true
---
# 2100 Crystal Drive
+5 -3
View File
@@ -1,10 +1,12 @@
---
id:
aliases: []
title:
title: 450-460 James Robertson Parkway
tags:
- authorship/original
- destiny/permanent
- status/not-started
- occupational/project
---
- status/not-started
dg-publish: true
---
# 450-460 James Robertson Parkway
+78 -4
View File
@@ -6,6 +6,7 @@ tags:
- authorship/original
- destiny/permanent
- status/incomplete
dg-publish: false
---
# 463 Davison Ave NE
@@ -24,16 +25,85 @@ Flood Insurance:
Insurer: [National General](https://eservice.nationalgeneral.com/)
Policy Number: 0003457855
## Resources
### Websites
[South Florida Plant Guide](https://www.south-florida-plant-guide.com/)
### Contractors
* **HVAC:** Agape Air (semiannual service)
* **Plumbing:** Hafke Plumbing
* **Pest Control:** "Michael" (727) 410-2636 (semiannual service)
## Spaces
### General
#### TODO
* [ ] draw floorplan
### Exterior
#### Plans
* Gutters
#### Design Principles
Keyword is _cozy_.
The sort of place you want to be on a weekend morning,
planning a day of birdwatching, while sipping coffee.
### Living/Dining
#### Design Principles
Television must not be the focal point, only present.
### Main Bedroom
Largest by room area
small closet
### Guest Bedroom A
Smaller than main
large closet
### Guest Bedroom B
Smaller by far than other bedrooms
### West Yard
#### TODO
* [ ] cleanup brick, block pieces in west yard
#### Plans
* Fence in west yard
* Carport
### Back Yard
#### Plans
* Fire pit
* Suspended shades
* Eureka palms?
### Front Yard
#### Plans
* Raised beds
* Vegetation along driveway
* Bahia/Bermuda grass?
## Needs
### Appliances
@@ -50,9 +120,13 @@ Maybe take back from Val.
### Furnishings
#### Tables
* Coffee table
* Dining table (island extension?)
#### Rugs
1 each bedroom (3)
2--3 living/dining area
####
* 1 each bedroom (total 3)
* 2--3 living/dining area
* long rug for hallway
+1
View File
@@ -11,6 +11,7 @@ tags:
- type/media/book
author: Erving Goffman
date: 1959
dg-publish: false
---
# The Presentation of Self in Everyday Life
+1 -1
View File
@@ -1,5 +1,5 @@
---
id: TODO
id:
aliases:
- todo
title: TODO
+13
View File
@@ -1,3 +1,16 @@
---
id:
aliases:
- LICENSE
title: UNLICENSE
tags:
- authorship/other
- destiny/permanent
- status/complete
- topic/meta
---
# UNLICENSE
This is free and unencumbered software released into the public domain.
Anyone is free to copy, modify, publish,
+6 -1
View File
@@ -2,7 +2,12 @@
id:
aliases: []
title: Advanced Tables
tags: []
tags:
- authorship/original
- destiny/uncertain
- status/incomplete
- topic/meta
dg-publish: true
---
# Advanced Tables
-2
View File
@@ -141,5 +141,3 @@ but their effects cancel each other out rather than add.
The Venn Diagram of ferroelectric and ferromagnetic materials
has a large but not complete intersection.
+1 -1
View File
@@ -26,7 +26,7 @@ and undoing years of poor conditioning is... not easy.
## Naming Conventions (Use Case vs. Description)
Related topic: [[realism-vs-instrumentalism]]
Related topic: [[heuristics#Realism vs. Instrumentalism]]
Naming by use case is intuitive for those without estimating or field experience,
but has the side effect that those accustomed to the names
-1
View File
@@ -1,6 +1,5 @@
filters:
and:
- file.folder == "/"
- file.ext == "md"
- '!file.basename.endsWith(".excalidraw")'
views:
+5 -3
View File
@@ -1,10 +1,12 @@
---
id:
aliases: []
title:
title: Belle Meade Plaza
tags:
- authorship/original
- destiny/permanent
- status/not-started
- occupational/project
---
- status/not-started
dg-publish: true
---
# Belle Meade Plaza
+1 -1
View File
@@ -91,7 +91,7 @@ $$
where $\mathrm{Var}[C]$ is the [variance](https://en.wikipedia.org/wiki/Variance)
and $\lambda>0$ is a risk-loading parameter.
> This mirrors mean-variance pricing common in portfolio theory.
> This mirrors mean-variance pricing common in [[modern-portfolio-theory]].
## 3. Quantile-based pricing
+5 -1
View File
@@ -34,6 +34,8 @@ dg-publish: true
* [ring-billed gull (_Larus delawarensis_)](https://en.wikipedia.org/wiki/Ring-billed_gull)
* [Laughing gull (_Leucophaeus atricilla_)](https://en.wikipedia.org/wiki/Laughing_gull)
## [Order Passeriformes ("perching birds")](https://en.wikipedia.org/wiki/Passeriformes)
> [!info]
@@ -63,7 +65,7 @@ dg-publish: true
> * _Aigron_ -> "Heron"
> * _Aigrette_ -> "Egret"
>
> which itself just means "screecher".
> _Aigron_ itself just means "screecher".
* [tricolored heron (_E. tricolor_)](https://en.wikipedia.org/wiki/Tricolored_heron)
* [little blue heron (_E. caerulea_)](https://en.wikipedia.org/wiki/Little_blue_heron)
@@ -73,6 +75,8 @@ dg-publish: true
* [green heron (_Butorides virescens_)](https://en.wikipedia.org/wiki/Green_heron)
* [Yellow-crowned night heron (_Nyctanassa violacea_)](https://en.wikipedia.org/wiki/Yellow-crowned_night_heron)
### [Family Threskiornithidae (Ibises and Spoonbills)](https://en.wikipedia.org/wiki/Threskiornithidae)
* [American white ibis (_Eudocimus albus_)](https://en.wikipedia.org/wiki/American_white_ibis)
+30
View File
@@ -0,0 +1,30 @@
---
id:
aliases: []
title: Boll Weevil
tags:
- destiny/permanent
- status/incomplete
- topic/hobbies/music/banjo
---
# Boll Weevil
Boll weevil told the farmer \
"You better treat me right \
I'll eat up all o' your cotton \
Sleep in your grain rail tonight"
Boll weevil told the farmer \
"You don't need no Ford machine \
I'll eat up all of your cotton \
Can't buy no gasoline"
Yonder comes the spider \
Crawled up and down the wall \
He must've been going \
To get his hash's haul
I don't see no water \
But I'm about to drown \
I don't see no fire \
But I'm burning down
@@ -0,0 +1,19 @@
---
id:
aliases: []
title: Empirical Model-Building and Response Surfaces
tags:
- authorship/other
- destiny/permanent
- status/not-started
- topic/math/statistics
- type/media/book
dg-publish: false
authors:
- George E. P. Box
- Norman Richard Draper
date: 1987
---
# Empirical Model-Building and Response Surfaces
## The Use of Approximating Functions
+1
View File
@@ -16,6 +16,7 @@ origlanguage: Czech
translator: Dora Round
type: incollection
year: 1935
dg-publish: false
---
# From the Point of View of a Cat
+8
View File
@@ -0,0 +1,8 @@
---
id:
aliases: []
title: Charlotte South End Hotel
tags:
- occupational/project
---
# Charlotte South End Hotel
+58
View File
@@ -0,0 +1,58 @@
---
id:
aliases: []
title: Chili
tags:
- authorship/original
- destiny/permanent
- status/complete
- topic/hobbies/cooking
- type/recipe
---
# Chili
## Ingredients
* **2 tbsp.** olive oil
* **1** yellow onion, diced
* **2 cloves** garlic, minced
* **1 lb** ground beef, turkey, or pork
* **34 cup** dry kidney beans, soaked overnight and drained
* **34 cup** dry black beans, soaked overnight and drained
* **(1) 15oz can** diced or crushed tomatoes, not drained
* **6 oz** canned tomato paste
* **1 cup** water
### Chili Seasoning
* **1 tbsp.** chili powder
* **1 tsp.** ground cumin
* **14 tsp.** cayenne powder
* **14 tsp.** garlic powder
* **12 tsp.** onion powder
* **12 tbsp.** brown sugar
* **1 tsp.** salt
* **12 tsp.** black pepper
## Instructions
1. Heat the **oil** over medium heat in a large pot.
Add the **onion**, season with salt and pepper,
and cook until translucent, about 4-5 minutes.
2. Stir in the **garlic** and cook until fragrant, 30--60 seconds.
3. Add the **ground meat** and continue to cook,
breaking up the meat with a spoon as it cooks,
until it is browned and cooked through, about 5 minutes.
4. Add the **beans**, **tomatoes**, **tomato paste**, **water**, and **chili seasoning**.
Stir to combine.
5. Cover and simmer over low heat for at least 30 minutes, stirring occasionally.
6. Serve hot with preferred toppings.
## Notes
* Makes 6 cups.
+55
View File
@@ -0,0 +1,55 @@
---
id:
aliases: []
title: Chipotle Black Beans
tags:
- authorship/original
- destiny/permanent
- status/complete
- topic/hobbies/cooking
- type/recipe
---
# Chipotle Black Beans
## Ingredients
* **2 tbsp.** water or vegetable broth
* **12** medium yellow onion, diced
* **3 cloves** garlic, minced
* **3 cups** water or unsalted vegetable broth
* **1 cup** dried black beans
* **2 tsp.** cumin powder
* **1 tsp.** Spanish paprika
* **1 tsp.** chipotle powder
* **1 tbsp.** lime juice
## Instructions
1. Set the Instant Pot to Sauté.
Add the 2 tbsp. **water or vegetable broth**, **onion** and **garlic**.
Sauté for 5 minutes, stirring occasionally, or until the onions are soft and translucent
2. Add the **water or vegetable broth**, **dried black beans** and **all spices**.
Press Stop to reset the Instant Pot,
then press the Bean/Chili button (or Manual/Pressure Cook) and set the time to 35 minutes.
3. When the Instant Pot chimes, press Stop and allow the pressure to bleed off.
4. When the pressure is released, remove the lid.
Add **lime juice** and stir, adding more **chipotle powder** to taste.
5. Use a handheld strainer to remove the beans.
Save the liquid for adding to other recipes if desired.
## Notes
* Makes 3 cups
* If using soaked beans, reduce cooking time by 10--15 minutes.
* You can double the ingredients in this recipe. Cook for the same time.
* If the beans are not cooked to your liking at the end of the 35 minutes,
you can cook for additional 5 minutes on the same settings.
* Store in the fridge in an airtight container for up to 5 days.
+1
View File
@@ -13,6 +13,7 @@ authors:
- James Clear
published: 2018-10-16
type: book
dg-publish: false
---
# Atomic Habits
+8 -5
View File
@@ -7,6 +7,8 @@ tags:
- destiny/permanent
- occupational
- type/media
- status/incomplete
dg-publish: true
---
# ConEst Pre-Takeoff Email Template
@@ -49,10 +51,10 @@ Please confirm you have received this email and respond with any questions or co
* Cover Material:
%% Covers: Brass, Aluminum %%
* Wiring Devices:
* Units:
%% 15A Decora %%
* BOH/Common Areas:
%% 20A Toggle %%
* Units:
%% 15A Decora %%
* BOH/Common Areas:
%% 20A Toggle %%
* Switchboards/Panelboards:
%% Acceptable Manufacturers, AL or CU Bussing, Breaker Types (Snap-on, bolt on), ACI Ratings %%
* Transformers:
@@ -62,7 +64,8 @@ Please confirm you have received this email and respond with any questions or co
### Project Drawing/Detail Callouts
* Describe conflicts between drawings / proposal: %% Plans show CU feeders, proposal calls for aluminum, Specification grade devices, etc. %%
* Describe conflicts between drawings / proposal:
%% "Plans show CU feeders, proposal calls for aluminum", Specification grade devices, etc. %%
* Cost drivers in details not shown elsewhere on plans:
+1 -1
View File
@@ -27,7 +27,7 @@ Still deciding if I'm capable of being opinionated without rambling.
* [[estimating-methodologies]]
* [[construction-estimating-software]]
* [[history-of-construction-estimating]]
* [[labor-factoring]]
* [[estimate-laboring]]
### New Cross-Topics
+11 -11
View File
@@ -15,6 +15,15 @@ dg-publish: true
Construction estimating is a subset of cost estimation.
%%
## TALK
This note should be wide and shallow,
specific sub topics should be extracted and linked.
%%
## Scope
This note is intended for: _facts_
@@ -32,7 +41,7 @@ For philosophy see [[bid-process-strategy]]
* [[history-of-construction-estimating]]
* [[estimating-methodologies]]
* [[construction-estimating-software]]
* [[labor-factoring]]
* [[estimate-laboring]]
### Cross-Topics
@@ -82,13 +91,4 @@ Much bigger people are involved after the proposal is accepted.
* [[electrical-estimators-manual]]
* [[electrical-estimating-methods]]
* [[construction-estimating-using-excel]]
* [[mike-holts-illustrated-guide-to-electrical-estimating]]
%%
## TALK
This note should be wide and shallow,
specific sub topics should be extracted and linked.
%%
* [[holt_2023_estimating]]
+1 -1
View File
@@ -54,7 +54,7 @@ Those around elevator shafts form a "shear core".
> [!info] Reference
> * [Concrete Slab | Different types of Slabs in Construction](https://www.constructioncost.co/slabs-in-construction.html)
> * [Concrete Slab Types -- Construction, Cost, and Applications -- theconstructor.org](https://theconstructor.org/practical-guide/concrete-slab-construction-cost/28153/)
> * [Concrete Slab Types -- Construction, Cost, and Applications | theconstructor.org](https://theconstructor.org/practical-guide/concrete-slab-construction-cost/28153/)
### Conventional Slab
+1
View File
@@ -6,6 +6,7 @@ tags:
- destiny/permanent
- status/incomplete
- type/guide
- topic/hobbies/digitizing
title: Converting Documents to Markdown
dg-publish: true
---
+5 -2
View File
@@ -2,7 +2,7 @@
id:
aliases: []
tags:
- authorship/original
- authorship/other-for-now
- destiny/permanent
- status/incomplete
- topic/math
@@ -12,7 +12,10 @@ dg-publish: true
---
# Convex Hull
[Convex Hull](https://en.wikipedia.org/wiki/Convex_hull)
> [!quote] [Wikipedia](https://en.wikipedia.org/wiki/Convex_hull)
> the **convex hull**, **convex envelope** or **convex closure** of a shape
> is the smallest [convex set](https://en.wikipedia.org/wiki/Convex_set "Convex set")
> that contains it.
```tikz
\usepackage{pgfplots}
+46
View File
@@ -0,0 +1,46 @@
---
id:
aliases: []
title: Create Your Own Vault
tags:
- authorship/original
- destiny/permanent
- status/incomplete
dg-publish: true
---
# Create Your Own Vault
## Setup Obsidian
1. Download and install [Obsidian](https://obsidian.md/)
2. Open Obsidian and select "Create New Vault".
## Create a GitHub Repository
1. Create a [GitHub](https://github.com/)
account if you don't have one already.
2. Install [[git|Git]] via the `winget` package manager:
```
winget install Git.Git
```
%% TODO: %%
## Create and Push your Vault
```
git init
git commit -m "initial commit"
git branch -M main
git remote add origin https://github.com/ExampleName/myVault.git
git push -u origin main
```
## Set Up Your Vault
Add and enable the Git Community Plugin.
%% TODO: %%
+3
View File
@@ -7,10 +7,13 @@ tags:
- destiny/permanent
- status/incomplete
- type/encyclopedia-entry
dg-publish: true
---
# C\#
C\# (read "C sharp", like the [[music-theory|musical]] symbol)
is modern high-level [[programming-languages|language]]
supporting [[object-oriented-programing|object-oriented]] patterns.
It is the sane man's Java.
+1 -1
View File
@@ -11,4 +11,4 @@ dg-publish: true
---
# 2026-01-01
Made recipe: Granola
Made recipe: [[granola]]
+15
View File
@@ -0,0 +1,15 @@
---
id: 2026-02-05
aliases: []
title: 2026-02-05
tags:
- authorship/original
- destiny/permanent
- status/draft
- type/periodic/daily
date-created: 2026-03-08T19:22:24-04:00
dg-publish: true
---
# 2026-02-05
Made recipe: [[granola]]
+19
View File
@@ -0,0 +1,19 @@
---
id: 2026-02-09
aliases: []
title: 2026-02-09
tags:
- authorship/original
- destiny/permanent
- status/draft
- type/periodic/daily
dg-publish: true
date-created: 2026-02-09T19:25:20-05:00
weekly: "[[2026-W07]]"
monthly: "[[2026-02]]"
quarterly: "[[2026-Q1]]"
yearly: "[[2026]]"
---
# 2026-02-09
Made recipe: [[granola ]]
+19
View File
@@ -0,0 +1,19 @@
---
id: 2026-02-12
aliases: []
title: 2026-02-12
tags:
- authorship/original
- destiny/permanent
- status/draft
- type/periodic/daily
dg-publish: true
date-created: 2026-02-12T19:25:36-05:00
weekly: "[[2026-W07]]"
monthly: "[[2026-02]]"
quarterly: "[[2026-Q1]]"
yearly: "[[2026]]"
---
# 2026-02-12
Made recipe: [[granola]]
+19
View File
@@ -0,0 +1,19 @@
---
id: 2026-02-15
aliases: []
title: 2026-02-15
tags:
- authorship/original
- destiny/permanent
- status/draft
- type/periodic/daily
date-created: 2026-02-15T19:26:03-05:00
dg-publish: true
monthly: "[[2026-02]]"
quarterly: "[[2026-Q1]]"
weekly: "[[2026-W07]]"
yearly: "[[2026]]"
---
# 2026-02-15
Made recipe: [[granola]]
+19
View File
@@ -0,0 +1,19 @@
---
id: 2026-02-18
aliases: []
title: 2026-02-18
tags:
- authorship/original
- destiny/permanent
- status/draft
- type/periodic/daily
dg-publish: true
date-created: 2026-02-18T19:26:30-05:00
weekly: "[[2026-W08]]"
monthly: "[[2026-02]]"
quarterly: "[[2026-Q1]]"
yearly: "[[2026]]"
---
# 2026-02-18
Made recipe: [[granola]]
+19
View File
@@ -0,0 +1,19 @@
---
id: 2026-02-19
aliases: []
title: 2026-02-19
tags:
- authorship/original
- destiny/permanent
- status/draft
- type/periodic/daily
dg-publish: true
date-created: 2026-02-19T19:26:53-05:00
weekly: "[[2026-W08]]"
monthly: "[[2026-02]]"
quarterly: "[[2026-Q1]]"
yearly: "[[2026]]"
---
# 2026-02-19
Made recipe: [[red-beans-and-rice]]
+19
View File
@@ -0,0 +1,19 @@
---
id: 2026-02-22
aliases: []
title: 2026-02-22
tags:
- authorship/original
- destiny/permanent
- status/draft
- type/periodic/daily
dg-publish: true
date-created: 2026-02-22T19:27:17-05:00
weekly: "[[2026-W08]]"
monthly: "[[2026-02]]"
quarterly: "[[2026-Q1]]"
yearly: "[[2026]]"
---
# 2026-02-22
Made recipe: [[french-toast]]
+19
View File
@@ -0,0 +1,19 @@
---
id: 2026-02-24
aliases: []
title: 2026-02-24
tags:
- authorship/original
- destiny/permanent
- status/draft
- type/periodic/daily
date-created: 2026-02-24T19:27:37-05:00
dg-publish: true
monthly: "[[2026-02]]"
quarterly: "[[2026-Q1]]"
weekly: "[[2026-W09]]"
yearly: "[[2026]]"
---
# 2026-02-24
Made recipe: [[granola]]
+17
View File
@@ -0,0 +1,17 @@
---
id: 2026-02-27
aliases: []
title: 2026-02-27
tags:
- authorship/original
- destiny/permanent
- status/draft
- type/periodic/daily
dg-publish: true
date-created: 2026-02-27T09:44:15-05:00
weekly: "[[2026-W09]]"
monthly: "[[2026-02]]"
quarterly: "[[2026-Q1]]"
yearly: "[[2026]]"
---
# 2026-02-27
+19
View File
@@ -0,0 +1,19 @@
---
id: 2026-02-28
aliases: []
title: 2026-02-28
tags:
- authorship/original
- destiny/permanent
- status/draft
- type/periodic/daily
date-created: 2026-02-28T09:44:05-05:00
dg-publish: true
monthly: "[[2026-02]]"
quarterly: "[[2026-Q1]]"
weekly: "[[2026-W09]]"
yearly: "[[2026]]"
---
# 2026-02-28
Made recipe: [[granola]]
+17
View File
@@ -0,0 +1,17 @@
---
id: 2026-03-01
aliases: []
title: 2026-03-01
tags:
- authorship/original
- destiny/permanent
- status/draft
- type/periodic/daily
dg-publish: true
date-created: 2026-03-01T09:43:00-05:00
weekly: "[[2026-W09]]"
monthly: "[[2026-03]]"
quarterly: "[[2026-Q1]]"
yearly: "[[2026]]"
---
# 2026-03-01
+19
View File
@@ -0,0 +1,19 @@
---
id: 2026-03-02
aliases: []
title: 2026-03-02
tags:
- authorship/original
- destiny/permanent
- status/draft
- type/periodic/daily
date-created: 2026-03-02T19:28:12-05:00
dg-publish: true
monthly: "[[2026-03]]"
quarterly: "[[2026-Q1]]"
weekly: "[[2026-W10]]"
yearly: "[[2026]]"
---
# 2026-03-02
Made recipe: [[granola]]
+23
View File
@@ -0,0 +1,23 @@
---
id: 2026-03-05
aliases: []
title: 2026-03-05
tags:
- authorship/original
- destiny/permanent
- status/draft
- type/periodic/daily
dg-publish: true
date-created: 2026-03-05T08:30:04-05:00
weekly: "[[2026-W10]]"
monthly: "[[2026-03]]"
quarterly: "[[2026-Q1]]"
yearly: "[[2026]]"
---
# 2026-03-05
## TODO
* [ ] Cancel renter's insurance
* [ ] Start [St Pete utilities](https://pinellas.gov/services/request-utilities-service/)
* [ ] Order washer/dryer
+19
View File
@@ -0,0 +1,19 @@
---
id: 2026-03-06
aliases: []
title: 2026-03-06
tags:
- authorship/original
- destiny/permanent
- status/draft
- type/periodic/daily
dg-publish: true
date-created: 2026-03-06T19:28:45-05:00
weekly: "[[2026-W10]]"
monthly: "[[2026-03]]"
quarterly: "[[2026-Q1]]"
yearly: "[[2026]]"
---
# 2026-03-06
Made recipe: [[granola ]]
+19
View File
@@ -0,0 +1,19 @@
---
id: 2026-03-08
aliases: []
title: 2026-03-08
tags:
- authorship/original
- destiny/permanent
- status/draft
- type/periodic/daily
dg-publish: true
date-created: 2026-03-08T08:12:41-04:00
weekly: "[[2026-W10]]"
monthly: "[[2026-03]]"
quarterly: "[[2026-Q1]]"
yearly: "[[2026]]"
---
# 2026-03-08
Made recipe: [[granola]]
+6 -2
View File
@@ -2,7 +2,11 @@
id:
aliases: []
title: Digital Garden Homepage
tags: []
tags:
- authorship/original
- destiny/permanent/entry-point
- status/incomplete
- topic/meta
dg-home: true
dg-publish: true
---
@@ -47,7 +51,7 @@ see [[complaints]] for how you can help me fix it.
### Broken Links
The private repository from which this site is built includes copyrighted materials,
(which I own and have personally digitized, as is my right by case law)
(which I own and have personally digitized, as is my right, supported by case law)
of note, nearly the entirety of the [[nfpa-70_national-electric-code|NEC]],
which [[conductor-sizing]] and [[alternating-current]] frequently reference.
Because this website is public I choose not to publish those materials here,
+1 -1
View File
@@ -78,7 +78,7 @@ for consistency.
> Name = "Power Monitor"
See [[switchgear#SPD's/TVSS's]]
See [[switchgear-takeoff#SPD's/TVSS's]]
### Switchboards
+1
View File
@@ -7,6 +7,7 @@ tags:
- destiny/permanent
- type/task
- status/incomplete
dg-publish: true
---
# E-Ink Tablet
@@ -0,0 +1,26 @@
---
id:
aliases: []
title: Earned Value Management in Construction Estimating
tags:
- authorship/original
- destiny/permanent
- status/incomplete
- type/cross-topic
---
# Earned Value Management in Construction Estimating
Cross topic of [[earned-value-management]] and [[construction-estimating]].
The construction industry was an early adopter of EVM[^1]
[^1]: [Wikipedia](https://en.wikipedia.org/wiki/Earned_value_management)
I am not a fan of EVM as it is commonly used in construction
since its spurious claims of objectivity
are accepted without qualification.
Estimating is systematically absolved of error,
which is blamed on operations
(estimate accuracy is not incentivized).
[[purpose-of-construction-estimating#The Myth of Estimate Accuracy]]
+8 -1
View File
@@ -8,6 +8,7 @@ tags:
- status/incomplete
- topic/ergonomics/organizational
- type/encyclopedia-entry
dg-publish: true
---
# Earned Value Management
@@ -17,8 +18,14 @@ is a [[project-management]] technique
EVM is frequently stated to be capable of
"measuring project performance and progress
in an _objective_ manner",[^1]
_in an objective manner_",[^1]
an analysis that is either optimistic
or totally misleading, depending on the context.
[^1]: [Wikipedia](https://en.wikipedia.org/wiki/Earned_value_management) (emphasis added)
EVM can be an objective measure of _progress_,
but measuring _performance_,
variance of actual cost/hours versus estimated,
(obviously) requires an estimate,
which is subject to bias and error.
+49
View File
@@ -0,0 +1,49 @@
---
id:
aliases: []
title: Eggroll in a Bowl
tags:
- authorship/original
- destiny/permanent
- topic/hobbies/cooking
- type/recipe
---
# Eggroll in a Bowl
## Ingredients
* **1 lb** ground pork, beef, or turkey
* **1 tbsp.** sesame oil
* **1 tbsp.** minced garlic
* **1 tbsp.** minced ginger
* **8 oz** mushrooms, finely diced
* **12** white or yellow onion, diced
* **14 cup** low-sodium soy sauce
* **1 tbsp.** fish sauce
* **12--16 oz** cole slaw mix (1 package)
* **2 tbsp.** rice wine vinegar
* **1 tbsp.** hoisin sauce
* **1 tbsp.** sriracha or gochujang
## Directions
1. Heat the **oil** in a large pot at medium high.
Add the **ground meat** and cook until browned.
2. Add the **garlic**, **ginger**, **mushrooms**, and **onion**.
Saute ~~briefly~~.
3. Add the **soy sauce** and **fish sauce**.
Mix to combine.
4. Pour the **cole slaw mix** on top, but do not stir.
Cover and cook on medium low heat for 10 minutes
5. Stir and deglaze with the **vinegar**.
If cabbage isn't cooked all the way cover again for a few minutes.
6. Remove from heat.
Stir in the **hoisin sauce** and **sriracha or gochujang**.
7. Serve with wonton strips or over rice.
+2
View File
@@ -55,6 +55,8 @@ even where serving Amenity spaces.
Clubline Raceway, also called CRG Raceway,
is a glorified cable management trough.
It is not a [[nfpa-70_376_metal-wireways|wireway]],
so conductors must be run in a [[nfpa-70_national-electric-code#Chapter 3 Wiring Methods and Materials|Chapter 3]] wiring method.
Count receptacles normally,
using ==surface-mount EMT assemblies==.
+5 -3
View File
@@ -1,10 +1,12 @@
---
id:
aliases: []
title:
title: Elliot St. Hotel
tags:
- authorship/original
- destiny/permanent
- status/not-started
- occupational/project
---
- status/not-started
dg-publish: true
---
# Elliot St. Hotel
+2 -1
View File
@@ -7,7 +7,8 @@ tags:
- authorship/original
- destiny/permanent/entry-point
- status/incomplete
- type/supertopic
- type/encyclopedia
dg-publish: true
---
# Ergonomics
+19 -6
View File
@@ -1,20 +1,34 @@
---
id:
aliases: []
title: Estimate Laboring
tags:
- authorship/original
- destiny/permanent
- status/incomplete
- topic/automation
- topic/estimating
- topic/software
- type/idea
- authorship/original
title: Labor Factoring
- type/encyclopedia-entry
dg-publish: true
---
# Labor Factoring
# Estimate Laboring
In construction estimating,
**laboring** is the process of calculating the labor hours required
to install takeoff material.
## Labor Factoring
**Labor factoring** is the adjustment of base labor hours
to account for adverse or beneficial working conditions.
Labor factors are most often used to increase labor,
but decrease is also possible,
especially efficiency gains due to repetitive work.
%%
## TODO
Discuss purpose and practice of labor factoring,
@@ -81,7 +95,6 @@ can be converted to functions using regressions.
## Going Further
Base labor units suggest a highly functional nature,
most sensitive to weight.
most sensitive to _weight_.
Greater understanding of this relationship would make practical
the prediction of labor of unstudied items.
+2 -1
View File
@@ -8,7 +8,8 @@ tags:
- status/not-started
- topic/estimating
- type/encyclopedia-entry
dg-publish: true
---
# Estimating Golf
[[2025-12-18#Estimating Golf]]
[[2025-12-18_14-18-00]]
+3 -4
View File
@@ -113,7 +113,7 @@ much more so to dismiss the tests used to prove the validity of statistical meth
### False Lucky Fools
Taleb repeatedly conflates legitimate lucky fools
Taleb repeatedly conflates legitimate [[lucky-fools|lucky fools]]
and people with ideas he doesn't like.
> [[hubbard_2020_failure]]
@@ -133,12 +133,11 @@ One of many problems with this presentation
is that John is described as young, inexperienced,
and of low intelligence.
John is a typical lucky fool:
there is no indication that he has any strategy,
much less that he is practicing modern portfolio theory.
there is no indication that he has _any_ strategy,
much less that he is practicing [[modern-portfolio-theory]].
If I mistake Taleb's intent,
and the story was only meant to convey
that experienced, conscientious, and cautious decision-making
_can_ lead a person to success,
then I'm not sure who he's arguing against.
+48
View File
@@ -0,0 +1,48 @@
---
id:
aliases: []
title: French Toast
tags:
- authorship/original
- destiny/permanent
- topic/hobbies/cooking
- type/recipe
---
# French Toast
## Ingredients
* **4** large eggs or **1 cup** egg substitute
* **23 cup** milk
* **14 cup** all-purpose flour
* **14 cup** granulated sugar
* **14 tsp.** salt
* **1 tsp.** ground cinnamon
* **1 tsp.** vanilla extract
* **8** thick slices bread
## Instructions
1. Whisk together the eggs, milk, flour, sugar, salt, cinnamon, and vanilla.
2. Dip bread slices into the batter, dredging them well on both sides.
Place on a greased skillet over medium heat.
3. Cook until the bottom of the bread starts to turn golden brown.
Flip and cook on the other side the same.
4. Remove to a plate. Serve warm with syrup and a sprinkle of powdered sugar.
## Notes
* Bread that is slightly stale is preferable.
* Any kind of milk, even dairy-free, will work.
Higher fat milk will yield creamier batter.
* The batter can be made up to 2 days ahead of cooking.
* To freeze, allow french toast cool completely
before storing in a freezer-safe bag or container for up to 3 months.
Rewarm on a skillet, in the toaster, or for a few seconds in the microwave.
+2 -1
View File
@@ -61,4 +61,5 @@ dg-publish: true
## Next Steps
[[pdi-accubid-closeout]]
1. [[pdi-accubid-closeout]]
2. [[pdi-wbs]]
+2 -2
View File
@@ -45,8 +45,8 @@ dg-publish: true
| Hunter A \ Hunter B | Hunter B: Hunt Stag | Hunter B: Hunt Hare |
|:------------------- |:--------------------:|:--------------------:|
| Hunter A: Hunt Stag | Eat stag \ Eat stag | Go hungry \ Eat hare |
| Hunter A: Hunt Hare | Eat hare \ Go hungry | Eat hare \ Eat hare |
| **Hunter A: Hunt Stag** | Eat stag \ Eat stag | Go hungry \ Eat hare |
| **Hunter A: Hunt Hare** | Eat hare \ Go hungry | Eat hare \ Eat hare |
### Ultimatum Game
+15
View File
@@ -0,0 +1,15 @@
---
id:
aliases: []
title: Git
tags:
- authorship/original
- destiny/permanent
- status/not-started
dg-publish: true
---
# Git
[Git](https://git-scm.com/) is a **version control system**
Git was created by Linus Torvalds
+54
View File
@@ -0,0 +1,54 @@
---
id:
aliases: []
title: Goulash
tags:
- authorship/original
- destiny/permanent
- topic/hobbies/cooking
- type/recipe
---
# Goulash
## Ingredients
* **1 tbsp.** olive oil
* **1** yellow onion, diced
* **4** cloves garlic, minced
* **2** bell peppers, diced
* **1 lb** ground beef, turkey, or pork
* **12 cup** red wine (Cabernet Sauvignon)
* **(1) 28oz can** canned diced tomatoes (do not drain)
* **(1) 15oz can** canned tomato sauce
* **2 tbsp.** soy sauce
* **12 cup** water
* **8 oz** dry elbow macaroni
* **? tsp.** table salt
### Spices
* **2** whole bay leaves
* **12 tsp.** dried oregano
* **12 tsp.** dried basil
* **14 tsp.** crushed red pepper
## Instructions
1. Heat the **olive oil** in a large soup pot over medium heat.
Add the **onion** and **garlic** and sauté until the onions are translucent.
2. Add the **bell peppers** and continue to sauté for about two minutes more.
3. Add the **ground meat** and continue to sauté until the beef is cooked through.
4. Deglaze with the **red wine**.
Add the **diced tomatoes**, **tomato sauce**, **soy sauce**, **spices**, and **water**.
Stir to combine, then cover and allow the sauce to come to a boil.
Once boiling, turn down the heat to low and simmer for 30 minutes, stirring occasionally.
5. Add the pasta and stir to combine.
Re-cover and simmer, stirring occasionally, until the pasta is tender (10--12 minutes).
6. Remove from heat.
Add salt and more to taste.
Remove the bay leaves before serving.
+5 -3
View File
@@ -1,10 +1,12 @@
---
id:
aliases: []
title:
title: Grand Concourse
tags:
- authorship/original
- destiny/permanent
- status/not-started
- occupational/project
---
- status/not-started
dg-publish: true
---
# Grand Concourse
+54
View File
@@ -0,0 +1,54 @@
---
id:
aliases: []
title: Granola
tags:
- authorship/original
- destiny/permanent
- topic/hobbies/cooking
- type/recipe
---
# Granola
## Ingredients
* **2 cups** old-fashioned rolled oats
* **34 cup** raw nuts and/or seeds
* **12 tsp.** fine-grain sea salt or standard table salt
* **14 tsp.** ground cinnamon
* **14 cup** melted coconut oil or olive oil
* **14 cup** maple syrup or honey
* **12 tsp.** vanilla extract
* **14 cup** coconut flakes
## Instructions
1. Preheat oven to 350°F and line a large, rimmed baking sheet with parchment paper.
2. In a large mixing bowl, combine the **oats**, **nuts and/or seeds**, **salt**, and **cinnamon**.
Stir to blend.
3. Pour in the **oil**, **maple syrup or honey**, and **vanilla**.
Mix well, until every oat is lightly coated.
Pour the granola onto the prepared pan
and use a large spoon to spread it into an even layer.
4. Bake for 10 minutes, add **coconut flakes** and stir.
Press the stirred granola into the pan with a spatula to create a more even layer.
5. Bake until lightly golden (10--12 minutes).
6. Let the granola cool completely, undisturbed (at least 45 minutes).
## Notes
* Store in an airtight container at room temperature for up to 2 weeks,
or in a sealed freezer bag in the freezer for up to 3 months.
* Use olive oil for a slightly savory granola,
or coconut oil for a more neutral flavor.
* Use maple syrup for a sweet, distinctly maple-flavored granola
with few or no clumps.
Use honey for a more neutral flavored, clumpy granola.

Some files were not shown because too many files have changed in this diff Show More