جاوااسکریپت | JavaScript
507 subscribers
654 photos
139 videos
3 files
512 links
کانال @IR_javascript حاوی اطلاعات مفید در حوزه برنامه نویس فرانت که بصورت روزانه بروز می‌شود.
در این کانال شما به:
[1] مطالب تازه
[2] تحلیل‌های عمیق
[3] نکات آموزشی
[4] چالش
[5] ابزار و راهنمایی‌های کاربردی
دسترسی خواهید داشت.

🆔@IR_javascript
Download Telegram
Merge vs Rebase: تفاوت‌ها و زمان استفاده از هرکدام

هنگام کار با Git، ما معمولاً با دو دستور پرکاربرد برای مدیریت شاخه‌ها روبه‌رو می‌شویم: merge و rebase. هر دو این دستورات به ما کمک می‌کنند تا تغییرات را از دو شاخه مختلف در یک شاخه ترکیب کنیم، اما نحوه عملکردشان کاملاً متفاوت است. در اینجا تفاوت‌ها را بررسی می‌کنیم و می‌فهمیم که چه زمانی بهتر است هرکدام را استفاده کنیم.

🌀 Merge: ترکیب شاخه‌ها با حفظ تاریخچه
هنگامی که از دستور merge استفاده می‌کنیم، Git یک merge commit ایجاد می‌کند که تاریخچه دو شاخه را با هم ترکیب می‌کند. در این حالت، تمام تاریخچه موجود دست‌نخورده باقی می‌ماند و نتیجه به‌صورت ترکیبی از دو خط موازی به نظر می‌آید.

مثال:
ما یک شاخه به نام main و یک شاخه به نام feature داریم.
تغییراتی در هر دو شاخه انجام می‌دهیم.
هنگامی که در شاخه main قرار داریم و دستور git merge feature را اجرا می‌کنیم، یک merge commit جدید در تاریخچه شاخه main ایجاد می‌شود که هر دو مجموعه تغییرات را با هم ترکیب می‌کند.

💡 کی از merge استفاده کنیم؟
وقتی می‌خواهید تمام تاریخچه کامیت‌ها، از جمله شاخه‌ها، را حفظ کنید؛
وقتی برای شما مهم است که بفهمید تغییرات از کجا آمده‌اند؛
برای کار در تیم‌های بزرگ که شفافیت در روند کاری اهمیت دارد.

مثال بصری پس از merge (ترتیب زمانی از پایین به بالا: ابتدا در شاخه main کار کردیم (۲ کامیت)، سپس به شاخه feature رفتیم (۲ کامیت)، و بعد شاخه feature را به شاخه main وارد کردیم):

                 *   Merge branch 'feature' [merge commit]
|\
| * افزودن ویژگی جدید
| * اصلاح باگ
اصلاح استایل * |
بروزرسانی README * |
[شاخه main] [شاخه feature]


🔀 Rebase: بازنویسی تاریخچه
‏Rebase تغییرات را از یک شاخه به بالای شاخه دیگر منتقل می‌کند، به‌گونه‌ای که انگار این تغییرات ابتدا روی آن شاخه ایجاد شده‌اند. در نتیجه، تاریخچه به‌صورت خطی می‌شود و خبری از merge commit نخواهد بود.

مثال:
ما یک شاخه به نام main و یک شاخه به نام feature داریم.
بعد از اجرای دستور `git rebase main`، تغییرات شاخه feature روی نسخه فعلی شاخه main قرار می‌گیرند، به‌گونه‌ای که انگار شاخه feature قبل از ایجاد تغییرات، مشابه شاخه main بوده است.

💡 کی از rebase استفاده کنیم؟
وقتی می‌خواهید تاریخچه‌ای تمیز و خطی داشته باشید و خبری از merge commit نباشد؛
وقتی در شاخه شخصی خود کار می‌کنید و برای به‌روزرسانی تغییرات خود با آخرین نسخه شاخه اصلی نیاز به «هماهنگ کردن» دارید.

مثال بصری پس از rebase:

* اصلاح باگ
* افزودن ویژگی جدید
* اصلاح استایل
* بروزرسانی README
[شاخه feature]


