اشتراک‌ها
درس هایی که من از کار با نرم افزار hotjar گرفتم
همیشه مشکل و چالش بسیار زیادی که ما در سیستم‌های نرم افزاری با آن مواجه میشم، عدم درک مشتری و نیاز مشتری است و اینکه واقعا چه کسی درست می‌گوید؟ اینکه برخی از مهندسان از عدم درک مشتری شکایت میکنند و مشتری که سیستم را خراب اعلام میکند. در واقع مشکل و چالش‌ها بسیار کوچک هستند و این ما هستیم که آن‌ها را به خاطر شبه مساله‌های زندگی، کاری و محیطی بزرگ می‌کنیم. نرم افزار hotjar.com  به شما این امکان رو میدهد که از فرایند کارکردن مشتری فیلم بگیرید و کار شما رو به عنوان کسی که نرم افزار رو آزمایشی لانچ کردید بهتر و بهتر کند. مثلا من دیدم که در نسخه موبایل در سیستم عامل اندروید که ماشالله هر کدوم از مرورگرهاش هم یک داستانی دارند:
1- دکمه ثبت غیب شده یا رفته پایین صفحه
2- فرایند و حرکت ماوس کاربر چقدر گیج کننده است
3- دکمه افزودن به سبد خرید پررنگ بشه که کاربر ببیند
4-در موبایل اگر کاربر ثبت نام کند، کپچا را اشتباه وارد کند دکمه ثبت نام غیب میشه و دیگر کار نمیکند
و بسیاری مشکلاتی بسیار ریز ولی به نظر کارفرما خیلی بزرگ است چون کار نمیکند. جمله ایی که میشنوید همین است. این موضوع، این گزینه هایی  است که بسیار ساده است ولی برای کاربر اعصاب خورد کن و حوصله سربر.که ما وقتی آنها را برطرف میکنیم فقط خوشحالیم و از کدنویسی لذت می‌بریم و لازم هم نیست با کارفرما توی سر هم بکوبیم.
 
این صفحه اسکرین شات نرم افزار هست که گزینه‌های ضبط فیلم، قابلیت کار در تیم و ... رو میدهد. همیشه فیدبک گرفتن توی کار، و اون مسیر رو هی بهتر و بهتر کردن، باعث افزایش سرعت و کارایی نرم افزارهای ما میشود.
درس هایی که من از کار با نرم افزار hotjar گرفتم
مطالب
Roslyn #1
معرفی Roslyn

سکوی کامپایلر دات نت یا Roslyn (با تلفظ «رازلین») بازنویسی مجدد کامپایلرهای VB.NET و #C توسط همین زبان‌ها است. این سکوی کامپایلر به همراه یک سری کتابخانه و اسمبلی ارائه می‌شود که امکان آنالیز زبان‌های مدیریت شده را به صورت مستقل و یا یکپارچه‌ی با ویژوال استودیو، فراهم می‌کنند. برای نمونه در VS.NET 2015 تمام سرویس‌های زبان‌های موجود، با Roslyn API جایگزین و بازنویسی شده‌اند. نمونه‌هایی از این سرویس‌های زبان‌ها، شامل  Intellisense و مرور کدها مانند go to references and definitions، به همراه امکانات Refactoring می‌شوند. به علاوه به کمک Roslyn می‌توان یک کامپایلر و ابزارهای مرتبط با آن، مانند FxCop را تولید کرد و یا در نهایت یک فایل اسمبلی نهایی را از آن تحویل گرفت.


چرا مایکروسافت Roslyn را تولید کرد؟

پیش از پروژه‌ی Roslyn، کامپایلرهای VB.NET و #C با زبان ++C نوشته شده بودند؛ از این جهت که در اواخر دهه‌ی 90 که کار تولید سکوی دات نت در حال انجام بود، هنوز امکانات کافی برای نوشتن این کامپایلرها با زبان‌های مدیریت شده وجود نداشت و همچنین زبان محبوب کامپایلر نویسی در آن دوران نیز ++C بود. این انتخاب در دراز مدت مشکلاتی مانند کاهش انعطاف پذیری و productivity تیم کامپایلر نویس را با افزایش تعداد سطرهای کامپایلر نوشته شده به همراه داشت و افزودن ویژگی‌های جدید را به زبان‌های VB.NET و #C سخت‌تر و سخت‌تر کرده بود. همچنین در اینجا برنامه نویس‌های تیم کامپایلر مدام مجبور بودند که بین زبان‌های مدیریت شده و مدیریت نشده سوئیچ کنند و امکان استفاده‌ی همزمان از زبان‌هایی را که در حال توسعه‌ی آن هستند، نداشتند.
این مسایل سبب شدند تا در طی بیش از یک دهه، چندین نوع کامپایلر از صفر نوشته شوند:
- کامپایلرهای خط فرمانی مانند csc.exe و vbc.exe
- کامپایلر پشت صحنه‌ی ویژوال استودیو (برای مثال کشیدن یک خط قرمز زیر مشکلات دستوری موجود)
- کامپایلر snippet‌ها در immediate window ویژوال استودیو

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

