├── .gitignore ├── .obsidian ├── app.json ├── appearance.json ├── community-plugins.json ├── core-plugins-migration.json ├── core-plugins.json ├── graph.json ├── hotkeys.json ├── plugins │ ├── dynamic-rtl │ │ ├── main.js │ │ ├── manifest.json │ │ └── styles.css │ ├── obsidian-code-block-enhancer │ │ ├── main.js │ │ ├── manifest.json │ │ └── styles.css │ └── obsidian-rtl │ │ ├── main.js │ │ ├── manifest.json │ │ └── styles.css └── workspace.json ├── Headlines ├── Main.md └── Main.md.backup ├── LICENSE ├── README.md └── src ├── font ├── mitra.ttf └── mitra2.ttf └── img ├── calc_str.png ├── compiler.PNG ├── cpython.PNG ├── hayede.jpg ├── hide_pass.png ├── input.png ├── input2.png ├── meme_copy.jpg └── py_index.png /.gitignore: -------------------------------------------------------------------------------- 1 | .idea -------------------------------------------------------------------------------- /.obsidian/app.json: -------------------------------------------------------------------------------- 1 | { 2 | "pdfExportSettings": { 3 | "includeName": true, 4 | "pageSize": "A4", 5 | "landscape": false, 6 | "margin": "0", 7 | "downscalePercent": 100 8 | } 9 | } -------------------------------------------------------------------------------- /.obsidian/appearance.json: -------------------------------------------------------------------------------- 1 | { 2 | "accentColor": "" 3 | } -------------------------------------------------------------------------------- /.obsidian/community-plugins.json: -------------------------------------------------------------------------------- 1 | [ 2 | "obsidian-rtl", 3 | "obsidian-code-block-enhancer", 4 | "dynamic-rtl" 5 | ] -------------------------------------------------------------------------------- /.obsidian/core-plugins-migration.json: -------------------------------------------------------------------------------- 1 | { 2 | "file-explorer": true, 3 | "global-search": true, 4 | "switcher": true, 5 | "graph": true, 6 | "backlink": true, 7 | "canvas": true, 8 | "outgoing-link": true, 9 | "tag-pane": true, 10 | "properties": false, 11 | "page-preview": true, 12 | "daily-notes": true, 13 | "templates": true, 14 | "note-composer": true, 15 | "command-palette": true, 16 | "slash-command": false, 17 | "editor-status": true, 18 | "bookmarks": true, 19 | "markdown-importer": false, 20 | "zk-prefixer": false, 21 | "random-note": false, 22 | "outline": true, 23 | "word-count": true, 24 | "slides": false, 25 | "audio-recorder": false, 26 | "workspaces": false, 27 | "file-recovery": true, 28 | "publish": false, 29 | "sync": false 30 | } -------------------------------------------------------------------------------- /.obsidian/core-plugins.json: -------------------------------------------------------------------------------- 1 | [ 2 | "file-explorer", 3 | "global-search", 4 | "switcher", 5 | "graph", 6 | "backlink", 7 | "canvas", 8 | "outgoing-link", 9 | "tag-pane", 10 | "page-preview", 11 | "daily-notes", 12 | "templates", 13 | "note-composer", 14 | "command-palette", 15 | "editor-status", 16 | "bookmarks", 17 | "outline", 18 | "word-count", 19 | "file-recovery" 20 | ] -------------------------------------------------------------------------------- /.obsidian/graph.json: -------------------------------------------------------------------------------- 1 | { 2 | "collapse-filter": true, 3 | "search": "", 4 | "showTags": false, 5 | "showAttachments": false, 6 | "hideUnresolved": false, 7 | "showOrphans": true, 8 | "collapse-color-groups": true, 9 | "colorGroups": [], 10 | "collapse-display": true, 11 | "showArrow": false, 12 | "textFadeMultiplier": 0, 13 | "nodeSizeMultiplier": 1, 14 | "lineSizeMultiplier": 1, 15 | "collapse-forces": true, 16 | "centerStrength": 0.518713248970312, 17 | "repelStrength": 10, 18 | "linkStrength": 1, 19 | "linkDistance": 250, 20 | "scale": 1, 21 | "close": false 22 | } -------------------------------------------------------------------------------- /.obsidian/hotkeys.json: -------------------------------------------------------------------------------- 1 | {} -------------------------------------------------------------------------------- /.obsidian/plugins/dynamic-rtl/main.js: -------------------------------------------------------------------------------- 1 | /* 2 | THIS IS A GENERATED/BUNDLED FILE BY ESBUILD 3 | if you want to view the source, please visit the github repository of this plugin 4 | */ 5 | 6 | var __defProp = Object.defineProperty; 7 | var __getOwnPropDesc = Object.getOwnPropertyDescriptor; 8 | var __getOwnPropNames = Object.getOwnPropertyNames; 9 | var __hasOwnProp = Object.prototype.hasOwnProperty; 10 | var __export = (target, all) => { 11 | for (var name in all) 12 | __defProp(target, name, { get: all[name], enumerable: true }); 13 | }; 14 | var __copyProps = (to, from, except, desc) => { 15 | if (from && typeof from === "object" || typeof from === "function") { 16 | for (let key of __getOwnPropNames(from)) 17 | if (!__hasOwnProp.call(to, key) && key !== except) 18 | __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); 19 | } 20 | return to; 21 | }; 22 | var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); 23 | 24 | // main.ts 25 | var main_exports = {}; 26 | __export(main_exports, { 27 | default: () => DynamicRTL 28 | }); 29 | module.exports = __toCommonJS(main_exports); 30 | var import_obsidian = require("obsidian"); 31 | var DynamicRTL = class extends import_obsidian.Plugin { 32 | async onload() { 33 | const RTLRegEx = /[\u0591-\u07FF\u200F\u202B\u202E\uFB1D-\uFDFD\uFE70-\uFEFC]/; 34 | this.registerMarkdownPostProcessor((container, context) => { 35 | container.querySelectorAll("p,div.cm-line,h1,h2,h3,h4,h5,h6,div.callout-title-inner").forEach((element) => { 36 | element.setAttribute("dir", "auto"); 37 | }); 38 | container.querySelectorAll("table,ol,ul,pre").forEach((element) => { 39 | var _a; 40 | (_a = element.parentElement) == null ? void 0 : _a.setAttribute("dir", "auto"); 41 | }); 42 | container.querySelectorAll(".callout-title").forEach((element) => { 43 | if (RTLRegEx.test(element.innerText.charAt(0))) { 44 | element.style.direction = "rtl"; 45 | } 46 | }); 47 | container.querySelectorAll("blockquote").forEach((element) => { 48 | if (RTLRegEx.test(element.innerText.charAt(1))) { 49 | element.style.borderLeft = "0"; 50 | element.style.borderRight = "var(--blockquote-border-thickness) solid var(--blockquote-border-color)"; 51 | element.style.marginRight = "23px"; 52 | const innerContent = element.querySelector("p"); 53 | if (innerContent) { 54 | innerContent.style.marginRight = "23px"; 55 | } 56 | } 57 | }); 58 | container.querySelectorAll("li").forEach((element) => { 59 | if (RTLRegEx.test(element.innerText.charAt(0))) { 60 | element.querySelectorAll(".list-bullet").forEach((bullet) => { 61 | bullet.style.float = "right"; 62 | bullet.classList.add("rtl-bullet-point"); 63 | }); 64 | element.style.textAlign = "right"; 65 | element.style.direction = "rtl"; 66 | element.classList.add("rtlListItem"); 67 | } else { 68 | element.style.textAlign = "left"; 69 | element.style.direction = "ltr"; 70 | } 71 | }); 72 | container.querySelectorAll("h1,h2,h3,h4,h5,h6").forEach((element) => { 73 | if (RTLRegEx.test(element.innerText.charAt(0))) { 74 | const icon = element.querySelector("div"); 75 | if (icon) { 76 | icon.style.marginRight = "-22px"; 77 | icon.style.float = "right"; 78 | } 79 | } 80 | }); 81 | container.querySelectorAll("ol,ul").forEach((element) => { 82 | if (RTLRegEx.test(element.innerText.charAt(1))) { 83 | element.classList.add("rtlList"); 84 | } 85 | }); 86 | container.querySelectorAll("p").forEach((element) => { 87 | let biDiParagraph = ""; 88 | element.innerHTML.split("
").forEach((line) => { 89 | biDiParagraph += `
${line}
`; 90 | }); 91 | element.innerHTML = biDiParagraph; 92 | }); 93 | container.querySelectorAll("code").forEach((element) => { 94 | if (element.classList.length == 0) { 95 | let biDiCode = ""; 96 | const lineList = element.innerHTML.split("\n"); 97 | if (lineList.length > 1) { 98 | lineList.forEach((line, index, array) => { 99 | if (index != array.length - 1) { 100 | biDiCode += `
${line}
`; 101 | } 102 | }); 103 | element.innerHTML = biDiCode; 104 | } 105 | } 106 | }); 107 | container.querySelectorAll("pre").forEach((element) => { 108 | if (RTLRegEx.test(element.innerText.charAt(0))) { 109 | element.classList.add("rtlPre"); 110 | } 111 | }); 112 | container.querySelectorAll("a.external-link").forEach((element) => { 113 | if (RTLRegEx.test(element.innerText.charAt(0))) { 114 | element.style.backgroundPosition = "center left"; 115 | element.style.paddingRight = "unset"; 116 | element.style.paddingLeft = "16px"; 117 | } 118 | }); 119 | }); 120 | } 121 | }; 122 | //# sourceMappingURL=data:application/json;base64,ewogICJ2ZXJzaW9uIjogMywKICAic291cmNlcyI6IFsibWFpbi50cyJdLAogICJzb3VyY2VzQ29udGVudCI6IFsiLy8gSW4gdGhlIG5hbWUgb2YgQWxsYWhcblxuaW1wb3J0IHsgTWFya2Rvd25Qb3N0UHJvY2Vzc29yQ29udGV4dCwgUGx1Z2luIH0gZnJvbSAnb2JzaWRpYW4nO1xuXG5leHBvcnQgZGVmYXVsdCBjbGFzcyBEeW5hbWljUlRMIGV4dGVuZHMgUGx1Z2luIHtcblxuXHRhc3luYyBvbmxvYWQoKSB7XG5cdFx0Y29uc3QgUlRMUmVnRXggPSAvW1xcdTA1OTEtXFx1MDdGRlxcdTIwMEZcXHUyMDJCXFx1MjAyRVxcdUZCMUQtXFx1RkRGRFxcdUZFNzAtXFx1RkVGQ10vO1xuXG5cdFx0dGhpcy5yZWdpc3Rlck1hcmtkb3duUG9zdFByb2Nlc3NvcigoY29udGFpbmVyOiBIVE1MRWxlbWVudCwgY29udGV4dDogTWFya2Rvd25Qb3N0UHJvY2Vzc29yQ29udGV4dCkgPT4ge1xuXHRcdFx0Ly8gRml4ZXMgdGhlIFJlYWRpbmcgdmlldyAoZm9yIHRhYmxlcyAmIGNhbGxvdXRzIHRoaXMgZml4ZXMgdGhlIGVkaXRvciB0b28pXG5cdFx0XHRjb250YWluZXIucXVlcnlTZWxlY3RvckFsbCgncCxkaXYuY20tbGluZSxoMSxoMixoMyxoNCxoNSxoNicgKyAnLGRpdi5jYWxsb3V0LXRpdGxlLWlubmVyJykuZm9yRWFjaChlbGVtZW50ID0+IHtcblx0XHRcdFx0ZWxlbWVudC5zZXRBdHRyaWJ1dGUoJ2RpcicsICdhdXRvJyk7XG5cdFx0XHR9KTtcblx0XHRcdGNvbnRhaW5lci5xdWVyeVNlbGVjdG9yQWxsKCd0YWJsZSxvbCx1bCxwcmUnKS5mb3JFYWNoKChlbGVtZW50OiBIVE1MRWxlbWVudCkgPT4ge1xuXHRcdFx0XHRlbGVtZW50LnBhcmVudEVsZW1lbnQ/LnNldEF0dHJpYnV0ZSgnZGlyJywgJ2F1dG8nKTtcblx0XHRcdH0pO1xuXHRcdFx0Ly8gRml4ZXMgdGhlIENhbGxvdXQgdGl0bGVcblx0XHRcdGNvbnRhaW5lci5xdWVyeVNlbGVjdG9yQWxsKCcuY2FsbG91dC10aXRsZScpLmZvckVhY2goKGVsZW1lbnQ6IEhUTUxFbGVtZW50KSA9PiB7XG5cdFx0XHRcdGlmIChSVExSZWdFeC50ZXN0KGVsZW1lbnQuaW5uZXJUZXh0LmNoYXJBdCgwKSkpIHtcblx0XHRcdFx0XHRlbGVtZW50LnN0eWxlLmRpcmVjdGlvbiA9ICdydGwnO1xuXHRcdFx0XHR9XG5cdFx0XHR9KTtcblx0XHRcdC8vIEZpeGVzIHRoZSBxb3V0ZXMgYm9yZGVyIGRpcmVjdGlvbiBpbiBSVEwgdGV4dHNcblx0XHRcdGNvbnRhaW5lci5xdWVyeVNlbGVjdG9yQWxsKCdibG9ja3F1b3RlJykuZm9yRWFjaCgoZWxlbWVudDogSFRNTEVsZW1lbnQpID0+IHtcblx0XHRcdFx0aWYgKFJUTFJlZ0V4LnRlc3QoZWxlbWVudC5pbm5lclRleHQuY2hhckF0KDEpKSkge1xuXHRcdFx0XHRcdGVsZW1lbnQuc3R5bGUuYm9yZGVyTGVmdCA9ICcwJztcblx0XHRcdFx0XHRlbGVtZW50LnN0eWxlLmJvcmRlclJpZ2h0ID0gJ3ZhcigtLWJsb2NrcXVvdGUtYm9yZGVyLXRoaWNrbmVzcykgc29saWQgdmFyKC0tYmxvY2txdW90ZS1ib3JkZXItY29sb3IpJztcblx0XHRcdFx0XHRlbGVtZW50LnN0eWxlLm1hcmdpblJpZ2h0ID0gJzIzcHgnO1xuXHRcdFx0XHRcdGNvbnN0IGlubmVyQ29udGVudCA9IGVsZW1lbnQucXVlcnlTZWxlY3RvcigncCcpO1xuXHRcdFx0XHRcdGlmIChpbm5lckNvbnRlbnQpIHtcblx0XHRcdFx0XHRcdGlubmVyQ29udGVudC5zdHlsZS5tYXJnaW5SaWdodCA9ICcyM3B4Jztcblx0XHRcdFx0XHR9XG5cdFx0XHRcdH1cblx0XHRcdH0pO1xuXHRcdFx0Ly8gRml4ZXMgdGhlIGJ1bGxldCBwb2ludHMgcHJvYmxlbSAmIGJpZGlyZWN0aW9uYWwgcHJvYmxlbSBpbiByZWFkaW5nIG1vZGVcblx0XHRcdGNvbnRhaW5lci5xdWVyeVNlbGVjdG9yQWxsKCdsaScpLmZvckVhY2goZWxlbWVudCA9PiB7XG5cdFx0XHRcdGlmIChSVExSZWdFeC50ZXN0KGVsZW1lbnQuaW5uZXJUZXh0LmNoYXJBdCgwKSkpIHtcblx0XHRcdFx0XHRlbGVtZW50LnF1ZXJ5U2VsZWN0b3JBbGwoJy5saXN0LWJ1bGxldCcpLmZvckVhY2goKGJ1bGxldDogSFRNTEVsZW1lbnQpID0+IHtcblx0XHRcdFx0XHRcdGJ1bGxldC5zdHlsZS5mbG9hdCA9ICdyaWdodCc7XG5cdFx0XHRcdFx0XHRidWxsZXQuY2xhc3NMaXN0LmFkZCgncnRsLWJ1bGxldC1wb2ludCcpO1xuXHRcdFx0XHRcdH0pO1xuXHRcdFx0XHRcdGVsZW1lbnQuc3R5bGUudGV4dEFsaWduID0gJ3JpZ2h0Jztcblx0XHRcdFx0XHRlbGVtZW50LnN0eWxlLmRpcmVjdGlvbiA9ICdydGwnO1xuXHRcdFx0XHRcdGVsZW1lbnQuY2xhc3NMaXN0LmFkZCgncnRsTGlzdEl0ZW0nKTtcblx0XHRcdFx0fSBlbHNlIHtcblx0XHRcdFx0XHRlbGVtZW50LnN0eWxlLnRleHRBbGlnbiA9ICdsZWZ0Jztcblx0XHRcdFx0XHRlbGVtZW50LnN0eWxlLmRpcmVjdGlvbiA9ICdsdHInO1xuXHRcdFx0XHR9XG5cdFx0XHR9KTtcblx0XHRcdC8vIE1vdmVzIGNvbGxhcHNlIGljb24gdG8gdGhlIHJpZ2h0IGZvciBSVEwgaGVhZGluZ3Ncblx0XHRcdGNvbnRhaW5lci5xdWVyeVNlbGVjdG9yQWxsKCdoMSxoMixoMyxoNCxoNSxoNicpLmZvckVhY2goKGVsZW1lbnQ6IEhUTUxFbGVtZW50KSA9PiB7XG5cdFx0XHRcdGlmIChSVExSZWdFeC50ZXN0KGVsZW1lbnQuaW5uZXJUZXh0LmNoYXJBdCgwKSkpIHtcblx0XHRcdFx0XHRjb25zdCBpY29uID0gZWxlbWVudC5xdWVyeVNlbGVjdG9yKCdkaXYnKTtcblx0XHRcdFx0XHRpZiAoaWNvbikge1xuXHRcdFx0XHRcdFx0aWNvbi5zdHlsZS5tYXJnaW5SaWdodCA9ICctMjJweCc7XG5cdFx0XHRcdFx0XHRpY29uLnN0eWxlLmZsb2F0ID0gJ3JpZ2h0Jztcblx0XHRcdFx0XHR9XG5cdFx0XHRcdH1cblx0XHRcdH0pO1xuXHRcdFx0Ly8gTW92ZXMgbGlzdCBpbmRlbnQgYm9yZGVyIHRvIHJpZ2h0IGZvciBSVEwgbGlzdHMgKFJlYWRpbmcgdmlldylcblx0XHRcdGNvbnRhaW5lci5xdWVyeVNlbGVjdG9yQWxsKCdvbCx1bCcpLmZvckVhY2goKGVsZW1lbnQ6IEhUTUxFbGVtZW50KSA9PiB7XG5cdFx0XHRcdGlmIChSVExSZWdFeC50ZXN0KGVsZW1lbnQuaW5uZXJUZXh0LmNoYXJBdCgxKSkpIHtcblx0XHRcdFx0XHRlbGVtZW50LmNsYXNzTGlzdC5hZGQoJ3J0bExpc3QnKTtcblx0XHRcdFx0fVxuXHRcdFx0fSk7XG5cdFx0XHQvLyBGaXhlcyB0aGUgYmlkaSBwYXJncmFwaCBwcm9ibGVtIGluIHJlYWRpbmcgbW9kZVxuXHRcdFx0Y29udGFpbmVyLnF1ZXJ5U2VsZWN0b3JBbGwoJ3AnKS5mb3JFYWNoKChlbGVtZW50OiBIVE1MUGFyYWdyYXBoRWxlbWVudCkgPT4ge1xuXHRcdFx0XHRsZXQgYmlEaVBhcmFncmFwaDogc3RyaW5nID0gJyc7XG5cdFx0XHRcdGVsZW1lbnQuaW5uZXJIVE1MLnNwbGl0KCc8YnI+JykuZm9yRWFjaCgobGluZTogc3RyaW5nKSA9PiB7XG5cdFx0XHRcdFx0YmlEaVBhcmFncmFwaCArPSBgPGRpdiBkaXI9XCJhdXRvXCI+JHtsaW5lfTwvZGl2PmA7XG5cdFx0XHRcdH0pO1xuXHRcdFx0XHRlbGVtZW50LmlubmVySFRNTCA9IGJpRGlQYXJhZ3JhcGg7XG5cdFx0XHR9KTtcblx0XHRcdC8vIEZpeGVzIHRoZSBiaWRpIGNvZGUgYmxvY2sgcHJvYmxlbSBpbiByZWFkaW5nIG1vZGVcblx0XHRcdGNvbnRhaW5lci5xdWVyeVNlbGVjdG9yQWxsKCdjb2RlJykuZm9yRWFjaCgoZWxlbWVudDogSFRNTEVsZW1lbnQpID0+IHtcblx0XHRcdFx0aWYgKGVsZW1lbnQuY2xhc3NMaXN0Lmxlbmd0aCA9PSAwKSB7XG5cdFx0XHRcdFx0bGV0IGJpRGlDb2RlOiBzdHJpbmcgPSAnJztcblx0XHRcdFx0XHRjb25zdCBsaW5lTGlzdCA9IGVsZW1lbnQuaW5uZXJIVE1MLnNwbGl0KCdcXG4nKTtcblx0XHRcdFx0XHRpZiAobGluZUxpc3QubGVuZ3RoID4gMSkge1xuXHRcdFx0XHRcdFx0bGluZUxpc3QuZm9yRWFjaCgobGluZTogc3RyaW5nLCBpbmRleDogbnVtYmVyLCBhcnJheTogQXJyYXk8c3RyaW5nPikgPT4ge1xuXHRcdFx0XHRcdFx0XHRpZiAoaW5kZXggIT0gYXJyYXkubGVuZ3RoIC0gMSkge1xuXHRcdFx0XHRcdFx0XHRcdGJpRGlDb2RlICs9IGA8ZGl2IGRpcj1cImF1dG9cIj4ke2xpbmV9PC9kaXY+YDtcblx0XHRcdFx0XHRcdFx0fVxuXHRcdFx0XHRcdFx0fSk7XG5cdFx0XHRcdFx0XHRlbGVtZW50LmlubmVySFRNTCA9IGJpRGlDb2RlO1xuXHRcdFx0XHRcdH1cblx0XHRcdFx0fVxuXHRcdFx0fSk7XG5cdFx0XHQvLyBNb3ZlcyBjb3B5IGJ1dHRvbiBmb3IgUlRMIGNvZGUgYmxvY2tzIHRvIHRoZSBsZWZ0IGluIHJlYWRpbmcgdmlld1xuXHRcdFx0Y29udGFpbmVyLnF1ZXJ5U2VsZWN0b3JBbGwoJ3ByZScpLmZvckVhY2goKGVsZW1lbnQ6IEhUTUxQcmVFbGVtZW50KSA9PiB7XG5cdFx0XHRcdGlmIChSVExSZWdFeC50ZXN0KGVsZW1lbnQuaW5uZXJUZXh0LmNoYXJBdCgwKSkpIHtcblx0XHRcdFx0XHRlbGVtZW50LmNsYXNzTGlzdC5hZGQoJ3J0bFByZScpO1xuXHRcdFx0XHR9XG5cdFx0XHR9KTtcblx0XHRcdC8vIE1vdmVzIGV4dGVybmFsIGxpbmsgaWNvbiB0byB0aGUgbGVmdCBzaWRlIGZvciBSVEwgbGlua3MgKFJlYWRpbmcgdmlldylcblx0XHRcdGNvbnRhaW5lci5xdWVyeVNlbGVjdG9yQWxsKCdhLmV4dGVybmFsLWxpbmsnKS5mb3JFYWNoKChlbGVtZW50OiBIVE1MQW5jaG9yRWxlbWVudCkgPT4ge1xuXHRcdFx0XHRpZiAoUlRMUmVnRXgudGVzdChlbGVtZW50LmlubmVyVGV4dC5jaGFyQXQoMCkpKSB7XG5cdFx0XHRcdFx0ZWxlbWVudC5zdHlsZS5iYWNrZ3JvdW5kUG9zaXRpb24gPSAnY2VudGVyIGxlZnQnO1xuXHRcdFx0XHRcdGVsZW1lbnQuc3R5bGUucGFkZGluZ1JpZ2h0ID0gJ3Vuc2V0Jztcblx0XHRcdFx0XHRlbGVtZW50LnN0eWxlLnBhZGRpbmdMZWZ0ID0gJzE2cHgnO1xuXHRcdFx0XHR9XG5cdFx0XHR9KTtcblx0XHR9KTtcblxuXHR9XG59Il0sCiAgIm1hcHBpbmdzIjogIjs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUVBLHNCQUFxRDtBQUVyRCxJQUFxQixhQUFyQixjQUF3Qyx1QkFBTztBQUFBLEVBRTlDLE1BQU0sU0FBUztBQUNkLFVBQU0sV0FBVztBQUVqQixTQUFLLDhCQUE4QixDQUFDLFdBQXdCLFlBQTBDO0FBRXJHLGdCQUFVLGlCQUFpQix5REFBOEQsRUFBRSxRQUFRLGFBQVc7QUFDN0csZ0JBQVEsYUFBYSxPQUFPLE1BQU07QUFBQSxNQUNuQyxDQUFDO0FBQ0QsZ0JBQVUsaUJBQWlCLGlCQUFpQixFQUFFLFFBQVEsQ0FBQyxZQUF5QjtBQWRuRjtBQWVJLHNCQUFRLGtCQUFSLG1CQUF1QixhQUFhLE9BQU87QUFBQSxNQUM1QyxDQUFDO0FBRUQsZ0JBQVUsaUJBQWlCLGdCQUFnQixFQUFFLFFBQVEsQ0FBQyxZQUF5QjtBQUM5RSxZQUFJLFNBQVMsS0FBSyxRQUFRLFVBQVUsT0FBTyxDQUFDLENBQUMsR0FBRztBQUMvQyxrQkFBUSxNQUFNLFlBQVk7QUFBQSxRQUMzQjtBQUFBLE1BQ0QsQ0FBQztBQUVELGdCQUFVLGlCQUFpQixZQUFZLEVBQUUsUUFBUSxDQUFDLFlBQXlCO0FBQzFFLFlBQUksU0FBUyxLQUFLLFFBQVEsVUFBVSxPQUFPLENBQUMsQ0FBQyxHQUFHO0FBQy9DLGtCQUFRLE1BQU0sYUFB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 123 | -------------------------------------------------------------------------------- /.obsidian/plugins/dynamic-rtl/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "dynamic-rtl", 3 | "name": "Dynamic RTL", 4 | "version": "0.2.12", 5 | "minAppVersion": "0.15.0", 6 | "description": "Dynamic RTL/LTR direction per line/paragraph, dependant on language!", 7 | "author": "mwxgaf", 8 | "authorUrl": "http://mwxgaf.ir", 9 | "isDesktopOnly": false 10 | } 11 | -------------------------------------------------------------------------------- /.obsidian/plugins/dynamic-rtl/styles.css: -------------------------------------------------------------------------------- 1 | /* In the name of Allah */ 2 | 3 | .cm-line 4 | /* Fixes most elements of the editor */ 5 | , 6 | .inline-title 7 | /* Fixes the big note title inside the view */ 8 | , 9 | .view-header-title 10 | 11 | /* File title above editor or reading view for Obsidian v0.15.*/ 12 | { 13 | unicode-bidi: plaintext !important; 14 | } 15 | 16 | /* Fixes th elements */ 17 | th { 18 | text-align: -webkit-auto !important; 19 | } 20 | 21 | /* Fixes the bullet points margin with text in reading mode */ 22 | .rtl-bullet-point::after { 23 | margin-left: 20px !important; 24 | } 25 | 26 | /* Fixes RTL bullet point direction for ITS theme */ 27 | .rtlListItem::before { 28 | float: right !important; 29 | margin-left: unset !important; 30 | } 31 | 32 | /* Fixes the RTL checklists bad view */ 33 | input.task-list-item-checkbox { 34 | margin-left: 6px !important; 35 | } 36 | 37 | /* Moves copy button for RTL code blocks to the left in reading view */ 38 | .rtlPre>button { 39 | right: unset !important; 40 | left: 0 !important; 41 | } 42 | 43 | /* Fixes the code blocks indentation for RTL lines in editing view */ 44 | .markdown-source-view.mod-cm6 .cm-line.HyperMD-codeblock { 45 | padding-right: var(--size-4-4) !important; 46 | } 47 | 48 | /* Fixes the margin between bullet point & text in RTL bullet point (editing view) */ 49 | body:not(.is-mobile) .markdown-source-view.mod-cm6 .list-bullet:after { 50 | left: unset !important; 51 | } 52 | 53 | /* Fixes the indent border direction for RTL lists (Reading view) */ 54 | .rtlList::before { 55 | left: unset !important; 56 | right: 0px !important; 57 | } 58 | 59 | /* Fixes list indentation border margin with RTL text */ 60 | .markdown-source-view.mod-cm6 .cm-indent::before { 61 | transform: translateX(10px) !important; 62 | } 63 | 64 | /* Fixes the line break problem with Tasks plugin */ 65 | .tasks-list-text>div { 66 | display: inline !important; 67 | } 68 | 69 | .tasks-list-text>div>div { 70 | display: inline !important; 71 | } 72 | 73 | /* Fixes the Tasks plugin RTL problem */ 74 | /* .plugin-tasks-list-item { 75 | direction: rtl !important; 76 | text-align: right !important; 77 | } */ 78 | /* UNCOMMENT FOR RTL Tasks Plugin */ -------------------------------------------------------------------------------- /.obsidian/plugins/obsidian-code-block-enhancer/main.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var obsidian = require('obsidian'); 4 | 5 | /*! ***************************************************************************** 6 | Copyright (c) Microsoft Corporation. 7 | 8 | Permission to use, copy, modify, and/or distribute this software for any 9 | purpose with or without fee is hereby granted. 10 | 11 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH 12 | REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 13 | AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, 14 | INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 15 | LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR 16 | OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 17 | PERFORMANCE OF THIS SOFTWARE. 18 | ***************************************************************************** */ 19 | 20 | function __awaiter(thisArg, _arguments, P, generator) { 21 | function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } 22 | return new (P || (P = Promise))(function (resolve, reject) { 23 | function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } 24 | function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } 25 | function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } 26 | step((generator = generator.apply(thisArg, _arguments || [])).next()); 27 | }); 28 | } 29 | 30 | const DEFAULT_LANG_ATTR = 'language-text'; 31 | const DEFAULT_LANG = ''; 32 | const LANG_REG = /^language-/; 33 | const LINE_SPLIT_MARK = '\n'; 34 | const SVG_COPY = parseToSVG(' '); 35 | const SVG_SUCCESS = parseToSVG(' '); 36 | function enhanceCodeBlock(el, ctx, plugin) { 37 | const code = el.querySelector('pre > code'); 38 | // only change pre>code 39 | if (!code) { 40 | return; 41 | } 42 | let lang = DEFAULT_LANG; 43 | // return when lang is in exclude list 44 | if (plugin.settings.excludeLangs.some(eLangName => code.classList.contains(`language-${eLangName}`))) { 45 | return; 46 | } 47 | code.classList.forEach((value, key, parent) => { 48 | if (LANG_REG.test(value)) { 49 | lang = value.replace('language-', ''); 50 | return; 51 | } 52 | }); 53 | const pre = code.parentElement; 54 | const div = pre.parentElement; 55 | // Add default language style when lang is empty 56 | if (!code.classList.toString().contains('language-')) { 57 | pre.classList.add(DEFAULT_LANG_ATTR); 58 | } 59 | // Ignore already has copy button 60 | if (pre.querySelector('div.code-block-copy-button')) { 61 | return; 62 | } 63 | // let div position: relative; 64 | div.classList.add('code-block-wrap'); 65 | /* const { lineStart, lineEnd } = ctx.getSectionInfo(el) 66 | const lineSize = lineEnd - lineStart - 1 */ 67 | const contentList = code.textContent.split(LINE_SPLIT_MARK); 68 | const lineSize = contentList.length - 1; 69 | const cbMeta = { langName: lang, lineSize, pre, code, div, contentList }; 70 | const { useContextMenu, showLangName, showLineNumber } = plugin.settings; 71 | // create copy button in right 72 | addCopyButton(plugin, cbMeta); 73 | // create lang name tip in left 74 | if (showLangName) { 75 | addLangName(plugin, cbMeta); 76 | } 77 | // add line number 78 | if (showLineNumber) { 79 | addLineNumber(plugin, cbMeta); 80 | } 81 | //context menu 82 | if (useContextMenu) { 83 | enhanceContextMenu(plugin, cbMeta); 84 | } 85 | } 86 | function createElement(tagName, defaultClassName) { 87 | const element = document.createElement(tagName); 88 | if (defaultClassName) { 89 | element.className = defaultClassName; 90 | } 91 | return element; 92 | } 93 | function enhanceContextMenu(plugin, cbMeta) { 94 | const { pre, code, lineSize } = cbMeta; 95 | plugin.registerDomEvent(pre, 'contextmenu', (event) => { 96 | event.preventDefault(); 97 | const target = event.target; 98 | if (target.tagName !== 'BUTTON') { 99 | const contextMenu = new obsidian.Menu(plugin.app); 100 | const selection = window.getSelection().toString(); 101 | const editView = document.querySelector('.markdown-preview-view'); 102 | const blockHeight = parseFloat(window.getComputedStyle(pre).height); 103 | const viewHeight = editView.clientHeight; 104 | const { offsetY, pageY } = event; 105 | const toBottom = blockHeight - ((viewHeight - pageY) + offsetY); 106 | const toTop = offsetY - pageY + 100; 107 | const eventScrollTop = editView.scrollTop; 108 | let eRowNum = Math.ceil((offsetY - 16) / 24); 109 | if (eRowNum < 1) { 110 | eRowNum = 1; 111 | } 112 | else if (eRowNum > lineSize) { 113 | eRowNum = lineSize; 114 | } 115 | if (selection) { 116 | contextMenu.addItem((item) => { 117 | item 118 | .setTitle('Copy') 119 | .setIcon('two-blank-pages', 16) 120 | .onClick((e) => { 121 | navigator.clipboard.writeText(selection); 122 | }); 123 | }); 124 | } 125 | contextMenu.addItem((item) => { 126 | item 127 | .setTitle('Copy Block') 128 | .setIcon('two-blank-pages', 16) 129 | .onClick(() => { 130 | navigator.clipboard.writeText(code.textContent); 131 | }); 132 | }); 133 | contextMenu.addItem((item) => { 134 | item 135 | .setTitle('Copy Row') 136 | .setIcon('two-blank-pages', 16) 137 | .onClick(() => { 138 | navigator.clipboard.writeText(cbMeta.contentList[eRowNum - 1]); 139 | }); 140 | }); 141 | if (blockHeight > viewHeight) { 142 | if (toTop > 0) { 143 | contextMenu.addItem((item) => { 144 | item 145 | .setTitle('To Top') 146 | .onClick((e) => { 147 | editView.scrollTop = eventScrollTop - toTop; 148 | }); 149 | }); 150 | } 151 | if (toBottom > 0) { 152 | contextMenu.addItem((item) => { 153 | item 154 | .setTitle('To Bottom') 155 | .onClick((e) => { 156 | editView.scrollTop = eventScrollTop + toBottom; 157 | }); 158 | }); 159 | } 160 | } 161 | contextMenu.showAtPosition({ x: event.clientX, y: event.clientY }); 162 | } 163 | }); 164 | } 165 | function addLangName(plugin, cbMeta) { 166 | const { langName, pre } = cbMeta; 167 | const langNameTip = createElement('span', 'code-block-lang-name'); 168 | langNameTip.innerText = langName; 169 | pre.appendChild(langNameTip); 170 | } 171 | function addCopyButton(plugin, cbMeta) { 172 | const { code, pre } = cbMeta; 173 | const copyButton = createElement('div', 'code-block-copy-button'); 174 | copyButton.setAttribute('aria-label', 'Copy'); 175 | replaceFirstChild(copyButton, SVG_COPY()); 176 | const copyHandler = () => { 177 | navigator.clipboard.writeText(code.textContent).then(() => { 178 | replaceFirstChild(copyButton, SVG_SUCCESS()); 179 | setTimeout(() => { 180 | replaceFirstChild(copyButton, SVG_COPY()); 181 | }, 1500); 182 | }, () => { 183 | copyButton.innerText = 'Error'; 184 | }); 185 | }; 186 | plugin.registerDomEvent(copyButton, 'click', copyHandler); 187 | pre.appendChild(copyButton); 188 | pre.classList.add('code-block-pre__has-copy-button'); 189 | } 190 | function addLineNumber(plugin, cbMeta) { 191 | const { lineSize, pre } = cbMeta; 192 | // const { fontSize, lineHeight } = window.getComputedStyle(cbMeta.code) 193 | const lineNumber = createElement('span', 'code-block-linenum-wrap'); 194 | Array.from({ length: lineSize }, (v, k) => k).forEach(i => { 195 | const singleLine = createElement('span', 'code-block-linenum'); 196 | // singleLine.style.fontSize = fontSize 197 | // singleLine.style.lineHeight = lineHeight 198 | lineNumber.appendChild(singleLine); 199 | }); 200 | pre.appendChild(lineNumber); 201 | pre.classList.add('code-block-pre__has-linenum'); 202 | } 203 | function parseToSVG(svgString) { 204 | return function () { 205 | return new DOMParser().parseFromString(svgString, 'image/svg+xml').firstChild; 206 | }; 207 | } 208 | function replaceFirstChild(target, child) { 209 | if (target.childNodes && target.childNodes.length > 0) { 210 | target.removeChild(target.childNodes[0]); 211 | } 212 | target.appendChild(child); 213 | } 214 | 215 | const DEFAULT_SETTINGS = { 216 | excludeLangs: ['todoist'], 217 | showLangName: true, 218 | showLineNumber: true, 219 | useContextMenu: true 220 | }; 221 | class CodeBlockEnhancer extends obsidian.Plugin { 222 | onload() { 223 | return __awaiter(this, void 0, void 0, function* () { 224 | yield this.loadSettings(); 225 | this.addSettingTab(new CbEnhancerSettingsTab(this.app, this)); 226 | this.registerMarkdownPostProcessor((el, ctx) => { 227 | enhanceCodeBlock(el, ctx, this); 228 | }); 229 | }); 230 | } 231 | onunload() { 232 | console.log('Unloading Code Block Enhancer Plugin'); 233 | } 234 | loadSettings() { 235 | return __awaiter(this, void 0, void 0, function* () { 236 | this.settings = Object.assign({}, DEFAULT_SETTINGS, yield this.loadData()); 237 | }); 238 | } 239 | saveSettings() { 240 | return __awaiter(this, void 0, void 0, function* () { 241 | yield this.saveData(this.settings); 242 | }); 243 | } 244 | } 245 | class CbEnhancerSettingsTab extends obsidian.PluginSettingTab { 246 | constructor(app, plugin) { 247 | super(app, plugin); 248 | this.plugin = plugin; 249 | } 250 | display() { 251 | let { containerEl } = this; 252 | const pluginSetting = this.plugin.settings; 253 | containerEl.empty(); 254 | containerEl.createEl('h2', { text: `Code Block Enhancer Settings ${this.plugin.manifest.version}` }); 255 | new obsidian.Setting(containerEl) 256 | .setName('Exclude language list') 257 | .setDesc("Will not be enhanced in these languages") 258 | .addTextArea(text => text 259 | .setPlaceholder('Separate by `,` (like `todoist,other,...`)') 260 | .setValue(pluginSetting.excludeLangs.join(',')) 261 | .onChange((value) => __awaiter(this, void 0, void 0, function* () { 262 | pluginSetting.excludeLangs = value.split(','); 263 | yield this.plugin.saveSettings(); 264 | }))); 265 | new obsidian.Setting(containerEl) 266 | .setName('Show language name') 267 | .setDesc('Enable this options will show language name') 268 | .addToggle(cb => { 269 | cb 270 | .setValue(pluginSetting.showLangName) 271 | .onChange((isEnable) => __awaiter(this, void 0, void 0, function* () { 272 | pluginSetting.showLangName = isEnable; 273 | yield this.plugin.saveSettings(); 274 | })); 275 | }); 276 | new obsidian.Setting(containerEl) 277 | .setName('Show line number') 278 | .setDesc('Enable this options will show line number') 279 | .addToggle(cb => { 280 | cb 281 | .setValue(pluginSetting.showLineNumber) 282 | .onChange((isEnable) => __awaiter(this, void 0, void 0, function* () { 283 | pluginSetting.showLineNumber = isEnable; 284 | yield this.plugin.saveSettings(); 285 | })); 286 | }); 287 | new obsidian.Setting(containerEl) 288 | .setName('Use ContextMenu') 289 | .setDesc('Replace default contextmenu when right-click in code block') 290 | .addToggle(cb => { 291 | cb 292 | .setValue(pluginSetting.useContextMenu) 293 | .onChange((isEnable) => __awaiter(this, void 0, void 0, function* () { 294 | pluginSetting.useContextMenu = isEnable; 295 | yield this.plugin.saveSettings(); 296 | })); 297 | }); 298 | } 299 | } 300 | 301 | module.exports = CodeBlockEnhancer; 302 | //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibWFpbi5qcyIsInNvdXJjZXMiOlsiLi4vbm9kZV9tb2R1bGVzL3RzbGliL3RzbGliLmVzNi5qcyIsIi4uL3NyYy9jb3JlLnRzIiwiLi4vc3JjL21haW4udHMiXSwic291cmNlc0NvbnRlbnQiOm51bGwsIm5hbWVzIjpbIk1lbnUiLCJQbHVnaW4iLCJQbHVnaW5TZXR0aW5nVGFiIiwiU2V0dGluZyJdLCJtYXBwaW5ncyI6Ijs7OztBQUFBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUF1REE7QUFDTyxTQUFTLFNBQVMsQ0FBQyxPQUFPLEVBQUUsVUFBVSxFQUFFLENBQUMsRUFBRSxTQUFTLEVBQUU7QUFDN0QsSUFBSSxTQUFTLEtBQUssQ0FBQyxLQUFLLEVBQUUsRUFBRSxPQUFPLEtBQUssWUFBWSxDQUFDLEdBQUcsS0FBSyxHQUFHLElBQUksQ0FBQyxDQUFDLFVBQVUsT0FBTyxFQUFFLEVBQUUsT0FBTyxDQUFDLEtBQUssQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDLEVBQUU7QUFDaEgsSUFBSSxPQUFPLEtBQUssQ0FBQyxLQUFLLENBQUMsR0FBRyxPQUFPLENBQUMsRUFBRSxVQUFVLE9BQU8sRUFBRSxNQUFNLEVBQUU7QUFDL0QsUUFBUSxTQUFTLFNBQVMsQ0FBQyxLQUFLLEVBQUUsRUFBRSxJQUFJLEVBQUUsSUFBSSxDQUFDLFNBQVMsQ0FBQyxJQUFJLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsT0FBTyxDQUFDLEVBQUUsRUFBRSxNQUFNLENBQUMsQ0FBQyxDQUFDLENBQUMsRUFBRSxFQUFFO0FBQ25HLFFBQVEsU0FBUyxRQUFRLENBQUMsS0FBSyxFQUFFLEVBQUUsSUFBSSxFQUFFLElBQUksQ0FBQyxTQUFTLENBQUMsT0FBTyxDQUFDLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsT0FBTyxDQUFDLEVBQUUsRUFBRSxNQUFNLENBQUMsQ0FBQyxDQUFDLENBQUMsRUFBRSxFQUFFO0FBQ3RHLFFBQVEsU0FBUyxJQUFJLENBQUMsTUFBTSxFQUFFLEVBQUUsTUFBTSxDQUFDLElBQUksR0FBRyxPQUFPLENBQUMsTUFBTSxDQUFDLEtBQUssQ0FBQyxHQUFHLEtBQUssQ0FBQyxNQUFNLENBQUMsS0FBSyxDQUFDLENBQUMsSUFBSSxDQUFDLFNBQVMsRUFBRSxRQUFRLENBQUMsQ0FBQyxFQUFFO0FBQ3RILFFBQVEsSUFBSSxDQUFDLENBQUMsU0FBUyxHQUFHLFNBQVMsQ0FBQyxLQUFLLENBQUMsT0FBTyxFQUFFLFVBQVUsSUFBSSxFQUFFLENBQUMsRUFBRSxJQUFJLEVBQUUsQ0FBQyxDQUFDO0FBQzlFLEtBQUssQ0FBQyxDQUFDO0FBQ1A7O0FDMUVBLE1BQU0saUJBQWlCLEdBQUcsZUFBZSxDQUFBO0FBQ3pDLE1BQU0sWUFBWSxHQUFHLEVBQUUsQ0FBQTtBQUN2QixNQUFNLFFBQVEsR0FBRyxZQUFZLENBQUE7QUFDN0IsTUFBTSxlQUFlLEdBQUcsSUFBSSxDQUFBO0FBRTVCLE1BQU0sUUFBUSxHQUFHLFVBQVUsQ0FBQyx3bEJBQXdsQixDQUFDLENBQUE7QUFDcm5CLE1BQU0sV0FBVyxHQUFHLFVBQVUsQ0FBQyxxV0FBcVcsQ0FBQyxDQUFBO1NBMEJyWCxnQkFBZ0IsQ0FBRSxFQUFlLEVBQUUsR0FBaUMsRUFBRSxNQUEyQjtJQUMvRyxNQUFNLElBQUksR0FBZ0IsRUFBRSxDQUFDLGFBQWEsQ0FBQyxZQUFZLENBQUMsQ0FBQTs7SUFFeEQsSUFBSSxDQUFDLElBQUksRUFBRTtRQUNULE9BQU07S0FDUDtJQUNELElBQUksSUFBSSxHQUFHLFlBQVksQ0FBQTs7SUFFdkIsSUFBSSxNQUFNLENBQUMsUUFBUSxDQUFDLFlBQVksQ0FBQyxJQUFJLENBQUMsU0FBUyxJQUFJLElBQUksQ0FBQyxTQUFTLENBQUMsUUFBUSxDQUFDLFlBQVksU0FBUyxFQUFFLENBQUMsQ0FBQyxFQUFFO1FBQ3BHLE9BQU07S0FDUDtJQUNELElBQUksQ0FBQyxTQUFTLENBQUMsT0FBTyxDQUFDLENBQUMsS0FBSyxFQUFFLEdBQUcsRUFBRSxNQUFNO1FBQ3hDLElBQUksUUFBUSxDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsRUFBRTtZQUN4QixJQUFJLEdBQUcsS0FBSyxDQUFDLE9BQU8sQ0FBQyxXQUFXLEVBQUUsRUFBRSxDQUFDLENBQUE7WUFDckMsT0FBTTtTQUNQO0tBQ0YsQ0FBQyxDQUFBO0lBQ0YsTUFBTSxHQUFHLEdBQUcsSUFBSSxDQUFDLGFBQWEsQ0FBQTtJQUM5QixNQUFNLEdBQUcsR0FBRyxHQUFHLENBQUMsYUFBYSxDQUFBOztJQUU3QixJQUFJLENBQUMsSUFBSSxDQUFDLFNBQVMsQ0FBQyxRQUFRLEVBQUUsQ0FBQyxRQUFRLENBQUMsV0FBVyxDQUFDLEVBQUU7UUFDcEQsR0FBRyxDQUFDLFNBQVMsQ0FBQyxHQUFHLENBQUMsaUJBQWlCLENBQUMsQ0FBQTtLQUNyQzs7SUFFRCxJQUFJLEdBQUcsQ0FBQyxhQUFhLENBQUMsNEJBQTRCLENBQUMsRUFBRTtRQUNuRCxPQUFPO0tBQ1I7O0lBRUQsR0FBRyxDQUFDLFNBQVMsQ0FBQyxHQUFHLENBQUMsaUJBQWlCLENBQUMsQ0FBQTs7O0lBR3BDLE1BQU0sV0FBVyxHQUFhLElBQUksQ0FBQyxXQUFXLENBQUMsS0FBSyxDQUFDLGVBQWUsQ0FBQyxDQUFBO0lBQ3JFLE1BQU0sUUFBUSxHQUFHLFdBQVcsQ0FBQyxNQUFNLEdBQUcsQ0FBQyxDQUFBO0lBQ3ZDLE1BQU0sTUFBTSxHQUFrQixFQUFFLFFBQVEsRUFBRSxJQUFJLEVBQUUsUUFBUSxFQUFFLEdBQUcsRUFBRSxJQUFJLEVBQUUsR0FBRyxFQUFFLFdBQVcsRUFBRSxDQUFBO0lBQ3ZGLE1BQU0sRUFBRSxjQUFjLEVBQUUsWUFBWSxFQUFFLGNBQWMsRUFBRSxHQUFHLE1BQU0sQ0FBQyxRQUFRLENBQUE7O0lBRXhFLGFBQWEsQ0FBQyxNQUFNLEVBQUUsTUFBTSxDQUFDLENBQUE7O0lBRTdCLElBQUksWUFBWSxFQUFFO1FBQ2hCLFdBQVcsQ0FBQyxNQUFNLEVBQUUsTUFBTSxDQUFDLENBQUE7S0FDNUI7O0lBRUQsSUFBSSxjQUFjLEVBQUU7UUFDbEIsYUFBYSxDQUFDLE1BQU0sRUFBRSxNQUFNLENBQUMsQ0FBQTtLQUM5Qjs7SUFFRCxJQUFJLGNBQWMsRUFBRTtRQUNsQixrQkFBa0IsQ0FBQyxNQUFNLEVBQUUsTUFBTSxDQUFDLENBQUE7S0FDbkM7QUFDSCxDQUFDO0FBSUQsU0FBUyxhQUFhLENBQUUsT0FBZSxFQUFFLGdCQUF5QjtJQUNoRSxNQUFNLE9BQU8sR0FBRyxRQUFRLENBQUMsYUFBYSxDQUFDLE9BQU8sQ0FBQyxDQUFBO0lBQy9DLElBQUksZ0JBQWdCLEVBQUU7UUFDcEIsT0FBTyxDQUFDLFNBQVMsR0FBRyxnQkFBZ0IsQ0FBQTtLQUNyQztJQUNELE9BQU8sT0FBTyxDQUFBO0FBQ2hCLENBQUM7QUFFRCxTQUFTLGtCQUFrQixDQUFFLE1BQTJCLEVBQUUsTUFBcUI7SUFDN0UsTUFBTSxFQUFFLEdBQUcsRUFBRSxJQUFJLEVBQUUsUUFBUSxFQUFFLEdBQUcsTUFBTSxDQUFBO0lBQ3RDLE1BQU0sQ0FBQyxnQkFBZ0IsQ0FBQyxHQUFHLEVBQUUsYUFBYSxFQUFFLENBQUMsS0FBSztRQUNoRCxLQUFLLENBQUMsY0FBYyxFQUFFLENBQUE7UUFDdEIsTUFBTSxNQUFNLEdBQWdCLEtBQUssQ0FBQyxNQUFNLENBQUE7UUFDeEMsSUFBSSxNQUFNLENBQUMsT0FBTyxLQUFLLFFBQVEsRUFBRTtZQUMvQixNQUFNLFdBQVcsR0FBRyxJQUFJQSxhQUFJLENBQUMsTUFBTSxDQUFDLEdBQUcsQ0FBQyxDQUFBO1lBQ3hDLE1BQU0sU0FBUyxHQUFHLE1BQU0sQ0FBQyxZQUFZLEVBQUUsQ0FBQyxRQUFRLEVBQUUsQ0FBQTtZQUNsRCxNQUFNLFFBQVEsR0FBRyxRQUFRLENBQUMsYUFBYSxDQUFDLHdCQUF3QixDQUFDLENBQUE7WUFDakUsTUFBTSxXQUFXLEdBQUcsVUFBVSxDQUFDLE1BQU0sQ0FBQyxnQkFBZ0IsQ0FBQyxHQUFHLENBQUMsQ0FBQyxNQUFNLENBQUMsQ0FBQTtZQUNuRSxNQUFNLFVBQVUsR0FBRyxRQUFRLENBQUMsWUFBWSxDQUFBO1lBQ3hDLE1BQU0sRUFBRSxPQUFPLEVBQUUsS0FBSyxFQUFFLEdBQUcsS0FBSyxDQUFBO1lBQ2hDLE1BQU0sUUFBUSxHQUFHLFdBQVcsSUFBSSxDQUFDLFVBQVUsR0FBRyxLQUFLLElBQUksT0FBTyxDQUFDLENBQUE7WUFDL0QsTUFBTSxLQUFLLEdBQUcsT0FBTyxHQUFHLEtBQUssR0FBRyxHQUFHLENBQUE7WUFDbkMsTUFBTSxjQUFjLEdBQUcsUUFBUSxDQUFDLFNBQVMsQ0FBQTtZQUN6QyxJQUFJLE9BQU8sR0FBRyxJQUFJLENBQUMsSUFBSSxDQUFDLENBQUMsT0FBTyxHQUFHLEVBQUUsSUFBSSxFQUFFLENBQUMsQ0FBQTtZQUM1QyxJQUFJLE9BQU8sR0FBRyxDQUFDLEVBQUU7Z0JBQ2YsT0FBTyxHQUFHLENBQUMsQ0FBQTthQUNaO2lCQUFNLElBQUksT0FBTyxHQUFHLFFBQVEsRUFBRTtnQkFDN0IsT0FBTyxHQUFHLFFBQVEsQ0FBQTthQUNuQjtZQUNELElBQUksU0FBUyxFQUFFO2dCQUNiLFdBQVcsQ0FBQyxPQUFPLENBQUMsQ0FBQyxJQUFJO29CQUN2QixJQUFJO3lCQUNELFFBQVEsQ0FBQyxNQUFNLENBQUM7eUJBQ2hCLE9BQU8sQ0FBQyxpQkFBaUIsRUFBRSxFQUFFLENBQUM7eUJBQzlCLE9BQU8sQ0FBQyxDQUFDLENBQUM7d0JBQ1QsU0FBUyxDQUFDLFNBQVMsQ0FBQyxTQUFTLENBQUMsU0FBUyxDQUFDLENBQUE7cUJBQ3pDLENBQUMsQ0FBQTtpQkFDTCxDQUFDLENBQUE7YUFDSDtZQUNELFdBQVcsQ0FBQyxPQUFPLENBQUMsQ0FBQyxJQUFJO2dCQUN2QixJQUFJO3FCQUNELFFBQVEsQ0FBQyxZQUFZLENBQUM7cUJBQ3RCLE9BQU8sQ0FBQyxpQkFBaUIsRUFBRSxFQUFFLENBQUM7cUJBQzlCLE9BQU8sQ0FBQztvQkFDUCxTQUFTLENBQUMsU0FBUyxDQUFDLFNBQVMsQ0FBQyxJQUFJLENBQUMsV0FBVyxDQUFDLENBQUE7aUJBQ2hELENBQUMsQ0FBQTthQUNMLENBQUMsQ0FBQTtZQUNGLFdBQVcsQ0FBQyxPQUFPLENBQUMsQ0FBQyxJQUFJO2dCQUN2QixJQUFJO3FCQUNELFFBQVEsQ0FBQyxVQUFVLENBQUM7cUJBQ3BCLE9BQU8sQ0FBQyxpQkFBaUIsRUFBRSxFQUFFLENBQUM7cUJBQzlCLE9BQU8sQ0FBQztvQkFDUCxTQUFTLENBQUMsU0FBUyxDQUFDLFNBQVMsQ0FBQyxNQUFNLENBQUMsV0FBVyxDQUFDLE9BQU8sR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFBO2lCQUMvRCxDQUFDLENBQUE7YUFDTCxDQUFDLENBQUE7WUFFRixJQUFJLFdBQVcsR0FBRyxVQUFVLEVBQUU7Z0JBQzVCLElBQUksS0FBSyxHQUFHLENBQUMsRUFBRTtvQkFDYixXQUFXLENBQUMsT0FBTyxDQUFDLENBQUMsSUFBSTt3QkFDdkIsSUFBSTs2QkFDRCxRQUFRLENBQUMsUUFBUSxDQUFDOzZCQUNsQixPQUFPLENBQUMsQ0FBQyxDQUFDOzRCQUNULFFBQVEsQ0FBQyxTQUFTLEdBQUcsY0FBYyxHQUFHLEtBQUssQ0FBQTt5QkFDNUMsQ0FBQyxDQUFBO3FCQUNMLENBQUMsQ0FBQTtpQkFDSDtnQkFDRCxJQUFJLFFBQVEsR0FBRyxDQUFDLEVBQUU7b0JBQ2hCLFdBQVcsQ0FBQyxPQUFPLENBQUMsQ0FBQyxJQUFJO3dCQUN2QixJQUFJOzZCQUNELFFBQVEsQ0FBQyxXQUFXLENBQUM7NkJBQ3JCLE9BQU8sQ0FBQyxDQUFDLENBQUM7NEJBQ1QsUUFBUSxDQUFDLFNBQVMsR0FBRyxjQUFjLEdBQUcsUUFBUSxDQUFBO3lCQUMvQyxDQUFDLENBQUE7cUJBQ0wsQ0FBQyxDQUFBO2lCQUNIO2FBQ0Y7WUFDRCxXQUFXLENBQUMsY0FBYyxDQUFDLEVBQUUsQ0FBQyxFQUFFLEtBQUssQ0FBQyxPQUFPLEVBQUUsQ0FBQyxFQUFFLEtBQUssQ0FBQyxPQUFPLEVBQUUsQ0FBQyxDQUFBO1NBQ25FO0tBQ0YsQ0FBQyxDQUFBO0FBRUosQ0FBQztBQUNELFNBQVMsV0FBVyxDQUFFLE1BQTJCLEVBQUUsTUFBcUI7SUFDdEUsTUFBTSxFQUFFLFFBQVEsRUFBRSxHQUFHLEVBQUUsR0FBRyxNQUFNLENBQUE7SUFDaEMsTUFBTSxXQUFXLEdBQUcsYUFBYSxDQUFDLE1BQU0sRUFBRSxzQkFBc0IsQ0FBQyxDQUFBO0lBQ2pFLFdBQVcsQ0FBQyxTQUFTLEdBQUcsUUFBUSxDQUFBO0lBQ2hDLEdBQUcsQ0FBQyxXQUFXLENBQUMsV0FBVyxDQUFDLENBQUE7QUFDOUIsQ0FBQztBQUVELFNBQVMsYUFBYSxDQUFFLE1BQTJCLEVBQUUsTUFBcUI7SUFDeEUsTUFBTSxFQUFFLElBQUksRUFBRSxHQUFHLEVBQUUsR0FBRyxNQUFNLENBQUE7SUFDNUIsTUFBTSxVQUFVLEdBQUcsYUFBYSxDQUFDLEtBQUssRUFBRSx3QkFBd0IsQ0FBQyxDQUFBO0lBQ2pFLFVBQVUsQ0FBQyxZQUFZLENBQUMsWUFBWSxFQUFFLE1BQU0sQ0FBQyxDQUFBO0lBQzdDLGlCQUFpQixDQUFDLFVBQVUsRUFBRSxRQUFRLEVBQUUsQ0FBQyxDQUFBO0lBRXpDLE1BQU0sV0FBVyxHQUFHO1FBQ2xCLFNBQVMsQ0FBQyxTQUFTLENBQUMsU0FBUyxDQUFDLElBQUksQ0FBQyxXQUFXLENBQUMsQ0FBQyxJQUFJLENBQUM7WUFDbkQsaUJBQWlCLENBQUMsVUFBVSxFQUFFLFdBQVcsRUFBRSxDQUFDLENBQUE7WUFDNUMsVUFBVSxDQUFDO2dCQUNULGlCQUFpQixDQUFDLFVBQVUsRUFBRSxRQUFRLEVBQUUsQ0FBQyxDQUFBO2FBQzFDLEVBQUUsSUFBSSxDQUFDLENBQUM7U0FDVixFQUFFO1lBQ0QsVUFBVSxDQUFDLFNBQVMsR0FBRyxPQUFPLENBQUM7U0FDaEMsQ0FBQyxDQUFDO0tBQ0osQ0FBQTtJQUNELE1BQU0sQ0FBQyxnQkFBZ0IsQ0FBQyxVQUFVLEVBQUUsT0FBTyxFQUFFLFdBQVcsQ0FBQyxDQUFBO0lBQ3pELEdBQUcsQ0FBQyxXQUFXLENBQUMsVUFBVSxDQUFDLENBQUM7SUFDNUIsR0FBRyxDQUFDLFNBQVMsQ0FBQyxHQUFHLENBQUMsaUNBQWlDLENBQUMsQ0FBQTtBQUN0RCxDQUFDO0FBR0QsU0FBUyxhQUFhLENBQUUsTUFBMkIsRUFBRSxNQUFxQjtJQUN4RSxNQUFNLEVBQUUsUUFBUSxFQUFFLEdBQUcsRUFBRSxHQUFHLE1BQU0sQ0FBQTs7SUFFaEMsTUFBTSxVQUFVLEdBQUcsYUFBYSxDQUFDLE1BQU0sRUFBRSx5QkFBeUIsQ0FBQyxDQUFBO0lBQ25FLEtBQUssQ0FBQyxJQUFJLENBQUMsRUFBRSxNQUFNLEVBQUUsUUFBUSxFQUFFLEVBQUUsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDLE9BQU8sQ0FBQyxDQUFDO1FBQ3JELE1BQU0sVUFBVSxHQUFHLGFBQWEsQ0FBQyxNQUFNLEVBQUUsb0JBQW9CLENBQUMsQ0FBQTs7O1FBRzlELFVBQVUsQ0FBQyxXQUFXLENBQUMsVUFBVSxDQUFDLENBQUE7S0FDbkMsQ0FBQyxDQUFBO0lBQ0YsR0FBRyxDQUFDLFdBQVcsQ0FBQyxVQUFVLENBQUMsQ0FBQTtJQUMzQixHQUFHLENBQUMsU0FBUyxDQUFDLEdBQUcsQ0FBQyw2QkFBNkIsQ0FBQyxDQUFBO0FBQ2xELENBQUM7QUFFRCxTQUFTLFVBQVUsQ0FBRSxTQUFpQjtJQUNwQyxPQUFPO1FBQ0wsT0FBTyxJQUFJLFNBQVMsRUFBRSxDQUFDLGVBQWUsQ0FBQyxTQUFTLEVBQUUsZUFBZSxDQUFDLENBQUMsVUFBVSxDQUFBO0tBQzlFLENBQUE7QUFDSCxDQUFDO0FBRUQsU0FBUyxpQkFBaUIsQ0FBRSxNQUFtQixFQUFFLEtBQWdCO0lBQy9ELElBQUksTUFBTSxDQUFDLFVBQVUsSUFBSSxNQUFNLENBQUMsVUFBVSxDQUFDLE1BQU0sR0FBRyxDQUFDLEVBQUU7UUFDckQsTUFBTSxDQUFDLFdBQVcsQ0FBQyxNQUFNLENBQUMsVUFBVSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUE7S0FDekM7SUFDRCxNQUFNLENBQUMsV0FBVyxDQUFDLEtBQUssQ0FBQyxDQUFBO0FBQzNCOztBQ3JOQSxNQUFNLGdCQUFnQixHQUF1QjtJQUM1QyxZQUFZLEVBQUUsQ0FBQyxTQUFTLENBQUM7SUFDekIsWUFBWSxFQUFFLElBQUk7SUFDbEIsY0FBYyxFQUFFLElBQUk7SUFDcEIsY0FBYyxFQUFFLElBQUk7Q0FDcEIsQ0FBQTtNQUVvQixpQkFBa0IsU0FBUUMsZUFBTTtJQUc5QyxNQUFNOztZQUNYLE1BQU0sSUFBSSxDQUFDLFlBQVksRUFBRSxDQUFDO1lBQzFCLElBQUksQ0FBQyxhQUFhLENBQUMsSUFBSSxxQkFBcUIsQ0FBQyxJQUFJLENBQUMsR0FBRyxFQUFFLElBQUksQ0FBQyxDQUFDLENBQUE7WUFDN0QsSUFBSSxDQUFDLDZCQUE2QixDQUFDLENBQUMsRUFBRSxFQUFFLEdBQUc7Z0JBQzFDLGdCQUFnQixDQUFDLEVBQUUsRUFBRSxHQUFHLEVBQUUsSUFBSSxDQUFDLENBQUE7YUFDL0IsQ0FBQyxDQUFBO1NBRUY7S0FBQTtJQUVELFFBQVE7UUFDUCxPQUFPLENBQUMsR0FBRyxDQUFDLHNDQUFzQyxDQUFDLENBQUM7S0FDcEQ7SUFFSyxZQUFZOztZQUNqQixJQUFJLENBQUMsUUFBUSxHQUFHLE1BQU0sQ0FBQyxNQUFNLENBQUMsRUFBRSxFQUFFLGdCQUFnQixFQUFFLE1BQU0sSUFBSSxDQUFDLFFBQVEsRUFBRSxDQUFDLENBQUM7U0FDM0U7S0FBQTtJQUVLLFlBQVk7O1lBQ2pCLE1BQU0sSUFBSSxDQUFDLFFBQVEsQ0FBQyxJQUFJLENBQUMsUUFBUSxDQUFDLENBQUM7U0FDbkM7S0FBQTtDQUNEO0FBR0QsTUFBTSxxQkFBc0IsU0FBUUMseUJBQWdCO0lBR25ELFlBQVksR0FBUSxFQUFFLE1BQXlCO1FBQzlDLEtBQUssQ0FBQyxHQUFHLEVBQUUsTUFBTSxDQUFDLENBQUM7UUFDbkIsSUFBSSxDQUFDLE1BQU0sR0FBRyxNQUFNLENBQUM7S0FDckI7SUFFRCxPQUFPO1FBQ04sSUFBSSxFQUFFLFdBQVcsRUFBRSxHQUFHLElBQUksQ0FBQTtRQUMxQixNQUFNLGFBQWEsR0FBRyxJQUFJLENBQUMsTUFBTSxDQUFDLFFBQVEsQ0FBQTtRQUMxQyxXQUFXLENBQUMsS0FBSyxFQUFFLENBQUE7UUFDbkIsV0FBVyxDQUFDLFFBQVEsQ0FBQyxJQUFJLEVBQUUsRUFBRSxJQUFJLEVBQUUsZ0NBQWdDLElBQUksQ0FBQyxNQUFNLENBQUMsUUFBUSxDQUFDLE9BQU8sRUFBRSxFQUFFLENBQUMsQ0FBQTtRQUNwRyxJQUFJQyxnQkFBTyxDQUFDLFdBQVcsQ0FBQzthQUN0QixPQUFPLENBQUMsdUJBQXVCLENBQUM7YUFDaEMsT0FBTyxDQUFDLHlDQUF5QyxDQUFDO2FBQ2xELFdBQVcsQ0FBQyxJQUFJLElBQUksSUFBSTthQUN2QixjQUFjLENBQUMsNENBQTRDLENBQUM7YUFDNUQsUUFBUSxDQUFDLGFBQWEsQ0FBQyxZQUFZLENBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxDQUFDO2FBQzlDLFFBQVEsQ0FBQyxDQUFPLEtBQUs7WUFDckIsYUFBYSxDQUFDLFlBQVksR0FBRyxLQUFLLENBQUMsS0FBSyxDQUFDLEdBQUcsQ0FBQyxDQUFDO1lBQzlDLE1BQU0sSUFBSSxDQUFDLE1BQU0sQ0FBQyxZQUFZLEVBQUUsQ0FBQztTQUNqQyxDQUFBLENBQUMsQ0FBQyxDQUFBO1FBQ0wsSUFBSUEsZ0JBQU8sQ0FBQyxXQUFXLENBQUM7YUFDdEIsT0FBTyxDQUFDLG9CQUFvQixDQUFDO2FBQzdCLE9BQU8sQ0FBQyw2Q0FBNkMsQ0FBQzthQUN0RCxTQUFTLENBQUMsRUFBRTtZQUNaLEVBQUU7aUJBQ0EsUUFBUSxDQUFDLGFBQWEsQ0FBQyxZQUFZLENBQUM7aUJBQ3BDLFFBQVEsQ0FBQyxDQUFPLFFBQVE7Z0JBQ3hCLGFBQWEsQ0FBQyxZQUFZLEdBQUcsUUFBUSxDQUFBO2dCQUNyQyxNQUFNLElBQUksQ0FBQyxNQUFNLENBQUMsWUFBWSxFQUFFLENBQUE7YUFDaEMsQ0FBQSxDQUFDLENBQUE7U0FDSCxDQUFDLENBQUE7UUFDSCxJQUFJQSxnQkFBTyxDQUFDLFdBQVcsQ0FBQzthQUN0QixPQUFPLENBQUMsa0JBQWtCLENBQUM7YUFDM0IsT0FBTyxDQUFDLDJDQUEyQyxDQUFDO2FBQ3BELFNBQVMsQ0FBQyxFQUFFO1lBQ1osRUFBRTtpQkFDQSxRQUFRLENBQUMsYUFBYSxDQUFDLGNBQWMsQ0FBQztpQkFDdEMsUUFBUSxDQUFDLENBQU8sUUFBUTtnQkFDeEIsYUFBYSxDQUFDLGNBQWMsR0FBRyxRQUFRLENBQUE7Z0JBQ3ZDLE1BQU0sSUFBSSxDQUFDLE1BQU0sQ0FBQyxZQUFZLEVBQUUsQ0FBQTthQUNoQyxDQUFBLENBQUMsQ0FBQTtTQUNILENBQUMsQ0FBQTtRQUNILElBQUlBLGdCQUFPLENBQUMsV0FBVyxDQUFDO2FBQ3RCLE9BQU8sQ0FBQyxpQkFBaUIsQ0FBQzthQUMxQixPQUFPLENBQUMsNERBQTRELENBQUM7YUFDckUsU0FBUyxDQUFDLEVBQUU7WUFDWixFQUFFO2lCQUNBLFFBQVEsQ0FBQyxhQUFhLENBQUMsY0FBYyxDQUFDO2lCQUN0QyxRQUFRLENBQUMsQ0FBTyxRQUFRO2dCQUN4QixhQUFhLENBQUMsY0FBYyxHQUFHLFFBQVEsQ0FBQTtnQkFDdkMsTUFBTSxJQUFJLENBQUMsTUFBTSxDQUFDLFlBQVksRUFBRSxDQUFBO2FBQ2hDLENBQUEsQ0FBQyxDQUFBO1NBQ0gsQ0FBQyxDQUFBO0tBQ0g7Ozs7OyJ9 303 | -------------------------------------------------------------------------------- /.obsidian/plugins/obsidian-code-block-enhancer/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "obsidian-code-block-enhancer", 3 | "name": "Code Block Enhancer", 4 | "version": "1.0.5", 5 | "minAppVersion": "0.9.12", 6 | "description": "Enhance obsidian markdown code block,provides copy button,linenumber,language name tip and so on.", 7 | "author": "hafuhafu", 8 | "authorUrl": "https://github.com/nyable/obsidian-code-block-enhancer", 9 | "isDesktopOnly": false 10 | } -------------------------------------------------------------------------------- /.obsidian/plugins/obsidian-code-block-enhancer/styles.css: -------------------------------------------------------------------------------- 1 | .code-block-copy-button { 2 | display: none; 3 | margin: 0 0 0 auto; 4 | padding: 4px; 5 | position: absolute; 6 | top: 0; 7 | right: 0; 8 | } 9 | .code-block-copy-button svg.copy path { 10 | fill: var(--interactive-accent); 11 | } 12 | .code-block-copy-button:hover, .code-block-copy-button:active { 13 | cursor: pointer; 14 | } 15 | .code-block-copy-button:hover svg path, .code-block-copy-button:active svg path { 16 | filter: brightness(1.4); 17 | transition: all ease 0.3s; 18 | } 19 | .code-block-copy-button svg.copy-success path { 20 | fill: var(--interactive-success); 21 | } 22 | .code-block-copy-button:focus { 23 | outline: 0; 24 | } 25 | 26 | .code-block-lang-name { 27 | position: absolute; 28 | top: 0px; 29 | left: 0px; 30 | color: var(--text-normal); 31 | font-size: 0.8rem; 32 | margin-left: 4px; 33 | user-select: none; 34 | } 35 | 36 | .code-block-wrap { 37 | position: relative; 38 | } 39 | 40 | pre[class*=language-] { 41 | font-size: var(--editor-font-size); 42 | line-height: 1.5em; 43 | } 44 | pre[class*=language-] > code[class*=language-] { 45 | padding-top: 0 !important; 46 | font-size: var(--editor-font-size) !important; 47 | line-height: 1.5em !important; 48 | } 49 | pre[class*=language-].code-block-pre__has-linenum { 50 | padding-left: 4.5em; 51 | } 52 | 53 | .code-block-pre__has-copy-button:hover .code-block-copy-button { 54 | display: block; 55 | } 56 | 57 | .code-block-linenum-wrap { 58 | position: absolute; 59 | top: 1em; 60 | left: 0px; 61 | min-width: 4em; 62 | font-size: var(--editor-font-size); 63 | line-height: 1.5em; 64 | counter-reset: line-num; 65 | text-align: center; 66 | border-right: #999 1px solid; 67 | user-select: none; 68 | pointer-events: none; 69 | background-color: inherit; 70 | } 71 | .code-block-linenum-wrap .code-block-linenum { 72 | display: block; 73 | counter-increment: line-num; 74 | pointer-events: none; 75 | } 76 | .code-block-linenum-wrap .code-block-linenum::before { 77 | content: counter(line-num); 78 | } -------------------------------------------------------------------------------- /.obsidian/plugins/obsidian-rtl/main.js: -------------------------------------------------------------------------------- 1 | /* 2 | THIS IS A GENERATED/BUNDLED FILE BY ESBUILD 3 | if you want to view the source, please visit the github repository of this plugin 4 | */ 5 | 6 | var __defProp = Object.defineProperty; 7 | var __getOwnPropDesc = Object.getOwnPropertyDescriptor; 8 | var __getOwnPropNames = Object.getOwnPropertyNames; 9 | var __hasOwnProp = Object.prototype.hasOwnProperty; 10 | var __export = (target, all) => { 11 | for (var name in all) 12 | __defProp(target, name, { get: all[name], enumerable: true }); 13 | }; 14 | var __copyProps = (to, from, except, desc) => { 15 | if (from && typeof from === "object" || typeof from === "function") { 16 | for (let key of __getOwnPropNames(from)) 17 | if (!__hasOwnProp.call(to, key) && key !== except) 18 | __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); 19 | } 20 | return to; 21 | }; 22 | var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); 23 | 24 | // main.ts 25 | var main_exports = {}; 26 | __export(main_exports, { 27 | default: () => RtlPlugin 28 | }); 29 | module.exports = __toCommonJS(main_exports); 30 | var import_obsidian3 = require("obsidian"); 31 | 32 | // AutoDirPlugin.ts 33 | var import_view = require("@codemirror/view"); 34 | var import_state = require("@codemirror/state"); 35 | 36 | // globals.ts 37 | var RTL_CLASS = "is-rtl"; 38 | var AUTO_CLASS = "is-auto"; 39 | var STRONG_DIR_REGEX = /(?:([\p{sc=Arabic}\p{sc=Hebrew}\p{sc=Syriac}\p{sc=Thaana}])|([\p{sc=Armenian}\p{sc=Bengali}\p{sc=Bopomofo}\p{sc=Braille}\p{sc=Buhid}\p{sc=Canadian_Aboriginal}\p{sc=Cherokee}\p{sc=Cyrillic}\p{sc=Devanagari}\p{sc=Ethiopic}\p{sc=Georgian}\p{sc=Greek}\p{sc=Gujarati}\p{sc=Gurmukhi}\p{sc=Han}\p{sc=Hangul}\p{sc=Hanunoo}\p{sc=Hiragana}\p{sc=Inherited}\p{sc=Kannada}\p{sc=Katakana}\p{sc=Khmer}\p{sc=Lao}\p{sc=Latin}\p{sc=Limbu}\p{sc=Malayalam}\p{sc=Mongolian}\p{sc=Myanmar}\p{sc=Ogham}\p{sc=Oriya}\p{sc=Runic}\p{sc=Sinhala}\p{sc=Tagalog}\p{sc=Tagbanwa}\p{sc=Tamil}\p{sc=Telugu}\p{sc=Thai}\p{sc=Tibetan}\p{sc=Yi}]))/u; 40 | var detectDirection = (s) => { 41 | const match = s.match(STRONG_DIR_REGEX); 42 | if (match && match[1]) { 43 | return "rtl"; 44 | } else if (match && match[2]) { 45 | return "ltr"; 46 | } 47 | return null; 48 | }; 49 | 50 | // AutoDirPlugin.ts 51 | var import_obsidian = require("obsidian"); 52 | function getAutoDirectionPlugin(rtlPlugin) { 53 | return import_view.ViewPlugin.fromClass(class { 54 | constructor(view) { 55 | this.decorationRegions = []; 56 | this.active = false; 57 | this.rtlDec = import_view.Decoration.line({ 58 | attributes: { dir: "rtl" } 59 | }); 60 | this.ltrDec = import_view.Decoration.line({ 61 | attributes: { dir: "ltr" } 62 | }); 63 | this.emptyDirDec = import_view.Decoration.line({ 64 | attributes: { dir: "" } 65 | }); 66 | this.autoDec = import_view.Decoration.line({ 67 | attributes: { dir: "auto" } 68 | }); 69 | this.decorations = this.buildDecorations(); 70 | this.rtlPlugin = rtlPlugin; 71 | this.view = view; 72 | const editorInfo = this.view.state.field(import_obsidian.editorInfoField); 73 | if (editorInfo instanceof import_obsidian.MarkdownView) { 74 | this.rtlPlugin.adjustDirectionToView(editorInfo, this); 75 | } 76 | this.rtlPlugin.handleIframeEditor(this.view.dom, this.view, editorInfo.file, this); 77 | } 78 | update(vu) { 79 | if (vu.viewportChanged || vu.docChanged) { 80 | const regions = []; 81 | if (vu.docChanged) { 82 | vu.changes.iterChanges((fromA, toA, fromB, toB) => { 83 | const shift = toB - fromB - (toA - fromA); 84 | this.shiftDecorationRegions(shift < 0 ? toB : toA, shift); 85 | regions.push(...this.getLineRegions(vu.state.doc, fromB, toB)); 86 | }); 87 | } 88 | this.updateEx(vu.view, regions); 89 | } 90 | } 91 | destroy() { 92 | } 93 | setActive(active, view) { 94 | const forceUpdate = this.active !== active; 95 | this.active = active; 96 | this.decorations = this.buildDecorations(); 97 | if (forceUpdate) { 98 | this.updateEx(view); 99 | } 100 | } 101 | updateEx(view, regions = []) { 102 | if (regions.length === 0) { 103 | const { from, to } = view.viewport; 104 | regions = this.getLineRegions(view.state.doc, from, to); 105 | } 106 | for (const { from, to } of regions) { 107 | for (let pos = from; pos <= to; ) { 108 | const line = view.state.doc.lineAt(pos); 109 | let dec = this.emptyDirDec; 110 | if (this.active) { 111 | const s = view.state.doc.sliceString(line.from, line.to); 112 | const d = this.detectDecoration(s); 113 | dec = d ? d : this.lineBeforeDecoration(line.from); 114 | } 115 | this.addDecorationRegion({ from: line.from, to: line.to, dec }); 116 | pos = line.to + 1; 117 | } 118 | } 119 | this.decorations = this.buildDecorations(); 120 | } 121 | buildDecorations() { 122 | const builder = new import_state.RangeSetBuilder(); 123 | for (const dr of this.decorationRegions) { 124 | builder.add(dr.from, dr.from, dr.dec); 125 | } 126 | return builder.finish(); 127 | } 128 | addDecorationRegion(dr) { 129 | for (let i = 0; i < this.decorationRegions.length; i++) { 130 | if (this.decorationRegions[i].from < dr.from) { 131 | continue; 132 | } 133 | if (this.decorationRegions[i].from === dr.from) { 134 | this.decorationRegions[i] = dr; 135 | } else if (this.decorationRegions[i].from > dr.from) { 136 | this.decorationRegions.splice(i, 0, dr); 137 | } 138 | return; 139 | } 140 | this.decorationRegions.push(dr); 141 | } 142 | shiftDecorationRegions(from, amount) { 143 | if (amount === 0) { 144 | return; 145 | } 146 | for (let i = 0; i < this.decorationRegions.length; i++) { 147 | if (this.decorationRegions[i].from < from) { 148 | continue; 149 | } 150 | this.decorationRegions[i].from += amount; 151 | this.decorationRegions[i].to += amount; 152 | if (this.decorationRegions[i].from <= from) { 153 | this.decorationRegions.splice(i, 1); 154 | i--; 155 | } 156 | } 157 | } 158 | detectDecoration(s) { 159 | const direction = detectDirection(s.replace("- [x]", "")); 160 | switch (direction) { 161 | case "rtl": 162 | return this.rtlDec; 163 | case "ltr": 164 | return this.ltrDec; 165 | } 166 | return null; 167 | } 168 | lineBeforeDecoration(from, def = this.ltrDec) { 169 | const l = this.decorationRegions.length; 170 | if (l !== 0 && from > this.decorationRegions[l - 1].from) { 171 | return this.decorationRegions[l - 1].dec; 172 | } 173 | for (let i = 0; i < l; i++) { 174 | if (i !== 0 && this.decorationRegions[i].from >= from) { 175 | return this.decorationRegions[i - 1].dec; 176 | } 177 | } 178 | return def; 179 | } 180 | getLineRegions(doc, from, to) { 181 | const regions = []; 182 | for (let i = from; i <= to; i++) { 183 | const l = doc.lineAt(i); 184 | i = l.to; 185 | regions.push({ from: l.from, to: l.to }); 186 | } 187 | return regions; 188 | } 189 | }, { decorations: (v) => v.decorations }); 190 | } 191 | 192 | // AutoDirPostProcessor.ts 193 | var lastDetectedDir = "ltr"; 194 | var specialNodes = ["A", "STRONG", "EM", "DEL", "CODE"]; 195 | function breaksToDivs(el) { 196 | if (!el) 197 | return; 198 | if (el.tagName == "P") { 199 | const splitText = el.innerHTML.split("
"); 200 | if (splitText.length > 1) { 201 | let newInnerHtml = ""; 202 | splitText.map((line) => { 203 | newInnerHtml += `
${line}
204 | `; 205 | }); 206 | el.innerHTML = newInnerHtml; 207 | } 208 | } 209 | if (el.children && el.children.length > 0) { 210 | for (let i = 0; i < el.children.length; i++) 211 | breaksToDivs(el.children[i]); 212 | } 213 | } 214 | function detectCanvasElement(el, ctx, setPreviewDirection) { 215 | const container = ctx.containerEl; 216 | if (container && container.closest) { 217 | const possibleCanvas = container.closest(".canvas-node-content"); 218 | if (possibleCanvas) { 219 | const markdownPreview = container.closest(".markdown-preview-view"); 220 | if (markdownPreview && markdownPreview instanceof HTMLDivElement) { 221 | setPreviewDirection(ctx.sourcePath, markdownPreview); 222 | } 223 | } 224 | } 225 | } 226 | var autoDirectionPostProcessor = (el, ctx, setPreviewDirection) => { 227 | let shouldAddDir = false, addedDir = false; 228 | const childNodes = []; 229 | detectCanvasElement(el, ctx, setPreviewDirection); 230 | breaksToDivs(el); 231 | for (let i = 0; i < el.childNodes.length; i++) { 232 | const n = el.childNodes[i]; 233 | if (!addedDir && n.nodeName === "#text" && n.nodeValue && n.nodeValue !== "\n") { 234 | const dir = detectDirection(n.nodeValue); 235 | if (dir) { 236 | addedDir = true; 237 | lastDetectedDir = dir; 238 | if (specialNodes.contains(el.nodeName) && el.parentElement) { 239 | addDirClassIfNotAddedBefore(el.parentElement, dirClass(dir)); 240 | } else { 241 | el.addClass(dirClass(dir)); 242 | if (el.parentElement && el.parentElement.nodeName === "LI") { 243 | addDirClassIfNotAddedBefore(el.parentElement, dirClass(dir)); 244 | } 245 | } 246 | } 247 | shouldAddDir = true; 248 | continue; 249 | } 250 | childNodes.push(n); 251 | if (i === el.childNodes.length - 1 && shouldAddDir && !addedDir) { 252 | el.addClass(dirClass(lastDetectedDir)); 253 | } 254 | } 255 | for (let i = 0; i < childNodes.length; i++) { 256 | autoDirectionPostProcessor(childNodes[i], ctx, setPreviewDirection); 257 | } 258 | if (el.nodeName === "UL") { 259 | const lis = el.querySelectorAll("li"); 260 | if (lis.length > 0 && lis[0].hasClass("esm-rtl")) { 261 | el.addClass(dirClass("rtl")); 262 | } 263 | } 264 | }; 265 | function dirClass(dir) { 266 | if (dir === "rtl") { 267 | return "esm-rtl"; 268 | } else { 269 | return "esm-ltr"; 270 | } 271 | } 272 | function addDirClassIfNotAddedBefore(el, cls) { 273 | if (el.hasClass("esm-rtl") || el.hasClass("esm-ltr")) { 274 | return; 275 | } 276 | el.addClass(cls); 277 | } 278 | 279 | // main.ts 280 | var import_view2 = require("@codemirror/view"); 281 | 282 | // settingsTab.ts 283 | var import_obsidian2 = require("obsidian"); 284 | var DEFAULT_SETTINGS = { 285 | fileDirections: {}, 286 | defaultDirection: "ltr", 287 | rememberPerFile: true, 288 | setNoteTitleDirection: true, 289 | setYamlDirection: false, 290 | statusBar: true 291 | }; 292 | var RtlSettingsTab = class extends import_obsidian2.PluginSettingTab { 293 | constructor(app, plugin) { 294 | super(app, plugin); 295 | this.plugin = plugin; 296 | this.settings = plugin.settings; 297 | } 298 | display() { 299 | let { containerEl } = this; 300 | containerEl.empty(); 301 | containerEl.createEl("h2", { text: "RTL Settings" }); 302 | this.plugin.syncDefaultDirection(); 303 | new import_obsidian2.Setting(containerEl).setName("Remember text direction per file").setDesc("Store and remember the text direction used for each file individually.").addToggle((toggle) => toggle.setValue(this.settings.rememberPerFile).onChange((value) => { 304 | this.settings.rememberPerFile = value; 305 | this.plugin.saveSettings(); 306 | this.plugin.adjustDirectionToActiveView(); 307 | })); 308 | new import_obsidian2.Setting(containerEl).setName("Default text direction").setDesc("What should be the default text direction in Obsidian?").addDropdown((dropdown) => dropdown.addOption("ltr", "LTR").addOption("rtl", "RTL").addOption("auto", "Auto").setValue(this.settings.defaultDirection).onChange((value) => { 309 | this.settings.defaultDirection = value; 310 | this.app.vault.setConfig("rightToLeft", value == "rtl"); 311 | this.plugin.saveSettings(); 312 | this.plugin.adjustDirectionToActiveView(); 313 | })); 314 | new import_obsidian2.Setting(containerEl).setName("Set note title direction").setDesc("In RTL notes, also set the direction of the note title.").addToggle((toggle) => toggle.setValue(this.settings.setNoteTitleDirection).onChange((value) => { 315 | this.settings.setNoteTitleDirection = value; 316 | this.plugin.saveSettings(); 317 | this.plugin.adjustDirectionToActiveView(); 318 | })); 319 | new import_obsidian2.Setting(containerEl).setName("Set YAML direction in Preview").setDesc("For RTL notes, preview YAML blocks as RTL. (When turning off, restart of Obsidian is required.)").addToggle((toggle) => { 320 | var _a; 321 | return toggle.setValue((_a = this.settings.setYamlDirection) != null ? _a : false).onChange((value) => { 322 | this.settings.setYamlDirection = value; 323 | this.plugin.saveSettings(); 324 | this.plugin.adjustDirectionToActiveView(); 325 | }); 326 | }); 327 | new import_obsidian2.Setting(containerEl).setName("Show status bar item").setDesc("Show a clickable status bar item showing the current direction.").addToggle((toggle) => { 328 | var _a; 329 | return toggle.setValue((_a = this.settings.statusBar) != null ? _a : true).onChange((value) => { 330 | this.settings.statusBar = value; 331 | this.plugin.saveSettings(); 332 | this.plugin.adjustDirectionToActiveView(); 333 | }); 334 | }); 335 | } 336 | }; 337 | 338 | // main.ts 339 | var RtlPlugin = class extends import_obsidian3.Plugin { 340 | constructor() { 341 | super(...arguments); 342 | this.settings = null; 343 | this.statusBarItem = null; 344 | this.statusBarText = null; 345 | } 346 | async onload() { 347 | this.addCommand({ 348 | id: "switch-text-direction", 349 | name: "Switch Text Direction (LTR->RTL->auto)", 350 | icon: "arrow-left-right", 351 | callback: () => { 352 | const view = this.app.workspace.getActiveViewOfType(import_obsidian3.MarkdownView); 353 | if (!view || !(view == null ? void 0 : view.editor)) 354 | return; 355 | this.switchDocumentDirection(view.editor, view); 356 | } 357 | }); 358 | this.autoDirectionPlugin = getAutoDirectionPlugin(this); 359 | this.registerEditorExtension(this.autoDirectionPlugin); 360 | this.registerEditorExtension(import_view2.EditorView.perLineTextDirection.of(true)); 361 | this.registerMarkdownPostProcessor((el, ctx) => { 362 | autoDirectionPostProcessor(el, ctx, (path, markdownPreviewElement) => this.setCanvasPreviewDirection(path, markdownPreviewElement)); 363 | }); 364 | await this.convertLegacySettings(); 365 | await this.loadSettings(); 366 | this.addSettingTab(new RtlSettingsTab(this.app, this)); 367 | this.app.workspace.on("active-leaf-change", async (leaf) => { 368 | this.adjustDirectionToActiveView(); 369 | this.updateStatusBar(); 370 | }); 371 | this.app.workspace.on("file-open", async (file, ctx) => { 372 | this.adjustDirectionToActiveView(); 373 | this.updateStatusBar(); 374 | }); 375 | this.registerEvent(this.app.vault.on("delete", (file) => { 376 | if (file && file.path && file.path in this.settings.fileDirections) { 377 | delete this.settings.fileDirections[file.path]; 378 | this.saveSettings(); 379 | } 380 | })); 381 | this.registerEvent(this.app.vault.on("rename", (file, oldPath) => { 382 | if (file && file.path && oldPath in this.settings.fileDirections) { 383 | this.settings.fileDirections[file.path] = this.settings.fileDirections[oldPath]; 384 | delete this.settings.fileDirections[oldPath]; 385 | this.saveSettings(); 386 | } 387 | })); 388 | this.statusBarItem = this.addStatusBarItem(); 389 | const languageIcon = (0, import_obsidian3.getIcon)("arrow-left-right"); 390 | this.statusBarItem.appendChild(languageIcon); 391 | this.statusBarText = this.statusBarItem.createEl("span"); 392 | this.statusBarText.style.marginLeft = "5px"; 393 | this.statusBarItem.title = "Text direction"; 394 | this.statusBarItem.addClass("mod-clickable"); 395 | this.statusBarItem.addEventListener("click", (_ev) => { 396 | const view = this.app.workspace.getActiveViewOfType(import_obsidian3.MarkdownView); 397 | if (!view || !(view == null ? void 0 : view.editor)) 398 | return; 399 | this.switchDocumentDirection(view.editor, view); 400 | }); 401 | } 402 | onunload() { 403 | const view = this.app.workspace.getActiveViewOfType(import_obsidian3.MarkdownView); 404 | if (view && (view == null ? void 0 : view.editor)) { 405 | const editorView = view.editor.cm; 406 | this.adjustAutoDirection(editorView, "ltr"); 407 | } 408 | console.log("unloading RTL plugin"); 409 | } 410 | adjustDirectionToActiveView() { 411 | const view = this.app.workspace.getActiveViewOfType(import_obsidian3.MarkdownView); 412 | if (!view) 413 | return; 414 | this.adjustDirectionToView(view); 415 | } 416 | adjustDirectionToView(view, autoDirectionPlugin) { 417 | if (!view) 418 | return; 419 | this.syncDefaultDirection(); 420 | const file = view == null ? void 0 : view.file; 421 | const editor = view == null ? void 0 : view.editor; 422 | const editorView = editor == null ? void 0 : editor.cm; 423 | if (file && file.path && editorView) { 424 | const [requiredDirection, _usedDefault] = this.getRequiredFileDirection(file); 425 | this.setMarkdownViewDirection(view, editor, editorView, requiredDirection, autoDirectionPlugin); 426 | } 427 | } 428 | getRequiredFileDirection(file) { 429 | if (!file) { 430 | return [this.settings.defaultDirection, true]; 431 | } 432 | if (!(file instanceof import_obsidian3.TFile)) 433 | return null; 434 | let requiredDirection = null; 435 | const frontMatterDirection = this.getFrontMatterDirection(file); 436 | let usedDefault = false; 437 | if (frontMatterDirection) { 438 | if (frontMatterDirection == "rtl" || frontMatterDirection == "ltr" || frontMatterDirection == "auto") 439 | requiredDirection = frontMatterDirection; 440 | else 441 | console.log("Front matter direction in file", file.path, "is unknown:", frontMatterDirection); 442 | } else if (this.settings.rememberPerFile && file.path in this.settings.fileDirections) { 443 | requiredDirection = this.settings.fileDirections[file.path]; 444 | } else { 445 | requiredDirection = this.settings.defaultDirection; 446 | usedDefault = true; 447 | } 448 | return [requiredDirection, usedDefault]; 449 | } 450 | async saveSettings() { 451 | await this.saveData(this.settings); 452 | } 453 | async loadSettings() { 454 | this.settings = Object.assign({}, DEFAULT_SETTINGS, await this.loadData()); 455 | } 456 | async convertLegacySettings() { 457 | const legacySettingsPath = ".obsidian/rtl.json"; 458 | if (await this.app.vault.adapter.exists(legacySettingsPath)) { 459 | const legacyContent = await this.app.vault.adapter.read(legacySettingsPath); 460 | if (legacyContent) { 461 | this.settings = JSON.parse(legacyContent); 462 | } 463 | this.app.vault.adapter.remove(legacySettingsPath); 464 | new import_obsidian3.Notice("RTL Plugin: legacy settings were converted to the new format"); 465 | this.saveSettings(); 466 | } 467 | } 468 | updateStatusBar() { 469 | let hide = true; 470 | let usedDefault = false; 471 | const view = this.app.workspace.getActiveViewOfType(import_obsidian3.MarkdownView); 472 | if (view && (view == null ? void 0 : view.editor)) { 473 | const direction = this.getDocumentDirection(view.editor, view); 474 | if (view.file && view.file.path) 475 | [, usedDefault] = this.getRequiredFileDirection(view.file); 476 | if (this.settings.statusBar) { 477 | let directionString = direction === "auto" ? "auto" : direction === "ltr" ? "LTR" : "RTL"; 478 | let statusString = ""; 479 | if (usedDefault) 480 | statusString = `Default (${direction})`; 481 | else { 482 | if (direction === "auto") 483 | statusString = "Auto"; 484 | else 485 | statusString = directionString; 486 | } 487 | this.statusBarText.textContent = statusString; 488 | this.statusBarItem.style.display = null; 489 | hide = false; 490 | } 491 | } 492 | if (hide) 493 | this.hideStatusBar(); 494 | } 495 | hideStatusBar() { 496 | this.statusBarItem.style.display = "none"; 497 | } 498 | handleIframeEditor(editorDiv, editorView, file, autoDirectionPlugin) { 499 | const isInIframe = editorDiv.closest(".mod-inside-iframe"); 500 | if (isInIframe) { 501 | if (editorDiv instanceof HTMLDivElement) { 502 | const [requiredDirection, _] = this.getRequiredFileDirection(file); 503 | this.adjustAutoDirection(editorView, requiredDirection, autoDirectionPlugin); 504 | this.setDocumentDirectionForEditorDiv(editorDiv, requiredDirection); 505 | } 506 | } 507 | } 508 | setMarkdownViewDirection(view, editor, editorView, newDirection, autoDirectionPlugin) { 509 | if (!view || !editor) { 510 | this.hideStatusBar(); 511 | return; 512 | } 513 | let title = editorView.dom.querySelector(".inline-title"); 514 | if (!title) { 515 | title = view.previewMode.containerEl.querySelector(".inline-title"); 516 | } 517 | title == null ? void 0 : title.setAttribute("dir", newDirection === "auto" ? "auto" : ""); 518 | this.adjustAutoDirection(editorView, newDirection, autoDirectionPlugin); 519 | const editorDivs = view.contentEl.getElementsByClassName("cm-editor"); 520 | for (const editorDiv of editorDivs) { 521 | if (editorDiv instanceof HTMLDivElement) 522 | this.setDocumentDirectionForEditorDiv(editorDiv, newDirection); 523 | } 524 | const markdownPreviews = view.contentEl.getElementsByClassName("markdown-preview-view"); 525 | for (const preview of markdownPreviews) { 526 | if (preview instanceof HTMLDivElement) 527 | this.setDocumentDirectionForReadingDiv(preview, newDirection); 528 | } 529 | if (this.settings.setNoteTitleDirection) { 530 | const container = view.containerEl.parentElement; 531 | let header = container.getElementsByClassName("view-header-title-container"); 532 | header[0].style.direction = newDirection; 533 | } 534 | editor.refresh(); 535 | if (newDirection !== "auto") { 536 | this.setExportDirection(newDirection); 537 | } 538 | } 539 | adjustAutoDirection(editorView, newDirection, autoDirectionPlugin) { 540 | const autoDirection = autoDirectionPlugin != null ? autoDirectionPlugin : editorView.plugin(this.autoDirectionPlugin); 541 | if (autoDirection) { 542 | autoDirection.setActive(newDirection === "auto", editorView); 543 | if (!autoDirectionPlugin) 544 | editorView.dispatch(); 545 | } 546 | } 547 | setDocumentDirectionForEditorDiv(editorDiv, newDirection) { 548 | editorDiv.style.direction = newDirection === "auto" ? "" : newDirection; 549 | this.addDirectionClassToEl(editorDiv.parentElement, newDirection); 550 | } 551 | setDocumentDirectionForReadingDiv(readingDiv, newDirection) { 552 | readingDiv.style.direction = newDirection === "auto" ? "" : newDirection; 553 | this.addDirectionClassToEl(readingDiv, newDirection); 554 | readingDiv.classList.remove("rtl-yaml"); 555 | if (newDirection !== "auto" && this.settings.setYamlDirection) 556 | readingDiv.classList.add("rtl-yaml"); 557 | } 558 | setCanvasPreviewDirection(path, markdownPreviewElement) { 559 | const file = this.app.vault.getAbstractFileByPath(path); 560 | const [requiredDirection, _] = this.getRequiredFileDirection(file); 561 | this.setDocumentDirectionForReadingDiv(markdownPreviewElement, requiredDirection); 562 | } 563 | addDirectionClassToEl(el, direction) { 564 | switch (direction) { 565 | case "rtl": 566 | el.classList.remove(AUTO_CLASS); 567 | el.classList.add(RTL_CLASS); 568 | break; 569 | case "auto": 570 | el.classList.remove(RTL_CLASS); 571 | el.classList.add(AUTO_CLASS); 572 | break; 573 | default: 574 | el.classList.remove(RTL_CLASS); 575 | el.classList.remove(AUTO_CLASS); 576 | } 577 | } 578 | setExportDirection(newDirection) { 579 | this.replacePageStyleByString("searched and replaced", `/* This is searched and replaced by the plugin */ @media print { body { direction: ${newDirection}; } }`, true); 580 | } 581 | replacePageStyleByString(searchString, newStyle, addIfNotFound) { 582 | let alreadyExists = false; 583 | let style = this.findPageStyle(searchString); 584 | if (style) { 585 | if (style.getText() === searchString) 586 | alreadyExists = true; 587 | else 588 | style.setText(newStyle); 589 | } else if (addIfNotFound) { 590 | let style2 = document.createElement("style"); 591 | style2.textContent = newStyle; 592 | document.head.appendChild(style2); 593 | } 594 | return style && !alreadyExists; 595 | } 596 | findPageStyle(regex) { 597 | let styles = document.head.getElementsByTagName("style"); 598 | for (let style of styles) { 599 | if (style.getText().match(regex)) 600 | return style; 601 | } 602 | return null; 603 | } 604 | switchDocumentDirection(editor, view) { 605 | let newDirection = this.getDocumentDirection(editor, view); 606 | if (newDirection === null) { 607 | new import_obsidian3.Notice("Obsidian RTL can't set the direction of this document"); 608 | return; 609 | } 610 | let displayName = ""; 611 | switch (newDirection) { 612 | case "ltr": 613 | newDirection = "rtl"; 614 | displayName = "RTL"; 615 | break; 616 | case "rtl": 617 | newDirection = "auto"; 618 | displayName = "Auto"; 619 | break; 620 | case "auto": 621 | newDirection = "ltr"; 622 | displayName = "LTR"; 623 | break; 624 | } 625 | if (view instanceof import_obsidian3.MarkdownView) { 626 | const editorView = view.editor.cm; 627 | this.setMarkdownViewDirection(view, editor, editorView, newDirection); 628 | if (this.settings.rememberPerFile && view.file && view.file.path) { 629 | this.settings.fileDirections[view.file.path] = newDirection; 630 | this.saveSettings(); 631 | } 632 | new import_obsidian3.Notice(`Document direction set to ${displayName}`, 2e3); 633 | this.updateStatusBar(); 634 | } else { 635 | const canvasView = this.getCanvasContext(view); 636 | if (canvasView) { 637 | if (view.file) 638 | new import_obsidian3.Notice("To change a canvas card direction, open the document separately and reload the canvas."); 639 | else 640 | new import_obsidian3.Notice("Can't change the direction of a card without a file."); 641 | } 642 | } 643 | } 644 | getCanvasContext(ctx) { 645 | if (ctx instanceof import_obsidian3.MarkdownView) 646 | return null; 647 | const possibleCanvasContainer = ctx == null ? void 0 : ctx.containerEl; 648 | if (possibleCanvasContainer && possibleCanvasContainer.hasClass("canvas-node-content")) 649 | return possibleCanvasContainer; 650 | } 651 | getDocumentDirection(_editor, ctx) { 652 | let refElement = null; 653 | if (ctx instanceof import_obsidian3.MarkdownView) { 654 | refElement = ctx.contentEl; 655 | } else { 656 | refElement = this.getCanvasContext(ctx); 657 | } 658 | if (refElement === null) 659 | return null; 660 | const rtlEditors = refElement.getElementsByClassName(RTL_CLASS), autoEditors = refElement.getElementsByClassName(AUTO_CLASS); 661 | if (rtlEditors.length > 0) 662 | return "rtl"; 663 | else if (autoEditors.length > 0) 664 | return "auto"; 665 | else 666 | return "ltr"; 667 | } 668 | getFrontMatterDirection(file) { 669 | const fileCache = this.app.metadataCache.getFileCache(file); 670 | const frontMatter = fileCache == null ? void 0 : fileCache.frontmatter; 671 | if (frontMatter && (frontMatter == null ? void 0 : frontMatter.direction)) { 672 | try { 673 | const direction = frontMatter.direction; 674 | return direction; 675 | } catch (error) { 676 | } 677 | } 678 | } 679 | syncDefaultDirection() { 680 | const obsidianDirection = this.app.vault.getConfig("rightToLeft") ? "rtl" : "ltr"; 681 | if (obsidianDirection != this.settings.defaultDirection && this.settings.defaultDirection !== "auto") { 682 | this.settings.defaultDirection = obsidianDirection; 683 | this.saveSettings(); 684 | } 685 | } 686 | }; 687 | -------------------------------------------------------------------------------- /.obsidian/plugins/obsidian-rtl/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "obsidian-rtl", 3 | "name": "RTL Support", 4 | "version": "1.1.1", 5 | "minAppVersion": "0.15.3", 6 | "description": "Right to Left (RTL) text direction support for languages like Arabic, Hebrew and Persian (Farsi).", 7 | "author": "esm", 8 | "authorUrl": "", 9 | "isDesktopOnly": false 10 | } 11 | -------------------------------------------------------------------------------- /.obsidian/plugins/obsidian-rtl/styles.css: -------------------------------------------------------------------------------- 1 | @media print { 2 | span.cm-tab { 3 | width: 50px !important; 4 | display: inline-block; 5 | } 6 | 7 | .is-auto .esm-ltr { 8 | direction: ltr; 9 | text-align-last: left; 10 | } 11 | 12 | .is-auto .esm-rtl { 13 | direction: rtl; 14 | text-align: right; 15 | } 16 | } 17 | 18 | /* List indent fix */ 19 | .is-mobile .is-rtl .HyperMD-list-line, .is-mobile .HyperMD-list-line[dir="rtl"] { 20 | text-indent: 0px !important; 21 | padding-left: 0 !important; 22 | } 23 | 24 | .CodeMirror-rtl pre { 25 | text-indent: 0px !important; 26 | } 27 | 28 | /* Embedded links always LTR */ 29 | .embedded-backlinks { 30 | direction: ltr; 31 | } 32 | 33 | /* Patch YAML RTL */ 34 | /* In a preview that is strictly RTL (is-rtl) and the settings ask to right-aline YAML (rtl-yaml), set a YAML block to RTL. */ 35 | .is-rtl.rtl-yaml code.language-yaml { 36 | text-align: right; 37 | } 38 | /* Then move the 'copy' button to the left */ 39 | .is-rtl.rtl-yaml code.language-yaml + button.copy-code-button { 40 | right: unset; 41 | left: 0; 42 | } 43 | /* In a preview that is auto (is-auto), and the YAML was detected as RTL (esm-rtl), set the 'copy' button to the left */ 44 | .is-auto .esm-rtl.language-yaml + button.copy-code-button { 45 | right: unset; 46 | left: 0; 47 | } 48 | 49 | /* In RTL, or in Auto with a first line that is RTL, set the flair (where it says e.g. 'yaml' in Edit mode) to the left */ 50 | .is-rtl div:has(.HyperMD-codeblock-begin) .code-block-flair, 51 | .is-auto div:has(.HyperMD-codeblock-begin + .HyperMD-codeblock[dir="rtl"]) .code-block-flair { 52 | right: unset; 53 | left: 6px; 54 | } 55 | 56 | /* RTL and Auto callout titles that are detected as RTL - set to the right */ 57 | .is-rtl .callout-title:has(.esm-rtl), 58 | .is-auto .callout-title:has(.esm-rtl) { 59 | direction: rtl; 60 | } 61 | .is-auto .callout-content .esm-rtl { 62 | direction: rtl; 63 | } 64 | /* When an RTL callout title was set to the right, left-justify its edit block button */ 65 | .is-rtl div.cm-callout:has(.callout-title .esm-rtl) .edit-block-button, 66 | .is-auto div.cm-callout:has(.callout-title .esm-rtl) .edit-block-button { 67 | right: unset; 68 | left: var(--size-2-2); 69 | } 70 | 71 | .markdown-source-view .cm-line[dir="rtl"] .task-list-label { 72 | margin-left: 0; 73 | margin-right: -3px; 74 | } 75 | 76 | /* Better spacing between bullet and text */ 77 | .outliner-plugin-better-bullets .markdown-source-view.is-rtl .cm-formatting-list-ul, 78 | .outliner-plugin-better-bullets .markdown-source-view .cm-line[dir="rtl"] .cm-formatting-list-ul { 79 | margin-right: 0; 80 | margin-left: 0.3em; 81 | } 82 | 83 | .markdown-source-view.is-rtl .is-collapsed .collapse-indicator svg.svg-icon, 84 | .markdown-source-view .cm-line[dir="rtl"] .is-collapsed .collapse-indicator svg.svg-icon { 85 | transform: rotate(90deg); 86 | } 87 | 88 | /* Styling for collapse indicator on the headings */ 89 | .markdown-source-view.is-rtl .cm-line .cm-fold-indicator .collapse-indicator, 90 | .markdown-source-view .cm-line[dir="rtl"] .cm-fold-indicator .collapse-indicator { 91 | padding-right: 0; 92 | padding-left: 6px; 93 | right: -16px; 94 | } 95 | 96 | /* Styling for collapse indicator on the lists */ 97 | .markdown-source-view.is-rtl .cm-line:not(.cm-active):not(.HyperMD-header):not(.HyperMD-task-line) .cm-fold-indicator .collapse-indicator, 98 | .markdown-source-view .cm-line[dir="rtl"]:not(.cm-active):not(.HyperMD-header):not(.HyperMD-task-line) .cm-fold-indicator .collapse-indicator { 99 | padding-right: 0; 100 | padding-left: 18px; 101 | right: -16px; 102 | } 103 | 104 | /* Styling for tags in RTL */ 105 | .markdown-source-view.is-rtl .cm-line .cm-hashtag.cm-hashtag-begin, 106 | .markdown-source-view .cm-line[dir="rtl"] .cm-hashtag.cm-hashtag-begin { 107 | border-top-right-radius: var(--tag-radius); 108 | border-bottom-right-radius: var(--tag-radius); 109 | border-top-left-radius: 0; 110 | border-bottom-left-radius: 0; 111 | border-left: none; 112 | border-right: var(--tag-border-width) solid var(--tag-border-color); 113 | padding-right: var(--tag-padding-x); 114 | padding-left: 0; 115 | } 116 | .markdown-source-view.is-rtl .cm-line .cm-hashtag.cm-hashtag-end, 117 | .markdown-source-view .cm-line[dir="rtl"] .cm-hashtag.cm-hashtag-end { 118 | border-top-left-radius: var(--tag-radius); 119 | border-bottom-left-radius: var(--tag-radius); 120 | border-top-right-radius: 0; 121 | border-bottom-right-radius: 0; 122 | border-right: none; 123 | border-left: var(--tag-border-width) solid var(--tag-border-color); 124 | padding-left: var(--tag-padding-x); 125 | padding-right: 0; 126 | } 127 | 128 | .markdown-preview-view.is-auto .esm-rtl, 129 | .kanban-plugin__board .esm-rtl, 130 | .kanban-plugin__drag-container .esm-rtl { 131 | direction: rtl; 132 | text-align: right; 133 | } 134 | 135 | /* Moving bullets to right side of the page and adding enough space between the bullet and the text */ 136 | .markdown-preview-view.is-auto .esm-rtl > .list-bullet, 137 | .markdown-preview-view.is-rtl .list-bullet { 138 | float: right; 139 | margin-right: -12px; 140 | } 141 | 142 | /* Fixing indentation guides in nested lists */ 143 | .markdown-preview-view.is-auto.show-indentation-guide li.esm-rtl > ul::before, 144 | .markdown-preview-view.is-auto.show-indentation-guide li.esm-rtl > ol::before { 145 | left: auto; 146 | right: -15px; 147 | } 148 | 149 | /* Moving the collapse indicator to right side of the page */ 150 | .markdown-preview-view.is-auto .esm-rtl > .collapse-indicator, 151 | .markdown-preview-view.is-rtl .collapse-indicator { 152 | float: right; 153 | } 154 | 155 | /* Moving the collapse indicator icon on the right of the text with enough space between */ 156 | .markdown-preview-view.is-auto .esm-rtl > .list-collapse-indicator, 157 | .markdown-preview-view.is-rtl .list-collapse-indicator { 158 | margin-right: -48px; 159 | padding-left: 18px; 160 | } 161 | 162 | /* Moving the heading collapse indicator on the right of the text. Without 163 | This the collapse indicator will be over the heading text */ 164 | .markdown-preview-view.is-auto .esm-rtl > .heading-collapse-indicator, 165 | .markdown-preview-view.is-rtl .heading-collapse-indicator { 166 | margin-right: -22px; 167 | } 168 | 169 | /* Mirroring collapse icon for nested lists so it points to rtl text not outside of page */ 170 | .markdown-preview-view.is-auto .esm-rtl > .collapse-icon .is-collapsed svg.svg-icon, 171 | .markdown-preview-view.is-auto .esm-rtl.is-collapsed > .collapse-icon svg.svg-icon, 172 | .markdown-preview-view.is-rtl .collapse-icon .is-collapsed svg.svg-icon { 173 | transform: rotate(90deg); 174 | } 175 | 176 | /* Mirroring collapse icon for headings so it points to rtl text not outside of page */ 177 | .markdown-preview-view .is-collapsed .esm-rtl > .collapse-icon svg.svg-icon, 178 | .markdown-preview-view.is-rtl .collapse-icon svg.svg-icon { 179 | transform: rotate(90deg); 180 | } 181 | 182 | /* Reverting the margin so the text won't stick to the checkbox */ 183 | .markdown-preview-view.is-auto .esm-rtl > .task-list-item-checkbox, 184 | .markdown-preview-view.is-rtl .task-list-item-checkbox { 185 | margin-left: 6px; 186 | margin-right: 0; 187 | } 188 | 189 | .markdown-preview-view.is-auto .esm-ltr { 190 | direction: ltr; 191 | text-align-last: left; 192 | } 193 | 194 | /* Helper styles for debugging */ 195 | /* .cm-line[dir="rtl"] { */ 196 | /* border-right: dashed; */ 197 | /* border-right-color: blue; */ 198 | /* } */ 199 | /* .cm-line[dir="ltr"] { */ 200 | /* border-right: dashed; */ 201 | /* border-right-color: red; */ 202 | /* } */ 203 | -------------------------------------------------------------------------------- /.obsidian/workspace.json: -------------------------------------------------------------------------------- 1 | { 2 | "main": { 3 | "id": "bcae1f0fc23b0d4a", 4 | "type": "split", 5 | "children": [ 6 | { 7 | "id": "b526b3650ef92ea9", 8 | "type": "tabs", 9 | "dimension": 53.899721448467965, 10 | "children": [ 11 | { 12 | "id": "2986483b96741b56", 13 | "type": "leaf", 14 | "state": { 15 | "type": "markdown", 16 | "state": { 17 | "file": "Headlines/Main.md", 18 | "mode": "source", 19 | "source": true 20 | } 21 | } 22 | } 23 | ] 24 | }, 25 | { 26 | "id": "c17065cfa2b707fb", 27 | "type": "tabs", 28 | "dimension": 46.10027855153203, 29 | "children": [ 30 | { 31 | "id": "d4bed6ddc6bfc646", 32 | "type": "leaf", 33 | "state": { 34 | "type": "markdown", 35 | "state": { 36 | "file": "Headlines/Main.md", 37 | "mode": "preview", 38 | "source": false 39 | } 40 | } 41 | } 42 | ] 43 | } 44 | ], 45 | "direction": "vertical" 46 | }, 47 | "left": { 48 | "id": "6d146ac35b5e6a61", 49 | "type": "split", 50 | "children": [ 51 | { 52 | "id": "d7a93e10c9dee5a0", 53 | "type": "tabs", 54 | "children": [ 55 | { 56 | "id": "2519e2fc0b9a9346", 57 | "type": "leaf", 58 | "state": { 59 | "type": "file-explorer", 60 | "state": { 61 | "sortOrder": "alphabetical" 62 | } 63 | } 64 | }, 65 | { 66 | "id": "e9f5d3a81b988cc6", 67 | "type": "leaf", 68 | "state": { 69 | "type": "search", 70 | "state": { 71 | "query": "", 72 | "matchingCase": false, 73 | "explainSearch": false, 74 | "collapseAll": false, 75 | "extraContext": false, 76 | "sortOrder": "alphabetical" 77 | } 78 | } 79 | }, 80 | { 81 | "id": "4f633c05b8b2ebbd", 82 | "type": "leaf", 83 | "state": { 84 | "type": "bookmarks", 85 | "state": {} 86 | } 87 | } 88 | ] 89 | } 90 | ], 91 | "direction": "horizontal", 92 | "width": 200, 93 | "collapsed": true 94 | }, 95 | "right": { 96 | "id": "1f4a0c235bdfc39f", 97 | "type": "split", 98 | "children": [ 99 | { 100 | "id": "7ce395e264c32abd", 101 | "type": "tabs", 102 | "children": [ 103 | { 104 | "id": "5adde6f8455605be", 105 | "type": "leaf", 106 | "state": { 107 | "type": "backlink", 108 | "state": { 109 | "file": "Headlines/Main.md", 110 | "collapseAll": false, 111 | "extraContext": false, 112 | "sortOrder": "alphabetical", 113 | "showSearch": false, 114 | "searchQuery": "", 115 | "backlinkCollapsed": false, 116 | "unlinkedCollapsed": true 117 | } 118 | } 119 | }, 120 | { 121 | "id": "78dcf24ecc8729d0", 122 | "type": "leaf", 123 | "state": { 124 | "type": "outgoing-link", 125 | "state": { 126 | "file": "Headlines/Main.md", 127 | "linksCollapsed": false, 128 | "unlinkedCollapsed": true 129 | } 130 | } 131 | }, 132 | { 133 | "id": "44d86a831f243eff", 134 | "type": "leaf", 135 | "state": { 136 | "type": "tag", 137 | "state": { 138 | "sortOrder": "frequency", 139 | "useHierarchy": true 140 | } 141 | } 142 | }, 143 | { 144 | "id": "3dbe339e31187180", 145 | "type": "leaf", 146 | "state": { 147 | "type": "outline", 148 | "state": { 149 | "file": "Headlines/Main.md" 150 | } 151 | } 152 | } 153 | ] 154 | } 155 | ], 156 | "direction": "horizontal", 157 | "width": 300, 158 | "collapsed": true 159 | }, 160 | "left-ribbon": { 161 | "hiddenItems": { 162 | "switcher:Open quick switcher": false, 163 | "graph:Open graph view": false, 164 | "canvas:Create new canvas": false, 165 | "daily-notes:Open today's daily note": false, 166 | "templates:Insert template": false, 167 | "command-palette:Open command palette": false 168 | } 169 | }, 170 | "active": "2986483b96741b56", 171 | "lastOpenFiles": [ 172 | "src/img/hide_pass.png", 173 | "src/img/calc_str.png", 174 | "src/img/meme_copy.jpg", 175 | "src/img/py_index.png", 176 | "Headlines/Main.md", 177 | "README.md" 178 | ] 179 | } -------------------------------------------------------------------------------- /Headlines/Main.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | ## نکته: 4 | 5 | > **مشارکت کننده های مختلفی ممکنه روی این کتاب کار بکنن و نکات تخصصی تری رو بنویسن تا از دانش دوستان بهره مند بشیم. از همینجا عمیقا از دوستان مشارکت کننده معذرت میخوام که برای شروع نام خودمو بردم. کوچیک شما هم هستم ❤ .** 6 | 7 | --- 8 | 9 | ## معرفی نویسنده: 10 | 11 | خب سلام سلام. من علیرضا فاضلی هستم ، الان که این کتاب یا اگه بشه بهش گفت کتاب رو وقتی مینویسم که هجده سالمه ، حالا بعدا بزرگتر میشم :) . 12 | بنده حدود سه سالی هست که برنامه نویسی کار میکنم و توی حوزه های مختلف برنامه نویسی کار کردم ، اولش که صبح تا شب گیم میزدم مثل تمامی همسن و سالای خودم ، بعدش یکی از رفقا گفت یک زبان برنامی نویسی هست به نام پایتون بشین یادش بگیر خیلی باحاله ، اقا ما نشستیم یادش گرفتیم . مدتی باهاش کار کردیم تا اینکه وارد پروژه ای با دوست خوبم [سجاد عبدالهی](https://github.com/sajjadabd) 13 | شدم. و اونجا منو با JavaScript آشنا کرد و خلاصه یکسالو نیمی رفتم برای خودم که با جی اس کار کنم. حالا که رسیده به این زمان علاقه پیدا کردم که برم سمت هوش مصنوعی و بینایی کامپیوتر . 14 | 15 | ## چیشد که دارم این کتابو مینویسم ؟ 16 | 17 | خب پیشنیاز اولیه یادگیری هوش مصنوعی ، زبان برنامه نویسی پایتون هستش ، من برای خودم دوره آموزشی پایتون از وبسایت [Zero To Mastery](https://zerotomastery.io/) 18 | انتخاب کردم. من همیشه عادت دارم که کوچکترین چیزیو که یاد میگیریم بیام توی دفترم بنویسم ، ولی این بار با خودم گفتم پسر یکم اپدیت بشو توی این قضیه . تصمیم گرفتم نکاتی که یاد میگیرم رو روی نرم افزار [Notion](https://notion.so) 19 | بنویسم. اومدم صفحه یادگیری نوشنم رو پابلیک کردم تا بقیه دوستان هم بیان نظرشونو بگن و توی این مطلب کمکم بکنن و توی توییتر توییتش کردم ، تا اینکه دوست عزیزم 20 | [محمد زرچی](https://github.com/mzarchi) 21 | بهم گفت که چرا توی گیتهاب نمیزاریش تا بقیه راحت تر بتونن توش مشارکت داشته باشن ، با خودم گفتم فکر خوبیه و این شد که الا توی گیتهاب در خدمتتون هستیم. 22 | 23 | ### بدون مقدمه بریم یکم پایتون بخونیم 😁. 24 | 25 | ### تاریخچه 26 | 27 | زمینه یادگیری عمیق هر چیزی شناخت تاریخچه و اهداف و علت های ساخت اون چیزه 28 | 29 | پایتون که امروز به یه زبان همه منظوره و مفسری شناخته میشه که اولین بار در سال 1991 عرضه شد 30 | نویسنده پایتون گیدو ون راسوم (Guido van Rossum) است که متولد 1956 و اهل هلند است 31 | 32 | ### علت نام گذاری پایتون 33 | 34 | نام زبان برنامه‌نویسی پایتون از علاقه نویسنده آن به کمدین 35 | بریتانیایی معروف، مونتی پایتون (Monty Python)، گرفته شده است. 36 | گویدو ون راسوم، نویسنده این زبان برنامه‌نویسی، به خاطر علاقه خود به 37 | این برنامه تلویزیونی کمدی و همچنین برای جذب توجه ویژه‌ای به این زبان، 38 | از نام "پایتون" برای نامگذاری این زبان استفاده کرد. 39 | 40 | ### محبوبت و قدمت 41 | 42 | بر خلاف نظر اکثریت که فکر می کنند پایتون زبان جدیدیه، پایتون یه زبان نسبتا قدیمی حساب میشه 43 | علت این افکار عموما به این بر میگرده که پایتون توی سال های اخیر تازه بر سر زبان ها افتاده و تونسته جای خودش رو در صدر جدول برای چند سالی نگه داره 44 | 45 | برای مثال جاوااسکریپت (JavaScript) سال 1995 عرضه شد 5 سال بعد از پایتون 46 | 47 | روبی(Ruby) هم سال 1995 عرضه شد 48 | 49 | سی شارپ(C#) سال 2001 عرضه شد 50 | 51 | جولیا(Julia) سال 2012 عرضه شد 52 | 53 | گو(Go) سال 2009 عرضه شد 54 | 55 | ### چرا پایتون؟ 56 | 57 | عموما پایتون زبانی سطح بالا با سینتکس راحت و خوانا نزدیک به زبان انسان است برای همین می تونه گزینه خوبه برای شروع برنامه نویسی باشه 58 | و همچنین با توجه به محبوبیت و رشد پایتون و همچنین پکیج های زیادی که داره میتونه یه انتخاب مناسب برای شروع و کار در فیلد های مختلف باشه 59 | 60 | --- 61 | 62 | ### چرا اینهمه زبان برنامه نویسی داریم ؟ 63 | 64 | زبان های برنامه نویسی مثل ابزار های مختلف برای ساخت یک خونه میمونن مثل انبر ، چکش ، اره ، بیل ، کلنگ. هر کدوم از اینا برای کاری ساخته شدن ، مثلا با چکش نمیشه چاله کند. 65 | 66 | به عنوان مثال زبان پایتون یک زبان با سرعت پایین هستش و High level. ما میخوایم برای سخت افزارمون برنامه نویسی بکنیم و سرعت برنامه سخت افزاری ما باید زیاد باشه . ما نمیتونیم از زبانی مثل پایتون که به سخت افزار نزدیک نیست و توی این مورد سرعت پایینی داره استفاده بکنیم پس میایم از زبان اسمبلی یا سی استفاده میکنیم. 67 | 68 | زبان پایتون یک زبونیه که بهره وری رو بالاتر میبره به دلیل راحتی در کد و نزدیک بودن به زبان انگلیسی سرعت توسعه رو خیلی بالا میره. 69 | 70 | به طور خلاصه هر زبونی رو بهر کاری ساختن و هر زبونی توی یک سری کارها بهتر از بقیه زبون هاست. 71 | 72 | --- 73 | 74 | > accountability = مسئولیت 75 | > instructions = دستور عمل 76 | > gibberish = بیهودگی 77 | > 78 | > > valuable = hard to acquire 79 | 80 | ### نکته : همیشه بالای مطلبی معانی زبانی هستن که نوشتم ، این معانی خیلی توی دنیای کامپیوتر استفاده میشن پس به دردتون میخوره . 81 | 82 | --- 83 | 84 | زبان ماشین به صورت اعداد باینری (0 و 1) و یا بیت ها نوشته میشود. زبانی هست که فقط کامپیوتر (مدار های کامپیوتر) میفهمه و میتونه برنامه های مارو اجرا بکنه. و زبان های برنامه نویسی که ما باهاشون کار میکنیم و جوری طراحی شدن که برای ما قابل فهمه مثل زبان های برنامه نویسی پایتون ، جاوااسکریپت ، پایتون ، گولنگ .... 85 | زبان های میانی بین زبان ماشین و زبان انسان هستن . به خاطر همینه که ما راحت به حروف انگلیسی میتونیم برنامه های مختلف بسازیم وگرنه پوستمون کنده میشد. 86 | 87 | **زبان های Low level** : زبان هایی هستن که به زبان ماشین نزدیک تر هستند مثل c , c++ , assembly ... . 88 | 89 | **زبان های High Level** : زبان هایی که به زبان انسان نزدیک تر هستند ، مثل : python , JavaScipt .... 90 | 91 | #### به طور خلاصه : 92 | 93 | زبان سطح بالا به زبان هایی گفته میشه که به زبان ما انسان ها نزدیکه و درکش برای ما اسون و در عوض برای کامپیوتر سخته ولی زبان های سطح پایین برعکس برای ما سخت ولی برای کامپیوتر اسونه! 94 | 95 | --- 96 | 97 | ![](../src/img/compiler.PNG) 98 | 99 | 100 | **Translator:** وظیفه مترجم اینه که زبان برنامه نویسی که ما باهاش کد میزنیم رو به زبان ماشین ترجمه بکنه ، به عنوان مثال ما داریم پایتون کد میزنیم و به پایتون میگیم که یه متنی رو برای من چاپ بگیر ، کامپیوتر نمیفهمه که من توی زبان پایتون چی نوشتم ، میگه که این چرتو پرت چیه تحویل من میدی ، اینجاست که مترجم ها وارد کار میشن و و اون چرت و پرت رو برای کامپیوتر به زبان ماشین ترجمه میکنن و کامپیوتر حالا میگه که اها داداش تو میخوای واست یه متنیه چاپ بگیرم ، بیا اینم متنت . 101 | 102 | #### انواع Translator ها : 103 | 104 | 1. compiler 105 | 106 | کار کامپایلر به این صورت هستش که میاد کد های مارو از اول و تا آخر میخونه اگر مشکلی ، اروری چیزی نداشت میاد کد مارو تبدیل به فایل اجرایی میکنه مثلا فایل .exe ، و هر سری برای اجرای این برنامه نیاز نیستش از اول این کد کامپایل بشه و دوبارخ فایل اجرایی جدید برای اجرا ساخته بشه ولی تا زمانی که بخواید توی کدتون تغیری ایجاد کنید ، اونموق دوباره نیازه که کدتون کامپایل بشه و خب سرعت زبان های کامپایلری از زبان های interpreter یا همون مفسری بیشتر . به عنوان مثال زبان های : C++ , C# , Java زبان های کامپایلری هستند. 107 | 108 | 1. interpreter 109 | 110 | مفسر میاد خط به خط کدامون رو میخونه و اگر اون خط مشکلی نداشت خروجی همونو بهمون میده و مفسر هیچ فایل اجرایی نداره چون کامپایل نمیشه و داره ترجمه میشه پس در نتیجه برای هربار اجرا باید این روند رو طی بکنه و همین موضوع سرعتش رو پایین میره !. زبان مفسری مثل : python , PHP , JavaScript , Ruby. 111 | 112 | --- 113 | 114 | ### برنامه نویسی به صورت انلاین 115 | 116 | شما برای برنامه نویسی به صورت انلاین ( فقط برای یاگیری ) میتونید از 117 | وبسایت های زیر استفاده کنید: 118 | 119 | - [Glot.io](https://glot.io) 120 | - [Repl.it](https://repl.it) 121 | 122 | --- 123 | 124 | ```py 125 | print(’hello world’) 126 | ``` 127 | 128 | این دستور توی پایتون برای ما هر چی که بخوایم رو در درون ترمینال برای ما خروجی میگیره. این ساده ترین دستور درون پایتونه . به طور تخصصی به این اینا میگن سینتکس و این سینتکس ها از قبل درون زبان برنامه نویسی پایتون قرار داده شدند. 129 | 130 | --- 131 | 132 | ### نحوه تفسیر شدن کد پایتونی به زبان ماشین 133 | 134 |

135 | 136 | اول از همه ما کدی رو که توی پایتون مینویسم مثل همین `print('hello world')` 137 | ، این به مفسر پایتون داده میشه 138 | و بعدش اون مفسری که از قبل براش نوشتن ، میاد کد مارو به بایت کد ترجمه میکنه و اون بایت کد درون ماشین مجازی زبان سی به نام cpython قرار میگیره 139 | و اون ماشین مجازی ، بایت کد مارو به زبان ماشین تبدیل میکنه :) . 140 | 141 | --- 142 | 143 | ```py 144 | 145 | input('Whats your name ?') 146 | 147 | ``` 148 | 149 | این تابع یا فعلا بهتره از لفظ تابع استفاده نکنیم ، چون زوده یکم ، بهتره بگیم این کد ، کارش اینه که میاد از ما ورودی دریافت میکنه ، از کجا ؟ 150 | خب از ترمینال ما ، همونجایی که ما کد پایتونیمون رو خروجی میگیریم. 151 | به مثال زیر دقت کنید: 152 | 153 | ![](../src/img/input.png) 154 | 155 | 156 | اگه دقت کنید میتونید ببینید ، از ما پرسیده که اسمت چیه ؟ خب من جواب دادم علیرضا. ولی این اسم نه جایی ذخیره شده نه حرکتی زده شده مثلا بیاد بگه سلام علیرضا. 157 | 158 | باید چیکار بکنیم ؟ اینو توی یک متفیر ذخیره بکنیم ، وقتی چیزی رو توی متفیر ذخیره میکنیم این توی مموریما میره و ذخیره میشه و ما میتونیم با این کار های مختلف بکنیم. 159 | 160 | ```py 161 | 162 | userName = input('whats your name ? ') 163 | 164 | print('Hello ' + userName) 165 | 166 | ``` 167 | 168 | 169 | ![](../src/img/input2.png) 170 | 171 | 172 | و حالا میبینید که ما تونستیم از این تابع input استفاده بکنیم ، یک ورودی از کاربر دریافت بکنیم و اون ورودی رو درون متغیر بریزیم و از اون متغیر به عنوان خروجی استفاده بکنیم . 173 | 174 | --- 175 | 176 | # Python.3 vs Python.2 177 | 178 | > evolving = درحال تکامل | decided = تصمیم گرفت | legacy = میراث 179 | 180 | ### breaking changes : 181 | 182 | به اپدیتی گفته میشه که وقتی میاد دیگه اپلیکیشن ها برنامه ها و پروژه ها نمیتونن از اون اپدیت استفاده بکنن چون اصلا براشون طراحی نشده. به عنوان مثال وقتی پایتون 3 اومد دیگه شرکت ها نمیتونستن خودشونو تا مدت ها اپدیت بکنن و باید خط به خط پروژه هاشونو اپدیت میکردن. یعنی همه چی برای شرکتا ف\*\*اکداپ شده بود 😂. 183 | 184 | از سال 2008 سازنده پایتون تصمیم گرفت که ورژن جدید پایتون رو بسازه یعنی ورژن 3 که انقلابی در کامیونیتی پایتون بودش و اینکه اومد کلا تمامی زیرساخت های زبان پایتون رو از نو کوبید و ساخت باعث breaking changes شد. 185 | 186 | ### نمونه ای از کد های پایتون 2 و 3 : 187 | 188 | ```py 189 | #python 2 : 190 | print ‘hello world’ 191 | 192 | #python 3 : 193 | print(’hello world’) 194 | 195 | ``` 196 | 197 | --- 198 | 199 | ### Python Data Types - انواع داده در زبان پایتون 200 | 201 | > data = داده | type = نوع | fundamental = بنیادی ، اساسی 202 | 203 | اول بزار لیستی از دیتا تایپ های تو پایتون، توی پایتون رو بهت معرفی بکنم، فقط میخوایم به اسمشون اشنا بشیم: 204 | 205 | - ### Fundamental Data Types : 206 | 207 | 1. int 208 | 209 | ```py 210 | myAge = 18 211 | ``` 212 | 213 | 1. float 214 | 215 | ```py 216 | myMoney = 3.9 217 | ``` 218 | 219 | 1. str 220 | 221 | ```py 222 | myName = "Alireza Fazeli" 223 | ``` 224 | 225 | 1. bool 226 | 227 | ```py 228 | single = True 229 | ``` 230 | 231 | 1. list 232 | 1. tuple 233 | 1. set8 234 | 1. dict 235 | 236 | - ### Custom Data Types 237 | 238 | کلاس ها نمونه ای از دیتا تایپ های شخصی سازی شده هستند. 239 | 240 | > جلوتر به صورت تخصصی کلاس رو یاد میگیریم، فعلا فقط گوش ما باهاش اشنا بشه. 241 | 242 | - ### Specialized Data Types : 243 | 244 | > جلوتر به صورت تخصصی این بخش رو یاد میگیریم، فعلا فقط گوش ما باهاش اشنا بشه. 245 | 246 | ماژول ها نمونه ای از دیتا تایپ های خاص در پایتون هستنید 247 | 248 | - ### None 249 | 250 | --- 251 | 252 | ## چی میشه که ما بتونیم به راحتی از راحتی متغیرمون استفاده بکنیم 253 | 254 | خب ، مثلا فکر کنید میخواید یه برنامه بسازید ، که عملایت بعلاوه تو ریاضی رو انجام بده و ما میخوایم از مقدار قبلی توی متغیر استفاده بکنیم ، یکم گیج شدید 😂؟ منم گیج شدم بیا کدشو ببین : 255 | 256 | ```py 257 | 258 | numberOne = 2 259 | 260 | numberOne = 2 + 3 261 | 262 | ``` 263 | 264 | کد بالارو نگاه کنید ، الان من میخوام از همون متغیر برای مقدار دهی استفاده کنم و متغیر جدیدی نیام نسازم. اما الان تو کد بالا ما اومدیم چرتو پرت نوشتیم ، اخه دو بعلاوه سه ؟ پس مقدار قبلی متغیر رو چجوری بگیریم ؟ 265 | به روش زیر : 266 | 267 | ```py 268 | 269 | numberOne = 2 270 | 271 | numberOne = numberOne + 3 272 | 273 | ``` 274 | 275 | به همین اسونی تونستیم مقدار قبلی متغیر رو توی همون متغیر بریزیم و یک عملایت جدید انجام بدیم . ولی میتونیم این کار رو خیلی راحت تر انجام بدیم ، یک عملی هست که توی تمام های زبان های برنامه نویسی هستش ، اسم تخصصیش میشه : _augmented assignment operator_ حالا حفظم نکردی نکردی این اسمو مهم نیست 😂😂. 276 | 277 | ```py 278 | 279 | numberOne = 2 280 | 281 | numberOne += 3 282 | 283 | ``` 284 | 285 | خب این یعنی همون قطعه کد قبلی ولی ساده تر، اگه بخوام بگم میشه : نامبر وان بعلاوه مساوی هست با 3 . ایم سو خارجی 😎. 286 | 287 | --- 288 | 289 | ## استرینگ ها در زبان پایتون (آش رشته های برنامه نویسی ) 290 | 291 | > string = رشته | 292 | 293 | آش رشته های برنامه نویسی، یا همون استرینگ ها (string). 294 | خب ما توی زبان های به متن ها میگیم استرینگ که معنی فارسیش میشه رشته. چرا ؟ چون حروف ها مثل رشته بهم دیگه وصل شدن، توی دنیای کامپیوتر هرکدوم این حروف یک کد باینری مخصوص خودشو داره و اینا وقتی بهم وصل میشن بهشون میگن استرینگ. 295 | 296 | ##### ما توی زبان برنامه نویسی پایتون به سه روش میتونیم از استرینگ ها استفاده کنیم : 297 | 298 | تک کوت : (Single Quote) 299 | 300 | ```py 301 | 302 | myName = `alireza` 303 | 304 | ``` 305 | 306 | دابل کوت : (Double Quote) : 307 | 308 | ```py 309 | 310 | myName = "Alireza" 311 | 312 | ``` 313 | 314 | لانگ استرینگ (Long String) : 315 | این برای چیه ؟ خب ما وقتی بخوایم متنی بلندی رو در زبان پایتون چاپ بگیریم میتونیم از لانگ استرینگ استفاده بکنیم. شما اقایون و خانوما نمیتونید از سینگل کوت و دابل کوت برای نوشتن متن های چند خطی استفاده بکنید. 316 | بریم که از لانگ استرینگ استفاده کنیم : 317 | 318 | ```py 319 | 320 | 321 | hayedeMusic = ''' 322 | مـیگن مستی گناه به انگشت ملامت بایـد مستـها رو حد زد به شلاق ندامت 323 | 324 | سبوی ما شکستـه در مـیکده بستـه امـیـد همه ی ما به همت تـو بستـه 325 | ''' 326 | 327 | ``` 328 | 329 | اقا هایده گوش بدید موقع کد زدن، حلال حلاله 😂😂. 330 | 331 | 332 | ![hayedeh meme](../src/img/hayede.jpg) 333 | 334 | --- 335 | 336 | > concatenation = الحاق | first name = اسم کوچک | last name = فامیلی | 337 | 338 | ## الحاق رشته ها (Strings Concatenation) : 339 | 340 | **_خداوکیلی تبدیل این کلمات تخصصی سخته به فارسی. تا جایی که بشه سعی میکنم تبدیلشون بکنم ولی یکجایی نمیشه خدایی ._** 341 | 342 | ما یکجا هایی نیاز داریم که دوتا استرینگ رو بهم وصل بکنیم ، مثلا من دوتا متغیر دارم که یکیش اسم من و یکیش فامیلیه منه ، خب برای اینکار باید چیکار بکنم که توی یک استرینگ بیان ؟ باید از عملی استفاده بکنیم به نام string concatenation که از عملگر ریاضی بعلاوه میاد. کد زیر رو نگاه کنید ، چیز خاصی ندار اصلا : 343 | 344 | ```py 345 | 346 | firstName = 'alireza' 347 | lastName = 'fazeli' 348 | 349 | fullName = firstName + lastName 350 | 351 | # خروجی : alirezafazeli 352 | # برای اینکه بتونیم متنمون رو خوشگل تر بکنیم میتونیم از متن های دیگه استفاده بکنیم : 353 | 354 | fullName = 'Name :' + ' ' + firstName + ' . ' + 'last name :' + ' ' + lastName 355 | 356 | # حواستون هست که باید fullName رو پرینت بگیرید ؟ 357 | 358 | print(fullName) 359 | 360 | # خروجی : Name : alireza . last name : fazeli 361 | 362 | 363 | ``` 364 | 365 | --- 366 | 367 | ## الحاق رشته ها به روش حرفه ای ها ! 368 | خب برای اینکه بخوایم رشته رو به هم الحاق کنیم یا از متغیر ها توی رشته هامون استفاده بکنیم، واقعا سخته که بیایم هی از عملگر ریاضی **(+)** استفاده کنیم. پس بریم با روش خیلی خفن پایتون 3 استفاده کنیم :) . 369 | 370 | --- 371 | 372 | ## Formatted String ( F string ): 373 | 374 | ما میتونیم در پایتون بدون اینکه نیازی باشه از عملگر برای الحاق رشته استفاده بکنیم ، میتونیم از چیزی به نام **F String** استفاده کنیم. 375 | 376 | ```py 377 | first_name = "alireza" 378 | last_name = "fazeli" 379 | full_name = f"Your Full Name Is : {first_name} - {last_name}" 380 | 381 | print(full_name) 382 | 383 | # خروجی 384 | # Your Full Name Is : alireza - fazeli 385 | ``` 386 | 387 | 388 | به همین سادگی ما میتونیم از متغیر ها در رشته هامون استفاه بکنیم و نیازی نداریم که سختی بکشیم. 389 | اول از f در اول استرینگمون استفاده میکنیم ، و بعد هرجایی که نیاز بود یه پرانتز باز میکنیم و متغیرمون رو درونش قرار میدیم . 390 | 391 | ___ 392 | 393 | > Function : تابع 394 | ## تابع های ریاضی (Math Functions) : 395 | 396 | > بزارید اول از همه یک چیزی رو بگم، ما قرار نیست تو پایتون یا هر زبان برنامه نویسی دیگه همه چیز رو یاد بگیریم، بلکه قرار چیزهایی رو یاد بگیریم که مورد نیازمونه و هرچیزی رو که نمیدونیم بریم سرچ بزنیم چون همه چیز کف اینترنت ریخته و ما نیاز داریم که پایه های کار رو بدونیم . 😃 397 | 398 | > یک نکته دیگه رو هم بگم اینکه فعلا کار به این نداشته باشید که تابع چیه چون که جلوتر مفصل دربارش حرف میزنم، فعلا فقط بدونید که تابع مثل یک کارخونست، یک ورودی بهش میدی و اون نسبت به اون ورودی بهت یک محصولی رو ارائه میده 💣. 399 | 400 | 401 | ## round() : 402 | 403 | این تابع از اسمش معلومه کارش چیه، اعداد رو برای ما روند میکنه یا گرد میکنه. این تابع اگه اعداد اعشاری، اعشارشون از پنج کمتر باشه، میاد رو به پایین گرد میکنه و اگه پنج یا بالاتر از پنج باشن، رو به بالا گرد میکنه. مثلا عدد 3.5 میشه 4 و عدد 3.4 میشه 3. 404 | 405 | 406 | ```py 407 | print(round(3.5)) # خروجی : 4 408 | print(round(3.4)) # خروجی : 3 409 | ``` 410 | 411 | ## abs() : 412 | 413 | این فانکشن میاد علامت پشت یه عدد رو، بر میداره و برای ما خود اون عدد رو بر میگردونه به عنوان مثال اگه ما عدد (-8) داشته باشیم، این میاد (-) بر میداره و عدد 8 رو بر میگردونه. 414 | ```py 415 | print(abs(-8)) # خروجی : 8 416 | ``` 417 | 418 | --- 419 | > Efficient : کارآمد ، موثر | Precedence : تقدم ، اولویت 420 | 421 | ## Operator Precedence (اولویت عملگرهای ریاضی) : 422 | 423 | در پایتون عملگر های ریاضی یک اولویت بندی دارن، دقیقا مثل ریاضی. به عنوان مثال شما قراره یک محاسباتی رو انجام بدین خب باید بدونید وقتی که دارید این محسبات رو انجام میدید بر چه اساسیه و اولویت های اون چی هستن. 424 | به ترتیب میریم جلو : 425 | 426 | **1- () ** : 427 | خب پرانتز اولویت اول رو داره و هرچیزی که درون پرانتز قرار بگیره اولویت اول رو داره. دقیقا تمام این اولویت ها مثل ریاضی که یادگرفتین هستن. 428 | 429 | **2- ** ** : 430 | توان ! . این عملگر همون توان در ریاضیات هستش ، با استفاده از این عملگر هر عددی رو میتونیم به توان عدد دیگری برسونیم. 431 | 432 | ```py 433 | print(2 ** 2) # دو به توان دو 434 | # خروجی : 4 435 | ``` 436 | 437 | **3 - * ** : 438 | ضرب ! . اولویت بعدی با ضرب هستش. 439 | 440 | ```py 441 | print(2 * 2) # دو ضرب در دو 442 | # خروجی : 4 443 | ``` 444 | 445 | **4- / ** : 446 | تقسیم ! . اولویت بعدی با تقسیم هستش ما میتونیم با این عملگر هر عددی رو تقسیم بر عدد دیگری کنیم. 447 | 448 | ```py 449 | print(8 / 2) # هشت تقسیم بر دو 450 | # خروجی : 4 451 | ``` 452 | 453 | **5- + **: 454 | بعلاوه ! . خب بعلاوه بعلاوست دیگه 😂. 455 | 456 | ```py 457 | print(2 + 2) # دو بعلاوه دو 458 | # خروجی : 4 459 | ``` 460 | 461 | **6- ( - )** : 462 | منها ! . 463 | ```py 464 | print(8 - 2) # هشت منها دو 465 | # خروجی : 6 466 | ``` 467 | 468 | 469 | --- 470 | > sensitive : حساس | Variable : متغیر | Dynamic : پویا | Constant : ثابت 471 | 472 | ## متغیر ها (Variable) : 473 | خب ما درباره متغیر ها یکم حرف زدیم. و حالا دقیق تر ببینیم متغیر ها چی هستن؟ 474 | متغیر ها مثل ظرف هایی هستن که داده های مارو نگهداری میکنن. به عنوان مثال کابری توی سایت من ثبت نام میکنه ، من کجا باید اسمشو نگهداری کنم و نشونش بدم؟ توی متغیر !. و خب این متغیر ها کجا ذخیره میشن؟ هر وقت که پروژمون رو ران میکنیم درون مموری کامپیوتری یه گوشه ای رو برای خودشون رزرو میکنن و داده هارو نگهداری میکنن. 475 | به صورت کلی تر، متغیر ها با یک آدرسی در یک جای مموری، فضایی رو اشغال میکنن تا value های مارو یا همون مقدار های ما یا داده های مارو درون اون فضا قرار بدن تا ما بتونیم در پروژمون ازش استفاده بکنیم. 476 | 477 | ### چجوری میتونیم از یک متغیر استفاده بکنیم؟ به صورت زیر : 478 | ```py 479 | 480 | user_name = "alireza fazeli" 481 | # یک اسمی برای متغیر انتخاب کردیم و یک مقداری رو ریختیم توش. اسم متغیر من user_name هست . 482 | # و مقدار من alirezafazeli 483 | ``` 484 | 485 | > پایتون یک زبان dynamic type هستش. یعنی نیازی نیستش که ما برای اینکه متغیر تعریف کنیم به پایتون بگیم که آقا من قراره توی تو بیام استرینگ بریزم یا اینتیجر بریزم. پایتون کاری به این کارا نداره ! میگه هرچی دل تنگت میخواهد بریز تو من 😂. 486 | 487 | ### Case sensitive : 488 | پایتون یک زبان حساس به نوع نوشتاری متغیر هستش ، یعنی اینکه متغیر به نام : iq با iQ فرق داره و اگه متغیری با این دو نوع نوشتاری تعریف بکنی باهم دیگه فرق دارن، پس در نتیجه حواستون باشه ! . 489 | 490 | ### Constants : 491 | به متغیر هایی در زبان برنامه نویسی گفته میشه که قرار نیست هیچوقت مقادیر درونش تغییر بکنه. 492 | به عنوان مثال عدد پی یک عدد همیشه ثابته و اون عدد : 3.14 هستش. پس در نتیجه اگه من بخوام متغیری به نام عدد پی داشته باشم این هیچوقت قرار نیست تغییر بکنه و من به عنوان یک برنامه نویس باید منظورمو یک جوری به برنامه نویس های دیگه برسونم ! با چه روشی؟ به روش زیر : 493 | 494 | روش اول : در این روش اگه ما نام متغیرمون به صورت حروف بزرگ بنویسیم یا به اصطلاح upper case یعنی داریم میگیم که اون متغیر Constant هستش ! . 495 | ```py 496 | PI = 3.14 # این یکی متغیر ثابت هستش 497 | ``` 498 | 499 | روش دوم : اگه دو خط تیره به اول متغیرمون اضافه بکنیم یعنی داریم میگیم که این متغیر ثابت یا constant هستش. 500 | 501 | ```py 502 | __PI = 3.14 503 | ``` 504 | 505 | --- 506 | 507 | ## مقدار دهی متغیر در یک خط ! 508 | شاید براتون جاب باشه ولی ما میتونیم چندین متغیر رو در یک خط مقدار دهی بکنیم و نیاز نباشه بیایم برای هر متغیر در هر خط مجزا مقدار دهی بکنیم. 509 | 510 | ```py 511 | 512 | a, b, c = 1, 2, 3 513 | 514 | # a = 1 515 | # b = 2 516 | # c = 3 517 | 518 | ``` 519 | 520 | 521 | در این روش همونطوری که ما به ترتیب اومدیم اسم متغیر هارو نوشتیم همونجوری به ترتیب باید مقدار دهی بکنیم که متغیر اولی مقدارش میشه همون عدد اولی. 522 | به همین آسونی ! 523 | 524 | --- 525 | 526 | 527 | 528 | ## Type Conversion : 529 | 530 | شاید براتون سوال باشه که آیا ما میتونیم نوع داده هارو به یکدیگر تبدیل بکنیم یا نه ؟ 531 | مثلا یک استرینگ '3' رو آیا میتونیم به اینتیجر 3 تبدیل کنیم ؟ باید بگم بله این امکان پذیره ! 532 | 533 | ### تابع Type : 534 | ما با استفاده از تابع type در زبان برنامه نویسی پایتون میتونیم بفهمیم که آقا نوع این داده ما چی هستش به عنوان مثال برنامه به ما میگه خروجی شما عدد 100 هستش ! آیا این عددی که داری به من میدی 100 از نوع استرینگ هستش ("100") یا از نوع اینتیجر (100) ؟! با استفاده از این تابع ما میتونیم این موضوع رو بفهمیم. 535 | 536 | ```py 537 | number_one = 100 538 | number_two = '100' 539 | user_name = 'alireza fazeli' 540 | is_married = True 541 | 542 | 543 | print(type(number_one)) # خروجی : int 544 | print(type(number_two)) # خروجی : str 545 | print(type(user_name)) # خروجی : str 546 | print(type(is_married)) # خروجی : bool 547 | ``` 548 | 549 | 550 | ### تبدیل داده ها به string : 551 | ما میتونیم هر داده ای رو با استفاده از تابع string تبدیل بکنیم به نوع داده string کنیم. 552 | به عنوان مثال من در کد زیر میخوام عدد 100 رو که از نوع داده اینتیجر هستش رو به استرینگ تبدیل کنم . 553 | 554 | ```py 555 | 556 | number_one = 100 557 | number_two = str(number_one) 558 | print(number_two) # خروجی : 100 559 | print(type(number_two)) # حروجی : str 560 | 561 | ``` 562 | 563 | 564 | ### تبدیل داده ها به int : 565 | ما میتونیم هر داده ای رو با استفاده از تابع int تبدیل بکنیم به نوع داده int کنیم . 566 | به عنوان مثال من در کد زیر میخوام عدد "100" رو که از نوع داده string هستش رو به int تبدیل کنم . 567 | این تابع هم کاراییش دقیقا مثل بالایی هستش فقط با این تفاوت که نوع تبدیل داده فرق میکنه. 568 | 569 | ```py 570 | 571 | number_one = "100" 572 | number_two = int(number_one) 573 | print(number_two) # خروجی : 100 574 | print(type(number_two)) # حروجی : int 575 | 576 | ``` 577 | 578 | 579 | --- 580 | 581 | ## Escape Sequences : 582 | 583 | این مورد مثل جادو میمونه، ما میتونیم از یکسری ورد های جادویی توی استرینگ هامون استفاده بکنیم . 584 | به طور کلی Escape Sequences ها یکسری دستور عمل یا دستور هستن که فرم استرینگ مارو تغیر میدن. 585 | 586 | به عنوان مثال اگه من بخوام از دوتا تک کوتیشن یا دوتا دابل کوتیشن توی کدم استفاده بکنم نمیشه. 587 | من نمیتونم مثل کد زیر از استرینگ ها استفاده بکنم. 588 | چرا؟ اگه دقت بکنید میبینید اگه مات در درون یک کوتیشن از یک کوتیشن دیگه استفاده بکنیم انگار داریم دوتا استرینگ مجزا تعریف میکنیم و پایتون گیج میشه و میگه داداش داری چیکار میکنی ؟ 🤷‍♂️😐 589 | 590 | ```py 591 | "This is Alireza Fazeli From "Iran" " # ارور میده ❌ 592 | 593 | 'This is Alireza Fazeli From 'Iran' ' # ارور میده ❌ 594 | 595 | ``` 596 | 597 | > یادتون نره برنامه نویس ها جادوگر هستن و میتونن جادو بکنن. پس بریم جادوگری یاد بگیریم. 598 | > 599 | 600 | ### ( \ ) : 601 | 602 | بک اسلش ! اگه از همین اسلش ساده توی کدتون استفاده بکنید دارید به پایتون میگید که که بعد از اسلش هر چیزی اومد رو یک استرینگ در نظر بگیر نه یک دستور ناشناخته. شل کن پایتون جان :) 603 | 604 | ```py 605 | 606 | quote = "This Is Alireza Fazeli From \"Iran\" " # دیگه اروری نمیده و دابل کوتیشن های مارو به عنوان یک استرینگ شناخت نه به عنوان دو استرینگ مجزا ! 607 | ``` 608 | 609 | ### ( \t ) : 610 | 611 | وقتی (بک اسلش تی) توی استرینگ استفاده بشه، میاد از هرجایی که استفاده شده ، به اندازه یک تب (Tab) برای ما فاصله میندازه. 612 | 613 | ```py 614 | 615 | music = "کفتر کاکل به سر \t وای فای" 616 | print(music) # خروجی : کفتر کاکل به سر وای فای 617 | 618 | ``` 619 | 620 | ### ( \n ) : 621 | 622 | وقتی از این دستور در درون استرینگمون بیایم استفاده بکنیم ، میاد از هرجایی که استفاده شده میپره رو خط جدید ادامه استرینگ رو از خط جدید ادامه میده. معنی \n یعنی new line هستش. 623 | 624 | ```py 625 | 626 | music = " Nazi naz kon ke nazet \n ye sarve naze " 627 | print(music) 628 | 629 | 630 | # خروجی : Nazi naz kon ke nazet 631 | # ye sarve naze 632 | 633 | ``` 634 | 635 | 636 | --- 637 | 638 | ## String Index : 639 | یکی از بخش های جذاب با جادوگری های جذاب همین بخش string index هستش. 640 | به طور کلی و ساده میشه گفت که استرینگ ها از حروف تشکیل شدن و این حروف ها هم در مموری جایگاهی دارن. مثلا حرف a از جمله alireza در مموری یک ادرسی و جایگاهی داره که ما میتونیم بهش دسترسی داشته باشیم. و با این حروف و اون استرینگ بازی بکنیم یا یکسری استفاده ها بکنیم. 641 | 642 | خب چجوری میتونیم به این حروف دسترسی داشته باشیم؟ اول از همه باید گفت شمارش در برنامه نویسی از عدد 0 هستش. 643 | پس وقتی ما بخوایم به خونه یک در یک استرینگ دسترسی داشته باشیم باید از عدد 0 استفاده بکنیم. 644 | 645 | #### ایندکس : 646 | به جایگاه های هر خونه از اون استرینگ ایندکس گفته میشه که از عدد صفر شروع میشه . حالا این ایندکس جاهای دیگه ای غیر استرینگ ها هم استفاده میشه که مهم ترین استفاده اش در list ها هستش. جلوتر به این موضوع می پردازیم. 647 | 648 | ![python index](../src/img/py_index.png) 649 | 650 | بریم چندتا مثال حل بکنیم ! 651 | 652 | #### مثال : 653 | ما میخوایم به حروف a از کلمه alireza دسترسی داشته باشیم. 654 | برای این منظور باید به صورت زیر عمل کنیم. 655 | 656 | ```py 657 | 658 | name = "alireza" 659 | print(name[0]) # ایندکس صفر برابر هستش با حروف اول این استرینگ 660 | 661 | # خروجی : a 662 | 663 | 664 | # ---------------------------- 665 | 666 | 667 | print(name[3]) 668 | # خروجی : r 669 | 670 | ``` 671 | 672 | #### انتخاب بخشی خاص از یک استرینگ : 673 | حالا ما میتونیم بخش خاصی از یک استرینگ رو به راحتی برش بزنیم و بگیریم تو مشتمون. 674 | برای این منظور اول بهش میگیم که از کدوم ایندکس شروع بشه تا کدوم ایندکس ادامه داشته باشم. 675 | 676 | ```py 677 | 678 | name = "alireza fazeli" 679 | print(name[0:7]) 680 | 681 | # خرجی : alireza 682 | 683 | ``` 684 | 685 | نکته که ای که باید در نظر داشته باشید اینه که وقتی دارید ایندکس دوم رو وارد میکنید باید یک عدد بیشتر وارد بکنید . 686 | 687 | #### انتخاب حروف بر اساس گام : 688 | ما میتونیم حروف رو در string index وقتی برش میدیم و انتخاب میکنیم ، بر اساس گام ها باشه. مثلا حروف دوتا دوتا بره یا سه تا تا بره جلو تا به اون ایندکس مقصد برسه. 689 | بزارید اینجور بگم که مثلا من گفتم که از ایندکس 20 تا 50 یک استرینگ رو برای من بگیر و بیار. حالا میتونم بهش بگم وقتی داری میری از ایندکس 20 تا 50 میاری در این فاصله به صورت چندتا چندتا بیاری؟ 690 | 691 | بریم کد رو ببینیم تا بفهمیم : 692 | 693 | ```py 694 | 695 | quote = "123456789" 696 | 697 | print(quote[0:6:2]) 698 | 699 | # خروجی : 135 700 | 701 | ``` 702 | 703 | بهش گفتم که از ایندکس 0 تا ایندکس 6 رو به صورت یکی درمیون برام بگیره و بیاره. که از عدد 1 تا 5 اگه ما یکی در میون بریم جلو، اعداد 1 ، 3 ، 5 برای ما در میاد. 704 | 705 | 706 | > # [start : stop : over] 707 | > # [گام : پایان : شروع] 708 | 709 | 710 | 711 |
712 |
713 | 714 | #### خالی گذاشتن ایندکس : 715 | ما در string index اگه خونه ای ایندکسمون رو خالی بزاریم در واقع داریم یک معنی خاصی رو به زبان پایتون میرسونیم. 716 | 717 | - اگه خونه اول رو خالی بزاریم یعنی از ایندکس صفر شروع بکن. 718 | - اگه خونه دوم رو خالی بزاریم یعنی اخرین خونه ایندکس ما . مثل اگه 10 تا ایندکس داشته باشیم ، خالی گذاشتن به معنای عدد 10 هستش. 719 | - خونه سوم اگه خالی بشه یعنی یک یکی به صورت عادی ایتم های درون استرینگ رو جلو بره. 720 | 721 | 722 | 723 | 724 | ![mem copy](../src/img/meme_copy.jpg) 725 | 726 | 727 | --- 728 | 729 | 730 | > immutability : تغییر ناپذیری | greet : تبریک گفتن ، سلام دادن 731 | 732 | 733 | ## Immutability : 734 | 735 | یکی از بحث های بسیار مهم بحث immutability در زبان پایتون هستش که باید درکش بکنید. 736 | استرینگ ها در زبان پایتون تغییر ناپذیر هستند. به عنوان مثال ما میتونیم محتوای یک متغیر رو تغییر بدیم : 737 | ```py 738 | 739 | name = "alireza" 740 | print(name) 741 | # خروجی : alireza 742 | 743 | name = "sasan" 744 | print(name) 745 | #خروجی : sasan 746 | 747 | ``` 748 | 749 | ولی نمیتونیم محتوای ایندکس یک استرینگ رو تغییر بدیم. به عنوان مثال من اگه یک استرینگ به نام 'alireza' تعریف کرده باشم، دیگه نمیتونیم بیام مثلا حروف اول علیرضا که a هستش رو تبدیل بکنم به z . 750 | این مورد در زبان برنامه نویسی پایتون غیر امکان پذیره که ما ساختار یک استرینگی رو تغییر بدیم. 751 | ما با استرینگ ها نمیتونیم به شکل زیر رفتار بکنیم : 752 | 753 | ```py 754 | 755 | name = "alireza" 756 | name[0] = "z" # امکان تغییر ساختار یک استرینگ وجود نداره ! 757 | print(name) # خروجی : TypeError: 'str' object does not support item assignment 758 | 759 | ``` 760 | 761 | ما فقط میتونیم محتوای درون یک متغیر رو تغییر بدیم که تو مثال قبلی دیده بودید. تنها راه تغییر یک استرینگ اینه که ما یک استرینگ جدید ایجاد بکنیم یا به اصطلاح، produce بکنیم. 762 | جلوتر درباره این موضوع صحبت میکنیم. 763 | 764 | --- 765 | 766 | #### len() : 767 | 768 | این یک تابع built in یا از پیش ساخته شده در زبان پایتون هستش که کارایی های بسیار زیادی داره. 769 | ما میتونیم با استفاده از این تابع، هر چیزی که قابل اندازه گیری باشه رو اندازه گیری بکنیم. 770 | با استفاده از این تابع ما میتونیم تعداد آیتم های درون یک لیست ، آرایه ، دیکشنری ... ، یا استرینگ رو بفهمیم. 771 | منظور از تعداد آیتم های یک استرینگ همون تعداد حروف یک استرینگ هستش. مثلا کلمه alireza از چند حروف تشکیل شده !؟ . 772 | 773 | نکته : تابع len میاد مثل یک انسان عادی برای با از 1 میشماره، نه صفر. حواستون باشه خلاصه ! 774 | 775 | بریم ببینیم چجوری کار میکنه : 776 | 777 | ```py 778 | 779 | name = "alireza" 780 | last_name = "fazeli" 781 | greet = "Ye Toop Daram Ghel ghelie !" 782 | 783 | print(len(name)) # خروجی : 7 784 | print(len(last_name)) # خروجی : 6 785 | print(len(greet)) # خروجی : 27 786 | 787 | ``` 788 | 789 | --- 790 | 791 | ## پروژه تمرینی ( محسابه گر استرینگ ) : 792 | 793 | میخوایم باهم یک پروژه تمرینی بزنیم و یکم کیف کنیم 😁. اول از همه میخوایم از کاربر یک ورودی بگیریم، بعدش بیایم تعداد مقادیر استرینگ ورودی کاربر رو محاسبه بکنیم و بعد به کاربر بگیم که داداش ، این متن تو ، این تعداد مقادیر تو، حالشو ببر دیگه. 794 | سعی کنید این مور رو خودتون انجام بدید. 795 | اگه دادید چه خوب ، اگه نتونستید سورس کد پایین رو ببینید که کامل انجامش دادم. 796 | 797 | ```py 798 | 799 | get_input = input("داداچ یه چیزی بنویس : ") 800 | calc_input = len(get_input) 801 | 802 | show_msg = f""" 803 | 804 | داداچ متن تو این بود : {get_input} 805 | تعداد حروفات انقدره : {calc_input} 806 | 807 | نه جان من حال کردی؟ 💣 808 | 809 | 810 | """ 811 | 812 | print(show_msg) 813 | 814 | ``` 815 | 816 | 817 | #### خروجی : 818 | 819 | ![calc str input img](../src/img/calc_str.png) 820 | 821 | --- 822 | 823 | 824 | 825 | ## Method : 826 | 827 | متود ها شبیه به فانکشن ها هستن ولی متعلق به یک چیزین. برای یک چیز خاص یک کار خاصی رو انجام میدن. 828 | جلوتر به صورت کاملا مفصل درباره اینا اشنا میشیم، ولی برای شروع همینکه بدونیم متود ها برای یک سری چیزا هستن کافیه. مثلا استرینگ ها یکسری متود ها دارن که برای استرینگ ها یکسری کارهارو انجام میدن. مثلا یکی از متود ها میاد استرینگ مارو تمام حروف هاشو بزرگ میکنه یا یکی کوچیک میکنه. 829 | خلاصه هرکدوم از این استرینگ هارو بهر کاری ساخته اند !. 830 | 831 | 832 | --- 833 | 834 | #### String Method : 835 | متود هایی که متلع به استرینگ ها در پایتون هستند رو string method میگن که مثالشو بالا براتون زدم. که چجوریاست. 836 | برای اینکه ما از این متو ها استفاده بکنیم نیازه که بعد استرینگ یا بعد از متغیر حاوی یک استرینگ بیایم اون متود رو بهش اضافه بکنیم. 837 | به عنوان مثال : 838 | ```py 839 | "hello".upper() 840 | 841 | # یا 842 | 843 | name = "alireza" 844 | name.upper() 845 | ``` 846 | 847 | 848 | 849 | 850 | 851 | #### .upper() : 852 | 853 | این متود کارش اینه که میاد حروف های استرینگ مارو به حروف های بزرگ تبدیل میکنه. 854 | مثلا اگه من در استرینگم، یک حرف a داشته باشم اون میاد تبدیلش میکنه به A . یا اگه salam داشته باشیم تبدیل میکنه به SALAM . به همین اسونی. 855 | 856 | مثال : 857 | 858 | ```py 859 | 860 | name = "alireza" 861 | letter = "j" 862 | 863 | print(name.upper()) # خروجی : ALIREZA 864 | print(letter.upper()) # خروجی : J 865 | 866 | ``` 867 | 868 | 869 | > نکته : اگه شما این متود رو برای متغیر تون استفاده بکنید و اوت متغیرتون رو پرینت بگیرید. میبینید که متغیر شما هیچ تغییری نمیکنه. علتش چیه؟ علتش اینه که استرینگ همونجوری که گفته بودیم immutable هستش . شما برای اینکه محتوای درون متغیر خودتون رو تغییر بدید، باید با محتوای جدیدی که ساختیت جایگزین بکنید. شما در واقع با استفاده از این متود یک مقدار جدید produce کردید. 870 | 871 | نحوه جایگزینی با مقدار جدید : 872 | 873 | ```py 874 | 875 | name = "alireza" 876 | name = name.upper() 877 | 878 | print(name) # خروجی : ALIREZA 879 | ``` 880 | 881 | الان میبینید که خروجی متغیر ما تغییر کرده. 882 | 883 | #### .lower() : 884 | 885 | این متود دقیقا مثل متود بالایی هستش با این تفاوت جای اینکه بیاد حروف هارو بزرگ بکنه ، کوچیک میکنه. یعنی ما اگه داشته باشیم A این میکنه a. 886 | به همین آسونی ! . 887 | 888 | مثال : 889 | 890 | ```py 891 | 892 | name = "ALIREZA FAZELI" 893 | letter = "B" 894 | 895 | print(name.lower()) # خروجی : alireza fazeli 896 | print(name.lower()) # خروجی : b 897 | 898 | ``` 899 | 900 | 901 | #### .capitalize() : 902 | این متود میاد فقط اولین حروف از استرینگ مارو بزرگ میکنه. یعنی اگه ما استرینگ داشته باشیم : alireza fazeli این میاد تبدیل میکنه به Alireza fazeli . 903 | 904 | ```py 905 | 906 | name = "james clear" 907 | print(name.capitalize()) # خروجی : James clear 908 | 909 | ``` 910 | 911 | 912 | #### .find() : 913 | این متود از اسمش معلومه، find،به معنای پیدا کردن. 914 | این میره توی استرینگ برای ما میگرده که آیا یک حروفی، جمله ای، کلمه ای، درون اون استرینگ برای وجود داره یا خیر. اگر وجود داشته باشه، فقط اون اولین موردی که پیدا کرد رو اون ایندکس اولش رو برای میفرسته. به عنوان مثال من یک جمله دارم : To be or not to be که توی این جمله از چند تا be تشکیل شده که من میگم برو پیدا بکن که توی استرینگ من آیا اصلا be هست ؟ این میگه اره هست ، چندتا هم هست. برای من اون ادرس ایندکس اون اولین موردی که پیدا کرد رو میفرسته. دیگه بقیه رو نمیگه، میگه به من چه، خودت برو پیدا بکن. 915 | اگر پیدا نکرد، برای ما عدد -1 رو بر میگردونه. 916 | 917 | 918 | ```py 919 | 920 | greet = "to be or not to be" 921 | 922 | print(greet.find("be")) # خروجی : 3 . این عدد 3 همون ایندکس 3 هستش. 923 | 924 | ``` 925 | 926 | > نکته : ما میتونیم به متود فایند بگیم که از کجا تا کجای استرینگ مارو بگرده به این صورت که ایندکس اول اون کلمه ای که مدنظرمونه، ایندکس دوم اینکه از کجای استرینگ یا از کدوم ایندکس بگرده، و ایندکس سوم اینکه تا کجای استرینگ و تا کدوم ایندکس بگرده. 927 | 928 | مثال : 929 | ```py 930 | 931 | greet = "to be or not to be" 932 | print(greet.find("not", 8, 12)) # خروجی : 9 933 | 934 | ``` 935 | 936 | 937 | #### .replace() : 938 | 939 | این متود هر حروفی، جمله ای ، کلمه ایکه ما بهش بگیم رو توی تمام اون جمله با چیزی که ما بهش میگیم عوض میکنه. 940 | به عنوان مثال جمله to be or not to be رو در نظر بگیرید. 941 | اگه من بهش بگم که be رو به duck عوض بکن ، این میاد تمامی be هارو با duck عوض میکنه. 942 | و جمله ما میشه to duck or not to duck . 943 | 944 | ```py 945 | 946 | greet = "to be or not to be" 947 | greet = greet.replace("be", "duck") 948 | print(greet) # خروجی : to duck or not to duck 949 | 950 | ``` 951 | 952 | --- 953 | 954 | ## Boolean : 955 | 956 | بولین ها یک نوع داده در زبان برنامه نویسی پایتون هستند. این نوع داده دوتا هم بیشتر نیست. 957 | بله ! 958 | خیر ! 959 | فقط همین ! . بله و خیر. 960 | True به معنای بله هستش و False به معنای خیر. 961 | کابرد اینا کجاست ؟ 962 | به عنوان مثال فرض بکنید که شما یک وبسایتی دارید که قراره از کاربر یکسری اطلاعاتی رو بگیرید . یکی از اون اطلاعات ها این هستش که آیا ازدواج کرده یا خیر؟ خب این جواب دو گزینه بیشتر نداره شما یا باید بگید بله یا خیر. 963 | همین ! . 964 | 965 | ```py 966 | 967 | is_married = True 968 | print(is_married) # خروجی : True 969 | 970 | is_married = False 971 | print(is_married) # خروجی : False 972 | 973 | ``` 974 | 975 | --- 976 | 977 | > prons and cons : مزایا و معایب 978 | 979 | #### تکرار استرینگ : 980 | شاید براتون جالب باشه . ما در زبان پایتون میتونیم استرینگ هارو بدون نیاز به حلقه ها که جلوتر دربارش یاد میگیرید تکرار بکنیم. 981 | فقط کافیه اون استرینگ مورد نظر رو ضربدر اون تعداد بکنیم. 982 | 983 | ```py 984 | 985 | print("*" * 10) # خروجی : ********** 986 | 987 | ``` 988 | 989 | #### پروژه (مخفی کردن پسورد) : 990 | بریم باهم یک پروژه ای بسازیم که نام کاربری مارو ازمون میگیره و بعد پسورد مارو ازمون میگیره و نسبت به تعداد حروف پسوردمون اونو برای ما مخفی میکنه و جاش * میزاره. 991 | 992 | 993 | ```py 994 | 995 | get_username = input("لطفا نام کاربری را وارد کنید : ") 996 | get_password = input("لطفا پسورد خود را وارد کنید : ") 997 | hide_password = "*" * len(get_password) 998 | greet_to_user = f""" 999 | 1000 | سلام {get_username} پسورد {hide_password} در سیستم وارد شد. 😊 1001 | 1002 | """ 1003 | 1004 | print(greet_to_user) 1005 | 1006 | ``` 1007 | 1008 | خروجی : 1009 | ![hide password project](../src/img/hide_pass.png) 1010 | 1011 | 1012 | --- -------------------------------------------------------------------------------- /Headlines/Main.md.backup: -------------------------------------------------------------------------------- 1 | 13 | 14 | ## نکته: 15 | 16 | > **مشارکت کننده های مختلفی ممکنه روی این کتاب کار بکنن و نکات تخصصی تری رو بنویسن تا از دانش دوستان بهره مند بشیم. از همینجا عمیقا از دوستان مشارکت کننده معذرت میخوام که برای شروع نام خودمو بردم. کوچیک شما هم هستم ❤ .** 17 | 18 | --- 19 | 20 | ## معرفی نویسنده: 21 | 22 | خب سلام سلام. من علیرضا فاضلی هستم ، الان که این کتاب یا اگه بشه بهش گفت کتاب رو وقتی مینویسم که هجده سالمه ، حالا بعدا بزرگتر میشم :) . 23 | بنده حدود سه سالی هست که برنامه نویسی کار میکنم و توی حوزه های مختلف برنامه نویسی کار کردم ، اولش که صبح تا شب گیم میزدم مثل تمامی همسن و سالای خودم ، بعدش یکی از رفقا گفت یک زبان برنامی نویسی هست به نام پایتون بشین یادش بگیر خیلی باحاله ، اقا ما نشستیم یادش گرفتیم . مدتی باهاش کار کردیم تا اینکه وارد پروژه ای با دوست خوبم [سجاد عبدالهی](https://github.com/sajjadabd) 24 | شدم. و اونجا منو با JavaScript آشنا کرد و خلاصه یکسالو نیمی رفتم برای خودم که با جی اس کار کنم. حالا که رسیده به این زمان علاقه پیدا کردم که برم سمت هوش مصنوعی و بینایی کامپیوتر . 25 | 26 | ## چیشد که دارم این کتابو مینویسم ؟ 27 | 28 | خب پیشنیاز اولیه یادگیری هوش مصنوعی ، زبان برنامه نویسی پایتون هستش ، من برای خودم دوره آموزشی پایتون از وبسایت [Zero To Mastery](https://zerotomastery.io/) 29 | انتخاب کردم. من همیشه عادت دارم که کوچکترین چیزیو که یاد میگیریم بیام توی دفترم بنویسم ، ولی این بار با خودم گفتم پسر یکم اپدیت بشو توی این قضیه . تصمیم گرفتم نکاتی که یاد میگیرم رو روی نرم افزار [Notion](https://notion.so) 30 | بنویسم. اومدم صفحه یادگیری نوشنم رو پابلیک کردم تا بقیه دوستان هم بیان نظرشونو بگن و توی این مطلب کمکم بکنن و توی توییتر توییتش کردم ، تا اینکه دوست عزیزم 31 | [محمد زرچی](https://github.com/mzarchi) 32 | بهم گفت که چرا توی گیتهاب نمیزاریش تا بقیه راحت تر بتونن توش مشارکت داشته باشن ، با خودم گفتم فکر خوبیه و این شد که الا توی گیتهاب در خدمتتون هستیم. 33 | 34 | ### بدون مقدمه بریم یکم پایتون بخونیم 😁. 35 | 36 | ### تاریخچه 37 | 38 | زمینه یادگیری عمیق هر چیزی شناخت تاریخچه و اهداف و علت های ساخت اون چیزه 39 | 40 | پایتون که امروز به یه زبان همه منظوره و مفسری شناخته میشه که اولین بار در سال 1991 عرضه شد 41 | نویسنده پایتون گیدو ون راسوم (Guido van Rossum) است که متولد 1956 و اهل هلند است 42 | 43 | ### علت نام گذاری پایتون 44 | 45 | نام زبان برنامه‌نویسی پایتون از علاقه نویسنده آن به کمدین 46 | بریتانیایی معروف، مونتی پایتون (Monty Python)، گرفته شده است. 47 | گویدو ون راسوم، نویسنده این زبان برنامه‌نویسی، به خاطر علاقه خود به 48 | این برنامه تلویزیونی کمدی و همچنین برای جذب توجه ویژه‌ای به این زبان، 49 | از نام "پایتون" برای نامگذاری این زبان استفاده کرد. 50 | 51 | ### محبوبت و قدمت 52 | 53 | بر خلاف نظر اکثریت که فکر می کنند پایتون زبان جدیدیه، پایتون یه زبان نسبتا قدیمی حساب میشه 54 | علت این افکار عموما به این بر میگرده که پایتون توی سال های اخیر تازه بر سر زبان ها افتاده و تونسته جای خودش رو در صدر جدول برای چند سالی نگه داره 55 | 56 | برای مثال جاوااسکریپت (JavaScript) سال 1995 عرضه شد 5 سال بعد از پایتون 57 | 58 | روبی(Ruby) هم سال 1995 عرضه شد 59 | 60 | سی شارپ(C#) سال 2001 عرضه شد 61 | 62 | جولیا(Julia) سال 2012 عرضه شد 63 | 64 | گو(Go) سال 2009 عرضه شد 65 | 66 | ### چرا پایتون؟ 67 | 68 | عموما پایتون زبانی سطح بالا با سینتکس راحت و خوانا نزدیک به زبان انسان است برای همین می تونه گزینه خوبه برای شروع برنامه نویسی باشه 69 | و همچنین با توجه به محبوبیت و رشد پایتون و همچنین پکیج های زیادی که داره میتونه یه انتخاب مناسب برای شروع و کار در فیلد های مختلف باشه 70 | 71 | --- 72 | 73 | ### چرا اینهمه زبان برنامه نویسی داریم ؟ 74 | 75 | زبان های برنامه نویسی مثل ابزار های مختلف برای ساخت یک خونه میمونن مثل انبر ، چکش ، اره ، بیل ، کلنگ. هر کدوم از اینا برای کاری ساخته شدن ، مثلا با چکش نمیشه چاله کند. 76 | 77 | به عنوان مثال زبان پایتون یک زبان با سرعت پایین هستش و High level. ما میخوایم برای سخت افزارمون برنامه نویسی بکنیم و سرعت برنامه سخت افزاری ما باید زیاد باشه . ما نمیتونیم از زبانی مثل پایتون که به سخت افزار نزدیک نیست و توی این مورد سرعت پایینی داره استفاده بکنیم پس میایم از زبان اسمبلی یا سی استفاده میکنیم. 78 | 79 | زبان پایتون یک زبونیه که بهره وری رو بالاتر میبره به دلیل راحتی در کد و نزدیک بودن به زبان انگلیسی سرعت توسعه رو خیلی بالا میره. 80 | 81 | به طور خلاصه هر زبونی رو بهر کاری ساختن و هر زبونی توی یک سری کارها بهتر از بقیه زبون هاست. 82 | 83 | --- 84 | 85 | > accountability = مسئولیت 86 | > instructions = دستور عمل 87 | > gibberish = بیهودگی 88 | > 89 | > > valuable = hard to acquire 90 | 91 | ### نکته : همیشه بالای مطلبی معانی زبانی هستن که نوشتم ، این معانی خیلی توی دنیای کامپیوتر استفاده میشن پس به دردتون میخوره . 92 | 93 | --- 94 | 95 | زبان ماشین به صورت اعداد باینری (0 و 1) و یا بیت ها نوشته میشود. زبانی هست که فقط کامپیوتر (مدار های کامپیوتر) میفهمه و میتونه برنامه های مارو اجرا بکنه. و زبان های برنامه نویسی که ما باهاشون کار میکنیم و جوری طراحی شدن که برای ما قابل فهمه مثل زبان های برنامه نویسی پایتون ، جاوااسکریپت ، پایتون ، گولنگ .... 96 | زبان های میانی بین زبان ماشین و زبان انسان هستن . به خاطر همینه که ما راحت به حروف انگلیسی میتونیم برنامه های مختلف بسازیم وگرنه پوستمون کنده میشد. 97 | 98 | **زبان های Low level** : زبان هایی هستن که به زبان ماشین نزدیک تر هستند مثل c , c++ , assembly ... . 99 | 100 | **زبان های High Level** : زبان هایی که به زبان انسان نزدیک تر هستند ، مثل : python , JavaScipt .... 101 | 102 | #### به طور خلاصه : 103 | 104 | زبان سطح بالا به زبان هایی گفته میشه که به زبان ما انسان ها نزدیکه و درکش برای ما اسون و در عوض برای کامپیوتر سخته ولی زبان های سطح پایین برعکس برای ما سخت ولی برای کامپیوتر اسونه! 105 | 106 | --- 107 | 108 |

