مطالب
مروری بر پلاگین‌های چندسکویی مرورگرها
NPAPI
این عبارت مخفف Netscape Plugin Application Programming Interface هست و یک پلاگین چندسکویی است که بسیاری از مرورگرها از آن استفاده می‌کنند. معماری این پلاگین ابتدا در سال 1995 برای مرورگر netscape نسخه 2 آن توسعه پیدا کرد. ولی رفته رفته توسط دیگر مرورگرها هم استفاده و پیاده سازی شد و البته تعدادی هم بعدها استفاده از آن را رها کردند و از فناوری‌های دیگری استفاده کردند.
کار این پلاگین تعریف یک سری ContentType مانند audio/mp3 است و موقعی‌که مرورگر در رندر کردن این صفحات به چنین محتوایی برخورد کند، پلاگین مربوط به این محتوا را در حافظه بار می‌کند تا پلاگین را در حافظه رندر کرده و جابجایی داده‌ها با پلاگین صورت بگیرد. سپس آن پلاگین محتوای مربوطه را رندر می‌کند. امروزه پلاگین‌ها در همان قسمت از حافظه صفحه مرورگر بار می‌شوند و مانند مرورگرهای قدیمی مجبور به اجرای برنامه خارجی برای محتواهای ناشناخته نیستند.
این API نیاز دارد هر پلاگین تقریبا 15 تابع را پیاده سازی کند. این توابع برای پیاده سازی، ایجاد، نابودسازی آن و موقعیت مکانی آن به کار می‌روند. NPAPI همچنین امکاناتی از قبیل اسکریت نویسی، چاپ کردن، تمام صفحه شدن، پلاگین بدون پنجره، استریم کردن محتوا را نیز دارد.
مبداء و منشا ابتدایی این فناوری از شرکت Adobe و محصول Adobe Reader آن و خواندن PDF‌های تحت وب آغاز گشت. در آن زمان در وب، تنها فرمت HTML به همراه تصاویر به عنوان محتوا حساب میشد و مابقی نوع‌ها به دانلود ختم می‌شدند و شرکت ادوب قصد داشت کاربران تجربه‌ی جدیدی از خواندن فایل‌های PDF را بر روی مرورگر وب داشته باشند و برای دیدن حتما نیازی به دانلود نداشته باشند.
شرکت ادوب برای جلب نظر توسعه دهنگان netscape از یک نسخه‌ی دمو استفاده کرد و موقعی که روی لینک یک PDF کلیک میشد به جای دانلود آن، محتوا داخل صفحه مرورگر رندر میشد که مخلوطی از کدهای html و PDF بود ولی آن‌ها خواستار یک سیستم یکپارچه بودند تا دیگر مرورگر netscape درگیر آن نباشد و بدون وابستگی به مرورگر و به طور مستقل این کار انجام شود که کم کم باعث ایجاد این API شد و از آن موقع در طول این سال‌ها مرورگرهای زیادی از این فناوری استفاده کردند تا استاندارد عمومی در توسعه مرورگرها باشد.

عدم پشتیبانی گوگل از این پلاگین API
گوگل در سال 2013 عدم پشتیبانی از این API را در مرورگرش اعلام کرد که در این حالت پشتیبانی از تمامی فناوری‌های مرتبط آن نیز خاتمه میابد که شامل جاوا و سیلورلایت می‌شود و دلیل آن مسائل پایداری و امنیت آن در کنار سایر موارد است.

پشتیبانی از اسکریپت نویسی
این ویژگی اجازه میدهد که شما با استفاده از کدهای جاوااسکریپت، در صفحات وب با پلاگین تعامل کنید. ابتدا netscape این امکان را اضافه کرد و بعدها موزیلا این ویژگی را با استفاده از فناوری هایی چون Live Connect ،  XP Connect و npRuntime ارتقاء بخشید.

Live Connect
از netscape 4 به بعد NPAPI برای اسکریپت نویسی توسعه یافت. این ویژگی به مرورگرها اجازه میدهد که برنامه‌های نوشته شده با جاوا و جاوااسکریپت، با صفحات وب به تعامل بپردازند. به عنوان مثال اپلت نوشته شده با جاوا می‌تواند با کدهای داخل صفحه ارتباط برقرار کند یا بیشتر از خود اسکریت‌های صفحه با محیط جاوااسکریت داخلی ارتباط برقرار کند.  با این ویژگی یک پلاگین میتواند یک نمونه کلاس جاوا را پیاده سازی و بازگرداند. این کلاس میتواند از طریق جاوااسکریت یا اپلت‌های جاوا صدا زده شود.

XP Connect
ابتدا قبل از هر چیز بگذارید با XPCOM اشنا شویم. XPCOM یا Cross Platform Component Object Model از طرف شرکت موزیلا ارائه شده است و اصلی‌ترین ویژگی آن اتصال چندین زبان به یکدیگر از طریق IDL یا یک زبان واسط است. بدین ترتیب برنامه نویس‌ها میتوانستند کدهای اختصاصی خود را با دیگر کامپوننت‌ها مرتبط کنند.
حال کار xpconnect برقراری ارتباط بین جاوااسکریپت با XPCOM یا کدهای نوشته شده توسعه گران است. XP Connect به اشیاء جاوااسکریپتی اجازه می‌دهد به طور مستقیم به اشیاء XPCom دسترسی داشته و آن‌ها را دستکاری کنند.