با توجه به این مسایل، مایکروسافت از بازنویسی سکوی کامپایلر دات نت این اهداف را دنبال می‌کند:
- بالا بردن سرعت افزودن قابلیت‌های جدید به زبان‌های موجود
- سبک کردن حجم کاری کامپایلر نویسی و کاهش تعداد آن‌ها به یک مورد
- بالا بردن دسترسی پذیری به API کامپایلرها
برای مثال اکنون برنامه نویس‌ها بجای اینکه یک فایل cs را به کامپایلر csc.exe ارائه کنند و یک خروجی باینری دریافت کنند، امکان دسترسی به syntax trees، semantic analysis و تمام مسایل پشت صحنه‌ی یک کامپایلر را دارند.
- ساده سازی تولید افزونه‌های مرتبط با زبان‌های مدیریت شده.
اکنون برای تولید یک آنالیز کننده‌ی سفارشی، نیازی نیست هر توسعه دهنده‌ای شروع به نوشتن امکانات پایه‌ای یک کامپایلر کند. این امکانات به صورت یک API عمومی در دسترس برنامه نویس‌ها قرار گرفته‌اند.
- آموزش مسایل درونی یک کامپایلر و همچنین ایجاد اکوسیستمی از برنامه نویس‌های علاقمند در اطراف آن.
همانطور که اطلاع دارید، Roslyn به صورت سورس باز در GitHub در دسترس عموم است.


تفاوت Roslyn با کامپایلرهای سنتی

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


نمونه‌ای از این کامپایلرهای جعبه سیاه را در تصویر فوق مشاهده می‌کنید. در اینجا شاید این سؤال مطرح شود که در داخل جعبه‌ی سیاه کامپایلر سی‌شارپ، چه اتفاقاتی رخ می‌دهد؟


خلاصه‌ی مراحل رخ داده در کامپایلر سی‌شارپ را در تصویر فوق ملاحظه می‌کنید. در اینجا ابتدا کار parse اطلاعات متنی دریافتی شروع می‌شود و از روی آن syntax tree تولید می‌شود. در مرحله‌ی بعد مواردی مانند ارجاعاتی به mscorlib و امثال آن پردازش می‌شوند. در مرحله‌ی binder کار پردازش حوزه‌ی دید متغیرها، اشیاء و اتصال آن‌ها به هم انجام می‌شود. در مرحله‌ی آخر، کار تولید کدهای IL و اسمبلی باینری نهایی صورت می‌گیرد.
با معرفی Roslyn، این جعبه‌ی سیاه، به صورت یک API عمومی در دسترس برنامه نویس‌ها قرار گرفته‌است:


همانطور که مشاهده می‌کنید، هر مرحله‌ی کامپایل جعبه‌ی سیاه، به یک API عمومی Roslyn نگاشت شده‌است. برای مثال Parser به Syntax tree API نگاشت شده‌است. به علاوه این API صرفا به موارد فوق خلاصه نمی‌شود و همانطور که پیشتر نیز ذکر شد، برای اینکه بتواند جایگزین سه نوع کامپایلر موجود شود، به همراه Workspace API نیز می‌باشد:


Roslyn امکان کار با یک Solution و فایل‌های آن را دارد و شامل سرویس‌های زبان‌های مورد نیاز در ویژوال استودیو نیز می‌شود. برفراز Workspace API، یک مجموعه API دیگر به نام Diagnostics API تدارک دیده شده‌است تا برنامه نویس‌ها بتوانند امکانات Refactoring جانبی را توسعه داده و یا در جهت بهبود کیفیت کدهای نوشته شده، اخطارهایی را به برنامه نویس‌ها تحت عنوان Code fixes و آنالیز کننده‌ها، ارائه دهند.

مطالب
دریافت اطلاعات از سایت‌های غیر استاندارد

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

The server committed a protocol violation. Section=ResponseHeader Detail=CR must be followed by LF

و یا حالتی دیگر:

The underlying connection was closed: The server committed an HTTP protocol violation.

بعضی از وب سروها ممکن است پاسخ ارسالی خود را دقیقا مطابق سطر به سطر RFC های مربوطه ارائه ندهند و کلاس httpWebRequest دات نت هم تعارفی با آن‌ها نداشته و به دلایل امنیتی پردازش پاسخ دریافتی را نیمه کاره رها می‌کند.
برای مثال content-length دقیقا باید به همین شکل ارسال شود و اگر به صورت content length (با یک فاصله در میان کلمات ارسال گردد) به عنوان یک HTTP response split attack در نظر گرفته شده و خطاهای HTTP protocol violation حاصل می‌شوند.

اما می‌توان آگاهانه دات نت فریم ورک را وادار کرد که از این مساله چشم پوشی کند و این نوع سایت‌ها را نیز بررسی و دریافت نماید. برای این منظور در فایل app.config برنامه ویندوزی خود و یا web.config یک برنامه تحت وب، چند سطر زیر را اضافه کنید:

<configuration>
<system.net>
<settings>
<httpWebRequest useUnsafeHeaderParsing="true" />
</settings>
</system.net>
</configuration>

مطالب
OpenCVSharp #10
محاسبه و ترسیم Histogram تصاویر

