├── .gitignore
├── LICENSE
├── README.md
├── RS
├── .gitignore
├── RS.ipynb
├── lib
│ ├── .gitignore
│ ├── __init__.py
│ ├── config.py
│ ├── model.py
│ └── utils.py
└── seg_corpus
│ └── .gitignore
├── crawler
├── .gitignore
├── corpus
│ └── .gitignore
├── download_check.py
├── info_crawler.py
├── lib
│ ├── .gitignore
│ ├── __init__.py
│ ├── config.py
│ ├── model.py
│ └── utils.py
└── txt_downloader.py
├── requirements.txt
├── screenshot.png
└── web_demo
├── .babelrc
├── .editorconfig
├── .gitignore
├── README.md
├── build
├── build.js
├── dev-client.js
├── dev-server.js
├── utils.js
├── webpack.base.conf.js
├── webpack.dev.conf.js
└── webpack.prod.conf.js
├── config
├── dev.env.js
├── index.js
├── prod.env.js
└── test.env.js
├── dist
├── index.html
└── static
│ ├── bootstrap.min.css
│ ├── jquery.min.js
│ └── js
│ ├── app.d2d173414305722a1a2d.js
│ ├── app.d2d173414305722a1a2d.js.map
│ ├── manifest.b6282e62578cc7cefbdf.js
│ ├── manifest.b6282e62578cc7cefbdf.js.map
│ ├── vendor.0ad8be03111db2f40424.js
│ └── vendor.0ad8be03111db2f40424.js.map
├── index.html
├── lib
├── .gitignore
├── __init__.py
├── config.py
├── model.py
└── utils.py
├── main.py
├── package.json
├── src
├── App.vue
├── assets
│ └── logo.png
├── components
│ ├── NavBar.vue
│ ├── NovelList.vue
│ └── Search.vue
├── main.js
└── vuex
│ ├── actions.js
│ ├── getters.js
│ └── store.js
└── static
├── .gitkeep
├── bootstrap.min.css
└── jquery.min.js
/.gitignore:
--------------------------------------------------------------------------------
1 | .idea/
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2016 Kalen Blue
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # novelRS
2 | 一个简单的网络小说推荐系统。
3 |
4 | ## 开发环境
5 | python3.6 + mongodb
6 |
7 | ## 代码说明
8 | ### 运行小说爬虫
9 | #### 下载小说列表:
10 | ```bash
11 | cd crawler & python3 info_crawler.py
12 | ```
13 | #### 下载小说的txt文件:
14 | ```bash
15 | cd crawler & python3 txt_downloader.py
16 | ```
17 | #### 小说过滤(只考虑大于500KB的小说):
18 | ```bash
19 | cd crawler & python3 download_check.py
20 | ```
21 |
22 | ### 运行推荐算法
23 | 通过ipython notebook打开RS.ipynb
24 | ```bash
25 | cd RS & ipython3 notebook
26 | ```
27 | 然后逐步完成notebook中的以下步骤:
28 | - 1、分词
29 | - 2、词表分析
30 | - 3、TF-IDF构建
31 | - 4、KD-Tree最近邻查询
32 | - 5、相似度更新
33 |
34 | ### 运行网页Demo
35 | #### 导入数据
36 | 数据下载链接:https://pan.baidu.com/s/1PFjFBtaKaBeS90CL5-hIKA 密码:f16j
37 | ``` sh
38 | mongoimport -d novelRS -c novels --file=novels.json
39 | ```
40 |
41 | #### 前端说明
42 | 基于vue1.0编写,可以不用care。
43 | ``` sh
44 | cd web_demo
45 | npm install # 安装依赖库
46 | npm run dev # 调试模式
47 | npm run build # 导出dist
48 |
49 | ```
50 |
51 | #### 运行后台
52 | ```bash
53 | cd web_demo & python3 main.py
54 | ```
55 |
56 | #### 测试效果
57 | 运行后,打开[http://localhost:38438](http://localhost:38438)。
58 | 
59 |
60 | ## LICENSE
61 | MIT
62 |
--------------------------------------------------------------------------------
/RS/.gitignore:
--------------------------------------------------------------------------------
1 | *.pyc
2 | *.log
3 | 1.txt
4 | *.dat
5 | *.pickle
6 | .ipynb_checkpoints/
--------------------------------------------------------------------------------
/RS/lib/.gitignore:
--------------------------------------------------------------------------------
1 | *.pyc
2 | *.log
3 | __pycache__
--------------------------------------------------------------------------------
/RS/lib/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nladuo/novelRS/6bbb687e385f1137f387547d201f0dbbee1538c0/RS/lib/__init__.py
--------------------------------------------------------------------------------
/RS/lib/config.py:
--------------------------------------------------------------------------------
1 | # coding=utf-8
2 |
3 | config = {
4 | 'timeout': 10,
5 | 'db_user': '', # mongodb的用户名
6 | 'db_pass': '', # mongodb的密码
7 | 'db_host': 'localhost',
8 | 'db_port': 27017,
9 | 'db_name': 'novelRS',
10 | 'cpu_num': 4 # 开几个进程计算
11 | }
12 |
--------------------------------------------------------------------------------
/RS/lib/model.py:
--------------------------------------------------------------------------------
1 | # coding=utf-8
2 |
3 |
4 | class Novel:
5 | """ 小说结构 """
6 | def __init__(self, name, url, author, category, abstract, download_url):
7 | self.name = name
8 | self.url = url
9 | self.author = author
10 | self.category = category
11 | self.abstract = abstract
12 | self.download_url = download_url
13 |
14 | def dict(self):
15 | return {
16 | 'name': self.name,
17 | 'url': self.url,
18 | 'author': self.author,
19 | 'category': self.category,
20 | 'abstract': self.abstract,
21 | 'download_url': self.download_url,
22 | 'is_downloaded': False, # 是否下载
23 | 'success': True, # 下载是否成功,
24 | 'is_segment': False, # 是否分词
25 | }
26 |
27 |
28 | class FailedUrl:
29 | """ 失败的链接 """
30 | def __init__(self, url):
31 | self.url = url
32 |
33 | def dict(self):
34 | return {'url': self.url}
35 |
36 |
37 | class Similarity:
38 | """ 保存两个小说之间相似度 """
39 | def __init__(self, novel_id, similarity):
40 | self.novel_id = novel_id
41 | self.similarity = similarity
42 |
43 | def dict(self):
44 | return {
45 | 'novel_id': self.novel_id,
46 | 'similarity': self.similarity,
47 | }
48 |
--------------------------------------------------------------------------------
/RS/lib/utils.py:
--------------------------------------------------------------------------------
1 | # -*- coding:utf-8 -*-
2 | import pymongo
3 | import requests
4 | from .model import FailedUrl
5 | from .config import *
6 |
7 |
8 | def init_client():
9 | """ 初始化mongo客户端 """
10 | client = pymongo.MongoClient(config['db_host'], config['db_port'])
11 | if len(config['db_user']) != 0:
12 | admin = client['admin']
13 | admin.authenticate(config['db_user'], config['db_pass'])
14 | return client
15 |
16 |
17 | def get_body(url):
18 | """ 发送http请求 """
19 | retry_times = 0
20 | while retry_times < 3:
21 | try:
22 | content = requests.get(url, timeout=config['timeout']).content
23 | return content
24 | except KeyboardInterrupt:
25 | print("KeyboardInterrupt, now_url:", url)
26 | raise
27 | except:
28 | retry_times += 1
29 | return ''
30 |
31 |
32 | def add_failed_url(db, url):
33 | """ 把失败的url添加到数据库 """
34 | collection = db.failed_urls
35 | if collection.find({'url': url}).count() == 0:
36 | collection.insert(FailedUrl(url).dict())
37 |
38 | def read_novel(path):
39 | with open(path, "r") as f:
40 | return f.read().decode("gb2312", 'ignore')
41 |
--------------------------------------------------------------------------------
/RS/seg_corpus/.gitignore:
--------------------------------------------------------------------------------
1 | *.txt
--------------------------------------------------------------------------------
/crawler/.gitignore:
--------------------------------------------------------------------------------
1 | *.pyc
2 | *.log
3 | test.py
4 | test.txt
--------------------------------------------------------------------------------
/crawler/corpus/.gitignore:
--------------------------------------------------------------------------------
1 | *.txt
--------------------------------------------------------------------------------
/crawler/download_check.py:
--------------------------------------------------------------------------------
1 | # coding=utf-8
2 | """ 标记下载大小小于400K的小说 """
3 | from __future__ import print_function
4 | from lib.utils import *
5 | from lib.config import *
6 | import os.path
7 |
8 |
9 | def check_download(novel):
10 | path = os.path.join('corpus', str(novel["_id"]) + ".txt")
11 | try:
12 | filesize = os.path.getsize(path)
13 | success = filesize >= 500 * 1024 # 保留大于500KB的小说
14 | print(novel['_id'], novel['name'], "filesize:", filesize, "success:", success)
15 |
16 | return success
17 | except:
18 | return False
19 |
20 |
21 | class DownloadChecker:
22 | """ 爬取小说的章节,存到数据库中 """
23 | def __init__(self):
24 | self.client = init_client()
25 | self.db = self.client[config['db_name']]
26 | self.novels = self.db.novels.find({})
27 |
28 | def run(self):
29 | novels = []
30 | # 先把数据都读到内存里
31 | for novel in self.novels:
32 | novels.append(novel)
33 |
34 | for novel in novels:
35 | success = check_download(novel)
36 | self.__update_novel(novel, success)
37 |
38 | self.__close()
39 |
40 | def __update_novel(self, novel, success):
41 | """ 把小说设置为已经爬去取过 """
42 | self.db.novels.update({'_id': novel['_id']}, {
43 | '$set': {'is_saved': success},
44 | })
45 |
46 | def __close(self):
47 | """ 关闭数据库 """
48 | self.client.close()
49 |
50 |
51 | if __name__ == '__main__':
52 | checker = DownloadChecker()
53 | checker.run()
54 | print("DownloadChecker has been finished.")
55 |
56 |
--------------------------------------------------------------------------------
/crawler/info_crawler.py:
--------------------------------------------------------------------------------
1 | # coding=utf-8
2 | from __future__ import print_function
3 | from bs4 import BeautifulSoup
4 | from lib.utils import *
5 | from lib.model import *
6 | from lib.config import *
7 | import traceback
8 |
9 |
10 | def get_page_num(html):
11 | soup = BeautifulSoup(html, "html.parser")
12 | a = soup.find("div", {"class": "tspage"}).find_all("a")[1]
13 | page_str = a.attrs["href"].split("/")[-1].replace("index_", "").replace( ".html", "")
14 | return int(page_str)
15 |
16 |
17 | class InfoCrawler:
18 | """ 爬取小说基本信息 """
19 | def __init__(self):
20 | self.client = init_client()
21 | self.db = self.client[config['db_name']]
22 | self.collection = self.db.novels
23 | self.collection.ensure_index('url', unique=True)
24 |
25 | def run(self):
26 | # 只爬取玄幻奇幻和武侠仙侠两个类别
27 | start_urls = [
28 | "https://www.qisuu.la/soft/sort01/",
29 | "https://www.qisuu.la/soft/sort02/"
30 | ]
31 |
32 | # For中断重新爬取
33 | start_index = {
34 | "https://www.qisuu.la/soft/sort01/": 1,
35 | "https://www.qisuu.la/soft/sort02/": 1
36 | }
37 |
38 | # 开始爬取
39 | for start_url in start_urls:
40 | html = get_body(start_url)
41 | if html == "":
42 | raise Exception("Error download init url: %s" % start_url )
43 | page_num = get_page_num(html)
44 | print(start_url, "page_num:", page_num)
45 | for page in range(start_index[start_url], page_num + 1):
46 | url = start_url + "index_%d.html" % page
47 | if page == 1:
48 | url = start_url
49 | print("正在爬取:", url)
50 | html = get_body(url)
51 | if html == "":
52 | add_failed_url(self.db, url);continue
53 | novels = self.__parse(html)
54 | self.__add_novels(novels)
55 | self.__close()
56 |
57 | def __add_novels(self, novels):
58 | for novel in novels:
59 | try:
60 | if self.collection.find({"url": novel.url}).count() == 0:
61 | self.collection.insert(novel.dict())
62 | except Exception as ex:
63 | traceback.print_exc()
64 |
65 | def __close(self):
66 | """ 关闭数据库 """
67 | self.client.close()
68 |
69 | @staticmethod
70 | def __parse(html):
71 | """ 解析小说 """
72 | # print(html)
73 | novels = []
74 | soup = BeautifulSoup(html, "html.parser")
75 | lis = soup.find("div", {"class": "listBox"}).find_all("li")
76 | for li in lis:
77 | for i, child in enumerate(li.children):
78 | if i == 3:
79 | url = "https://www.qisuu.la" + child.attrs["href"]
80 | # 下载详情页面
81 | html2 = get_body(url)
82 | soup2 = BeautifulSoup(html2, "html.parser")
83 | abstract = soup2.find("div", {"class": "showInfo"}).get_text()
84 | author = soup2.find("div", {"class": "detail_right"}).find_all("li")[5].\
85 | get_text().replace("书籍作者:", "")
86 | name = soup2.find("div", {"class": "showDown"}).script.get_text().split("'")[5]
87 | txt_url = soup2.find("div", {"class": "showDown"}).script.get_text().split("','")[1]
88 | category = soup2.find("div", {"class": "wrap position"}).span.find_all("a")[-2].get_text()
89 | print("《"+name+"》", "作者:", author, "类别:", category, txt_url)
90 | novels.append(Novel(name, url, author, category, abstract, txt_url))
91 | return novels
92 |
93 |
94 | if __name__ == '__main__':
95 | crawler = InfoCrawler()
96 | crawler.run()
97 | print("info_crawler has been finished.")
98 |
--------------------------------------------------------------------------------
/crawler/lib/.gitignore:
--------------------------------------------------------------------------------
1 | *.pyc
2 | *.log
--------------------------------------------------------------------------------
/crawler/lib/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nladuo/novelRS/6bbb687e385f1137f387547d201f0dbbee1538c0/crawler/lib/__init__.py
--------------------------------------------------------------------------------
/crawler/lib/config.py:
--------------------------------------------------------------------------------
1 | # coding=utf-8
2 |
3 | config = {
4 | 'timeout': 10,
5 | 'db_user': '', # mongodb的用户名
6 | 'db_pass': '', # mongodb的密码
7 | 'db_host': 'localhost',
8 | 'db_port': 27017,
9 | 'db_name': 'novelRS',
10 | 'cpu_num': 4 # 开几个进程计算
11 | }
12 |
--------------------------------------------------------------------------------
/crawler/lib/model.py:
--------------------------------------------------------------------------------
1 | # coding=utf-8
2 |
3 |
4 | class Novel:
5 | """ 小说结构 """
6 | def __init__(self, name, url, author, category, abstract, download_url):
7 | self.name = name
8 | self.url = url
9 | self.author = author
10 | self.category = category
11 | self.abstract = abstract
12 | self.download_url = download_url
13 |
14 | def dict(self):
15 | return {
16 | 'name': self.name,
17 | 'url': self.url,
18 | 'author': self.author,
19 | 'category': self.category,
20 | 'abstract': self.abstract,
21 | 'download_url': self.download_url,
22 | 'is_downloaded': False, # 是否下载
23 | 'success': True, # 下载是否成功,
24 | 'is_segment': False, # 是否分词
25 | }
26 |
27 |
28 | class FailedUrl:
29 | """ 失败的链接 """
30 | def __init__(self, url):
31 | self.url = url
32 |
33 | def dict(self):
34 | return {'url': self.url}
35 |
36 |
37 | class Similarity:
38 | """ 保存两个小说之间相似度 """
39 | def __init__(self, novel_id, similarity):
40 | self.novel_id = novel_id
41 | self.similarity = similarity
42 |
43 | def dict(self):
44 | return {
45 | 'novel_id': self.novel_id,
46 | 'similarity': self.similarity,
47 | }
48 |
--------------------------------------------------------------------------------
/crawler/lib/utils.py:
--------------------------------------------------------------------------------
1 | # -*- coding:utf-8 -*-
2 | import pymongo
3 | import requests
4 | from .model import FailedUrl
5 | from .config import *
6 |
7 |
8 | def init_client():
9 | """ 初始化mongo客户端 """
10 | client = pymongo.MongoClient(config['db_host'], config['db_port'])
11 | if len(config['db_user']) != 0:
12 | admin = client['admin']
13 | admin.authenticate(config['db_user'], config['db_pass'])
14 | return client
15 |
16 |
17 | def get_body(url):
18 | """ 发送http请求 """
19 | retry_times = 0
20 | while retry_times < 3:
21 | try:
22 | content = requests.get(url, timeout=config['timeout']).content
23 | return content
24 | except KeyboardInterrupt:
25 | print("KeyboardInterrupt, now_url:", url)
26 | raise
27 | except:
28 | retry_times += 1
29 | return ''
30 |
31 |
32 | def add_failed_url(db, url):
33 | """ 把失败的url添加到数据库 """
34 | collection = db.failed_urls
35 | if collection.find({'url': url}).count() == 0:
36 | collection.insert(FailedUrl(url).dict())
37 |
38 |
39 | def read_novel(path):
40 | with open(path, "r") as f:
41 | return f.read().decode("gb2312", 'ignore')
42 |
--------------------------------------------------------------------------------
/crawler/txt_downloader.py:
--------------------------------------------------------------------------------
1 | # coding=utf-8
2 | from __future__ import print_function
3 | import time
4 | from lib.utils import *
5 | from lib.config import *
6 | from urllib.parse import quote
7 | from urllib.request import urlretrieve
8 | import os.path
9 | import socket
10 | import sys
11 | socket.setdefaulttimeout(20)
12 |
13 |
14 | def reporthook(count, block_size, total_size):
15 | global start_time
16 | if count == 0:
17 | start_time = time.time()
18 | return
19 | duration = time.time() - start_time
20 | if duration == 0:
21 | duration = 1
22 | progress_size = int(count * block_size)
23 | speed = int(progress_size / (1024 * duration))
24 | percent = min(int(count * block_size * 100 / total_size), 100)
25 | sys.stdout.write("\r.....%d%%, %d KB, %d KB/s, %d seconds passed....." %
26 | (percent, progress_size / 1024, speed, duration))
27 | sys.stdout.flush()
28 |
29 |
30 | class TxtDownloader:
31 | """ 爬取小说的章节,存到数据库中 """
32 | def __init__(self):
33 | self.client = init_client()
34 | self.db = self.client[config['db_name']]
35 | self.novels = self.db.novels.find({'is_downloaded': False})
36 |
37 | def run(self):
38 | novels = []
39 | # 先把数据都读到内存里
40 | for novel in self.novels:
41 | novels.append(novel)
42 |
43 | for novel in novels:
44 | download_url = quote(str(novel['download_url'])).replace("https%3A", "https:")
45 | print("downloading", novel['_id'], novel['name'], novel['author'], novel["category"],
46 | download_url)
47 |
48 | filename = os.path.join('corpus', str(novel["_id"]) + ".txt")
49 | success = False
50 | while not success:
51 | try:
52 | urlretrieve(download_url, filename, reporthook)
53 | success = True
54 | except IOError as ex:
55 | if "HTTP Error 404: Not Found" in str(ex):
56 | break
57 | print("timeout error")
58 | time.sleep(1)
59 |
60 | # 判断爬取是否正确
61 | if success:
62 | print("\nSaved in", time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(time.time())))
63 | else:
64 | print("HTTP Error 404: Not Found")
65 | self.__update_failed_novel(novel) # 把novel的success设为false
66 | self.__update_novel(novel) # 把novel的is_downloaded设为true
67 | print("\n")
68 | time.sleep(1)
69 |
70 | self.__close()
71 |
72 | def __update_novel(self, novel):
73 | """ 把小说设置为已经爬去取过 """
74 | self.db.novels.update({'_id': novel['_id']}, {
75 | '$set': {'is_downloaded': True},
76 | })
77 |
78 | def __update_failed_novel(self, novel):
79 | """ 把小说设置为已经爬去取过 """
80 | self.db.novels.update({'_id': novel['_id']}, {
81 | '$set': {'success': False},
82 | })
83 |
84 | def __close(self):
85 | """ 关闭数据库 """
86 | self.client.close()
87 |
88 |
89 | if __name__ == '__main__':
90 | crawler = TxtDownloader()
91 | crawler.run()
92 | print("txt_downloader has been finished.")
93 |
--------------------------------------------------------------------------------
/requirements.txt:
--------------------------------------------------------------------------------
1 | pymongo
2 | requests
3 | lxml
4 | jieba
5 | bs4
6 | gevent
7 | numpy
8 | scikit-learn
9 | flask
10 | scipy
--------------------------------------------------------------------------------
/screenshot.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nladuo/novelRS/6bbb687e385f1137f387547d201f0dbbee1538c0/screenshot.png
--------------------------------------------------------------------------------
/web_demo/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": ["es2015", "stage-2"],
3 | "plugins": ["transform-runtime"],
4 | "comments": false
5 | }
6 |
--------------------------------------------------------------------------------
/web_demo/.editorconfig:
--------------------------------------------------------------------------------
1 | root = true
2 |
3 | [*.js]
4 | charset = utf-8
5 | indent_style = space
6 | indent_size = 2
7 | end_of_line = lf
8 | insert_final_newline = true
9 | trim_trailing_whitespace = true
10 |
11 | [*.vue]
12 | charset = utf-8
13 | indent_style = space
14 | indent_size = 2
15 | end_of_line = lf
16 | insert_final_newline = true
17 | trim_trailing_whitespace = true
18 |
--------------------------------------------------------------------------------
/web_demo/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | node_modules/
3 | npm-debug.log
4 | .idea/
5 | package-lock.json
--------------------------------------------------------------------------------
/web_demo/README.md:
--------------------------------------------------------------------------------
1 | # web_demo
2 |
3 | > Novel Recommend System WebSite Demo.
4 |
5 | ## Build Setup
6 |
7 | ``` bash
8 | # install dependencies
9 | npm install
10 |
11 | # serve with hot reload at localhost:8080
12 | npm run dev
13 |
14 | # build for production with minification
15 | npm run build
16 |
17 | For detailed explanation on how things work, checkout the [guide](http://vuejs-templates.github.io/webpack/) and [docs for vue-loader](http://vuejs.github.io/vue-loader).
18 |
--------------------------------------------------------------------------------
/web_demo/build/build.js:
--------------------------------------------------------------------------------
1 | // https://github.com/shelljs/shelljs
2 | require('shelljs/global')
3 | env.NODE_ENV = 'production'
4 |
5 | var path = require('path')
6 | var config = require('../config')
7 | var ora = require('ora')
8 | var webpack = require('webpack')
9 | var webpackConfig = require('./webpack.prod.conf')
10 |
11 | console.log(
12 | ' Tip:\n' +
13 | ' Built files are meant to be served over an HTTP server.\n' +
14 | ' Opening index.html over file:// won\'t work.\n'
15 | )
16 |
17 | var spinner = ora('building for production...')
18 | spinner.start()
19 |
20 | var assetsPath = path.join(config.build.assetsRoot, config.build.assetsSubDirectory)
21 | rm('-rf', assetsPath)
22 | mkdir('-p', assetsPath)
23 | cp('-R', 'static/', assetsPath)
24 |
25 | webpack(webpackConfig, function (err, stats) {
26 | spinner.stop()
27 | if (err) throw err
28 | process.stdout.write(stats.toString({
29 | colors: true,
30 | modules: false,
31 | children: false,
32 | chunks: false,
33 | chunkModules: false
34 | }) + '\n')
35 | })
36 |
--------------------------------------------------------------------------------
/web_demo/build/dev-client.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable */
2 | require('eventsource-polyfill')
3 | var hotClient = require('webpack-hot-middleware/client?noInfo=true&reload=true')
4 |
5 | hotClient.subscribe(function (event) {
6 | if (event.action === 'reload') {
7 | window.location.reload()
8 | }
9 | })
10 |
--------------------------------------------------------------------------------
/web_demo/build/dev-server.js:
--------------------------------------------------------------------------------
1 | var path = require('path')
2 | var express = require('express')
3 | var webpack = require('webpack')
4 | var config = require('../config')
5 | var proxyMiddleware = require('http-proxy-middleware')
6 | var webpackConfig = process.env.NODE_ENV === 'testing'
7 | ? require('./webpack.prod.conf')
8 | : require('./webpack.dev.conf')
9 |
10 | // default port where dev server listens for incoming traffic
11 | var port = process.env.PORT || config.dev.port
12 | // Define HTTP proxies to your custom API backend
13 | // https://github.com/chimurai/http-proxy-middleware
14 | var proxyTable = config.dev.proxyTable
15 |
16 | var app = express()
17 | var compiler = webpack(webpackConfig)
18 |
19 | var devMiddleware = require('webpack-dev-middleware')(compiler, {
20 | publicPath: webpackConfig.output.publicPath,
21 | stats: {
22 | colors: true,
23 | chunks: false
24 | }
25 | })
26 |
27 | var hotMiddleware = require('webpack-hot-middleware')(compiler)
28 | // force page reload when html-webpack-plugin template changes
29 | compiler.plugin('compilation', function (compilation) {
30 | compilation.plugin('html-webpack-plugin-after-emit', function (data, cb) {
31 | hotMiddleware.publish({ action: 'reload' })
32 | cb()
33 | })
34 | })
35 |
36 | // proxy api requests
37 | Object.keys(proxyTable).forEach(function (context) {
38 | var options = proxyTable[context]
39 | if (typeof options === 'string') {
40 | options = { target: options }
41 | }
42 | app.use(proxyMiddleware(context, options))
43 | })
44 |
45 | // handle fallback for HTML5 history API
46 | app.use(require('connect-history-api-fallback')())
47 |
48 | // serve webpack bundle output
49 | app.use(devMiddleware)
50 |
51 | // enable hot-reload and state-preserving
52 | // compilation error display
53 | app.use(hotMiddleware)
54 |
55 | // serve pure static assets
56 | var staticPath = path.posix.join(config.dev.assetsPublicPath, config.dev.assetsSubDirectory)
57 | app.use(staticPath, express.static('./static'))
58 |
59 | module.exports = app.listen(port, function (err) {
60 | if (err) {
61 | console.log(err)
62 | return
63 | }
64 | console.log('Listening at http://localhost:' + port + '\n')
65 | })
66 |
--------------------------------------------------------------------------------
/web_demo/build/utils.js:
--------------------------------------------------------------------------------
1 | var path = require('path')
2 | var config = require('../config')
3 | var ExtractTextPlugin = require('extract-text-webpack-plugin')
4 |
5 | exports.assetsPath = function (_path) {
6 | var assetsSubDirectory = process.env.NODE_ENV === 'production'
7 | ? config.build.assetsSubDirectory
8 | : config.dev.assetsSubDirectory
9 | return path.posix.join(assetsSubDirectory, _path)
10 | }
11 |
12 | exports.cssLoaders = function (options) {
13 | options = options || {}
14 | // generate loader string to be used with extract text plugin
15 | function generateLoaders (loaders) {
16 | var sourceLoader = loaders.map(function (loader) {
17 | var extraParamChar
18 | if (/\?/.test(loader)) {
19 | loader = loader.replace(/\?/, '-loader?')
20 | extraParamChar = '&'
21 | } else {
22 | loader = loader + '-loader'
23 | extraParamChar = '?'
24 | }
25 | return loader + (options.sourceMap ? extraParamChar + 'sourceMap' : '')
26 | }).join('!')
27 |
28 | if (options.extract) {
29 | return ExtractTextPlugin.extract('vue-style-loader', sourceLoader)
30 | } else {
31 | return ['vue-style-loader', sourceLoader].join('!')
32 | }
33 | }
34 |
35 | // http://vuejs.github.io/vue-loader/configurations/extract-css.html
36 | return {
37 | css: generateLoaders(['css']),
38 | postcss: generateLoaders(['css']),
39 | less: generateLoaders(['css', 'less']),
40 | sass: generateLoaders(['css', 'sass?indentedSyntax']),
41 | scss: generateLoaders(['css', 'sass']),
42 | stylus: generateLoaders(['css', 'stylus']),
43 | styl: generateLoaders(['css', 'stylus'])
44 | }
45 | }
46 |
47 | // Generate loaders for standalone style files (outside of .vue)
48 | exports.styleLoaders = function (options) {
49 | var output = []
50 | var loaders = exports.cssLoaders(options)
51 | for (var extension in loaders) {
52 | var loader = loaders[extension]
53 | output.push({
54 | test: new RegExp('\\.' + extension + '$'),
55 | loader: loader
56 | })
57 | }
58 | return output
59 | }
60 |
--------------------------------------------------------------------------------
/web_demo/build/webpack.base.conf.js:
--------------------------------------------------------------------------------
1 | var path = require('path')
2 | var config = require('../config')
3 | var utils = require('./utils')
4 | var projectRoot = path.resolve(__dirname, '../')
5 |
6 | module.exports = {
7 | entry: {
8 | app: './src/main.js'
9 | },
10 | output: {
11 | path: config.build.assetsRoot,
12 | publicPath: process.env.NODE_ENV === 'production' ? config.build.assetsPublicPath : config.dev.assetsPublicPath,
13 | filename: '[name].js'
14 | },
15 | resolve: {
16 | extensions: ['', '.js', '.vue'],
17 | fallback: [path.join(__dirname, '../node_modules')],
18 | alias: {
19 | 'src': path.resolve(__dirname, '../src'),
20 | 'assets': path.resolve(__dirname, '../src/assets'),
21 | 'components': path.resolve(__dirname, '../src/components')
22 | }
23 | },
24 | resolveLoader: {
25 | fallback: [path.join(__dirname, '../node_modules')]
26 | },
27 | module: {
28 | loaders: [
29 | {
30 | test: /\.vue$/,
31 | loader: 'vue'
32 | },
33 | {
34 | test: /\.js$/,
35 | loader: 'babel',
36 | include: projectRoot,
37 | exclude: /node_modules/
38 | },
39 | {
40 | test: /\.json$/,
41 | loader: 'json'
42 | },
43 | {
44 | test: /\.html$/,
45 | loader: 'vue-html'
46 | },
47 | {
48 | test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
49 | loader: 'url',
50 | query: {
51 | limit: 10000,
52 | name: utils.assetsPath('img/[name].[hash:7].[ext]')
53 | }
54 | },
55 | {
56 | test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/,
57 | loader: 'url',
58 | query: {
59 | limit: 10000,
60 | name: utils.assetsPath('fonts/[name].[hash:7].[ext]')
61 | }
62 | }
63 | ]
64 | },
65 | vue: {
66 | loaders: utils.cssLoaders()
67 | }
68 | }
69 |
--------------------------------------------------------------------------------
/web_demo/build/webpack.dev.conf.js:
--------------------------------------------------------------------------------
1 | var config = require('../config')
2 | var webpack = require('webpack')
3 | var merge = require('webpack-merge')
4 | var utils = require('./utils')
5 | var baseWebpackConfig = require('./webpack.base.conf')
6 | var HtmlWebpackPlugin = require('html-webpack-plugin')
7 |
8 | // add hot-reload related code to entry chunks
9 | Object.keys(baseWebpackConfig.entry).forEach(function (name) {
10 | baseWebpackConfig.entry[name] = ['./build/dev-client'].concat(baseWebpackConfig.entry[name])
11 | })
12 |
13 | module.exports = merge(baseWebpackConfig, {
14 | module: {
15 | loaders: utils.styleLoaders({ sourceMap: config.dev.cssSourceMap })
16 | },
17 | // eval-source-map is faster for development
18 | devtool: '#eval-source-map',
19 | plugins: [
20 | new webpack.DefinePlugin({
21 | 'process.env': config.dev.env
22 | }),
23 | // https://github.com/glenjamin/webpack-hot-middleware#installation--usage
24 | new webpack.optimize.OccurenceOrderPlugin(),
25 | new webpack.HotModuleReplacementPlugin(),
26 | new webpack.NoErrorsPlugin(),
27 | // https://github.com/ampedandwired/html-webpack-plugin
28 | new HtmlWebpackPlugin({
29 | filename: 'index.html',
30 | template: 'index.html',
31 | inject: true
32 | })
33 | ]
34 | })
35 |
--------------------------------------------------------------------------------
/web_demo/build/webpack.prod.conf.js:
--------------------------------------------------------------------------------
1 | var path = require('path')
2 | var config = require('../config')
3 | var utils = require('./utils')
4 | var webpack = require('webpack')
5 | var merge = require('webpack-merge')
6 | var baseWebpackConfig = require('./webpack.base.conf')
7 | var ExtractTextPlugin = require('extract-text-webpack-plugin')
8 | var HtmlWebpackPlugin = require('html-webpack-plugin')
9 | var env = process.env.NODE_ENV === 'testing'
10 | ? require('../config/test.env')
11 | : config.build.env
12 |
13 | var webpackConfig = merge(baseWebpackConfig, {
14 | module: {
15 | loaders: utils.styleLoaders({ sourceMap: config.build.productionSourceMap, extract: true })
16 | },
17 | devtool: config.build.productionSourceMap ? '#source-map' : false,
18 | output: {
19 | path: config.build.assetsRoot,
20 | filename: utils.assetsPath('js/[name].[chunkhash].js'),
21 | chunkFilename: utils.assetsPath('js/[id].[chunkhash].js')
22 | },
23 | vue: {
24 | loaders: utils.cssLoaders({
25 | sourceMap: config.build.productionSourceMap,
26 | extract: true
27 | })
28 | },
29 | plugins: [
30 | // http://vuejs.github.io/vue-loader/workflow/production.html
31 | new webpack.DefinePlugin({
32 | 'process.env': env
33 | }),
34 | new webpack.optimize.UglifyJsPlugin({
35 | compress: {
36 | warnings: false
37 | }
38 | }),
39 | new webpack.optimize.OccurenceOrderPlugin(),
40 | // extract css into its own file
41 | new ExtractTextPlugin(utils.assetsPath('css/[name].[contenthash].css')),
42 | // generate dist index.html with correct asset hash for caching.
43 | // you can customize output by editing /index.html
44 | // see https://github.com/ampedandwired/html-webpack-plugin
45 | new HtmlWebpackPlugin({
46 | filename: process.env.NODE_ENV === 'testing'
47 | ? 'index.html'
48 | : config.build.index,
49 | template: 'index.html',
50 | inject: true,
51 | minify: {
52 | removeComments: true,
53 | collapseWhitespace: true,
54 | removeAttributeQuotes: true
55 | // more options:
56 | // https://github.com/kangax/html-minifier#options-quick-reference
57 | },
58 | // necessary to consistently work with multiple chunks via CommonsChunkPlugin
59 | chunksSortMode: 'dependency'
60 | }),
61 | // split vendor js into its own file
62 | new webpack.optimize.CommonsChunkPlugin({
63 | name: 'vendor',
64 | minChunks: function (module, count) {
65 | // any required modules inside node_modules are extracted to vendor
66 | return (
67 | module.resource &&
68 | /\.js$/.test(module.resource) &&
69 | module.resource.indexOf(
70 | path.join(__dirname, '../node_modules')
71 | ) === 0
72 | )
73 | }
74 | }),
75 | // extract webpack runtime and module manifest to its own file in order to
76 | // prevent vendor hash from being updated whenever app bundle is updated
77 | new webpack.optimize.CommonsChunkPlugin({
78 | name: 'manifest',
79 | chunks: ['vendor']
80 | })
81 | ]
82 | })
83 |
84 | if (config.build.productionGzip) {
85 | var CompressionWebpackPlugin = require('compression-webpack-plugin')
86 |
87 | webpackConfig.plugins.push(
88 | new CompressionWebpackPlugin({
89 | asset: '[path].gz[query]',
90 | algorithm: 'gzip',
91 | test: new RegExp(
92 | '\\.(' +
93 | config.build.productionGzipExtensions.join('|') +
94 | ')$'
95 | ),
96 | threshold: 10240,
97 | minRatio: 0.8
98 | })
99 | )
100 | }
101 |
102 | module.exports = webpackConfig
103 |
--------------------------------------------------------------------------------
/web_demo/config/dev.env.js:
--------------------------------------------------------------------------------
1 | var merge = require('webpack-merge')
2 | var prodEnv = require('./prod.env')
3 |
4 | module.exports = merge(prodEnv, {
5 | NODE_ENV: '"development"'
6 | })
7 |
--------------------------------------------------------------------------------
/web_demo/config/index.js:
--------------------------------------------------------------------------------
1 | // see http://vuejs-templates.github.io/webpack for documentation.
2 | var path = require('path')
3 |
4 | module.exports = {
5 | build: {
6 | env: require('./prod.env'),
7 | index: path.resolve(__dirname, '../dist/index.html'),
8 | assetsRoot: path.resolve(__dirname, '../dist'),
9 | assetsSubDirectory: 'static',
10 | assetsPublicPath: '/',
11 | productionSourceMap: true,
12 | // Gzip off by default as many popular static hosts such as
13 | // Surge or Netlify already gzip all static assets for you.
14 | // Before setting to `true`, make sure to:
15 | // npm install --save-dev compression-webpack-plugin
16 | productionGzip: false,
17 | productionGzipExtensions: ['js', 'css']
18 | },
19 | dev: {
20 | env: require('./dev.env'),
21 | port: 8080,
22 | assetsSubDirectory: 'static',
23 | assetsPublicPath: '/',
24 | proxyTable: {},
25 | // CSS Sourcemaps off by default because relative paths are "buggy"
26 | // with this option, according to the CSS-Loader README
27 | // (https://github.com/webpack/css-loader#sourcemaps)
28 | // In our experience, they generally work as expected,
29 | // just be aware of this issue when enabling this option.
30 | cssSourceMap: false
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/web_demo/config/prod.env.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | NODE_ENV: '"production"'
3 | }
4 |
--------------------------------------------------------------------------------
/web_demo/config/test.env.js:
--------------------------------------------------------------------------------
1 | var merge = require('webpack-merge')
2 | var devEnv = require('./dev.env')
3 |
4 | module.exports = merge(devEnv, {
5 | NODE_ENV: '"testing"'
6 | })
7 |
--------------------------------------------------------------------------------
/web_demo/dist/index.html:
--------------------------------------------------------------------------------
1 |
网络小说推荐系统
--------------------------------------------------------------------------------
/web_demo/dist/static/js/app.d2d173414305722a1a2d.js:
--------------------------------------------------------------------------------
1 | webpackJsonp([1,0],[function(e,t,o){"use strict";function n(e){return e&&e.__esModule?e:{default:e}}var r=o(1),s=n(r),u=o(13),a=n(u);new s.default({el:"body",components:{App:a.default}})},,function(e,t){"use strict";Object.defineProperty(t,"__esModule",{value:!0});t.searchNovels=function(e,t){var o=e.dispatch;o("SEARCH_NOVELS",t)}},function(e,t){"use strict";function o(e){return e.novels}Object.defineProperty(t,"__esModule",{value:!0}),t.getNovels=o},function(e,t,o){"use strict";function n(e){return e&&e.__esModule?e:{default:e}}Object.defineProperty(t,"__esModule",{value:!0});var r=o(1),s=n(r),u=o(17),a=n(u);s.default.use(a.default);var c={novels:[]},l={SEARCH_NOVELS:function(e,t){var o="/api/search/"+t;$.ajax({type:"GET",url:o,dataType:"json",success:function(o){e.novels=o,0==o.length&&alert("未找到"+t)}})}};t.default=new a.default.Store({state:c,mutations:l})},function(e,t,o){"use strict";function n(e){return e&&e.__esModule?e:{default:e}}Object.defineProperty(t,"__esModule",{value:!0});var r=o(15),s=n(r),u=o(16),a=n(u),c=o(14),l=n(c),d=o(4),p=n(d);t.default={components:{NavBar:l.default,Search:a.default,NovelList:s.default},store:p.default}},function(e,t){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default={}},function(e,t,o){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var n=o(3);t.default={methods:{convert:function(e){return Math.floor(1e4*e)/100+"%"}},vuex:{getters:{novels:n.getNovels}}}},function(e,t,o){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var n=o(2);t.default={data:function(){return{novel_name:""}},vuex:{actions:{searchNovels:n.searchNovels}},methods:{search:function(){this.searchNovels(this.novel_name)}}}},function(e,t){e.exports="
"},function(e,t){e.exports=" "},function(e,t){e.exports=' 书名 | 作者 | 分类 | 相似度 |
{{ novel.name }} | {{ novel.author }} | {{ novel.category }} | {{ convert(novel.similarity) }} |
'},function(e,t){e.exports=' '},function(e,t,o){var n,r,s={};n=o(5),r=o(9),e.exports=n||{},e.exports.__esModule&&(e.exports=e.exports.default);var u="function"==typeof e.exports?e.exports.options||(e.exports.options={}):e.exports;r&&(u.template=r),u.computed||(u.computed={}),Object.keys(s).forEach(function(e){var t=s[e];u.computed[e]=function(){return t}})},function(e,t,o){var n,r,s={};n=o(6),r=o(10),e.exports=n||{},e.exports.__esModule&&(e.exports=e.exports.default);var u="function"==typeof e.exports?e.exports.options||(e.exports.options={}):e.exports;r&&(u.template=r),u.computed||(u.computed={}),Object.keys(s).forEach(function(e){var t=s[e];u.computed[e]=function(){return t}})},function(e,t,o){var n,r,s={};n=o(7),r=o(11),e.exports=n||{},e.exports.__esModule&&(e.exports=e.exports.default);var u="function"==typeof e.exports?e.exports.options||(e.exports.options={}):e.exports;r&&(u.template=r),u.computed||(u.computed={}),Object.keys(s).forEach(function(e){var t=s[e];u.computed[e]=function(){return t}})},function(e,t,o){var n,r,s={};n=o(8),r=o(12),e.exports=n||{},e.exports.__esModule&&(e.exports=e.exports.default);var u="function"==typeof e.exports?e.exports.options||(e.exports.options={}):e.exports;r&&(u.template=r),u.computed||(u.computed={}),Object.keys(s).forEach(function(e){var t=s[e];u.computed[e]=function(){return t}})}]);
2 | //# sourceMappingURL=app.d2d173414305722a1a2d.js.map
--------------------------------------------------------------------------------
/web_demo/dist/static/js/app.d2d173414305722a1a2d.js.map:
--------------------------------------------------------------------------------
1 | {"version":3,"sources":["webpack:///static/js/app.d2d173414305722a1a2d.js","webpack:///./src/main.js","webpack:///./src/vuex/actions.js","webpack:///./src/vuex/getters.js","webpack:///./src/vuex/store.js","webpack:///App.vue","webpack:///NovelList.vue","webpack:///Search.vue","webpack:///./src/App.vue?d818","webpack:///./src/components/NavBar.vue?a699","webpack:///./src/components/NovelList.vue?23c4","webpack:///./src/components/Search.vue?699a","webpack:///./src/App.vue","webpack:///./src/components/NavBar.vue","webpack:///./src/components/NovelList.vue","webpack:///./src/components/Search.vue"],"names":["webpackJsonp","module","exports","__webpack_require__","_interopRequireDefault","obj","__esModule","default","_vue","_vue2","_App","_App2","Vue","el","components","App","Object","defineProperty","value","searchNovels","_ref","novel_name","dispatch","getNovels","state","novels","_vuex","_vuex2","use","Vuex","mutations","SEARCH_NOVELS","name","url","$","ajax","type","dataType","success","data","length","alert","Store","_NovelList","_NovelList2","_Search","_Search2","_NavBar","_NavBar2","_store","_store2","NavBar","Search","NovelList","store","_getters","methods","convert","similarity","Math","floor","vuex","getters","_actions","actions","search","this","__vue_script__","__vue_template__","__vue_styles__","__vue_options__","options","template","computed","keys","forEach","key"],"mappings":"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","file":"static/js/app.d2d173414305722a1a2d.js","sourcesContent":["webpackJsonp([1,0],[\n/* 0 */\n/***/ (function(module, exports, __webpack_require__) {\n\n\t'use strict';\n\t\n\tvar _vue = __webpack_require__(1);\n\t\n\tvar _vue2 = _interopRequireDefault(_vue);\n\t\n\tvar _App = __webpack_require__(13);\n\t\n\tvar _App2 = _interopRequireDefault(_App);\n\t\n\tfunction _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }\n\t\n\tnew _vue2.default({\n\t el: 'body',\n\t components: { App: _App2.default }\n\t});\n\n/***/ }),\n/* 1 */,\n/* 2 */\n/***/ (function(module, exports) {\n\n\t'use strict';\n\t\n\tObject.defineProperty(exports, \"__esModule\", {\n\t value: true\n\t});\n\tvar searchNovels = exports.searchNovels = function searchNovels(_ref, novel_name) {\n\t var dispatch = _ref.dispatch;\n\t\n\t dispatch('SEARCH_NOVELS', novel_name);\n\t};\n\n/***/ }),\n/* 3 */\n/***/ (function(module, exports) {\n\n\t\"use strict\";\n\t\n\tObject.defineProperty(exports, \"__esModule\", {\n\t value: true\n\t});\n\texports.getNovels = getNovels;\n\tfunction getNovels(state) {\n\t return state.novels;\n\t}\n\n/***/ }),\n/* 4 */\n/***/ (function(module, exports, __webpack_require__) {\n\n\t'use strict';\n\t\n\tObject.defineProperty(exports, \"__esModule\", {\n\t value: true\n\t});\n\t\n\tvar _vue = __webpack_require__(1);\n\t\n\tvar _vue2 = _interopRequireDefault(_vue);\n\t\n\tvar _vuex = __webpack_require__(17);\n\t\n\tvar _vuex2 = _interopRequireDefault(_vuex);\n\t\n\tfunction _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }\n\t\n\t_vue2.default.use(_vuex2.default);\n\t\n\tvar state = {\n\t novels: []\n\t};\n\t\n\tvar mutations = {\n\t SEARCH_NOVELS: function SEARCH_NOVELS(state, name) {\n\t var url = '/api/search/' + name;\n\t $.ajax({\n\t type: \"GET\",\n\t url: url,\n\t dataType: \"json\",\n\t success: function success(data) {\n\t state.novels = data;\n\t if (data.length == 0) {\n\t alert(\"未找到\" + name);\n\t }\n\t }\n\t });\n\t }\n\t};\n\t\n\texports.default = new _vuex2.default.Store({\n\t state: state,\n\t mutations: mutations\n\t});\n\n/***/ }),\n/* 5 */\n/***/ (function(module, exports, __webpack_require__) {\n\n\t'use strict';\n\t\n\tObject.defineProperty(exports, \"__esModule\", {\n\t value: true\n\t});\n\t\n\tvar _NovelList = __webpack_require__(15);\n\t\n\tvar _NovelList2 = _interopRequireDefault(_NovelList);\n\t\n\tvar _Search = __webpack_require__(16);\n\t\n\tvar _Search2 = _interopRequireDefault(_Search);\n\t\n\tvar _NavBar = __webpack_require__(14);\n\t\n\tvar _NavBar2 = _interopRequireDefault(_NavBar);\n\t\n\tvar _store = __webpack_require__(4);\n\t\n\tvar _store2 = _interopRequireDefault(_store);\n\t\n\tfunction _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }\n\t\n\texports.default = {\n\t components: {\n\t NavBar: _NavBar2.default,\n\t Search: _Search2.default,\n\t NovelList: _NovelList2.default\n\t },\n\t store: _store2.default\n\t};\n\n/***/ }),\n/* 6 */\n/***/ (function(module, exports) {\n\n\t\"use strict\";\n\n\tObject.defineProperty(exports, \"__esModule\", {\n\t value: true\n\t});\n\texports.default = {};\n\n/***/ }),\n/* 7 */\n/***/ (function(module, exports, __webpack_require__) {\n\n\t'use strict';\n\t\n\tObject.defineProperty(exports, \"__esModule\", {\n\t value: true\n\t});\n\t\n\tvar _getters = __webpack_require__(3);\n\t\n\texports.default = {\n\t methods: {\n\t convert: function convert(similarity) {\n\t return Math.floor(similarity * 10000) / 100 + '%';\n\t }\n\t },\n\t vuex: {\n\t getters: {\n\t novels: _getters.getNovels\n\t }\n\t }\n\t};\n\n/***/ }),\n/* 8 */\n/***/ (function(module, exports, __webpack_require__) {\n\n\t\"use strict\";\n\t\n\tObject.defineProperty(exports, \"__esModule\", {\n\t value: true\n\t});\n\t\n\tvar _actions = __webpack_require__(2);\n\t\n\texports.default = {\n\t data: function data() {\n\t return {\n\t novel_name: \"\"\n\t };\n\t },\n\t\n\t vuex: {\n\t actions: {\n\t searchNovels: _actions.searchNovels\n\t }\n\t },\n\t methods: {\n\t search: function search() {\n\t this.searchNovels(this.novel_name);\n\t }\n\t }\n\t};\n\n/***/ }),\n/* 9 */\n/***/ (function(module, exports) {\n\n\tmodule.exports = \"
\";\n\n/***/ }),\n/* 10 */\n/***/ (function(module, exports) {\n\n\tmodule.exports = \" \";\n\n/***/ }),\n/* 11 */\n/***/ (function(module, exports) {\n\n\tmodule.exports = \" 书名 | 作者 | 分类 | 相似度 |
{{ novel.name }} | {{ novel.author }} | {{ novel.category }} | {{ convert(novel.similarity) }} |
\";\n\n/***/ }),\n/* 12 */\n/***/ (function(module, exports) {\n\n\tmodule.exports = \" \";\n\n/***/ }),\n/* 13 */\n/***/ (function(module, exports, __webpack_require__) {\n\n\tvar __vue_script__, __vue_template__\n\tvar __vue_styles__ = {}\n\t__vue_script__ = __webpack_require__(5)\n\t__vue_template__ = __webpack_require__(9)\n\tmodule.exports = __vue_script__ || {}\n\tif (module.exports.__esModule) module.exports = module.exports.default\n\tvar __vue_options__ = typeof module.exports === \"function\" ? (module.exports.options || (module.exports.options = {})) : module.exports\n\tif (__vue_template__) {\n\t__vue_options__.template = __vue_template__\n\t}\n\tif (!__vue_options__.computed) __vue_options__.computed = {}\n\tObject.keys(__vue_styles__).forEach(function (key) {\n\tvar module = __vue_styles__[key]\n\t__vue_options__.computed[key] = function () { return module }\n\t})\n\n\n/***/ }),\n/* 14 */\n/***/ (function(module, exports, __webpack_require__) {\n\n\tvar __vue_script__, __vue_template__\n\tvar __vue_styles__ = {}\n\t__vue_script__ = __webpack_require__(6)\n\t__vue_template__ = __webpack_require__(10)\n\tmodule.exports = __vue_script__ || {}\n\tif (module.exports.__esModule) module.exports = module.exports.default\n\tvar __vue_options__ = typeof module.exports === \"function\" ? (module.exports.options || (module.exports.options = {})) : module.exports\n\tif (__vue_template__) {\n\t__vue_options__.template = __vue_template__\n\t}\n\tif (!__vue_options__.computed) __vue_options__.computed = {}\n\tObject.keys(__vue_styles__).forEach(function (key) {\n\tvar module = __vue_styles__[key]\n\t__vue_options__.computed[key] = function () { return module }\n\t})\n\n\n/***/ }),\n/* 15 */\n/***/ (function(module, exports, __webpack_require__) {\n\n\tvar __vue_script__, __vue_template__\n\tvar __vue_styles__ = {}\n\t__vue_script__ = __webpack_require__(7)\n\t__vue_template__ = __webpack_require__(11)\n\tmodule.exports = __vue_script__ || {}\n\tif (module.exports.__esModule) module.exports = module.exports.default\n\tvar __vue_options__ = typeof module.exports === \"function\" ? (module.exports.options || (module.exports.options = {})) : module.exports\n\tif (__vue_template__) {\n\t__vue_options__.template = __vue_template__\n\t}\n\tif (!__vue_options__.computed) __vue_options__.computed = {}\n\tObject.keys(__vue_styles__).forEach(function (key) {\n\tvar module = __vue_styles__[key]\n\t__vue_options__.computed[key] = function () { return module }\n\t})\n\n\n/***/ }),\n/* 16 */\n/***/ (function(module, exports, __webpack_require__) {\n\n\tvar __vue_script__, __vue_template__\n\tvar __vue_styles__ = {}\n\t__vue_script__ = __webpack_require__(8)\n\t__vue_template__ = __webpack_require__(12)\n\tmodule.exports = __vue_script__ || {}\n\tif (module.exports.__esModule) module.exports = module.exports.default\n\tvar __vue_options__ = typeof module.exports === \"function\" ? (module.exports.options || (module.exports.options = {})) : module.exports\n\tif (__vue_template__) {\n\t__vue_options__.template = __vue_template__\n\t}\n\tif (!__vue_options__.computed) __vue_options__.computed = {}\n\tObject.keys(__vue_styles__).forEach(function (key) {\n\tvar module = __vue_styles__[key]\n\t__vue_options__.computed[key] = function () { return module }\n\t})\n\n\n/***/ })\n]);\n\n\n// WEBPACK FOOTER //\n// static/js/app.d2d173414305722a1a2d.js","import Vue from 'vue'\r\nimport App from './App'\r\n\r\nnew Vue({\r\n el: 'body',\r\n components: { App }\r\n});\r\n\n\n\n// WEBPACK FOOTER //\n// ./src/main.js","/**\r\n * Created by kalen on 10/14/16.\r\n */\r\n\r\nexport const searchNovels = ({ dispatch }, novel_name) => {\r\n dispatch('SEARCH_NOVELS', novel_name)\r\n};\r\n\n\n\n// WEBPACK FOOTER //\n// ./src/vuex/actions.js","/**\r\n * Created by kalen on 10/14/16.\r\n */\r\n\r\nexport function getNovels (state) {\r\n return state.novels\r\n}\r\n\n\n\n// WEBPACK FOOTER //\n// ./src/vuex/getters.js","/**\r\n * Created by kalen on 10/11/16.\r\n */\r\n\r\nimport Vue from 'vue'\r\nimport Vuex from 'vuex'\r\n\r\nVue.use(Vuex);\r\n\r\nconst state = {\r\n novels: []\r\n};\r\n\r\nconst mutations = {\r\n SEARCH_NOVELS (state, name) {\r\n let url = '/api/search/' + name;\r\n $.ajax({\r\n type: \"GET\",\r\n url: url,\r\n dataType: \"json\",\r\n success: (data) => {\r\n state.novels = data;\r\n if (data.length == 0){\r\n alert(\"未找到\" + name);\r\n }\r\n }\r\n });\r\n }\r\n};\r\n\r\n\r\nexport default new Vuex.Store({\r\n state,\r\n mutations\r\n});\r\n\n\n\n// WEBPACK FOOTER //\n// ./src/vuex/store.js","\r\n \r\n \r\n \r\n \r\n
\r\n\r\n\r\n\r\n\n\n\n// WEBPACK FOOTER //\n// App.vue?2755cc5b","\r\n \r\n \r\n \r\n 书名 | \r\n 作者 | \r\n 分类 | \r\n 相似度 | \r\n
\r\n \r\n \r\n \r\n {{ novel.name }} | \r\n {{ novel.author }} | \r\n {{ novel.category }} | \r\n {{ convert(novel.similarity) }} | \r\n
\r\n \r\n
\r\n\r\n\r\n\r\n\n\n\n// WEBPACK FOOTER //\n// NovelList.vue?f1707bf2","\r\n \r\n\r\n\r\n\r\n\n\n\n// WEBPACK FOOTER //\n// Search.vue?4b8ffd04","module.exports = \"
\";\n\n\n//////////////////\n// WEBPACK FOOTER\n// ./~/vue-html-loader!./~/vue-loader/lib/selector.js?type=template&index=0!./src/App.vue\n// module id = 9\n// module chunks = 1","module.exports = \" \";\n\n\n//////////////////\n// WEBPACK FOOTER\n// ./~/vue-html-loader!./~/vue-loader/lib/selector.js?type=template&index=0!./src/components/NavBar.vue\n// module id = 10\n// module chunks = 1","module.exports = \" 书名 | 作者 | 分类 | 相似度 |
{{ novel.name }} | {{ novel.author }} | {{ novel.category }} | {{ convert(novel.similarity) }} |
\";\n\n\n//////////////////\n// WEBPACK FOOTER\n// ./~/vue-html-loader!./~/vue-loader/lib/selector.js?type=template&index=0!./src/components/NovelList.vue\n// module id = 11\n// module chunks = 1","module.exports = \" \";\n\n\n//////////////////\n// WEBPACK FOOTER\n// ./~/vue-html-loader!./~/vue-loader/lib/selector.js?type=template&index=0!./src/components/Search.vue\n// module id = 12\n// module chunks = 1","var __vue_script__, __vue_template__\nvar __vue_styles__ = {}\n__vue_script__ = require(\"!!babel-loader?presets[]=es2015&plugins[]=transform-runtime&comments=false!../node_modules/vue-loader/lib/selector.js?type=script&index=0!./App.vue\")\n__vue_template__ = require(\"!!vue-html-loader!../node_modules/vue-loader/lib/selector.js?type=template&index=0!./App.vue\")\nmodule.exports = __vue_script__ || {}\nif (module.exports.__esModule) module.exports = module.exports.default\nvar __vue_options__ = typeof module.exports === \"function\" ? (module.exports.options || (module.exports.options = {})) : module.exports\nif (__vue_template__) {\n__vue_options__.template = __vue_template__\n}\nif (!__vue_options__.computed) __vue_options__.computed = {}\nObject.keys(__vue_styles__).forEach(function (key) {\nvar module = __vue_styles__[key]\n__vue_options__.computed[key] = function () { return module }\n})\n\n\n\n//////////////////\n// WEBPACK FOOTER\n// ./src/App.vue\n// module id = 13\n// module chunks = 1","var __vue_script__, __vue_template__\nvar __vue_styles__ = {}\n__vue_script__ = require(\"!!babel-loader?presets[]=es2015&plugins[]=transform-runtime&comments=false!../../node_modules/vue-loader/lib/selector.js?type=script&index=0!./NavBar.vue\")\n__vue_template__ = require(\"!!vue-html-loader!../../node_modules/vue-loader/lib/selector.js?type=template&index=0!./NavBar.vue\")\nmodule.exports = __vue_script__ || {}\nif (module.exports.__esModule) module.exports = module.exports.default\nvar __vue_options__ = typeof module.exports === \"function\" ? (module.exports.options || (module.exports.options = {})) : module.exports\nif (__vue_template__) {\n__vue_options__.template = __vue_template__\n}\nif (!__vue_options__.computed) __vue_options__.computed = {}\nObject.keys(__vue_styles__).forEach(function (key) {\nvar module = __vue_styles__[key]\n__vue_options__.computed[key] = function () { return module }\n})\n\n\n\n//////////////////\n// WEBPACK FOOTER\n// ./src/components/NavBar.vue\n// module id = 14\n// module chunks = 1","var __vue_script__, __vue_template__\nvar __vue_styles__ = {}\n__vue_script__ = require(\"!!babel-loader?presets[]=es2015&plugins[]=transform-runtime&comments=false!../../node_modules/vue-loader/lib/selector.js?type=script&index=0!./NovelList.vue\")\n__vue_template__ = require(\"!!vue-html-loader!../../node_modules/vue-loader/lib/selector.js?type=template&index=0!./NovelList.vue\")\nmodule.exports = __vue_script__ || {}\nif (module.exports.__esModule) module.exports = module.exports.default\nvar __vue_options__ = typeof module.exports === \"function\" ? (module.exports.options || (module.exports.options = {})) : module.exports\nif (__vue_template__) {\n__vue_options__.template = __vue_template__\n}\nif (!__vue_options__.computed) __vue_options__.computed = {}\nObject.keys(__vue_styles__).forEach(function (key) {\nvar module = __vue_styles__[key]\n__vue_options__.computed[key] = function () { return module }\n})\n\n\n\n//////////////////\n// WEBPACK FOOTER\n// ./src/components/NovelList.vue\n// module id = 15\n// module chunks = 1","var __vue_script__, __vue_template__\nvar __vue_styles__ = {}\n__vue_script__ = require(\"!!babel-loader?presets[]=es2015&plugins[]=transform-runtime&comments=false!../../node_modules/vue-loader/lib/selector.js?type=script&index=0!./Search.vue\")\n__vue_template__ = require(\"!!vue-html-loader!../../node_modules/vue-loader/lib/selector.js?type=template&index=0!./Search.vue\")\nmodule.exports = __vue_script__ || {}\nif (module.exports.__esModule) module.exports = module.exports.default\nvar __vue_options__ = typeof module.exports === \"function\" ? (module.exports.options || (module.exports.options = {})) : module.exports\nif (__vue_template__) {\n__vue_options__.template = __vue_template__\n}\nif (!__vue_options__.computed) __vue_options__.computed = {}\nObject.keys(__vue_styles__).forEach(function (key) {\nvar module = __vue_styles__[key]\n__vue_options__.computed[key] = function () { return module }\n})\n\n\n\n//////////////////\n// WEBPACK FOOTER\n// ./src/components/Search.vue\n// module id = 16\n// module chunks = 1"],"sourceRoot":""}
--------------------------------------------------------------------------------
/web_demo/dist/static/js/manifest.b6282e62578cc7cefbdf.js:
--------------------------------------------------------------------------------
1 | !function(e){function t(r){if(a[r])return a[r].exports;var n=a[r]={exports:{},id:r,loaded:!1};return e[r].call(n.exports,n,n.exports,t),n.loaded=!0,n.exports}var r=window.webpackJsonp;window.webpackJsonp=function(o,p){for(var c,l,s=0,d=[];s1?t.apply(e,arguments):t.call(e,i):t.call(e)}}function g(t,e){e=e||0;for(var i=t.length-e,n=new Array(i);i--;)n[i]=t[i+e];return n}function _(t,e){for(var i=Object.keys(e),n=i.length;n--;)t[i[n]]=e[i[n]];return t}function y(t){return null!==t&&"object"==typeof t}function b(t){return Qi.call(t)===Gi}function w(t,e,i,n){Object.defineProperty(t,e,{value:i,enumerable:!!n,writable:!0,configurable:!0})}function C(t,e){var i,n,r,s,o,a=function a(){var h=Date.now()-s;h=0?i=setTimeout(a,e-h):(i=null,o=t.apply(r,n),i||(r=n=null))};return function(){return r=this,n=arguments,s=Date.now(),i||(i=setTimeout(a,e)),o}}function $(t,e){for(var i=t.length;i--;)if(t[i]===e)return i;return-1}function k(t){var e=function e(){if(!e.cancelled)return t.apply(this,arguments)};return e.cancel=function(){e.cancelled=!0},e}function x(t,e){return t==e||!(!y(t)||!y(e))&&JSON.stringify(t)===JSON.stringify(e)}function A(t){return/native code/.test(t.toString())}function O(t){this.size=0,this.limit=t,this.head=this.tail=void 0,this._keymap=Object.create(null)}function T(){return vn.charCodeAt(_n+1)}function N(){return vn.charCodeAt(++_n)}function E(){return _n>=gn}function j(){for(;T()===jn;)N()}function S(t){return t===On||t===Tn}function F(t){return Sn[t]}function D(t,e){return Fn[t]===e}function P(){for(var t,e=N();!E();)if(t=N(),t===En)N();else if(t===e)break}function M(t){for(var e=0,i=t;!E();)if(t=T(),S(t))P();else if(i===t&&e++,D(i,t)&&e--,N(),0===e)break}function R(){for(var t=_n;!E();)if(yn=T(),S(yn))P();else if(F(yn))M(yn);else if(yn===Nn){if(N(),yn=T(),yn!==Nn){bn!==$n&&bn!==An||(bn=kn);break}N()}else{if(yn===jn&&(bn===xn||bn===An)){j();break}bn===kn&&(bn=xn),N()}return vn.slice(t+1,_n)||null}function L(){for(var t=[];!E();)t.push(H());return t}function H(){var t,e={};return bn=kn,e.name=R().trim(),bn=An,t=V(),t.length&&(e.args=t),e}function V(){for(var t=[];!E()&&bn!==kn;){var e=R();if(!e)break;t.push(I(e))}return t}function I(t){if(Cn.test(t))return{value:l(t),dynamic:!1};var e=c(t),i=e===t;return{value:i?t:e,dynamic:i}}function W(t){var e=wn.get(t);if(e)return e;vn=t,mn={},gn=vn.length,_n=-1,yn="",bn=$n;var i;return vn.indexOf("|")<0?mn.expression=vn.trim():(mn.expression=R().trim(),i=L(),i.length&&(mn.filters=i)),wn.put(t,mn),mn}function B(t){return t.replace(Pn,"\\$&")}function U(){var t=B(Bn.delimiters[0]),e=B(Bn.delimiters[1]),i=B(Bn.unsafeDelimiters[0]),n=B(Bn.unsafeDelimiters[1]);Rn=new RegExp(i+"((?:.|\\n)+?)"+n+"|"+t+"((?:.|\\n)+?)"+e,"g"),Ln=new RegExp("^"+i+"((?:.|\\n)+?)"+n+"$"),Mn=new O(1e3)}function z(t){Mn||U();var e=Mn.get(t);if(e)return e;if(!Rn.test(t))return null;for(var i,n,r,s,o,a,h=[],l=Rn.lastIndex=0;i=Rn.exec(t);)n=i.index,n>l&&h.push({value:t.slice(l,n)}),r=Ln.test(i[0]),s=r?i[1]:i[2],o=s.charCodeAt(0),a=42===o,s=a?s.slice(1):s,h.push({tag:!0,value:s.trim(),html:r,oneTime:a}),l=n+i[0].length;return l1?t.map(function(t){return q(t,e)}).join("+"):q(t[0],e,!0)}function q(t,e,i){return t.tag?t.oneTime&&e?'"'+e.$eval(t.value)+'"':Q(t.value,i):'"'+t.value+'"'}function Q(t,e){if(Hn.test(t)){var i=W(t);return i.filters?"this._applyFilters("+i.expression+",null,"+JSON.stringify(i.filters)+",false)":"("+t+")"}return e?t:"("+t+")"}function G(t,e,i,n){Y(t,1,function(){e.appendChild(t)},i,n)}function Z(t,e,i,n){Y(t,1,function(){rt(t,e)},i,n)}function X(t,e,i){Y(t,-1,function(){ot(t)},e,i)}function Y(t,e,i,n,r){var s=t.__v_trans;if(!s||!s.hooks&&!an||!n._isCompiled||n.$parent&&!n.$parent._isCompiled)return i(),void(r&&r());var o=e>0?"enter":"leave";s[o](i,r)}function K(t){if("string"==typeof t){t=document.querySelector(t)}return t}function tt(t){if(!t)return!1;var e=t.ownerDocument.documentElement,i=t.parentNode;return e===t||e===i||!(!i||1!==i.nodeType||!e.contains(i))}function et(t,e){var i=t.getAttribute(e);return null!==i&&t.removeAttribute(e),i}function it(t,e){var i=et(t,":"+e);return null===i&&(i=et(t,"v-bind:"+e)),i}function nt(t,e){return t.hasAttribute(e)||t.hasAttribute(":"+e)||t.hasAttribute("v-bind:"+e)}function rt(t,e){e.parentNode.insertBefore(t,e)}function st(t,e){e.nextSibling?rt(t,e.nextSibling):e.parentNode.appendChild(t)}function ot(t){t.parentNode.removeChild(t)}function at(t,e){e.firstChild?rt(t,e.firstChild):e.appendChild(t)}function ht(t,e){var i=t.parentNode;i&&i.replaceChild(e,t)}function lt(t,e,i,n){t.addEventListener(e,i,n)}function ut(t,e,i){t.removeEventListener(e,i)}function ct(t){var e=t.className;return"object"==typeof e&&(e=e.baseVal||""),e}function ft(t,e){nn&&!/svg$/.test(t.namespaceURI)?t.className=e:t.setAttribute("class",e)}function pt(t,e){if(t.classList)t.classList.add(e);else{var i=" "+ct(t)+" ";i.indexOf(" "+e+" ")<0&&ft(t,(i+e).trim())}}function dt(t,e){if(t.classList)t.classList.remove(e);else{for(var i=" "+ct(t)+" ",n=" "+e+" ";i.indexOf(n)>=0;)i=i.replace(n," ");ft(t,i.trim())}t.className||t.removeAttribute("class")}function vt(t,e){var i,n;if(_t(t)&&$t(t.content)&&(t=t.content),t.hasChildNodes())for(mt(t),n=e?document.createDocumentFragment():document.createElement("div");i=t.firstChild;)n.appendChild(i);return n}function mt(t){for(var e;e=t.firstChild,gt(e);)t.removeChild(e);for(;e=t.lastChild,gt(e);)t.removeChild(e)}function gt(t){return t&&(3===t.nodeType&&!t.data.trim()||8===t.nodeType)}function _t(t){return t.tagName&&"template"===t.tagName.toLowerCase()}function yt(t,e){var i=Bn.debug?document.createComment(t):document.createTextNode(e?" ":"");return i.__v_anchor=!0,i}function bt(t){if(t.hasAttributes())for(var e=t.attributes,i=0,n=e.length;i=h.length){for(var t=0;t=97&&e<=122||e>=65&&e<=90?"ident":e>=49&&e<=57?"number":"else"}function Bt(t){var e=t.trim();return("0"!==t.charAt(0)||!isNaN(t))&&(o(e)?c(e):"*"+e)}function Ut(t){function e(){var e=t[u+1];if(c===dr&&"'"===e||c===vr&&'"'===e)return u++,n="\\"+e,p[sr](),!0}var i,n,r,s,o,a,h,l=[],u=-1,c=lr,f=0,p=[];for(p[or]=function(){void 0!==r&&(l.push(r),r=void 0)},p[sr]=function(){void 0===r?r=n:r+=n},p[ar]=function(){p[sr](),f++},p[hr]=function(){if(f>0)f--,c=pr,p[sr]();else{if(f=0,r=Bt(r),r===!1)return!1;p[or]()}};null!=c;)if(u++,i=t[u],"\\"!==i||!e()){if(s=Wt(i),h=_r[c],o=h[s]||h.else||gr,o===gr)return;if(c=o[0],a=p[o[1]],a&&(n=o[2],n=void 0===n?i:n,a()===!1))return;if(c===mr)return l.raw=t,l}}function zt(t){var e=rr.get(t);return e||(e=Ut(t),e&&rr.put(t,e)),e}function Jt(t,e){return ee(e).get(t)}function qt(t,e,i){var r=t;if("string"==typeof e&&(e=Ut(e)),!e||!y(t))return!1;for(var s,o,a=0,h=e.length;a-1?i.replace(Tr,Xt):i,e+"scope."+i)}function Xt(t,e){return Sr[e]}function Yt(t){kr.test(t),Sr.length=0;var e=t.replace(Or,Gt).replace(xr,"");return e=(" "+e).replace(Er,Zt).replace(Tr,Xt),Kt(e)}function Kt(t){try{return new Function("scope","return "+t+";")}catch(t){return Qt}}function te(t){var e=zt(t);if(e)return function(t,i){qt(t,e,i)}}function ee(t,e){t=t.trim();var i=br.get(t);if(i)return e&&!i.set&&(i.set=te(i.exp)),i;var n={exp:t};return n.get=ie(t)&&t.indexOf("[")<0?Kt("scope."+t):Yt(t),e&&(n.set=te(t)),br.put(t,n),n}function ie(t){return Nr.test(t)&&!jr.test(t)&&"Math."!==t.slice(0,5)}function ne(){Dr.length=0,Pr.length=0,Mr={},Rr={},Lr=!1}function re(){for(var t=!0;t;)t=!1,se(Dr),se(Pr),Dr.length?t=!0:(Ki&&Bn.devtools&&Ki.emit("flush"),ne())}function se(t){for(var e=0;e0){var o=s+(n?e:kt(e));r=Yr.get(o),r||(r=Ze(i,t.$options,!0),Yr.put(o,r))}else r=Ze(i,t.$options,!0);this.linker=r}function Ce(t,e,i){var n=t.node.previousSibling;if(n){for(t=n.__v_frag;!(t&&t.forId===i&&t.inserted||n===e);){if(n=n.previousSibling,!n)return;t=n.__v_frag}return t}}function $e(t){for(var e=-1,i=new Array(Math.floor(t));++e47&&e<58?parseInt(t,10):1===t.length&&(e=t.toUpperCase().charCodeAt(0),e>64&&e<91)?e:ys[t]});return i=[].concat.apply([],i),function(e){if(i.indexOf(e.keyCode)>-1)return t.call(this,e)}}function Ne(t){return function(e){return e.stopPropagation(),t.call(this,e)}}function Ee(t){return function(e){return e.preventDefault(),t.call(this,e)}}function je(t){return function(e){if(e.target===e.currentTarget)return t.call(this,e)}}function Se(t){if(ks[t])return ks[t];var e=Fe(t);return ks[t]=ks[e]=e,e}function Fe(t){t=d(t);var e=f(t),i=e.charAt(0).toUpperCase()+e.slice(1);xs||(xs=document.createElement("div"));var n,r=ws.length;if("filter"!==e&&e in xs.style)return{kebab:t,camel:e};for(;r--;)if(n=Cs[r]+i,n in xs.style)return{kebab:ws[r]+t,camel:n}}function De(t){var e=[];if(Zi(t))for(var i=0,n=t.length;i=r?i():t[s].call(e,n)}var r=t.length,s=0;t[0].call(e,n)}function Re(t,e,i){for(var n,r,s,a,h,l,u,c=[],p=i.$options.propsData,v=Object.keys(e),m=v.length;m--;)if(r=v[m],n=e[r]||Is,h=f(r),Ws.test(h)){if(u={name:r,path:h,options:n,mode:Vs.ONE_WAY,raw:null},s=d(r),null===(a=it(t,s))&&(null!==(a=it(t,s+".sync"))?u.mode=Vs.TWO_WAY:null!==(a=it(t,s+".once"))&&(u.mode=Vs.ONE_TIME)),null!==a)u.raw=a,l=W(a),a=l.expression,u.filters=l.filters,o(a)&&!l.filters?u.optimizedLiteral=!0:u.dynamic=!0,u.parentPath=a;else if(null!==(a=et(t,s)))u.raw=a;else if(p&&null!==(a=p[r]||p[h]))u.raw=a;else;c.push(u)}return Le(c)}function Le(t){return function(e,i){e._props={};for(var n,r,o,a,h,f=e.$options.propsData,p=t.length;p--;)if(n=t[p],h=n.raw,r=n.path,o=n.options,e._props[r]=n,f&&s(f,r)&&Ve(e,n,f[r]),null===h)Ve(e,n,void 0);else if(n.dynamic)n.mode===Vs.ONE_TIME?(a=(i||e._context||e).$get(n.parentPath),Ve(e,n,a)):e._context?e._bindDir({name:"prop",def:Us,prop:n},null,null,i):Ve(e,n,e.$get(n.parentPath));else if(n.optimizedLiteral){var v=c(h);a=v===h?u(l(h)):v,Ve(e,n,a)}else a=o.type===Boolean&&(""===h||h===d(n.name))||h,Ve(e,n,a)}}function He(t,e,i,n){var r=e.dynamic&&ie(e.parentPath),s=i;void 0===s&&(s=We(t,e)),s=Ue(e,s,t);var o=s!==i;Be(e,s,t)||(s=void 0),r&&!o?Pt(function(){n(s)}):n(s)}function Ve(t,e,i){He(t,e,i,function(i){Vt(t,e.path,i)})}function Ie(t,e,i){He(t,e,i,function(i){t[e.path]=i})}function We(t,e){var i=e.options;if(!s(i,"default"))return i.type!==Boolean&&void 0;var n=i.default;return y(n),"function"==typeof n&&i.type!==Function?n.call(t):n}function Be(t,e,i){if(!t.options.required&&(null===t.raw||null==e))return!0;var n=t.options,r=n.type,s=!r,o=[];if(r){Zi(r)||(r=[r]);for(var a=0;ae?-1:t===e?0:1}),e=0,i=a.length;ep.priority)&&(p=f,u=r.name,a=gi(r.name),o=r.value,l=h[1],c=h[2]));return p?vi(t,l,o,i,p,u,c,a):void 0}function di(){}function vi(t,e,i,n,r,s,o,a){var h=W(i),l={name:e,arg:o,expression:h.expression,filters:h.filters,raw:i,attr:s,modifiers:a,def:r};"for"!==e&&"router-view"!==e||(l.ref=bt(t));var u=function(t,e,i,n,r){l.ref&&Vt((n||t).$refs,l.ref,null),t._bindDir(l,e,i,n,r)};return u.terminal=!0,u}function mi(t,e){function i(t,e,i){var n=i&&yi(i),r=!n&&W(s);v.push({name:t,attr:o,raw:a,def:e,arg:l,modifiers:u,expression:r&&r.expression,filters:r&&r.filters,interp:i,hasOneTime:n})}for(var n,r,s,o,a,h,l,u,c,f,p,d=t.length,v=[];d--;)if(n=t[d],r=o=n.name,s=a=n.value,f=z(s),l=null,u=gi(r),r=r.replace(so,""),f)s=J(f),l=r,i("bind",Rs.bind,f);else if(oo.test(r))u.literal=!io.test(r),i("transition",eo.transition);else if(no.test(r))l=r.replace(no,""),i("on",Rs.on);else if(io.test(r))h=r.replace(io,""),"style"===h||"class"===h?i(h,eo[h]):(l=h,i("bind",Rs.bind));else if(p=r.match(ro)){if(h=p[1],l=p[2],"else"===h)continue;c=Ft(e,"directives",h,!0),c&&i(h,c)}if(v.length)return _i(v)}function gi(t){var e=Object.create(null),i=t.match(so);if(i)for(var n=i.length;n--;)e[i[n].slice(1)]=!0;return e}function _i(t){return function(e,i,n,r,s){for(var o=t.length;o--;)e._bindDir(t[o],i,n,r,s)}}function yi(t){for(var e=t.length;e--;)if(t[e].oneTime)return!0}function bi(t){return"SCRIPT"===t.tagName&&(!t.hasAttribute("type")||"text/javascript"===t.getAttribute("type"))}function wi(t,e){return e&&(e._containerAttrs=$i(t)),_t(t)&&(t=pe(t)),e&&(e._asComponent&&!e.template&&(e.template=""),e.template&&(e._content=vt(t),t=Ci(t,e))),$t(t)&&(at(yt("v-start",!0),t),t.appendChild(yt("v-end",!0))),t}function Ci(t,e){var i=e.template,n=pe(i,!0);if(n){var r=n.firstChild;if(!r)return n;var s=r.tagName&&r.tagName.toLowerCase();return e.replace?(t===document.body,n.childNodes.length>1||1!==r.nodeType||"component"===s||Ft(e,"components",s)||nt(r,"is")||Ft(e,"elementDirectives",s)||r.hasAttribute("v-for")||r.hasAttribute("v-if")?n:(e._replacerAttrs=$i(r),ki(t,r),r)):(t.appendChild(n),t)}}function $i(t){if(1===t.nodeType&&t.hasAttributes())return g(t.attributes)}function ki(t,e){for(var i,n,r=t.attributes,s=r.length;s--;)i=r[s].name,n=r[s].value,e.hasAttribute(i)||lo.test(i)?"class"===i&&!z(n)&&(n=n.trim())&&n.split(/\s+/).forEach(function(t){pt(e,t)}):e.setAttribute(i,n)}function xi(t,e){if(e){for(var i,n,r=t._slotContents=Object.create(null),s=0,o=e.children.length;s1?g(i):i;var r=e&&i.some(function(t){return t._fromParent});r&&(n=!1);for(var s=g(arguments,1),o=0,a=i.length;oe?s:-s}var i=null,n=void 0;t=go(t);var r=g(arguments,1),s=r[r.length-1];"number"==typeof s?(s=s<0?-1:1,r=r.length>1?r.slice(0,-1):r):s=1;var o=r[0];return o?("function"==typeof o?i=function(t,e){return o(t,e)*s}:(n=Array.prototype.concat.apply([],r),i=function(t,r,s){return s=s||0,s>=n.length-1?e(t,r,s):e(t,r,s)||i(t,r,s+1)}),t.slice().sort(i)):t}function Ii(t,e){var i;if(b(t)){var n=Object.keys(t);for(i=n.length;i--;)if(Ii(t[n[i]],e))return!0}else if(Zi(t)){for(i=t.length;i--;)if(Ii(t[i],e))return!0}else if(null!=t)return t.toString().toLowerCase().indexOf(e)>-1}function Wi(t){function e(t){return new Function("return function "+v(t)+" (options) { this._init(options) }")()}t.options={directives:Rs,elementDirectives:mo,filters:yo,transitions:{},components:{},partials:{},replace:!0},t.util=ir,t.config=Bn,t.set=n,t.delete=r,t.nextTick=fn,t.compiler=uo,t.FragmentFactory=we,t.internalDirectives=eo,t.parsers={path:yr,text:Vn,template:Zr,directive:Dn,expression:Fr},t.cid=0;var i=1;t.extend=function(t){t=t||{};var n=this,r=0===n.cid;if(r&&t._Ctor)return t._Ctor;var s=t.name||n.options.name,o=e(s||"VueComponent");return o.prototype=Object.create(n.prototype),o.prototype.constructor=o,o.cid=i++,o.options=St(n.options,t),o.super=n,o.extend=n.extend,Bn._assetTypes.forEach(function(t){o[t]=n[t]}),s&&(o.options.components[s]=o),r&&(t._Ctor=o),o},t.use=function(t){if(!t.installed){var e=g(arguments,1);return e.unshift(this),"function"==typeof t.install?t.install.apply(t,e):t.apply(null,e),t.installed=!0,this}},t.mixin=function(e){t.options=St(t.options,e)},Bn._assetTypes.forEach(function(e){t[e]=function(i,n){return n?("component"===e&&b(n)&&(n.name||(n.name=i),n=t.extend(n)),this.options[e+"s"][i]=n,n):this.options[e+"s"][i]}}),_(t.transition,zn)}var Bi=Object.prototype.hasOwnProperty,Ui=/^\s?(true|false|-?[\d\.]+|'[^']*'|"[^"]*")\s?$/,zi=/-(\w)/g,Ji=/([^-])([A-Z])/g,qi=/(?:^|[-_\/])(\w)/g,Qi=Object.prototype.toString,Gi="[object Object]",Zi=Array.isArray,Xi="__proto__"in{},Yi="undefined"!=typeof window&&"[object Object]"!==Object.prototype.toString.call(window),Ki=Yi&&window.__VUE_DEVTOOLS_GLOBAL_HOOK__,tn=Yi&&window.navigator.userAgent.toLowerCase(),en=tn&&tn.indexOf("trident")>0,nn=tn&&tn.indexOf("msie 9.0")>0,rn=tn&&tn.indexOf("android")>0,sn=tn&&/iphone|ipad|ipod|ios/.test(tn),on=void 0,an=void 0,hn=void 0,ln=void 0;if(Yi&&!nn){var un=void 0===window.ontransitionend&&void 0!==window.onwebkittransitionend,cn=void 0===window.onanimationend&&void 0!==window.onwebkitanimationend;on=un?"WebkitTransition":"transition",an=un?"webkitTransitionEnd":"transitionend",hn=cn?"WebkitAnimation":"animation",ln=cn?"webkitAnimationEnd":"animationend"}var fn=function(){function t(){i=!1;var t=e.slice(0);e.length=0;for(var n=0;n=this.length&&(this.length=Number(t)+1),this.splice(t,1,e)[0]}),w(Yn,"$remove",function(t){if(this.length){var e=$(this,t);return e>-1?this.splice(e,1):void 0}});var tr=Object.getOwnPropertyNames(Kn),er=!0;Mt.prototype.walk=function(t){for(var e=Object.keys(t),i=0,n=e.length;i",""],tr:[2,""],col:[2,""]};Ur.td=Ur.th=[3,""],Ur.option=Ur.optgroup=[1,'"],Ur.thead=Ur.tbody=Ur.colgroup=Ur.caption=Ur.tfoot=[1,""],Ur.g=Ur.defs=Ur.symbol=Ur.use=Ur.image=Ur.text=Ur.circle=Ur.ellipse=Ur.line=Ur.path=Ur.polygon=Ur.polyline=Ur.rect=[1,'"];var zr=/<([\w:-]+)/,Jr=/?\w+?;/,qr=/
14 |