45 subscribers
30 photos
22 videos
2 files
41 links
Freedom through power. Power through intelligence.| voidNetwork.ir
Download Telegram
This media is not supported in your browser
VIEW IN TELEGRAM
😈3
خیلی هاتون وقتی وارد portfolio من میشید میگید حتما دستی ریپازتوری هاشو وارد کرده
🤓3
اما همش بخاطر این ماژوله قسمت بعدی میریم برای توضیح
💯3
مرحله اول: تعریف ثابت‌ها
const GITHUB_API = "https://api.github.com";
const CACHE_KEY = "v0id_gh_cache_v1";
const CACHE_TTL_MS = 1000 * 60 * 30;

در این قسمت سه مقدار ثابت تعریف شده است:
GITHUB_API آدرس اصلی API گیت‌هاب است.
CACHE_KEY کلیدی است که برای ذخیره اطلاعات در sessionStorage استفاده می‌شود.
CACHE_TTL_MS مدت اعتبار کش را مشخص می‌کند. مقدار 1000 * 60 * 30 یعنی ۳۰ دقیقه.
بنابراین اگر اطلاعات کمتر از ۳۰ دقیقه قبل دریافت شده باشند، برنامه دوباره به GitHub درخواست ارسال نمی‌کند.
مرحله دوم: ساختار داده‌های کش
interface CachePayload {
timestamp: number;
repos: GithubRepo[];
}

این Interface مشخص می‌کند که اطلاعات ذخیره‌شده در مرورگر چه ساختاری دارند.
دو مقدار ذخیره می‌شود:
timestamp زمان ذخیره شدن داده‌ها
repos لیست Repositoryها
نمونه داده‌ای که در sessionStorage ذخیره می‌شود:
{
"timestamp": 1715000000000,
"repos": [...]
}

مرحله سوم: خواندن کش
function readCache(): GithubRepo[] | null

اولین کاری که برنامه انجام می‌دهد این است که بررسی کند آیا قبلاً اطلاعاتی ذخیره شده یا خیر.
const raw = sessionStorage.getItem(CACHE_KEY);

اگر هیچ داده‌ای وجود نداشته باشد:
return null;

در غیر این صورت داده JSON به شیء جاوااسکریپت تبدیل می‌شود.
const parsed = JSON.parse(raw);

حالا باید بررسی شود که کش هنوز معتبر است یا نه.
if (Date.now() - parsed.timestamp > CACHE_TTL_MS)

در این خط:
Date.now() زمان فعلی را بر حسب میلی‌ثانیه برمی‌گرداند.
parsed.timestamp زمان ذخیره شدن اطلاعات است.
اگر اختلاف این دو بیشتر از ۳۰ دقیقه باشد، کش منقضی شده است.
در نتیجه:
return null;

اما اگر کمتر از ۳۰ دقیقه گذشته باشد:
return parsed.repos;

و دیگر هیچ درخواستی به GitHub ارسال نمی‌شود.
مرحله چهارم: ذخیره اطلاعات در کش
function writeCache(repos: GithubRepo[])

این تابع بعد از دریافت اطلاعات از GitHub اجرا می‌شود.
ابتدا یک شیء می‌سازد:
const payload = {
timestamp: Date.now(),
repos
};

سپس آن را به رشته JSON تبدیل کرده و در sessionStorage ذخیره می‌کند.
sessionStorage.setItem(
CACHE_KEY,
JSON.stringify(payload)
);

اگر مرورگر اجازه استفاده از Storage را ندهد، برنامه کرش نمی‌کند و فقط از این مرحله عبور می‌کند.
مرحله پنجم: دریافت اطلاعات از GitHub
اصلی‌ترین قسمت برنامه این تابع است:
fetchGithubRepos(username)

ابتدا کش بررسی می‌شود.
const cached = readCache();

if (cached) {
return cached;
}

اگر اطلاعات داخل کش موجود باشد، همان داده‌ها برگردانده می‌شوند.
اما اگر کش وجود نداشته باشد، درخواست به GitHub ارسال می‌شود.
fetch(
`https://api.github.com/users/${username}/repos`
)

