نظرات مطالب
آموزش مفاهیم Data Warehouse
بسیار عالی 
آیا OLTP و DW می‌توانند بر روی یک سرور باشند مثلا" بر روی یک SQL Server باشند   
اشتراک‌ها
پشتیبانی EF Core از دیتابیس های چندگانه

در بیشتر مواقع نیازی به ارائه پروایدرهای پایگاه داده چندگانه ندارید. به عنوان مثال ، شما با پروایدرSQL Server شروع می‌کنید و نیازی به رفتن به پروایدر پایگاه داده دیگری نیست. در این پروژه‌ی نمونه، ما باید چندین پروایدر را برای پشتیبانی از محیط‌های مختلف استقرار اضافه کنیم. برخی از مشتریان ترجیح می‌دهند از پایگاه داده Windows Server و SQL Server و برخی دیگر از Linux و MySQL یا PostgreSQL استفاده کنند. 

پشتیبانی EF Core از دیتابیس های چندگانه
مطالب
نگاشت اشیاء در AutoMapper توسط Attribute ها #2 - تبدیل ویژگی‌ها به نگاشت
پس از معرفی ویژگی‌های لازم، در ادامه با نحوه‌ی تبدیل این ویژگی‌ها به معادل نگاشت آن‌ها در automapper خواهم پرداخت.
متد زیر هسته‌ی اصلی عملیات است و کلیه‌ی نگاشت‌های لازم را انجام می‌دهد. این متد وظیفه‌ی تبدیل نگاشت‌ها را دارد. نگاشت‌هایی که با Attributes مشخص شده‌اند:
 public static void Initialize(Assembly assembly)
 {
     //register global convertors.
     AutoMapper.Mapper.CreateMap<DateTime, string>().ConvertUsing<DateTimeToPersianDateTimeConverter>();

     var typesToMap = from t in assembly.GetTypes()
         let attr = t.GetCustomAttribute<MapFromAttribute>()
         where attr != null
         select new {SourceType = attr.SourceType, Destination = t, Attribute = attr};

     foreach (var map in typesToMap)
     {
         AutoMapper.Mapper.CreateMap(map.SourceType, map.Destination)             
             .DoMapForMemberAttribute() // for different property names in source and destination
             .DoIgnoreMapAttribute()// ignore specified properties
             .DoUseValueResolverAttribute()// set value resolvers
             .DoIgnoreAllNonExisting()// its have to be the latest.
             ;
     } //endeach
     AutoMapper.Mapper.AssertConfigurationIsValid();
 }
ورودی این متد اسملبی مربوط به ویوومدل می‌باشد (برای زمانیکه ویوومدل‌ها در اسمبلی دیگری باشند).
در سطر اول، اقدام به رجیستر کردن کلیه‌ی مبدل‌های سراسری می‌کنیم. در این سطر مبدل تاریخ به کوچی خورشیدی مورد استفاده قرار گرفته است. سپس در اسمبلی داده شده، کلیه نوع‌هایی که ویژگی MapFromAttribute را دارند، یافته و جدا می‌کنیم. در حلقه‌ی foreach ابتدا نگاشت نوع مبدأ و مقصد را انجام می‌دهیم. خروجی این متد از نوع IMappingExpression است. گر چه این اینترفیس برای تغییر بسته است، ولی قابل توسعه می‌باشد و عملیات را توسط متدهای الحاقی انجام می‌دهیم(اصل OCP).
اگر به نحوه‌ی نامگذاری متدهای الحاقی تعریف شده دقت کرده باشید، تنها کلمه‌ی Do به ابتدای نام ویژگی‌ها اضافه شده است
.

متد الحاقی DoMapFormMemberAttribute
public static IMappingExpression DoMapForMemberAttribute(this IMappingExpression expression)
{
    var ok =
        from p in expression.TypeMap.DestinationType.GetProperties()
        let attr = p.GetCustomAttribute<MapForMemberAttribute>()
        where attr != null
        select new {AttributeValue = attr, PropertyName = p.Name};

     foreach (var property in ok)
     {
         expression.ForMember(property.PropertyName, 
             opt => opt.MapFrom(property.AttributeValue.MemberToMap));
     }
    return expression;
}
هر IMappingExpression دارای امکاناتی برای نگهداری و انجام فعالیت بر روی یک نگاشت می‌باشد. در کوئری ابتدای متد، کلیه‌ی پروپرتی‌هایی را که دارای ویژگی MapForMemeberAttribute می‌باشند، یافته و جدا می‌کنیم. این پروپرتی‌ها از نظر معادل اسمی در نوع مبدأ و مقصد متفاوت هستند. سپس در حلقه، کار اتصال پروپرتی مبدأ و مقصد صورت می‌گیرد.

