Бөлісу құралы:


Chapter 1: Introduction

Getting Started - Prerequisites, System Requirements, Downloading and Installation | Spectrum of Web Applications | Characteristics of Modern Web Applications | Considerations for Building Modern Web Applications - Team Skills, Technologies, Ajax, JavaScript, jQuery, Modernizr, ASP.NET MVC Razor, Dependency Injection | Exploring This Guidance - Exploring the Mileage Stats Reference Implementation, Using Mileage Stats, Exploring the QuickStart, Exploring the Documentation | Community | Further Reading

Project Silk provides guidance for building maintainable cross-browser web applications that are characterized by an intentional design, rich interactivity, and a responsive user interface (UI), resulting in an immersive and engaging user experience (UX). Such applications take advantage of the latest web standards, including HTML5, CSS3, and ECMAScript version 5, and modern web technologies such as jQuery and ASP.NET MVC3.

An intentional design indicates that deliberate attention was paid to the modularity of the JavaScript code, and the usability of the application was an explicit focus. Under the direction of the team's web designer, UI and UX concerns received special attention, and this guidance aims to help you be successful addressing these concerns in your own applications. Modularity is important when building highly interactive web applications because they often require a significant amount of JavaScript code. This guidance aims to help you understand how to write maintainable JavaScript code that reaps the many benefits of a modular design.

Project Silk also illustrates how you can take advantage of the fast JavaScript engines of the modern, standards-based web browsers to achieve a user experience and execution speeds that rival desktop applications. Windows® Internet Explorer® 9 further enriches the user experience by taking advantage of integration with the operating system and hardware-accelerated graphics processing.

The concepts explained in the Project Silk written guidance are demonstrated via a real-world customer-facing web application called the Mileage Stats Reference Implementation (Mileage Stats). Mileage Stats allows users to track and compare their vehicles' fuel efficiency, usage, and operating costs, and to schedule vehicle maintenance reminders.

Getting Started

This section describes how to install and start exploring the Project Silk guidance. You can download Project Silk from MSDN®.

Prerequisites

This guidance is intended for web developers and assumes you have some hands-on experience with ASP.NET MVC, CSS, HTML, JavaScript, and jQuery. Mileage Stats relies heavily on a few important JavaScript and jQuery concepts that you need to understand. They include:

  • JavaScript: Object literals, immediate functions, closures, object prototypes, scoping rules, use of the this keyword
  • jQuery: Selectors, wrapped sets, chaining

If you are not familiar with these concepts or have not used them in your own projects, see the "Further Reading" section at the end of this chapter for more information on these topics.

System Requirements

Mileage Stats was designed to run and was fully tested on Microsoft Windows® 7 and Windows Server® 2008 operating systems. In addition, it has been smoke tested on Windows Vista® and Windows XP but not exhaustively tested.

Before you can compile and run Mileage Stats, the following must be installed:

Downloading and Installation

Project Silk includes the written guidance you're reading now and the source code for both the Mileage Stats Reference Implementation and Widget QuickStart. To download and install, simply follow these steps:

  1. Download Project Silk from the Microsoft Download Center.
  2. To extract the download, run the .exe file. This will extract the source code and documentation into the folder of your choice.
  3. Read the Readme file included with the source code, which contains instructions on installing external dependencies from NuGet and downloading the required external JavaScript libraries.

Spectrum of Web Applications

There is a spectrum of web applications being built today that can be grouped into four application types. These types of web applications are categorized by their full-page reload behavior and the amount of client-side interactivity they provide. Each application type provides a richer experience than the one listed before it.

  • Staticsites. These consist of static HTML pages, CSS, and images. They are static in that as each page is navigated to, the browser performs a full-page reload and there is no interaction with portions of the page. In addition, the page does not change no matter who requests it or when.
  • Server rendered. In this model, the server dynamically assembles the pages from one or more source files and can incorporate data from another source during the rendering. The client-side script in these applications might perform some data validation, simple hover effects, or Ajax calls. As each page is navigated to, the browser performs a full-page reload. ASP.NET applications that don't make heavy use of client-side JavaScript are examples of server-rendered web applications.
  • Hybrid design. This model is similar to the server-rendered web application, except that it relies heavily on client-side JavaScript to deliver an engaging experience. This type of application has islands of interactivity within the site that do not require full-page reloads to change the UI as well as some pages that do require a full-page reload. Mileage Stats is an example of a hybrid design.
  • Single-page interface. In this model, a full-page load happens only once. From that point on, all page changes and data loading is performed without a full-page reload. Hotmail, Office Live, and Twitter are examples of single-page-interface web applications.

