From aea48353529773cfd6e237fe60a661f1fdc78201 Mon Sep 17 00:00:00 2001
From: "art.dambrine" <art.dambrine@gmail.com>
Date: Thu, 1 Apr 2021 16:51:05 +0200
Subject: [PATCH] autocompletion for pokemon search with api platform &
 autocomplete.js

---
 public/autocomplete/LICENSE                   | 201 ++++++
 public/autocomplete/README.md                 | 124 ++++
 public/autocomplete/dist/css/autoComplete.css | 153 +++++
 .../dist/css/images/magnifier.svg             |   3 +
 .../autocomplete/dist/css/images/search.svg   |   8 +
 public/autocomplete/dist/js/autoComplete.js   | 618 ++++++++++++++++++
 .../autocomplete/dist/js/autoComplete.min.js  |   1 +
 public/autocomplete/dist/js/index.js          |  67 ++
 public/js/customButton.js                     |   1 +
 templates/pokemon/index.html.twig             |   7 +-
 10 files changed, 1181 insertions(+), 2 deletions(-)
 create mode 100644 public/autocomplete/LICENSE
 create mode 100644 public/autocomplete/README.md
 create mode 100644 public/autocomplete/dist/css/autoComplete.css
 create mode 100644 public/autocomplete/dist/css/images/magnifier.svg
 create mode 100644 public/autocomplete/dist/css/images/search.svg
 create mode 100644 public/autocomplete/dist/js/autoComplete.js
 create mode 100644 public/autocomplete/dist/js/autoComplete.min.js
 create mode 100644 public/autocomplete/dist/js/index.js