متد الحاقی DoIgnoreMapAttribute  
public static IMappingExpression DoIgnoreAttribute(this IMappingExpression expression)
{
    foreach (var property in
        expression.TypeMap.DestinationType.GetProperties()
        .Where(x => x.GetCustomAttribute<IgnoreMapAttribute>() != null))
    {
        expression.ForMember(property.Name, opt => opt.Ignore());
    }
    return expression;
}
این متد کلیه‌ی پروپرتی‌هایی را که دارای ویژگی IgnoreMapAttribute باشند، از گردونه‌ی نگاشت automapper خارج می‌کند. به عنوان مثال پروپرتی Password در ویوومدل مربوط به تغییر گذرواژه را نظر بگیرید. این پروپرتی نباید مقدار معادلی در شیء EF داشته باشد. از طرفی هم باید در ویوو وجودداشته باشد. با استفاده از این ویژگی هیچ نگاشتی انجام نمی‌شود و می‌توان تضمین کرد که گذرواژه به ویوومدل و ویوو راه پیدا نمی‌کند.

متد الحاقی DoUseValueResolverAttribute 
public static IMappingExpression DoUseValueResolverAttribute(this IMappingExpression expression)
{
    var ok =
        from p in expression.TypeMap.DestinationType.GetProperties()
        let attr = p.GetCustomAttribute<UseValueResolverAttribute>()
        where attr != null
        select new {AttributeValue = attr, PropertyName = p.Name};

    foreach (var property in ok)
    {
        expression.ForMember(property.PropertyName,
            opt => opt.ResolveUsing(property.AttributeValue.ValueResolver));
    }
    return expression;
}
به شیوه‌ی قبل، ابتدا نوع هایی را که دارای ویژگی UseValueResolverAttribute باشند، یافته و جدا می‌کنیم. سپس در حلقه، کار نگاشت متناظر در automapper انجام می‌گیرد. لازم به ذکر است که متد opt.ResolveUsing یک شیء با کارآیی (can do) اینترفیس IValueResolver را به عنوان آرگومان می‌گیرد.

متد الحاقی DoIgnoreAllNonExisting  
public static IMappingExpression DoIgnoreAllNonExisting(this IMappingExpression expression)
{
    var attr = expression.TypeMap.DestinationType.GetCustomAttribute<MapFromAttribute>();
    
    if (attr?.IgnoreAllNonExistingProperty == false)//instead of if(attr == null || attr.IgnoreAllNonExistingProperty == false)
        return expression;
    
    foreach (var property in expression.TypeMap.GetUnmappedPropertyNames())
    {
        expression.ForMember(property, opt => opt.Ignore());
    }
    return expression;
}
این متد برحسب پرچم تعیین شده در هنگام بکارگیری ویژگی MapFromAttribute رفتار می‌کند. به این صورت که اگر موقع تعریف، مقدار IgnoreAllNonExistingProperty را صحیح اعلام کنیم، تمام پروپرتی‌های مقصد را که معادل اسمی در مبدأ نداشته باشند و همچنین هیچگونه تنظیمی جهت مشخص سازی تکلیف نگاشت آن‌ها صورت نگرفته باشد، از گردونه‌ی نگاشت Automapper خارج می‌کند.

