first commit

This commit is contained in:
Eduard Kuksa 2024-11-18 00:06:34 +07:00
commit 671ce3eaa0
94 changed files with 7484 additions and 0 deletions

1
README.md Normal file
View File

@ -0,0 +1 @@
Дипломный проект для курса "Java-разработчик PRO" от Skillbox

24
application.yaml Normal file
View File

@ -0,0 +1,24 @@
server:
port: 8080
spring:
datasource:
username: root
password: hRMH94dJ
url: jdbc:mysql://localhost:3306/search_engine?useSSL=false&requireSSL=false&allowPublicKeyRetrieval=true
jpa:
hibernate:
ddl-auto: update
# Ниже - временный вариант, таблица удаляется после завершения работы приложения
# ddl-auto: create-drop
show-sql: true
open-in-view: false
indexing-settings:
sites:
- url: https://www.lenta.ru
name: Лента.ру
- url: https://www.skillbox.ru
name: Skillbox
- url: https://www.playback.ru
name: PlayBack.Ru

Binary file not shown.

49
pom.xml Normal file
View File

@ -0,0 +1,49 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>dev.kuksa</groupId>
<artifactId>searchengine</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<maven.compiler.source>23</maven.compiler.source>
<maven.compiler.target>23</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.3.5</version>
<relativePath/>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.34</version>
</dependency>
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<version>8.4.0</version>
<scope>runtime</scope>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,11 @@
package searchengine;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}

View File

@ -0,0 +1,11 @@
package searchengine.config;
import lombok.Getter;
import lombok.Setter;
@Setter
@Getter
public class Site {
private String url;
private String name;
}

View File

@ -0,0 +1,16 @@
package searchengine.config;
import lombok.Getter;
import lombok.Setter;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
import java.util.List;
@Getter
@Setter
@Component
@ConfigurationProperties(prefix = "indexing-settings")
public class SitesList {
private List<Site> sites;
}

View File

@ -0,0 +1,31 @@
package searchengine.controllers;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import searchengine.config.SitesList;
import searchengine.dto.statistics.StatisticsResponse;
import searchengine.services.StatisticsService;
@RestController
@RequestMapping("/api")
public class ApiController {
private final StatisticsService statisticsService;
public ApiController(StatisticsService statisticsService) {
this.statisticsService = statisticsService;
}
@GetMapping("/statistics")
public ResponseEntity<StatisticsResponse> statistics() {
return ResponseEntity.ok(statisticsService.getStatistics());
}
@GetMapping("/startIndexing")
public ResponseEntity<StatisticsResponse> startIndexing() {
System.out.println(new SitesList().getSites());
return ResponseEntity.ok(statisticsService.getStatistics());
}
}

View File

@ -0,0 +1,18 @@
package searchengine.controllers;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
public class DefaultController {
/**
* Метод формирует страницу из HTML-файла index.html,
* который находится в папке resources/templates.
* Это делает библиотека Thymeleaf.
*/
@RequestMapping("/")
public String index() {
return "index";
}
}

View File

@ -0,0 +1,14 @@
package searchengine.dto.statistics;
import lombok.Data;
@Data
public class DetailedStatisticsItem {
private String url;
private String name;
private String status;
private long statusTime;
private String error;
private int pages;
private int lemmas;
}

View File

@ -0,0 +1,11 @@
package searchengine.dto.statistics;
import lombok.Data;
import java.util.List;
@Data
public class StatisticsData {
private TotalStatistics total;
private List<DetailedStatisticsItem> detailed;
}

View File

@ -0,0 +1,9 @@
package searchengine.dto.statistics;
import lombok.Data;
@Data
public class StatisticsResponse {
private boolean result;
private StatisticsData statistics;
}

View File

@ -0,0 +1,11 @@
package searchengine.dto.statistics;
import lombok.Data;
@Data
public class TotalStatistics {
private int sites;
private int pages;
private int lemmas;
private boolean indexing;
}

View File