109 | 110 | **Translator:** وظیفه مترجم اینه که زبان برنامه نویسی که ما باهاش کد میزنیم رو به زبان ماشین ترجمه بکنه ، به عنوان مثال ما داریم پایتون کد میزنیم و به پایتون میگیم که یه متنی رو برای من چاپ بگیر ، کامپیوتر نمیفهمه که من توی زبان پایتون چی نوشتم ، میگه که این چرتو پرت چیه تحویل من میدی ، اینجاست که مترجم ها وارد کار میشن و و اون چرت و پرت رو برای کامپیوتر به زبان ماشین ترجمه میکنن و کامپیوتر حالا میگه که اها داداش تو میخوای واست یه متنیه چاپ بگیرم ، بیا اینم متنت . 111 | 112 | #### انواع Translator ها : 113 | 114 | 1. compiler 115 | 116 | کار کامپایلر به این صورت هستش که میاد کد های مارو از اول و تا آخر میخونه اگر مشکلی ، اروری چیزی نداشت میاد کد مارو تبدیل به فایل اجرایی میکنه مثلا فایل .exe ، و هر سری برای اجرای این برنامه نیاز نیستش از اول این کد کامپایل بشه و دوبارخ فایل اجرایی جدید برای اجرا ساخته بشه ولی تا زمانی که بخواید توی کدتون تغیری ایجاد کنید ، اونموق دوباره نیازه که کدتون کامپایل بشه و خب سرعت زبان های کامپایلری از زبان های interpreter یا همون مفسری بیشتر . به عنوان مثال زبان های : C++ , C# , Java زبان های کامپایلری هستند. 117 | 118 | 1. interpreter 119 | 120 | مفسر میاد خط به خط کدامون رو میخونه و اگر اون خط مشکلی نداشت خروجی همونو بهمون میده و مفسر هیچ فایل اجرایی نداره چون کامپایل نمیشه و داره ترجمه میشه پس در نتیجه برای هربار اجرا باید این روند رو طی بکنه و همین موضوع سرعتش رو پایین میره !. زبان مفسری مثل : python , PHP , JavaScript , Ruby. 121 | 122 | --- 123 | 124 | ### برنامه نویسی به صورت انلاین 125 | 126 | شما برای برنامه نویسی به صورت انلاین ( فقط برای یاگیری ) میتونید از 127 | وبسایت های زیر استفاده کنید: 128 | 129 | - [Glot.io](https://glot.io) 130 | - [Repl.it](https://repl.it) 131 | 132 | --- 133 | 134 | ```py 135 | print(’hello world’) 136 | ``` 137 | 138 | این دستور توی پایتون برای ما هر چی که بخوایم رو در درون ترمینال برای ما خروجی میگیره. این ساده ترین دستور درون پایتونه . به طور تخصصی به این اینا میگن سینتکس و این سینتکس ها از قبل درون زبان برنامه نویسی پایتون قرار داده شدند. 139 | 140 | --- 141 | 142 | ### نحوه تفسیر شدن کد پایتونی به زبان ماشین 143 | 144 |