NPRuntime
در پایان سال 2004 بسیاری از شرکت‌های اصلی ارائه کننده مرورگرهای وب که از NPAPI استفاده می‌کردند، به این توافق رسیدند که از فناوری NPRuntime به عنوان یک اکستنشن (افزونه) برای تامین اسکریپت نویسی NPAPI استفاده کنند. اسکریپت نویسی این فناوری مستقل از دیگر فناوری‌هایی چون جاوا و XPCOM است و توسط گوگل (در آن زمان)، فایرفاکس، سافاری و اپرا (در آن زمان)  پشتیبانی می‌شود.

PPAPI
این فناوری در 12 آگوست 2009 معرفی شد. Pepper Plugin API مجموعه ای از تغییرات و اصلاحات روی NPAPI است که باعث انعطاف پذیری و امنیت بیشتر می‌شود. این افزونه جهت پیاده سازی آسان اجرای پلاگین در یک پروسه‌ی جداگانه است. هدف این پروژه تهیه یک فریمورک برای ایجاد پلاگین‌های مستقل یا Cross-Platform میباشد.
تعدادی از مواردی که در طراحی این افزونه در نظر گرفته شده است:
  • اجرای جداگانه از پروسه‌ی مرورگر
  • تعریف رویدادهای استاندارد و رسم تصاویر دو بعدی
  • تهیه گرافیک سه بعدی
  • ریجستری پلاگین
  • استاندارد سازی برای استفاده از سیستم رندر مرورگر Compositing Process 
  • تعریف مفهوم یا معنای واحد از NPAPI بین تمامی مروگرها
مرورگرهایی که در حال حاضر به این افزونه روی آورده اند طبعا مرورگر کروم و اپرا از نسخه 24 به بعد است.
شرکت موزیلا در سال 2011 اعلام کرد که فعلا علاقه ای به شرکت در این پروژه ندارد.
شرکت ادوب برای افزونه flash player اعلام کرد که دیگر تنها بر روی PPAPI فعالیت می‌کنند و از آخرین نسخه فلش پلیر 11.2 که برای NPAPI ایجاد شده است تنها به مدت پنج سال بسته‌های آپدیت آن را در دسترس قرار میدهد.

ActiveX
یکی دیگر از این پلاگین‌ها ActiveX است که توسط IE مورد استفاده قرار می‌گیرد ولی در مرورگر Edge  حذف شده است. به این دلیل، پشتیبانی از جاوا در این مرورگر قطع شده است و فلش پلیر را به صورت ذاخلی Built-in پشتیبانی می‌کند. امروزه بسیاری از تولیدکنندگان اعتقاد دارند که با Html5 بسیاری از مسائل حل می‌شود.
نظرات مطالب
شروع کار با Apache Cordova در ویژوال استودیو #2
سلام.
کندی این فریمورک مربوط میشود به طبیعت خود تکنولوژی که در آن استفاده شده است.استفاده از  WebView به جای مرورگر هم باعث کاهش سرعت اجرای کد‌های جاوا اسکریپت خواهد شد. ولی حاد هم نیست  ،الان اگر این سایت  را مشاده کنید، بیشتر برنامه‌های چت و بازی، با استفاده از این فریمورک ساخته میشود. در مقابل شما لازم نیست لزوما با زبان بومی پلتفرم مورد نظر خود درگیر باشید. میتوانید از فریمورک‌های CSS , JS که الآن هم روز به روز بهینه‌تر و محبوبتر میشود ، استفاده کنید. اگر کارایی این فریمورک برای ساخت بازی‌ها کافی باشد  چرا باید برای ساخت اپلیکیشن‌های مورد نیاز ما بهینه نباشند.توجه کنید که این فریمورک ،وب اپلیکیشن ما را به زبان‌های بومی هر پلتفرم تبدیل نمی‌کند. زمانی که شما نیاز دارید به API‌های بومی سیستم عامل مورد نظری که دسترسی داشته باشید که برای آن امکان ساخت پلاگین وجود ندارد (در حال حاضر برای Calendar) در این صورت اگر برنامه شما نیاز به همچین امکانی دارد لذا نباید Cordova را انتخاب کنید.
بنده تا حالا سمت Android Studio نرفتم اصلا و صرفا به دلیل اینکه Cordova با فیلد من(وب) نزدیکی زیادی داشت سمت آن رفتم(یکی از مزایای آن)
در مقاله بعد در مورد این مبحث بیشتر تمرکز خواهیم کرد.
مطالب
پیاده سازی ماژولار Autofac
یکی از مشکلاتی که در برخی از طراحی‌هایی که تا کنون دیده‌ام وجود دارد، عدم استفاده از قابلیت ماژولار نویسی تنظیمات Autofac  و عدم استفاده از Interfaceها برای ارتباط بین قسمت‌های مختلف سیستم است. به این صورت که تمام تنظیمات مربوط به Autofac را در بالاترین لایه سمت سرور خود یعنی Service یا Web انجام می‌دهند که باعث می‌شود این لایه به تمامی لایه‌های پایین خود از جمله DataAccess دسترسی مستقیم داشته باشد. در یک سیستم بزرگ به دلایل بسیار از جمله حساسیت داده‌ها، مدیریت درست بر روی قسمت‌های مختلف و یکبار نویسی هر قسمت، بهتر است تمام تغییرات از فیلتر Business و بصورت مدیریت شده بر روی داده‌های ما صورت بپذیرد. در این نوع سیستم ما نمی‌توانیم دسترسی مستقیمی را به لایه DataAccess به تمام توسعه دهندگان بدهیم و امیدوار باشیم که کسی از آن استفاده نکند. برای رفع این مشکل می‌توانیم تنظیمات قسمت Autofac را در هر لایه بصورت جداگانه انجام دهیم. به اینصورت که لایه‌های پایین‌تر اطلاعات خود را تنها در اختیار لایه‌هایی که باید به آنها دسترسی داشته باشند، قرار می‌دهند و در نهایت با تجمیع این اطلاعات در بالاترین لایه می‌توانیم بصورت کنترل شدهی از آنها استفاده کنیم. دسترسی هر قسمت نیز تنها می‌تواند از طریق Interface هایی که در اختیار سایر قسمت‌ها گذاشته می‌شود صورت بپذیرد. به این صورت می‌توان از طریق Interfaceها دسترسی‌های کنترل شده‌ای را در اختیار سایر قسمتهایی که بصورت مستقیم یا غیر مستقیم به لایه مربوطه دسترسی دارند، قرار دهیم. در اینجا نکته دیگری را که باید در نظر بگیرید این است که هدف اصلی DI، حذف وابستگی‌های کامل و تبدیل آنها به وابستگی‌های محدود است و این عمل از طریق Interface‌ها صورت می‌پذیرد. پس قاعدتا نباید بی دلیل بصورت مستقیم از کلاسها استفاده شود، یا آنها را در اختیار سایر لایه‌ها قرار بدهیم. تمام ارتباطات می‌توانند از طریق Interface‌ها بصورت کاملا کنترل شده انجام بپذیرند.



