DotNetZoom – Telegram
DotNetZoom
2.98K subscribers
342 photos
18 videos
36 files
606 links
DotNetZoom
💎 Everything about .NET

ارتباط با مدیر و تبلیغات آگهی استخدام:
@mjebrahimi

لینک گروه ASPNET Core:
https://news.1rj.ru/str/+ufG25x7lVFgyYTNk
Download Telegram
🔰دنبال یه برنامه Monitoring ساده واسه ویندوز میگشتم که رایگان هم باشه
این 2تا رو پیدا کردم خیلی خوب بودن گفتم معرفی کنم شاید به کارتون اومد
سرعت و میزان Download و Upload در روز/هفته/ماه/سال - میزان مصرف و دمای CPU - فضای استفاده شده و آزاد RAM و ... رو نشونتون میده

🔹اولی SidebarDiagnostics هست که حاشیه کنار صفحه نشون میده. از قسمت Release ریپو هم میتونین فایل نصبیشو دانلود کنین

🔸دومی TrafficMonitor هست که امکاناتش کمتره ولی مینیمال تره و تحت یه Toolbar نشون میده (عکس دومی). از قسمت Release ریپو هم میتونین فایل اجراییشو دانلود کنین.

بازم از این ابزار های کار راه بنداز معرفی کنم؟ :)
__________________
@DotNetZoom
Forwarded from DotNetZoom (محمد جواد ابراهیمی)
❇️ ساخت برنامه های gRPC بدون فایل های proto. در ASP.NET Core

🔰برای ساخت برنامه های gRPC در دات نت، 2 پیاده سازی متفاوت (یکی رسمی و دیگری غیر رسمی) وجود دارد

1️⃣ پیاده سازی grpc-dotnet (یا gRPC for .NET) که کتابخانه رسمی gRPC برای دات نت است
https://github.com/grpc/grpc-dotnet

2️⃣ پیاده سازی protobuf-net.Grpc که کتابخانه غیر رسمی و از توسط Marc Gravell (یکی از برنامه نویسان بزرگ سایت Stackoverflow، و نویسنده کتابخانه های محبوب Dapper و StackExchange.Redis) تهیه شده است
https://github.com/protobuf-net/protobuf-net.Grpc

🔸یکی از تفاوت های این دو کتابخانه این است که در حالت عادی (توسط grpc-dotnet) ساخت فایل های .proto جهت تعریف ساختار API الزامی است ولی توسط کتابخانه protobuf-net.Grpc نیازی به فایل های اضافی .proto نبوده و ساختار متد های سرویس دهنده توسط Interface ها مشخص می شوند.

