Home  >  Angular 2

Angular 2 Custom Pipe Example

By Arvind Rai, January 02, 2017
This page will walk through angular 2 custom pipe example. We can write our own custom pipe and that will be used in the same way as angular built-in pipes. To create custom pipe, angular provides Pipe and PipeTransform interfaces. Every pipe is decorated with @Pipe where we define the name of our custom pipe. Every pipe will implement PipeTransform interface. This interface provides transform() method and we have to override it in our custom pipe class. transform() method will decide the input types, number of arguments and its types and output type of our custom pipe. We perform the following steps to create a custom pipe.

Step 1: Create a typescript class.
Step 2: Decorate the class using @Pipe.
Step 3: Implement PipeTransform interface.
Step 4: Override transform() method.
Step 5: Configure the class in application module with @NgModule.
Step 6: Ready to use our custom pipe anywhere in application.

On the basis of change detention, angular provides two types of pipes.

Pure pipe: This will run only for pure changes in component properties.
Impure pipe: This will run for any type of changes in component properties.

Pure and impure pipe are declared using @Pipe decorator. Here on this page we will create custom pipes with and without arguments. We will also create custom pipe using angular built-in pipes. We will also provide example of pure and impure pipe. Now find the angular custom pipe tutorial with examples step by step using TypeScript.

Software Used

Find the software used in our demo.
1. Angular 2.3.0
2. TypeScript 2.0.10
3. Node.js 4.6.0
4. NPM 3.10.8
5. Firefox 50.1.0

Diagram to Create Custom Pipe

Here we are creating a custom pipe named as myjson. This will convert a given object input into JSON format. Our pipe will accept input of any type of object. Our custom pipe will accept two arguments. Find the demo by diagram.
Angular 2 Custom Pipe Example
We are doing following steps to create our custom pipe.
1. Create a typescript class, for example MyJSONPipe and import Pipe and PipeTransform interface.
2. Decorate class using @Pipe and assign pipe name to name metadata for example myjson .
3. Implement PipeTransform interface and override transform() method.
4. Our custom pipe needs two arguments. So transform() method has three parameters. First parameter is for pipe input and the rest two is for pipe arguments.
5. In transform() method first parameter is of any type, so myjson pipe will accept any type of object as an input.
6. In transform() method, second parameter is of number type. This will be used to decide whether myjson pipe will give pretty print output or not. If its value is 0, then no pretty print and if 1 or greater than 1, then result will be pretty print when using myjson pipe with <pre> tag.
7. In transform() method, third parameter provide the fields of input object that will be involved in JSON output.
8. We are using return type of transform() method as string, so myjson will give output as string.
9. In transform() method second and third parameter is optional. If we do not provide any argument to myjson pipe then all the fields will be involved in JSON format and the output will be no pretty print.

Create Component and Module

Find the component that is using our custom pipes.
custompipe.component.ts
import {Component} from '@angular/core';
import {Person} from './person';
import {Company} from './company';
@Component({
  selector: 'pipe-app',
  template: `
            <h3>1. Using welcome Pipe</h3>
		{{person.name | welcome}} <br/>
			
            <h3>2. Using strformat Pipe</h3>			
		{{message | strformat:'+'}}
			
	    <h3>3. Using division Pipe</h3>
		<div>Dividend: <input [(ngModel)]="dividend"> </div>
		<div>Divisor: <input [(ngModel)]="divisor"> </div>
		<p>
		  Division Result: {{dividend | division: divisor}}
		</p>
			
	    <h3>4. Using repeat Pipe</h3>
		{{person.name | repeat:10}}
			
	    <h3>5. Using myjson Pipe</h3>
		<pre>{{person | myjson}}</pre>
		<pre>{{person | myjson:0:'id,age'}}</pre>
		<pre>{{person | myjson:1:'id,name'}}</pre>
             
	    <h3>6. Using myuppercaseone and myuppercasetwo Pipe</h3>	
		{{message | myuppercaseone}} <br/>
		{{message | myuppercasetwo:'+'}} <br/>	
			
            <h3>7. Chaining of Custom Pipes</h3>			
		{{person.name | repeat:5 | myuppercaseone}}
			
	    <h3>8. Using Pure and Impure Pipe</h3>
		Company Name: <input [(ngModel)] ="compName"/> {{compName}}
		<br/>Location: <input [(ngModel)] ="compLocation"/> {{compLocation}}
		<br/><br/><button (click)="updateCompany()">Update Existing</button> 
		<button (click)="createCompany()">Create New </button> 
				 
		<br/><b>a. Using Pure Pipe : companyone</b><br/><br/>
		 {{company | companyone}}
			  
		<br/><br/><b>b. Using Impure Pipe : companytwo</b><br/><br/>
		 {{company | companytwo}}
         ` 
})
export class CustomPipeComponent {
        //For welcome, repeat, myjson Pipe 
        person: Person = new Person(1, 'Ram', 30);	
        //For strformat, myuppercaseone and myuppercasetwo Pipe
	message: string = "My name is Mahesh";
	//For division Pipe
	dividend : number = 23;
	divisor : number = 7;
	//For pure and impure pipe
	compName:string = "ABCD LTD";
	compLocation:string = "Varanasi";
	company = new Company(this.compName, this.compLocation);