Characteristics of Modern Web Applications

While there are many types of modern web applications, addressing many different needs, they all have some characteristics in common.

  • They are standards-focused. To have the broadest reach across multiple platforms and devices, applications attempt to implement the current and evolving standards and adopt future standards once ratified.
  • They are interactive. Modern web applications keep the user engaged by providing constant feedback on their actions. This feedback can come in the form of messages, animations to hide or show elements, mouse-over effects, drag and drop feedback, the automatic refreshing of screen data, animation of various elements, or the implementation of fade-in or fade-out effects. Interactive applications leverage the fast JavaScript engines in modern browsers to perform their client-side tasks.
  • They limit full-page reloads. Modern web applications seek to limit the number of full-page reloads. Reloads are much slower than a localized Ajax call to update a portion of the UI. Full-page reloads also limit the ability to animate state or page changes. By not performing a full-page reload, users can be kept in context, providing a fluid experience as they navigate from one task to another.
  • They are asynchronous. Modern web applications use Ajax to dynamically load data, page fragments, or other assets instead of performing a full-page reload to acquire data or HTML content. Because the loading of data is asynchronous, the UI is able to stay responsive and keep the user informed while the data request is being fulfilled. This asynchronous on-demand loading also reduces application response time because requests can be tuned to return only the data and other content that needs to change.
  • They manage data. When applicable, modern web applications provide client-side data caching and prefetching to boost client-side performance. This enables the UI to immediately respond to user input gestures because it does not have to make a call to the server for data. Data caching also serves to minimize the impact on server resources, increasing application scalability because fewer calls to the server are required.

Considerations for Building Modern Web Applications

Building a rich modern web application can be rewarding and fun. For developers or web software firms that have typically delivered server-centric applications, possibly with small amounts of JavaScript, embarking on a modern web application project will involve a paradigm change that should not be minimized or overlooked.

In the next two sections we will examine the skill sets a project team will need and the technologies used when building a modern web application.

Team Skills

Developing modern web applications requires a broad range of skills. Depending on your application requirements, your team will need expertise provided by people in the following roles:

  • Designer roles. These will be responsible for user experience, user interface, and graphics.
  • Client-side developer roles. These will bring programming expertise in the areas of user interface, user interaction, and test.
  • Server-side developer roles. These will have programming expertise in the areas of web pages, business objects and logic, databases, and test.

The composition of the web project team will vary from project to project based on the application's requirements and the team's resources. For example, on a large project, each of the roles above would probably be filled by a different person or possibly a team. On a small project, team members will likely fill multiple roles with augmentation from consultants as required to fill in the gaps.

On Project Silk, all of the above roles were filled by a lead developer, web designer, server-side developer, and two client-side developers. Project Silk also had a test team that consisted of a test manager, test program manager, and two software test engineers. The test team was responsible for testing browser compatibility, deployment testing, performance testing, stress testing, and security testing. To accomplish this, the test team set up a lab with servers running Windows Server® 2008, each with different configurations, and client computers configured with different operating systems and browsers. These systems were then used to perform daily automated and manual tests.

Technologies

This section will familiarize you with technologies and patterns used in building Mileage Stats. If any of these are new to you, please review the resources in the "Further Reading" section so you will get the most from the guidance and will be able to understand the Mileage Stats JavaScript, HTML5, CSS3, and C# code. This section does not intend to convey all of the important concepts you must know. Rather, you should consider it a list of indicators you may need to research further before building an application such as Mileage Stats.

Ajax

For over 10 years, the web has benefited from the ability to replace full-page reloads with Ajax calls. But given the advances in standards such as CSS3 and HTML5, browsers adherence to those standards, and the arrival of powerful, cross-browser JavaScript frameworks, we have all the tools necessary to build highly engaging client-side experiences.

Ajax facilitates a paradigm change in web development from the traditional full-page reload model of server-centric applications to rich, responsive client-centric applications. The client receives data and updates the UI using JavaScript. Bandwidth requirements are minimized because the server responds to requests by returning just the requested data instead of HTML pages (and all their elements) along with the data. The application runs faster because the data requests take less time to complete, and the UI is quickly updated without a full-page reload. Asynchronous calls are essential to keeping interactive and immersive applications responsive from the user's perspective.