توضیح تکمیلی:
پس از تنظیم کلیه‌ی نگاشت‌ها در automapper جهت اطمینان از صحت تنظیمات، فراخوانی متد AutoMapper.Mapper.AssertConfigurationIsValid الزامی است. یکی از عواملی که باعث شکست این متد می‌شود، وجود پروپرتی‌هایی در نوع مقصد است، بطوریکه معادل اسمی در نوع مبدأ نداشته باشند و یا تنظیمی جهت مشخص سازی نگاشت آن انجام نشده باشد (پروپرتی که قابل نگاشت نباشد). در حقیقت این شکست بسیار مفید است. به این صورت که اگر این شکست صورت نگیرد در حین نگاشت مقادیر، باید از null یا مقدار default بدون اطلاع برنامه نویس برای مقداردهی پروپرتی استفاده کند و این یک حالت نامعلوم شیء است. اگر می‌خواهید این پروپرتی‌ها مقدار پیشفرضی بگیرند و همچنین باعث شکست عملیات هم نشوند، باید بطور صریح این موضوع را اعلام کنید. این اعلام یا باید به همین روش صورت بگیرد یا باید از ویژگی IgnorMapAttribute استفاده شود. تنها تفاوت این دو، نحوه‌ی اعمال تنظیم می‌باشد. IgnorMapAttribute باید روی تک تک پروپرتی‌های مدنظر قرار گیرد، ولی در روش اول تنها کافیست که مقدار true تنظیم گردد. به‌نظر استفاده از IgnoreMapAttribute باعث طولانی شدن کدها می‌شود؛ اما توصیه می‌شود که از همین شیوه استفاده کنید.

تا اینجا کدهای مورد نیاز نوشته شدند. در ادامه به ارائه‌ی یک مثال برای نگاشت اشیاء در Automapper توسط Attributeها می‌پردازم.
مدل ساده‌ی زیر را در نظر بگیرید:
public class Student
{
    public virtual int Id { set; get; }
    public virtual string Name { set; get; }
    public virtual string Family { set; get; }
    public virtual string Email { set; get; }
    public virtual DateTime RegisterDateTime { set; get; }
    public virtual ICollection<Book> Books { set; get; }
}
public class Book
{
    public virtual int Id { set; get; }
    public virtual string Name { set; get; }
    public virtual DateTime BorrowDateTime { set; get; }
    public virtual DateTime ExpiredDateTime { set; get; }
    public virtual decimal Price { set; get; }
    [ForeignKey("StudentIdFk")]
    public virtual Student Student { set; get; }
    public virtual int StudentIdFk { set; get; }
}
با ویوومدل متناظر ذیل:
[MapFrom(typeof (Student), ignoreAllNonExistingProperty: true, alsoCopyMetadata: true)]
public class AdminStudentViewModel
{
    // [IgnoreMap]
    public int Id { set; get; }

    [MapForMember("Name")]
    public string FirstName { set; get; }

    [MapForMember("Family")]
    public string LastName { set; get; }

 [IgnoreMap]  public string Email { set; get; } [MapForMember("RegisterDateTime")] public string RegisterDateTimePersian { set; get; } [UseValueResolver(typeof (BookCountValueResolver))] public int BookCounts { set; get; } [UseValueResolver(typeof (BookPriceValueResolver))] public decimal TotalBookPrice { set; get; } };