هیستوگرام یک تصویر، توزیع میزان روشنایی آن تصویر را نمایش می‌دهد و در آن تعداد نقاط قسمت‌های روشن تصویر، ترسیم می‌شوند. محاسبه‌ی هیستوگرام تصاویر در حین دیباگ الگوریتم‌های پردازش تصویر، کاربرد زیادی دارند.
OpenCV به همراه متد توکاری است به نام cv::calcHist که قادر است هیستوگرام تعدادی آرایه را محاسبه کند و در C++ API آن قرار دارد. البته هدف اصلی این متد، انجام محاسبات مرتبط است و در اینجا قصد داریم این محاسبات را نمایش دهیم.


تغییر میزان روشنایی و وضوح تصاویر در OpenCV

همانطور که عنوان شد، کار هیستوگرام تصاویر، نمایش توزیع میزان روشنایی نقاط و اجزای آن‌ها است. بنابراین می‌توان جهت مشاهده‌ی تغییر هیستوگرام محاسبه شده با تغییر میزان روشنایی و وضوح تصویر، از متد ذیل کمک گرفت:
private static void updateBrightnessContrast(Mat src, Mat modifiedSrc, int brightness, int contrast)
{
    brightness = brightness - 100;
    contrast = contrast - 100;
 
    double alpha, beta;
    if (contrast > 0)
    {
        double delta = 127f * contrast / 100f;
        alpha = 255f / (255f - delta * 2);
        beta = alpha * (brightness - delta);
    }
    else
    {
        double delta = -128f * contrast / 100;
        alpha = (256f - delta * 2) / 255f;
        beta = alpha * brightness + delta;
    }
    src.ConvertTo(modifiedSrc, MatType.CV_8UC3, alpha, beta);
}
در اینجا src تصویر اصلی است. brightness و contrast، مقادیر میزان روشنایی و وضوح دریافتی از کاربر هستند. این مقادیر را می‌توان به متد ConvertTo ارسال کرد تا src را تبدیل به modifiedSrc نماید و وضوح و روشنایی آن‌را تغییر دهد.

پس از اینکه متد تغییر وضوح تصویر اصلی را تهیه کردیم، می‌توان به پنجره‌ی نمایش تصویر اصلی، دو tracker جهت دریافت brightness و contrast اضافه کرد و به این ترتیب امکان نمایش پویای تغییرات را مهیا نمود:
using (var src = new Mat(@"..\..\Images\Penguin.Png", LoadMode.AnyDepth | LoadMode.AnyColor))
{
    using (var sourceWindow = new Window("Source", image: src,
           flags: WindowMode.AutoSize | WindowMode.FreeRatio))
    {
        using (var histogramWindow = new Window("Histogram",
               flags: WindowMode.AutoSize | WindowMode.FreeRatio))
        {
            var brightness = 100;
            var contrast = 100;
 
            var brightnessTrackbar = sourceWindow.CreateTrackbar(
                    name: "Brightness", value: brightness, max: 200,
                    callback: pos =>
                    {
                        brightness = pos;
                        updateImageCalculateHistogram(sourceWindow, histogramWindow, src, brightness, contrast);
                    });
 
            var contrastTrackbar = sourceWindow.CreateTrackbar(
                name: "Contrast", value: contrast, max: 200,
                callback: pos =>
                {
                    contrast = pos;
                    updateImageCalculateHistogram(sourceWindow, histogramWindow, src, brightness, contrast);
                });
 
 
            brightnessTrackbar.Callback.DynamicInvoke(brightness);
            contrastTrackbar.Callback.DynamicInvoke(contrast);
 
            Cv2.WaitKey();
        }
    }
}
در اینجا src تصویر اصلی است. پنجره‌ی Source کار نمایش تصویر اصلی را به عهده دارد. همچنین به این پنجره، دو tracker اضافه شده‌اند تا کار دریافت مقادیر روشنایی و وضوح را از کاربر، مدیریت کنند.
پنجره‌ی دومی نیز به نام هیستوگرام در اینجا تعریف شده‌است. در این پنجره قصد داریم هیستوگرام تغییرات پویای تصویر اصلی را نمایش دهیم.



روش محاسبه‌ی هیستوگرام تصاویر و نمایش آن‌ها در OpenCVSharp