JavaScript

JavaScript is a dynamic, functional, prototypal language that has a very close relationship with the document object model (DOM). For both JavaScript and the DOM, there are features you can use with confidence and others you should avoid. Over the past ten years, the web development community has learned a great deal about how to use these together to maximize success. See the "Further Reading" section for resources that explain the recommended ways of using JavaScript. Project Silk adheres to these practices, but we do not present a primer here.

As is true with all environments, you will be most successful using it as intended. If you aren't presently writing JavaScript code according to the patterns currently accepted in the JavaScript community, be sure your team has time to become familiar with them, because you may be surprised. For example, the Project Silk team members who had recently worked in the Microsoft .NET environment needed to ramp up on the following aspects of JavaScript:

  • JavaScript uses object-oriented concepts, but classes and inheritance hierarchies are not the same as in other .NET languages such as Visual C# and Visual Basic.NET.
  • Understanding closures and variable scoping is important. They are used intentionally and often by allowing variables defined within one scope to be used in another function.
  • The object that the this keyword refers to changes based on where it is used. For example in a single method, this may refer to the object the method is defined on, and in a loop within that same method this may refer to the current item of the collection being iterated over. You should understand its rules.
  • Objects without type definitions are very common and use an object literal syntax. The commas between properties and functions used in these object literals may cause syntax errors until you are familiar with them.

jQuery

jQuery is an open-source JavaScript library that addresses the challenges of working with the DOM across browsers. It has a straightforward API that can be divided into two calling conventions:

  • Functions are called on the jQuery object itself. For example, the extend function merges the properties and methods of two different objects together. It looks like this: $.extend(targetObject, objectToMerge).
  • Methods are called on the wrapped set. A wrapped set is the result of a query that uses a selector to find elements in the DOM. To call a method on a wrapped set of elements, a selector is used to select elements in the DOM. For example, to add the listing CSS class to all ul elements directly inside a div element, $('div ul').addClass('listing') can be used.

jQuery also provides features to raise and handle events, make Ajax requests, and process the data returned from Ajax requests. To be successful developing with jQuery, you should:

  • Know that the selector syntax uses and extends the CSS selector syntax. The better you're able to leverage this syntax, the cleaner your HTML can be.
  • Understand what the wrapped set is, how it's different from an array of DOM elements, and which you're working with at any given time. For example, when using $.each, inside the callback, this is not wrapped.
  • Understand that animations are asynchronous and are queued. Use a named queue or the stop method to gain more control over how the animations behave.

Modernizr

In the past, the client-side application would use navigator.userAgent to determine which browser was in use and choose its code paths accordingly. Today, the accepted practice is to explicitly detect each feature the application intends to use.

Modernizr is an open-source JavaScript library that detects the support for browser features (geolocation, canvas, SVG, border-radius, etc.) and exposes its findings in CSS and JavaScript. Once a script reference to Modernizr is included, Modernizr will add a CSS class to the html element for each feature it can detect. If the feature isn't supported, the CSS class will start with no-. For example, if a browser supports canvas and not webgl, its html element will look like this: <html class="canvas no-webgl ...">. Modernizr also exposes a Modernizr JavaScript object that has Boolean properties for each feature it can detect.

ASP.NET MVC Razor

Razor is the name of one of the view engines in ASP.NET MVC 3 (WebForms is the other). The razor view engine is used to render MVC views, which are comprised of HTML and server-side code.

The Razor syntax is clean and concise, and easy to learn, and Visual Studio includes IntelliSense® and syntax highlighting for Razor syntax.

For a more detailed overview of Razor, see "ASP.NET MVC 3 Overview, The Razor View Engine" in the "Further Reading" section.

Dependency Injection

Dependency injection is a variant of the Inversion of Control design pattern. Dependency injection containers reduce the dependency coupling between objects by providing a facility to instantiate instances of classes and manage their lifetimes based on the configuration of the container. During the creation of objects, the container injects into the object any dependencies the object requires. If those dependencies have not yet been created, the container creates and resolves their dependencies first.

