<!DOCTYPE html>
<html>
  <head>
    <title>Angular 2 Autocomplete - Example</title>
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <!-- CSS file -->
    <link rel="stylesheet" type="text/css" href="style.css">
   <!-- Latest compiled and minified CSS -->
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css" >

    <!-- IE polyfills, keep the order please -->
    <script src="https://cdnjs.cloudflare.com/ajax/libs/es6-shim/0.33.3/es6-shim.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/systemjs/0.19.20/system-polyfills.js"></script>
    
    <!-- Agular 2 -->
    <script src="https://code.angularjs.org/2.0.0-beta.7/angular2-polyfills.js"></script>
    <script src="https://code.angularjs.org/tools/system.js"></script>
    <script src="https://code.angularjs.org/tools/typescript.js"></script>
    <script src="https://code.angularjs.org/2.0.0-beta.7/Rx.js"></script>
    <script src="https://code.angularjs.org/2.0.0-beta.7/angular2.dev.js"></script>
     <!-- Config Agular 2 and Typescript -->
    <script>
      System.config({
        transpiler: 'typescript', 
        typescriptOptions: { emitDecoratorMetadata: true }, 
        packages: {'app': {defaultExtension: 'ts'}} 
      });
      System.import('app/main')
            .then(null, console.error.bind(console));
    </script>

  </head>
 
  <!-- Run the application -->
  <body>
    <h1>Angular 2 Autocomplete</h1> 
    <my-app class="container" style="display: block">Loading Sample...</my-app>
  
    <div style="padding-top:50px">
    <a target="_blank" href="http://www.angulartypescript.com/angular-2-tutorial/" title="Angular 2 Tutorial"> 
     <img src="http://www.angulartypescript.com/wp-content/uploads/2016/03/learn-more-angular-2.png" alt="Smiley face" height="200" width="500">   
    </a>  
        <ul class="nav nav-pills nav-stacked" >
            <li><a target="_blank" href="http://www.angulartypescript.com/angular-2-tutorial/" title="Angular 2 Home"> Angular 2 Tutorial </a></li>
          <li><a target="_blank" href="http://www.angulartypescript.com/angular-2-introduction/">Angular 2 Introduction</a></li>
          <li><a target="_blank" href="http://www.angulartypescript.com/angular-2-architecture/">Angular 2 Architecture</a></li>
      <li><a target="_blank" href="http://www.angulartypescript.com/angular-2-annotations/">Angular 2 Annotations</a></li>
      <li><a target="_blank" href="http://www.angulartypescript.com/angular-2-getting-started/">Angular 2 Setup</a></li>
      <li><a target="_blank" href="http://www.angulartypescript.com/angular-2-hello-world/">Angular 2 Hello World</a></li>
      <li><a target="_blank" href="http://www.angulartypescript.com/angular-2-components/">Angular 2 Components</a></li>
      <li><a target="_blank" href="http://www.angulartypescript.com/angular-2-template-syntax/">Angular 2 Template Syntax</a></li>
      <li><a target="_blank" href="http://www.angulartypescript.com/angular-2-data-binding/">Angular 2 Data Binding</a></li>
      <li><a target="_blank" href="http://www.angulartypescript.com/angular-2-forms/">Angular 2 Forms</a></li>
      <li><a target="_blank" href="http://www.angulartypescript.com/angular-2-formbuilder-example/">Angular 2 Formbuilder</a></li>
      <li><a target="_blank" href="http://www.angulartypescript.com/angular-2-router-example/">Angular 2 Router</a></li>
      <li><a target="_blank" href="http://www.angulartypescript.com/angular-2-http-example-typescript/">Angular 2 HTTP</a></li>
      <li><a target="_blank" href="http://www.angulartypescript.com/angular-2-services/">Angular 2 Service</a></li> 
    
        </ul>
    </div> 
  </body>

</html>
<!-- 
Copyright 2016 angulartypescript.com. All Rights Reserved.
Everyone can use this source code; don’t forget to indicate the source please:
http://www.angulartypescript.com/ 
-->

/* Styles go here */

/**
 * Created by Tareq Boulakjar. from angulartypescript.com
 */
import {bootstrap}  from 'angular2/platform/browser';
import {Angular2Autocomplete} from './autocomplete-example';

bootstrap(Angular2Autocomplete);


/*
Copyright 2016 angulartypescript.com. All Rights Reserved.
Everyone can use this source code; don’t forget to indicate the source please:
http://www.angulartypescript.com/ 
*/
import { latinMap } from './latin-map';
export class AutocompleteUtils {
    static latinMap:any = latinMap;

    public static latinize(str:string) {
        return str.replace(/[^A-Za-z0-9\[\] ]/g, function (a) {
            return AutocompleteUtils.latinMap[a] || a;
        });
    }

    public static escapeRegexp(queryToEscape:string) {
        // Regex: capture the whole query string and replace it with the string that will be used to match
        // the results, for example if the capture is 'a' the result will be \a
        return queryToEscape.replace(/([.?*+^$[\]\\(){}|-])/g, '\\$1');
    }

    public static tokenize(str:string, wordRegexDelimiters:string = ' ', phraseRegexDelimiters:string = ''):Array<string> {
        let regexStr:string = '(?:[' + phraseRegexDelimiters + '])([^' + phraseRegexDelimiters + ']+)(?:[' + phraseRegexDelimiters + '])|([^' + wordRegexDelimiters + ']+)';
        let preTokenized:Array<string> = str.split(new RegExp(regexStr, 'g'));
        let result:Array<string> = [];
        let preTokenizedLength:number = preTokenized.length;
        let token:string;
        let replacePhraseDelimiters = new RegExp('[' + phraseRegexDelimiters + ']+', 'g');

        for (let i = 0; i < preTokenizedLength; i += 1) {
            token = preTokenized[i];
            if (token && token.length && token !== wordRegexDelimiters) {
                result.push(token.replace(replacePhraseDelimiters, ''));
            }
        }

        return result;
    }
}
/**
 * bootstrap
 */
import {
    Injectable,
    ElementRef
} from 'angular2/core';
import {IAttribute} from './IAttribute';

export class PositionService {
    private get window():any {
        return window;
    }

    private get document():any {
        return window.document;
    }

    private getStyle(nativeEl:any, cssProp:string):any {
        // IE
        if (nativeEl.currentStyle) {
            return nativeEl.currentStyle[cssProp];
        }

        if (this.window.getComputedStyle) {
            return this.window.getComputedStyle(nativeEl)[cssProp];
        }
        // finally try and get inline style
        return nativeEl.style[cssProp];
    }


    /**
     * Checks if a given element is statically positioned
     * @param nativeEl - raw DOM element
     */
    private isStaticPositioned(nativeEl:any):any {
        return (this.getStyle(nativeEl, 'position') || 'static' ) === 'static';
    }