@ -0,0 +1,30 @@
package searchengine.model;
import jakarta.persistence.*;
import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
@Entity
@Table(name = "page", indexes = @Index(columnList = "path"))
public class PageEntity {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(nullable = false)
private int id;
@ManyToOne(cascade = CascadeType.ALL)
@JoinColumn(name = "site_id", nullable = false)
private SiteEntity site;
@Column(columnDefinition = "TEXT NOT NULL, UNIQUE KEY INDEX_PATH (path(255))") // Unique index version
// @Column(columnDefinition = "TEXT NOT NULL, INDEX PATH_INDEX USING BTREE(path(255))") // Non-unique index version
private String path;
@Column(nullable = false)
private int code;
@Column(nullable = false, columnDefinition = "MEDIUMTEXT")
private String content;
}

View File

@ -0,0 +1,34 @@
package searchengine.model;
import jakarta.persistence.*;
import lombok.Getter;
import lombok.Setter;
import java.time.LocalDateTime;
@Getter
@Setter
@Entity
@Table(name = "site")
public class SiteEntity {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(nullable = false)
private int id;
@Enumerated(EnumType.STRING)
@Column(nullable = false)
private StatusType status;
@Column(nullable = false)
private LocalDateTime status_time;
@Column(columnDefinition = "TEXT")
private String last_error;
@Column(nullable = false, columnDefinition = "VARCHAR(255)")
private String url;
@Column(nullable = false, columnDefinition = "VARCHAR(255)")
private String name;
}

View File

@ -0,0 +1,7 @@
package searchengine.model;
public enum StatusType {
INDEXING,
INDEXED,
FAILED
}

View File

@ -0,0 +1,9 @@
package searchengine.repository;
import org.springframework.data.repository.CrudRepository;
import org.springframework.stereotype.Repository;
import searchengine.model.PageEntity;
@Repository
public interface PageRepository extends CrudRepository<PageEntity, Integer> {
}

View File

@ -0,0 +1,9 @@
package searchengine.repository;
import org.springframework.data.repository.CrudRepository;
import org.springframework.stereotype.Repository;
import searchengine.model.SiteEntity;
@Repository
public interface SiteRepository extends CrudRepository<SiteEntity, Integer> {
}

View File

@ -0,0 +1,4 @@
package searchengine.services;
public interface IndexingService {
}

View File

@ -0,0 +1,16 @@
package searchengine.services;
public class IndexingServiceImpl implements IndexingService {
boolean indexingIsRunning = false;
public void startIndexing() {
if (indexingIsRunning) {
System.out.println("Индексация уже запущена");
return;
}
// Логика для запуска индексации или перенидексации сайтов
System.out.println("Запуск индексации");
indexingIsRunning = true;
System.out.println("Индексация запущена");
}
}

View File

@ -0,0 +1,7 @@
package searchengine.services;
import searchengine.dto.statistics.StatisticsResponse;
public interface StatisticsService {
StatisticsResponse getStatistics();
}

View File