Dependency injection provides several benefits:

  • Reduced coupling; classes and components don't have to locate dependencies or manage their lifetimes.
  • Improved testability; dependencies can be easily substituted with mocked implementations.
  • Improvedflexibility and maintainability; dependencies can be replaced easily.

ASP.NET MVC 3 provides better support for applying dependency injection and for integrating with dependency injection or inversion of control containers. For more information about dependency injection in ASP.NET MVC 3, see "ASP.NET MVC 3 Overview, Dependency Injection Improvements" in the "Further Reading" section. For an introduction to dependency injection and inversion of control, see "Loosen Up: Tame Your Software Dependencies for More Flexible Apps" in MSDN Magazine.

Exploring This Guidance

The purpose of this guidance is to show you how to plan, design, and build a rich, interactive web application your users will enjoy using. This guidance includes the following resources:

  • Mileage Stats Reference Implementation. Comprehensive sample application demonstrating a real-world, interactive, cross-browser, consumer-facing, rich web application. The reference implementation is intentionally incomplete, but does illustrate the core concepts, design patterns, coding patterns, security requirements, web technologies, and unit testing necessary to be successful.
  • Widget QuickStart. Small sample application that demonstrates how to use and develop jQuery UI Widgets.
  • Documentation. This guidance provides an architectural overview of rich web applications and chapters that cover the design, concepts, patterns, security, testing, and implementation of Mileage Stats. This guidance also includes documentation that covers the Widget QuickStart and How-to topics on automated testing.

Exploring the Mileage Stats Reference Implementation

Mileage Stats is an ASP.NET MVC application that enables users to track and compare various metrics about their vehicles including fuel consumption, fuel costs, miles driven, and maintenance reminders. The application is a multi-page interactive web application where the pages are rendered without requiring a full-page reload. The lack of full-page reloads enables rich UI transitions between states (pages) and the application runs fast because of the client-side data caching and some data prefetching.

Much of the effort in building Mileage Stats was applied to the usability and rich interactivity of the experience. Animations were included to enhance the enjoyment of the site and Ajax is used to keep the interface responsive and immersive. A great deal of care was also taken to ensure that the client-side JavaScript was modularized for maintainability. To accomplish these design goals, the JavaScript code was structured using jQuery UI Widgets and JavaScript objects. Widgets allow you to break the UI into discrete stateful objects that provide a clean separation of responsibilities and concerns.

The Mileage Stats solution is partitioned into three layers: data, business, and web, spread across five Visual Studio projects pictured on the left side of the image below. Mileage Stats also includes four unit test projects for testing the C# projects, and a suite of JavaScript unit tests, pictured on the right side of the image below.

Mileage Stats project and unit tests

Hh404096.3ef620a0-9677-4546-94f8-13233fbc30ab(en-us,PandP.10).png

The design and implementation of the Mileage Stats solution is used for illustration throughout the guidance and will be covered in the remaining chapters. Now let's walk through Mileage Stats from a user's perspective.

Using Mileage Stats

Unauthenticated users accessing Mileage Stats will be redirected to the landing page to sign in. Mileage Stats uses third-party OpenID providers for user authentication. Mileage Stats supports deep linking, so that previously authenticated users returning to the website can go directly to any page.

For Internet Explorer 9 users, Mileage Stats provides a customized pinned sites experience that is accessed from the landing page. The image below shows the pinned site running in the pinned sites customized chrome of Internet Explorer 9. The menu, favorites bar, command bar, and status bar have been removed from view. The back and forward buttons are rendered with a custom color, and the site's favicon is displayed to the left of the back button, which navigates to the landing page.

Landing page

Hh404096.8196d566-efd1-4de3-9ed8-5d21669fd4d0(en-us,PandP.10).png

The first time a new user logs into Mileage Stats, the summary pane will display the "Complete your Registration" form pictured below. This form will continue to be displayed in the Summary pane until the user clicks the Save button. Further edits to the user's profile can be made by clicking the Profile link at the top right of the browser window.

Third-party authentication providers do not uniformly expose their user data to applications requesting authentication services. For example, a user may have an OpenID account, but Mileage Stats may not be able to request information such as the user's first and last name from the provider to populate the Display Name field. The UX designer did not want to force a new user to complete a form in order to use Mileage Stats. Instead, we implemented a non-intrusive form for collecting the new user's name, country, and postal code. New users can immediately use Mileage Stats and can complete the registration information at their leisure.

First time logging in