    /**
     * returns the closest, non-statically positioned parentOffset of a given element
     * @param nativeEl
     */
    private parentOffsetEl(nativeEl:any) {
        let offsetParent = nativeEl.offsetParent || this.document;
        while (offsetParent && offsetParent !== this.document &&
        this.isStaticPositioned(offsetParent)) {
            offsetParent = offsetParent.offsetParent;
        }
        return offsetParent || this.document;
    };

    /**
     * Provides read-only equivalent of jQuery's position function:
     * http://api.jquery.com/position/
     */
    public position(nativeEl:any):{width: number, height: number, top: number, left: number} {
        let elBCR = this.offset(nativeEl);
        let offsetParentBCR = {top: 0, left: 0};
        let offsetParentEl = this.parentOffsetEl(nativeEl);
        if (offsetParentEl !== this.document) {
            offsetParentBCR = this.offset(offsetParentEl);
            offsetParentBCR.top += offsetParentEl.clientTop - offsetParentEl.scrollTop;
            offsetParentBCR.left += offsetParentEl.clientLeft - offsetParentEl.scrollLeft;
        }

        let boundingClientRect = nativeEl.getBoundingClientRect();
        return {
            width: boundingClientRect.width || nativeEl.offsetWidth,
            height: boundingClientRect.height || nativeEl.offsetHeight,
            top: elBCR.top - offsetParentBCR.top,
            left: elBCR.left - offsetParentBCR.left
        };
    }

    /**
     * Provides read-only equivalent of jQuery's offset function:
     * http://api.jquery.com/offset/
     */
    public offset(nativeEl:any):{width: number, height: number, top: number, left: number} {
        let boundingClientRect = nativeEl.getBoundingClientRect();
        return {
            width: boundingClientRect.width || nativeEl.offsetWidth,
            height: boundingClientRect.height || nativeEl.offsetHeight,
            top: boundingClientRect.top + (this.window.pageYOffset || this.document.documentElement.scrollTop),
            left: boundingClientRect.left + (this.window.pageXOffset || this.document.documentElement.scrollLeft)
        };
    }

    /**
     * Provides coordinates for the targetEl in relation to hostEl
     */
    public positionElements(hostEl:any, targetEl:any, positionStr:any, appendToBody:any):{top: number, left: number} {
        let positionStrParts = positionStr.split('-');
        let pos0 = positionStrParts[0];
        let pos1 = positionStrParts[1] || 'center';
        let hostElPos = appendToBody ?
            this.offset(hostEl) :
            this.position(hostEl);
        let targetElWidth = targetEl.offsetWidth;
        let targetElHeight = targetEl.offsetHeight;

        let shiftWidth:IAttribute = {
            center: function () {
                return hostElPos.left + hostElPos.width / 2 - targetElWidth / 2;
            },
            left: function () {
                return hostElPos.left;
            },
            right: function () {
                return hostElPos.left + hostElPos.width;
            }
        };

        let shiftHeight:IAttribute = {
            center: function ():number {
                return hostElPos.top + hostElPos.height / 2 - targetElHeight / 2;
            },
            top: function ():number {
                return hostElPos.top;
            },
            bottom: function ():number {
                return hostElPos.top + hostElPos.height;
            }
        };

        let targetElPos:{top: number, left: number};
        switch (pos0) {
            case 'right':
                targetElPos = {
                    top: shiftHeight[pos1](),
                    left: shiftWidth[pos0]()
                };
                break;
            case 'left':
                targetElPos = {
                    top: shiftHeight[pos1](),
                    left: hostElPos.left - targetElWidth
                };
                break;
            case 'bottom':
                targetElPos = {
                    top: shiftHeight[pos0](),
                    left: shiftWidth[pos1]()
                };
                break;
            default:
                targetElPos = {
                    top: hostElPos.top - targetElHeight,
                    left: shiftWidth[pos1]()
                };
                break;
        }

        return targetElPos;
    }
}

export const positionService = new PositionService();
export class AutocompleteOptions {
    public placement:string;
    public animation:boolean;