🔹تفاوت دیگر آن این است که کتابخانه protobuf-net.Grpc تارگت های NETFramework 4.6.1. و NETStandard 2.0. و NETStandard 2.1. را پشتیبانی میکند در حالی که کتابخانه grpc-dotnet فقط NETStandard 2.1. را پشتیبانی میکند در نتیجه بر روی .NET Framework و .NET Core نسخه های قبل از 3.0 قابل اجرا نیست
- البته یک پیاده سازی رسمی دیگر (به نام gRPC for C#) نیز وجود دارد که از نسخه های قدیمی تر مانند NETFramework 4.5. و NETStandard 1.5. و NETStandard 2.0. هم پشتیبانی میکند
https://github.com/grpc/grpc/tree/master/src/csharp

🔸نکته بعدی، تفاوت در سرعت این دو کتابخانه است به صورتی که طبق بنچمارک زیر protobuf-net.Grp کمی کند تر از grpc-dotnet است
https://pawelkmiec.net/2019/11/17/gRPC-performance-benchmark.html

🔹تفاوت بعد آن این است که API های کتابخانه رسمی grpc-dotnet و #gRPC for C شبیه پیاده سازی اصلی grpc گوگل بوده در حالی که کتابخانه protobuf- net.Grpc بیشتر متمایل به Contract های سی شارپی بوده و کار با آن برای برنامه نویسان سی شارپ ساده تر و باب میل تر است


🔰 مشابه قضیه بالا، برای استفاده از protobuf در دات نت نیز 2 کتابخانه وجود دارد

1️⃣ کتابخانه Google.Protobuf : که پیاده سازی و استفاده از آن شبیه نسخه اصلی protobuf است. (ریپازیتوری گیتهاب)

2️⃣ کتابخانه protobuf-net : که پیاده سازی و استفاده از آن شبیه بقیه سریالایزر‌های دات نتی بوده و بیشتر متمایل به سی شارپ است. (ریپازیتوری گیتهاب)

کتابخانه دومی بیشتر باب میل سی شارپی‌ها بوده و نیز ساده تر است. با دیدن مثال هر دو کتابخانه میتوانید بهتر متوجه این تفاوت شوید.
لینک زیر هم به مقایسه این دو کتابخانه پرداخته :
How to choose between protobuf-csharp-port and protobuf-net


آموزش استفاده از protobuf-net.Grpc
✔️Getting Started with protobuf-net.Grpc
✔️Mark Gravell Talking Between Services with gRPC and Other Tricks

آموزش استفاده از grpc-dotnet و #gRPC for C
✔️Introduction to gRPC on .NET Core
✔️gRPC services with C#
✔️
gRPC services with ASP.NET Core
✔️Call gRPC services with the .NET client
✔️Create a gRPC client and server in ASP.NET Core
✔️Trying out gRPC in ASP.NET Core 3

__________________
@DotNetZoom
Forwarded from کدهک
اصل CQS بیان میکند که یک متد یا باید وضعیت (State) را تغییر دهد یا باید مقداری را برگرداند. بر مبنای این اصل متدهایی که وضعیت را تغییر میدهند Command و متدهایی که مقداری را بر میگردانند Query خوانده میشوند.

اگر قرار باشد هنگام خواندن یک Value وضعیت آن یا وضعیت Value دیگر تغییر کند میتواند یک نا هماهنگی در سیستم ایجاد کند که در نهایت منجر به باگ یا خطا شود.

اصل CQS با تکنیک CQRS از نظر مفهومی شباهت زیادی دارد . در CQS ما متدهای درون یک کلاس را جدا می کنیم اما در CQRS ساختار برنامه را جدا می کنیم که در نهایت ممکن است تا جدا شدن دیتابیس ها هم پیش رود.

باید توجه کنید که CQS یک اصل یا Principle در برنامه نویسی به حساب می آید و CQRS یک الگوی معماری است.
حاصل 2تا نصفه روز و رفتن با RazorPages شده پیدا کردن 2تا باگ ساده و بدیهی (که توی فیلم میتونین ببینین)
همینطوری ادامه بدم باگ های بیشتری هم پیدا میکنم احتمالا

چون خیلی سادس احتمالا قبلا issue هاش تو گیتهاب زده شده ولی بازم چک میکنم و اگه نبود گزارش میدم
تازه اینها باگ های بدیهی و مُبرهن هستند. در مورد ضعف ها و ایراداتش هم کلی میتونم توضیح بدم که اینجا جاش نیست.

نظر خودم: RazorPages یه مقدار (نه خیلی) ساده تره نسبت به MVC و مادامی که به کمبود هاش برنخورین و نیاز پیدا نکنین میتونه گزینه خوبی باشه ولی یه مقدار که نیازمندی هاتون پیچیده میشه ایرادات و کمبود های ساختاریش خودشو نشون میده و دیگه باید با راه حل های Workaround ایی ردش کنین.

خلاصه که قبل از اینکه خواستین RazorPages رو واسه پروژه تون انتخاب کنین بیشتر تحقیق کنین

ریپازیتوری گیتهاب برای Reproduce:
https://github.com/mjebrahimi/RazorPages_Bugs
______________
@DotNetZoom
DotNetZoom
حاصل 2تا نصفه روز و رفتن با RazorPages شده پیدا کردن 2تا باگ ساده و بدیهی (که توی فیلم میتونین ببینین) همینطوری ادامه بدم باگ های بیشتری هم پیدا میکنم احتمالا چون خیلی سادس احتمالا قبلا issue هاش تو گیتهاب زده شده ولی بازم چک میکنم و اگه نبود گزارش میدم تازه…
توضیحات تکمیلی:

مشکل دوم که مشخصا باگ هست و نیاز به توضیح نداره.
و اما توضیح علت اصلی مشکل اول (همون مورد TempData) یه مقدار طولانیه و اگه دقیق تر بخوایم بگیم اسمش رو نمیشه باگ گذاشت. این مشکل حتی توی مروگر FireFox رخ نمیده ولی توی Chrome و Edge رخ میده که دلیل منطقی خودش رو هم داره.
ریشه اصلی این مشکل بر میگرده به عملکرد پشت صحنه اتریبیوت [TempData] که باعث میشه این مشکل وجود بیاد.
خلاصه اش اینکه وقتی از Property به همراه اتریبیوت [TempData] استفاده میکنین. توی هر request مقدار TempData به صورت خودکار bind میشه به Property مربوطه (حتی اگه نخواین) و از اونجایی که مروگر های بر پایه کرومیوم مثل Chrome و Edge همراه با ریکوست به مسیر root سایت، یه ریکوئست دیگه هم به آدرس /favicon جهت پیدا کردن آیکون سایت میزنن این مشکل پیش میاد که request دومی باعث bind شدن خودکار مقدار TempData به Property مربوطه میشه که باعث "خوانده" شدن مقدار از TempData و درنتیجه حذف شدن مقدار اون میشه.
درواقع ما توی ریکوئست /favicon نیاز نداریم مقدار TempData خونده بشه ولی چون خودکار این کار رو برامون انجام میده باعث میشه مقدارش حذف بشه.
و این همون دلیلی هست که اگر از TempData["Message"] به جای اتریبیوت [TempData] استفاده کنیم این مشکل برامون پیش نمیاد. چون اون attribute دیگه وجود نداره که بخواد سرِخود اون مقدار رو read کنه
دستور Keep هم چون باعث میشه پس از خونده شدن سرِخود مقادیر، باز هم اونها رو نگه داره، میتونه این ایراد رو دور بزنه.

یه نکته دیگه اینه که توی MVC قدیم. طول عمر TempData فقط به اندازه "یک درخواست" دیگر بود یعنی توی درخواست اول مقدار رو ست میکردیم و توی درخواست دوم میتونستیم بخونیمش. حالا اگه نمیخوندیم هم مقدارش از دست میرفت و برای جلوگیری از این کار باید از Keep استفاده میکردیم
ولی توی MVC Core این طول عمر تغییر کرده و مادامی که مقدار از TempData "خوانده" نشه مقدارش حذف نمیشه. ولی به محض اینکه خوانده شد مقدارش حذف میشه. یعنی اگه توی 10 تا درخواست هم مقدار اون رو نخونید، باقی میمونه و حذف نمیشه
حالا با توجه به اینکه اتریبیوت [TempData] خودکار مقدار رو read میکنه. شما فقط توی "یک درخواست" بعدی میتونین مقدار رو استفاده کنین و اگرم استفاده نکردین، اون کاری به اینا نداره و حذفش میکنه. (و برای جلوگیری ازش هم باید از متد Keep استفاده کنین)
__________________
@DotNetZoom
Forwarded from DotNetZoom (محمد جواد ابراهیمی)
❇️ ساخت دیتابیس یکبار مصرف Mongo بدون نیاز به نصب آن!

کتابخانه Mongo2Go یه کتابخونه عالی برای Integration Testing پروژه هایی هست که از MongoDb استفاده میکنند

🔶 توسط این کتابخونه می تونین دیتابیس های MongoDb رو بدون نیاز به نصب اون به صورت یکبار مصرف ایجاد کنین، یعنی یه دیتابیس موقت (توی پوشه Temp سیستم عامل) براتون میسازه و در آخر وقتی کارتون باهاش تموم شد اون رو حذف میکنه. در نتیجه برای Integration Testing بسیار مناسب و کاربردی هست.

🔷 قاعدتا برای استفاده از مونگو باید ورژن متناسب با سیستم عاملتون رو نصب و کانفیگ کنین یا راحت تر اینکه اون رو توسط Docker راه اندازی کنین ولی توسط این کتابخونه دیگه نیازی به نصب اون ندارین چون فایل های باینری MonogDb رو داخل خودش داره (واسه همین یه مقدار حجمش زیاده، 69 مگابایت)

🔰طرز کار باهاش خیلی سادس فقط کافیه ناگتش رو نصب کنین
Install-Package Mongo2Go
و به صورت زیر ازش استفاده کنین
using (var runner = MongoDbRunner.Start())
{
var client = new MongoClient(runner.ConnectionString);
var database = client.GetDatabase("IntegrationTest");
var collection = database.GetCollection<TestDocument>("TestCollection");

//Just use it!
}

ریپازیتوری گیتهاب :
https://github.com/Mongo2Go/Mongo2Go
_________________
@DotNetZoom
Forwarded from کدهک
آموزش کار با CSS Isolation در ASP NET Core 6.0

https://youtu.be/kqdn7dzEyhk
freetalk
فری تاک
🔰گپ و گفت خودمونی و فان

توی این قسمت از #فری_تاک، من و حکیم و معین یه گپ و گفت خودنی و فان داریم
از سوتی هامون توی برنامه نویسی میگیم و ضرر هایی که بالا آوردیم
از تجربه های شکست و موفقیت هامون حرف میزنیم و...
و میگیم و میخندیم و شوخی میکنیم

این قسمت اولین قسمت از این سبک جدید هست که گپ و گفت های خودمونی و فان داریم.
گوش که دادین حتما فیدبک بدین که اگه دوس داشتین بیشتر از اینا بذاریم.
همیشه قرار نیس بحث فنی بکنیم، یه وقتایی هم لازمه بگیم و بخندیم و حال دلمون رو خوب کنیم. (این وسط یه تجربیاتی هم رد و بدل میکنیم)
خوش باشین :)
_________________
@DotNetZoom
🔰گپ و گفت خودمونی و فان