کدهای کامل محاسبه‌ی هیستوگرام تصویر اصلی تغییر یافته (modifiedSrc) و سپس نمایش آن‌را در پنجره‌ی histogramWindow، در ادامه ملاحظه می‌کنید:
private static void calculateHistogram1(Window histogramWindow, Mat src, Mat modifiedSrc)
{
    const int histogramSize = 64;
    int[] dimensions = { histogramSize }; // Histogram size for each dimension
    Rangef[] ranges = { new Rangef(0, histogramSize) }; // min/max
 
    using (var histogram = new Mat())
    {
        Cv2.CalcHist(
            images: new[] { modifiedSrc },
            channels: new[] { 0 },
            mask: null,
            hist: histogram,
            dims: 1,
            histSize: dimensions,
            ranges: ranges);
 
        using (var histogramImage = (Mat)(Mat.Ones(rows: src.Rows, cols: src.Cols, type: MatType.CV_8U) * 255))
        {
            // Scales and draws histogram
 
            Cv2.Normalize(histogram, histogram, 0, histogramImage.Rows, NormType.MinMax);
            var binW = Cv.Round((double)histogramImage.Cols / histogramSize);
 
            var color = Scalar.All(100);
 
            for (var i = 0; i < histogramSize; i++)
            {
                Cv2.Rectangle(histogramImage,
                    new Point(i * binW, histogramImage.Rows),
                    new Point((i + 1) * binW, histogramImage.Rows - Cv.Round(histogram.Get<float>(i))),
                    color,
                    -1);
            }
 
            histogramWindow.Image = histogramImage;
        }
    }
}
معادل متد cv::calcHist، متد Cv2.CalcHist در OpenCVSharp است. این متد آرایه‌ای از تصاویر را قبول می‌کند که در اینجا تنها قصد داریم با یک تصویر کار کنیم. به همین جهت آرایه‌های images، اندازه‌های آن‌ها و بازه‌های min/max این تصاویر تنها یک عضو دارند. خروجی این متد پارامتر hist آن است که توسط یک new Mat تامین شده‌است. مقدار dims به یک تنظیم شده‌است؛ زیرا در اینجا تنها قصد داریم شدت نقاط را اندازه گیری کنیم. پارامتر ranges مشخص می‌کند که مقادیر اندازه گیری شده باید در چه بازه‌ایی جمع آوری شوند.
پس از محاسبه‌ی هیستوگرام، یک تصویر خالی پر شده‌ی با عدد یک را توسط متد Mat.Ones ایجاد می‌کنیم. این تصویر به عنوان منبع تصویر هیستوگرام نمایش داده شده، مورد استفاده قرار می‌گیرد. سپس نیاز است اطلاعات محاسبه شده، در مقیاسی قرار گیرند که قابل نمایش باشد. به همین جهت با استفاده از متد Normalize، آن‌ها را در مقیاس و بازه‌ی ارتفاع تصویر، تغییر اندازه خواهیم داد. سپس به کمک متد مستطیل، خروجی آرایه هیستوگرام را در صفحه، با رنگ خاکستری مشخص شده توسط متد Scalar.All ترسیم خواهیم کرد.


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


کدهای کامل این مثال را از اینجا می‌توانید دریافت کنید.
نظرات نظرسنجی‌ها
چه نوع محیط کاری را بیشتر ترجیح می‌دهید؟
کار برنامه نویسی نیاز به «تمرکز بالایی در طولانی مدت» دارد و برای یک چنین مورد خاصی، محیط باز (رفت و آمد مراجعین، مدیران شلوغ در کنار دست، رفت و آمد خدمت‌کاران، با هم صحبت کردن همکاران، با تلفن صحبت کردن منشی‌ها و ...)، بدترین انتخاب ممکن هست.

نظرات مطالب
صفحه بندی، مرتب سازی و جستجوی پویای اطلاعات به کمک Kendo UI Grid
- این فقط یک مثال هست و منبع داده‌ای صرفا جهت دموی ساده‌ی برنامه. فقط برای اینکه با یک کلیک بتوانید برنامه را اجرا کنید و نیازی به برپایی و تنظیم بانک اطلاعاتی و امثال آن نداشته باشد.
- شما در کدها و کوئری‌های مثلا EF در اصل با یک سری IQueryable کار می‌کنید. همینجا باید متد الحاقی ToDataSourceResult را اعمال کنید تا نتیجه‌ی نهایی در حداقل بار تعداد رفت و برگشت و با کوئری مناسبی بر اساس پارامترهای دریافتی به صورت خودکار تولید شود. در انتهای کار بجای مثلا ToList بنویسید ToDataSourceResult.
مطالب
Vue CLI
تیم Vue یک ابزار را جهت scaffold سریع یک پروژه Vue، به صورت رسمی ارائه کرده‌است. توسط این ابزار به صورت سریع می‌توانیم ساختار یک پروژه استاندارد Vue را ایجاد کنیم.

چرا نیاز به Vue CLI داریم؟
  • زیرا نیاز به build processهایی داریم که به ما امکان استفاده از ES6, SCSS و دیگر ویژگیهای عالی را خواهند داد.
  • جهت ساخت و یکی‌سازی فایل‌های تمپلیت
  • بارگذاری نکردن تمامی فایل‌ها به صورت یکجا در زمان Startup 
  • می‌توانیم تسک‌هایی از قبیل Server-side rendering, code-splitting را انجام دهیم.
 
نصب Vue CLI 
ابتدا مطمئن شوید که آخرین نگارش Node.js را نصب کرده‌اید. سپس جهت نصب Vue CLI، خط فرمان را گشوده و دستور زیر ذیل را صادر کنید: 
npm install -g vue-cli

با اجرای فرمان فوق، ابزار CLI به صورت global و عمومی نصب خواهد شد. در ادامه می‌توانیم با دستور vue list، لیستی از قالب‌های رسمی را که توسط CLI قابل ایجاد هستند، مشاهده نمائید: 