    constructor(options:AutocompleteOptions) {
        Object.assign(this, options);
    }
}
export const latinMap = {
  'Á': 'A',
  'Ă': 'A',
  'Ắ': 'A',
  'Ặ': 'A',
  'Ằ': 'A',
  'Ẳ': 'A',
  'Ẵ': 'A',
  'Ǎ': 'A',
  'Â': 'A',
  'Ấ': 'A',
  'Ậ': 'A',
  'Ầ': 'A',
  'Ẩ': 'A',
  'Ẫ': 'A',
  'Ä': 'A',
  'Ǟ': 'A',
  'Ȧ': 'A',
  'Ǡ': 'A',
  'Ạ': 'A',
  'Ȁ': 'A',
  'À': 'A',
  'Ả': 'A',
  'Ȃ': 'A',
  'Ā': 'A',
  'Ą': 'A',
  'Å': 'A',
  'Ǻ': 'A',
  'Ḁ': 'A',
  'Ⱥ': 'A',
  'Ã': 'A',
  'Ꜳ': 'AA',
  'Æ': 'AE',
  'Ǽ': 'AE',
  'Ǣ': 'AE',
  'Ꜵ': 'AO',
  'Ꜷ': 'AU',
  'Ꜹ': 'AV',
  'Ꜻ': 'AV',
  'Ꜽ': 'AY',
  'Ḃ': 'B',
  'Ḅ': 'B',
  'Ɓ': 'B',
  'Ḇ': 'B',
  'Ƀ': 'B',
  'Ƃ': 'B',
  'Ć': 'C',
  'Č': 'C',
  'Ç': 'C',
  'Ḉ': 'C',
  'Ĉ': 'C',
  'Ċ': 'C',
  'Ƈ': 'C',
  'Ȼ': 'C',
  'Ď': 'D',
  'Ḑ': 'D',
  'Ḓ': 'D',
  'Ḋ': 'D',
  'Ḍ': 'D',
  'Ɗ': 'D',
  'Ḏ': 'D',
  'Dz': 'D',
  'Dž': 'D',
  'Đ': 'D',
  'Ƌ': 'D',
  'DZ': 'DZ',
  'DŽ': 'DZ',
  'É': 'E',
  'Ĕ': 'E',
  'Ě': 'E',
  'Ȩ': 'E',
  'Ḝ': 'E',
  'Ê': 'E',
  'Ế': 'E',
  'Ệ': 'E',
  'Ề': 'E',
  'Ể': 'E',
  'Ễ': 'E',
  'Ḙ': 'E',
  'Ë': 'E',
  'Ė': 'E',
  'Ẹ': 'E',
  'Ȅ': 'E',
  'È': 'E',
  'Ẻ': 'E',
  'Ȇ': 'E',
  'Ē': 'E',
  'Ḗ': 'E',
  'Ḕ': 'E',
  'Ę': 'E',
  'Ɇ': 'E',
  'Ẽ': 'E',
  'Ḛ': 'E',
  'Ꝫ': 'ET',
  'Ḟ': 'F',
  'Ƒ': 'F',
  'Ǵ': 'G',
  'Ğ': 'G',
  'Ǧ': 'G',
  'Ģ': 'G',
  'Ĝ': 'G',
  'Ġ': 'G',
  'Ɠ': 'G',
  'Ḡ': 'G',
  'Ǥ': 'G',
  'Ḫ': 'H',
  'Ȟ': 'H',
  'Ḩ': 'H',
  'Ĥ': 'H',
  'Ⱨ': 'H',
  'Ḧ': 'H',
  'Ḣ': 'H',
  'Ḥ': 'H',
  'Ħ': 'H',
  'Í': 'I',
  'Ĭ': 'I',
  'Ǐ': 'I',
  'Î': 'I',
  'Ï': 'I',
  'Ḯ': 'I',
  'İ': 'I',
  'Ị': 'I',
  'Ȉ': 'I',
  'Ì': 'I',
  'Ỉ': 'I',
  'Ȋ': 'I',
  'Ī': 'I',
  'Į': 'I',
  'Ɨ': 'I',
  'Ĩ': 'I',
  'Ḭ': 'I',
  'Ꝺ': 'D',
  'Ꝼ': 'F',
  'Ᵹ': 'G',
  'Ꞃ': 'R',
  'Ꞅ': 'S',
  'Ꞇ': 'T',
  'Ꝭ': 'IS',
  'Ĵ': 'J',
  'Ɉ': 'J',
  'Ḱ': 'K',
  'Ǩ': 'K',
  'Ķ': 'K',
  'Ⱪ': 'K',
  'Ꝃ': 'K',
  'Ḳ': 'K',
  'Ƙ': 'K',
  'Ḵ': 'K',
  'Ꝁ': 'K',
  'Ꝅ': 'K',
  'Ĺ': 'L',
  'Ƚ': 'L',
  'Ľ': 'L',
  'Ļ': 'L',
  'Ḽ': 'L',
  'Ḷ': 'L',
  'Ḹ': 'L',
  'Ⱡ': 'L',
  'Ꝉ': 'L',
  'Ḻ': 'L',
  'Ŀ': 'L',
  'Ɫ': 'L',
  'Lj': 'L',
  'Ł': 'L',
  'LJ': 'LJ',
  'Ḿ': 'M',
  'Ṁ': 'M',
  'Ṃ': 'M',
  'Ɱ': 'M',
  'Ń': 'N',
  'Ň': 'N',
  'Ņ': 'N',
  'Ṋ': 'N',
  'Ṅ': 'N',
  'Ṇ': 'N',
  'Ǹ': 'N',
  'Ɲ': 'N',
  'Ṉ': 'N',
  'Ƞ': 'N',
  'Nj': 'N',
  'Ñ': 'N',
  'NJ': 'NJ',
  'Ó': 'O',
  'Ŏ': 'O',
  'Ǒ': 'O',
  'Ô': 'O',
  'Ố': 'O',
  'Ộ': 'O',
  'Ồ': 'O',
  'Ổ': 'O',
  'Ỗ': 'O',
  'Ö': 'O',
  'Ȫ': 'O',
  'Ȯ': 'O',
  'Ȱ': 'O',
  'Ọ': 'O',
  'Ő': 'O',
  'Ȍ': 'O',
  'Ò': 'O',
  'Ỏ': 'O',
  'Ơ': 'O',
  'Ớ': 'O',
  'Ợ': 'O',
  'Ờ': 'O',
  'Ở': 'O',
  'Ỡ': 'O',
  'Ȏ': 'O',
  'Ꝋ': 'O',
  'Ꝍ': 'O',
  'Ō': 'O',
  'Ṓ': 'O',
  'Ṑ': 'O',
  'Ɵ': 'O',
  'Ǫ': 'O',
  'Ǭ': 'O',
  'Ø': 'O',
  'Ǿ': 'O',
  'Õ': 'O',
  'Ṍ': 'O',
  'Ṏ': 'O',
  'Ȭ': 'O',
  'Ƣ': 'OI',
  'Ꝏ': 'OO',
  'Ɛ': 'E',
  'Ɔ': 'O',
  'Ȣ': 'OU',
  'Ṕ': 'P',
  'Ṗ': 'P',
  'Ꝓ': 'P',
  'Ƥ': 'P',
  'Ꝕ': 'P',
  'Ᵽ': 'P',
  'Ꝑ': 'P',
  'Ꝙ': 'Q',
  'Ꝗ': 'Q',
  'Ŕ': 'R',
  'Ř': 'R',
  'Ŗ': 'R',
  'Ṙ': 'R',
  'Ṛ': 'R',
  'Ṝ': 'R',
  'Ȑ': 'R',
  'Ȓ': 'R',
  'Ṟ': 'R',
  'Ɍ': 'R',
  'Ɽ': 'R',
  'Ꜿ': 'C',
  'Ǝ': 'E',
  'Ś': 'S',
  'Ṥ': 'S',
  'Š': 'S',
  'Ṧ': 'S',
  'Ş': 'S',
  'Ŝ': 'S',
  'Ș': 'S',
  'Ṡ': 'S',
  'Ṣ': 'S',
  'Ṩ': 'S',
  'Ť': 'T',
  'Ţ': 'T',
  'Ṱ': 'T',
  'Ț': 'T',
  'Ⱦ': 'T',
  'Ṫ': 'T',
  'Ṭ': 'T',
  'Ƭ': 'T',
  'Ṯ': 'T',
  'Ʈ': 'T',
  'Ŧ': 'T',
  'Ɐ': 'A',
  'Ꞁ': 'L',
  'Ɯ': 'M',
  'Ʌ': 'V',
  'Ꜩ': 'TZ',
  'Ú': 'U',
  'Ŭ': 'U',
  'Ǔ': 'U',
  'Û': 'U',
  'Ṷ': 'U',
  'Ü': 'U',
  'Ǘ': 'U',
  'Ǚ': 'U',
  'Ǜ': 'U',
  'Ǖ': 'U',
  'Ṳ': 'U',
  'Ụ': 'U',
  'Ű': 'U',
  'Ȕ': 'U',
  'Ù': 'U',
  'Ủ': 'U',
  'Ư': 'U',
  'Ứ': 'U',
  'Ự': 'U',
  'Ừ': 'U',
  'Ử': 'U',
  'Ữ': 'U',
  'Ȗ': 'U',
  'Ū': 'U',
  'Ṻ': 'U',
  'Ų': 'U',
  'Ů': 'U',
  'Ũ': 'U',
  'Ṹ': 'U',
  'Ṵ': 'U',
  'Ꝟ': 'V',
  'Ṿ': 'V',
  'Ʋ': 'V',
  'Ṽ': 'V',
  'Ꝡ': 'VY',
  'Ẃ': 'W',
  'Ŵ': 'W',
  'Ẅ': 'W',
  'Ẇ': 'W',
  'Ẉ': 'W',
  'Ẁ': 'W',
  'Ⱳ': 'W',
  'Ẍ': 'X',
  'Ẋ': 'X',
  'Ý': 'Y',
  'Ŷ': 'Y',
  'Ÿ': 'Y',
  'Ẏ': 'Y',
  'Ỵ': 'Y',
  'Ỳ': 'Y',
  'Ƴ': 'Y',
  'Ỷ': 'Y',
  'Ỿ': 'Y',
  'Ȳ': 'Y',
  'Ɏ': 'Y',
  'Ỹ': 'Y',
  'Ź': 'Z',
  'Ž': 'Z',
  'Ẑ': 'Z',
  'Ⱬ': 'Z',
  'Ż': 'Z',
  'Ẓ': 'Z',
  'Ȥ': 'Z',
  'Ẕ': 'Z',
  'Ƶ': 'Z',
  'IJ': 'IJ',
  'Œ': 'OE',
  'ᴀ': 'A',
  'ᴁ': 'AE',
  'ʙ': 'B',
  'ᴃ': 'B',
  'ᴄ': 'C',
  'ᴅ': 'D',
  'ᴇ': 'E',
  'ꜰ': 'F',
  'ɢ': 'G',
  'ʛ': 'G',
  'ʜ': 'H',
  'ɪ': 'I',
  'ʁ': 'R',
  'ᴊ': 'J',
  'ᴋ': 'K',
  'ʟ': 'L',
  'ᴌ': 'L',
  'ᴍ': 'M',
  'ɴ': 'N',
  'ᴏ': 'O',
  'ɶ': 'OE',
  'ᴐ': 'O',
  'ᴕ': 'OU',
  'ᴘ': 'P',
  'ʀ': 'R',
  'ᴎ': 'N',
  'ᴙ': 'R',
  'ꜱ': 'S',
  'ᴛ': 'T',
  'ⱻ': 'E',
  'ᴚ': 'R',
  'ᴜ': 'U',
  'ᴠ': 'V',
  'ᴡ': 'W',
  'ʏ': 'Y',
  'ᴢ': 'Z',
  'á': 'a',
  'ă': 'a',
  'ắ': 'a',
  'ặ': 'a',
  'ằ': 'a',
  'ẳ': 'a',
  'ẵ': 'a',
  'ǎ': 'a',
  'â': 'a',
  'ấ': 'a',
  'ậ': 'a',
  'ầ': 'a',
  'ẩ': 'a',
  'ẫ': 'a',
  'ä': 'a',
  'ǟ': 'a',
  'ȧ': 'a',
  'ǡ': 'a',
  'ạ': 'a',
  'ȁ': 'a',
  'à': 'a',
  'ả': 'a',
  'ȃ': 'a',
  'ā': 'a',
  'ą': 'a',
  'ᶏ': 'a',
  'ẚ': 'a',
  'å': 'a',
  'ǻ': 'a',
  'ḁ': 'a',
  'ⱥ': 'a',
  'ã': 'a',
  'ꜳ': 'aa',
  'æ': 'ae',
  'ǽ': 'ae',
  'ǣ': 'ae',
  'ꜵ': 'ao',
  'ꜷ': 'au',
  'ꜹ': 'av',
  'ꜻ': 'av',
  'ꜽ': 'ay',
  'ḃ': 'b',
  'ḅ': 'b',
  'ɓ': 'b',
  'ḇ': 'b',
  'ᵬ': 'b',
  'ᶀ': 'b',
  'ƀ': 'b',
  'ƃ': 'b',
  'ɵ': 'o',
  'ć': 'c',
  'č': 'c',
  'ç': 'c',
  'ḉ': 'c',
  'ĉ': 'c',
  'ɕ': 'c',
  'ċ': 'c',
  'ƈ': 'c',
  'ȼ': 'c',
  'ď': 'd',
  'ḑ': 'd',
  'ḓ': 'd',
  'ȡ': 'd',
  'ḋ': 'd',
  'ḍ': 'd',
  'ɗ': 'd',
  'ᶑ': 'd',
  'ḏ': 'd',
  'ᵭ': 'd',
  'ᶁ': 'd',
  'đ': 'd',
  'ɖ': 'd',
  'ƌ': 'd',
  'ı': 'i',
  'ȷ': 'j',
  'ɟ': 'j',
  'ʄ': 'j',
  'dz': 'dz',
  'dž': 'dz',
  'é': 'e',
  'ĕ': 'e',
  'ě': 'e',
  'ȩ': 'e',
  'ḝ': 'e',
  'ê': 'e',
  'ế': 'e',
  'ệ': 'e',
  'ề': 'e',
  'ể': 'e',
  'ễ': 'e',
  'ḙ': 'e',
  'ë': 'e',
  'ė': 'e',
  'ẹ': 'e',
  'ȅ': 'e',
  'è': 'e',
  'ẻ': 'e',
  'ȇ': 'e',
  'ē': 'e',
  'ḗ': 'e',
  'ḕ': 'e',
  'ⱸ': 'e',
  'ę': 'e',
  'ᶒ': 'e',
  'ɇ': 'e',
  'ẽ': 'e',
  'ḛ': 'e',
  'ꝫ': 'et',
  'ḟ': 'f',
  'ƒ': 'f',
  'ᵮ': 'f',
  'ᶂ': 'f',
  'ǵ': 'g',
  'ğ': 'g',
  'ǧ': 'g',
  'ģ': 'g',
  'ĝ': 'g',
  'ġ': 'g',
  'ɠ': 'g',
  'ḡ': 'g',
  'ᶃ': 'g',
  'ǥ': 'g',
  'ḫ': 'h',
  'ȟ': 'h',
  'ḩ': 'h',
  'ĥ': 'h',
  'ⱨ': 'h',
  'ḧ': 'h',
  'ḣ': 'h',
  'ḥ': 'h',
  'ɦ': 'h',
  'ẖ': 'h',
  'ħ': 'h',
  'ƕ': 'hv',
  'í': 'i',
  'ĭ': 'i',
  'ǐ': 'i',
  'î': 'i',
  'ï': 'i',
  'ḯ': 'i',
  'ị': 'i',
  'ȉ': 'i',
  'ì': 'i',
  'ỉ': 'i',
  'ȋ': 'i',
  'ī': 'i',
  'į': 'i',
  'ᶖ': 'i',
  'ɨ': 'i',
  'ĩ': 'i',
  'ḭ': 'i',
  'ꝺ': 'd',
  'ꝼ': 'f',
  'ᵹ': 'g',
  'ꞃ': 'r',
  'ꞅ': 's',
  'ꞇ': 't',
  'ꝭ': 'is',
  'ǰ': 'j',
  'ĵ': 'j',
  'ʝ': 'j',
  'ɉ': 'j',
  'ḱ': 'k',
  'ǩ': 'k',
  'ķ': 'k',
  'ⱪ': 'k',
  'ꝃ': 'k',
  'ḳ': 'k',
  'ƙ': 'k',
  'ḵ': 'k',
  'ᶄ': 'k',
  'ꝁ': 'k',
  'ꝅ': 'k',
  'ĺ': 'l',
  'ƚ': 'l',
  'ɬ': 'l',
  'ľ': 'l',
  'ļ': 'l',
  'ḽ': 'l',
  'ȴ': 'l',
  'ḷ': 'l',
  'ḹ': 'l',
  'ⱡ': 'l',
  'ꝉ': 'l',
  'ḻ': 'l',
  'ŀ': 'l',
  'ɫ': 'l',
  'ᶅ': 'l',
  'ɭ': 'l',
  'ł': 'l',
  'lj': 'lj',
  'ſ': 's',
  'ẜ': 's',
  'ẛ': 's',
  'ẝ': 's',
  'ḿ': 'm',
  'ṁ': 'm',
  'ṃ': 'm',
  'ɱ': 'm',
  'ᵯ': 'm',
  'ᶆ': 'm',
  'ń': 'n',
  'ň': 'n',
  'ņ': 'n',
  'ṋ': 'n',
  'ȵ': 'n',
  'ṅ': 'n',
  'ṇ': 'n',
  'ǹ': 'n',
  'ɲ': 'n',
  'ṉ': 'n',
  'ƞ': 'n',
  'ᵰ': 'n',
  'ᶇ': 'n',
  'ɳ': 'n',
  'ñ': 'n',
  'nj': 'nj',
  'ó': 'o',
  'ŏ': 'o',
  'ǒ': 'o',
  'ô': 'o',
  'ố': 'o',
  'ộ': 'o',
  'ồ': 'o',
  'ổ': 'o',
  'ỗ': 'o',
  'ö': 'o',
  'ȫ': 'o',
  'ȯ': 'o',
  'ȱ': 'o',
  'ọ': 'o',
  'ő': 'o',
  'ȍ': 'o',
  'ò': 'o',
  'ỏ': 'o',
  'ơ': 'o',
  'ớ': 'o',
  'ợ': 'o',
  'ờ': 'o',
  'ở': 'o',
  'ỡ': 'o',
  'ȏ': 'o',
  'ꝋ': 'o',
  'ꝍ': 'o',
  'ⱺ': 'o',
  'ō': 'o',
  'ṓ': 'o',
  'ṑ': 'o',
  'ǫ': 'o',
  'ǭ': 'o',
  'ø': 'o',
  'ǿ': 'o',
  'õ': 'o',
  'ṍ': 'o',
  'ṏ': 'o',
  'ȭ': 'o',
  'ƣ': 'oi',
  'ꝏ': 'oo',
  'ɛ': 'e',
  'ᶓ': 'e',
  'ɔ': 'o',
  'ᶗ': 'o',
  'ȣ': 'ou',
  'ṕ': 'p',
  'ṗ': 'p',
  'ꝓ': 'p',
  'ƥ': 'p',
  'ᵱ': 'p',
  'ᶈ': 'p',
  'ꝕ': 'p',
  'ᵽ': 'p',
  'ꝑ': 'p',
  'ꝙ': 'q',
  'ʠ': 'q',
  'ɋ': 'q',
  'ꝗ': 'q',
  'ŕ': 'r',
  'ř': 'r',
  'ŗ': 'r',
  'ṙ': 'r',
  'ṛ': 'r',
  'ṝ': 'r',
  'ȑ': 'r',
  'ɾ': 'r',
  'ᵳ': 'r',
  'ȓ': 'r',
  'ṟ': 'r',
  'ɼ': 'r',
  'ᵲ': 'r',
  'ᶉ': 'r',
  'ɍ': 'r',
  'ɽ': 'r',
  'ↄ': 'c',
  'ꜿ': 'c',
  'ɘ': 'e',
  'ɿ': 'r',
  'ś': 's',
  'ṥ': 's',
  'š': 's',
  'ṧ': 's',
  'ş': 's',
  'ŝ': 's',
  'ș': 's',
  'ṡ': 's',
  'ṣ': 's',
  'ṩ': 's',
  'ʂ': 's',
  'ᵴ': 's',
  'ᶊ': 's',
  'ȿ': 's',
  'ɡ': 'g',
  'ᴑ': 'o',
  'ᴓ': 'o',
  'ᴝ': 'u',
  'ť': 't',
  'ţ': 't',
  'ṱ': 't',
  'ț': 't',
  'ȶ': 't',
  'ẗ': 't',
  'ⱦ': 't',
  'ṫ': 't',
  'ṭ': 't',
  'ƭ': 't',
  'ṯ': 't',
  'ᵵ': 't',
  'ƫ': 't',
  'ʈ': 't',
  'ŧ': 't',
  'ᵺ': 'th',
  'ɐ': 'a',
  'ᴂ': 'ae',
  'ǝ': 'e',
  'ᵷ': 'g',
  'ɥ': 'h',
  'ʮ': 'h',
  'ʯ': 'h',
  'ᴉ': 'i',
  'ʞ': 'k',
  'ꞁ': 'l',
  'ɯ': 'm',
  'ɰ': 'm',
  'ᴔ': 'oe',
  'ɹ': 'r',
  'ɻ': 'r',
  'ɺ': 'r',
  'ⱹ': 'r',
  'ʇ': 't',
  'ʌ': 'v',
  'ʍ': 'w',
  'ʎ': 'y',
  'ꜩ': 'tz',
  'ú': 'u',
  'ŭ': 'u',
  'ǔ': 'u',
  'û': 'u',
  'ṷ': 'u',
  'ü': 'u',
  'ǘ': 'u',
  'ǚ': 'u',
  'ǜ': 'u',
  'ǖ': 'u',
  'ṳ': 'u',
  'ụ': 'u',
  'ű': 'u',
  'ȕ': 'u',
  'ù': 'u',
  'ủ': 'u',
  'ư': 'u',
  'ứ': 'u',
  'ự': 'u',
  'ừ': 'u',
  'ử': 'u',
  'ữ': 'u',
  'ȗ': 'u',
  'ū': 'u',
  'ṻ': 'u',
  'ų': 'u',
  'ᶙ': 'u',
  'ů': 'u',
  'ũ': 'u',
  'ṹ': 'u',
  'ṵ': 'u',
  'ᵫ': 'ue',
  'ꝸ': 'um',
  'ⱴ': 'v',
  'ꝟ': 'v',
  'ṿ': 'v',
  'ʋ': 'v',
  'ᶌ': 'v',
  'ⱱ': 'v',
  'ṽ': 'v',
  'ꝡ': 'vy',
  'ẃ': 'w',
  'ŵ': 'w',
  'ẅ': 'w',
  'ẇ': 'w',
  'ẉ': 'w',
  'ẁ': 'w',
  'ⱳ': 'w',
  'ẘ': 'w',
  'ẍ': 'x',
  'ẋ': 'x',
  'ᶍ': 'x',
  'ý': 'y',
  'ŷ': 'y',
  'ÿ': 'y',
  'ẏ': 'y',
  'ỵ': 'y',
  'ỳ': 'y',
  'ƴ': 'y',
  'ỷ': 'y',
  'ỿ': 'y',
  'ȳ': 'y',
  'ẙ': 'y',
  'ɏ': 'y',
  'ỹ': 'y',
  'ź': 'z',
  'ž': 'z',
  'ẑ': 'z',
  'ʑ': 'z',
  'ⱬ': 'z',
  'ż': 'z',
  'ẓ': 'z',
  'ȥ': 'z',
  'ẕ': 'z',
  'ᵶ': 'z',
  'ᶎ': 'z',
  'ʐ': 'z',
  'ƶ': 'z',
  'ɀ': 'z',
  'ff': 'ff',
  'ffi': 'ffi',
  'ffl': 'ffl',
  'fi': 'fi',
  'fl': 'fl',
  'ij': 'ij',
  'œ': 'oe',
  'st': 'st',
  'ₐ': 'a',
  'ₑ': 'e',
  'ᵢ': 'i',
  'ⱼ': 'j',
  'ₒ': 'o',
  'ᵣ': 'r',
  'ᵤ': 'u',
  'ᵥ': 'v',
  'ₓ': 'x'
};
/**
 * bootstrap
 */