145 | 146 | اول از همه ما کدی رو که توی پایتون مینویسم مثل همین `print('hello world')` 147 | ، این به مفسر پایتون داده میشه 148 | و بعدش اون مفسری که از قبل براش نوشتن ، میاد کد مارو به بایت کد ترجمه میکنه و اون بایت کد درون ماشین مجازی زبان سی به نام cpython قرار میگیره 149 | و اون ماشین مجازی ، بایت کد مارو به زبان ماشین تبدیل میکنه :) . 150 | 151 | --- 152 | 153 | ```py 154 | 155 | input('Whats your name ?') 156 | 157 | ``` 158 | 159 | این تابع یا فعلا بهتره از لفظ تابع استفاده نکنیم ، چون زوده یکم ، بهتره بگیم این کد ، کارش اینه که میاد از ما ورودی دریافت میکنه ، از کجا ؟ 160 | خب از ترمینال ما ، همونجایی که ما کد پایتونیمون رو خروجی میگیریم. 161 | به مثال زیر دقت کنید: 162 | 163 |

164 | 165 | اگه دقت کنید میتونید ببینید ، از ما پرسیده که اسمت چیه ؟ خب من جواب دادم علیرضا. ولی این اسم نه جایی ذخیره شده نه حرکتی زده شده مثلا بیاد بگه سلام علیرضا. 166 | 167 | باید چیکار بکنیم ؟ اینو توی یک متفیر ذخیره بکنیم ، وقتی چیزی رو توی متفیر ذخیره میکنیم این توی مموریما میره و ذخیره میشه و ما میتونیم با این کار های مختلف بکنیم. 168 | 169 | ```py 170 | 171 | userName = input('whats your name ? ') 172 | 173 | print('Hello ' + userName) 174 | 175 | ``` 176 | 177 |