        //Impure change because there is no change in object reference: company	
	//Impure pipe will run again and Pure pipe will do nothing.
	updateCompany() {
	   this.company.cname = this.compName;
	   this.company.location = this.compLocation;
	}
	
	//Pure change because there is change in object reference: company	
	//Impure pipe and Pure pipe both will run again.
	createCompany() {
	   this.company = new Company(this.compName, this.compLocation);   
	}
} 
We have also created some classes that will act as input for custom pipes.
company.ts
export class Company {
	constructor(public cname:string, public location:string) {
	}
} 
person.ts
export class Person {
	constructor(public id:number, public name:string, public age:number) {
	}
} 
Now find the module, main and index.html used in our example.
module.ts
import {NgModule}      from '@angular/core';
import {BrowserModule} from '@angular/platform-browser';
import {FormsModule}   from '@angular/forms';
import {CustomPipeComponent}  from './custompipe.component';
import {WelcomePipe}  from './welcome.pipe';
import {StrFormatPipe} from './strformat.pipe';
import {MyUppercaseOnePipe}  from './myuppercaseone.pipe';
import {MyUppercaseTwoPipe}  from './myuppercasetwo.pipe';
import {DivisionPipe}  from './division.pipe';
import {RepeatPipe}  from './repeat.pipe';
import {MyJSONPipe}  from './myjson.pipe';
import {CompanyOnePipe}  from './companyone.pipe';
import {CompanyTwoPipe}  from './companytwo.pipe';

@NgModule({
  imports:      [BrowserModule,
                 FormsModule],
  declarations: [WelcomePipe,
		 StrFormatPipe,
		 MyUppercaseOnePipe,
		 MyUppercaseTwoPipe,
		 DivisionPipe,
		 RepeatPipe,
		 MyJSONPipe,
		 CompanyOnePipe,
		 CompanyTwoPipe,
		 CustomPipeComponent],
  bootstrap:    [CustomPipeComponent]
})
export class AppModule { } 
main.ts
import {platformBrowserDynamic} from '@angular/platform-browser-dynamic';
import {AppModule} from './module';
const platform = platformBrowserDynamic();
platform.bootstrapModule(AppModule); 
index.html
<html>
  <head>
    <title>Angular 2 Demo</title>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <script src="node_modules/core-js/client/shim.min.js"></script>
    <script src="node_modules/zone.js/dist/zone.js"></script>
    <script src="node_modules/reflect-metadata/Reflect.js"></script>
    <script src="node_modules/systemjs/dist/system.src.js"></script>
    <!-- Configure SystemJS -->
    <script src="systemjs.config.js"></script>
    <script>
      System.import('myApp').catch(function(err){ console.error(err); });
    </script>
  </head>
  <body>
      <pipe-app>Please Wait...</pipe-app>
  </body>
</html> 

@Pipe Decorator and PipeTransform Interface

To create custom pipe we need to understand angular Pipe and PipeTransform API.

@Pipe Decorator

@Pipe decorator is a Pipe interface. A typescript class is decorated by @Pipe to create an angular custom pipe. Find the Pipe interface from the angular Pipe API document.
interface Pipe {
   name : string
   pure : boolean
} 
name: Assign custom pipe name.
pure: Assign true or false. Default is true. If true then pipe will be a pure pipe otherwise impure pipe. So by default all pipes are pure pipe.