در اینجا ما از قالب webpack-simple استفاده خواهیم کرد. برای اینکار دستور زیر را جهت ایجاد یک پروژه بر اساس این قالب صادر کنید: 
vue init webpack-simple dntVue

به این ترتیب در سریعترین زمان ممکن توانستیم یک برنامه‌ی Vue را ایجاد کنیم: 

در اینجا ساختار یک پروژه جدید Vue را مشاهده می‌کنید:

index.html: کار شروع و ارائه برنامه را انجام می‌دهد.
package.json: وابستگی‌های npm برنامه را به همراه دارد.
src/App.vue: کامپوننت اصلی برنامه است.
پوشه src/assets: حاوی فایل‌های استاتیک پروژه است.
src/main.js: نقطه‌ی آغاز برنامه است.
webpack.config.json: تنظیمات وب‌پک جهت اجرای پروژه و بارگذاری ماژول‌های موردنیاز.


اجرای برنامه
ابتدا نیاز است وابستگی‌های برنامه دریافت شوند. اینکار را توسط دستور npm install و یا دستور yarn (در صورتیکه yarn را از قبل بر روی سیستم خود نصب کرده‌اید) انجام خواهیم داد:
npm install
به این ترتیب تمامی وابستگی‌های پروژه درون پوشه‌ی node_module تشکیل خواهند شد. اکنون می‌توانیم با صدور دستور npm run dev پروژه را اجرا کنیم:

بررسی فایل‌های Vue
درون یک برنامه‌ی Vue واقعی، فایل‌هایی با پسوند vue. وجود دارند. این فایل شامل تمپلیت، کدها و همچنین استایل‌های یک کامپوننت می‌باشند. 
<template>
    <div>
        <!-- Write your HTML with Vue in here -->
    </div>
</template>

<script>
    export default {
        // Write your Vue component logic here
    }
</script>

<style scoped>
    /* Write your styles for the component in here */
</style>

بنابراین درون فایلی با ساختار فوق، تمامی موارد مورد نیاز برای یک کامپوننت ویو را خواهیم داشت و به اصطلاح نیازی به context switching نخواهیم داشت؛ زیرا تمامی قسمت‌ها را به صورت یکجا در یک محل در اختیار داریم و به راحتی می‌توانیم تمرکز خود را بر روی کدها قرار دهیم. درون کامپوننت نیز می‌توانیم کامپوننت‌های موردنیاز را ایمپورت و از آن استفاده کنیم: 
import { New } from "./components/New.vue";
export default {
    components: {
        New
    }
}


Vue CLI 3
تا اینجا از نسخه‌ی پایدار Vue CLI استفاده کردیم. نسخه‌ی 3 آن هنوز در مرحله‌ی beta قرار دارد. در این نسخه امکانات و دستورات بیشتری اضافه شده‌است؛ از ایجاد یک پروژه ساده تا ایجاد یک پروژه مبتنی بر TypeScript. برای نصب و یا آپگرید می‌توانید از دستور زیر استفاده کنید:
npm install -g @vue/cli
اکنون می‌توانید با صادر کردن دستور vue --version، شماره نسخه‌ی آن را مشاهده نمائید:
3.0.0-beta.11


ایجاد یک پروژه جدید
برای ایجاد یک پروژه جدید می‌توانید دستور زیر را صادر کنید:
vue create my-project
همانطور که مشاهده می‌کنید در این نسخه بجای استفاده از دستور vue init، از vue create استفاده شده است. در اینحالت می‌توانید نوع ایجاد پروژه را تعیین کنید:
Vue CLI v3.0.0-beta.11
? Please pick a preset: (Use arrow keys)
❯ default (babel, eslint)
  Manually select features
حالت پیش‌فرض، چنین ساختاری را برایتان ایجاد خواهد کرد:

بعد از طی کردن مراحل، می‌توانید قالب پروژه‌ی ایجاد شده را به صورت یک preset داشته باشید تا در پروژه‌های آینده مجبور نباشید مراحل قبل را طی کنید. این preset درون یک فایل JSON به صورت زیر ذخیره خواهد شد و حاوی اطلاعات زیر است:
{
  "useConfigFiles": true,
  "router": true,
  "vuex": true,
  "cssPreprocessor": "sass",
  "plugins": {
    "@vue/cli-plugin-babel": {},
    "@vue/cli-plugin-eslint": {
      "config": "airbnb",
      "lintOn": ["save", "commit"]
    }
  }
}

در حالت manually نیز می‌توانید گزینه‌های بیشتری را برای تعیین نوع قالب پروژه، انتخاب نمائید. به عنوان مثال می‌توان از TypeScript یا اینکه از lintter یا formatter خاصی برای کدها استفاده کرد:

در ادامه دیگر آپشن‌ها را نیز می‌توانید تعیین کرده و در نهایت به صورت یک قالب از پیش تعریف شده نیز پروژه را داشته باشید:


Zero-config Prototyping 
یکی از قابلیت‌های جالب Vue، امکان تهیه سریع prototype یا طرح اولیه می‌باشد. شاید اکثر اوقات نیاز داشته باشید یک ویژگی یا قابلیت خاص را با Vue تست کنید. در این موارد ممکن است از سایتی مانند CodePen استفاده کنید. اما توسط افزونه‌ی cli-service-global می‌توانید به صورت لوکال و بدون نیاز به راه‌اندازی یک پروژه‌ی جدید، کدهای موردنیاز را آزمایش کنید. فرض کنید می‌خواهیم تمپلیت زیر را قبل از افزودن آن به پروژه، مورد تست قرار دهیم:
<!-- MyCard.vue -->
<template>
    <div class="card">
    <h1>Card Title</h1>
    <p>Card content goes here. Make sure it's not Lorem.</p>
    </div>
</template>
در این‌حالت می‌توانیم با نصب افزونه موردنظر، فایل فوق را به راحتی و بدون نیاز به راه‌اندازی یک پروژه جدید، تست کنیم:
npm install -g @vue/cli-service-global
اکنون می‌توانیم خروجی را با صدور فرمان زیر درون مرورگر مشاهده کنیم:
vue serve MyCard.vue
با صدرو فرمان فوق، فایل توسط افزونه‌ی عنوان شده، از طریق مرورگر قابل دسترسی می‌باشد:

خروجی:

مطالب
ساختار داده‌های خطی Linear Data Structure قسمت دوم
در قسمت قبلی به مقدمات و ساخت لیست‌های ایستا و پویا به صورت دستی پرداختیم و در این قسمت (مبحث پایانی) لیست‌های آماده در دات نت را مورد بررسی قرار می‌دهیم.

کلاس ArrayList
این کلاس همان پیاده سازی لیست‌های ایستایی را دارد که در مطلب پیشین در مورد آن صحبت کردیم و نحوه کدنویسی آن نیز بیان شد و امکاناتی بیشتر از آنچه که در جدول مطلب پیشین گفته بودیم در دسترس ما قرار می‌دهد. از این کلاس با اسم untyped dynamically-extendable array به معنی آرایه پویا قابل توسعه بدون نوع هم اسم می‌برند چرا که به هیچ نوع داده‌ای مقید نیست و می‌توانید یکبار به آن رشته بدهید، یکبار عدد صحیح، یکبار اعشاری و یکبار زمان و تاریخ، کد زیر به خوبی نشان دهنده‌ی این موضوع است و نحوه استفاده‌ی از این آرایه‌ها را نشان می‌دهد.
using System;
using System.Collections;
 
class ProgrArrayListExample
{
    static void Main()
    {
        ArrayList list = new ArrayList();
        list.Add("Hello");
        list.Add(5);
        list.Add(3.14159);
        list.Add(DateTime.Now);
 
        for (int i = 0; i < list.Count; i++)
        {
            object value = list[i];
            Console.WriteLine("Index={0}; Value={1}", i, value);
        }
    }
}
نتیجه کد بالا:
Index=0; Value=Hello
Index=1; Value=5
Index=2; Value=3.14159
Index=3; Value=29.02.2015 23:17:01
البته برای خواندن و قرار دادن متغیرها از آنجا که فقط نوع Object را برمی‌گرداند، باید یک تبدیل هم انجام داد یا اینکه از کلمه‌ی کلیدی dynamic استفاده کنید:
ArrayList list = new ArrayList();
list.Add(2);
list.Add(3.5f);
list.Add(25u);
list.Add(" ریال");
dynamic sum = 0;
for (int i = 0; i < list.Count; i++)
{
    dynamic value = list[i];
    sum = sum + value;
}
Console.WriteLine("Sum = " + sum);
// Output: Sum = 30.5ریال

مجموعه‌های جنریک Generic Collections
مشکل ما در حین کار با کلاس arrayList و همه کلاس‌های مشتق شده از system.collection.IList این است که نوع داده‌ی ما تبدیل به Object می‌شود و موقعی‌که آن را به ما بر می‌گرداند باید آن را به صورت دستی تبدیل کرده یا از کلمه‌ی کلیدی dynamic استفاده کنیم. در نتیجه در یک شرایط خاص، هیچ تضمینی برای ما وجود نخواهد داشت که بتوانیم کنترلی بر روی نوع داده‌های خود داشته باشیم و به علاوه عمل تبدیل یا casting هم یک عمل زمان بر هست.
برای حل این مشکل، از جنریک‌ها استفاده می‌کنیم. جنریک‌ها می‌توانند با هر نوع داده‌ای کار کنند. در حین تعریف یک کلاس جنریک نوع آن را مشخص می‌کنیم و مقادیری که از آن به بعد خواهد پذیرفت، از نوعی هستند که ابتدا تعریف کرده‌ایم.
یک ساختار جنریک به صورت زیر تعریف می‌شود:
GenericType<T> instance = new GenericType<T>();
نام کلاس و به جای T نوع داده از قبیل int,bool,string را می‌نویسیم. مثال‌های زیر را ببینید:
List<int> intList = new List<int>();
List<bool> boolList = new List<bool>();
List<double> realNumbersList = new List<double>();