import {Directive, TemplateRef, ViewContainerRef, Inject} from 'angular2/core';

export interface IAttribute {
    [key: string]: any;
}

@Directive({
    selector: '[ngTransclude]',
    properties: ['ngTransclude']
})
export class NgTransclude {
    private _ngTransclude: TemplateRef;

    private set ngTransclude(templateRef:TemplateRef) {
        this._ngTransclude = templateRef;
        if (templateRef) {
            this.viewRef.createEmbeddedView(templateRef);
        }
    }

    private get ngTransclude() {
        return this._ngTransclude;
    }

    constructor(@Inject(ViewContainerRef) public viewRef:ViewContainerRef) {
    }
}
/**
 * Created by Tareq Boulakjar. from angulartypescript.com
 */

import {Component, ElementRef, ViewEncapsulation} from 'angular2/core';
import {Component} from 'angular2/core';
import {CORE_DIRECTIVES, FORM_DIRECTIVES} from 'angular2/common';
import {AutocompleteContainer} from './autocomplete-container';
import {Autocomplete} from './autocomplete.component';
export const AUTOCOMPLETE_DIRECTIVES = [Autocomplete, AutocompleteContainer];


/*Angular 2 Autocomplete Example*/
@Component({
    selector: 'my-app',

    template:`
                <div class='container-fluid'>
                    <h3>Angular 2 Autocomplete Example</h3>
                    <h4>The Selected Car: {{selectedCar}}</h4>
                    <input [(ngModel)]="selectedCar"
                           [autocomplete]="carsExample2"
                           (autocompleteOnSelect)="autocompleteOnSelect($event)"
                           [autocompleteOptionField]="'name'"
                           class="form-control">

                    <h3>Asynchronous results</h3>
                    <h4>Model: {{asyncSelectedCar}}</h4>
                    <input [(ngModel)]="asyncSelectedCar"
                           [autocomplete]="getAsyncData(getCurrentContext())"
                           (autocompleteLoading)="changeAutocompleteLoading($event)"
                           (autocompleteNoResults)="changeAutocompleteNoResults($event)"
                           (autocompleteOnSelect)="autocompleteOnSelect($event)"
                           [autocompleteOptionsLimit]="7"
                           placeholder="Locations loaded with timeout"
                           class="form-control">
                    <div [hidden]="autocompleteLoading!==true">
                        <i class="glyphicon glyphicon-refresh ng-hide" style=""></i>
                    </div>
                    <div [hidden]="autocompleteNoResults!==true" class="" style="">
                        <i class="glyphicon glyphicon-remove"></i> Empty Query !
                    </div>
                </div>
               `,
    directives: [AUTOCOMPLETE_DIRECTIVES, CORE_DIRECTIVES, FORM_DIRECTIVES],
})
export class Angular2Autocomplete {
    private selectedCar:string = '';
    private asyncSelectedCar:string = '';
    private autocompleteLoading:boolean = false;
    private autocompleteNoResults:boolean = false;
    private carsExample1:Array<string> = ['BMW', 'Audi','Mercedes','Porsche','Volkswagen','Opel','Maserati','Volkswagen','BMW Serie 1','BMW Serie 2'];
    private carsExample2:Array<any> = [
        {id: 1, name: 'BMW'},
        {id: 2, name: 'Audi'},
        {id: 3, name: 'Mercedes'},
        {id: 4, name: 'Porsche'},
        {id: 5, name: 'Volkswagen'},
        {id: 6, name: 'Opel'},
        {id: 7, name: 'Maserati'},
        {id: 8, name: 'Volkswagen'},
        {id: 9, name: 'BMW Serie 1'},
        {id: 10, name: 'BMW Serie 2'},
    ];