diff --git a/public/autocomplete/LICENSE b/public/autocomplete/LICENSE
new file mode 100644
index 0000000..261eeb9
--- /dev/null
+++ b/public/autocomplete/LICENSE
@@ -0,0 +1,201 @@
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "[]"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright [yyyy] [name of copyright owner]
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
diff --git a/public/autocomplete/README.md b/public/autocomplete/README.md
new file mode 100644
index 0000000..73d2f28
--- /dev/null
+++ b/public/autocomplete/README.md
@@ -0,0 +1,124 @@
+# autoComplete.js :sparkles:
+
+[![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0)
+[![GitHub package.json version](https://img.shields.io/github/package-json/v/TarekRaafat/autoComplete.js)](https://badge.fury.io/gh/tarekraafat%2FautoComplete.js)
+[![npm](https://img.shields.io/npm/v/@tarekraafat/autocomplete.js)](https://badge.fury.io/js/%40tarekraafat%2Fautocomplete.js)
+![GitHub top language](https://img.shields.io/github/languages/top/TarekRaafat/autoComplete.js?color=yellow)
+![\[Zero Dependencies\]()](https://img.shields.io/badge/Dependencies-0-blue.svg)
+![\[Size\]()](https://img.shields.io/badge/Size-10%20KB-green.svg)
+![Maintained](https://img.shields.io/badge/Maintained%3F-yes-success)
+[![](https://data.jsdelivr.com/v1/package/npm/@tarekraafat/autocomplete.js/badge)](https://www.jsdelivr.com/package/npm/@tarekraafat/autocomplete.js)
+![npm](https://img.shields.io/npm/dm/@tarekraafat/autocomplete.js?label=npm)
+[![Open Source Love](https://badges.frapsoft.com/os/v1/open-source.svg?v=103)](https://github.com/TarekRaafat/autoComplete.js)
+
+<br>
+<br>
+<p align="center">
+	<a href="https://tarekraafat.github.io/autoComplete.js/">
+  		<img src="./docs/img/autoComplete.js.png" alt="autoComplete.js Design" width="50%">
+	</a>
+</p>
+<br>
+<br>
+
+> Simple autocomplete pure vanilla Javascript library. <a href="https://tarekraafat.github.io/autoComplete.js/demo/" target="\_blank">:rocket: Live Demo</a> **v8.3**
+
+autoComplete.js is a simple pure vanilla Javascript library that's progressively designed for speed, high versatility and seamless integration with a wide range of projects & systems, made for users and developers in mind.
+
+## Features
+
+-   Pure Vanilla Javascript
+-   Zero Dependencies
+-   Simple & Easy to use
+-   Extremely Lightweight
+-   Blazing Fast
+-   Versatile
+-   Hackable & highly customizable
+
+## [![autoComplete.js Code Example](./docs/img/autoComplete.init.png "autoComplete.js Code Example")](https://codepen.io/tarekraafat/pen/rQopdW?editors=0010)
+
+## Get Started
+
+### Clone:
+
+-   Clone autoComplete.js to your local machine
+
+```shell
+git clone https://github.com/TarekRaafat/autoComplete.js.git
+```
+
+### Installation:
+
+-   <a href="https://www.jsdelivr.com/package/gh/TarekRaafat/autoComplete.js"><img src="https://www.jsdelivr.com/img/logo@2x.png" alt="jsDelivr" width="100px"></a> CDN
+
+`CSS`
+
+```html
+<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@tarekraafat/autocomplete.js@8.3.2/dist/css/autoComplete.min.css">
+```
+
+`JS`
+
+```html
+<script src="https://cdn.jsdelivr.net/npm/@tarekraafat/autocomplete.js@8.3.2/dist/js/autoComplete.min.js"></script>
+```
+
+-   <a href="https://www.npmjs.com/package/@tarekraafat/autocomplete.js">npm</a> install `(Node Package Manager)`
+
+```shell
+npm i @tarekraafat/autocomplete
+```
+
+-   <a href="https://yarn.pm/@tarekraafat/autocomplete.js">Yarn</a> install `(Javascript Package Manager)`
+
+```shell
+yarn add @tarekraafat/autocomplete
+```
+
+<!-- * * * -->
+
+## Documentation:
+
+-   For more details check out **autoComplete.js** <a href="https://tarekraafat.github.io/autoComplete.js/">**docs** :notebook_with_decorative_cover:</a>
+
+<!-- * * * -->
+
+## Third-Party Plugins:
+
+-   [Contao autoComplete.js Bundle](https://github.com/heimrichhannot/contao-autocompletejs-bundle) by [@heimrichhannot](https://github.com/heimrichhannot)
+-   [Contentful Fontawesome autoComplete Field](https://github.com/ModiiMedia/contentful-fontawesome-autocomplete-field) by [@ModiiMedia](https://github.com/ModiiMedia)
+
+* * *
+
+## Support
+
+For general questions about autoComplete.js, tweet at [@TarekRaafat].
+
+For technical questions, you should post a question on [Stack Overflow] and tag
+it with [autoComplete.js][so tag].
+
+<!-- section links -->
+
+[stack overflow]: https://stackoverflow.com/
+
+[@tarekraafat]: https://twitter.com/TarekRaafat
+
+[so tag]: https://stackoverflow.com/questions/tagged/autoComplete.js
+
+* * *
+
+## Author
+
+**Tarek Raafat**
+
+-   Email: tarek.m.raafat@gmail.com
+-   Website: <http://www.tarekraafat.com/>
+-   Github: <https://github.com/TarekRaafat/>
+
+Distributed under the Apache 2.0 license. See `Apache 2.0` for more information.
+
+* * *
+
+## License
+
+Apache 2.0 © [Tarek Raafat](http://www.tarekraafat.com)
diff --git a/public/autocomplete/dist/css/autoComplete.css b/public/autocomplete/dist/css/autoComplete.css
new file mode 100644
index 0000000..6828992
--- /dev/null
+++ b/public/autocomplete/dist/css/autoComplete.css
@@ -0,0 +1,153 @@
+.autoComplete_wrapper {
+  position: relative;
+  display: inline-block;
+  width: 370px;
+}
+
+/*#autoComplete {
+  height: 3rem;
+  margin: 0;
+  padding: 0 2rem 0 3.2rem;
+  box-sizing: border-box;
+  -moz-box-sizing: border-box;
+  -webkit-box-sizing: border-box;
+  font-size: 1rem;
+  text-overflow: ellipsis;
+  color: rgba(11, 94, 215, 0.3);
+  outline: none;
+  border-radius: 10rem;
+  border: 0;
+  border: 0.05rem solid rgba(255, 122, 122, 0.5);
+  background-image: url(./images/search.svg);
+  background-size: 1.4rem;
+  background-position: left 1.05rem top 0.8rem;
+  background-repeat: no-repeat;
+  background-origin: border-box;
+  background-color: #fff;
+  transition: all 0.4s ease;
+  -webkit-transition: all -webkit-transform 0.4s ease;
+}*/
+
+#autoComplete::placeholder {
+  color: rgba(11, 94, 215, 0.5);
+  transition: all 0.3s ease;
+  -webkit-transition: all -webkit-transform 0.3s ease;
+}
+
+#autoComplete:hover::placeholder {
+  color: rgba(11, 94, 215, 0.6);
+  transition: all 0.3s ease;
+  -webkit-transition: all -webkit-transform 0.3s ease;
+}
+
+#autoComplete:focus::placeholder {
+  padding: 0.1rem 0.6rem;
+  font-size: 0.95rem;
+  color: rgba(11, 94, 215, 0.4);
+}
+
+#autoComplete:focus::selection {
+  background-color: rgba(11, 94, 215, 0.15);
+}
+
+#autoComplete::selection {
+  background-color: rgba(11, 94, 215, 0.15);
+}
+
+#autoComplete:hover {
+  color: rgba(11, 94, 215, 0.8);
+  transition: all 0.3s ease;
+  -webkit-transition: all -webkit-transform 0.3s ease;
+}
+
+#autoComplete:focus {
+  color: rgba(11, 94, 215, 1);
+  border: 0.06rem solid rgba(11, 94, 215, 0.8);
+}
+
+#autoComplete_list {
+  position: absolute;
+  top: 100%;
+  left: 0;
+  right: 0;
+  padding: 0;
+  margin-top: 0.5rem;
+  border-radius: 0.6rem;
+  background-color: #fff;
+  box-shadow: 0 3px 6px rgba(149, 157, 165, 0.15);
+  border: 1px solid rgba(33, 33, 33, 0.07);
+  z-index: 1000;
+  outline: none;
+}
+
+.autoComplete_result {
+  margin: 0.3rem;
+  padding: 0.3rem 0.5rem;
+  list-style: none;
+  text-align: left;
+  font-size: 1rem;
+  color: #212121;
+  transition: all 0.1s ease-in-out;
+  border-radius: 0.35rem;
+  background-color: rgba(255, 255, 255, 1);
+  white-space: nowrap;
+  overflow: hidden;
+  text-overflow: ellipsis;
+  transition: all 0.2s ease;
+}
+
+.autoComplete_result::selection {
+  color: rgba(#ffffff, 0);
+  background-color: rgba(#ffffff, 0);
+}
+
+.autoComplete_result:hover {
+  cursor: pointer;
+  background-color: rgba(11, 94, 215, 0.15);
+}
+
+.autoComplete_highlighted {
+  color: rgba(11, 94, 215, 1);
+  font-weight: bold;
+}
+
+.autoComplete_highlighted::selection {
+  color: rgba(#ffffff, 0);
+  background-color: rgba(#ffffff, 0);
+}
+
+.autoComplete_selected {
+  cursor: pointer;
+  background-color: rgba(11, 94, 215, 0.15);
+}
+
+@media only screen and (max-width: 600px) {
+  .autoComplete_wrapper {
+    width: 320px;
+  }
+
+  #autoComplete {
+    width: 18rem;
+    background-size: 1.6rem;
+    background-position: left 1.1rem top 0.75rem;
+  }
+
+  #autoComplete_list {
+    margin: 10px;
+  }
+}
+
+@media screen and (-webkit-min-device-pixel-ratio: 0) {
+  #autoComplete {
+    border-width: 1px;
+  }
+}
+
+@-moz-document url-prefix() {
+  #autoComplete {
+    background-size: 1.2rem;
+    background-origin: border-box;
+    border-width: 1px;
+    background-position: left 1.1rem top 0.8rem;
+  }
+}
diff --git a/public/autocomplete/dist/css/images/magnifier.svg b/public/autocomplete/dist/css/images/magnifier.svg
new file mode 100644
index 0000000..2a0ee79
--- /dev/null
+++ b/public/autocomplete/dist/css/images/magnifier.svg
@@ -0,0 +1,3 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="218" height="218">
+    <path d="M209.33 170.924l-54.375-54.394c5.082-10.625 8-22.48 8-35.045C162.966 36.482 126.48 0 81.48 0S0 36.482 0 81.48s36.48 81.48 81.48 81.48c12.573 0 24.42-2.936 35.056-8l54.383 54.375c10.598 10.61 27.804 10.61 38.408 0 10.61-10.612 10.61-27.815 0-38.405zM18.108 81.48c0-35.013 28.372-63.376 63.374-63.376s63.374 28.364 63.374 63.376c0 34.99-28.37 63.374-63.374 63.374s-63.374-28.38-63.374-63.374zm178.415 115.044a9.05 9.05 0 0 1-12.801 0l-51.415-51.42c4.722-3.8 9.015-8.084 12.803-12.806l51.412 51.426c1.7 1.697 2.654 4 2.654 6.4s-.955 4.704-2.654 6.4z" fill="#ff7a7a" fill-rule="nonzero"/>
+</svg>
\ No newline at end of file
diff --git a/public/autocomplete/dist/css/images/search.svg b/public/autocomplete/dist/css/images/search.svg
new file mode 100644
index 0000000..8063ea1
--- /dev/null
+++ b/public/autocomplete/dist/css/images/search.svg
@@ -0,0 +1,8 @@
+<svg xmlns="http://www.w3.org/2000/svg" focusable="false" x="0px" y="0px" width="30" height="30" viewBox="0 0 171 171" style=" fill:#000000;">
+    <g fill="none" fill-rule="nonzero" stroke="none" stroke-width="1" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="10" stroke-dasharray="" stroke-dashoffset="0" font-family="none" font-weight="none" font-size="none" text-anchor="none" style="mix-blend-mode: normal">
+        <path d="M0,171.99609v-171.99609h171.99609v171.99609z" fill="none"></path>
+        <g fill="#ff7a7a">
+            <path d="M74.1,17.1c-31.41272,0 -57,25.58728 -57,57c0,31.41272 25.58728,57 57,57c13.6601,0 26.20509,-4.85078 36.03692,-12.90293l34.03301,34.03301c1.42965,1.48907 3.55262,2.08891 5.55014,1.56818c1.99752,-0.52073 3.55746,-2.08067 4.07819,-4.07819c0.52073,-1.99752 -0.0791,-4.12049 -1.56818,-5.55014l-34.03301,-34.03301c8.05215,-9.83182 12.90293,-22.37682 12.90293,-36.03692c0,-31.41272 -25.58728,-57 -57,-57zM74.1,28.5c25.2517,0 45.6,20.3483 45.6,45.6c0,25.2517 -20.3483,45.6 -45.6,45.6c-25.2517,0 -45.6,-20.3483 -45.6,-45.6c0,-25.2517 20.3483,-45.6 45.6,-45.6z"></path>
+        </g>
+    </g>
+</svg>
\ No newline at end of file
diff --git a/public/autocomplete/dist/js/autoComplete.js b/public/autocomplete/dist/js/autoComplete.js
new file mode 100644
index 0000000..d1b57ec
--- /dev/null
+++ b/public/autocomplete/dist/js/autoComplete.js
@@ -0,0 +1,618 @@
+(function (global, factory) {
+  typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
+  typeof define === 'function' && define.amd ? define(factory) :
+  (global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.autoComplete = factory());
+}(this, (function () { 'use strict';
+
+  function _classCallCheck(instance, Constructor) {
+    if (!(instance instanceof Constructor)) {
+      throw new TypeError("Cannot call a class as a function");
+    }
+  }
+
+  function _defineProperties(target, props) {
+    for (var i = 0; i < props.length; i++) {
+      var descriptor = props[i];
+      descriptor.enumerable = descriptor.enumerable || false;
+      descriptor.configurable = true;
+      if ("value" in descriptor) descriptor.writable = true;
+      Object.defineProperty(target, descriptor.key, descriptor);
+    }
+  }
+
+  function _createClass(Constructor, protoProps, staticProps) {
+    if (protoProps) _defineProperties(Constructor.prototype, protoProps);
+    if (staticProps) _defineProperties(Constructor, staticProps);
+    return Constructor;
+  }
+
+  function _defineProperty(obj, key, value) {
+    if (key in obj) {
+      Object.defineProperty(obj, key, {
+        value: value,
+        enumerable: true,
+        configurable: true,
+        writable: true
+      });
+    } else {
+      obj[key] = value;
+    }
+
+    return obj;
+  }
+
+  function ownKeys(object, enumerableOnly) {
+    var keys = Object.keys(object);
+
+    if (Object.getOwnPropertySymbols) {
+      var symbols = Object.getOwnPropertySymbols(object);
+      if (enumerableOnly) symbols = symbols.filter(function (sym) {
+        return Object.getOwnPropertyDescriptor(object, sym).enumerable;
+      });
+      keys.push.apply(keys, symbols);
+    }
+
+    return keys;
+  }
+
+  function _objectSpread2(target) {
+    for (var i = 1; i < arguments.length; i++) {
+      var source = arguments[i] != null ? arguments[i] : {};
+
+      if (i % 2) {
+        ownKeys(Object(source), true).forEach(function (key) {
+          _defineProperty(target, key, source[key]);
+        });
+      } else if (Object.getOwnPropertyDescriptors) {
+        Object.defineProperties(target, Object.getOwnPropertyDescriptors(source));
+      } else {
+        ownKeys(Object(source)).forEach(function (key) {
+          Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key));
+        });
+      }
+    }
+
+    return target;
+  }
+
+  function _unsupportedIterableToArray(o, minLen) {
+    if (!o) return;
+    if (typeof o === "string") return _arrayLikeToArray(o, minLen);
+    var n = Object.prototype.toString.call(o).slice(8, -1);
+    if (n === "Object" && o.constructor) n = o.constructor.name;
+    if (n === "Map" || n === "Set") return Array.from(o);
+    if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen);
+  }
+
+  function _arrayLikeToArray(arr, len) {
+    if (len == null || len > arr.length) len = arr.length;
+
+    for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i];
+
+    return arr2;
+  }
+
+  function _createForOfIteratorHelper(o, allowArrayLike) {
+    var it;
+
+    if (typeof Symbol === "undefined" || o[Symbol.iterator] == null) {
+      if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") {
+        if (it) o = it;
+        var i = 0;
+
+        var F = function () {};
+
+        return {
+          s: F,
+          n: function () {
+            if (i >= o.length) return {
+              done: true
+            };
+            return {
+              done: false,
+              value: o[i++]
+            };
+          },
+          e: function (e) {
+            throw e;
+          },
+          f: F
+        };
+      }
+
+      throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
+    }
+
+    var normalCompletion = true,
+        didErr = false,
+        err;
+    return {
+      s: function () {
+        it = o[Symbol.iterator]();
+      },
+      n: function () {
+        var step = it.next();
+        normalCompletion = step.done;
+        return step;
+      },
+      e: function (e) {
+        didErr = true;
+        err = e;
+      },
+      f: function () {
+        try {
+          if (!normalCompletion && it.return != null) it.return();
+        } finally {
+          if (didErr) throw err;
+        }
+      }
+    };
+  }
+
+  var inputComponent = (function (config) {
+    config.inputField.setAttribute("type", "text");
+    config.inputField.setAttribute("role", "combobox");
+    config.inputField.setAttribute("aria-haspopup", true);
+    config.inputField.setAttribute("aria-expanded", false);
+    config.inputField.setAttribute("aria-controls", config.resultsList.idName);
+    config.inputField.setAttribute("aria-autocomplete", "both");
+  });
+
+  var createList = (function (config) {
+    var list = document.createElement(config.resultsList.element);
+    list.setAttribute("id", config.resultsList.idName);
+    list.setAttribute("aria-label", config.name);
+    list.setAttribute("class", config.resultsList.className);
+    list.setAttribute("role", "listbox");
+    list.setAttribute("tabindex", "-1");
+    if (config.resultsList.container) config.resultsList.container(list);
+    var destination = "string" === typeof config.resultsList.destination ? document.querySelector(config.resultsList.destination) : config.resultsList.destination();
+    destination.insertAdjacentElement(config.resultsList.position, list);
+    return list;
+  });
+
+  var createItem = (function (item, index, config) {
+    var result = document.createElement(config.resultItem.element);
+    result.setAttribute("id", "".concat(config.resultItem.idName, "_").concat(index));
+    result.setAttribute("class", config.resultItem.className);
+    result.setAttribute("role", "option");
+    result.innerHTML = item.match;
+    if (config.resultItem.content) config.resultItem.content(item, result);
+    return result;
+  });
+
+  var closeAllLists = function closeAllLists(config, element) {
+    var list = document.getElementsByClassName(config.resultsList.className);
+    for (var index = 0; index < list.length; index++) {
+      if (element !== list[index] && element !== config.inputField) list[index].parentNode.removeChild(list[index]);
+    }
+    config.inputField.removeAttribute("aria-activedescendant");
+    config.inputField.setAttribute("aria-expanded", false);
+  };
+  var generateList = function generateList(config, data, matches) {
+    var list = createList(config);
+    config.inputField.setAttribute("aria-expanded", true);
+    var _loop = function _loop(index) {
+      var item = data.results[index];
+      var resultItem = createItem(item, index, config);
+      resultItem.addEventListener("click", function (event) {
+        var dataFeedback = {
+          event: event,
+          matches: matches,
+          input: data.input,
+          query: data.query,
+          results: data.results,
+          selection: _objectSpread2(_objectSpread2({}, item), {}, {
+            index: index
+          })
+        };
+        if (config.onSelection) config.onSelection(dataFeedback);
+      });
+      list.appendChild(resultItem);
+    };
+    for (var index = 0; index < data.results.length; index++) {
+      _loop(index);
+    }
+    return list;
+  };
+
+  var eventEmitter = (function (target, detail, name) {
+    target.dispatchEvent(new CustomEvent(name, {
+      bubbles: true,
+      detail: detail,
+      cancelable: true
+    }));
+  });
+
+  var navigate = function navigate(config, dataFeedback) {
+    var currentFocus = -1;
+    var update = function update(event, list, state, config) {
+      event.preventDefault();
+      if (state) {
+        currentFocus++;
+      } else {
+        currentFocus--;
+      }
+      addActive(list);
+      config.inputField.setAttribute("aria-activedescendant", list[currentFocus].id);
+      eventEmitter(event.srcElement, _objectSpread2(_objectSpread2({
+        event: event
+      }, dataFeedback), {}, {
+        selection: dataFeedback.results[currentFocus]
+      }), "navigation");
+    };
+    var removeActive = function removeActive(list) {
+      for (var index = 0; index < list.length; index++) {
+        list[index].removeAttribute("aria-selected");
+        list[index].classList.remove("autoComplete_selected");
+      }
+    };
+    var addActive = function addActive(list) {
+      if (!list) return false;
+      removeActive(list);
+      if (currentFocus >= list.length) currentFocus = 0;
+      if (currentFocus < 0) currentFocus = list.length - 1;
+      list[currentFocus].setAttribute("aria-selected", "true");
+      list[currentFocus].classList.add("autoComplete_selected");
+    };
+    var navigation = function navigation(event) {
+      var list = document.getElementById(config.resultsList.idName);
+      if (!list) return config.inputField.removeEventListener("keydown", navigate);
+      list = list.getElementsByTagName(config.resultItem.element);
+      if (event.keyCode === 27) {
+        config.inputField.value = "";
+        closeAllLists(config);
+      } else if (event.keyCode === 40 || event.keyCode === 9) {
+        update(event, list, true, config);
+      } else if (event.keyCode === 38 || event.keyCode === 9) {
+        update(event, list, false, config);
+      } else if (event.keyCode === 13) {
+        event.preventDefault();
+        if (currentFocus > -1) {
+          if (list) list[currentFocus].click();
+        }
+      }
+    };
+    var navigate = config.resultsList.navigation || navigation;
+    if (config.inputField.autoCompleteNavigate) config.inputField.removeEventListener("keydown", config.inputField.autoCompleteNavigate);
+    config.inputField.autoCompleteNavigate = navigate;
+    config.inputField.addEventListener("keydown", navigate);
+  };
+
+  var searchEngine = (function (query, record, config) {
+    var recordLowerCase = config.diacritics ? record.toLowerCase().normalize("NFD").replace(/[\u0300-\u036f]/g, "").normalize("NFC") : record.toLowerCase();
+    if (config.searchEngine === "loose") {
+      query = query.replace(/ /g, "");
+      var match = [];
+      var searchPosition = 0;
+      for (var number = 0; number < recordLowerCase.length; number++) {
+        var recordChar = record[number];
+        if (searchPosition < query.length && recordLowerCase[number] === query[searchPosition]) {
+          recordChar = config.highlight ? "<span class=\"autoComplete_highlighted\">".concat(recordChar, "</span>") : recordChar;
+          searchPosition++;
+        }
+        match.push(recordChar);
+      }
+      if (searchPosition === query.length) {
+        return match.join("");
+      }
+    } else {
+      if (recordLowerCase.includes(query)) {
+        var pattern = new RegExp("".concat(query), "i");
+        query = pattern.exec(record);
+        var _match = config.highlight ? record.replace(query, "<span class=\"autoComplete_highlighted\">".concat(query, "</span>")) : record;
+        return _match;
+      }
+    }
+  });
+
+  var getInputValue = function getInputValue(inputField) {
+    return inputField instanceof HTMLInputElement || inputField instanceof HTMLTextAreaElement ? inputField.value.toLowerCase() : inputField.innerHTML.toLowerCase();
+  };
+  var prepareQueryValue = function prepareQueryValue(inputValue, config) {
+    return config.query && config.query.manipulate ? config.query.manipulate(inputValue) : config.diacritics ? inputValue.normalize("NFD").replace(/[\u0300-\u036f]/g, "").normalize("NFC") : inputValue;
+  };
+  var checkTriggerCondition = function checkTriggerCondition(config, queryValue) {
+    return config.trigger.condition ? config.trigger.condition(queryValue) : queryValue.length >= config.threshold && queryValue.replace(/ /g, "").length;
+  };
+  var listMatchingResults = function listMatchingResults(config, query) {
+    var resList = [];
+    var _loop = function _loop(index) {
+      var record = config.data.store[index];
+      var search = function search(key) {
+        var recordValue = (key ? record[key] : record).toString();
+        if (recordValue) {
+          var match = typeof config.searchEngine === "function" ? config.searchEngine(query, recordValue) : searchEngine(query, recordValue, config);
+          if (match && key) {
+            resList.push({
+              key: key,
+              index: index,
+              match: match,
+              value: record
+            });
+          } else if (match && !key) {
+            resList.push({
+              index: index,
+              match: match,
+              value: record
+            });
+          }
+        }
+      };
+      if (config.data.key) {
+        var _iterator = _createForOfIteratorHelper(config.data.key),
+            _step;
+        try {
+          for (_iterator.s(); !(_step = _iterator.n()).done;) {
+            var key = _step.value;
+            search(key);
+          }
+        } catch (err) {
+          _iterator.e(err);
+        } finally {
+          _iterator.f();
+        }
+      } else {
+        search();
+      }
+    };
+    for (var index = 0; index < config.data.store.length; index++) {
+      _loop(index);
+    }
+    var list = config.sort ? resList.sort(config.sort) : resList;
+    return list;
+  };
+
+  var debouncer = (function (callback, delay) {
+    var inDebounce;
+    return function () {
+      var context = this;
+      var args = arguments;
+      clearTimeout(inDebounce);
+      inDebounce = setTimeout(function () {
+        return callback.apply(context, args);
+      }, delay);
+    };
+  });
+
+  var autoComplete = function () {
+    function autoComplete(config) {
+      _classCallCheck(this, autoComplete);
+      var _config$name = config.name,
+          name = _config$name === void 0 ? "Search" : _config$name,
+          _config$selector = config.selector,
+          selector = _config$selector === void 0 ? "#autoComplete" : _config$selector,
+          _config$observer = config.observer,
+          observer = _config$observer === void 0 ? false : _config$observer,
+          _config$data = config.data,
+          src = _config$data.src,
+          key = _config$data.key,
+          _config$data$cache = _config$data.cache,
+          cache = _config$data$cache === void 0 ? false : _config$data$cache,
+          store = _config$data.store,
+          results = _config$data.results,
+          query = config.query,
+          _config$trigger = config.trigger;
+      _config$trigger = _config$trigger === void 0 ? {} : _config$trigger;
+      var _config$trigger$event = _config$trigger.event,
+          event = _config$trigger$event === void 0 ? ["input"] : _config$trigger$event,
+          _config$trigger$condi = _config$trigger.condition,
+          condition = _config$trigger$condi === void 0 ? false : _config$trigger$condi,
+          _config$searchEngine = config.searchEngine,
+          searchEngine = _config$searchEngine === void 0 ? "strict" : _config$searchEngine,
+          _config$diacritics = config.diacritics,
+          diacritics = _config$diacritics === void 0 ? false : _config$diacritics,
+          _config$threshold = config.threshold,
+          threshold = _config$threshold === void 0 ? 1 : _config$threshold,
+          _config$debounce = config.debounce,
+          debounce = _config$debounce === void 0 ? 0 : _config$debounce,
+          _config$resultsList = config.resultsList;
+      _config$resultsList = _config$resultsList === void 0 ? {} : _config$resultsList;
+      var _config$resultsList$r = _config$resultsList.render,
+          render = _config$resultsList$r === void 0 ? true : _config$resultsList$r,
+          _config$resultsList$c = _config$resultsList.container,
+          container = _config$resultsList$c === void 0 ? false : _config$resultsList$c,
+          destination = _config$resultsList.destination,
+          _config$resultsList$p = _config$resultsList.position,
+          position = _config$resultsList$p === void 0 ? "afterend" : _config$resultsList$p,
+          _config$resultsList$e = _config$resultsList.element,
+          resultsListElement = _config$resultsList$e === void 0 ? "ul" : _config$resultsList$e,
+          _config$resultsList$i = _config$resultsList.idName,
+          resultsListId = _config$resultsList$i === void 0 ? "autoComplete_list" : _config$resultsList$i,
+          _config$resultsList$c2 = _config$resultsList.className,
+          resultsListClass = _config$resultsList$c2 === void 0 ? "autoComplete_list" : _config$resultsList$c2,
+          _config$resultsList$n = _config$resultsList.navigation,
+          navigation = _config$resultsList$n === void 0 ? false : _config$resultsList$n,
+          _config$sort = config.sort,
+          sort = _config$sort === void 0 ? false : _config$sort,
+          placeHolder = config.placeHolder,
+          _config$maxResults = config.maxResults,
+          maxResults = _config$maxResults === void 0 ? 5 : _config$maxResults,
+          _config$resultItem = config.resultItem;
+      _config$resultItem = _config$resultItem === void 0 ? {} : _config$resultItem;
+      var _config$resultItem$co = _config$resultItem.content,
+          content = _config$resultItem$co === void 0 ? false : _config$resultItem$co,
+          _config$resultItem$el = _config$resultItem.element,
+          resultItemElement = _config$resultItem$el === void 0 ? "li" : _config$resultItem$el,
+          _config$resultItem$id = _config$resultItem.idName,
+          resultItemId = _config$resultItem$id === void 0 ? "autoComplete_result" : _config$resultItem$id,
+          _config$resultItem$cl = _config$resultItem.className,
+          resultItemClass = _config$resultItem$cl === void 0 ? "autoComplete_result" : _config$resultItem$cl,
+          noResults = config.noResults,
+          _config$highlight = config.highlight,
+          highlight = _config$highlight === void 0 ? false : _config$highlight,
+          feedback = config.feedback,
+          onSelection = config.onSelection;
+      this.name = name;
+      this.selector = selector;
+      this.observer = observer;
+      this.data = {
+        src: src,
+        key: key,
+        cache: cache,
+        store: store,
+        results: results
+      };
+      this.query = query;
+      this.trigger = {
+        event: event,
+        condition: condition
+      };
+      this.searchEngine = searchEngine;
+      this.diacritics = diacritics;
+      this.threshold = threshold;
+      this.debounce = debounce;
+      this.resultsList = {
+        render: render,
+        container: container,
+        destination: destination || this.selector,
+        position: position,
+        element: resultsListElement,
+        idName: resultsListId,
+        className: resultsListClass,
+        navigation: navigation
+      };
+      this.sort = sort;
+      this.placeHolder = placeHolder;
+      this.maxResults = maxResults;
+      this.resultItem = {
+        content: content,
+        element: resultItemElement,
+        idName: resultItemId,
+        className: resultItemClass
+      };
+      this.noResults = noResults;
+      this.highlight = highlight;
+      this.feedback = feedback;
+      this.onSelection = onSelection;
+      this.inputField = typeof this.selector === "string" ? document.querySelector(this.selector) : this.selector();
+      this.observer ? this.preInit() : this.init();
+    }
+    _createClass(autoComplete, [{
+      key: "start",
+      value: function start(input, query) {
+        var _this = this;
+        var results = this.data.results ? this.data.results(listMatchingResults(this, query)) : listMatchingResults(this, query);
+        var dataFeedback = {
+          input: input,
+          query: query,
+          matches: results,
+          results: results.slice(0, this.maxResults)
+        };
+        eventEmitter(this.inputField, dataFeedback, "results");
+        if (!results.length) return this.noResults ? this.noResults(dataFeedback, generateList) : null;
+        if (!this.resultsList.render) return this.feedback(dataFeedback);
+        results.length ? generateList(this, dataFeedback, results) : null;
+        eventEmitter(this.inputField, dataFeedback, "rendered");
+        navigate(this, dataFeedback);
+        document.addEventListener("click", function (event) {
+          return closeAllLists(_this, event.target);
+        });
+      }
+    }, {
+      key: "dataStore",
+      value: function dataStore() {
+        var _this2 = this;
+        return new Promise(function ($return, $error) {
+          if (_this2.data.cache && _this2.data.store) return $return(null);
+          return new Promise(function ($return, $error) {
+            if (typeof _this2.data.src === "function") {
+              return _this2.data.src().then($return, $error);
+            }
+            return $return(_this2.data.src);
+          }).then(function ($await_5) {
+            try {
+              _this2.data.store = $await_5;
+              eventEmitter(_this2.inputField, _this2.data.store, "fetch");
+              return $return();
+            } catch ($boundEx) {
+              return $error($boundEx);
+            }
+          }, $error);
+        });
+      }
+    }, {
+      key: "compose",
+      value: function compose() {
+        var _this3 = this;
+        return new Promise(function ($return, $error) {
+          var input, query, triggerCondition;
+          input = getInputValue(_this3.inputField);
+          query = prepareQueryValue(input, _this3);
+          triggerCondition = checkTriggerCondition(_this3, query);
+          if (triggerCondition) {
+            return _this3.dataStore().then(function ($await_6) {
+              try {
+                closeAllLists(_this3);
+                _this3.start(input, query);
+                return $If_3.call(_this3);
+              } catch ($boundEx) {
+                return $error($boundEx);
+              }
+            }, $error);
+          } else {
+            closeAllLists(_this3);
+            return $If_3.call(_this3);
+          }
+          function $If_3() {
+            return $return();
+          }
+        });
+      }
+    }, {
+      key: "init",
+      value: function init() {
+        var _this4 = this;
+        inputComponent(this);
+        if (this.placeHolder) this.inputField.setAttribute("placeholder", this.placeHolder);
+        this.hook = debouncer(function () {
+          _this4.compose();
+        }, this.debounce);
+        this.trigger.event.forEach(function (eventType) {
+          _this4.inputField.removeEventListener(eventType, _this4.hook);
+          _this4.inputField.addEventListener(eventType, _this4.hook);
+        });
+        eventEmitter(this.inputField, null, "init");
+      }
+    }, {
+      key: "preInit",
+      value: function preInit() {
+        var _this5 = this;
+        var config = {
+          childList: true,
+          subtree: true
+        };
+        var callback = function callback(mutationsList, observer) {
+          var _iterator = _createForOfIteratorHelper(mutationsList),
+              _step;
+          try {
+            for (_iterator.s(); !(_step = _iterator.n()).done;) {
+              var mutation = _step.value;
+              if (_this5.inputField) {
+                observer.disconnect();
+                eventEmitter(_this5.inputField, null, "connect");
+                _this5.init();
+              }
+            }
+          } catch (err) {
+            _iterator.e(err);
+          } finally {
+            _iterator.f();
+          }
+        };
+        var observer = new MutationObserver(callback);
+        observer.observe(document, config);
+      }
+    }, {
+      key: "unInit",
+      value: function unInit() {
+        this.inputField.removeEventListener("input", this.hook);
+        eventEmitter(this.inputField, null, "unInit");
+      }
+    }]);
+    return autoComplete;
+  }();
+
+  return autoComplete;
+
+})));
diff --git a/public/autocomplete/dist/js/autoComplete.min.js b/public/autocomplete/dist/js/autoComplete.min.js
new file mode 100644
index 0000000..9694263
--- /dev/null
+++ b/public/autocomplete/dist/js/autoComplete.min.js
@@ -0,0 +1 @@
+var a,b;a=this,b=function(){"use strict";function e(e,t){for(var n=0;n<t.length;n++){var i=t[n];i.enumerable=i.enumerable||!1,i.configurable=!0,"value"in i&&(i.writable=!0),Object.defineProperty(e,i.key,i)}}function t(t,e){var n,i=Object.keys(t);return Object.getOwnPropertySymbols&&(n=Object.getOwnPropertySymbols(t),e&&(n=n.filter(function(e){return Object.getOwnPropertyDescriptor(t,e).enumerable})),i.push.apply(i,n)),i}function c(i){for(var e=1;e<arguments.length;e++){var r=null!=arguments[e]?arguments[e]:{};e%2?t(Object(r),!0).forEach(function(e){var t,n;t=i,e=r[n=e],n in t?Object.defineProperty(t,n,{value:e,enumerable:!0,configurable:!0,writable:!0}):t[n]=e}):Object.getOwnPropertyDescriptors?Object.defineProperties(i,Object.getOwnPropertyDescriptors(r)):t(Object(r)).forEach(function(e){Object.defineProperty(i,e,Object.getOwnPropertyDescriptor(r,e))})}return i}function a(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,i=new Array(t);n<t;n++)i[n]=e[n];return i}function l(e,t){var n;if("undefined"==typeof Symbol||null==e[Symbol.iterator]){if(Array.isArray(e)||(n=function(e,t){if(e){if("string"==typeof e)return a(e,t);var n=Object.prototype.toString.call(e).slice(8,-1);return"Map"===(n="Object"===n&&e.constructor?e.constructor.name:n)||"Set"===n?Array.from(e):"Arguments"===n||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)?a(e,t):void 0}}(e))||t&&e&&"number"==typeof e.length){n&&(e=n);var i=0,t=function(){};return{s:t,n:function(){return i>=e.length?{done:!0}:{done:!1,value:e[i++]}},e:function(e){throw e},f:t}}throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}var r,o=!0,s=!1;return{s:function(){n=e[Symbol.iterator]()},n:function(){var e=n.next();return o=e.done,e},e:function(e){s=!0,r=e},f:function(){try{o||null==n.return||n.return()}finally{if(s)throw r}}}}function u(e,t){for(var n=document.getElementsByClassName(e.resultsList.className),i=0;i<n.length;i++)t!==n[i]&&t!==e.inputField&&n[i].parentNode.removeChild(n[i]);e.inputField.removeAttribute("aria-activedescendant"),e.inputField.setAttribute("aria-expanded",!1)}function r(s,a,l){var e,t,u=(e=s,(t=document.createElement(e.resultsList.element)).setAttribute("id",e.resultsList.idName),t.setAttribute("aria-label",e.name),t.setAttribute("class",e.resultsList.className),t.setAttribute("role","listbox"),t.setAttribute("tabindex","-1"),e.resultsList.container&&e.resultsList.container(t),("string"==typeof e.resultsList.destination?document.querySelector(e.resultsList.destination):e.resultsList.destination()).insertAdjacentElement(e.resultsList.position,t),t);s.inputField.setAttribute("aria-expanded",!0);for(var n=function(t){var e,n,i,r,o=a.results[t],r=(e=o,n=t,i=s,(r=document.createElement(i.resultItem.element)).setAttribute("id","".concat(i.resultItem.idName,"_").concat(n)),r.setAttribute("class",i.resultItem.className),r.setAttribute("role","option"),r.innerHTML=e.match,i.resultItem.content&&i.resultItem.content(e,r),r);r.addEventListener("click",function(e){e={event:e,matches:l,input:a.input,query:a.query,results:a.results,selection:c(c({},o),{},{index:t})};s.onSelection&&s.onSelection(e)}),u.appendChild(r)},i=0;i<a.results.length;i++)n(i);return u}function d(e,t,n){e.dispatchEvent(new CustomEvent(n,{bubbles:!0,detail:t,cancelable:!0}))}function o(n,r){function i(e,t,n,i){e.preventDefault(),n?o++:o--,s(t),i.inputField.setAttribute("aria-activedescendant",t[o].id),d(e.srcElement,c(c({event:e},r),{},{selection:r.results[o]}),"navigation")}var o=-1,s=function(e){if(!e)return!1;!function(e){for(var t=0;t<e.length;t++)e[t].removeAttribute("aria-selected"),e[t].classList.remove("autoComplete_selected")}(e),e[o=(o=o>=e.length?0:o)<0?e.length-1:o].setAttribute("aria-selected","true"),e[o].classList.add("autoComplete_selected")},a=n.resultsList.navigation||function(e){var t=document.getElementById(n.resultsList.idName);if(!t)return n.inputField.removeEventListener("keydown",a);t=t.getElementsByTagName(n.resultItem.element),27===e.keyCode?(n.inputField.value="",u(n)):40===e.keyCode||9===e.keyCode?i(e,t,!0,n):38===e.keyCode||9===e.keyCode?i(e,t,!1,n):13===e.keyCode&&(e.preventDefault(),-1<o&&t&&t[o].click())};n.inputField.autoCompleteNavigate&&n.inputField.removeEventListener("keydown",n.inputField.autoCompleteNavigate),n.inputField.autoCompleteNavigate=a,n.inputField.addEventListener("keydown",a)}function s(o,s){for(var a=[],e=function(n){function e(e){var t=(e?i[e]:i).toString();t&&((t="function"==typeof o.searchEngine?o.searchEngine(s,t):function(e,t,n){var i=n.diacritics?t.toLowerCase().normalize("NFD").replace(/[\u0300-\u036f]/g,"").normalize("NFC"):t.toLowerCase();if("loose"===n.searchEngine){e=e.replace(/ /g,"");for(var r=[],o=0,s=0;s<i.length;s++){var a=t[s];o<e.length&&i[s]===e[o]&&(a=n.highlight?'<span class="autoComplete_highlighted">'.concat(a,"</span>"):a,o++),r.push(a)}if(o===e.length)return r.join("")}else if(i.includes(e))return e=new RegExp("".concat(e),"i").exec(t),n.highlight?t.replace(e,'<span class="autoComplete_highlighted">'.concat(e,"</span>")):t}(s,t,o))&&e?a.push({key:e,index:n,match:t,value:i}):t&&!e&&a.push({index:n,match:t,value:i}))}var i=o.data.store[n];if(o.data.key){var t,r=l(o.data.key);try{for(r.s();!(t=r.n()).done;)e(t.value)}catch(e){r.e(e)}finally{r.f()}}else e()},t=0;t<o.data.store.length;t++)e(t);return o.sort?a.sort(o.sort):a}var n,i,h;function T(e){!function(e){if(!(e instanceof T))throw new TypeError("Cannot call a class as a function")}(this);var t=e.name,n=void 0===t?"Search":t,i=e.selector,r=void 0===i?"#autoComplete":i,o=e.observer,s=void 0!==o&&o,a=e.data,l=a.src,u=a.key,c=a.cache,d=void 0!==c&&c,h=a.store,p=a.results,f=e.query,v=e.trigger,m=(v=void 0===v?{}:v).event,b=void 0===m?["input"]:m,y=v.condition,g=void 0!==y&&y,F=e.searchEngine,L=void 0===F?"strict":F,k=e.diacritics,C=void 0!==k&&k,E=e.threshold,A=void 0===E?1:E,w=e.debounce,N=void 0===w?0:w,O=e.resultsList,j=(O=void 0===O?{}:O).render,x=void 0===j||j,S=O.container,I=void 0!==S&&S,P=O.destination,t=O.position,i=void 0===t?"afterend":t,o=O.element,c=void 0===o?"ul":o,a=O.idName,m=void 0===a?"autoComplete_list":a,v=O.className,y=void 0===v?"autoComplete_list":v,F=O.navigation,k=void 0!==F&&F,E=e.sort,w=void 0!==E&&E,j=e.placeHolder,S=e.maxResults,t=void 0===S?5:S,o=e.resultItem,a=(o=void 0===o?{}:o).content,v=void 0!==a&&a,O=o.element,F=void 0===O?"li":O,E=o.idName,S=void 0===E?"autoComplete_result":E,a=o.className,O=void 0===a?"autoComplete_result":a,E=e.noResults,o=e.highlight,a=void 0!==o&&o,o=e.feedback,e=e.onSelection;this.name=n,this.selector=r,this.observer=s,this.data={src:l,key:u,cache:d,store:h,results:p},this.query=f,this.trigger={event:b,condition:g},this.searchEngine=L,this.diacritics=C,this.threshold=A,this.debounce=N,this.resultsList={render:x,container:I,destination:P||this.selector,position:i,element:c,idName:m,className:y,navigation:k},this.sort=w,this.placeHolder=j,this.maxResults=t,this.resultItem={content:v,element:F,idName:S,className:O},this.noResults=E,this.highlight=a,this.feedback=o,this.onSelection=e,this.inputField="string"==typeof this.selector?document.querySelector(this.selector):this.selector(),this.observer?this.preInit():this.init()}return n=T,(i=[{key:"start",value:function(e,t){var n=this,i=this.data.results?this.data.results(s(this,t)):s(this,t),t={input:e,query:t,matches:i,results:i.slice(0,this.maxResults)};return d(this.inputField,t,"results"),i.length?this.resultsList.render?(i.length&&r(this,t,i),d(this.inputField,t,"rendered"),o(this,t),void document.addEventListener("click",function(e){return u(n,e.target)})):this.feedback(t):this.noResults?this.noResults(t,r):null}},{key:"dataStore",value:function(){var i=this;return new Promise(function(t,n){return i.data.cache&&i.data.store?t(null):new Promise(function(e,t){return"function"==typeof i.data.src?i.data.src().then(e,t):e(i.data.src)}).then(function(e){try{return i.data.store=e,d(i.inputField,i.data.store,"fetch"),t()}catch(e){return n(e)}},n)})}},{key:"compose",value:function(){var a=this;return new Promise(function(e,t){var n,i,r,o;return o=a.inputField,n=(o instanceof HTMLInputElement||o instanceof HTMLTextAreaElement?o.value:o.innerHTML).toLowerCase(),r=n,i=(o=a).query&&o.query.manipulate?o.query.manipulate(r):o.diacritics?r.normalize("NFD").replace(/[\u0300-\u036f]/g,"").normalize("NFC"):r,o=i,((r=a).trigger.condition?r.trigger.condition(o):o.length>=r.threshold&&o.replace(/ /g,"").length)?a.dataStore().then(function(e){try{return u(a),a.start(n,i),s.call(a)}catch(e){return t(e)}},t):(u(a),s.call(a));function s(){return e()}})}},{key:"init",value:function(){var e,n,i,r,t=this;(e=this).inputField.setAttribute("type","text"),e.inputField.setAttribute("role","combobox"),e.inputField.setAttribute("aria-haspopup",!0),e.inputField.setAttribute("aria-expanded",!1),e.inputField.setAttribute("aria-controls",e.resultsList.idName),e.inputField.setAttribute("aria-autocomplete","both"),this.placeHolder&&this.inputField.setAttribute("placeholder",this.placeHolder),this.hook=(n=function(){t.compose()},i=this.debounce,function(){var e=this,t=arguments;clearTimeout(r),r=setTimeout(function(){return n.apply(e,t)},i)}),this.trigger.event.forEach(function(e){t.inputField.removeEventListener(e,t.hook),t.inputField.addEventListener(e,t.hook)}),d(this.inputField,null,"init")}},{key:"preInit",value:function(){var r=this;new MutationObserver(function(e,t){var n,i=l(e);try{for(i.s();!(n=i.n()).done;){n.value;r.inputField&&(t.disconnect(),d(r.inputField,null,"connect"),r.init())}}catch(e){i.e(e)}finally{i.f()}}).observe(document,{childList:!0,subtree:!0})}},{key:"unInit",value:function(){this.inputField.removeEventListener("input",this.hook),d(this.inputField,null,"unInit")}}])&&e(n.prototype,i),h&&e(n,h),T},"object"==typeof exports&&"undefined"!=typeof module?module.exports=b():"function"==typeof define&&define.amd?define(b):(a="undefined"!=typeof globalThis?globalThis:a||self).autoComplete=b();
diff --git a/public/autocomplete/dist/js/index.js b/public/autocomplete/dist/js/index.js
new file mode 100644
index 0000000..23ef04f
--- /dev/null
+++ b/public/autocomplete/dist/js/index.js
@@ -0,0 +1,67 @@
+new autoComplete({
+    data: {                              // Data src [Array, Function, Async] | (REQUIRED)
+        src: async () => {
+            // API key token
+            // const token = "this_is_the_API_token_number";
+            // User search query
+            const query = document.querySelector("#autoComplete").value;
+            // Fetch External Data Source
+            const source = await fetch(`http://localhost/api/pokemon.json?nom=${query}`);
+            // Format data into JSON
+            const data = await source.json();
+            // Return Fetched data
+            return data;
+        },
+        key: ["nom"],
+        cache: false
+    },
+    query: {                             // Query Interceptor               | (Optional)
+        manipulate: (query) => {
+            return query.replace("Pikachu", "Charmander");
+        }
+    },
+    sort: (a, b) => {                    // Sort rendered results ascendingly | (Optional)
+        if (a.match < b.match) return -1;
+        if (a.match > b.match) return 1;
+        return 0;
+    },
+    placeHolder: "Saisir un nom de pokemon, type, generation...",     // Place Holder text                 | (Optional)
+    selector: "#autoComplete",           // Input field selector              | (Optional)
+    observer: true,                      // Input field observer | (Optional)
+    threshold: 3,                        // Min. Chars length to start Engine | (Optional)
+    debounce: 300,                       // Post duration for engine to start | (Optional)
+    searchEngine: "strict",              // Search Engine type/mode           | (Optional)
+    resultsList: {                       // Rendered results list object      | (Optional)
+        container: source => {
+            source.setAttribute("id", "pokemon_list");
+        },
+        destination: "#autoComplete",
+        position: "afterend",
+        element: "ul"
+    },
+    maxResults: 5,                         // Max. number of rendered results | (Optional)
+    highlight: {
+        render: true,                    // Highlight matching results        | (Optional)
+    },
+    resultItem: {                          // Rendered result item            | (Optional)
+        content: (data, source) => {
+            source.innerHTML = data.match;
+        },
+        element: "li"
+    },
+    noResults: (dataFeedback, generateList) => {
+        // Generate autoComplete List
+        generateList(autoCompleteJS, dataFeedback, dataFeedback.results);
+        // No Results List Item
+        const result = document.createElement("li");
+        result.setAttribute("class", "no_result");
+        result.setAttribute("tabindex", "1");
+        result.innerHTML = `<span style="display: flex; align-items: center; font-weight: 100; color: rgba(0,0,0,.2);">Found No Results for "${dataFeedback.query}"</span>`;
+        document.querySelector(`#${autoCompleteJS.resultsList.idName}`).appendChild(result);
+    },
+    onSelection: feedback => {             // Action script onSelection event | (Optional)
+        const resultNameFromAutocomplete = feedback.matches[0].value.nom
+        document.getElementById("autoComplete").value = resultNameFromAutocomplete
+        window.location = "/pokemon?keyword=" + resultNameFromAutocomplete
+    }
+});
\ No newline at end of file
diff --git a/public/js/customButton.js b/public/js/customButton.js
index 8a85ad9..2096621 100644
--- a/public/js/customButton.js
+++ b/public/js/customButton.js
@@ -3,3 +3,4 @@
     event.preventDefault()
     window.location = "/pokemon"
 })