در تنظیم ویژگی MapFromAttribute ابتدا نوع مبدأ (Student) را مشخص کردیم و بعد صراحتاً گفتیم که از نگاشت پروپرتی‌های بلاتکلیف صرف نظر کند و همچنین پرچم انتقال Data Annotation‌های EF به ویوومدل را هم برافراشتیم. توسط MapForMember پروپرتی FirstName را به پروپرتی Name در مبدأ تنظیم کردیم و LastName را به Family. همچنین Email را بصورت صریح از نگاشت شدن منع کردیم. پروپرتی BookCounts تعداد کتاب‌ها را محاسبه می‌کند و TotalBookPrice قیمت کلیه‌ی کتاب‌ها را. برای این موارد از تأمین کننده‌ی داده (Value Resolver) استفاده کردیم. این تأمین کننده‌ها می‌توانند اینچنین پیاده سازی شوند:
public class BookCountValueResolver : ValueResolver<Student, int>
{
    protected override int ResolveCore(Student source) => source.Books.Count;
};
public class BookPriceValueResolver : ValueResolver<Student, decimal>
{
    protected override decimal ResolveCore(Student source) => source.Books.Sum(b => b.Price);
};
نحوه‌ی پیکربندی و مشاهده‌ی نتایج را در یک برنامه‌ی تحت کنسول پیاده سازی کردم. متد Main آن می‌تواند اینچنین باشد:
static void Main(string[] args)
{
    var assemblyToLoad = Assembly.GetAssembly(typeof (AdminStudentViewModel));//get assembly
    global::AttributesForAutomapper.Configuration.Initialize(assemblyToLoad);//init automaper
    IList<Student> lst;
    using (var context = new MySampleContext())
    {
        lst = context.Students.Include(x => x.Books).ToList();
    }
    foreach (var student in lst)
        {
            WriteLine( $"[{student.Id}]*\n{student.Name} {student.Family}.\nmailto:{student.Email}.\nRegistered at'{student.RegisterDateTime}'");
            foreach (var book in student.Books)
                WriteLine($"\tBook name:{book.Name}, Book price:{book.Price}");
        }
    
    var lstViewModel = AutoMapper.Mapper.Map<IList<Student>, IList<AdminStudentViewModel>>(lst);
    foreach (var adminStudentViewModel in lstViewModel)
    {
        WriteLine(
            $"[{adminStudentViewModel.Id}]*\n\t{adminStudentViewModel.FirstName} {adminStudentViewModel.LastName}.\n\t" +
            $"mailto:{adminStudentViewModel.Email}.\n\tRegistered at'{adminStudentViewModel.RegisterDateTimePersian}'\n\t" +
            $"Book Counts: {adminStudentViewModel.BookCounts} with total price of {adminStudentViewModel.TotalBookPrice}");
    }
    WriteLine("Press any key to exit...");
    ReadKey();
}
ابتدا اسمبلی مربوط به ویوومدل‌ها را مشخص می‌کنیم. سپس این اسمبلی را جهت تبدیل ویژگی‌ها به نگاشت‌های معتبر automapper به متد Initialize ارسال می‌کنیم. تنها بکار بردن همین دوسطر برای اعمال تنظیم‌ها مورد نیاز می‌باشد. بعد از اجرای موفق متد Initialize، نگاشت‌های اشیاء آماده هستند.
نمونه‌ی خروجی:
[1]*
Morteza Raeisi.
mailto:MrRaeisi@outlook.com.
Registered at'23/08/1392 19:11:43'    // I'm using Windows 10 with Persian calendar as default, On other OS or calendar settings, this value is different.
        Book name:AutoMapper Attr, Book price:1000.00
        Book name:Second Book, Book price:2500.00
        Book name:Hungry Book, Book price:2500.00
...
[1]*
Morteza Raeisi. //MapForMemebers
mailto:.  // IgnoreMap
Registered at'1392/08/23 19:11' // Convert using
Book Counts: 3 with total price of 6000.00  // Value resolvers
...
دریافت کدها + مثال
نظرات مطالب
بررسی خطاهای ممکن در حین راه اندازی اولیه برنامه‌های ASP.NET Core در IIS

- رفع خطای اجرای برنامه در Windows 8.1 / Windows Server 2012 R2
The program can't start because api-ms-win-crt-runtime-l1-1-0.dll is missing from your computer. 
Try reinstalling the program to fix this problem.
KB2999226 را نصب کنید.

- رفع خطای اجرای برنامه در Windows 7 / Windows Server 2008 R2 
the library hostfxr.dll was found, but loading it from C:\<path_to_app>\hostfxr.dll failed
KB2533623 را نصب کنید.
مطالب
آشنایی با Window Function ها در SQL Server بخش پنجم
در این بخش فانکشن د‌یگری از توابع تحلیلی به نام CUME_DIST را بررسی می‌نماییم.
  •      CUME_DIST: 
      بوسیله تابع CUME_DIST می‌توان ارزیابی نمود، در یک گروه، چه درصد از مقادیر،مساوی یا کوچکتر از مقدار سطر جاری می‌باشند، به این تابع cumulative distribution نیز گفته می‌شود.
   Syntax تابع CUME_DIST به صورت زیر است:
CUME_DIST( )
    OVER ( [ partition_by_clause ] order_by_clause )
شرح Syntax:
1- Partition By Clause : بوسیله پارامتر فوق می‌توانید، نتیجه پرس جو (Query)،خود را دسته بندی نمایید.
2- order by clause : همانطور که از نامش مشخص است، جهت مرتب نمودن خروجی Query می‌باشد.
معمولا شرح عملکرد توابع تحلیلی، کمی مشکل است. بنابراین برای درک، عملکرد تابع CUME_DIST چند مثال را بررسی می‌کنیم.
در ابتدا بوسیله Script زیر یک جدول ایجاد و 10 رکورد در آن درج می‌کنیم:
Create Table TestCUME_DIST
(SalesOrderID int not null,
OrderQty smallint not null,
ProductID int not null
 );
 GO
Insert Into TestCUME_DIST
       Values (43663,1,760),(43667,3,710),(43667,1,773),
  (43667,1,775),(43667,1,778),(43669,1,747),
  (43670,1,709),(43670,2,710),(43670,2,773),(43670,1,776)