    private getCurrentContext() {
        return this;
    }

    private _cachedResult:any;
    private _previousContext:any;

    private getAsyncData(context:any):Function {
        if (this._previousContext === context) {
            return this._cachedResult;
        }

        this._previousContext = context;
        let f:Function = function ():Promise<string[]> {
            let p:Promise<string[]> = new Promise((resolve:Function) => {
                setTimeout(() => {
                    let query = new RegExp(context.asyncSelectedCar, 'ig');
                    return resolve(context.carsExample1.filter((state:any) => {
                        return query.test(state);
                    }));
                }, 500);
            });
            return p;
        };
        this._cachedResult = f;
        return this._cachedResult;
    }

    private changeAutocompleteLoading(e:boolean) {
        this.autocompleteLoading = e;
    }

    private changeAutocompleteNoResults(e:boolean) {
        this.autocompleteNoResults = e;
    }

    private autocompleteOnSelect(e:any) {
        console.log(`Selected value: ${e.item}`);
    }
}
/**
 * bootstrap
 */
import {Component, ElementRef, ViewEncapsulation} from 'angular2/core';
import {CORE_DIRECTIVES} from 'angular2/common';
import {Autocomplete} from './autocomplete.component';
import {AutocompleteOptions} from './options.class';
import {positionService} from './position';