کلاس جنریک <List<T
این کلاس مشابه همان کلاس ArrayList است و فقط به صورت جنریک پیاده سازی شده است.
List<int> intList = new List<int>();
تعریف بالا سبب ایجاد ArrayList ـی می‌باشد که تنها مقادیر int را دریافت می‌کند و دیگر نوع Object ـی در کار نیست. یک آرایه از نوع int ایجاد می‌کند و مقدار خانه‌های پیش فرضی را نیز در ابتدا، برای آن در نظر می‌گیرد و با افزودن هر مقدار جدید می‌بیند که آیا خانه‌ی خالی وجود دارد یا خیر. اگر وجود داشته باشد مقدار جدید، به خانه‌ی بعدی آخرین خانه‌ی پر شده انتقال می‌یابد و اگر هم نباشد، مقدار خانه از آن چه هست 2 برابر می‌شود. درست است عملیات resizing یا افزایش طول آرایه عملی زمان بر محسوب میشود ولی همیشه این اتفاق نمی‌افتد و با زیاد شدن مقادیر خانه‌ها این عمل کمتر هم می‌شود. هر چند با زیاد شدن خانه‌ها حافظه مصرفی ممکن است به خاطر زیاد شدن خانه‌های خالی بدتر هم بشود. فرض کنید بار اول خانه‌ها 16 تایی باشند که بعد می‌شوند 32 تایی و بعدا 64 تایی. حالا فرض کنید به خاطر یک عنصر، خانه‌ها یا ظرفیت بشود 128 تایی در حالی که طول آرایه (خانه‌های پر شده) 65 تاست و حال این وضعیت را برای موارد بزرگتر پیش بینی کنید. در این نوع داده اگر منظور زمان باشد نتجه خوبی را در بر دارد ولی اگر مراعات حافظه را هم در نظر بگیرید و داده‌ها زیاد باشند، باید تا حدامکان به روش‌های دیگر هم فکر کنید.

چه موقع از <List<T استفاده کنیم؟
استفاده از این روش مزایا و معایبی دارد که باید در توضیحات بالا متوجه شده باشید ولی به طور خلاصه:
  • استفاده از index برای دسترسی به یک مقدار، صرف نظر از اینکه چه میزان داده‌ای در آن وجود دارد، بسیار سریع انجام میگیرد.
  • جست و جوی یک عنصر بر اساس مقدار: جست و جو خطی است در نتیجه اگر مقدار مورد نظر در آخرین خانه‌ها باشد بدترین وضعیت ممکن رخ می‌دهد و بسیار کند عمل می‌کند. داده هر چی کمتر بهتر و هر چه بیشتر بدتر. البته اگر بخواهید مجموعه‌ای از مقدارهای برابر را برگردانید هم در بدترین وضعیت ممکن خواهد بود.
  • حذف و درج (منظور insert) المان‌ها به خصوص موقعی که انتهای آرایه نباشید، شیفت پیدا کردن در آرایه عملی کاملا کند و زمانبر است.
  • موقعی که عنصری را بخواهید اضافه کنید اگر ظرفیت آرایه تکمیل شده باشد، نیاز به عمل زمانبر افزایش ظرفیت خواهد بود که البته این عمل به ندرت رخ می‌دهد و عملیات افزودن Add هم هیچ وابستگی به تعداد المان‌ها ندارد و عملی سریع است.
با توجه به موارد خلاصه شده بالا، موقعی از لیست اضافه می‌کنیم که عملیات درج و حذف زیادی نداریم و بیشتر برای افزودن مقدار به انتها و دسترسی به المان‌ها بر اساس اندیس باشد.

<LinkedList<T
یک کلاس از پیش آماده در دات نت که لیست‌های پیوندی دو طرفه را پیاده سازی می‌کند. هر المان یا گره یک متغیر جهت ذخیره مقدار دارد و یک اشاره گر به گره قبل و بعد.
چه موقع باید از این ساختار استفاده کنیم؟
از مزایا و معایب آن :
  • افزودن به انتهای لیست به خاطر این که همیشه گره آخر در tail وجود دارد بسیار سریع است.
  • عملیات درج insert در هر موقعیتی که باشد اگر یک اشاره گر به آن محل باشد یک عملیات سریع است یا اینکه درج در ابتدا یاانتهای لیست باشد.
  • جست و جوی یک مقدار چه بر اساس اندیس باشد و چه مقدار، کار جست و جو کند خواهد بود. چرا که باید تمامی المان‌ها از اول به آخر اسکن بشن.
  • عملیات حذف هم به خاطر اینکه یک عمل جست و جو در ابتدای خود دارد، یک عمل کند است.
استفاده از این کلاس موقعی خوب است که عملیات‌های درج و حذف ما در یکی از دو طرف لیست باشد یا اشاره‌گری به گره مورد نظر وجود داشته باشد. از لحاظ مصرف حافظه به خاطر داشتن فیلدهای اشاره‌گر به جز مقدار، زیاد‌تر از نوع List می‌باشد. در صورتی که دسترسی سریع به داده‌ها برایتان مهم باشد استفاده از List باز هم به صرفه‌تر است.