طراحی لایه DataAccess

در این نوع طراحی، هر لایه تنها از طریق Interfaceها به لایه بالاتر از خودش سرویس می‌دهد و در مواردی که ما در نظر بگیریم، می‌توانیم به لایه‌های دیگر نیز دسترسی‌های غیر مستقیم و کنترل شده‌ای را بدهیم. بطور مثال هر کلاس Repository می‌تواند به‌صورت Internal تعریف شود؛ پس تنها در لایه DataAccess در دسترس است. برای دسترسی سایر لایه‌ها به Repository‌ها، هر Repository می‌تواند از یک IRepository (این Interface دسترسی خواندنی نوشتنی به کلاس Repository دارد) که در لایه DataAccess بصورت public تعریف شده و تنها در لایه Business قابل دسترس است و یک IRepositoryReadOnly (این Interface دسترسی فقط خواندنی به کلاس Repository دارد) که در قسمت Common تعریف شده، ارث ببرد. به این صورت همان طور که در شکل بالا نیز می‌بینید، دسترسی‌هایی که از بیرون به لایه DataAccess صورت می‌گیرد، به دو قسمت تقسیم می‌شوند: اول دسترسی کامل به IRepository که تنها از طریق Business صورت می‌پذیرد و دوم دسترسی از طریق IRepositoryReadOnly که می‌تواند از هر جایی در سیستم که به قسمت Common دسترسی دارد صورت بپذیرد (البته استفاده از IRepositoryReadOnly به سیاست‌هایی که شما در نظر می‌گیرید بستگی دارد). با این کار مطمئن می‌شوید که تغییرات تنها می‌توانند از طریق Business صورت بپذیرند. همچنین حتی در صورتیکه نیاز بدانید، یک دسترسی فقط خواندنی را نیز به توسعه دهندگان سایر قسمت‌ها داده‌اید.

حال با توجه به توضیحات فوق، تنظیمات مربوط به Autofac را در لایه DataAccess انجام می‌دهیم.


طراحی تنظیمات Autofac در لایه DataAccess

public class DataAccessSetupDependency : Autofac.Module
    {
        protected override void Load(ContainerBuilder builder)
        {
            base.Load(builder);
            builder.RegisterType<EFContext>().As<IDbContext>();
            builder.RegisterType<UnitOfWork>().As<IUnitOfWork>();
            builder.RegisterAssemblyTypes(Assembly.GetExecutingAssembly())
             .Where(x => x.Namespace.EndsWith("Repositories"))
             .AsImplementedInterfaces();
        }
    }
همانطور که می‌بینید در این قسمت تنها تنظیمات وابستگی‌های لایه DataAccess در ماژول DataAccessSetupDependency انجام شده‌است.


طراحی لایه Business