@Component({
    selector: 'autocomplete-container',
    directives: [CORE_DIRECTIVES],
    template: `
                  <ul class="dropdown-menu"
                      [ngStyle]="{top: top, left: left, display: display}"
                      style="display: block">
                    <li *ngFor="#match of matches"
                        [class.active]="isActive(match)"
                        (mouseenter)="selectActive(match)">
                        <a href="#" (click)="selectMatch(match, $event)" tabindex="-1" [innerHtml]="hightlight(match, query)"></a>
                    </li>
                  </ul>
              `,

    encapsulation: ViewEncapsulation.None
})
export class AutocompleteContainer {
    public parent:Autocomplete;
    public query:any;
    private _matches:Array<any> = [];
    private _field:string;
    private _active:any;
    private top:string;
    private left:string;
    private display:string;
    private placement:string;

    constructor(public element:ElementRef, options:AutocompleteOptions) {
        Object.assign(this, options);
    }

    public get matches():Array<string> {
        return this._matches;
    }

    public set matches(value:Array<string>) {
        this._matches = value;

        if (this._matches.length > 0) {
            this._active = this._matches[0];
        }
    }

    public set field(value:string) {
        this._field = value;
    }

    public position(hostEl:ElementRef) {
        this.display = 'block';
        this.top = '0px';
        this.left = '0px';
        let p = positionService
            .positionElements(hostEl.nativeElement,
                this.element.nativeElement.children[0],
                this.placement, false);
        this.top = p.top + 'px';
        this.left = p.left + 'px';
    }