توی این قسمت از #فری_تاک، من و حکیم و معین یه گپ و گفت خودنی و فان داریم
از سوتی هامون توی برنامه نویسی میگیم و ضرر هایی که بالا آوردیم
از تجربه های شکست و موفقیت هامون حرف میزنیم و...
و میگیم و میخندیم و شوخی میکنیم

این قسمت اولین قسمت از این سبک جدید هست که گپ و گفت های خودمونی و فان داریم.
گوش که دادین حتما فیدبک بدین که اگه دوس داشتین بیشتر از اینا بذاریم.
همیشه قرار نیس بحث فنی بکنیم، یه وقتایی هم لازمه بگیم و بخندیم و حال دلمون رو خوب کنیم. (این وسط یه تجربیاتی هم رد و بدل میکنیم)
خوش باشین :)

لینک ویس ضبط شده:
https://news.1rj.ru/str/DotNetZoom/1236
_________________
@DotNetZoom
Forwarded from کدهک
مقایسه رفتار Thread Pool در متدهای Sync و Async

https://youtu.be/AdauMu7fpkI
آموزش Unit Testing با استفاده از NUnit و Moq بخش دوم: Mocking

در زمینه Unit Testing گاهی اوقات یک Unit یا کلاس وابستگی هایی دارد که مورد بررسی برای تست نیستند. همچنین Unit مورد نظر بدون داشتن این وابستگی ها نمیتواند کار کند. یکی از راه های حل این مشکل، شبیه سازی وابستگی های Unit یا کلاس است که به Mocking معروف می باشد. یکی از کتابخانه های بسیار کاربردی و معروف در زمینه Mocking ، کتابخانه Moq می باشد که در این مقاله قصد داریم به بررسی آن بپردازیم