پشته Stack
یک سری مکعب را تصور کنید که روی هم قرار گرفته اند و برای اینکه به یکی از مکعب‌های پایینی بخواهید دسترسی داشته باشید باید تعدادی از مکعب‌ها را از بالا بردارید تا به آن برسید. یعنی بر خلاف موقعی که آن‌ها روی هم می‌گذاشتید و آخرین مکعب روی همه قرار گرفته است. حالا همان مکعب‌ها به صورت مخالف و معکوس باید برداشته شوند.
یک مثال واقعی‌تر و ملموس‌تر، یک کمد لباس را تصور کنید که مجبورید برای آن که به لباس خاصی برسید، باید آخرین لباس‌هایی را که در داخل کمد قرار داده‌اید را اول از همه از کمد در بیاورید تا به آن لباس برسید.
در واقع  پشته چنین ساختاری را پیاده می‌کند که اولین عنصری که از پشته بیرون می‌آید، آخرین عنصری است که از آن درج شده است و به آن LIFO گویند که مخفف عبارت Last Input First Output آخرین ورودی اولین خروجی است. این ساختار از قدیمی‌ترین ساختارهای موجود است. حتی این ساختار در سیستم‌های داخل دات نت CLR هم به عنوان نگهدارنده متغیرها و پارامتر متدها استفاده می‌شود که به آن Program Execution Stack می‌گویند.
پشته سه عملیات اصلی را پیاده سازی می‌کند: Push جهت قرار دادن مقدار جدید در پشته، POP جهت بیرون کشیدن مقداری که آخرین بار در پشته اضافه شده و Peek جهت برگرداندن آخرین مقدار اضافه شده به پشته ولی آن مقدار از پشته حذف نمی‌شود.
این ساختار میتواند پیاده سازی‌های متفاوتی را داشته باشد ولی دو نوع اصلی که ما بررسی می‌کنیم، ایستا و پویا بودن آن است. ایستا بر اساس آرایه است و پویا بر اساس لیست‌های پیوندی. شکل زیر پشته‌ای را به صورت استفاده از پیاده‌سازی ایستا با آرایه‌ها نشان می‌دهد و کلمه Top به بالای پشته یعنی آخرین عنصر اضافه شده اشاره می‌کند.

استفاده از لیست پیوندی برای پیاده سازی پشته:

لیست پیوندی لازم نیست دو طرفه باشد و یک طرف برای کار با پشته مناسب است و دیگر لازم نیست که به انتهای لیست پیوندی عمل درج انجام شود؛ بلکه مقدار جدید به ابتدای آن اضافه شده و برای حذف گره هم اولین گره باید حذف شود و گره دوم به عنوان head شناخته می‌شود. همچنین لیست پیوندی نیازی به افزایش ظرفیت مانند آرایه‌ها ندارد.
ساختار پشته در دات نت توسط کلاس Stack از قبل آماده است:
Stack<string> stack = new Stack<string>();
stack.Push("A");
stack.Push("B");
stack.Push("C");
 while (stack.Count > 0)
    {
        string letter= stack.Pop();
        Console.WriteLine(letter);
    }
//خروجی
//C
//B
//A

صف Queue
ساختار صف هم از قدیمی‌ترین ساختارهاست و مثال آن در همه جا و در همه اطراف ما دیده می‌شود؛ مثل صف نانوایی، صف چاپ پرینتر، دسترسی به منابع مشترک توسط سیستمها. در این ساختار ما عنصر جدید را به انتهای صف اضافه می‌کنیم و برای دریافت مقدار، عنصر را از ابتدا حذف می‌کنیم. به این ساختار FIFO مخفف First Input First Output به معنی اولین ورودی و اولین خروجی هم می‌گویند.
ساختار ایستا که توسط آرایه‌ها پیاده سازی شده است:

ابتدای آرایه مکانی است که عنصر از آنجا برداشته می‌شود و Head به آن اشاره می‌کند و tail هم به انتهای آرایه که جهت درج عنصر جدید مفید است. با برداشتن هر خانه‌ای که head به آن اشاره می‌کند، head یک خانه به سمت جلو حرکت می‌کند و زمانی که Head از tail بیشتر شود، یعنی اینکه دیگر عنصری یا المانی در صف وجود ندارد و head و Tail به ابتدای صف حرکت می‌کنند. در این حالت موقعی که المان جدیدی قصد اضافه شدن داشته باشد، افزودن، مجددا از اول صف آغاز می‌شود و به این صف‌ها، صف حلقوی می‌گویند.

عملیات اصلی صف دو مورد هستند enqueue که المان جدید را در انتهای صف قرار می‌دهد و dequeue اولین المان صف را بیرون می‌کشد.


پیاده سازی صف به صورت پویا با لیست‌های پیوندی

برای پیاده سازی صف، لیست‌های پیوندی یک طرفه کافی هستند:

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

کلاس از پیش آمده صف در دات نت <Queue<T است و نحوه‌ی استفاده آن بدین شکل است:

static void Main()
{
    Queue<string> queue = new Queue<string>();
    queue.Enqueue("Message One");
    queue.Enqueue("Message Two");
    queue.Enqueue("Message Three");
    queue.Enqueue("Message Four");
 
    while (queue.Count > 0)
    {
        string msg = queue.Dequeue();
        Console.WriteLine(msg);
    }
}
//خروجی
//Message One
//Message Two
//Message Thre
//Message Four