From b3ac5b80663ec6416cc1a433ff7046923c087844 Mon Sep 17 00:00:00 2001 From: asserthq Date: Wed, 20 May 2026 16:42:03 +0700 Subject: [PATCH] vault backup: 2026-05-20 16:42:03 --- .gitattributes | 1 + .gitignore | 7 + .obsidian/app.json | 7 + .obsidian/community-plugins.json | 10 + .obsidian/core-plugins.json | 33 + .obsidian/plugins/d2-obsidian/main.js | 535 + .obsidian/plugins/d2-obsidian/manifest.json | 10 + .obsidian/plugins/d2-obsidian/styles.css | 49 + .obsidian/plugins/drawio-obsidian/data.json | 11 + .obsidian/plugins/drawio-obsidian/main.js | 17 + .../plugins/drawio-obsidian/manifest.json | 10 + .obsidian/plugins/drawio-obsidian/styles.css | 28 + .obsidian/plugins/excel/main.js | 47153 ++++++++++++++++ .obsidian/plugins/excel/manifest.json | 11 + .obsidian/plugins/excel/styles.css | 1177 + .../obsidian-excel-to-markdown-table/main.js | 230 + .../manifest.json | 10 + .../styles.css | 1 + .obsidian/plugins/obsidian-git/data.json | 68 + .obsidian/plugins/obsidian-git/main.js | 452 + .obsidian/plugins/obsidian-git/manifest.json | 10 + .../plugins/obsidian-git/obsidian_askpass.sh | 23 + .obsidian/plugins/obsidian-git/styles.css | 710 + .obsidian/plugins/obsidian-plantuml/main.js | 7938 +++ .../plugins/obsidian-plantuml/manifest.json | 10 + .../plugins/obsidian-plantuml/styles.css | 38 + .obsidian/plugins/omnisearch/data.json | 42 + .obsidian/plugins/omnisearch/main.js | 171 + .obsidian/plugins/omnisearch/manifest.json | 14 + .obsidian/plugins/omnisearch/styles.css | 135 + .obsidian/plugins/pdf-plus/data.json | 326 + .obsidian/plugins/pdf-plus/main.js | 161 + .obsidian/plugins/pdf-plus/manifest.json | 15 + .obsidian/plugins/pdf-plus/styles.css | 694 + README.md | 22 + attachments/Pasted image 20260503222243.png | 3 + attachments/Pasted image 20260503235922.png | 3 + attachments/Pasted image 20260504022452.png | 3 + attachments/Pasted image 20260515140803.png | 3 + attachments/Pasted image 20260515141623.png | 3 + attachments/Pasted image 20260515141633.png | 3 + attachments/Pasted image 20260518170400.png | 3 + attachments/Лелеков Вестник Ed1.pdf | 3 + hello.md | 1 + stm32.md | 3 + база/0_Миссия/Mission_REQ.md | 0 база/1_Система/System_REQ.md | 0 база/1_Система/архитектура.md | 0 база/1_Система/баллистический расчет.md | 0 база/1_Система/бюджет данных.md | 0 база/1_Система/бюджет масс.md | 0 база/1_Система/бюджет радиолиний.md | 0 база/1_Система/концепция.md | 0 база/1_Система/космический сегмент.md | 2 + база/1_Система/наземный сегмент.md | 0 база/1_Система/пользовательский сегмент.md | 0 база/1_Система/система IoT.md | 15 + база/1_Система/энергетический бюджет.md | 0 база/2_Аппарат/Satellite_REQ.md | 0 база/2_Аппарат/МКА.md | 9 + база/3_СОС/ADCS_Architecture.md | 0 база/3_СОС/ADCS_Modes.md | 23 + база/3_СОС/ADCS_Overview.md | 11 + база/3_СОС/ADCS_REQ.md | 3 + база/3_СОС/REQ/REQ-ADCS-001.md | 12 + база/3_СОС/REQ/REQ-ADCS-002.md | 12 + база/3_СОС/REQ/REQ-ADCS-003.md | 12 + база/3_СОС/СОС.md | 5 + база/3_СОС/актуаторы.md | 0 база/3_СОС/датчики.md | 0 база/3_СОС/декомпозиция/сос.md | 72 + база/3_СОС/декомпозиция/уровень 0.md | 13 + база/3_СОС/декомпозиция/уровень 1.md | 70 + база/3_СОС/испытания.md | 0 база/3_СОС/софт.md | 0 база/3_СОС/требования.md | 0 база/3_СОС/функции.md | 0 база/3_СЭП/EPS_REQ.md | 0 база/3_СЭП/СЭП.md | 0 база/3_ТМТК/TMTC_REQ.md | 0 база/3_ТМТК/ТМТК.md | 0 база/КПЭО.md | 0 база/МИССИЯ.md | 8 + база/Проект/дорожная карта.md | 0 база/верификация.md | 0 база/требования.md | 0 база/уровни.md | 11 + полезное/бортовая система.md | 60 + полезное/платформа.md | 6 + полезное/система ориентации.md | 235 + полезное/система электропитания.md | 1 + санч/rust.md | 17 + санч/t.md | 7 + санч/КПА.md | 6 + санч/вопросы.md | 30 + санч/лекция 29.04.md | 40 + санч/лекция Громова.md | 47 + санч/полезное от Лелекова.md | 10 + этап 3/СОС.md | 2 + .../программа и методика испытаний подсистем.md | 1 + этап 3/сос/изменения в СОС.md | 110 + этап 3/сос/испытания.md | 0 этап 3/сос/требования.md | 0 103 files changed, 61007 insertions(+) create mode 100644 .gitattributes create mode 100644 .gitignore create mode 100644 .obsidian/app.json create mode 100644 .obsidian/community-plugins.json create mode 100644 .obsidian/core-plugins.json create mode 100644 .obsidian/plugins/d2-obsidian/main.js create mode 100644 .obsidian/plugins/d2-obsidian/manifest.json create mode 100644 .obsidian/plugins/d2-obsidian/styles.css create mode 100644 .obsidian/plugins/drawio-obsidian/data.json create mode 100644 .obsidian/plugins/drawio-obsidian/main.js create mode 100644 .obsidian/plugins/drawio-obsidian/manifest.json create mode 100644 .obsidian/plugins/drawio-obsidian/styles.css create mode 100644 .obsidian/plugins/excel/main.js create mode 100644 .obsidian/plugins/excel/manifest.json create mode 100644 .obsidian/plugins/excel/styles.css create mode 100644 .obsidian/plugins/obsidian-excel-to-markdown-table/main.js create mode 100644 .obsidian/plugins/obsidian-excel-to-markdown-table/manifest.json create mode 100644 .obsidian/plugins/obsidian-excel-to-markdown-table/styles.css create mode 100644 .obsidian/plugins/obsidian-git/data.json create mode 100644 .obsidian/plugins/obsidian-git/main.js create mode 100644 .obsidian/plugins/obsidian-git/manifest.json create mode 100644 .obsidian/plugins/obsidian-git/obsidian_askpass.sh create mode 100644 .obsidian/plugins/obsidian-git/styles.css create mode 100644 .obsidian/plugins/obsidian-plantuml/main.js create mode 100644 .obsidian/plugins/obsidian-plantuml/manifest.json create mode 100644 .obsidian/plugins/obsidian-plantuml/styles.css create mode 100644 .obsidian/plugins/omnisearch/data.json create mode 100644 .obsidian/plugins/omnisearch/main.js create mode 100644 .obsidian/plugins/omnisearch/manifest.json create mode 100644 .obsidian/plugins/omnisearch/styles.css create mode 100644 .obsidian/plugins/pdf-plus/data.json create mode 100644 .obsidian/plugins/pdf-plus/main.js create mode 100644 .obsidian/plugins/pdf-plus/manifest.json create mode 100644 .obsidian/plugins/pdf-plus/styles.css create mode 100644 README.md create mode 100644 attachments/Pasted image 20260503222243.png create mode 100644 attachments/Pasted image 20260503235922.png create mode 100644 attachments/Pasted image 20260504022452.png create mode 100644 attachments/Pasted image 20260515140803.png create mode 100644 attachments/Pasted image 20260515141623.png create mode 100644 attachments/Pasted image 20260515141633.png create mode 100644 attachments/Pasted image 20260518170400.png create mode 100644 attachments/Лелеков Вестник Ed1.pdf create mode 100644 hello.md create mode 100644 stm32.md create mode 100644 база/0_Миссия/Mission_REQ.md create mode 100644 база/1_Система/System_REQ.md create mode 100644 база/1_Система/архитектура.md create mode 100644 база/1_Система/баллистический расчет.md create mode 100644 база/1_Система/бюджет данных.md create mode 100644 база/1_Система/бюджет масс.md create mode 100644 база/1_Система/бюджет радиолиний.md create mode 100644 база/1_Система/концепция.md create mode 100644 база/1_Система/космический сегмент.md create mode 100644 база/1_Система/наземный сегмент.md create mode 100644 база/1_Система/пользовательский сегмент.md create mode 100644 база/1_Система/система IoT.md create mode 100644 база/1_Система/энергетический бюджет.md create mode 100644 база/2_Аппарат/Satellite_REQ.md create mode 100644 база/2_Аппарат/МКА.md create mode 100644 база/3_СОС/ADCS_Architecture.md create mode 100644 база/3_СОС/ADCS_Modes.md create mode 100644 база/3_СОС/ADCS_Overview.md create mode 100644 база/3_СОС/ADCS_REQ.md create mode 100644 база/3_СОС/REQ/REQ-ADCS-001.md create mode 100644 база/3_СОС/REQ/REQ-ADCS-002.md create mode 100644 база/3_СОС/REQ/REQ-ADCS-003.md create mode 100644 база/3_СОС/СОС.md create mode 100644 база/3_СОС/актуаторы.md create mode 100644 база/3_СОС/датчики.md create mode 100644 база/3_СОС/декомпозиция/сос.md create mode 100644 база/3_СОС/декомпозиция/уровень 0.md create mode 100644 база/3_СОС/декомпозиция/уровень 1.md create mode 100644 база/3_СОС/испытания.md create mode 100644 база/3_СОС/софт.md create mode 100644 база/3_СОС/требования.md create mode 100644 база/3_СОС/функции.md create mode 100644 база/3_СЭП/EPS_REQ.md create mode 100644 база/3_СЭП/СЭП.md create mode 100644 база/3_ТМТК/TMTC_REQ.md create mode 100644 база/3_ТМТК/ТМТК.md create mode 100644 база/КПЭО.md create mode 100644 база/МИССИЯ.md create mode 100644 база/Проект/дорожная карта.md create mode 100644 база/верификация.md create mode 100644 база/требования.md create mode 100644 база/уровни.md create mode 100644 полезное/бортовая система.md create mode 100644 полезное/платформа.md create mode 100644 полезное/система ориентации.md create mode 100644 полезное/система электропитания.md create mode 100644 санч/rust.md create mode 100644 санч/t.md create mode 100644 санч/КПА.md create mode 100644 санч/вопросы.md create mode 100644 санч/лекция 29.04.md create mode 100644 санч/лекция Громова.md create mode 100644 санч/полезное от Лелекова.md create mode 100644 этап 3/СОС.md create mode 100644 этап 3/программа и методика испытаний подсистем.md create mode 100644 этап 3/сос/изменения в СОС.md create mode 100644 этап 3/сос/испытания.md create mode 100644 этап 3/сос/требования.md diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..42f4c8e --- /dev/null +++ b/.gitattributes @@ -0,0 +1 @@ +attachments/** filter=lfs diff=lfs merge=lfs -text diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..774d106 --- /dev/null +++ b/.gitignore @@ -0,0 +1,7 @@ +.obsidian/* + +# исключения (не игнорируем) +!.obsidian/core-plugins.json +!.obsidian/community-plugins.json +!.obsidian/app.json +!.obsidian/plugins/ diff --git a/.obsidian/app.json b/.obsidian/app.json new file mode 100644 index 0000000..e4c706e --- /dev/null +++ b/.obsidian/app.json @@ -0,0 +1,7 @@ +{ + "attachmentFolderPath": "/attachments", + "alwaysUpdateLinks": true, + "showUnsupportedFiles": true, + "readableLineLength": true, + "promptDelete": false +} \ No newline at end of file diff --git a/.obsidian/community-plugins.json b/.obsidian/community-plugins.json new file mode 100644 index 0000000..68b2527 --- /dev/null +++ b/.obsidian/community-plugins.json @@ -0,0 +1,10 @@ +[ + "obsidian-git", + "omnisearch", + "pdf-plus", + "obsidian-excel-to-markdown-table", + "excel", + "drawio-obsidian", + "d2-obsidian", + "obsidian-plantuml" +] \ No newline at end of file diff --git a/.obsidian/core-plugins.json b/.obsidian/core-plugins.json new file mode 100644 index 0000000..639b90d --- /dev/null +++ b/.obsidian/core-plugins.json @@ -0,0 +1,33 @@ +{ + "file-explorer": true, + "global-search": true, + "switcher": true, + "graph": true, + "backlink": true, + "canvas": true, + "outgoing-link": true, + "tag-pane": true, + "footnotes": false, + "properties": true, + "page-preview": true, + "daily-notes": true, + "templates": true, + "note-composer": true, + "command-palette": true, + "slash-command": false, + "editor-status": true, + "bookmarks": true, + "markdown-importer": false, + "zk-prefixer": false, + "random-note": false, + "outline": true, + "word-count": true, + "slides": false, + "audio-recorder": false, + "workspaces": false, + "file-recovery": true, + "publish": false, + "sync": true, + "bases": true, + "webviewer": false +} \ No newline at end of file diff --git a/.obsidian/plugins/d2-obsidian/main.js b/.obsidian/plugins/d2-obsidian/main.js new file mode 100644 index 0000000..0afed0f --- /dev/null +++ b/.obsidian/plugins/d2-obsidian/main.js @@ -0,0 +1,535 @@ +/* +THIS IS A GENERATED/BUNDLED FILE BY ESBUILD +if you want to view the source, please visit the github repository of this plugin: https://github.com/terrastruct/d2-obsidian +*/ +var __create = Object.create; +var __defProp = Object.defineProperty; +var __getOwnPropDesc = Object.getOwnPropertyDescriptor; +var __getOwnPropNames = Object.getOwnPropertyNames; +var __getProtoOf = Object.getPrototypeOf; +var __hasOwnProp = Object.prototype.hasOwnProperty; +var __commonJS = (cb, mod) => function __require() { + return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports; +}; +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 __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, mod)); +var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); + +// node_modules/lodash.debounce/index.js +var require_lodash = __commonJS({ + "node_modules/lodash.debounce/index.js"(exports, module2) { + var FUNC_ERROR_TEXT = "Expected a function"; + var NAN = 0 / 0; + var symbolTag = "[object Symbol]"; + var reTrim = /^\s+|\s+$/g; + var reIsBadHex = /^[-+]0x[0-9a-f]+$/i; + var reIsBinary = /^0b[01]+$/i; + var reIsOctal = /^0o[0-7]+$/i; + var freeParseInt = parseInt; + var freeGlobal = typeof global == "object" && global && global.Object === Object && global; + var freeSelf = typeof self == "object" && self && self.Object === Object && self; + var root = freeGlobal || freeSelf || Function("return this")(); + var objectProto = Object.prototype; + var objectToString = objectProto.toString; + var nativeMax = Math.max; + var nativeMin = Math.min; + var now = function() { + return root.Date.now(); + }; + function debounce2(func, wait, options) { + var lastArgs, lastThis, maxWait, result, timerId, lastCallTime, lastInvokeTime = 0, leading = false, maxing = false, trailing = true; + if (typeof func != "function") { + throw new TypeError(FUNC_ERROR_TEXT); + } + wait = toNumber(wait) || 0; + if (isObject(options)) { + leading = !!options.leading; + maxing = "maxWait" in options; + maxWait = maxing ? nativeMax(toNumber(options.maxWait) || 0, wait) : maxWait; + trailing = "trailing" in options ? !!options.trailing : trailing; + } + function invokeFunc(time) { + var args = lastArgs, thisArg = lastThis; + lastArgs = lastThis = void 0; + lastInvokeTime = time; + result = func.apply(thisArg, args); + return result; + } + function leadingEdge(time) { + lastInvokeTime = time; + timerId = setTimeout(timerExpired, wait); + return leading ? invokeFunc(time) : result; + } + function remainingWait(time) { + var timeSinceLastCall = time - lastCallTime, timeSinceLastInvoke = time - lastInvokeTime, result2 = wait - timeSinceLastCall; + return maxing ? nativeMin(result2, maxWait - timeSinceLastInvoke) : result2; + } + function shouldInvoke(time) { + var timeSinceLastCall = time - lastCallTime, timeSinceLastInvoke = time - lastInvokeTime; + return lastCallTime === void 0 || timeSinceLastCall >= wait || timeSinceLastCall < 0 || maxing && timeSinceLastInvoke >= maxWait; + } + function timerExpired() { + var time = now(); + if (shouldInvoke(time)) { + return trailingEdge(time); + } + timerId = setTimeout(timerExpired, remainingWait(time)); + } + function trailingEdge(time) { + timerId = void 0; + if (trailing && lastArgs) { + return invokeFunc(time); + } + lastArgs = lastThis = void 0; + return result; + } + function cancel() { + if (timerId !== void 0) { + clearTimeout(timerId); + } + lastInvokeTime = 0; + lastArgs = lastCallTime = lastThis = timerId = void 0; + } + function flush() { + return timerId === void 0 ? result : trailingEdge(now()); + } + function debounced() { + var time = now(), isInvoking = shouldInvoke(time); + lastArgs = arguments; + lastThis = this; + lastCallTime = time; + if (isInvoking) { + if (timerId === void 0) { + return leadingEdge(lastCallTime); + } + if (maxing) { + timerId = setTimeout(timerExpired, wait); + return invokeFunc(lastCallTime); + } + } + if (timerId === void 0) { + timerId = setTimeout(timerExpired, wait); + } + return result; + } + debounced.cancel = cancel; + debounced.flush = flush; + return debounced; + } + function isObject(value) { + var type = typeof value; + return !!value && (type == "object" || type == "function"); + } + function isObjectLike(value) { + return !!value && typeof value == "object"; + } + function isSymbol(value) { + return typeof value == "symbol" || isObjectLike(value) && objectToString.call(value) == symbolTag; + } + function toNumber(value) { + if (typeof value == "number") { + return value; + } + if (isSymbol(value)) { + return NAN; + } + if (isObject(value)) { + var other = typeof value.valueOf == "function" ? value.valueOf() : value; + value = isObject(other) ? other + "" : other; + } + if (typeof value != "string") { + return value === 0 ? value : +value; + } + value = value.replace(reTrim, ""); + var isBinary = reIsBinary.test(value); + return isBinary || reIsOctal.test(value) ? freeParseInt(value.slice(2), isBinary ? 2 : 8) : reIsBadHex.test(value) ? NAN : +value; + } + module2.exports = debounce2; + } +}); + +// src/main.ts +var main_exports = {}; +__export(main_exports, { + default: () => D2Plugin +}); +module.exports = __toCommonJS(main_exports); +var import_obsidian3 = require("obsidian"); + +// src/settings.ts +var import_obsidian = require("obsidian"); + +// src/constants.ts +var LAYOUT_ENGINES = { + DAGRE: { + value: "dagre", + label: "dagre" + }, + ELK: { + value: "elk", + label: "ELK" + }, + TALA: { + value: "tala", + label: "TALA" + } +}; +var RecompileIcon = ` + + + + + +`; + +// src/settings.ts +var DEFAULT_SETTINGS = { + layoutEngine: "dagre", + debounce: 500, + theme: 0, + apiToken: "", + d2Path: "", + pad: 100, + sketch: false, + containerHeight: 800 +}; +var D2SettingsTab = class extends import_obsidian.PluginSettingTab { + constructor(app, plugin) { + super(app, plugin); + this.plugin = plugin; + } + addTALASettings() { + const talaSettings = this.containerEl.createEl("div"); + talaSettings.createEl("h3", { + text: "TALA settings" + }); + new import_obsidian.Setting(talaSettings).setName("API token").setDesc('To use TALA, copy your API token here or in ~/.local/state/tstruct/auth.json under the field "api_token"').addText((text) => text.setPlaceholder("tstruct_...").setValue(this.plugin.settings.apiToken).setDisabled(this.plugin.settings.layoutEngine !== LAYOUT_ENGINES.TALA.value).onChange(async (value) => { + if (value && !value.startsWith("tstruct_")) { + new import_obsidian.Notice("Invalid API token"); + } else { + this.plugin.settings.apiToken = value; + await this.plugin.saveSettings(); + } + })); + this.talaSettings = talaSettings; + } + display() { + const { containerEl } = this; + containerEl.empty(); + containerEl.createEl("h1", { text: "D2 plugin settings" }); + new import_obsidian.Setting(containerEl).setName("Layout engine").setDesc('Available layout engines include "dagre", "ELK", and "TALA" (TALA must be installed separately from D2)').addDropdown((dropdown) => { + dropdown.addOption(LAYOUT_ENGINES.DAGRE.value, LAYOUT_ENGINES.DAGRE.label).addOption(LAYOUT_ENGINES.ELK.value, LAYOUT_ENGINES.ELK.label).addOption(LAYOUT_ENGINES.TALA.value, LAYOUT_ENGINES.TALA.label).setValue(this.plugin.settings.layoutEngine).onChange(async (value) => { + var _a; + this.plugin.settings.layoutEngine = value; + await this.plugin.saveSettings(); + if (value === LAYOUT_ENGINES.TALA.value) { + this.addTALASettings(); + } else { + (_a = this.talaSettings) == null ? void 0 : _a.remove(); + } + }); + }); + new import_obsidian.Setting(containerEl).setName("Theme ID").setDesc("Available themes are located at https://github.com/terrastruct/d2/tree/master/d2themes").addText((text) => text.setPlaceholder("Enter a theme ID").setValue(String(this.plugin.settings.theme)).onChange(async (value) => { + if (!isNaN(Number(value)) || value === "") { + this.plugin.settings.theme = Number(value || DEFAULT_SETTINGS.theme); + await this.plugin.saveSettings(); + } else { + new import_obsidian.Notice("Please specify a valid number"); + } + })); + new import_obsidian.Setting(containerEl).setName("Pad").setDesc("Pixels padded around the rendered diagram").addText((text) => text.setPlaceholder(String(DEFAULT_SETTINGS.pad)).setValue(String(this.plugin.settings.pad)).onChange(async (value) => { + if (isNaN(Number(value))) { + new import_obsidian.Notice("Please specify a valid number"); + this.plugin.settings.pad = Number(DEFAULT_SETTINGS.pad); + } else if (value === "") { + this.plugin.settings.pad = Number(DEFAULT_SETTINGS.pad); + } else { + this.plugin.settings.pad = Number(value); + } + await this.plugin.saveSettings(); + })); + new import_obsidian.Setting(containerEl).setName("Sketch mode").setDesc("Render the diagram to look like it was sketched by hand").addToggle((toggle) => toggle.setValue(this.plugin.settings.sketch).onChange(async (value) => { + this.plugin.settings.sketch = value; + await this.plugin.saveSettings(); + })); + new import_obsidian.Setting(containerEl).setName("Container height").setDesc("Diagram max render height in pixels (Requires d2 v0.2.2 and up)").addText((text) => text.setPlaceholder(String(DEFAULT_SETTINGS.containerHeight)).setValue(String(this.plugin.settings.containerHeight)).onChange(async (value) => { + if (isNaN(Number(value))) { + new import_obsidian.Notice("Please specify a valid number"); + this.plugin.settings.containerHeight = Number(DEFAULT_SETTINGS.containerHeight); + } else if (value === "") { + this.plugin.settings.containerHeight = Number(DEFAULT_SETTINGS.containerHeight); + } else { + this.plugin.settings.containerHeight = Number(value); + } + await this.plugin.saveSettings(); + })); + new import_obsidian.Setting(containerEl).setName("Debounce").setDesc("How often should the diagram refresh in milliseconds (min 100)").addText((text) => text.setPlaceholder(String(DEFAULT_SETTINGS.debounce)).setValue(String(this.plugin.settings.debounce)).onChange(async (value) => { + if (isNaN(Number(value))) { + new import_obsidian.Notice("Please specify a valid number"); + this.plugin.settings.debounce = Number(DEFAULT_SETTINGS.debounce); + } else if (value === "") { + this.plugin.settings.debounce = Number(DEFAULT_SETTINGS.debounce); + } else if (Number(value) < 100) { + new import_obsidian.Notice("The value must be greater than 100"); + this.plugin.settings.debounce = Number(DEFAULT_SETTINGS.debounce); + } else { + this.plugin.settings.debounce = Number(value); + } + await this.plugin.saveSettings(); + })); + new import_obsidian.Setting(containerEl).setName("Path (optional)").setDesc("Customize the local path to the directory `d2` is installed in (ex. if d2 is located at `/usr/local/bin/d2`, then the path is `/usr/local/bin`). This is only necessary if `d2` is not found automatically by the plugin (but is installed).").addText((text) => { + text.setPlaceholder("/usr/local/Cellar").setValue(this.plugin.settings.d2Path).onChange(async (value) => { + this.plugin.settings.d2Path = value; + await this.plugin.saveSettings(); + }); + }); + if (this.plugin.settings.layoutEngine === LAYOUT_ENGINES.TALA.value) { + this.addTALASettings(); + } + } +}; + +// src/processor.ts +var import_obsidian2 = require("obsidian"); +var import_child_process = require("child_process"); +var import_path = require("path"); +var import_lodash = __toESM(require_lodash()); +var import_os = __toESM(require("os")); +var D2Processor = class { + constructor(plugin) { + this.attemptExport = async (source, el, ctx) => { + var _a; + el.createEl("h6", { + text: "Generating D2 diagram...", + cls: "D2__Loading" + }); + const pageContainer = ctx.containerEl; + let pageID = pageContainer.dataset.pageID; + if (!pageID) { + pageID = Math.floor(Math.random() * Date.now()).toString(); + pageContainer.dataset.pageID = pageID; + } + let debouncedFunc = this.debouncedMap.get(pageID); + if (!debouncedFunc) { + await this.export(source, el, ctx); + debouncedFunc = (0, import_lodash.default)(this.export, this.plugin.settings.debounce, { + leading: true + }); + this.debouncedMap.set(pageID, debouncedFunc); + return; + } + (_a = this.abortControllerMap.get(pageID)) == null ? void 0 : _a.abort(); + const newAbortController = new AbortController(); + this.abortControllerMap.set(pageID, newAbortController); + await debouncedFunc(source, el, ctx, newAbortController.signal); + }; + this.isValidUrl = (urlString) => { + let url; + try { + url = new URL(urlString); + } catch (e) { + return false; + } + return url.protocol === "http:" || url.protocol === "https:"; + }; + this.formatLinks = (svgEl) => { + const links = svgEl.querySelectorAll("a"); + links.forEach((link) => { + var _a; + const href = (_a = link.getAttribute("href")) != null ? _a : ""; + if (!this.isValidUrl(href)) { + link.classList.add("internal-link"); + link.setAttribute("data-href", href); + link.setAttribute("target", "_blank"); + link.setAttribute("rel", "noopener"); + } + }); + }; + this.sanitizeSVGIDs = (svgEl, docID) => { + const overrides = svgEl.querySelectorAll("marker, mask, filter"); + const overrideIDs = []; + overrides.forEach((override) => { + const id = override.getAttribute("id"); + if (id) { + overrideIDs.push(id); + } + }); + return overrideIDs.reduce((svgHTML, overrideID) => { + return svgHTML.replaceAll(overrideID, [overrideID, docID].join("-")); + }, svgEl.outerHTML); + }; + this.export = async (source, el, ctx, signal) => { + try { + const image = await this.generatePreview(source, signal); + if (image) { + el.empty(); + this.prevImage = image; + this.insertImage(image, el, ctx); + const button = new import_obsidian2.ButtonComponent(el).setClass("Preview__Recompile").setIcon("recompile").onClick((e) => { + e.preventDefault(); + e.stopPropagation(); + el.empty(); + this.attemptExport(source, el, ctx); + }); + button.buttonEl.createEl("span", { + text: "Recompile" + }); + } + } catch (err) { + el.empty(); + const errorEl = el.createEl("pre", { + cls: "markdown-rendered pre Preview__Error" + }); + errorEl.createEl("code", { + text: "D2 Compilation Error:", + cls: "Preview__Error--Title" + }); + errorEl.createEl("code", { + text: err.message + }); + if (this.prevImage) { + this.insertImage(this.prevImage, el, ctx); + } + } finally { + const pageContainer = ctx.containerEl; + this.abortControllerMap.delete(pageContainer.dataset.id); + } + }; + this.plugin = plugin; + this.debouncedMap = /* @__PURE__ */ new Map(); + this.abortControllerMap = /* @__PURE__ */ new Map(); + } + insertImage(image, el, ctx) { + const parser = new DOMParser(); + const svg = parser.parseFromString(image, "image/svg+xml"); + const containerEl = el.createDiv(); + const svgEl = svg.documentElement; + svgEl.style.maxHeight = `${this.plugin.settings.containerHeight}px`; + svgEl.style.maxWidth = "100%"; + svgEl.style.height = "fit-content"; + svgEl.style.width = "fit-content"; + this.formatLinks(svgEl); + containerEl.innerHTML = this.sanitizeSVGIDs(svgEl, ctx.docId); + } + async generatePreview(source, signal) { + var _a, _b; + const pathArray = [process.env.PATH, "/opt/homebrew/bin", "/usr/local/bin"]; + if (import_os.default.platform() === "win32") { + pathArray.push(`C:Program FilesD2`); + } else { + pathArray.push(`${process.env.HOME}/.local/bin`); + } + let GOPATH = ""; + try { + GOPATH = (0, import_child_process.execSync)("go env GOPATH", { + env: { + ...process.env, + PATH: pathArray.join(import_path.delimiter) + } + }).toString(); + } catch (error) { + } + if (GOPATH) { + pathArray.push(`${GOPATH.replace("\n", "")}/bin`); + } + if (this.plugin.settings.d2Path) { + pathArray.push(this.plugin.settings.d2Path); + } + const options = { + ...process.env, + env: { + PATH: pathArray.join(import_path.delimiter) + }, + signal + }; + if (this.plugin.settings.apiToken) { + options.env.TSTRUCT_TOKEN = this.plugin.settings.apiToken; + } + let args = [ + `d2`, + "-", + `--theme=${this.plugin.settings.theme}`, + `--layout=${this.plugin.settings.layoutEngine}`, + `--pad=${this.plugin.settings.pad}`, + `--sketch=${this.plugin.settings.sketch}`, + "--bundle=false", + "--scale=1" + ]; + const cmd = args.join(" "); + const child = (0, import_child_process.exec)(cmd, options); + (_a = child.stdin) == null ? void 0 : _a.write(source); + (_b = child.stdin) == null ? void 0 : _b.end(); + let stdout; + let stderr; + if (child.stdout) { + child.stdout.on("data", (data) => { + if (stdout === void 0) { + stdout = data; + } else { + stdout += data; + } + }); + } + if (child.stderr) { + child.stderr.on("data", (data) => { + if (stderr === void 0) { + stderr = data; + } else { + stderr += data; + } + }); + } + return new Promise((resolve, reject) => { + child.on("error", reject); + child.on("close", (code) => { + if (code === 0) { + resolve(stdout); + return; + } else if (stderr) { + console.error(stderr); + reject(new Error(stderr)); + } else if (stdout) { + console.error(stdout); + reject(new Error(stdout)); + } + }); + }); + } +}; + +// src/main.ts +var D2Plugin = class extends import_obsidian3.Plugin { + async onload() { + (0, import_obsidian3.addIcon)("recompile", RecompileIcon); + await this.loadSettings(); + this.addSettingTab(new D2SettingsTab(this.app, this)); + const processor = new D2Processor(this); + this.registerMarkdownCodeBlockProcessor("d2", processor.attemptExport); + this.processor = processor; + } + onunload() { + const abortControllers = this.processor.abortControllerMap.values(); + Array.from(abortControllers).forEach((controller) => { + controller.abort(); + }); + } + async loadSettings() { + this.settings = Object.assign({}, DEFAULT_SETTINGS, await this.loadData()); + } + async saveSettings() { + await this.saveData(this.settings); + } +}; + +/* nosourcemap */ \ No newline at end of file diff --git a/.obsidian/plugins/d2-obsidian/manifest.json b/.obsidian/plugins/d2-obsidian/manifest.json new file mode 100644 index 0000000..4bffa8b --- /dev/null +++ b/.obsidian/plugins/d2-obsidian/manifest.json @@ -0,0 +1,10 @@ +{ + "id": "d2-obsidian", + "name": "D2", + "version": "1.1.4", + "minAppVersion": "0.15.0", + "description": "The official D2 plugin for Obsidian. D2 is a modern diagram scripting language that turns text to diagrams.", + "author": "Terrastruct", + "authorUrl": "https://d2lang.com", + "isDesktopOnly": true +} diff --git a/.obsidian/plugins/d2-obsidian/styles.css b/.obsidian/plugins/d2-obsidian/styles.css new file mode 100644 index 0000000..46e334a --- /dev/null +++ b/.obsidian/plugins/d2-obsidian/styles.css @@ -0,0 +1,49 @@ +.D2__Loading { + font-style: italic; +} + +.Preview__Error--Title { + color: #be0b41 !important; +} + +.Preview__Error { + display: flex; + flex-direction: column; + white-space: pre; + white-space: pre-wrap; +} + +.Preview__Recompile { + position: absolute; + top: 4px; + left: 4px; + height: 24px; + padding: 6px; + background-color: white !important; + color: #2e3346; + display: flex; + gap: 4px; + box-shadow: none !important; + border: 1px solid #dee1eb; + filter: drop-shadow(1px 1px 4px rgba(31, 36, 58, 0.08)); +} + +.Preview__Recompile:hover { + filter: drop-shadow(2px 2px 16px rgba(31, 36, 58, 0.12)); + cursor: pointer; +} + +.Preview__Recompile > .svg-icon { + height: 12px !important; + width: 12px !important; +} + +.block-language-d2 { + position: relative; +} + +@media print { + .Preview__Recompile { + display: none; + } +} diff --git a/.obsidian/plugins/drawio-obsidian/data.json b/.obsidian/plugins/drawio-obsidian/data.json new file mode 100644 index 0000000..6878ad5 --- /dev/null +++ b/.obsidian/plugins/drawio-obsidian/data.json @@ -0,0 +1,11 @@ +{ + "welcomeComplete": true, + "theme": { + "dark": null, + "layout": "full" + }, + "drawing": { + "sketch": false + }, + "cssSnippets": [] +} \ No newline at end of file diff --git a/.obsidian/plugins/drawio-obsidian/main.js b/.obsidian/plugins/drawio-obsidian/main.js new file mode 100644 index 0000000..b334dda --- /dev/null +++ b/.obsidian/plugins/drawio-obsidian/main.js @@ -0,0 +1,17 @@ +"use strict";var e=require("obsidian"); +/*! ***************************************************************************** +Copyright (c) Microsoft Corporation. + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH +REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY +AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, +INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM +LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR +OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR +PERFORMANCE OF THIS SOFTWARE. +***************************************************************************** */function t(e,t,i,n){return new(i||(i=Promise))((function(a,l){function r(e){try{s(n.next(e))}catch(e){l(e)}}function o(e){try{s(n.throw(e))}catch(e){l(e)}}function s(e){var t;e.done?a(e.value):(t=e.value,t instanceof i?t:new i((function(e){e(t)}))).then(r,o)}s((n=n.apply(e,t||[])).next())}))}const i="diagram-edit",n="diagram";class a extends e.EditableFileView{constructor(e,t){super(e),this.plugin=t}onMoreOptionsMenu(e){e.addItem((e=>{e.onClick((e=>{this.saveAsPng()})),e.setIcon("image-file"),e.setTitle("Export as png")}))}readBlob(e){const t=new FileReader;return new Promise((i=>{t.onload=e=>{i(e.target.result)},t.readAsDataURL(e)}))}loadImage(e){const t=new Image;return new Promise((i=>{t.onload=()=>i(t),t.src=e}))}saveAsPng(){return t(this,void 0,void 0,(function*(){const e=yield this.app.vault.read(this.file),t=document.createElement("canvas"),i=t.getContext("2d"),n=new Blob([e],{type:"image/svg+xml"}),a=yield this.readBlob(n),l=yield this.loadImage(a);t.height=l.naturalHeight,t.width=l.naturalWidth,i.fillStyle="#fff",i.fillRect(0,0,t.width,t.height),i.drawImage(l,0,0);const r=t.toDataURL("image/png"),o=document.createElement("a");o.setAttribute("href",r),o.setAttribute("download",this.file.basename+".png"),document.body.appendChild(o),o.click(),document.body.removeChild(o)}))}}var l,r;!function(e){e.Script="script",e.Stylesheet="stylesheet",e.Css="css",e.FrameConfig="frame-config",e.Load="load",e.ToggleBodyClass="toggle-body-class"}(l||(l={})),function(e){e.Change="change",e.Iframe="iframe",e.Init="init",e.Load="load",e.FocusIn="focusin",e.FocusOut="focusout"}(r||(r={}));class o{constructor(e,t){this.awaitedMessages=new Set,this.targetFactory=e,this.listener=i=>{const n=e();if(i.source!==n)return;const a=JSON.parse(i.data);t&&t(a);Array.from(this.awaitedMessages.values()).forEach((e=>{e.filter(a)&&(this.awaitedMessages.delete(e),e.callback(a))}))},window.addEventListener("message",this.listener)}validateTarget(e){if("object"!=typeof e||null===e)throw Error("Target window is not an object");if("function"!=typeof e.postMessage)throw Error("Target window does not have a postMessage function")}waitForMessage(e,t){return new Promise(((i,n)=>{const a=setTimeout((()=>{this.awaitedMessages.delete(l),n("Timeout waiting for message")}),t),l={filter:e,callback:e=>{this.awaitedMessages.delete(l),clearTimeout(a),i(e)}};this.awaitedMessages.add(l)}))}sendMessageAndWait(e,t,i){const n=this.targetFactory();this.validateTarget(n);const a=this.waitForMessage(t,i);return n.postMessage(JSON.stringify(e),"*"),a}sendMessage(e){const t=this.targetFactory();this.validateTarget(t),t.postMessage(JSON.stringify(e),"*")}destroy(){window.removeEventListener("message",this.listener)}}class s extends Event{constructor(e){super("fileChange"),this.data=e}}class c extends Event{constructor(e){super("fileLoad"),this.data=e}}class g extends Event{constructor(e){super("stateChange"),this.initialized=e}}class d{constructor(e,t){this.iframeElement=null,this.contentEl=e,this.settings=t,this.file=null,this.isInitialized=!1,this.iframeElement=this.createFrameElement(),this.frameMessenger=new o((()=>this.iframeElement.contentWindow),this.handleMessage.bind(this)),this.contentEl.appendChild(this.iframeElement)}destroy(){this.iframeElement&&(this.iframeElement.parentElement&&this.iframeElement.parentElement.removeChild(this.iframeElement),this.iframeElement=null),this.frameMessenger&&this.frameMessenger.destroy()}loadFile(e){return t(this,void 0,void 0,(function*(){this.file=null,this.isInitialized||(yield this.waitForInit()),this.frameMessenger.sendMessage({action:l.Load,xml:e});const t="undefined"!==(yield this.frameMessenger.waitForMessage((e=>"load"===e.event),5e3)).xml;return t&&(this.file={data:e}),t}))}addEventListener(e,t,i){return this.iframeElement.addEventListener.call(this.iframeElement,e,t,i)}dispatchEvent(e){return this.iframeElement.dispatchEvent.call(this.iframeElement,e)}removeEventListener(e,t,i){return this.iframeElement.removeEventListener.call(this.iframeElement,e,t,i)}createFrameElement(){const e="data:text/html,"+encodeURIComponent('\n