در لایه Business نیز دسترسی‌های خود را تنها از طریق Interface هایی که کلاسهای Business از آنها ارث برده‌اند و آنها را پیاده سازی کرده‌اند، به قسمت Web می‌دهید.

طراحی تنظیمات Autofac در لایه Business

public class BusinessSetupDependency : Autofac.Module
    {
        protected override void Load(ContainerBuilder builder)
        {
            base.Load(builder);

            builder.RegisterAssemblyModules(typeof(SqlServerDataAccess.SetupDependencies.DataAccessSetupDependency).Assembly);

            //builder.RegisterAssemblyModules(typeof(CassandraDataAccess.SetupDependecies.SetupDependency).Assembly);

            builder.RegisterAssemblyTypes(Assembly.GetExecutingAssembly())
           .Where(x => x.Namespace.EndsWith("Business.Core"))
           .AsImplementedInterfaces();

            builder.RegisterAssemblyTypes(Assembly.GetExecutingAssembly())
            .Where(x => x.Namespace.EndsWith("Business.Businesses"))
            .AsImplementedInterfaces();
        }
    }
 همانطور که می‌بینید در ماژول BusinessSetupDependency ابتدا تنظیمات وابستگی‌های موجود در لایه DataAccess بدست آمده و در ادامه سایر تنظیمات موجود در لایه Business انجام شده‌اند.


طراحی لایه Web

جمع بندی تمام تنظیمات Autofac در لایه Web

public class WebSetupDependency : Autofac.Module
    {
        protected override void Load(ContainerBuilder builder)
        {
            base.Load(builder);
            builder.RegisterAssemblyModules(typeof(Business.SetupDependencies.BusinessSetupDependency).Assembly);
            builder.RegisterControllers(Assembly.GetExecutingAssembly());
            //سایر تنظیمات
            var container = builder.Build();
            CommonDependencyResolver.SetContainer(container);
            DependencyResolver.SetResolver(new AutofacDependencyResolver(container));

        }
    }
 public class AutofacConfig
    {
        public static void SetupContainer()
        {
             var builder = new ContainerBuilder();
            builder.RegisterAssemblyModules(Assembly.GetExecutingAssembly());
            var container = builder.Build();
            CommonDependencyResolver.SetContainer(container);
            DependencyResolver.SetResolver(new AutofacDependencyResolver(container));
        }
    }
ماژول WebSetupDependency در واقع جمع بندی از تمام وابستگی‌های لایه‌های موجود در سیستم است. بصورتیکه ابتدا تنظیمات وابستگی‌های لایه Business که خود شامل تنظیمات وابستگی‌های لایه DataAccess نیز هست، بدست می‌آیند و سپس لایه Web تنظیمات مرتبط با خودش را بر روی آنها اعمال می‌کند.

همچنین کلاس AutofacConfig مسئول جمع بندی تمام ماژول‌ها و ایجاد Container آنهاست و سپس این Container را در DependencyResolver  ثبت می‌کند. نکته‌ای را که باید در اینجا در نظر بگیرید، CommonDependencyResolver است که مسئول ثبت Container در قسمت Common است. به این صورت دیگر تنها لایه‌ای که به Container دسترسی دارد، لایه Web نیست. در واقع با ثبت Container در قسمت Common شما دسترسی کنترل شده‌ای را از Container به سایر لایه‌های سیستم  داده‌اید و در این حالت در صورتیکه لایه‌های دیگر مانند DataAccess یا Business به Container نیاز پیدا کنند، می‌توانند از طریق CommonDependencyResolver این دسترسی را داشته باشند.


جمع بندی

با طراحی ماژولار تنظیمات Autofac و استفاده از Interface‌ها برای ارتباط با دیگر قسمتها، دیگر نیازی نیست دسترسی‌های بی‌موردی از یک لایه را  به سایر قسمت‌ها داد و دیگر نیازی نیست شما نگران این باشید که ممکن است یکی  از توسعه دهندگان به‌دلایلی مانند کم تجربگی، کاری را خارج از زیرساختی که شما یا گروه پیاده سازی زیرساخت، پیاده سازی کرده‌اید انجام دهد. همه چیز آنطور که شما می‌خواهید و برنامه ریزی کرده‌اید، انجام می‌شود.
اشتراک‌ها
استفاده از Docker با برنامه‌های دات نت

Docker lets you build and run apps, more quickly, with less hardware. That’s why application container technology (and Docker in particular) is so popular. You can run hundreds of containers on a server which could only run a handful of VMs, and containers are fast to deploy and can be versioned like the software they run. 

استفاده از Docker با برنامه‌های دات نت
مطالب
طرحبندی صفحات وب با بوت استرپ 4 - قسمت اول
یکی از مفیدترین قسمت‌های بوت استرپ 4، سیستم طرحبندی و گرید آن است که در ابتدا با یک Container آغاز می‌شود. این Container می‌تواند واکنشگرا و با عرض ثابت باشد و یا fluid انتخاب شود که کل عرض صفحه را به خود اختصاص می‌دهد. داخل هر Container می‌توان ستون‌ها و ردیف‌هایی را تعریف کرد. بوت استرپ 4، یک گرید طرحبندی 12 ستونه را ارائه می‌دهد که برای اندازه‌های زیر، تعدادی break-point را تعریف کرده‌است:
extra small, small, medium, large, extra large
در این نگارش، break-point از نوع extra small، نسبت به نگارش سوم بوت استرپ، جدید است.
به این ترتیب این گرید به شدت انعطاف پذیر شده و می‌توان برای اندازه‌های مختلف صفحه، طرحبندی‌های متفاوتی را ارائه داد.