178 | 179 | و حالا میبینید که ما تونستیم از این تابع input استفاده بکنیم ، یک ورودی از کاربر دریافت بکنیم و اون ورودی رو درون متغیر بریزیم و از اون متغیر به عنوان خروجی استفاده بکنیم . 180 | 181 | --- 182 | 183 | # Python.3 vs Python.2 184 | 185 | > evolving = درحال تکامل | decided = تصمیم گرفت | legacy = میراث 186 | 187 | ### breaking changes : 188 | 189 | به اپدیتی گفته میشه که وقتی میاد دیگه اپلیکیشن ها برنامه ها و پروژه ها نمیتونن از اون اپدیت استفاده بکنن چون اصلا براشون طراحی نشده. به عنوان مثال وقتی پایتون 3 اومد دیگه شرکت ها نمیتونستن خودشونو تا مدت ها اپدیت بکنن و باید خط به خط پروژه هاشونو اپدیت میکردن. یعنی همه چی برای شرکتا ف\*\*اکداپ شده بود 😂. 190 | 191 | از سال 2008 سازنده پایتون تصمیم گرفت که ورژن جدید پایتون رو بسازه یعنی ورژن 3 که انقلابی در کامیونیتی پایتون بودش و اینکه اومد کلا تمامی زیرساخت های زبان پایتون رو از نو کوبید و ساخت باعث breaking changes شد. 192 | 193 | ### نمونه ای از کد های پایتون 2 و 3 : 194 | 195 | ```py 196 | #python 2 : 197 | print ‘hello world’ 198 | 199 | #python 3 : 200 | print(’hello world’) 201 | 202 | ``` 203 | 204 | --- 205 | 206 |