    public selectActiveMatch() {
        this.selectMatch(this._active);
    }

    public prevActiveMatch() {
        let index = this.matches.indexOf(this._active);
        this._active = this.matches[index - 1 < 0 ? this.matches.length - 1 : index - 1];
    }

    public nextActiveMatch() {
        let index = this.matches.indexOf(this._active);
        this._active = this.matches[index + 1 > this.matches.length - 1 ? 0 : index + 1];
    }

    private selectActive(value:any) {
        this._active = value;
    }

    private isActive(value:any):boolean {
        return this._active === value;
    }

    private selectMatch(value:any, e:Event = null) {
        if (e) {
            e.stopPropagation();
            e.preventDefault();
        }

        this.parent.changeModel(value);
        this.parent.autocompleteOnSelect.emit({
            item: value
        });
        return false;
    }

    private hightlight(item:any, query:string) {
        let itemStr:string = (typeof item === 'object' && this._field ? item[this._field] : item).toString();
        //let itemStrHelper:string = (this.parent.autocompleteLatinize ? AutocompleteUtils.latinize(itemStr) : itemStr).toLowerCase();
        let itemStrHelper:string =itemStr.toLowerCase();
        let startIdx:number;
        let tokenLen:number;

        if (typeof query === 'object') {
            let queryLen:number = query.length;
            for (let i = 0; i < queryLen; i += 1) {
                startIdx = itemStrHelper.indexOf(query[i]);
                tokenLen = query[i].length;
                if (startIdx >= 0 && tokenLen > 0) {
                    itemStr = itemStr.substring(0, startIdx) + '<strong>' + itemStr.substring(startIdx, startIdx + tokenLen) + '</strong>' + itemStr.substring(startIdx + tokenLen);
                    itemStrHelper = itemStrHelper.substring(0, startIdx) + '        ' + ' '.repeat(tokenLen) + '         ' + itemStrHelper.substring(startIdx + tokenLen);
                }
            }
        } else if (query) {
            startIdx = itemStrHelper.indexOf(query);
            tokenLen = query.length;
            if (startIdx >= 0 && tokenLen > 0) {
                itemStr = itemStr.substring(0, startIdx) + '<strong>' + itemStr.substring(startIdx, startIdx + tokenLen) + '</strong>' + itemStr.substring(startIdx + tokenLen);
            }
        }

        return itemStr;
    }
}
/**
 * bootstrap
 */
import {Component, ElementRef, ViewEncapsulation} from 'angular2/core';
import {CORE_DIRECTIVES} from 'angular2/common';
import {
    Directive, Input, Output, HostListener,
    EventEmitter, OnInit,
    ElementRef, Renderer,
    DynamicComponentLoader, ComponentRef, Provider, Injector
} from 'angular2/core';
import {NgModel}from 'angular2/common';

function setProperty(renderer:Renderer, elementRef:ElementRef, propName:string, propValue:any) {
    renderer.setElementProperty(elementRef.nativeElement, propName, propValue);
}

import {positionService} from './position';
import {AutocompleteUtils} from './sanitize';
import {AutocompleteContainer} from './autocomplete-container';
import {AutocompleteOptions} from './options.class';




@Directive({
    selector: 'autocomplete[ngModel], [ngModel][autocomplete]'
})
export class Autocomplete implements OnInit {
    @Output() public autocompleteLoading:EventEmitter<boolean> = new EventEmitter();
    @Output() public autocompleteNoResults:EventEmitter<boolean> = new EventEmitter();
    @Output() public autocompleteOnSelect:EventEmitter<{item: any}> = new EventEmitter();

    @Input() public autocomplete:any;
    @Input() public autocompleteMinLength:number;
    @Input() public autocompleteWaitMs:number;
    @Input() public autocompleteOptionsLimit:number;
    @Input() public autocompleteOptionField:string;
    @Input() public autocompleteAsync:boolean = null;
    @Input() public autocompleteLatinize:boolean = true;
    @Input() public autocompleteSingleWords:boolean = true;
    @Input() public autocompleteWordDelimiters:string = ' ';
    @Input() public autocompletePhraseDelimiters:string = '\'"';



    public container:AutocompleteContainer;

    private debouncer:Function;
    private _matches:Array<any> = [];
    private placement:string = 'bottom-left';
    private popup:Promise<ComponentRef>;

    constructor(private cd:NgModel,
                private element:ElementRef,
                private renderer:Renderer,
                private loader:DynamicComponentLoader) {
    }

    public get matches() {
        return this._matches;
    }

    private debounce(func:Function, wait:number):Function {
        let timeout:any;
        let args:Array<any>;
        let timestamp:number;
        let waitOriginal:number = wait;

        return function () {
            // save details of latest call
            args = [].slice.call(arguments, 0);
            timestamp = Date.now();

            // this trick is about implementing of 'autocompleteWaitMs'
            // in this case we have adaptive 'wait' parameter
            // we should use standard 'wait'('waitOriginal') in case of
            // popup is opened, otherwise - 'autocompleteWaitMs' parameter
            wait = this.container ? waitOriginal : this.autocompleteWaitMs;

            // this is where the magic happens
            let later = function () {

                // how long ago was the last call
                let last = Date.now() - timestamp;

                // if the latest call was less that the wait period ago
                // then we reset the timeout to wait for the difference
                if (last < wait) {
                    timeout = setTimeout(later, wait - last);
                    // or if not we can null out the timer and run the latest
                } else {
                    timeout = null;
                    func.apply(this, args);
                }
            };

            // we only need to set the timer now if one isn't already running
            if (!timeout) {
                timeout = setTimeout(later, wait);
            }
        };
    }