For example we will use Pipe interface as @Pipe decorator as follows.
@Pipe({
    name: 'welcome'
}) 
Here custom pipe name is welcome and as we know that by default pure metadata value is true, so welcome pipe will be a pure pipe.

PipeTransform Interface

PipeTransform is an angular interface. To create a custom pipe our typescript class has to implement PipeTransform interface. It has been defined as follows in angular PipeTransform API document.
interface PipeTransform {
    transform(value: any, ...args: any[]) : any
} 
In the above interface a method transform() has been defined. It accepts minimum one argument and maximum any number of arguments. The parameter type is any. It means we can pass any type of object. transform() method returns value of type any. To create custom pipe our typescript class will implement PipeTransform and override transform() method. The use of parameters is as follows.

1. First parameter (value: any): This is the value in left side of our pipe operator (|).
2. Optional parameters: These are arguments used with pipe in right side of pipe operator (|).
3. Value returned by method: This is the value that is the output of our custom pipe.

Create Simple Custom Pipe

Now we will start creating our custom pipe. Here we will create a simple custom pipe named as welcome. The syntax is as follows.

string_expression | welcome

We will pass a person name for string_expression as string and output will be a welcome message. Now follow the steps to create our welcome pipe.
step 1: Create a typescript class named as WelcomePipe.
step 2: Import Pipe and PipeTransform interface from angular core module.
step 3: Decorate WelcomePipe with @Pipe . Its name metadata will define custom pipe name.
step 4: WelcomePipe will implement PipeTransform interface.
step 5: Override transform() method of PipeTransform interface. The parameter of transform() can be of any type. In our example we are using string data type and return type is also a string. Here we will perform task which needs to be done by our custom pipe and return the result. This is the result which will be returned by custom pipe.
step 6: To make custom pipe available at application level, declare WelcomePipe in @NgModule decorator. In our example module file is module.ts.

Find the WelcomePipe class.
welcome.pipe.ts
import {Pipe, PipeTransform} from '@angular/core';
@Pipe({
    name: 'welcome'
})
export class WelcomePipe implements PipeTransform {
  transform(value: string): string {
    let message = "Welcome to " + value;
    return message;
  }
} 
The name metadata of @Pipe decorator has the value welcome and that will be the name of our custom pipe. In our custompipe.component.ts file we are using welcome pipe as given below.
{{person.name | welcome}} 
Output
Welcome to Ram 

Pass Arguments in Custom Pipe

Now we will discuss some custom pipes that will accept arguments. To facilitate custom pipe to accept arguments we have to use optional parameters in transform() method while creating custom pipe API. If we want one argument with custom pipe then use one optional parameter in transform() method. If we want two arguments with custom pipe then use two optional parameters in transform() method and so on. Now find our custom pipes that are using arguments.

1. Create strformat Custom Pipe

Find the syntax.

string_expression | strformat[:seperator]

The strformat will format the given string expression. The spaces between words will be replaced by given separator. Now find the typescript class StrFormatPipe that will create strformat pipe.
strformat.pipe.ts
import {Pipe, PipeTransform} from '@angular/core';
@Pipe({
    name: 'strformat'
})
export class StrFormatPipe implements PipeTransform {
  transform(value: string, seperator: string): string {
    let result = value.split(' ').join(seperator);
    return result;
  }
} 
The name metadata of @Pipe decorator has the value strformat and that will be the name of our custom pipe. We will observe that in transform() method first parameter is a string and this will be used by string_expression. Second parameter is also a string and this will be used by strformat pipe to pass arguments. In our example argument is string value given by separator. Now transform() method has return type as string, so the output of our pipe strformat will be a string.
In our custompipe.component.ts file we are using strformat pipe as given below.
{{message | strformat:'+'}} 
Output
My+name+is+Mahesh 
2. Create division Custom Pipe

Using division custom pipe we will divide a number by a given number. Find the syntax.

number_expression | division[:num_divisor]

Find the description.
number_expression : An expression that will return a number and that will be dividend.
num_divisor: This number is the argument of our pipe that will be used as divisor.