@ -0,0 +1,64 @@
package searchengine.services;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import searchengine.config.Site;
import searchengine.config.SitesList;
import searchengine.dto.statistics.DetailedStatisticsItem;
import searchengine.dto.statistics.StatisticsData;
import searchengine.dto.statistics.StatisticsResponse;
import searchengine.dto.statistics.TotalStatistics;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
@Service
@RequiredArgsConstructor
public class StatisticsServiceImpl implements StatisticsService {
private final Random random = new Random();
private final SitesList sites;
@Override
public StatisticsResponse getStatistics() {
String[] statuses = { "INDEXED", "FAILED", "INDEXING" };
String[] errors = {
"Ошибка индексации: главная страница сайта не доступна",
"Ошибка индексации: сайт не доступен",
""
};
TotalStatistics total = new TotalStatistics();
total.setSites(sites.getSites().size());
total.setIndexing(true);
List<DetailedStatisticsItem> detailed = new ArrayList<>();
List<Site> sitesList = sites.getSites();
for(int i = 0; i < sitesList.size(); i++) {
Site site = sitesList.get(i);
DetailedStatisticsItem item = new DetailedStatisticsItem();
item.setName(site.getName());
item.setUrl(site.getUrl());
int pages = random.nextInt(1_000);
int lemmas = pages * random.nextInt(1_000);
item.setPages(pages);
item.setLemmas(lemmas);
item.setStatus(statuses[i % 3]);
item.setError(errors[i % 3]);
item.setStatusTime(System.currentTimeMillis() -
(random.nextInt(10_000)));
total.setPages(total.getPages() + pages);
total.setLemmas(total.getLemmas() + lemmas);
detailed.add(item);
}
StatisticsResponse response = new StatisticsResponse();
StatisticsData data = new StatisticsData();
data.setTotal(total);
data.setDetailed(detailed);
response.setStatistics(data);
response.setResult(true);
return response;
}
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,12 @@
@font-face {
font-family: "Montserrat Black";
src: url("Montserrat-Black.eot"); /* IE9 */
src: url("Montserrat-Black.eot?#iefix") format("embedded-opentype"), /* IE6-IE8 */
url("Montserrat-Black.woff") format("woff"), /* chrome, firefox */
url("Montserrat-Black.ttf") format("truetype"), /* chrome, firefox, opera, Safari, Android, iOS 4.2+ */
url("Montserrat-Black.svg#Montserrat Black") format("svg"); /* iOS 4.1- */
font-style: normal;
font-weight: normal;
}

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 50 KiB

View File

@ -0,0 +1,12 @@
@font-face {
font-family: "Montserrat";
src: url("Montserrat-Bold.eot"); /* IE9 */
src: url("Montserrat-Bold.eot?#iefix") format("embedded-opentype"), /* IE6-IE8 */
url("Montserrat-Bold.woff") format("woff"), /* chrome, firefox */
url("Montserrat-Bold.ttf") format("truetype"), /* chrome, firefox, opera, Safari, Android, iOS 4.2+ */
url("Montserrat-Bold.svg#Montserrat") format("svg"); /* iOS 4.1- */
font-style: normal;
font-weight: normal;
}

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 52 KiB

View File

@ -0,0 +1,12 @@
@font-face {
font-family: "Montserrat ExtraBold";
src: url("Montserrat-ExtraBold.eot"); /* IE9 */
src: url("Montserrat-ExtraBold.eot?#iefix") format("embedded-opentype"), /* IE6-IE8 */
url("Montserrat-ExtraBold.woff") format("woff"), /* chrome, firefox */
url("Montserrat-ExtraBold.ttf") format("truetype"), /* chrome, firefox, opera, Safari, Android, iOS 4.2+ */
url("Montserrat-ExtraBold.svg#Montserrat ExtraBold") format("svg"); /* iOS 4.1- */
font-style: normal;
font-weight: normal;
}

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 51 KiB

View File

@ -0,0 +1,12 @@
@font-face {
font-family: "Montserrat ExtraLight";
src: url("Montserrat-ExtraLight.eot"); /* IE9 */
src: url("Montserrat-ExtraLight.eot?#iefix") format("embedded-opentype"), /* IE6-IE8 */
url("Montserrat-ExtraLight.woff") format("woff"), /* chrome, firefox */
url("Montserrat-ExtraLight.ttf") format("truetype"), /* chrome, firefox, opera, Safari, Android, iOS 4.2+ */
url("Montserrat-ExtraLight.svg#Montserrat ExtraLight") format("svg"); /* iOS 4.1- */
font-style: normal;
font-weight: normal;
}

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 53 KiB

View File

@ -0,0 +1,12 @@
@font-face {
font-family: "Montserrat Light";
src: url("Montserrat-Light.eot"); /* IE9 */
src: url("Montserrat-Light.eot?#iefix") format("embedded-opentype"), /* IE6-IE8 */
url("Montserrat-Light.woff") format("woff"), /* chrome, firefox */
url("Montserrat-Light.ttf") format("truetype"), /* chrome, firefox, opera, Safari, Android, iOS 4.2+ */
url("Montserrat-Light.svg#Montserrat Light") format("svg"); /* iOS 4.1- */
font-style: normal;
font-weight: normal;
}

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 53 KiB

View File

@ -0,0 +1,12 @@
@font-face {
font-family: "Montserrat Medium";
src: url("Montserrat-Medium.eot"); /* IE9 */
src: url("Montserrat-Medium.eot?#iefix") format("embedded-opentype"), /* IE6-IE8 */
url("Montserrat-Medium.woff") format("woff"), /* chrome, firefox */
url("Montserrat-Medium.ttf") format("truetype"), /* chrome, firefox, opera, Safari, Android, iOS 4.2+ */
url("Montserrat-Medium.svg#Montserrat Medium") format("svg"); /* iOS 4.1- */
font-style: normal;
font-weight: normal;
}

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 53 KiB

View File

@ -0,0 +1,12 @@
@font-face {
font-family: "Montserrat";
src: url("Montserrat-Regular.eot"); /* IE9 */
src: url("Montserrat-Regular.eot?#iefix") format("embedded-opentype"), /* IE6-IE8 */
url("Montserrat-Regular.woff") format("woff"), /* chrome, firefox */
url("Montserrat-Regular.ttf") format("truetype"), /* chrome, firefox, opera, Safari, Android, iOS 4.2+ */
url("Montserrat-Regular.svg#Montserrat") format("svg"); /* iOS 4.1- */
font-style: normal;
font-weight: normal;
}

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 53 KiB

View File

@ -0,0 +1,12 @@
@font-face {
font-family: "Montserrat SemiBold";
src: url("Montserrat-SemiBold.eot"); /* IE9 */
src: url("Montserrat-SemiBold.eot?#iefix") format("embedded-opentype"), /* IE6-IE8 */
url("Montserrat-SemiBold.woff") format("woff"), /* chrome, firefox */
url("Montserrat-SemiBold.ttf") format("truetype"), /* chrome, firefox, opera, Safari, Android, iOS 4.2+ */
url("Montserrat-SemiBold.svg#Montserrat SemiBold") format("svg"); /* iOS 4.1- */
font-style: normal;
font-weight: normal;
}

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 52 KiB

View File

@ -0,0 +1,12 @@
@font-face {
font-family: "Montserrat Thin";
src: url("Montserrat-Thin.eot"); /* IE9 */
src: url("Montserrat-Thin.eot?#iefix") format("embedded-opentype"), /* IE6-IE8 */
url("Montserrat-Thin.woff") format("woff"), /* chrome, firefox */
url("Montserrat-Thin.ttf") format("truetype"), /* chrome, firefox, opera, Safari, Android, iOS 4.2+ */
url("Montserrat-Thin.svg#Montserrat Thin") format("svg"); /* iOS 4.1- */
font-style: normal;
font-weight: normal;
}

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 54 KiB

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 386.257 386.257"><path d="M0 96.879l193.129 192.5 193.128-192.5z"/></svg>

After

Width:  |  Height:  |  Size: 126 B

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path d="M256 0C115.3 0 0 115.3 0 256s115.3 256 256 256 256-115.3 256-256S396.7 0 256 0z" fill="#ff3636"/><path d="M512 256c0 140.7-115.3 256-256 256V0c140.7 0 256 115.3 256 256z" fill="#f40000"/><path fill="#e7e7e7" d="M298.299 256l84.901 84.901-42.299 42.299L256 298.299 171.099 383.2 128.8 340.901 213.701 256 128.8 171.099l42.299-42.299L256 213.701l84.901-84.901 42.299 42.299z"/><path fill="#d3d3d8" d="M298.299 256l84.901 84.901-42.299 42.299L256 298.299v-84.598l84.901-84.901 42.299 42.299z"/></svg>

After

Width:  |  Height:  |  Size: 568 B

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path d="M256 0C115.3 0 0 115.3 0 256s115.3 256 256 256 256-115.3 256-256S396.7 0 256 0z" fill="#7d0"/><path d="M512 256c0 140.7-115.3 256-256 256V0c140.7 0 256 115.3 256 256z" fill="#6b0"/><path fill="#e7e7e7" d="M401.8 212.5L226 388.299l-126.301-126 42.602-42.6 83.699 84 30-30L359.5 170.2z"/><path fill="#d3d3d8" d="M401.8 212.5L256 358.299v-84.6L359.5 170.2z"/></svg>

After

Width:  |  Height:  |  Size: 433 B

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path fill="#ffb74f" d="M432.106 250.534v219.487H296.578V336.975h-75.179v133.046H79.894V250.534L256 115.075z"/><path d="M439.485 183.135V90.306h-74.167v35.772L256 41.979 0 238.92l53.633 69.712L256 152.959l202.367 155.672L512 238.92l-72.515-55.785z" fill="#ff7d3c"/><path fill="#ff9a00" d="M432.106 250.534v219.487H296.578V336.975H256v-221.9z"/><path fill="#ff4e19" d="M512 238.92l-53.633 69.712L256 152.959V41.979l109.318 84.099V90.306h74.167v92.829z"/></svg>

After

Width:  |  Height:  |  Size: 521 B

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 12 KiB

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path d="M0 256c0 141.384 114.615 256 256 256l22.261-256L256 0C114.615 0 0 114.615 0 256z" fill="#bfdcff"/><path d="M256 0v512c141.384 0 256-114.616 256-256S397.384 0 256 0z" fill="#8bc0ff"/><path fill="#3897ff" d="M155.826 144.696h66.783v222.609h-66.783z"/><path fill="#2d79cc" d="M289.391 144.696h66.783v222.609h-66.783z"/></svg>

After

Width:  |  Height:  |  Size: 393 B

View File

@ -0,0 +1 @@
<svg height="512" width="512" xmlns="http://www.w3.org/2000/svg"><path d="M179.907 317.89l63.63-63.63 17.675 17.676-63.63 63.63z" fill="#83a3ab"/><path d="M176.371 314.355l63.63-63.63 10.605 10.605-63.63 63.63zM66.192 403.381l-53.033 95.46c17.545 17.545 46.094 17.546 63.64 0l21.213-21.213z" fill="#93b7c0"/><path d="M34.373 413.988L13.16 435.201c-17.546 17.546-17.545 46.094 0 63.64l74.246-74.246z" fill="#acd5df"/><path d="M98.012 477.627L240.06 335.58l-31.82-31.82-92.237 49.811-49.811 92.237z" fill="#3a6fd8"/><path d="M34.335 413.954L176.36 271.93l31.815 31.815L66.15 445.769z" fill="#3b88f5"/><path d="M463.526 48.474l-175.539 58.513-58.513 175.539c64.632 64.632 169.421 64.632 234.052 0s64.632-169.42 0-234.052z" fill="#93b7c0"/><path d="M229.474 48.474c-64.632 64.632-64.632 169.421 0 234.052L463.526 48.474c-64.632-64.632-169.42-64.632-234.052 0z" fill="#acd5df"/><path d="M421.1 90.9l-111.9 37.3-37.3 111.9c41.2 41.2 107.999 41.2 149.2 0s41.2-107.999 0-149.2z" fill="#c4f3ff"/><path d="M271.9 90.9c-41.2 41.2-41.2 107.999 0 149.2L421.1 90.9c-41.201-41.2-107.999-41.2-149.2 0z" fill="#fff"/></svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,7 @@
/*
jQuery Masked Input Plugin
Copyright (c) 2007 - 2015 Josh Bush (digitalbush.com)
Licensed under the MIT license (http://digitalbush.com/projects/masked-input-plugin/#license)
Version: 1.4.1
*/
!function(a){"function"==typeof define&&define.amd?define(["jquery"],a):a("object"==typeof exports?require("jquery"):jQuery)}(function(a){var b,c=navigator.userAgent,d=/iphone/i.test(c),e=/chrome/i.test(c),f=/android/i.test(c);a.mask={definitions:{9:"[0-9]",a:"[A-Za-z]","*":"[A-Za-z0-9]"},autoclear:!0,dataName:"rawMaskFn",placeholder:"_"},a.fn.extend({caret:function(a,b){var c;if(0!==this.length&&!this.is(":hidden"))return"number"==typeof a?(b="number"==typeof b?b:a,this.each(function(){this.setSelectionRange?this.setSelectionRange(a,b):this.createTextRange&&(c=this.createTextRange(),c.collapse(!0),c.moveEnd("character",b),c.moveStart("character",a),c.select())})):(this[0].setSelectionRange?(a=this[0].selectionStart,b=this[0].selectionEnd):document.selection&&document.selection.createRange&&(c=document.selection.createRange(),a=0-c.duplicate().moveStart("character",-1e5),b=a+c.text.length),{begin:a,end:b})},unmask:function(){return this.trigger("unmask")},mask:function(c,g){var h,i,j,k,l,m,n,o;if(!c&&this.length>0){h=a(this[0]);var p=h.data(a.mask.dataName);return p?p():void 0}return g=a.extend({autoclear:a.mask.autoclear,placeholder:a.mask.placeholder,completed:null},g),i=a.mask.definitions,j=[],k=n=c.length,l=null,a.each(c.split(""),function(a,b){"?"==b?(n--,k=a):i[b]?(j.push(new RegExp(i[b])),null===l&&(l=j.length-1),k>a&&(m=j.length-1)):j.push(null)}),this.trigger("unmask").each(function(){function h(){if(g.completed){for(var a=l;m>=a;a++)if(j[a]&&C[a]===p(a))return;g.completed.call(B)}}function p(a){return g.placeholder.charAt(a<g.placeholder.length?a:0)}function q(a){for(;++a<n&&!j[a];);return a}function r(a){for(;--a>=0&&!j[a];);return a}function s(a,b){var c,d;if(!(0>a)){for(c=a,d=q(b);n>c;c++)if(j[c]){if(!(n>d&&j[c].test(C[d])))break;C[c]=C[d],C[d]=p(d),d=q(d)}z(),B.caret(Math.max(l,a))}}function t(a){var b,c,d,e;for(b=a,c=p(a);n>b;b++)if(j[b]){if(d=q(b),e=C[b],C[b]=c,!(n>d&&j[d].test(e)))break;c=e}}function u(){var a=B.val(),b=B.caret();if(o&&o.length&&o.length>a.length){for(A(!0);b.begin>0&&!j[b.begin-1];)b.begin--;if(0===b.begin)for(;b.begin<l&&!j[b.begin];)b.begin++;B.caret(b.begin,b.begin)}else{for(A(!0);b.begin<n&&!j[b.begin];)b.begin++;B.caret(b.begin,b.begin)}h()}function v(){A(),B.val()!=E&&B.change()}function w(a){if(!B.prop("readonly")){var b,c,e,f=a.which||a.keyCode;o=B.val(),8===f||46===f||d&&127===f?(b=B.caret(),c=b.begin,e=b.end,e-c===0&&(c=46!==f?r(c):e=q(c-1),e=46===f?q(e):e),y(c,e),s(c,e-1),a.preventDefault()):13===f?v.call(this,a):27===f&&(B.val(E),B.caret(0,A()),a.preventDefault())}}function x(b){if(!B.prop("readonly")){var c,d,e,g=b.which||b.keyCode,i=B.caret();if(!(b.ctrlKey||b.altKey||b.metaKey||32>g)&&g&&13!==g){if(i.end-i.begin!==0&&(y(i.begin,i.end),s(i.begin,i.end-1)),c=q(i.begin-1),n>c&&(d=String.fromCharCode(g),j[c].test(d))){if(t(c),C[c]=d,z(),e=q(c),f){var k=function(){a.proxy(a.fn.caret,B,e)()};setTimeout(k,0)}else B.caret(e);i.begin<=m&&h()}b.preventDefault()}}}function y(a,b){var c;for(c=a;b>c&&n>c;c++)j[c]&&(C[c]=p(c))}function z(){B.val(C.join(""))}function A(a){var b,c,d,e=B.val(),f=-1;for(b=0,d=0;n>b;b++)if(j[b]){for(C[b]=p(b);d++<e.length;)if(c=e.charAt(d-1),j[b].test(c)){C[b]=c,f=b;break}if(d>e.length){y(b+1,n);break}}else C[b]===e.charAt(d)&&d++,k>b&&(f=b);return a?z():k>f+1?g.autoclear||C.join("")===D?(B.val()&&B.val(""),y(0,n)):z():(z(),B.val(B.val().substring(0,f+1))),k?b:l}var B=a(this),C=a.map(c.split(""),function(a,b){return"?"!=a?i[a]?p(b):a:void 0}),D=C.join(""),E=B.val();B.data(a.mask.dataName,function(){return a.map(C,function(a,b){return j[b]&&a!=p(b)?a:null}).join("")}),B.one("unmask",function(){B.off(".mask").removeData(a.mask.dataName)}).on("focus.mask",function(){if(!B.prop("readonly")){clearTimeout(b);var a;E=B.val(),a=A(),b=setTimeout(function(){B.get(0)===document.activeElement&&(z(),a==c.replace("?","").length?B.caret(0,a):B.caret(a))},10)}}).on("blur.mask",v).on("keydown.mask",w).on("keypress.mask",x).on("input.mask paste.mask",function(){B.prop("readonly")||setTimeout(function(){var a=A(!0);B.caret(a),h()},0)}),e&&f&&B.off("input.mask").on("input.mask",u),A()})}})});

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,162 @@
<!--END-->
<!--END--><!DOCTYPE html><!--[if IE 7]>
<html class="ie7" lang="ru">
<![endif]-->
<!--[if IE 8]>
<html class="ie8" lang="ru">
<![endif]-->
<!--[if IE 9]>
<html class="ie9" lang="ru">
<![endif]-->
<!--[if gt IE 9]><!--> <html lang="ru"> <!--<![endif]-->
<head>
<title>Site Search Engine</title>
<meta name="description" content="Site Search Engine">
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=0">
<!--meta( http-equiv="cache-control" content="no-cache")-->
<!--meta( http-equiv="expires" content="0")-->
<!--link(rel="preload" href="assets/css/extra.min.css?v=" + version as="style" crossorigin="anonymous")-->
<link href="favicon.ico" rel="shortcut icon">
<link rel="preload" href="/assets/fonts/Montserrat/Montserrat-SemiBold.woff2" as="font" crossorigin="anonymous">
<link rel="preload" href="/assets/fonts/Montserrat/Montserrat-Light.woff2" as="font" crossorigin="anonymous">
<link rel="preload" href="/assets/fonts/Montserrat/Montserrat-Medium.woff2" as="font" crossorigin="anonymous">
<link rel="preload" href="/assets/fonts/Montserrat/Montserrat-ExtraBold.woff2" as="font" crossorigin="anonymous">
<link rel="stylesheet" href="/assets/css/fonts.css?v=82368483">
<link rel="stylesheet" href="/assets/css/basic.css?v=82368483">
<link rel="stylesheet" href="/assets/css/extra.css?v=82368483"><!--[if lt IE 9]>
<script src="http://html5shiv.googlecode.com/svn/trunk/html5.js"></script><![endif]-->
<script>
var backendApiUrl = 'api'
</script>
<script defer src="/assets/js/scripts.js?v=38874865"></script>
</head>
<body class="Site">
<!--if lt IE 8
p.error-browser
| Ваш браузер&nbsp;
em устарел!&nbsp;
a(href="http://browsehappy.com/") Выберите новую версию
+s
| браузера здесь&nbsp;
| для правильного отображения сайта.
-->
<div class="Site-loader">
<div class="Site-loader-block">
<div>
</div>
<div>
</div>
<div>
</div>
<div>
</div>
</div>
</div>
<div class="Middle">
<div class="wrap">
<div class="Site-loadingIsComplete">
<main class="Tabs Tabs_column Middle-main">
<div class="Column">
<div class="Tabs-links"><a class="Tabs-link Tabs-link_ACTIVE" href="#dashboard"><img class="Tabs-icon" src="/assets/img/icons/dashboard.svg" alt="dashboard.svg"/><span class="Tabs-linkText">Dashboard</span></a><a class="Tabs-link" href="#management"><img class="Tabs-icon" src="/assets/img/icons/management.svg" alt="management.svg"/><span class="Tabs-linkText">Management</span></a><a class="Tabs-link" href="#search"><img class="Tabs-icon" src="/assets/img/icons/search.svg" alt="search.svg"/><span class="Tabs-linkText">Search</span></a>
</div>
</div>
<div class="Tabs-wrap">
<div class="Tabs-block" id="dashboard">
<div class="Section">
<div class="Section-header">
<h2 class="Section-title">Dashboard
</h2>
</div>
<div class="Statistics">
<div class="Statistics-info">
<div class="Statistics-block"><span class="Statistics-amount" id="totalSites"></span><span class="Statistics-title">sites</span>
</div>
<div class="Statistics-block"><span class="Statistics-amount" id="totalPages"></span><span class="Statistics-title">pages</span>
</div>
<div class="Statistics-block"><span class="Statistics-amount" id="totalLemmas"></span><span class="Statistics-title">lemmas</span>
</div>
</div>
<div class="HideBlock Statistics-example">
<header class="HideBlock-header HideBlock-trigger">
<strong class="HideBlock-title"><span class="Statistics-status"></span>
</strong>
<button class="HideBlock-btn" type="button">
</button>
</header>
<div class="HideBlock-content">
<p class="Statistics-description">
</p>
</div>
</div>
</div>
</div>
</div>
<div class="Tabs-block" id="management">
<div class="Section">
<div class="Section-header">
<h2 class="Section-title">Management
</h2>
</div>
<div>
<button class="btn btn_primary API-startIndexing" data-btntype="check" data-check="false" data-alttext="Stop indexing" data-send="startIndexing" data-altsend="stopIndexing"><span class="btn-content">Start indexing</span>
</button>
</div><br>
<div class="UpdatePageBlock">
<h3>Add/update page:
</h3>
<form class="form form_close" action="#" method="post" data-send="indexPage">
<div class="form-group form-group_row">
<input class="form-input" id="page" name="page" type="text"/>
<button class="btn btn_primary form-btn" type="submit">Add/update
</button>
</div>
</form>
</div>
</div>
</div>
<div class="Tabs-block" id="search">
<div class="Section">
<div class="Section-header">
<h2 class="Section-title">Search
</h2>
</div>
<form class="form form_close" action="#" method="post" data-send="search" data-sendlimit="10">
<div class="form-group">
<div class="form-selectWrap">
<!-- - var options = setOptions(items, ['value', 'selected', 'disabled']);-->
<select class="form-select" name="site">
<option value="" selected="selected">All sites
</option>
</select>
</div>
</div>
<div class="form-group form-group_row">
<input class="form-input" id="query" name="query" type="text" placeholder="Query"/>
<button class="btn btn_primary form-btn" type="submit">Search
</button>
</div>
</form>
<div class="SearchResult">
<strong class="SearchResult-title">Found&#32;<span class="SearchResult-amount">0</span>&#32;results
</strong>
<div class="SearchResult-content">
</div>
<div class="SearchResult-footer SearchResult-footer_hide">
<button class="btn btn_primary" data-send="search" data-sendtype="next">Show more<span class="SearchResult-remain">(0)</span>
</button>
</div>
</div>
</div>
</div>
</div>
</main>
</div>
</div>
</div>
<script src="/assets/plg/jQuery/jquery-3.5.1.min.js"></script>
</body></html>