در این آدرس، مقدار username جایگزین نام کاربر می‌شود.
مثلاً:
https://api.github.com/users/octocat/repos

GitHub لیست Repositoryهای عمومی این کاربر را برمی‌گرداند.
بررسی موفق بودن درخواست
بعد از دریافت پاسخ، ابتدا وضعیت آن بررسی می‌شود.
if (!res.ok)

اگر پاسخ موفق نباشد (مانند 404 یا 403)، یک Error ساخته می‌شود.
در غیر این صورت اطلاعات JSON خوانده می‌شوند.
const data = await res.json();

مرحله ششم: حذف Repositoryهای Fork
در GitHub ممکن است کاربر پروژه‌های دیگران را Fork کرده باشد.
اگر فقط پروژه‌های اصلی خود کاربر مورد نیاز باشند، از این کد استفاده می‌شود:
const repos = data.filter((r) => !r.fork);

عبارت !r.fork یعنی فقط Repositoryهایی انتخاب شوند که مقدار fork آن‌ها false باشد.
مرحله هفتم: ذخیره نتیجه در کش
بعد از دریافت اطلاعات، آن‌ها در مرورگر ذخیره می‌شوند.
writeCache(repos);

در نتیجه اگر کاربر دوباره صفحه را باز کند، تا ۳۰ دقیقه اطلاعات از Storage خوانده می‌شوند و درخواست جدیدی ارسال نخواهد شد.
مرحله هشتم: مدیریت خطا
اگر اینترنت قطع باشد یا GitHub پاسخ ندهد، برنامه نباید متوقف شود.
به همین دلیل از try...catch استفاده شده است.
catch (err) {
console.warn(err);
return [];
}

به جای کرش کردن، یک آرایه خالی برگردانده می‌شود تا رابط کاربری همچنان قابل نمایش باشد.
مرحله نهم: محاسبه آمار Repositoryها
تابع
computeGithubStats()

روی Repositoryهای دریافت‌شده چند آمار تولید می‌کند.
۱- تعداد Repositoryها
repoCount: repos.length

فقط تعداد کل پروژه‌ها را محاسبه می‌کند.
۲- مجموع ستاره‌ها
🎃3
const totalStars = repos.reduce(
(sum, repo) => sum + repo.stargazers_count,
0
);

متد reduce روی تمام پروژه‌ها حرکت می‌کند و تعداد ستاره‌های هر پروژه را با هم جمع می‌کند.
فرض کنید سه پروژه داریم:
Repository
Stars
Portfolio
15
Chat App
8
Dashboard
12
خروجی برابر خواهد بود با:
35

۳- پیدا کردن زبان‌های پرکاربرد
ابتدا یک Map ساخته می‌شود.
const languageCounts = new Map();

سپس تمام Repositoryها پیمایش می‌شوند.
for (const repo of repos)

اگر پروژه زبان برنامه‌نویسی نداشته باشد، از آن عبور می‌شود.
if (!repo.language) continue;

در غیر این صورت تعداد استفاده از آن زبان افزایش پیدا می‌کند.
مثلاً نتیجه Map ممکن است این باشد:
TypeScript → 7
JavaScript → 5
Python → 2
Go → 1

در نهایت این زبان‌ها بر اساس تعداد مرتب شده و فقط شش مورد اول انتخاب می‌شوند.
خروجی نهایی
در پایان تابع این شیء را برمی‌گرداند:
{
repoCount: repos.length,
totalStars,
topLanguages
}

نمونه خروجی:
{
repoCount: 18,
totalStars: 142,
topLanguages: [
"TypeScript",
"JavaScript",
"Python",
"Go",
"Rust",
"C#"
]
}
👾3
Forwarded from کاف
This media is not supported in your browser
VIEW IN TELEGRAM
لحظه‌ای که صدها مرد برای یک زنِ استثنایی از جا بلند شدند…
تمام آن تشویق‌ها فقط برای یک نام بود: ماری کوری.
زنی که عمرش را وقف علم کرد و مسیر تاریخ را تغییر داد.