Now find the typescript class DivisionPipe that will create division pipe.
division.pipe.ts
import {Pipe, PipeTransform} from '@angular/core';
@Pipe({
   name: 'division'
})
export class DivisionPipe implements PipeTransform {
  transform(dividend: number, divisor: number): number {
    let num = dividend / divisor;
    return num;
  }
} 
Custom pipe name is assigned to name metadata of @Pipe decorator. Here custom pipe name is division. In transform() method, there are two parameters of number type. First parameter is for expression used with pipe operator and second parameter is used for pipe argument. Return type of method is also a number, so division pipe operator will give output as number.
In our custompipe.component.ts file we are using division pipe as given below.
<div>Dividend: <input [(ngModel)]="dividend"> </div>
<div>Divisor: <input [(ngModel)]="divisor"> </div>
<p>
  Division Result: {{dividend | division: divisor}}
</p> 
Here dividend and divisor values are input by user. Pure pipe and impure pipe both detect changes immediately for component string property value changes. So whenever there will be change in value of component property dividend and divisor, our custom pipe division will run every time. Find the output print screen.
Angular 2 Custom Pipe Example

3. Create repeat Custom Pipe

We are creating a repeat pipe. This pipe will repeat a given word. This will be repeated as many times as given frequency. Find the syntax.

string_expression | repeat[:frequency]

Find the typescript class RepeatPipe that will create repeat pipe.
repeat.pipe.ts
import {Pipe, PipeTransform} from '@angular/core';
@Pipe({
    name: 'repeat'
})
export class RepeatPipe implements PipeTransform {
  transform(word: string, frequency: number): string {
	let cnt = 1;
	let strResult= word;
	while (cnt < frequency) {
	    strResult = strResult + ' ' + word;
	    cnt = cnt + 1;
	}
        return strResult;
  }
} 
@Pipe decorator has defined the pipe name as repeat. The method transform() has two parameters. One is of string type and second is of number type. First parameter is for string_expression and second parameter is for frequency.
In our custompipe.component.ts file we are using repeat pipe as given below.
{{person.name | repeat:10}} 
Output
Ram Ram Ram Ram Ram Ram Ram Ram Ram Ram 
4. Create myjson Custom Pipe

Here we are creating myjson custom pipe. This pipe will convert an expression into JSON format. It will accept two arguments. Find the syntax.

expression | myjson[:prettyprint[:fields]]

Find the description.
expression : Expression that will be converted into JSON format. It can be primitive data type or any object.
prettyprint : If the value is 0, then no pretty print and if the value is 1 or greater than 1, then we will get pretty print JSON format.
fields : If no fields are provided then all the fields of object will take part in JSON format, if specified then only those fields will take part in JSON format.

If no argument is passed then myjson will convert the given object into JSON format with all fields and without pretty print. Now find the typescript class MyJSONPipe that will create myjson pipe.
myjson.pipe.ts
import {Pipe, PipeTransform} from '@angular/core';
@Pipe({
    name: 'myjson'
})
export class MyJSONPipe implements PipeTransform {
  transform(value: any, prettyprint: number, fields: string): string {
	let array = (fields == null? null : fields.split(','));
	let pp = (prettyprint == null ? 0 : prettyprint);
	let result = JSON.stringify(value, array, pp);
        return result;
  }
} 
The name of custom pipe myjson is provided in @Pipe decorator. The method transform() has three parameters. First parameter is of any type. It means any type of object can be passed to convert into JSON format. The rest two parameters are pipe arguments. Pretty print of JSON format also requires <pre> tag while using myjson pipe.
In our custompipe.component.ts file we are using myjson pipe as given below.
<pre>{{person | myjson}}</pre>
<pre>{{person | myjson:0:'id,age'}}</pre>
<pre>{{person | myjson:1:'id,name'}}</pre> 
Output
{"id":1,"name":"Ram","age":30}

{"id":1,"age":30}

{
 "id": 1,
 "name": "Ram"
} 

Use Built-in Pipe in Custom Pipe

Custom pipe can also use angular built-in pipe such as DatePipe, UpperCasePipe, LowerCasePipe, CurrencyPipe, and PercentPipe. In our example we will create myuppercaseone and myuppercasetwo pipe. Both pipes will use UpperCasePipe built-in pipe. There are two ways to use UpperCasePipe in our custom pipes.

1. Extending UpperCasePipe built-in pipe class:

UpperCasePipe is an angular built-in pipe. It implements PipeTransform interface and override transform() method as we do in our custom pipes. Here we will create our custom pipe class named as MyUppercaseOnePipe. This time our class MyUppercaseOnePipe will not implement PipeTransform because it will extend UpperCasePipe built-in pipe and that is already implementing PipeTransform interface. Now find the MyUppercaseOnePipe class.
myuppercaseone.pipe.ts
import {Pipe} from '@angular/core';
import {UpperCasePipe} from '@angular/common';
@Pipe({
    name: 'myuppercaseone'
})
export class MyUppercaseOnePipe extends UpperCasePipe{
  transform(value: string): string {
	let result = super.transform(value);
	result = result.split(' ').join('-');
        return result;
  }
} 
UpperCasePipe is the API of CommonModule, so we need to import UpperCasePipe class from angular common package. Here we are overriding transform() method from UpperCasePipe, so we cannot change number of parameters and types in transform() method. Now find the line of code.
let result = super.transform(value); 
Using super keyword we call the parent class method. The value passed to transform() method of MyUppercaseOnePipe class is first processed by transform() method of UpperCasePipe class and then we perform our changes and then we return the final result.
In our custompipe.component.ts file we are using myuppercaseone pipe as given below.
{{message | myuppercaseone}} 
Output
MY-NAME-IS-MAHESH 
2. Using object of UpperCasePipe built-in pipe class:

We can also use built-in pipe in our custom pipe by creating object of built-in pipe API. Here we will create our custom pipe as usual by implementing PipeTransform and within transform() method we will use parameters and their types according to our requirements. To process the data by UpperCasePipe pipe, we will create the object of it and pass the data to its transform() method. Now find the MyUppercaseTwoPipe class.
myuppercasetwo.pipe.ts
import {Pipe, PipeTransform} from '@angular/core';
import {UpperCasePipe} from '@angular/common';
@Pipe({
    name: 'myuppercasetwo'
})
export class MyUppercaseTwoPipe implements PipeTransform{
  transform(value: string, seperator: string): string {
        let upipe = new UpperCasePipe();
	let result = upipe.transform(value);
	result = result.split(' ').join(seperator);
        return result;
  }
} 
In our custompipe.component.ts file we are using myuppercasetwo pipe as given below.
{{message | myuppercasetwo:'+'}} 
Output
MY+NAME+IS+MAHESH 

Chaining of Custom Pipes

Chaining of custom pipes is using more than one pipe together. The output of first pipe will be the input for next pipe and so on. Find the example.
{{person.name | repeat:5 | myuppercaseone}} 
In the above code snippet we are using two custom pipes repeat and myuppercaseone. First repeat pipe will run and then its output will be the input for myuppercaseone pipe. Find the output.
RAM-RAM-RAM-RAM-RAM 

Pure and Impure Custom Pipe and Change Detection

Angular provides pure and impure pipes on the basis of change detection. Here we will discuss pure and impure pipes with examples.
1. Change Detection

Angular uses a change detection process for changes in data-bound values. Change detection runs after every keystroke, mouse move, timer tick, and server response. In case of pipe, angular picks a simpler, faster change detection algorithm.

2. Pure Pipes

By default all pipes are pure pipe. Pure pipes are those pipes that have pure: true in @Pipe decorator while creating pipe class. If we have not used pure metadata then its default value will be true in @Pipe decorator. Pure pipes executes only for pure changes in its input values.
Find the pure changes.
a. Change to a primitive input values such as String, Number, Boolean.
b. Change to object reference of Date, Array, Function, Object.

Above changes are pure changes. If the input values used with pure pipe, comes under the pure changes then pipe will run again to give output accordingly. Pure pipe is created as follows.
@Pipe({
    name: 'companyone'
}) 
By default @Pipe decorator is using pure: true.

3. Impure Pipes

Impure pipes will run for every component change detection cycle. So it is obvious that impure pipes will also run for pure changes. Impure pipe will run for every keystroke or mouse move. So the conclusion is that impure pipe will run a lot and hence we should take care while using impure pipe because it may reduce performance of the application and can destroy user experience. Impure pipe is created as follows.
@Pipe({
    name: 'companytwo',
    pure: false
}) 
Make sure that metadata pure has been assigned with false boolean value.

4. Example of Pure and Impure Pipes