#بابک_طارمی
https://vrgl.ir/BnMoW
_____________
@DotNetZoom
🔰 الان داشتم اینو سرچ میکردم میزارم اینجا هم آرشیو بشه هم شاید به دردتون بخوره
واسه Encode کردن URL راه های مختلفی تو دات نت وجود داره

HttpUtility.UrlPathEncode
HttpUtility.UrlEncode
WebUtility.UrlEncode
Uri.EscapeUriString
Uri.EscapeDataString

🔸داغون ترینشون اینه HttpUtility.UrlPathEncode
اصلا درست کار نمیکنه و خروجی رو خراب میکنه تو بعضی موارد. مثلا % و # رو encode نمیکنه
اینجا یه سری مواردش رو گفته
https://stackoverflow.com/a/1148326

🔹اینم یه سری مشکلات داره Uri.EscapeUriString و جدیدا deprecate شده
تو یه سری موارد خروجی رو خراب میکنه مثلا # رو encode نمیکنه
توضیحات بیشتر
https://stackoverflow.com/a/34189188

🔸این 2تا مثل هم رفتار میکنن و روششون اینطوریه که space رو به "+" تبدیل میکنن. فقط یه تفاوت کوچیک دارن
WebUtility.UrlEncode (حروف UpperCase تولید میکنه)
HttpUtility.UrlEncode (حروف LowerCase تولید میکنه)
🔹این 2تا مشکلی که دارن اینه که یه سری کاراکتر های «رزرو نشده» مثل "~" رو هم encode میکنن
توضیحات بیشتر
https://stackoverflow.com/a/47877559