دربرگیرنده‌ها و ردیف‌های گرید بوت استرپ

گرید طرحبندی بوت استرپ 4، 12 ستونه است و از فناوری خاصی به نام Flexbox استفاده می‌کند. برای کار با آن نیاز است با دو عنصر اصلی زیر آشنا بود:
- Containers: هدف آن‌ها تنظیم طرحبندی، مطابق با break-point (های) خاصی می‌باشد.
- ردیف‌ها و ستون‌ها: طرحبندی اصلی را تشکیل می‌دهند و ردیف‌ها، تعریف ستون‌ها را میسر می‌کنند.


بررسی Grid Containers

در بوت استرپ 4، دو نوع Container با کلاس‌های زیر وجود دارند:
- container: یک دربرگیرنده‌ی متداول است و طرحبندی را در میانه‌ی صفحه و بر اساس break-point (های) خاصی نمایش می‌دهد. این دربرگیرنده، در اطرف آن یک padding با اندازه‌ی 15px را نیز به همراه دارد و با break-pointهای زیر خودش را تطبیق می‌دهد:
extra small: کمتر از 576px
small: بیشتر از 576px
medium: بیشتر از 768px
large: بیشتر از 992px
extra-large: بیشتر از 1200px

- container-fluid: این دربرگیرنده، کل عرض نمایشی صفحه را پوشش می‌دهد.


یک مثال: تعریف container، row و columns

<head>
    <style>
        img {
          width: 100px;
          display: block;
        }
      </style>
</head>

<body>
    <header class="clearfix" style="height: 50vh; background: url(images/background.jpg) no-repeat center center; background-size: cover; margin-bottom: 20px;">
        <div class="container">
            <img src="images/wisdompetlogo.svg" alt="Wisdom Pet Logo">
        </div>
    </header>

    <div class="container">
        <section id="services">
            <div class="row">
                <article class="col">
                    <img class="mx-auto" src="images/icon-exoticpets.svg" alt="Icon">
                    <h3>Exotic Pets</h3>
                    <p>We offer specialized care for reptiles, rodents, birds,
                        and other exotic pets.</p>
                </article>

                <article class="col">
                    <img class="mx-auto" src="images/icon-grooming.svg" alt="Icon">
                    <h3>Grooming</h3>
                    <p>Our therapeutic grooming treatments help battle fleas,
                        allergic dermatitis, and other challenging skin
                        conditions.</p>
                </article>

                <article class="col">
                    <img class="mx-auto" src="images/icon-health.svg" alt="Icon">
                    <h3>General Health</h3>
                    <p>Wellness and senior exams, ultrasound, x-ray, and dental
                        cleanings are just a few of our general health
                        services.</p>
                </article>

                <article class="col">
                    <img class="mx-auto" src="images/icon-nutrition.svg" alt="Icon">
                    <h3>Nutrition</h3>
                    <p>Let our nutrition experts review your pet's diet and
                        prescribe a custom nutrition plan for optimum health
                        and disease prevention.</p>
                </article>

                <article class="col">
                    <img class="mx-auto" src="images/icon-pestcontrol.svg" alt="Icon">
                    <h3>Pest Control</h3>
                    <p>We offer the latest advances in safe and effective
                        prevention and treatment of fleas, ticks, worms, heart
                        worm, and other parasites.</p>
                </article>

                <article class="col">
                    <img class="mx-auto" src="images/icon-vaccinations.svg" alt="Icon">
                    <h3>Vaccinations</h3>
                    <p>Our veterinarians are experienced in modern vaccination
                        protocols that prevent many of the deadliest diseases
                        in pets.</p>
                </article>
            </div>
        </section>
    </div>
</body>
با این خروجی:


توضیحات:
- برای آزمایش این مثال، ابتدا کلاس container آن‌را حذف کنید:
<div class="container">
مشاهده خواهید کرد که کل صفحه بجای نمایش در وسط آن، از سمت چپ و بدون هیچ فاصله‌ای شروع می‌شود. این کلاس container است که محتوا را به میانه‌ی صفحه با فواصلی معین از دو طرف، منتقل می‌کند. به همین جهت عنصرheader  ابتدای آن‌را داخل این container قرار نداده‌ایم تا کل عرض صفحه را پر کند. مقدار height: 50vh، به معنای استفاده‌ی از 50 درصد view-port height است.
اما چون می‌خواهیم محل قرارگیری لوگوی داخل این هدر، با حاشیه‌ی سمت چپ container ذیل آن یکی باشد، این logo را داخل container قرار داده‌ایم.
- از این جهت که تصاویر استفاده شده از نوع svg هستند و بسیار بزرگ می‌باشند، با style تعریف شده‌ی در ابتدای head، اندازه‌ی آن‌ها را کاهش داده‌ایم و همچنین نوع نمایشی آن‌ها را نیز به block تنظیم کرده‌ایم. در این حالت برای اینکه تصاویر در میانه‌ی این block قرار گیرند، از کلاس mx-auto استفاده شده‌است.
- در مرحله‌ی بعد، کار تعریف سطرها و ستون‌ها انجام شده‌است:
    <div class="container">
        <section id="services">
            <div class="row">
                <article class="col">