مثال اول: Script زیر را اجرا می‌کنیم، سپس خروجی آن را بررسی می‌نماییم:
SELECT SalesOrderID, OrderQty,
       CUME_DIST() OVER(ORDER BY SalesOrderID) AS [CUME_DIST]
FROM TestCUME_DIST ORDER BY [CUME_DIST] DESC
پس از اجرا خروجی بصورت زیر خواهد بود:

در ادامه اجازه دهید،مقادیری که در فیلد CUME_DIST بدست آمده است را بصورت تصویری بررسی کنیم.
مقادیر سطر اول تا چهارم:

*** برای بدست آوردن CUME_DIST سطر پنجم نیز خواهیم داشت:

Rows=(c1+c2)/c3 بنابراین خواهیم داشت: 0/6=10/(5+1)=Rows

مثال دوم : ابتدا Script زیر را اجرا نمایید:

SELECT SalesOrderID, OrderQty, ProductID,
       CUME_DIST() OVER(PARTITION BY SalesOrderID ORDER BY ProductID ) AS [CUME_DIST]
FROM TestCUME_DIST
WHERE SalesOrderID IN (43670, 43669, 43667, 43663)
ORDER BY SalesOrderID DESC, [CUME_DIST] DESC
خروجی : 

   همانگونه که ملاحظه می‌کنید، در این مثال، خروجی، براساس SalesOrderID به چهار گروه تقسیم می‌شود و عملیات مرتب سازی روی فیلد ProductID انجام  می گیرد، بنابراین CUME_DIST، روی هر گروه بر روی فیلد ProductID محاسبه می‌شود.

گروه اول : نحوه محاسبه Cume_DIST سطر اول:

سوال:چه تعداد از مقادیر ProductID آن برابر 776 میباشد؟

جواب: فقط مقدار سطر اول، بنابراین خواهیم داشت                   C1=1

سوال: چه تعداد از مقادیر کوچکتر از ProductID=776 می‌باشد؟

جواب: مقدار سه سطر، در واقع مقادیر سطر دوم،سوم و چهارم کوچکتر از مقدار سطر اول می‌باشند،                          c2=3

سوال: تعداد کل سطرهای گروه اول چه مقدار می‌باشد؟

جواب: 4سطر 

بنابراین برای بدست آوردن CUME_DIST سطر اول خواهیم داشت:

1=4/(1+3)=Rows 

محاسبه سطر دوم از گروه اول بدون شرح:

0/75=4/(1+2)=Rows  

امیدوارم مفید واقع شده باشد.

اشتراک‌ها
نگاهی به Docker ها در ویندوز سرور 2016
With the release of Technical Preview 3 (TP3) for Windows Server 2016, Microsoft for the first time have enabled native Containers under the Windows platform. Integrated with this is the Docker support for Windows Server, meaning you can run Docker containers in a Windows environment 
نگاهی به Docker ها در ویندوز سرور 2016
نظرات مطالب
معرفی و استفاده از DDL Triggers در SQL Server
باید از از حالت INSTEAD OF استفاده کنیم در DML Trigger ای که قراره نوشته بشه.
می‌توانیم در یک جدول از دیتابیس مان بر اساس یک شرط خاص, عملیات Insert,Delete,Update را مدیریت کنیم.
بعنوان مثال در قطعه کد زیر ما قبل از عملیات Insert در جدول tblTest چک میکنیم که اگر مقدار ستون FirstName برابر با null بود عملیات Insert آن رکورد در دیتابیس لغو شود.
ALTER TRIGGER [dbo].[Prevent_Befor_Insert_Null]
   ON  [dbTest].[dbo].[tblTest] 
   INSTEAD OF INSERT 
AS 
BEGIN
SET NOCOUNT ON
IF OBJECT_ID(N'dbTest.dbo.tblTest.FirstName') is null
BEGIN
DECLARE @Id int
SET @Id = (select Id from inserted)
RAISERROR ('مقدار فیلد نام نباید خالی باشد',16,1)
ROLLBACK
END
END

