From 3db8642113cbbb90c9c95a2a7dba7b2b5d1e04c8 Mon Sep 17 00:00:00 2001 From: Filipe Silva Date: Mon, 20 Jun 2016 01:31:49 +0100 Subject: [PATCH 01/21] fix(quickstart): add styles.css to js quickstart Fix #1684 While looking at this, I saw that plunkers were getting some unintended unit testing files and added them to the default plunker builder ignore. --- .../docs/_examples/quickstart/js/styles.1.css | 14 +++++++++++++ public/docs/js/latest/quickstart.jade | 21 +++++++++++++++---- tools/plunker-builder/plunkerBuilder.js | 4 ++++ 3 files changed, 35 insertions(+), 4 deletions(-) create mode 100644 public/docs/_examples/quickstart/js/styles.1.css diff --git a/public/docs/_examples/quickstart/js/styles.1.css b/public/docs/_examples/quickstart/js/styles.1.css new file mode 100644 index 0000000000..fbc30e2c9e --- /dev/null +++ b/public/docs/_examples/quickstart/js/styles.1.css @@ -0,0 +1,14 @@ +/* #docregion */ +h1 { + color: #369; + font-family: Arial, Helvetica, sans-serif; + font-size: 250%; +} +body { + margin: 2em; +} + + /* + * See https://github.com/angular/angular.io/blob/master/public/docs/_examples/styles.css + * for the full set of master styles used by the documentation samples + */ diff --git a/public/docs/js/latest/quickstart.jade b/public/docs/js/latest/quickstart.jade index 73684f66e6..2edd48bb7a 100644 --- a/public/docs/js/latest/quickstart.jade +++ b/public/docs/js/latest/quickstart.jade @@ -31,9 +31,9 @@ figure.image-display .file app.component.js .file main.js .file index.html - .file license.md + .file styles.css :marked - Functionally, it's an `index.html` and two JavaScript files in an `app/` folder. + Functionally, it's an `index.html`, `styles.css` and two JavaScript files in an `app/` folder. We can handle that! Of course we won't build many apps that only run in plunker. @@ -43,6 +43,7 @@ figure.image-display 1. Write the Angular root component for our app 1. Bootstrap it to take control of the main web page 1. Write the main page (`index.html`) + 1. Add some CSS (`styles.css`) .l-sub-section :marked @@ -257,6 +258,16 @@ code-example(format=""). metadata, finds the `my-app` selector, locates an element tag named `my-app`, and loads our application between those tags. +:marked + ### Add some style + Styles aren't essential but they're nice, and `index.html` assumes we have + a stylesheet called `styles.css`. + + Create a `styles.css` file in the *#{_indexHtmlDir}* folder and start styling, perhaps with the minimal + styles shown below. For the full set of master styles used by the documentation samples, + see [styles.css](https://github.com/angular/angular.io/blob/master/public/docs/_examples/styles.css). ++makeExample('quickstart/js/styles.1.css', null, 'styles.css')(format=".") + .l-main-section :marked ## Run! @@ -306,15 +317,17 @@ figure.image-display .file main.js .file index.html .file package.json + .file styles.css :marked And here are the files: +makeTabs(` quickstart/js/app/app.component.js, quickstart/js/app/main.js, quickstart/js/index.html, - quickstart/js/package.1.json + quickstart/js/package.1.json, + quickstart/js/styles.1.css `,null, - `app/app.component.js, app/main.js, index.html,package.json`) + `app/app.component.js, app/main.js, index.html, package.json, styles.css`) :marked .l-main-section diff --git a/tools/plunker-builder/plunkerBuilder.js b/tools/plunker-builder/plunkerBuilder.js index da1d3fd910..7318a01857 100644 --- a/tools/plunker-builder/plunkerBuilder.js +++ b/tools/plunker-builder/plunkerBuilder.js @@ -143,6 +143,10 @@ function initConfigAndCollectFileNames(configFileName) { '!**/tslint.json', '!**/.editorconfig', '!**/systemjs.config.js', + '!**/wallaby.js', + '!**/karma-test-shim.js', + '!**/karma.conf.js', + '!**/spec.js' ]; Array.prototype.push.apply(gpaths, defaultExcludes); From 42e8c4a10c3ed9ba265e9cd2717b2be5c9a05a9f Mon Sep 17 00:00:00 2001 From: Eric Jimenez Date: Thu, 12 May 2016 16:01:10 -0400 Subject: [PATCH 02/21] feat(filter stable): filter by stability stable --- public/resources/js/directives/api-list.js | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/public/resources/js/directives/api-list.js b/public/resources/js/directives/api-list.js index 98d41ef366..7be1c88d6d 100644 --- a/public/resources/js/directives/api-list.js +++ b/public/resources/js/directives/api-list.js @@ -27,6 +27,7 @@ angularIO.directive('apiList', function () { var $ctrl = this; $ctrl.apiTypes = [ + { cssClass: 'stable', title: 'Stable', matches: ['stable']}, { cssClass: 'directive', title: 'Directive', matches: ['directive'] }, { cssClass: 'decorator', title: 'Decorator', matches: ['decorator'] }, { cssClass: 'class', title: 'Class', matches: ['class'] }, @@ -51,6 +52,16 @@ angularIO.directive('apiList', function () { var isVisible = false; section.items.forEach(function(item) { + + // Filter by stability (ericjim: only 'stable' for now) + if ($ctrl.apiType && $ctrl.apiType.matches.length === 1 && + $ctrl.apiType.matches[0] === 'stable' && item.stability === 'stable') { + item.show = true; + isVisible = true; + return isVisible; + } // NOTE: other checks can be performed for stability (experimental, deprecated, etc) + + // Filter by docType var matchesDocType = !$ctrl.apiType || $ctrl.apiType.matches.indexOf(item.docType) !== -1; var matchesTitle = !apiFilter || item.title.toLowerCase().indexOf(apiFilter) !== -1; item.show = matchesDocType && (matchesTitle || matchesModule); From 4e7318552d430d03d778843f45e23a55211893ab Mon Sep 17 00:00:00 2001 From: Brandon Roberts Date: Fri, 17 Jun 2016 22:55:36 -0400 Subject: [PATCH 03/21] docs(router): Updated docs to reflect alpha 7 release --- public/docs/_examples/package.json | 2 +- public/docs/_examples/router/e2e-spec.ts | 6 +- .../router/ts/app/app.component.2.ts | 2 +- .../_examples/router/ts/app/app.routes.1.ts | 6 +- .../_examples/router/ts/app/app.routes.2.ts | 4 +- .../_examples/router/ts/app/app.routes.3.ts | 2 +- .../crisis-center/crisis-center.routes.1.ts | 6 +- .../crisis-center/crisis-center.routes.2.ts | 17 ++- .../crisis-center/crisis-center.routes.3.ts | 19 ++- .../crisis-center/crisis-center.routes.4.ts | 19 ++- .../app/crisis-center/crisis-center.routes.ts | 18 ++- .../ts/app/crisis-center/crisis.service.ts | 2 +- .../ts/app/heroes/hero-detail.component.ts | 2 +- .../router/ts/app/heroes/heroes.routes.ts | 4 +- .../router/ts/app/login.component.ts | 3 +- .../_examples/router/ts/app/login.routes.ts | 2 +- .../docs/_examples/systemjs.config.plunker.js | 2 +- public/docs/ts/latest/guide/router.jade | 142 ++++++++++-------- 18 files changed, 143 insertions(+), 115 deletions(-) diff --git a/public/docs/_examples/package.json b/public/docs/_examples/package.json index 1cb56e65de..50622f9aaf 100644 --- a/public/docs/_examples/package.json +++ b/public/docs/_examples/package.json @@ -31,7 +31,7 @@ "@angular/http": "2.0.0-rc.2", "@angular/platform-browser": "2.0.0-rc.2", "@angular/platform-browser-dynamic": "2.0.0-rc.2", - "@angular/router": "2.0.0-rc.2", + "@angular/router": "3.0.0-alpha.7", "@angular/router-deprecated": "2.0.0-rc.2", "@angular/upgrade": "2.0.0-rc.2", "angular2-in-memory-web-api": "0.0.12", diff --git a/public/docs/_examples/router/e2e-spec.ts b/public/docs/_examples/router/e2e-spec.ts index f86293e823..ac3e36f4ea 100644 --- a/public/docs/_examples/router/e2e-spec.ts +++ b/public/docs/_examples/router/e2e-spec.ts @@ -24,14 +24,18 @@ describe('Router', function () { heroDetail: element(by.css('my-app > undefined > div')), heroDetailTitle: element(by.css('my-app > undefined > div > h3')), + adminHref: hrefEles.get(2), + loginHref: hrefEles.get(3) }; } it('should be able to see the start screen', function () { let page = getPageStruct(); - expect(page.hrefs.count()).toEqual(2, 'should be two dashboard choices'); + expect(page.hrefs.count()).toEqual(4, 'should be two dashboard choices'); expect(page.crisisHref.getText()).toEqual('Crisis Center'); expect(page.heroesHref.getText()).toEqual('Heroes'); + expect(page.adminHref.getText()).toEqual('Crisis Admin'); + expect(page.loginHref.getText()).toEqual('Login'); }); it('should be able to see crises center items', function () { diff --git a/public/docs/_examples/router/ts/app/app.component.2.ts b/public/docs/_examples/router/ts/app/app.component.2.ts index 779d43a063..f1580cf6f8 100644 --- a/public/docs/_examples/router/ts/app/app.component.2.ts +++ b/public/docs/_examples/router/ts/app/app.component.2.ts @@ -3,7 +3,7 @@ // #docregion import { Component } from '@angular/core'; -import { Router, ROUTER_DIRECTIVES } from '@angular/router'; +import { ROUTER_DIRECTIVES } from '@angular/router'; // #enddocregion /* diff --git a/public/docs/_examples/router/ts/app/app.routes.1.ts b/public/docs/_examples/router/ts/app/app.routes.1.ts index 480b4eb95c..8c4caeda55 100644 --- a/public/docs/_examples/router/ts/app/app.routes.1.ts +++ b/public/docs/_examples/router/ts/app/app.routes.1.ts @@ -16,11 +16,11 @@ import { HeroDetailComponent } from './heroes/hero-detail.component'; // #docregion route-config export const routes: RouterConfig = [ // #docregion route-defs - { path: '/crisis-center', component: CrisisCenterComponent }, - { path: '/heroes', component: HeroListComponent }, + { path: 'crisis-center', component: CrisisCenterComponent }, + { path: 'heroes', component: HeroListComponent }, // #enddocregion route-defs // #docregion hero-detail-route - { path: '/hero/:id', component: HeroDetailComponent } + { path: 'hero/:id', component: HeroDetailComponent } // #enddocregion hero-detail-route ]; diff --git a/public/docs/_examples/router/ts/app/app.routes.2.ts b/public/docs/_examples/router/ts/app/app.routes.2.ts index 57c069c81d..d0d64e2ea0 100644 --- a/public/docs/_examples/router/ts/app/app.routes.2.ts +++ b/public/docs/_examples/router/ts/app/app.routes.2.ts @@ -9,8 +9,8 @@ import { HeroListComponent } from './hero-list.component'; // #docregion route-config export const routes: RouterConfig = [ - { path: '/crisis-center', component: CrisisListComponent }, - { path: '/heroes', component: HeroListComponent } + { path: 'crisis-center', component: CrisisListComponent }, + { path: 'heroes', component: HeroListComponent } ]; export const APP_ROUTER_PROVIDERS = [ diff --git a/public/docs/_examples/router/ts/app/app.routes.3.ts b/public/docs/_examples/router/ts/app/app.routes.3.ts index f7becf70ea..c6e9cffc72 100644 --- a/public/docs/_examples/router/ts/app/app.routes.3.ts +++ b/public/docs/_examples/router/ts/app/app.routes.3.ts @@ -7,7 +7,7 @@ import { HeroesRoutes } from './heroes/heroes.routes'; export const routes = [ ...HeroesRoutes, - { path: '/crisis-center', component: CrisisListComponent } + { path: 'crisis-center', component: CrisisListComponent } ]; export const APP_ROUTER_PROVIDERS = [ diff --git a/public/docs/_examples/router/ts/app/crisis-center/crisis-center.routes.1.ts b/public/docs/_examples/router/ts/app/crisis-center/crisis-center.routes.1.ts index 0bd846c600..0c50d6b7df 100644 --- a/public/docs/_examples/router/ts/app/crisis-center/crisis-center.routes.1.ts +++ b/public/docs/_examples/router/ts/app/crisis-center/crisis-center.routes.1.ts @@ -7,11 +7,11 @@ import { CrisisCenterComponent } from './crisis-center.component'; // #docregion routes export const CrisisCenterRoutes: RouterConfig = [ { - path: '/crisis-center', + path: 'crisis-center', component: CrisisCenterComponent, children: [ - { path: '/', component: CrisisListComponent }, - { path: '/:id', component: CrisisDetailComponent } + { path: ':id', component: CrisisDetailComponent }, + { path: '', component: CrisisListComponent } ] } ]; diff --git a/public/docs/_examples/router/ts/app/crisis-center/crisis-center.routes.2.ts b/public/docs/_examples/router/ts/app/crisis-center/crisis-center.routes.2.ts index 2856544136..43eadbd55e 100644 --- a/public/docs/_examples/router/ts/app/crisis-center/crisis-center.routes.2.ts +++ b/public/docs/_examples/router/ts/app/crisis-center/crisis-center.routes.2.ts @@ -6,17 +6,20 @@ import { CrisisCenterComponent } from './crisis-center.component'; // #docregion routes export const CrisisCenterRoutes: RouterConfig = [ + // #docregion redirect { - path: '/crisis-center', + path: '', + redirectTo: '/crisis-center', + terminal: true + }, + // #enddocregion redirect + { + path: 'crisis-center', component: CrisisCenterComponent, - index: true, children: [ - { path: '/:id', component: CrisisDetailComponent }, - { path: '/', component: CrisisListComponent, - index: true - } + { path: ':id', component: CrisisDetailComponent }, + { path: '', component: CrisisListComponent } ] } ]; // #enddocregion routes - diff --git a/public/docs/_examples/router/ts/app/crisis-center/crisis-center.routes.3.ts b/public/docs/_examples/router/ts/app/crisis-center/crisis-center.routes.3.ts index 5d7170d500..1f194ac6f7 100644 --- a/public/docs/_examples/router/ts/app/crisis-center/crisis-center.routes.3.ts +++ b/public/docs/_examples/router/ts/app/crisis-center/crisis-center.routes.3.ts @@ -10,25 +10,28 @@ import { CanDeactivateGuard } from '../interfaces'; export const CrisisCenterRoutes: RouterConfig = [ { - path: '/crisis-center', + path: '', + redirectTo: '/crisis-center', + terminal: true + }, + { + path: 'crisis-center', component: CrisisCenterComponent, - index: true, children: [ // #docregion admin-route-no-guard { - path: '/admin', + path: 'admin', component: CrisisAdminComponent }, // #enddocregion admin-route-no-guard { - path: '/:id', + path: ':id', component: CrisisDetailComponent, canDeactivate: [CanDeactivateGuard] }, { - path: '/', - component: CrisisListComponent, - index: true + path: '', + component: CrisisListComponent } ] } @@ -40,7 +43,7 @@ export const CrisisCenterRoutes: RouterConfig = [ import { AuthGuard } from '../auth.guard'; { - path: '/admin', + path: 'admin', component: CrisisAdminComponent, canActivate: [AuthGuard] } diff --git a/public/docs/_examples/router/ts/app/crisis-center/crisis-center.routes.4.ts b/public/docs/_examples/router/ts/app/crisis-center/crisis-center.routes.4.ts index 0e16b01d1c..f238e132a7 100644 --- a/public/docs/_examples/router/ts/app/crisis-center/crisis-center.routes.4.ts +++ b/public/docs/_examples/router/ts/app/crisis-center/crisis-center.routes.4.ts @@ -11,25 +11,28 @@ import { AuthGuard } from '../auth.guard'; export const CrisisCenterRoutes: RouterConfig = [ { - path: '/crisis-center', + path: '', + redirectTo: '/crisis-center', + terminal: true + }, + { + path: 'crisis-center', component: CrisisCenterComponent, - index: true, children: [ { - path: '/admin', + path: 'admin', component: CrisisAdminComponent, canActivate: [AuthGuard] }, { - path: '/:id', + path: ':id', component: CrisisDetailComponent, canDeactivate: [CanDeactivateGuard] }, // #docregion default-route { - path: '/', - component: CrisisListComponent, - index: true + path: '', + component: CrisisListComponent } // #enddocregion default-route ] @@ -42,7 +45,7 @@ export const CrisisCenterRoutes: RouterConfig = [ import { AuthGuard } from '../auth.guard'; { - path: '/admin', + path: 'admin', component: CrisisAdminComponent, canActivate: [AuthGuard] } diff --git a/public/docs/_examples/router/ts/app/crisis-center/crisis-center.routes.ts b/public/docs/_examples/router/ts/app/crisis-center/crisis-center.routes.ts index f9d0a26f8d..a924aa5771 100644 --- a/public/docs/_examples/router/ts/app/crisis-center/crisis-center.routes.ts +++ b/public/docs/_examples/router/ts/app/crisis-center/crisis-center.routes.ts @@ -10,25 +10,29 @@ import { AuthGuard } from '../auth.guard'; export const CrisisCenterRoutes: RouterConfig = [ { - path: '/crisis-center', + path: '', + redirectTo: '/crisis-center', + terminal: true + }, + { + path: 'crisis-center', component: CrisisCenterComponent, - index: true, children: [ // #docregion admin-route { - path: '/admin', + path: 'admin', component: CrisisAdminComponent, canActivate: [AuthGuard] }, // #enddocregion admin-route { - path: '/:id', + path: ':id', component: CrisisDetailComponent, canDeactivate: [CanDeactivateGuard] }, - { path: '/', - component: CrisisListComponent, - index: true + { + path: '', + component: CrisisListComponent } ] } diff --git a/public/docs/_examples/router/ts/app/crisis-center/crisis.service.ts b/public/docs/_examples/router/ts/app/crisis-center/crisis.service.ts index 72e2500669..20597752cc 100644 --- a/public/docs/_examples/router/ts/app/crisis-center/crisis.service.ts +++ b/public/docs/_examples/router/ts/app/crisis-center/crisis.service.ts @@ -14,7 +14,7 @@ const CRISES = [ let crisesPromise = Promise.resolve(CRISES); // #docregion -import {Injectable} from '@angular/core'; +import { Injectable } from '@angular/core'; @Injectable() export class CrisisService { diff --git a/public/docs/_examples/router/ts/app/heroes/hero-detail.component.ts b/public/docs/_examples/router/ts/app/heroes/hero-detail.component.ts index 9f765d0ad0..bfa9ca6d0f 100644 --- a/public/docs/_examples/router/ts/app/heroes/hero-detail.component.ts +++ b/public/docs/_examples/router/ts/app/heroes/hero-detail.component.ts @@ -56,7 +56,7 @@ export class HeroDetailComponent implements OnInit, OnDestroy { let heroId = this.hero ? this.hero.id : null; // Pass along the hero id if available // so that the HeroList component can select that hero. - this.router.navigate(['/heroes'], { queryParams: { id: `${heroId}`, foo: 'foo' } }); + this.router.navigate(['/heroes'], { queryParams: { id: heroId, foo: 'foo' } }); } // #enddocregion gotoHeroes-navigate } diff --git a/public/docs/_examples/router/ts/app/heroes/heroes.routes.ts b/public/docs/_examples/router/ts/app/heroes/heroes.routes.ts index c4463cc8a1..80018d1f26 100644 --- a/public/docs/_examples/router/ts/app/heroes/heroes.routes.ts +++ b/public/docs/_examples/router/ts/app/heroes/heroes.routes.ts @@ -4,9 +4,9 @@ import { HeroListComponent } from './hero-list.component'; import { HeroDetailComponent } from './hero-detail.component'; export const HeroesRoutes: RouterConfig = [ - { path: '/heroes', component: HeroListComponent }, + { path: 'heroes', component: HeroListComponent }, // #docregion hero-detail-route - { path: '/hero/:id', component: HeroDetailComponent } + { path: 'hero/:id', component: HeroDetailComponent } // #enddocregion hero-detail-route ]; // #enddocregion diff --git a/public/docs/_examples/router/ts/app/login.component.ts b/public/docs/_examples/router/ts/app/login.component.ts index 898ca2d4c5..2790bfc79d 100755 --- a/public/docs/_examples/router/ts/app/login.component.ts +++ b/public/docs/_examples/router/ts/app/login.component.ts @@ -4,7 +4,6 @@ import { Router } from '@angular/router'; import { AuthService } from './auth.service'; @Component({ - selector: 'login', template: `

LOGIN

{{message}}

@@ -25,7 +24,7 @@ export class LoginComponent { } login() { - this.message = "Trying to log in ..."; + this.message = 'Trying to log in ...'; this.authService.login().subscribe(() => { this.setMessage(); diff --git a/public/docs/_examples/router/ts/app/login.routes.ts b/public/docs/_examples/router/ts/app/login.routes.ts index 71ad3cf9e4..6dabba376f 100644 --- a/public/docs/_examples/router/ts/app/login.routes.ts +++ b/public/docs/_examples/router/ts/app/login.routes.ts @@ -4,7 +4,7 @@ import { AuthService } from './auth.service'; import { LoginComponent } from './login.component'; export const LoginRoutes = [ - { path: '/login', component: LoginComponent } + { path: 'login', component: LoginComponent } ]; export const AUTH_PROVIDERS = [AuthGuard, AuthService]; diff --git a/public/docs/_examples/systemjs.config.plunker.js b/public/docs/_examples/systemjs.config.plunker.js index 0479c88703..bf2fc3de68 100644 --- a/public/docs/_examples/systemjs.config.plunker.js +++ b/public/docs/_examples/systemjs.config.plunker.js @@ -6,7 +6,7 @@ (function(global) { var ngVer = '@2.0.0-rc.2'; // lock in the angular package version; do not let it float to current! - var routerVer = '@3.0.0-alpha.3'; // lock router version + var routerVer = '@3.0.0-alpha.7'; // lock router version //map tells the System loader where to look for things var map = { diff --git a/public/docs/ts/latest/guide/router.jade b/public/docs/ts/latest/guide/router.jade index 853f735d65..a92d0386c0 100644 --- a/public/docs/ts/latest/guide/router.jade +++ b/public/docs/ts/latest/guide/router.jade @@ -47,7 +47,7 @@ include ../_util-fns * navigating under [program control](#navigate) * embedding critical information in the URL with [route parameters](#route-parameters) * add [child routes](#child-routing-component) under a feature section - * setting an [index route](#index) as the default + * [redirecting](#redirect) from one route to another * confirming or canceling navigation with [guards](#guards) * [CanActivate](#can-activate-guard) to prevent navigation to a route * [CanDeactivate](#can-deactivate-deactivate) to prevent navigation away from the current route @@ -100,6 +100,9 @@ include ../_util-fns The `RouterConfig` is an array of *routes* that describe how to navigate. Each *Route* maps a URL `path` to a component. + There are no **leading slashes** in our **path**. The router parses and builds the URL for us, + allowing us to use relative and absolute paths when navigating between application views. + The `:id` in the third route is a token for a route parameter. In a URL such as `/hero/42`, "42" is the value of the `id` parameter. The corresponding `HeroDetailComponent` will use that value to find and present the hero whose `id` is 42. @@ -167,7 +170,7 @@ table tr td Route td. - Defines how the router should navigate to a component based on a URL pattern. + Defines how the router should navigate to a component based on a URL pattern. Most routes consist of a path and a component type. tr td RouterOutlet @@ -343,10 +346,10 @@ figure.image-display h4#import Import from the Component Router library :marked - We begin by importing some symbols from the router library. - + We begin by importing some symbols from the router library. + The Component Router is in its own `@angular/router` package. - It's not part of the Angular 2 core. + It's not part of the Angular 2 core. The router is an optional service because not all applications need routing and, depending on your requirements, you may need a different routing library. @@ -371,17 +374,17 @@ h4#define-routes Define routes * *When the application requests navigation to the path `/crisis-center`, create or retrieve an instance of the `CrisisListComponent`, display its view, and update the browser's address location and history with the URL - for that path.* + for that path.* h4#provideRouter Call provideRouter :marked - We pass the route configuration to the `provideRouter` function which returns an array containing the configured + We pass the route configuration to the `provideRouter` function which returns an array containing the configured `Router` service provider ... and some other, unseen providers that the routing library requires. :marked We add the `provideRouter` array to an `APP_ROUTER_PROVIDERS` array and export it. - We could add *additional* service providers to `APP_ROUTER_PROVIDERS` — + We could add *additional* service providers to `APP_ROUTER_PROVIDERS` — providers that are specific to our routing configuration. We don't have any yet. We will have some later in this chapter. @@ -398,10 +401,10 @@ h4#register-providers Register routing in bootstrap and pass it as the second parameter of the `bootstrap` function. +makeExample('router/ts/app/main.1.ts','all', 'main.ts')(format=".") :marked - Providing the router providers at the root makes the Router available everywhere in our application. + Providing the router providers at bootstrap makes the Router available everywhere in our application. .alert.is-important :marked - We must register router providers in `bootstrap`. + We must register router providers in `bootstrap`. We cannot wait to do it in `AppComponent`. h3#shell The AppComponent shell @@ -424,7 +427,7 @@ h3#router-outlet RouterOutlet .l-sub-section :marked A template may hold exactly one ***unnamed*** ``. - The router supports multiple *named* outlets, a feature we'll cover in future. + The router supports multiple *named* outlets, a feature we'll cover in future. h3#router-link RouterLink binding :marked @@ -434,7 +437,7 @@ h3#router-link RouterLink binding The template expression to the right of the equals (=) returns a *link parameters array*. A link parameters array holds the ingredients for router navigation: - * the *path* of the route to the destination component + * the *path* of the route to the destination component * optional route and query parameters that go into the route URL The arrays in this example each have a single string parameter, the path of a route that @@ -445,7 +448,7 @@ h3#router-link RouterLink binding h3#router-directives ROUTER_DIRECTIVES :marked - `RouterLink` and `RouterOutlet` are directives in the `ROUTER_DIRECTIVES` collection. + `RouterLink` and `RouterOutlet` are directives in the `ROUTER_DIRECTIVES` collection. Remember to add them to the `directives` array of the `@Component` metadata. +makeExample('router/ts/app/app.component.1.ts','directives')(format=".") :marked @@ -574,8 +577,8 @@ figure.image-display ### *Hero* feature route configuration - We recommend giving each feature area its own route configuration file. - + We recommend giving each feature area its own route configuration file. + Create a new `hero.routes.ts` in the `heroes` folder like this: +makeExample('router/ts/app/heroes/heroes.routes.ts','', 'app/heroes/heroes.routes.ts')(format=".") :marked @@ -610,7 +613,7 @@ code-example(format="." language="bash"). h3#merge-hero-routes Merge hero routes into application routes :marked - Our application doesn't know about our hero routes yet. + Our application doesn't know about our hero routes yet. We'll need to merge them into the application routes we defined in `app.routes.ts`. Update `app.routes.ts` as follows: @@ -626,7 +629,7 @@ h3#merge-hero-routes Merge hero routes into application routes h3#navigate Navigate to hero detail imperatively :marked - *We won't navigate to the detail component by clicking a link* + *We won't navigate to the detail component by clicking a link* so we won't be adding a new `RouterLink` anchor tag to the shell. Instead, when the user *clicks* a hero in the list, we'll *command* the router @@ -700,7 +703,7 @@ a#hero-detail-ctor .l-sub-section :marked - Learn about the `ngOnInit` and `ngOnDestroy` methods in the + Learn about the `ngOnInit` and `ngOnDestroy` methods in the [Lifecycle Hooks](lifecycle-hooks.html) chapter. h4#reuse Observable params and component re-use @@ -708,11 +711,11 @@ h4#reuse Observable params and component re-use In this example, we subscribe to the route params `Observable`. That implies that the route params can change during the lifetime of this component. - They might. By default, the router reuses a component instance when it re-navigates to the same component type + They might. By default, the router reuses a component instance when it re-navigates to the same component type without visiting a different component first. The parameters can change between each re-use. - Suppose a parent component navigation bar had "forward" and "back" buttons - that scrolled through the list of heroes. + Suppose a parent component navigation bar had "forward" and "back" buttons + that scrolled through the list of heroes. Each click navigated imperatively to the `HeroDetailComponent` with the next or previous `id`. We don't want the router to remove the current `HeroDetailComponent` instance from the @@ -720,13 +723,13 @@ h4#reuse Observable params and component re-use That could be visibly jarring. Better to simply re-use the same component instance and update the parameter. - But `ngOnInit` is only called once per instantiation. + But `ngOnInit` is only called once per instantiation. We need a way to detect when the route parameters change from _within the same instance_. The observable `params` property handles that beautifully. h4#snapshot Snapshot: the no-observable alternative :marked - This application won't reuse the `HeroDetailComponent`. + This application won't reuse the `HeroDetailComponent`. We always return to the hero list to select another hero to view. There's no way to navigate from hero detail to hero detail without visiting the list component in between. @@ -742,8 +745,8 @@ h4#snapshot Snapshot: the no-observable alternative .l-sub-section :marked **Remember:** we only get the _initial_ value of the parameters with this technique. - Stick with the observable `params` approach if there's even a chance that we might navigate - to this component multiple times in a row. + Stick with the observable `params` approach if there's even a chance that we might navigate + to this component multiple times in a row. We are leaving the observable `params` strategy in place just in case. h3#nav-to-list Navigating back to the list component @@ -841,7 +844,7 @@ h3#nav-to-list Navigating back to the list component * Our `CrisisService` is only needed within the *Crisis Center* feature area. We should limit access to it to that feature area. - * Changes to a sub-module such as *Crisis Center* shouldn't provoke changes to the `AppComponent` or + * Changes to a sub-module such as *Crisis Center* shouldn't provoke changes to the `AppComponent` or any other feature's component. We need to [*separate our concerns*](https://blog.8thlight.com/uncle-bob/2014/05/08/SingleReponsibilityPrinciple.html). @@ -861,7 +864,7 @@ h3#nav-to-list Navigating back to the list component * each area with its own area root component * each area root component with its own router-outlet and child routes * area routes rarely (if ever) cross - + If we had many feature areas, their component trees might look like this: figure.image-display @@ -883,8 +886,8 @@ h3#child-routing-component Child Routing Component * It is dead simple — simpler even than the `AppComponent` template. It has no content, no links, just a `` for the *Crisis Center* child views. - Unlike `AppComponent` (and most other components), it **lacks a selector**. - It doesn't need one. We don't *embed* this component in a parent template. + Unlike `AppComponent` (and most other components), it **lacks a selector**. + It doesn't need one. We don't *embed* this component in a parent template. We *navigate* to it from the outside, via the router. .l-sub-section :marked @@ -907,9 +910,9 @@ h3#child-routing-component Child Routing Component First we can evolve the service independently of the rest of the application without fear of breaking what should be unrelated modules. - + Second, we can delay loading this service into memory until we need it. - We can remove it from the application launch bundle, + We can remove it from the application launch bundle, reducing the size of the initial payload and improving performance. We can load it optionally, asynchronously with the other *Crisis Center* components if and when the user begins that workflow. @@ -924,11 +927,11 @@ h3#child-routing-component Child Routing Component We create a `crisis-center.routes.ts` file as we did the `heroes.routes.ts` file. But this time we define **child routes** *within* the parent `/crisis-center` route. -+makeExample('router/ts/app/crisis-center/crisis-center.routes.1.ts', 'routes', 'app/crisis-center/crisis-center.routes.ts (Routes)' )(format='.') ++makeExample('router/ts/app/crisis-center/crisis-center.routes.1.ts', 'routes', 'app/crisis-center/crisis-center.routes.ts (Routes)' )(format='.') :marked Notice that the parent `/crisis-center` route has a `children` property with an array of two routes. - These two routes navigate to the two *Crisis Center* child components, + These two routes navigate to the two *Crisis Center* child components, `CrisisListComponent` and `CrisisDetailComponent`. There are some *important differences* in the treatment of these routes. @@ -939,8 +942,8 @@ h3#child-routing-component Child Routing Component Second, the child paths *extend* the path of their parent route. Normally paths that begin with `/` refer to the root of the application. - Here they are appended to the path to the `CrisisCenterComponent`. - + Here they are appended to the path to the `CrisisCenterComponent`. + To write an URL that navigates to the `CrisisListComponent`, we'd append its child route path, `/`, to `/crisis-center`. @@ -952,7 +955,7 @@ code-example(format=""). :marked Here's the complete `crisis-center.routes.ts` with its imports. -+makeExample('router/ts/app/crisis-center/crisis-center.routes.1.ts', '', 'app/crisis-center/crisis-center.routes.ts' )(format='.') ++makeExample('router/ts/app/crisis-center/crisis-center.routes.1.ts', '', 'app/crisis-center/crisis-center.routes.ts' )(format='.') h3#merge-crisis-routes Merge crisis routes into the application routes :marked @@ -960,10 +963,10 @@ h3#merge-crisis-routes Merge crisis routes into the application routes by merging the crisis routes into the app routes: +makeExample('router/ts/app/app.routes.4.ts', '', 'app/app.routes.ts' )(format='.') :marked - We used the spread operator again (...) to insert the crisis routes array. + We used the spread operator again (...) to insert the crisis routes array. -a#index -h3#default-route Setting default routes +a#redirect +h3#redirect Redirecting routes :marked When the application launches, the initial URL in the browser bar is something like: code-example(format=""). @@ -973,15 +976,24 @@ code-example(format=""). The user must click one of the navigation links to trigger a navigation and display something. We want the application to display the list of crises as it would if we pasted `localhost:3000/crisis-center/` into the address bar. - This is our *default* route. + This is our intended default route. - We can arrange for that behavior in several ways. - One way is to add `index: true` to each route on the path to the default component. + We can arrange for that behavior in several ways. + One way is to use a `redirect` to transparently navigate from one route to another. - In our example, we'll add `index: true` to two routes: - 1. The parent route for the `CrisisCenterComponent` - 1. The child route for the `CrisisListComponent` + In our example, we'll add a route to match our initial URL and redirect to our `crisis-center` route: ++makeExample('router/ts/app/crisis-center/crisis-center.routes.2.ts', 'redirect', 'app/crisis-center/crisis-center.routes.ts (redirect route)' )(format='.') +:marked + Since we only want to redirect when our path specifically matches `''`, we've added an extra configuration + to our route using `terminal: true`. Mainly for redirects, the `terminal` property gives us more control over + when the router should continue matching our URL against our defined routes. + +.l-sub-section + :marked + We'll discuss redirects further in a future update to this chapter. + +:marked The updated route definitions look like this: +makeExample('router/ts/app/crisis-center/crisis-center.routes.2.ts', 'routes', 'app/crisis-center/crisis-center.routes.ts (Routes v.2)' )(format='.') @@ -1006,18 +1018,18 @@ h2#guards Route Guards :marked The guard can also tell the router to navigate elsewhere, effectively canceling the current navigation. :marked - The guard *might* return its boolean answer synchronously. + The guard *might* return its boolean answer synchronously. But in many cases, the guard can't produce an answer synchronously. The guard could ask the user a question, save changes to the server, or fetch fresh data. These are all asynchronous operations. Accordingly, a routing guard can return an `Observable` and the - router will wait for the observable to resolve to `true` or `false. + router will wait for the observable to resolve to `true` or `false. The router supports two kinds of guards: - - 1. [CanActivate](../api/router/index/CanActivate-interface.html) to mediate navigation *to* a route. - + + 1. [CanActivate](../api/router/index/CanActivate-interface.html) to mediate navigation *to* a route. + 2. [CanDeactivate](../api/router/index/CanDeactivate-interface.html) to mediate navigation *away* from the current route. .l-sub-section @@ -1027,7 +1039,7 @@ h2#guards Route Guards We can have multiple guards at every level of a routing hierarchy. The router checks the `CanDeactive` guards first, from deepest child route to the top. Then it checks the `CanActivate` guards from the top down to the deepest child route. - If _any_ guard returns false, pending guards that have not completed will be canceled, + If _any_ guard returns false, pending guards that have not completed will be canceled, and the entire navigation is canceled. Let's look at some examples. @@ -1058,27 +1070,27 @@ h3#can-activate-guard CanActivate: requiring authentication +makeExample('router/ts/app/crisis-center/crisis-center.routes.3.ts', 'admin-route-no-guard', 'crisis-center.routes.ts (admin route)')(format=".") :marked And we add a link to the `AppComponent` shell that users can click to get to this feature. -+makeExample('router/ts/app/app.component.4.ts', 'template', 'app/app.component.ts (template)')(format=".") ++makeExample('router/ts/app/app.component.4.ts', 'template', 'app/app.component.ts (template)')(format=".") :marked #### Guard the admin feature - Currently every route within our *Crisis Center* is open to everyone. + Currently every route within our *Crisis Center* is open to everyone. The new *admin* feature should be accessible only to authenticated users. - We could hide the link until the user logs in. But that's tricky and difficult to maintain. + We could hide the link until the user logs in. But that's tricky and difficult to maintain. Instead we'll write a `CanActivate` guard to redirect anonymous users to the login page when they try to reach the admin component. - + This is a general purpose guard — we can imagine other features that require authenticated users — - so we create an `auth.guard.ts` in the application root folder. - + so we create an `auth.guard.ts` in the application root folder. + At the moment we're interested in seeing how guards work so our first version does nothing useful. It simply logs to console and `returns` true immediately, allowing navigation to proceed: -+makeExample('router/ts/app/auth.guard.1.ts', '', 'app/auth.guard.ts')(format=".") ++makeExample('router/ts/app/auth.guard.1.ts', '', 'app/auth.guard.ts')(format=".") :marked - Next we open `crisis-center.routes.ts `, import the `AuthGuard` class, and + Next we open `crisis-center.routes.ts `, import the `AuthGuard` class, and update the admin route with a `CanActivate` guard property that references it: +makeExample('router/ts/app/crisis-center/crisis-center.routes.ts', 'admin-route', 'crisis-center.routes.ts (guarded admin route)')(format=".") - Our admin feature is now protected by the guard, albeit protected poorly. + Our admin feature is now protected by the guard, albeit protected poorly. :marked #### Teach *AuthGuard* to authenticate Let's make our `AuthGuard` at least pretend to authenticate. @@ -1087,24 +1099,24 @@ h3#can-activate-guard CanActivate: requiring authentication Here's a demo `AuthService`: +makeExample('router/ts/app/auth.service.ts', '', 'app/auth.service.ts')(format=".") :marked - Although it doesn't actually log in, it has what we need for this discussion. + Although it doesn't actually log in, it has what we need for this discussion. It has an `isLoggedIn` flag to tell us whether the user is authenticated. Its `login` method simulates an API call to an external service by returning an observable that resolves successfully after a short pause. Let's revise our `AuthGuard` to call it. +makeExample('router/ts/app/auth.guard.ts', '', 'app/auth.guard.ts (v.2)')(format=".") :marked - Notice that we *inject* the `AuthService` and the `Router` in the constructor. + Notice that we *inject* the `AuthService` and the `Router` in the constructor. We haven't provided the `AuthService` yet but it's good to know that we can inject helpful services into our routing guards. - This guard returns a synchronous boolean result. + This guard returns a synchronous boolean result. If the user is logged in, it returns true and the navigation continues. If the user is not logged in, we tell the router to navigate to a login page — a page we haven't created yet. This secondary navigation automatically cancels the current navigation; we return `false` just to be clear about that. #### Add the *LoginComponent* - We need a `LoginComponent` for the user to log in to the app. + We need a `LoginComponent` for the user to log in to the app. There is nothing new about this component or the way we wire it into the router configuration. Here is the pertinent code, offered without comment: +makeTabs( @@ -1427,7 +1439,7 @@ code-example(format="." language="bash"). :marked ## Wrap Up We've covered a lot of ground in this chapter and the application is too big to reprint here. - Please visit the [live example](/resources/live-examples/router/ts/plnkr.html) and + Please visit the [live example](/resources/live-examples/router/ts/plnkr.html) and where you can download the final source code. .l-main-section From 560bf2be6c1c17a415fed305388b6a08e0214898 Mon Sep 17 00:00:00 2001 From: Filipe Silva Date: Mon, 20 Jun 2016 02:12:42 +0100 Subject: [PATCH 04/21] chore: optimize gulp watchers Reduce amount of watchers for `gulp serve-and-sync-devguide` by roughly 50% (~4900-ish to ~2500). This should help with the 100% CPU usage #1082, on my machine it went from ~90% to ~50%. At the end of the day we're still watching an insane amount of files, so it is a demanding process. Maybe using better watcher libs would also help. --- gulpfile.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/gulpfile.js b/gulpfile.js index 08aa969107..504b50d299 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -37,7 +37,7 @@ var DOCS_PATH = path.join(PUBLIC_PATH, 'docs'); var EXAMPLES_PATH = path.join(DOCS_PATH, '_examples'); var EXAMPLES_PROTRACTOR_PATH = path.join(EXAMPLES_PATH, '_protractor'); -var NOT_API_DOCS_GLOB = path.join(PUBLIC_PATH, './{docs/*/latest/!(api),!(docs)}/**/*'); +var NOT_API_DOCS_GLOB = path.join(PUBLIC_PATH, './{docs/*/latest/!(api),!(docs)}/**/*.*'); var RESOURCES_PATH = path.join(PUBLIC_PATH, 'resources'); var LIVE_EXAMPLES_PATH = path.join(RESOURCES_PATH, 'live-examples'); @@ -989,6 +989,7 @@ function devGuideExamplesWatch(shredOptions, postShredAction) { // gulp.watch([includePattern, excludePattern], {readDelay: 500}, function (event, done) { var ignoreThese = [ '**/node_modules/**', '**/_fragments/**', '**/dist/**', '**/typings/**', '**/dart/.pub/**', '**/dart/build/**', '**/dart/packages/**']; + ignoreThese = ignoreThese.concat(_exampleBoilerplateFiles.map((file) => `public/docs/_examples/*/*/${file}`)); var files = globby.sync( [includePattern], { ignore: ignoreThese }); gulp.watch([files], {readDelay: 500}, function (event, done) { gutil.log('Dev Guide example changed') @@ -1003,7 +1004,8 @@ function devGuideSharedJadeWatch(shredOptions, postShredAction) { // removed this version because gulp.watch has the same glob issue that dgeni has. // var excludePattern = '!' + path.join(shredOptions.jadeDir, '**/node_modules/**/*.*'); // gulp.watch([includePattern, excludePattern], {readDelay: 500}, function (event, done) { - var files = globby.sync( [includePattern], { ignore: [ '**/node_modules/**', '**/_examples/**', '**/_fragments/**']}); + var ignoreThese = [ '**/node_modules/**', '**/_examples/**', '**/_fragments/**', '**/latest/api/**' ]; + var files = globby.sync( [includePattern], { ignore: ignoreThese}); gulp.watch([files], {readDelay: 500}, function (event, done) { gutil.log('Dev Guide jade file changed') gutil.log('Event type: ' + event.type); // added, changed, or deleted From 749c5eae1bd1f779ffe1e759b6bb76683236018b Mon Sep 17 00:00:00 2001 From: Foxandxss Date: Sun, 19 Jun 2016 11:09:07 +0200 Subject: [PATCH 05/21] chore: add lint instructions to readme --- .travis.yml | 1 + README.md | 3 +++ 2 files changed, 4 insertions(+) diff --git a/.travis.yml b/.travis.yml index a8084eae11..48358bc56e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,6 +7,7 @@ os: - linux env: global: + - DBUS_SESSION_BUS_ADDRESS=/dev/null - DISPLAY=:99.0 - CHROME_BIN=chromium-browser matrix: diff --git a/README.md b/README.md index 59732e1d95..27eb2cf153 100644 --- a/README.md +++ b/README.md @@ -96,6 +96,9 @@ Look at the scripts in `package.json` for other options. Also, open any `plunkr.no-link.html` to see the code execute in plunker (you may have to run `gulp build-plunkers` first to create/update). +You may want to check that your example is free of lint errors. +- `gulp lint` + ### Sample end-to-end tests All samples should be covered to some degree by end-to-end tests: From 3cb219c5ab00efdd3bacd40006f23ecf781cb905 Mon Sep 17 00:00:00 2001 From: Torgeir Helgevold Date: Sat, 18 Jun 2016 12:00:04 -0400 Subject: [PATCH 06/21] docs(dynamic-cookbook): upgrade to use new forms api convert exiting to use deprecated name converted to new api text warnings fix plunker text test weak text space text lint order tweak --- .../cb-dynamic-form-deprecated/e2e-spec.ts | 27 ++++ .../ts/app/app.component.ts | 24 +++ .../app/dynamic-form-question.component.html | 17 ++ .../ts/app/dynamic-form-question.component.ts | 15 ++ .../ts/app/dynamic-form.component.html | 17 ++ .../ts/app/dynamic-form.component.ts | 30 ++++ .../cb-dynamic-form-deprecated/ts/app/main.ts | 6 + .../ts/app/question-base.ts | 25 +++ .../ts/app/question-control.service.ts | 18 +++ .../ts/app/question-dropdown.ts | 12 ++ .../ts/app/question-textbox.ts | 12 ++ .../ts/app/question.service.ts | 47 ++++++ .../ts/example-config.json | 0 .../cb-dynamic-form-deprecated/ts/index.html | 29 ++++ .../cb-dynamic-form-deprecated/ts/plnkr.json | 9 ++ .../cb-dynamic-form-deprecated/ts/sample.css | 7 + .../app/dynamic-form-question.component.html | 8 +- .../ts/app/dynamic-form-question.component.ts | 7 +- .../ts/app/dynamic-form.component.html | 2 +- .../ts/app/dynamic-form.component.ts | 10 +- .../_examples/cb-dynamic-form/ts/app/main.ts | 11 +- .../ts/app/question-control.service.ts | 14 +- .../ts/app/question.service.ts | 2 +- public/docs/_examples/package.json | 1 + public/docs/_examples/systemjs.config.js | 1 + .../docs/_examples/systemjs.config.plunker.js | 5 + public/docs/ts/latest/cookbook/_data.json | 2 +- .../cookbook/dynamic-form-deprecated.jade | 149 ++++++++++++++++++ .../docs/ts/latest/cookbook/dynamic-form.jade | 38 ++++- 29 files changed, 516 insertions(+), 29 deletions(-) create mode 100644 public/docs/_examples/cb-dynamic-form-deprecated/e2e-spec.ts create mode 100644 public/docs/_examples/cb-dynamic-form-deprecated/ts/app/app.component.ts create mode 100644 public/docs/_examples/cb-dynamic-form-deprecated/ts/app/dynamic-form-question.component.html create mode 100644 public/docs/_examples/cb-dynamic-form-deprecated/ts/app/dynamic-form-question.component.ts create mode 100644 public/docs/_examples/cb-dynamic-form-deprecated/ts/app/dynamic-form.component.html create mode 100644 public/docs/_examples/cb-dynamic-form-deprecated/ts/app/dynamic-form.component.ts create mode 100644 public/docs/_examples/cb-dynamic-form-deprecated/ts/app/main.ts create mode 100644 public/docs/_examples/cb-dynamic-form-deprecated/ts/app/question-base.ts create mode 100644 public/docs/_examples/cb-dynamic-form-deprecated/ts/app/question-control.service.ts create mode 100644 public/docs/_examples/cb-dynamic-form-deprecated/ts/app/question-dropdown.ts create mode 100644 public/docs/_examples/cb-dynamic-form-deprecated/ts/app/question-textbox.ts create mode 100644 public/docs/_examples/cb-dynamic-form-deprecated/ts/app/question.service.ts create mode 100644 public/docs/_examples/cb-dynamic-form-deprecated/ts/example-config.json create mode 100644 public/docs/_examples/cb-dynamic-form-deprecated/ts/index.html create mode 100644 public/docs/_examples/cb-dynamic-form-deprecated/ts/plnkr.json create mode 100644 public/docs/_examples/cb-dynamic-form-deprecated/ts/sample.css create mode 100644 public/docs/ts/latest/cookbook/dynamic-form-deprecated.jade diff --git a/public/docs/_examples/cb-dynamic-form-deprecated/e2e-spec.ts b/public/docs/_examples/cb-dynamic-form-deprecated/e2e-spec.ts new file mode 100644 index 0000000000..725022d0f1 --- /dev/null +++ b/public/docs/_examples/cb-dynamic-form-deprecated/e2e-spec.ts @@ -0,0 +1,27 @@ +/// +'use strict'; +/* tslint:disable:quotemark */ +describe('Dynamic Form Deprecated', function () { + + beforeAll(function () { + browser.get(''); + }); + + it('should submit form', function () { + let firstNameElement = element.all(by.css('input[id=firstName]')).get(0); + expect(firstNameElement.getAttribute('value')).toEqual('Bombasto'); + + let emailElement = element.all(by.css('input[id=emailAddress]')).get(0); + let email = 'test@test.com'; + emailElement.sendKeys(email); + expect(emailElement.getAttribute('value')).toEqual(email); + + element(by.css('select option[value="solid"]')).click(); + + let saveButton = element.all(by.css('button')).get(0); + saveButton.click().then(function(){ + expect(element(by.xpath("//strong[contains(text(),'Saved the following values')]")).isPresent()).toBe(true); + }); + }); + +}); diff --git a/public/docs/_examples/cb-dynamic-form-deprecated/ts/app/app.component.ts b/public/docs/_examples/cb-dynamic-form-deprecated/ts/app/app.component.ts new file mode 100644 index 0000000000..e51561770e --- /dev/null +++ b/public/docs/_examples/cb-dynamic-form-deprecated/ts/app/app.component.ts @@ -0,0 +1,24 @@ +// #docregion +import { Component } from '@angular/core'; + +import { DynamicFormComponent } from './dynamic-form.component'; +import { QuestionService } from './question.service'; + +@Component({ + selector: 'my-app', + template: ` +
+

Job Application for Heroes

+ +
+ `, + directives: [DynamicFormComponent], + providers: [QuestionService] +}) +export class AppComponent { + questions: any[]; + + constructor(service: QuestionService) { + this.questions = service.getQuestions(); + } +} diff --git a/public/docs/_examples/cb-dynamic-form-deprecated/ts/app/dynamic-form-question.component.html b/public/docs/_examples/cb-dynamic-form-deprecated/ts/app/dynamic-form-question.component.html new file mode 100644 index 0000000000..ceb2f41177 --- /dev/null +++ b/public/docs/_examples/cb-dynamic-form-deprecated/ts/app/dynamic-form-question.component.html @@ -0,0 +1,17 @@ + +
+ + +
+ + + + + +
+ +
{{question.label}} is required
+
diff --git a/public/docs/_examples/cb-dynamic-form-deprecated/ts/app/dynamic-form-question.component.ts b/public/docs/_examples/cb-dynamic-form-deprecated/ts/app/dynamic-form-question.component.ts new file mode 100644 index 0000000000..0593fd523e --- /dev/null +++ b/public/docs/_examples/cb-dynamic-form-deprecated/ts/app/dynamic-form-question.component.ts @@ -0,0 +1,15 @@ +// #docregion +import { Component, Input } from '@angular/core'; +import { ControlGroup } from '@angular/common'; + +import { QuestionBase } from './question-base'; + +@Component({ + selector: 'df-question', + templateUrl: 'app/dynamic-form-question.component.html' +}) +export class DynamicFormQuestionComponent { + @Input() question: QuestionBase; + @Input() form: ControlGroup; + get isValid() { return this.form.controls[this.question.key].valid; } +} diff --git a/public/docs/_examples/cb-dynamic-form-deprecated/ts/app/dynamic-form.component.html b/public/docs/_examples/cb-dynamic-form-deprecated/ts/app/dynamic-form.component.html new file mode 100644 index 0000000000..e8f14612c9 --- /dev/null +++ b/public/docs/_examples/cb-dynamic-form-deprecated/ts/app/dynamic-form.component.html @@ -0,0 +1,17 @@ + +
+
+ +
+ +
+ +
+ +
+
+ +
+ Saved the following values
{{payLoad}} +
+
diff --git a/public/docs/_examples/cb-dynamic-form-deprecated/ts/app/dynamic-form.component.ts b/public/docs/_examples/cb-dynamic-form-deprecated/ts/app/dynamic-form.component.ts new file mode 100644 index 0000000000..5d6eb833ed --- /dev/null +++ b/public/docs/_examples/cb-dynamic-form-deprecated/ts/app/dynamic-form.component.ts @@ -0,0 +1,30 @@ +// #docregion +import { Component, Input, OnInit } from '@angular/core'; +import { ControlGroup } from '@angular/common'; + +import { QuestionBase } from './question-base'; +import { QuestionControlService } from './question-control.service'; +import { DynamicFormQuestionComponent } from './dynamic-form-question.component'; + +@Component({ + selector: 'dynamic-form', + templateUrl: 'app/dynamic-form.component.html', + directives: [DynamicFormQuestionComponent], + providers: [QuestionControlService] +}) +export class DynamicFormComponent implements OnInit { + + @Input() questions: QuestionBase[] = []; + form: ControlGroup; + payLoad = ''; + + constructor(private qcs: QuestionControlService) { } + + ngOnInit() { + this.form = this.qcs.toControlGroup(this.questions); + } + + onSubmit() { + this.payLoad = JSON.stringify(this.form.value); + } +} diff --git a/public/docs/_examples/cb-dynamic-form-deprecated/ts/app/main.ts b/public/docs/_examples/cb-dynamic-form-deprecated/ts/app/main.ts new file mode 100644 index 0000000000..5a8d9c5044 --- /dev/null +++ b/public/docs/_examples/cb-dynamic-form-deprecated/ts/app/main.ts @@ -0,0 +1,6 @@ +import { bootstrap } from '@angular/platform-browser-dynamic'; + +import { AppComponent } from './app.component'; + +bootstrap(AppComponent, []) + .catch((err: any) => console.error(err)); diff --git a/public/docs/_examples/cb-dynamic-form-deprecated/ts/app/question-base.ts b/public/docs/_examples/cb-dynamic-form-deprecated/ts/app/question-base.ts new file mode 100644 index 0000000000..2b32b00f2a --- /dev/null +++ b/public/docs/_examples/cb-dynamic-form-deprecated/ts/app/question-base.ts @@ -0,0 +1,25 @@ +// #docregion +export class QuestionBase{ + value: T; + key: string; + label: string; + required: boolean; + order: number; + controlType: string; + + constructor(options: { + value?: T, + key?: string, + label?: string, + required?: boolean, + order?: number, + controlType?: string + } = {}) { + this.value = options.value; + this.key = options.key || ''; + this.label = options.label || ''; + this.required = !!options.required; + this.order = options.order === undefined ? 1 : options.order; + this.controlType = options.controlType || ''; + } +} diff --git a/public/docs/_examples/cb-dynamic-form-deprecated/ts/app/question-control.service.ts b/public/docs/_examples/cb-dynamic-form-deprecated/ts/app/question-control.service.ts new file mode 100644 index 0000000000..3d56b0c2f6 --- /dev/null +++ b/public/docs/_examples/cb-dynamic-form-deprecated/ts/app/question-control.service.ts @@ -0,0 +1,18 @@ +// #docregion +import { Injectable } from '@angular/core'; +import { FormBuilder, Validators } from '@angular/common'; +import { QuestionBase } from './question-base'; + +@Injectable() +export class QuestionControlService { + constructor(private fb: FormBuilder) { } + + toControlGroup(questions: QuestionBase[] ) { + let group = {}; + + questions.forEach(question => { + group[question.key] = question.required ? [question.value || '', Validators.required] : [question.value || '']; + }); + return this.fb.group(group); + } +} diff --git a/public/docs/_examples/cb-dynamic-form-deprecated/ts/app/question-dropdown.ts b/public/docs/_examples/cb-dynamic-form-deprecated/ts/app/question-dropdown.ts new file mode 100644 index 0000000000..35a9074c74 --- /dev/null +++ b/public/docs/_examples/cb-dynamic-form-deprecated/ts/app/question-dropdown.ts @@ -0,0 +1,12 @@ +// #docregion +import { QuestionBase } from './question-base'; + +export class DropdownQuestion extends QuestionBase { + controlType = 'dropdown'; + options: {key: string, value: string}[] = []; + + constructor(options: {} = {}) { + super(options); + this.options = options['options'] || []; + } +} diff --git a/public/docs/_examples/cb-dynamic-form-deprecated/ts/app/question-textbox.ts b/public/docs/_examples/cb-dynamic-form-deprecated/ts/app/question-textbox.ts new file mode 100644 index 0000000000..aaa7edf267 --- /dev/null +++ b/public/docs/_examples/cb-dynamic-form-deprecated/ts/app/question-textbox.ts @@ -0,0 +1,12 @@ +// #docregion +import { QuestionBase } from './question-base'; + +export class TextboxQuestion extends QuestionBase { + controlType = 'textbox'; + type: string; + + constructor(options: {} = {}) { + super(options); + this.type = options['type'] || ''; + } +} diff --git a/public/docs/_examples/cb-dynamic-form-deprecated/ts/app/question.service.ts b/public/docs/_examples/cb-dynamic-form-deprecated/ts/app/question.service.ts new file mode 100644 index 0000000000..ee169d0827 --- /dev/null +++ b/public/docs/_examples/cb-dynamic-form-deprecated/ts/app/question.service.ts @@ -0,0 +1,47 @@ +// #docregion +import { Injectable } from '@angular/core'; + +import { QuestionBase } from './question-base'; +import { TextboxQuestion } from './question-textbox'; +import { DropdownQuestion } from './question-dropdown'; + +@Injectable() +export class QuestionService { + + // Todo: get from a remote source of question metadata + // Todo: make asynchronous + getQuestions() { + + let questions: QuestionBase[] = [ + + new DropdownQuestion({ + key: 'brave', + label: 'Bravery Rating', + options: [ + {key: 'solid', value: 'Solid'}, + {key: 'great', value: 'Great'}, + {key: 'good', value: 'Good'}, + {key: 'unproven', value: 'Unproven'} + ], + order: 3 + }), + + new TextboxQuestion({ + key: 'firstName', + label: 'First name', + value: 'Bombasto', + required: true, + order: 1 + }), + + new TextboxQuestion({ + key: 'emailAddress', + label: 'Email', + type: 'email', + order: 2 + }) + ]; + + return questions.sort((a, b) => a.order - b.order); + } +} diff --git a/public/docs/_examples/cb-dynamic-form-deprecated/ts/example-config.json b/public/docs/_examples/cb-dynamic-form-deprecated/ts/example-config.json new file mode 100644 index 0000000000..e69de29bb2 diff --git a/public/docs/_examples/cb-dynamic-form-deprecated/ts/index.html b/public/docs/_examples/cb-dynamic-form-deprecated/ts/index.html new file mode 100644 index 0000000000..ec3e1cbbb2 --- /dev/null +++ b/public/docs/_examples/cb-dynamic-form-deprecated/ts/index.html @@ -0,0 +1,29 @@ + + + + + + Dynamic Form + + + + + + + + + + + + + + + + + + Loading app... + + + diff --git a/public/docs/_examples/cb-dynamic-form-deprecated/ts/plnkr.json b/public/docs/_examples/cb-dynamic-form-deprecated/ts/plnkr.json new file mode 100644 index 0000000000..5034d652aa --- /dev/null +++ b/public/docs/_examples/cb-dynamic-form-deprecated/ts/plnkr.json @@ -0,0 +1,9 @@ +{ + "description": "Dynamic Form Deprecated", + "files":[ + "!**/*.d.ts", + "!**/*.js", + "!**/*.[1].*" + ], + "tags":["cookbook"] +} diff --git a/public/docs/_examples/cb-dynamic-form-deprecated/ts/sample.css b/public/docs/_examples/cb-dynamic-form-deprecated/ts/sample.css new file mode 100644 index 0000000000..fe2cc28481 --- /dev/null +++ b/public/docs/_examples/cb-dynamic-form-deprecated/ts/sample.css @@ -0,0 +1,7 @@ +.errorMessage{ + color:red; +} + +.form-row{ + margin-top: 10px; +} \ No newline at end of file diff --git a/public/docs/_examples/cb-dynamic-form/ts/app/dynamic-form-question.component.html b/public/docs/_examples/cb-dynamic-form/ts/app/dynamic-form-question.component.html index ceb2f41177..9f1b8cd4a6 100644 --- a/public/docs/_examples/cb-dynamic-form/ts/app/dynamic-form-question.component.html +++ b/public/docs/_examples/cb-dynamic-form/ts/app/dynamic-form-question.component.html @@ -1,17 +1,17 @@ -
+
- - -
+
{{question.label}} is required
diff --git a/public/docs/_examples/cb-dynamic-form/ts/app/dynamic-form-question.component.ts b/public/docs/_examples/cb-dynamic-form/ts/app/dynamic-form-question.component.ts index 0593fd523e..3381d1c444 100644 --- a/public/docs/_examples/cb-dynamic-form/ts/app/dynamic-form-question.component.ts +++ b/public/docs/_examples/cb-dynamic-form/ts/app/dynamic-form-question.component.ts @@ -1,15 +1,16 @@ // #docregion import { Component, Input } from '@angular/core'; -import { ControlGroup } from '@angular/common'; +import { FormGroup, REACTIVE_FORM_DIRECTIVES } from '@angular/forms'; import { QuestionBase } from './question-base'; @Component({ selector: 'df-question', - templateUrl: 'app/dynamic-form-question.component.html' + templateUrl: 'app/dynamic-form-question.component.html', + directives: [REACTIVE_FORM_DIRECTIVES] }) export class DynamicFormQuestionComponent { @Input() question: QuestionBase; - @Input() form: ControlGroup; + @Input() form: FormGroup; get isValid() { return this.form.controls[this.question.key].valid; } } diff --git a/public/docs/_examples/cb-dynamic-form/ts/app/dynamic-form.component.html b/public/docs/_examples/cb-dynamic-form/ts/app/dynamic-form.component.html index e8f14612c9..717f09ff71 100644 --- a/public/docs/_examples/cb-dynamic-form/ts/app/dynamic-form.component.html +++ b/public/docs/_examples/cb-dynamic-form/ts/app/dynamic-form.component.html @@ -1,6 +1,6 @@
-
+
diff --git a/public/docs/_examples/cb-dynamic-form/ts/app/dynamic-form.component.ts b/public/docs/_examples/cb-dynamic-form/ts/app/dynamic-form.component.ts index 5d6eb833ed..15730806d1 100644 --- a/public/docs/_examples/cb-dynamic-form/ts/app/dynamic-form.component.ts +++ b/public/docs/_examples/cb-dynamic-form/ts/app/dynamic-form.component.ts @@ -1,27 +1,27 @@ // #docregion import { Component, Input, OnInit } from '@angular/core'; -import { ControlGroup } from '@angular/common'; +import { FormGroup, REACTIVE_FORM_DIRECTIVES } from '@angular/forms'; +import { DynamicFormQuestionComponent } from './dynamic-form-question.component'; import { QuestionBase } from './question-base'; import { QuestionControlService } from './question-control.service'; -import { DynamicFormQuestionComponent } from './dynamic-form-question.component'; @Component({ selector: 'dynamic-form', templateUrl: 'app/dynamic-form.component.html', - directives: [DynamicFormQuestionComponent], + directives: [DynamicFormQuestionComponent, REACTIVE_FORM_DIRECTIVES], providers: [QuestionControlService] }) export class DynamicFormComponent implements OnInit { @Input() questions: QuestionBase[] = []; - form: ControlGroup; + form: FormGroup; payLoad = ''; constructor(private qcs: QuestionControlService) { } ngOnInit() { - this.form = this.qcs.toControlGroup(this.questions); + this.form = this.qcs.toFormGroup(this.questions); } onSubmit() { diff --git a/public/docs/_examples/cb-dynamic-form/ts/app/main.ts b/public/docs/_examples/cb-dynamic-form/ts/app/main.ts index 5a8d9c5044..461ce210c6 100644 --- a/public/docs/_examples/cb-dynamic-form/ts/app/main.ts +++ b/public/docs/_examples/cb-dynamic-form/ts/app/main.ts @@ -1,6 +1,11 @@ -import { bootstrap } from '@angular/platform-browser-dynamic'; +// #docregion +import { bootstrap } from '@angular/platform-browser-dynamic'; +import { disableDeprecatedForms, provideForms } from '@angular/forms'; import { AppComponent } from './app.component'; -bootstrap(AppComponent, []) - .catch((err: any) => console.error(err)); +bootstrap(AppComponent, [ + disableDeprecatedForms(), + provideForms() +]) +.catch((err: any) => console.error(err)); diff --git a/public/docs/_examples/cb-dynamic-form/ts/app/question-control.service.ts b/public/docs/_examples/cb-dynamic-form/ts/app/question-control.service.ts index 3d56b0c2f6..1378ba8490 100644 --- a/public/docs/_examples/cb-dynamic-form/ts/app/question-control.service.ts +++ b/public/docs/_examples/cb-dynamic-form/ts/app/question-control.service.ts @@ -1,18 +1,20 @@ // #docregion import { Injectable } from '@angular/core'; -import { FormBuilder, Validators } from '@angular/common'; +import { FormControl, FormGroup, Validators } from '@angular/forms'; + import { QuestionBase } from './question-base'; @Injectable() export class QuestionControlService { - constructor(private fb: FormBuilder) { } + constructor() { } - toControlGroup(questions: QuestionBase[] ) { - let group = {}; + toFormGroup(questions: QuestionBase[] ) { + let group: any = {}; questions.forEach(question => { - group[question.key] = question.required ? [question.value || '', Validators.required] : [question.value || '']; + group[question.key] = question.required ? new FormControl(question.value || '', Validators.required) + : new FormControl(question.value || ''); }); - return this.fb.group(group); + return new FormGroup(group); } } diff --git a/public/docs/_examples/cb-dynamic-form/ts/app/question.service.ts b/public/docs/_examples/cb-dynamic-form/ts/app/question.service.ts index ee169d0827..bb452cf5e6 100644 --- a/public/docs/_examples/cb-dynamic-form/ts/app/question.service.ts +++ b/public/docs/_examples/cb-dynamic-form/ts/app/question.service.ts @@ -1,9 +1,9 @@ // #docregion import { Injectable } from '@angular/core'; +import { DropdownQuestion } from './question-dropdown'; import { QuestionBase } from './question-base'; import { TextboxQuestion } from './question-textbox'; -import { DropdownQuestion } from './question-dropdown'; @Injectable() export class QuestionService { diff --git a/public/docs/_examples/package.json b/public/docs/_examples/package.json index 50622f9aaf..00a3eb533c 100644 --- a/public/docs/_examples/package.json +++ b/public/docs/_examples/package.json @@ -28,6 +28,7 @@ "@angular/common": "2.0.0-rc.2", "@angular/compiler": "2.0.0-rc.2", "@angular/core": "2.0.0-rc.2", + "@angular/forms": "0.1.0", "@angular/http": "2.0.0-rc.2", "@angular/platform-browser": "2.0.0-rc.2", "@angular/platform-browser-dynamic": "2.0.0-rc.2", diff --git a/public/docs/_examples/systemjs.config.js b/public/docs/_examples/systemjs.config.js index ca37f9e8e1..22b0c210cc 100644 --- a/public/docs/_examples/systemjs.config.js +++ b/public/docs/_examples/systemjs.config.js @@ -24,6 +24,7 @@ 'common', 'compiler', 'core', + 'forms', 'http', 'platform-browser', 'platform-browser-dynamic', diff --git a/public/docs/_examples/systemjs.config.plunker.js b/public/docs/_examples/systemjs.config.plunker.js index bf2fc3de68..cf1ca0486f 100644 --- a/public/docs/_examples/systemjs.config.plunker.js +++ b/public/docs/_examples/systemjs.config.plunker.js @@ -7,6 +7,7 @@ var ngVer = '@2.0.0-rc.2'; // lock in the angular package version; do not let it float to current! var routerVer = '@3.0.0-alpha.7'; // lock router version + var formsVer = '@0.1.0'; // lock forms version //map tells the System loader where to look for things var map = { @@ -14,6 +15,7 @@ '@angular': 'https://npmcdn.com/@angular', // sufficient if we didn't pin the version '@angular/router': 'https://npmcdn.com/@angular/router' + routerVer, + '@angular/forms': 'https://npmcdn.com/@angular/forms' + formsVer, 'angular2-in-memory-web-api': 'https://npmcdn.com/angular2-in-memory-web-api', // get latest 'rxjs': 'https://npmcdn.com/rxjs@5.0.0-beta.6', 'ts': 'https://npmcdn.com/plugin-typescript@4.0.10/lib/plugin.js', @@ -57,6 +59,9 @@ // No umd for router yet packages['@angular/router'] = { main: 'index.js', defaultExtension: 'js' }; + // Forms not on rc yet + packages['@angular/forms'] = { main: 'index.js', defaultExtension: 'js' }; + var config = { // DEMO ONLY! REAL CODE SHOULD NOT TRANSPILE IN THE BROWSER transpiler: 'ts', diff --git a/public/docs/ts/latest/cookbook/_data.json b/public/docs/ts/latest/cookbook/_data.json index 7043e62696..f6ef392936 100644 --- a/public/docs/ts/latest/cookbook/_data.json +++ b/public/docs/ts/latest/cookbook/_data.json @@ -26,7 +26,7 @@ "intro": "Techniques for Dependency Injection" }, - "dynamic-form": { + "dynamic-form-deprecated": { "title": "Dynamic Form", "intro": "Render dynamic forms with NgFormModel" }, diff --git a/public/docs/ts/latest/cookbook/dynamic-form-deprecated.jade b/public/docs/ts/latest/cookbook/dynamic-form-deprecated.jade new file mode 100644 index 0000000000..2efa5f8197 --- /dev/null +++ b/public/docs/ts/latest/cookbook/dynamic-form-deprecated.jade @@ -0,0 +1,149 @@ +include ../_util-fns + +.alert.is-important + :marked + This cookbook is using the deprecated forms API. + + We have created a new version of this cookbook using the new API here. + +:marked + We can't always justify the cost and time to build handcrafted forms, + especially if we'll need a great number of them, they're similar to each other, and they change frequently + to meet rapidly changing business and regulatory requirements. + + It may be more economical to create the forms dynamically, based on metadata that describe the business object model. + + In this cookbook we show how to use `ngFormModel` to dynamically render a simple form with different control types and validation. + It's a primitive start. + It might evolve to support a much richer variety of questions, more graceful rendering, and superior user experience. + All such greatness has humble beginnings. + + In our example we use a dynamic form to build an online application experience for heroes seeking employment. + The agency is constantly tinkering with the application process. + We can create the forms on the fly *without changing our application code*. + + +:marked + ## Table of contents + + [Question Model](#object-model) + + [Form Component](#form-component) + + [Questionnaire Metadata](#questionnaire-metadata) + + [Dynamic Template](#dynamic-template) + +:marked + **See the [live example](/resources/live-examples/cb-dynamic-form-deprecated/ts/plnkr.html)**. + +.l-main-section + +:marked + ## Question Model + + The first step is to define an object model that can describe all scenarios needed by the form functionality. + The hero application process involves a form with a lot of questions. + The "question" is the most fundamental object in the model. + + We have created `QuestionBase` as the most fundamental question class. + ++makeExample('cb-dynamic-form-deprecated/ts/app/question-base.ts','','app/question-base.ts') + +:marked + From this base we derived two new classes in `TextboxQuestion` and `DropdownQuestion` that represent Textbox and Dropdown questions. + The idea is that the form will be bound to specific question types and render the appropriate controls dynamically. + + `TextboxQuestion` supports multiple html5 types like text, email, url etc via the `type` property. + ++makeExample('cb-dynamic-form-deprecated/ts/app/question-textbox.ts',null,'app/question-textbox.ts')(format='.') + +:marked + `DropdownQuestion` presents a list of choices in a select box. + ++makeExample('cb-dynamic-form-deprecated/ts/app/question-dropdown.ts',null,'app/question-dropdown.ts')(format='.') + +:marked + Next we have defined `QuestionControlService`, a simple service for transforming our questions to an ngForm control group. + In a nutshell, the control group consumes the metadata from the question model and allows us to specify default values and validation rules. + ++makeExample('cb-dynamic-form-deprecated/ts/app/question-control.service.ts',null,'app/question-control.service.ts')(format='.') + + +:marked + ## Question form components + Now that we have defined the complete model we are ready to create components to represent the dynamic form. + +:marked + `DynamicFormComponent` is the entry point and the main container for the form. ++makeTabs( + `cb-dynamic-form-deprecated/ts/app/dynamic-form.component.html, + cb-dynamic-form-deprecated/ts/app/dynamic-form.component.ts`, + null, + `dynamic-form.component.html, + dynamic-form.component.ts` +) +:marked + It presents a list of questions, each question bound to a `` component element. + The `` tag matches the `DynamicFormQuestionComponent`, + the component responsible for rendering the details of each _individual_ question based on values in the data-bound question object. + ++makeTabs( + `cb-dynamic-form-deprecated/ts/app/dynamic-form-question.component.html, + cb-dynamic-form-deprecated/ts/app/dynamic-form-question.component.ts`, + null, + `dynamic-form-question.component.html, + dynamic-form-question.component.ts` +) +:marked + Notice this component can present any type of question in our model. + We only have two types of questions at this point but we can imagine many more. + The `ngSwitch` determines which type of question to display. + + In both components we're relying on Angular's **ngFormModel** to connect the template HTML to the + underlying control objects, populated from the question model with display and validation rules. + + +:marked + ## Questionnaire data +:marked + `DynamicFormComponent` expects the list of questions in the form of an array bound to `@Input() questions`. + + The set of questions we have defined for the job application is returned from the `QuestionService`. + In a real app we'd retrieve these questions from storage. + + The key point is that we control the hero job application questions entirely through the objects returned from `QuestionService`. + Questionnaire maintenance is a simple matter of adding, updating, and removing objects from the `questions` array. + ++makeExample('cb-dynamic-form-deprecated/ts/app/question.service.ts','','app/question.service.ts') + +:marked + Finally, we display an instance of the form in the `AppComponent` shell. + ++makeExample('cb-dynamic-form-deprecated/ts/app/app.component.ts','','app.component.ts') + + +:marked + ## Dynamic Template + Although in this example we're modelling a job application for heroes, there are no references to any specific hero question + outside the objects returned by `QuestionService`. + + This is very important since it allows us to repurpose the components for any type of survey + as long as it's compatible with our *question* object model. + The key is the dynamic data binding of metadata used to render the form + without making any hardcoded assumptions about specific questions. + In addition to control metadata, we are also adding validation dynamically. + + The *Save* button is disabled until the form is in a valid state. + When the form is valid, we can click *Save* and the app renders the current form values as JSON. + This proves that any user input is bound back to the data model. + Saving and retrieving the data is an exercise for another time. + +:marked + The final form looks like this: +figure.image-display + img(src="/resources/images/cookbooks/dynamic-form/dynamic-form.png" alt="Dynamic-Form") + + +:marked + [Back to top](#top) diff --git a/public/docs/ts/latest/cookbook/dynamic-form.jade b/public/docs/ts/latest/cookbook/dynamic-form.jade index 0f0e188edd..e4eb6af1d4 100644 --- a/public/docs/ts/latest/cookbook/dynamic-form.jade +++ b/public/docs/ts/latest/cookbook/dynamic-form.jade @@ -1,5 +1,11 @@ include ../_util-fns +.alert.is-important + :marked + This cookbook uses the new forms API. + + The old forms API is deprecated, but we still maintain a separate version of the cookbook using the deprecated forms API here. + :marked We can't always justify the cost and time to build handcrafted forms, especially if we'll need a great number of them, they're similar to each other, and they change frequently @@ -7,7 +13,7 @@ include ../_util-fns It may be more economical to create the forms dynamically, based on metadata that describe the business object model. - In this cookbook we show how to use `ngFormModel` to dynamically render a simple form with different control types and validation. + In this cookbook we show how to use `formGroup` to dynamically render a simple form with different control types and validation. It's a primitive start. It might evolve to support a much richer variety of questions, more graceful rendering, and superior user experience. All such greatness has humble beginnings. @@ -20,6 +26,8 @@ include ../_util-fns :marked ## Table of contents + [Bootstrap](#bootstrap) + [Question Model](#object-model) [Form Component](#form-component) @@ -31,12 +39,28 @@ include ../_util-fns :marked **See the [live example](/resources/live-examples/cb-dynamic-form/ts/plnkr.html)**. +.l-main-section + +:marked + ## Bootstrap + + During bootstrap we have to register the new forms module by calling `provideForms()` and pass the result to the provider array. + ++makeExample('cb-dynamic-form/ts/app/main.ts','','app/main.ts') + +:marked + The old forms API is going through a deprecation phase. During this transition Angular is supporting both form modules. + + To remind us that the old API is deprecated, Angular will print a warning message to the console. + + Since we are converting to the new API, and no longer need the old API, we call `disableDeprecatedForms()` to disable the old form functionality and the warning message. + .l-main-section :marked ## Question Model - The first step is to define an object model that can describe all scenarios needed by the form functionality. + The next step is to define an object model that can describe all scenarios needed by the form functionality. The hero application process involves a form with a lot of questions. The "question" is the most fundamental object in the model. @@ -58,8 +82,8 @@ include ../_util-fns +makeExample('cb-dynamic-form/ts/app/question-dropdown.ts',null,'app/question-dropdown.ts')(format='.') :marked - Next we have defined `QuestionControlService`, a simple service for transforming our questions to an ngForm control group. - In a nutshell, the control group consumes the metadata from the question model and allows us to specify default values and validation rules. + Next we have defined `QuestionControlService`, a simple service for transforming our questions to a `FormGroup`. + In a nutshell, the form group consumes the metadata from the question model and allows us to specify default values and validation rules. +makeExample('cb-dynamic-form/ts/app/question-control.service.ts',null,'app/question-control.service.ts')(format='.') @@ -94,9 +118,13 @@ include ../_util-fns We only have two types of questions at this point but we can imagine many more. The `ngSwitch` determines which type of question to display. - In both components we're relying on Angular's **ngFormModel** to connect the template HTML to the + In both components we're relying on Angular's **formGroup** to connect the template HTML to the underlying control objects, populated from the question model with display and validation rules. + `formControlName` and `formGroup` have to be registered as directives before we can use them in our templates. + + It turns out we get access to all form directives by importing and registering `REACTIVE_FORM_DIRECTIVES`. + :marked ## Questionnaire data From 9e1e5a1ef81c77686a919119d7ada383707ea090 Mon Sep 17 00:00:00 2001 From: Filipe Silva Date: Fri, 17 Jun 2016 15:19:31 +0100 Subject: [PATCH 07/21] chore: add forms, update router --- public/docs/_examples/quickstart/js/package.1.json | 3 ++- public/docs/_examples/quickstart/ts/package.1.json | 3 ++- public/docs/_examples/quickstart/ts/systemjs.config.1.js | 1 + public/docs/_examples/systemjs.config.plunker.js | 1 + .../upgrade-phonecat-2-hybrid/ts/systemjs.config.1.js | 1 + .../_examples/upgrade-phonecat-3-final/ts/systemjs.config.1.js | 1 + public/docs/_examples/webpack/ts/package.webpack.json | 1 + 7 files changed, 9 insertions(+), 2 deletions(-) diff --git a/public/docs/_examples/quickstart/js/package.1.json b/public/docs/_examples/quickstart/js/package.1.json index c54e43307a..eda746382a 100644 --- a/public/docs/_examples/quickstart/js/package.1.json +++ b/public/docs/_examples/quickstart/js/package.1.json @@ -10,10 +10,11 @@ "@angular/common": "2.0.0-rc.2", "@angular/compiler": "2.0.0-rc.2", "@angular/core": "2.0.0-rc.2", + "@angular/forms": "0.1.0", "@angular/http": "2.0.0-rc.2", "@angular/platform-browser": "2.0.0-rc.2", "@angular/platform-browser-dynamic": "2.0.0-rc.2", - "@angular/router": "2.0.0-rc.2", + "@angular/router": "3.0.0-alpha.7", "@angular/router-deprecated": "2.0.0-rc.2", "@angular/upgrade": "2.0.0-rc.2", diff --git a/public/docs/_examples/quickstart/ts/package.1.json b/public/docs/_examples/quickstart/ts/package.1.json index afd11cdda5..3ff6892bd9 100644 --- a/public/docs/_examples/quickstart/ts/package.1.json +++ b/public/docs/_examples/quickstart/ts/package.1.json @@ -14,10 +14,11 @@ "@angular/common": "2.0.0-rc.2", "@angular/compiler": "2.0.0-rc.2", "@angular/core": "2.0.0-rc.2", + "@angular/forms": "0.1.0", "@angular/http": "2.0.0-rc.2", "@angular/platform-browser": "2.0.0-rc.2", "@angular/platform-browser-dynamic": "2.0.0-rc.2", - "@angular/router": "2.0.0-rc.2", + "@angular/router": "3.0.0-alpha.7", "@angular/router-deprecated": "2.0.0-rc.2", "@angular/upgrade": "2.0.0-rc.2", diff --git a/public/docs/_examples/quickstart/ts/systemjs.config.1.js b/public/docs/_examples/quickstart/ts/systemjs.config.1.js index 4dbe1974c2..901b8f01d0 100644 --- a/public/docs/_examples/quickstart/ts/systemjs.config.1.js +++ b/public/docs/_examples/quickstart/ts/systemjs.config.1.js @@ -25,6 +25,7 @@ 'common', 'compiler', 'core', + 'forms', 'http', 'platform-browser', 'platform-browser-dynamic', diff --git a/public/docs/_examples/systemjs.config.plunker.js b/public/docs/_examples/systemjs.config.plunker.js index cf1ca0486f..67b8a0b1e7 100644 --- a/public/docs/_examples/systemjs.config.plunker.js +++ b/public/docs/_examples/systemjs.config.plunker.js @@ -33,6 +33,7 @@ 'common', 'compiler', 'core', + 'forms', 'http', 'platform-browser', 'platform-browser-dynamic', diff --git a/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/systemjs.config.1.js b/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/systemjs.config.1.js index a4134235b8..3661eb52a2 100644 --- a/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/systemjs.config.1.js +++ b/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/systemjs.config.1.js @@ -25,6 +25,7 @@ 'common', 'compiler', 'core', + 'forms', 'http', 'platform-browser', 'platform-browser-dynamic', diff --git a/public/docs/_examples/upgrade-phonecat-3-final/ts/systemjs.config.1.js b/public/docs/_examples/upgrade-phonecat-3-final/ts/systemjs.config.1.js index a4134235b8..3661eb52a2 100644 --- a/public/docs/_examples/upgrade-phonecat-3-final/ts/systemjs.config.1.js +++ b/public/docs/_examples/upgrade-phonecat-3-final/ts/systemjs.config.1.js @@ -25,6 +25,7 @@ 'common', 'compiler', 'core', + 'forms', 'http', 'platform-browser', 'platform-browser-dynamic', diff --git a/public/docs/_examples/webpack/ts/package.webpack.json b/public/docs/_examples/webpack/ts/package.webpack.json index 94e5525bd2..d1d79fe9f4 100644 --- a/public/docs/_examples/webpack/ts/package.webpack.json +++ b/public/docs/_examples/webpack/ts/package.webpack.json @@ -13,6 +13,7 @@ "@angular/common": "2.0.0-rc.2", "@angular/compiler": "2.0.0-rc.2", "@angular/core": "2.0.0-rc.2", + "@angular/forms": "0.1.0", "@angular/http": "2.0.0-rc.2", "@angular/platform-browser": "2.0.0-rc.2", "@angular/platform-browser-dynamic": "2.0.0-rc.2", From 212183bbb7810b84996093a61b750b165f705393 Mon Sep 17 00:00:00 2001 From: Filipe Silva Date: Tue, 21 Jun 2016 04:36:07 +0100 Subject: [PATCH 08/21] fix(plunkers): fix form plunkers --- public/docs/_examples/systemjs.config.plunker.js | 1 - 1 file changed, 1 deletion(-) diff --git a/public/docs/_examples/systemjs.config.plunker.js b/public/docs/_examples/systemjs.config.plunker.js index 67b8a0b1e7..cf1ca0486f 100644 --- a/public/docs/_examples/systemjs.config.plunker.js +++ b/public/docs/_examples/systemjs.config.plunker.js @@ -33,7 +33,6 @@ 'common', 'compiler', 'core', - 'forms', 'http', 'platform-browser', 'platform-browser-dynamic', From b11e8827bc6281c957b9c1b87cde19fb60276cf7 Mon Sep 17 00:00:00 2001 From: Rob Wormald Date: Mon, 20 Jun 2016 21:44:26 -0700 Subject: [PATCH 09/21] chore(bios): add rob w --- harp.json | 9 +++++++++ public/resources/images/bios/rob-wormald.jpg | Bin 0 -> 15111 bytes 2 files changed, 9 insertions(+) create mode 100644 public/resources/images/bios/rob-wormald.jpg diff --git a/harp.json b/harp.json index e79fb92241..0aaa384225 100644 --- a/harp.json +++ b/harp.json @@ -294,6 +294,15 @@ "bio": "Stephen is a Developer Advocate working on the Angular team. Before joining Google, he was a Google Expert. Stephen loves to help enterprises use technology more effectively.", "type": "Google" }, + "robwormald": { + "name": "Rob Wormald", + "picture": "/resources/images/bios/rob-wormald.jpg", + "twitter": "robwormald", + "website": "http://github.com/robwormald", + "bio": "Rob is a Developer Advocate on the Angular team at Google. He's the Angular team's resident reactive programming geek and founded the Reactive Extensions for Angular project, ngrx.", + "type": "Google" + }, + "pawel": { "name": "Pawel Kozlowski", "picture": "/resources/images/bios/pawel.jpg", diff --git a/public/resources/images/bios/rob-wormald.jpg b/public/resources/images/bios/rob-wormald.jpg new file mode 100644 index 0000000000000000000000000000000000000000..2c0080e5bba0bc48d2a80f6a33a74bd6c2eca362 GIT binary patch literal 15111 zcmdVAbyQqS*C*V#yGwBQ#@*fB9U6BDgkZtFgF{GgcXxuj1czY3A&}rsfUlG1-uvE} z_0D`Vf6ne+tE@ulCueUY1`r0ho%i3bFtwC@8=gpCDk=ab z004jpfP=yYz(871kPiTg7y$RD4FD)Yk^Ixvgktzh1{wf}v0RVEL|FLqG3-eEV8lngB5^mSd%garWo!!Ng z&BEH%62xZZ>dfwI;l>VR<6s8}i}|`)SUG~cC@ev?_AVmyrybq&6!z94^m;rh94c;7 zAUk_`KM#dEPPpAJgFfT zkSYGykOp~LdDy#o*}J;@eLH726_tOi{kJ1?cK+=H1%)ugQ56+IH4l5p@GP99U9G&G zK`vej(xSXP(m-xW4hbL+Cs0C`pHoUkT9!*%l9!v8g9FF~T?H3UFAEnd z5X2rtn$6zcTF{1{gF}Ezz>1ZF(?)=mo0AvBY9U}_$tqyME5OGMw6x;j;QHJ4ztsQB z=70G}@%u0I0C~E4dsu-)=zrhA`v33_^c3v>j}2d#{r719HQE3B0Qlce|37mtr~(N` zYYQ(6X$voqC?^Mymz9H?m4i;#!_Ld%y$guuP?O)t~G$1zwIq6H=LvZ7d$DG_; z+<%Gx&#eDZ$KZdh^DowaA7}rGJqUb4fRz0oxP^570c?;91f@NG!|}^1Knei;hhU(g zVPIikU|`{3Aq0m2_nQz95&jV3UxfUJP<|8IKlIxO6vPHZ86NUQLqb6MhxdQncvy6#b2lqk=Q>+D_QH;Qm2qS*2EtSL+mjD2)-(yqB z($%xM1B+=T$G#ROS-?VDTVjhNhT60jp~4JD^pIdHOYc<_!-y0t9%eQ*I%+vdL{A@w zZ+!et11nBL1wg8(=nskVLmSOY1{z(IF7j|U7DodO98{v)zG$kjwVJJpM*7nzBVuEU zzYjqwujmgAmg-R`yo_r((0wc7T2_FAm1vt?pYM9Pgf=sty^5f*%$gnYwUkO8iZ}_{ z(E(~}geEv4+X$@3)1=5k6V-HMxT5(3En%>fZy$FoT4-;MJ$&I(0=|$!UUP+Kf#T4e zOi7M*yduL8T6J-edvQlZ^MkQ%BeShSHIQ9i(8@Er$!9XNI;LUy^Iz;`l>2m9{LYddi6@l?@B6YX%1=fqU5YhK{-HJ(a|G-29L<*C+L=ZLq)by?@0 z&k1O0oliI}=29Loqp&=zAbCP{DpaG4^M^zY6^B7qx1$HCsq2=eIi+G-6Z^U&Ft_DG zUKel`WKbgpb#m^N<#A=wwj$nJmV$*gt|va)-z(Y9z1Nu?SDG=y%RM_xmQyAm)SMo> z4h&am`1sVe;s}2)*J$NERA9`nRUL&e1BE;zJ-5NK=JVx9$nZEm!M zaA^8WVp;>$$(&m0U4Ut!;+!BuH+j4ryGeuzc14kQS5|L=%(d1hH=y*Vwe9o)s zj!p7#WfVlK&FZ4!?Z3R;DJW2mM?0TbHT&rIYlP*2%_*nl+%60g6H1(3GF&)0v<^0H zukcc|qT|iRhHmCm9FLX~dfaM9qUXcM>cyWai{pXv8i6D;!=v2Whs(z#D|fpR(AZHM^|L;548f^_kR9QKWex9Ag3tSXU8b+}rAo^vWJb3wxHt~o5TothiP z2U&vMdi$Xz(K1qQFg*%o@vxZQ^lFuX*Gc2!(E8kh_&A6)`jv-Mh5xT1iA-?FT5X1<|)hErGTTMaP?0gVJU+ z)k4bUe0i$(0gQ4rd>y~&Z}zl(CEz#bv*4h(N=wz>$(IwQ(1BX~@4*e8=&>s9O{>Ub z8|}9IamB4Wf^RN`tSo>y3-?>XZ;*K*nJ(%(;+Xdrx~7p)kzCaeQ*6)cdk;?p$=xzF zLfF-YRZd0u>Bg6Dtze89pMpN%j9kc4w(%kYVGF02~%J z4lV^H2RtSfwKyIPkc(R#0^^7fbcce2egTYe4slEpgT)X;J;;QA>8G1Jp_1H9^m+`< z!eTf$U8>uDh_c9Pl}%h72<^vz_;9!u1bB)DsCbVwu{4aOI`J|#5pvAeepa^B&Y~>q z*9QjQSP+?BBop1-Pmy-js@k@27n5V|2AUBWfYUt_&+*BzE@;%7zu3AA1M0{eo!?}L zuK80>PvAPWFu8S%4fHv?`GEGhI&V! zrF~Y&Gk9l2Uwr0*i8^D`vU`ryYQeXk2%bBBsm9*m1zN(ZGanerd1MaW78y9zZ-U#ckd3)cvhLF%CuDXsUcNln|bNS56) zb_sYRJ2b~f$*ROIj#5Y;T0^gik0(;Kqp!!7=jW{(pH4M?5tI>!i3(ihm;|G;A-v=C zBov=}qYDbjk)54;!aXANAkM}Y=0CT+>%*(JOR*|}m+!AUyW?$qp8b{f=1lJ?35?C3 zi};oaWc^mxP8Yc6+uN5tQ86$I{+KYAAU)ng)S;`i!r`}dxAxiyredCLu$5A=?ZG9- zkqlEe+V3f2H=%$QutgZKQ}<(o+yAutcyWNb>_SY0cF#JP^zfbl({}dEJ3N|J&A7o| znms^@sr^aY;P|ISeNxiQ*QQtc&2I&4{igK=niEXN1Z&3iRAen)hx^j_?Ng%J);Wa1 zBX@$5hWSWh7UG>#f2K_hI`Wh(9_O_XYo3`uWJ}=!E9>5%)J6=9}KRGs%w)WqKy(v4`c_$Y<}@9B6E65f&pO z*u#7TsH%`RWf!oRB$PW=DbRXSi<<2vTWKuu+-4lO?d*`nyv=Zw598L`!k?|Qq175< z-iwY@3D2#-^I6s})vZ*ht62GQuFR`BH00uFP{Yo6`ICyJTb9p3HgoSOTiVg^idk>UL#;OPJabg1Lm1ebx0je9>bNwM8XsM|#ODSr(MW9yj?+-Q^Co$mhO z-h8uFl(%4i|0ci}ZmTccK-LOo!XY)Pw9Eo#?pPx7UV-AUB5Ps7)%VYL-!jtJr0ckS zojdt`$QJoX4|3A{kxqXRPxEBvM^TYGy&Gmt07fVg?@r4O1?c+=HcDdY1W5n#RD3V@ z6a+F<>^5`CcXnOy>&n!<)%yXCPkI4FljQjjG5#rgQ?ME2Px2wfp+)h#+OZZxpu#_45>pOm1}jbp?^Ji2oYPzpf`wxTE%TmggBaqN#1d!s|DD(4)8$U2zUE4o) zYSv+Y=)mcvx4iEqxn_*_<(AJZZO_yzDUXoqqveT>JifhX{y;7fUX zR19kf3NJ1zY(mU#!?e1| zh7_we1X7H{a1Jy1HNbOQ(M0ZgZ>#oUHioe3AMPlF*g8gs_NCh3%mx!uv!!QRyt`ye zjXmDS)bCdAB@r&py~sw{NY&amNsZ?;th6Y5xIfA5>o0nFTIh;gf;UG7mzRdGA&JTW z&!{JNO?z+QT<@$NkF&rSLlG$&#$ha_jfa+isK)3(**-;!=2=s`wX33OH`+p=XffXB zs7aaiw`RX+i@%vFvNSI>-6;y36>y^6P-z$7%YHE3M&|7`;2($fkbyW{0%YOI$S8LvQ|K?L*Phtn%Cw4tExHeTlYJ~w;)dy-8(i$BifVL z_W_yX@~KR#L0WAhs`+@VJRyQdKfk6NXgW+7f)qcPjCK$otsWU2Z=T%;j-&Kp&<-`Y z3uSq}Q}bA5$pNcX&nr2ZrQ)Pc(HdC;&sw!z^*_RLOWY6L4ZAq|4l=rG*z++grlM7zxJ5`p{PFLU@c99e>s}Q06Tihow_Po z%j`ZSoo4=q=i4q6nxnk^EylDF; zWwzqSYuX4pIy(M1n-W~mQ4nNpGC|fRWO2g4LLMmpda#3n#)84bri2BG!{Km9P;qKl z;8IKeCpm!ry)YrkLH#hdtL)C3K%NBI)6G?CD~2tSacjM3P=ehr8Aj?g(&=5f2V5^x zoYccZpW>}FK5JMvcDN3vgabtXctT0xP^H5^I#&v4(8 zDwkj1XIcw6Of>ArwFzu)2=`5lTtkns3~y%)vog+{k?u zbrEV6L!3%6`8?P)GYJ%zQZ481#>>zwtn8l0$@ECLWirZb`GY;Hda~|kG-}NcD}kNehJ}zu%oHtfBv3aCNy@B*~`B|45?QYQ({U{NJ5^gx|7f@mki>xq{ zD85q`bz3Hzaeb7%VX++Ji2=fW4F(Jkg_;zYW(5P^{>?uc}dGdzH?z zuUzq^k?qXG4e{wyBbn6$HQb;_BMb4?(yxjs=ixx;wpXkVcq88?&3LYv_x*-t*2Aa@ z1jc*Qw&Bqhh}^>!*{pn@^v0lc0>@5XLB|D`srr?F77&-xklJJy45qfVh-fckhMU-< zVbgsc&lsInhf~&#;hc2K3jR_KO(isC#^S*nXD8h#n_KC)`t<433|PnamoX6uI2T5zaM%ETP zZcW?f6X}^1(hJRJ!JEM<5WiIm)JFCzPDj-WZOBK<){>u*(Ef(ZX@Z43JA6)0wlI^A z_FBjIv-S6RK=-YV%}@+o%h}jrd3CwJs;`<)?oau7Hr3BZm+crjL`z3nhq#8E@5~%J z*XCS1X#4A!qV zboJ$fe*uhaeyTNygAcdaFAwm>xs9H za2vK_j=D7ql3sF#$#?-+OH!0kiX#RRAiVxjFZSJtbNMZCNmB$~I^N(^Gdj)38p^l0 zqR6QXE^K<9noQslm!*!5cUMditQlgZ4wa(Q<7>bTkp1E38Qb+n2wGxmyq!X7E}7Jq zJ!18vP4RS7KMjJht^YZ1abg(o%?X*nCQT!__bhEOars{o^(q^E2-n$AsZ ziH1!7_UF@b&kY6tNpDqmamURPai4R8D8pBLlAZIC`JIPOWp zbLF3z>cd$zK7@cnyKg5R{RtFV-BQP|WOP4ah2)PYc3!^OKx$U`LM~0X0@cp*&G0nw zL%I%Ok1w^oeXz_8{zrjBUy`%|9(amqdb&OCDNb`z?jnj;uJ7f3)X$tEMTISt}e8? zR%;+5Bpp0HM)BB_my-Vsauy)<#4K5(&|SVsAC{#lQwM7w$v)7?59g%?pB$NYYVQ&NIeB_7gXL(iBcwGw{zCb9Gjr0 zGMB}zaWZobZx27pjelz?v7^7J*-RK9JN^EgJOYg$Q1cMn2GcSk_M@*;s4P(Ji01?N z>J*`{Ie5tMaRSkfX!3{@Czxv&hjh04xg(qm|3ez#r%O0qb#l=D-f+#-GJX zVpP+y!t$ivz54>t*yl_B6$7{aqf(ODh5uKHh#7eN1wbdiqP&wc;2HV$nf8Hf)#Cnk z<#ael9(m`&D(6jGJ?1CEYd^%-(KCX=YeujEKgDkJbG|5Z1Ym=3W_@Pgzd6M_ zzIfYP%AB%E;{hKxRwjqqm2j2FkM?OJ2pIR)%Ze#q@|6!mrQ$38Z^D&OsRi(QT&;^kf^+_I)`plLhI9^J0L#Wnbb`R+ z0Y7-ZwKiY6F3Kv9UOC1#tM=EMd4ym5B^x3MLO$KQG!vWpkohln63Y_VER!`WBy9+^ zs?!u_jU}OLh)J85?Xk|*(qiyW{PF-Z2Lwx*5FNNZ_BO81iG;Gi#gH9?njJ^4Sg*>W zp`@lF_Zed6Mk8pLI-mD#6I}%y-SY8Zzrr@nQ;1}MLl8gPgBj-L>m4K_tVq2|>mSxW zhog^-;Z6q;!09o(8F>M4uC-iX{TkX2S-tG8!+NAY%gi(yp!7x8&jX!erAd8C$liSJ2D-UaOrrX%wc{`5EfC8zNot|ep(CHlFmfDA016(4|t9#z>5#>g0704xYe zY&N>DbFSUN+yrr1nU^w8TeN{@12Asjy_SFYxC&$rEfme&riuQtA;VVKZX@sGYx%XgY0o*u;EA%hv%m$=@Ro z1q~>^WBjs0R@)FgK=p~_l64Gs{xTE@efUjQ+tN!v08c>LpX(e+Pr{{jlWEIzIEY0e zO|mzBt|n+D^VH6Sf6cKGdh3}&;m5nr+3yDG4G)57ZGazYCVrCcwWAM_4U(N0=MSR{Xgs&pL7DFBwe=N!(QJ}6Z5l0ZTjaFX20C4KCE4S_Ng@(F7 zuc7lAw4x4QpFNxK+KLc1XndJfkrNT>+-z|^YDRVOe(mP>o}0*~)z~S<%6%o5*1>sn zb)ZKWJ4IldIPWdt@`v~b9sCElUhN$qW-Qv4X5MvFtt>F^`g>!mMC`oQuDQT&?PcTO z#E_TmeD<{emmwFy=O)HCa9Z&O#jL*0v54GDc0Y~YyoQSsLJVwbB1r{GP341o(WcS( zrZ&Ggzq%slGS`m|K<@}Zi6Iw{Q&%iRdmTYkG2nJ%af#Dr`Dv3^Z6Cx%0lIbBmYUGThet+$XtLjT1 zRXmtDjW)$%q1({52!U+b}3_3caYUjq;V9S10xewQ%>&rF*<7&&@l?!t=NEZplj3k zDM_N&yFC|C2q8xN%86&OuO(G`8Fk5wev;|f>c0RelnS8`L^uG`8sz!g2c=h_t5%sX zjZ)X8Ug*_^vQ-+^ao@mu+X4PcQc$-=3WBw{+a9(Y=)I}dj3{VZp5y5<845n@MV!X=Y1r(yEei3Lwa85oC zb_pos*e@g8um+1Kc;AmBL@Nr`#HLU>vV2rv9N!mzzYFz?TV5D1!_mc-7Mh#+9BP3X zaWeu&oG&3g8Yj@3)75>H4jalj;q9JlYnL?o(R+`#GVo&RWDW}h#g1F+_I8W_lyHOc zy;r1OYS@y3b? zCC+hqOI;gfks7=IHRw)yfN~GFZ%rC)P{2a={j0QrX^r#oO~2g-N@q-!!D*G;5JN~- zCg*L2^NK59k#hi%7i)d;7xVWekK9R#wl!dxO-WPyRfrF&K|i8$YWOu~+7aTK8o_s} z8Kg$qH8KrZebiZ#cZ11D%MmkBw(0{tGy(j_F`v#gJFB;rPmG*^Sj=m#mf6xFIvp zb40Z7!hpDu>T8MOZ5C))-q4w}gpoRE*>vy9GOS_15JjsY>X3An)UctKd}*QIAP`5Y=nQg zYwhd3^DHf&Ugr!kotRa$?doAu&7fA)>E$`n+~2$Ezr=`mq(5w1Op%j)2*5 zyrGKH5#(VWm>T3B_Wh8G4j&NIglPz#00gu=#20mMo`FI0xoMP$Qnw8GAGG##z6NR- zQBv>uzTUqM#F&sExI975;0XE*!ZJU{8w{te0@!E1Hbfe<6iCp| zMw;}HejK|++Qo%BZ^VOJz=;r6&!S<&MSXCshct!gAR+o(O|#g?WXMjAV>Kj+uVib4{q3CKN4Z zqf_O_AJjdo1qDbgMPjyp=XN6rI~nqAbu?n{Otl089yD0L4|@DQW&(hG|CH?i1`iGk zck#r$ng0OC?}{Mi9YQzVXf1GuB{PQx_zZ9=3u1FAGP=6HO@JqzA$a!*KGm zC0<4CTYM#+?T0#%(|Xmq8*zl7E4n!^=pN)x9(S?2yoy!ZXR9Suf1X~%aqHqv8wX=m zkt3X5)4%SCbtXQ8!PNY(6ToC z8jP>!;^aKIZN#D^fz@tw_AOmkN`p_O=ksEC6*j}i{VCh1jv#+zUBFkCHrsO?@(!+H zJu=oX@!e~TG8-}{=PdXYOcPX3Q}PJ^)sVFKW%|zMSciK4bndPM1EHMAcx|i(J*_=d zuAOewyIMMt%G!<93w?E=*438d7l3EViu1$cSG{b79VnW5r)u~WdvD%*;T(j_<^xD3 zr6n%nt0FBD8hTAv(l%nw={ff5wfrciQy1q!<~wrFb5Q{?EzV89trixP^-03WHBv^I_5_aG4%rUe;q0(Hg!+Pe3vFqF*82nlK1m5?qMhh` zbhpL-X+jIWwQ&ASjJONbLTjka z=9A^TX%;cS0rWj-(lOXR8*?k=@<@5LM0PelZ-l5S=~zZoDR2C(q1+Qo>)u`$D?(by zMoS(RMf4Wt$Fcq&Oz4D7{Io>(ho3Z(m|26%4q+vfCo5Q2ttL_Er?kLT#Ye)cLN2Q8R;S zexSr&yhd?D*TxAY+Ymd?(PZ`| zaiydSlq(P`bvixb65T0#nmRhr!iW79`u%*bJDNC=9-hWXxnhk$R$4&#wipF#S{1IB z!=@V+QSN>m`eISz+j*4xCnxdhLDT?@0T?A1oocqK%cS<;w`eqY+lwumkE0AA`e1aL1a4Ypr}@*ISVzmJMKVwx>oq8g!$(&Rwr$`SI577uM}2Oa3T@(onyI>*nKWk#V*9kMf;4M^5aIMYZ53#2{2H%93ld9yZ=SO7BnyqB6y z;Kb6q)&OuCz{vwo$lnMdKM(~zTa08^Ky{|SGWkr&6QbTT*#_@RNCq$;UDqkvUN|T{ zF84wTY~@=bBP$_~#}hdZN#4F0=e1qTzURa}jz-0~GyyF>!ZKX$^zb8O-Mw z^{1@8$Bz-Pzxu$1f8o|!+Gj%KkwNw{EU8)}16hcZjms@(=M&)Zq0it0DEfK?qb$-n z@sLSuLy=R%&A?!iIAmzjBHV7~@8}=k>zde`#!pOQp-)?C%JOR~@w9Qc7Sg9EGux*1 z0g+4lnhr)N6Y{G4t8;iVOf%we9y)YFC%Md|;&>mLG=uG1uq5{!8e5=en{>)A83{p& zGS#I-Z(jhwsF7Nq^yAR^TKmQGK&UUHMDYhYw0phJl(ABgLGDV=JZ+|@GzxbW=aD#fkoS7A@O63c^cmuE zp@L4!Gseo#)zaNFtH$ehE1xa%4-gw*u{Ovv@EieOHwffnKT~=p*Hr~Mxf_usmpqS$ zQVg+NK#DHz7UEQU-l}(?%mg58$ArHPX%C;9$eM>G%b)>8h1&nr??5DDwAc8Xqp>TT7zu*2=S|G$Q<1jEtZ4UhbHfjpW6I+w$y1B-C*5E%lt_5 z{CW47kBAlra8J}F*aW#Ss!fZ7;MYvQ-#E@2ZR>af;zlz*CRXLv)2hlAs1`3%WA0}q z^fbNzTwKhYDqf=Y?$)d;_c&G5 ztSLt}gyNM+ND{?)+do1-ZGzVc-Y`eDfvKP_<|2 zVA{JWHNV5cUm$w-Lxlr^t1N+%Te}8TQE)5WnwKu@t@Ymcv4NMahDW%$7~`^c-Hjak ztEN>xOwbu>>Bdr~@Nr=F>K%>oAdQ|@M}wz9StntQahN!K40`e?CMn%Bya5~J1^vst zcf5qZjLZkD$X-=c+?6FGO~7TeBncQFiws&vzd_7Q0i>07^}+XX8PTGfsh4ZUW*>j5 zD=0OZLMJ79Bi&YE70*7Vu=1U<1ojqLiV&~CcJG%2bTUYj&hw;br7UHLD=Qq0)h=)J z1yK6tT@xc;WDySN4%`H{4(D8-c|9TMA8K*?$v3XdwR}Maj;*RTP?z7_i3NR$e0x(* z$;ffL_b~?W%F420;dre`96-!uTw%7235CVS=E!+MStbukkBQBIC9~Ra$g2?raMJol zRtZWhXMTLtQn)9bzUQna%XHgzq@K;X_K1_oT?jdUW??Dx z&Yuc*{Khn4s%KbBNRqmOvCo|f`Lc4+kF60PrqSnFu10P96t9EDs zg?Y()iQ5WyoSu%)CzQMkx)p|cl-bW9j_H!>V0~dw*4DOuPcEx1)`R>{ZZFS3HWQ|k z_o_e_ktoHy78hg}$=fca%uy6L7JO4fhu(okOV*weVUdB>&6)iBwTg zTU@SAdQvhDog4JRIR=WXuh`pf8eVwup=B|OI%E1*=MMhY4LUN6OhZZJq&W41jlKbpE&@V8LYEotx zTFJShj}3^VT;fa|DzehnjzOT*Q-wo$-+4-P_iHSC+It+ggl`z(mbenZx?Id17fq*n z$*dJK!eZZ}(V@3ICd%%%Zv!IPA7GC{HxG8*OBP&dWT&n`Tc4sRmLlwpa;; z;o9|{v(+*4@#b4FzvCD%7~n$IRg#QN8v-PN-b&6unXGjEsw@A-?-8GpFBG=pNKwjT z99(@=*8p=OuGq<76B#!d#ewm-X45w?_yTA_REe_=@&r-lc@5R=;vsFk4xA3fGf;0o zAlkWd^;t^sbExW`Y^-%A`KRribu**SsO2cDVo5R{SnBYZK6fS0@r>XBXu(2afk5kGg z^N|-AWg(6D=^z((URwKI$CHphYMLZaOrxxWDYt3w1(2xvL1}c)c;oaOCcGN;dsZB) zjEfP7j^kj$s_%xQ&EbE;-xu(+tka5^L7}SF$GK`+-w~LL~6&G^oH8e3RvrY_Jy{fi?GBi0MN3DZAnwC-;HQ5pu z-uJ9Npj%f)(RQS1;lBHXUlmeaT~rOdV&qu*ZFY<_*l%iED_$G~-6`HFQBTs#^x;jI zxt6pdG+&#HL}m@{%=k?^;id#tuH(D( z+>O`2-ivE*c+N-$JK1i6WVKhL|R@F*^tjw2Ky~f}m@W+*#P2-i8as*hAN~ zW;nqZ6g&{@!`$$p=iH;FBaikoscU2jMeN1RWyJ`lTg5uYcAH^0eC{Jq5#<73;`7It zFRW8)Uk9lhV5gukRJ`#UzPgc;sc`V$VvkLS#v^sE+<^A)lEHPOy+bj#1;VvamRle98@Yr z8MsTv!#?F)60U2(9cN>9_vBJ^d8H?u{wj9Bwq8OTZFUgV<4tgd&bjfdk*ReR0L26s z Date: Tue, 21 Jun 2016 01:18:19 -0400 Subject: [PATCH 10/21] chore(bios) Add tor --- harp.json | 8 ++++++++ .../resources/images/bios/torgeirhelgevold.jpg | Bin 0 -> 36685 bytes 2 files changed, 8 insertions(+) create mode 100644 public/resources/images/bios/torgeirhelgevold.jpg diff --git a/harp.json b/harp.json index 0aaa384225..862f9f988b 100644 --- a/harp.json +++ b/harp.json @@ -431,6 +431,14 @@ "website": "http://angular-tips.com", "bio": "Jesus is an open source lover, a book author and editor, and AngularUI lead developer. He is currently a core contributor to the UI Bootstrap project.", "type": "Community" + }, + "torgeirhelgevold": { + "name": "Torgeir Helgevold", + "picture": "/resources/images/bios/torgeirhelgevold.jpg", + "twitter": "helgevold", + "website": "http://www.syntaxsuccess.com", + "bio": "Torgeir (Tor) is a front-end architect with a passion for JavaScript development. He is also an author for angular.io and an active tech blogger.", + "type": "Community" } } } diff --git a/public/resources/images/bios/torgeirhelgevold.jpg b/public/resources/images/bios/torgeirhelgevold.jpg new file mode 100644 index 0000000000000000000000000000000000000000..1945c90b3582f777f83b7bc1ccde35c054dc879b GIT binary patch literal 36685 zcmeFZcU)83(=WV3@4dGmRX}=2AR^MFDM;_V_ZDgd6{HIYQj{VnA|)cyn{<_?ARVL$ zNRxno0YbPNJ;!sN`+1)G-p~E_{VhoH-Lqz9&CHs;_gb?9XOm|O0M&JMEp-3_fdHD| z4{)|fz^4Xxa|QriT|f{303v`GLJ8o2hyZ+rL8yLVVi4bk&;YpLCj|TfAS?j>FAM+) z5Y|699dhw69#8{B{Ff}AoQN0zk@$t_K$+Y)HvsQ1*(&f8Q1SKkbOPLNxcYcIamt)i z&MiA1<@cwAn7E9Bn7D$3Jg0=1g0!@PxI6%G#^nAzDvngllRsGTKG#1M+~@y|@sASU@Eo0LxXiw=5^^DsT)d@NiA5I;^&`yDB9Nl73*{U2QTx6R^W zVug^ubb@gy#Q76JR3Yvk{P8K{Up!#+i+}q9PBZ|N;QU2D$GHE(_4QWFn5QHl$9YDc^WlI$U>tEoK%4}6 za6ZSb;BgZemA`o)pf`Wx05Grr#(^OB-xvaB{`q`^8IH>ZQvaeuXaS19G1v<>dtXnt zfIu-ZeQI!Eh&3P!1OhIAB47eo0Tuv0&NZA3AOUa$vVeDh48$A|2kEweIUo<%0H%N| zL=aK{=l}&k6VLPiCnD?vIO z$Obu6!0}9hJg`3-q6J6*LEv#9$P*4&gOV{o1o(Licm(!mL39CLzya_E3_$(n;JZ8! z0`lJi!I^6YQlMS8K{{d;tYO8kElgUIX_b$^a*5O(HlYH^A|208ao0 z@crt41iS(~AUYsU0{iX*xuCtpps&23gg7XZ1ylpp5EqCRL={2-$pfwJ1|EZY>_BdH zFxuHbJ&+7}4P*dype;V2Y&qz;2Po+P7y&myS`+XZA`5VV(UAv6K+l}O_$7fc_5qAR zOCE#%RYC+nYb-#UVnEGoAfF-VZ4?-zOrQd21!_V61i+}s0@s0i05^aDXu;TI15^-4 zAQIFM=FG2#bDoLk?eEXuM*t4l-`VmRyrkga6A%&^IeXf<1Q-R|c?LNdIr;iHxS9pJ zc{v3**m*ipf!T&Llsy{YVnzkfT+aOf5K%L-a|?^gfmez1_UmLm2j|)O?*=I#a>pU!VW=+RJHg=itHVVCUuJZ^tPmA};Oa z#px_6AtC|ZC&*=80|R{(L`A&=MC=@W?43j$e7r>AcD|zGB4VO|A`I>e3OfaI+B>

H4ZVxw>hF`8yeg>D_V&^Kg)Nf`UkDJ>!;BE|(u`#U--7+h2TOBOs* z;`+gyy5vN?GNoXc|mBdg-?WcNP^d-;m~7Ch(qBVu=czZQ0O`!7Q0v|mO#+c`M7c{}_3 z@zPg86_gHix(2?KxXy0}!eZjW67skHzL|@Fx4m<7d=+$k9NnBl|3}8(Ouw}G_}}vJ z@l@gh*A`rye%MmW0Z!*pQsOdj3h)W?cW^pS zkiR(3&l5K%$6G%Cgpl)B*cDvCfuyA5xc)i}QR0%6kdgZPFv!~tOeJ48xRWQB=s)Uy z53B>;NdC%VLnpt#kf+;U;NNNamleOwQwJmbZ_~i&f`gw=kwT~vmzao@jJ%i_7?!_i zphaRL;xZuV9~yX?iHS(aN&K4zIs($frT$I(ZN9gUzn7h-TbPsMzkN`H2mX~zoPTG8 zf{M3`r;`>q`(}3M!*cyMJqA9W;Jiu5{<~Av$J^P>(aGDvNyjPJ3G4>fJOA##b$*2m zv^zf$K?7x_c9)ndGDVqm@?;o+J7SOp9uUX0{@A?ekyq0{`rRoV>yHX9&2%0nWAo zI9S>Gy)odF1WRFZSG9EU&I@1w0Am9S1h}lc8f;*}2CQVT;lKa_2{CDDad|czWq{~> z1uG^l0UpTy`#|w;rr)}Ff9axnD!ktwm02?j9odO|Mr~1hwnS#CrK)Ok!$4nMOGoY3 z=8;TO$IaUZ2P{i@c?bF%Xk6tqH8bZV90CU?1`8wN0AS}3;Hzt>e(PMPmYOPO0Lb)9 z|DU(R@!#9rQDMy+oSc8i|961e!Ph?!+{oSl*(DvpjTeaTg4i=8(D$5<0x_Mv$2rD1 zj}e_eXdsB0&aumHeCZd@Z+zt(J9>FLf;{Io`#O3#p5ty1-wzIQ0x_-*h+~7@oI*hS z8N@uEL0)bkMuV8n%gHVPtO}By(*vCxz|s+(7>LRIZyBh9SP|Uglezp0+y4s(I>A9Z z0YKHqH`L$F#Wj%gqJsb@xZjlH)N~5*bP5a@GUDa-cV4D7i##0DZ{q6!l-SEHsVK~p1f9=2BoE${X1Nx`^e=_{x{GY+U#uGUo z?@#PFuQ@r}1$hQ?o(I*z#}nMaaRz`T2`5hB|2>KSp9TMA*1znyWZ>lN%zw;Udv?W-8&PD{F8U~BZ+XDa|Eh&I&nGg0r z{>+;Wu`yUZ0{|1~+V8vvG1&j>{lC27q=JVy0d6jw=VVobTbvF-{$N4ryy2a{;e*9e zN`MYv1~|aF*hN4XtRu<-mw_vQ8dxjS2diynzbbLAfEQRB3;`>1(LgL%2Ydil)^fpW zW(io|tO6^9^V|=nV;iL_qF95+Ui3Tu2e53{nkggmggOLq0*KAd8T7$R6Yv2N#D7 zhYp7whYv>-M-E2?M;qrBjunmzjvr1K&Rv`ooNSz@I2AZ`I2}0sIAb^qIGZ>JV2zv< zmjU+zt}w0~t}3oRt~stVu0L)RZUSx=?o-?<+$P*U+)>;G+%4QAJOVsgJWf1eyvul+ zct&^*cz$?Mcu9Dw z_+$7h_=f}p1PlcH1hNF01ZD*81mOfp1WyQ%1aApG5iAoN5E2qH6ABS35$Y4#5e5>* z66O$A5VjMJ5UvoSiAaf{L=r^mMCL@^L@`8JL@$Zjh(?Ikh)#&9hi1mpbi9?A~ ziA#u^h=+++h)+nUN%%>WNN$n1lSGqblT?xPkj#?&ASET`B9$k-N$N&=n>3sB73n+D zMbaZO8ZtpLRWeJmAhHy)QnI&XQ)EBL$;tW1uaKLQ2a>0dmyvgoe<4Rx&{Bv{Xi+#) zASm)E>L^AizEcuY@=~f$T2qEmW>MBq4pVMX5mWI|sZ!ZdMN#EZHBwDb9Z=I!i&N`U zdr>D*zodRo{f&l@hL1*##*yYOO)*Uu%`z=6EjO(ytpn{H+7j9x+7&tiI(|AWI(NE6 zx=OksIutz(y%fDMJ)Ay|zLkD~0hfV~L5snYA(i1Z!#Kk+BRiuCqZ4C1V-@2F<4-15 zrYlTNObJX#rZJ{tW=>``W)J2x=6dEi7CaU~mYXagEcq-wEL*H}te06GSQA)Zvre<& zunDpmu!XY~vkkBvuye3$u=}#-uy?U!o|;J#1+GZF9jK7?J_9FR3*hRmKPcMEJAP|rf@DO++ z@KF#)P+HJcFi&t;2uDap$W7>p(5FlIm*g*bUwV3JLYPcgML1ZvTzFB0K}1I+MxepT$M|JB;7KUEb}BURsC!@Z_)E#cab8jYHfTCUm`buM)m^>THThO|bw z##>E%O>NCI%?T}bEeEYKE!1_{>yg*HwaK&%wR5$XbOd$$b((Z>bg%1X=+5f#>Urzc z>jU~)`WgCjH~4S(-Dti^aP!8^yql{A;sy~0eTKA#Hij<^4{u$)m3nK&=%P`OQKvDb zv88dD@lTU$Cg~;%rlO{iru}9tW^QH;=7i?P=FiO!EYvJAEmkb0En_Xmt@y3rR`0D@ ztUaw;Z76N*Y-()rZB1-n+G6bV?Vj2l*lXE8wnsUrIy`dNbiCsD&~e>K$tm4w%~{Dg z-T9k~l1qlmx+}~z%XQ05)h*X;*Im=S!2PF(zDKFYnWu>-(u>H;)~nH*#@oZY+lRvk z?(@l4$T!w^!B4?2(+}mZ?f*Og5?~e35J(3urUrs82Hgu<3|0=#3r2?+ht$BS;ok6p zP{Gjn(6uo2uxH_T;SS-Q5f>t&BNii7B8#FRQT9=t2yVn(#L8`r+b^O?qCKJqW5i<8 zWA^Wu+-bVYe)sm><$D_U%3~>F{bMKMF2@zz$Gh)#e<)ruJ|`ZV;F$0sQ7kbl5tHPQ z^dVV1IXn3*#W`gtRVFq60l@?B2jgk5v=`~r>0#;18M+yD4>=zuJlxN;$$XzBl~wSF z0Sdh8&)p2RWEr*W9tZt9i)BY>(p~|9s;3WF-GeepLZ`L1Mvipc>++V#2nX7^B! zcF((B_1>;NmA>|OO7B|UE4**~AoroZU#7oqKzg8dP9hNu027JY=++8JK&02%5m3@==*0Qd?{&B-%V`bBK^JFV_ zn|k~4_lw`(>|EIyK$)UecKvtH_L6=u|0vy;+V4ELaq#8P>+s}f0-729;z;hO@7Uyc z?IZ+4h{-+`IBmjeV`tC2&d$!>0@Os{4I70EekA~h8iGp=IqL?X;7S4?ylI2&e1&k{ z{(k61OhO7W)Pmn7fZ*cd;NjxqpKpL5k>}6Z@u=}>E{LlT(B8BoMM#d)K^2Wi@$=Su# z%{?G6C^!Tj8g}RIz1X<>@d@b}4>PkKW#{BREiQTXy!1uc%hxq;YU}D78k;)1x_f&2 z-o5`YGWvOJd}4BHdU0v_>&oidxAl$Py&wArhdazaTgv=Z;h3;a?CZpi#L=Xy-@EB@sn>htj+tmytm7lc_5il zK>)oxM(AjX$=pbp7)!WG_aiKLoPU$@E@Gi5iUHgC#-zTQ?1e1`xZ!}P8CZUS&t}dDYri@ zTrM7b!>{}Z1zii)^JKE#8rnLimyZ$WuCRRPN)bGRr z&9MuwF<#?l%$i>k`q6m?9Fo^E3i)^~D>-w?@m5x{^6#pcVOLITe@ZMrHn4FjD3pvE z=b+0YJdse@Im~l718OEZ80JxWNV+-BtkETDjMlf~pkl;U=aU!6y0%rf(|YYAv%`bF zZQezT+h!Gf9Gw;cXF#pcQui4UR`uYZ!W3`1#n`&JkO8MkKR35 z_PLGmLLs}cc=__4-nEeut3%ACYOZOeNrgPcGFOI+j!k0VJ6PhyWxP*cB_pnw1q;|# zmh?6s{-}u`B6R?wKTiZxlw557!Odn2Bex1CehxqF+nPJED~$_GrWm$H%^ub<_*ryM zu&|dT^SDbS_20YYRZ3QU&sy@f7IHF@w)6Y6Q(A-7ovq!7)?R9jRdK7G`|dq+YP1}r z9U+KN^eF01$8lWewomu5NpE>G{+LK)Ujl;;hfGOLbt=X z;AV@A!LjQf_m#CDAg=G8${t#rRs=4jX&~VUBJswOcI(KPJJu#+C%Ta<71-3AL($lX zn~RkfuBB`HG57KGa4zp5AM&2&p8;O3ugAmU;zVx!WSqVmdIq#T8z#$$ndZLhhO=Uc*Y@4kO=#dHe8c=FCHpT(m6E%s$)lpqFZoA%y$!)zA*;eq%W(3jPo z=ye%OD!DKh%$V>~zfp_ZA+1S3ozSpAz+(T{#OKi3g?s_~Lw>xYAMp-5{RT-FHSD)R zwW;6$_ZKP;rljw_Y0gt!C;rg4D6@K&$^$))4hK)lYpCIrgGs4mn&}0p=DJtOP!Ta4 z&%G|Ec!148nzn0I>Zi`&NQZPWhH}gM$J;aDwM)D=-4%+zMM$$i_b9?s#p(IN}Z#FHgy@#0(#H7Wfc(MF?#tQd{pxo@aUA?4KY0O(>{m~haa~x2P z=%8(1c=(9-FoOD1o4@4BaKv4QlV)!@-}fzZ|*4-uw_ezQZWw1eCn8(o6kY)wUpA0@O^P`Tt`I*r(?LpUyTu51Vb4TiX;9?tF-jvE+ax|Ka=>lUH3K8q@O(U<~5tQMx-x)?#DI7cf^)UZ=ga zFB`%Wv!yK>AWlXq_s0%J=&vl8tOeJcz|r~a=DM((?PFe;Cyi9C<6RGky6)P}a`?j6 ztpb0L4Z-lHd`M#=Z|+-Hp8*8Nhz<$Gc!uGw>C?IebwkU?1*HSe+uRZ8i}?3%vJcgl z@ewL})|>S;ijTjkdAxKyn0DYvvPtXHjX?Q4+9Io1Q{&*PH)6(ff2xn1zdNBgUyr?e zvk*Z$r{3O^^OcFCK+0-Uf4gP=XnywYs|H3)X$HIiOGJHg(W3YaaB^?s(OZaoP1v`F zA2tiCZ;y#tfH$la&HEOdNCmY7JYELH5=_ZRv4%^@E?6Qb6v1#HL(>@$53%cKtn=yr z$BC_fImdNJI5q^GeZEe(k7T~(gqpqgjV@W*C7iIKV?*n=~ z5r;QzihQwiEM&Mc971*a{^MRpjtTYMjZGWa9W=rG6kPUGxLdgS!5HFs6}yT%g(gSFYuBkgYOsmEj&gj*t) zw79Ow7LM(xJ`c<18&cX_DbL}!yi+S6ctp5g74JA1(!%|dxwqug&)z#H_SjFya9IV) z?smGFcgtiZX02>&h*2MN^dpT2gDu;g2TC;=gMPzYU1tDK)bdklR+xs={7muTNZms% zr(K_(PcIZ96;}1%9HnS(HQ28b;G~sI@5a zSjjHiBrH?L+KT+d`QT4HTbhemz013NzbiVUSJ!?|N2G1(Bu%e)ZT8d%1;fzmV@c?j zpiozacUkSTGwXhO|(pUD__gD+G*2ujUFovfu9` zFSDoHWfFcDZI~gwd7?Xfz+kaL_`wpAyRz-At{OwEgb>8o%e1aF9(Pv`79DYe7vuBRJ!keJR0K3y9vwBZeM6XpbXwE&B-Q7z1LLQ4_CoFG+DXiN7EzoHEm|R zUF8w!$|lx|d#UZ!NkR276vK$bk{FeCQXa0}<79*IB@<(Hg!VX?S#(^y=}8;+0hb?# z74swuP)yU+!;D9UhhSbVilQ$*OM-c}DAP4uJNe?A-hT!Z>d7P5p8x26guU?DyvKRU zaciqcArtp@z^Iba%L&|-pX2Emy)nMjW`t`hS}X5Tcrk4yHL2VN#w za6;~!0TW1Qo_SO9GDBIbWIspa&OY+GoNLuxMOBvwtJL@- zOz+vK;H!^cRCPC198}^iwcl5SAsC8X0;Ei+#9W^zPs`s(+4!ciypNRfkgPUkU;fPD zk^h|G@mR^DVMEg)%~SYk9&Dkk{Y`0ymHVi{_(8m)Td|PSR;@hg!0o+=Ml6bdmtzX~ zo;5sv|0v6}eJA7N@(Uy_eWx7DJiGMX$1xMw3)W$@oJDWg4dZ6C6J51L43guivX8gj zLdp?xbtNd=V@^>6Cf=~{lX;ncE(|)<@&YAd-PUz7MbC%rI3@aW26S}EK>vfKSbWzuX=%Eu*CMCOuawIE!#lofNOF>VmO}_ zY|9XiYt~IUtyewN2n;D}4J?aSTbh_kDPWe=`I2JdYAB>eJb5Q6K{a-2L7S z5IbC=KqxJ>=V-%QX6`S?6D+-T%t(3q5KSp+1^oiG%sF*lZ%0}0#0+1mYns1X`)!(c z)|{bUDD~v{a=6LfAabtD!|l?|J8N@d!W8rUX&IGp%-Xml6UrS|wxWi)Sd2!4L61WyT0ib}L@gT|n? z!}lJ|p8>#1k5LG$h@28jN_=v0l<*MVmp>*AHbhxEm`?2n=n!VtS(A;^$@~| ztxFBCq^s@ua@&>{ryG@@*QFBmJySRAlRW!`4S+4=gx!08TCFH@CymGCn|hc}ZN^b9 zc#FjwGo;)uSh$^idfNR78u?Mna_X}|Nooi=->0|OkK*evRQ*Ast~XTN%3e_4=xwjc z2IWXo>a=KQwL6qq8ooN4&LuKJS=_Kb|IFj=%ZJp1RwcvfE&2;ZZb#tQ96T&K;b=p$Va9R*jM8eo<9>-&Lz8-=f5d=t1eDQD(v;wuz6A za{1$099XU1J)Qox5c(f5WT%IKSVmDbn;GY5S9}WiCpe!yA7F6%t=XOZ0mto%T zn>KEnkKW!MPG5QvUb;KvMZ=8CZ=@Jz2sIfEc`(BDcp)G^a`WI3UWEJ*diM;djt~u1 zYX6e4VxWK7qDm+pU0p>m>LrCMZfXJ z93TAF*WD%CU!!V236s;TCNwq|n_0Psq)qE6yUn|2SPj0p=~kB&)=wryd%;_-SA{%( zA!$Og$Ml#?*^v3Yqz9J1bA7U=~D2(35GBM@<`wfsl(X!Y<&yT(=<*%O#<6Dq&3 zGUPb}-_%#uCtQAaXgN+`(alLA^p%&67-1C4u;AR9ttb=sD7>-#VCCyss_(uNDel@7 z8$@u*D6=PC|D0Kp{!z*uee$m49{)xI#zS*0;ZV+x11ih<7E{{xq|#<9#NFX5M>y@Q zNjWAE<#|k2;GMu#Mr*q}c?KM8&UP#n-@?paelKWO@;%f$r;Jt0cv?04tGxAN+6k0& zzlIxJ$3m5sbGG<%a8HmHU&L{q62E2QKy8d}$0Siff;5uJ zB{(p$aqsIqx|VzCOjV;l+bbhs{2iD5RfTt~3;53f>x`bswTv8Ytj#^{hU!Q1NF4!8#HqtwEKuBi<#aJhW*3{&6D+) zc9FNebWGQR-D8D{Eh{=2DeADazWdtvvj9UKu8sx0i@6P#IMkSDZ%H5MD&n~1bVOLV z)OrSBi78RTSSrft5A!`f;q=opaD;I)j$*+jHP3FENIj2^B{m&?^@+>AH(|_C5*yk} z&_wG?yK?d@DUD^8xEnl8Y0pjqfm-_Z=!=!Lh8O3B!{ETn>d25+Qi+E zJgw~G^fEl22wk)xeSXi0YgRs#&vSuBCVD1Ca`V=_r2J`7kT729>TsJ-iRPlMz79q0 zbuGd-Vl-1UO40EgrMVlPMRiSbs(btIn1%%2WQVKfpD+u(`kFD)G<7M{V&Fjxqv8q0 z{>-cJKEXP{m#V(CTlu_bja|}?W8tdSr8(Riqr#$fp^S{iBWi51*JujWZRzXPRc})Y zs;uAK#+@oS8^OA@FFdJ#K6*HY_BSkPdX=~fpEdb5u{C_cf$dQyL9Z?9--nVb!`7#< zmCxL7TAHtiS9Z;PP`KJ)JCi2|K1{aebIZGt$?FzHc1*@c^V9;G*Iq9*5hmNmdL*^9 z$>V&L*}{$0<)PoiNV^`w6*+0Ri0FmgpH68F*p0h_8rvL{kWMMFjWs&mZ0zj!qopEs z@MT)6?^tCDqFWK|$hH>?Vx7duqGaQ5N}G%wtX>e|77}OT=SjK#6PNv7RK+@2-RoyJ z7%TeNrht~Q4<#GzN@5Gv&Ke9HhTcQ$?J{2y*6UkIsR;ZE`aw+;vtdi)`T69%H#Tji6OmRBjXPv3LY!?Mjfm#nY6 z`vwy^IGzW~Xn2~Z&wRE^67_eHF;!+ICd)T62?%YD?EMUCA{3@Qc7zvSo&f^rvJh0I zu|xQxGtHg;D}DU)cKe60CsE`47;4hP<+{(h!?8Xs&=4x1kY(sg_~|zlw!@cZ+tP0) zzSyE_5f3qvyNI}|KqOIrP_RszqT3tri7|4;rYYc;Q8h;-yQCEi_7W# z7WMx6&X+q;NA$qO@?5 zNLs1dQ8z*A5b7n6PHxciu!pT^uJIw;ZONnn%gNbMNp|Pv# zNAP|MSfC-?M^@HSPUaofzG_N6QC%#JFTQZKZBAn4HtGCbxp&BMHwVt+;w5^4AlT(L zUL87fN&nym{s}yjPiJ5O8eBgmUDA6%ONFeB2O{ z76O_v?@|h>{F1iUn4e{@q*-v(X?14`dFYmj<{UFWoBP&O`)H=}O1eD3tpki2n9L*? zm|TpN%!UMav_IWG+j3<@6`x|h=%*rxBy3y=k>0Wut2!)LjTrLEZBWfpfJ&lMyOoL29dx<62agX0 z{PqgO{QKwKxS8o|i_itV2Jp_4&YE?|!U*+Bqmk7BJq5AO?UMX1Zl&^X#_S^|sjE>z z3ZKOT4ueVu_v8^N&>G|&Dbbj&o;JKJRla04Z}yZW4U#GT>f!6h9!put&uy?Dlm*8y z$|vLBJDwRa9|bq99iIvn2n=k5d+2H8^n?nNzI<0(yZ+{E4K!%jC^8R{)2nh9hq)kpr>5Ljo*KdbVzGG;by569Q0pRRsSmy?NDJFSvu{^l`M`hH-Lrn<3mLqR6hef_C3wpn3J4g+T9PFQLEhS7%&DalHC~ z?yN%B-D7Xyt2+Z6NIiTgBZy9)DjFNw=@Uv9r-#l3T~sYlout$;xszJPQd{^mq}L0Y zmTT2A!6?qoYe{c(r7vBsqd%}izVf2&lfWNd?uzf~;uIgK!Z8!wYC`t=iM;nqMCaI7Sly zhCgiU!cH$9?uN4%Dr+PfwqL3)kA464-KI?u=wMA;M|R#eG4C>$fc@abg(O?w;!2lo z(Z-ykwHNSI^GjaS3$K<}YLFP;1S?(5MTqyoq3YQ))NRlw@tt(^5rR@goCW>)wUbCWz$oD@t59sNx_YEHRL6C-q29UbF&>FtF&S2qc}e<&$)!ef zgxFY`R6OacyabsKXP{xvO!pQ>6Uo)p8j_9 zl8_C_M(L7BQTU4~b5{mg6BF1}4byY@GLa^eE%Da{+JqlIGr3rHmqq>LBoP^{#ghZd zAp!&OeEFr;fs_QFFUkS(d77wJ7?xz}M4HDQZ&x&>0`qJ-M1?Jm#5dGT&+kin4wBJy z7VTkF7qcbZIY1PAv(|s!Kyozy@x(Vev=1dLipJ%Ag_kbpqcX63V2vGbCx>~pM~`AC z(cw$ORPLW_EY1p1QQ< z6Xe&IFPxO)ULXr2SQq_J-{&f>hlT{aYG@Sv&{5(Gu{DXI5PCZ#?%mwvvWbB`FnlZO zI9%$jOa^!8x4L?9$qA7Ye?yDED$HfH(jL5ZT7>IZX*aXo)`wb}d z9>$w7EqN6Dp;0|a@UhDSe~2<>;$0K}wsfQ$qU_tDf@58s%*ay>sSY#eub2-;@l1Ue zZuii<9YAg{l`Fl2SCDN7a5+W=1a(b|dMnr)J!KGSml? z74i8t^CzwG*k;@gqmA(>PH$B*R}3{MHajV8f`>1rq>&}Bbx^s9v0M?;;n)B)#=v5uYkti&=AgiE!Hxk|v5l zGL=hEV)yDvhTz<(!ul)9&S~fygve*=P+9}gC+-o49uGfNQaW$DG%0N!lAsMw=v~{1 zq@e_ufR7P0)3J}rYAY+S{F$7sjY;ayCK=LX$-ka{x;G?*`f*s?qTL?viw^$jpH4za7#h3#MHV-(12clj=qUp4mAUPSd4R9_*RcInb5l+pC;snnAvmx>eZV=Cv}( zn?b~F#01H?(tCLgxn})L=Xq19+t{Svlgr_SMdVb-!uBKZSv(^KHj3piHJd`` zvzqRBRtB*?d9=&Dlcf07C)JJl!<_;Hp$$rsr*MZ3nf|vd!8zW=>}|u~nrJy zJbm(T!!RaJI(6`3yX_e;Wk+|VouuwLNi^gAD)>RK8bTH}{j;tq^WbAccxhv16-mk6 zOp2LAA2LFJF*)hOwD-FMtYCj980 z-ttNoGH7(2EV^ofrPEg-TPr1ni8?4~ye(nDBXbSr z!`WKQ^m>%cE?-_rPjOGVb>+~tbcxvy^jaIGYwtP3LMoi1dm~@ojSQdwb@0`1X`p!K zBI~i#HVnPX?9!wzY~j>4gUbEK@RyM!c3GS?N36LB_a$)5AH%y58Y80lc_U(s{As3xUinA5mee% z@1EFg`cr9m(7-;?NGT_*e- zc?R^i3TUvN0WcDSF4$|t*=Ovn2O}H)3DrIzlAw*V3=XLi9@q35n70&JVRkA%{E>@%sAnuf8Z(NlgRr#Up=>WEW#*ZF(!tuP^Gyp z3B*<2CBgADmV%Pqd9QsH0`Xr*3Jocf!fR9ux=M9rS;{Rh5!p43-jc6%RrxT;OrRy} z2ub49lbnoDcP}?AFISxS5Uz>Zj?I&u6mdwA>lY_)x=}=1+~6s*n{q{(&I_7g)}o@c zhmN7->~_4Z#?Z5Y+so$Ve{09mKlBi(AMRl6E+@v29GpJ+`nmO z8F{{P8CsAbOD;y5AFCd6pC$*j-?w@5{7DtY7lkb?fh!!3Xg3sRY#U$wE*Gr4|G<|1 zL8eVhi?^WMV6Z*UQe{9pvASV?xnXbA1&kdae}oIF?~YH^elvgVD952`OTUmA zYw$X+@73x{w<%t-CM7L^)uMU&phQHn4ekMSs_*K@t^Ibge*5DHnZxu@gSXVdrBln6 z{O=}hE4!${g3;jJ?xBp<)Tf<}`|SFMSqK6J-M)mc6FjJ&$%PCV>Zyt**4Eq(RF|{V z3~&3Z6K&dD!)T+FYfv-2VQXCoCQH)6>%Cgr-e0d>ylH<`_0?C-x8%b*sn?G$F554^ zm&;f8xmV2cs7rfCxfAVD=!%s_iDVSQbL9i4xTv!WbQ)7kSA4&H8_|#;CYou~RPCaI zpBE$BPaZ#7i{hd(SC^~q+5`VO`W)Q1~S#nAG zRjrORh~S5}60cwHG2sqI7_$-wIULV->7UxV3;6{q&PFkHY%(AlmYh6Sygr?N>A|dk7A{$=F%#$7XOr67F@@hF37OE^ z_j+&Y<29O}qz-G($J9shqEb1XHRov%Rjb4VS@8|B}D3rYlvv6tn^ z+)iAD@YG^WBOhN%ut;@0#8O=oM=3dft&W&}pQ>-k{tO6WEk3%;_~50q(i5xUNBcH+ zj`Ita-g&x=zsWA0V?!#;NxUqHHhK_i#Cu1Em<>lxZndp{6ydZ(=w8p#dg5`%fWcpL zqTe>VsU8;klq*=3HREv*K`UWW_n;f8B>mkamtnoIT>d5N#Bz`R5(`UaX>#QeqFSQ+ z9Vu62z7JnzD*NWqgYjAx#qZlK&>M|npXw9NFLv=0?k#-PLMwTV(O=K;s3g#q*dD^n z4Fp&_Sti_C4vre@YH{8bofuAs3{eK1ySlQ(FBp3RX+TdViL+d zM&F8zZXX|ix-Qn1wC_8%c?&&EzZFa_vkgwwdJa00T{D=G6SW(rZ(g@mj)zcmRe7 zJ1duM{^}zQdcW{4>_%=gCbgh8T%QF#(LIe!3SuQl4`25dWqN^cGN_0n*;xhNBR;kf zedHX;u&QlrjX7k6U(>trfPlhx;I<4K?cSZt4Zr>4DdT&*@9JO_51&|!z4$(y9U)w3 zZEiL@%j(ZfojkNgV)o?9aH;t*ZnrXS>NQkrZ?yO7#<37W+0`M&YQxxxSC)$5>PtEC z6%ECo70ZdqYK?;mX*X9jV8SV_lyOK!mFLrR_i``0eU~l2%KWiKQwt!REIHn_(ZuMX z%c{_bL+u*0(~_0M(3jaaYU1uluFkiRtalOn_F9CM4lLAdYdP9%8`_!I(1dTlP>;13 zEkA*&$Bb2d3E#XX451*A+Kv6{NM4MrjjBL&Kru#(NL+Mc4@*I6;7LHKR*9mqJ*&Z9 zWL?M*bA_o-gkny;AnfMJuvX zxThF=JW=dydZtkjfF9XJ-j=4Mz;FIMKbVO_bhTI@@NE~{Jx&U_-bjyq2P{c*1x93| z-9uQT=L{hA;vIS8Wf)k;&}^jG@RKemGR}@m&D-QfPgJvBMqCf~l2~?+mDM%O3@Sg5 z{$OU-ovPaPW5Wh9_lvh|t8Iy39Pf>8O*ZE^2IPkxQ8FplW=81m6+azp=Ag%^tliRA zOr=ZjUnL-YV46>NV)EtVyahq1Rof^LZlDKC*05ncH-1AEV|>FA^X}K@``YwBk`v5S zgNOVZaZ@NFg=Efv8&>KYORF29_8q}p%6dKTapm6f@0TZ4aX!38D*jzE%<)w(V-uIFv+hk zV%VO96EGSby#YR>=g^@%8^cDz?DVI8bR*cX7vYRLySl~e=4zGQn|@WbV2tF@MK^D0&W+{t)j>{~ynE5u|f9ZSHaCTMur=M)c2LMNHB3RKLeS`K{ z4u|3LC^(HLB0@aZ%LR$Zq7xq6ei@4gZM7+=_yV_7HKN`ed)xaA zI#-Z_sNU{G%bJcUUS5VDC=nbEtupi42x>a*tt3C_{a_Nc=iAQ;uyH(X*J^hip0ep_ zCj-9~DatwzH`Ey`=qeBKsMrjt<};vgRfpI4z{hT<#cSJh^d-Iic=lk?&-I}tR%Qk||oge6AO{89kmCp?{#ngHOBqU{oncFtB zXhJNBP+8Of<4y${x;U8p0sg#`AfH)e_2gE}U;?FxO`iAZNsbw%P}+DahQP)M>Cg8@ zsP}Ts&%u_UvIv1)50AQ6S~3M<F*;!Nyc=C}i`oKhvFKP= zpC}Re{Bn7h|1%XX*U=C6>E(JSgH2Wn+sju<{WWqbpOF;H;hV)?|6!9_zz%a4jm_srtCd7}q2&v$ zzU3>md=|0&EaK4Um`g`?i`YJC`@#Fh;D}--rGSJM29oAVS1iAbU>ke+vw)@fJ0a7K zSf$URL2}8{rrNBD_l=EQ@`-&ba@b{HK6I0N-QIF5*VF-jI-s+f74vwn@H_W(Z;#f=#VEq!E_91B`AKMVfAt|_2dO?4 z@~yDFD4mAX@$*K7FO?-DZ|jXeT0E`re^0Tn-LlePd5@EdJXqoka7Pz+ALiO5m9n&$ z_(>n6l-h2d7CEtyZ`A)3w`H32t>mD7Ke-Wg5K(nmpzG7KZPw4Hgm)U+p*E6tm!XDh zPt+F^)(Y(5RR%2%?|rQOQ}6%3M8qh*BWhQJHKN3(_bnd)5~+HE!$9~l1-Vq)4~f*7{NStuV%s9!%c#yUoEA$Ls39ESMkD9DnZXO=@a$d@mW?(4i7lEPUSNT_tq@KrlFP-inqL$$12{u>-p?E)AAtR@o{G* zPK;I3{|fLt55ww+v9~RT*4~$MEP^&!g&0S~2rOBMfhizV1Qj$~Ys`R}Jys!x8v< z#gOWjOCsoAB57sQWw@A0FP#%@x{a}txs!9CZg!sCE9R?Zl=)B7aGX;oO&?qQJNS{O zJ;`{;k}M75IU|f`8T7BtSzE>48gIAgQ?z7fjPiKt#d!5{3+*H7upDbDPxrBB>^1JW z;k(!)xRNDceKFtGza(_;kA5}NEeumz7L{^yobjJePfEr)9a!vrJwFlfty@#|ifLHE_i>&8XWO8>y>$1a{!_nrd`sWGlDaL*jB&Ac8g8;pW!bAU%ZmZ zpxMD~dnCxalHz7BJPwQZm1U8KazX3fzQ%026#&btj51 z1%>N*7a!Z&d@hko847n?7@31Cg?7XME(j#C>0X2J7s7X%UEP{B?S-mY$sdxIF}$gG z5;bc=%-~@oR?A@gs)IcVu2kAu81gAf$DsT*_$ROF`gP8m2EA{rY5J?IuNI)|JHc)j z8-!1`XyocXS6mk49AdA0Ce{2!r6g-Er3SFqQshHny4z9JuE@z)-#gOYFfa+&r9dQw z9P#2NKYyEXv$*{eTwGguBS_M8Or|vsuGnWH2ki9z;hLliH$M)CYdit+2hs-f?fgTu-*)cPy-UB9C$Cn_cn7gOJ`(Zc_u%+W->D{Vt?8v z`Pa>#59MudR<-cu!Exu@2i^c+tF(sTkAK(SO`zI%V?*%nlW%WzVq#^~H4Ehb09z{B!XzmW+!gL6bwXD?NEO}74w5kT zZ2SscJR7H&qZUOD8C0L<38$d0l`L5fEoFg~M@4RO?Oq0>$b|JMF={{U;>*fL+)s{6+l9}R9M)--+XZwq$M~5Nqmh+bdK3pME#^L&aYcZ~QNR{{RVL(q#~8 z4SsebLc60a2wkif9XQQ?d697@D-(-_8js!Tn%Cs-`X9dW7XnKMgPmwJer4MJ+20%` z9v{`AyN26Z@R(K6bvR>Hp2Y%$DINyhjH3m55J>M|Ch6=1Lmlh%xn+2DD{`NbEL~?C z$+P+^@b~-{!{MH%;axJr<1fP3%gB&{UA#gQcr%htsW1-N8pS5&PsUsLEb5S$LR0JU)txu-?Y}PrfL2O_;X?4NOZ~O zy*C!O4K>8OquT2s*om}(&wX67-O4IDE?_jfwPV?3EDLm_h zg`^h!ql__bNG*;y=CXN)9xvH*E@P!-xQQ=lqwb$u{{X>1e`o8T6Tzu|(tazqT~|u* z#mYf%VJy7QFkRD6wC*hS;gzC7r+a7nqQ6M~33zA0AG4N?;r{>!7;f}y+f{odzg@ra zJ82j^n;Z>@P<-2D#ERc46W@-$DoxrNpr=JcUgxm*6T?0!@RyF#!{FZg-9J=??jX8i zscx|_3h`U4%r?&%U`5IUy)q>X$_-WUedmt6GvXKVE{8aS!uRVV=~{GzytbZW26hk0 z3oZ#*iT%mQ?}77~wreapyd$alUx$1T4C1}2&yooJC-`UkHh4$jf5YRXO=%O~-@9Gi zt+b8hiKQ8RfSe4UyjKB^PkQ;P%it)+w}kTi zwQ^yVi~cG7mi#w+u8l`c)MT-@1o^PZ7?+N}A;`fV{8vB!01J>>Tpc^b<*m&B04hA0 z3QwS8-`cWjs#Zs5_Kj5inpZim9sbGsPP?V0r-eLI1)bzqHuL`grdu<{;s@SQgl-7W zOpcZ8`gPugdu(S()<$krlh4w-a5Mp1zn zD!}kXeI6Hy>OCtiWAnV@!Q3rMeE3N?`s#lwH~uk?!haj|Pali6@eFWVMvmVvmn3oT zK^Mt{-T?V{$vCd#_My=(^esb9)Gw0XNQrITts}N^D$21=WI}R)sQ`h2o;%m-)M`dZ z{$s>Zl_zO4)P6Ylv%}g~!e;P|<%~C4hNE?+rKYGGBGHy6oumK)LdpunK*r_-w>6ch zTNyqB*m&bZcDvOtZkG1gBC8d=id1HcYh!A}s9S6G7{^msPLytRQ?Dp1#hiwObuB(v zv=19w2(FlJTrhNSc*-)IW7zZTD(1K2%}e4ow*DgVLdkD&f2TtuM{j815?EV_F|~nW zP75mzI`*y!;Tn#|*I+Z)^K#T@SiT9hyB}TFBwT~E|=lRmg#KnC-RzUUA(A@ zsO7fF^LEbD&THrE`z=P+SAQ7!rdh3{ySsRo{Zug$%NSJzM;iR9gBZyyYuSblFj}7- zkIiLJpTc^^rQ;8Xw_ZP*@hz^cXNqYW<1OYoK77RmfjGfpGxe_Lz&;r9C8xvNy#hNc zTgkOiX>bx!eEduvMsP~)8&Gl&sOGh=qCEOhKTbSOB$rI^{{V|_T3GHpWa}-}#+7U5 zM$nL5qXY>+8&yNbc^M$&RR~U@s7N&p2SaTtEf&BT*23~AV47KwG2TGxu&zJVh8g?S z6(SyaRs-u)I5uEaR`AzksL+iWCB8Qv~t)a906WwX!=f- z@W;c}x4s(G?Ee6@?rpr=oj&SG)lRp=uWG zEYc+Mo#7fqf=KcdW=CSHj&cns#j`Vd(*FR(vDrbTd@i(oKS4$=HQ0#~TqCw#YlU#~ ztVI0M60IbMkRwl;xXnjV@o$fQ&ny?(U7gOM6Zw7`^Bc>SKnjPwkudJio>>uAHo#I_ zsM0Z8XjQDPnalpuU$c*mKWM!c9|!1OCb`!&t2ax5ad$f=l41aF5e4%aNwCU8IV33~ zJq>z?hBf_5z`hRDJT36T{{ULlJVzFvHJOeCN42z>LV~NeY+hOtHWX)g!NKW@=cwyZ z)}4yO(1mwtv-3qi;FdqMO@j$E-|W5P2XMV{^8=iKVjO!OmFeU5sQBxrDoOtU2_4kK zjI6F(j{NXzmRQVVeABV(%Y*2xrtE%pd|mi);}3?v5cMC0o-K_(wyd2Mqqk!svr4Mz zv9Jqn3^B)A{Uu)<>E95q&y9Rjrp0@!9jw=KqCCd~Vx8=}vI5|G0bbP(BXL}_ixS}^ z{uwJDn>ufSz9ZU7((C#y#f&z|=1eZ4Yj)Z{iG0nakFMO;>0ZCD>3$(m7PF`Ququ=u zc@KqbZUZ3jam_>GIZybIHm$<6WBfU@^9MxLwHtT6k^%(ru_3YeXX{^n4+{J=K46Q( zcCl~!#~CN`#Z+@@d!x^MKR)Q!{gx-tEq)y9x{N*^z40H7bx0?P9j+EAEnz^OQ^jtJ zx>B+n$Xw@ZVMiGq?|{A_>K_ig6Q_6=K-iGkGf3ASQvIe!V#fwS$czTzIqAu-pUkni ziAwa9{aZ)5l;l`>Cb3g-kCIH+_&fV3{?h*d4E_-}#Sa>IL(I@TXFPVc(3zRV5J!0)U5o^&*;7tT=|}Mqj-Wb$q^|nkE>$6FI&D5X|u~4 z=Lp&StLkajt0`JrdLIu{E~8E^R@Hf&C&QgK8~ra;uu<~fGe;KgxQK3Ed-GR*7T!sx zMW;_6-&vkP^$p+htnt-cA2d-JZW=Ws$thdR^`F^e;H~$Me0QdNP1fz6PY8H_SGSK) zm_%kRBR7~LhB*HKc;^fAw;kJ*EP&vULgu{hL-@a--A#3@>3Hz|zL3jdrm8QS2Byy;3nR(~ zT4$4$jm{&^RItrpskDiTZ7Uwh`zQD-z_EN_xY0Zn;v0=y!#ZWCnJuTB%@jsb8_bSk zNoI0R@Ne~Df?@f<$|wE6UldpIGFP$FX@&wlPq%%A`W$UB&0dFL3f zjN=$e@wAWVZv-&ZTbHyyb9FEHRntsgPt+~r$Rwa}PZjy|bKxHp=&0uVamOEb74dYi zb9>DGjl?W6*`H49x4sU$S#0NqEkfMn9s5~N&>Yvx_7M2ck1t5meD(EtRxyvqKgzfI zwYO)HI<(W$KZ)L3_yfSYi^|$FUTJI&K)0FIaD5SrFX>$H{{V%J0)NOd+AvN&YoYxV z(scV7M;PODk=#S@bHUdIE;Vgd_Tz8NM3RlZm?2bW-n`RZw)l^wczW~1(b+*Ev5BW- zg6I}1gC_x$1AsHsRYwa`p>H2bod)p_+&?$}0Bz5QJ`nI{i!JnD0o{2K+*{7W?Qbl$ z`$CK)Ti@n;>^z}3fJERVQ+)$rM@f8iq1d@@Y5hMQqo_*TAIcm4i_{g-~k(ZRVK+fE*?!NW({{W8e?8(=(9c#xLa;Bqe4x)xAZPPQb zBM3alDoaMB^(Q$sO#~#-`LE(DEkOA8@55Fy3&(deZ&Wd^)5~sG`?%9)Z@0jy4VZOu{Fa(Al?e?3K4P-1RwBT&OJ`Gn9e#Lf8q^dKNRc2+rrj%wyun_ z&0x^^VG(wM%-9W<3+|(wR`MiK%JhPK_cL zQ00sT5d*O?NbI@6$qHAVeYdo$$#r3@XxYJd2SVsw_wV zZz^1!$K@oRDRf^H>fRvnhO4Z2pTaiUwZ5Bc4XJx+VVD9lD-gE|jgyhnrE~i^brIfb zdiTa%FJILBQD^p4v9i1JZgm*4V{1f>B6fz=*|Q`}3l?SwG10lN8Pn|SyfYYw;;rO* zSA?~2^V?}Kxe*(JK`_mao>q_$L{a>kxI3x)Fgx9L>*3@HJbAy9c}^KfQW{Bb8UtS2S=p?17aEC6B(k-idYIF4ysd@< zltG*UoB>C|DXX3Dh2iiQf~A*B@cy^rDd5xOivHE@qq%5=GXCyxHozk)4oK<_MRuA# zr}0Bs(7ZFPYntwlq(OIYCYJkc-bNwg;ImIM1DB7CD8V()QS%umWAiKHufs1Cctgfo zoVsS6cX6T5deT~6m>E#VF$_12qh=Y3kimHs^oQ*);!le=9xU+Yh?>+F{vOqImX7vI zNcJzN&!IMD|v_g z&;qaMGx*l5@-4U#o(4F_r)uY`9&d|pO;18Hiif(-757h=3<2uR;AP6dPXXxzPCFjIdR}{43l) zXU~A&5dQ#aZ;QGw!4HKNe{I*b>5MQd9g)VUrb%U$z&j#|6uY)K1EDw-g<0~uNK&g5 zuG#<4_}js{&+OnWN%nqIL2gdqVj~$kqtKG+pg1%uRZ(;Lh zzdMJAScpwjjb3EEPv0u|of?pI)E~(G*8c#4RBHYPgTkIX(luBu-P6Q!G!jX$6^QNw z8@q5ltMIGAUl4qC;IndkEvnpDeW`;>VG=#;+_V?<0>i9noS-*3-PTCB{xoS z`;YBr9ZTVrs1K?xoWK!-Ax7uv$o(t$#?}5a{8ze0^ZZGu9m8qF>bK+lxJ|NY6SEgy7+V-{=GFn{OFWK${;wCYC z@$K9<;~}yLujMmSzt?qrvuhW37YN*jnchMAlZyI&9pF4}60fwLCBH3Cn9n%h2Z^U> zVflRYK7;rX;dk+Np{GN5&laC%hUZbaM0fIS)xcwj)sE*RB60VK?V9>i_Ce5mZE5ho zQ`WRulG{wy-K}q@jm&q64U>6_u)ad(Nm~F9oR#Ak&3)D>*!VgXT3+e*m&F_3f%<=m z?ta3zBS_P9_&3{sX&VCrIU54OGXWrRjoAQ{e4Zm)J| z>wkRL4;r`cFK))b$Et;F;|+|Q*U`52`Ui%77VADF@q%C6T3p8ZkBC!Klg_#S08WMN z<4vTpCy@~tRRCpy$EGr^B>mFs(w`;aq46L56IbGQ{3<(*f5TRw3ybSpTh@?`%v_RN z2e-<@@~%JjQ1EV{@W=MPi@`oWiLE2L(FC#YA&aM$HZl?Nwoq~hLI|&r;*2jeez7z6 zp8#`e)aN`qk1_i3sr-M{yh5#~ywS=V)c_;$^{PH2&^{eP?Kg(5#H`$s%Z;bsJZ8Q+ zl8OCQT~(U+5lj1H#Fwe&SRvRtka<4!m82gHTS#WtO!w&AVV(T3?5YS~(zlYjK5G|; zntIsXeNS4mwI=RWayk9u42su_;t#_MJ*#D-+o3~(UNN7?IjHuB57p-V+ZYyF_O0S8 zE1fpb8SR-G8CVb_`GyMTxxwfwGW*5Wx~984{vT9G9~)wbe5Bw4*aEeKk>%zXrTiw3 zfW9OA1G?~i)!qHBkp{15&?+IakIA}#ETTewU99;ZDcC{BTKiYTHuAEYok}dq%yzIO z06zjN>o9yzULVBN{C79-`vp7 zl3Ccv;|bGIZ9?YV?JRUXLgqs3(w))AYjeCqJ7aERB_EEQSFcXI8SwLjk@8=Nwci`- z);a=TTWN96CR#OCk&l-WVMaELCAGr(E#@)#s7WVz z4B5#G)DvAAbTd)Dtk&?2hOMT2E%7&uHQfTv^)IdsoxJ8mK3uY~Rrw@M+e1m!PDiH| z$ZHX4Bf!2C@GX=YxNC)*P`|TZJIg``?npv$o_B6SN8?hP8|6LY;E#m-ci~M-PQBAK z-7?JT5#6M1D@fasN&tU$igC3@GI{Gz>6ZQoXuKTn;q7AYG07W;S@yFSayD<7SE}UV zrNJ|5b~{}^NY(Dv(R_KM+iI59m-onHvRP%FrDt)xEA1R)@*8z|weS2R+ECT?4J$*{ z^tZIXcKb?vt!)#9EPi=d1GKUGq~oP!>`J;S>sEdovyfitz8ln{k}X!@h?q+Xw0pd; zrP@LP86yqU@mvRv{v_Vd;QdF#m->|V3vGV0L%tCd)4?ML6Rf{0o<@FPGh0H54zcSV z8S!?9q=s$SyYh^^y>Pu!v-Kle*1B_llNn$DzRC{;Tz4{Dkwr{SZi-rvcpYZ?{KKqi+HBSy-vF--7- zBt~nN_Sn_J=0a=#01a(*-5bRp5d2Nz8Ix03?Ho&OJ%zMUV9KRF%^H@;J9#I$`gG~z zKZIJ}!ru-JW5$;;&ucZGm@VQ*j4HpD$8Xt=P7Zk|(z0?)mm3eY_U|EUH_~4L-@nU9d1n80c%Rhrk*nUN^k7_g%66&V z&dwMx3^>k44O#K;h5Se3kJ;#Vb9P}id2c$}b^=|E61XVkv7WqF zpHhOGwa)AoH`uG#_`g%stR_36nGcv1N6ZO4`ewY(MbT_ENm3}FV$ahJ>FHWLy32F5 zXYrPnJ?0&S76o8&#sLSVFNQu5>iYCa_FFdIasU}UJ8@jqFwu+LukH8|H|~iGlatf> z*9+pW2Wq+#6}gR+soF;)>s>!pQd^B@l+N+76l2WijGsZpd*}QUv-WG!{{U!TjrW?@ z#5}ix{vTRLuWOMPZ}iZ!#}%%g269E*>=DT1M6P<`ynN#mPX`6g{zsvM%oS&7qxBd5 z38&yc7kM_PPD_#tz z%n9bD)B<@#H`c42kto=FHpupad$zy{#&9uS-SA`J#=G%T#5z8S9^|*wu409XM$$i& z%sj?bP)Q*(f$LaL70O*IT*vIk>}&8}!(Rw~3V3tk7l}rnqw2D0@@ltNx~qAtvAm5W zDQ|AlA}L|F=g#A|7_VNJ#QH9$s9$_C_*0@-Tk0BHK=;>rn?-dct-Z33v)jml{#OW| zY>DOtjd)-Q+g>et(wnn85{lUMOH0{xeI5-Wy7NoJDplc#1Eda)e%kIms1;Nb;jg zCXYGzietRH(7ZJ8$s*m{%Xi{iTn1rlYao(8Fb=`mHQSD3$n9LckB=^Nt4|ev)R)%m z<>da(xv?YXlG@kzHqL|inn?+9kGzfT#i%##!RmCw`K4x$H~5R8w~2lxJo;_L#2P1q z)P0Xrv9fs+s7CHpx_3<>6&Pt#6JVR5jTlEHF<5TrNC>+?Ta18{_(!- z5-2$v*eFLF0n}GLNGhMYlF;_B7^>KR-o{QW^B6umd{eW%ytBE`&xoxw=|nQ>8Zj=6 zNZrgXcW%Mt0zf_L8uj3@HH zy!|eRiaF$dI=^~f@C@%3e%sS&Rw-lP&kkSex4X8;lfxuY!|S-9Zbxy(FJ`$yVdF}5Hi zV->=~_qKwqo|!e}8b^iop9J_8!9Qm26GL$(yxR?o&F9%Pjx#*SLGvw&4lp zzEwAgBN#ZxQS;A=b*}^J-`IZ#J|k%o_)k(eQ>jTNz?R9&wZ5Yk05dnr7DBv}l{H+9 z^Cbp)w~T%sd^`BP;XPYf@%)qMi+2f+Pt!F9*(_GdNLJJDzI>Tnk`NhFkPK^E`jyv@ zFLi5Ahx0=R#2*IfOBLPpERikzYtr66*7qO*yx=2{I+I&Lv|&1E{Py_6@CV{&!M%4( z_>bb3|qyiD~m`JHT13Ln^Q8#50X$bg~=YM8_PyehS?4VF^;2(udjSO`19hg z7pyn>b=9D{v@AZ$YbL`Q9!O#wu=%*#-@R`RQya+n?n9~g&r#9gyYp`*xVMVh<|qB% z?rj@%d)RKsXw>Dt_CeydJU?@%X&U{7gj3%vYWEONF%FL4#^D4?M(`WI1Fr_OW9GK! z-}dpPyjr$}uWE0)OZz5GCqzaInG9SRKKNb$<)Z}iN#W~_O!!+}i$%Dw@Wq@^TIve7 zDjs(+#;hC+tV&qN{7mOPMR~Oqk<@)D@Z!V7nn%QKV^8phf~~C0&8@Vm`i;^FHs#Qk zF|6_&lgQomtT;7)hm!dBNz||P&1=OYQnHc;O93+>f0krWwrdo4``i{d#%qbD&7&)x zsiQ&hs!xJfHu8UATSuj|pvC1~JBGBJzf#CMdU7i-z}^+`YwJED@S*r`s7)Nw{iZ1| zB8gdHx=dvG)3abWH6n99lD)L}i+|!@4QqOxhJmeH-lW#vNfSpC8R8PIe8rtXJ9s{| z^ZtdSXs6+YrllXltLM4!^~8RC&Yd-?ur{)7kYX#CN;O3cYd*O>cMoXv+k2wIg zWWivvE(u(Wu1UvEmGs}hPug?f=f#aJBk)$I0!J)HdwXej!*%5-K4VL7B8Q7cP z%0crFBank9t}FT{k{caL0p_YqhYT_UFR>k~zZ1jNRIi1r$}B!QF;=M?pUv;=b^iba z!L$93{{Uy7iasvWr?HxU7k!jS5Vh12Y5ISilva^L#$HK8ql~K{ujseLS_OxQd_8&L z+t60t@)v?lydAPBQ;*KPoa=`%RcJZ$^UWRDEZst?vb0ahA0B)$@Xx{TfzW(Y@JtRr z;T_U!V9_sG_epJV&zJd5=;m1@ncba$+Hf}fqP?r)SHo|J9}@Ka2jMS;qK8lTdu4MC zt?Z0JxVaEdv6E*fhC=*c4CRj)ADP1mDf|6b$okwiIVz3Rc8}tJ|I+?J^zVUQD!Wl7 z?ZUznW-6v&N+R8t6&OSvT zgM!B(0&DbN!ulQFgQ7>_wwm6`&RHX#Nv+OixRIigP)j$<7~2Q~Z#eX>%r$Sca@LCM zW8dgr4ESB)nQX68DK0GRZD5uwNcWlE;^A86=63)W+YDsxY$ycvCa7KNdQ>n$@aIBi zmq{_%U2AtNcgXg)HsaX;ez_0B{{VFun$|Kg9(^gJpGmo6^1*J-B!V*7`KE$o zG34h9w6$EL*wPSZp8QYKwQIi}cw6DNjK~TO9$~Dr>`W!{=#WMyGg)N=Q(^Ty|jwyv@#Q(DyZ_blo#h@%O~xd*KazH9afC0bECZ zt0Z#Y$`8sUiv;;moaBRsHOc9#;hihNDW>VVV&8a=Q<2EI(P>8b`CJ(XLw3x!X=kA5VrFb5# z;-3wCG}UzLYi|o)HLr%Cmj2>NVUgL$UoH~v%E|*fGZrKb*sPvjs(eVdn7C0TOZ($myCE4VOE)ShBi(pj>K2^ZU;{@iucGva0uMqgE{{X}~w8&(d zNhgv!nD&74v33A~jt2vS#e2AVDw47D7>rN0)aB-mM%5U{2bSstYG5N|ndOH#{vTh? zon>y0IS+1KfpH%yjUnNH=jGdwc>0Ro4$kK!BBi1CZ|v8r{h#|fKMCG|EQ8%Pov7}O zCAg53UoG*u8Dkk!^C&&BUIC$a+V@DF_f2g=&g#M7T*oRH{{VOa+UV+Xj-#O;m2g+2 z=C2zbtp^njSu^x!!ut1swa*yp9}&gX--0!S4+W#CSd6O|`sc|8+Ut99kGw$WE6e^E z_`Bi1jQ$)+;E8Ugz0~K5F%Fx5vPfk}*-NT9Rl^a^ScV;XX1vMb8uw(G=q$c2pEOza zM}~eO{7CROh4mjE{9^FZ_>R+7M0c9a0hJ&hEHO!ACUd(vVH-Cm?$-t2t!u;{B-bLc z_+hInX}SX}vuN7Gv-x)|kRuLrEJ88J4Zb|%2Nk3xW6i0Ak?ei}@b;DAuLeir4}hK^ zj^A3>ZZP&SmYUP;Qyj2sW+Gc-0`ci!t}CDw(f&1q&} zxL9r)Wd)|5Ia3QXDnJZ(WkLJBYi?VdQ=_T%28(TZeR+3(@gl`$@YjM-;Pdq6l2i8h zkV$oMB8{(z)cI=boH=~;uPN|wxbYXluMhk%_#@*ud_!~MSB*6rTcB3rIAzV%{LI88 z$gTq@W>OB}f@!vnZd)C-o%W3X00QmoG@ln-+W3pdcTp^`J;*Grs>_!pE)=lxtw!Fw zZLeC_VAOnN@o!1dyj$S!wngDfX1<%q@-7fuT`!SpnPR8qh)DQ7G7T+Ia@^*ADMzPx zOIpp=p<>W!-X6T0?GhnHDh36&em8S+abF4MVsSCeY`mw~)j;J=7oDez=b=^D1V zH}-w5pL-iyM>d~o>utd1HYLoi8A(3XZs?C@k1F_w@Jm4WuW8_GF>!CDYFaLYw^vs- zb|y#+AGt-1q(ZGJS38(&2baMKruYxwv{!nEgmrO$1h)cAK$9hc8ReCU-3*1N+s<-H=A5yTT?+PS`PR$A zKN@uF{aeEqn(?&$&PeYp-c2#1E`YwM9>HabJW#jvO7UxUX&V{O8-CK*uA(6(#j_d;H zFv?3XD#?NmQQ9Lo^deDv9QK8zd`HrJRjGI?YkS>p((c?}NhXo1GG7LBoDtn~i?Ikj&LO6wA(&{<%Y$~(dXhTj_oR>9lThb4W1 zB#&qCKg7u{?6hqOb^GVP(yw1nZ9B#mixjiKPm<*>V^t5v+>O!@MsP)8&#LR!Uk-d% zquYIl$6775g>rwvzmv=|1sq=L|Vst;-JICHB)2_T7 zsb~`TSH_n1i!HX2QcIYpWXO){JF9_jA2Jm&tZ~Sh+DT9jId6nN6*blI&6cU~qvE!e zt^6d`;+$FOb67_A5lZBsv$lQA!D9m`fbJk;XIk^6k5qN1D?Z47+1%SB*E}Qt00kb_ zJRof>emZHorKA?jmN%N5`e?F*OTPwb5J@=>FjiGkBT@4V94&Vq2>4t3G!GhUJ{tIk zquyy^;@Uk_>Gv}a?7uD}wXWduHb|yMKfDqW2^hvjcjbAeD;0Whsq$>)#$j;Ob(}uq z>;C}R$Kq$fuZw;kxYqsHrCU$3ab{kl}O9D9vMnKLhknm28<4=RK zUSD`I>~((uUE0g4+RY(~%6n2(S~wm+imz@W8-(r*pnR{p?^o93xs@CWamB~xwLBbb zV^{bu??3<3_@__!FXCt~CAQSznA}@R@X8$W9yZ#;8R!T#{Vx1Y{gHkj_^aY&&XaPF zqTcJQ_f~h%oW}Ao{o+d*;GNv$VBpu~GQ`fu>G4SZeDv=ENnnc+jggnW(gl8xd{_OI zJ}G=R*KYhha*%3qKr*u0O&;kNwjyQ{XVd_GwZ}TMXG~H*Iy^@#{u9#S)Fd8iO?L&W zZcZJi5z5SuX^>eXsK5B zj$CXSN5|H!1($}bZ$2d78>P|y&m^(A5W$NX<+Gi30t*yI4bSkNmFJqit?<)9)xWp3 zX^yKU@;&)mgXcTO;6r^H#=HkrD<~Kl*xr@*)1;#P!@^Qc>U##AbE5cfK#RdzT+u}q zi+Mhqs@}KysI;w62_TwBI0gP_f`7E8x&2dIk4W(4lK3(R?;|jaZF17)F}(IuK2}(j$C)M3#_i9?+7Rvp zIA!1rZ0mX_gFX{@YF`ETv1hr7W1CRWbvsu-Xpw?$F|54#MlAfBkCxEj5O75t=6YFdTGs1j)UiinXc;^hsg!>A5&&xK`XIVDYJDtGv#b;6rHD_*hq!{QGf+vxWr zN%19yn5%m<59V4anYfHFB4lDZuS{1X;k_UJ5f2Dn_>xT*SkSdQ&G%t#u6A0_o@0fb z8c5Iu>A4d<0ir733A?0^K=8bNE%7hJJO2O`_-p$oPK!>6TbpU3^R`^bpi91MX93tK z192PuF7C;v1OssARYE<7a}viDkmJM#f+U?ZolYyl?h`u<(@c2Z#Iy zSu~Ff+eV8O!Ix~)%z)fU<;%)~-!A}T8OK`ms6xk=iLD>9d|$fdtXkX$SuU8n!7t3M z7Y8cG*a6qrijsMz1){qzB%f#b6M*r5w1=aw^cB*P=eC)zqT2aa7IVb1kmcn`Aj6P= zVO7xQ?&s2y#z7{k*EU&mZvfn4K1`!M%AOm6^r>p*)Z~%U{{U>XT3!9v)g#?3g#>fM zhd9CvV{gAfS*xti4vA-{i^lT{d9543e9?@*UWX?f;}t3d)T)@a8qT+&Y7lBVOT*?* zae^h`<^zGa3~d~IxaE4}8mShSsY*1rlEMZz3|N2F$=-`O=zJKVNc*TcRdwp%-ksf>TxGE1`R*vNA8M?84*0qKHNkKznDuaf5))znvdcBQ8?TG>XX zIK;|UGE|aBL(kWW<5(8YMme39$JyR0@im^aqTFcyB{AIiUrUiKEsmP|F0P+;UR8_& zSV+TTDmEMf)$n(PZ*@NlwYA)HoibqxOKkH4DNZoLHw}T2)L@@#wS;I?agmm`KKAhx zR{FP!?7ks*jhjtfHpr%%szAa!mm_O@s|ng0teeAYUT1%A_?AHEl8+V-R4Tj(Ry zHDvolP-+qHG9M*jhZE<_G7K*0@^&7Bt#f*ojC@6M-XZwwD_GdsnGS_?$YP1wB2?W- zI;G3w_h`fJ^ciX@Mk7m^a@hLI#6B<4?*18gAK;gZbi;22V8QcSZZBI40?~y8v>y3ycGd z;*1w%3(tr8rpqll;q{qTLT;@T!b}!%vShN7+uw%B130f0_*3FP z2x$Hc)_y3=^XQ%_^_g$ag6iE$OAVGqe5bAoUWENb@u0ERPEk@jAJ@ha<4_>-@A z)8f93=IL4`vgom1S})q{!(>l+BLnj<@F~jiw2JXfVSXn3JNRK^@YnZRt@nuJFi&xB znC^+V%-6Cq{ny%sz&v$Y&YH0FhsCk!KNBoGao~+LwM!ooY5K0GBvz8CXd{;D z7+_y5&ITck30^rpD_2d{blcw^+TMI0g31fKO)u>C)^{&kC zeWqlUm95}Qm}6JL$ba6U4V}5juMzQ9yWnW_e+@9&%s+zQ`hzOzz9vA6-*9UOq_au+0nw>bFk;t$13f7$;4NuKXP zZ|zSHY7eAeEvi41S!8w>@xdk=%ian|0a6v%WMd+{tjh^Hi`++M7PMl0y`%gb_S3JaP#&z-sl=cr&-!v-N@x3mMuYN9#Je?4$8<#0FH59cdz_t_+#;-;U2f~ z(oYU*J{oCZi%Hh>?ITbS$2#r;Cr`BQj|m`Gk~L`9o_6w0c(cJdJ8~rbKgj5fNcTTO z{u2B~{iJmN03GT702zJ|>Pum%S!uT#HO02K0lEWY#%7Mm0yLvLN+7|Bi7y;@=D#dF z8}Vmf_#?) Date: Mon, 20 Jun 2016 22:33:48 -0700 Subject: [PATCH 11/21] chore(bios): update core team list --- harp.json | 8 -------- public/resources/images/bios/brian-ford.jpg | Bin 10980 -> 0 bytes public/resources/images/bios/chuckj.jpg | Bin 68171 -> 67301 bytes 3 files changed, 8 deletions(-) delete mode 100644 public/resources/images/bios/brian-ford.jpg diff --git a/harp.json b/harp.json index 862f9f988b..2b47dc88c1 100644 --- a/harp.json +++ b/harp.json @@ -88,14 +88,6 @@ "type": "Google" }, - "brianford": { - "name": "Brian Ford", - "picture": "/resources/images/bios/brian-ford.jpg", - "twitter": "briantford", - "bio": "Brian works on the AngularJS core team at Google where he tries his very best to make computers do the right thing.", - "type": "Google" - }, - "rado": { "name": "Rado Kirov", "picture": "/resources/images/bios/rado.jpg", diff --git a/public/resources/images/bios/brian-ford.jpg b/public/resources/images/bios/brian-ford.jpg deleted file mode 100644 index 67a4bd89508eb76c0659b61fe51e10c08676e39d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 10980 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

Z!rrx?RI8-K?5P%oo8l5Jn(y&r7c&OTD2> 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%0DTUHRtwrqJ7sclcM%i1i+lYEwyj8qHMZvxs26 z=_S&4|1KCDv~n;bZTD_9Ao{pxfY@Orm~kL_?C1SoHoalna6=;2SJUCc$Dyc#M2r_5qedFDJHKT$#AAWt$L?XL>X8 z)80yWsovvdH03VmnYhHb)T!#D&+CS=$6_&Ak8RGHj8!_<4GnDV49eHy7su`i>v^gIgV_FED?#v0J#PKw}|4)xe_t`-Db z?IV-rr9aj*z4>GC63O@R{LVj#zWhhFnT1}twL-vnql;5GD7Cx#xqiq3Z6;e(kJ)$9 z6`P5mma{tkvK`a0F1>@CLHuRogOlfrpMLH9;OoQ z7(jgH`Y@&Mxk1Nuf0_HKvZpNmi#`2r_m2+YI4}Pr8`wr5=$kzdUW^lWs<%Z;X*;YM zW)&>^9C&wiKsHT*S1r5*&!~Y;I=YXxj`qhmA7natFGPAHdUNck+3V|jQy;wDDS|H- zZY}9n#lq$I)bxgGKBX=LBM2~Q)q7nO=mn~mdNR%o+m6=J!kY6ytT&=o&-|d|NEM8; zXAh9YxV7uawrugnV4B;rZ3;s#!p3E;Kc{k`YtEqKt=V^MIsfBa)PyK4JxR~{idqe_ zU7E}p4;yC{7+F+G=4slr8}@TdAS!G<8W0QlxGFjojNdgmFrJ0*MhFtHkAW>nJVpgx z`F;r$jYmIdta@pDUo}oyyVzZZP*P8?ws&$QpAo;!8LQupTDwqFZh>~T zLhIiw4;cQ)mu-BsmszInt?MI?{1h~6^3V!ILdy+5u|({p_{fe`U#kH)c!?B3WLVcC zbeR|xr0K)oDB+OD9Udpgh;=N95h+-xs$7+w!nNvmriK;YBd9E3?^YuH#rNS3G_U3j z9~9hq0A$oiPm#74;`V$-Es9qhs3x+R%*?zL_Bc?w64exg{mjoNI#_n}Ou1?JWIN!Hs!@2u5NPm=k$#(GW^8Wj?p|Zu3;7fNldrh8g8;R(33N?WICaaAL zmXCtSEEZrSg}lXwfZVd$3 z`6s-AE`pO0kmjv>xVYVcGi_?|>zG@UmYSOY@Y<)Z(DjHlJ7r;#uUuJt=g?a)Q`%{c``7YK&KiKW|(0lS%3&rEZ;0RwpRU1R7kmm>hb#3 zidnY3Q;euHTOMP!EV03>WIMe7>BGSTmH9vIVREuG*XfHHYOD1W}?U~Pm(buArSP?8tzGz*8vIRSsa5{o2I$&zh!72)a$%dZBlFWko>{&Utf@$Am;n8Te&l4Vzhq9J z=tuVO`VU*ze2;b#vyO|4PO`8vfn|ml1D)n5B)ZY~lWiS!VyO;KD*EInXbFuO+%RlW;1u{jT4LG* zm;IM*=3JY``QCXC?g#(ef5*XP+%I#>-#ZTSG)3%&wOg(gxaX7r^S(o{Hd%vkDITxG zx(@NBlBv|3%Zgz5BnJ39vZ;H` z)8|^h!05Fg@!oE7bn#TkDyd|dv}vMIp=)QrHS)i44kP#xPT<@^P5DgqL|~v;;M!Up zt5GCJ*5TJX;CR%mhQ`s@)J5Hp4QCYMtW}k{3f0qRl@8?NpR}sVJ{1rwO-A<1Pk_e) zjns$R`WewAovi;~YQ@dA`kAJ(Bn;o=yM4PegNb6*a0+ylCGx>_=w#kmKDZLQNAIQl zGnzCyNw*;%tyTHZ*9)YF@V%b66D)^bAF%B@kqnsR`ub_VY4D#50!WMW_cOjcTj#5T zcK_!9@yfQ0On!1z+3!9lrLNq4(=1Fwuz>oGh5vcjw5W*YthAyKz~93}hVQW_pM%c) zWos`ufy+cP?o4Tygg9Hp*ss-|!8K&Ij^%q#C;J_vx>U~vdRU&>JSxRp3Jct2wb-(N zJF^m|9Jz#!Zn)6ldK#`cnN>m%s{v2Cirplk`;NTZLz1MfN z-}>=?J{D`t@rOpV9x-w5$-!4Qc~4-*fh^j`!(87ltf4#)QELk?->9$~_BEO0B09_H zXEt9ta$0QVr&z$_6GAy+dcI+A?{@*_A2#M1{2IURgY_6$B@ zSf6Bwb}qzkLb|F<{aVfto%@L^p$e{>u^6;u;U}2Nz(Ox?^2euJPO#23Qvlii=ED!) zTaKw^lZ_JC{pUHf--8}1ONz)CaGFBNhQbh-?THAgi(SWW8qJ_;kv_;7$Y|k15>{Tn zLhstai<$7#!zY}^$cSxwldf<24z-qT-8aCl4FFxvX)OGWkg$WWw06r5i}U~j8D>3h zEWwOqq`PoL7)?>PCqn?mS!^t(@RVVK<$+s;7lzYxe{`csOW`VNR`XQB@RwndisV$I z2L6{`y~}xKdTD227C3llBG{CE)teNFyUj@reyDGJE-0A3pHdo& zd1#!fv8lwDiFgI-X7*|}gj$$kVJi)j{soe4KU!b_7s7ND{cE3KwKnN&Gm)^y7|7Lu zqooqWYqlV-u%@-`vU1gw`##ToMrJP+#kh9s-{GH4WI4!W{Fj>Qo6U%{HChFC$Rw0K z&TDtf%ObyuyxLE9S;S9UgC_m%v;B0fGgO7Oj%{{`8DYZZH4S|$A|a8hl?GS)?8vVuY{!^VNm0uzNg=(~CXzdiFe zOl@q9>`$)w>MU4rh!?#+CcMabro%%AxaX)Mf5Ta8Jq`T-J`UCatXjiGWXOk|}y;dD|2^g@!t1MSZJnjyx| zKbqf7o16I;wL<&dvWN-2UMA7GNIe^ZZ<-AhQ(2E0mqKS8O10J7_?Q833&8I6V1bI} z3>v=OZ4Aaf-uqVBV-`qS#HTnP1I|Y1*O8uAxJ9?!JTNsUSR-fb{)^h9%YLir)ws>i zE>a=$<5thPIJS2MVwd}%rzJrmSev>WaK!8)`-(c*Ug``99U37dq>Z4}Uc+BnNSlk>VG z#G_z86{K1;-c1-!oY8(R?N7>%;(H%pU?;K(_K%gpQRLk!E3mGeE;bMK9AK57-J1_^dj z`R5W#cD3C|K+ow>pP-fW)7|1`y`3SJ@M|iK>iyUt;XT<_;8D_CaK9d&*z_EEcj-~y zJ#a7{mQX^R8=mKk3>hLHfx-m_^e^!+u5GA$FSX3wv!93SgXo9v%N@Wi&HjrPP7p8& z>Rb(!SygVBVPX*zQ14LP(g0Zn1_GC(CT8Y}il{)y`+vAk`YPSj-ls9jR?N{RZ!9M1 zRA7gBvv>2o4zIdl?AwBwBN$BRkqaf)K(#9L!mTE@|B^pwf^QwG)@Zax!Hm%WmMO$W z$Yqh&eM&v$=VFQ$O0I8!p+tQjhU}a*)n9ymX5jwVEh^-=K-VEdqvW#CHb}0~55*8s z9l%h!TO4+M7}p&Bj841uEqUd#Vdhn__ZnljPnYQX_ql2L$9`R927@Zh;NPYCUr|3y z92+Sv2V(DgMoQh2KnN+5^dx2E%gmGcJfy4@?WL> zOakY%tE8@oG9o3__+?aeb1zzE64zR27*PHo%M!P+tGBjR-FtylpD;fPoCM5NaAo)o zLGK)de4^KX_0MA0IG<~@dgv!nRLxLEGiFD*$8|; zQk>q84_JEheW+dG>$PNKKyQWdXTs_51U+cCLbt*-C#gP_Km$k&$ZsRbQj65`-VpCK zyjiyM=ObLJ-i_*H@}KfHxqsPavpl;v;#N@qooxtB(&)`F&1q>AlgOUah> z2uoAlAr@vEH{dply?C$=U}WaE&DYd2EEPLGHTe9a&u*Uif(FTd{?0J9%^07QRv}W}=dFDuH#&58 zk*EfjflWQ1%dgr72WMopchlV@!4(5C7yzT8d@@>$f4A{u=Io3!+V7(<)rURgspi=m zhwS0fmlpQPkh9c|r{)<7o+i{v3>h|-YeaLp7gpjMk_U<#BWfZCE{rfl zX3jljQA~-oOns*7^=|q8cj&vq`Y5X;Xm)gdf%M+0GtW-_z_?tM zakl;TxnwEi)K#N-HGCI&Z+Qpi?YKFS^y$Fm-ms2tkzJX?xbuo&Oz)W9YO|3;gP!|7 zDK&$wC!+SA)5k}=k9e)wu-7!QX)8TN7!=iE;FEJEA#i?t!A@Au#V~{O+Ka@%=CR7W zu^e!)*wHv6GXZQBC}rVzF0)Ob{D)zu#u^QO&gmc(*0(Zb_SwDLqDvfEG>`3JWz@@?#8y2_^et0+dq=ywH=Qq zMzaa9g!#m=b*D?F!mJ9lBC1?cK##d+zv($Bx4jiOz^xV(Ca+5w6A_^w<8N(8PMsBN z98-tn10NH59#s!blI}4>m%Z9-N;rFz5k_FQi1HNrY$U%XdiTM_dy)00*>KZ@Ws@W$ zDo^kcc&CD)>+kh>o&n})RxijAL$-h6e=AavuB_j3Hg|=Dl8VIc&0;Z;InYr{pRXgJ zz`k58{!xjvtE_cG0}}MibEifiUKH7dR1(`P%@QQ~#ovmo2z)iU+=c2AM%k0gTx>EL zuvxwILt)-Bi;wSzGK@&(U`y;Wv|K+$;Z5k+_k%f=x5@!RsW*FTp2}6)(%)>p*j(tH z{e=OWPi9zT7uSsRUp60eunIgF9JYAKB52Xm&}Rqo1E{jcG~hEKkIkqyAJ{E zpcU13KusR18A1_Ok#U8aXI>4&fxmOOPe);S_NdKP=9D0|ihBKToO!;zG*(17Kl^ls zrX>bAMWH|sd_X8ZW+sB~1(esY5@tJUSwtv})B=x2m)&}$2k{Fsb=NsV1>^_%QnkbK zAqp*K&l>z9NY3E6Czx*p3vrKCP;XX~K&goSja2 zQEHS514k7@+qO2QS@J_Vws7n-mdvK#nEh(lDKxxn*|z(-+6;M{IA?lp5dJ|O_%Dzm zwfQx*7k)1~^eG7v}hD&?7tnx7~3shigLx5quS>Cp0 z_MDq<>l8P8ylvK(z*!vwSa>>o$Eq<>K8R)14Bcv+Io+WssFyHnia=^V+T2Tn1Er&X z#%d?>J9keQBRw)MZ{YebpR0)gnzj*ZAvr&|6sOj#btv&pT3%nh&X+v04mP2xrJ9fk zL3<<4lTjWh_07v-(<>fLyx>T!JDt`N7KuyPuw@8f6mB}6Tpo;6Tx$_&+`gjs1QpEl zqtu#XyC!@XsQu>l?)%2T!ne;_c5(ds;IK?&bXk?gvpOO;2D4y_VAzR7s}Fq&H}r#FAE+`t`b|q>|fZL7%J;WC8WTKAPCr89(bwF)ff_W55@jhAeDZuI1 zEg|p2+h${d0>VtbQyI@Xm<}dN$qkb(Fe<35jcStXY-T6;bsACbt@h+sQ3vrbwCA|< zAK)Z@sv%50K>-uNz2$P7$T(ej6``$38~BkcH_Mkje3AcE#UlH;pRqRL^9KJy z3ps5(4KiGjz>Qw`y*g5w`J@`Q0j!Pl?VJVMhy6aG^$Y7#jXR;;m{>v!bDxTH`SibQ*W``y9AeXSFSMkad&;m!PMYQ zZpTf`Mog_DPYA+xSam+jJjDz*{9FoOpBiG~0PFBLt`qC=SoryE>)7e!dm-uH(oQ<( zegQIURnTb6nSFeTUICQB*sIi0u z?Ig3rLbv`ni)Vl8*&3+bMd>!X^DYA}9t@e_lVzCIa*DrV47QZ#AfPc2n-;l-i2jh3|8LTQh ze$i)gZ#(4iFRSTE>uWopO&xf$Nx67I7jo;ed_r@U-u-~(#!Mxwh@bQSpgkOv>)TvF z3E`vV4mLL=z{t`s$hojqEp-t|ncbGs+wN$?Tyi>MAL29vm!T6m$ygtm%WG+6NdMGS zv)9kg=sf=Vl-F0{W1r{pl421Nsh4qcLMfd#4%(cEelXw>)hD?hknCO~me!cvG4Rlp z^KX|iC&FrcD2FGmyIO#7w)kDCdv@&`8iWW_0g&%wpDh*^(X0Tsz;4XyK9X1URl4pf z-5JJsCbr}dyM*n$c|+1f>{J*jvS^-W);lh56Z<+vn4MJ$`@fP$P_@`Sm}Mg6L3sZB z_jpg6#(dwyc_7{v$TH(L^b9@%rIDAwQ{t4VIZ|AZ+j$Mo4<#>Typ5KTiTL-YUB+eU z=@Uls)^0qu7VK7Lqq_uFkD8^Nl}@az@ge7XED6iwjkXsMyNc~!sb^w{vSiw5ozQ5Ou$rzSQeZ4-29zWW&JTdA9tSBm|+LLM|pcL85+5z5@` zhOuLYwH%d%O!Qp;VL{D&VGnVSlZnn=uQUI>gZ)dmDu!8N*`~%6XJr^^OUy1IK<7ce z32*{FG~Td7e(YSf`s_KNt8wGa`ih8e%3U-9gBOP;jb+`Ohl?GvnPl~G$=#5RWxqZ( zp(TWFn5qd<=ytb1NI*mYw<7}nWl|rA9eoWuCbd9vA>qO7j}`03)BCp5AkJURkjxV9 zdNJG)$KKFh-@i;E^>64o>JTdOOBUO$R+aB|J#K>-1taiN%u-bVT#BzHK-VZYf z)6u!tCfFcxxB^^#tCXd}^-V{*VD@94xRS zNa1Z=A-HDuJ%1wLJ#ZDGCpCWCL>|} zgg>{IRsH6(>KDMx$cy*9+&W$G zUn#q_?xv2X1!=F|pMtzwP8#*2y7~lk>5Z$@ZPFmrb5n0#wj##s%AM7tk9KGopR%u? zJn}9o{P3TyVtvi)xcuJ~xAZC+`d>%E(-XXb#P5&U#caTry5Yk&f`%(hS?-Z0$0?y0 z{j5|H(7%cgXYhvcnAOz`ZRjCYV9qxYvBZ7#pa*k`vmv7e3UVPlzJM6{P>590ur2VbRzK<;<%#ByCP}dM!JTl0&{qkj z^8a2iUpmM7OLQV`f!=tHMFWhRtb4b*NM8I4FtP3Idk11EhM0)MVW*Kb8{2HwvPLq0 zETl4f-5g#>Qpe_5+>SeVi@0<7^xckyf=d2?d4qt%&RdsYC1}M$f~A^N1-3Mp^5U83 zfR|;%etmlC0(uN1N%2SiqQK_kThNbnc{H{&CoILi+u)b7@8hpEC6$Z4^x;=>*f|2` z9#l)7=kYod+$Y5xffDOTXpXOs~7^gY4)6P6CqZ(7 ze1g}#wntvR5jAYj8xo+XVv0hU@YBT^U+_th-5BykBu8(__8cM(D5ap{rz0HLkdi)I=+ z5L9l75}4|eo@!5u30YYuz?NaY>fuzmW9^Q4n@hv)8@D12zHlhnfB(+=oHKUpH}7sD z&>Aorh~=y?bxGN@|5N-a4{(0gS*$YVzC4LH-3@8zt#|QZ7SG)sG?8jR7+-jQb1?En z!pC7iHR0Fc*04##&?Y<(z_c9g4P>jO4I}l_5t47yRsrE!KO4V2)&7Hw?G~!>tp4Xs zcp(hdYc{ARrk{1^XXo{!ypTlUD#V3y#AJC?a1*CB;4^y_fb4 zf95+$Fi~qwv%9())nQ85I02;8QAf40FTHnlB~449TN2cFc%)QyjrPV;erDs1wcGK3%NV4h96~hvItZg; z$WI14wDXdM*y$l4gl^yBy)6FW;q7nl^X+fA@`b2%{ADVhbu0Lvv}-ybJWnSRS3*Cx zrcmYih*$5zebMTPC52_BcME(WsLgxEUd>1XK*j*eNBj}y?QKg4k#0?NBe;8zf9|Hn zZ@lY9b)#Tm0vYU1JO7==sr>Vi+$V)T4bMUPq1XV3Up0EEmaBqu`JT z$E{#MqX5CZw2>vW6VIzIV?iP-tAAt*KM@u{j-6P{zpWV%cYiHzS}-7s&US5JqK~l) ze4&bn@Wv1L8#hl$&J7_`?IuOdaX=-i_dKaq*Vb&`{6zoPiP6zBs>Q6^okD1~ePczG zCzyfO>}6V1FeoR~yS`er=jUcfKJ)XaZ7Z9>+_BZ)ly!~&in=el=l}ad0ZB!z?@MXz9h=-rJ)Bqj7e(ZO^Hy>vdJ({5v_-dW)!za0fQTV@UnG5 zJI>Q?7^+w_BXzF4snhfP zUl!q#8o^I)HgUMq^Q3XO2dTea-?=6HP|tr)Knc>|Ky`XmoS&xe(}j6MS_aeaYx#RE zrod2DRAcc9?TC!RrKZjkW`Jl;R-{v)1FPS;Y`GI+sP`m^1l-G{CNJneb* zN&8uS_PwtQdFMoIMGYIuhW9NS(1&CaKJ(L3YiCo?1jZCLX0ck>kh#7`AS{Swz81M= zaN0;`Om$!8cj~HtaPz17OB7Gf${$>(1Gj(iw+8)?DKLtQlbE(~KkAwWPA&z%gAKOX zV&^gk;cAj)Xdu^Z^BFjUO2VctZd+_2V?)nV8_8W^&7?Ns)LEkBQulp=s>!8H=j*So zD%RA0RDE?uaW#P|95;5oLXV|mFzm4S38|y3GFuk2s-L}d@RQEI7dR)Eyj=)2GBS*H ziDy%p1R=AS0Jsm@QAcCFmV_CalKH+D8)QAWct=PVcxe6b+JcY8Z^x$s5x2m4?I!h) zkfkc;GoPDFKu6HN`w=Y^9J@>u0nYtk*F3)xnvdls-6xR5v1`B`7abt(eFo+~GW$eC z%l#!~GAQ1dxXk!H8t-6w;b82M%E1nW9x^p$XnHK7rM+WrMi2VSWOY+BKA4lUSyx-? z^6HVzVq0%7N)FwdtLg1|BSBhL>zrB*kM-q1vu{s-92~+!@gPc!Ie}zGqo7xe%(K$f zZc-L8`_%08#s~BQb-7>>B6bpLO7+`z27<2>L*e+(ul^*N$BHk|XS0@dD>9d2wSKcL zer4*0%kAH|H`Jz|lG3P;Od$d0if?#bot4^I$FK(`rFB!|jcNG$!+4O<+cKz=;&JBi zQ-+4ud(V;H)Nnt(3DNc}ik^(2AZ=dS)OPZe?3g{iuoZa47Bf`ga=oG8p7%32@HV@k zbRDF21$y$b9ppsySXb=-iVV7L6tvWR-%u(|ogmni-F z-7>8ItV^Okx0Q6n%ihxG{bCV(R{0O(m=qgFw)NQ49NadCOAOBAioy1 zLRoc$`PR{V=mLU$0^eqaEvBw&_gi6hfJhoWHE#l&xme_DVh_7H6t%M{QvLb`{?^w3 zeyQ1ZF$`P(IsLrE1{~pNmBufXW^Za?5;I+Qu6rzGDzs=Lb>50oKy-JUW;*s)GvBM;!e6#8=MIQF z&8A!#Fs&egd6zO!TW^mF#`$Rvti`ib*L}F3VH5jnd92{#T|1*pMZ<9CW7$~|CH=!h z+rDdV(ox3A?wmrsA^b}Pt;W->3W;EtC{+RHL2^o>O@>wc+e4wK zaT}KIhBS#kJy}ruTQb4q9h@HMK37yX)w1;p0}0L3LwVearI4W?{fM^dVF`Zd4xL}% z9nh_M$SEBgW?%Qpz&G)J%ekBSw3`LC;~4VMo?4HZf_AcV@8thRnlIsEN<8Q9)xDJN zfJnVQ2i0zuLg473c;amRszxZ;60c8%vS8-&FP~Pb!%$(EIIluZpc{d#`9mv84&`@{HYJY zA#B*w@WA(24NS=`ix88E4G6kR`5fb81vT-8kYLDcR-1f{C(EU-{kyy+VZg!bm+Pzt#AHVQpK9-0Cc75{{U?m- zOkLVk)J%&AS|wVOWiaJfKt@F|GIBEt38GK?9MAg$k!_Z3g|U1wwORQG zWNCa#pGX&JbOO3>1$!%O_tjg3i8s4{qDv-5$lCR1V;`sOT9VH6;$-J)kSjj_#Clnw z&7i5{3|Hs$lnZDqITAvrla~TU(4j;QjuAq5eYvv(_wd{&9L}lF&#F_l#Qt2I#nxFx zwGPruaXZ4?k_||7woMD9jCA!%>Cm#z#g~u=Ok5=W>y9;Z3D|w}eH<;=d>hitjgJm~ zW-t7igF*WB6}?y$TLi0;S*i8=Qu-gAaVd$nkg@hsn|9e&B#g7~q$}Ti%z<`bwg$YN zEucvI9w6-Wtk>doU91vBa6Pl7NoI$Z5S8BY7tPs{fC>jaj$K{bxcDsMDYzy^_ELoI z?Nk@MDLnR$3XuCp~+z2dd`fZ5e3qS@b=ctz`f3 z37wClRh92Gf;mX3Si{g6nwW31+AF{BnfNJX`U1fUlPAaa1=#wj&QBGad-KzO!-rK~ z0@B7&)UG9qx$1;$B0l;jpAAo-n=EVY~!vDnq2dZA^$w2Z$@A65Nt4GUG^Q{>Bs zW`bT(4o~^q*63p*#|4}yGoG~iD|sooZZ7XIFo!UAlGnxdaNpItSZKUE@u+r9{f2*4 zhwe7IBhtNa%+K8ys++JC0SnOj2E4ejtm<(V!Z*C*U!+{E*hg|AE*vr7p$*j{9W39v zVj2mxI8)Lh@yY(<{+1DS#jW1|QXU0(zi~|q6LfC)9lyjZatr+Ltw`A4P@H|H7nR4k z>5c)J&=5Dwu`8zi>E%mWKihfU)JBofbUPp}YhVySPB=EZ*Y*)-Rv{=rsf7gzBF>w=toYeTljQ;dGq6%|Jx0oNr|=+z3m72f82RqYLv1Dn#zn% z4eO!`;OYj@TePdIn2aaG^p-#H!U~Y)WzwsCqeT0wSsByYBRGwZjoBAPO_{nRo6#3wJkhbG`zpFVWSY- zT5MF!Yg#TUC(NrSd>*M{c@REcH*FQl4Id_T6uh4Uvv=v=KlV76xLHpmw95Hbl5ebx zkEso>hXzvP4*+wj-<*VlOCWUJ6y*;!$U1~NVfA_aQB4PzyWKqm_uok-eqa@D_U6)<1eKwY{HT7l2`G14h7=O_dWv4%83Z6Z1LU zT~Vd(pQR~q>ZE;~_S-;_PagK^moZ{6tY~lXlab*D=~#cHvjI*bHR~{^45sjvF2@v~ z@v}s0De07li|uHz)Geir_34cqfI2bZ1MHSq+fPum#d_jhyvof>prOxwu?4Yg&{!yh z*aHS5!p#M5iFdEYO|yUbR5S#ZtzHWn1Akr+k7`7GMn$y#S&X@!GzopSguy4`Cqf=z zRvT}E`$YuDuFbHdkIuk9&%A?*N_B)<6Lyck9Z@D@za1^rNA20(u`Y*Ct{orZQjv2$ zi~9v(1wn!%-N=5hbwKrl95U6A@DBA92#}lfb-Jn|q$T8^m%2b$mq<`Nvm=v7RI9Kp zH2;8#?=WsL(!D!mcFc$l+C=8;){MX+yS>(`*G*DImohTf2Q6t793U8)+ANEY;JX52 zy-aP<-iAchE7^OZr`OC~Rn^pS@`RuZmWsC#lg&?miei`!F`IZc(bwhc_)|dh@T>-! zXQ!yB-IOP(zMuzPc<8lKiiqD8Yke^u=brgi)l}Q3*evw$K~l_h0jFk;P&1t5j-T5R zo{5^Xl{9;6HUUX>Z*nHUF z6Sk5YW-(L!EE|f%-FC5e-?x$fm08 zO>ODKi#}n=?h96kFGfn<+4qRk*8~eJy^(&orXrnw#q20*_y|k|MNvN(pX)X#|JqdK zOsv|qSW^z3XS}q1IZ@Kh;&*DEYfZ(GHr~LiagN>iR18vCZq-@YRG`xcGWQ8Bm{ngs zB7>_P9|o&r4N-s&S0pm7Nl(tnEM87Id67H05TC|=XF>=ZeZ+i&$nTy7{kLXzkV_}L zlT?S-OhlbTsQ52egXu+CdW<;`lS^HD!|Tg!I?O3y9*Wr_Y##4fD7z9b^};V5*ib>6 zx^PZENSzCpWUB@Q!9ncoBu+dqk1wE$=sbC#gMk8Iub!$_t}X4d-gf#6EuNppB@cP5 z!vgMDd779Qs{-Z z0^pwdhoWYya9etjCA1H=YL7>KSH&$0Qg9kbtN&Wguphwo$@4A_OsSa=$<5fXh+6h=EqMZMgJ}aT(n9P*O)S+sAaKJ5k zoxYGbSx0(~sv-?&=I-j}oB&Zp%kukxJDh!zgiW-t9??c-mu!zYj2?PpcE z&_iROX0)be$esKCMH#KaUk{^%xFq==chIxI`#jBa#6m-+d4~7rRef8VTbNoS;97`y zqHTzJy4cJ_|J4yOZp3+#o?}2A+<(=fb`m!}PHOe(R(tZWu~Gd_)Rq%r4Nw?x4iyfO z-+fM~*M!?kTWstl70(%Sdp!Qpc|)Y;dH+g)hTX@Gnbi)ac}k5jLP$u-*lomUad30X zPp|Lb;g;P%NKZu zE&4(^Nr=*2-jGsJHvLuF6}Z8Ht$G+tJl8vOhBw2im0Fr<^vlj!&azT)(Xu;5y21!~ z24Cq1hJQHLwcPG>vZrlh^E0`<^<>lilFQIWd4vhGdV9=+5u2-^aAaN&C)IkqNHk*r zKb$!rqbb)WX@(P%qj}7doB2_y(Do11eqf7d|#FC3o8b&|J$5sU8V*lopblg!Nx zl=@4BN#UNu3IcIn^>NRtCx=2hD`a9;DTi|qjszv@AX!-+^?`$NlEpzey?z`dF96Y|Cp5A+#?mEEK<3bzFB&E z<(NgsUQhEqxE7NS%!kNTf*BbR8$B{_Qnwn-1(RWhB}lVFJ=>{_)pi+|UW+~z-||(U znM`U=0ox#>sLduCcdDxf(0PbX$w9e>4>BCQ6xOdyE6ly2NgrEv^|WeaDR~RfPd@HP zlUbMUd=dnE`trEyB$TFY#?Lq+=tL)L{a)2)8zU8oLr$ynsG!WK3t5JQn_Tfp1}f4{ayA*yM~cTUZ1 zaN136N$3~epwz!XT8S$keCNio9FPoB?=f*Da(&y!%&_Gt2QbkNMW(YoPiu-z^w2_Mb)pGV-RYA>iFMuxi@*)Cf}f=>>DBKd z!L!o%Jb}fB0{CjoBGI)u+Eic@EdeU7>wFkFrlN0NVnw|U?{3sVajCNm*KNrvpL8+E z73b6?0(77mb-wW4;A3PSUp+rC*eE?)5ZMZJCC~eJ1LW=_edOp+yHSUM>1y}k*I_w) z&e7rVmEgD0ZG7C3&xa*j$14p&(mXaJU)>>Hub$aBmtmj1ygbs>&kUU~kJU8?lE4Z1 zFVnffrnd$?TlEts*xOEZ?uCc@j9PxD#&o&x#fejP$<~_3&6jVK-A?8*bBJwdV%-Fe zj%17bq?gvFyQYbIwFe#S+Hm9aa+|5fRH7}adut~Mb9ss?^-?^=d&>D9<-x7$*_7hfIQ*%+j6H|nXS9-MA?u+ zXU(*Su_+C?U8W@zLKj|XXxYbQzW|P^gH25>l;sw0RyJm(9n#=CN?G3VNR9g)14z@y zo8Q}y8{SPFNl}%vpRYhGQ=*G4p1B-lj0Y#KN4!h;O8WV1JbH=0w%~C>oJvyEKA-dV zW@Rl!Q0vjMItJ);m~M&Us#0z$a0XeK`sJBTt{q}iGdFWk{)f$}Nl)bZFn|!9Uavh; zWgza=;krJSCS$&_!TaMh2%j#P_eg*HGy!=YARv^))RvOGMR*X(g|^bayi#(M#`}|wvHpv8S)8SC+Rh26INEpO@Ytr z0ztS}fyDH0MhGhu3@MeJdU7rLT+}B^dn?U~ zPu+aY_;N-(AMe&qhiXTZJ+rB^s4Un^o}a$#ckHXzNm=Wk1@il&0w&6-3&Hmmij*L5 z%dB!Y8J#f{AiS{~Y@{`bat%!me(^`uk*!JUW8h}2kBz1Q(FgTiGFUUe%`;tB^u}I) zrL&p&){kAuvfPA3tv6p!KEY2%(GSB4T86238AfNzV}$Y*?U?byd>UHhS;MU~{S+}P zm1!8DupPmp+_IHrMK88Abs0vG1t~WQ&dzgGE_)^cx}E!Gv+IsI|R z=S(7iE|Q7zo2;sL$2OXj?dYH-pYVe3roO*l=!UmnxE#p6B_rM;IrjoRw>6j)mW1q? z@7mypLRLqv}tQ18eS3B$8 zpT6*U`U5uSIbCME!IP(VcA7ILa>Hvr^FDY4D3@n=v4#fCafVw(!rMvem=eP%$ zyUqn^$+}GyYqe(nk{K-Ef5N^|@|eFN2426KPa7nQ`nntuunTx1);!Mg zI%ROhg&!?0lU)`P<`>14p8M*WVYb>e}S`4|!gsl)8M7d76;L`bRf6uNNy zH#QY;7+P9`F!=0;yPXTXk9F#La&K4XnRaNh{ytQ!rtQ6gD za!^Uuv+>n29VQ*of?4K+6l^%Qo{xzqs#R<(#9Y1}6PmY=iD@FdBdfou0qAO($JSs`$xuW5=cI~t@Bj>fG zTI2W(o){uEF#A7%t=_zd%(*%1&e6$2&3^b3S7%l9%SNG%j}K&&zd~bV#WQ$dqwR03 zlm5+_vwP2c;walatDSlfVVjm`sjEmYF}-?NtlxL(fZ;%}8Vdz#Qs$A$@u%Z(RbjeX z!E(14++TMRsrVFgy(5K12%qYcfbHCo&1MK&urz#*3`AN|(31?zK{P}`bNEgr%b7kz z!35&?S>cWL!wcF0B_=Utnp0aE7b4Hki7Z*ro$YKT(+wiU(MFfdf_I=7_i8_ydlJ#p zP1|LX$m@1U1h8OY|K$k#bouTaJ!7zTF$Ud(tw?Ro99bpJO7Z(^8ZkOS`-mJ$S9`!M zkzfeF>ytIiZ%G)P5d0!r!y^=&cpY)BAe5xZmGV|QLSDVEHb+8eqkA&Ya&o@0Hal`| zi!08CvgO0OQZhjGu|4vu4JlakA@w&0^Sis3k^|oYDIX|V8@lo&JNin+TfCvFU>2{( zlSHM16}2g$)_&%%#2&kPJNfKVo2<-QE6n^3ubf_%me4~85d6d9agG%H}OAm|6YiQ9zy5d7^*N?93%$s?w$1a z+{%$H5V4WtX1&?Y9cM7FpP0|qB$CVrrO@@7Io7Q$Vt@nV z-B+zUpxRT385WT26FU}^0m>B{A89Idiy0Je4M*={DUM{Wd!3Ri^pDM@f0+QzWcw9j ze22ED%Ml##sZ$XFlkh6alhp7nSyJWHyczm~)|A^%{YHv#Rm&`%cEzWv4n|CWH$^?{ zW_SU;!TqdXI(IF#HAm!rR28R_r2aZKO|k!^d>pCb`TjY7 zx9Yo=Glp_P1O^)bQopPy%xCL9BU?;C7D`{O7QSPp&Pzwsn>vmBoD8lCdQx8+Tm!W; z?d>p7@Tz~c1+eBtwh3-ltOxA2+1(*UU~s6F5xfK(*}dX^>4az=HY*lIjCyS-1i6n4?3j{h1`bBX$Hnwp@V3hh<70U*qdUah z;V}O1x1?$6)*d-Kqp#+LF}sx5dw-(f-DTOt{UhNWr8s$y^q8BQB#ikXU<-t0SEaVC z1bfa=bab-~g8&vMKaKO^_J|79lx5?9>W5R}pC?3T7Iyc?BTQr3=W;$a5fIu4esL4i zMaKa^sAhho*TdiPTKk-f=)0Mk^dv3kgZ#-#O_AdpC(D8sHas4VaAjvb+ zaq38j;P;1NI3Lenv|N+v#y+!Jb6oCSmIWkMXdC1a9XEA!kZ(X7l0YYhO9bo8x{r~b z)i|YeNnLS%Vo-Ud{Z4fyOljjy<#^sHi&>lQxUjl=+9vj&VOqwYEO9zsZ46fMgZ!|K zDAK&bd)T>N$DS-Wg`zKENmiP8FFrp18>-c-%=qGp>E0r*A;z694CKXz`mtYlmN z%;sm?q5Lbh)-9g%QoLl6&bTFTnb}_g%sc;2+)%T6<_xCyM=~|Nm2n4oAvz_>xhl!T z$rxWh(*0diuROVOIJ8xO>@MVwm z$*{n>Lt?zl9$L}4Q}2!P4r6g669uq=H>@SZ--wQ0d_3aPjl$~$pdsk$pD#;BEr+D{ zEN#1V(g!W&gbLHA`{4lgK*ycqiR&PXmYJ@U#bB$Sr;N~W%!ps-_ng|OSBArgxYPfr zMl;gp>qJDF#wU$yM;M_t3Xoe6 zSEX|Vd>{Xn*KpWu#P`zcRrl$M!s^B--phiqc^8!VZDI4p z5cJk~Ye;@2E(h41fQT&cJusi8X;NklI-xSWTCzKdAg$q+PyxSDo`VXqhX!SAZ zb7%n0B@$p?DB&N=P;Mb&>1rks9meFvbE53P)>`peXw)HaONeZs@3)u{qQ zm75bB4x-H`LaeJP?B`Ytqxx)dmZ4nOQ+1K9==pyn2D zS@u9Sueo}(x_YSD@L<%ruDI4X>C^nlROh`zufyEIK?Ry)Gr)cVoyqi?ZXJJ{JFYPL z9ychtA(2I4cRPQqky`p#U56Z0NV5fG)NZhcYLdrNG!c$3xn4r*^KwM^+2_@s%M#rc}(Ogpw($5g5WR zhIU<&LM}N6Y6~(8yDpB-2Lk^TEIw?-A}L9 z*?iiY&q(IB9Y_?y+)YbgN5jJ%J%!x(rs^xK8ZNFUcHsvVWM3mQX2p8NG|)n!{w-Er z*9`Zp@cnF@{?|J2%)y#LbJ-kDerC!-m}u)x6i@UGPLsO2VfAT&)$w3ABHt73^~)u* zn$T4CqZ9v+x941w=+N%Bz@nK+fKq_qkcnMa4bshAOvvvj`?J|>4+zOU7_VWxIbR}; z>09o z(~+U|`IjA^ia02{bc(q}GRG>%Tfw$vC(}tm?|^=2s~WEb?C2ojK*jDRx`pRuTEA8O zH>YY=mdU|+Qg!HKjEHDF8Rs*AQG^%M|J)ASk~lPrHQ4M-W9E9 z7D6K<<@zPIfz%P87}lBX`}(2gGj#7m*P@8eZZx7)S)^zL8xjlUv($j4}^t3 z&6~#P$^u*JyHP{0;!Ow2_GojHKL5r`VA88O;(Ux{U65f4uVy@ygt^LI3}&jfoDmiC zFC=E~6OVAk$$f=3F)vfbbqgjHCdu%646eU7^n!mX<1!Hc88>yMe(X~8JeOd$uEoo5 zaMdU7T-P*$?q%Kj&$GKM5XavXD(g}CqZ*qwJDh&#h)k~l-OKKboBbR8XREQV?_)$; zb%4N2N4|;R^F-*B>k+Dz+rs%mFFZ&C(3o>1PKIAF1_1%Jf6; zfk`4C>4BlE{*XDh=($*k)=;I*<5Tp4JAi6QSB`4)Y_6|o29sC8Bi?Hn2aASFMdLdhG zR+#z66xDt9VeLwL$)_Ol)^cV73WnYP?Th_*yg7V7tiFki(0pAeaO^Q6p`TGm>zoM^U{;ymwcm0Fly~ovWXuTf*>muT$Y{68p6NM*8V^$3rzr!jWliDf$ z-N`-myYvdYORvDJ!utY(Y*4{Rpp|>i&o@o2-dN09$ECR3=JC^WcjS!NUv6gyo1>Bz zs4+x#Fk2_uD@jXe8dppk0n&}T5ifL|+pmQAxjUp#@I<|lP3q5F%lGeV6Pi*rwyml>&<)HX8w%XIZH z5ANeNWe=Q-0}p}B)6G+|ADg*# zhYog6ZV*aOd^pfS_TK8>=U9L%of2)IxV1@tnL1|U^{Nx*M}281oUh4;ldfuGnG_3s zc?6%!OPV$!Pq2X5NJ~iUgm?I=9-Ti865O^O`cE88H8)lh;I4Uh+jRHYPM=&rjkTpM zy|`+R@I62!)J4bc*v=Vp4GaA;eTl(O4wN}D-BxR8$ITOfLg6SMewH-_l(&2W%tt_B zlreslP5v=+tiVeHrqh^pgl7hqIF31WS+T@4=Y3u`_oWBP0%mQ(2 z#k9PvFG=A`PK!ax>FGi>R`q(V%*xV z!$zHzSUc+xn&~iMW6tr@XioWM6v8LN*(m%OUzhq`V1Uq3aL2(iv+=Kb33YCCc!ADy z<$WRGS-)9EX3b_vow>V>kuN@b65EKQ7hLq<(S2ZCp2j1^mY+D)1QYjglOz&EwL3h{ zyeylzq}GUMCd81TWob;Pq1}&@wJCw3HpnK*Iwv(w0KY zx_Y{(e)Fe-W^L42zCim1u`K;;HepYHCbWjLf6wWOy-wE zC}R`WkaX=bsILATQp704EZy~B5l1`NpF9V};bKcSxW%GX5Gi0B!xh^;D>I(A5znEw zKUjyIKZy<2@O*zT;KRLI*2_rG&Rh7NzlFFhYV6@+9&Odu-YYjk_JIS}cAgw`Q2|a& zFz?88tL?Q2@2!vRsc@mJ?A`UPP@HcaNi)HLUjp4JL|=`?Br~zBjgP9rpI5VC?&W!qIG?TV2q3Vp zi3}!#^c-Y|(V+f}KHd$)kW0*b!%(q^s;I+@UeGmHADMlQ>XSe(uMgO1Pwe zYLca_%Zq}-t8k&w)Nd(_^ge%-eCK`XmKpLNBLrm~V-$!9&0nIKIQr!pVuw?{YVJ-M zwah37% zAlqcsR^XDRfwgmo0~NVvubwB|y62`=Z+j8*Iowrsc~jB;p6=blWmAE>C&vxbP)Wvv zJPm*AXNoA{PZ*xEjQZF>AvFFHnqhCVqAn0`I4Bon|2CycLAvU5xsKP*@n5g$3#odq z5tegi!VWp-pM;%V=VlasY#9c>x~G9f5neT1k*G~n z1#fnif2R5l7K5L<5q0Z`790CkFOBR!n~7M2mlCfa5})U-+z|MBd44a83kf})qFRU( zE!ITzJ{spnZ=m~f_v#vPE{DY3I4M*_&x0bzJs=r*q094QnqFZ%4DzAZQcq0BLT6T8 zi2h$8qp4<#vz7CX4*xl7`m;fy%!L>&`&smBKZ4{tDuq&WUa(H;!F!vn(^pHFj$%HZ zd*598!eehpbYux-ScIy%o00usBM(a%>CBeMnD-p5O;)QX<(=U+2nz}}jH)#D)AMyB z1_F0!#<*4pRv}_;KowkrE+4Cvp+wub8yiCM+nb*=i170fXGn?agGJ1gkNvjdQ!%eI z3Xia*8OHi11WVszV*i?AV7(Y23OlYvzD}p4`K=G{Rp?rk;f109W{n2_w5A!=Lsn8{ zteYcL%UV3TE*3neHCiuZTUZo2STvzt<@*p+`(~Mr!jCo8ajW{a#9C92B#@0h^&Mj|&-=1lx4vy9Nokame1W*bF`n&Jgq0(W}oC zh_os{tv>?SViPp?t+sIJ3((}3$(s52fkb6f>_#~RfT!L&4@4C#O<@3IT1F@8@J}gS z@{a7?8J)X5>{6$eMpHoo(;*zkQz~1mjI<7eia0H};Hgom+Yg%Tvuch!%@(=xrx?fw zZtR(|bTzg+$2yjsT&eV%^Iv7U@M7&5w`R6!d=aZUDdrJiQ5AlF!O=*yb6RtH zpMhaOt%5n|s9?LTbi=UO{1BLS2+Hr&JH)r5@l^SNMkbF2!-v2*+}+#;A)_7SMt232 zxIeMK#WktT`s7-`liI+ellT!x#PpUy_64#hN#hNuXo|f$DXCiLd^@S@LKNlx8LRiD zJpY|8R;BLxXUJw_BQlSI@t8lyG3t&V+S^5w_cpTnLwu@m#3R_SJD9)7#!4y}?!yMX zfl1)MFFsE-=mo^<=5}8v-k7=Z{e9=e=sDtt#A_&#wj!Ilb&MBz?uWmVR&9!v)pvAC z?FwbUs;mLC>mCPjZ-81>y0e{#5jH{cPv&(a5o0)DoqBQZJZUMZ_x}Q%8Dr*cyYSe+ z!St_l3xcmC>f#coPpf;s^8Wxon_m%{@f``p;jljZ-(~K{qSvo~%c=2C#tmm$)HRO} zT6mvYo5X%N@l467>vvaj?oBJhnry(qr`kYpu%wdX44?)Idv*Q0!Cb0YmUk@1QMDXD zy9@Q3-d=4lOCQeOHD=2!$s?CaSFeh+r)`uMO~G*skT@DZABf^CX1x!U5@?mGoC`NxdIWm-V|oVo~O& zC`Dg&XLgr+`5&ae3GQyZSEk(f>&1Q>)_iy2-3!1vcY!Z|?ex2g>nn{jPqDgd-5qar z>omA%ojlpZ21MH;ouuNvD>cK=!OEUjgv8Uq)UQ@m;HpM5jHJ?2YBF(8SjE0q(?oq9 zSze|u+h*B@4z4ydX-5rF(v+i8FpHC?8A=Je+N8N#Ni_9(-Q4lUulpx>i^10u9Rv2a z@FusT+uTlnr^22t*YEV$E@PAAVQt}?unrgkgUC__Mh7_I#AW^pFON zO{AaNs|5Cc&A;QO8!_pS4C!**k1{MX=pXy z+2=)*;K%Jns`zGa3&fUM?YHeI;k`=NR*qu`G95dAT-IWY$r9tNh57kIX1*Ele5&Va zw-WI8)|Gu>EV8T`vi^E>aXW8&|HJ}GIU;l#tjIv<9-QJ`2m6;`&pg>5&$ z*y{d&ch?x>^c*h)aFsaHt4Aut<+UxNtva-)FEshBC3m9bwYs~Xo?6*g zgk7Z^Jvue1LG^^K8>x4_PnO36;f+#D9Y;~UT~78{@2+0vNN%1awSrQ_8*32|{nSTr z#A9$(;2wm1ZYvE%Vd>CNT(DNYt+bM}ZSMDf-p>C3Bjj*c+U~sZ4sFV9x3pF6^j6tw zwCwckW&8!wd{yJW5`0bY=Y@2+?)3{_5{-Y$w~`@hmQ$gINX6B`SX72y7ja{p?ZL?N zc;|?6ZXBb7#AcOLRN=_KnY|tPSG~)w?H;ECWI4utJY5X3lX8VcQQJtXt6QD>yxM$! zH@e=+==DDk*m$eKch=B&n?lw!d1KVAmOr*a#v<~z!cpNSHdD_>KTl7Zz~AOHFLkN&XuCe_@HjXITa!lrt(7DZY5wwA$6%Mw3l`UT4vMDe(S>`$m4x zz9Y~z=xuMjL7>`6q-!CiPd@8Pi!G&p>V8u5=i42nBwQXk`hG8&Wz;Zv%}kFU4r~Tt z86>TB7d5I^+g_a?ZoknSA;npiSM_c#$trSYIc(FFnoe+9H6)dqlrEn}v_F^6iJk)1 z{vLSC#6A|+Eo5CwN19Yyf`l%iWW<{tMgqKTxQ`8xFdQ=W#~Ok(tr>XTB;#RV%6|6WOyltUE5ofXd);?`ho|*n;;O?1UJDcxH_(o;j<-%Dys%C_=2&M-EzXR*hFnmsu-Xr@XHwrthm?%Ul=4 zwW{XR%av&1@OA1=RH4bt+~oPEO;vKVVBDLgoOEBiRF-m z_-=cvol?RW-2VV-cvn!deK*9~aR7!gM`+({x53Gl-2l$&{GTDrCk#`<(tNY2%k1U1 zEm%Hka$D%-?#s$<`y=&C>n^7}Dy>>7QG!5ahiYj>vCJZXs@5=?cIv$$5qkN zNVPi~T}J0md6ofp_M2OOc?p94)^2a?$JdqiuS-Z^!96)Lt#{bgg4Fx5Z*x=uYjE z$9V#IcXrJg+U7$Z;z%V}jBrLP-NjN^OhhWwii*30wb8B9zP5^cU1|Av6e>Js3Z@np zmWre=zcTovZ5wWXH`?pS`K#l8hwZv8I56Tz=J)TI|M=1-gLJ3l*Fq?W&f>G7_)s;9)i zf?gc)6m4~Psaj}FV*j*DYdc7PGB@ow=r+Yrb+EM+KZ+{P zYu#wyRcEENUv~b6QHfZ5#ZaEGtoflCHqwl&-m6yEy?s@i+k5=Dx;eQr%W^K5$pL$7 zY4t4<_1zjE*g>R?$rvCV@+T*bc+bkw=WVH`t*)*ze{xGsr`^<=jFVPPzLAn&_!Gb6 zzYDJ%@o$HJJhhd@l%^7af!#06(hyh8G7eK4*Oec81P%pqVkyQg>2=fBqkHM+{zt8Y ztmhcDH5T+r`sv%M>Ak%*SNZo^x1RPFvA(qzi68FlrQ|P{AITN0iH*B)kQisCbI(5` zn&G8hjGr4J$*WKUjva0^ds^omFJHEH|zRuczey-a2Pl5bNs(csthYqR)@_2t# zkU^@!x!w?^@f^{@nZw1Br+`Z1JuCSi#cm3oCJ!G$e)5&}UlQ!}`@0|2ei`wUC{18% zPSoboPokGczRzd3N8aDCo*MC2hx}>bt7lIlduxall2L}*BuuG(xb!(6;a|@5XUz+G zuGY7I$o=kDZ=Zgz{sHs1j{Fk?&v4d|sf}ci1quUo<4s>qpq3iV`-iS)&6v1xXwqf9J(@#}^4T&%gEkY`@ErSZPz6wx4ys zU+eB&UYVxPbjl5*xF=)Cr(sZe=0J1#4u2|t?Tt!sSABYa!~XzX>~l|^`meiB_&?X( z>l!wNaj0FwW{zhl23l`1ihy!9$vGr+7{dBvwP>+)sKb&LSM6`>@3*gP9UAr8RplnV zZ~6ZKU$4-*G`<-4f1>KXEZ6Q}v$4=L`<+)(y>ut+b~cb1WH71aow2o0;IaIM3Ruj4 z*1RwnWam1PvPnDZ<>Zy$W!p>XRbleXJh4?;j3BPt{Pynqr+>rdkA&VU)c!Ge=fvL> zHE6D_zqDkPG<`hA!aEHH*#c=+ZifsQMf=GV4jq_uukHT;3Al0@K2=K$mE3IG?Ov4VPkEmr+ncXxK_uj;VU);|XL1|-3nFAl(DS7iO$ zNd97^agJ1uyVQ_-%^PY2OQWIaxw^Wwe_w={<EZLYCru6V7iS4WELN}59@j=iP+_R33nV!-pt zW;OsWI@iN-t_KB)%jjZrECjPUP@99NNlG!t@gLyRb_vyd_nP#_O#M;d)YLh>FGFGfXRg^YPW?z5f8aN>;Md{Ew^0 z=YB2G!^*A?GRg5V>B$JWINP(t!&~cn>Dv4J6YwMUiTIoG7USaAz^{pa9whMP7hliwUM1qpW(GNCc`7b7BQ9QA5Q~jiwSGyelaozd+U`8MHr?;j zcnviTF!;9BFD|Yow9_tsF7Gt!jYjf&%jiYXNv9oHaA03v}_Nu?Mo90y8l3dG0En0S0Y3V1sy5B)OKjO3l6=#>LOsUdk%& zZS77xw`*5-EmU>YXrF#dmg4ig#ZbaYQjF}}rG8kX?By%jN$nLK<)@opPX5h4D^G`d zr^Jc$jRRlQ^^2?628(LeFQwXRFE$1Kqj7Vo7(+Q?F&bp30Y?}W{CmaOmSe>^n#}W> zu%~p?Am+WuEuxZty^>bF(!0C${-oh7E*FNf{{X7x)TJkVT8+7z-c7cy-%BqphuFHm z#(i4%PqneR@E)Nv-9V3cn%$M0RyOnOV>(=YrJRAs$niwPpS$n#SX=|ARaE-KBP}(A z+m^3JxpjVN+vV5nE9Ua8Pm$r|(^~V!%WZf3(s%q%mOdMQd`=z`*Y#V*nk#KTTfLsb zebGrJjiTOOv?3d*ol%-3+)_p)U}1pc75x{V@a=rdE1@M9I@o$@f8Lr=P1)=3by{ll zKO^C;B%_z+HDM>qMzu~v<#z?mCX$kCWqUr_G}_U8+52ex10Ey0xrDpw9{Ydjcit3np2^Vp*Yl~Rxy=1#itoYNjS+qsjZhryY2tb{SUUb zx;F1M&BIS2g5ZgCcQ!tB;Wx#pFi=X)g!%qtBXDI?8zJVu(P^qvm$Qr%V9%(I z4zFwBEk-+NB7^%|QqnKY?c%{2M3-8emN#h&%ETWy2;&TQ{HhKI=D4p3xO%l;t>J1` zrsUh@Q-z}U<&QK|OHD4_m8{=i(JZq8?#1{gM=%AzyiL`IA3LlgemHj zQrB5tD&F%}S9`Z*f6wFU;?+z=O0_-LDLE#+)$ca!lh)DITK?~n4Qkg#*6eOH+r86& zZxXB$Jd!~VoD`E3Z?(Z;(V0)oc?EHr?!i{YVCyRIYCBzgPT$wv=8rcs!r?OvJE2)Q zw|h42uKVlr*Itc1{v-HVJ80fJ@vnjIEfy<{CjQ@4u#$U;8X=?V(llz3q>r77;nA3G z$>*<6(({EJP6C~H%J8WMtd*ZSv-|dceLq9;Y@SlX;;K_|<((<3w(lNUHj;OHXxG|z zUv`bphV*-X7G7wcB9?m%GFdLPXV%qHJDnEKRtM~w(jejEg`EuWuqESC04L@i7Bdx! zsg={ra4}P>O>^=+rs45ZX==HW(W_at=z5q;CKC^vRLgT`DA26kKWSv8PuhHc6;spT zy1HrJDXTYo{NM18;17tPU)rPgfAI#F7K8D#;ML8)#=nN1PA)XxiC+z`WIDfyG%Y^l z2DiD=wRoYPO(#%<8Lg+7BU&(TF>0P74@pp|qP&%^s#2H7 z2W3$!rj(SI*JXSmi^gU3_;)aWrl{umY-KDxME%S~IKE}A<@<{9vWw+%p!Bq=Qk-S^ z_u@S++r#?yp=o7uZfpdi=SXN}@T3vk=z63Js%UdbE+M%Qy|YBvP)R7kv(>(~tR+hm z%Jkmq@K(EeTSn~f-_`W;C{>Op0~+*X-!e@}bIDrCrk$FzPqzO6BzgCLh_r^fNThPa zDV5e=F^aq(?L!=@0Ns`t5&C12YnH7kx9Y#IpWolTy<8R|oTJNo+WlYr4LWSUCVcVY ze+|tEnd7%EZKO~Oi1wEItv1BQ2t0h_IV6xVlk<4$a*Azq@A_@|{mXx?z*dB;z82EI zt^Rs{U5^IwMw@A>O7^dR7=<0u6-Nt_!FX&l9zAkKd*`A2%Ra-?#`8hO*Z#jRHhzhuvPBg=2v?GAV%a*i%Qst9+Npw%owd~)S z_T`6(ZTwMWm#|G8)N>)39U3N#p#YXg&jZwF>BmpSYF19CGvE61KVrkl^0`@CO}4-F z{UNdGwzmucNYVVy^?^t}<#-_ddE>P;Ce_ow_5F4=sN9{J@A>}#U(zR7X5 z2)r>Pl14fVbCI8ar(9Gj&f1)+jW>HoU+cH|en)4gv=$b^c9kun0i_BrHn_2Ql3IJ>L+ zl8-F8ZtR}Tw{0$yNjv`lJ$T2&A6dxdg`qbU3Bqxx3+s$Hyoeeesx!pp$W zNd#Li8g|oeVpNhjt?w;c?3YkVTnw|>!bFf2IgFNO2WuwNjFNZ;s{2@BJ;!NNm$Y71 zYTcjR__NGzjcm{(PW*JRhSz{{3R{hMR+>_Gt>a>?Gx@x+mqDgszL8jk- zwY9*G+I?CVvi`-tXwB8aHS~fjYfDlUByI8)QL)2~z^i7XGQwf&(Vy2X?4qS9-{DFs z@|3z+EnV)NtivtG;wa7$!ClmxqZsntw&wlS8(F)_*)*@M?u;LU9xm~xfc`7^p87BC z9XrIjHMXN2_k;XZscIMcL7Gyf-r~xC=39v_P_OSHc;wnQ4l+3W<38YS3gV2P+vQZ@ z3C>HBwK$~K`!9AXFRx!TeuSf*PaLu4!7;c$^#sA1s41KP-WCDs)g0E+yp=@r2L08*<@jc}2SX;pEhTa{T}PxmwP zeC<<{(odc*RU0qspQ1;KHMplCei`FyN#io>)}hZU%2aP^w7S_-cbrwyNz}T#)BoAF CMeaZV delta 57857 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�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 Date: Tue, 21 Jun 2016 10:46:31 -0400 Subject: [PATCH 12/21] feat: add fatima bio to about page --- harp.json | 8 ++++++++ public/resources/images/bios/fatima.jpg | Bin 0 -> 34729 bytes 2 files changed, 8 insertions(+) create mode 100644 public/resources/images/bios/fatima.jpg diff --git a/harp.json b/harp.json index 2b47dc88c1..69fb7cb9f1 100644 --- a/harp.json +++ b/harp.json @@ -431,6 +431,14 @@ "website": "http://www.syntaxsuccess.com", "bio": "Torgeir (Tor) is a front-end architect with a passion for JavaScript development. He is also an author for angular.io and an active tech blogger.", "type": "Community" + }, + "fatimaremtullah": { + "name": "Fatima Remtullah", + "picture": "/resources/images/bios/fatima.jpg", + "twitter": "amitafr", + "website": "http://www.amitafremtullah.com", + "bio": "Fatima is a Product Designer and Front-End Developer. When she is not nerding out she is probably eating an abundance of cookies.", + "type": "Community" } } } diff --git a/public/resources/images/bios/fatima.jpg b/public/resources/images/bios/fatima.jpg new file mode 100644 index 0000000000000000000000000000000000000000..55486d716eb8f5c6fe5630ee59667ab01d6b4c27 GIT binary patch literal 34729 zcmeFabzD`?_AtB;-CfchB1m^P(jgL}z~Rtvh(k#!ASg(Rh#-O@V9*_sDlJH-(jC$r z?>_L=uiyK-&wcLuyr1W<*E#IjYt~w`X3d(Jz4z={dpH|9o1}W7>|<{O09snWWdH!M z089u8fC@qo@CQJs0rYbi0IVQ1zhDOl=U+T1AP+wP#sDjLxI+ZaVKNX-47Uf+{>qyJ zo`(RQrg{M2Ao_Whw}xB67J}8i% zG9V%-zhqNdoJ#`$HSi2t=Hh%dbhZlMo!8{Hq80!-TLTErQ-JkdB;VO65DMU7VPRoo z;bCLr5#!?E5|b0+;SrKkk&=>=l2Q@lork|p7m0t3A^5ns_yqVw1O!B61OxYLflEdAU+yJKYI6_%J))-*7;E2?_K);s)Zc6syQ{2noYf&yxbcCHg92DZ0kzkXmour5E*jK-0Dkleb`&89Hv5mLh^EjMnF zL@N7SUqe*U#bIRzMcVjJWQ+i=4AG-Cy7*k z?#Vj151bsd(+TuO2FmYsaa0j_1&W~4muaNaQ8mzfS9NGO12UmCj}-M2 zUS&wQ`w{M<<8n(B#MSM2L7;{q#$SRK zQBzhu0-Cxy)0P809#=@|L$1Cy9lVEzB~@{k@EM`YTo#3JLv?Ljl!hs8#^jZt-5Yc< zJMVM#*MF4U`9h6x^Xr7_C+DEuy}XR99Xy%hN6VK_Ftps3yIassaLtakO%BS6w{wCP zdfv&Si3p$urWk*;#pgv0RzSus^B&$Fzt4eB9N>FghZ30Gn4lVx#DxKFoYqmO%UkYD6`?~a8lrJ`5tR#k< zXf9%gh?+`sH#B*3o=!$~EXB?bSFW!GGN$q1@ODeTTG(f8g4}8~7C4mUfD2`63R*-j zR8<7EV=ci7S>3HZeX;sZ_sbUbf^FqPEH3X@TG0ph0P2+k8*j7c~PZy@&QE_yodG)%hWv>_9#5x#BI8Gr)7GG}Vhx^;3TK_Hl&r z-PkQZ^&NWI=Ve`*ktR!$3mFBsiOZ5JOHPa}Vs14~Pl&0s9acWFyOL$P&~xo;;}Y4d z>CzSW@aB*x^+N*3l+(xb14qvJr^ywQuQ?w+S?k~~uCI#R;1QY;g$I|1KYbh$-_c<} z`BfcXN;>;svX=Q7RP)8&~^U#+EzR63U zH@6-snmaLuKwyB4j;rxpjYD`z2}PAfs#M_4JS}kvo%TCQUlWrz7mQbIxbegM{6-U^;GGMGeA(UKu9VUZ5i#D z#6q&c0$34{EnSlhzNR@)mr)zOl_*dOCK;*aH6s*Eu-zj-;pwDEgnADvBc z4Ac~peq-?r81KPx4Sb7u9IlnB(5zL~H!$#3=0O2`k70Zp9BoVHs@Wqy^h%xaYpQQ~ zl~g=*99{D{9uz(P49y(2k?lXmkp4W=zf{>N2wC%ZZ@a^t-2>H&)^nwQxji&RQ^mS` z2IxQIa;(k0M^miD`|Qz(I$LJxSGGLgu{G(_6Pc9QO^E>m=Wkl2MX#XSrSV^b^2WU@ z?L09e3d@8G22%rXe<-es(JAf6NydGPCS|BTG!H5NPD4|Z4XvB#RXNPh6;ke#h>FQ@ z(bA-Ub3(pd9RNSo`O$X<%+y#RYSW&jczla!`#vI4HR%~#rWpM#zt5!fNc!~YSEV*s ziQ(>;oX3ls+;AWjar%x@b7?-abXSz*c_iJNqG19%2JQ68Q~WdFU_;6dpC@sG^21^h zm9b>rr_55^&H-Ed_(ni zI&OY%{SnWRx+Dg>pR;9@Y>IZwJ8n>b7V%A4=|xX722a2o7ROTunZz{m;6_4opT|F% zeMV0-Fkxj)Mds<X23?NB4-24J99FJh z>rF~azH=HGhy(dF{1U*}*x-7rv>BkKNf)>K zR-B*cYVZ#mgp7RkH%4BIcy6@(3jQ0Cvcj-LuvH~YUd)gx{xZm}Rw6ge7OjK2$cN7B2D{emfB@R<> zJn8cWgbHJq)xt{alry^a9?KQKnvxsO(0DVl5}9U4Y<@?_9_Mkum#5zGfesiJPf0XN zB^Godo}n2|O9`E#7}gs-QW`GrmdU4~`^tCQa*sN!u9d)p`wXZb`JCPjgpBwc#THNv zSU?RM@L=Q^F+5Sqyd#8Z!4~xCWvU9Z)_xLSl!Wm6#=5gUXy!(=dyC&~wL?pbZ>{br ze>Xie3gOvt5N_ySv)Lj%1A^gIpI)(2dAwX8YQ9Jh(H8NC%V@OMNHrWX6sCeoOq90OEGcAY0eM>ej_$XIJs z=t?S2HJVaUna#6}KA|bTQaEbHV{0k9qpfE%PnD{Dmy|j!0#55vdL`u2dkOB`op%Ke z&ez4$>`F-RW9NzrGjcp#c5Ax4i?SpSmq{}aIo>m)adBpmqco^t;~vd#tF1+kNuL#; z3VRAoid1Wre%*2dWJboL=aYz6{YIP}W#ekDSD5TpfAcz-Z46Kwr!gt+8(ujB_|>e@ zl;p;ijOy<^tW6en4)Geew^)Kv;>zfEUE^|rQ1Xj8)D}3-RtDm(RKJJWrxN<>_AVpQ z_dd5bJIafQcWsaq+{PFbTVSW|o~U~M0T+vxmzQ2c@a;B3A@org3_6COG-?m|PU|hc z=7dq&VLN}+mlV+vYB#+wEra7{lbdbcD~ra@tQz+4`@W_3-DmsgEHn#sH#S$=7KWZ0 z!{%zDqfeg+b)8~l>_l>KP~xN%YM3|{T{4y&8SNKoRA*|Je8W`D`*iPdAHFN&#GhelaX!#%v~`~s9|Wvtt`EEk}?ff(&tFCrtA z!^10AWZutjdHdzu;9eRU{p`N?0}!?A)p@;Ir*Q_b7umJ@EjE`m>b!;8y8%Lc4C_x+ z_f^gSE<{qF6@RX?r+}44h*Hw=eD$JV!ra?D-eKHttN6JyC|C%0tbI=N*txhvW?EaP zbxVd`$O_A+u15-reE{X97y^SUUgkSNXMIbMh|%?H<$kK4<*N$ZE!B%?Cf~(j@0I58 zdPSkA8y|?Pvdu(M$viMv8nzvM@G-xq;Mm6@Yu?GpOLyjpolMUD%R|+Lj#xZypSvns zECrZ!dxiBUS6{B|o{&F{c4}>nXz-12^m@+yLO-Yhw&_=izzn@#9^ zaZ7~L8PHmZGit}~Qo(;JE*5f{yHk7y$Z$nsu{u!CXN^sh4{LPY4SYj^=*$`wNmhsd zC@KAT{N+peX~c&B$}+;0<>3>(+uu&u1kEBE@W=*&ysC@n$G5m#`aTkUu#Pu+9efeoliQn#D_IIMX`<=-GM+_-3ba2z2iuOAJ-8j>7Hqr{Om;cMZFgtDe@7ke>C$;7WF`#Q^U83z}v}@ zHd;c^l!pYUy2B*uhxqq(tvV>|d}(#2ii=)ojoV_FnXtyuo&mOdWY1Uuj(3G}ZE}dE z&Z46$B17KNGZksVc<&YE9}jC~(Qs%{csYKbGOpK%zUzDZ#FVuh!JumP%1EXIUI4TX z*S2eslc*ed8;|#lZ3;OUr{vc5?lTVW zGBf4Y7o>FrBpOYh+!$h5Gdj^s8}Hl?>ly#(K%iVk-R@k>$@jpuj>@!AHo?xeTU|$Z zC$hJgV(v?cMBJ5ETT7)~1h&Pb?6|(|{@XB=4d5x4>Ie2$&N;#om*$7)AdD=Hm z>&^yx+P=8(uzg|3lxdr*KLZc}%mXnUCO%){)dgiEqHP?vHqk#vz0I|Qa_1;25%!4b z9BL3>mNc1rmUvSoTxEdDwW)J9H74x%`dUiwQa0U*DreZ@p}+wUXy-c$&NT$LBg*K- zYKMIzM&HM*n^E36T=?#865W*e@jh%_=7F=OEI6yJTrEE3k)*xzH8dS&VcR8aS8b|;2YvJw{EexZZ%eRTOsVntS9QpgX2=P(v2=zM%fTu zMdl;IdE2y=!n(bttPvgI`RZvq_=(m|Cgz^U8PJKkY25eq`^pl-eD&#(ySkq3$zbRH z;TdqWAG+t%7ufSk@?k~5c-||zkgYop_9Z@^0YUEQ1B1qoANO%?6=h4;$r@1nI4nt+ zn-zcNd;Ro9PPuTs%vWi=cO%lX&&U>cA31uhoVsLYn8fNtWC;)`S9fZ7P&bq&iWHjI z%WB1hY}Xa*mzwOpnF+Y1*-f9Q^tN)cVz+WkINI$1zeR2-O9S5s7i-9PuF5CePx1^f z;dGJemyV3=lejNVC2G_ZCcHZAJX%u^soQq8-1AG$RMjUR)GLgi6R2s(l5WV|^(*(Q zd-r}PF7kdz0HQ#AF!13R%2(RKVVs_Gv8 z^s=OTvAO1}cJxtAu2SI-3m#|KWh^QP2)K14_j^_w^W#vij0?>#mOm zj+SYv4p*Fx*B$ThFP{dDLQlba=&OKM^2_SSD|0*=lAzb%m~ z5vLChuW|X0h%jwNc30neO>oU5X<%lmHhF|@Nj!axEyGcJdRwthOjw3;D=JMUXeb}Q zS`}=zOa|8D>(H8o=EQ~FT#XJ`fZ39_%PAFC;2x^LdVB`dqo6JvmMT zN`_0`gS{W4bz6zw(!NAh?+Y#laE|;KKOP@D1H!lUZMzXZY4g7GCEz^Z3{c7$tH!94 zewA|+dElM4wyX}Pn<+UQeHM;OZfx0pIga#KU@kPn zi!#l3baqXvuE~U)V#Yk}J~eGyIs?9@ZL_$>5YC%z%TAsF`DcIwDWuPsCi~XY;I`U0D0N}d1gDVO;o(NY@1eioF zX#lz&2m>oP-07S{-30-Ixp+Dw2}l@uR&;VlrU}pU8rb_FITY*>$UI2$g-n>cwxu)7 zP}$fJL|qhikwMoT4!1FYAv|4mtQ?>q5f9J>+yOZFvjG?Z0{{jf08hXbDGI=G{lyKY z&c!G=Azc2_2+zvX-U(svaxN02W1n*?YME$USVIyi0)+>R{;n~}Z#C9&McBh#JU}`n zl2g$Y;qtQ*U?r{Ge3k;PgNF6x^*1ue%^r zSoEEcZTl-II9W6PJG{P!6XG1N>*FNnUjLIH#|s8Uz}=NB5thgroGYnotLyQzS0G^| zFL*|(4QRq_F2wvxv4-GE*1s#(0P1vs*L8==nII*c2O_9D-1UYX3~XGmhuXW?{xlx} zlAsUjqyR@C;Lc8P7u&zG;Qgc^Rrn2${}ZooZ)^8E0rw{X)a@5Pa;%`PUg!Y10-nKD zjGyQ8am0R3BlxRO@FaT|xae>A=Q!lrp6NN~rC(|KbE#YBY3%bDj3DQ^z;!=l!1-&C zfF1Uncjp|d23)nV0Vz&k46f3F0rD5-<+J2p7=d%VDH#9c5kAKtd;VXTbD8^K8bFS$ zvws^<7m(zCOFH}iLOZtwQZ!gM0CJu}u8RWatBDtu<2z5IKrX0Ay^)$D``WoR(6G)i ze~n@kIS>sVe_5R#3H>IE8ks~@2cwI+Ba;B|6+G6#0|&ScxPVs}d+=}quQk>H55N!N z{~CNC^mq6jhs=wV@sIF3!%qSc2>gY2@pM975s{U}u!4KKSbO}-NQWYjMI$>5fE*sb z`XHG8mp%+A{N2~j)zJUDDpH7!fRwItjss=jTY4hksxTLryCni<4I%(TU)P_v37iXNBnC-Q zceZ5&Pye^;kLu~}^pBejfHeL;Fbq_T|EzO^o zJglGSe=uX)!QJo3JK5X*v=re*<<)+o!J1=Q!)z=)&o9B)UNCpWzhO7}iT)=$u9dAK z+zIafn{kORAK!pKz5#!H1OE61{J-`MIDaqC1ipC(0CVtwAYa520`lNe7aXtxm%JFk z1$R3TMu3OMIphj*Q2uW?7y(7_#|Q`jeBgrF#RB7bNf)bZm;f4B5cqdCNf2#^K)6a= zz3Sq@Yl-}pkrxVgzUpJ?dX=A-?*Hz(b%Y@ptzh69lQi>>>N;jdduwUt8^T(A zTCR#PJA1V|?l6Np+J?|Oj!9F;0n4YLYf)W^r8yRuD`_oTU-6csHOFvS)HAc z1~?b%fl&4WOZiWY;DKCIx~dQJfP1<_Vai@G7X-`C?5;mQJpK0~ev!{x^JgY&=r3+p za4GKGJl4>wFejKZDBA<%8mf^9hRC2#7$1&-DWHE5V_j zNOK_bU-VsTI24re%cK%8D8Go9kQkIlR7^;eho4_moX1ko1{4Vsvb5q8w}Qc}U_Yf@ zEXP_p{Vo-$l{F|)SXe~VN{CO4$5Kcf)XK^dhSbW6M?`?nQp`%&(n{FchMDp2a?h6& zwcysEbp?ONt1Bvk&NVjnP9VVpbWCAXS5_3^7Z(AI&&$uuXbqLHfxA0fg1yb&+0qtv z)xi~Ji|qWM9$^;Di_Wf%(8Nl5Bf}HFb&-nH!W_5aJjP&-Q( zTNrr7y~>QN(N*NN>7seA{%gzq-A8`*GkI_XAludBFIy;B+WxYNjF5n$lCqKjKfkgF zpMs*8Fh9Sbl9Gy&fFQr3inyq%kokE9 z|8xFhfj<`bV}U;w_+x=T7Wn^>1^%8}!d$?|8*gytcs7M+3_ix**45WhQP)&HpAO@x zY1+HMQHTJ*8T7?QKGzzXm@;B^g07m_pw}qqlxYd|aMdzUF$5>Z0Qk(yh=Hoo{6EZ?g(&dt_$)DT7$Dh5Do=lCvSu+5|8w-BeQZu!YD}J zIx=@qK@g@w!nPMM(l?pR>H?NS!q(0%pfe^4QfF6dXKN(<34|Ybc_N)OQ8ht0%*!6; z4Z?jO%zVZtM9r0AR{M~ixHe0i!rLfyq#bO1dlE_;kR_R2B+iBu9hyo0B})fWG;Z@ ze@raS(HGHwB>u+tpFm{WUeLGn&f5$^(eXF#@0@?*;IBaMM$iKrHTG|u)iVGnzYhRZ zBY)#q)4?|@p#V_U^;>-?kp1Pimj(7PC@<2Wzrz2P;TPxs8u+a|USxT{CS{CD7w)Ev z$X*Qv-A6s$89l)FEigu&f9=Ho#~FW9>o+~F=)-Ja?l5q6z-R>aGSFooY;G58d*l?4 z(ca}BQ^(&V{2ylfO#%|U=+_`X`uY?gyUhy_b&&z6s~rFuDK3C|^94wO{AxE%Y$Na$ z7y#U0n7`=vAPmya<9|dbF<=tK!~Wcb8Bo+WWQ2OUdtI=gAy4R_KRF>l23!K@0TzH0 z^d%PnL;*=a4p0WJ0Xl#oU;^9%px{e3XYd;rZ@?e82ZVthv9Z7tAQ?ylUITA|JfH|D z2R;A|Koigo`k40vqre0(3oL{F>bt-ZxC0d?1Rp{QxddT=utB&X0uV8X3`7~C3DJj` zKrA4(5EqCi#2*p@iG;*Mk|8f4Zy|+{N=O5w719kEhD<^hA)Amx6jT&E6fzV#6n2!W zC}Jq`C>kh+DCQ`(C~hcsP(o3nQIb$zq2!>Hp){bhqx7Rppe&>8fE$G2qEetTq4J=L zp(>*4pqirEpt_?5qDG)5qP{}SL#;w>M(stNKwUvSK*K;IMPo$cL6byNL%WU!MRP+7 zM0)7^L zdoX7)_pxxX7_bDeRIp63T(E+%60zQ4)nfHv&0`&56JfJqOJM6@TVwlT$6&w4uEOrZ zp2a@GA;#grk;XB^alpBUlZ2Cp^BHFhXA2h>ml;SPXNkz~1Kon-6e zB;-QmM&v%^DdaWe6BMWv>=f!0P82Z|MHB-Rhm>@b@{};jhm?7gJ(PP?G*og_FscZu ze5!t`!%K{plrK46in~;P=^Hf~^<`>3YH#Wn)SszWXvk7LPjq+6kBjkrvyTgdON`5rE0yc(Wt7Xp zm+da6T<+pV;TGYx=T7DBzJh*5{EEw!S62pk@Ob2Tym;R8O!89jYVrp2mh-M%WxZ;8 zHSTKj)l)uUJ}17{e53p%{MYz{`K$Oh1uhFf1yTh11n~t`1cL-C1UH1ZgVI7CCFVEV+4kE_ny} z9Qic`J_UD$QiVN53B>@#dL>jPRiy}}PGu71>&nT>-&L4ZY*pT?tg8yE`l;5dp{r@A z#iR=)6TKF2?UM$chJi-1#+2q|O?S;IEflS5T938HwAr*>w99n>9d(_@ zI^T3Tblr5T^)U2w^-}ca^!fGu^_vYy4Q?B}GuSm$FpM!Az0P^v^LnEZq0vpFw?=z6 zly1b|m@vL-9AMmTLTzGiQelc|YGj&ax?`qn_QY)VrtrS@k;U9_crn__96Ch@#*lr?EBDn z{*KC>Og}U~s9&Q$lm9*c$pHC)mw}K#tH8z}mY~p}*}JND-`vBw=Xmc+Fkf(d@OH?J zkg8C+(7U12_f_w|4_9zTLUYK!8J zN{Tv*wu$bH5s7&bixKM*I}j%u_a>e={!aY#W39(!35*F53ENL@KWR-AN=$o-^VIX{ zM3QDw#WU7tvCoc^?UMUb6jJh^(>{Ord@t2HwdaN0i@Y?tw8*r>bo=z7m#QzzUa`MQ z%)rR-%9wj?^tw4yEc0y^byj57Nw!PfuLpWceTefy5~UCeuw_nz+;b8hB*%~i^+ z$m7X-nNN`)SpXDx7AzH76b=+=6g3u$73Y<(l{_ycEsZFHl=+sem)n(3RG3tBS6-`Z ztdguMt>&%H{=oDhrG~sFrWU6*wDzp-PTfwuYyC=tZNqfq?Z(lM#vl7W>3!<_tns;} zNu}vyvwU-1i*(C}R*BZiHnFzyc9Hh74&jc{FT!6+J4HInxXz!R?UC(i z=vC@%>QnD)@7M0{9=JX*G&EM|8}1utn~%0GZDnr@Z8z@d?tI^M-aXoj*uS*@=0NPA`S8Z!{E_!D z=5f*q*Gbi>#_8CZGx(j{8o+eE(gd!ofdSl3lL!?B^^A3d@3R$s{g}nE*p{CTz&=CQ6b>I zkQduregeLLk2a{t{Vgw41!Gij$4U$cCV&NQBKkWXBtek7Tb}Q0i3UMKfuMnOBo>r_ zMoh$njzPl6Pm0M*Ccr1JK*1tN&dLrJ1nxhH0#+Co4I3R~1|BX^(_Aiam& z0h6df--?B-8{B>JRZ(M)pb!T1acIK&A8d$Hw`_hy9SuoJ7+pwZuUJ>qP(IqX`%y^m9@6)-XOrz%RC@+2# z=zF=xRPLEJPnN_G%+=zPqr7`D9=;ZlA~wDdAVGNVv3yl!G%8Kct-o7)#aUg+Bj&{7c zO!=+tD9yBs?k)MDiiX+%EaRD-wV?ica=V9Z*$;=5(PZ9gJx`qJ4%Q0v?R9pr>{6S} z`)+9S2C755+7RV2lyegAihd>R!0BMeTVk0Vx99HbmXP>~q+m~WI$dF&^z7`3t>G0x zdRIFq&yj|-9<{XROYeo7hl_9ByZQ0W$L;Cz`QeIJnAGOa9q-k<+-|#jPoGMiAY3o? zT}QKa2oE=l^42?3-`eLaqOk+gw>gR*7W)>~iJ<1E*oS?Y%~%Vx7g5d&hqUIs0!pt< zsAptJ7~*}IA9B$yHZ-m1vaPXsoG{?-=TUrh8-rjW7#^PHwXs$(&`d|rcTYmCu&E;4 zChPt^BP?wE?R|RB4+9?F8Zs%A8ZhWcAF$_tlyRr8M2gC6tFu;#-lqHz_j&hRcC87) z8h3|qX}juuBK=ru!Q1#9%QJ&^79t)re(G(A*@HF70M)1F+7fcUZwK<`Y3ig!lD3`t z10T=vkcInu&`dfCL!%SdRB(Hi6|nFtY|&>Mqfv%?{ZwNQ#c8_M`aB$Bu3mS1$NhX< zTZnpVofXrzdh>gwZTNT0-d3N~GH*)`s#49z4|qJptFMe0Mo1hCDZX0x>=?;QumF8` z;8cVlH_ofQqg6Q(H@YmH6214@LPF3nJLaiK<>Je>E=GG-8T2)$g0Fq7-)~3Oikq2V zvb*D>k{8aKKKtsx?p>xaeYAi14H2T+@U}Xojc+}VRBeP#Xsc$NHhSErWJ5DMsM@GH z6SL!{e^5}jC59B=k8;E1c3UDa&3y6ha&>QVZ{W2QS((L(OEBR>(Xa;tg!#0*h2VBG z@0wLJlPF*TYC}Ev!jI-Qg|tMg8BBNt%oL7Mm9$M3e{*>_I!Wv`cWK|<+d zA}6St?)Oq*CpqMc1kmrbs>CBI2ispP%w-h&b!D#IkkH8BuXW&VJ-F2$uOTR17MRjI zZz?7sqs_GGPc~%1%uN2Vv-(wgHas#ZQ~gDrL*R>>O_5sB$vHwy{BW*X6Bh6)~q+Sg5i5XjwotgehGaw!vJzPt?TWrBL% z!=C~wYwhJfgnS9$f4I~RUevK5;1}cQKwIa1;CV1l8;yOcf1E^c@Tle_Ug)4T(eu^K zhjJM!L?)`=Xw!*?$?u11-^a)&x$&u12+D+y(p10l!}c&NTxYE~55b0)CCF{@;qf&# zqMBG&rF4Oq4PRvv*B)JY7+OG6Ccb(jM2LBXLzA-8fc;yZiMENBxLm@Iso7AXZDCqQ zBVA=QBfW1z%yQb_q=5%|t-%CIw?-JI^h^{3Fz#mOq#GH;q_Y&c>G)zzAFn28#SVUXm8HOkp?PwwTh+IXLyvh~YUYjZb*1|B<>Pf_$!#BS6=vqGo5G-)QioXmREX!WnXD0IbmTeWDyi9(J`JW!fQ zz4VUC_v0V*F$-}n5p#8-!>r#lq1ARY;Sy_cJ|U{7CaztQ^{IJoP>Mx|BM~}FSp{{E zZqo^}qK$0yB2`htVvL?uddW4)L08{rr)Sd3%~ehG${u@^i!OmK!L=Z{BTEn$>kcz^ zrkaR{?vCVG&W{X;mL*%P&qG(uW;tC~O-?if=Zc{NfAGYM9xVG?Y#6DgjWhc##tKsT zv@9$N2MS?wWM$7$rJobr6tdF`MWJq)oI!~~e~#I4jgY$|eJfr06N;Mg5H%r`47j*oGVOc%%GLy4VUxkUv3tDeYf_*{i{Jp~1+s|jR| zRH}$o1txr~@4m$HN@J-6DY*m7)I#~JI0-96dVWCK+QtH>JfUo<>^eX zKckUx57mg>!ER&0dTYHYW}@k$EiG=+OKoWjxweWDJ~m0qafDv`3~S=O01y`CvLVXw zmCgD}C`>CR4x!b$iZY^KQDWb7YKi=dfVaiZ3 zFpDvgP2UV|#9^t$VG<9$i__Q`uZtRig-$BeYPMKbVZ0rW;wDc<#?WFZKKe9ap3E$i zEWh(EyC|m87`}*EkQ!H5JJ;Kn*BzMX5?d#j z7-A#%u0i-K*+T6%GSZgBtcgQO4K5Xk-BPw*Fv#?{gxY%hd^CYun4<%YO_`!{t`QB! zy|`HTYP|t`(F?`cc`bIv#;OMCUzwwynaEwSf0BTqXMaoWNt8fLwaV&_ty}~(^yVG2 zOY(2-ht9!>9>_84a#dLpzx=x3iM1R>JvHLG492>ABxk~hUrz#0U?fUsBUZ0qtX#)nw9-F`c}HGg;1^Uj$9vJ<%`qB zJakCtWWvDPYi`}M=p4m$k9D`{Q0VWby%f_E#d1oXnJZmT!U&zbgrVN5)1#lZ_U$Xp z9k+$1a8)9;Z;(nCQX@StviMmj_8X3)`YY70)fs5<4RZ zi%M}zGm#zFJl30NT9s9~oP0LR#n<2fZ-%72r3uEEmWvM8?a_1#TQJOTl@~D_48>Be z=jbHvrD1w`t4$6|u?K-eRX~JeJ7GuB4l8?RW;Y17A?J};!p8zt`8T?%GuI%JBi_LQ zG|Nw(B=lC{V!f4)UQEAB{FSMw(?CU2Z@(m+tgD`*`~LkHmF1&ySE0+dof{cryR$}I z$_=MD(}^#)Zw5#@1{W9+$ypLw8$L+)f>#b+7NMkggc9tx{;+G?%Z%|ZXAtR2{a5#f zv)zkx)d~ngC)9a$GT_>WFi|X)m-7XQ8lG5)f;76eYmdCP9jcr`vMv=`HaYhuqQ&fv z$3lzTeTcEKGD)tq%3QW2H&>?rWS(Ce8%dTI#0#-0mpcINtki0jB~?-~L-ah2cLwHj z|1JfQ_9LjRt6WE|E~ zVOL0#r9o?sqv9z~yPA=r|4lV#b&V|k&$C{+W8c`|5rMz}?8rZ>(v6uMpvjyU%zalB|iw*3L;zA|?#vFSJToQy#_N*pnghzls-> zaQo3?=|>3%zG{P^`$4mpP-E;))KMQ4D`*H0;VJCRn%rB}A^=VuYW(pF1gdR)vKs|o ztm=;!@ziwPKMHK%U8ei^WRhp&c{cG-MeBYw|K)D!_|46c2sIP3AghhIx{jLMxE_Y& z=9HOOixOW9(I)ST2TMfUEfZuqkRpq+u^=|%mp-n(y!kgnwTYMl9`EAOx##TuxE&yq z(r)T3o7ZX{lG%C->vjAkQ+c@Vs>tCuF9TWOre-3hIv!zEchh(w*Hf`JYo`@I&G^di zyyAiWnx7u>NLb=y4qZu@?f<@crE;7$tm~8NG_Gn=vLOSLbVgCb;J&wpck2A%59Q2H z{Q<81G}JU!)wdbo%LP`iKT*}k)fsrnjxF~j**yI2M9IeRBdYaT9wNBRGO?qU52dl2 z_5S8lp_T@2v8HQ#Vv{N-GvDNKX9yX?@Gu^S)x2LN80CPjq~hlHE`Lyk&fl45^Lwp*&}isp+y5i zDqq#1YSALkCN}s#pbQzaIx1>@iAtl93iN6bpr(XZ`K%T99F{Y+dq^i@bP@93^1eRh zvoJ{lK0#@m%s-B{^;)A}T5S^jHn}oDDMtTv(9zs+Xs#1tYn^Zg6b>deqkiACUPpm5 zM2toAsjjWuBl`Ff{5J?jtLAwQg=~pZ?LlPiGB&lWut!%5`A(yD0+Nk<#96I-%rnjP zrc8$qS~+Swo^9qkbP4d@sJjv^YpxHzF}YIH(tkha_{C=TXl8_rHulPX@!aOq=EmlS zVYW?H5po)RN|^N?#2XIQ-KA!}o0uenkzX3CgOgFyik$qVS<+QTQpv_r=3q(hhiVv| zwRur3$Lek-%G*AOd}K6(NQBN;wiP0lx6Jz-S^9RnV&aMB{rU@9`;#m3!03l zJM^STjDhNAKjy=S(=0MPMN@mQ&top`0+CWNqqH9}FLmepr}BRGBhnIdD&v+<{MKv? zyD>Urkyz(4L&F*`7ETdd`?{Dd@AZWLU0&OOXkv{=>`>qgh)_i(5{DkwN?xD#cPFO@ z@>J`m_^G0r)*WvSR#ZRQ+_d9|Uh%(GFBWo3HL&Df zp3~LK1{?|6&~PeR>q2QC#KN;4b#fg0L`Q+`0#XiH`^in)R{=lRL z-`H;JdKP{uY4TC&s~2YE(-GR1_avV@X)kJS+w4~D-sg1K;5)66bQABYOcZJUH0Lgo zgef&OJEdl++59{P?c}=AH9D*658)$^CF+=uRueNFq@o_YL9};kaw)Mym$HyOSGLtL zYo1Ji?fA5bP@vj8ZZr;$DPHo;97_ja=>6h|!^o(TNmZ`0{-FzcuMxd~c zvR+1zvMIeKSiwK!t{+1=hu7so(^9r)SoKjKyP`5%np&CeIN#zAbI2#rxi)Pk`-O(_ z$u6B)o_kD$Bt?d;we?f3O%j364K!-Y$Cfj`3+uRY9|0SE6#-F zU8Pj-I+-V@?n_9nNUf4O@ZJc?H_{;_-qF$-T8%s6JH73SvIf07&GkhiKYmoo@t!b& z!+XUmxhxv21p3hSlFde(?Is!<-LI`d4tuvVI~zHdD9q2mykfjjvKQzqG*6^$@p&6!zu^PBMfb2+-;#0~b?>`DB_Y|B z`aS7_1PA>)l?>jH=u(FZK1#X(5el;40)XB z5I1$oXQ^9aAEH>^B+h;*k^~!pAPTInR!`dEKs~zslT3u%PGh8SpZ6x&{3X z!;7o;qTzzH8UD9r_%IXiK-Bw`?@`GSOnmqi1OMDtnspH(g2cloBmrL|BzJ)5uxd-Nhi2R57H z@{Otm`Wz^r6Wk}rr@Ks~KOf4I5g-tLxlZFb?)JfqgU5sZ*@C5kxZreldLHUN+Sk** zG4ze6>ZMgL&{x17_ z|MAN-f)$RGQ*JHZ6Xw;1yA!zvNi**S2+G@P2Bv2AyD4cVS$w&tW1MfPr16{Ph}nBT z$fILgmhxk^v)e3}?uy0XF3CpLG86=Q7>M4U{a zwyPR>A|AnZw+4qe&D$ljXlUUIk)JoB4d3S2BxAH*Mi5ZxW@rYYEta*zh4XgP4Cz~k zz4yyUXHRbgWnN4J&x^%<0GIqBlg-^euG2Wj(ZeaQRiUTsHTkAB`FkUeqP$8!WwJ=5 zE)xUyNba+Dddi+|xQe$BI9%h{U7ttLzC77V7H)WoP!6s!(5{+#gh}kLpN%@V z+i=;n@PpNTvTglLuiY}PT|W#g-IogZem99eUv?JPn7xlf#(R5ZclQca)?>L5YRg7F?u;Afp;Y~zUjo<_&swD4Hs-B>k9z<95va0PC0`DG& z+hsj+R=gblbTc8}d^IZIxns2nN>T$wGT&?K=KWOD>ONkRnMB2kcyaWkf(94aVv$$* zyN~(U=WAZ5B=MtJS~g7>_wt=yDxfQ+vH45|2-c#(G~8@hn0fr&MAPR~bX`k-1h(O` zkaCc*56^17K}jq`v%Rlk62f%}V!_{HM9w94bLtM?D;3I{viQt}Mr{920M-~O=f{i^ z1-RH!>Xk}^jltnpwXwsdiF0xV??&Cl;@MuUYmN+ZuK6x~L)BLT-GB=7_xps~M0_RA zEpMWuyxxj2a{Z*6xi~zeLYM5ts7Jiz=#ZRQqH;(cpPr*{zsDQME}{F3J8elUE}Mw6 zTt;72){3^G7T1Y|q#a}F3cOMR-V^xU1aLJG(dLrf_fw=T&O}=t+F2Uxo3x+R6!Id`zwhX48g1XNP4;*>UQm10jFIRtDBMnt0MrEsI}Sz3e+F6pso4ev$>L zEG*i`8aU^}g%alMF$0L}tgJ8H98X>xD)N9&1sMv%uo(*1D+^x*IUd?18!5?#RFdu7yf+?Z)yeYRc#o=j>OJn%>xu9q zDI$<~ko^`PrA;If0XpByHnz3mt@XO0BD5X~D^{yuEJtlaq?6wPyC^8gH?ZEWYe^)C*6G69 zx~f}tdns%!V{2895uI_hYClArYQX3!;D+=X^E}Iy79!cvE;2R)ixa}N$N_RaRd18- zTUXW1cME`1j7WYX(8uAR@`sX12`Zd1 zBg2I*>rsARIas-b910v3QT5ZNmDGohKp9wMK^Fv3bp}9jwnU5KDmHK!;$tTk0OwFE zo9c(Udi3F1nAobK$WIcaiUg6O)&!hyO4q%?85&RlzM(^;i~2#UT(!mZ5lG{S(!;60 z15~LEywoiql&e^_y9-?EwZN+YO96nrfuI^Y7P)c_z&F5psDvX??t*w;l!-x! zE+iJdrUt-@RUSSAEKf}bwZdS8@##LAz_ke(90AQxbl00Tw>-hcAhapy&jx%q~aSB)mx=uWRL9O;c!l-HD$rg zk$Oe*Be7^GISS6KPB){sgpJuDdffhvH$C4+{{U6HIyS)Ou#DRrwV%R6sLCTI5B5Au2K&Dfc ztm$PKuD+=q>P#aqGQ3u+&K>(MSoumYT1|?tgSv6~?)i@;oGp2hw`jX&(C9$|JViNIuo_ zC*mWgNV%Z|OZHJFgkBmzwM)z6+rt_(%Q6yyP8p$L-YCbtpNgZ}Jco206{Oa-vz)-` zU#&{G2e)-j1E^7r`C*pX7|x=4@UJ3GTW!%6@?{pe=mxHt91TR9rFnM6)K45n(iQr+ z9`$VbpDmwul0rkmCC36WR@9)^bdJg@c#7n6gN~q>^oJ^GkhPAcu*B4AR28uAbQF1hD*DB%oRDv5E)V4jN#G@f3M|B1qQKXlS4xa= z%+n$rF(Dy(Fyd=!oT^D>+{g!*rEEOiR?@5v3#YxRrse$3HIjX~AWSW+FvA8F7?F!G zBwX808WbU zV|&=wFJ~7kKVAU1BK0qprK8n}zC^B78D%#X#2hVH+X5)!4@Ce+0txLD;@Ijn>-SK( z$puGJ#L&ORdwS@QYzPM)+ES#OfHCW8n5zM48vJpu81+@P*mYL+4~l;-AbPK; z`vq-$zZULEw+=>UQ|Mn%T4+}>ncylRIvEwswVXnpk_|}ez!JPTbPC)n;P?+-AkzRW z#`ui8da2};>tGIa80CBqT`W6&^w7l#)e@r+6z7NFt()##&A2eBl1BK$49{&CT=-Af z9+l|yWma6(hh7Ge&S|<(aN%V&ASX$EE`S_J(ke5Uu*RDA%pYwM1;(7|K{?utHU*mO ztayqSH)|W)uvR$t&AnBXu{n0o9W=xMN}CJz(FVbVuZ9-AMRRM|iw=WZulUWE$S;ja z4xmymvqBGwNAZ4Y*2n{P+qAH_=qmb$v8p}kcDZ}Yr|6srwp6poo_@{$0EfJZNn7+f zixV8P%Y=cmdOSehW{;CeX0Th1JwICl2!S&NyF<66@41fpcrHmF5A-)(8 z1}4-y54ccbFxJ3driKGE@1faJgKri!-R|51NbRV|IAL#IHMy+fG z1}3B0Y;HMb$goG_EQiM_{hH=m2gU*;oex8sp&pf{hzqT)emAS_-J)T8jM0x;91SuZ zyelpMZW1jHEqrhz#d=}5kjSboWHuM|Qx#$m3{CKr-@Ijrf|F^fFlb7-34QaAez|4UoO9T3N2doN2mjX;qDyz}1Pp@%Gkb z^(~s?E~*$|V}E4~FL@2FD0ZKHC>UP&)4puYa($G+vI7ft)FAwKxjk6c=qMf8m|<6~ z*4j>Dn@O#37#1z{bgy{Vl?t?s#>xgIs(sA3ZnsVi#{h!`9h7zVWI3s;+V|takDA|* zGq1FNDj+aHneILJ6Lf1f${}Wa&zjf#@BSFNTF4e zaO;MW3DN=SYT3LuRgx98kA((8w6%)@LlSV#^~B-BvX#gg00|UF0dPAjTI5B=SoQqW zrvf#w$Fh)+FLUpu)BzaOnk+1Eq$RO8)quwu#N389Jaety0Y{u|g-JB>goY(ABb(v#kk(I zB*#x)I8kSmf^#E3T{8k&Q-CKL*2DqC(6@wpX;fj2%>_Jjt(!90_R4n8)?&i`k#Cb_ z2HrN3UH09?XuMfm51xcOhYh>jsFHZ?{_&W8s5Z51!6WRp_9UBlO|M7};Y+zCRNzP% z(N~ZL)0Q{HQWku$y^n1(3$`b^Gwr6a;@Emk3~X$EY8t-QO-xcex~_Vw%UH^yc(|LI zz0JBUOs7x>i0M2jUR#U}gJ9RcMG+DOTi>+S1d5Ae4&oiQ)!Sa;N!iz4lifk3TUXLG zxtDXz&gXJA@Ar7%jiLec_6P>-AePMcexR@f|3RF>KNl%lFp!B>OsS<)%`!XjFpj0 z<4_kix|#xA&zZQDG=i)y0pbRCt*|p!mS)Zdo!XH z1;5j#i72J}0XL%TZ+xrYNR1-I7~9N|f~e~x+LkCemdwVW1Wh~#4(ye=idNgp5s8a= zVo>;F-2}4mp`_dpE$XaJ2CRM_HKd;J8oI7@+m2(o`=n6e4w%f0(jFtY>H?0h6-PfR z-!!51wD3x#SS_wl>5m+5r}Jo~!2yU2G9r&j<5$l}z*jEXu(PBHWc+3tkG`T^MkZz- zY==vWV}TtxS18-ODJ0WK?-umkWQ}9Cv=+gZT|-u{qf@FZW!5)f`MR~R&xIn&bxf?} zxxOO&O*Mehpjn4aFm58=x`|Eui(`OabzN>r>Gjp`(m)k#usEL4S^BEX!+mM@Un68-)`;srBmNpzy5!4mc%q@q~Eb*y?@ed z_nu2-9I!H!^xT5AbGMLn={0snKraYZA<9u?d3Y(BF1+DL;cDYh6qp0-Nh@?4!Yz6vw)w+oFR(Ssav?yHDJDVy3 zN$M1Ae#{((T~&_?2Z=Tn67EYZN5`RA*pH$D1~)a`PGT4QW**wKeB*VuBRJ-FHuOw~ z-(U3n{UkjSh#Y!gu;N&H2eYf+bg8grniD{xrUXRG8>&_SS~M;jU<_Py=v6r|qX^GUOb zyYhFW?BFPq;x(V5l@IWs@44VuXA~dz2vh+^_ys}qw?a_SKG-h)Q&K|<{~`@4`mG; z-+JJ1J@f1GuU7v6^=DJ@C}mUs04}iP^2~me^8kNI+N?Pq*e+LRMn9-%{nKf&+cmr_ z9Jj7DT04#BE{QiAcDUT_BO4oB5yw!yNi2=riAf~!H74RqolV{Bpe=@XrUdlb zuPm##jOv$hJKIcgj4$56pM_WArIY^IzUIV%r*k?smIEz5Yeb=XG{&?8e@)7R>PHc` z=1E=6p8IA`6&r;8R&iF3o9e{QV&@h{M@ zA^qyG<{R0Y`xuIkWOZW)Gu#iXTn}p{UAaExt(K`V^?9^T>ymC^h+@+SnZnzNXq}u> zFDB-Vx`taI+fKuC9;p~8K+S1lJ|mBYw|i-$5WG^bF@vZmIEx-58rVifq}&GF$T;3Z zar!p-1y3{FD(J*#i*T)RL zh&?tn7cqhqmvrO1HsGJTz^jqcF?o)E*{{U4_WuCXaK`@t62!Y?$MVaycR#30_oJk30pW2ay_T;2?_&t*0q^=wwf3Cy z1pGyZ_L-}{&)DDSc|-M3)rUWvH(M>evD&Z8`P@6Heh6ibCM5J~h@+2HP0V?|*zI?} z{9X3ZuNZ4!t$=dP{i3x;7!4-teKMoJ8!^Z8R+1>k*~Fm|-3lx{)oK(Cgzl27WTFjEtkoo;W!!wO)3r{ZF7fZ zJgp$HQRS_OH@|dK%I4*XB%Zne=SJC#>0yi#U4r*kFS^goM$tq`vfC+btQv43 zn3Rd+KkpsdM%DCa2>$@4kraJxqMv1Vzo*Bb?OW%r_w@6g$o9wfsA~S7oPI13{>#_? z4|Dy;2t*?A7*sn{O9EGQ>Yo4R`sOx}Qex2D*}%?!jFa_#au-|-eqf4g?A&gEh9yn|#zh*n{4>FA<( z{HjT|mc7SaDQSt~2_1bk&VydcH38B?nvPQ{jZbozocK@|%R0)sC(!m23 z+wI1cCpK;@eZsLcPpX0-yETO!)Tmx}7Kv2ZiEe^?KaEPQyn~m(g3&>?fJhN~HOxiN z;-zEHW$Y2{zXe@+!?5eyz~1Xt9K<(n)jnnw{Pch2f7`5g(U0)M=X$eqHD1lML*B-| z*PXJDs+)NI;Mdx7`R~#9s1w*0vFEe@0G^JmA3ofIa<=v+_7G^c)165m;IqRF>-ou{ zsiNn6x-Ma{0_{G`v3TwA`7ic@-%1zMv?NKJaGQoQM>CtVMsQ1>HWWTtSv6d#?H>La8aSDS*S&iZIx075l@(cTwqjR-$YVj$K*+-e{35V% zM;xhANr2pLgDi2bn}o@j;fF;E`KrRc^|<~FSex|HgS|T#FL^gA%NYtj6?egJ^oM$` zZNGjpu-xv6KaFNu!AK% zuJ0{&{{Ray_loZFc}V{N=&|>T?($i^8v*z$9!)>_0r)D@a;H(pUoUHV!Wy%ATS+(@ zPqbire#}>y%DLo|z}6pknd9A~1Hd=&6Z5H53k3iH+42$cZ=;B)kj30D;kY9@9%+mQ zbyp>BKx1uL@V#?!JmpT#McX5&#G?z}w3>{z<-|;Jviu;}@uiL>))gw*P9)-VC*w6*E=3|B$Vs|_GjGLRR;+nFzsAM;wT~*d_{jeN zcE9ncJ9lgIC4VCb?cEdZO8!@DJ9iF!$zRLuKfaguEBSqy{{YsP_bd5Lq3oVdohuE7 z*}FF^J@M8&t~UHl;*ZurL~gkb>7(Q2Ne1A4ZlyG{ZMkD?w`gr6%eVWx*|-mdy6srd zwlq&)$ns3VQHsZQAPceU?5)y9Q5n#fT01e;F;Z>TE1EAbXMN7;l0xReiBNj2jUvph z`fqEtJ>!l-qVmDLgD3}v7R1!k%wro#4WmebS+%gwRz%*k?WA?x?U!4uz84FH$Nouwe!JYzeooFY?_*zS&D?fD0{g+P{{TFcbzg43vt90eE&l-HZO81^9Qtqb z8-LxbIrQD0cHI8WeV;m&y&HG^n(p&?Jv(Sy-Cf>nKPzV$9>x@O?zS`aNd&PU&~~Wg z=21Z%iCEii?&{o4!+=(W_}5iqjTWu8*hMU?%+i&KbzlaOa&Q^bji%pl%BrCTk%{6k z;akn_?L=FMm07lqNH`0ON7ATeigHwU8I$vySldit*{?B(bgOPa_LEMHx!v50 z$M=Sj&^H1>6l0JO>PTR4HyyN~@ymq^8ynPm)rz(!NWFL)3tV6@pv@JmF4tl6P?aNR zM@Xbnu{kAXZ3uilJ|XZgd8+_`-yF_Vy1;ATpbkBCbyY5eFn1QxgyW4WL~phmh@G0o O`eSQ?0QiT3zyH}_U+@tC literal 0 HcmV?d00001 From 9107eeeee86ec1d7c27a96ff9afa49d34c25a9c4 Mon Sep 17 00:00:00 2001 From: Eric Jimenez Date: Tue, 21 Jun 2016 10:25:38 -0400 Subject: [PATCH 13/21] feat: add bio for eric. --- harp.json | 7 +++++++ public/resources/images/bios/eric.jpg | Bin 0 -> 25085 bytes 2 files changed, 7 insertions(+) create mode 100644 public/resources/images/bios/eric.jpg diff --git a/harp.json b/harp.json index 69fb7cb9f1..90bb16ca07 100644 --- a/harp.json +++ b/harp.json @@ -438,6 +438,13 @@ "twitter": "amitafr", "website": "http://www.amitafremtullah.com", "bio": "Fatima is a Product Designer and Front-End Developer. When she is not nerding out she is probably eating an abundance of cookies.", + }, + "eric": { + "name": "Eric Jimenez", + "picture": "/resources/images/bios/eric.jpg", + "twitter": "_ericjim", + "website": "http://eric.to/", + "bio": "Eric is a gamer, writer, and programmer.", "type": "Community" } } diff --git a/public/resources/images/bios/eric.jpg b/public/resources/images/bios/eric.jpg new file mode 100644 index 0000000000000000000000000000000000000000..62e25c3942d054cc20cf7b0b12aebfd8cf0fb1fb GIT binary patch literal 25085 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 T9z^cS{lWQ3714g=!N~surDs0o literal 0 HcmV?d00001 From fb179d96904def16bdf0f119d3790b0d2dcac195 Mon Sep 17 00:00:00 2001 From: Martin Probst Date: Mon, 20 Jun 2016 23:34:14 -0700 Subject: [PATCH 14/21] docs(security): Add security documentation. Substantially rewritten, based on original content by Brian Clarkio and Ward Bell and contributions from Naomi Black. --- public/docs/_examples/security/e2e-spec.ts | 25 ++ .../security/ts/app/app.component.ts | 20 ++ .../ts/app/bypass-security.component.html | 15 ++ .../ts/app/bypass-security.component.ts | 33 +++ .../ts/app/inner-html-binding.component.html | 6 + .../ts/app/inner-html-binding.component.ts | 14 + public/docs/_examples/security/ts/app/main.ts | 8 + .../_examples/security/ts/example-config.json | 0 public/docs/_examples/security/ts/index.html | 26 ++ public/docs/_examples/security/ts/plnkr.json | 8 + public/docs/dart/latest/guide/_data.json | 5 + public/docs/dart/latest/guide/security.jade | 1 + public/docs/js/latest/guide/_data.json | 5 + public/docs/js/latest/guide/security.jade | 1 + public/docs/ts/latest/guide/_data.json | 5 + public/docs/ts/latest/guide/security.jade | 246 ++++++++++++++++++ .../devguide/security/binding-inner-html.png | Bin 0 -> 47162 bytes .../security/bypass-security-component.png | Bin 0 -> 243877 bytes 18 files changed, 418 insertions(+) create mode 100644 public/docs/_examples/security/e2e-spec.ts create mode 100644 public/docs/_examples/security/ts/app/app.component.ts create mode 100644 public/docs/_examples/security/ts/app/bypass-security.component.html create mode 100644 public/docs/_examples/security/ts/app/bypass-security.component.ts create mode 100644 public/docs/_examples/security/ts/app/inner-html-binding.component.html create mode 100644 public/docs/_examples/security/ts/app/inner-html-binding.component.ts create mode 100644 public/docs/_examples/security/ts/app/main.ts create mode 100644 public/docs/_examples/security/ts/example-config.json create mode 100644 public/docs/_examples/security/ts/index.html create mode 100644 public/docs/_examples/security/ts/plnkr.json create mode 100644 public/docs/dart/latest/guide/security.jade create mode 100644 public/docs/js/latest/guide/security.jade create mode 100644 public/docs/ts/latest/guide/security.jade create mode 100644 public/resources/images/devguide/security/binding-inner-html.png create mode 100644 public/resources/images/devguide/security/bypass-security-component.png diff --git a/public/docs/_examples/security/e2e-spec.ts b/public/docs/_examples/security/e2e-spec.ts new file mode 100644 index 0000000000..410f1428e1 --- /dev/null +++ b/public/docs/_examples/security/e2e-spec.ts @@ -0,0 +1,25 @@ +/// +'use strict'; +describe('Security E2E Tests', () => { + beforeAll(function() { browser.get(''); }); + + it('sanitizes innerHTML', () => { + let interpolated = element(By.className('e2e-inner-html-interpolated')); + expect(interpolated.getText()) + .toContain('Template Syntax'); + let bound = element(By.className('e2e-inner-html-bound')); + expect(bound.getText()).toContain('Template alert("0wned") Syntax'); + let bold = element(By.css('.e2e-inner-html-bound b')); + expect(bold.getText()).toContain('Syntax'); + }); + + it('binds trusted URLs', () => { + let dangerousUrl = element(By.className('e2e-dangerous-url')); + expect(dangerousUrl.getAttribute('href')).toMatch(/^javascript:alert/); + }); + + it('binds trusted resource URLs', () => { + let iframe = element(By.className('e2e-iframe')); + expect(iframe.getAttribute('src')).toMatch(/^https:\/\/www.youtube.com\//); + }); +}); diff --git a/public/docs/_examples/security/ts/app/app.component.ts b/public/docs/_examples/security/ts/app/app.component.ts new file mode 100644 index 0000000000..153e6b9e49 --- /dev/null +++ b/public/docs/_examples/security/ts/app/app.component.ts @@ -0,0 +1,20 @@ +// #docregion +import { Component } from '@angular/core'; + +import { BypassSecurityComponent } from './bypass-security.component'; +import { InnerHtmlBindingComponent } from './inner-html-binding.component'; + +@Component({ + selector: 'app-root', + template: ` +

Security

+ + + `, + directives: [ + BypassSecurityComponent, + InnerHtmlBindingComponent, + ], +}) +export class AppComponent { +} diff --git a/public/docs/_examples/security/ts/app/bypass-security.component.html b/public/docs/_examples/security/ts/app/bypass-security.component.html new file mode 100644 index 0000000000..75b7734dd4 --- /dev/null +++ b/public/docs/_examples/security/ts/app/bypass-security.component.html @@ -0,0 +1,15 @@ + +

Bypass Security Component

+ + +

A dangerous URL:

+

Click me.

+ + + +

Resource URL:

+

+ + + + diff --git a/public/docs/_examples/security/ts/app/bypass-security.component.ts b/public/docs/_examples/security/ts/app/bypass-security.component.ts new file mode 100644 index 0000000000..6a5f350d28 --- /dev/null +++ b/public/docs/_examples/security/ts/app/bypass-security.component.ts @@ -0,0 +1,33 @@ +// #docplaster +// #docregion +import { Component } from '@angular/core'; +import { DomSanitizationService, SafeResourceUrl, SafeUrl } from '@angular/platform-browser'; + +@Component({ + selector: 'bypass-security', + templateUrl: 'app/bypass-security.component.html', +}) +export class BypassSecurityComponent { + dangerousUrl: SafeUrl; + videoUrl: SafeResourceUrl; + + // #docregion trust-url + constructor(private sanitizer: DomSanitizationService) { + // javascript: URLs are dangerous if attacker controlled. Angular sanitizes them in data + // binding, but we can explicitly tell Angular to trust this value: + this.dangerousUrl = sanitizer.bypassSecurityTrustUrl('javascript:alert("Hi there")'); + // #enddocregion trust-url + this.updateVideoUrl('PUBnlbjZFAI'); + } + + // #docregion trust-video-url + updateVideoUrl(id: string) { + // Appending an ID to a YouTube URL is safe. + // Always make sure to construct SafeValue objects as close as possible to the input data, so + // that it's easier to check if the value is safe. + this.videoUrl = + this.sanitizer.bypassSecurityTrustResourceUrl('https://www.youtube.com/embed/' + id); + } + // #enddocregion trust-video-url +} +// #enddocregion diff --git a/public/docs/_examples/security/ts/app/inner-html-binding.component.html b/public/docs/_examples/security/ts/app/inner-html-binding.component.html new file mode 100644 index 0000000000..fe540d25fe --- /dev/null +++ b/public/docs/_examples/security/ts/app/inner-html-binding.component.html @@ -0,0 +1,6 @@ + +

Binding innerHTML

+

Bound value:

+

{{htmlSnippet}}

+

Result of binding to innerHTML:

+

diff --git a/public/docs/_examples/security/ts/app/inner-html-binding.component.ts b/public/docs/_examples/security/ts/app/inner-html-binding.component.ts new file mode 100644 index 0000000000..95a9f55979 --- /dev/null +++ b/public/docs/_examples/security/ts/app/inner-html-binding.component.ts @@ -0,0 +1,14 @@ +// #docregion +import { Component } from '@angular/core'; + +@Component({ + moduleId: module.id, + selector: 'inner-html-binding', + templateUrl: 'inner-html-binding.component.html', +}) +// #docregion inner-html-controller +export class InnerHtmlBindingComponent { + // E.g. a user/attacker controlled value from a URL. + htmlSnippet = 'Template Syntax'; +} +// #enddocregion inner-html-controller diff --git a/public/docs/_examples/security/ts/app/main.ts b/public/docs/_examples/security/ts/app/main.ts new file mode 100644 index 0000000000..3e1476beac --- /dev/null +++ b/public/docs/_examples/security/ts/app/main.ts @@ -0,0 +1,8 @@ +// #docregion +import { bootstrap } from '@angular/platform-browser-dynamic'; + +// #docregion import +import { AppComponent } from './app.component'; +// #enddocregion import + +bootstrap(AppComponent); diff --git a/public/docs/_examples/security/ts/example-config.json b/public/docs/_examples/security/ts/example-config.json new file mode 100644 index 0000000000..e69de29bb2 diff --git a/public/docs/_examples/security/ts/index.html b/public/docs/_examples/security/ts/index.html new file mode 100644 index 0000000000..b665a8bc6f --- /dev/null +++ b/public/docs/_examples/security/ts/index.html @@ -0,0 +1,26 @@ + + + + + Angular Content Security + + + + + + + + + + + + + + + + + Loading... + + diff --git a/public/docs/_examples/security/ts/plnkr.json b/public/docs/_examples/security/ts/plnkr.json new file mode 100644 index 0000000000..e66527cb6b --- /dev/null +++ b/public/docs/_examples/security/ts/plnkr.json @@ -0,0 +1,8 @@ +{ + "description": "Content Security", + "files": [ + "!**/*.d.ts", + "!**/*.js" + ], + "tags": ["security"] +} diff --git a/public/docs/dart/latest/guide/_data.json b/public/docs/dart/latest/guide/_data.json index eed8cf36a4..7d25438019 100644 --- a/public/docs/dart/latest/guide/_data.json +++ b/public/docs/dart/latest/guide/_data.json @@ -73,6 +73,11 @@ "intro": "Learn how to apply CSS styles to components." }, + "security": { + "title": "Security", + "intro": "Prevent security vulnerabilities" + }, + "hierarchical-dependency-injection": { "title": "Hierarchical Dependency Injectors", "navTitle": "Hierarchical Injectors", diff --git a/public/docs/dart/latest/guide/security.jade b/public/docs/dart/latest/guide/security.jade new file mode 100644 index 0000000000..f8df2a84a6 --- /dev/null +++ b/public/docs/dart/latest/guide/security.jade @@ -0,0 +1 @@ +!= partial("../../../_includes/_ts-temp") \ No newline at end of file diff --git a/public/docs/js/latest/guide/_data.json b/public/docs/js/latest/guide/_data.json index 939d7c5c4a..437e7df624 100644 --- a/public/docs/js/latest/guide/_data.json +++ b/public/docs/js/latest/guide/_data.json @@ -73,6 +73,11 @@ "intro": "Learn how to apply CSS styles to components." }, + "security": { + "title": "Security", + "intro": "Prevent security vulnerabilities" + }, + "hierarchical-dependency-injection": { "title": "Hierarchical Dependency Injectors", "navTitle": "Hierarchical Injectors", diff --git a/public/docs/js/latest/guide/security.jade b/public/docs/js/latest/guide/security.jade new file mode 100644 index 0000000000..f8df2a84a6 --- /dev/null +++ b/public/docs/js/latest/guide/security.jade @@ -0,0 +1 @@ +!= partial("../../../_includes/_ts-temp") \ No newline at end of file diff --git a/public/docs/ts/latest/guide/_data.json b/public/docs/ts/latest/guide/_data.json index 19d65f49b2..ca414862e5 100644 --- a/public/docs/ts/latest/guide/_data.json +++ b/public/docs/ts/latest/guide/_data.json @@ -78,6 +78,11 @@ "intro": "Learn how to apply CSS styles to components." }, + "security": { + "title": "Security", + "intro": "Prevent security vulnerabilities" + }, + "hierarchical-dependency-injection": { "title": "Hierarchical Dependency Injectors", "navTitle": "Hierarchical Injectors", diff --git a/public/docs/ts/latest/guide/security.jade b/public/docs/ts/latest/guide/security.jade new file mode 100644 index 0000000000..b937f6214b --- /dev/null +++ b/public/docs/ts/latest/guide/security.jade @@ -0,0 +1,246 @@ +block includes + include ../_util-fns +:marked + # Security + Web application security has many aspects. This documentation describes Angular's built in + protections against common web application vulnerabilities and attacks, such as Cross Site + Scripting Attacks. It does not cover application level security, such as authentication (_Who is + this user?_) or authorization (_What can this user do?_). + + The [Open Web Application Security Project (OWASP)](https://www.owasp.org/index.php/Category:OWASP_Guide_Project) + has further information on the attacks and mitigations described below. + +.l-main-section +:marked + # Table Of Contents + + * [Reporting Vulnerabilities](#report-issues) + * [Best Practices](#best-practices) + * [Preventing Cross-Site Scripting (XSS)](#xss) + * [Trusting Safe Values](#bypass-security-apis) + * [HTTP-level Vulnerabilities](#http) + * [Auditing Angular Applications](#code-review) + +p Try the #[+liveExampleLink2()] of the code shown in this chapter. + +.l-main-section +h2#report-issues Reporting Vulnerabilities +:marked + Email us at [security@angular.io](mailto:security@angular.io) to report vulnerabilities in + Angular itself. + + For further details on how Google handles security issues please refer to [Google's security + philosophy](https://www.google.com/about/appsecurity/). + +.l-main-section +h2#best-practices Best Practices +:marked + * **Keep current with the latest Angular library releases.** + We regularly update our Angular libraries and these updates may fix security defects discovered in + previous version. Check the Angular [change + log](https://github.com/angular/angular/blob/master/CHANGELOG.md) for security-related updates. + + * **Don't modify your copy of Angular.** + Private, customized versions of Angular tend to fall behind the current version and may neglect + important security fixes and enhancements. Instead, share your Angular improvements with the + community and make a pull request. + + * **Avoid Angular APIs marked in the documentation as “[_Security Risk_](#bypass-security-apis)”.** + +.l-main-section +h2#xss Preventing Cross-Site Scripting (XSS) +:marked + [Cross-Site Scripting (XSS)](https://en.wikipedia.org/wiki/Cross-site_scripting) enables attackers + to inject malicious code into web pages. Such code can then for example steal user's data (in + particular their login data), or perform actions impersonating the user. This is one of the most + common attacks on the web. + + To block XSS attacks, we must prevent malicious code from entering the DOM. For example, if an + attacker can trick us into inserting a ` + + + + + + + + + + + + + + + + + + + + + + + + Loading... + + + diff --git a/public/docs/_examples/forms-deprecated/js/plnkr.json b/public/docs/_examples/forms-deprecated/js/plnkr.json new file mode 100644 index 0000000000..0105283bd3 --- /dev/null +++ b/public/docs/_examples/forms-deprecated/js/plnkr.json @@ -0,0 +1,4 @@ +{ + "description": "Forms", + "files":["app/**/*.js", "**/*.html", "**/*.css"] +} diff --git a/public/docs/_examples/forms-deprecated/ts/app/app.component.ts b/public/docs/_examples/forms-deprecated/ts/app/app.component.ts new file mode 100644 index 0000000000..2dcbc8037a --- /dev/null +++ b/public/docs/_examples/forms-deprecated/ts/app/app.component.ts @@ -0,0 +1,10 @@ +// #docregion +import { Component } from '@angular/core'; +import { HeroFormComponent } from './hero-form.component'; + +@Component({ + selector: 'my-app', + template: '', + directives: [HeroFormComponent] +}) +export class AppComponent { } diff --git a/public/docs/_examples/forms-deprecated/ts/app/hero-form.component.html b/public/docs/_examples/forms-deprecated/ts/app/hero-form.component.html new file mode 100644 index 0000000000..6fcfc2a7cb --- /dev/null +++ b/public/docs/_examples/forms-deprecated/ts/app/hero-form.component.html @@ -0,0 +1,208 @@ + + +
+ +
+

Hero Form

+ + + + +
+ + + + +
+ + Name is required +
+ +
+ +
+ + +
+ +
+ + +
+ Power is required +
+
+ + + + + + + + + + + +
+
+ Name via form.controls = {{showFormControls(heroForm)}} +
+ + + +
+ + +
+

You submitted the following:

+
+
Name
+
{{ model.name }}
+
+
+
Alter Ego
+
{{ model.alterEgo }}
+
+
+
Power
+
{{ model.power }}
+
+
+ +
+ +
+ + + +
+
+ + + + +
+
+ + + +
+ +
+ +
+

Hero Form

+
+
+ + +
+ +
+ + +
+ + + +
+ + +
+ + + + + +
+
+ + + + +
+ +
+

Hero Form

+
+ + {{diagnostic}} +
+ + +
+ +
+ + +
+ +
+ + +
+ + + + +
+
+ + + +
+ + + TODO: remove this: {{model.name}} + +
+ + + TODO: remove this: {{model.name}} + +
+ +
+ + + + + +
+ + +
TODO: remove this: {{spy.className}} + +
+ +
diff --git a/public/docs/_examples/forms-deprecated/ts/app/hero-form.component.ts b/public/docs/_examples/forms-deprecated/ts/app/hero-form.component.ts new file mode 100644 index 0000000000..7ea7c44738 --- /dev/null +++ b/public/docs/_examples/forms-deprecated/ts/app/hero-form.component.ts @@ -0,0 +1,66 @@ +// #docplaster +// #docregion +// #docregion first, final +import { Component } from '@angular/core'; +import { NgForm } from '@angular/common'; + +import { Hero } from './hero'; + +@Component({ + selector: 'hero-form', + templateUrl: 'app/hero-form.component.html' +}) +export class HeroFormComponent { + + powers = ['Really Smart', 'Super Flexible', + 'Super Hot', 'Weather Changer']; + + model = new Hero(18, 'Dr IQ', this.powers[0], 'Chuck Overstreet'); + + // #docregion submitted + submitted = false; + + onSubmit() { this.submitted = true; } + // #enddocregion submitted + + // #enddocregion final + // TODO: Remove this when we're done + get diagnostic() { return JSON.stringify(this.model); } + // #enddocregion first + + // #docregion final + // Reset the form with a new hero AND restore 'pristine' class state + // by toggling 'active' flag which causes the form + // to be removed/re-added in a tick via NgIf + // TODO: Workaround until NgForm has a reset method (#6822) + // #docregion new-hero + active = true; + + // #docregion new-hero-v1 + newHero() { + this.model = new Hero(42, '', ''); + // #enddocregion new-hero-v1 + this.active = false; + setTimeout(() => this.active = true, 0); + // #docregion new-hero-v1 + } + // #enddocregion new-hero-v1 + // #enddocregion new-hero + // #enddocregion final + //////// NOT SHOWN IN DOCS //////// + + // Reveal in html: + // Name via form.controls = {{showFormControls(heroForm)}} + showFormControls(form: NgForm) { + + return form && form.controls['name'] && + // #docregion form-controls + form.controls['name'].value; // Dr. IQ + // #enddocregion form-controls + } + + ///////////////////////////// + + // #docregion first, final +} +// #enddocregion first, final diff --git a/public/docs/_examples/forms-deprecated/ts/app/hero.ts b/public/docs/_examples/forms-deprecated/ts/app/hero.ts new file mode 100644 index 0000000000..c128626452 --- /dev/null +++ b/public/docs/_examples/forms-deprecated/ts/app/hero.ts @@ -0,0 +1,11 @@ +// #docregion +export class Hero { + + constructor( + public id: number, + public name: string, + public power: string, + public alterEgo?: string + ) { } + +} diff --git a/public/docs/_examples/forms-deprecated/ts/app/main.ts b/public/docs/_examples/forms-deprecated/ts/app/main.ts new file mode 100644 index 0000000000..5338161d66 --- /dev/null +++ b/public/docs/_examples/forms-deprecated/ts/app/main.ts @@ -0,0 +1,6 @@ +// #docregion +import { bootstrap } from '@angular/platform-browser-dynamic'; + +import { AppComponent } from './app.component'; + +bootstrap(AppComponent); diff --git a/public/docs/_examples/forms-deprecated/ts/example-config.json b/public/docs/_examples/forms-deprecated/ts/example-config.json new file mode 100644 index 0000000000..e69de29bb2 diff --git a/public/docs/_examples/forms-deprecated/ts/forms.css b/public/docs/_examples/forms-deprecated/ts/forms.css new file mode 100644 index 0000000000..d7e11405b1 --- /dev/null +++ b/public/docs/_examples/forms-deprecated/ts/forms.css @@ -0,0 +1,9 @@ +/* #docregion */ +.ng-valid[required] { + border-left: 5px solid #42A948; /* green */ +} + +.ng-invalid { + border-left: 5px solid #a94442; /* red */ +} +/* #enddocregion */ \ No newline at end of file diff --git a/public/docs/_examples/forms-deprecated/ts/index.html b/public/docs/_examples/forms-deprecated/ts/index.html new file mode 100644 index 0000000000..4df2d32d46 --- /dev/null +++ b/public/docs/_examples/forms-deprecated/ts/index.html @@ -0,0 +1,34 @@ + + + + + Hero Form + + + + + + + + + + + + + + + + + + + + + + + + Loading... + + + diff --git a/public/docs/_examples/forms-deprecated/ts/plnkr.json b/public/docs/_examples/forms-deprecated/ts/plnkr.json new file mode 100644 index 0000000000..c813933f8e --- /dev/null +++ b/public/docs/_examples/forms-deprecated/ts/plnkr.json @@ -0,0 +1,7 @@ +{ + "description": "Forms-Deprecated", + "files":[ + "!**/*.d.ts", + "!**/*.js" + ] +} \ No newline at end of file diff --git a/public/docs/_examples/forms/e2e-spec.ts b/public/docs/_examples/forms/e2e-spec.ts index 502a2cbdce..87ab6ef904 100644 --- a/public/docs/_examples/forms/e2e-spec.ts +++ b/public/docs/_examples/forms/e2e-spec.ts @@ -33,7 +33,7 @@ describeIf(browser.appIsTs || browser.appIsJs, 'Forms Tests', function () { }); it('should hide form after submit', function () { - let alterEgoEle = element.all(by.css('input[ngcontrol=alterEgo]')).get(0); + let alterEgoEle = element.all(by.css('input[name=alterEgo]')).get(0); expect(alterEgoEle.isDisplayed()).toBe(true); let submitButtonEle = element.all(by.css('button[type=submit]')).get(0); submitButtonEle.click().then(function() { @@ -44,7 +44,7 @@ describeIf(browser.appIsTs || browser.appIsJs, 'Forms Tests', function () { it('should reflect submitted data after submit', function () { let test = 'testing 1 2 3'; let newValue: string; - let alterEgoEle = element.all(by.css('input[ngcontrol=alterEgo]')).get(0); + let alterEgoEle = element.all(by.css('input[name=alterEgo]')).get(0); alterEgoEle.getAttribute('value').then(function(value) { // alterEgoEle.sendKeys(test); sendKeys(alterEgoEle, test); diff --git a/public/docs/_examples/forms/js/app/hero-form.component.html b/public/docs/_examples/forms/js/app/hero-form.component.html index fdf8e08396..fbe6ee917f 100644 --- a/public/docs/_examples/forms/js/app/hero-form.component.html +++ b/public/docs/_examples/forms/js/app/hero-form.component.html @@ -13,7 +13,7 @@ + name="name" #name="ngModel" >
Name is required
@@ -24,14 +24,14 @@ + name="alterEgo" >
@@ -133,19 +133,19 @@
+ [(ngModel)]="model.name" name="name" >
+ [(ngModel)]="model.alterEgo" name="alterEgo">
@@ -173,18 +173,18 @@
- + - + name="name" > +
- + + name="name" #spy >
TODO: remove this: {{spy.className}} - +
diff --git a/public/docs/_examples/forms/js/app/main.js b/public/docs/_examples/forms/js/app/main.js index 5930bdd061..2b866b3685 100644 --- a/public/docs/_examples/forms/js/app/main.js +++ b/public/docs/_examples/forms/js/app/main.js @@ -1,6 +1,9 @@ // #docregion (function(app) { document.addEventListener('DOMContentLoaded', function() { - ng.platformBrowserDynamic.bootstrap(app.AppComponent); + ng.platformBrowserDynamic.bootstrap(app.AppComponent,[ + ng.forms.disableDeprecatedForms(), + ng.forms.provideForms() + ]); }); })(window.app || (window.app = {})); diff --git a/public/docs/_examples/forms/js/index.html b/public/docs/_examples/forms/js/index.html index e15f41e4fe..8353dfb180 100644 --- a/public/docs/_examples/forms/js/index.html +++ b/public/docs/_examples/forms/js/index.html @@ -24,6 +24,7 @@ + diff --git a/public/docs/_examples/forms/ts/app/hero-form.component.html b/public/docs/_examples/forms/ts/app/hero-form.component.html index 6fcfc2a7cb..80401a1313 100644 --- a/public/docs/_examples/forms/ts/app/hero-form.component.html +++ b/public/docs/_examples/forms/ts/app/hero-form.component.html @@ -13,7 +13,7 @@ + name="name" #name="ngModel" >
@@ -26,14 +26,14 @@ + name="alterEgo" >
@@ -148,19 +148,19 @@
+ [(ngModel)]="model.name" name="name">
+ [(ngModel)]="model.alterEgo" name="alterEgo">
@@ -176,7 +176,7 @@
+ [(ngModel)]="model.name" name="name"> TODO: remove this: {{model.name}}
@@ -191,18 +191,18 @@
- + - + name="name" > +
- + + name="name" #spy >
TODO: remove this: {{spy.className}} - +
diff --git a/public/docs/_examples/forms/ts/app/main.ts b/public/docs/_examples/forms/ts/app/main.ts index 5338161d66..9e0244c26a 100644 --- a/public/docs/_examples/forms/ts/app/main.ts +++ b/public/docs/_examples/forms/ts/app/main.ts @@ -1,6 +1,11 @@ // #docregion import { bootstrap } from '@angular/platform-browser-dynamic'; +import { disableDeprecatedForms, provideForms } from '@angular/forms'; import { AppComponent } from './app.component'; -bootstrap(AppComponent); +bootstrap(AppComponent, [ + disableDeprecatedForms(), + provideForms() + ]) + .catch((err: any) => console.error(err)); diff --git a/public/docs/js/latest/guide/_data.json b/public/docs/js/latest/guide/_data.json index 437e7df624..a0f8270eec 100644 --- a/public/docs/js/latest/guide/_data.json +++ b/public/docs/js/latest/guide/_data.json @@ -29,7 +29,7 @@ "basics": true }, - "forms": { + "forms-deprecated": { "title": "Forms", "intro": "A form creates a cohesive, effective, and compelling data entry experience. An Angular form coordinates a set of data-bound user controls, tracks changes, validates input, and presents errors.", "nextable": true, diff --git a/public/docs/js/latest/guide/forms-deprecated.jade b/public/docs/js/latest/guide/forms-deprecated.jade new file mode 100644 index 0000000000..185b25dee5 --- /dev/null +++ b/public/docs/js/latest/guide/forms-deprecated.jade @@ -0,0 +1,648 @@ +include ../_util-fns + +.alert.is-important + :marked + This guide is using the deprecated forms API. + + We have created a new version using the new API here. + +:marked + We’ve all used a form to login, submit a help request, place an order, book a flight, + schedule a meeting and perform countless other data entry tasks. + Forms are the mainstay of business applications. + + Any seasoned web developer can slap together an HTML form with all the right tags. + It's more challenging to create a cohesive data entry experience that guides the + user efficiently and effectively through the workflow behind the form. + + *That* takes design skills that are, to be frank, well out of scope for this chapter. + + It also takes framework support for + **two-way data binding, change tracking, validation, and error handling** + ... which we shall cover in this chapter on Angular forms. + + We will build a simple form from scratch, one step at a time. Along the way we'll learn + + - How to build an Angular form with a component and template + + - The `ngModel` two-way data binding syntax for reading and writing values to input controls + + - The `ngControl` directive to track the change state and validity of form controls + + - The special CSS classes that `ngControl` adds to form controls and how we can use them to provide strong visual feedback + + - How to display validation errors to users and enable/disable form controls + + - How to share information across controls with template local variables + + [Live Example](/resources/live-examples/forms-deprecated/js/plnkr.html) +.l-main-section +:marked + ## Template-Driven Forms + + Many of us will build forms by writing templates in the Angular [template syntax](./template-syntax.html) with + the form-specific directives and techniques described in this chapter. +.l-sub-section + :marked + That's not the only way to create a form but it's the way we'll cover in this chapter. +:marked + We can build almost any form we need with an Angular template — login forms, contact forms ... pretty much any business forms. + We can lay out the controls creatively, bind them to data, specify validation rules and display validation errors, + conditionally enable or disable specific controls, trigger built-in visual feedback, and much more. + + It will be pretty easy because Angular handles many of the repetitive, boiler plate tasks we'd + otherwise wrestle with ourselves. + + We'll discuss and learn to build the following template-driven form: + +figure.image-display + img(src="/resources/images/devguide/forms/hero-form-1.png" width="400px" alt="Clean Form") + +:marked + Here at the *Hero Employment Agency* we use this form to maintain personal information about the + heroes in our stable. Every hero needs a job. It's our company mission to match the right hero with the right crisis! + + Two of the three fields on this form are required. Required fields have a green bar on the left to make them easy to spot. + + If we delete the hero name, the form displays a validation error in an attention grabbing style: + +figure.image-display + img(src="/resources/images/devguide/forms/hero-form-2.png" width="400px" alt="Invalid, Name Required") + +:marked + Note that the submit button is disabled and the "required" bar to the left of the input control changed from green to red. + +.l-sub-section + p We'll' customize the colors and location of the "required" bar with standard CSS. + +:marked + We will build this form in the following sequence of small steps + + 1. Create the `Hero` model class + 1. Create the component that controls the form + 1. Create a template with the initial form layout + 1. Add the **ngModel** directive to each form input control + 1. Add the **ngControl** directive to each form input control + 1. Add custom CSS to provide visual feedback + 1. Show and hide validation error messages + 1. Handle form submission with **ngSubmit** + 1. Disable the form’s submit button until the form is valid + +:marked + ## Setup + Create a new project folder (`angular2-forms`) and follow the steps in the [QuickStart](../quickstart.html). + + ## Create the Hero Model Class + + As users enter form data, we capture their changes and update an instance of a model. + We can't layout the form until we know what the model looks like. + + A model can be as simple as a "property bag" that holds facts about a thing of application importance. + That describes well our `Hero` class with its three required fields (`id`, `name`, `power`) + and one optional field (`alterEgo`). + + Create a new file in the app folder called `hero.js` and give it the following constructor: + ++makeExample('forms-deprecated/js/app/hero.js', null, 'app/hero.js') + +:marked + It's an anemic model with few requirements and no behavior. Perfect for our demo. + + The `alterEgo` is optional and the constructor lets us omit it by being the last argument. + + We can create a new hero like this: +code-example(format=""). + var myHero = new Hero(42, 'SkyDog', + 'Fetch any object at any distance', 'Leslie Rollover'); + console.log('My hero is called ' + myHero.name); // "My hero is called SkyDog" +:marked + We update the `` of the `index.html` to include this javascript file. + ++makeExample('forms-deprecated/js/index.html', 'scripts-hero', 'index.html (excerpt)')(format=".") + +.l-main-section +:marked + ## Create a Form component + + An Angular form has two parts: an HTML-based template and a code-based Component to handle data and user interactions. + + We begin with the Component because it states, in brief, what the Hero editor can do. + + Create a new file called `hero-form.component.js` and give it the following definition: + ++makeExample('forms-deprecated/js/app/hero-form.component.js', 'first', 'app/hero-form.component.js') + +:marked + There’s nothing special about this component, nothing form-specific, nothing to distinguish it from any component we've written before. + + Understanding this component requires only the Angular 2 concepts we’ve learned in previous chapters + + 1. We use the `ng.core` object from the Angular library as we usually do. + + 1. The `Component()` selector value of "hero-form" means we can drop this form in a parent template with a `` tag. + + 1. The `templateUrl` property points to a separate file for template HTML called `hero-form.component.html`. + + 1. We defined dummy data for `model` and `powers` as befits a demo. + Down the road, we can inject a data service to get and save real data + or perhaps expose these properties as [inputs and outputs](./template-syntax.html#inputs-outputs) for binding to a + parent component. None of this concerns us now and these future changes won't affect our form. + + 1. We threw in a `diagnostic` method at the end to return a JSON representation of our model. + It'll help us see what we're doing during our development; we've left ourselves a cleanup note to discard it later. + + Why don't we write the template inline in the component file as we often do + elsewhere in the Developer Guide? + + There is no “right” answer for all occasions. We like inline templates when they are short. + Most form templates won't be short. TypeScript and JavaScript files generally aren't the best place to + write (or read) large stretches of HTML and few editors are much help with files that have a mix of HTML and code. + We also like short files with a clear and obvious purpose like this one. + + We made a good choice to put the HTML template elsewhere. + We'll write that template in a moment. Before we do, we'll take a step back + and revise the `app.component.js` to make use of our new `HeroFormComponent`. + +:marked + Again we update the `` of the `index.html` to include the new javascript file. + ++makeExample('forms-deprecated/js/index.html', 'scripts-hero-form', 'index.html (excerpt)')(format=".") + +.l-main-section +:marked + ## Revise the *app.component.js* + + `app.component.js` is the application's root component. It will host our new `HeroFormComponent`. + + Replace the contents of the "QuickStart" version with the following: ++makeExample('forms-deprecated/js/app/app.component.js', null, 'app/app.component.js') + +:marked +.l-sub-section + :marked + There are only two changes: + + 1. The `template` is simply the new element tag identified by the component's `select` property. + + 1. The `directives` array tells Angular that our template depends upon the `HeroFormComponent` + which is itself a Directive (as are all Components). + +.l-main-section +:marked + ## Create an initial HTML Form Template + + Create a new template file called `hero-form.component.html` and give it the following definition: + ++makeExample('forms-deprecated/js/app/hero-form.component.html', 'start', 'app/hero-form.component.html') + +:marked + That is plain old HTML 5. We're presenting two of the `Hero` fields, `name` and `alterEgo`, and + opening them up for user input in input boxes. + + The *Name* `` control has the HTML5 `required` attribute; + the *Alter Ego* `` control does not because `alterEgo` is optional. + + We've got a *Submit* button at the bottom with some classes on it. + + **We are not using Angular yet**. There are no bindings. No extra directives. Just layout. + + The `container`,`form-group`, `form-control`, and `btn` classes + come from [Twitter Boostrap](http://getbootstrap.com/css/). Purely cosmetic. + We're using Bootstrap to gussy up our form. + Hey, what's a form without a little style! + +.callout.is-important + header Angular Forms Do Not Require A Style Library + :marked + Angular makes no use of the `container`, `form-group`, `form-control`, and `btn` classes or + the styles of any external library. Angular apps can use any CSS library + ... or none at all. + +:marked + Let's add the stylesheet. + +ol + li Open a terminal window in the application root folder and enter the command: + code-example(language="html" escape="html"). + npm install bootstrap --save + li Open index.html and add the following link to the <head>. + +makeExample('forms-deprecated/js/index.html', 'bootstrap')(format=".") +:marked +.l-main-section +:marked + ## Add Powers with ***ngFor** + Our hero may choose one super power from a fixed list of Agency-approved powers. + We maintain that list internally (in `HeroFormComponent`). + + We'll add a `select` to our + form and bind the options to the `powers` list using `NgFor`, + a technique we might have seen before in the [Displaying Data](./displaying-data.html) chapter. + + Add the following HTML *immediately below* the *Alter Ego* group. ++makeExample('forms-deprecated/js/app/hero-form.component.html', 'powers', 'app/hero-form.component.html (excerpt)')(format=".") + +:marked + We are repeating the `` tag for each power in the list of Powers. + The `#p` local template variable is a different power in each iteration; + we display its name using the interpolation syntax with the double-curly-braces. + +.l-main-section +:marked + ## Two-way data binding with ***ngModel** + Running the app right now would be disappointing. + +figure.image-display + img(src="/resources/images/devguide/forms/hero-form-3.png" width="400px" alt="Early form with no binding") +:marked + We don't see hero data because we are not binding to the `Hero` yet. + We know how to do that from earlier chapters. + [Displaying Data](./displaying-data.html) taught us Property Binding. + [User Input](./user-input.html) showed us how to listen for DOM events with an + Event Binding and how to update a component property with the displayed value. + + Now we need to display, listen, and extract at the same time. + + We could use those techniques again in our form. + Instead we'll introduce something new, the `NgModel` directive, that + makes binding our form to the model super-easy. + + Find the `` tag for the "Name" and update it like this + ++makeExample('forms-deprecated/js/app/hero-form.component.html', 'ngModel-1','app/hero-form.component.html (excerpt)')(format=".") + +.l-sub-section + :marked + We appended a diagnostic interpolation after the input tag + so we can see what we're doing. + We left ourselves a note to throw it way when we're done. + +:marked + Focus on the binding syntax: `[(ngModel)]="..."`. + + If we ran the app right now and started typing in the *Name* input box, + adding and deleting characters, we'd see them appearing and disappearing + from the interpolated text. + At some point it might look like this. +figure.image-display + img(src="/resources/images/devguide/forms/ng-model-in-action.png" width="400px" alt="ngModel in action") +:marked + The diagnostic is evidence that we really are flowing values from the input box to the model and + back again. **That's two-way data binding!** + + Let's add similar `[(ngModel)]` bindings to *Alter Ego* and *Hero Power*. + We'll ditch the input box binding message + and add a new binding at the top to the component's `diagnostic` method. + Then we can confirm that two-way data binding works *for the entire Hero model*. + + After revision the core of our form should have three `[(ngModel)]` bindings that + look much like this: + ++makeExample('forms-deprecated/js/app/hero-form.component.html', 'ngModel-2', 'app/hero-form.component.html (excerpt)') + +:marked + If we ran the app right now and changed every Hero model property, the form might display like this: +figure.image-display + img(src="/resources/images/devguide/forms/ng-model-in-action-2.png" width="400px" alt="ngModel in super action") +:marked + The diagnostic near the top of the form + confirms that all of our changes are reflected in the model. + + **Delete** the `{{diagnostic()}}` binding at the top as it has served its purpose. + +.l-sub-section + :marked + ### Inside [(ngModel)] + *This section is an optional deep dive into [(ngModel)]. Not interested? Skip ahead!* + + The punctuation in the binding syntax, [()], is a good clue to what's going on. + + In a Property Binding, a value flows from the model to a target property on screen. + We identify that target property by surrounding its name in brackets, []. + This is a one-way data binding **from the model to the view**. + + In an Event Binding, we flow the value from the target property on screen to the model. + We identify that target property by surrounding its name in parentheses, (). + This is a one-way data binding in the opposite direction **from the view to the model**. + + No wonder Angular chose to combine the punctuation as [()] + to signify a two-way data binding and a **flow of data in both directions**. + + In fact, we can break the `NgModel` binding into its two separate modes + as we do in this re-write of the "Name" `` binding: + +makeExample('forms-deprecated/js/app/hero-form.component.html', 'ngModel-3','app/hero-form.component.html (excerpt)')(format=".") + + :marked +
The Property Binding should feel familiar. The Event Binding might seem strange. + + The `ngModelChange` is not an `` element event. + It is actually an event property of the `NgModel` directive. + When Angular sees a binding target in the form [(x)], + it expects the `x` directive to have an `x` input property and an `xChange` output property. + + The other oddity is the template expression, `model.name = $event`. + We're used to seeing an `$event` object coming from a DOM event. + The `ngModelChange` property doesn't produce a DOM event; it's an Angular `EventEmitter` + property that returns the input box value when it fires — which is precisely what + we should assign to the model's `name' property. + + Nice to know but is it practical? We almost always prefer `[(ngModel)]`. + We might split the binding if we had to do something special in + the event handling such as debounce or throttle the key strokes. + + Learn more about `NgModel` and other template syntax in the + [Template Syntax](./template-syntax.html) chapter. + +.l-main-section +:marked + ## Track change-state and validity with **ngControl** + + A form isn't just about data binding. We'd also like to know the state of the controls on our form. + The `NgControl` directive keeps track of control state for us. + +.callout.is-helpful + header NgControl requires Form + :marked + The `NgControl` is one of a family of `NgForm` directives that can only be applied to + a control within a ` tag. +:marked + Our application can ask an `NgControl` if the user touched the control, + if the value changed, or if the value became invalid. + + `NgControl` doesn't just track state; it updates the control with special + Angular CSS classes from the set we listed above. + We can leverage those class names to change the appearance of the + control and make messages appear or disappear. + + We'll explore those effects soon. Right now + we should **add `ngControl`to all three form controls**, + starting with the *Name* input box ++makeExample('forms-deprecated/js/app/hero-form.component.html', 'ngControl-1', 'app/hero-form.component.html (excerpt)')(format=".") +:marked + Be sure to assign a unique name to each `ngControl` directive. + +.l-sub-section + :marked + Angular registers controls under their `ngControl` names + with the `NgForm`. + We didn't add the `NgForm` directive explicitly but it's here + and we'll talk about it [later in this chapter](#ngForm). + +.l-main-section +:marked + ## Add Custom CSS for Visual Feedback + + `NgControl` doesn't just track state. + It updates the control with three classes that reflect the state. + +table + tr + th State + th Class if true + th Class if false + tr + td Control has been visited + td ng-touched + td ng-untouched + tr + td Control's value has changed + td ng-dirty + td ng-pristine + tr + td Control's value is valid + td ng-valid + td ng-invalid +:marked + Let's add a temporary [local template variable](./template-syntax.html#local-vars) named **spy** + to the "Name" `` tag and use the spy to display those classes. + ++makeExample('forms-deprecated/js/app/hero-form.component.html', 'ngControl-2','app/hero-form.component.html (excerpt)')(format=".") + +:marked + Now run the app and focus on the *Name* input box. + Follow the next four steps *precisely* + + 1. Look but don't touched + 1. Click in the input box, then click outside the text input box + 1. Add slashes to the end of the name + 1. Erase the name + + The actions and effects are as follows: +figure.image-display + img(src="/resources/images/devguide/forms/control-state-transitions-anim.gif" alt="Control State Transition") +:marked + We should be able to see the following four sets of class names and their transitions: +figure.image-display + img(src="/resources/images/devguide/forms/ng-control-class-changes.png" width="400px" alt="Control State Transitions") + +:marked + The (`ng-valid` | `ng-invalid`) pair are most interesting to us. We want to send a + strong visual signal when the data are invalid and we want to mark required fields. + + We realize we can do both at the same time with a colored bar on the left of the input box: + +figure.image-display + img(src="/resources/images/devguide/forms/validity-required-indicator.png" width="400px" alt="Invalid Form") + +:marked + We achieve this effect by adding two styles to a new `forms.css` file + that we add to our project as a sibling to `index.html`. + ++makeExample('forms-deprecated/js/forms.css',null,'forms.css')(format=".") +:marked + These styles select for the two Angular validity classes and the HTML 5 "required" attribute. + + We update the `` of the `index.html` to include this style sheet. ++makeExample('forms-deprecated/js/index.html', 'styles', 'index.html (excerpt)')(format=".") +:marked + ## Show and Hide Validation Error messages + + We can do better. + + The "Name" input box is required. Clearing it turns the bar red. That says *something* is wrong but we + don't know *what* is wrong or what to do about it. + We can leverage the `ng-invalid` class to reveal a helpful message. + + Here's the way it should look when the user deletes the name: +figure.image-display + img(src="/resources/images/devguide/forms/name-required-error.png" width="400px" alt="Name required") + +:marked + To achieve this effect we extend the `` tag with + 1. a [local template variable](./template-syntax.html#local-vars) + 1. the "*is required*" message in a nearby `
` which we'll display only if the control is invalid. + + Here's how we do it for the *name* input box: +-var stylePattern = { otl: /(#name="form")|(.*div.*$)|(Name is required)/gm }; ++makeExample('forms-deprecated/js/app/hero-form.component.html', + 'name-with-error-msg', + 'app/hero-form.component.html (excerpt)', + stylePattern) +:marked + When we added the `ngControl` directive, we bound it to the model's `name` property. + Here we initialize a template local variable (`name`) with the value "ngForm" (`#name="ngForm"`). + Angular recognizes that syntax and re-sets the `name` local template variable to the + `ngControl` directive instance. + In other words, the `name` local template variable becomes a handle on the `ngControl` object + for this input box. + + Now we can control visibility of the "name" error message by binding the message `
` element's `hidden` property + to the `ngControl` object's `valid` property. The message is hidden while the control is valid; + the message is revealed when the control becomes invalid. + +.l-sub-section + :marked + ### The NgForm directive + We just set a template local variable with the value of an `NgForm` directive. + Why did that work? We didn't add the **[`NgForm`](../api/common/NgForm-directive.html) directive** explicitly. + + Angular added it surreptitiously, wrapping it around the `
` element + + The `NgForm` directive supplements the `form` element with additional features. + It collects `Controls` (elements identified by an `ngControl` directive) + and monitors their properties including their validity. + It also has its own `valid` property which is true only if every contained + control is valid. +:marked + The Hero *Alter Ego* is optional so we can leave that be. + + Hero *Power* selection is required. + We can add the same kind of error handling to the `` tag. This is a requirement when using `[(ngModel)]` in combination with a form, so that we can easily refer to it in the aggregate form value and validity state. + Let's add similar `[(ngModel)]` bindings to *Alter Ego* and *Hero Power*. We'll ditch the input box binding message and add a new binding at the top to the component's `diagnostic` method. @@ -348,44 +373,33 @@ figure.image-display .l-main-section :marked - ## Track change-state and validity with **ngControl** + ## Track change-state and validity with **ngModel** A form isn't just about data binding. We'd also like to know the state of the controls on our form. - The `NgControl` directive keeps track of control state for us. -.callout.is-helpful - header NgControl requires Form - :marked - The `NgControl` is one of a family of `NgForm` directives that can only be applied to - a control within a ` tag. -:marked - Our application can ask an `NgControl` if the user touched the control, - if the value changed, or if the value became invalid. + Using `ngModel` in a form gives us more than just two way data binding. It also tells us if the user touched the control, if the value changed, or if the value became invalid. - `NgControl` doesn't just track state; it updates the control with special - Angular CSS classes from the set we listed above. + `ngModel` doesn't just track state; it updates the control with special Angular CSS classes from the set we listed above. We can leverage those class names to change the appearance of the control and make messages appear or disappear. We'll explore those effects soon. Right now - we should **add `ngControl`to all three form controls**, - starting with the *Name* input box -+makeExample('forms/js/app/hero-form.component.html', 'ngControl-1', 'app/hero-form.component.html (excerpt)')(format=".") + let's make sure we have `ngModel` and the corresponding name attribute on all three form controls, + starting with the *Name* input box. ++makeExample('forms/js/app/hero-form.component.html', 'ngModelName-1', 'app/hero-form.component.html (excerpt)')(format=".") :marked - Be sure to assign a unique name to each `ngControl` directive. + We set the `name` attribute to "name" which makes sense for our app. Any unique value will do. .l-sub-section :marked - Angular registers controls under their `ngControl` names - with the `NgForm`. - We didn't add the `NgForm` directive explicitly but it's here - and we'll talk about it [later in this chapter](#ngForm). + Internally Angular creates `FormControls` and registers them with an `NgForm` directive that Angular attached to the `` tag. Each `FormControl` is registered under the name we assigned to the `name` attribute. + We'll talk about `NgForm` [later in the chapter](#ngForm). .l-main-section :marked ## Add Custom CSS for Visual Feedback - `NgControl` doesn't just track state. + `NgModel` doesn't just track state. It updates the control with three classes that reflect the state. table @@ -409,7 +423,7 @@ table Let's add a temporary [local template variable](./template-syntax.html#local-vars) named **spy** to the "Name" `` tag and use the spy to display those classes. -+makeExample('forms/js/app/hero-form.component.html', 'ngControl-2','app/hero-form.component.html (excerpt)')(format=".") ++makeExample('forms/js/app/hero-form.component.html', 'ngModelName-2','app/hero-form.component.html (excerpt)')(format=".") :marked Now run the app and focus on the *Name* input box. @@ -472,16 +486,18 @@ figure.image-display 'app/hero-form.component.html (excerpt)', stylePattern) :marked - When we added the `ngControl` directive, we bound it to the model's `name` property. - Here we initialize a template local variable (`name`) with the value "ngForm" (`#name="ngForm"`). - Angular recognizes that syntax and re-sets the `name` local template variable to the - `ngControl` directive instance. - In other words, the `name` local template variable becomes a handle on the `ngControl` object - for this input box. - - Now we can control visibility of the "name" error message by binding the message `
` element's `hidden` property - to the `ngControl` object's `valid` property. The message is hidden while the control is valid; - the message is revealed when the control becomes invalid. + We need a template reference variable to access the input box's Angular control from within the template. + Here we created a variable called `name` and gave it the value "ngModel". +.l-sub-section + :marked + Why "ngModel"? + A directive's [exportAs](../api/core/DirectiveMetadata-class.html#!#exportAs) property + tells Angular how to link the reference variable to the directive. + We set `name` to `ngModel` because the `ngModel` directive's `exportAs` property happens to be "ngModel". + + Now we can control visibility of the "name" error message by binding properties of the `name` control to the message `
` element's `hidden` property. + + The message is hidden while the control is valid; the message is revealed when the control becomes invalid. .l-sub-section :marked @@ -492,7 +508,7 @@ figure.image-display Angular added it surreptitiously, wrapping it around the `` element The `NgForm` directive supplements the `form` element with additional features. - It collects `Controls` (elements identified by an `ngControl` directive) + It holds the controls we created for the elements with `ngModel` directive and `name` attribute and monitors their properties including their validity. It also has its own `valid` property which is true only if every contained control is valid. @@ -597,8 +613,7 @@ figure.image-display - A form component class with a `Component` decorator. - The `ngSubmit` directive for handling the form submission. - Template local variables such as `#heroForm`, `#name`, `#alter-ego` and `#power`. - - The `ngModel` directive for two-way data binding. - - The `ngControl` for validation and form element change tracking. + - The `[(ngModel)]` syntax for two-way data binding, validation and change tracking. - The local variable’s `valid` property on input controls to check if a control is valid and show/hide error messages. - Controlling the submit button's enabled state by binding to `NgForm` validity. - Custom CSS classes that provide visual feedback to users about invalid controls. diff --git a/public/docs/ts/latest/guide/_data.json b/public/docs/ts/latest/guide/_data.json index c24dd17ee4..aee44f8f1f 100644 --- a/public/docs/ts/latest/guide/_data.json +++ b/public/docs/ts/latest/guide/_data.json @@ -29,7 +29,7 @@ "basics": true }, - "forms": { + "forms-deprecated": { "title": "Forms", "intro": "A form creates a cohesive, effective, and compelling data entry experience. An Angular form coordinates a set of data-bound user controls, tracks changes, validates input, and presents errors.", "nextable": true, diff --git a/public/docs/ts/latest/guide/forms-deprecated.jade b/public/docs/ts/latest/guide/forms-deprecated.jade new file mode 100644 index 0000000000..ed3699f402 --- /dev/null +++ b/public/docs/ts/latest/guide/forms-deprecated.jade @@ -0,0 +1,718 @@ +include ../_util-fns + +.alert.is-important + :marked + This guide is using the deprecated forms API. + + We have created a new version using the new API here. + +:marked + We’ve all used a form to login, submit a help request, place an order, book a flight, + schedule a meeting and perform countless other data entry tasks. + Forms are the mainstay of business applications. + + Any seasoned web developer can slap together an HTML form with all the right tags. + It's more challenging to create a cohesive data entry experience that guides the + user efficiently and effectively through the workflow behind the form. + + *That* takes design skills that are, to be frank, well out of scope for this chapter. + + It also takes framework support for + **two-way data binding, change tracking, validation, and error handling** + ... which we shall cover in this chapter on Angular forms. + + We will build a simple form from scratch, one step at a time. Along the way we'll learn + + - to build an Angular form with a component and template + + - two-way data binding with `[(ngModel)]` syntax for reading and writing values to input controls + + - using `ngControl` to track the change state and validity of form controls + + - the special CSS classes that `ngControl` adds to form controls and how we can use them to provide strong visual feedback + + - displaying validation errors to users and enable/disable form controls + + - sharing information among controls with template reference variables + + [Live Example](/resources/live-examples/forms-deprecated/ts/plnkr.html) +.l-main-section +:marked + ## Template-Driven Forms + + Many of us will build forms by writing templates in the Angular [template syntax](./template-syntax.html) with + the form-specific directives and techniques described in this chapter. +.l-sub-section + :marked + That's not the only way to create a form but it's the way we'll cover in this chapter. +:marked + We can build almost any form we need with an Angular template — login forms, contact forms ... pretty much any business forms. + We can lay out the controls creatively, bind them to data, specify validation rules and display validation errors, + conditionally enable or disable specific controls, trigger built-in visual feedback, and much more. + + It will be pretty easy because Angular handles many of the repetitive, boiler plate tasks we'd + otherwise wrestle with ourselves. + + We'll discuss and learn to build the following template-driven form: + +figure.image-display + img(src="/resources/images/devguide/forms/hero-form-1.png" width="400px" alt="Clean Form") + +:marked + Here at the *Hero Employment Agency* we use this form to maintain personal information about the + heroes in our stable. Every hero needs a job. It's our company mission to match the right hero with the right crisis! + + Two of the three fields on this form are required. Required fields have a green bar on the left to make them easy to spot. + + If we delete the hero name, the form displays a validation error in an attention grabbing style: + +figure.image-display + img(src="/resources/images/devguide/forms/hero-form-2.png" width="400px" alt="Invalid, Name Required") + +:marked + Note that the submit button is disabled and the "required" bar to the left of the input control changed from green to red. + +.l-sub-section + p We'll customize the colors and location of the "required" bar with standard CSS. + +:marked + We will build this form in the following sequence of small steps + + 1. Create the `Hero` model class + 1. Create the component that controls the form + 1. Create a template with the initial form layout + 1. Bind data properties to each form input control with the `ngModel` two-way data binding syntax + 1. Add the **ngControl** directive to each form input control + 1. Add custom CSS to provide visual feedback + 1. Show and hide validation error messages + 1. Handle form submission with **ngSubmit** + 1. Disable the form’s submit button until the form is valid + +:marked + ## Setup + Create a new project folder (`angular2-forms`) and follow the steps in the [QuickStart](../quickstart.html). + +include ../_quickstart_repo +:marked + ## Create the Hero Model Class + + As users enter form data, we capture their changes and update an instance of a model. + We can't layout the form until we know what the model looks like. + + A model can be as simple as a "property bag" that holds facts about a thing of application importance. + That describes well our `Hero` class with its three required fields (`id`, `name`, `power`) + and one optional field (`alterEgo`). + + Create a new file in the app folder called `hero.ts` and give it the following class definition: + ++makeExample('forms-deprecated/ts/app/hero.ts', null, 'app/hero.ts') + +:marked + It's an anemic model with few requirements and no behavior. Perfect for our demo. + + The TypeScript compiler generates a public field for each `public` constructor parameter and + assigns the parameter’s value to that field automatically when we create new heroes. + + The `alterEgo` is optional and the constructor lets us omit it; note the (?) in `alterEgo?`. + + We can create a new hero like this: +code-example(format=""). + let myHero = new Hero(42, 'SkyDog', + 'Fetch any object at any distance', 'Leslie Rollover'); + console.log('My hero is called ' + myHero.name); // "My hero is called SkyDog" +:marked + +.l-main-section +:marked + ## Create a Form component + + An Angular form has two parts: an HTML-based template and a code-based Component to handle data and user interactions. + + We begin with the Component because it states, in brief, what the Hero editor can do. + + Create a new file called `hero-form.component.ts` and give it the following definition: + ++makeExample('forms-deprecated/ts/app/hero-form.component.ts', 'first', 'app/hero-form.component.ts') + +:marked + There’s nothing special about this component, nothing form-specific, nothing to distinguish it from any component we've written before. + + Understanding this component requires only the Angular 2 concepts we’ve learned in previous chapters + + 1. We import the `Component` decorator from the Angular library as we usually do. + + 1. The `@Component` selector value of "hero-form" means we can drop this form in a parent template with a `` tag. + + 1. The `templateUrl` property points to a separate file for template HTML called `hero-form.component.html`. + + 1. We defined dummy data for `model` and `powers` as befits a demo. + Down the road, we can inject a data service to get and save real data + or perhaps expose these properties as [inputs and outputs](./template-syntax.html#inputs-outputs) for binding to a + parent component. None of this concerns us now and these future changes won't affect our form. + + 1. We threw in a `diagnostic` property at the end to return a JSON representation of our model. + It'll help us see what we're doing during our development; we've left ourselves a cleanup note to discard it later. + + Why don't we write the template inline in the component file as we often do + elsewhere in the Developer Guide? + + There is no “right” answer for all occasions. We like inline templates when they are short. + Most form templates won't be short. TypeScript and JavaScript files generally aren't the best place to + write (or read) large stretches of HTML and few editors are much help with files that have a mix of HTML and code. + We also like short files with a clear and obvious purpose like this one. + + We made a good choice to put the HTML template elsewhere. + We'll write that template in a moment. Before we do, we'll take a step back + and revise the `app.component.ts` to make use of our new `HeroFormComponent`. + +.l-main-section +:marked + ## Revise the *app.component.ts* + + `app.component.ts` is the application's root component. It will host our new `HeroFormComponent`. + + Replace the contents of the "QuickStart" version with the following: ++makeExample('forms-deprecated/ts/app/app.component.ts', null, 'app/app.component.ts') + +:marked +.l-sub-section + :marked + There are only three changes: + + 1. We import the new `HeroFormComponent`. + + 1. The `template` is simply the new element tag identified by the component's `selector` property. + + 1. The `directives` array tells Angular that our template depends upon the `HeroFormComponent` + which is itself a Directive (as are all Components). + +.l-main-section +:marked + ## Create an initial HTML Form Template + + Create a new template file called `hero-form.component.html` and give it the following definition: + ++makeExample('forms-deprecated/ts/app/hero-form.component.html', 'start', 'app/hero-form.component.html') + +:marked + That is plain old HTML 5. We're presenting two of the `Hero` fields, `name` and `alterEgo`, and + opening them up for user input in input boxes. + + The *Name* `` control has the HTML5 `required` attribute; + the *Alter Ego* `` control does not because `alterEgo` is optional. + + We've got a *Submit* button at the bottom with some classes on it. + + **We are not using Angular yet**. There are no bindings. No extra directives. Just layout. + + The `container`,`form-group`, `form-control`, and `btn` classes + come from [Twitter Bootstrap](http://getbootstrap.com/css/). Purely cosmetic. + We're using Bootstrap to gussy up our form. + Hey, what's a form without a little style! + +.callout.is-important + header Angular Forms Do Not Require A Style Library + :marked + Angular makes no use of the `container`, `form-group`, `form-control`, and `btn` classes or + the styles of any external library. Angular apps can use any CSS library + ... or none at all. + +:marked + Let's add the stylesheet. + +ol + li Open a terminal window in the application root folder and enter the command: + code-example(language="html" escape="html"). + npm install bootstrap --save + li Open index.html and add the following link to the <head>. + +makeExample('forms-deprecated/ts/index.html', 'bootstrap')(format=".") +:marked +.l-main-section +:marked + ## Add Powers with ***ngFor** + Our hero may choose one super power from a fixed list of Agency-approved powers. + We maintain that list internally (in `HeroFormComponent`). + + We'll add a `select` to our + form and bind the options to the `powers` list using `ngFor`, + a technique we might have seen before in the [Displaying Data](./displaying-data.html) chapter. + + Add the following HTML *immediately below* the *Alter Ego* group. ++makeExample('forms-deprecated/ts/app/hero-form.component.html', 'powers', 'app/hero-form.component.html (excerpt)')(format=".") + +:marked + We are repeating the `` tag for each power in the list of Powers. + The `p` template input variable is a different power in each iteration; + we display its name using the interpolation syntax with the double-curly-braces. + + +.l-main-section +:marked + ## Two-way data binding with **ngModel** + Running the app right now would be disappointing. + +figure.image-display + img(src="/resources/images/devguide/forms/hero-form-3.png" width="400px" alt="Early form with no binding") +:marked + We don't see hero data because we are not binding to the `Hero` yet. + We know how to do that from earlier chapters. + [Displaying Data](./displaying-data.html) taught us Property Binding. + [User Input](./user-input.html) showed us how to listen for DOM events with an + Event Binding and how to update a component property with the displayed value. + + Now we need to display, listen, and extract at the same time. + + We could use those techniques again in our form. + Instead we'll introduce something new, the `[(ngModel)]` syntax, that + makes binding our form to the model super-easy. + + Find the `` tag for the "Name" and update it like this + ++makeExample('forms-deprecated/ts/app/hero-form.component.html', 'ngModel-1','app/hero-form.component.html (excerpt)')(format=".") + +.l-sub-section + :marked + We appended a diagnostic interpolation after the input tag + so we can see what we're doing. + We left ourselves a note to throw it away when we're done. + +:marked + Focus on the binding syntax: `[(ngModel)]="..."`. + + If we ran the app right now and started typing in the *Name* input box, + adding and deleting characters, we'd see them appearing and disappearing + from the interpolated text. + At some point it might look like this. +figure.image-display + img(src="/resources/images/devguide/forms/ng-model-in-action.png" width="400px" alt="ngModel in action") +:marked + The diagnostic is evidence that we really are flowing values from the input box to the model and + back again. **That's two-way data binding!** + + Let's add similar `[(ngModel)]` bindings to *Alter Ego* and *Hero Power*. + We'll ditch the input box binding message + and add a new binding at the top to the component's `diagnostic` property. + Then we can confirm that two-way data binding works *for the entire Hero model*. + + After revision the core of our form should have three `[(ngModel)]` bindings that + look much like this: + ++makeExample('forms-deprecated/ts/app/hero-form.component.html', 'ngModel-2', 'app/hero-form.component.html (excerpt)') + +:marked + If we ran the app right now and changed every Hero model property, the form might display like this: +figure.image-display + img(src="/resources/images/devguide/forms/ng-model-in-action-2.png" width="400px" alt="ngModel in super action") +:marked + The diagnostic near the top of the form + confirms that all of our changes are reflected in the model. + + **Delete** the `{{diagnostic}}` binding at the top as it has served its purpose. + +.l-sub-section + :marked + ### Inside [(ngModel)] + *This section is an optional deep dive into [(ngModel)]. Not interested? Skip ahead!* + + The punctuation in the binding syntax, [()], is a good clue to what's going on. + + In a Property Binding, a value flows from the model to a target property on screen. + We identify that target property by surrounding its name in brackets, []. + This is a one-way data binding **from the model to the view**. + + In an Event Binding, we flow the value from the target property on screen to the model. + We identify that target property by surrounding its name in parentheses, (). + This is a one-way data binding in the opposite direction **from the view to the model**. + + No wonder Angular chose to combine the punctuation as [()] + to signify a two-way data binding and a **flow of data in both directions**. + + In fact, we can break the `NgModel` binding into its two separate modes + as we do in this re-write of the "Name" `` binding: + +makeExample('forms-deprecated/ts/app/hero-form.component.html', 'ngModel-3','app/hero-form.component.html (excerpt)')(format=".") + + :marked +
The Property Binding should feel familiar. The Event Binding might seem strange. + + The `ngModelChange` is not an `` element event. + It is actually an event property of the `NgModel` directive. + When Angular sees a binding target in the form [(x)], + it expects the `x` directive to have an `x` input property and an `xChange` output property. + + The other oddity is the template expression, `model.name = $event`. + We're used to seeing an `$event` object coming from a DOM event. + The `ngModelChange` property doesn't produce a DOM event; it's an Angular `EventEmitter` + property that returns the input box value when it fires — which is precisely what + we should assign to the model's `name` property. + + Nice to know but is it practical? We almost always prefer `[(ngModel)]`. + We might split the binding if we had to do something special in + the event handling such as debounce or throttle the key strokes. + + Learn more about `NgModel` and other template syntax in the + [Template Syntax](./template-syntax.html) chapter. + +.l-main-section +:marked + ## Track change-state and validity with **ngControl** + + A form isn't just about data binding. We'd also like to know the state of the controls on our form. + + By setting `ngControl` we create a directive that can tell if the user touched the control, + if the value changed, or if the value became invalid. + + This directive doesn't just track state; it updates the control with special + Angular CSS classes from the set we listed above. + We can leverage those class names to change the appearance of the + control and make messages appear or disappear. + + We'll explore those effects soon. Right now + we should **add `ngControl` to all three form controls**, + starting with the *Name* input box ++makeExample('forms-deprecated/ts/app/hero-form.component.html', 'ngControl-1', 'app/hero-form.component.html (excerpt)')(format=".") +:marked + We set this particular `ngControl` to "name" which makes sense for our app. Any unique value will do. + +.l-sub-section + :marked + Internally Angular creates `Controls` and registers them under their `ngControl` names + with an `NgForm` directive that Angular attached to the `` tag. + We'll talk about `NgForm` [later in the chapter](#ngForm). + + The `ngControl` *attribute* in our template actually maps to the + [NgControlName](../api/common/NgControlName-directive.html) directive. + There is also a `NgControl` *abstract* directive which is *not the same thing*. + We often ignore this technical distinction and refer to `NgControlName` more conveniently (albeit incorrectly) as the *NgControl* directive. + + While we're under the hood, we might as well note that the `ngModel` in the + two-way binding syntax is now a property of the `NgControlName` directive. + The `NgModel` directive is no longer involved. We only need one directive to manage the DOM element + and there is no practical difference in the way either directive handles data binding. + +.l-main-section +:marked + ## Add Custom CSS for Visual Feedback + + The *NgControl* directive doesn't just track state. + It updates the control with three classes that reflect the state. + +table + tr + th State + th Class if true + th Class if false + tr + td Control has been visited + td ng-touched + td ng-untouched + tr + td Control's value has changed + td ng-dirty + td ng-pristine + tr + td Control's value is valid + td ng-valid + td ng-invalid +:marked + Let's add a temporary [template reference variable](./template-syntax.html#ref-vars) named **spy** + to the "Name" `` tag and use the spy to display those classes. + ++makeExample('forms-deprecated/ts/app/hero-form.component.html', 'ngControl-2','app/hero-form.component.html (excerpt)')(format=".") + +:marked + Now run the app and focus on the *Name* input box. + Follow the next four steps *precisely* + + 1. Look but don't touch + 1. Click in the input box, then click outside the text input box + 1. Add slashes to the end of the name + 1. Erase the name + + The actions and effects are as follows: +figure.image-display + img(src="/resources/images/devguide/forms/control-state-transitions-anim.gif" alt="Control State Transition") +:marked + We should be able to see the following four sets of class names and their transitions: +figure.image-display + img(src="/resources/images/devguide/forms/ng-control-class-changes.png" width="400px" alt="Control State Transitions") + +:marked + The (`ng-valid` | `ng-invalid`) pair are most interesting to us. We want to send a + strong visual signal when the data are invalid and we want to mark required fields. + + We realize we can do both at the same time with a colored bar on the left of the input box: + +figure.image-display + img(src="/resources/images/devguide/forms/validity-required-indicator.png" width="400px" alt="Invalid Form") + +:marked + We achieve this effect by adding two styles to a new `forms.css` file + that we add to our project as a sibling to `index.html`. + ++makeExample('forms-deprecated/ts/forms.css',null,'forms.css')(format=".") +:marked + These styles select for the two Angular validity classes and the HTML 5 "required" attribute. + + We update the `` of the `index.html` to include this style sheet. ++makeExample('forms-deprecated/ts/index.html', 'styles', 'index.html (excerpt)')(format=".") +:marked + ## Show and Hide Validation Error messages + + We can do better. + + The "Name" input box is required. Clearing it turns the bar red. That says *something* is wrong but we + don't know *what* is wrong or what to do about it. + We can leverage the `ng-invalid` class to reveal a helpful message. + + Here's the way it should look when the user deletes the name: +figure.image-display + img(src="/resources/images/devguide/forms/name-required-error.png" width="400px" alt="Name required") + +:marked + To achieve this effect we extend the `` tag with + 1. a [template reference variable](./template-syntax.html#ref-vars) + 1. the "*is required*" message in a nearby `
` which we'll display only if the control is invalid. + + Here's how we do it for the *name* input box: ++makeExample('forms-deprecated/ts/app/hero-form.component.html', + 'name-with-error-msg', + 'app/hero-form.component.html (excerpt)')(format=".") +:marked + We need a template reference variable to access the input box's Angular control from within the template. + Here we created a variable called `name` and gave it the value "ngForm". +.l-sub-section + :marked + Why "ngForm"? + A directive's [exportAs](../api/core/DirectiveMetadata-class.html#!#exportAs) property + tells Angular how to link the reference variable to the directive. + We set `name` to `ngForm` because the `NgControlName` directive's `exportAs` property happens to be "ngForm". + + This seems unintuitive at first until we realize that *all* control directives in the + Angular form family — including `NgForm`, `NgModel`, `NgControlName` and `NgControlGroup` — *exportAs* "ngForm" + and we only ever apply *one* of these directives to an element tag. + Consistency rules! + + Now we can control visibility of the "name" error message by binding properties of the `name` control to the message `
` element's `hidden` property. ++makeExample('forms-deprecated/ts/app/hero-form.component.html', + 'hidden-error-msg', + 'app/hero-form.component.html (excerpt)') +:marked + In this example, we hide the message when the control is valid or pristine; + pristine means the user hasn't changed the value since it was displayed in this form. + + This user experience is the developer's choice. Some folks want to see the message at all times. + If we ignore the `pristine` state, we would hide the message only when the value is valid. + If we arrive in this component with a new (blank) hero or an invalid hero, + we'll see the error message immediately, before we've done anything. + + Some folks find that behavior disconcerting. They only want to see the message when the user makes an invalid change. + Hiding the message while the control is "pristine" achieves that goal. + We'll see the significance of this choice when we [add a new hero](#new-hero) to the form. + + The Hero *Alter Ego* is optional so we can leave that be. + + Hero *Power* selection is required. + We can add the same kind of error handling to the `` tag. This is a requirement when using `[(ngModel)]` in combination with a form, so that we can easily refer to it in the aggregate form value and validity state. + Let's add similar `[(ngModel)]` bindings to *Alter Ego* and *Hero Power*. We'll ditch the input box binding message and add a new binding at the top to the component's `diagnostic` property. @@ -348,46 +374,33 @@ figure.image-display .l-main-section :marked - ## Track change-state and validity with **ngControl** + ## Track change-state and validity with **ngModel** A form isn't just about data binding. We'd also like to know the state of the controls on our form. - By setting `ngControl` we create a directive that can tell if the user touched the control, - if the value changed, or if the value became invalid. + Using `ngModel` in a form gives us more than just two way data binding. It also tells us if the user touched the control, if the value changed, or if the value became invalid. - This directive doesn't just track state; it updates the control with special - Angular CSS classes from the set we listed above. + `ngModel` doesn't just track state; it updates the control with special Angular CSS classes from the set we listed above. We can leverage those class names to change the appearance of the control and make messages appear or disappear. We'll explore those effects soon. Right now - we should **add `ngControl` to all three form controls**, - starting with the *Name* input box -+makeExample('forms/ts/app/hero-form.component.html', 'ngControl-1', 'app/hero-form.component.html (excerpt)')(format=".") + let's make sure we have `ngModel` and the corresponding name attribute on all three form controls, + starting with the *Name* input box. ++makeExample('forms/ts/app/hero-form.component.html', 'ngModelName-1', 'app/hero-form.component.html (excerpt)')(format=".") :marked - We set this particular `ngControl` to "name" which makes sense for our app. Any unique value will do. + We set the `name` attribute to "name" which makes sense for our app. Any unique value will do. .l-sub-section :marked - Internally Angular creates `Controls` and registers them under their `ngControl` names - with an `NgForm` directive that Angular attached to the `` tag. + Internally Angular creates `FormControls` and registers them with an `NgForm` directive that Angular attached to the `` tag. Each `FormControl` is registered under the name we assigned to the `name` attribute. We'll talk about `NgForm` [later in the chapter](#ngForm). - The `ngControl` *attribute* in our template actually maps to the - [NgControlName](../api/common/NgControlName-directive.html) directive. - There is also a `NgControl` *abstract* directive which is *not the same thing*. - We often ignore this technical distinction and refer to `NgControlName` more conveniently (albeit incorrectly) as the *NgControl* directive. - - While we're under the hood, we might as well note that the `ngModel` in the - two-way binding syntax is now a property of the `NgControlName` directive. - The `NgModel` directive is no longer involved. We only need one directive to manage the DOM element - and there is no practical difference in the way either directive handles data binding. - .l-main-section :marked ## Add Custom CSS for Visual Feedback - The *NgControl* directive doesn't just track state. + The *NgModel* directive doesn't just track state. It updates the control with three classes that reflect the state. table @@ -411,7 +424,7 @@ table Let's add a temporary [template reference variable](./template-syntax.html#ref-vars) named **spy** to the "Name" `` tag and use the spy to display those classes. -+makeExample('forms/ts/app/hero-form.component.html', 'ngControl-2','app/hero-form.component.html (excerpt)')(format=".") ++makeExample('forms/ts/app/hero-form.component.html', 'ngModelName-2','app/hero-form.component.html (excerpt)')(format=".") :marked Now run the app and focus on the *Name* input box. @@ -473,18 +486,13 @@ figure.image-display 'app/hero-form.component.html (excerpt)')(format=".") :marked We need a template reference variable to access the input box's Angular control from within the template. - Here we created a variable called `name` and gave it the value "ngForm". + Here we created a variable called `name` and gave it the value "ngModel". .l-sub-section :marked - Why "ngForm"? + Why "ngModel"? A directive's [exportAs](../api/core/DirectiveMetadata-class.html#!#exportAs) property tells Angular how to link the reference variable to the directive. - We set `name` to `ngForm` because the `NgControlName` directive's `exportAs` property happens to be "ngForm". - - This seems unintuitive at first until we realize that *all* control directives in the - Angular form family — including `NgForm`, `NgModel`, `NgControlName` and `NgControlGroup` — *exportAs* "ngForm" - and we only ever apply *one* of these directives to an element tag. - Consistency rules! + We set `name` to `ngModel` because the `ngModel` directive's `exportAs` property happens to be "ngModel". Now we can control visibility of the "name" error message by binding properties of the `name` control to the message `
` element's `hidden` property. +makeExample('forms/ts/app/hero-form.component.html', @@ -588,7 +596,7 @@ figure.image-display Angular did. Angular creates and attaches an `NgForm` directive to the `` tag automatically. The `NgForm` directive supplements the `form` element with additional features. - It holds the controls we created for the elements with `ngControl` attributes + It holds the controls we created for the elements with `ngModel` directive and `name` attribute and monitors their properties including their validity. It also has its own `valid` property which is true only *if every contained control* is valid. @@ -667,8 +675,7 @@ figure.image-display - A form component class with a `Component` decorator. - The `ngSubmit` directive for handling the form submission. - Template reference variables such as `#heroForm`, `#name`, `#alter-ego` and `#power`. - - The `[(ngModel)]` syntax for two-way data binding. - - The `ngControlName` directive for validation and form element change tracking. + - The `[(ngModel)]` syntax for two-way data binding, validation and change tracking. - The reference variable’s `valid` property on input controls to check if a control is valid and show/hide error messages. - Controlling the submit button's enabled state by binding to `NgForm` validity. - Custom CSS classes that provide visual feedback to users about invalid controls. From e4f2a22014865e16b87a0bd72ad9cfc493fb8a7f Mon Sep 17 00:00:00 2001 From: Ricardo Torres Date: Wed, 22 Jun 2016 10:42:26 -0500 Subject: [PATCH 21/21] fix(docs) router-deprecated still in rc.2 --- public/docs/_examples/quickstart/js/package.1.json | 2 +- public/docs/_examples/quickstart/ts/package.1.json | 2 +- public/docs/_examples/webpack/ts/package.webpack.json | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/public/docs/_examples/quickstart/js/package.1.json b/public/docs/_examples/quickstart/js/package.1.json index 13b8bc64f2..b5b25a4f10 100644 --- a/public/docs/_examples/quickstart/js/package.1.json +++ b/public/docs/_examples/quickstart/js/package.1.json @@ -15,7 +15,7 @@ "@angular/platform-browser": "2.0.0-rc.3", "@angular/platform-browser-dynamic": "2.0.0-rc.3", "@angular/router": "3.0.0-alpha.7", - "@angular/router-deprecated": "2.0.0-rc.3", + "@angular/router-deprecated": "2.0.0-rc.2", "@angular/upgrade": "2.0.0-rc.3", "core-js": "^2.4.0", diff --git a/public/docs/_examples/quickstart/ts/package.1.json b/public/docs/_examples/quickstart/ts/package.1.json index ce3cf6edba..9353dfaa3e 100644 --- a/public/docs/_examples/quickstart/ts/package.1.json +++ b/public/docs/_examples/quickstart/ts/package.1.json @@ -19,7 +19,7 @@ "@angular/platform-browser": "2.0.0-rc.3", "@angular/platform-browser-dynamic": "2.0.0-rc.3", "@angular/router": "3.0.0-alpha.7", - "@angular/router-deprecated": "2.0.0-rc.3", + "@angular/router-deprecated": "2.0.0-rc.2", "@angular/upgrade": "2.0.0-rc.3", "systemjs": "0.19.27", diff --git a/public/docs/_examples/webpack/ts/package.webpack.json b/public/docs/_examples/webpack/ts/package.webpack.json index 347d300ca1..4064a86611 100644 --- a/public/docs/_examples/webpack/ts/package.webpack.json +++ b/public/docs/_examples/webpack/ts/package.webpack.json @@ -17,7 +17,7 @@ "@angular/http": "2.0.0-rc.3", "@angular/platform-browser": "2.0.0-rc.3", "@angular/platform-browser-dynamic": "2.0.0-rc.3", - "@angular/router-deprecated": "2.0.0-rc.3", + "@angular/router-deprecated": "2.0.0-rc.2", "core-js": "^2.4.0", "reflect-metadata": "0.1.2", "rxjs": "5.0.0-beta.6",