Hh404096.74752ccb-920a-4929-9faa-9e65a343b23d(en-us,PandP.10).png

The dashboard provides a summary view of the user's vehicles. From here the user can add a new vehicle, drill down to more detail for a vehicle, and see maintenance reminders that are overdue or due soon. There is a navigation bar at the top of the browser window that provides top-level navigation to the Dashboard, Charts, or Profile pages and a link to sign out of the application.

Dashboard

Hh404096.0cbc46d5-61fd-4453-9a14-4e581497b113(en-us,PandP.10).png

A high-value scenario for this guidance was to demonstrate fluid and rich UI transitions and animations. The image below shows the application transitioning from the Dashboard (two column vehicle listing) to the Details view (single column vehicle listing) in response to the user clicking the Details button in Hot Rod's vehicle tile. The image demonstrates the synchronization of opacity and position animations as the summary pane, vehicle tiles, and info pane animate into their respective positions.

Transitioning from the Dashboard to Details

Hh404096.24e1c556-dbc2-407a-acc4-d2f9d1b22095(en-us,PandP.10).png

The Details view displays aggregated monthly trends for fuel efficiency, distance traveled, and fuel cost. Users are able to quickly see trends in their vehicle usage as well as overdue maintenance reminders. In addition to displaying maintenance reminders, the Details view allows users to edit or delete the vehicle, as well as navigate to the Fill ups and Reminders views.

Details

Hh404096.3684cc9b-59f1-4679-85b3-58e14ac02ae7(en-us,PandP.10).png

The Charts page provides three charts, which allow users to easily compare their vehicles' fuel efficiency, distance travelled, and cost. The displayed data can be filtered by vehicle and date range. The data displayed in these charts is prefetched and cached, providing a fast user experience.

Charts

Hh404096.5608da0e-243d-4f32-a913-657fc0e2a5f2(en-us,PandP.10).png

Exploring the QuickStart

The Widget QuickStart is a small, focused application that illustrates the way Mileage Stats uses the jQuery UI Widget Factory to create maintainable widgets that implement client-side behavior.

Exploring the Documentation

This guidance covers a wide range of topics, including: planning and designing your application, understanding and writing jQuery UI Widgets, writing server-side code that supports the client-side application, patterns and concepts used in JavaScript code, data and caching, and securing and testing your application.