از دو طریق می‌توان به مقادیر فیلدهای رکورد جاری دسترس داشت:
1- استفاده از OBJECT_ID و ذکر نام فیلد مورد نظر
2- گرفتن فیلد مورد نظر از جدول INSERTED یا DELETED
DML Trigger‌ها دارای دو جدول خاص بنام‌های INSERTED و DELETED هستند که توسط خود SQL Server مدیریت می‌شوند.در حقیقت در پشت صحنه, ما با این دو جدول در هنگام تغییر مقادیر داده‌های جداول دیتابیس کار می‌کنیم و نمی‌توانیم بصورت مستقیم داده‌های جداول موجود در دیتا بیس مان را تغییر دهیم.
جدول INSERTED و DELETED حاوی رکورد جاری است که تحت تاثیر عمل درج, ویرایش و حذف در دیتابیس قرار گرفته است.
اطلاعات بیشتر در اینجا و اینجا
اشتراک‌ها
دوره 3 ساعته PostgreSQL

PostgreSQL Tutorial Full Course 2022

I provide here in this PostgreSQL tutorial a full course you can use to master PostgreSQL. Postgres is an object relational database that is just as fast as MySQL that adheres more closely to SQL standards and excels at concurrency. Postgres is also superior at avoiding data corruption.

TABLE OF CONTENTS
00:00 Intro
00:30 Why Use Postgres?
01:13 What is a Database
03:12 Change Database Theme
03:53 Create a Database
04:46 Design a Database
05:50 Turn Invoice into a Database
07:04 Make a Table
12:13 Data Types
16:36 Adding Data to Table
18:15 To See Data
18:25 SELECT
19:19 Create Custom Type
20:48 Change Column Data Type
22:58 Thinking About Tables
25:37 Breaking Up Tables
27:03  Primary & Foreign Keys
32:40 Foreign & Primary Keys
33:28 Altering Tables Many Examples
53:00 Getting Data from One Table
53:40 Where
54:30 Conditional Operators
55:48 Logical Operators
58:12 Order By
59:32 Limit
1:01:45 GROUP BY
1:03:11 Distinct
1:05:00 Getting Data from Multiple Tables
1:05:21 Inner Join
1:08:50 Join 3 Tables
1:13:15  Arithmetic Operators
1:13:45 Join with Where
1:14:55 Outer Joins
1:17:03 Cross Joins
1:18:16 Unions
1:19:27 Extract
1:21:05 IS NULL
1:22:03 SIMILAR LIKE & ~
1:29:25 GROUP BY
1:31:14  HAVING
1:32:18  AGGREGATE FUNCTIONS
1:34:22 WORKING WITH VIEWS
1:45:01 SQL Functions
1:49:00 Dollar Quotes
1:50:06 Functions that Return Void
1:52:38 Get Maximum Product Price
1:53:39 Get Total Value of Inventory
1:54:26 Get Number of Customers
1:56:15 Named Parameters
2:01:30 Return a Row / Composite
2:03:38 Get Multiple Rows
2:07:08 PL/pgSQL
2:11:35 Variables in Functions
2:15:55 Store Rows in Variables
2:19:17 IN INOUT and OUT
2:21:01 Using Multiple Outs
2:25:56 Return Query Results
2:33:42 IF ELSEIF and ELSE
2:38:48  CASE Statement
2:42:01 Loop Statement
2:45:20 FOR LOOP
2:48:34 Result Sets, Blocks & Raise Notice
2:51:11 For Each and Arrays
2:53:20 While Loop
2:54:54 Continue
3:01:34 Stored Procedures
3:09:35 Triggers
3:29:25 Cursors
3:39:45 Installation 

دوره 3 ساعته PostgreSQL
مطالب
زیرنویس فارسی ویدئوهای مقدمات AngularJS - قسمت سوم
زیرنویس‌های فارسی قسمت سوم را اینجا می‌توانید دریافت کنید.
لیست سرفصل‌های قسمت سوم به شرح زیر است :
01. Introduction to Services
02. Demo - Creating Your First Custom Service
03. Demo - Another Custom Service Example
04. Introduction to Built-In AngularJS Services
05. Demo - Using the $http and $q Services Together
06. Demo - Using the $rsource and $q Services
07. Demo - Using the $anchorScroll Service
08. Demo - Using the $cacheFactory Service
09. Demo - Using the $compile Service
10. Demo - Using the $parse Service
11. Demo - Using the $locale Service
12. Demo - Using the $timeout Service
13. Demo - Using the $exceptionHandler Service
14. Demo - Using the $filter Service
15. Demo - Using the $cookieStore Service
16. Overview of Less Common Services
17. Suggested Exercises
این قسمت به ساخت سرویس‌های سفارشی و همچنین چگونگی استفاده از سرویس‌های توکار انگولار می‌پردازد؛ در این قسمت تقریباً تمامی سرویس‌های موردنیاز جهت توسعه یک برنامه مبتنی بر انگولار شرح داده می‌شود. همچنین در آن به صورت عملی با سرویس‌ها آشنا می‌شوید و هر سرویسی که معرفی میشود مثال مربوط به آن ارائه شده است. به طور مثال در قسمت پیاده سازی سرویس‌های سفارشی مثال نمایش Gravatar با وارد کردن آدرس ایمیل کاربر مطرح می‌شود که در ادامه کد آن را مشاهده میکنید :
'use strict';