+
diff --git a/templates/pokemon/index.html.twig b/templates/pokemon/index.html.twig
index 87f461d..da21269 100644
--- a/templates/pokemon/index.html.twig
+++ b/templates/pokemon/index.html.twig
@@ -5,6 +5,7 @@
 {% block stylesheets %}
 
     <link rel="stylesheet" href="{{ asset('css/bootstrap.min.css') }}">
+    <link rel="stylesheet" href="{{ asset('autocomplete/dist/css/autoComplete.css') }}">
 
     <style>
         .col-actions {
@@ -19,11 +20,11 @@
     <form action="/pokemon" method="get">
         <div class="row">
             <div class="col-md-7">
-                <input type="text" class="form-control" name="keyword" placeholder="Saisir un nom de pokemon, type, generation...">
+                <input id="autoComplete" tabindex="1" type="text" class="form-control" name="keyword" placeholder="Saisir un nom de pokemon, type, generation...">
             </div>
             <div class="col-auto">
                 <button class="btn btn-primary">Rechercher <i class="fas fa-search"></i></button>
-                <a href={{ path('pokemon_index') }}><button type="button" id="refreshPokemonListBtn" class="btn btn-secondary">Annuler recherche <i class="far fa-times-circle"></i></button></a>
+                <a href={{ path('pokemon_index') }}><button type="button" id="refreshPokemonListBtn" class="btn btn-secondary">Annuler filtre <i class="far fa-times-circle"></i></button></a>
             </div>
 
             <div class="col-auto">
@@ -79,5 +80,7 @@
 
 
     <script src={{ asset('js/customButton.js') }}></script>
+    <script src={{ asset('autocomplete/dist/js/autoComplete.js') }}></script>
+    <script type="module" src={{ asset('autocomplete/dist/js/index.js') }}></script>
 
 {% endblock %}