The documentation includes the following:

  • Chapter 2, "Architecture." This chapter explains the Mileage Stats client-side architecture by studying how its structure, modularity, communication, navigation, and data relate to one another.
  • Chapter 3, "jQuery UI Widgets." An understanding of jQuery UI Widgets is important to comprehending this guidance and Mileage Stats because the application makes heavy use of widgets to modularize its JavaScript. This chapter provides instruction on widget fundamentals, lifetime, creation, events, properties and methods, and inheritance. It largely uses code examples from the Widget QuickStart.
  • Chapter 4, "Design and Layout." This chapter explains the importance of an iterative design process and the roles different team members fulfill. After a survey of user experience and UI design considerations, we will walk through the design and building of Mileage Stats and see how these considerations influenced the application.
  • Chapter 5, "Modularity." Rich and interactive web applications can require a fair amount of JavaScript coding. Modularizing your JavaScript makes your code easier to maintain and evolve. In this chapter we will explain how the Mileage Stats JavaScript was modularized using jQuery UI Widgets and JavaScript objects.
  • Chapter 6, "Client Data Management and Caching." This chapter covers how JavaScript objects in Mileage Stats request and send data. It also covers how the data manager façade performs the Ajax calls to the server and provides transparent data caching.
  • Chapter 7, "Manipulating Client-Side HTML." This chapter discusses how an interactive application like Mileage Stats can manage client-side HTML changes without having to fully reload the page each time the user navigates or completes a task.
  • Chapter 8, "Communication." This chapter explains how communication between widgets and JavaScript objects was implemented in Mileage Stats. Some topics include loosely coupled communication that uses the "publish and subscribe" metaphor, events, and inter-widget communication.
  • Chapter 9, "Navigation." Rich web applications support client-side transitions, animations, and deep linking. Even when the site avoids the use of full-page refreshes, users expect their browser back button to function as expected. This chapter explains the challenges client-side web developers face maintaining the browser history when using Ajax calls instead of full-page reloads. In addition, the Mileage Stats state-change management is fully explained.
  • Chapter 10, "Application Notifications." Web applications that users consider responsive have one thing in common: they provide appropriate and timely feedback to the user. In this chapter we show how to provide unobtrusive feedback to the user and how to implement notifications on the desktop with the Internet Explorer 9 Pinned Sites API.
  • Chapter 11, "Server-Side Implementation." This chapter covers the Mileage Stats ASP.NET MVC application, the components it's dependent upon, and the services they provide to support the client-side JavaScript objects. The chapter takes you from the database, through the repositories, to the business objects that provide data validation and data shaping services to the controllers that consume their data and render it to the client.
  • Chapter 12, "Security." Web security is critical to consumer confidence. Poor security can cause your customer's data, your own data, or your intellectual property to be compromised. This chapter covers some of the security features of the ASP.NET MVC platform and security features in Mileage Stats that provide countermeasures against the relevant threats for authentication, input validation, anti-forgery, and JavaScript Object Notation (JSON) hijacking.
  • Chapter 13, "Unit Testing Web Applications." Unit tests are long-term investments that give the development team confidence when refactoring or evolving the application, and when updating external dependencies, such as when versions of external libraries are updated. This chapter is meant to help you get started unit testing JavaScript and ASP.NET MVC code.
  • Chapter 14, "Widget QuickStart." This topic describes the Widget QuickStart and includes information on attaching widgets, widget initialization, and widget interactions.
  • "How to: Check UIElement Properties Using Coded UI Test." This How-to topic walks you through the creation of an automated test that checks that UIElement properties in Mileage Stats are displayed with the correct values. It uses Coded UI Test that is available in Visual Studio 2010 Premium or Ultimate Edition.
  • "How to: Create an Automated Negative Test Case Using Coded UI Test." This How-to topic walks you through the creation of an automated negative test case that checks the error handling capability of Mileage Stats. It uses Coded UI Test that is available in Visual Studio 2010 Premium or Ultimate Edition.
  • "How to: Create a Web Client UI Test Using Coded UI Test." This How-to topic walks you through the creation of an automated test that verifies that the correct controls are displayed with the correct values. It uses Coded UI Test that is available in Visual Studio 2010 Premium or Ultimate Edition.
  • "Project Silk Road Map." This list helps you locate sections of the guidance by topic.
  • "Glossary." This topic provides a summary of the terms, concepts, and technologies used in this guidance.
  • "Bibliography." This is a summary of the resources referred to in the guidance.

Community

Project Silk's community site is https://silk.codeplex.com. There, you can post questions, provide feedback, or connect with other users to share ideas. Community members can also help Microsoft plan and test future offerings. In addition, the community site has links to tutorial videos, MSDN content, and the Readme file.

Further Reading

For information on the designer role, see Chapter 4, "Design and Layout."

For information on unit testing, see Chapter 13, "Unit Testing Web Applications."

Crockford, Douglas. JavaScript: The Good Parts. O'Reilly Media, 2008.

Stefanov, Stoyan. JavaScript Patterns. O'Reilly Media, 2010.

"ASP.NET MVC 3 Overview, The Razor View Engine" on ASP.NET:
https://www.asp.net/mvc/mvc3#BM_The_Razor_View_Engine

"ASP.NET MVC 3 Overview, Dependency Injection Improvements" on ASP.NET:
https://www.asp.net/mvc/mvc3#BM_Dependency_Injection_Improvements

"Loosen Up: Tame Your Software Dependencies for More Flexible Apps" in MSDN Magazine:
https://msdn.microsoft.com/en-us/magazine/cc337885.aspx

"Entity Framework 4.1 Released" on the ADO.NET team blog:
https://blogs.msdn.com/b/adonet/archive/2011/04/11/ef-4-1-released.aspx

"Entity Framework 4.1 Update 1 Released" on the ADO.NET team blog:
https://blogs.msdn.com/b/adonet/archive/2011/07/25/ef-4-1-update-1-released.aspx

jQuery Documentation Main Page:
http://docs.jquery.com/Main_Page

ASP.NET MVC 3:
https://www.asp.net/mvc/mvc3

NuGet version 1.4 or later:
https://nuget.org/

Internet Explorer 9:
https://windows.microsoft.com/en-US/windows/downloads/internet-explorer

Modernizr:
http://www.modernizr.com/

Next | Previous | Home | Community