feat(pipe): added the Pipe decorator and the pipe property to View

BREAKING CHANGE:
    Instead of configuring pipes via a Pipes object, now you can configure them by providing the pipes property to the View decorator.

    @Pipe({
      name: 'double'
    })
    class DoublePipe {
      transform(value, args) { return value * 2; }
    }

    @View({
      template: '{{ 10 | double}}'
      pipes: [DoublePipe]
    })
    class CustomComponent {}

Closes #3572
This commit is contained in:
vsavkin
2015-08-07 11:41:38 -07:00
committed by Victor Savkin
parent 02b7e61ef7
commit 5b5d31fa9a
62 changed files with 627 additions and 524 deletions
@@ -6,5 +6,6 @@
export {
Component as ComponentAnnotation,
Directive as DirectiveAnnotation,
Pipe as PipeAnnotation,
LifecycleEvent
} from '../annotations_impl/annotations';
@@ -1,4 +1,9 @@
import {ComponentAnnotation, DirectiveAnnotation, LifecycleEvent} from './annotations';
import {
ComponentAnnotation,
DirectiveAnnotation,
PipeAnnotation,
LifecycleEvent
} from './annotations';
import {ViewAnnotation} from './view';
import {AttributeAnnotation, QueryAnnotation, ViewQueryAnnotation} from './di';
import {makeDecorator, makeParamDecorator, TypeDecorator, Class} from '../../util/decorators';
@@ -25,6 +30,7 @@ export interface ComponentDecorator extends TypeDecorator {
templateUrl?: string,
template?: string,
directives?: List<Type | any | List<any>>,
pipes?: List<Type | any | List<any>>,
renderer?: string,
styles?: List<string>,
styleUrls?: List<string>,
@@ -44,6 +50,7 @@ export interface ViewDecorator extends TypeDecorator {
templateUrl?: string,
template?: string,
directives?: List<Type | any | List<any>>,
pipes?: List<Type | any | List<any>>,
renderer?: string,
styles?: List<string>,
styleUrls?: List<string>,
@@ -337,6 +344,30 @@ export interface QueryFactory {
new (selector: Type | string, {descendants}?: {descendants?: boolean}): QueryAnnotation;
}
/**
* {@link Pipe} factory for creating decorators.
*
* ## Example as TypeScript Decorator
*
* ```
* import {Pipe} from "angular2/angular2";
*
* @Pipe({...})
* class MyPipe {
* constructor() {
* ...
* }
*
* transform(v, args) {}
* }
* ```
*/
export interface PipeFactory {
(obj: {name: string}): any;
new (obj: {
name: string,
}): any;
}
/**
* {@link Component} factory function.
@@ -369,3 +400,8 @@ export var Query: QueryFactory = makeParamDecorator(QueryAnnotation);
* {@link ViewQuery} factory function.
*/
export var ViewQuery: QueryFactory = makeParamDecorator(ViewQueryAnnotation);
/**
* {@link Pipe} factory function.
*/
export var Pipe: PipeFactory = <PipeFactory>makeDecorator(PipeAnnotation);
@@ -1030,3 +1030,27 @@ export enum LifecycleEvent {
*/
onAllChangesDone
}
/**
* Declare reusable pipe function.
*
* ## Example
*
* ```
* @Pipe({
* name: 'lowercase'
* })
* class Lowercase {
* transform(v, args) { return v.toLowerCase(); }
* }
* ```
*/
@CONST()
export class Pipe extends InjectableMetadata {
name: string;
constructor({name}: {name: string}) {
super();
this.name = name;
}
}
@@ -87,6 +87,8 @@ export class View {
// for an unused import.
directives: List<Type | any | List<any>>;
pipes: List<Type | any | List<any>>;
/**
* Specify how the template and the styles should be encapsulated.
* The default is {@link ViewEncapsulation#EMULATED `ViewEncapsulation.EMULATED`} if the view
@@ -95,10 +97,11 @@ export class View {
*/
encapsulation: ViewEncapsulation;
constructor({templateUrl, template, directives, encapsulation, styles, styleUrls}: {
constructor({templateUrl, template, directives, pipes, encapsulation, styles, styleUrls}: {
templateUrl?: string,
template?: string,
directives?: List<Type | any | List<any>>,
pipes?: List<Type | any | List<any>>,
encapsulation?: ViewEncapsulation,
styles?: List<string>,
styleUrls?: List<string>,
@@ -108,6 +111,7 @@ export class View {
this.styleUrls = styleUrls;
this.styles = styles;
this.directives = directives;
this.pipes = pipes;
this.encapsulation = encapsulation;
}
}
@@ -21,19 +21,19 @@ import {
DynamicChangeDetection,
JitChangeDetection,
PreGeneratedChangeDetection,
Pipes,
defaultPipes,
IterableDiffers,
defaultIterableDiffers,
KeyValueDiffers,
defaultKeyValueDiffers
} from 'angular2/src/change_detection/change_detection';
import {DEFAULT_PIPES} from 'angular2/pipes';
import {ExceptionHandler} from './exception_handler';
import {ViewLoader} from 'angular2/src/render/dom/compiler/view_loader';
import {StyleUrlResolver} from 'angular2/src/render/dom/compiler/style_url_resolver';
import {StyleInliner} from 'angular2/src/render/dom/compiler/style_inliner';
import {ViewResolver} from './compiler/view_resolver';
import {DirectiveResolver} from './compiler/directive_resolver';
import {PipeResolver} from './compiler/pipe_resolver';
import {List, ListWrapper} from 'angular2/src/facade/collection';
import {Promise, PromiseWrapper, PromiseCompleter} from 'angular2/src/facade/async';
import {NgZone} from 'angular2/src/core/zone/ng_zone';
@@ -137,12 +137,13 @@ function _injectorBindings(appComponentType): List<Type | Binding | List<any>> {
Compiler,
CompilerCache,
ViewResolver,
defaultPipes,
DEFAULT_PIPES,
bind(IterableDiffers).toValue(defaultIterableDiffers),
bind(KeyValueDiffers).toValue(defaultKeyValueDiffers),
bind(ChangeDetection).toClass(bestChangeDetection),
ViewLoader,
DirectiveResolver,
PipeResolver,
Parser,
Lexer,
bind(ExceptionHandler).toFactory(() => new ExceptionHandler(DOM, isDart ? false : true), []),
+35 -30
View File
@@ -1,4 +1,4 @@
import {Binding, resolveForwardRef, Injectable} from 'angular2/di';
import {Binding, resolveForwardRef, Injectable, Inject} from 'angular2/di';
import {
Type,
isBlank,
@@ -19,6 +19,7 @@ import {AppProtoView, AppProtoViewMergeMapping} from './view';
import {ProtoViewRef} from './view_ref';
import {DirectiveBinding} from './element_injector';
import {ViewResolver} from './view_resolver';
import {PipeResolver} from './pipe_resolver';
import {View} from '../annotations_impl/view';
import {ComponentUrlMapper} from './component_url_mapper';
import {ProtoViewFactory} from './proto_view_factory';
@@ -26,6 +27,8 @@ import {UrlResolver} from 'angular2/src/services/url_resolver';
import {AppRootUrl} from 'angular2/src/services/app_root_url';
import {ElementBinder} from './element_binder';
import {wtfStartTimeRange, wtfEndTimeRange} from '../../profile/profile';
import {PipeBinding} from '../pipes/pipe_binding';
import {DEFAULT_PIPES_TOKEN} from 'angular2/pipes';
import * as renderApi from 'angular2/src/render/api';
@@ -83,46 +86,40 @@ export class CompilerCache {
*/
@Injectable()
export class Compiler {
private _reader: DirectiveResolver;
private _compilerCache: CompilerCache;
private _compiling: Map<Type, Promise<AppProtoView>>;
private _viewResolver: ViewResolver;
private _componentUrlMapper: ComponentUrlMapper;
private _urlResolver: UrlResolver;
private _compiling: Map<Type, Promise<AppProtoView>> = new Map();
private _appUrl: string;
private _render: renderApi.RenderCompiler;
private _protoViewFactory: ProtoViewFactory;
private _defaultPipes: Type[];
/**
* @private
*/
constructor(reader: DirectiveResolver, cache: CompilerCache, viewResolver: ViewResolver,
componentUrlMapper: ComponentUrlMapper, urlResolver: UrlResolver,
render: renderApi.RenderCompiler, protoViewFactory: ProtoViewFactory,
appUrl: AppRootUrl) {
this._reader = reader;
this._compilerCache = cache;
this._compiling = new Map();
this._viewResolver = viewResolver;
this._componentUrlMapper = componentUrlMapper;
this._urlResolver = urlResolver;
constructor(private _directiveResolver: DirectiveResolver, private _pipeResolver: PipeResolver,
@Inject(DEFAULT_PIPES_TOKEN) _defaultPipes: Type[],
private _compilerCache: CompilerCache, private _viewResolver: ViewResolver,
private _componentUrlMapper: ComponentUrlMapper, private _urlResolver: UrlResolver,
private _render: renderApi.RenderCompiler,
private _protoViewFactory: ProtoViewFactory, appUrl: AppRootUrl) {
this._defaultPipes = _defaultPipes;
this._appUrl = appUrl.value;
this._render = render;
this._protoViewFactory = protoViewFactory;
}
private _bindDirective(directiveTypeOrBinding): DirectiveBinding {
if (directiveTypeOrBinding instanceof DirectiveBinding) {
return directiveTypeOrBinding;
} else if (directiveTypeOrBinding instanceof Binding) {
let annotation = this._reader.resolve(directiveTypeOrBinding.token);
let annotation = this._directiveResolver.resolve(directiveTypeOrBinding.token);
return DirectiveBinding.createFromBinding(directiveTypeOrBinding, annotation);
} else {
let annotation = this._reader.resolve(directiveTypeOrBinding);
let annotation = this._directiveResolver.resolve(directiveTypeOrBinding);
return DirectiveBinding.createFromType(directiveTypeOrBinding, annotation);
}
}
private _bindPipe(typeOrBinding): PipeBinding {
let meta = this._pipeResolver.resolve(typeOrBinding);
return PipeBinding.createFromType(typeOrBinding, meta);
}
// Create a hostView as if the compiler encountered <hostcmp></hostcmp>.
// Used for bootstrapping.
compileInHost(componentTypeOrBinding: Type | Binding): Promise<ProtoViewRef> {
@@ -143,7 +140,7 @@ export class Compiler {
this._render.compileHost(directiveMetadata)
.then((hostRenderPv) => {
var protoViews = this._protoViewFactory.createAppProtoViews(
componentBinding, hostRenderPv, [componentBinding]);
componentBinding, hostRenderPv, [componentBinding], []);
return this._compileNestedProtoViews(protoViews, componentType, new Map());
})
.then((appProtoView) => {
@@ -186,14 +183,17 @@ export class Compiler {
}
var boundDirectives = this._removeDuplicatedDirectives(
ListWrapper.map(directives, (directive) => this._bindDirective(directive)));
directives.map(directive => this._bindDirective(directive)));
var pipes = this._flattenPipes(view);
var boundPipes = pipes.map(pipe => this._bindPipe(pipe));
var renderTemplate = this._buildRenderTemplate(component, view, boundDirectives);
resultPromise =
this._render.compile(renderTemplate)
.then((renderPv) => {
var protoViews = this._protoViewFactory.createAppProtoViews(
componentBinding, renderPv, boundDirectives);
componentBinding, renderPv, boundDirectives, boundPipes);
return this._compileNestedProtoViews(protoViews, component, componentPath);
})
.then((appProtoView) => {
@@ -317,12 +317,17 @@ export class Compiler {
});
}
private _flattenDirectives(template: View): List<Type> {
if (isBlank(template.directives)) return [];
private _flattenPipes(view: View): any[] {
if (isBlank(view.pipes)) return this._defaultPipes;
var pipes = ListWrapper.clone(this._defaultPipes);
this._flattenList(view.pipes, pipes);
return pipes;
}
private _flattenDirectives(view: View): List<Type> {
if (isBlank(view.directives)) return [];
var directives = [];
this._flattenList(template.directives, directives);
this._flattenList(view.directives, directives);
return directives;
}
@@ -42,14 +42,11 @@ import {ElementRef} from './element_ref';
import {TemplateRef} from './template_ref';
import {Directive, Component, LifecycleEvent} from 'angular2/src/core/annotations_impl/annotations';
import {hasLifecycleHook} from './directive_lifecycle_reflector';
import {
ChangeDetector,
ChangeDetectorRef,
Pipes
} from 'angular2/src/change_detection/change_detection';
import {ChangeDetector, ChangeDetectorRef} from 'angular2/src/change_detection/change_detection';
import {QueryList} from './query_list';
import {reflector} from 'angular2/src/reflection/reflection';
import {DirectiveMetadata} from 'angular2/src/render/api';
import {PipeBinding} from '../pipes/pipe_binding';
var _staticKeys;
@@ -59,7 +56,6 @@ export class StaticKeys {
viewContainerId: number;
changeDetectorRefId: number;
elementRefId: number;
pipesKey: Key;
constructor() {
this.viewManagerId = Key.get(avmModule.AppViewManager).id;
@@ -67,8 +63,6 @@ export class StaticKeys {
this.viewContainerId = Key.get(ViewContainerRef).id;
this.changeDetectorRefId = Key.get(ChangeDetectorRef).id;
this.elementRefId = Key.get(ElementRef).id;
// not an id because the public API of injector works only with keys and tokens
this.pipesKey = Key.get(Pipes);
}
static instance(): StaticKeys {
@@ -541,11 +535,6 @@ export class ElementInjector extends TreeNode<ElementInjector> implements Depend
injector.internalStrategy.attach(parentInjector, isBoundary);
}
getPipes(): Pipes {
var pipesKey = StaticKeys.instance().pipesKey;
return this._injector.getOptional(pipesKey);
}
hasVariableBinding(name: string): boolean {
var vb = this._proto.directiveVariableBindings;
return isPresent(vb) && vb.has(name);
@@ -589,51 +578,57 @@ export class ElementInjector extends TreeNode<ElementInjector> implements Depend
getDependency(injector: Injector, binding: ResolvedBinding, dep: Dependency): any {
var key: Key = dep.key;
if (!(dep instanceof DirectiveDependency)) return undefinedValue;
if (!(binding instanceof DirectiveBinding)) return undefinedValue;
var dirDep = <DirectiveDependency>dep;
var dirBin = <DirectiveBinding>binding;
var staticKeys = StaticKeys.instance();
if (binding instanceof DirectiveBinding) {
var dirDep = <DirectiveDependency>dep;
var dirBin = binding;
var staticKeys = StaticKeys.instance();
if (key.id === staticKeys.viewManagerId) return this._preBuiltObjects.viewManager;
if (key.id === staticKeys.viewManagerId) return this._preBuiltObjects.viewManager;
if (isPresent(dirDep.attributeName)) return this._buildAttribute(dirDep);
if (isPresent(dirDep.attributeName)) return this._buildAttribute(dirDep);
if (isPresent(dirDep.queryDecorator)) return this._findQuery(dirDep.queryDecorator).list;
if (isPresent(dirDep.queryDecorator)) return this._findQuery(dirDep.queryDecorator).list;
if (dirDep.key.id === StaticKeys.instance().changeDetectorRefId) {
// We provide the component's view change detector to components and
// the surrounding component's change detector to directives.
if (dirBin.metadata.type === DirectiveMetadata.COMPONENT_TYPE) {
if (dirDep.key.id === StaticKeys.instance().changeDetectorRefId) {
// We provide the component's view change detector to components and
// the surrounding component's change detector to directives.
if (dirBin.metadata.type === DirectiveMetadata.COMPONENT_TYPE) {
var componentView = this._preBuiltObjects.view.getNestedView(
this._preBuiltObjects.elementRef.boundElementIndex);
return componentView.changeDetector.ref;
} else {
return this._preBuiltObjects.view.changeDetector.ref;
}
}
if (dirDep.key.id === StaticKeys.instance().elementRefId) {
return this.getElementRef();
}
if (dirDep.key.id === StaticKeys.instance().viewContainerId) {
return this.getViewContainerRef();
}
if (dirDep.key.id === StaticKeys.instance().templateRefId) {
if (isBlank(this._preBuiltObjects.templateRef)) {
if (dirDep.optional) {
return null;
}
throw new NoBindingError(null, dirDep.key);
}
return this._preBuiltObjects.templateRef;
}
} else if (binding instanceof PipeBinding) {
if (dep.key.id === StaticKeys.instance().changeDetectorRefId) {
var componentView = this._preBuiltObjects.view.getNestedView(
this._preBuiltObjects.elementRef.boundElementIndex);
return componentView.changeDetector.ref;
} else {
return this._preBuiltObjects.view.changeDetector.ref;
}
}
if (dirDep.key.id === StaticKeys.instance().elementRefId) {
return this.getElementRef();
}
if (dirDep.key.id === StaticKeys.instance().viewContainerId) {
return this.getViewContainerRef();
}
if (dirDep.key.id === StaticKeys.instance().templateRefId) {
if (isBlank(this._preBuiltObjects.templateRef)) {
if (dirDep.optional) {
return null;
}
throw new NoBindingError(null, dirDep.key);
}
return this._preBuiltObjects.templateRef;
}
return undefinedValue;
}
@@ -0,0 +1,30 @@
import {resolveForwardRef, Injectable} from 'angular2/di';
import {Type, isPresent, BaseException, stringify} from 'angular2/src/facade/lang';
import {Pipe} from '../annotations_impl/annotations';
import {reflector} from 'angular2/src/reflection/reflection';
/**
* Resolve a `Type` for {@link Pipe}.
*
* This interface can be overridden by the application developer to create custom behavior.
*
* See {@link Compiler}
*/
@Injectable()
export class PipeResolver {
/**
* Return {@link Pipe} for a given `Type`.
*/
resolve(type: Type): Pipe {
var metas = reflector.annotations(resolveForwardRef(type));
if (isPresent(metas)) {
for (var i = 0; i < metas.length; i++) {
var annotation = metas[i];
if (annotation instanceof Pipe) {
return annotation;
}
}
}
throw new BaseException(`No Pipe decorator found on ${stringify(type)}`);
}
}
@@ -15,6 +15,9 @@ import {
ASTWithSource
} from 'angular2/src/change_detection/change_detection';
import {PipeBinding} from 'angular2/src/core/pipes/pipe_binding';
import {ProtoPipes} from 'angular2/src/core/pipes/pipes';
import * as renderApi from 'angular2/src/render/api';
import {AppProtoView} from './view';
import {ElementBinder} from './element_binder';
@@ -160,7 +163,7 @@ export class ProtoViewFactory {
createAppProtoViews(hostComponentBinding: DirectiveBinding,
rootRenderProtoView: renderApi.ProtoViewDto,
allDirectives: List<DirectiveBinding>): AppProtoView[] {
allDirectives: List<DirectiveBinding>, pipes: PipeBinding[]): AppProtoView[] {
var allRenderDirectiveMetadata =
ListWrapper.map(allDirectives, directiveBinding => directiveBinding.metadata);
var nestedPvsWithIndex = _collectNestedProtoViews(rootRenderProtoView);
@@ -177,7 +180,7 @@ export class ProtoViewFactory {
ListWrapper.forEach(nestedPvsWithIndex, (pvWithIndex: RenderProtoViewWithIndex) => {
var appProtoView =
_createAppProtoView(pvWithIndex.renderProtoView, protoChangeDetectors[pvWithIndex.index],
nestedPvVariableBindings[pvWithIndex.index], allDirectives);
nestedPvVariableBindings[pvWithIndex.index], allDirectives, pipes);
if (isPresent(pvWithIndex.parentIndex)) {
var parentView = appProtoViews[pvWithIndex.parentIndex];
parentView.elementBinders[pvWithIndex.boundElementIndex].nestedProtoView = appProtoView;
@@ -252,14 +255,16 @@ function _getChangeDetectorDefinitions(
function _createAppProtoView(
renderProtoView: renderApi.ProtoViewDto, protoChangeDetector: ProtoChangeDetector,
variableBindings: Map<string, string>, allDirectives: List<DirectiveBinding>): AppProtoView {
variableBindings: Map<string, string>, allDirectives: List<DirectiveBinding>,
pipes: PipeBinding[]): AppProtoView {
var elementBinders = renderProtoView.elementBinders;
// Embedded ProtoViews that contain `<ng-content>` will be merged into their parents and use
// a RenderFragmentRef. I.e. renderProtoView.transitiveNgContentCount > 0.
var protoPipes = new ProtoPipes(pipes);
var protoView = new AppProtoView(
renderProtoView.type, renderProtoView.transitiveNgContentCount > 0, renderProtoView.render,
protoChangeDetector, variableBindings, createVariableLocations(elementBinders),
renderProtoView.textBindings.length);
renderProtoView.textBindings.length, protoPipes);
_createElementBinders(protoView, elementBinders, allDirectives);
_bindDirectiveEvents(protoView, elementBinders);
+3 -1
View File
@@ -31,6 +31,7 @@ import * as renderApi from 'angular2/src/render/api';
import {RenderEventDispatcher} from 'angular2/src/render/api';
import {ViewRef, ProtoViewRef, internalView} from './view_ref';
import {ElementRef} from './element_ref';
import {ProtoPipes} from 'angular2/src/core/pipes/pipes';
export {DebugContext} from 'angular2/src/change_detection/interfaces';
@@ -335,7 +336,8 @@ export class AppProtoView {
public render: renderApi.RenderProtoViewRef,
public protoChangeDetector: ProtoChangeDetector,
public variableBindings: Map<string, string>,
public variableLocations: Map<string, number>, public textBindingCount: number) {
public variableLocations: Map<string, number>, public textBindingCount: number,
public pipes: ProtoPipes) {
this.ref = new ProtoViewRef(this);
if (isPresent(variableBindings)) {
MapWrapper.forEach(variableBindings,
@@ -9,6 +9,7 @@ import {ElementRef} from './element_ref';
import {TemplateRef} from './template_ref';
import {Renderer, RenderViewWithFragments} from 'angular2/src/render/api';
import {Locals} from 'angular2/src/change_detection/change_detection';
import {Pipes} from 'angular2/src/core/pipes/pipes';
import {RenderViewRef, RenderFragmentRef, ViewType} from 'angular2/src/render/api';
@Injectable()
@@ -206,21 +207,15 @@ export class AppViewManagerUtils {
this._setUpHostActions(currView, elementInjector, boundElementIndex);
}
}
var pipes = this._getPipes(imperativelyCreatedInjector, hostElementInjector);
var pipes = isPresent(hostElementInjector) ?
new Pipes(currView.proto.pipes, hostElementInjector.getInjector()) :
null;
currView.changeDetector.hydrate(currView.context, currView.locals, currView, pipes);
viewIdx++;
}
}
}
_getPipes(imperativelyCreatedInjector: Injector, hostElementInjector: eli.ElementInjector) {
var pipesKey = eli.StaticKeys.instance().pipesKey;
if (isPresent(imperativelyCreatedInjector))
return imperativelyCreatedInjector.getOptional(pipesKey);
if (isPresent(hostElementInjector)) return hostElementInjector.getPipes();
return null;
}
_populateViewLocals(view: viewModule.AppView, elementInjector: eli.ElementInjector,
boundElementIdx: number): void {
if (isPresent(elementInjector.getDirectiveVariableBindings())) {
@@ -0,0 +1,15 @@
import {Type} from 'angular2/src/facade/lang';
import {Key, Dependency, ResolvedBinding, Binding} from 'angular2/di';
import {Pipe} from 'angular2/src/core/annotations_impl/annotations';
export class PipeBinding extends ResolvedBinding {
constructor(public name: string, key: Key, factory: Function, dependencies: Dependency[]) {
super(key, factory, dependencies);
}
static createFromType(type: Type, metadata: Pipe): PipeBinding {
var binding = new Binding(type, {toClass: type});
var rb = binding.resolve();
return new PipeBinding(metadata.name, rb.key, rb.factory, rb.dependencies);
}
}
+28
View File
@@ -0,0 +1,28 @@
import {isBlank, isPresent, BaseException, CONST, Type} from 'angular2/src/facade/lang';
import {Injectable, OptionalMetadata, SkipSelfMetadata, Binding, Injector, bind} from 'angular2/di';
import {PipeBinding} from './pipe_binding';
import * as cd from 'angular2/src/change_detection/pipes';
export class ProtoPipes {
/**
* Map of {@link Pipe} names to {@link Pipe} implementations.
*/
config: StringMap<string, PipeBinding> = {};
constructor(bindings: PipeBinding[]) { bindings.forEach(b => this.config[b.name] = b); }
get(name: string): PipeBinding {
var binding = this.config[name];
if (isBlank(binding)) throw new BaseException(`Cannot find pipe '${name}'.`);
return binding;
}
}
export class Pipes implements cd.Pipes {
constructor(public proto: ProtoPipes, public injector: Injector) {}
get(name: string): any {
var b = this.proto.get(name);
return this.injector.instantiateResolved(b);
}
}