هر row باید داخل container قرار گیرد. سپس داخل آن می‌توان 12 ستون را تعریف کرد که در اینجا از کلاس col برای این منظور استفاده شده‌است. col ساده‌ترین نوع ستون در بوت استرپ 4 است. کار آن این است که محتوا را تا جائیکه می‌تواند در فضای مهیا نمایش دهد.


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


انواع ستون‌های طرحبندی در بوت استرپ 4

همانطور که عنوان شد، گرید بوت استرپ 4، دارای 12 ستون است. البته در اینجا یک ستون می‌تواند عرض چندین ستون را نیز به خود اختصاص دهد.

در این تصویر، فرمول تعریف کلاس‌های ستون‌ها را در بوت استرپ 4 مشاهده می‌کنید. هر قسمتی از این فرمول که داخل پرانتز قرار گرفته‌است، یعنی ذکر آن اختیاری می‌باشد؛ به همین جهت در مثال قبلی، ذکر صرفا col نیز کار کرد. در این حالت اگر دو ستون را تعریف کنید، هر کدام 50 درصد عرض container را به خود اختصاص می‌دهند و اگر سه ستون تعریف شود، هر کدام 33 درصد عرض را اشغال می‌کنند.
در این فرمول BP به معنای break-point است و یکی از مقادیر ذکر شده‌ی مقابل آن‌را می‌تواند داشته باشد. برای مثال اگر col-sm را تعریف کردیم، یعنی این ستون تا زمانیکه اندازه‌ی صفحه تا 576px باشد، کل عرض صفحه را پر می‌کند.
COL در اینجا به معنای تعداد ستونی است که این محتوا قرار است به خود اختصاص دهد. برای مثال col-md-6 یعنی این ستون تا رسیدن به break-point از نوع md، کل عرض صفحه را به خود اختصاص می‌دهد؛ پس از آن (اندازه‌ی صفحه‌ی بیشتر از 768px) این ستون، 6 واحد از 12 واحد ممکن را به خود اختصاص خواهد داد.
ذکر BP نیز اختیاری است. یعنی اگر تنها col-6 را تعریف کردیم، این ستون در تمام break-pointها و در تمام اندازه‌های ممکن صفحه، همواره 6 واحد از 12 واحد موجود را به خود اختصاص می‌دهد.

مثال: بررسی فرمول تعریف ستون‌ها در بوت استرپ 4

<head>
    <style>
        img {
              width: 100%;
              height: 200px;
              max-height: 200px;
            }
    </style>
</head>

<body>
    <div class="container">
        <div id="services">
            <div class="row">
                <section class="col">
                    <img src="images/image.png" alt="sample image">
                    <h4>Exotic Pets</h4>
                    <p>We offer <strong>specialized</strong> care for <em>reptiles,
                            rodents, birds,</em> and other exotic pets.</p>
                </section>
                <section class="col">
                    <img src="images/image.png" alt="sample image">
                    <h4>Grooming</h4>
                    <p>Our therapeutic <span class="font-weight-bold">grooming</span>
                        treatments help battle fleas, allergic dermatitis, and
                        other challenging skin conditions.</p>
                </section>
                <section class="col">
                    <img src="images/image.png" alt="sample image">
                    <h4>General Health</h4>
                    <p>Wellness and senior exams, ultrasound, x-ray, and dental
                        cleanings are just a few of our general health
                        services.</p>
                </section>
                <section class="col">
                    <img class="img-fluid" src="images/image.png" alt="sample image">
                    <h4>Nutrition</h4>
                    <p>Let our nutrition experts review your pet's diet and
                        prescribe a custom nutrition plan for optimum health
                        and
                        disease prevention.</p>
                </section>
                <section class="col">
                    <img src="images/image.png" alt="sample image">
                    <h4>Pest Control</h4>
                    <p>We offer the latest advances in safe and effective
                        prevention and treatment of fleas, ticks, worms, heart
                        worm, and other parasites.</p>
                </section>
                <section class="col">
                    <img src="images/image.png" alt="sample image">
                    <h4>Vaccinations</h4>
                    <p>Our veterinarians are experienced in modern vaccination
                        protocols that prevent many of the deadliest diseases
                        in
                        pets.</p>
                </section>
            </div>
        </div>
    </div>
</body>
- ابتدا یک container تعریف شده‌است تا محتوا را به میانه‌ی صفحه منتقل کند و همچنین شیوه‌نامه‌های پیش‌فرض بوت استرپ را به آن اعمال نماید.
- سپس کل محتوا را داخل یک ردیف تعریف کرده‌ایم.
- در ادامه هر المان section تعریف شده را به صورت یک col در آورده‌ایم. به این ترتیب بوت استرپ سعی می‌کند تا کل عرض را با ستون‌های تعریف شده تا جائیکه ممکن است پر کند:


و اگر عرض صفحه را کوچک‌تر کنیم، باز هم تاجائیکه ممکن است تعدادی را در سطر اول و مابقی را در سطرهای بعدی جا خواهد داد:


در ادامه می‌خواهیم مشخص کنیم، ستون‌های خاصی، همیشه عرض مشخصی را به خود اختصاص دهند:
    <div class="container">
        <div id="services">
            <div class="row">
                <section class="col-6">
با این خروجی:


در این حالت، اولین ستون تعریف شده، تحت هر حالتی و با هر اندازه‌ی صفحه‌ای، همیشه نصف عرض (6 واحد از 12 واحد) را به خود اختصاص خواهد داد.

مرحله‌ی بعد این است که مشخص کنیم یک ستون در چه اندازه‌ای از صفحه شروع کند به اختصاص دادن عرضی خاص به خود. برای این منظور هر 6 عنصر section تعریف شده را به صورت زیر ویرایش می‌کنیم:
<section class="col-sm">
در این حالت اگر اندازه‌ی صفحه کمتر از این break-point باشد، هر ستون، کل عرض صفحه را به خود اختصاص می‌دهد:


و اگر صفحه را بزرگتر کنیم، مجددا همان حالت تعریف col خالی تکرار می‌شود و بوت استرپ سعی می‌کند در هر سطر، تا جائیکه می‌تواند، تعداد آیتم بیشتری را جا دهد. اگر بخواهیم این تعداد جا دادن‌ها را نیز کنترل کنیم، می‌توان به صورت زیر عمل کرد:
<section class="col-sm-6">
در اینجا col-sm-6 را به هر المان section انتساب داده‌ایم. به این ترتیب باز هم اگر عرض صفحه کمتر از sm باشد، هر آیتم، کل عرض صفحه را به خود اختصاص می‌دهد. اما اگر اندازه‌ی صفحه بیشتر از sm شود، هر آیتم همواره 6 واحد، یا نیمی از عرض را به خود اختصاص خواهد داد:



امکان تعریف بیش از یک break-point برای هر ستون در بوت استرپ 4


در این جدول انواع break-pointهای قابل تعریف توسط بوت استرپ 4 را ملاحظه می‌کنید. تا اینجا تاثیر اعمال تنها یکی از این‌ها را بر روی یک ستون بررسی کردیم؛ اما می‌توان چندین break-point را بر روی یک ستون نیز اعمال کرد. برای مثال اگر به تمام sectionهای مثال این قسمت ترکیب زیر را اضافه کنیم:
<section class="col-sm-6 col-md-4">
به این معنا خواهد بود که تا زمانیکه عرض صفحه کمتر از 576px است (sm)، هر آیتم کل عرض صفحه را پوشش می‌دهد. زمانیکه از این break-point رد شدیم، هر آیتم 6 واحد از 12 واحد را به خود اختصاص خواهد داد؛ تا زمانیکه عرض صفحه کمتر از 768px است (md). پس از اینکه این break-point را نیز رد کردیم و اندازه‌ی صفحه بزرگتر از آن شد، اینبار هر آیتم، 4 واحد از 12 واحد را به خود اختصاص می‌دهد:



امکان تغییر موقعیت شروع ستون‌ها در بوت استرپ 4


در تصویر فوق، فرمول تغییر موقعیت شروع ستون‌ها در بوت استرپ 4 را مشاهده می‌کنید. برای مثال اگر offset-sm-1 را به اولین section اضافه کنیم:
<section class="col-sm-6 col-md-4 offset-sm-1">
پس از رد شدن از break-point تعریف شده‌ی sm، اولین section، به اندازه‌ی یک واحد به سمت راست منتقل می‌شود و از لبه‌ی سمت چپ فاصله پیدا می‌کند:


برای نمونه این قابلیت، پیشتر یکی از روش‌های در مرکز صفحه قرار دادن ستون‌ها بود؛ اما چون بوت استرپ 4 از Flexbox استفاده می‌کند، روش‌های بهتری نیز برای آن وجود دارند که آن‌ها را در قسمت‌های بعد بررسی می‌کنیم.



کدهای کامل این قسمت را از اینجا می‌توانید دریافت کنید: Bootstrap4_04.zip
مطالب
پیاده سازی Load Balancing در Nginx