Now we will discuss an example of pure and impure pipe. We will see that pure pipe will run only for pure changes whereas impure pipe will run for every type of changes in component properties. We will start by creating pure and impure pipes whose transform() method will use Company class as parameter type and string as return type.
Find the pure pipe named as companyone
companyone.pipe.ts
import {Pipe, PipeTransform} from '@angular/core';
import {Company} from './company';
@Pipe({
    name: 'companyone'
})
export class CompanyOnePipe implements PipeTransform {
  transform(obj: Company): string {
    let output = obj.cname+' : '+ obj.location;
    return output;
  }
} 
Now find the impure pipe named as companytwo
companytwo.pipe.ts
import {Pipe, PipeTransform} from '@angular/core';
import {Company} from './company';
@Pipe({
    name: 'companytwo',
    pure: false
})
export class CompanyTwoPipe implements PipeTransform {
  transform(obj: Company): string {
    let output = obj.cname+' : '+ obj.location;
    return output;
  }
} 
We will observe that companyone and companytwo both pipes are doing same task. The only difference is that companyone is a pure pipe and companytwo is an impure pipe.
Now we will code scenarios for pure and impure changes in Company object. Suppose we have created Company object as follows.
compName:string = "ABCD LTD";
compLocation:string = "Varanasi";
company = new Company(this.compName, this.compLocation); 
a. Pure change in company object by changing its reference: To change the reference we will create a new object of Company class and assign it to component property company as follows.
createCompany() {
   this.company = new Company(this.compName, this.compLocation);   
} 
When we call the above method then pure and impure both pipes will run. It means companyone and companytwo both pipe will run again.

b. Impure change in company object by updating its property values: To generate the scenario of impure change, we will update the property value of our company object as follows.
updateCompany() {
   this.company.cname = this.compName;
   this.company.location = this.compLocation;
} 
When we call the above method then only impure pipe will run. It means companyone pipe will not run again but companytwo pipe will run again for the changes in company object.

Now find the below code from custompipe.component.ts file.
Company Name: <input [(ngModel)] ="compName"/> {{compName}}
<br/>Location: <input [(ngModel)] ="compLocation"/> {{compLocation}}
<br/><br/><button (click)="updateCompany()">Update Existing</button> 
<button (click)="createCompany()">Create New </button> 
				 
<br/><b>a. Using Pure Pipe : companyone</b><br/><br/>
 {{company | companyone}}
			  
<br/><br/><b>b. Using Impure Pipe : companytwo</b><br/><br/>
 {{company | companytwo}} 
Output

Initially both text box will be populated with following values.
Company Name : ABCD LTD
Location: Varanasi
Angular 2 Custom Pipe Example

Case 1: Change the text box values as follows.
Company Name : ABCD LTD11
Location: Varanasi11

Now click on Update Existing button. Output of companyone pipe will be as follows.
ABCD LTD : Varanasi 
And output of companytwo pipe will be as follows.
ABCD LTD11 : Varanasi11 
Let us understand what is happening now. When we click on Update Existing button then updateCompany() will execute and performs impure change in company object. So only impure pipe companytwo will run again and change its output. There will be no change in pure pipe companyone output because it has not run again due to impure change in company object.

Case 2: Change the text box values as follows.
Company Name : ABCD LTD1111
Location: Varanasi1111

Now click on Create New button. Output of companyone pipe will be as follows.
ABCD LTD1111 : Varanasi1111 
And output of companytwo pipe will be as follows.
ABCD LTD1111 : Varanasi1111 
Let us understand what is happening. When we click on Create New button then createCompany() will execute and performs pure change in company object. So this time pure and impure pipe both will run again. It means companyone and companytwo both pipe will run again and change its output.

Run Application

Find the steps to run the example.
1. Install Node.js and NPM in the system if not already installed. Make sure that Node.js version must be 4.x.x or higher and NPM version must be 3.x.x or higher.
2. Download the source code using download link given below in the example.
3. Go to the root folder of the project using command prompt and run npm install command.
4. Now run npm start command.
5. Now run index.html file. Find the print screen of the output.
Angular 2 Custom Pipe Example


I am done now. Happy angular learning!

Reference

Angular 2 PIPES

Download Source Code

POSTED BY
ARVIND RAI
ARVIND RAI
FIND MORE TUTORILAS
comments powered by Disqus


Copyright ©2017 concretepage.com, all rights reserved |Privacy Policy | Contact Us