بهترینشون هم که خروجی کاملا استاندارد تولید میکنه و هیچ کدوم از این مشکلات رو نداره اینه
Uri.EscapeDataString

توضیحات بیشتر
https://stackoverflow.com/questions/602642/server-urlencode-vs-httputility-urlencode/
____________________
@DotNetZoom
Forwarded from کدهک
نگاهی به قابلیت های جدید Visual Studio 2022


https://youtu.be/BYFuQaIJo-k
Forwarded from DotNetZoom (محمد جواد ابراهیمی)
نمایش تعداد کاربران آنلاین در AspNet Core

برای محاسبه تعداد کاربران آنلاین اساسا دو روش وجود داره

1️⃣ روش اول - با استفاده از Cookie

در ASP.NET قدیم داخل کلاس global.asax متد هایی وجود داشت به نام Session_Start و Session_End که به هنگام شروع و پایان "سشن" کاربری، فراخوانی میشدن (با شی Session اشتباه گرفته نشود)
رخداد Session_Start زمانی raise یا اجرا میشد که یک سشن جدید برای یک کاربر ساخته بشه
و رخداد Session_End نیز زمانی raise میشد که یک سشن expire (منقضی) بشه

🔰مکانیزمی که سشن کاربری رو ایجاد ومنقضی میکرد، مراحلش به این صورت بود که:

▪️اولین بار که شخصی سایت رو باز میکرد، خود ASP.NET یک کوکی به نام "ASP.NET_SessionD" با مقدار یک "کلید تصادفی" به همراه Response برای کاربر میفرستاد و اون در مرورگر کاربر ذخیره میشد و از اون طرف همین "کلید تصادفی" در حافظه مموری سرور (به کمک شی Session) به عنوان شناسه یک کاربر (که شاید هنوز نمیدونیم کیه ولی میدونیم یه کاربره) ذخیره میشد (تا اینجای کار یک سشن برای کاربر جدید ساخته شده، در نتیجه رخداد Session_Start فراخوانی میشد)

▪️از درخواست های بعدی، این کوکی به همراه مقدارش (همون کلید تصادفی)، به Server ارسال میشد سپس ASP.NET این کلید رو میخوند و با مقادیر ذخیره شده در شی Session (در حافظه رم) مطابقت میداد و متوجه میشد که این همون کاربری هست که قبلا درخواست زده بود.
تایم منقضی شدن این سشن ها (session expire) به صورت پیشفرض 20 دقیقه بود و مادامی که درخواست یا بازدید از سمت همون کاربر میومد، این مدت زمان تمدید میشد.
در نتیجه مادامی که آخرین درخواست کاربر کمتر از 20 دقیقه قبل بود، سشن برقرار بود و زمانی که این مدت از 20 بیشتر میشد. اون سشن به صورت خودکار expire/منقضی میشد (در این مرحله رخداد Session_End فراخوانی میشد)

🔸بنابراین مادامی که کاربر ما، فاصله بین هر درخواستش کمتر از 20 دقیقه بود، سشن اون کاربر برقرار بود و یک کاربر "آنلاین" به حساب میومد
و زمانی که از آخرین درخواست کاربر، بیش از 20 دقیقه میگذشت، سشن کاربر منقضی شده و یک کاربر "آفلاین" به حساب میومد
در این حالت با کمی کد نویسی میشد تعداد کاربران آنلاین رو محاسبه کرد، به این صورت که یک متغیر global برای تعداد کاربران آنلاین در نظر میگرفتیم و به هنگام Session_Start اون رو ++ (یکی اضافه) و به هنگام Session_End اون رو -- (یکی کم) میکردیم

نکته: این توضیحات حالت پیشفرض هست، در صورت تنظیم sessionState میتونه محل ذخیره سازی سشن و کوکی در سمت سرور و کلاینت متفاوت باشه (مثلا ذخیره شدن سشن ها درون یک دیتابیس SqlServer به جای Memory یا تنظیم شدن کلید تصادفی درون URL به جای کوکی) - توضیحات بیشتر