زمانیکه تعداد کاربران سایت بیشتر میشود و ترافیک سایت افزایش می‌یابد عموما یک نمونه ( instance ) از برنامه نمیتواند پاسخگوی همه درخواست‌ها باشد و مجبور هستیم چندین نمونه برنامه را بر روی چند سرور اجرا کنیم. با این حال نیازمند یک وب سرور هستیم که درخواست‌های ارسال شده را در بین instance های موجود پخش کند. با انجام این کار تعداد ریکوئست‌ها در بین instance ها تقسیم میشوند. برای انجام اینکار میتوانیم از nginx استفاده کنیم. nginx قابلیت load balancing را دارد. برای پیاده سازی load balancing در nginx باید در فایل nginx.conf یک گروه از نوع upstream ایجاد کنید در کانتکست http.
http {
    upstream backend {
        server backend1.example.com;
        server backend2.example.com;
        server backend3.example.com;
    }
}
در کانفیگ بالا یک گروه به نام backend ایجاد کرده‌ایم که شامل سه سرور می‌باشد. یعنی سه instance از برنامه در حال اجرا هستند و میتوانیم ریکوئست‌های ارسال شده را بر روی این سرور‌ها ارسال کنیم. سپس باید در کانتکس server ( این کانتکست هم درون کانتکست http قرار دارد ) یک بلاک از نوع location ایجاد کنیم. بعد از کلمه location باید مسیری را که درخواست‌ها به آن ارسال میشوند را بنویسید که در مثال پایین همان روت وب سایت نوشته شده است ( / ). نوشتن / بعد از location تمامی درخواست‌ها را شامل میشود. همچنین میتوانید فقط درخواست‌هایی را که به api ها ارسال میشوند، فیلتر کنید که میتوانید به جای / از api/ استفاده کنید. با این کار تمامی درخواست‌هایی که url آنها با api/ شروع شود وارد بلاک location میشوند.
سپس برای ارسال کردن درخواست‌ها در بین برنامه‌های در حال اجرا باید از proxy_pass استفاده کنیم. بعد از کلمه proxy_pass باید نام upstream ی را که در بالا نوشته‌ایم، وارد کنیم. با انجام اینکار تمامی درخواست‌های ارسال شده به / در بین سرور‌های backend پخش میشوند.
http {
    upstream backend {
        server backend1.example.com;
        server backend2.example.com;
        server backend3.example.com;
    }
    
    server {
        location / {
            proxy_pass http://backend;
        }
    }
}
وب سرور nginx به طور پیشفرض از الگوریتم Round robin برای پخش کردن درخواست‌ها در بین سرور‌ها استفاده میکند. البته میتوانیم این الگوریتم را تغییر بدهیم. به طور مثال میتوانیم مشخص کنیم که به هرکدام از سرور‌ها چند درخواست ارسال شود.
با افزودن weight در کنار نام سرور‌ها مشخص میکنم که به طور مثال اگر 7 درخواست به سرور ارسال شود، 5 مورد به backend1 ارسال میشود و 2 مورد به backend2. همچنین میتوانیم مشخص کنیم که یک سرور به عنوان سرور backup باشد مانند backend4.
اگر سروری در دسترس نباشد میتوانید با اضافه کردن کلمه down بعد از نام سرور، از ارسال درخواست به آن جلوگیری کنید؛ مانند backend3 و یا قبل از کلمه server یک علامت # قرار دهید.
    upstream backend {
        server backend1.example.com weight=5;
        server backend2.example.com weight=2;
        server backend3.example.com down;
        server backend4.example.com backup;
    }
با انجام این کار سرور backend4 به عنوان سرور backup معرفی شده است و تا زمانیکه ما بقی سرورها در دسترس باشند، هیچ ریکوئستی به سرور backend4 ارسال نمیشود. اگر تمامی سرور‌های backend1 و backend2 از دسترس خارج شوند، آنگاه nginx درخواست‌های ارسال شده را به سرور backup یعنی backend4 ارسال میکند. البته به طور پیشفرض nginx سلامت سرورها را بررسی نمیکند و باید یک سری تنظیمات مربوط به health_check را ثبت کنیم. با اضافه کردن دستور health_check در پایین proxy_pass وب سرور nginx هر 5 ثانیه یک بار یک ریکوئست را به سرورهای backend ارسال میکند و اگر هرکدام از سرور‌ها ریسپانس کدی خارج از کدهای 200 تا 399 را ارسال کنند، درخواست‌های بعدی را به آن سرورها ارسال نمیکند.
server {
    location / {
        proxy_pass   http://backend;
        health_check;
    }
}
در کنار دستور health_check میتوانیم یک سری پارامتر را هم مشخص کنیم. به طور مثال میتوانیم مشخص کنیم که درخواست health_check را به چه uri ای ارسال کند و یا به چه پورتی درخواست را ارسال کند.
server {
    location / {
        proxy_pass   http://backend;
        health_check port=8080;
       #health_check uri=/healthcheck;
    }
}
(برای کامنت کردن یک دستور از # استفاده میشود).
همچنین میتوانیم یک درخواست سفارشی را برای مشخص کردن health_check ایجاد کنیم:
http {
    #...
    match welcome {
        status 200;
        header Content-Type = text/html;
        body ~ "Welcome to nginx!";
    }
    server {
        #...
        location / {
            proxy_pass http://backend;
            health_check match=welcome;
        }
    }
}
در کانفیگ بالا مشخص کرده‌ایم که برای نشان دادن در دسترس بودن هرکدام از سرورها باید استتوس کد 200 برگردانده شود و body دریافت شده حاوی !Welcome to nginx باشد.
نکته : match و health_check در نسخه تجاری nginx قابل استفاده می‌باشند.