او با آزمایش‌هایش روی اورانیوم، مفهوم رادیواکتیویته را کشف کرد،
ویژگی‌های رادیواکتیو توریوم را شناخت
و توانست رادیوم را از دل ماده جدا کند—کاری که جهان علم را وارد عصر تازه‌ای کرد ⚛️🔥

ماری کوری نه‌تنها اولین زنی بود که نوبل گرفت،
بلکه اولین دانشمندی شد که این جایزه را دو بار دریافت کرد؛
یکی در فیزیک (۱۹۰۳) و دیگری در شیمی (۱۹۱۱).
او پایه‌گذار علم رادیولوژی و یکی از تأثیرگذارترین چهره‌های تاریخ علم است.

مادام کوری ثابت کرد
نبوغ جنسیت نمی‌شناسد؛ فقط اراده، کنجکاوی و شجاعت می‌خواهد.
و او هر سه را داشت… به شکلی که جهان را مجبور کرد بایستد و برایش دست بزند 👏

NiNa @Kafiha
3
Media is too big
VIEW IN TELEGRAM
اینا چیه من میسازم😂
🤷‍♀3
VOIDNETWORK
اینا چیه من میسازم😂
from textual.app import App, ComposeResult
from textual.containers import Horizontal, Vertical
from textual.widgets import (
Header,
Footer,
Button,
Static,
DataTable,
ProgressBar,
Input,
)


class MailSender(App):

CSS = """
Screen {
background: #0b1220;
color: white;
}

Header {
background: #2563eb;
color: white;
}

Footer {
background: #111827;
color: #9ca3af;
}

#sidebar {
width: 30;
background: #111827;
border: round #2563eb;
padding: 1;
}

#content {
background: #0f172a;
padding: 1 2;
}

Button {
width: 100%;
height: 3;
margin-bottom: 1;
background: #1e293b;
color: white;
border: round #334155;
}

Button:hover {
background: #2563eb;
color: white;
border: round #3b82f6;
}

Button:focus {
background: #3b82f6;
color: black;
text-style: bold;
}

Input {
margin-top: 1;
border: round #2563eb;
background: #111827;
color: white;
}

DataTable {
margin-top: 1;
height: 1fr;
border: round #334155;
}

ProgressBar {
margin-top: 1;
color: #22c55e;
}

#stats {
height: 10;
padding: 1;
border: round #8b5cf6;
background: #111827;
color: white;
}
"""

def compose(self) -> ComposeResult:

yield Header()

with Horizontal():

with Vertical(id="sidebar"):
yield Static("📧 Mail Sender Pro\n")
yield Button("📊 Dashboard")
yield Button("👥 Contacts")
yield Button("📝 Templates")
yield Button("📨 Campaigns")
yield Button("⚙️ SMTP")
yield Button("📄 Logs")
yield Button(" Exit", id="exit")

with Vertical(id="content"):

yield Static(
"""[b]Dashboard[/b]

Total Emails : 12450
Sent : 12120
Failed : 330
SMTP : Connected
""",
id="stats",
)

yield Input(
placeholder="Search email..."
)

table = DataTable()
table.add_columns("Email", "Status")
table.add_row("ali@gmail.com", " Sent")
table.add_row("sara@gmail.com", " Sent")
table.add_row("test@test.com", " Failed")
table.add_row("info@company.com", " Sending")
yield table

progress = ProgressBar(total=100)
progress.advance(73)
yield progress

yield Footer()

def on_button_pressed(self, event: Button.Pressed):
if event.button.id == "exit":
self.exit()