🔹در ASP.NET Core اما این مکانیزم و این دو متد دیگه وجود نداره. پس مجبوریم مشابه همین مکانیزم رو خودمون کدنویسی و طراحی کنیم. کد نویسیش کار خاصی نداره، همین مراحل ساخت کوکی با یک "کلید تصادفی" (مثلا guid) و ذخیره اون علاوه بر Response، درون یک InMemory Cache داخل یک Middleware به سادگی انجام میشه

🔸در این روش چون فاصله زمانی 20 دقیقه رو برای session expire هست در نتیجه همیشه ما یک تلورانس و اختلاف 20 دقیقه ای ممکنه داشته باشیم. اگر کاربر جاری همین الان مرورگرش رو میبنده یا برق میره چون session اش تا 20 دقیقه از آخرین بازدیدش معتبر هست، همچنان تا 20 دقیقه آینده "آنلاین" محسوب میشه

2️⃣ روش دوم - با استفاده از ارتباطات Realtime مانند SignalR

🔹این روش خیلی مشابه روش قبل هست با این تفاوت که به محض برقرار شدن اتصال کاربر (رخداد OnConnectedAsync کلاس Hub) اون رو به عنوان کاربر آنلاین و به محض قطع شدن ارتباطش (رخداد OnDisconnectedAsync کلاس Hub) اون کاربر رو آفلاین در نظر میگیریم.
بقیه موارد ساخت کلید تصادفی و تنظیم کوکی جهت تشخیص کاربر از بقیه کاربر ها تقریبا مشابه قبل هست

🔸مزیت این روش اینه که دیگه ما تلورانس و اختلاف 20 دقیقه رو نخواهیم داشت و به صورت آنی و در لحظه تعداد کاربران آنلاین بروزرسانی خواهد شد
معایبش هم اینه که به دلیل استفاده از ارتباطات realtime پردازش بیشتری نسبت به روش اول روی سرور میوفته و یا اینکه امکان استفاده از ارتباطات realtime در برنامه شما به هر دلیل از جمله زیرساخت network یا محدودیت های سرور و application شما وجود نداشته باشه

🔹نکته آخر اینکه در اینجا سعی کردم مکانیزم خیلی ساده توضیح بدم اما پیاده سازی صحیح چنین مکانیزمی با توجه به امکان وقوع همزمانی مستلزم اینه که نکات پیشگیری از مشکلات همزمانی رعایت بشه

🔰در اینجا یک پروژه نمونه آماده کردم که هر دو این روش ها رو پیاده سازی کرده و میتونین با بررسی سورس کدش بیشتر با نحوه عملکرد اون آشنا بشین
https://github.com/dotnetzoom/OnlineUsers-AspNetCore
_________
@DotNetZoom
Forwarded from کدهک
بررسی مکانیزم Garbage Collection با کمک ابزار پروفایل در ویژوال استودیو

https://youtu.be/2AxqmNTmC-s
تولید تگ های SEO در ASPNET Core با کتابخانه SeoTags

تگ های زیاد و متنوعی برای بهبود SEO سایت وجود دارند. از انواع meta و link گرفته تا تگ های تنظیم Twitter Card و Open Graph تا JSON-LD و Microdata برای Structred Data تا SiteMap و...
هرکدوم هم مسلما مقادیر خاص خودشون رو میپذیرن و بسته به شرایط و نوع محتوا متفاوت هستند.

کتابخانه SeoTags تمامی تگ های مهم و کاربردی رو براحتی برای وبسایت ASPNET Core ایی شما میسازه و حالت ها و تگ های زیادی هم پشتیبانی میکنه.

اینو کتابخونه رو تازگی نوشتم (در جهت راه اندازی سایت DotNetZoom) و به زودی تکمیل ترش هم میکنم.
شما هم اگه دوست داشتین توش مشارکت کنین، issue بزنین و pull request بفرستین

طریقه استفاده و نمونه خروجی تگ ها رو میتونین توی ریپازیتوری مشاهده کنین
https://github.com/mjebrahimi/SeoTags
___________________
@DotNetZoom
تصاویر پس زمینه Windows 11

دسکتاپ تون رو صفا بدین :)

https://www.windowsobserver.com/dwnld/38638/
_____________________
@DotNetZoom