├── application
├── views
│ ├── account
│ │ ├── edit.php
│ │ ├── confirm.php
│ │ ├── reset.php
│ │ ├── recovery.php
│ │ ├── login.php
│ │ ├── profile.php
│ │ └── register.php
│ ├── errors
│ │ ├── 403.php
│ │ └── 404.php
│ ├── admin
│ │ ├── login.php
│ │ ├── history.php
│ │ ├── tariffs.php
│ │ └── withdraw.php
│ ├── dashboard
│ │ ├── history.php
│ │ ├── tariffs.php
│ │ ├── referrals.php
│ │ └── invest.php
│ ├── main
│ │ └── index.php
│ └── layouts
│ │ ├── default.php
│ │ └── admin.php
├── config
│ ├── admin.php
│ ├── db.php
│ ├── tariffs.php
│ └── routes.php
├── models
│ ├── Main.php
│ ├── Merchant.php
│ ├── Dashboard.php
│ ├── Admin.php
│ └── Account.php
├── acl
│ ├── main.php
│ ├── merchant.php
│ ├── admin.php
│ ├── dashboard.php
│ └── account.php
├── lib
│ ├── Dev.php
│ ├── Db.php
│ └── Pagination.php
├── core
│ ├── Model.php
│ ├── View.php
│ ├── Controller.php
│ └── Router.php
└── controllers
│ ├── MainController.php
│ ├── MerchantController.php
│ ├── DashboardController.php
│ ├── AdminController.php
│ └── AccountController.php
├── README.md
├── public
├── fonts
│ └── RobotoCondensed.ttf
├── styles
│ ├── main.css
│ └── admin.css
└── scripts
│ ├── form.js
│ ├── popper.js
│ └── bootstrap.js
├── .htaccess
├── index.php
└── db.sql
/application/views/account/edit.php:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/application/views/errors/403.php:
--------------------------------------------------------------------------------
1 | Страница 403
--------------------------------------------------------------------------------
/application/views/errors/404.php:
--------------------------------------------------------------------------------
1 | Страница 404
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # php-invest
2 | Simple PHP OOP invest project (HYIP) based on mvc
3 |
--------------------------------------------------------------------------------
/application/config/admin.php:
--------------------------------------------------------------------------------
1 | 'admin',
5 | 'password' => '12345',
6 | ];
--------------------------------------------------------------------------------
/public/fonts/RobotoCondensed.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/php-youtube/php-invest/HEAD/public/fonts/RobotoCondensed.ttf
--------------------------------------------------------------------------------
/application/config/db.php:
--------------------------------------------------------------------------------
1 | '',
5 | 'name' => '',
6 | 'user' => '',
7 | 'password' => '',
8 | ];
--------------------------------------------------------------------------------
/application/models/Main.php:
--------------------------------------------------------------------------------
1 | [
5 | 'index',
6 | ],
7 | 'authorize' => [
8 | //
9 | ],
10 | 'guest' => [
11 | //
12 | ],
13 | 'admin' => [
14 | //
15 | ],
16 | ];
--------------------------------------------------------------------------------
/application/lib/Dev.php:
--------------------------------------------------------------------------------
1 | ';
8 | var_dump($str);
9 | echo '';
10 | exit;
11 | }
--------------------------------------------------------------------------------
/application/acl/merchant.php:
--------------------------------------------------------------------------------
1 | [
5 | 'perfectmoney',
6 | ],
7 | 'authorize' => [
8 | //
9 | ],
10 | 'guest' => [
11 | //
12 | ],
13 | 'admin' => [
14 | //
15 | ],
16 | ];
--------------------------------------------------------------------------------
/application/core/Model.php:
--------------------------------------------------------------------------------
1 | db = new Db;
13 | }
14 |
15 | }
--------------------------------------------------------------------------------
/application/acl/admin.php:
--------------------------------------------------------------------------------
1 | [
5 | 'login',
6 | ],
7 | 'authorize' => [
8 | //
9 | ],
10 | 'guest' => [
11 | //
12 | ],
13 | 'admin' => [
14 | 'withdraw',
15 | 'tariffs',
16 | 'history',
17 | 'logout',
18 | ],
19 | ];
--------------------------------------------------------------------------------
/application/acl/dashboard.php:
--------------------------------------------------------------------------------
1 | [
5 | //
6 | ],
7 | 'authorize' => [
8 | 'tariffs',
9 | 'invest',
10 | 'history',
11 | 'referrals',
12 | ],
13 | 'guest' => [
14 | //
15 | ],
16 | 'admin' => [
17 | //
18 | ],
19 | ];
--------------------------------------------------------------------------------
/application/acl/account.php:
--------------------------------------------------------------------------------
1 | [
5 | //
6 | ],
7 | 'authorize' => [
8 | 'profile',
9 | 'logout',
10 | ],
11 | 'guest' => [
12 | 'register',
13 | 'login',
14 | 'recovery',
15 | 'confirm',
16 | 'reset',
17 | ],
18 | 'admin' => [
19 | //
20 | ],
21 | ];
--------------------------------------------------------------------------------
/application/views/account/confirm.php:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/application/controllers/MainController.php:
--------------------------------------------------------------------------------
1 | $this->tariffs,
12 | ];
13 | $this->view->render('Главная страница', $vars);
14 | }
15 |
16 | }
--------------------------------------------------------------------------------
/index.php:
--------------------------------------------------------------------------------
1 | run();
--------------------------------------------------------------------------------
/application/views/account/reset.php:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/public/styles/main.css:
--------------------------------------------------------------------------------
1 | body {
2 | padding-top: 54px;
3 | }
4 |
5 | @media (min-width: 992px) {
6 | body {
7 | padding-top: 56px;
8 | }
9 | }
10 |
11 | .carousel-item {
12 | height: 65vh;
13 | min-height: 300px;
14 | background: no-repeat center center scroll;
15 | -webkit-background-size: cover;
16 | -moz-background-size: cover;
17 | -o-background-size: cover;
18 | background-size: cover;
19 | }
20 |
21 | .portfolio-item {
22 | margin-bottom: 30px;
23 | }
--------------------------------------------------------------------------------
/public/scripts/form.js:
--------------------------------------------------------------------------------
1 | $(document).ready(function() {
2 | $('form').submit(function(event) {
3 | if ($(this).attr('id') == 'no_ajax') {
4 | return;
5 | }
6 | var json;
7 | event.preventDefault();
8 | $.ajax({
9 | type: $(this).attr('method'),
10 | url: $(this).attr('action'),
11 | data: new FormData(this),
12 | contentType: false,
13 | cache: false,
14 | processData: false,
15 | success: function(result) {
16 | json = jQuery.parseJSON(result);
17 | if (json.url) {
18 | window.location.href = '/' + json.url;
19 | } else {
20 | alert(json.status + ' - ' + json.message);
21 | }
22 | },
23 | });
24 | });
25 | });
--------------------------------------------------------------------------------
/application/views/account/recovery.php:
--------------------------------------------------------------------------------
1 |
2 |
Восстановление пароля
3 |
17 |
--------------------------------------------------------------------------------
/application/controllers/MerchantController.php:
--------------------------------------------------------------------------------
1 | view->errorCode(404);
21 | }
22 | $data = $this->model->validatePerfectMoney($_POST, $this->tariffs);
23 | if (!$data) {
24 | $this->view->errorCode(403);
25 | }
26 | $this->model->createTariff($data, $this->tariffs[$data['tid']]);
27 | }
28 |
29 | }
--------------------------------------------------------------------------------
/application/views/admin/login.php:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/application/views/dashboard/history.php:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
История пуста
7 |
8 |
9 |
10 |
11 | | Дата |
12 | Описание |
13 |
14 |
15 |
16 |
17 |
18 | |
19 | |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/application/views/account/login.php:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/application/lib/Db.php:
--------------------------------------------------------------------------------
1 | db = new PDO('mysql:host='.$config['host'].';dbname='.$config['name'].'', $config['user'], $config['password']);
14 | }
15 |
16 | public function query($sql, $params = []) {
17 | $stmt = $this->db->prepare($sql);
18 | if (!empty($params)) {
19 | foreach ($params as $key => $val) {
20 | if (is_int($val)) {
21 | $type = PDO::PARAM_INT;
22 | } else {
23 | $type = PDO::PARAM_STR;
24 | }
25 | $stmt->bindValue(':'.$key, $val, $type);
26 | }
27 | }
28 | $stmt->execute();
29 | return $stmt;
30 | }
31 |
32 | public function row($sql, $params = []) {
33 | $result = $this->query($sql, $params);
34 | return $result->fetchAll(PDO::FETCH_ASSOC);
35 | }
36 |
37 | public function column($sql, $params = []) {
38 | $result = $this->query($sql, $params);
39 | return $result->fetchColumn();
40 | }
41 |
42 | public function lastInsertId() {
43 | return $this->db->lastInsertId();
44 | }
45 |
46 | }
--------------------------------------------------------------------------------
/application/core/View.php:
--------------------------------------------------------------------------------
1 | route = $route;
13 | $this->path = $route['controller'].'/'.$route['action'];
14 | }
15 |
16 | public function render($title, $vars = []) {
17 | extract($vars);
18 | $path = 'application/views/'.$this->path.'.php';
19 | if (file_exists($path)) {
20 | ob_start();
21 | require $path;
22 | $content = ob_get_clean();
23 | require 'application/views/layouts/'.$this->layout.'.php';
24 | }
25 | }
26 |
27 | public function redirect($url) {
28 | header('location: /'.$url);
29 | exit;
30 | }
31 |
32 | public static function errorCode($code) {
33 | http_response_code($code);
34 | $path = 'application/views/errors/'.$code.'.php';
35 | if (file_exists($path)) {
36 | require $path;
37 | }
38 | exit;
39 | }
40 |
41 | public function message($status, $message) {
42 | exit(json_encode(['status' => $status, 'message' => $message]));
43 | }
44 |
45 | public function location($url) {
46 | exit(json_encode(['url' => $url]));
47 | }
48 |
49 | }
--------------------------------------------------------------------------------
/application/config/tariffs.php:
--------------------------------------------------------------------------------
1 | [
5 | 'title' => 'Минимальный',
6 | 'description' => 'подойдет для новичков',
7 | 'hour' => 50,
8 | 'percent' => 5,
9 | 'min' => 100,
10 | 'max' => 1000,
11 | ],
12 | 2 => [
13 | 'title' => 'Стартовый',
14 | 'description' => 'это старт вашей карьеры',
15 | 'hour' => 100,
16 | 'percent' => 25,
17 | 'min' => 1500,
18 | 'max' => 5000,
19 | ],
20 | 3 => [
21 | 'title' => 'Простой',
22 | 'description' => 'проще чем ходить на работу',
23 | 'hour' => 300,
24 | 'percent' => 50,
25 | 'min' => 5000,
26 | 'max' => 10000,
27 | ],
28 | 4 => [
29 | 'title' => 'Расширенный',
30 | 'description' => 'для ценителей ощущений',
31 | 'hour' => 100,
32 | 'percent' => 500,
33 | 'min' => 25000,
34 | 'max' => 50000,
35 | ],
36 | 5 => [
37 | 'title' => 'Профессиональный',
38 | 'description' => 'решение для акул бизнеса',
39 | 'hour' => 5000,
40 | 'percent' => 2000,
41 | 'min' => 100000,
42 | 'max' => 300000,
43 | ],
44 | 6 => [
45 | 'title' => 'Роскошный',
46 | 'description' => 'сюда инвестируют только киты',
47 | 'hour' => 10000,
48 | 'percent' => 5000,
49 | 'min' => 500000,
50 | 'max' => 1000000,
51 | ],
52 | ];
--------------------------------------------------------------------------------
/db.sql:
--------------------------------------------------------------------------------
1 | CREATE TABLE IF NOT EXISTS `accounts` (
2 | `id` int(11) NOT NULL AUTO_INCREMENT,
3 | `email` varchar(50) NOT NULL,
4 | `login` varchar(15) NOT NULL,
5 | `wallet` varchar(15) NOT NULL,
6 | `password` varchar(200) NOT NULL,
7 | `ref` int(11) NOT NULL,
8 | `refBalance` float NOT NULL,
9 | `token` varchar(30) NOT NULL,
10 | `status` int(11) NOT NULL,
11 | PRIMARY KEY (`id`)
12 | ) ENGINE=MyISAM DEFAULT CHARSET=utf8;
13 |
14 | CREATE TABLE IF NOT EXISTS `history` (
15 | `id` int(11) NOT NULL AUTO_INCREMENT,
16 | `uid` int(11) NOT NULL,
17 | `unixTime` int(11) NOT NULL,
18 | `description` text NOT NULL,
19 | PRIMARY KEY (`id`)
20 | ) ENGINE=MyISAM DEFAULT CHARSET=utf8;
21 |
22 |
23 | CREATE TABLE IF NOT EXISTS `ref_withdraw` (
24 | `id` int(11) NOT NULL AUTO_INCREMENT,
25 | `uid` int(11) NOT NULL,
26 | `unixTime` int(11) NOT NULL,
27 | `amount` float NOT NULL,
28 | PRIMARY KEY (`id`)
29 | ) ENGINE=MyISAM DEFAULT CHARSET=utf8;
30 |
31 | CREATE TABLE IF NOT EXISTS `tariffs` (
32 | `id` int(11) NOT NULL AUTO_INCREMENT,
33 | `uid` int(11) NOT NULL,
34 | `sumIn` float NOT NULL,
35 | `sumOut` float NOT NULL,
36 | `percent` float NOT NULL,
37 | `unixTimeStart` int(11) NOT NULL,
38 | `unixTimeFinish` int(11) NOT NULL,
39 | PRIMARY KEY (`id`)
40 | ) ENGINE=MyISAM DEFAULT CHARSET=utf8;
--------------------------------------------------------------------------------
/application/core/Controller.php:
--------------------------------------------------------------------------------
1 | route = $route;
16 | if (!$this->checkAcl()) {
17 | View::errorCode(403);
18 | }
19 | $this->view = new View($route);
20 | $this->model = $this->loadModel($route['controller']);
21 | $this->tariffs = require 'application/config/tariffs.php';
22 | }
23 |
24 | public function loadModel($name) {
25 | $path = 'application\models\\'.ucfirst($name);
26 | if (class_exists($path)) {
27 | return new $path;
28 | }
29 | }
30 |
31 | public function checkAcl() {
32 | $this->acl = require 'application/acl/'.$this->route['controller'].'.php';
33 | if ($this->isAcl('all')) {
34 | return true;
35 | }
36 | elseif (isset($_SESSION['account']['id']) and $this->isAcl('authorize')) {
37 | return true;
38 | }
39 | elseif (!isset($_SESSION['account']['id']) and $this->isAcl('guest')) {
40 | return true;
41 | }
42 | elseif (isset($_SESSION['admin']) and $this->isAcl('admin')) {
43 | return true;
44 | }
45 | return false;
46 | }
47 |
48 | public function isAcl($key) {
49 | return in_array($this->route['action'], $this->acl[$key]);
50 | }
51 |
52 | }
--------------------------------------------------------------------------------
/application/controllers/DashboardController.php:
--------------------------------------------------------------------------------
1 | $this->tariffs[$this->route['id']],
13 | ];
14 | $this->view->render('Инвестировать', $vars);
15 | }
16 |
17 | public function tariffsAction() {
18 | $pagination = new Pagination($this->route, $this->model->tariffsCount());
19 | $vars = [
20 | 'pagination' => $pagination->get(),
21 | 'list' => $this->model->tariffsList($this->route),
22 | ];
23 | $this->view->render('Тарифы', $vars);
24 | }
25 |
26 | public function historyAction() {
27 | $pagination = new Pagination($this->route, $this->model->historyCount());
28 | $vars = [
29 | 'pagination' => $pagination->get(),
30 | 'list' => $this->model->historyList($this->route),
31 | ];
32 | $this->view->render('История', $vars);
33 | }
34 |
35 | public function referralsAction() {
36 | if (!empty($_POST)) {
37 | if ($_SESSION['account']['refBalance'] <= 0) {
38 | $this->view->message('success', 'Реферальный баланс пуст');
39 | }
40 | $this->model->creatRefWithdraw();
41 | $this->view->message('success', 'Заявка на вывод создана');
42 | }
43 | $pagination = new Pagination($this->route, $this->model->referralsCount());
44 | $vars = [
45 | 'pagination' => $pagination->get(),
46 | 'list' => $this->model->referralsList($this->route),
47 | ];
48 | $this->view->render('Рефералы', $vars);
49 | }
50 |
51 | }
--------------------------------------------------------------------------------
/application/views/main/index.php:
--------------------------------------------------------------------------------
1 |
2 |
Тарифы
3 |
4 | $val): ?>
5 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/application/views/account/profile.php:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/application/views/admin/history.php:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
История пуста
10 |
11 |
12 |
13 |
14 | | Дата |
15 | Логин |
16 | E-mail |
17 | Описание |
18 |
19 |
20 |
21 |
22 |
23 | |
24 | |
25 | |
26 | |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
--------------------------------------------------------------------------------
/application/core/Router.php:
--------------------------------------------------------------------------------
1 | $val) {
15 | $this->add($key, $val);
16 | }
17 | }
18 |
19 | public function add($route, $params) {
20 | $route = preg_replace('/{([a-z]+):([^\}]+)}/', '(?P<\1>\2)', $route);
21 | $route = '#^'.$route.'$#';
22 | $this->routes[$route] = $params;
23 | }
24 |
25 | public function match() {
26 | $url = trim($_SERVER['REQUEST_URI'], '/');
27 | foreach ($this->routes as $route => $params) {
28 | if (preg_match($route, $url, $matches)) {
29 | foreach ($matches as $key => $match) {
30 | if (is_string($key)) {
31 | if (is_numeric($match)) {
32 | $match = (int) $match;
33 | }
34 | $params[$key] = $match;
35 | }
36 | }
37 | $this->params = $params;
38 | return true;
39 | }
40 | }
41 | return false;
42 | }
43 |
44 | public function run(){
45 | if ($this->match()) {
46 | $path = 'application\controllers\\'.ucfirst($this->params['controller']).'Controller';
47 | if (class_exists($path)) {
48 | $action = $this->params['action'].'Action';
49 | if (method_exists($path, $action)) {
50 | $controller = new $path($this->params);
51 | $controller->$action();
52 | } else {
53 | View::errorCode(404);
54 | }
55 | } else {
56 | View::errorCode(404);
57 | }
58 | } else {
59 | View::errorCode(404);
60 | }
61 | }
62 |
63 | }
--------------------------------------------------------------------------------
/application/views/dashboard/tariffs.php:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
Список инвестиций пуст
7 |
8 |
9 |
10 |
11 | | Дата старта |
12 | Дата завершения |
13 | Сумма |
14 | Получаете |
15 | Процент |
16 | Статус |
17 |
18 |
19 |
20 |
21 |
22 | |
23 | |
24 | $ |
25 | $ |
26 | % |
27 |
28 | = $val['unixTimeFinish']): ?>
29 |
30 | Ожидает выплаты
31 |
32 | Закрыт
33 |
34 |
35 | Активна
36 |
37 | |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
--------------------------------------------------------------------------------
/application/views/dashboard/referrals.php:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
22 |
23 |
24 |
Список рефералов пуст
25 |
26 |
27 |
28 |
29 | | Логин |
30 | E-mail |
31 |
32 |
33 |
34 |
35 |
36 | |
37 | |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
--------------------------------------------------------------------------------
/application/views/account/register.php:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/application/controllers/AdminController.php:
--------------------------------------------------------------------------------
1 | view->layout = 'admin';
13 | }
14 |
15 | public function loginAction() {
16 | if (isset($_SESSION['admin'])) {
17 | $this->view->redirect('admin/withdraw');
18 | }
19 | if (!empty($_POST)) {
20 | if (!$this->model->loginValidate($_POST)) {
21 | $this->view->message('error', $this->model->error);
22 | }
23 | $_SESSION['admin'] = true;
24 | $this->view->location('admin/withdraw');
25 | }
26 | $this->view->render('Вход');
27 | }
28 |
29 | public function withdrawAction() {
30 | if (!empty($_POST)) {
31 | if ($_POST['type'] == 'ref') {
32 | $result = $this->model->withdrawRefComplete($_POST['id']);
33 | if ($result) {
34 | $this->view->location('admin/withdraw');
35 | }
36 | else {
37 | $this->view->message('error', 'Ошибка обработки запроса');
38 | }
39 | }
40 | elseif ($_POST['type'] == 'tariff') {
41 | $result = $this->model->withdrawTariffsComplete($_POST['id']);
42 | if ($result) {
43 | $this->view->location('admin/withdraw');
44 | }
45 | else {
46 | $this->view->message('error', 'Ошибка обработки запроса');
47 | }
48 | }
49 | }
50 | $vars = [
51 | 'listRef' => $this->model->withdrawRefList(),
52 | 'listTariffs' => $this->model->withdrawTariffsList(),
53 | ];
54 | $this->view->render('Заказы на вывод средств', $vars);
55 | }
56 |
57 | public function historyAction() {
58 | $pagination = new Pagination($this->route, $this->model->historyCount());
59 | $vars = [
60 | 'pagination' => $pagination->get(),
61 | 'list' => $this->model->historyList($this->route),
62 | ];
63 | $this->view->render('История', $vars);
64 | }
65 |
66 | public function tariffsAction() {
67 | $pagination = new Pagination($this->route, $this->model->tariffsCount());
68 | $vars = [
69 | 'pagination' => $pagination->get(),
70 | 'list' => $this->model->tariffsList($this->route),
71 | ];
72 | $this->view->render('Список инвестиций', $vars);
73 | }
74 |
75 | public function logoutAction() {
76 | unset($_SESSION['admin']);
77 | $this->view->redirect('admin/login');
78 | }
79 |
80 | }
--------------------------------------------------------------------------------
/application/models/Merchant.php:
--------------------------------------------------------------------------------
1 | $tariff[$tid]['max'] or $amount < $tariff[$tid]['min']) {
34 | return false;
35 | }
36 | return [
37 | 'tid' => $tid,
38 | 'uid' => $uid,
39 | 'amount' => $amount,
40 | ];
41 | }
42 |
43 | public function createTariff($data, $tarif) {
44 | $dataRef = $this->db->column('SELECT ref FROM accounts WHERE id = :id', ['id' => $data['uid']]);
45 | if ($dataRef === false) {
46 | return false;
47 | }
48 | if ($dataRef != 0) {
49 | $refSum = round((($data['amount'] * 5) / 100), 2);
50 | $params = [
51 | 'sum' => $refSum,
52 | 'id' => $dataRef,
53 | ];
54 | $this->db->query('UPDATE accounts SET refBalance = refBalance + :sum WHERE id = :id', $params);
55 | $params = [
56 | 'id' => '',
57 | 'uid' => $dataRef,
58 | 'unixTime' => time(),
59 | 'description' => 'Реферальное вознаграждение, сумма '.$refSum.' $',
60 | ];
61 | $this->db->query('INSERT INTO history VALUES (:id, :uid, :unixTime, :description)', $params);
62 | }
63 | $params = [
64 | 'id' => '',
65 | 'uid' => $data['uid'],
66 | 'sumIn' => round($data['amount'], 2),
67 | 'sumOut' => round($data['amount'] + (($data['amount'] * $tarif['percent']) / 100), 2),
68 | 'percent' => $tarif['percent'],
69 | 'unixTimeStart' => time(),
70 | 'unixTimeFinish' => strtotime('+ '.$tarif['hour'].' hours'),
71 | ];
72 | $this->db->query('INSERT INTO tariffs VALUES (:id, :uid, :sumIn, :sumOut, :percent, :unixTimeStart, :unixTimeFinish)', $params);
73 |
74 | $params = [
75 | 'id' => '',
76 | 'uid' => $data['uid'],
77 | 'unixTime' => time(),
78 | 'description' => 'Инвестиция, номер вклада # '.$this->db->lastInsertId(),
79 | ];
80 | $this->db->query('INSERT INTO history VALUES (:id, :uid, :unixTime, :description)', $params);
81 | }
82 |
83 | }
--------------------------------------------------------------------------------
/application/models/Dashboard.php:
--------------------------------------------------------------------------------
1 | $_SESSION['account']['id'],
12 | ];
13 | return $this->db->column('SELECT COUNT(id) FROM history WHERE uid = :uid', $params);
14 | }
15 |
16 | public function historyList($route) {
17 | $max = 10;
18 | $params = [
19 | 'max' => $max,
20 | 'start' => ((($route['page'] ?? 1) - 1) * $max),
21 | 'uid' => $_SESSION['account']['id'],
22 | ];
23 | return $this->db->row('SELECT * FROM history WHERE uid = :uid ORDER BY id DESC LIMIT :start, :max', $params);
24 | }
25 |
26 | public function referralsCount() {
27 | $params = [
28 | 'uid' => $_SESSION['account']['id'],
29 | ];
30 | return $this->db->column('SELECT COUNT(id) FROM accounts WHERE ref = :uid', $params);
31 | }
32 |
33 | public function referralsList($route) {
34 | $max = 10;
35 | $params = [
36 | 'max' => $max,
37 | 'start' => ((($route['page'] ?? 1) - 1) * $max),
38 | 'uid' => $_SESSION['account']['id'],
39 | ];
40 | return $this->db->row('SELECT login, email FROM accounts WHERE ref = :uid ORDER BY id DESC LIMIT :start, :max', $params);
41 | }
42 |
43 | public function tariffsCount() {
44 | $params = [
45 | 'uid' => $_SESSION['account']['id'],
46 | ];
47 | return $this->db->column('SELECT COUNT(id) FROM tariffs WHERE uid = :uid', $params);
48 | }
49 |
50 | public function tariffsList($route) {
51 | $max = 10;
52 | $params = [
53 | 'max' => $max,
54 | 'start' => ((($route['page'] ?? 1) - 1) * $max),
55 | 'uid' => $_SESSION['account']['id'],
56 | ];
57 | return $this->db->row('SELECT * FROM tariffs WHERE uid = :uid ORDER BY id DESC LIMIT :start, :max', $params);
58 | }
59 |
60 | public function creatRefWithdraw() {
61 | $amount = $_SESSION['account']['refBalance'];
62 | $_SESSION['account']['refBalance'] = 0;
63 |
64 | $params = [
65 | 'id' => $_SESSION['account']['id'],
66 | ];
67 | $this->db->query('UPDATE accounts SET refBalance = 0 WHERE id = :id', $params);
68 |
69 | $params = [
70 | 'id' => '',
71 | 'uid' => $_SESSION['account']['id'],
72 | 'unixTime' => time(),
73 | 'amount' => $amount,
74 | ];
75 | $this->db->query('INSERT INTO ref_withdraw VALUES (:id, :uid, :unixTime, :amount)', $params);
76 |
77 | $params = [
78 | 'id' => '',
79 | 'uid' => $_SESSION['account']['id'],
80 | 'unixTime' => time(),
81 | 'description' => 'Вывод реферального вознаграждения, сумма '.$amount.' $',
82 | ];
83 | $this->db->query('INSERT INTO history VALUES (:id, :uid, :unixTime, :description)', $params);
84 | }
85 |
86 | }
--------------------------------------------------------------------------------
/application/config/routes.php:
--------------------------------------------------------------------------------
1 | [
6 | 'controller' => 'main',
7 | 'action' => 'index',
8 | ],
9 | // MerchantController
10 | 'merchant/perfectmoney' => [
11 | 'controller' => 'merchant',
12 | 'action' => 'perfectmoney',
13 | ],
14 | // DashboardController
15 | 'dashboard/tariffs' => [
16 | 'controller' => 'dashboard',
17 | 'action' => 'tariffs',
18 | ],
19 | 'dashboard/tariffs/{page:\d+}' => [
20 | 'controller' => 'dashboard',
21 | 'action' => 'tariffs',
22 | ],
23 | 'dashboard/invest/{id:\d+}' => [
24 | 'controller' => 'dashboard',
25 | 'action' => 'invest',
26 | ],
27 | 'dashboard/history' => [
28 | 'controller' => 'dashboard',
29 | 'action' => 'history',
30 | ],
31 | 'dashboard/history/{page:\d+}' => [
32 | 'controller' => 'dashboard',
33 | 'action' => 'history',
34 | ],
35 | 'dashboard/referrals' => [
36 | 'controller' => 'dashboard',
37 | 'action' => 'referrals',
38 | ],
39 | 'dashboard/referrals/{page:\d+}' => [
40 | 'controller' => 'dashboard',
41 | 'action' => 'referrals',
42 | ],
43 | // AccountController
44 | 'account/login' => [
45 | 'controller' => 'account',
46 | 'action' => 'login',
47 | ],
48 | 'account/register' => [
49 | 'controller' => 'account',
50 | 'action' => 'register',
51 | ],
52 | 'account/register/{ref:\w+}' => [
53 | 'controller' => 'account',
54 | 'action' => 'register',
55 | ],
56 | 'account/recovery' => [
57 | 'controller' => 'account',
58 | 'action' => 'recovery',
59 | ],
60 | 'account/confirm/{token:\w+}' => [
61 | 'controller' => 'account',
62 | 'action' => 'confirm',
63 | ],
64 | 'account/reset/{token:\w+}' => [
65 | 'controller' => 'account',
66 | 'action' => 'reset',
67 | ],
68 | 'account/profile' => [
69 | 'controller' => 'account',
70 | 'action' => 'profile',
71 | ],
72 | 'account/logout' => [
73 | 'controller' => 'account',
74 | 'action' => 'logout',
75 | ],
76 | // AdminController
77 | 'admin/withdraw' => [
78 | 'controller' => 'admin',
79 | 'action' => 'withdraw',
80 | ],
81 | 'admin/history' => [
82 | 'controller' => 'admin',
83 | 'action' => 'history',
84 | ],
85 | 'admin/history/{page:\d+}' => [
86 | 'controller' => 'admin',
87 | 'action' => 'history',
88 | ],
89 | 'admin/tariffs' => [
90 | 'controller' => 'admin',
91 | 'action' => 'tariffs',
92 | ],
93 | 'admin/tariffs/{page:\d+}' => [
94 | 'controller' => 'admin',
95 | 'action' => 'tariffs',
96 | ],
97 | 'admin/login' => [
98 | 'controller' => 'admin',
99 | 'action' => 'login',
100 | ],
101 | 'admin/logout' => [
102 | 'controller' => 'admin',
103 | 'action' => 'logout',
104 | ],
105 | ];
--------------------------------------------------------------------------------
/application/views/dashboard/invest.php:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/application/lib/Pagination.php:
--------------------------------------------------------------------------------
1 | route = $route;
16 | $this->total = $total;
17 | $this->limit = $limit;
18 | $this->amount = $this->amount();
19 | $this->setCurrentPage();
20 | }
21 |
22 | public function get() {
23 | $links = null;
24 | $limits = $this->limits();
25 | $html = '';
42 | return $html;
43 | }
44 |
45 | private function generateHtml($page, $text = null) {
46 | if (!$text) {
47 | $text = $page;
48 | }
49 | return ''.$text.'';
50 | }
51 |
52 | private function limits() {
53 | $left = $this->current_page - round($this->max / 2);
54 | $start = $left > 0 ? $left : 1;
55 | if ($start + $this->max <= $this->amount) {
56 | $end = $start > 1 ? $start + $this->max : $this->max;
57 | }
58 | else {
59 | $end = $this->amount;
60 | $start = $this->amount - $this->max > 0 ? $this->amount - $this->max : 1;
61 | }
62 | return array($start, $end);
63 | }
64 |
65 | private function setCurrentPage() {
66 | if (isset($this->route['page'])) {
67 | $currentPage = $this->route['page'];
68 | } else {
69 | $currentPage = 1;
70 | }
71 | $this->current_page = $currentPage;
72 | if ($this->current_page > 0) {
73 | if ($this->current_page > $this->amount) {
74 | $this->current_page = $this->amount;
75 | }
76 | } else {
77 | $this->current_page = 1;
78 | }
79 | }
80 |
81 | private function amount() {
82 | return ceil($this->total / $this->limit);
83 | }
84 | }
--------------------------------------------------------------------------------
/application/views/layouts/default.php:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
51 |
52 |
53 |
--------------------------------------------------------------------------------
/application/views/layouts/admin.php:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 | route['action'] != 'login'): ?>
16 |
46 |
47 |
48 | route['action'] != 'login'): ?>
49 |
56 |
57 |
58 |
--------------------------------------------------------------------------------
/application/views/admin/tariffs.php:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
Список инвестиций пуст
10 |
11 |
12 |
13 |
14 | | Номер вклада |
15 | Дата старта |
16 | Дата завершения |
17 | Сумма |
18 | Получаете |
19 | Процент |
20 | Логин |
21 | E-mail |
22 | Статус |
23 |
24 |
25 |
26 |
27 |
28 | |
29 | |
30 | |
31 | $ |
32 | $ |
33 | % |
34 | |
35 | |
36 |
37 | = $val['unixTimeFinish']): ?>
38 |
39 | Ожидает выплаты
40 |
41 | Закрыт
42 |
43 |
44 | Активна
45 |
46 | |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
--------------------------------------------------------------------------------
/application/controllers/AccountController.php:
--------------------------------------------------------------------------------
1 | model->validate(['email', 'login', 'wallet', 'password', 'ref'], $_POST)) {
14 | $this->view->message('error', $this->model->error);
15 | }
16 | elseif ($this->model->checkEmailExists($_POST['email'])) {
17 | $this->view->message('error', 'Этот E-mail уже используется');
18 | }
19 | elseif (!$this->model->checkLoginExists($_POST['login'])) {
20 | $this->view->message('error', $this->model->error);
21 | }
22 | $this->model->register($_POST);
23 | $this->view->message('success', 'Регистрация завершена, подтвердите свой E-mail');
24 | }
25 | $this->view->render('Регистрация');
26 | }
27 |
28 | public function confirmAction() {
29 | if (!$this->model->checkTokenExists($this->route['token'])) {
30 | $this->view->redirect('account/login');
31 | }
32 | $this->model->activate($this->route['token']);
33 | $this->view->render('Аккаунт активирован');
34 | }
35 |
36 | // Вход
37 |
38 | public function loginAction() {
39 | if (!empty($_POST)) {
40 | if (!$this->model->validate(['login', 'password'], $_POST)) {
41 | $this->view->message('error', $this->model->error);
42 | }
43 | elseif (!$this->model->checkData($_POST['login'], $_POST['password'])) {
44 | $this->view->message('error', 'Логин или пароль указан неверно');
45 | }
46 | elseif (!$this->model->checkStatus('login', $_POST['login'])) {
47 | $this->view->message('error', $this->model->error);
48 | }
49 | $this->model->login($_POST['login']);
50 | $this->view->location('account/profile');
51 | }
52 | $this->view->render('Вход');
53 | }
54 |
55 | // Профиль
56 |
57 | public function profileAction() {
58 | if (!empty($_POST)) {
59 | if (!$this->model->validate(['email', 'wallet'], $_POST)) {
60 | $this->view->message('error', $this->model->error);
61 | }
62 | $id = $this->model->checkEmailExists($_POST['email']);
63 | if ($id and $id != $_SESSION['account']['id']) {
64 | $this->view->message('error', 'Этот E-mail уже используется');
65 | }
66 | if (!empty($_POST['password']) and !$this->model->validate(['password'], $_POST)) {
67 | $this->view->message('error', $this->model->error);
68 | }
69 | $this->model->save($_POST);
70 | $this->view->message('error', 'Сохранено');
71 | }
72 | $this->view->render('Профиль');
73 | }
74 |
75 | public function logoutAction() {
76 | unset($_SESSION['account']);
77 | $this->view->redirect('account/login');
78 | }
79 |
80 | // Восстановление пароля
81 |
82 | public function recoveryAction() {
83 | if (!empty($_POST)) {
84 | if (!$this->model->validate(['email'], $_POST)) {
85 | $this->view->message('error', $this->model->error);
86 | }
87 | elseif (!$this->model->checkEmailExists($_POST['email'])) {
88 | $this->view->message('error', 'Пользователь не найден');
89 | }
90 | elseif (!$this->model->checkStatus('email', $_POST['email'])) {
91 | $this->view->message('error', $this->model->error);
92 | }
93 | $this->model->recovery($_POST);
94 | $this->view->message('success', 'Запрос на восстановление пароля отправлен на E-mail');
95 | }
96 | $this->view->render('Восстановление пароля');
97 | }
98 |
99 | public function resetAction() {
100 | if (!$this->model->checkTokenExists($this->route['token'])) {
101 | $this->view->redirect('account/login');
102 | }
103 | $password = $this->model->reset($this->route['token']);
104 | $vars = [
105 | 'password' => $password,
106 | ];
107 | $this->view->render('Пароль сброшен', $vars);
108 | }
109 | }
--------------------------------------------------------------------------------
/application/models/Admin.php:
--------------------------------------------------------------------------------
1 | error = 'Логин или пароль указан неверно';
13 | return false;
14 | }
15 | return true;
16 | }
17 |
18 | public function historyCount() {
19 | return $this->db->column('SELECT COUNT(id) FROM history');
20 | }
21 |
22 | public function historyList($route) {
23 | $max = 10;
24 | $params = [
25 | 'max' => $max,
26 | 'start' => ((($route['page'] ?? 1) - 1) * $max),
27 | ];
28 | $arr = [];
29 | $result = $this->db->row('SELECT * FROM history ORDER BY id DESC LIMIT :start, :max', $params);
30 | if (!empty($result)) {
31 | foreach ($result as $key => $val) {
32 | $arr[$key] = $val;
33 | $params = [
34 | 'id' => $val['uid'],
35 | ];
36 | $account = $this->db->row('SELECT login, email FROM accounts WHERE id = :id', $params)[0];
37 | $arr[$key]['login'] = $account['login'];
38 | $arr[$key]['email'] = $account['email'];
39 | }
40 | }
41 | return $arr;
42 | }
43 |
44 | public function withdrawRefList() {
45 | $arr = [];
46 | $result = $this->db->row('SELECT * FROM ref_withdraw ORDER BY id DESC');
47 | if (!empty($result)) {
48 | foreach ($result as $key => $val) {
49 | $arr[$key] = $val;
50 | $params = [
51 | 'id' => $val['uid'],
52 | ];
53 | $account = $this->db->row('SELECT login, wallet FROM accounts WHERE id = :id', $params)[0];
54 | $arr[$key]['login'] = $account['login'];
55 | $arr[$key]['wallet'] = $account['wallet'];
56 | }
57 | }
58 | return $arr;
59 | }
60 |
61 | public function withdrawTariffsList() {
62 | $arr = [];
63 | $result = $this->db->row('SELECT * FROM tariffs WHERE UNIX_TIMESTAMP() >= unixTimeFinish AND sumOut != 0 ORDER BY id DESC');
64 | if (!empty($result)) {
65 | foreach ($result as $key => $val) {
66 | $arr[$key] = $val;
67 | $params = [
68 | 'id' => $val['uid'],
69 | ];
70 | $account = $this->db->row('SELECT login, wallet FROM accounts WHERE id = :id', $params)[0];
71 | $arr[$key]['login'] = $account['login'];
72 | $arr[$key]['wallet'] = $account['wallet'];
73 | }
74 | }
75 | return $arr;
76 | }
77 |
78 | public function withdrawRefComplete($id) {
79 | $params = [
80 | 'id' => $id,
81 | ];
82 | $data = $this->db->row('SELECT uid, amount FROM ref_withdraw WHERE id = :id', $params);
83 | if (!$data) {
84 | return false;
85 | }
86 | $this->db->query('DELETE FROM ref_withdraw WHERE id = :id', $params);
87 | $data = $data[0];
88 | $params = [
89 | 'id' => '',
90 | 'uid' => $data['uid'],
91 | 'unixTime' => time(),
92 | 'description' => 'Выплата реферального вознаграждения произведена, сумма '.$data['amount'].' $',
93 | ];
94 | $this->db->query('INSERT INTO history VALUES (:id, :uid, :unixTime, :description)', $params);
95 | return true;
96 | }
97 |
98 | public function withdrawTariffsComplete($id) {
99 | $params = [
100 | 'id' => $id,
101 | ];
102 | $data = $this->db->row('SELECT uid, sumOut FROM tariffs WHERE id = :id', $params);
103 | if (!$data) {
104 | return false;
105 | }
106 | $this->db->query('UPDATE tariffs SET sumOut = 0 WHERE id = :id', $params);
107 | $data = $data[0];
108 | $params = [
109 | 'id' => '',
110 | 'uid' => $data['uid'],
111 | 'unixTime' => time(),
112 | 'description' => 'Выплата по тарифу # '.$id.' произведена, сумма '.$data['sumOut'].' $',
113 | ];
114 | $this->db->query('INSERT INTO history VALUES (:id, :uid, :unixTime, :description)', $params);
115 | return true;
116 | }
117 |
118 | public function tariffsCount() {
119 | return $this->db->column('SELECT COUNT(id) FROM tariffs');
120 | }
121 |
122 | public function tariffsList($route) {
123 | $max = 10;
124 | $params = [
125 | 'max' => $max,
126 | 'start' => ((($route['page'] ?? 1) - 1) * $max),
127 | ];
128 | $arr = [];
129 | $result = $this->db->row('SELECT * FROM tariffs ORDER BY id DESC LIMIT :start, :max', $params);
130 | if (!empty($result)) {
131 | foreach ($result as $key => $val) {
132 | $arr[$key] = $val;
133 | $params = [
134 | 'id' => $val['uid'],
135 | ];
136 | $account = $this->db->row('SELECT login, email FROM accounts WHERE id = :id', $params)[0];
137 | $arr[$key]['login'] = $account['login'];
138 | $arr[$key]['email'] = $account['email'];
139 | }
140 | }
141 | return $arr;
142 | }
143 |
144 | }
--------------------------------------------------------------------------------
/application/views/admin/withdraw.php:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
Список заявок на вывод по тарфиам пуст
10 |
11 |
12 |
13 |
14 | | Номер вклада |
15 | Дата |
16 | Сумма |
17 | Логин |
18 | Кошелек |
19 | |
20 |
21 |
22 |
23 |
24 |
25 | | # |
26 | |
27 | $ |
28 | |
29 | |
30 |
31 |
36 | |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
Список заявок на вывод реферального вознаграждения пуст
53 |
54 |
55 |
56 |
57 | | Дата |
58 | Сумма |
59 | Логин |
60 | Кошелек |
61 | |
62 |
63 |
64 |
65 |
66 |
67 | |
68 | $ |
69 | |
70 | |
71 |
72 |
77 | |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
--------------------------------------------------------------------------------
/application/models/Account.php:
--------------------------------------------------------------------------------
1 | [
12 | 'pattern' => '#^([a-z0-9_.-]{1,20}+)@([a-z0-9_.-]+)\.([a-z\.]{2,10})$#',
13 | 'message' => 'E-mail адрес указан неверно',
14 | ],
15 | 'login' => [
16 | 'pattern' => '#^[a-z0-9]{3,15}$#',
17 | 'message' => 'Логин указан неверно (разрешены только латинские буквы и цифры от 3 до 15 символов',
18 | ],
19 | 'ref' => [
20 | 'pattern' => '#^[a-z0-9]{3,15}$#',
21 | 'message' => 'Логин пригласившего указан неверно',
22 | ],
23 | 'wallet' => [
24 | 'pattern' => '#^[A-z0-9]{3,15}$#',
25 | 'message' => 'Кошелек Perfect Money указан неверно',
26 | ],
27 | 'password' => [
28 | 'pattern' => '#^[a-z0-9]{10,30}$#',
29 | 'message' => 'Пароль указан неверно (разрешены только латинские буквы и цифры от 10 до 30 символов',
30 |
31 | ],
32 | ];
33 | foreach ($input as $val) {
34 | if (!isset($post[$val]) or !preg_match($rules[$val]['pattern'], $post[$val])) {
35 | $this->error = $rules[$val]['message'];
36 | return false;
37 | }
38 | }
39 | if (isset($post['ref'])) {
40 | if ($post['login'] == $post['ref']) {
41 | $this->error = 'Регистрация невозможна';
42 | return false;
43 | }
44 | }
45 | return true;
46 | }
47 |
48 | public function checkEmailExists($email) {
49 | $params = [
50 | 'email' => $email,
51 | ];
52 | return $this->db->column('SELECT id FROM accounts WHERE email = :email', $params);
53 | }
54 |
55 | public function checkLoginExists($login) {
56 | $params = [
57 | 'login' => $login,
58 | ];
59 | if ($this->db->column('SELECT id FROM accounts WHERE login = :login', $params)) {
60 | $this->error = 'Этот логин уже используется';
61 | return false;
62 | }
63 | return true;
64 | }
65 |
66 | public function checkTokenExists($token) {
67 | $params = [
68 | 'token' => $token,
69 | ];
70 | return $this->db->column('SELECT id FROM accounts WHERE token = :token', $params);
71 | }
72 |
73 | public function activate($token) {
74 | $params = [
75 | 'token' => $token,
76 | ];
77 | $this->db->query('UPDATE accounts SET status = 1, token = "" WHERE token = :token', $params);
78 | }
79 |
80 | public function checkRefExists($login) {
81 | $params = [
82 | 'login' => $login,
83 | ];
84 | return $this->db->column('SELECT id FROM accounts WHERE login = :login', $params);
85 | }
86 |
87 | public function createToken() {
88 | return substr(str_shuffle(str_repeat('0123456789abcdefghijklmnopqrstuvwxyz', 30)), 0, 30);
89 | }
90 |
91 | public function register($post) {
92 | $token = $this->createToken();
93 | if ($post['ref'] == 'none') {
94 | $ref = 0;
95 | }
96 | else {
97 | $ref = $this->checkRefExists($post['ref']);
98 | if (!$ref) {
99 | $ref = 0;
100 | }
101 | }
102 | $params = [
103 | 'id' => '',
104 | 'email' => $post['email'],
105 | 'login' => $post['login'],
106 | 'wallet' => $post['wallet'],
107 | 'password' => password_hash($post['password'], PASSWORD_BCRYPT),
108 | 'ref' => $ref,
109 | 'refBalance' => 0,
110 | 'token' => $token,
111 | 'status' => 0,
112 | ];
113 | $this->db->query('INSERT INTO accounts VALUES (:id, :email, :login, :wallet, :password, :ref, :refBalance, :token, :status)', $params);
114 | mail($post['email'], 'Register', 'Confirm: '.$_SERVER['REQUEST_SCHEME'].'://'.$_SERVER['HTTP_HOST'].'/account/confirm/'.$token);
115 | }
116 |
117 | public function checkData($login, $password) {
118 | $params = [
119 | 'login' => $login,
120 | ];
121 | $hash = $this->db->column('SELECT password FROM accounts WHERE login = :login', $params);
122 | if (!$hash or !password_verify($password, $hash)) {
123 | return false;
124 | }
125 | return true;
126 | }
127 |
128 | public function checkStatus($type, $data) {
129 | $params = [
130 | $type => $data,
131 | ];
132 | $status = $this->db->column('SELECT status FROM accounts WHERE '.$type.' = :'.$type, $params);
133 | if ($status != 1) {
134 | $this->error = 'Аккаунт ожидает подтверждения по E-mail';
135 | return false;
136 | }
137 | return true;
138 | }
139 |
140 | public function login($login) {
141 | $params = [
142 | 'login' => $login,
143 | ];
144 | $data = $this->db->row('SELECT * FROM accounts WHERE login = :login', $params);
145 | $_SESSION['account'] = $data[0];
146 | }
147 |
148 | public function recovery($post) {
149 | $token = $this->createToken();
150 | $params = [
151 | 'email' => $post['email'],
152 | 'token' => $token,
153 | ];
154 | $this->db->query('UPDATE accounts SET token = :token WHERE email = :email', $params);
155 | mail($post['email'], 'Recovery', 'Confirm: '.$_SERVER['REQUEST_SCHEME'].'://'.$_SERVER['HTTP_HOST'].'/account/reset/'.$token);
156 | }
157 |
158 | public function reset($token) {
159 | $new_password = $this->createToken();
160 | $params = [
161 | 'token' => $token,
162 | 'password' => password_hash($new_password, PASSWORD_BCRYPT),
163 | ];
164 | $this->db->query('UPDATE accounts SET status = 1, token = "", password = :password WHERE token = :token', $params);
165 | return $new_password;
166 | }
167 |
168 | public function save($post) {
169 | $params = [
170 | 'id' => $_SESSION['account']['id'],
171 | 'email' => $post['email'],
172 | 'wallet' => $post['wallet'],
173 | ];
174 | if (!empty($post['password'])) {
175 | $params['password'] = password_hash($post['password'], PASSWORD_BCRYPT);
176 | $sql = ',password = :password';
177 | }
178 | else {
179 | $sql = '';
180 | }
181 | foreach ($params as $key => $val) {
182 | $_SESSION['account'][$key] = $val;
183 | }
184 | $this->db->query('UPDATE accounts SET email = :email, wallet = :wallet'.$sql.' WHERE id = :id', $params);
185 | }
186 |
187 | }
--------------------------------------------------------------------------------
/public/styles/admin.css:
--------------------------------------------------------------------------------
1 | html {
2 | position: relative;
3 | min-height: 100%; }
4 |
5 | body {
6 | overflow-x: hidden; }
7 |
8 | body.sticky-footer {
9 | margin-bottom: 56px; }
10 | body.sticky-footer .content-wrapper {
11 | min-height: calc(100vh - 56px - 56px); }
12 |
13 | body.fixed-nav {
14 | padding-top: 56px; }
15 |
16 | .content-wrapper {
17 | min-height: calc(100vh - 56px);
18 | padding-top: 1rem; }
19 |
20 | .scroll-to-top {
21 | position: fixed;
22 | right: 15px;
23 | bottom: 3px;
24 | display: none;
25 | width: 50px;
26 | height: 50px;
27 | text-align: center;
28 | color: white;
29 | background: rgba(52, 58, 64, 0.5);
30 | line-height: 45px; }
31 | .scroll-to-top:focus, .scroll-to-top:hover {
32 | color: white; }
33 | .scroll-to-top:hover {
34 | background: #343a40; }
35 | .scroll-to-top i {
36 | font-weight: 800; }
37 |
38 | .smaller {
39 | font-size: 0.7rem; }
40 |
41 | .o-hidden {
42 | overflow: hidden !important; }
43 |
44 | .z-0 {
45 | z-index: 0; }
46 |
47 | .z-1 {
48 | z-index: 1; }
49 |
50 | #mainNav .navbar-collapse {
51 | overflow: auto;
52 | max-height: 75vh; }
53 | #mainNav .navbar-collapse .navbar-nav .nav-item .nav-link {
54 | cursor: pointer; }
55 | #mainNav .navbar-collapse .navbar-sidenav .nav-link-collapse:after {
56 | float: right;
57 | content: '\f107';
58 | font-family: 'FontAwesome'; }
59 | #mainNav .navbar-collapse .navbar-sidenav .nav-link-collapse.collapsed:after {
60 | content: '\f105'; }
61 | #mainNav .navbar-collapse .navbar-sidenav .sidenav-second-level,
62 | #mainNav .navbar-collapse .navbar-sidenav .sidenav-third-level {
63 | padding-left: 0; }
64 | #mainNav .navbar-collapse .navbar-sidenav .sidenav-second-level > li > a,
65 | #mainNav .navbar-collapse .navbar-sidenav .sidenav-third-level > li > a {
66 | display: block;
67 | padding: 0.5em 0; }
68 | #mainNav .navbar-collapse .navbar-sidenav .sidenav-second-level > li > a:focus, #mainNav .navbar-collapse .navbar-sidenav .sidenav-second-level > li > a:hover,
69 | #mainNav .navbar-collapse .navbar-sidenav .sidenav-third-level > li > a:focus,
70 | #mainNav .navbar-collapse .navbar-sidenav .sidenav-third-level > li > a:hover {
71 | text-decoration: none; }
72 | #mainNav .navbar-collapse .navbar-sidenav .sidenav-second-level > li > a {
73 | padding-left: 1em; }
74 | #mainNav .navbar-collapse .navbar-sidenav .sidenav-third-level > li > a {
75 | padding-left: 2em; }
76 | #mainNav .navbar-collapse .sidenav-toggler {
77 | display: none; }
78 | #mainNav .navbar-collapse .navbar-nav > .nav-item.dropdown > .nav-link {
79 | position: relative;
80 | min-width: 45px; }
81 | #mainNav .navbar-collapse .navbar-nav > .nav-item.dropdown > .nav-link:after {
82 | float: right;
83 | width: auto;
84 | content: '\f105';
85 | border: none;
86 | font-family: 'FontAwesome'; }
87 | #mainNav .navbar-collapse .navbar-nav > .nav-item.dropdown > .nav-link .indicator {
88 | position: absolute;
89 | top: 5px;
90 | left: 21px;
91 | font-size: 10px; }
92 | #mainNav .navbar-collapse .navbar-nav > .nav-item.dropdown.show > .nav-link:after {
93 | content: '\f107'; }
94 | #mainNav .navbar-collapse .navbar-nav > .nav-item.dropdown .dropdown-menu > .dropdown-item > .dropdown-message {
95 | overflow: hidden;
96 | max-width: none;
97 | text-overflow: ellipsis; }
98 |
99 | @media (min-width: 992px) {
100 | #mainNav .navbar-brand {
101 | width: 250px; }
102 | #mainNav .navbar-collapse {
103 | overflow: visible;
104 | max-height: none; }
105 | #mainNav .navbar-collapse .navbar-sidenav {
106 | position: absolute;
107 | top: 0;
108 | left: 0;
109 | overflow-x: hidden;
110 | overflow-y: auto;
111 | -webkit-flex-direction: column;
112 | -ms-flex-direction: column;
113 | flex-direction: column;
114 | margin-top: 56px; }
115 | #mainNav .navbar-collapse .navbar-sidenav > .nav-item {
116 | width: 250px;
117 | padding: 0; }
118 | #mainNav .navbar-collapse .navbar-sidenav > .nav-item > .nav-link {
119 | padding: 1em; }
120 | #mainNav .navbar-collapse .navbar-sidenav > .nav-item .sidenav-second-level,
121 | #mainNav .navbar-collapse .navbar-sidenav > .nav-item .sidenav-third-level {
122 | padding-left: 0;
123 | list-style: none; }
124 | #mainNav .navbar-collapse .navbar-sidenav > .nav-item .sidenav-second-level > li,
125 | #mainNav .navbar-collapse .navbar-sidenav > .nav-item .sidenav-third-level > li {
126 | width: 250px; }
127 | #mainNav .navbar-collapse .navbar-sidenav > .nav-item .sidenav-second-level > li > a,
128 | #mainNav .navbar-collapse .navbar-sidenav > .nav-item .sidenav-third-level > li > a {
129 | padding: 1em; }
130 | #mainNav .navbar-collapse .navbar-sidenav > .nav-item .sidenav-second-level > li > a {
131 | padding-left: 2.75em; }
132 | #mainNav .navbar-collapse .navbar-sidenav > .nav-item .sidenav-third-level > li > a {
133 | padding-left: 3.75em; }
134 | #mainNav .navbar-collapse .navbar-nav > .nav-item.dropdown > .nav-link {
135 | min-width: 0; }
136 | #mainNav .navbar-collapse .navbar-nav > .nav-item.dropdown > .nav-link:after {
137 | width: 24px;
138 | text-align: center; }
139 | #mainNav .navbar-collapse .navbar-nav > .nav-item.dropdown .dropdown-menu > .dropdown-item > .dropdown-message {
140 | max-width: 300px; } }
141 |
142 | #mainNav.fixed-top .sidenav-toggler {
143 | display: none; }
144 |
145 | @media (min-width: 992px) {
146 | #mainNav.fixed-top .navbar-sidenav {
147 | height: calc(100vh - 112px); }
148 | #mainNav.fixed-top .sidenav-toggler {
149 | position: absolute;
150 | top: 0;
151 | left: 0;
152 | display: flex;
153 | overflow-x: hidden;
154 | overflow-y: auto;
155 | -webkit-flex-direction: column;
156 | -ms-flex-direction: column;
157 | flex-direction: column;
158 | margin-top: calc(100vh - 56px); }
159 | #mainNav.fixed-top .sidenav-toggler > .nav-item {
160 | width: 250px;
161 | padding: 0; }
162 | #mainNav.fixed-top .sidenav-toggler > .nav-item > .nav-link {
163 | padding: 1em; } }
164 |
165 | #mainNav.fixed-top.navbar-dark .sidenav-toggler {
166 | background-color: #212529; }
167 | #mainNav.fixed-top.navbar-dark .sidenav-toggler a i {
168 | color: #adb5bd; }
169 |
170 | #mainNav.fixed-top.navbar-light .sidenav-toggler {
171 | background-color: #dee2e6; }
172 | #mainNav.fixed-top.navbar-light .sidenav-toggler a i {
173 | color: rgba(0, 0, 0, 0.5); }
174 |
175 | body.sidenav-toggled #mainNav.fixed-top .sidenav-toggler {
176 | overflow-x: hidden;
177 | width: 55px; }
178 | body.sidenav-toggled #mainNav.fixed-top .sidenav-toggler .nav-item,
179 | body.sidenav-toggled #mainNav.fixed-top .sidenav-toggler .nav-link {
180 | width: 55px !important; }
181 |
182 | body.sidenav-toggled #mainNav.fixed-top #sidenavToggler i {
183 | -webkit-transform: scaleX(-1);
184 | -moz-transform: scaleX(-1);
185 | -o-transform: scaleX(-1);
186 | transform: scaleX(-1);
187 | filter: FlipH;
188 | -ms-filter: 'FlipH'; }
189 |
190 | #mainNav.static-top .sidenav-toggler {
191 | display: none; }
192 |
193 | @media (min-width: 992px) {
194 | #mainNav.static-top .sidenav-toggler {
195 | display: flex; } }
196 |
197 | body.sidenav-toggled #mainNav.static-top #sidenavToggler i {
198 | -webkit-transform: scaleX(-1);
199 | -moz-transform: scaleX(-1);
200 | -o-transform: scaleX(-1);
201 | transform: scaleX(-1);
202 | filter: FlipH;
203 | -ms-filter: 'FlipH'; }
204 |
205 | .content-wrapper {
206 | overflow-x: hidden;
207 | background: white; }
208 | @media (min-width: 992px) {
209 | .content-wrapper {
210 | margin-left: 250px; } }
211 |
212 | #sidenavToggler i {
213 | font-weight: 800; }
214 |
215 | .navbar-sidenav-tooltip.show {
216 | display: none; }
217 |
218 | @media (min-width: 992px) {
219 | body.sidenav-toggled .content-wrapper {
220 | margin-left: 55px; } }
221 |
222 | body.sidenav-toggled .navbar-sidenav {
223 | overflow-x: hidden;
224 | width: 55px; }
225 | body.sidenav-toggled .navbar-sidenav .nav-link-text {
226 | display: none; }
227 | body.sidenav-toggled .navbar-sidenav .nav-item,
228 | body.sidenav-toggled .navbar-sidenav .nav-link {
229 | width: 55px !important; }
230 | body.sidenav-toggled .navbar-sidenav .nav-item:after,
231 | body.sidenav-toggled .navbar-sidenav .nav-link:after {
232 | display: none; }
233 |
234 | body.sidenav-toggled .navbar-sidenav-tooltip.show {
235 | display: flex; }
236 |
237 | #mainNav.navbar-dark .navbar-collapse .navbar-sidenav .nav-link-collapse:after {
238 | color: #868e96; }
239 |
240 | #mainNav.navbar-dark .navbar-collapse .navbar-sidenav > .nav-item > .nav-link {
241 | color: #868e96; }
242 | #mainNav.navbar-dark .navbar-collapse .navbar-sidenav > .nav-item > .nav-link:hover {
243 | color: #adb5bd; }
244 |
245 | #mainNav.navbar-dark .navbar-collapse .navbar-sidenav > .nav-item .sidenav-second-level > li > a,
246 | #mainNav.navbar-dark .navbar-collapse .navbar-sidenav > .nav-item .sidenav-third-level > li > a {
247 | color: #868e96; }
248 | #mainNav.navbar-dark .navbar-collapse .navbar-sidenav > .nav-item .sidenav-second-level > li > a:focus, #mainNav.navbar-dark .navbar-collapse .navbar-sidenav > .nav-item .sidenav-second-level > li > a:hover,
249 | #mainNav.navbar-dark .navbar-collapse .navbar-sidenav > .nav-item .sidenav-third-level > li > a:focus,
250 | #mainNav.navbar-dark .navbar-collapse .navbar-sidenav > .nav-item .sidenav-third-level > li > a:hover {
251 | color: #adb5bd; }
252 |
253 | #mainNav.navbar-dark .navbar-collapse .navbar-nav > .nav-item.dropdown > .nav-link:after {
254 | color: #adb5bd; }
255 |
256 | @media (min-width: 992px) {
257 | #mainNav.navbar-dark .navbar-collapse .navbar-sidenav {
258 | background: #343a40; }
259 | #mainNav.navbar-dark .navbar-collapse .navbar-sidenav li.active a {
260 | color: white !important;
261 | background-color: #495057; }
262 | #mainNav.navbar-dark .navbar-collapse .navbar-sidenav li.active a:focus, #mainNav.navbar-dark .navbar-collapse .navbar-sidenav li.active a:hover {
263 | color: white; }
264 | #mainNav.navbar-dark .navbar-collapse .navbar-sidenav > .nav-item .sidenav-second-level,
265 | #mainNav.navbar-dark .navbar-collapse .navbar-sidenav > .nav-item .sidenav-third-level {
266 | background: #343a40; } }
267 |
268 | #mainNav.navbar-light .navbar-collapse .navbar-sidenav .nav-link-collapse:after {
269 | color: rgba(0, 0, 0, 0.5); }
270 |
271 | #mainNav.navbar-light .navbar-collapse .navbar-sidenav > .nav-item > .nav-link {
272 | color: rgba(0, 0, 0, 0.5); }
273 | #mainNav.navbar-light .navbar-collapse .navbar-sidenav > .nav-item > .nav-link:hover {
274 | color: rgba(0, 0, 0, 0.7); }
275 |
276 | #mainNav.navbar-light .navbar-collapse .navbar-sidenav > .nav-item .sidenav-second-level > li > a,
277 | #mainNav.navbar-light .navbar-collapse .navbar-sidenav > .nav-item .sidenav-third-level > li > a {
278 | color: rgba(0, 0, 0, 0.5); }
279 | #mainNav.navbar-light .navbar-collapse .navbar-sidenav > .nav-item .sidenav-second-level > li > a:focus, #mainNav.navbar-light .navbar-collapse .navbar-sidenav > .nav-item .sidenav-second-level > li > a:hover,
280 | #mainNav.navbar-light .navbar-collapse .navbar-sidenav > .nav-item .sidenav-third-level > li > a:focus,
281 | #mainNav.navbar-light .navbar-collapse .navbar-sidenav > .nav-item .sidenav-third-level > li > a:hover {
282 | color: rgba(0, 0, 0, 0.7); }
283 |
284 | #mainNav.navbar-light .navbar-collapse .navbar-nav > .nav-item.dropdown > .nav-link:after {
285 | color: rgba(0, 0, 0, 0.5); }
286 |
287 | @media (min-width: 992px) {
288 | #mainNav.navbar-light .navbar-collapse .navbar-sidenav {
289 | background: #f8f9fa; }
290 | #mainNav.navbar-light .navbar-collapse .navbar-sidenav li.active a {
291 | color: #000 !important;
292 | background-color: #e9ecef; }
293 | #mainNav.navbar-light .navbar-collapse .navbar-sidenav li.active a:focus, #mainNav.navbar-light .navbar-collapse .navbar-sidenav li.active a:hover {
294 | color: #000; }
295 | #mainNav.navbar-light .navbar-collapse .navbar-sidenav > .nav-item .sidenav-second-level,
296 | #mainNav.navbar-light .navbar-collapse .navbar-sidenav > .nav-item .sidenav-third-level {
297 | background: #f8f9fa; } }
298 |
299 | .card-body-icon {
300 | position: absolute;
301 | z-index: 0;
302 | top: -25px;
303 | right: -25px;
304 | font-size: 5rem;
305 | -webkit-transform: rotate(15deg);
306 | -ms-transform: rotate(15deg);
307 | transform: rotate(15deg); }
308 |
309 | @media (min-width: 576px) {
310 | .card-columns {
311 | column-count: 1; } }
312 |
313 | @media (min-width: 768px) {
314 | .card-columns {
315 | column-count: 2; } }
316 |
317 | @media (min-width: 1200px) {
318 | .card-columns {
319 | column-count: 2; } }
320 |
321 | .card-login {
322 | max-width: 25rem; }
323 |
324 | .card-register {
325 | max-width: 40rem; }
326 |
327 | footer.sticky-footer {
328 | position: absolute;
329 | right: 0;
330 | bottom: 0;
331 | width: 100%;
332 | height: 56px;
333 | background-color: #e9ecef;
334 | line-height: 55px; }
335 | @media (min-width: 992px) {
336 | footer.sticky-footer {
337 | width: calc(100% - 250px); } }
338 |
339 | @media (min-width: 992px) {
340 | body.sidenav-toggled footer.sticky-footer {
341 | width: calc(100% - 55px); } }
--------------------------------------------------------------------------------
/public/scripts/popper.js:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright (C) Federico Zivolo 2017
3 | Distributed under the MIT License (license terms are at http://opensource.org/licenses/MIT).
4 | */(function(e,t){'object'==typeof exports&&'undefined'!=typeof module?module.exports=t():'function'==typeof define&&define.amd?define(t):e.Popper=t()})(this,function(){'use strict';function e(e){return e&&'[object Function]'==={}.toString.call(e)}function t(e,t){if(1!==e.nodeType)return[];var o=window.getComputedStyle(e,null);return t?o[t]:o}function o(e){return'HTML'===e.nodeName?e:e.parentNode||e.host}function n(e){if(!e||-1!==['HTML','BODY','#document'].indexOf(e.nodeName))return window.document.body;var i=t(e),r=i.overflow,p=i.overflowX,s=i.overflowY;return /(auto|scroll)/.test(r+s+p)?e:n(o(e))}function r(e){var o=e&&e.offsetParent,i=o&&o.nodeName;return i&&'BODY'!==i&&'HTML'!==i?-1!==['TD','TABLE'].indexOf(o.nodeName)&&'static'===t(o,'position')?r(o):o:window.document.documentElement}function p(e){var t=e.nodeName;return'BODY'!==t&&('HTML'===t||r(e.firstElementChild)===e)}function s(e){return null===e.parentNode?e:s(e.parentNode)}function d(e,t){if(!e||!e.nodeType||!t||!t.nodeType)return window.document.documentElement;var o=e.compareDocumentPosition(t)&Node.DOCUMENT_POSITION_FOLLOWING,i=o?e:t,n=o?t:e,a=document.createRange();a.setStart(i,0),a.setEnd(n,0);var f=a.commonAncestorContainer;if(e!==f&&t!==f||i.contains(n))return p(f)?f:r(f);var l=s(e);return l.host?d(l.host,t):d(e,s(t).host)}function a(e){var t=1=o.clientWidth&&i>=o.clientHeight}),f=0i[e]&&!t.escapeWithReference&&(n=z(p[o],i[e]-('right'===e?p.width:p.height))),pe({},o,n)}};return n.forEach(function(e){var t=-1===['left','top'].indexOf(e)?'secondary':'primary';p=se({},p,s[t](e))}),e.offsets.popper=p,e},priority:['left','right','top','bottom'],padding:5,boundariesElement:'scrollParent'},keepTogether:{order:400,enabled:!0,fn:function(e){var t=e.offsets,o=t.popper,i=t.reference,n=e.placement.split('-')[0],r=V,p=-1!==['top','bottom'].indexOf(n),s=p?'right':'bottom',d=p?'left':'top',a=p?'width':'height';return o[s]r(i[s])&&(e.offsets.popper[d]=r(i[s])),e}},arrow:{order:500,enabled:!0,fn:function(e,t){if(!F(e.instance.modifiers,'arrow','keepTogether'))return e;var o=t.element;if('string'==typeof o){if(o=e.instance.popper.querySelector(o),!o)return e;}else if(!e.instance.popper.contains(o))return console.warn('WARNING: `arrow.element` must be child of its popper element!'),e;var i=e.placement.split('-')[0],n=e.offsets,r=n.popper,p=n.reference,s=-1!==['left','right'].indexOf(i),d=s?'height':'width',a=s?'top':'left',f=s?'left':'top',l=s?'bottom':'right',m=O(o)[d];p[l]-mr[l]&&(e.offsets.popper[a]+=p[a]+m-r[l]);var h=p[a]+p[d]/2-m/2,g=h-c(e.offsets.popper)[a];return g=_(z(r[d]-m,g),0),e.arrowElement=o,e.offsets.arrow={},e.offsets.arrow[a]=Math.round(g),e.offsets.arrow[f]='',e},element:'[x-arrow]'},flip:{order:600,enabled:!0,fn:function(e,t){if(W(e.instance.modifiers,'inner'))return e;if(e.flipped&&e.placement===e.originalPlacement)return e;var o=w(e.instance.popper,e.instance.reference,t.padding,t.boundariesElement),i=e.placement.split('-')[0],n=L(i),r=e.placement.split('-')[1]||'',p=[];switch(t.behavior){case fe.FLIP:p=[i,n];break;case fe.CLOCKWISE:p=K(i);break;case fe.COUNTERCLOCKWISE:p=K(i,!0);break;default:p=t.behavior;}return p.forEach(function(s,d){if(i!==s||p.length===d+1)return e;i=e.placement.split('-')[0],n=L(i);var a=e.offsets.popper,f=e.offsets.reference,l=V,m='left'===i&&l(a.right)>l(f.left)||'right'===i&&l(a.left)l(f.top)||'bottom'===i&&l(a.top)l(o.right),g=l(a.top)l(o.bottom),b='left'===i&&h||'right'===i&&c||'top'===i&&g||'bottom'===i&&u,y=-1!==['top','bottom'].indexOf(i),w=!!t.flipVariations&&(y&&'start'===r&&h||y&&'end'===r&&c||!y&&'start'===r&&g||!y&&'end'===r&&u);(m||b||w)&&(e.flipped=!0,(m||b)&&(i=p[d+1]),w&&(r=j(r)),e.placement=i+(r?'-'+r:''),e.offsets.popper=se({},e.offsets.popper,S(e.instance.popper,e.offsets.reference,e.placement)),e=N(e.instance.modifiers,e,'flip'))}),e},behavior:'flip',padding:5,boundariesElement:'viewport'},inner:{order:700,enabled:!1,fn:function(e){var t=e.placement,o=t.split('-')[0],i=e.offsets,n=i.popper,r=i.reference,p=-1!==['left','right'].indexOf(o),s=-1===['top','left'].indexOf(o);return n[p?'left':'top']=r[t]-(s?n[p?'width':'height']:0),e.placement=L(t),e.offsets.popper=c(n),e}},hide:{order:800,enabled:!0,fn:function(e){if(!F(e.instance.modifiers,'hide','preventOverflow'))return e;var t=e.offsets.reference,o=T(e.instance.modifiers,function(e){return'preventOverflow'===e.name}).boundaries;if(t.bottomo.right||t.top>o.bottom||t.right=4)throw new Error("Bootstrap's JavaScript requires at least jQuery v1.9.1 but less than v4.0.0")}(),function(){function t(t,e){if(!t)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!e||"object"!=typeof e&&"function"!=typeof e?t:e}function e(t,e){if("function"!=typeof e&&null!==e)throw new TypeError("Super expression must either be null or a function, not "+typeof e);t.prototype=Object.create(e&&e.prototype,{constructor:{value:t,enumerable:!1,writable:!0,configurable:!0}}),e&&(Object.setPrototypeOf?Object.setPrototypeOf(t,e):t.__proto__=e)}function n(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}var i="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t},o=function(){function t(t,e){for(var n=0;n0?n:null}catch(t){return null}},reflow:function(t){return t.offsetHeight},triggerTransitionEnd:function(e){t(e).trigger(s.end)},supportsTransitionEnd:function(){return Boolean(s)},typeCheckConfig:function(t,i,o){for(var r in o)if(o.hasOwnProperty(r)){var s=o[r],a=i[r],l=a&&n(a)?"element":e(a);if(!new RegExp(s).test(l))throw new Error(t.toUpperCase()+': Option "'+r+'" provided type "'+l+'" but expected type "'+s+'".')}}};return s=o(),t.fn.emulateTransitionEnd=r,l.supportsTransitionEnd()&&(t.event.special[l.TRANSITION_END]=i()),l}(jQuery),s=(function(t){var e="alert",i=t.fn[e],s={DISMISS:'[data-dismiss="alert"]'},a={CLOSE:"close.bs.alert",CLOSED:"closed.bs.alert",CLICK_DATA_API:"click.bs.alert.data-api"},l={ALERT:"alert",FADE:"fade",SHOW:"show"},h=function(){function e(t){n(this,e),this._element=t}return e.prototype.close=function(t){t=t||this._element;var e=this._getRootElement(t);this._triggerCloseEvent(e).isDefaultPrevented()||this._removeElement(e)},e.prototype.dispose=function(){t.removeData(this._element,"bs.alert"),this._element=null},e.prototype._getRootElement=function(e){var n=r.getSelectorFromElement(e),i=!1;return n&&(i=t(n)[0]),i||(i=t(e).closest("."+l.ALERT)[0]),i},e.prototype._triggerCloseEvent=function(e){var n=t.Event(a.CLOSE);return t(e).trigger(n),n},e.prototype._removeElement=function(e){var n=this;t(e).removeClass(l.SHOW),r.supportsTransitionEnd()&&t(e).hasClass(l.FADE)?t(e).one(r.TRANSITION_END,function(t){return n._destroyElement(e,t)}).emulateTransitionEnd(150):this._destroyElement(e)},e.prototype._destroyElement=function(e){t(e).detach().trigger(a.CLOSED).remove()},e._jQueryInterface=function(n){return this.each(function(){var i=t(this),o=i.data("bs.alert");o||(o=new e(this),i.data("bs.alert",o)),"close"===n&&o[n](this)})},e._handleDismiss=function(t){return function(e){e&&e.preventDefault(),t.close(this)}},o(e,null,[{key:"VERSION",get:function(){return"4.0.0-beta"}}]),e}();t(document).on(a.CLICK_DATA_API,s.DISMISS,h._handleDismiss(new h)),t.fn[e]=h._jQueryInterface,t.fn[e].Constructor=h,t.fn[e].noConflict=function(){return t.fn[e]=i,h._jQueryInterface}}(jQuery),function(t){var e="button",i=t.fn[e],r={ACTIVE:"active",BUTTON:"btn",FOCUS:"focus"},s={DATA_TOGGLE_CARROT:'[data-toggle^="button"]',DATA_TOGGLE:'[data-toggle="buttons"]',INPUT:"input",ACTIVE:".active",BUTTON:".btn"},a={CLICK_DATA_API:"click.bs.button.data-api",FOCUS_BLUR_DATA_API:"focus.bs.button.data-api blur.bs.button.data-api"},l=function(){function e(t){n(this,e),this._element=t}return e.prototype.toggle=function(){var e=!0,n=!0,i=t(this._element).closest(s.DATA_TOGGLE)[0];if(i){var o=t(this._element).find(s.INPUT)[0];if(o){if("radio"===o.type)if(o.checked&&t(this._element).hasClass(r.ACTIVE))e=!1;else{var a=t(i).find(s.ACTIVE)[0];a&&t(a).removeClass(r.ACTIVE)}if(e){if(o.hasAttribute("disabled")||i.hasAttribute("disabled")||o.classList.contains("disabled")||i.classList.contains("disabled"))return;o.checked=!t(this._element).hasClass(r.ACTIVE),t(o).trigger("change")}o.focus(),n=!1}}n&&this._element.setAttribute("aria-pressed",!t(this._element).hasClass(r.ACTIVE)),e&&t(this._element).toggleClass(r.ACTIVE)},e.prototype.dispose=function(){t.removeData(this._element,"bs.button"),this._element=null},e._jQueryInterface=function(n){return this.each(function(){var i=t(this).data("bs.button");i||(i=new e(this),t(this).data("bs.button",i)),"toggle"===n&&i[n]()})},o(e,null,[{key:"VERSION",get:function(){return"4.0.0-beta"}}]),e}();t(document).on(a.CLICK_DATA_API,s.DATA_TOGGLE_CARROT,function(e){e.preventDefault();var n=e.target;t(n).hasClass(r.BUTTON)||(n=t(n).closest(s.BUTTON)),l._jQueryInterface.call(t(n),"toggle")}).on(a.FOCUS_BLUR_DATA_API,s.DATA_TOGGLE_CARROT,function(e){var n=t(e.target).closest(s.BUTTON)[0];t(n).toggleClass(r.FOCUS,/^focus(in)?$/.test(e.type))}),t.fn[e]=l._jQueryInterface,t.fn[e].Constructor=l,t.fn[e].noConflict=function(){return t.fn[e]=i,l._jQueryInterface}}(jQuery),function(t){var e="carousel",s="bs.carousel",a="."+s,l=t.fn[e],h={interval:5e3,keyboard:!0,slide:!1,pause:"hover",wrap:!0},c={interval:"(number|boolean)",keyboard:"boolean",slide:"(boolean|string)",pause:"(string|boolean)",wrap:"boolean"},u={NEXT:"next",PREV:"prev",LEFT:"left",RIGHT:"right"},d={SLIDE:"slide"+a,SLID:"slid"+a,KEYDOWN:"keydown"+a,MOUSEENTER:"mouseenter"+a,MOUSELEAVE:"mouseleave"+a,TOUCHEND:"touchend"+a,LOAD_DATA_API:"load.bs.carousel.data-api",CLICK_DATA_API:"click.bs.carousel.data-api"},f={CAROUSEL:"carousel",ACTIVE:"active",SLIDE:"slide",RIGHT:"carousel-item-right",LEFT:"carousel-item-left",NEXT:"carousel-item-next",PREV:"carousel-item-prev",ITEM:"carousel-item"},p={ACTIVE:".active",ACTIVE_ITEM:".active.carousel-item",ITEM:".carousel-item",NEXT_PREV:".carousel-item-next, .carousel-item-prev",INDICATORS:".carousel-indicators",DATA_SLIDE:"[data-slide], [data-slide-to]",DATA_RIDE:'[data-ride="carousel"]'},_=function(){function l(e,i){n(this,l),this._items=null,this._interval=null,this._activeElement=null,this._isPaused=!1,this._isSliding=!1,this.touchTimeout=null,this._config=this._getConfig(i),this._element=t(e)[0],this._indicatorsElement=t(this._element).find(p.INDICATORS)[0],this._addEventListeners()}return l.prototype.next=function(){this._isSliding||this._slide(u.NEXT)},l.prototype.nextWhenVisible=function(){document.hidden||this.next()},l.prototype.prev=function(){this._isSliding||this._slide(u.PREV)},l.prototype.pause=function(e){e||(this._isPaused=!0),t(this._element).find(p.NEXT_PREV)[0]&&r.supportsTransitionEnd()&&(r.triggerTransitionEnd(this._element),this.cycle(!0)),clearInterval(this._interval),this._interval=null},l.prototype.cycle=function(t){t||(this._isPaused=!1),this._interval&&(clearInterval(this._interval),this._interval=null),this._config.interval&&!this._isPaused&&(this._interval=setInterval((document.visibilityState?this.nextWhenVisible:this.next).bind(this),this._config.interval))},l.prototype.to=function(e){var n=this;this._activeElement=t(this._element).find(p.ACTIVE_ITEM)[0];var i=this._getItemIndex(this._activeElement);if(!(e>this._items.length-1||e<0))if(this._isSliding)t(this._element).one(d.SLID,function(){return n.to(e)});else{if(i===e)return this.pause(),void this.cycle();var o=e>i?u.NEXT:u.PREV;this._slide(o,this._items[e])}},l.prototype.dispose=function(){t(this._element).off(a),t.removeData(this._element,s),this._items=null,this._config=null,this._element=null,this._interval=null,this._isPaused=null,this._isSliding=null,this._activeElement=null,this._indicatorsElement=null},l.prototype._getConfig=function(n){return n=t.extend({},h,n),r.typeCheckConfig(e,n,c),n},l.prototype._addEventListeners=function(){var e=this;this._config.keyboard&&t(this._element).on(d.KEYDOWN,function(t){return e._keydown(t)}),"hover"===this._config.pause&&(t(this._element).on(d.MOUSEENTER,function(t){return e.pause(t)}).on(d.MOUSELEAVE,function(t){return e.cycle(t)}),"ontouchstart"in document.documentElement&&t(this._element).on(d.TOUCHEND,function(){e.pause(),e.touchTimeout&&clearTimeout(e.touchTimeout),e.touchTimeout=setTimeout(function(t){return e.cycle(t)},500+e._config.interval)}))},l.prototype._keydown=function(t){if(!/input|textarea/i.test(t.target.tagName))switch(t.which){case 37:t.preventDefault(),this.prev();break;case 39:t.preventDefault(),this.next();break;default:return}},l.prototype._getItemIndex=function(e){return this._items=t.makeArray(t(e).parent().find(p.ITEM)),this._items.indexOf(e)},l.prototype._getItemByDirection=function(t,e){var n=t===u.NEXT,i=t===u.PREV,o=this._getItemIndex(e),r=this._items.length-1;if((i&&0===o||n&&o===r)&&!this._config.wrap)return e;var s=(o+(t===u.PREV?-1:1))%this._items.length;return-1===s?this._items[this._items.length-1]:this._items[s]},l.prototype._triggerSlideEvent=function(e,n){var i=this._getItemIndex(e),o=this._getItemIndex(t(this._element).find(p.ACTIVE_ITEM)[0]),r=t.Event(d.SLIDE,{relatedTarget:e,direction:n,from:o,to:i});return t(this._element).trigger(r),r},l.prototype._setActiveIndicatorElement=function(e){if(this._indicatorsElement){t(this._indicatorsElement).find(p.ACTIVE).removeClass(f.ACTIVE);var n=this._indicatorsElement.children[this._getItemIndex(e)];n&&t(n).addClass(f.ACTIVE)}},l.prototype._slide=function(e,n){var i=this,o=t(this._element).find(p.ACTIVE_ITEM)[0],s=this._getItemIndex(o),a=n||o&&this._getItemByDirection(e,o),l=this._getItemIndex(a),h=Boolean(this._interval),c=void 0,_=void 0,g=void 0;if(e===u.NEXT?(c=f.LEFT,_=f.NEXT,g=u.LEFT):(c=f.RIGHT,_=f.PREV,g=u.RIGHT),a&&t(a).hasClass(f.ACTIVE))this._isSliding=!1;else if(!this._triggerSlideEvent(a,g).isDefaultPrevented()&&o&&a){this._isSliding=!0,h&&this.pause(),this._setActiveIndicatorElement(a);var m=t.Event(d.SLID,{relatedTarget:a,direction:g,from:s,to:l});r.supportsTransitionEnd()&&t(this._element).hasClass(f.SLIDE)?(t(a).addClass(_),r.reflow(a),t(o).addClass(c),t(a).addClass(c),t(o).one(r.TRANSITION_END,function(){t(a).removeClass(c+" "+_).addClass(f.ACTIVE),t(o).removeClass(f.ACTIVE+" "+_+" "+c),i._isSliding=!1,setTimeout(function(){return t(i._element).trigger(m)},0)}).emulateTransitionEnd(600)):(t(o).removeClass(f.ACTIVE),t(a).addClass(f.ACTIVE),this._isSliding=!1,t(this._element).trigger(m)),h&&this.cycle()}},l._jQueryInterface=function(e){return this.each(function(){var n=t(this).data(s),o=t.extend({},h,t(this).data());"object"===(void 0===e?"undefined":i(e))&&t.extend(o,e);var r="string"==typeof e?e:o.slide;if(n||(n=new l(this,o),t(this).data(s,n)),"number"==typeof e)n.to(e);else if("string"==typeof r){if(void 0===n[r])throw new Error('No method named "'+r+'"');n[r]()}else o.interval&&(n.pause(),n.cycle())})},l._dataApiClickHandler=function(e){var n=r.getSelectorFromElement(this);if(n){var i=t(n)[0];if(i&&t(i).hasClass(f.CAROUSEL)){var o=t.extend({},t(i).data(),t(this).data()),a=this.getAttribute("data-slide-to");a&&(o.interval=!1),l._jQueryInterface.call(t(i),o),a&&t(i).data(s).to(a),e.preventDefault()}}},o(l,null,[{key:"VERSION",get:function(){return"4.0.0-beta"}},{key:"Default",get:function(){return h}}]),l}();t(document).on(d.CLICK_DATA_API,p.DATA_SLIDE,_._dataApiClickHandler),t(window).on(d.LOAD_DATA_API,function(){t(p.DATA_RIDE).each(function(){var e=t(this);_._jQueryInterface.call(e,e.data())})}),t.fn[e]=_._jQueryInterface,t.fn[e].Constructor=_,t.fn[e].noConflict=function(){return t.fn[e]=l,_._jQueryInterface}}(jQuery),function(t){var e="collapse",s="bs.collapse",a=t.fn[e],l={toggle:!0,parent:""},h={toggle:"boolean",parent:"string"},c={SHOW:"show.bs.collapse",SHOWN:"shown.bs.collapse",HIDE:"hide.bs.collapse",HIDDEN:"hidden.bs.collapse",CLICK_DATA_API:"click.bs.collapse.data-api"},u={SHOW:"show",COLLAPSE:"collapse",COLLAPSING:"collapsing",COLLAPSED:"collapsed"},d={WIDTH:"width",HEIGHT:"height"},f={ACTIVES:".show, .collapsing",DATA_TOGGLE:'[data-toggle="collapse"]'},p=function(){function a(e,i){n(this,a),this._isTransitioning=!1,this._element=e,this._config=this._getConfig(i),this._triggerArray=t.makeArray(t('[data-toggle="collapse"][href="#'+e.id+'"],[data-toggle="collapse"][data-target="#'+e.id+'"]'));for(var o=t(f.DATA_TOGGLE),s=0;s0&&this._triggerArray.push(l)}this._parent=this._config.parent?this._getParent():null,this._config.parent||this._addAriaAndCollapsedClass(this._element,this._triggerArray),this._config.toggle&&this.toggle()}return a.prototype.toggle=function(){t(this._element).hasClass(u.SHOW)?this.hide():this.show()},a.prototype.show=function(){var e=this;if(!this._isTransitioning&&!t(this._element).hasClass(u.SHOW)){var n=void 0,i=void 0;if(this._parent&&((n=t.makeArray(t(this._parent).children().children(f.ACTIVES))).length||(n=null)),!(n&&(i=t(n).data(s))&&i._isTransitioning)){var o=t.Event(c.SHOW);if(t(this._element).trigger(o),!o.isDefaultPrevented()){n&&(a._jQueryInterface.call(t(n),"hide"),i||t(n).data(s,null));var l=this._getDimension();t(this._element).removeClass(u.COLLAPSE).addClass(u.COLLAPSING),this._element.style[l]=0,this._triggerArray.length&&t(this._triggerArray).removeClass(u.COLLAPSED).attr("aria-expanded",!0),this.setTransitioning(!0);var h=function(){t(e._element).removeClass(u.COLLAPSING).addClass(u.COLLAPSE).addClass(u.SHOW),e._element.style[l]="",e.setTransitioning(!1),t(e._element).trigger(c.SHOWN)};if(r.supportsTransitionEnd()){var d="scroll"+(l[0].toUpperCase()+l.slice(1));t(this._element).one(r.TRANSITION_END,h).emulateTransitionEnd(600),this._element.style[l]=this._element[d]+"px"}else h()}}}},a.prototype.hide=function(){var e=this;if(!this._isTransitioning&&t(this._element).hasClass(u.SHOW)){var n=t.Event(c.HIDE);if(t(this._element).trigger(n),!n.isDefaultPrevented()){var i=this._getDimension();if(this._element.style[i]=this._element.getBoundingClientRect()[i]+"px",r.reflow(this._element),t(this._element).addClass(u.COLLAPSING).removeClass(u.COLLAPSE).removeClass(u.SHOW),this._triggerArray.length)for(var o=0;o0},l.prototype._getPopperConfig=function(){var t={placement:this._getPlacement(),modifiers:{offset:{offset:this._config.offset},flip:{enabled:this._config.flip}}};return this._inNavbar&&(t.modifiers.applyStyle={enabled:!this._inNavbar}),t},l._jQueryInterface=function(e){return this.each(function(){var n=t(this).data(s),o="object"===(void 0===e?"undefined":i(e))?e:null;if(n||(n=new l(this,o),t(this).data(s,n)),"string"==typeof e){if(void 0===n[e])throw new Error('No method named "'+e+'"');n[e]()}})},l._clearMenus=function(e){if(!e||3!==e.which&&("keyup"!==e.type||9===e.which))for(var n=t.makeArray(t(d.DATA_TOGGLE)),i=0;i0&&r--,40===e.which&&rdocument.documentElement.clientHeight;!this._isBodyOverflowing&&t&&(this._element.style.paddingLeft=this._scrollbarWidth+"px"),this._isBodyOverflowing&&!t&&(this._element.style.paddingRight=this._scrollbarWidth+"px")},a.prototype._resetAdjustments=function(){this._element.style.paddingLeft="",this._element.style.paddingRight=""},a.prototype._checkScrollbar=function(){this._isBodyOverflowing=document.body.clientWidth=n){var i=this._targets[this._targets.length-1];this._activeTarget!==i&&this._activate(i)}else{if(this._activeTarget&&t0)return this._activeTarget=null,void this._clear();for(var o=this._offsets.length;o--;)this._activeTarget!==this._targets[o]&&t>=this._offsets[o]&&(void 0===this._offsets[o+1]||t .dropdown-menu .active"},l=function(){function e(t){n(this,e),this._element=t}return e.prototype.show=function(){var e=this;if(!(this._element.parentNode&&this._element.parentNode.nodeType===Node.ELEMENT_NODE&&t(this._element).hasClass(s.ACTIVE)||t(this._element).hasClass(s.DISABLED))){var n=void 0,o=void 0,l=t(this._element).closest(a.NAV_LIST_GROUP)[0],h=r.getSelectorFromElement(this._element);l&&(o=t.makeArray(t(l).find(a.ACTIVE)),o=o[o.length-1]);var c=t.Event(i.HIDE,{relatedTarget:this._element}),u=t.Event(i.SHOW,{relatedTarget:o});if(o&&t(o).trigger(c),t(this._element).trigger(u),!u.isDefaultPrevented()&&!c.isDefaultPrevented()){h&&(n=t(h)[0]),this._activate(this._element,l);var d=function(){var n=t.Event(i.HIDDEN,{relatedTarget:e._element}),r=t.Event(i.SHOWN,{relatedTarget:o});t(o).trigger(n),t(e._element).trigger(r)};n?this._activate(n,n.parentNode,d):d()}}},e.prototype.dispose=function(){t.removeData(this._element,"bs.tab"),this._element=null},e.prototype._activate=function(e,n,i){var o=this,l=t(n).find(a.ACTIVE)[0],h=i&&r.supportsTransitionEnd()&&l&&t(l).hasClass(s.FADE),c=function(){return o._transitionComplete(e,l,h,i)};l&&h?t(l).one(r.TRANSITION_END,c).emulateTransitionEnd(150):c(),l&&t(l).removeClass(s.SHOW)},e.prototype._transitionComplete=function(e,n,i,o){if(n){t(n).removeClass(s.ACTIVE);var l=t(n.parentNode).find(a.DROPDOWN_ACTIVE_CHILD)[0];l&&t(l).removeClass(s.ACTIVE),n.setAttribute("aria-expanded",!1)}if(t(e).addClass(s.ACTIVE),e.setAttribute("aria-expanded",!0),i?(r.reflow(e),t(e).addClass(s.SHOW)):t(e).removeClass(s.FADE),e.parentNode&&t(e.parentNode).hasClass(s.DROPDOWN_MENU)){var h=t(e).closest(a.DROPDOWN)[0];h&&t(h).find(a.DROPDOWN_TOGGLE).addClass(s.ACTIVE),e.setAttribute("aria-expanded",!0)}o&&o()},e._jQueryInterface=function(n){return this.each(function(){var i=t(this),o=i.data("bs.tab");if(o||(o=new e(this),i.data("bs.tab",o)),"string"==typeof n){if(void 0===o[n])throw new Error('No method named "'+n+'"');o[n]()}})},o(e,null,[{key:"VERSION",get:function(){return"4.0.0-beta"}}]),e}();t(document).on(i.CLICK_DATA_API,a.DATA_TOGGLE,function(e){e.preventDefault(),l._jQueryInterface.call(t(this),"show")}),t.fn.tab=l._jQueryInterface,t.fn.tab.Constructor=l,t.fn.tab.noConflict=function(){return t.fn.tab=e,l._jQueryInterface}}(jQuery),function(t){if("undefined"==typeof Popper)throw new Error("Bootstrap tooltips require Popper.js (https://popper.js.org)");var e="tooltip",s=".bs.tooltip",a=t.fn[e],l=new RegExp("(^|\\s)bs-tooltip\\S+","g"),h={animation:"boolean",template:"string",title:"(string|element|function)",trigger:"string",delay:"(number|object)",html:"boolean",selector:"(string|boolean)",placement:"(string|function)",offset:"(number|string)",container:"(string|element|boolean)",fallbackPlacement:"(string|array)"},c={AUTO:"auto",TOP:"top",RIGHT:"right",BOTTOM:"bottom",LEFT:"left"},u={animation:!0,template:'',trigger:"hover focus",title:"",delay:0,html:!1,selector:!1,placement:"top",offset:0,container:!1,fallbackPlacement:"flip"},d={SHOW:"show",OUT:"out"},f={HIDE:"hide"+s,HIDDEN:"hidden"+s,SHOW:"show"+s,SHOWN:"shown"+s,INSERTED:"inserted"+s,CLICK:"click"+s,FOCUSIN:"focusin"+s,FOCUSOUT:"focusout"+s,MOUSEENTER:"mouseenter"+s,MOUSELEAVE:"mouseleave"+s},p={FADE:"fade",SHOW:"show"},_={TOOLTIP:".tooltip",TOOLTIP_INNER:".tooltip-inner",ARROW:".arrow"},g={HOVER:"hover",FOCUS:"focus",CLICK:"click",MANUAL:"manual"},m=function(){function a(t,e){n(this,a),this._isEnabled=!0,this._timeout=0,this._hoverState="",this._activeTrigger={},this._popper=null,this.element=t,this.config=this._getConfig(e),this.tip=null,this._setListeners()}return a.prototype.enable=function(){this._isEnabled=!0},a.prototype.disable=function(){this._isEnabled=!1},a.prototype.toggleEnabled=function(){this._isEnabled=!this._isEnabled},a.prototype.toggle=function(e){if(e){var n=this.constructor.DATA_KEY,i=t(e.currentTarget).data(n);i||(i=new this.constructor(e.currentTarget,this._getDelegateConfig()),t(e.currentTarget).data(n,i)),i._activeTrigger.click=!i._activeTrigger.click,i._isWithActiveTrigger()?i._enter(null,i):i._leave(null,i)}else{if(t(this.getTipElement()).hasClass(p.SHOW))return void this._leave(null,this);this._enter(null,this)}},a.prototype.dispose=function(){clearTimeout(this._timeout),t.removeData(this.element,this.constructor.DATA_KEY),t(this.element).off(this.constructor.EVENT_KEY),t(this.element).closest(".modal").off("hide.bs.modal"),this.tip&&t(this.tip).remove(),this._isEnabled=null,this._timeout=null,this._hoverState=null,this._activeTrigger=null,null!==this._popper&&this._popper.destroy(),this._popper=null,this.element=null,this.config=null,this.tip=null},a.prototype.show=function(){var e=this;if("none"===t(this.element).css("display"))throw new Error("Please use show on visible elements");var n=t.Event(this.constructor.Event.SHOW);if(this.isWithContent()&&this._isEnabled){t(this.element).trigger(n);var i=t.contains(this.element.ownerDocument.documentElement,this.element);if(n.isDefaultPrevented()||!i)return;var o=this.getTipElement(),s=r.getUID(this.constructor.NAME);o.setAttribute("id",s),this.element.setAttribute("aria-describedby",s),this.setContent(),this.config.animation&&t(o).addClass(p.FADE);var l="function"==typeof this.config.placement?this.config.placement.call(this,o,this.element):this.config.placement,h=this._getAttachment(l);this.addAttachmentClass(h);var c=!1===this.config.container?document.body:t(this.config.container);t(o).data(this.constructor.DATA_KEY,this),t.contains(this.element.ownerDocument.documentElement,this.tip)||t(o).appendTo(c),t(this.element).trigger(this.constructor.Event.INSERTED),this._popper=new Popper(this.element,o,{placement:h,modifiers:{offset:{offset:this.config.offset},flip:{behavior:this.config.fallbackPlacement},arrow:{element:_.ARROW}},onCreate:function(t){t.originalPlacement!==t.placement&&e._handlePopperPlacementChange(t)},onUpdate:function(t){e._handlePopperPlacementChange(t)}}),t(o).addClass(p.SHOW),"ontouchstart"in document.documentElement&&t("body").children().on("mouseover",null,t.noop);var u=function(){e.config.animation&&e._fixTransition();var n=e._hoverState;e._hoverState=null,t(e.element).trigger(e.constructor.Event.SHOWN),n===d.OUT&&e._leave(null,e)};r.supportsTransitionEnd()&&t(this.tip).hasClass(p.FADE)?t(this.tip).one(r.TRANSITION_END,u).emulateTransitionEnd(a._TRANSITION_DURATION):u()}},a.prototype.hide=function(e){var n=this,i=this.getTipElement(),o=t.Event(this.constructor.Event.HIDE),s=function(){n._hoverState!==d.SHOW&&i.parentNode&&i.parentNode.removeChild(i),n._cleanTipClass(),n.element.removeAttribute("aria-describedby"),t(n.element).trigger(n.constructor.Event.HIDDEN),null!==n._popper&&n._popper.destroy(),e&&e()};t(this.element).trigger(o),o.isDefaultPrevented()||(t(i).removeClass(p.SHOW),"ontouchstart"in document.documentElement&&t("body").children().off("mouseover",null,t.noop),this._activeTrigger[g.CLICK]=!1,this._activeTrigger[g.FOCUS]=!1,this._activeTrigger[g.HOVER]=!1,r.supportsTransitionEnd()&&t(this.tip).hasClass(p.FADE)?t(i).one(r.TRANSITION_END,s).emulateTransitionEnd(150):s(),this._hoverState="")},a.prototype.update=function(){null!==this._popper&&this._popper.scheduleUpdate()},a.prototype.isWithContent=function(){return Boolean(this.getTitle())},a.prototype.addAttachmentClass=function(e){t(this.getTipElement()).addClass("bs-tooltip-"+e)},a.prototype.getTipElement=function(){return this.tip=this.tip||t(this.config.template)[0]},a.prototype.setContent=function(){var e=t(this.getTipElement());this.setElementContent(e.find(_.TOOLTIP_INNER),this.getTitle()),e.removeClass(p.FADE+" "+p.SHOW)},a.prototype.setElementContent=function(e,n){var o=this.config.html;"object"===(void 0===n?"undefined":i(n))&&(n.nodeType||n.jquery)?o?t(n).parent().is(e)||e.empty().append(n):e.text(t(n).text()):e[o?"html":"text"](n)},a.prototype.getTitle=function(){var t=this.element.getAttribute("data-original-title");return t||(t="function"==typeof this.config.title?this.config.title.call(this.element):this.config.title),t},a.prototype._getAttachment=function(t){return c[t.toUpperCase()]},a.prototype._setListeners=function(){var e=this;this.config.trigger.split(" ").forEach(function(n){if("click"===n)t(e.element).on(e.constructor.Event.CLICK,e.config.selector,function(t){return e.toggle(t)});else if(n!==g.MANUAL){var i=n===g.HOVER?e.constructor.Event.MOUSEENTER:e.constructor.Event.FOCUSIN,o=n===g.HOVER?e.constructor.Event.MOUSELEAVE:e.constructor.Event.FOCUSOUT;t(e.element).on(i,e.config.selector,function(t){return e._enter(t)}).on(o,e.config.selector,function(t){return e._leave(t)})}t(e.element).closest(".modal").on("hide.bs.modal",function(){return e.hide()})}),this.config.selector?this.config=t.extend({},this.config,{trigger:"manual",selector:""}):this._fixTitle()},a.prototype._fixTitle=function(){var t=i(this.element.getAttribute("data-original-title"));(this.element.getAttribute("title")||"string"!==t)&&(this.element.setAttribute("data-original-title",this.element.getAttribute("title")||""),this.element.setAttribute("title",""))},a.prototype._enter=function(e,n){var i=this.constructor.DATA_KEY;(n=n||t(e.currentTarget).data(i))||(n=new this.constructor(e.currentTarget,this._getDelegateConfig()),t(e.currentTarget).data(i,n)),e&&(n._activeTrigger["focusin"===e.type?g.FOCUS:g.HOVER]=!0),t(n.getTipElement()).hasClass(p.SHOW)||n._hoverState===d.SHOW?n._hoverState=d.SHOW:(clearTimeout(n._timeout),n._hoverState=d.SHOW,n.config.delay&&n.config.delay.show?n._timeout=setTimeout(function(){n._hoverState===d.SHOW&&n.show()},n.config.delay.show):n.show())},a.prototype._leave=function(e,n){var i=this.constructor.DATA_KEY;(n=n||t(e.currentTarget).data(i))||(n=new this.constructor(e.currentTarget,this._getDelegateConfig()),t(e.currentTarget).data(i,n)),e&&(n._activeTrigger["focusout"===e.type?g.FOCUS:g.HOVER]=!1),n._isWithActiveTrigger()||(clearTimeout(n._timeout),n._hoverState=d.OUT,n.config.delay&&n.config.delay.hide?n._timeout=setTimeout(function(){n._hoverState===d.OUT&&n.hide()},n.config.delay.hide):n.hide())},a.prototype._isWithActiveTrigger=function(){for(var t in this._activeTrigger)if(this._activeTrigger[t])return!0;return!1},a.prototype._getConfig=function(n){return(n=t.extend({},this.constructor.Default,t(this.element).data(),n)).delay&&"number"==typeof n.delay&&(n.delay={show:n.delay,hide:n.delay}),n.title&&"number"==typeof n.title&&(n.title=n.title.toString()),n.content&&"number"==typeof n.content&&(n.content=n.content.toString()),r.typeCheckConfig(e,n,this.constructor.DefaultType),n},a.prototype._getDelegateConfig=function(){var t={};if(this.config)for(var e in this.config)this.constructor.Default[e]!==this.config[e]&&(t[e]=this.config[e]);return t},a.prototype._cleanTipClass=function(){var e=t(this.getTipElement()),n=e.attr("class").match(l);null!==n&&n.length>0&&e.removeClass(n.join(""))},a.prototype._handlePopperPlacementChange=function(t){this._cleanTipClass(),this.addAttachmentClass(this._getAttachment(t.placement))},a.prototype._fixTransition=function(){var e=this.getTipElement(),n=this.config.animation;null===e.getAttribute("x-placement")&&(t(e).removeClass(p.FADE),this.config.animation=!1,this.hide(),this.show(),this.config.animation=n)},a._jQueryInterface=function(e){return this.each(function(){var n=t(this).data("bs.tooltip"),o="object"===(void 0===e?"undefined":i(e))&&e;if((n||!/dispose|hide/.test(e))&&(n||(n=new a(this,o),t(this).data("bs.tooltip",n)),"string"==typeof e)){if(void 0===n[e])throw new Error('No method named "'+e+'"');n[e]()}})},o(a,null,[{key:"VERSION",get:function(){return"4.0.0-beta"}},{key:"Default",get:function(){return u}},{key:"NAME",get:function(){return e}},{key:"DATA_KEY",get:function(){return"bs.tooltip"}},{key:"Event",get:function(){return f}},{key:"EVENT_KEY",get:function(){return s}},{key:"DefaultType",get:function(){return h}}]),a}();return t.fn[e]=m._jQueryInterface,t.fn[e].Constructor=m,t.fn[e].noConflict=function(){return t.fn[e]=a,m._jQueryInterface},m}(jQuery));!function(r){var a="popover",l=".bs.popover",h=r.fn[a],c=new RegExp("(^|\\s)bs-popover\\S+","g"),u=r.extend({},s.Default,{placement:"right",trigger:"click",content:"",template:''}),d=r.extend({},s.DefaultType,{content:"(string|element|function)"}),f={FADE:"fade",SHOW:"show"},p={TITLE:".popover-header",CONTENT:".popover-body"},_={HIDE:"hide"+l,HIDDEN:"hidden"+l,SHOW:"show"+l,SHOWN:"shown"+l,INSERTED:"inserted"+l,CLICK:"click"+l,FOCUSIN:"focusin"+l,FOCUSOUT:"focusout"+l,MOUSEENTER:"mouseenter"+l,MOUSELEAVE:"mouseleave"+l},g=function(s){function h(){return n(this,h),t(this,s.apply(this,arguments))}return e(h,s),h.prototype.isWithContent=function(){return this.getTitle()||this._getContent()},h.prototype.addAttachmentClass=function(t){r(this.getTipElement()).addClass("bs-popover-"+t)},h.prototype.getTipElement=function(){return this.tip=this.tip||r(this.config.template)[0]},h.prototype.setContent=function(){var t=r(this.getTipElement());this.setElementContent(t.find(p.TITLE),this.getTitle()),this.setElementContent(t.find(p.CONTENT),this._getContent()),t.removeClass(f.FADE+" "+f.SHOW)},h.prototype._getContent=function(){return this.element.getAttribute("data-content")||("function"==typeof this.config.content?this.config.content.call(this.element):this.config.content)},h.prototype._cleanTipClass=function(){var t=r(this.getTipElement()),e=t.attr("class").match(c);null!==e&&e.length>0&&t.removeClass(e.join(""))},h._jQueryInterface=function(t){return this.each(function(){var e=r(this).data("bs.popover"),n="object"===(void 0===t?"undefined":i(t))?t:null;if((e||!/destroy|hide/.test(t))&&(e||(e=new h(this,n),r(this).data("bs.popover",e)),"string"==typeof t)){if(void 0===e[t])throw new Error('No method named "'+t+'"');e[t]()}})},o(h,null,[{key:"VERSION",get:function(){return"4.0.0-beta"}},{key:"Default",get:function(){return u}},{key:"NAME",get:function(){return a}},{key:"DATA_KEY",get:function(){return"bs.popover"}},{key:"Event",get:function(){return _}},{key:"EVENT_KEY",get:function(){return l}},{key:"DefaultType",get:function(){return d}}]),h}(s);r.fn[a]=g._jQueryInterface,r.fn[a].Constructor=g,r.fn[a].noConflict=function(){return r.fn[a]=h,g._jQueryInterface}}(jQuery)}();
--------------------------------------------------------------------------------