if __name__ == "__main__":
MailSender().run()
🦄3
VOIDNETWORK
اینا چیه من میسازم😂
راستش کارفرما ازم خواسته بود یه سیستم برای مدیریت ارتباط با کاربران و کارمند هاشون توسعه بدم سیستمی که بتونن خیلی راحت و متمرکز برای همه کاربران، یک کاربر خاص، همه کارمند ها یا حتی فقط یک کارمند، پیامک یا ایمیل ارسال کنن نکته مهم این بود که ارسال پیام ‌ها کاملاً هدفمند، قابل مدیریت و مقیاس ‌پذیر باشه و مدیر سیستم بتونه بدون دردسر مخاطب ‌ها رو انتخاب و کمپین ‌های مختلف رو اجرا کنه
برای همین کل پروژه رو در دو نسخه مجزا پیاده ‌سازی کردم نسخه اول یک پنل گرافیکی (GUI Panel) بود که تمرکزش روی تجربه کاربری سادگی مدیریت و دسترسی سریع به تمام امکانات بود از انتخاب گیرنده ‌ها گرفته تا ارسال انبوه یا تکی پیام مدیریت قالب‌های پیام و کنترل فرآیند ارسال
در کنار اون یک نسخه مبتنی بر CLI هم توسعه دادم که بیشتر برای سناریو های اتوماسیون اجرای اسکریپت‌ ها استفاده روی سرور ها و ادغام با سایر سرویس ‌ها طراحی شده بود. این نسخه با وجود رابط متنی،تمام قابلیت ‌های اصلی پنل گرافیکی رو در اختیار قرار می‌داد و برای محیط ‌هایی که نیاز به سرعت انعطاف و اجرای خودکار فرآیند ها وجود داشت، گزینه بسیار مناسبی بود.
2👏1
پاشو برو تخصصش و یاد بگیرررررررر
2😭1
VOID
Lady is here
رفتم که بخرمش
فروشنده گفت هزینه نصب ویندوز و آنتی ویروس بقیه برنامه های مورد نیاز میشه ۱ میلیون 😂
منم گفتم اوکیه ولی ویندوز نمی‌خوام
گفت پس چی؟ گفتم ارچ لینوکس بریز روش حتما هم KDE
بنده خدا هم گفت باشه
فردا زنگ زد گفت ویندوز ریختم
2🥰1
This media is not supported in your browser
VIEW IN TELEGRAM
2
یک Flipper Zero موجود داریم برای کسب اطلاعات بیشتر و در صورت تمایل به خرید،
لطفا به پیوی مراجعه کنید

به فروش رسید
کم‌ کم دارم به آخرین مراحل توسعه یکی از پروژه ‌های مورد علاقه‌م می ‌رسم پروژه‌ای که واقعا با اشتیاق و دقت روش کار کردم.
VOIDADB
یک ابزار متن‌ باز و کراس ‌پلتفرم برای مدیریت و کنترل دستگاه ‌های اندرویدی از طریق Wireless ADB با رابط گرافیکی مدرن، CLI قدرتمند و معماری ماژولار که هم به‌عنوان یک اپلیکیشن و هم به ‌عنوان یک کتابخانه Python قابل استفاده خواهد بود.
هنوز کار تموم نشده اما بی‌صبرانه منتظرم نسخه نهایی رو منتشر کنم و بازخورد جامعه متن‌باز رو ببینم.
🏆3
فقط خواستم قبل از امتحان فردا یه چیزی بگم...
این چند وقت برای خیلی ‌هامون سخت گذشت اتفاقاتی افتاد که شاید تمرکز، انگیزه و حتی حال خوبمون رو گرفت اگه حس می‌کنید اون ‌طور که باید درس نخوندید یا آمادگی کامل ندارید خودتون رو سرزنش نکنید.
امتحان مهمه اما نه به اندازه‌ی سلامتی، آرامش و امیدی که باید برای ادامه راه داشته باشید یه برگه امتحان قرار نیست ارزش شما یا آینده ‌تون رو مشخص کنه.
فردا فقط سعی کنید بهترین تلاشتون رو بکنید حتی اگه فکر می‌کنید کم بوده همون تلاش هم ارزشمنده.
و در آخر از صمیم قلب برای همتون آرزوی موفقیت دارم چه رفیقایی که همیشه کنارم بودن، چه اونایی که هیچ‌وقت چشم دیدن مارو نداشتن امیدوارم همه ‌مون از این روزهای سخت عبور کنیم و روزهای خیلی بهتری در انتظارمون باشه.
موفق باشید و امیدوارم فردا با لبخند از جلسه امتحان بیرون بیاید. 🤍
💘3
VOID
Video
مایکت با این موضوع مشکل داره که سایفر گارد اوپن سورسه😐
1