    private processMatches() {
        this._matches = [];
        if (this.cd.model.toString().length >= this.autocompleteMinLength) {
            // If singleWords, break model here to not be doing extra work on each iteration
            let normalizedQuery = (this.autocompleteLatinize ? AutocompleteUtils.latinize(this.cd.model) : this.cd.model).toString().toLowerCase();
            normalizedQuery = this.autocompleteSingleWords ? AutocompleteUtils.tokenize(normalizedQuery, this.autocompleteWordDelimiters, this.autocompletePhraseDelimiters) : normalizedQuery;
            for (let i = 0; i < this.autocomplete.length; i++) {
                let match:string;

                if (typeof this.autocomplete[i] === 'object' &&
                    this.autocomplete[i][this.autocompleteOptionField]) {
                    match = this.autocompleteLatinize ? AutocompleteUtils.latinize(this.autocomplete[i][this.autocompleteOptionField].toString()) : this.autocomplete[i][this.autocompleteOptionField].toString();
                }

                if (typeof this.autocomplete[i] === 'string') {
                    match = this.autocompleteLatinize ? AutocompleteUtils.latinize(this.autocomplete[i].toString()) : this.autocomplete[i].toString();
                }

                if (!match) {
                    console.log('Invalid match type', typeof this.autocomplete[i], this.autocompleteOptionField);
                    continue;
                }

                if (this.testMatch(match.toLowerCase(), normalizedQuery)) {
                    this._matches.push(this.autocomplete[i]);
                    if (this._matches.length > this.autocompleteOptionsLimit - 1) {
                        break;
                    }
                }
            }
        }
    }

    private testMatch(match:string, test:any) {
        let spaceLength:number;

        if (typeof test === 'object') {
            spaceLength = test.length;
            for (let i = 0; i < spaceLength; i += 1) {
                if (test[i].length > 0 && match.indexOf(test[i]) < 0) {
                    return false;
                }
            }
            return true;
        } else {
            return match.indexOf(test) >= 0;
        }
    }

    private finalizeAsyncCall() {
        this.autocompleteLoading.emit(false);
        this.autocompleteNoResults.emit(this.cd.model.toString().length >=
            this.autocompleteMinLength && this.matches.length <= 0);

        if (this.cd.model.toString().length <= 0 || this._matches.length <= 0) {
            this.hide();
            return;
        }

        if (this.container && this._matches.length > 0) {
            // This improves the speedas it won't have to be done for each list item
            let normalizedQuery = (this.autocompleteLatinize ? AutocompleteUtils.latinize(this.cd.model) : this.cd.model).toString().toLowerCase();
            this.container.query = this.autocompleteSingleWords ? AutocompleteUtils.tokenize(normalizedQuery, this.autocompleteWordDelimiters, this.autocompletePhraseDelimiters) : normalizedQuery;
            this.container.matches = this._matches;
        }

        if (!this.container && this._matches.length > 0) {
            this.show(this._matches);
        }
    }

    ngOnInit() {
        this.autocompleteOptionsLimit = this.autocompleteOptionsLimit || 20;
        this.autocompleteMinLength = this.autocompleteMinLength || 1;
        this.autocompleteWaitMs = this.autocompleteWaitMs || 0;

        // async should be false in case of array
        if (this.autocompleteAsync === null && typeof this.autocomplete !== 'function') {
            this.autocompleteAsync = false;
        }

        // async should be true for any case of function
        if (typeof this.autocomplete === 'function') {
            this.autocompleteAsync = true;
        }

        if (this.autocompleteAsync === true) {
            this.debouncer = this.debounce(() => {
                if (typeof this.autocomplete === 'function') {
                    this.autocomplete().then((matches:any[]) => {
                        this._matches = [];
                        if (this.cd.model.toString().length >= this.autocompleteMinLength) {
                            for (let i = 0; i < matches.length; i++) {
                                this._matches.push(matches[i]);
                                if (this._matches.length > this.autocompleteOptionsLimit - 1) {
                                    break;
                                }
                            }
                        }

                        this.finalizeAsyncCall();
                    });
                }

                // source is array
                if (typeof this.autocomplete === 'object' && this.autocomplete.length) {
                    this.processMatches();
                    this.finalizeAsyncCall();
                }
            }, 100);
        }
    }

    @HostListener('keyup', ['$event'])
    onChange(e:KeyboardEvent) {
        if (this.container) {
            // esc
            if (e.keyCode === 27) {
                this.hide();
                return;
            }

            // up
            if (e.keyCode === 38) {
                this.container.prevActiveMatch();
                return;
            }

            // down
            if (e.keyCode === 40) {
                this.container.nextActiveMatch();
                return;
            }

            // enter
            if (e.keyCode === 13) {
                this.container.selectActiveMatch();
                return;
            }
        }

        this.autocompleteLoading.emit(true);

        if (this.autocompleteAsync === true) {
            this.debouncer();
        }

        if (this.autocompleteAsync === false) {
            this.processMatches();
            this.finalizeAsyncCall();
        }
    }

    public changeModel(value:any) {
        let valueStr:string = ((typeof value === 'object' && this.autocompleteOptionField) ? value[this.autocompleteOptionField] : value).toString();
        this.cd.viewToModelUpdate(valueStr);
        setProperty(this.renderer, this.element, 'value', valueStr);
        this.hide();
    }

    show(matches:Array<any>) {
        let options = new AutocompleteOptions({
            placement: this.placement,
            animation: false
        });

        let binding = Injector.resolve([
            new Provider(AutocompleteOptions, {useValue: options})
        ]);


        this.popup = this.loader
            .loadNextToLocation(AutocompleteContainer, this.element, binding)
            .then((componentRef:ComponentRef) => {
                componentRef.instance.position(this.element);
                this.container = componentRef.instance;
                this.container.parent = this;
                // This improves the speedas it won't have to be done for each list item
                let normalizedQuery = (this.autocompleteLatinize ? AutocompleteUtils.latinize(this.cd.model) : this.cd.model).toString().toLowerCase();
                this.container.query = this.autocompleteSingleWords ? AutocompleteUtils.tokenize(normalizedQuery, this.autocompleteWordDelimiters, this.autocompletePhraseDelimiters) : normalizedQuery;
                this.container.matches = matches;
                this.container.field = this.autocompleteOptionField;
                this.element.nativeElement.focus();
                return componentRef;
            });
    }

    hide() {
        if (this.container) {
            this.popup.then((componentRef:ComponentRef) => {
                componentRef.dispose();
                this.container = null;
                return componentRef;
            });
        }
    }
}