eventsApp.factory('gravatarUrlBuilder', function() {
return {
buildGravatarUrl: function(email) {
        // try angularjsdemo@gmail.com as an email
            var defaultGravatarUrl = "http://www.gravatar.com/avatar/000?s=200";

            var regex = /^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
            if (!regex.test(email))
                return defaultGravatarUrl;

            var MD5=function(s){function L(k,d){return(k<<d)|(k>>>(32-d))}function K(G,k){var I,d,F,H,x;F=(G&2147483648);H=(k&2147483648);I=(G&1073741824);d=(k&1073741824);x=(G&1073741823)+(k&1073741823);if(I&d){return(x^2147483648^F^H)}if(I|d){if(x&1073741824){return(x^3221225472^F^H)}else{return(x^1073741824^F^H)}}else{return(x^F^H)}}function r(d,F,k){return(d&F)|((~d)&k)}function q(d,F,k){return(d&k)|(F&(~k))}function p(d,F,k){return(d^F^k)}function n(d,F,k){return(F^(d|(~k)))}function u(G,F,aa,Z,k,H,I){G=K(G,K(K(r(F,aa,Z),k),I));return K(L(G,H),F)}function f(G,F,aa,Z,k,H,I){G=K(G,K(K(q(F,aa,Z),k),I));return K(L(G,H),F)}function D(G,F,aa,Z,k,H,I){G=K(G,K(K(p(F,aa,Z),k),I));return K(L(G,H),F)}function t(G,F,aa,Z,k,H,I){G=K(G,K(K(n(F,aa,Z),k),I));return K(L(G,H),F)}function e(G){var Z;var F=G.length;var x=F+8;var k=(x-(x%64))/64;var I=(k+1)*16;var aa=Array(I-1);var d=0;var H=0;while(H<F){Z=(H-(H%4))/4;d=(H%4)*8;aa[Z]=(aa[Z]|(G.charCodeAt(H)<<d));H++}Z=(H-(H%4))/4;d=(H%4)*8;aa[Z]=aa[Z]|(128<<d);aa[I-2]=F<<3;aa[I-1]=F>>>29;return aa}function B(x){var k="",F="",G,d;for(d=0;d<=3;d++){G=(x>>>(d*8))&255;F="0"+G.toString(16);k=k+F.substr(F.length-2,2)}return k}function J(k){k=k.replace(/rn/g,"n");var d="";for(var F=0;F<k.length;F++){var x=k.charCodeAt(F);if(x<128){d+=String.fromCharCode(x)}else{if((x>127)&&(x<2048)){d+=String.fromCharCode((x>>6)|192);d+=String.fromCharCode((x&63)|128)}else{d+=String.fromCharCode((x>>12)|224);d+=String.fromCharCode(((x>>6)&63)|128);d+=String.fromCharCode((x&63)|128)}}}return d}var C=Array();var P,h,E,v,g,Y,X,W,V;var S=7,Q=12,N=17,M=22;var A=5,z=9,y=14,w=20;var o=4,m=11,l=16,j=23;var U=6,T=10,R=15,O=21;s=J(s);C=e(s);Y=1732584193;X=4023233417;W=2562383102;V=271733878;for(P=0;P<C.length;P+=16){h=Y;E=X;v=W;g=V;Y=u(Y,X,W,V,C[P+0],S,3614090360);V=u(V,Y,X,W,C[P+1],Q,3905402710);W=u(W,V,Y,X,C[P+2],N,606105819);X=u(X,W,V,Y,C[P+3],M,3250441966);Y=u(Y,X,W,V,C[P+4],S,4118548399);V=u(V,Y,X,W,C[P+5],Q,1200080426);W=u(W,V,Y,X,C[P+6],N,2821735955);X=u(X,W,V,Y,C[P+7],M,4249261313);Y=u(Y,X,W,V,C[P+8],S,1770035416);V=u(V,Y,X,W,C[P+9],Q,2336552879);W=u(W,V,Y,X,C[P+10],N,4294925233);X=u(X,W,V,Y,C[P+11],M,2304563134);Y=u(Y,X,W,V,C[P+12],S,1804603682);V=u(V,Y,X,W,C[P+13],Q,4254626195);W=u(W,V,Y,X,C[P+14],N,2792965006);X=u(X,W,V,Y,C[P+15],M,1236535329);Y=f(Y,X,W,V,C[P+1],A,4129170786);V=f(V,Y,X,W,C[P+6],z,3225465664);W=f(W,V,Y,X,C[P+11],y,643717713);X=f(X,W,V,Y,C[P+0],w,3921069994);Y=f(Y,X,W,V,C[P+5],A,3593408605);V=f(V,Y,X,W,C[P+10],z,38016083);W=f(W,V,Y,X,C[P+15],y,3634488961);X=f(X,W,V,Y,C[P+4],w,3889429448);Y=f(Y,X,W,V,C[P+9],A,568446438);V=f(V,Y,X,W,C[P+14],z,3275163606);W=f(W,V,Y,X,C[P+3],y,4107603335);X=f(X,W,V,Y,C[P+8],w,1163531501);Y=f(Y,X,W,V,C[P+13],A,2850285829);V=f(V,Y,X,W,C[P+2],z,4243563512);W=f(W,V,Y,X,C[P+7],y,1735328473);X=f(X,W,V,Y,C[P+12],w,2368359562);Y=D(Y,X,W,V,C[P+5],o,4294588738);V=D(V,Y,X,W,C[P+8],m,2272392833);W=D(W,V,Y,X,C[P+11],l,1839030562);X=D(X,W,V,Y,C[P+14],j,4259657740);Y=D(Y,X,W,V,C[P+1],o,2763975236);V=D(V,Y,X,W,C[P+4],m,1272893353);W=D(W,V,Y,X,C[P+7],l,4139469664);X=D(X,W,V,Y,C[P+10],j,3200236656);Y=D(Y,X,W,V,C[P+13],o,681279174);V=D(V,Y,X,W,C[P+0],m,3936430074);W=D(W,V,Y,X,C[P+3],l,3572445317);X=D(X,W,V,Y,C[P+6],j,76029189);Y=D(Y,X,W,V,C[P+9],o,3654602809);V=D(V,Y,X,W,C[P+12],m,3873151461);W=D(W,V,Y,X,C[P+15],l,530742520);X=D(X,W,V,Y,C[P+2],j,3299628645);Y=t(Y,X,W,V,C[P+0],U,4096336452);V=t(V,Y,X,W,C[P+7],T,1126891415);W=t(W,V,Y,X,C[P+14],R,2878612391);X=t(X,W,V,Y,C[P+5],O,4237533241);Y=t(Y,X,W,V,C[P+12],U,1700485571);V=t(V,Y,X,W,C[P+3],T,2399980690);W=t(W,V,Y,X,C[P+10],R,4293915773);X=t(X,W,V,Y,C[P+1],O,2240044497);Y=t(Y,X,W,V,C[P+8],U,1873313359);V=t(V,Y,X,W,C[P+15],T,4264355552);W=t(W,V,Y,X,C[P+6],R,2734768916);X=t(X,W,V,Y,C[P+13],O,1309151649);Y=t(Y,X,W,V,C[P+4],U,4149444226);V=t(V,Y,X,W,C[P+11],T,3174756917);W=t(W,V,Y,X,C[P+2],R,718787259);X=t(X,W,V,Y,C[P+9],O,3951481745);Y=K(Y,h);X=K(X,E);W=K(W,v);V=K(V,g)}var i=B(Y)+B(X)+B(W)+B(V);return i.toLowerCase()};

            var url = 'http://www.gravatar.com/avatar/' + MD5(email) + ".jpg?s=200&r=g";
            console.log(url);
            return url;
        }
};
});
اگر زیرنویس‌ها دارای اشکال هستند می‌توانید در این قسمت فایل‌های اصلاح شده را مجدداً آپلود کنید.