🔑 نکته:
Merge برای تیم، Rebase برای تمیزی تاریخچه
👀 از merge برای حفظ تاریخچه کامل و منابع/نویسندگان تغییرات در پروژه‌های بزرگ استفاده کنید؛
👀 از rebase در شاخه شخصی/شاخه‌های مربوط به تکالیف استفاده کنید تا تغییرات خود را قبل از ارسال به شاخه اصلی به‌روزرسانی کنید (اما از انجام rebase روی کامیت‌های منتشر شده اجتناب کنید، زیرا ممکن است باعث ایجاد تداخل‌ها و سردرگمی هنگام همکاری شود).

#️⃣#tip
👥@IR_javascript_group
🆔@IR_javascript
👍3
API دسترسی به سیستم فایل (File System Access API) 🧐
این API تقریباً در هیچ‌جای دیگری کار نمی‌کند، اما در Chrome امتحانش جالب است! 😁

وقتی اولین بار درباره‌ی File System Access API شنیدم، اولین فکر من این بود: "خب، بالاخره مرورگرها می‌توانند مثل برنامه‌ها روی کامپیوتر با فایل‌ها کار کنند!" و بلافاصله دومین فکر به ذهنم آمد: "آیا اصلاً این کار در جایی کار می‌کند؟"

پاسخ کوتاه: بله، کار می‌کند، اما تقریباً فقط در Chrome و چند مرورگر دیگر مبتنی بر Chromium. (لینک: [caniuse.com](https://caniuse.com/?search=File%20System%20Access%20API)) بنابراین، اگر طرفدار Firefox یا Safari هستید، فعلاً باید فقط در رویاهایتان بماند. 😒 اما برای آزمایشات، این API یک کشف عالی است! بیایید بررسی کنیم که این API چطور کار می‌کند و چه کاربردهایی دارد.

‏**File System Access API** به وب‌اپلیکیشن‌ها اجازه می‌دهد تا مستقیماً با فایل‌های موجود در کامپیوتر کاربر ارتباط برقرار کنند.

مثلاً ویرایشگر متن شما در مرورگر می‌تواند فایل‌ها را باز کرده، تغییرات را ذخیره کند و حتی به طور خودکار آن‌ها را همگام‌سازی کند! همه‌ی این‌ها بدون نیاز به بارگذاری فایل‌ها بر روی سرور.

### امکانات این API:
باز کردن فایل‌ها: آیا می‌خواهید یک سند متنی یا تصویر را مستقیماً در مرورگر بارگذاری کنید؟ به سادگی!

ذخیره تغییرات: این API به شما امکان می‌دهد تا داده‌ها را در فایلی که قبلاً موجود است، بدون ارسال درخواست‌های اضافی ذخیره کنید.

کار با پوشه‌ها: می‌توانید به کل پوشه دسترسی پیدا کرده و همزمان چندین فایل را مدیریت کنید.

پیاده‌سازی ذخیره‌سازی خودکار: دیگر هیچ "اوه، فراموش کردم Ctrl+S بزنم" نخواهید داشت.

### چرا این موضوع جالب است؟ 🤨

‏**File System Access API** موانع اضافی بین کاربر و وب‌اپلیکیشن را از بین می‌برد. این یک روش است برای طبیعی و راحت کردن تعاملات با فایل‌ها.

برای اطلاعات بیشتر می‌توانید به [مستندات Chrome](https://developer.chrome.com/docs/capabilities/web-apis/file-system-access) مراجعه کنید.

توصیه: امتحانش کنید! گاهی اوقات خوب است که چیزی جدید را امتحان کنیم، حتی اگر فقط در چند مرورگر پشتیبانی شود.


#️⃣#tip
👥@IR_javascript_group
🆔@IR_javascript
👍2
اسکرول بی‌پایان مقابل اسکرول مجازی

اسکرول بی‌پایان

محتوای اضافی به محض اسکرول کردن صفحه بارگذاری می‌شود. از روش‌هایی مانند AJAX برای بارگذاری داده‌ها از سرور و افزودن آن‌ها به انتهای لیست استفاده می‌شود، به طوری که وقتی کاربر به انتهای صفحه می‌رسد، داده‌ها به طور خودکار بارگذاری می‌شوند.

کاربران بدون نیاز به فشردن دکمه "بارگذاری بیشتر" یا رفتن به صفحه دیگر، محتوای جدید را مشاهده می‌کنند. این امر تجربه‌ای روان و پیوسته از مشاهده محتوا را فراهم می‌کند.

با افزایش حجم داده‌ها در DOM، کارایی کاهش می‌یابد، زیرا تمام داده‌ها به طور همزمان رندر می‌شوند.

اسکرول مجازی

عملکرد لیست‌های بزرگ با رندر کردن فقط قسمت‌های قابل مشاهده داده‌ها بهبود می‌یابد. تعداد مشخصی از عناصر در DOM نگه داشته می‌شود و محتوای آن‌ها بسته به موقعیت اسکرول به طور دینامیک به‌روزرسانی می‌شود.

کاربران همچنین لیست را اسکرول می‌کنند، اما فقط عناصر قابل مشاهده رندر می‌شوند، که این باعث بهبود عملکرد به‌ویژه برای لیست‌های بسیار بزرگ می‌شود. این روش فشار بر حافظه را کاهش می‌دهد و روانی اسکرول را بهبود می‌بخشد.

#️⃣#tip
👥@IR_javascript_group
🆔@IR_javascript
👍4
پلاگین vite-plugin-json-md

این پلاگین در فایل‌های JSON/JSON5 مارک‌داون را با HTML تبدیل‌شده جایگزین می‌کند.

این ابزار به خصوص برای i18n (بین‌المللی‌سازی) مفید است، زمانی که متن ترجمه در فایل‌های JSON قرار دارد، اما گاهی اوقات فرمت‌بندی پیچیده‌ای در صفحه وجود دارد و تقسیم‌بندی متن به صورت کلید-مقدار خیلی شلوغ می‌شود. در چنین مواقعی می‌توان متن را از طریق مارک‌داون نوشت.

این پلاگین هم پشتیبانی از گنجاندن مارک‌داون به صورت این‌لاین و هم لینک به فایل‌های مارک‌داون خارجی را ارائه می‌دهد.

🔗 https://www.npmjs.com/package/vite-plugin-json-md
#️⃣#npm_module
👥@IR_javascript_group
🆔@IR_javascript
This media is not supported in your browser
VIEW IN TELEGRAM
ولادت امام حسین(ع) مبارک!
💠 امام حسین عليه السلام فرمودند:
إنَّ شِيعَتَنَا مَنْ سَلِمَتْ قُلُوبُهُمْ مِنْ كُلِّ غِشٍّ وَ غِلٍّ وَ دَغَلٍ

💫 بی گمان شیعیان ما، دلهایشان از هر خیانت، کینه و فریبکاری پاک است.
📚 بحار الأنوار، ج۵۶، ص۱۵۴

#️⃣#event
👥@IR_javascript_group
🆔@IR_javascript
9👎6
پاک‌سازی آرایه در جاوا اسکریپت: کدام روش را انتخاب کنیم — arr.length = 0 یا arr = []؟ 🗑

پاک‌سازی آرایه یکی از وظایف رایج در جاوا اسکریپت است و روش‌های مختلفی برای انجام آن وجود دارد. امروز دو روش پرکاربرد را مقایسه می‌کنیم:

🧩 arr.length = 0

این روش ویژگی length آرایه را تغییر می‌دهد که به صورت آنی تمام عناصر را حذف می‌کند.

✔️ آرایه به‌صورت درجا پاک می‌شود و ارجاع جاری حفظ می‌شود؛
✔️ اگر سایر متغیرها به این آرایه ارجاع دارند، تغییرات در همه جا اعمال می‌شود.

🧩 arr = []

این روش به متغیر یک آرایه خالی جدید اختصاص می‌دهد.

✔️ آرایه جدیدی ایجاد می‌شود؛
✔️ ارجاع قبلی به آرایه حفظ می‌شود، بنابراین سایر متغیرهایی که به آرایه اصلی اشاره می‌کنند تحت تأثیر قرار نمی‌گیرند.

💡 کدام روش را باید انتخاب کنید؟
از arr.length = 0 استفاده کنید اگر می‌خواهید آرایه را درجا پاک کنید و مهم است که تمام ارجاع‌ها به آن به‌روز بمانند؛
از arr = [] استفاده کنید اگر می‌خواهید آرایه جدیدی بسازید و ارتباط با آرایه قبلی را قطع کنید.

حالا می‌دانید که بسته به موقعیت، چگونه باید آرایه را به‌درستی پاک کنید! 👍

#️⃣#tip
👥@IR_javascript_group
🆔@IR_javascript
👌5
برای لینوکس:
"count:sfc": "find . -type f -name '*.vue' ! -path '*/node_modules/*' | wc -l"


برای ویندوز:
"count:sfc": "Get-ChildItem -Recurse -Include *.vue -Exclude '*/node_modules/*' | Measure-Object -Line"


این دستورات را به اسکریپت‌های فایل package.json خود اضافه کنید.

این اسکریپت تعداد کامپوننت‌ها در پروژه vue را می‌شمارد.
#️⃣#tool
👥@IR_javascript_group
🆔@IR_javascript
👏2👍1
This media is not supported in your browser
VIEW IN TELEGRAM
ولادت امام سجاد(ع) مبارک!
💠 امام زین العابدین علیه السلام:
از شاد شدن به گناه بپرهیز ،که شاد شدن به گناه از ارتکاب آن بدتر است.

[+لینک ویدیو]


#️⃣#event
👥@IR_javascript_group
🆔@IR_javascript
10👎10
‏**SSE چیست؟**

‏SSE (Server-Sent Events) یک فناوری برای ایجاد ارتباط یک‌طرفه بین سرور و کلاینت است که به سرور این امکان را می‌دهد تا به‌روزرسانی‌های داده را به‌صورت آنی ارسال کند.

اغلب SSE می‌تواند یک جایگزین عالی برای WebSocket باشد. این فناوری به‌ویژه برای مواردی مناسب است که:
1. نیاز به دریافت مداوم به‌روزرسانی‌ها از سرور داریم.
2. نیازی به ارسال مداوم داده‌ها از سمت کلاینت نیست.

این نوع ارتباط یک‌طرفه در موارد زیر مفید است:
- ارسال اعلان‌ها
- به‌روزرسانی داده‌ها به‌صورت آنی (مانند قیمت‌ها، بارگذاری CPU و ...)
- نشانگر پیشرفت در هنگام بارگذاری فایل‌های حجیم
- حتی در بازی‌ها

و بسیاری موارد دیگر.

مزیت SSE این است که نگهداری آن بسیار ساده‌تر و ارزان‌تر از WebSocket است، هم از لحاظ کد و هم از نظر عملکرد.

برای پیاده‌سازی آن، تنها به یک endpoint ساده در سرور نیاز داریم. فرآیند آن به این صورت است:
1. کلاینت یک درخواست GET به endpoint آماده‌شده از طریق EventStream ارسال می‌کند.
2. سرور یک event-stream ایجاد می‌کند با تنظیم هدر مناسب. ارتباط قطع نمی‌شود و از این لحظه به بعد، سرور می‌تواند هر داده متنی را به استریم ارسال کند.
3. کلاینت به‌روزرسانی‌های جدید در استریم را دریافت می‌کند.

در سرور، این کد به شکل زیر خواهد بود:

const http = require('http');

http.createServer((req, res) => {
if (req.url === '/stream') {
res.writeHead(200, {
'Content-Type': 'text/event-stream',
'Cache-Control': 'no-cache',
'Connection': 'keep-alive',
});

setInterval(() => {
res.write('data: سلام!\n\n');
}, 1000);
}
}).listen(3000);


در کلاینت، اینطور خواهد بود:

const source = new EventSource('/stream');

source.addEventListener('message', (message) => {
console.log(message.data);
});


با این کد، کلاینت هر ثانیه پیامی به نام "سلام!" دریافت می‌کند.

البته، هیچ مانعی برای پیچیده‌تر کردن منطق در سمت سرور وجود ندارد. سرور می‌تواند فقط در صورت تغییر داده‌ها، پیام‌های جدید را به استریم ارسال کند، نه هر ثانیه.

همچنین، هیچ مشکلی برای قرار دادن استریم در یک هُک React و ساخت یک راه‌حل عمومی برای پروژه‌ها وجود ندارد.

اگر تا به حال با SSE کار نکرده‌اید، حتماً توصیه می‌کنم حداقل یک بار در یک محیط آزمایشی امتحان کنید — واقعا تکنولوژی جالبی است!

به طور خلاصه:
‏SSE یک فناوری ارتباط یک‌طرفه از سرور به کلاینت است. با استفاده از SSE می‌توان داده‌ها را در کلاینت در یک اتصال ثابت و در زمان واقعی به‌روز کرد.


#️⃣#tip
👥@IR_javascript_group
🆔@IR_javascript
👍4
ویدیو دوبله شده در مورد Material UI با Vuetify و Vue.js [+لینک] از vue school
با استفاده از Vuetify، به راحتی و در کمترین زمان یک اپلیکیشن Vue.js با رابط کاربری زیبا و کاربردی ایجاد کنید! این کتابخانه رابط کاربری شامل بیش از هشتاد کامپوننت آماده است که طبق مشخصات زیبا و کاربردی Material Design طراحی شده‌اند. همچنین، این کتابخانه پرکاربردترین کتابخانه رابط کاربری برای Vue.j
است که بیش از نیم میلیون دانلود هفتگی دارد!

🔗https://www.aparat.com/playlist/13837598
#️⃣#tip #dub
👥@IR_javascript_group
🆔@IR_javascript
2
چگونه انیمیشن‌ها را نرم‌تر کنیم: نکات مهم و بهینه‌سازی 🧐

زمانی که صحبت از ایجاد انیمیشن‌های نرم در صفحات وب می‌شود، باید به نحوه پردازش انیمیشن‌ها توسط مرورگر و منابعی که برای اجرای آن‌ها استفاده می‌شود توجه کرد. در این پست، بنحوه بهینه‌سازی انیمیشن‌ها برای عملکرد نرم و مؤثر آن‌ها، به ویژه در زمینه شتاب‌دهی GPU و محاسبات مجدد طرح (reflow)، را بررسی می‌کنیم.

محاسبه مجدد طرح (Reflow) چیست و کی اتفاق می‌افتد؟

محاسبه مجدد طرح (یا reflow) زمانی رخ می‌دهد که تغییراتی در یک عنصر باعث شود مرورگر موقعیت و اندازه آن را نسبت به سایر عناصر صفحه وب مجدداً محاسبه کند.

این تغییرات می‌توانند شامل موارد زیر باشند:
اندازه عناصر: عرض (width)، ارتفاع (height)
موقعیت عناصر: بالا (top)، چپ (left)، راست (right)، پایین (bottom) (فقط زمانی که position: absolute/fixed/relative باشد)
موقعیت در جریان سند: به عنوان مثال، تغییراتی که بر نمایش یک بلوک درون ظرف والد تأثیر می‌گذارد (display، position)
فاصله‌ها و حاشیه‌ها: هرگونه تغییر در margin، padding، border-width
تغییرات در متن داخل بلوک، فونت، اندازه و سبک آن: font-size و غیره

زمانی که چنین ویژگی‌هایی را انیمیت می‌کنید، مرورگر باید طرح (layout) عناصر و فرزندان آن‌ها را دوباره محاسبه کند که باعث کندی در رندر فریم‌های انیمیشن می‌شود.

یک مثال بد (از تجربه شخصی):
زمانی که اولین بار با انیمیشن‌ها کار می‌کردم، سعی داشتم با استفاده از ویژگی CSS top عناصر را جابه‌جا کنم:

.box {
position: absolute;
transition: top 0.3s ease-in-out;
}

.box:hover {
top: 100px;
}


مشکل این است که انیمیشن با استفاده از top باعث محاسبه مجدد طرح (reflow) می‌شود، چرا که مرورگر باید موقعیت عنصر را نسبت به دیگر اشیاء در صفحه دوباره محاسبه کند. این باعث کندی انیمیشن می‌شود، به‌ویژه اگر چندین عنصر در صفحه وجود داشته باشد.

چگونه سرعت انیمیشن را افزایش دهیم:
برای افزایش سرعت انیمیشن، می‌توان از ویژگی CSS transform به جای top استفاده کرد. زمانی که با transform انیمیت می‌کنید، مرورگر از شتاب‌دهی GPU استفاده می‌کند که باعث می‌شود فریم‌های انیمیشن سریع‌تر رندر شوند نسبت به زمانی که از CPU استفاده شود.

.box {
transition: transform 0.3s ease-in-out;
}

.box:hover {
transform: translateY(100px);
}


در این حالت، مرورگر عنصر را در یک لایه ترکیب جداگانه (compositing layer) با استفاده از GPU جابه‌جا می‌کند، که باعث جلوگیری از محاسبه مجدد طرح (reflow) غیرضروری و بهبود نرمی انیمیشن می‌شود.

### چگونه انیمیشن‌ها را با GPU اجرا کنیم؟
برای تسریع انیمیشن‌ها، مرورگرها از شتاب‌دهی GPU استفاده می‌کنند. ویژگی‌های CSS مانند transform`، `opacity و filter با استفاده از GPU پردازش می‌شوند، که به مرورگر این امکان را می‌دهد که انیمیشن‌ها را نرم‌تر و سریع‌تر رندر کند، بدون اینکه محتوای دیگر صفحه تحت تأثیر قرار گیرد. بنابراین، برای اینکه مرورگر بتواند رندر فریم‌های انیمیشن شما را به GPU محول کرده و انیمیشن شما نرم‌تر به نظر برسد، باید از ویژگی‌های CSS مانند transform`، `opacity و filter استفاده کنید.


#️⃣#tip #css
👥@IR_javascript_group
🆔@IR_javascript
👍31
اگر صفحه‌ای را از طریق <router-view> نمایش می‌دهید که شامل پارامترهای مسیری (مانند محصولات، کاتالوگ‌ها یا کاربران از طریق شناسه) است و باید در صورت تغییر پارامتر، اطلاعات جدیدی بارگذاری کنید، یعنی باید تغییرات پارامتر را پیگیری کنید، این کار را می‌توان به دو روش انجام داد.

از طریق watch:

watch(
() => route.params.id,
async () => {
userData.value = await fetchUser(to.params.id);
},
{ immediate: true }
);


از طریق هوک روتر onBeforeRouteUpdate:

import { onBeforeRouteUpdate } from 'vue-router'

onBeforeRouteUpdate(async (to, from) => {
if (to.params.id !== from.params.id) {
userData.value = await fetchUser(to.params.id);
}
})


روش دوم این امکان را فراهم می‌آورد که از onBeforeRouteLeave نیز استفاده کنید، اگر به هر دلیلی نیاز باشد.

#️⃣#tip #vue
👥@IR_javascript_group
🆔@IR_javascript
👍1
چگونه اسکرول صفحه را زمانی که یک دیالوگ مدال نمایش داده می‌شود، غیرفعال کنیم؟

body:has(dialog[open]) {
overflow: hidden;
}


چگونه پس‌زمینه یا اورلی را محو کنیم؟

dialog::backdrop {
backdrop-filter: blur(2px);
}


#️⃣#tip #css
👥@IR_javascript_group
🆔@IR_javascript
👍2🔥1
This media is not supported in your browser
VIEW IN TELEGRAM
اَلسّلامُ عَلَیکَ یَا اَباعَبدِالله
🌸 سالروز میلاد حضرت علی اکبر (ع) و روز جوان

🔅 وقتي كه به ميدان كارزار قدم نهادند اينچنين رجز خواندند:
من علي پسر حسين پسر علي (ع)هستم ،به خانه خدا سوگند،كه ما به نبّي(ص) نزديكتر و اولي هستيم، تا شبث و شمر فرومايه ،آنقدر با شمشير به شما مي زنم تا شمشير تاب بردارد،شمشير زدن جوان هاشمي علوي.بخدا قسم پيوسته امروز از پدرم حمايت ميكنم.تا فرزند زنا زاده در ميان ما حكومت نكند.


🔗https://www.valiasr-aj.com/persian/mobile_shownews.php?idnews=5985
#️⃣#event
👥@IR_javascript_group
🆔@IR_javascript
18👎6
بازسازی (Reflow) و تجدید نقاشی (Repaint) در مرورگر [+لینک]
بازسازی (Reflow) و تجدید نقاشی (Repaint) مفاهیم اساسی در نحوه رندر شدن صفحات وب توسط مرورگرها هستند. این دو فرآیند بخش‌های مختلفی از روند به‌روزرسانی و رندر کردن محتوای صفحه در مرورگر را تشکیل می‌دهند. درک نحوه عملکرد این دو و تأثیر آن‌ها بر عملکرد بسیار مهم است تا بتوان بهینه‌سازی‌های لازم را در وب‌سایت‌ها انجام داد.

🔗https://aparat.com/v/rxr7h3h
#️⃣#tip #dub
👥@IR_javascript_group
🆔@IR_javascript