first commit of v3
26
.env.example
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
###################################
|
||||
# Blessing Skin Server V3 #
|
||||
# Configuration #
|
||||
###################################
|
||||
|
||||
# 务必在生产环境下禁用!
|
||||
APP_DEBUG = false
|
||||
|
||||
# 数据库连接信息
|
||||
DB_HOST = 127.0.0.1
|
||||
DB_PORT = 3306
|
||||
DB_DATABASE = ""
|
||||
DB_USERNAME = ""
|
||||
DB_PASSWORD = ""
|
||||
DB_PREFIX = ""
|
||||
|
||||
# 盐,用于 token 加密
|
||||
# 修改为任意随机字符串以保证站点安全
|
||||
SALT = "change-it+to*what)you^like"
|
||||
|
||||
# SMTP 配置,用于发送重置密码的邮件
|
||||
MAIL_HOST = ""
|
||||
MAIL_PORT = 465
|
||||
MAIL_USERNAME = ""
|
||||
MAIL_PASSWORD = ""
|
||||
MAIL_ENCRYPTION = "ssl"
|
||||
9
.gitignore
vendored
|
|
@ -1,3 +1,8 @@
|
|||
.env
|
||||
.sass-cache
|
||||
vendor/*
|
||||
textures/*
|
||||
config.php
|
||||
setup/update_cache/*
|
||||
node_modules/*
|
||||
resoureces/cache/*
|
||||
assets/bower_components/*
|
||||
assets/dist/*
|
||||
|
|
|
|||
14
.htaccess
|
|
@ -1,10 +1,4 @@
|
|||
RewriteEngine on
|
||||
RewriteBase /
|
||||
|
||||
RewriteRule ^([^/]*).json$ get.php?type=json&uname=$1 [L]
|
||||
RewriteRule ^(skin|cape)/([^/-]*)(|-)(|alex|steve).png$ get.php?type=$1&model=$4&uname=$2 [L]
|
||||
# 同时支持 UniSkinAPI 和 CustomSkinLoader API
|
||||
RewriteRule ^(usm|csl)/([^/]*).json$ get.php?type=json&uname=$2&api=$1 [L]
|
||||
RewriteRule ^(usm|csl)/textures/(.*)$ textures/$2 [L]
|
||||
# 用于获取皮肤头像
|
||||
RewriteRule ^avatar/(|[0-9]*/)([^/-]*).png$ get.php?type=avatar&uname=$2&size=$1 [L]
|
||||
RewriteEngine On
|
||||
RewriteCond %{REQUEST_FILENAME} !-f
|
||||
RewriteCond %{REQUEST_FILENAME} !-d
|
||||
RewriteRule ^ index.php [QSA,L]
|
||||
|
|
|
|||
21
LICENSE
|
|
@ -1,21 +0,0 @@
|
|||
The MIT License
|
||||
|
||||
Copyright (c) 2016 Blessing Studio
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
246
README.md
|
|
@ -1,247 +1,5 @@
|
|||
# Blessing Skin Server
|
||||
|
||||
由于开发者学业原因,本项目已经暂停开发。开源协议已改为 MIT。
|
||||
已更新 V3,文档正在撰写中~
|
||||
|
||||
优雅的开源 PHP Minecraft 皮肤站。[演示地址](https://skin.prinzeugen.net/)
|
||||
|
||||

|
||||
|
||||
特性:
|
||||
-----------
|
||||
|
||||
- 支持 [UniSkinAPI](https://github.com/RecursiveG/UniSkinServer/blob/master/doc/UniSkinAPI_zh-CN.md)
|
||||
- 支持 [CustomSkinLoader API](https://github.com/xfl03/CustomSkinLoaderAPI/blob/master/CustomSkinAPI/CustomSkinAPI_en.md)
|
||||
- 同时支持旧版样式链接
|
||||
- 支持与 Authme、CrazyLogin、Discuz 等程序进行数据对接
|
||||
- 完善的用户管理后台以及配置页面
|
||||
- 多种后台配色
|
||||
- 可以获取由用户皮肤生成的头像(example.com/avatar/{{size}}/username.png)
|
||||
|
||||
环境要求:
|
||||
-----------
|
||||
|
||||
1. 一台支持 URL 重写的主机,Nginx、Apache 或 IIS
|
||||
2. **PHP 版本 >= 5.4**
|
||||
3. 目录的写权限~~(SAE 等不可写应用引擎的支持正在开发中)~~
|
||||
|
||||
快速使用:
|
||||
-----------
|
||||
|
||||
1. 下载源码,重命名 `config.example.php` 为 `config.php` 并配置你的数据库连接信息
|
||||
2. 运行 `./setup/install.php`
|
||||
3. 如果你是用的是 Nginx,请配置你的 `nginx.conf` 并加入重写规则
|
||||
4. 注册一个新账户或者使用 `安装时所配置的账户` (管理员账户)登录
|
||||
5. 可以上传你的皮肤&披风啦
|
||||
6. 在你所使用的皮肤 Mod 配置文件中加入你的地址
|
||||
7. 完成啦~
|
||||
|
||||
服务器配置:
|
||||
------------
|
||||
|
||||
如果你使用 Apache 或者 IIS 作为 web 服务器(大部分的虚拟主机),那么恭喜你,我已经帮你把重写规则写好啦,开箱即用,无需任何配置~
|
||||
|
||||
如果你使用 Nginx,请在你的 `nginx.conf` 中加入如下 rewrite 规则**(重要)**:
|
||||
|
||||
```
|
||||
rewrite ^/([^/]*).json$ /get.php?type=json&uname=$1 last;
|
||||
rewrite ^/(skin|cape)/([^/-]*)(|-)(|alex|steve).png$ /get.php?type=$1&model=$4&uname=$2 last;
|
||||
rewrite ^/(usm|csl)/([^/]*).json$ /get.php?type=json&uname=$2&api=$1 last;
|
||||
rewrite ^/(usm|csl)/textures/(.*)$ /textures/$2 last;
|
||||
# 用于获取皮肤头像
|
||||
rewrite ^/avatar/(|[0-9]*/)([^/-]*).png$ /get.php?type=avatar&uname=$2&size=$1 last;
|
||||
```
|
||||
|
||||
如果你将皮肤站放在子目录中,你需要把重写规则改成类似于**这样**:
|
||||
|
||||
```
|
||||
rewrite ^/subdir/([^/]*).json$ /subdir/get.php?type=json&uname=$1 last;
|
||||
```
|
||||
|
||||
注意 `^/` 后和 `/get.php` 前都要加上你的子目录名。
|
||||
|
||||
现在你可以访问 `http://example.com/username.json` 来得到你的首选 API 的 JSON 用户数据。另外一个 API 的 JSON 数据可以通过访问 `http://example.com/(usm|csl)/username.json` 得到。
|
||||
|
||||
上传完皮肤后,你就可以访问 `http://example.com/skin/username.png` 得到你的首选模型皮肤啦。 披风图片在这里:`http://example.com/cape/username.png` 。你还可以访问 `http://example.com/skin/username-(alex|steve).png` 来得到用户的 Alex/Steve 模型的皮肤文件(用户没上传则返回 404)。
|
||||
|
||||
数据对接:
|
||||
------------
|
||||
|
||||
Blessing Skin Server 支持与 Authme、CrazyLogin、Discuz 等程序进行数据对接,只需在 `/admin/options.php` 中进行相应配置即可。
|
||||
|
||||
如果在插件配置中修改过用户名或者密码的字段,请自行修改 `对接数据表用户名字段` 等信息。
|
||||
|
||||
注意,`config.php` 中填写的数据库连接信息必须与被对接的程序的连接信息相同**(即同一个数据库)**。
|
||||
|
||||
如需适配其他程序,继承 `Database` 类并实现 `EncryptInterface` 与 `SyncInterface` 两个接口即可。
|
||||
|
||||
客户端配置:
|
||||
------------
|
||||
|
||||
#### CustomSkinLoader 13.1 及以上(推荐)
|
||||
|
||||
CustomSkinLoader 13.1 经过作者的完全重写,支持了 CSL API,并且使用了高端洋气的 JSON 配置文件。你问我 JSON 是什么?为什么不去问问神奇海螺呢。
|
||||
|
||||
配置文件位于 `.minecraft/CustomSkinLoader/CustomSkinLoader.json`,你需要在 loadlist 数组最顶端加入你的皮肤站配置。
|
||||
|
||||
举个栗子(原来的 JSON 长这样):
|
||||
|
||||
```json
|
||||
{
|
||||
"enable": true,
|
||||
"loadlist": [
|
||||
{
|
||||
"name": "Mojang",
|
||||
"type": "MojangAPI"
|
||||
},
|
||||
{
|
||||
"name": "SkinMe",
|
||||
"type": "UniSkinAPI",
|
||||
"root": "http://www.skinme.cc/uniskin/"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
你需要将其修改成像这样:
|
||||
|
||||
```json
|
||||
{
|
||||
"enable": true,
|
||||
"loadlist": [
|
||||
{
|
||||
"name": "YourSkinServer",
|
||||
"type": "CustomSkinAPI",
|
||||
"root": "http://example.com/"
|
||||
},
|
||||
{
|
||||
"name": "Mojang",
|
||||
"type": "MojangAPI"
|
||||
},
|
||||
{
|
||||
"name": "SkinMe",
|
||||
"type": "UniSkinAPI",
|
||||
"root": "http://www.skinme.cc/uniskin/"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
`"type"` 字段按照你的 `config.php` 中配置的首选 API 来填(CustomSkinAPI|UniSkinAPI),CSL 13.1 版是支持三种加载方式的~~万受♂之王~~
|
||||
|
||||
如果还是不会填的话,请查看 CSL 开发者的 [MCBBS 发布贴](http://www.mcbbs.net/thread-269807-1-1.html)。
|
||||
|
||||
#### CustomSkinLoader 13.1 版以下:
|
||||
|
||||
在 `.minecraft/CustomSkinLoader/skinurls.txt` 中添加你的皮肤站地址:
|
||||
|
||||
```
|
||||
http://example.com/skin/*.png
|
||||
http://skins.minecraft.net/MinecraftSkins/*.png
|
||||
http://minecrack.fr.nf/mc/skinsminecrackd/*.png
|
||||
http://www.skinme.cc/MinecraftSkins/*.png
|
||||
```
|
||||
|
||||
注意你需要将你的皮肤站地址放在配置文件最上方以优先加载。
|
||||
|
||||
同理在 `.minecraft/CustomSkinLoader/capeurls.txt` 中加入:
|
||||
|
||||
```
|
||||
http://example.com/cape/*.png
|
||||
```
|
||||
|
||||
#### UniSkinMod 1.4 版及以上(推荐)
|
||||
|
||||
配置文件位于 `.minecraft/config/UniSkinMod/UniSkinMod.json`。
|
||||
|
||||
举个栗子(原来的 JSON 长这样):
|
||||
|
||||
```json
|
||||
{
|
||||
"rootURIs": [
|
||||
"http://www.skinme.cc/uniskin",
|
||||
"https://skin.prinzeugen.net"
|
||||
],
|
||||
"legacySkinURIs": [],
|
||||
"legacyCapeURIs": []
|
||||
}
|
||||
```
|
||||
|
||||
你需要在 `rootURIs` 字典中加入你的皮肤站的地址:
|
||||
|
||||
```json
|
||||
{
|
||||
"rootURIs": [
|
||||
"http://www.skinme.cc/uniskin",
|
||||
"https://skin.prinzeugen.net",
|
||||
"http://example.com"
|
||||
],
|
||||
"legacySkinURIs": [],
|
||||
"legacyCapeURIs": []
|
||||
}
|
||||
```
|
||||
|
||||
如果你的皮肤站首选 API 为 CustomSkinLoader API 的话,你需要在 UniSkinMod 配置文件中填入类似于 `http://example.com/usm` (添加后缀)来支持 UniSkinMod。
|
||||
|
||||
配置 `rootURIs` 后,`legacySkinURIs` 和 `legacyCapeURIs` 可以不用配置。详见[文档](https://github.com/RecursiveG/UniSkinMod/blob/1.9/README.md)。
|
||||
|
||||
#### UniSkinMod 1.2 及 1.3 版
|
||||
|
||||
在你 MC 客户端的 `.minecraft/config/UniSkinMod.cfg` 中加入你的皮肤站根地址:
|
||||
|
||||
举个栗子:
|
||||
|
||||
```
|
||||
# SkinMe Default
|
||||
Root: http://www.skinme.cc/uniskin
|
||||
# Your Server
|
||||
Root: http://example.com
|
||||
```
|
||||
|
||||
如果你把皮肤站安装到子目录的话,请一起带上你的子目录。
|
||||
|
||||
#### UniSkinMod 1.2 版以下
|
||||
|
||||
同样是在 `.minecraft/config/UniSkinMod.cfg` 中配置你的皮肤站地址,但是稍有点不一样。旧版的 UniSkinMod 是不支持 Json API 的,而是使用了传统图片链接的方式(其实这样的话皮肤站也好实现):
|
||||
|
||||
举个栗子:
|
||||
|
||||
```
|
||||
Skin: http://skins.minecraft.net/MinecraftSkins/%s.png
|
||||
Cape: http://skins.minecraft.net/MinecraftCloaks/%s.png
|
||||
# Your Server
|
||||
Skin: http://example.com/skin/%s.png
|
||||
Cape: http://example.com/cape/%s.png
|
||||
```
|
||||
|
||||
这是通过 URL 重写(伪静态)实现的,所以皮肤站目录下没有 `skin` 和 `cape` 目录也不要惊讶哦。
|
||||
|
||||
如果一切都正常工作,你就可以在游戏中看到你的皮肤啦~
|
||||
|
||||

|
||||
|
||||
常见问题:
|
||||
------------
|
||||
|
||||
#### 访问 `example.com/skin/xxx.png ` 404?
|
||||
|
||||
请确认你的伪静态(URL 重写)是否配置正确。
|
||||
|
||||
#### 500 错误?
|
||||
|
||||
本程序使用了一些 PHP 5.4 的新特性,请确保你的 PHP 版本 >= 5.4
|
||||
|
||||
#### 游戏中皮肤不显示?
|
||||
|
||||
请先确认你的皮肤站 URL 重写规则已经配置正确,并且可以正常获取皮肤图片。
|
||||
|
||||
如果还是不能显示皮肤,请阅读您所使用的皮肤 Mod 的 FAQ。
|
||||
|
||||
还是不行的话,请在启动器开启调试模式,并且查看所有关于 skin 的日志, CSL 的日志位于 `.minecraft/CustomSkinLoader/CustomSkinLoader.log`。
|
||||
|
||||
一般来说看了就可以明白了,如果还是不明白请邮件 [联系我](mailto:h@prinzeugen.net)(带上你的日志)。
|
||||
|
||||
版权:
|
||||
------------
|
||||
Blessing Skin Server 程序是基于 The MIT License 开放源代码的自由软件,你可以遵照 MIT 协议来修改和重新发布这一程序。
|
||||
|
||||
程序原作者为 [@printempw](https://prinzeugen.net/),转载请注明。
|
||||
V2 文档在 [这里](https://github.com/printempw/blessing-skin-server/tree/v2)。
|
||||
|
|
|
|||
|
|
@ -1,114 +0,0 @@
|
|||
<?php
|
||||
/**
|
||||
* @Author: printempw
|
||||
* @Date: 2016-03-19 21:00:58
|
||||
* @Last Modified by: printempw
|
||||
* @Last Modified time: 2016-05-12 21:53:48
|
||||
*/
|
||||
require "../libraries/session.inc.php";
|
||||
if (!$user->is_admin) Utils::redirect('../index.php', '看起来你并不是管理员');
|
||||
View::show('admin/header', array('page_title' => "添加用户"));
|
||||
$db = new Database\Database('users');
|
||||
?>
|
||||
<!-- Content Wrapper. Contains page content -->
|
||||
<div class="content-wrapper">
|
||||
<!-- Content Header (Page header) -->
|
||||
<section class="content-header">
|
||||
<h1>
|
||||
批量添加用户
|
||||
<small>Add Users</small>
|
||||
</h1>
|
||||
</section>
|
||||
<style>
|
||||
input {
|
||||
margin: 0;
|
||||
}
|
||||
a > i, button > i {
|
||||
padding-right: 5px;
|
||||
}
|
||||
</style>
|
||||
<!-- Main content -->
|
||||
<section class="content">
|
||||
<?php
|
||||
function showCallout($type, $id, $msg) {
|
||||
echo "<div class='callout callout-".$type."'>$id".":".$_POST['username-'.$id]." $msg"."</div>";
|
||||
}
|
||||
if (isset($_POST['submit'])) {
|
||||
for ($i = 1; $i <= (int)$_POST['submit']; $i++) {
|
||||
if (User::checkValidUname($_POST['username-'.$i])) {
|
||||
$password = ($_POST['password-'.$i] == "") ? '123456' : $_POST['password-'.$i];
|
||||
if (strlen($password) < 16 && strlen($password) > 5) {
|
||||
$user = new User($_POST['username-'.$i]);
|
||||
if (!$user->is_registered) {
|
||||
if ($user->register($password, 'added by admin')) {
|
||||
if ($_FILES['skin-'.$i]['name'] != "") {
|
||||
if ($user->setTexture('steve', $_FILES['skin-'.$i])) {
|
||||
showCallout('success', $i, "皮肤上传成功!");
|
||||
} else {
|
||||
showCallout('danger', $i, "出现了奇怪的错误。。请联系作者 :(");
|
||||
}
|
||||
} else {
|
||||
showCallout('success', $i, "注册成功!密码 $password");
|
||||
}
|
||||
} else {
|
||||
showCallout('danger', $i, "注册失败.");
|
||||
}
|
||||
} else {
|
||||
showCallout('danger', $i, "用户名已被注册。");
|
||||
}
|
||||
} else {
|
||||
showCallout('danger', $i, "无效的密码。密码长度应该大于 6 并小于 15。");
|
||||
}
|
||||
} else {
|
||||
showCallout('danger', $i, "无效的用户名。用户名只能包含数字,字母以及下划线。");
|
||||
}
|
||||
}
|
||||
} ?>
|
||||
<form method="post" action="adduser.php" enctype="multipart/form-data">
|
||||
<div class="box">
|
||||
<div class="box-body table-responsive no-padding">
|
||||
<table class="table table-hover">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>#</th>
|
||||
<th>用户名</th>
|
||||
<th>密码(默认 123456)</th>
|
||||
<th>上传皮肤</th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
<tbody id="users">
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
<a href="javascript:add();" style="float: right; margin-left: 10px;" class="btn btn-primary"><i class="fa fa-plus"></i>添加一个用户</a>
|
||||
<button type="submit" name="submit" style="float: right;" class="btn btn-primary"><i class="fa fa-upload"></i>提交</button>
|
||||
</form>
|
||||
|
||||
</section><!-- /.content -->
|
||||
</div><!-- /.content-wrapper -->
|
||||
<?php
|
||||
$data['script'] = <<< 'EOT'
|
||||
<script type="text/javascript" src="../assets/libs/bootstrap-fileinput/js/fileinput.min.js"></script>
|
||||
<script type="text/javascript" src="../assets/libs/bootstrap-fileinput/js/fileinput_locale_zh.js"></script>
|
||||
<script type="text/javascript">
|
||||
var user_count = 1;
|
||||
$(document).ready(function() {
|
||||
add();
|
||||
});
|
||||
function add() {
|
||||
var dom = '<tr id="user-'+user_count+'">'+
|
||||
'<td>'+user_count+'</td>'+
|
||||
'<td><input type="text" class="form-control" name="username-'+user_count+'"></td>'+
|
||||
'<td><input type="password" class="form-control" name="password-'+user_count+'"></td>'+
|
||||
'<td><input type="file" class="form-control" name="skin-'+user_count+'" data-show-preview="false" name="site_name" accept="image/png" ></td>'+
|
||||
'</tr>';
|
||||
$('#users').append($(dom));
|
||||
$('input[type=file]').fileinput({showCaption: false, 'showUpload':false, 'language': 'zh'});
|
||||
$('button[type=submit]').prop('value', user_count);
|
||||
user_count++;
|
||||
}
|
||||
</script>
|
||||
EOT;
|
||||
View::show('admin/footer', $data); ?>
|
||||
|
|
@ -1,81 +0,0 @@
|
|||
<?php
|
||||
/**
|
||||
* @Author: printempw
|
||||
* @Date: 2016-02-04 13:53:55
|
||||
* @Last Modified by: printempw
|
||||
* @Last Modified time: 2016-05-12 21:53:48
|
||||
*/
|
||||
require "../libraries/session.inc.php";
|
||||
|
||||
// Check token, won't allow non-admin user to access
|
||||
if (!$user->is_admin) Utils::redirect('../index.php', '看起来你并不是管理员');
|
||||
|
||||
/*
|
||||
* No protection here,
|
||||
* I don't think you wanna fuck yourself :(
|
||||
*/
|
||||
if (isset($_GET['action'])) {
|
||||
$action = $_GET['action'];
|
||||
$user = new User(isset($_GET['uname']) ? $_GET['uname'] : '');
|
||||
|
||||
if ($action == "upload") {
|
||||
$type = isset($_GET['type']) ? $_GET['type'] : "skin";
|
||||
$file = isset($_FILES['file']) ? $_FILES['file'] : null;
|
||||
if (!is_null($file)) {
|
||||
if ($user->setTexture($type, $file)) {
|
||||
$json['errno'] = 0;
|
||||
$json['msg'] = "皮肤上传成功。";
|
||||
} else {
|
||||
$json['errno'] = 1;
|
||||
$json['msg'] = "出现了奇怪的错误。。请联系作者";
|
||||
}
|
||||
} else {
|
||||
throw new E('你没有选择任何文件哦', 1);
|
||||
}
|
||||
} else if ($action == "change") {
|
||||
if (User::checkValidPwd($_POST['passwd'])) {
|
||||
$user->changePasswd($_POST['passwd']);
|
||||
$json['errno'] = 0;
|
||||
$json['msg'] = "成功更改了 ".$_GET['uname']." 的密码。";
|
||||
} // Will raise exception if password invalid
|
||||
} else if ($action == "deleteAccount") {
|
||||
$user->unRegister();
|
||||
$json['errno'] = 0;
|
||||
$json['msg'] = "成功删除了该用户。";
|
||||
} else if ($action == "deleteTexture") {
|
||||
for ($i = 1; $i <= 3; $i++) {
|
||||
switch($i) {
|
||||
case 1: $type = "steve"; break;
|
||||
case 2: $type = "alex"; break;
|
||||
case 3: $type = "cape"; break;
|
||||
}
|
||||
if ($_POST[$type] == "true" && $user->getTexture($type) != "") {
|
||||
Utils::remove("./textures/".$user->getTexture($type));
|
||||
$user->db->update('hash_'.$type, '', ['where' => "username='$user->uname'"]);
|
||||
}
|
||||
}
|
||||
$json['errno'] = 0;
|
||||
$json['msg'] = "成功地删除了该用户的所选材质。";
|
||||
} else if ($action == "model") {
|
||||
if (isset($_POST['model']) && $_POST['model'] == 'slim' || $_POST['model'] == 'default') {
|
||||
$user->setPreference($_POST['model']);
|
||||
$json['errno'] = 0;
|
||||
$json['msg'] = "成功地将用户 ".$_GET['uname']." 的优先皮肤模型更改为 ".$_POST['model']." 。";
|
||||
} else {
|
||||
throw new E('非法参数。', 1);
|
||||
}
|
||||
} else if ($action == "color") {
|
||||
if (isset($_POST['color_scheme'])) {
|
||||
$color_scheme = str_replace('_', '-', $_POST['color_scheme']);
|
||||
Option::set('color_scheme', $color_scheme);
|
||||
$json['errno'] = 0;
|
||||
$json['msg'] = "修改配色成功。";
|
||||
} else {
|
||||
throw new E('非法参数。', 1);
|
||||
}
|
||||
} else {
|
||||
throw new E('非法参数。', 1);
|
||||
}
|
||||
}
|
||||
|
||||
echo json_encode($json);
|
||||
|
|
@ -1,244 +0,0 @@
|
|||
<?php
|
||||
/**
|
||||
* @Author: printempw
|
||||
* @Date: 2016-03-19 14:34:21
|
||||
* @Last Modified by: printempw
|
||||
* @Last Modified time: 2016-05-12 21:53:48
|
||||
*/
|
||||
require "../libraries/session.inc.php";
|
||||
if (!$user->is_admin) Utils::redirect('../index.php', '看起来你并不是管理员');
|
||||
$data['style'] = <<< 'EOT'
|
||||
<link rel="stylesheet" href="../assets/libs/AdminLTE/dist/css/skins/_all-skins.min.css">
|
||||
<style>
|
||||
.callout {
|
||||
margin: 15px 0;
|
||||
}
|
||||
</style>
|
||||
EOT;
|
||||
$data['page_title'] = "个性化";
|
||||
View::show('admin/header', $data);
|
||||
$db = new Database\Database('users');
|
||||
?>
|
||||
<!-- Content Wrapper. Contains page content -->
|
||||
<div class="content-wrapper">
|
||||
<!-- Content Header (Page header) -->
|
||||
<section class="content-header">
|
||||
<h1>
|
||||
个性化
|
||||
<small>Customize</small>
|
||||
</h1>
|
||||
</section>
|
||||
|
||||
<!-- Main content -->
|
||||
<section class="content">
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
<div class="box box-primary">
|
||||
<div class="box-header with-border">
|
||||
<h3 class="box-title">更改配色</h3>
|
||||
</div><!-- /.box-header -->
|
||||
<div class="box-body no-padding">
|
||||
<table id="layout-skins-list" class="table table-striped bring-up nth-2-center">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>蓝色主题(默认)</td>
|
||||
<td><a href="#" data-skin="skin-blue" class="btn btn-primary btn-xs"><i class="fa fa-eye"></i></a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>蓝色主题-白色侧边栏</td>
|
||||
<td><a href="#" data-skin="skin-blue-light" class="btn btn-primary btn-xs"><i class="fa fa-eye"></i></a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>黄色主题</td>
|
||||
<td><a href="#" data-skin="skin-yellow" class="btn btn-warning btn-xs"><i class="fa fa-eye"></i></a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>黄色主题-白色侧边栏</td>
|
||||
<td><a href="#" data-skin="skin-yellow-light" class="btn btn-warning btn-xs"><i class="fa fa-eye"></i></a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>绿色主题</td>
|
||||
<td><a href="#" data-skin="skin-green" class="btn btn-success btn-xs"><i class="fa fa-eye"></i></a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>绿色主题-白色侧边栏</td>
|
||||
<td><a href="#" data-skin="skin-green-light" class="btn btn-success btn-xs"><i class="fa fa-eye"></i></a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>基佬紫</td>
|
||||
<td><a href="#" data-skin="skin-purple" class="btn bg-purple btn-xs"><i class="fa fa-eye"></i></a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>紫色主题-白色侧边栏</td>
|
||||
<td><a href="#" data-skin="skin-purple-light" class="btn bg-purple btn-xs"><i class="fa fa-eye"></i></a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>喜庆红(笑)</td>
|
||||
<td><a href="#" data-skin="skin-red" class="btn btn-danger btn-xs"><i class="fa fa-eye"></i></a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>红色主题-白色侧边栏</td>
|
||||
<td><a href="#" data-skin="skin-red-light" class="btn btn-danger btn-xs"><i class="fa fa-eye"></i></a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>高端黑</td>
|
||||
<td><a href="#" data-skin="skin-black" class="btn bg-black btn-xs"><i class="fa fa-eye"></i></a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>黑色主题-白色侧边栏</td>
|
||||
<td><a href="#" data-skin="skin-black-light" class="btn bg-black btn-xs"><i class="fa fa-eye"></i></a></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div><!-- /.box-body -->
|
||||
<div class="box-footer">
|
||||
<button id="color-submit" class="btn btn-primary">提交</button>
|
||||
<div id="msg" class="callout callout-info hide"></div>
|
||||
</div>
|
||||
</div><!-- /.box -->
|
||||
|
||||
<div class="box box-warning">
|
||||
<div class="box-header with-border">
|
||||
<h3 class="box-title">Google Font CDN</h3>
|
||||
</div><!-- /.box-header -->
|
||||
<form method="post" action="customize.php">
|
||||
<input type="hidden" name="option" value="adapter">
|
||||
<div class="box-body">
|
||||
<?php
|
||||
if (isset($_POST['google_font_cdn'])) {
|
||||
Option::set('google_font_cdn', $_POST['google_font_cdn']);
|
||||
echo '<div class="callout callout-success">设置已保存。</div>';
|
||||
} ?>
|
||||
<table class="table">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td class="value">
|
||||
<select class="form-control" name="google_font_cdn">
|
||||
<option <?php echo (Option::get('google_font_cdn') == 'google') ? 'selected="selected"' : ''; ?> value="google">Google Fonts(部分地区被墙)</option>
|
||||
<option <?php echo (Option::get('google_font_cdn') == 'moefont') ? 'selected="selected"' : ''; ?> value="moefont">MoeFont CDN</option>
|
||||
<option <?php echo (Option::get('google_font_cdn') == 'useso') ? 'selected="selected"' : ''; ?> value="useso">三六蛋 CDN(不支持 HTTPS)</option>
|
||||
</select>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div><!-- /.box-body -->
|
||||
<div class="box-footer">
|
||||
<button type="submit" name="submit" class="btn btn-primary">提交</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-md-6">
|
||||
<div class="box box-warning">
|
||||
<div class="box-header with-border">
|
||||
<h3 class="box-title">首页配置</h3>
|
||||
</div><!-- /.box-header -->
|
||||
<form method="post" action="customize.php">
|
||||
<input type="hidden" name="option" value="adapter">
|
||||
<div class="box-body">
|
||||
<?php
|
||||
if (isset($_POST['home_pic_url'])) {
|
||||
Option::set('home_pic_url', $_POST['home_pic_url']);
|
||||
echo '<div class="callout callout-success">设置已保存。</div>';
|
||||
} ?>
|
||||
<table class="table">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td class="key">首页图片地址</td>
|
||||
<td class="value">
|
||||
<input type="text" data-toggle="tooltip" data-placement="bottom" title="相对与首页的路径或绝对路径。" class="form-control" name="home_pic_url" value="<?php echo Option::get('home_pic_url'); ?>">
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
</tbody>
|
||||
</table>
|
||||
</div><!-- /.box-body -->
|
||||
<div class="box-footer">
|
||||
<button type="submit" name="submit" class="btn btn-primary">提交</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<div class="box box-default">
|
||||
<div class="box-header with-border">
|
||||
<h3 class="box-title">自定义 CSS/JavaScript
|
||||
<i class="fa fa-question-circle" data-toggle="tooltip" data-placement="bottom" title="字符串将会被转义"></i>
|
||||
</h3>
|
||||
</div><!-- /.box-header -->
|
||||
<form method="post" action="customize.php">
|
||||
<input type="hidden" name="option" value="adapter">
|
||||
<div class="box-body">
|
||||
<?php
|
||||
if (isset($_POST['custom_css']) && isset($_POST['custom_js'])) {
|
||||
Option::set('custom_css', Utils::convertString($_POST['custom_css']));
|
||||
Option::set('custom_js', Utils::convertString($_POST['custom_js']));
|
||||
echo '<div class="callout callout-success">设置已保存。</div>';
|
||||
} else {
|
||||
echo '<div class="callout callout-info">内容将会被追加至每个页面的 <style> 和 <script> 标签中</div>';
|
||||
} ?>
|
||||
<table class="table">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td class="key">CSS</td>
|
||||
<td class="value">
|
||||
<textarea name="custom_css" class="form-control" rows="3"><?php echo Option::get('custom_css'); ?></textarea>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="key">JavaScript</td>
|
||||
<td class="value">
|
||||
<textarea name="custom_js" class="form-control" rows="3"><?php echo Option::get('custom_js'); ?></textarea>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
</tbody>
|
||||
</table>
|
||||
</div><!-- /.box-body -->
|
||||
<div class="box-footer">
|
||||
<button type="submit" name="submit" class="btn btn-primary">提交</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</section><!-- /.content -->
|
||||
</div><!-- /.content-wrapper -->
|
||||
<?php
|
||||
$color_scheme = Option::get('color_scheme');
|
||||
$data['script'] = <<< EOT
|
||||
<script type="text/javascript">
|
||||
// Skin switcher
|
||||
var current_skin = "$color_scheme";
|
||||
$('#layout-skins-list [data-skin]').click(function(e) {
|
||||
e.preventDefault();
|
||||
var skin_name = $(this).data('skin');
|
||||
$('body').removeClass(current_skin);
|
||||
$('body').addClass(skin_name);
|
||||
current_skin = skin_name;
|
||||
});
|
||||
$('#color-submit').click(function() {
|
||||
$.ajax({
|
||||
type: "POST",
|
||||
url: "admin_ajax.php?action=color",
|
||||
dataType: "json",
|
||||
data: { "color_scheme": current_skin },
|
||||
beforeSend: function() {
|
||||
showCallout('alert-info', '提交中。。');
|
||||
},
|
||||
success: function(json) {
|
||||
console.log(json);
|
||||
if (json.errno == 0) {
|
||||
showCallout('alert-info', '设置已保存。');
|
||||
} else {
|
||||
showCallout('alert-warning', json.msg);
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
||||
EOT;
|
||||
View::show('admin/footer', $data); ?>
|
||||
|
|
@ -1,58 +0,0 @@
|
|||
<?php
|
||||
/**
|
||||
* @Author: printempw
|
||||
* @Date: 2016-02-03 14:39:50
|
||||
* @Last Modified by: printempw
|
||||
* @Last Modified time: 2016-05-12 21:53:49
|
||||
*/
|
||||
require "../libraries/session.inc.php";
|
||||
if (!$user->is_admin) Utils::redirect('../index.php', '看起来你并不是管理员');
|
||||
View::show('admin/header', array('page_title' => "仪表盘"));
|
||||
$db = new Database\Database('users');
|
||||
?>
|
||||
<!-- Content Wrapper. Contains page content -->
|
||||
<div class="content-wrapper">
|
||||
<!-- Content Header (Page header) -->
|
||||
<section class="content-header">
|
||||
<h1>
|
||||
仪表盘
|
||||
<small>Dashboard</small>
|
||||
</h1>
|
||||
</section>
|
||||
|
||||
<!-- Main content -->
|
||||
<section class="content">
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
<div class="info-box">
|
||||
<a href="manage.php">
|
||||
<span class="info-box-icon bg-aqua"><i class="fa fa-users"></i></span>
|
||||
<div class="info-box-content">
|
||||
<span class="info-box-text">注册用户</span>
|
||||
<span class="info-box-number"><?php echo $db->getRecordNum();?></span>
|
||||
</div><!-- /.info-box-content -->
|
||||
</a>
|
||||
</div><!-- /.info-box -->
|
||||
|
||||
<div class="info-box">
|
||||
<span class="info-box-icon bg-green"><i class="fa fa-files-o"></i></span>
|
||||
<div class="info-box-content">
|
||||
<span class="info-box-text">上传材质总数</span>
|
||||
<span class="info-box-number"><?php echo Utils::getFileNum(BASE_DIR."/textures/");?></span>
|
||||
</div><!-- /.info-box-content -->
|
||||
</div><!-- /.info-box -->
|
||||
|
||||
<div class="info-box">
|
||||
<span class="info-box-icon bg-yellow"><i class="fa fa-hdd-o"></i></span>
|
||||
<div class="info-box-content">
|
||||
<span class="info-box-text">占用空间大小</span>
|
||||
<span class="info-box-number"><?php echo floor(Utils::getDirSize(BASE_DIR."/textures/")/1024)."KB";?></span>
|
||||
</div><!-- /.info-box-content -->
|
||||
</div><!-- /.info-box -->
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</section><!-- /.content -->
|
||||
</div><!-- /.content-wrapper -->
|
||||
<?php
|
||||
View::show('admin/footer'); ?>
|
||||
|
|
@ -1,29 +0,0 @@
|
|||
<?php
|
||||
/**
|
||||
* @Author: printempw
|
||||
* @Date: 2016-03-06 14:19:20
|
||||
* @Last Modified by: printempw
|
||||
* @Last Modified time: 2016-05-12 21:53:49
|
||||
*/
|
||||
require "../libraries/session.inc.php";
|
||||
if (!$user->is_admin) Utils::redirect('../index.php', '看起来你并不是管理员');
|
||||
View::show('admin/header', array('page_title' => "用户管理"));
|
||||
$db = new Database\Database('users');
|
||||
|
||||
if (isset($_GET['show'])) {
|
||||
View::show('admin/show', ['uid' => (int)$_GET['show']]);
|
||||
} else {
|
||||
View::show('admin/list');
|
||||
}
|
||||
|
||||
$data['script'] = <<< 'EOT'
|
||||
<script type="text/javascript" src="../assets/js/admin.utils.js"></script>
|
||||
<script>
|
||||
$('#page-select').on('change', function() {
|
||||
window.location = "manage.php?page="+$(this).val();
|
||||
});
|
||||
</script>
|
||||
EOT;
|
||||
if (isset($_GET['show']))
|
||||
$data['script'] .= '<script type="text/javascript" src="../assets/js/preview.utils.js"></script>';
|
||||
View::show('admin/footer', $data); ?>
|
||||
|
|
@ -1,232 +0,0 @@
|
|||
<?php
|
||||
/**
|
||||
* @Author: printempw
|
||||
* @Date: 2016-03-18 22:50:25
|
||||
* @Last Modified by: printempw
|
||||
* @Last Modified time: 2016-06-12 11:09:02
|
||||
*/
|
||||
require "../libraries/session.inc.php";
|
||||
if (!$user->is_admin) Utils::redirect('../index.php', '看起来你并不是管理员');
|
||||
View::show('admin/header', array('page_title' => "站点配置"));
|
||||
$db = new Database\Database('users');
|
||||
?>
|
||||
<!-- Content Wrapper. Contains page content -->
|
||||
<div class="content-wrapper">
|
||||
<!-- Content Header (Page header) -->
|
||||
<section class="content-header">
|
||||
<h1>
|
||||
站点配置
|
||||
<small>Options</small>
|
||||
</h1>
|
||||
</section>
|
||||
|
||||
<!-- Main content -->
|
||||
<section class="content">
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
<div class="box box-primary">
|
||||
<div class="box-header with-border">
|
||||
<h3 class="box-title">常规选项</h3>
|
||||
</div><!-- /.box-header -->
|
||||
<form method="post" action="options.php">
|
||||
<input type="hidden" name="option" value="general">
|
||||
<div class="box-body">
|
||||
<?php
|
||||
if (isset($_POST['option']) && ($_POST['option'] == "general")) {
|
||||
// pre-set user_can_register because it will not be posted if not checked
|
||||
if (!isset($_POST['user_can_register'])) $_POST['user_can_register'] = '0';
|
||||
foreach ($_POST as $key => $value) {
|
||||
// remove slash if site_url is ended with slash
|
||||
if ($key == "site_url" && preg_match("/.*(\/)$/", $value)) {
|
||||
$value = substr($value, 0, -1);
|
||||
}
|
||||
if ($key != "option" && $key != "submit") {
|
||||
Option::set($key, $value);
|
||||
}
|
||||
}
|
||||
echo '<div class="callout callout-success">设置已保存。</div>';
|
||||
} ?>
|
||||
<table class="table">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td class="key">站点标题</td>
|
||||
<td class="value">
|
||||
<input type="text" class="form-control" name="site_name" value="<?php echo Option::get('site_name'); ?>">
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="key">站点描述</td>
|
||||
<td class="value">
|
||||
<input type="text" class="form-control" name="site_description" value="<?php echo Option::get('site_description'); ?>">
|
||||
</td>
|
||||
</tr>
|
||||
<tr data-toggle="tooltip" data-placement="bottom" title="以 http:// 开头,带上子目录(如果有)">
|
||||
<td class="key">站点地址(URL)</td>
|
||||
<td class="value">
|
||||
<input type="text" class="form-control" name="site_url" value="<?php echo Option::get('site_url'); ?>">
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="key">开放注册</td>
|
||||
<td class="value">
|
||||
<label for="user_can_register">
|
||||
<input <?php echo (Option::get('user_can_register') == '1') ? 'checked="true"' : ''; ?> type="checkbox" id="user_can_register" name="user_can_register" value="1">任何人都可以注册
|
||||
</label>
|
||||
</td>
|
||||
</tr>
|
||||
<tr data-toggle="tooltip" data-placement="bottom" title="默认皮肤文件请放置于 textures 目录下,并在此键入文件名。默认留空。">
|
||||
<td class="key">新用户默认皮肤</td>
|
||||
<td class="value">
|
||||
<input type="text" class="form-control" name="user_default_skin" value="<?php echo Option::get('user_default_skin'); ?>">
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="key">每个 IP 限制注册数</td>
|
||||
<td class="value">
|
||||
<input type="text" class="form-control" name="regs_per_ip" value="<?php echo Option::get('regs_per_ip'); ?>">
|
||||
</td>
|
||||
</tr>
|
||||
<tr data-toggle="tooltip" data-placement="bottom" title="PHP 限制:<?php echo ini_get('post_max_size'); ?>,定义在 php.ini 中。">
|
||||
<td class="key">最大允许上传大小</td>
|
||||
<td class="value">
|
||||
<div class="input-group">
|
||||
<input type="text" class="form-control" name="upload_max_size" value="<?php echo Option::get('upload_max_size'); ?>">
|
||||
<span class="input-group-addon">KB</span>
|
||||
</div>
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="key">首选 JSON API</td>
|
||||
<td class="value">
|
||||
<select class="form-control" name="api_type">
|
||||
<option <?php echo (Option::get('api_type') == '0') ? 'selected="selected"' : ''; ?> value="0">CustomSkinLoader API</option>
|
||||
<option <?php echo (Option::get('api_type') == '1') ? 'selected="selected"' : ''; ?> value="1">UniversalSkinAPI</option>
|
||||
</select>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="key">站点公告</td>
|
||||
<td class="value">
|
||||
<textarea name="announcement" class="form-control" rows="3"><?php echo Option::get('announcement'); ?></textarea>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div><!-- /.box-body -->
|
||||
<div class="box-footer">
|
||||
<button type="submit" name="submit" class="btn btn-primary">提交</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-md-6">
|
||||
<div class="box box-warning">
|
||||
<div class="box-header with-border">
|
||||
<h3 class="box-title">数据对接配置</h3>
|
||||
</div><!-- /.box-header -->
|
||||
<form method="post" action="options.php">
|
||||
<input type="hidden" name="option" value="adapter">
|
||||
<div class="box-body">
|
||||
<?php
|
||||
if (isset($_POST['option']) && ($_POST['option'] == "adapter")) {
|
||||
foreach ($_POST as $key => $value) {
|
||||
if ($key != "option" && $key != "submit") {
|
||||
Option::set($key, $value);
|
||||
//echo $key."=".$value."<br />";
|
||||
}
|
||||
}
|
||||
echo '<div class="callout callout-success">设置已保存。</div>';
|
||||
} else {
|
||||
echo '<div class="callout callout-warning">如果你不知道下面这些是干什么的,请不要继续编辑。</div>';
|
||||
} ?>
|
||||
<table class="table">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td class="key">数据对接适配器</td>
|
||||
<td class="value">
|
||||
<select class="form-control" name="data_adapter">
|
||||
<option <?php echo (Option::get('data_adapter') == '') ? 'selected="selected"' : ''; ?> value="">不进行数据对接</option>
|
||||
<option <?php echo (Option::get('data_adapter') == 'Authme') ? 'selected="selected"' : ''; ?> value="Authme">Authme</option>
|
||||
<option <?php echo (Option::get('data_adapter') == 'Crazy') ? 'selected="selected"' : ''; ?> value="Crazy">CrazyLogin</option>
|
||||
<option <?php echo (Option::get('data_adapter') == 'Discuz') ? 'selected="selected"' : ''; ?> value="Discuz">Discuz</option>
|
||||
<option <?php echo (Option::get('data_adapter') == 'Phpwind') ? 'selected="selected"' : ''; ?> value="Phpwind">Phpwind</option>
|
||||
</select>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="key">对接数据表名</td>
|
||||
<td class="value">
|
||||
<input type="text" class="form-control" name="data_table_name" value="<?php echo Option::get('data_table_name'); ?>">
|
||||
</td>
|
||||
</tr>
|
||||
<tr data-toggle="tooltip" data-placement="bottom">
|
||||
<td class="key">密码加密算法</td>
|
||||
<td class="value">
|
||||
<select class="form-control" name="encryption">
|
||||
<option <?php echo (Option::get('encryption') == 'MD5') ? 'selected="selected"' : ''; ?> value="MD5">MD5</option>
|
||||
<option <?php echo (Option::get('encryption') == 'SALTED2MD5') ? 'selected="selected"' : ''; ?> value="SALTED2MD5">SALTED2MD5</option>
|
||||
<option <?php echo (Option::get('encryption') == 'SHA256') ? 'selected="selected"' : ''; ?> value="SHA256">SHA256</option>
|
||||
<option <?php echo (Option::get('encryption') == 'CrazyCrypt1') ? 'selected="selected"' : ''; ?> value="CrazyCrypt1">CrazyCrypt1</option>
|
||||
</select>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="key">对接数据表用户名字段</td>
|
||||
<td class="value">
|
||||
<input data-toggle="tooltip" data-placement="bottom" type="text" class="form-control" name="data_column_uname" value="<?php echo Option::get('data_column_uname'); ?>">
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="key">对接数据表密码字段</td>
|
||||
<td class="value">
|
||||
<input data-toggle="tooltip" data-placement="bottom" type="text" class="form-control" name="data_column_passwd" value="<?php echo Option::get('data_column_passwd'); ?>">
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="key">对接数据表 IP 字段</td>
|
||||
<td class="value">
|
||||
<input data-toggle="tooltip" data-placement="bottom" type="text" class="form-control" name="data_column_ip" value="<?php echo Option::get('data_column_ip'); ?>">
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div><!-- /.box-body -->
|
||||
<div class="box-footer">
|
||||
<button type="submit" name="submit" class="btn btn-primary">提交</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<div class="box box-default collapsed-box">
|
||||
<div class="box-header with-border">
|
||||
<h3 class="box-title">如何填写数据对接配置?</h3>
|
||||
<div class="box-tools pull-right">
|
||||
<button type="button" class="btn btn-box-tool" data-widget="collapse">
|
||||
<i class="fa fa-plus"></i>
|
||||
</button>
|
||||
</div>
|
||||
<!-- /.box-tools -->
|
||||
</div><!-- /.box-header -->
|
||||
<div class="box-body">
|
||||
<h4>对接数据表名</h4>
|
||||
<p>所需要对接的程序的用户信息数据表,Authme 默认为 `authme`,CrazyLogin 默认为 `crazylogin_accounts`,Discuz 默认为 `pre_ucenter_members`,Phpwind 默认为 `windid_user`。请根据实际情况填写。</p>
|
||||
<h4>密码加密算法</h4>
|
||||
<p>皮肤站默认为 MD5。Authme 默认为 SHA256,CrazyLogin 为 CrazyCrypt1,Discuz 和 Phpwind 为 SALTED2MD5。没有需要的加密算法?请联系作者。</p>
|
||||
<h4>对接数据表用户名字段</h4>
|
||||
<p>如果你没有修改插件配置的话,请保持默认(`username`)。CrazyLogin 的话请将此字段改为 `name`。</p>
|
||||
<h4>对接数据表密码字段</h4>
|
||||
<p>同上,不要瞎球改。默认为 `password`</p>
|
||||
<h4>对接数据表 IP 字段</h4>
|
||||
<p>CrazyLogin 的话请将此字段改为 `ips`,Discuz 和 Phpwind 请改为 `regip`。</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</section><!-- /.content -->
|
||||
</div><!-- /.content-wrapper -->
|
||||
<?php
|
||||
View::show('admin/footer'); ?>
|
||||
|
|
@ -1,29 +0,0 @@
|
|||
<?php
|
||||
/**
|
||||
* @Author: printempw
|
||||
* @Date: 2016-03-27 15:03:40
|
||||
* @Last Modified by: printempw
|
||||
* @Last Modified time: 2016-05-12 21:53:49
|
||||
*/
|
||||
require "../libraries/session.inc.php";
|
||||
if (!$user->is_admin) Utils::redirect('../index.php', '看起来你并不是管理员');
|
||||
$action = isset($_GET['action']) ? $_GET['action'] : "";
|
||||
|
||||
$updater = new Updater(Option::get('current_version'));
|
||||
|
||||
if ($action == "check" && $updater->newVersionAvailable()) {
|
||||
exit(json_encode([
|
||||
'new_version_available' => true,
|
||||
'latest_version' => $updater->latest_version
|
||||
]));
|
||||
}
|
||||
|
||||
View::show('admin/header', array('page_title' => "检查更新"));
|
||||
|
||||
if ($action == "download") {
|
||||
View::show('admin/download');
|
||||
} else {
|
||||
View::show('admin/check');
|
||||
}
|
||||
|
||||
View::show('admin/footer'); ?>
|
||||
296
ajax.php
|
|
@ -1,296 +0,0 @@
|
|||
<?php
|
||||
/**
|
||||
* @Author: printempw
|
||||
* @Date: 2016-01-16 23:01:33
|
||||
* @Last Modified by: printempw
|
||||
* @Last Modified time: 2016-04-03 10:16:00
|
||||
*
|
||||
* - login, register, logout
|
||||
* - upload, change, delete
|
||||
*
|
||||
* All ajax requests will be handled here
|
||||
*/
|
||||
|
||||
session_start();
|
||||
header('Access-Control-Allow-Origin: *');
|
||||
header('Content-type: application/json');
|
||||
|
||||
$dir = dirname(__FILE__);
|
||||
require "$dir/libraries/autoloader.php";
|
||||
Database\Database::checkConfig();
|
||||
|
||||
if (isset($_POST['uname'])) {
|
||||
$uname = $_POST['uname'];
|
||||
if (User::checkValidUname($uname)) {
|
||||
$user = new User($_POST['uname']);
|
||||
} else {
|
||||
throw new E('无效的用户名。用户名只能包含数字,字母以及下划线。', 3);
|
||||
}
|
||||
} else {
|
||||
throw new E('空用户名。', 3);
|
||||
}
|
||||
$action = isset($_GET['action']) ? $_GET['action'] : null;
|
||||
$json = null;
|
||||
|
||||
/**
|
||||
* Handle requests from index.php
|
||||
*/
|
||||
if ($action == "login") {
|
||||
if (checkPost()) {
|
||||
if (!$user->is_registered) {
|
||||
$json['errno'] = 2;
|
||||
$json['msg'] = "用户不存在哦";
|
||||
} else {
|
||||
if ($user->checkPasswd($_POST['passwd'])) {
|
||||
$json['errno'] = 0;
|
||||
$json['msg'] = '登录成功,欢迎回来~';
|
||||
$json['token'] = $user->getToken();
|
||||
$_SESSION['token'] = $user->getToken();
|
||||
} else {
|
||||
$json['errno'] = 1;
|
||||
$json['msg'] = "用户名或密码不对哦";
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if ($action == "register") {
|
||||
if (checkPost('register')) {
|
||||
if (!$user->is_registered) {
|
||||
if (Option::get('user_can_register') == 1) {
|
||||
if (User::checkValidPwd($_POST['passwd'])) {
|
||||
// If amount of registered accounts of IP is more than allowed mounts,
|
||||
// then reject the registration.
|
||||
if ($user->db->getNumRows('ip', getRealIP()) < Option::get('regs_per_ip')) {
|
||||
// use once md5 to encrypt password
|
||||
if ($user->register($_POST['passwd'], getRealIP())) {
|
||||
$json['errno'] = 0;
|
||||
$json['msg'] = "注册成功~";
|
||||
}
|
||||
} else {
|
||||
$json['errno'] = 7;
|
||||
$json['msg'] = "你最多只能注册 ".Option::get('regs_per_ip')." 个账户哦";
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$json['errno'] = 7;
|
||||
$json['msg'] = "残念。。本皮肤站已经关闭注册咯 QAQ";
|
||||
}
|
||||
} else {
|
||||
$json['errno'] = 5;
|
||||
$json['msg'] = "这个用户名已经被人注册辣,换一个吧";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function getRealIP() {
|
||||
if (!empty($_SERVER['HTTP_CLIENT_IP'])) {
|
||||
$ip = $_SERVER['HTTP_CLIENT_IP'];
|
||||
} elseif (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) {
|
||||
$ip = $_SERVER['HTTP_X_FORWARDED_FOR'];
|
||||
} else {
|
||||
$ip = $_SERVER['REMOTE_ADDR'];
|
||||
}
|
||||
return $ip;
|
||||
}
|
||||
|
||||
function checkPost() {
|
||||
global $json;
|
||||
if (!isset($_POST['passwd'])) {
|
||||
$json['errno'] = 2;
|
||||
$json['msg'] = "空密码。";
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle request from user/index.php
|
||||
*/
|
||||
if ($action == "upload") {
|
||||
if (Utils::getValue('token', $_SESSION) == $user->getToken()) {
|
||||
if (checkFile()) {
|
||||
if ($file = Utils::getValue('skin_file', $_FILES)) {
|
||||
$model = (isset($_GET['model']) && $_GET['model'] == "steve") ? "steve" : "alex";
|
||||
if ($user->setTexture($model, $file)) {
|
||||
$json['skin']['errno'] = 0;
|
||||
$json['skin']['msg'] = "皮肤上传成功!";
|
||||
}
|
||||
}
|
||||
if ($file = Utils::getValue('cape_file', $_FILES)) {
|
||||
if ($user->setTexture('cape', $file)) {
|
||||
$json['cape']['errno'] = 0;
|
||||
$json['cape']['msg'] = "披风上传成功!";
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$json['errno'] = 1;
|
||||
$json['msg'] = "无效的 token,请先登录。";
|
||||
}
|
||||
} else if ($action == "model") {
|
||||
if (Utils::getValue('token', $_SESSION) == $user->getToken()) {
|
||||
$new_model = ($user->getPreference() == "default") ? "slim" : "default";
|
||||
$user->setPreference($new_model);
|
||||
$json['errno'] = 0;
|
||||
$json['msg'] = "优先模型已经更改为 ".$user->getPreference()."。";
|
||||
} else {
|
||||
$json['errno'] = 1;
|
||||
$json['msg'] = "无效的 token,请先登录。";
|
||||
}
|
||||
}
|
||||
|
||||
function checkFile() {
|
||||
global $json;
|
||||
|
||||
if (!(Utils::getValue('skin_file', $_FILES) || Utils::getValue('cape_file', $_FILES))) {
|
||||
$json['errno'] = 1;
|
||||
$json['msg'] = "什么文件都没有诶?";
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check for skin_file
|
||||
*/
|
||||
if (isset($_FILES['skin_file']) && ($_FILES['skin_file']['type'] == "image/png" ||
|
||||
$_FILES['skin_file']['type'] == "image/x-png"))
|
||||
{
|
||||
// if error occured while uploading file
|
||||
if ($_FILES['skin_file']["error"] > 0) {
|
||||
$json['skin']['errno'] = 1;
|
||||
$json['skin']['msg'] = $_FILES['skin_file']["error"];
|
||||
return false;
|
||||
}
|
||||
if ($_FILES['skin_file']['size'] > (Option::get('upload_max_size')) * 1024) {
|
||||
$json['skin']['errno'] = 1;
|
||||
$json['skin']['msg'] = "本站最大只允许上传 ".Option::get('upload_max_size')." KB 的材质。";
|
||||
return false;
|
||||
}
|
||||
$size = getimagesize($_FILES['skin_file']["tmp_name"]);
|
||||
$ratio = $size[0] / $size[1];
|
||||
if ($ratio != 2 && $ratio != 1) {
|
||||
$json['skin']['errno'] = 1;
|
||||
$json['skin']['msg'] = "不是有效的皮肤文件(宽 {$size[0]},高 {$size[1]})";
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
if (Utils::getValue('skin_file', $_FILES)) {
|
||||
$json['skin']['errno'] = 1;
|
||||
$json['skin']['msg'] = '错误的皮肤文件类型。';
|
||||
return false;
|
||||
} else {
|
||||
$json['skin']['errno'] = 0;
|
||||
$json['skin']['msg'] = '什么文件都没有诶?';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check for cape_file
|
||||
*/
|
||||
if (isset($_FILES['cape_file']) && ($_FILES['cape_file']['type'] == "image/png" ||
|
||||
$_FILES['cape_file']['type'] == "image/x-png"))
|
||||
{
|
||||
// if error occured while uploading file
|
||||
if ($_FILES['cape_file']["error"] > 0) {
|
||||
$json['cape']['errno'] = 1;
|
||||
$json['cape']['msg'] = $_FILES['cape_file']["error"];
|
||||
return false;
|
||||
}
|
||||
if ($_FILES['cape_file']['size'] > (Option::get('upload_max_size')) * 1024) {
|
||||
$json['cape']['errno'] = 1;
|
||||
$json['cape']['msg'] = "本站最大只允许上传 ".(Option::get('upload_max_size') * 1024)." KB 的材质。";
|
||||
return false;
|
||||
}
|
||||
$size = getimagesize($_FILES['cape_file']["tmp_name"]);
|
||||
$ratio = $size[0] / $size[1];
|
||||
if ($ratio != 2) {
|
||||
$json['cape']['errno'] = 1;
|
||||
$json['cape']['msg'] = "不是有效的披风文件(宽 {$size[0]},高 {$size[1]})";
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
if (Utils::getValue('cape_file', $_FILES)) {
|
||||
$json['cape']['errno'] = 1;
|
||||
$json['cape']['msg'] = '错误的披风文件类型。';
|
||||
return false;
|
||||
} else {
|
||||
$json['cape']['errno'] = 0;
|
||||
$json['cape']['msg'] = '什么文件都没有诶?';
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle requests from user/profile.php
|
||||
*/
|
||||
if ($action == "change") {
|
||||
if (checkPost()) {
|
||||
if (isset($_POST['new_passwd'])) {
|
||||
if ($user->checkPasswd($_POST['passwd'])) {
|
||||
$user->changePasswd($_POST['new_passwd']);
|
||||
$json['errno'] = 0;
|
||||
$json['msg'] = "密码更改成功。请重新登录。";
|
||||
} else {
|
||||
$json['errno'] = 2;
|
||||
$json['msg'] = "原密码不对哦?";
|
||||
}
|
||||
} else {
|
||||
$json['errno'] = 1;
|
||||
$json['msg'] = "新密码呢?";
|
||||
}
|
||||
}
|
||||
} else if ($action == "delete") {
|
||||
if (isset($_SESSION['token']) && $_SESSION['token'] == $user->getToken()) {
|
||||
if (checkPost()) {
|
||||
if (!$user->is_admin) {
|
||||
if ($user->checkPasswd($_POST['passwd'])) {
|
||||
session_destroy();
|
||||
$user->unRegister();
|
||||
$json['errno'] = 0;
|
||||
$json['msg'] = "账号已经成功删除,再见~";
|
||||
} else {
|
||||
$json['errno'] = 2;
|
||||
$json['msg'] = "错误的密码。";
|
||||
}
|
||||
} else {
|
||||
$json['errno'] = 1;
|
||||
$json['msg'] = "管理员账号不能被删除哟~";
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$json['errno'] = 1;
|
||||
$json['msg'] = "无效的 token,请先登录。";
|
||||
}
|
||||
} else if ($action == "reset") {
|
||||
if (isset($_SESSION['token']) && $_SESSION['token'] == $user->getToken()) {
|
||||
if (checkPost()) {
|
||||
if ($user->checkPasswd($_POST['passwd'])) {
|
||||
$user->reset();
|
||||
$json['errno'] = 0;
|
||||
$json['msg'] = "重置成功。";
|
||||
} else {
|
||||
$json['errno'] = 2;
|
||||
$json['msg'] = "错误的密码。";
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$json['errno'] = 1;
|
||||
$json['msg'] = "无效的 token,请先登录。";
|
||||
}
|
||||
} else if ($action == "logout") {
|
||||
if (Utils::getValue('token', $_SESSION)) {
|
||||
session_destroy();
|
||||
$json['errno'] = 0;
|
||||
$json['msg'] = '成功登出 | ゚ ∀゚)ノ';
|
||||
} else {
|
||||
$json['errno'] = 1;
|
||||
$json['msg'] = '并没有任何有效的 session。';
|
||||
}
|
||||
}
|
||||
|
||||
if (!$action) {
|
||||
$json['errno'] = 6;
|
||||
$json['msg'] = "无效的参数。不要乱 POST 玩哦。";
|
||||
}
|
||||
|
||||
echo json_encode($json);
|
||||
190
app/Controllers/AuthController.php
Normal file
|
|
@ -0,0 +1,190 @@
|
|||
<?php
|
||||
|
||||
namespace App\Controllers;
|
||||
|
||||
use App\Models\User;
|
||||
use App\Models\UserModel;
|
||||
use App\Exceptions\E;
|
||||
use Mail;
|
||||
use View;
|
||||
use Option;
|
||||
|
||||
class AuthController extends BaseController
|
||||
{
|
||||
public function login()
|
||||
{
|
||||
View::show('auth.login');
|
||||
}
|
||||
|
||||
public function handleLogin()
|
||||
{
|
||||
$user = new User($_POST['email']);
|
||||
|
||||
if (\Utils::getValue('login_fails', $_SESSION) > 3) {
|
||||
if (strtolower(\Utils::getValue('captcha', $_POST)) != strtolower($_SESSION['phrase']))
|
||||
View::json('验证码填写错误', 1);
|
||||
}
|
||||
|
||||
if (!$user->is_registered) {
|
||||
View::json('用户不存在哦', 2);
|
||||
} else {
|
||||
if ($user->checkPasswd($_POST['password'])) {
|
||||
$_SESSION['token'] = $user->getToken();
|
||||
unset($_SESSION['login_fails']);
|
||||
|
||||
header('Content-type: application/json');
|
||||
|
||||
// setcookie('email', $user->email, time()+3600, '/');
|
||||
// setcookie('token', $user->getToken(), time()+3600, '/');
|
||||
|
||||
echo json_encode([
|
||||
'errno' => 0,
|
||||
'msg' => '登录成功,欢迎回来~',
|
||||
'token' => $user->getToken()
|
||||
]);
|
||||
} else {
|
||||
$_SESSION['login_fails'] = isset($_SESSION['login_fails']) ?
|
||||
$_SESSION['login_fails'] + 1 : 1;
|
||||
View::json([
|
||||
'errno' => 1,
|
||||
'msg' => '邮箱或密码不对哦~',
|
||||
'login_fails' => $_SESSION['login_fails']
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function logout()
|
||||
{
|
||||
if (isset($_SESSION['token'])) {
|
||||
session_destroy();
|
||||
View::json('登出成功~', 0);
|
||||
} else {
|
||||
throw new E('并没有有效的 session', 1);
|
||||
}
|
||||
}
|
||||
|
||||
public function register()
|
||||
{
|
||||
View::show('auth.register');
|
||||
}
|
||||
|
||||
public function handleRegister()
|
||||
{
|
||||
if (strtolower(\Utils::getValue('captcha', $_POST)) != strtolower($_SESSION['phrase']))
|
||||
View::json('验证码填写错误', 1);
|
||||
|
||||
$user = new User($_POST['email']);
|
||||
|
||||
if (!$user->is_registered) {
|
||||
if (Option::get('user_can_register') == 1) {
|
||||
if (\Validate::checkValidPwd($_POST['password'])) {
|
||||
// If amount of registered accounts of IP is more than allowed mounts,
|
||||
// then reject the registration.
|
||||
if (count(UserModel::where('ip', \Http::getRealIP())->get()) < Option::get('regs_per_ip')) {
|
||||
// use once md5 to encrypt password
|
||||
$user = $user->register($_POST['password'], \Http::getRealIP());
|
||||
$user->setNickName($_POST['nickname']);
|
||||
View::json('注册成功~', 0);
|
||||
|
||||
} else {
|
||||
View::json('你最多只能注册 '.Option::get('regs_per_ip').' 个账户哦', 7);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
View::json('残念。。本皮肤站已经关闭注册咯 QAQ', 7);
|
||||
}
|
||||
} else {
|
||||
View::json('这个邮箱已经注册过啦,换一个吧', 5);
|
||||
}
|
||||
}
|
||||
|
||||
public function forgot()
|
||||
{
|
||||
View::show('auth.forgot');
|
||||
}
|
||||
|
||||
public function handleForgot()
|
||||
{
|
||||
if (strtolower(\Utils::getValue('captcha', $_POST)) != strtolower($_SESSION['phrase']))
|
||||
View::json('验证码填写错误', 1);
|
||||
|
||||
if (isset($_SESSION['last_mail_time']) && (time() - $_SESSION['last_mail_time']) < 60)
|
||||
View::json('你邮件发送得太频繁啦,过 60 秒后再点发送吧', 1);
|
||||
|
||||
$user = new User($_POST['email']);
|
||||
|
||||
if (!$user->is_registered)
|
||||
View::json('该邮箱尚未注册', 1);
|
||||
|
||||
$mail = new Mail();
|
||||
|
||||
$mail->from(Option::get('site_name'))
|
||||
->to($_POST['email'])
|
||||
->subject('重置您在 '.Option::get('site_name').' 上的账户密码');
|
||||
|
||||
$uid = $user->uid;
|
||||
$token = base64_encode($user->getToken().substr(time(), 4, 6).\Utils::generateRndString(16));
|
||||
|
||||
$url = Option::get('site_url')."/auth/reset?uid={$uid}&token=$token";
|
||||
$content = View::make('auth.mail')->with('reset_url', $url)->render();
|
||||
|
||||
if(!$mail->Send($content)) {
|
||||
View::json('邮件发送失败,详细信息:'.$mail->getLastError(), 2);
|
||||
} else {
|
||||
$_SESSION['last_mail_time'] = time();
|
||||
View::json('邮件已发送,一小时内有效,请注意查收.', 0);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public function reset()
|
||||
{
|
||||
if (isset($_GET['uid']) && isset($_GET['token'])) {
|
||||
$user = new User('', $_GET['uid']);
|
||||
if (!$user->is_registered)
|
||||
\Http::redirect('./forgot', '无效的链接');
|
||||
|
||||
$token = substr(base64_decode($_GET['token']), 0, -22);
|
||||
|
||||
if ($user->getToken() != $token) {
|
||||
\Http::redirect('./forgot', '无效的链接');
|
||||
}
|
||||
|
||||
$timestamp = substr(base64_decode($_GET['token']), strlen($token), 6);
|
||||
|
||||
// more than 1 hour
|
||||
if ((substr(time(), 4, 6) - $timestamp) > 3600) {
|
||||
\Http::redirect('./forgot', '链接已过期');
|
||||
}
|
||||
|
||||
echo View::make('auth.reset')->with('user', $user);
|
||||
} else {
|
||||
\Http::redirect('./login', '非法访问');
|
||||
}
|
||||
}
|
||||
|
||||
public function handleReset()
|
||||
{
|
||||
\Utils::checkPost(['uid', 'password']);
|
||||
|
||||
if (\Validate::checkValidPwd($_POST['password'])) {
|
||||
$user = new User('', $_POST['uid']);
|
||||
|
||||
$user->changePasswd($_POST['password']);
|
||||
|
||||
View::json('密码重置成功', 0);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public function captcha()
|
||||
{
|
||||
$builder = new \Gregwar\Captcha\CaptchaBuilder;
|
||||
$builder->build($width = 100, $height = 34);
|
||||
$_SESSION['phrase'] = $builder->getPhrase();
|
||||
header('Content-type: image/jpeg');
|
||||
$builder->output();
|
||||
}
|
||||
|
||||
}
|
||||
10
app/Controllers/BaseController.php
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
<?php
|
||||
|
||||
namespace App\Controllers;
|
||||
|
||||
/**
|
||||
* 突然发现这个基类卵用没有 (;´Д`)
|
||||
*/
|
||||
class BaseController
|
||||
{
|
||||
}
|
||||
73
app/Controllers/ClosetController.php
Normal file
|
|
@ -0,0 +1,73 @@
|
|||
<?php
|
||||
|
||||
namespace App\Controllers;
|
||||
|
||||
use App\Models\User;
|
||||
use App\Models\Texture;
|
||||
use App\Models\Closet;
|
||||
use App\Models\ClosetModel;
|
||||
use App\Exceptions\E;
|
||||
use View;
|
||||
use Option;
|
||||
|
||||
class ClosetController extends BaseController
|
||||
{
|
||||
public $closet;
|
||||
|
||||
function __construct()
|
||||
{
|
||||
$this->closet = new Closet((new User($_SESSION['email']))->uid);
|
||||
}
|
||||
|
||||
public function index()
|
||||
{
|
||||
$category = isset($_GET['category']) ? $_GET['category'] : "skin";
|
||||
|
||||
$page = isset($_GET['page']) ? $_GET['page'] : 1;
|
||||
|
||||
$items = array_slice($this->closet->getItems($category), ($page-1)*6, 6);
|
||||
|
||||
$total_pages = ceil(count($this->closet->getItems($category)) / 6);
|
||||
|
||||
echo View::make('user.closet')->with('items', $items)
|
||||
->with('page', $page)
|
||||
->with('category', $category)
|
||||
->with('total_pages', $total_pages)
|
||||
->with('user', (new User($_SESSION['email'])))
|
||||
->render();
|
||||
}
|
||||
|
||||
public function info()
|
||||
{
|
||||
View::json($this->closet->getItems());
|
||||
}
|
||||
|
||||
public function add()
|
||||
{
|
||||
if (!is_numeric(\Utils::getValue('tid', $_POST)))
|
||||
throw new E('Invalid parameters.', 1);
|
||||
|
||||
if ($this->closet->add($_POST['tid'])) {
|
||||
$t = Texture::find($_POST['tid']);
|
||||
$t->likes += 1;
|
||||
$t->save();
|
||||
|
||||
View::json('收藏成功~', 0);
|
||||
}
|
||||
}
|
||||
|
||||
public function remove()
|
||||
{
|
||||
if (!is_numeric(\Utils::getValue('tid', $_POST)))
|
||||
throw new E('Invalid parameters.', 1);
|
||||
|
||||
if ($this->closet->remove($_POST['tid'])) {
|
||||
$t = Texture::find($_POST['tid']);
|
||||
$t->likes = $t->likes - 1;
|
||||
$t->save();
|
||||
|
||||
View::json('材质已从衣柜中移除', 0);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
15
app/Controllers/HomeController.php
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
<?php
|
||||
|
||||
namespace App\Controllers;
|
||||
|
||||
use App\Models\User;
|
||||
|
||||
class HomeController extends BaseController
|
||||
{
|
||||
|
||||
public function index()
|
||||
{
|
||||
echo \View::make('index')->with('user', (isset($_SESSION['email']) ? new User($_SESSION['email']) : null));
|
||||
}
|
||||
|
||||
}
|
||||
152
app/Controllers/PlayerController.php
Normal file
|
|
@ -0,0 +1,152 @@
|
|||
<?php
|
||||
|
||||
namespace App\Controllers;
|
||||
|
||||
use App\Models\User;
|
||||
use App\Models\Player;
|
||||
use App\Models\PlayerModel;
|
||||
use App\Models\Texture;
|
||||
use App\Exceptions\E;
|
||||
use Utils;
|
||||
use Option;
|
||||
use View;
|
||||
|
||||
class PlayerController extends BaseController
|
||||
{
|
||||
private $player = null;
|
||||
|
||||
function __construct()
|
||||
{
|
||||
if (isset($_POST['pid'])) {
|
||||
$this->player = new Player($_POST['pid']);
|
||||
if (!$this->player)
|
||||
\Http::abort(404, '角色不存在');
|
||||
}
|
||||
}
|
||||
|
||||
public function index()
|
||||
{
|
||||
echo View::make('user.player')->with('players', (new User($_SESSION['email']))->getPlayers()->toArray())->with('user', new User($_SESSION['email']));
|
||||
}
|
||||
|
||||
public function add()
|
||||
{
|
||||
$player_name = $_POST['player_name'];
|
||||
|
||||
if (!isset($player_name))
|
||||
View::json('你还没有填写要添加的角色名哦', 1);
|
||||
|
||||
if (!\Validate::checkValidPlayerName($player_name))
|
||||
{
|
||||
$msg = "无效的角色名。角色名只能包含" . ((Option::get('allow_chinese_playername') == "1") ? "汉字、" : "")."字母、数字以及下划线";
|
||||
View::json($msg, 2);
|
||||
}
|
||||
|
||||
if (!PlayerModel::where('player_name', $player_name)->get()->isEmpty())
|
||||
View::json('该角色名已经被其他人注册掉啦', 6);
|
||||
|
||||
$user = new User($_SESSION['email']);
|
||||
|
||||
if ($user->getScore() < 100)
|
||||
View::json('积分不够添加角色啦', 7);
|
||||
|
||||
$player = new PlayerModel();
|
||||
$player->uid = $user->uid;
|
||||
$player->player_name = $player_name;
|
||||
$player->preference = "default";
|
||||
$player->save();
|
||||
|
||||
$user->setScore(100, 'minus');
|
||||
|
||||
View::json('成功添加了角色 '.$player_name.'', 0);
|
||||
|
||||
}
|
||||
|
||||
public function delete()
|
||||
{
|
||||
$player_name = $this->player->eloquent_model->player_name;
|
||||
$this->player->eloquent_model->delete();
|
||||
|
||||
(new User($_SESSION['email']))->setScore(100, 'plus');
|
||||
|
||||
View::json('角色 '.$player_name.' 已被删除', 0);
|
||||
}
|
||||
|
||||
public function show()
|
||||
{
|
||||
echo json_encode($this->player->eloquent_model->toArray(), JSON_NUMERIC_CHECK);
|
||||
}
|
||||
|
||||
public function rename()
|
||||
{
|
||||
$new_player_name = Utils::getValue('new_player_name', $_POST);
|
||||
|
||||
if (!$new_player_name)
|
||||
throw new E('Invalid parameters', 1);
|
||||
|
||||
if (!\Validate::checkValidPlayerName($new_player_name))
|
||||
{
|
||||
$msg = "无效的角色名。角色名只能包含" . ((Option::get('allow_chinese_playername') == "1") ? "汉字、" : "")."字母、数字以及下划线";
|
||||
View::json($msg, 2);
|
||||
}
|
||||
|
||||
if (!PlayerModel::where('player_name', $new_player_name)->get()->isEmpty())
|
||||
View::json('此角色名已被他人使用,换一个吧~', 6);
|
||||
|
||||
$old_player_name = $this->player->eloquent_model->player_name;
|
||||
$this->player->eloquent_model->player_name = $new_player_name;
|
||||
$this->player->eloquent_model->last_modified = Utils::getTimeFormatted();
|
||||
$this->player->eloquent_model->save();
|
||||
|
||||
View::json('角色 '.$old_player_name.' 已更名为 '.$_POST['new_player_name'], 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* A wrapper of Player::setTexture()
|
||||
*/
|
||||
public function setTexture()
|
||||
{
|
||||
$tid = Utils::getValue('tid', $_POST);
|
||||
|
||||
if (!is_numeric($tid))
|
||||
throw new E('Invalid parameters.', 1);
|
||||
|
||||
if (!($texture = Texture::find($tid)))
|
||||
View::json('Unexistent texture.', 6);
|
||||
|
||||
$field_name = "tid_".$texture->type;
|
||||
|
||||
$this->player->eloquent_model->$field_name = $tid;
|
||||
$this->player->eloquent_model->save();
|
||||
|
||||
View::json('材质已成功应用至角色 '.$this->player->eloquent_model->player_name.'', 0);
|
||||
}
|
||||
|
||||
|
||||
|
||||
public function clearTexture()
|
||||
{
|
||||
$this->player->eloquent_model->preference = "default";
|
||||
$this->player->eloquent_model->tid_steve = "";
|
||||
$this->player->eloquent_model->tid_alex = "";
|
||||
$this->player->eloquent_model->tid_cape = "";
|
||||
|
||||
$this->player->eloquent_model->save();
|
||||
|
||||
View::json('角色 '.$this->player->eloquent_model->player_name.' 的材质已被成功重置', 0);
|
||||
}
|
||||
|
||||
public function setPreference()
|
||||
{
|
||||
if (!isset($_POST['preference']) ||
|
||||
($_POST['preference'] != "default" && $_POST['preference'] != "slim"))
|
||||
{
|
||||
throw new E('Invalid parameters.', 1);
|
||||
}
|
||||
|
||||
$this->player->setPreference($_POST['preference']);
|
||||
|
||||
View::json('角色 '.$this->player->player_name.' 的优先模型已更改至 '.$_POST['preference'], 0);
|
||||
}
|
||||
|
||||
}
|
||||
266
app/Controllers/SkinlibController.php
Normal file
|
|
@ -0,0 +1,266 @@
|
|||
<?php
|
||||
|
||||
namespace App\Controllers;
|
||||
|
||||
use App\Models\User;
|
||||
use App\Models\Texture;
|
||||
use App\Exceptions\E;
|
||||
use Utils;
|
||||
use View;
|
||||
use Option;
|
||||
|
||||
class SkinlibController extends BaseController
|
||||
{
|
||||
private $user = null;
|
||||
|
||||
function __construct()
|
||||
{
|
||||
$this->user = isset($_SESSION['email']) ? new User($_SESSION['email']) : null;
|
||||
}
|
||||
|
||||
public function index()
|
||||
{
|
||||
$filter = isset($_GET['filter']) ? $_GET['filter'] : "skin";
|
||||
|
||||
$sort = isset($_GET['sort']) ? $_GET['sort'] : "time";
|
||||
$sort_by = ($sort == "time") ? "upload_at" : $sort;
|
||||
|
||||
$page = isset($_GET['page']) ? $_GET['page'] : 1;
|
||||
|
||||
if ($filter == "skin") {
|
||||
$textures = Texture::where(function($query) {
|
||||
$query->where('public', '=', '1')
|
||||
->where('type', '=', 'steve')
|
||||
->orWhere('type', '=', 'alex');
|
||||
})->orderBy($sort_by, 'desc')->skip(($page - 1) * 20)->take(20)->get();
|
||||
} elseif ($filter == "user") {
|
||||
$uid = isset($_GET['uid']) ? $_GET['uid'] : 0;
|
||||
|
||||
if ($uid == $this->user->uid) {
|
||||
// show private textures when show uploaded textures of current user
|
||||
$textures = Texture::where('uploader', $uid)->orderBy($sort_by, 'desc')->skip(($page - 1) * 20)->take(20)->get();
|
||||
} else {
|
||||
$textures = Texture::where('uploader', $uid)->where('public', '1')->orderBy($sort_by, 'desc')->skip(($page - 1) * 20)->take(20)->get();
|
||||
}
|
||||
|
||||
} else {
|
||||
$textures = Texture::where('type', $filter)->where('public', '1')->orderBy($sort_by, 'desc')->skip(($page - 1) * 20)->take(20)->get();
|
||||
}
|
||||
|
||||
$total_pages = ceil(count($textures) / 20);
|
||||
|
||||
echo View::make('skinlib.index')->with('user', $this->user)
|
||||
->with('sort', $sort)
|
||||
->with('filter', $filter)
|
||||
->with('textures', $textures)
|
||||
->with('page', $page)
|
||||
->with('total_pages', $total_pages)
|
||||
->render();
|
||||
}
|
||||
|
||||
public function search()
|
||||
{
|
||||
$q = isset($_GET['q']) ? $_GET['q'] : "";
|
||||
|
||||
$filter = isset($_GET['filter']) ? $_GET['filter'] : "skin";
|
||||
|
||||
$sort = isset($_GET['sort']) ? $_GET['sort'] : "time";
|
||||
$sort_by = ($sort == "time") ? "upload_at" : $sort;
|
||||
|
||||
if ($filter == "skin") {
|
||||
$textures = Texture::like('name', $q)->where(function($query) use ($q) {
|
||||
$query->where('public', '=', '1')
|
||||
->where('type', '=', 'steve')
|
||||
->orWhere('type', '=', 'alex');
|
||||
})->orderBy($sort_by, 'desc')->get();
|
||||
} else {
|
||||
$textures = Texture::like('name', $q)
|
||||
->where('type', $filter)
|
||||
->where('public', '1')
|
||||
->orderBy($sort_by, 'desc')->get();
|
||||
}
|
||||
|
||||
echo View::make('skinlib.search')->with('user', $this->user)
|
||||
->with('sort', $sort)
|
||||
->with('filter', $filter)
|
||||
->with('q', $q)
|
||||
->with('textures', $textures)->render();
|
||||
}
|
||||
|
||||
public function show()
|
||||
{
|
||||
if (!isset($_GET['tid'])) \Http::abort(404, 'No specified tid.');
|
||||
$texture = Texture::find($_GET['tid']);
|
||||
if (!$texture) \Http::abort(404, '请求的材质已经被删除');
|
||||
|
||||
if ($texture->public == "0") {
|
||||
if (is_null($this->user) || ($this->user->uid != $texture->uploader && !$this->user->is_admin))
|
||||
\Http::abort(404, '请求的材质已经设为隐私,仅上传者和管理员可查看');
|
||||
}
|
||||
|
||||
echo View::make('skinlib.show')->with('texture', $texture)->with('with_out_filter', true)->with('user', $this->user)->render();
|
||||
}
|
||||
|
||||
public function info($tid)
|
||||
{
|
||||
echo json_encode(Texture::find($tid)->toArray());
|
||||
}
|
||||
|
||||
public function upload()
|
||||
{
|
||||
echo View::make('skinlib.upload')->with('user', $this->user)->with('with_out_filter', true)->render();
|
||||
}
|
||||
|
||||
public function handleUpload()
|
||||
{
|
||||
$this->checkUpload(isset($_POST['type']) ? $_POST['type'] : "");
|
||||
|
||||
$t = new Texture();
|
||||
$t->name = $_POST['name'];
|
||||
$t->type = $_POST['type'];
|
||||
$t->hash = \Storage::upload($_FILES['file']);
|
||||
$t->size = ceil($_FILES['file']['size'] / 1024);
|
||||
$t->public = ($_POST['public'] == 'true') ? "1" : "0";
|
||||
$t->uploader = $this->user->uid;
|
||||
|
||||
if ($this->user->getScore() < $t->size)
|
||||
View::json('积分不够啦', 7);
|
||||
|
||||
$results = Texture::where('hash', $t->hash)->get();
|
||||
if (!$results->isEmpty())
|
||||
{
|
||||
foreach ($results as $result) {
|
||||
if (($result['name'] == $t->name) && ($result['type'] == $t->type)) {
|
||||
throw new E('The same file with same name has been already '.
|
||||
'uploaded by others. Try another filr or change your texture name.', 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$t->save();
|
||||
|
||||
$this->user->setScore($t->size, 'minus');
|
||||
|
||||
if ($this->user->closet->add($t->tid)) {
|
||||
$t = Texture::find($t->tid);
|
||||
$t->likes += 1;
|
||||
$t->save();
|
||||
|
||||
View::json([
|
||||
'errno' => 0,
|
||||
'msg' => '材质 '.$_POST['name'].' 上传成功',
|
||||
'tid' => $t->tid
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
public function save()
|
||||
{
|
||||
Utils::checkPost(['name', 'type', 'public', 'original_tid']);
|
||||
|
||||
$original_texture = Texture::find($_POST['original_tid']);
|
||||
|
||||
if ($_POST['name'] == $original_texture->name)
|
||||
View::json('名字不能和原来的一样哦', 1);
|
||||
|
||||
$t = new Texture();
|
||||
$t->name = $_POST['name'];
|
||||
$t->type = $_POST['type'];
|
||||
$t->likes = 1;
|
||||
$t->hash = $original_texture->hash;
|
||||
$t->size = $original_texture->size;
|
||||
$t->public = ($_POST['public'] == true) ? "1" : "0";
|
||||
$t->uploader = $this->user->uid;
|
||||
|
||||
$t->save();
|
||||
|
||||
$this->user->setScore($t->size, 'minus');
|
||||
|
||||
if ($this->user->closet->add($t->tid)) {
|
||||
$t = Texture::find($t->tid);
|
||||
$t->likes += 1;
|
||||
$t->save();
|
||||
|
||||
View::json([
|
||||
'errno' => 0,
|
||||
'msg' => '材质成功另存为 '.$_POST['name'],
|
||||
'tid' => $t->tid
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
public function delete()
|
||||
{
|
||||
if (is_numeric(Utils::getValue('tid', $_POST))) {
|
||||
$result = Texture::find($_POST['tid']);
|
||||
|
||||
if (!$result)
|
||||
throw new E('Unexistent texture.', 1);
|
||||
|
||||
// check if file occupied
|
||||
if (Texture::where('hash', $result['hash'])->count() == 1)
|
||||
\Storage::remove("./textures/".$result['hash']);
|
||||
|
||||
$this->user->setScore($result->size, 'plus');
|
||||
|
||||
if ($result->delete())
|
||||
View::json('材质已被成功删除', 0);
|
||||
|
||||
} else {
|
||||
throw new E('Invalid parameters.', 1);
|
||||
}
|
||||
}
|
||||
|
||||
public function privacy($tid)
|
||||
{
|
||||
$t = Texture::find($tid);
|
||||
if ($t->setPrivacy(!$t->public)) {
|
||||
View::json([
|
||||
'errno' => 0,
|
||||
'msg' => '材质已被设为'.($t->public == "0" ? "隐私" : "公开"),
|
||||
'public' => $t->public
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
private function checkUpload($type)
|
||||
{
|
||||
\Validate::checkValidTextureName(Utils::getValue('name', $_POST));
|
||||
|
||||
if (!Utils::getValue('file', $_FILES))
|
||||
throw new E('你还没有选择任何文件哟', 1);
|
||||
|
||||
if (!isset($_POST['public']) || ($_POST['public'] != 0 && $_POST['public'] != 1))
|
||||
throw new E('Invalid parameters.', 1);
|
||||
|
||||
if ($_FILES['file']['type'] == "image/png" || $_FILES['file']['type'] == "image/x-png")
|
||||
{
|
||||
// if error occured while uploading file
|
||||
if ($_FILES['file']["error"] > 0)
|
||||
throw new E($_FILES['file']["error"], 1);
|
||||
|
||||
$size = getimagesize($_FILES['file']["tmp_name"]);
|
||||
$ratio = $size[0] / $size[1];
|
||||
|
||||
if ($type == "steve" || $type == "alex") {
|
||||
if ($ratio != 2 && $ratio != 1)
|
||||
throw new E("不是有效的皮肤文件(宽 {$size[0]},高 {$size[1]})", 1);
|
||||
} elseif ($type == "cape") {
|
||||
if ($ratio != 2)
|
||||
throw new E("不是有效的披风文件(宽 {$size[0]},高 {$size[1]})", 1);
|
||||
} else {
|
||||
throw new E('Invalid parameters.', 1);
|
||||
}
|
||||
|
||||
} else {
|
||||
if (Utils::getValue('file', $_FILES)) {
|
||||
throw new E('文件格式不对哦', 1);
|
||||
} else {
|
||||
throw new E('No file selected.', 1);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
107
app/Controllers/TextureController.php
Normal file
119
app/Controllers/UserController.php
Normal file
|
|
@ -0,0 +1,119 @@
|
|||
<?php
|
||||
|
||||
namespace App\Controllers;
|
||||
|
||||
use App\Models\User;
|
||||
use App\Models\Texture;
|
||||
use App\Exceptions\E;
|
||||
use Utils;
|
||||
use View;
|
||||
|
||||
class UserController extends BaseController
|
||||
{
|
||||
private $action = "";
|
||||
private $user = null;
|
||||
|
||||
function __construct()
|
||||
{
|
||||
$this->action = isset($_GET['action']) ? $_GET['action'] : "";
|
||||
$this->user = new User($_SESSION['email']);
|
||||
}
|
||||
|
||||
public function index()
|
||||
{
|
||||
echo View::make('user.index')->with('user', $this->user)->render();
|
||||
}
|
||||
|
||||
public function sign()
|
||||
{
|
||||
if ($aquired_score = $this->user->sign()) {
|
||||
View::json([
|
||||
'errno' => 0,
|
||||
'msg' => '签到成功,获得了 '.$aquired_score.' 积分~',
|
||||
'score' => $this->user->getScore()
|
||||
]);
|
||||
} else {
|
||||
View::json($this->user->canSign(true).' 小时后才能再次签到哦~', 1);
|
||||
}
|
||||
}
|
||||
|
||||
public function profile()
|
||||
{
|
||||
echo View::make('user.profile')->with('user', $this->user);
|
||||
}
|
||||
|
||||
public function handleProfile()
|
||||
{
|
||||
// handle changing nickname
|
||||
if ($this->action == "nickname") {
|
||||
if (!isset($_POST['new_nickname'])) throw new E('Invalid parameters.');
|
||||
|
||||
if (Utils::convertString($_POST['new_nickname']) != $_POST['new_nickname'])
|
||||
View::json('无效的昵称。昵称中包含了奇怪的字符。', 1);
|
||||
|
||||
if ($this->user->setNickName($_POST['new_nickname']))
|
||||
View::json('昵称已成功设置为 '.$_POST['new_nickname'], 0);
|
||||
// handle changing password
|
||||
} elseif ($this->action == "password") {
|
||||
if (!(isset($_POST['current_password']) && isset($_POST['new_password'])))
|
||||
throw new E('Invalid parameters.');
|
||||
|
||||
if (!$this->user->checkPasswd($_POST['current_password']))
|
||||
View::json('原密码错误', 1);
|
||||
|
||||
if (\Validate::checkValidPwd($_POST['new_password'])) {
|
||||
if ($this->user->changePasswd($_POST['new_password']))
|
||||
View::json('密码修改成功,请重新登录', 0);
|
||||
}
|
||||
// handle changing email
|
||||
} elseif ($this->action == "email") {
|
||||
if (!(isset($_POST['new_email']) && isset($_POST['password'])))
|
||||
throw new E('Invalid parameters.');
|
||||
|
||||
if (!filter_var($_POST['new_email'], FILTER_VALIDATE_EMAIL)) {
|
||||
View::json('邮箱格式错误', 3);
|
||||
}
|
||||
|
||||
if (!$this->user->checkPasswd($_POST['password']))
|
||||
View::json('密码错误', 1);
|
||||
|
||||
if ($this->user->setEmail($_POST['new_email']))
|
||||
View::json('邮箱修改成功,请重新登录', 0);
|
||||
|
||||
// handle deleting account
|
||||
} elseif ($this->action == "delete") {
|
||||
if (!isset($_POST['password']))
|
||||
throw new E('Invalid parameters.');
|
||||
|
||||
if (!$this->user->checkPasswd($_POST['password']))
|
||||
View::json('密码错误', 1);
|
||||
|
||||
if ($this->user->delete())
|
||||
View::json('账号已被成功删除', 0);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public function config()
|
||||
{
|
||||
echo View::make('user.config')->with('user', $this->user);
|
||||
}
|
||||
|
||||
public function setAvatar()
|
||||
{
|
||||
if (!isset($_POST['tid'])) throw new E('Empty tid.');
|
||||
|
||||
$result = Texture::find($_POST['tid']);
|
||||
if ($result) {
|
||||
if ($result->type == "cape") throw new E('披风可不能设置为头像哦~', 1);
|
||||
|
||||
if ((new User($_SESSION['email']))->setAvatar($_POST['tid'])) {
|
||||
View::json('设置成功!', 0);
|
||||
}
|
||||
} else {
|
||||
throw new E('材质不存在。', 1);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,12 +1,8 @@
|
|||
<?php
|
||||
/**
|
||||
* @Author: printempw
|
||||
* @Date: 2016-03-27 11:04:14
|
||||
* @Last Modified by: printempw
|
||||
* @Last Modified time: 2016-04-03 15:53:59
|
||||
*/
|
||||
|
||||
class E extends Exception
|
||||
namespace App\Exceptions;
|
||||
|
||||
class E extends \Exception
|
||||
{
|
||||
/**
|
||||
* Custom error handler
|
||||
|
|
@ -15,7 +11,8 @@ class E extends Exception
|
|||
* @param integer $code
|
||||
* @param boolean $render, to show a error page
|
||||
*/
|
||||
function __construct($message = "Error occured.", $code = -1, $render = false) {
|
||||
function __construct($message = "Error occured.", $code = -1, $render = false)
|
||||
{
|
||||
parent::__construct($message, $code);
|
||||
if ($render) {
|
||||
$this->showErrorPage();
|
||||
|
|
@ -24,17 +21,17 @@ class E extends Exception
|
|||
}
|
||||
}
|
||||
|
||||
private function showErrorJson() {
|
||||
private function showErrorJson()
|
||||
{
|
||||
$exception['errno'] = $this->code;
|
||||
$exception['msg'] = $this->message;
|
||||
@header('Content-type: application/json; charset=utf-8');
|
||||
exit(json_encode($exception));
|
||||
}
|
||||
|
||||
private function showErrorPage() {
|
||||
$message = $this->message;
|
||||
$code = $this->code;
|
||||
require dirname(dirname(__FILE__))."/templates/error.tpl.php";
|
||||
private function showErrorPage()
|
||||
{
|
||||
echo \View::make('errors.exception')->with('code', $this->code)->with('message', $this->message);
|
||||
exit;
|
||||
}
|
||||
}
|
||||
22
app/Exceptions/RouterExceptionHandler.php
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
<?php
|
||||
|
||||
namespace App\Exceptions;
|
||||
|
||||
use Pecee\Http\Request;
|
||||
use Pecee\SimpleRouter\RouterEntry;
|
||||
use Pecee\Handler\IExceptionHandler;
|
||||
|
||||
class RouterExceptionHandler implements IExceptionHandler
|
||||
{
|
||||
|
||||
public function handleError(Request $request, RouterEntry $router = null, \Exception $error)
|
||||
{
|
||||
if ($error->getCode() === 404) {
|
||||
\Http::abort(404, $error->getMessage(), ($_SERVER['REQUEST_METHOD'] == "POST"));
|
||||
} else {
|
||||
throw $error;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
29
app/Middlewares/CheckLoggedInMiddleware.php
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
<?php
|
||||
|
||||
namespace App\Middlewares;
|
||||
|
||||
use Pecee\Http\Middleware\IMiddleware;
|
||||
use Pecee\Http\Request;
|
||||
use App\Models\User;
|
||||
use App\Exceptions\E;
|
||||
use Utils;
|
||||
|
||||
class CheckLoggedInMiddleware implements IMiddleware
|
||||
{
|
||||
public function handle(Request $request)
|
||||
{
|
||||
if (isset($_COOKIE['email']) && isset($_COOKIE['token'])) {
|
||||
$_SESSION['email'] = $_COOKIE['email'];
|
||||
$_SESSION['token'] = $_COOKIE['token'];
|
||||
}
|
||||
|
||||
if (isset($_SESSION['email'])) {
|
||||
if ($_SESSION['token'] != (new User($_SESSION['email']))->getToken())
|
||||
{
|
||||
\Http::redirect('../auth/login', '无效的 token,请重新登录~');
|
||||
}
|
||||
} else {
|
||||
\Http::redirect('../auth/login', '非法访问,请先登录');
|
||||
}
|
||||
}
|
||||
}
|
||||
34
app/Middlewares/CheckPlayerExistMiddleware.php
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
<?php
|
||||
|
||||
namespace App\Middlewares;
|
||||
|
||||
use Pecee\Http\Middleware\IMiddleware;
|
||||
use Pecee\Http\Request;
|
||||
use App\Models\User;
|
||||
use App\Models\PlayerModel;
|
||||
use App\Exceptions\E;
|
||||
|
||||
class CheckPlayerExistMiddleware implements IMiddleware
|
||||
{
|
||||
public function handle(Request $request)
|
||||
{
|
||||
if (stripos($request->getUri(), '.json') != false) {
|
||||
preg_match('/\/([^\/]*)\.json/', $request->getUri(), $matches);
|
||||
} else {
|
||||
preg_match('/\/([^\/]*)\.png/', $request->getUri(), $matches);
|
||||
}
|
||||
|
||||
$player_name = $matches[1];
|
||||
|
||||
if (\Option::get('allow_chinese_playername')) {
|
||||
$player_name = urldecode($player_name);
|
||||
// quick fix of chinese playername route parameter problem
|
||||
$GLOBALS['player_name'] = $player_name;
|
||||
}
|
||||
|
||||
if (!PlayerModel::where('player_name', $player_name)->count()) {
|
||||
\Http::abort(404, '角色不存在');
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
33
app/Middlewares/CheckPostMiddleware.php
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
<?php
|
||||
|
||||
namespace App\Middlewares;
|
||||
|
||||
use \Pecee\Http\Middleware\IMiddleware;
|
||||
use \Pecee\Http\Request;
|
||||
use View;
|
||||
use App\Exceptions\E;
|
||||
|
||||
class CheckPostMiddleware implements IMiddleware
|
||||
{
|
||||
public function handle(Request $request)
|
||||
{
|
||||
if (isset($_POST['email']) && $_POST['email'] != "") {
|
||||
if (!filter_var($_POST['email'], FILTER_VALIDATE_EMAIL)) {
|
||||
View::json('邮箱格式错误', 3);
|
||||
}
|
||||
|
||||
if ($request->getUri() == "/auth/forgot") return true;
|
||||
|
||||
if (isset($_POST['nickname']) && ($_POST['nickname'] != \Utils::convertString($_POST['nickname'])))
|
||||
View::json('无效的昵称,昵称不能包含奇怪的字符', 1);
|
||||
|
||||
if (isset($_POST['password']) && $_POST['password'] != "") {
|
||||
return true;
|
||||
} else {
|
||||
View::json('密码不能为空哦', 2);
|
||||
}
|
||||
} else {
|
||||
View::json('邮箱地址不能为空哦', 3);
|
||||
}
|
||||
}
|
||||
}
|
||||
27
app/Middlewares/RedirectIfLoggedInMiddleware.php
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
<?php
|
||||
|
||||
namespace App\Middlewares;
|
||||
|
||||
use Pecee\Http\Middleware\IMiddleware;
|
||||
use Pecee\Http\Request;
|
||||
use App\Models\User;
|
||||
|
||||
class RedirectIfLoggedInMiddleware implements IMiddleware
|
||||
{
|
||||
public function handle(Request $request)
|
||||
{
|
||||
if (isset($_COOKIE['email']) && isset($_COOKIE['token'])) {
|
||||
$_SESSION['email'] = $_COOKIE['email'];
|
||||
$_SESSION['token'] = $_COOKIE['token'];
|
||||
}
|
||||
|
||||
if (isset($_SESSION['email'])) {
|
||||
if ($_SESSION['token'] != (new User($_SESSION['email']))->getToken())
|
||||
{
|
||||
$_SESSION['msg'] = "无效的 token,请重新登录~";
|
||||
} else {
|
||||
\Http::redirect('../user');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
26
app/Middlewares/RemoveUrlSlashMiddleware.php
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
<?php
|
||||
|
||||
namespace App\Middlewares;
|
||||
|
||||
use \Pecee\Http\Middleware\IMiddleware;
|
||||
use \Pecee\Http\Request;
|
||||
|
||||
class RemoveUrlSlashMiddleware implements IMiddleware
|
||||
{
|
||||
public function handle(Request $request)
|
||||
{
|
||||
/**
|
||||
* URL ends with slash will cause many reference problems
|
||||
* so I deal it globally in this middleware :)
|
||||
*/
|
||||
if ($_SERVER["REQUEST_URI"] != "/" && substr($_SERVER["REQUEST_URI"], -1) == "/")
|
||||
{
|
||||
$url = (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on') ? "https://" : "http://";
|
||||
$url .= $_SERVER["SERVER_NAME"];
|
||||
$url .= ($_SERVER["SERVER_PORT"] == "80") ? "" : (":".$_SERVER["SERVER_PORT"]);
|
||||
$url .= substr($_SERVER["REQUEST_URI"], 0, -1);
|
||||
|
||||
\Http::redirect($url);
|
||||
}
|
||||
}
|
||||
}
|
||||
150
app/Models/Closet.php
Normal file
|
|
@ -0,0 +1,150 @@
|
|||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use App\Exceptions\E;
|
||||
use Utils;
|
||||
|
||||
class Closet
|
||||
{
|
||||
public $uid;
|
||||
|
||||
/**
|
||||
* Instance of App\Models\ClosetModel
|
||||
* @var null
|
||||
*/
|
||||
private $eloquent_model = null;
|
||||
|
||||
/**
|
||||
* Textures array generated from json
|
||||
* @var Array
|
||||
*/
|
||||
private $textures = [];
|
||||
|
||||
/**
|
||||
* Array of App\Models\Texture instances
|
||||
* @var array
|
||||
*/
|
||||
private $textures_skin = [];
|
||||
|
||||
/**
|
||||
* Array of App\Models\Texture instances
|
||||
* @var array
|
||||
*/
|
||||
private $textures_cape = [];
|
||||
|
||||
/**
|
||||
* Construct Closet object with owner's uid
|
||||
* @param int $uid
|
||||
*/
|
||||
function __construct($uid)
|
||||
{
|
||||
$this->uid = $uid;
|
||||
$this->eloquent_model = ClosetModel::find($uid);
|
||||
$this->textures = json_decode($this->eloquent_model->textures, true);
|
||||
$this->textures = is_null($this->textures) ? [] : $this->textures;
|
||||
|
||||
$textures_invalid = [];
|
||||
|
||||
foreach ($this->textures as $texture) {
|
||||
$result = Texture::find($texture['tid']);
|
||||
if ($result) {
|
||||
if ($result->type == "cape") {
|
||||
$this->textures_cape[] = $result;
|
||||
} else {
|
||||
$this->textures_skin[] = $result;
|
||||
}
|
||||
} else {
|
||||
$textures_invalid[] = $texture['tid'];
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($textures_invalid as $tid) {
|
||||
$this->remove($tid);
|
||||
}
|
||||
|
||||
unset($textures_invalid);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get array of instances of App\Models\Texture
|
||||
* @param string $category
|
||||
* @return array
|
||||
*/
|
||||
public function getItems($category = "skin")
|
||||
{
|
||||
// need to reverse the array to sort desc by add_at
|
||||
return array_reverse(($category == "skin") ? $this->textures_skin : $this->textures_cape);
|
||||
}
|
||||
|
||||
public function getAmount()
|
||||
{
|
||||
return $this->eloquent_model->amount;
|
||||
}
|
||||
|
||||
public function add($tid)
|
||||
{
|
||||
foreach ($this->textures as $item) {
|
||||
if ($item['tid'] == $tid)
|
||||
throw new E('你已经收藏过这个材质啦', 1);
|
||||
}
|
||||
|
||||
$this->textures[] = array(
|
||||
'tid' => $tid,
|
||||
'add_at' => Utils::getTimeFormatted()
|
||||
);
|
||||
|
||||
$this->eloquent_model->amount += 1;
|
||||
$this->eloquent_model->textures = json_encode($this->textures);
|
||||
return $this->eloquent_model->save();
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if texture is in the closet
|
||||
* @param int $tid
|
||||
* @return boolean
|
||||
*/
|
||||
public function has($tid)
|
||||
{
|
||||
foreach ($this->textures as $item) {
|
||||
if ($item['tid'] == $tid) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a texture from closet
|
||||
* @param int $tid
|
||||
* @return boolean
|
||||
*/
|
||||
public function remove($tid)
|
||||
{
|
||||
$offset = 0;
|
||||
// remove array element
|
||||
foreach ($this->textures as $item) {
|
||||
if ($item['tid'] == $tid) {
|
||||
array_splice($this->textures, $offset, 1);
|
||||
$this->eloquent_model->amount -= 1;
|
||||
$this->eloquent_model->textures = json_encode($this->textures);
|
||||
return $this->eloquent_model->save();
|
||||
}
|
||||
$offset++;
|
||||
}
|
||||
|
||||
throw new E('The texture is not in the closet.', 1);
|
||||
}
|
||||
|
||||
private function checkTextureExist($tid)
|
||||
{
|
||||
return (Texture::where('tid', $tid)->count() > 0) ? true : false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class ClosetModel extends \Illuminate\Database\Eloquent\Model
|
||||
{
|
||||
public $primaryKey = 'uid';
|
||||
protected $table = 'closets';
|
||||
public $timestamps = false;
|
||||
}
|
||||
154
app/Models/Player.php
Normal file
|
|
@ -0,0 +1,154 @@
|
|||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use App\Exceptions\E;
|
||||
use Utils;
|
||||
|
||||
class Player
|
||||
{
|
||||
public $pid = "";
|
||||
public $player_name = "";
|
||||
|
||||
public $eloquent_model = null;
|
||||
|
||||
/**
|
||||
* Construct player with pid or playername
|
||||
* @param int $pid
|
||||
* @param string $player_name
|
||||
*/
|
||||
public function __construct($pid, $player_name = "")
|
||||
{
|
||||
if ($player_name == "") {
|
||||
$this->pid = $pid;
|
||||
$this->eloquent_model = PlayerModel::find($pid);
|
||||
} else {
|
||||
$this->eloquent_model = PlayerModel::where('player_name', $player_name)->first();
|
||||
@$this->pid = $this->eloquent_model->pid;
|
||||
}
|
||||
|
||||
if (!$this->eloquent_model)
|
||||
\Http::abort(404, '角色不存在');
|
||||
|
||||
$this->player_name = $this->eloquent_model->player_name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get textures of player
|
||||
* @param string $type steve|alex|cape, 'skin' for texture of preferred model
|
||||
* @return string sha256-hash of texture file
|
||||
*/
|
||||
public function getTexture($type)
|
||||
{
|
||||
if ($type == "skin")
|
||||
$type = ($this->getPreference() == "default") ? "steve" : "alex";
|
||||
if ($type == "steve" | $type == "alex" | $type == "cape") {
|
||||
$tid = $this->eloquent_model['tid_'.$type];
|
||||
return Texture::find($tid)['hash'];
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public function setTexture(Array $tids)
|
||||
{
|
||||
if (!isset($tids['tid_steve']) && !isset($tids['tid_alex']) && !isset($tids['tid_cape']))
|
||||
{
|
||||
throw new E('Invalid parameters.', 1);
|
||||
}
|
||||
|
||||
$this->eloquent_model->tid_steve = isset($tids['tid_steve']) ? $tids['tid_steve'] : $this->eloquent_model['tid_steve'];
|
||||
$this->eloquent_model->tid_alex = isset($tids['tid_alex']) ? $tids['tid_alex'] : $this->eloquent_model['tid_alex'];
|
||||
$this->eloquent_model->tid_cape = isset($tids['tid_cape']) ? $tids['tid_cape'] : $this->eloquent_model['tid_cape'];
|
||||
|
||||
$this->eloquent_model->last_modified = Utils::getTimeFormatted();
|
||||
return $this->eloquent_model->save();
|
||||
}
|
||||
|
||||
public function getBinaryTexture($type)
|
||||
{
|
||||
if ($this->getTexture($type) != "") {
|
||||
$filename = BASE_DIR."/textures/".$this->getTexture($type);
|
||||
|
||||
if (file_exists($filename)) {
|
||||
header('Content-Type: image/png');
|
||||
// Cache friendly
|
||||
header('Last-Modified: ' . gmdate('D, d M Y H:i:s', $this->getLastModified()).' GMT');
|
||||
header('Content-Length: '.filesize($filename));
|
||||
|
||||
return \Storage::fread($filename);
|
||||
} else {
|
||||
\Http::abort(404, '请求的贴图已被删除。');
|
||||
}
|
||||
} else {
|
||||
\Http::abort(404, '该用户尚未上传请求的贴图类型 '.$type);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set preferred model
|
||||
* @param string $type, 'slim' or 'default'
|
||||
*/
|
||||
public function setPreference($type) {
|
||||
|
||||
return $this->eloquent_model->update([
|
||||
'preference' => $type,
|
||||
'last_modified' => Utils::getTimeFormatted()
|
||||
]);
|
||||
}
|
||||
|
||||
public function getPreference() {
|
||||
return $this->eloquent_model['preference'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get JSON profile
|
||||
* @param int $api_type, which API to use, 0 for CustomSkinAPI, 1 for UniSkinAPI
|
||||
* @return string, user profile in json format
|
||||
*/
|
||||
public function getJsonProfile($api_type) {
|
||||
header('Content-type: application/json');
|
||||
|
||||
// Support both CustomSkinLoader API & UniSkinAPI
|
||||
if ($api_type == 0 || $api_type == 1) {
|
||||
$json[($api_type == 0) ? 'username' : 'player_name'] = $this->player_name;
|
||||
$model = $this->getPreference();
|
||||
$sec_model = ($model == 'default') ? 'slim' : 'default';
|
||||
if ($api_type == 1) {
|
||||
$json['last_update'] = $this->getLastModified();
|
||||
$json['model_preference'] = [$model, $sec_model];
|
||||
}
|
||||
if ($this->getTexture('steve') || $this->getTexture('alex')) {
|
||||
// Skins dict order by preference model
|
||||
$json['skins'][$model] = $this->getTexture($model == "default" ? "steve" : "alex");
|
||||
$json['skins'][$sec_model] = $this->getTexture($sec_model == "default" ? "steve" : "alex");
|
||||
}
|
||||
$json['cape'] = $this->getTexture('cape');
|
||||
} else {
|
||||
throw new E('不支持的 API_TYPE。', -1, true);
|
||||
}
|
||||
|
||||
return json_encode($json, JSON_PRETTY_PRINT);
|
||||
}
|
||||
|
||||
public function updateLastModified() {
|
||||
// @see http://stackoverflow.com/questions/2215354/php-date-format-when-inserting-into-datetime-in-mysql
|
||||
return $this->eloquent_model->update(['last_modified' => Utils::getTimeFormatted()]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get last modified time
|
||||
* @return timestamp
|
||||
*/
|
||||
public function getLastModified() {
|
||||
return strtotime($this->eloquent_model['last_modified']);
|
||||
}
|
||||
}
|
||||
|
||||
class PlayerModel extends \Illuminate\Database\Eloquent\Model
|
||||
{
|
||||
public $primaryKey = 'pid';
|
||||
protected $table = 'players';
|
||||
public $timestamps = false;
|
||||
|
||||
protected $fillable = ['preference', 'last_modified'];
|
||||
}
|
||||
30
app/Models/Texture.php
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
class Texture extends \Illuminate\Database\Eloquent\Model
|
||||
{
|
||||
public $primaryKey = 'tid';
|
||||
public $timestamps = false;
|
||||
|
||||
public static function checkTextureOccupied($tid)
|
||||
{
|
||||
$skin_type_map = ["steve", "alex", "cape"];
|
||||
for ($i = 0; $i <= 2; $i++) {
|
||||
if (PlayerModel::where('tid_'.$skin_type_map[$i], $tid)->count() > 0)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public function setPrivacy($public)
|
||||
{
|
||||
$this->public = $public ? "1" : "0";
|
||||
return $this->save();
|
||||
}
|
||||
|
||||
public function scopeLike($query, $field, $value)
|
||||
{
|
||||
return $query->where($field, 'LIKE', "%$value%");
|
||||
}
|
||||
}
|
||||
235
app/Models/User.php
Normal file
|
|
@ -1,12 +1,6 @@
|
|||
<?php
|
||||
/**
|
||||
* @Author: printempw
|
||||
* @Date: 2016-04-03 14:55:38
|
||||
* @Last Modified by: printempw
|
||||
* @Last Modified time: 2016-04-05 14:09:59
|
||||
*/
|
||||
|
||||
namespace Cipher;
|
||||
namespace App\Services\Cipher;
|
||||
|
||||
class CrazyCrypt1 implements EncryptInterface
|
||||
{
|
||||
|
|
@ -15,7 +9,7 @@ class CrazyCrypt1 implements EncryptInterface
|
|||
*
|
||||
* https://github.com/ST-DDT/CrazyLogin/blob/master/php/Encryptors/CrazyCrypt1.php
|
||||
*/
|
||||
public static function encrypt($raw_passwd, $salt = "") {
|
||||
public function encrypt($raw_passwd, $salt = "") {
|
||||
// salt is username
|
||||
$text = "ÜÄaeut//&/=I " . $raw_passwd . "7421€547" . $salt . "__+IÄIH§%NK " . $raw_passwd;
|
||||
$t1 = unpack("H*", $text);
|
||||
15
app/Services/Cipher/EncryptInterface.php
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
<?php
|
||||
|
||||
namespace App\Services\Cipher;
|
||||
|
||||
interface EncryptInterface
|
||||
{
|
||||
/**
|
||||
* Encrypt given string w/ or w/o salt
|
||||
*
|
||||
* @param string $raw_passwd
|
||||
* @param string $salt
|
||||
* @return string ecrypted password
|
||||
*/
|
||||
public function encrypt($raw_passwd, $salt = "");
|
||||
}
|
||||
14
app/Services/Cipher/MD5.php
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
<?php
|
||||
|
||||
namespace App\Services\Cipher;
|
||||
|
||||
class MD5 implements EncryptInterface
|
||||
{
|
||||
/**
|
||||
* Once MD5 encrypt
|
||||
*/
|
||||
public function encrypt($raw_passwd, $salt = "") {
|
||||
$encrypt = md5($raw_passwd);
|
||||
return $encrypt;
|
||||
}
|
||||
}
|
||||
11
app/Services/Cipher/SALTED2MD5.php
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
<?php
|
||||
|
||||
namespace App\Services\Cipher;
|
||||
|
||||
class SALTED2MD5 implements EncryptInterface
|
||||
{
|
||||
public function encrypt($raw_passwd, $salt = "") {
|
||||
$encrypt = md5(md5($raw_passwd).$salt);
|
||||
return $encrypt;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,12 +1,6 @@
|
|||
<?php
|
||||
/**
|
||||
* @Author: printempw
|
||||
* @Date: 2016-04-03 14:50:45
|
||||
* @Last Modified by: printempw
|
||||
* @Last Modified time: 2016-04-05 14:10:07
|
||||
*/
|
||||
|
||||
namespace Cipher;
|
||||
namespace App\Services\Cipher;
|
||||
|
||||
class SHA256 implements EncryptInterface
|
||||
{
|
||||
|
|
@ -15,7 +9,7 @@ class SHA256 implements EncryptInterface
|
|||
*
|
||||
* @see http://pastebin.com/1wy9g2HT
|
||||
*/
|
||||
public static function encrypt($raw_passwd, $salt = "") {
|
||||
public function encrypt($raw_passwd, $salt = "") {
|
||||
$encrypt = hash('sha256', hash('sha256', $raw_passwd).$salt);
|
||||
return $encrypt;
|
||||
}
|
||||
|
|
@ -1,40 +1,66 @@
|
|||
<?php
|
||||
|
||||
namespace App\Services;
|
||||
|
||||
use App\Exceptions\E;
|
||||
|
||||
/**
|
||||
* @Author: printempw
|
||||
* @Date: 2016-02-02 21:59:06
|
||||
* @Last Modified by: printempw
|
||||
* @Last Modified time: 2016-06-12 10:43:47
|
||||
* Light-weight database helper
|
||||
*
|
||||
* @author <h@prinzeugen.net>
|
||||
*/
|
||||
|
||||
namespace Database;
|
||||
|
||||
use Utils;
|
||||
use E;
|
||||
|
||||
class Database implements PasswordInterface, SyncInterface
|
||||
class Database
|
||||
{
|
||||
/**
|
||||
* Instance of MySQLi
|
||||
* @var null
|
||||
*/
|
||||
private $connection = null;
|
||||
|
||||
/**
|
||||
* Table name to do operations in
|
||||
* @var string
|
||||
*/
|
||||
private $table_name = "";
|
||||
|
||||
function __construct($table_name = '') {
|
||||
$this->connection = self::checkConfig();
|
||||
$this->table_name = DB_PREFIX.$table_name;
|
||||
/**
|
||||
* Construct with table name and another config optionally
|
||||
*
|
||||
* @param string $table_name
|
||||
* @param array $config
|
||||
*/
|
||||
function __construct($table_name = '', $config = null) {
|
||||
$config = is_null($config) ? (require BASE_DIR.'/config/database.php') : $config;
|
||||
$this->connection = self::checkConfig($config);
|
||||
$this->table_name = $config['prefix'].$table_name;
|
||||
}
|
||||
|
||||
public static function checkConfig() {
|
||||
/**
|
||||
* Check database config
|
||||
*
|
||||
* @param Array $config
|
||||
* @return object instance of MySQLi
|
||||
*/
|
||||
public static function checkConfig(Array $config) {
|
||||
// use error control to hide shitty connect warnings
|
||||
@$conn = new \mysqli(DB_HOST, DB_USER, DB_PASSWD, DB_NAME, DB_PORT);
|
||||
@$conn = new \mysqli($config['host'], $config['username'], $config['password'], $config['database'], $config['port']);
|
||||
|
||||
if ($conn->connect_error)
|
||||
throw new E("无法连接至 MySQL 服务器。请确认 config.php 中的配置是否正确:".$conn->connect_error, $conn->connect_errno, true);
|
||||
throw new E("Could not connect to MySQL database. Check your config.php:".$conn->connect_error, $conn->connect_errno, true);
|
||||
|
||||
$sql = "SELECT table_name FROM `INFORMATION_SCHEMA`.`TABLES` WHERE (table_name ='".DB_PREFIX."users'OR table_name ='".DB_PREFIX."options') AND TABLE_SCHEMA='".DB_NAME."'";
|
||||
if ($conn->query($sql)->num_rows != 2)
|
||||
throw new E("数据库中不存在 ".DB_PREFIX."users 或 ".DB_PREFIX."options 表。请先访问 <a href='./setup'>/setup</a> 进行安装。", -1, true);
|
||||
$tables = ['users', 'closets', 'players', 'textures', 'options'];
|
||||
|
||||
foreach ($tables as $table_name) {
|
||||
$table_name = $config['prefix'].$table_name;
|
||||
$sql = "SELECT table_name FROM `INFORMATION_SCHEMA`.`TABLES`
|
||||
WHERE table_name ='$table_name' AND TABLE_SCHEMA='".$config['database']."'";
|
||||
|
||||
if ($conn->query($sql)->num_rows == 0)
|
||||
throw new E("数据库内未发现 $table_name 表。请先运行 <a href='./setup'>安装程序</a>。", -1, true);
|
||||
}
|
||||
|
||||
if (!is_dir(BASE_DIR."/textures/"))
|
||||
throw new E("textures 文件夹不存在。请先访问 <a href='./setup'>/setup</a> 进行安装,或者手动放置一个。", -1, true);
|
||||
throw new E("根目录下未发现 `textures` 文件夹,请先运行 <a href='./setup'>安装程序</a>,或者手动放置一个。", -1, true);
|
||||
|
||||
$conn->query("SET names 'utf8'");
|
||||
return $conn;
|
||||
|
|
@ -111,17 +137,6 @@ class Database implements PasswordInterface, SyncInterface
|
|||
return $this->query("DELETE FROM $table".$this->where($condition));
|
||||
}
|
||||
|
||||
public function checkTableExist($table_name) {
|
||||
$sql = "SELECT table_name FROM `INFORMATION_SCHEMA`.`TABLES` WHERE (table_name ='$table_name') AND TABLE_SCHEMA='".DB_NAME."'";
|
||||
return ($this->query($sql)->num_rows == 0) ? false : true;
|
||||
}
|
||||
|
||||
public function checkColumnExist($column_name, $table = null) {
|
||||
$table = is_null($table) ? $this->table_name : $table;
|
||||
$sql = "SELECT * FROM `INFORMATION_SCHEMA`.`COLUMNS` WHERE TABLE_SCHEMA = '".DB_NAME."' AND TABLE_NAME = '$table' AND COLUMN_NAME = '$column_name'";
|
||||
return ($this->query($sql)->num_rows == 0) ? false : true;
|
||||
}
|
||||
|
||||
public function getNumRows($key, $value, $table = null) {
|
||||
$table = is_null($table) ? $this->table_name : $table;
|
||||
$sql = "SELECT * FROM $table WHERE $key='$value'";
|
||||
|
|
@ -134,15 +149,6 @@ class Database implements PasswordInterface, SyncInterface
|
|||
return $this->query($sql)->num_rows;
|
||||
}
|
||||
|
||||
public function encryptPassword($raw_passwd, $username = "") {
|
||||
$class_name = "Cipher\\".\Option::get('encryption');
|
||||
return $class_name::encrypt($raw_passwd);
|
||||
}
|
||||
|
||||
public function sync($username, $reverse = false) {
|
||||
return ($this->has('username', $username)) ? true : false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate where statement
|
||||
*
|
||||
50
app/Services/Http.php
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
<?php
|
||||
|
||||
namespace App\Services;
|
||||
|
||||
class Http
|
||||
{
|
||||
/**
|
||||
* HTTP redirect
|
||||
*
|
||||
* @param string $url
|
||||
* @return null
|
||||
*/
|
||||
public static function redirect($url, $msg = "", $use_js = false)
|
||||
{
|
||||
if ($msg != "") $_SESSION['msg'] = $msg;
|
||||
|
||||
if ($use_js)
|
||||
echo "<script>window.location = '$url';</script>";
|
||||
else
|
||||
header('Location: '.$url);
|
||||
exit;
|
||||
}
|
||||
|
||||
public static function getRealIP()
|
||||
{
|
||||
if (!empty($_SERVER['HTTP_CLIENT_IP'])) {
|
||||
$ip = $_SERVER['HTTP_CLIENT_IP'];
|
||||
} elseif (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) {
|
||||
$ip = $_SERVER['HTTP_X_FORWARDED_FOR'];
|
||||
} else {
|
||||
$ip = $_SERVER['REMOTE_ADDR'];
|
||||
}
|
||||
return $ip;
|
||||
}
|
||||
|
||||
public static function abort($code, $msg = "Something happened.", $is_json = false)
|
||||
{
|
||||
http_response_code((int)$code);
|
||||
if ($is_json) {
|
||||
View::json($msg, $code);
|
||||
} else {
|
||||
$config = require BASE_DIR."/config/view.php";
|
||||
if (file_exists($config['view_path']."/errors/".$code.".tpl"))
|
||||
echo View::make('errors.'.$code)->with('code', $code)->with('message', $msg);
|
||||
else
|
||||
echo View::make('errors.exception')->with('code', $this->code)->with('message', $this->message);
|
||||
exit;
|
||||
}
|
||||
}
|
||||
}
|
||||
72
app/Services/Mail.php
Normal file
|
|
@ -0,0 +1,72 @@
|
|||
<?php
|
||||
|
||||
namespace App\Services;
|
||||
|
||||
use PHPMailer;
|
||||
|
||||
class Mail
|
||||
{
|
||||
/**
|
||||
* Instance of PHPMailer
|
||||
* @var object
|
||||
*/
|
||||
private $mail;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$mail = new PHPMailer();
|
||||
// $mail->SMTPDebug = 3; // Enable verbose debug output
|
||||
$mail->isSMTP(); // Set mailer to use SMTP
|
||||
$mail->Host = $_ENV['MAIL_HOST']; // Specify main and backup SMTP servers
|
||||
$mail->SMTPAuth = true; // Enable SMTP authentication
|
||||
$mail->Username = $_ENV['MAIL_USERNAME']; // SMTP username
|
||||
$mail->Password = $_ENV['MAIL_PASSWORD']; // SMTP password
|
||||
$mail->SMTPSecure = $_ENV['MAIL_ENCRYPTION']; // Enable TLS encryption, `ssl` also accepted
|
||||
$mail->Port = $_ENV['MAIL_PORT']; // TCP port to connect to
|
||||
$mail->CharSet = 'UTF-8';
|
||||
$this->mail = $mail;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set sender name
|
||||
*
|
||||
* @param string $name [description]
|
||||
*/
|
||||
public function from($name)
|
||||
{
|
||||
$this->mail->setFrom($_ENV['MAIL_USERNAME'], $name);
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function to($address)
|
||||
{
|
||||
$this->mail->addAddress($address);
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function subject($subject)
|
||||
{
|
||||
$this->mail->Subject = $subject;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getLastError()
|
||||
{
|
||||
return $this->mailer->ErrorInfo;
|
||||
}
|
||||
|
||||
/**
|
||||
* Send a mail
|
||||
*
|
||||
* @param string $body
|
||||
* @return boolean
|
||||
*/
|
||||
public function send($body)
|
||||
{
|
||||
$this->mail->isHTML(true);
|
||||
$this->mail->Body = $body;
|
||||
|
||||
return $this->mail->send();
|
||||
}
|
||||
|
||||
}
|
||||
123
app/Services/Minecraft.php
Normal file
|
|
@ -0,0 +1,123 @@
|
|||
<?php
|
||||
|
||||
namespace App\Services;
|
||||
|
||||
class Minecraft
|
||||
{
|
||||
/**
|
||||
* Cut and resize to get avatar from skin, HD support by <xfl03@hotmail.com>
|
||||
*
|
||||
* @author https://github.com/jamiebicknell/Minecraft-Avatar/blob/master/face.php
|
||||
* @param string $resource, img path or base64
|
||||
* @param int $size
|
||||
* @param string $view, default for 'f'
|
||||
* @param bool $base64, if given $resource is encoded in base64
|
||||
* @return resource
|
||||
*/
|
||||
public static function generateAvatarFromSkin($resource, $size, $view='f', $base64 = false)
|
||||
{
|
||||
$src = $base64 ? imagecreatefromstring(base64_decode($resource)) : imagecreatefrompng($resource);
|
||||
$dest = imagecreatetruecolor($size, $size);
|
||||
$ratio = imagesx($src) / 64; // width/64
|
||||
|
||||
// f => front, l => left, r => right, b => back
|
||||
$x = array('f' => 8, 'l' => 16, 'r' => 0, 'b' => 24);
|
||||
|
||||
imagecopyresized($dest, $src, 0, 0, $x[$view] * $ratio, 8 * $ratio, $size, $size, 8 * $ratio, 8 * $ratio); // Face
|
||||
imagecolortransparent($src, imagecolorat($src, 63 * $ratio, 0)); // Black Hat Issue
|
||||
imagecopyresized($dest, $src, 0, 0, ($x[$view] + 32) * $ratio, 8 * $ratio, $size, $size, 8 * $ratio, 8 * $ratio); // Accessories
|
||||
|
||||
imagedestroy($src);
|
||||
return $dest;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate skin preview
|
||||
*
|
||||
* @see https://github.com/NC22/Minecraft-HD-skin-viewer-2D/blob/master/SkinViewer2D.class.php
|
||||
* @param resource $resource
|
||||
* @param int $size
|
||||
* @param boolean|string $side, 'front' or 'back'
|
||||
* @param boolean $base64, generate image from base64 string
|
||||
* @return resource
|
||||
*/
|
||||
public static function generatePreviewFromSkin($resource, $size, $side = false, $base64 = false)
|
||||
{
|
||||
$src = $base64 ? imagecreatefromstring(base64_decode($resource)) : imagecreatefrompng($resource);
|
||||
|
||||
$ratio = imagesx($src) / 64;
|
||||
$dest = imagecreatetruecolor((($side) ? 16 : 36) * $ratio, 32 * $ratio);
|
||||
$half_width = ($side) ? 0 : imagesx($dest) / 2 + 2 * $ratio;
|
||||
|
||||
$transparent = imagecolorallocatealpha($dest, 255, 255, 255, 127);
|
||||
imagefill($dest, 0, 0, $transparent);
|
||||
|
||||
if (!$side or $side === 'front') {
|
||||
imagecopy($dest, $src, 4 * $ratio, 0 * $ratio, 8 * $ratio, 8 * $ratio, 8 * $ratio, 8 * $ratio);
|
||||
imagecopy($dest, $src, 0 * $ratio, 8 * $ratio, 44 * $ratio, 20 * $ratio, 4 * $ratio, 12 * $ratio);
|
||||
self::imageflip($dest, $src, 12 * $ratio, 8 * $ratio, 44 * $ratio, 20 * $ratio, 4 * $ratio, 12 * $ratio);
|
||||
imagecopy($dest, $src, 4 * $ratio, 8 * $ratio, 20 * $ratio, 20 * $ratio, 8 * $ratio, 12 * $ratio);
|
||||
imagecopy($dest, $src, 4 * $ratio, 20 * $ratio, 4 * $ratio, 20 * $ratio, 4 * $ratio, 12 * $ratio);
|
||||
self::imageflip($dest, $src, 8 * $ratio, 20 * $ratio, 4 * $ratio, 20 * $ratio, 4 * $ratio, 12 * $ratio);
|
||||
imagecopy($dest, $src, 4 * $ratio, 0 * $ratio, 40 * $ratio, 8 * $ratio, 8 * $ratio, 8 * $ratio);
|
||||
}
|
||||
|
||||
if (!$side or $side === 'back') {
|
||||
imagecopy($dest, $src, $half_width + 4 * $ratio, 8 * $ratio, 32 * $ratio, 20 * $ratio, 8 * $ratio, 12 * $ratio);
|
||||
imagecopy($dest, $src, $half_width + 4 * $ratio, 0 * $ratio, 24 * $ratio, 8 * $ratio, 8 * $ratio, 8 * $ratio);
|
||||
self::imageflip($dest, $src, $half_width + 0 * $ratio, 8 * $ratio, 52 * $ratio, 20 * $ratio, 4 * $ratio, 12 * $ratio);
|
||||
imagecopy($dest, $src, $half_width + 12 * $ratio, 8 * $ratio, 52 * $ratio, 20 * $ratio, 4 * $ratio, 12 * $ratio);
|
||||
self::imageflip($dest, $src, $half_width + 4 * $ratio, 20 * $ratio, 12 * $ratio, 20 * $ratio, 4 * $ratio, 12 * $ratio);
|
||||
imagecopy($dest, $src, $half_width + 8 * $ratio, 20 * $ratio, 12 * $ratio, 20 * $ratio, 4 * $ratio, 12 * $ratio);
|
||||
imagecopy($dest, $src, $half_width + 4 * $ratio, 0 * $ratio, 56 * $ratio, 8 * $ratio, 8 * $ratio, 8 * $ratio);
|
||||
}
|
||||
|
||||
$size_x = ($side) ? $size / 2 : $size / 32 * 36;
|
||||
$fullsize = imagecreatetruecolor($size_x, $size);
|
||||
|
||||
imagesavealpha($fullsize, true);
|
||||
$transparent = imagecolorallocatealpha($fullsize, 255, 255, 255, 127);
|
||||
imagefill($fullsize, 0, 0, $transparent);
|
||||
|
||||
imagecopyresized($fullsize, $dest, 0, 0, 0, 0, imagesx($fullsize), imagesy($fullsize), imagesx($dest), imagesy($dest));
|
||||
|
||||
imagedestroy($dest);
|
||||
imagedestroy($src);
|
||||
|
||||
return $fullsize;
|
||||
}
|
||||
|
||||
private static function imageflip(&$result, &$img, $rx = 0, $ry = 0, $x = 0, $y = 0, $size_x = null, $size_y = null)
|
||||
{
|
||||
if ($size_x < 1)
|
||||
$size_x = imagesx($img);
|
||||
if ($size_y < 1)
|
||||
$size_y = imagesy($img);
|
||||
|
||||
imagecopyresampled($result, $img, $rx, $ry, ($x + $size_x - 1), $y, $size_x, $size_y, 0 - $size_x, $size_y);
|
||||
}
|
||||
|
||||
public static function generatePreviewFromCape($resource)
|
||||
{
|
||||
$src = imagecreatefrompng($resource);
|
||||
|
||||
$dest = imagecreatetruecolor(250, 166);
|
||||
imagesavealpha($dest, true);
|
||||
|
||||
$trans_colour = imagecolorallocatealpha($dest, 0, 0, 0, 127);
|
||||
imagefill($dest, 0, 0, $trans_colour);
|
||||
|
||||
$src_width = imagesx($src) * 11 / 64;
|
||||
$src_height = imagesy($src) * 17 / 32;
|
||||
|
||||
$dst_height = 100;
|
||||
// 100 / 17 * 11
|
||||
$dst_width = 64;
|
||||
|
||||
// dst_x = (250 - 64) / 2
|
||||
imagecopyresized($dest, $src, 93, 30, 0, 0, $dst_width, $dst_height, $src_width, $src_height);
|
||||
|
||||
imagedestroy($src);
|
||||
return $dest;
|
||||
}
|
||||
}
|
||||
50
app/Services/Option.php
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
<?php
|
||||
|
||||
namespace App\Services;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use App\Exceptions\E;
|
||||
|
||||
class Option
|
||||
{
|
||||
public $timestamps = false;
|
||||
|
||||
public static function get($key) {
|
||||
$option = OptionModel::where('option_name', $key)->first();
|
||||
if (!$option) throw new E('Unexistent option.', 1);
|
||||
return $option->option_value;
|
||||
}
|
||||
|
||||
public static function set($key, $value) {
|
||||
$option = OptionModel::firstOrCreate('option_name', $key);
|
||||
$option->update(['option_value' => $value]);
|
||||
}
|
||||
|
||||
public static function add($key, $value) {
|
||||
$option = new OptionModel;
|
||||
$option->option_name = $key;
|
||||
$option->option_value = $value;
|
||||
$option->save();
|
||||
}
|
||||
|
||||
public static function has($key) {
|
||||
try {
|
||||
OptionModel::where('option_name', $key)->firstOrFail();
|
||||
} catch (Illuminate\Database\Eloquent\ModelNotFoundException $e) {
|
||||
return false;
|
||||
} finally {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public static function delete($key) {
|
||||
OptionModel::where('option_name', $key)->first()->delete();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class OptionModel extends Model
|
||||
{
|
||||
protected $table = 'options';
|
||||
public $timestamps = false;
|
||||
}
|
||||
142
app/Services/Storage.php
Normal file
|
|
@ -0,0 +1,142 @@
|
|||
<?php
|
||||
|
||||
namespace App\Services;
|
||||
|
||||
class Storage
|
||||
{
|
||||
/**
|
||||
* Rename uploaded file
|
||||
*
|
||||
* @param array $file, files uploaded via HTTP POST
|
||||
* @return string $hash, sha256 hash of file
|
||||
*/
|
||||
public static function upload($file)
|
||||
{
|
||||
move_uploaded_file($file["tmp_name"], BASE_DIR."/textures/tmp.png");
|
||||
$hash = hash_file('sha256', BASE_DIR."/textures/tmp.png");
|
||||
rename(BASE_DIR."/textures/tmp.png", BASE_DIR."/textures/".$hash);
|
||||
return $hash;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read a file and return bin data
|
||||
*
|
||||
* @param string $filename
|
||||
* @return resource, binary data
|
||||
*/
|
||||
public static function fread($filename)
|
||||
{
|
||||
return fread(fopen($filename, 'r'), filesize($filename));
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a file
|
||||
*
|
||||
* @param $filename
|
||||
* @return $bool
|
||||
*/
|
||||
public static function remove($filename)
|
||||
{
|
||||
if (file_exists($filename)) {
|
||||
return unlink($filename);
|
||||
}
|
||||
}
|
||||
|
||||
public static function removeDir($dir)
|
||||
{
|
||||
$resource = opendir($dir);
|
||||
$size = 0;
|
||||
while($filename = @readdir($resource)) {
|
||||
if ($filename != "." && $filename != "..") {
|
||||
$path = $dir.$filename;
|
||||
if (is_dir($path)) {
|
||||
// recursion
|
||||
self::removeDir($path."/");
|
||||
} else {
|
||||
unlink($path);
|
||||
}
|
||||
}
|
||||
}
|
||||
closedir($resource);
|
||||
|
||||
return rmdir($dir);
|
||||
}
|
||||
|
||||
/**
|
||||
* Recursively count the size of specified directory
|
||||
*
|
||||
* @param string $dir
|
||||
* @return int, total size in bytes
|
||||
*/
|
||||
public static function getDirSize($dir)
|
||||
{
|
||||
$resource = opendir($dir);
|
||||
$size = 0;
|
||||
while($filename = @readdir($resource)) {
|
||||
if ($filename != "." && $filename != "..") {
|
||||
$path = $dir.$filename;
|
||||
if (is_dir($path)) {
|
||||
// recursion
|
||||
$size += self::getDirSize($path);
|
||||
} else if (is_file($path)) {
|
||||
$size += filesize($path);
|
||||
}
|
||||
}
|
||||
}
|
||||
closedir($resource);
|
||||
return $size;
|
||||
}
|
||||
|
||||
/**
|
||||
* Recursively count files of specified directory
|
||||
*
|
||||
* @param string $dir
|
||||
* @param $file_num
|
||||
* @return int, total size in bytes
|
||||
*/
|
||||
public static function getFileNum($dir, $file_num = 0)
|
||||
{
|
||||
$resource = opendir($dir);
|
||||
while($filename = readdir($resource)) {
|
||||
if ($filename != "." && $filename != "..") {
|
||||
$path = $dir.$filename;
|
||||
if (is_dir($path)) {
|
||||
// recursion
|
||||
$file_num = self::getFileNum($path, $file_num);
|
||||
} else {
|
||||
$file_num++;
|
||||
}
|
||||
}
|
||||
}
|
||||
closedir($resource);
|
||||
return $file_num;
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy directory recursively
|
||||
*
|
||||
* @param string $source
|
||||
* @param string $dest
|
||||
* @return bool
|
||||
*/
|
||||
public static function copyDir($source, $dest)
|
||||
{
|
||||
if(!is_dir($source)) return false;
|
||||
if(!is_dir($dest)) mkdir($dest, 0777, true);
|
||||
|
||||
$handle = dir($source);
|
||||
|
||||
while($entry = $handle->read()) {
|
||||
if ($entry != "." && $entry != "..") {
|
||||
if (is_dir($source.'/'.$entry)) {
|
||||
// recursion
|
||||
self::copyDir($source.'/'.$entry, $dest.'/'.$entry);
|
||||
} else {
|
||||
@copy($source.'/'.$entry, $dest.'/'.$entry);
|
||||
// echo $source.'/'.$entry." => ".$dest.'/'.$entry."<br />";
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,10 +1,6 @@
|
|||
<?php
|
||||
/**
|
||||
* @Author: printempw
|
||||
* @Date: 2016-03-27 15:16:22
|
||||
* @Last Modified by: printempw
|
||||
* @Last Modified time: 2016-04-05 14:29:25
|
||||
*/
|
||||
|
||||
namespace App\Services;
|
||||
|
||||
class Updater
|
||||
{
|
||||
|
|
@ -53,7 +49,7 @@ class Updater
|
|||
$zip_path = $update_cache."update_".time().".zip";
|
||||
|
||||
if (file_put_contents($zip_path, $file) === false) {
|
||||
Utils::removeDir(BASE_DIR.'/setup/update_cache/');
|
||||
\Storage::removeDir(BASE_DIR.'/setup/update_cache/');
|
||||
return false;
|
||||
}
|
||||
return $zip_path;
|
||||
63
app/Services/Utils.php
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
<?php
|
||||
|
||||
namespace App\Services;
|
||||
|
||||
use App\Exceptions\E;
|
||||
|
||||
class Utils
|
||||
{
|
||||
/**
|
||||
* Simple SQL injection protection
|
||||
*
|
||||
* @param string $string
|
||||
* @return string
|
||||
*/
|
||||
public static function convertString($string) {
|
||||
return addslashes(trim($string));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the value of key in an array if index exist
|
||||
*
|
||||
* @param string $key
|
||||
* @param array $array
|
||||
* @return object
|
||||
*/
|
||||
public static function getValue($key, $array) {
|
||||
if (array_key_exists($key, $array)) {
|
||||
return $array[$key];
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate random string
|
||||
*
|
||||
* @param int $length
|
||||
* @return string
|
||||
*/
|
||||
public static function generateRndString($length) {
|
||||
$chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$%^&*()-_ []{}<>~`+=,.;:/?|';
|
||||
$rnd_string = '';
|
||||
for ($i = 0; $i < $length; $i++) {
|
||||
$rnd_string .= $chars[mt_rand(0, strlen($chars) - 1)];
|
||||
}
|
||||
return $rnd_string;
|
||||
}
|
||||
|
||||
public static function getTimeFormatted($timestamp = 0)
|
||||
{
|
||||
// set default time zone to UTC+8
|
||||
date_default_timezone_set('Asia/Shanghai');
|
||||
return ($timestamp == 0) ? date('Y-m-d H:i:s') : date('Y-m-d H:i:s', $timestamp);
|
||||
}
|
||||
|
||||
public static function checkPost(Array $keys)
|
||||
{
|
||||
foreach ($keys as $key) {
|
||||
if (!isset($_POST[$key]))
|
||||
throw new E('Invalid parameters.', 1);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
30
app/Services/Validate.php
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
<?php
|
||||
|
||||
namespace App\Services;
|
||||
|
||||
class Validate
|
||||
{
|
||||
public static function checkValidPlayerName($player_name) {
|
||||
$regx = (Option::get('allow_chinese_playername') == "1") ?
|
||||
"/^([A-Za-z0-9\x{4e00}-\x{9fa5}_]+)$/u" : "/^([A-Za-z0-9_]+)$/";
|
||||
return preg_match($regx, $player_name);
|
||||
}
|
||||
|
||||
public static function checkValidTextureName($texture_name) {
|
||||
if (strlen($texture_name) > 32 || strlen($texture_name) < 1) {
|
||||
throw new E('无效的材质名称。材质名长度应该小于 32。', 2);
|
||||
} else if (Utils::convertString($texture_name) != $texture_name) {
|
||||
throw new E('无效的材质名称。材质名称中包含了奇怪的字符。', 2);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public static function checkValidPwd($passwd) {
|
||||
if (strlen($passwd) > 16 || strlen($passwd) < 8) {
|
||||
throw new E('无效的密码。密码长度应该大于 8 并小于 16。', 2);
|
||||
} else if (Utils::convertString($passwd) != $passwd) {
|
||||
throw new E('无效的密码。密码中包含了奇怪的字符。', 2);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
60
app/Services/View.php
Normal file
|
|
@ -0,0 +1,60 @@
|
|||
<?php
|
||||
|
||||
namespace App\Services;
|
||||
|
||||
/**
|
||||
* Just a wrapper for Blade template engine
|
||||
*/
|
||||
class View
|
||||
{
|
||||
public static function show($view, $data = [], $mergeData = [])
|
||||
{
|
||||
echo self::make($view, $data, $mergeData)->render();
|
||||
}
|
||||
|
||||
public static function make($view, $data = [], $mergeData = [])
|
||||
{
|
||||
$config = require BASE_DIR."/config/view.php";
|
||||
$view_path = [$config['view_path']];
|
||||
$cache_path = $config['cache_path'];
|
||||
|
||||
$compiler = new \Xiaoler\Blade\Compilers\BladeCompiler($cache_path);
|
||||
|
||||
$engine = new \Xiaoler\Blade\Engines\CompilerEngine($compiler);
|
||||
$finder = new \Xiaoler\Blade\FileViewFinder($view_path);
|
||||
|
||||
$finder->addExtension('tpl');
|
||||
|
||||
$factory = new \Xiaoler\Blade\Factory($engine, $finder);
|
||||
|
||||
return $factory->make($view, $data, $mergeData);
|
||||
}
|
||||
|
||||
// function reload
|
||||
public static function json()
|
||||
{
|
||||
@header('Content-type: application/json; charset=utf-8');
|
||||
$args = func_get_args();
|
||||
if (count($args) == 1) {
|
||||
self::jsonCustom($args[0]);
|
||||
} elseif(count($args) == 2) {
|
||||
self::jsonException($args[0], $args[1]);
|
||||
}
|
||||
}
|
||||
|
||||
private static function jsonCustom($array)
|
||||
{
|
||||
if (is_array($array))
|
||||
exit(json_encode($array));
|
||||
else
|
||||
throw new \Exception('The given arugument should be array.');
|
||||
}
|
||||
|
||||
private static function jsonException($msg, $errno)
|
||||
{
|
||||
exit(json_encode([
|
||||
'errno' => $errno,
|
||||
'msg' => $msg
|
||||
]));
|
||||
}
|
||||
}
|
||||
|
|
@ -1,68 +0,0 @@
|
|||
/*
|
||||
* @Author: printempw
|
||||
* @Date: 2016-02-04 16:47:54
|
||||
* @Last Modified by: printempw
|
||||
* @Last Modified time: 2016-04-03 13:29:12
|
||||
*/
|
||||
|
||||
body, .ply-layer {
|
||||
font-family: Ubuntu, 'Segoe UI', 'Microsoft Yahei', 'Microsoft Jhenghei', sans-serif;
|
||||
}
|
||||
.main-header .logo .logo-lg {
|
||||
font-family: Ubuntu, 'Segoe UI', 'Microsoft Yahei', 'Microsoft Jhenghei', sans-serif;
|
||||
}
|
||||
input {
|
||||
width: 100%;
|
||||
}
|
||||
input[type=checkbox] {
|
||||
width: initial;
|
||||
margin: 0;
|
||||
margin: 0 5px 0 5px;
|
||||
}
|
||||
label {
|
||||
display: block;
|
||||
margin: 6px 0;
|
||||
}
|
||||
.key {
|
||||
vertical-align: middle !important;
|
||||
}
|
||||
.value {
|
||||
width: 70%;
|
||||
}
|
||||
.value > input {
|
||||
margin: 0 !important;
|
||||
}
|
||||
td[class='key'], td[class='value'] {
|
||||
border-top: 0 !important;
|
||||
}
|
||||
.info-box > a {
|
||||
color: #333;
|
||||
font-size: 18px;
|
||||
}
|
||||
.pager>.active>a,
|
||||
.pager>.active>a:focus,
|
||||
.pager>.active>a:hover {
|
||||
z-index: 3;
|
||||
color: #fff;
|
||||
cursor: default;
|
||||
background-color: #337ab7;
|
||||
border-color: #337ab7;
|
||||
}
|
||||
.pager > select {
|
||||
display: inline-block;
|
||||
padding: 6px 14px;
|
||||
color: #3c8dbc;
|
||||
background-color: #fff;
|
||||
border: 1px solid #ddd;
|
||||
border-radius: 15px;
|
||||
outline: none;
|
||||
}
|
||||
.user-search-form {
|
||||
display: inline;
|
||||
}
|
||||
.user-search-input {
|
||||
display: inline;
|
||||
width: 30%;
|
||||
float: right;
|
||||
margin: 0;
|
||||
}
|
||||
|
|
@ -1,163 +0,0 @@
|
|||
/*
|
||||
* @Author: printempw
|
||||
* @Date: 2016-01-21 20:07:47
|
||||
* @Last Modified by: printempw
|
||||
* @Last Modified time: 2016-03-19 15:33:10
|
||||
*/
|
||||
.home-menu-blur {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
z-index: -100;
|
||||
}
|
||||
.home-menu-wrp {
|
||||
height: 100%;
|
||||
background-color: rgba(255,255,255,0.4);
|
||||
}
|
||||
.home-menu-bg {
|
||||
background-position: center 0;
|
||||
background-size: auto 800px;
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
z-index: -1;
|
||||
filter: blur(4px);
|
||||
-webkit-filter: blur(4px);
|
||||
-moz-filter: blur(4px);
|
||||
-o-filter: blur(4px);
|
||||
-ms-filter: blur(4px);
|
||||
box-shadow: rgba(0,0,0,0.1) 0 1px 2px;
|
||||
}
|
||||
|
||||
.container {
|
||||
background-size: auto 800px;
|
||||
background-repeat: no-repeat;
|
||||
background-position: center 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
top: 0;
|
||||
left: 0;
|
||||
position: fixed !important;
|
||||
}
|
||||
.container .pure-button {
|
||||
color: white;
|
||||
padding: 0.8em 2.5em;
|
||||
border-radius: 5px;
|
||||
background: transparent;
|
||||
border: 1px solid #fff;
|
||||
font-size: 120%;
|
||||
transition: color 0.25s ease-in-out,
|
||||
border-color 0.25s ease-in-out,
|
||||
background-color 0.25s ease-in-out;
|
||||
}
|
||||
.container .pure-button:hover {
|
||||
background-color: rgba(255, 255, 255, 0.2);
|
||||
}
|
||||
|
||||
.splash {
|
||||
width: 80%;
|
||||
height: 50%;
|
||||
margin: auto;
|
||||
position: absolute;
|
||||
top: 100px; left: 0; bottom: 0; right: 0;
|
||||
text-align: center;
|
||||
}
|
||||
.splash-head {
|
||||
font-size: 20px;
|
||||
font-weight: bold;
|
||||
color: white;
|
||||
padding: 1em 0.5em;
|
||||
font-weight: 100;
|
||||
line-height: 1.5em;
|
||||
margin: 0.2em 0 0.5em;
|
||||
font-family: Minecraft, 'Segoe UI', 'Microsoft Yahei', 'Microsoft Jhenghei', sans-serif;
|
||||
text-shadow:
|
||||
0px 4px 3px rgba(0,0,0,0.4),
|
||||
0px 8px 13px rgba(0,0,0,0.1),
|
||||
0px 18px 23px rgba(0,0,0,0.1);
|
||||
}
|
||||
.splash-subhead {
|
||||
letter-spacing: 0.05em;
|
||||
margin-top: 0.8em;
|
||||
margin-bottom: 1.5em;
|
||||
}
|
||||
|
||||
.pure-form {
|
||||
margin: 10px auto;
|
||||
width: 50%;
|
||||
}
|
||||
.pure-input {
|
||||
margin: 10px 0;
|
||||
width: 100%;
|
||||
}
|
||||
#keep-label {
|
||||
float: left;
|
||||
}
|
||||
#login-button {
|
||||
float: right;
|
||||
margin: .5em 0;
|
||||
}
|
||||
#register-button {
|
||||
margin: .5em 0;
|
||||
width: 100%;
|
||||
float: left;
|
||||
}
|
||||
#msg {
|
||||
width: 50%;
|
||||
margin: 4.3em auto 0;
|
||||
}
|
||||
.alert {
|
||||
padding: 15px 0;
|
||||
}
|
||||
.pure-form > .pure-button {
|
||||
height: 40px;
|
||||
}
|
||||
|
||||
/* Mobile phone */
|
||||
@media (max-width: 48em) {
|
||||
.splash-head {
|
||||
font-size: 200%;
|
||||
}
|
||||
.splash {
|
||||
width: 100%;
|
||||
height: 50%;
|
||||
}
|
||||
.pure-form {
|
||||
width: 100%;
|
||||
}
|
||||
#msg {
|
||||
width: 100%;
|
||||
}
|
||||
#login-button {
|
||||
width: 40%;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@media (min-width: 48em) {
|
||||
|
||||
.splash {
|
||||
width: 80%;
|
||||
height: 50%;
|
||||
}
|
||||
|
||||
.splash-head {
|
||||
font-size: 250%;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@media (min-width: 64em) {
|
||||
.splash-head {
|
||||
font-size: 300%;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-height: 800px) {
|
||||
.home-menu-bg,
|
||||
.container {
|
||||
background-size: cover;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,342 +0,0 @@
|
|||
/*
|
||||
* @Author: printempw
|
||||
* @Date: 2016-03-12 18:54:09
|
||||
* @Last Modified by: printempw
|
||||
* @Last Modified time: 2016-04-03 11:14:36
|
||||
*/
|
||||
|
||||
@import url(https://cdn.moefont.com/fonts/css?family=Ubuntu);
|
||||
@import url(https://work.prinzeugen.net/font/Minecraft.css);
|
||||
|
||||
html {
|
||||
background: #f1f1f1;
|
||||
margin: 0 20px;
|
||||
font-weight: 400;
|
||||
}
|
||||
body {
|
||||
background: #FFF none repeat scroll 0% 0%;
|
||||
color: #444;
|
||||
font-family: Ubuntu, 'Microsoft Yahei', 'Microsoft Jhenghei', sans-serif;
|
||||
margin: 140px auto 25px;
|
||||
padding: 20px 20px 10px;
|
||||
max-width: 700px;
|
||||
box-shadow: 0px 1px 3px rgba(0, 0, 0, 0.13);
|
||||
}
|
||||
h1, h2 {
|
||||
border-bottom: 1px solid #DEDEDE;
|
||||
clear: both;
|
||||
color: #666;
|
||||
font-size: 24px;
|
||||
}
|
||||
#logo a, p, h1, h2 {
|
||||
font-weight: 400;
|
||||
}
|
||||
#logo, h1, h2 {
|
||||
padding: 0px 0px 7px;
|
||||
}
|
||||
p {
|
||||
padding-bottom: 2px;
|
||||
font-size: 14px;
|
||||
line-height: 1.5;
|
||||
}
|
||||
#logo a {
|
||||
font-family: Minecraft, sans-serif;
|
||||
transition: all .2s ease-in-out;
|
||||
font-size: 50px;
|
||||
color: #666;
|
||||
height: 84px;
|
||||
line-height: 1.3em;
|
||||
margin: -130px auto 25px;
|
||||
padding: 0;
|
||||
outline: 0;
|
||||
text-decoration: none;
|
||||
overflow: hidden;
|
||||
display: block;
|
||||
}
|
||||
#logo a:hover {
|
||||
color: #42a5f5;
|
||||
}
|
||||
/* Mobile phone */
|
||||
@media (max-width: 48em) {
|
||||
#logo a {
|
||||
font-size: 40px;
|
||||
}
|
||||
}
|
||||
@media (max-width: 35.5em) {
|
||||
#logo a {
|
||||
font-size: 30px;
|
||||
}
|
||||
}
|
||||
#logo {
|
||||
margin: 6px 0 14px;
|
||||
border-bottom: none;
|
||||
text-align: center;
|
||||
}
|
||||
.step {
|
||||
margin: 20px 0 15px;
|
||||
text-align: left;
|
||||
padding: 0;
|
||||
}
|
||||
.step>input {
|
||||
font-family: Ubuntu, 'Microsoft Yahei', 'Microsoft Jhenghei', sans-serif;
|
||||
}
|
||||
fieldset {
|
||||
padding: 0;
|
||||
margin: 0
|
||||
}
|
||||
|
||||
label {
|
||||
cursor: pointer
|
||||
}
|
||||
|
||||
.step {
|
||||
margin: 20px 0 15px
|
||||
}
|
||||
|
||||
.step,th {
|
||||
text-align: left;
|
||||
padding: 0
|
||||
}
|
||||
|
||||
.language-chooser.wp-core-ui .step .button.button-large {
|
||||
height: 36px;
|
||||
vertical-align: middle;
|
||||
font-size: 14px
|
||||
}
|
||||
|
||||
.form-table td,.form-table th {
|
||||
padding: 10px 20px 10px 0;
|
||||
vertical-align: top;
|
||||
font-size: 14px
|
||||
}
|
||||
|
||||
textarea {
|
||||
border: 1px solid #dfdfdf;
|
||||
width: 100%;
|
||||
-webkit-box-sizing: border-box;
|
||||
-moz-box-sizing: border-box;
|
||||
box-sizing: border-box
|
||||
}
|
||||
|
||||
.form-table {
|
||||
border-collapse: collapse;
|
||||
margin-top: 1em;
|
||||
width: 100%
|
||||
}
|
||||
|
||||
.form-table td {
|
||||
margin-bottom: 9px
|
||||
}
|
||||
|
||||
.form-table th {
|
||||
text-align: left;
|
||||
width: 140px
|
||||
}
|
||||
|
||||
.form-table code {
|
||||
line-height: 18px;
|
||||
font-size: 14px
|
||||
}
|
||||
|
||||
.form-table p {
|
||||
margin: 4px 0 0;
|
||||
font-size: 11px
|
||||
}
|
||||
|
||||
.form-table input {
|
||||
line-height: 20px;
|
||||
font-size: 15px;
|
||||
padding: 3px 5px;
|
||||
border: 1px solid #ddd;
|
||||
-webkit-box-shadow: inset 0 1px 2px rgba(0,0,0,.07);
|
||||
box-shadow: inset 0 1px 2px rgba(0,0,0,.07)
|
||||
}
|
||||
|
||||
.form-table input[type=email],.form-table input[type=password],.form-table input[type=text],.form-table input[type=url] {
|
||||
width: 206px
|
||||
}
|
||||
|
||||
.form-table.install-success td,.form-table.install-success th {
|
||||
vertical-align: middle;
|
||||
padding: 16px 20px 16px 0
|
||||
}
|
||||
|
||||
.form-table.install-success td p {
|
||||
margin: 0;
|
||||
font-size: 14px
|
||||
}
|
||||
|
||||
.form-table.install-success td code {
|
||||
margin: 0;
|
||||
font-size: 18px
|
||||
}
|
||||
.container .button,.container .button-primary,.container .button-secondary {
|
||||
display:inline-block;
|
||||
text-decoration:none;
|
||||
font-size:13px;
|
||||
line-height:26px;
|
||||
height:28px;
|
||||
margin:0;
|
||||
padding:0 10px 1px;
|
||||
cursor:pointer;
|
||||
border-width:1px;
|
||||
border-style:solid;
|
||||
-webkit-appearance:none;
|
||||
-webkit-border-radius:3px;
|
||||
border-radius:3px;
|
||||
white-space:nowrap;
|
||||
-webkit-box-sizing:border-box;
|
||||
-moz-box-sizing:border-box;
|
||||
box-sizing:border-box
|
||||
}
|
||||
.container button::-moz-focus-inner,.container input[type=reset]::-moz-focus-inner,.container input[type=button]::-moz-focus-inner,.container input[type=submit]::-moz-focus-inner {
|
||||
border-width:0;
|
||||
border-style:none;
|
||||
padding:0
|
||||
}
|
||||
.container .button-group.button-large .button,.container .button.button-large {
|
||||
height:30px;
|
||||
line-height:28px;
|
||||
padding:0 12px 2px
|
||||
}
|
||||
.container .button-group.button-small .button,.container .button.button-small {
|
||||
height:24px;
|
||||
line-height:22px;
|
||||
padding:0 8px 1px;
|
||||
font-size:11px
|
||||
}
|
||||
.container .button-group.button-hero .button,.container .button.button-hero {
|
||||
font-size:14px;
|
||||
height:46px;
|
||||
line-height:44px;
|
||||
padding:0 36px
|
||||
}
|
||||
.container .button:active,.container .button:focus {
|
||||
outline:0
|
||||
}
|
||||
.container .button.hidden {
|
||||
display:none
|
||||
}
|
||||
.container input[type=reset],.container input[type=reset]:active,.container input[type=reset]:focus,.container input[type=reset]:hover {
|
||||
background:0 0;
|
||||
border:none;
|
||||
-webkit-box-shadow:none;
|
||||
box-shadow:none;
|
||||
padding:0 2px 1px;
|
||||
width:auto
|
||||
}
|
||||
.container .button,.container .button-secondary {
|
||||
color:#555;
|
||||
border-color:#ccc;
|
||||
background:#f7f7f7;
|
||||
-webkit-box-shadow:0 1px 0 #ccc;
|
||||
box-shadow:0 1px 0 #ccc;
|
||||
vertical-align:top
|
||||
}
|
||||
.container p .button {
|
||||
vertical-align:baseline
|
||||
}
|
||||
.container .button-secondary:focus,.container .button-secondary:hover,.container .button.focus,.container .button.hover,.container .button:focus,.container .button:hover {
|
||||
background:#fafafa;
|
||||
border-color:#999;
|
||||
color:#23282d
|
||||
}
|
||||
.container .button-link:focus,.container .button-secondary:focus,.container .button.focus,.container .button:focus {
|
||||
border-color:#5b9dd9;
|
||||
-webkit-box-shadow:0 0 3px rgba(0,115,170,.8);
|
||||
box-shadow:0 0 3px rgba(0,115,170,.8)
|
||||
}
|
||||
.container .button-secondary:active,.container .button.active,.container .button.active:hover,.container .button:active {
|
||||
background:#eee;
|
||||
border-color:#999;
|
||||
-webkit-box-shadow:inset 0 2px 5px -3px rgba(0,0,0,.5);
|
||||
box-shadow:inset 0 2px 5px -3px rgba(0,0,0,.5);
|
||||
-webkit-transform:translateY(1px);
|
||||
-ms-transform:translateY(1px);
|
||||
transform:translateY(1px)
|
||||
}
|
||||
.container .button.active:focus {
|
||||
border-color:#5b9dd9;
|
||||
-webkit-box-shadow:inset 0 2px 5px -3px rgba(0,0,0,.5),0 0 3px rgba(0,115,170,.8);
|
||||
box-shadow:inset 0 2px 5px -3px rgba(0,0,0,.5),0 0 3px rgba(0,115,170,.8)
|
||||
}
|
||||
.container .button-disabled,.container .button-secondary.disabled,.container .button-secondary:disabled,.container .button-secondary[disabled],.container .button.disabled,.container .button:disabled,.container .button[disabled] {
|
||||
color:#a0a5aa!important;
|
||||
border-color:#ddd!important;
|
||||
background:#f7f7f7!important;
|
||||
-webkit-box-shadow:none!important;
|
||||
box-shadow:none!important;
|
||||
text-shadow:0 1px 0 #fff!important;
|
||||
cursor:default;
|
||||
-webkit-transform:none!important;
|
||||
-ms-transform:none!important;
|
||||
transform:none!important
|
||||
}
|
||||
.container .button-link {
|
||||
margin:0;
|
||||
padding:0;
|
||||
-webkit-box-shadow:none;
|
||||
box-shadow:none;
|
||||
border:0;
|
||||
-webkit-border-radius:0;
|
||||
border-radius:0;
|
||||
background:0 0;
|
||||
outline:0;
|
||||
cursor:pointer
|
||||
}
|
||||
.container .button-primary {
|
||||
background:#0085ba;
|
||||
border-color:#0073aa #006799 #006799;
|
||||
-webkit-box-shadow:0 1px 0 #006799;
|
||||
box-shadow:0 1px 0 #006799;
|
||||
color:#fff;
|
||||
text-decoration:none;
|
||||
text-shadow:0 -1px 1px #006799,1px 0 1px #006799,0 1px 1px #006799,-1px 0 1px #006799
|
||||
}
|
||||
.container .button-primary.focus,.container .button-primary.hover,.container .button-primary:focus,.container .button-primary:hover {
|
||||
background:#008ec2;
|
||||
border-color:#006799;
|
||||
color:#fff
|
||||
}
|
||||
.container .button-primary.focus,.container .button-primary:focus {
|
||||
-webkit-box-shadow:0 1px 0 #0073aa,0 0 2px 1px #33b3db;
|
||||
box-shadow:0 1px 0 #0073aa,0 0 2px 1px #33b3db
|
||||
}
|
||||
.alert {
|
||||
padding: 15px;
|
||||
margin-top: 15px;
|
||||
margin-bottom: 20px;
|
||||
border: 1px solid transparent;
|
||||
border-radius: 4px;
|
||||
}
|
||||
.alert-warning {
|
||||
color: #8a6d3b;
|
||||
background-color: #fcf8e3;
|
||||
border-color: #faebcc;
|
||||
}
|
||||
.test {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
.test-name {
|
||||
display: inline-block;
|
||||
width: 250px;
|
||||
font-size: 16px;
|
||||
/*font-weight: 700;*/
|
||||
}
|
||||
.result.passed {
|
||||
color: #4caf50;
|
||||
}
|
||||
.result.failed {
|
||||
color: #f44336;
|
||||
}
|
||||
.result {
|
||||
float: right;
|
||||
display: inline-block;
|
||||
width: 250px;
|
||||
text-align: right;
|
||||
font-weight: bold;
|
||||
}
|
||||
.info {
|
||||
margin: 4px 0 0 0;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
|
@ -1,188 +0,0 @@
|
|||
/*
|
||||
* @Author: printempw
|
||||
* @Date: 2016-01-21 07:57:38
|
||||
* @Last Modified by: printempw
|
||||
* @Last Modified time: 2016-04-03 11:21:35
|
||||
*/
|
||||
|
||||
@font-face {
|
||||
font-family: 'Minecraft';
|
||||
src: url('../fonts/minecraft.eot');
|
||||
src: url('../fonts/minecraft.eot') format('embedded-opentype'),
|
||||
url('../fonts/minecraft.woff2') format('woff2'),
|
||||
url('../fonts/minecraft.woff') format('woff'),
|
||||
url('../fonts/minecraft.ttf') format('truetype'),
|
||||
url('../fonts/minecraft.svg#minecraft') format('svg');
|
||||
}
|
||||
|
||||
html {
|
||||
line-height: 1.7em;
|
||||
color: #fff;
|
||||
font-size: 13px;
|
||||
font-family: Ubuntu, 'Segoe UI', 'Microsoft Yahei', 'Microsoft Jhenghei', sans-serif;
|
||||
}
|
||||
|
||||
p {
|
||||
margin: 10px 0;
|
||||
}
|
||||
|
||||
.home-menu {
|
||||
padding: 0;
|
||||
text-align: center;
|
||||
border-bottom: 1px solid rgba(0, 0, 0, 0.3);
|
||||
box-shadow: rgba(0,0,0,0.1) 0 1px 2px;
|
||||
/* for firefox */
|
||||
white-space: normal;
|
||||
}
|
||||
.home-menu .pure-menu-heading {
|
||||
color: #5e5e5e;
|
||||
font-weight: 400;
|
||||
font-size: 18px;
|
||||
font-family: Minecraft, 'Segoe UI', 'Microsoft Yahei', 'Microsoft Jhenghei', sans-serif;
|
||||
text-transform: none;
|
||||
}
|
||||
.pure-menu-heading:hover {
|
||||
color: #444;
|
||||
}
|
||||
.home-menu button {
|
||||
color: #fff;
|
||||
font-size: 15px;
|
||||
}
|
||||
.pure-menu-selected {
|
||||
font-weight: bold;
|
||||
}
|
||||
.pure-menu-item {
|
||||
color: #5e5e5e !important;
|
||||
}
|
||||
.pure-menu-link {
|
||||
display: inline-block;
|
||||
color: #5e5e5e !important;
|
||||
font-size: 15px;
|
||||
cursor: pointer;
|
||||
padding: .5em .5em;
|
||||
}
|
||||
.pure-menu-link:hover,
|
||||
.pure-menu-link:focus {
|
||||
background: none;
|
||||
border: none;
|
||||
color: #0078e7 !important;
|
||||
}
|
||||
.pure-button {
|
||||
margin: .5em 1em;
|
||||
}
|
||||
.pure-button-error {
|
||||
background: rgb(202, 60, 60);
|
||||
color: #fff;
|
||||
}
|
||||
.pure-button-warning {
|
||||
background: #ec971f;
|
||||
color: #fff;
|
||||
}
|
||||
.container {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
top: 0;
|
||||
left: 0;
|
||||
position: fixed !important;
|
||||
}
|
||||
|
||||
.footer {
|
||||
color: #fff;
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
top: 93%;
|
||||
text-align: center;
|
||||
letter-spacing: 0.05em;
|
||||
}
|
||||
.footer a {
|
||||
text-decoration: none;
|
||||
color: white;
|
||||
}
|
||||
.footer a:hover {
|
||||
color: #1f8dd6;
|
||||
}
|
||||
|
||||
/* Mobile phone */
|
||||
@media (max-width: 48em) {
|
||||
.home-menu .pure-menu-selected a {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@media (min-width: 48em) {
|
||||
body {
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.home-menu {
|
||||
text-align: left;
|
||||
}
|
||||
.home-menu ul {
|
||||
float: right;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
.panel {
|
||||
background-color: #fff;
|
||||
border: 1px solid transparent;
|
||||
border-radius: 4px;
|
||||
-webkit-box-shadow: 0 1px 1px rgba(0,0,0,.05);
|
||||
box-shadow: 0 1px 1px rgba(0,0,0,.05);
|
||||
width: 90%;
|
||||
margin: 0 auto 20px;
|
||||
}
|
||||
|
||||
.panel-default {
|
||||
border-color: #ddd!important;
|
||||
}
|
||||
.panel-danger {
|
||||
border-color: #ebccd1!important;
|
||||
}
|
||||
.panel-warning {
|
||||
border-color: #faebcc;
|
||||
}
|
||||
|
||||
.panel-default > .panel-heading {
|
||||
color: #333;
|
||||
background-color: #f5f5f5;
|
||||
border-color: #ddd;
|
||||
}
|
||||
.panel-danger > .panel-heading {
|
||||
color: #a94442;
|
||||
background-color: #f2dede;
|
||||
border-color: #ebccd1;
|
||||
}
|
||||
.panel-warning > .panel-heading {
|
||||
color: #8a6d3b;
|
||||
background-color: #fcf8e3;
|
||||
border-color: #faebcc;
|
||||
}
|
||||
.panel-heading {
|
||||
padding: 10px 15px;
|
||||
border-bottom: 1px solid transparent;
|
||||
border-top-left-radius: 3px;
|
||||
border-top-right-radius: 3px;
|
||||
}
|
||||
.panel-body {
|
||||
padding: 10px 15px 15px;
|
||||
}
|
||||
.pure-g:first-child {
|
||||
margin-top: 75px;
|
||||
}
|
||||
.pure-g {
|
||||
font-family: Ubuntu, 'Segoe UI', 'Microsoft Yahei', 'Microsoft Jhenghei', sans-serif;
|
||||
}
|
||||
@media screen and (max-width: 40em) {
|
||||
.pure-g:first-child {
|
||||
margin-top: 100px;
|
||||
}
|
||||
}
|
||||
.ply-layer {
|
||||
font-family: Ubuntu, 'Segoe UI', 'Microsoft Yahei', 'Microsoft Jhenghei', sans-serif !important;
|
||||
}
|
||||
/* fucking webkit autofill */
|
||||
input:-webkit-autofill {
|
||||
-webkit-box-shadow: 0 0 0px 1000px #fff inset !important;
|
||||
}
|
||||
|
|
@ -1,26 +0,0 @@
|
|||
/*
|
||||
* @Author: printempw
|
||||
* @Date: 2016-01-21 19:12:06
|
||||
* @Last Modified by: printempw
|
||||
* @Last Modified time: 2016-04-03 11:21:24
|
||||
*/
|
||||
|
||||
body, .ply-layer {
|
||||
font-family: Ubuntu, 'Segoe UI', 'Microsoft Yahei', 'Microsoft Jhenghei', sans-serif;
|
||||
}
|
||||
.main-header .logo .logo-lg {
|
||||
font-family: Ubuntu, 'Segoe UI', 'Microsoft Yahei', 'Microsoft Jhenghei', sans-serif;
|
||||
}
|
||||
.box-body {
|
||||
line-height: 1.8;
|
||||
}
|
||||
.callout {
|
||||
border-radius: 3px;
|
||||
margin: 10px 0 0 0;
|
||||
padding: 15px 30px 15px 15px;
|
||||
border-left: 5px solid #eee;
|
||||
}
|
||||
.model-label {
|
||||
font-weight: 500;
|
||||
font-size: 15px;
|
||||
}
|
||||
BIN
assets/fonts/FontAwesome.otf
Normal file
BIN
assets/fonts/fontawesome-webfont.eot
Normal file
|
|
@ -169,7 +169,7 @@
|
|||
<glyph unicode="" horiz-adv-x="1792" d="M1408 608v-320q0 -119 -84.5 -203.5t-203.5 -84.5h-832q-119 0 -203.5 84.5t-84.5 203.5v832q0 119 84.5 203.5t203.5 84.5h704q14 0 23 -9t9 -23v-64q0 -14 -9 -23t-23 -9h-704q-66 0 -113 -47t-47 -113v-832q0 -66 47 -113t113 -47h832q66 0 113 47t47 113v320 q0 14 9 23t23 9h64q14 0 23 -9t9 -23zM1792 1472v-512q0 -26 -19 -45t-45 -19t-45 19l-176 176l-652 -652q-10 -10 -23 -10t-23 10l-114 114q-10 10 -10 23t10 23l652 652l-176 176q-19 19 -19 45t19 45t45 19h512q26 0 45 -19t19 -45z" />
|
||||
<glyph unicode="" d="M1184 640q0 -26 -19 -45l-544 -544q-19 -19 -45 -19t-45 19t-19 45v288h-448q-26 0 -45 19t-19 45v384q0 26 19 45t45 19h448v288q0 26 19 45t45 19t45 -19l544 -544q19 -19 19 -45zM1536 992v-704q0 -119 -84.5 -203.5t-203.5 -84.5h-320q-13 0 -22.5 9.5t-9.5 22.5 q0 4 -1 20t-0.5 26.5t3 23.5t10 19.5t20.5 6.5h320q66 0 113 47t47 113v704q0 66 -47 113t-113 47h-288h-11h-13t-11.5 1t-11.5 3t-8 5.5t-7 9t-2 13.5q0 4 -1 20t-0.5 26.5t3 23.5t10 19.5t20.5 6.5h320q119 0 203.5 -84.5t84.5 -203.5z" />
|
||||
<glyph unicode="" horiz-adv-x="1664" d="M458 653q-74 162 -74 371h-256v-96q0 -78 94.5 -162t235.5 -113zM1536 928v96h-256q0 -209 -74 -371q141 29 235.5 113t94.5 162zM1664 1056v-128q0 -71 -41.5 -143t-112 -130t-173 -97.5t-215.5 -44.5q-42 -54 -95 -95q-38 -34 -52.5 -72.5t-14.5 -89.5q0 -54 30.5 -91 t97.5 -37q75 0 133.5 -45.5t58.5 -114.5v-64q0 -14 -9 -23t-23 -9h-832q-14 0 -23 9t-9 23v64q0 69 58.5 114.5t133.5 45.5q67 0 97.5 37t30.5 91q0 51 -14.5 89.5t-52.5 72.5q-53 41 -95 95q-113 5 -215.5 44.5t-173 97.5t-112 130t-41.5 143v128q0 40 28 68t68 28h288v96 q0 66 47 113t113 47h576q66 0 113 -47t47 -113v-96h288q40 0 68 -28t28 -68z" />
|
||||
<glyph unicode="" d="M394 184q-8 -9 -20 3q-13 11 -4 19q8 9 20 -3q12 -11 4 -19zM352 245q9 -12 0 -19q-8 -6 -17 7t0 18q9 7 17 -6zM291 305q-5 -7 -13 -2q-10 5 -7 12q3 5 13 2q10 -5 7 -12zM322 271q-6 -7 -16 3q-9 11 -2 16q6 6 16 -3q9 -11 2 -16zM451 159q-4 -12 -19 -6q-17 4 -13 15 t19 7q16 -5 13 -16zM514 154q0 -11 -16 -11q-17 -2 -17 11q0 11 16 11q17 2 17 -11zM572 164q2 -10 -14 -14t-18 8t14 15q16 2 18 -9zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-224q-16 0 -24.5 1t-19.5 5t-16 14.5t-5 27.5v239q0 97 -52 142q57 6 102.5 18t94 39 t81 66.5t53 105t20.5 150.5q0 121 -79 206q37 91 -8 204q-28 9 -81 -11t-92 -44l-38 -24q-93 26 -192 26t-192 -26q-16 11 -42.5 27t-83.5 38.5t-86 13.5q-44 -113 -7 -204q-79 -85 -79 -206q0 -85 20.5 -150t52.5 -105t80.5 -67t94 -39t102.5 -18q-40 -36 -49 -103 q-21 -10 -45 -15t-57 -5t-65.5 21.5t-55.5 62.5q-19 32 -48.5 52t-49.5 24l-20 3q-21 0 -29 -4.5t-5 -11.5t9 -14t13 -12l7 -5q22 -10 43.5 -38t31.5 -51l10 -23q13 -38 44 -61.5t67 -30t69.5 -7t55.5 3.5l23 4q0 -38 0.5 -103t0.5 -68q0 -22 -11 -33.5t-22 -13t-33 -1.5 h-224q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
|
||||
<glyph unicode="" d="M519 336q4 6 -3 13q-9 7 -14 2q-4 -6 3 -13q9 -7 14 -2zM491 377q-5 7 -12 4q-6 -4 0 -12q7 -8 12 -5q6 4 0 13zM450 417q2 4 -5 8q-7 2 -8 -2q-3 -5 4 -8q8 -2 9 2zM471 394q2 1 1.5 4.5t-3.5 5.5q-6 7 -10 3t1 -11q6 -6 11 -2zM557 319q2 7 -9 11q-9 3 -13 -4 q-2 -7 9 -11q9 -3 13 4zM599 316q0 8 -12 8q-10 0 -10 -8t11 -8t11 8zM638 323q-2 7 -13 5t-9 -9q2 -8 12 -6t10 10zM1280 640q0 212 -150 362t-362 150t-362 -150t-150 -362q0 -167 98 -300.5t252 -185.5q18 -3 26.5 5t8.5 20q0 52 -1 95q-6 -1 -15.5 -2.5t-35.5 -2t-48 4 t-43.5 20t-29.5 41.5q-23 59 -57 74q-2 1 -4.5 3.5l-8 8t-7 9.5t4 7.5t19.5 3.5q6 0 15 -2t30 -15.5t33 -35.5q16 -28 37.5 -42t43.5 -14t38 3.5t30 9.5q7 47 33 69q-49 6 -86 18.5t-73 39t-55.5 76t-19.5 119.5q0 79 53 137q-24 62 5 136q19 6 54.5 -7.5t60.5 -29.5l26 -16 q58 17 128 17t128 -17q11 7 28.5 18t55.5 26t57 9q29 -74 5 -136q53 -58 53 -137q0 -57 -14 -100.5t-35.5 -70t-53.5 -44.5t-62.5 -26t-68.5 -12q35 -31 35 -95q0 -40 -0.5 -89t-0.5 -51q0 -12 8.5 -20t26.5 -5q154 52 252 185.5t98 300.5zM1536 1120v-960 q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
|
||||
<glyph unicode="" horiz-adv-x="1664" d="M1280 64q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -45t45 -19t45 19t19 45zM1536 64q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -45t45 -19t45 19t19 45zM1664 288v-320q0 -40 -28 -68t-68 -28h-1472q-40 0 -68 28t-28 68v320q0 40 28 68t68 28h427q21 -56 70.5 -92 t110.5 -36h256q61 0 110.5 36t70.5 92h427q40 0 68 -28t28 -68zM1339 936q-17 -40 -59 -40h-256v-448q0 -26 -19 -45t-45 -19h-256q-26 0 -45 19t-19 45v448h-256q-42 0 -59 40q-17 39 14 69l448 448q18 19 45 19t45 -19l448 -448q31 -30 14 -69z" />
|
||||
<glyph unicode="" d="M1407 710q0 44 -7 113.5t-18 96.5q-12 30 -17 44t-9 36.5t-4 48.5q0 23 5 68.5t5 67.5q0 37 -10 55q-4 1 -13 1q-19 0 -58 -4.5t-59 -4.5q-60 0 -176 24t-175 24q-43 0 -94.5 -11.5t-85 -23.5t-89.5 -34q-137 -54 -202 -103q-96 -73 -159.5 -189.5t-88 -236t-24.5 -248.5 q0 -40 12.5 -120t12.5 -121q0 -23 -11 -66.5t-11 -65.5t12 -36.5t34 -14.5q24 0 72.5 11t73.5 11q57 0 169.5 -15.5t169.5 -15.5q181 0 284 36q129 45 235.5 152.5t166 245.5t59.5 275zM1535 712q0 -165 -70 -327.5t-196 -288t-281 -180.5q-124 -44 -326 -44 q-57 0 -170 14.5t-169 14.5q-24 0 -72.5 -14.5t-73.5 -14.5q-73 0 -123.5 55.5t-50.5 128.5q0 24 11 68t11 67q0 40 -12.5 120.5t-12.5 121.5q0 111 18 217.5t54.5 209.5t100.5 194t150 156q78 59 232 120q194 78 316 78q60 0 175.5 -24t173.5 -24q19 0 57 5t58 5 q81 0 118 -50.5t37 -134.5q0 -23 -5 -68t-5 -68q0 -10 1 -18.5t3 -17t4 -13.5t6.5 -16t6.5 -17q16 -40 25 -118.5t9 -136.5z" />
|
||||
<glyph unicode="" horiz-adv-x="1408" d="M1408 296q0 -27 -10 -70.5t-21 -68.5q-21 -50 -122 -106q-94 -51 -186 -51q-27 0 -52.5 3.5t-57.5 12.5t-47.5 14.5t-55.5 20.5t-49 18q-98 35 -175 83q-128 79 -264.5 215.5t-215.5 264.5q-48 77 -83 175q-3 9 -18 49t-20.5 55.5t-14.5 47.5t-12.5 57.5t-3.5 52.5 q0 92 51 186q56 101 106 122q25 11 68.5 21t70.5 10q14 0 21 -3q18 -6 53 -76q11 -19 30 -54t35 -63.5t31 -53.5q3 -4 17.5 -25t21.5 -35.5t7 -28.5q0 -20 -28.5 -50t-62 -55t-62 -53t-28.5 -46q0 -9 5 -22.5t8.5 -20.5t14 -24t11.5 -19q76 -137 174 -235t235 -174 q2 -1 19 -11.5t24 -14t20.5 -8.5t22.5 -5q18 0 46 28.5t53 62t55 62t50 28.5q14 0 28.5 -7t35.5 -21.5t25 -17.5q25 -15 53.5 -31t63.5 -35t54 -30q70 -35 76 -53q3 -7 3 -21z" />
|
||||
|
|
@ -178,7 +178,7 @@
|
|||
<glyph unicode="" d="M1280 343q0 11 -2 16q-3 8 -38.5 29.5t-88.5 49.5l-53 29q-5 3 -19 13t-25 15t-21 5q-18 0 -47 -32.5t-57 -65.5t-44 -33q-7 0 -16.5 3.5t-15.5 6.5t-17 9.5t-14 8.5q-99 55 -170.5 126.5t-126.5 170.5q-2 3 -8.5 14t-9.5 17t-6.5 15.5t-3.5 16.5q0 13 20.5 33.5t45 38.5 t45 39.5t20.5 36.5q0 10 -5 21t-15 25t-13 19q-3 6 -15 28.5t-25 45.5t-26.5 47.5t-25 40.5t-16.5 18t-16 2q-48 0 -101 -22q-46 -21 -80 -94.5t-34 -130.5q0 -16 2.5 -34t5 -30.5t9 -33t10 -29.5t12.5 -33t11 -30q60 -164 216.5 -320.5t320.5 -216.5q6 -2 30 -11t33 -12.5 t29.5 -10t33 -9t30.5 -5t34 -2.5q57 0 130.5 34t94.5 80q22 53 22 101zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
|
||||
<glyph unicode="" horiz-adv-x="1664" d="M1620 1128q-67 -98 -162 -167q1 -14 1 -42q0 -130 -38 -259.5t-115.5 -248.5t-184.5 -210.5t-258 -146t-323 -54.5q-271 0 -496 145q35 -4 78 -4q225 0 401 138q-105 2 -188 64.5t-114 159.5q33 -5 61 -5q43 0 85 11q-112 23 -185.5 111.5t-73.5 205.5v4q68 -38 146 -41 q-66 44 -105 115t-39 154q0 88 44 163q121 -149 294.5 -238.5t371.5 -99.5q-8 38 -8 74q0 134 94.5 228.5t228.5 94.5q140 0 236 -102q109 21 205 78q-37 -115 -142 -178q93 10 186 50z" />
|
||||
<glyph unicode="" horiz-adv-x="1024" d="M959 1524v-264h-157q-86 0 -116 -36t-30 -108v-189h293l-39 -296h-254v-759h-306v759h-255v296h255v218q0 186 104 288.5t277 102.5q147 0 228 -12z" />
|
||||
<glyph unicode="" d="M1536 640q0 -251 -146.5 -451.5t-378.5 -277.5q-27 -5 -39.5 7t-12.5 30v211q0 97 -52 142q57 6 102.5 18t94 39t81 66.5t53 105t20.5 150.5q0 121 -79 206q37 91 -8 204q-28 9 -81 -11t-92 -44l-38 -24q-93 26 -192 26t-192 -26q-16 11 -42.5 27t-83.5 38.5t-86 13.5 q-44 -113 -7 -204q-79 -85 -79 -206q0 -85 20.5 -150t52.5 -105t80.5 -67t94 -39t102.5 -18q-40 -36 -49 -103q-21 -10 -45 -15t-57 -5t-65.5 21.5t-55.5 62.5q-19 32 -48.5 52t-49.5 24l-20 3q-21 0 -29 -4.5t-5 -11.5t9 -14t13 -12l7 -5q22 -10 43.5 -38t31.5 -51l10 -23 q13 -38 44 -61.5t67 -30t69.5 -7t55.5 3.5l23 4q0 -38 0.5 -89t0.5 -54q0 -18 -13 -30t-40 -7q-232 77 -378.5 277.5t-146.5 451.5q0 209 103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
|
||||
<glyph unicode="" d="M768 1408q209 0 385.5 -103t279.5 -279.5t103 -385.5q0 -251 -146.5 -451.5t-378.5 -277.5q-27 -5 -40 7t-13 30q0 3 0.5 76.5t0.5 134.5q0 97 -52 142q57 6 102.5 18t94 39t81 66.5t53 105t20.5 150.5q0 119 -79 206q37 91 -8 204q-28 9 -81 -11t-92 -44l-38 -24 q-93 26 -192 26t-192 -26q-16 11 -42.5 27t-83.5 38.5t-85 13.5q-45 -113 -8 -204q-79 -87 -79 -206q0 -85 20.5 -150t52.5 -105t80.5 -67t94 -39t102.5 -18q-39 -36 -49 -103q-21 -10 -45 -15t-57 -5t-65.5 21.5t-55.5 62.5q-19 32 -48.5 52t-49.5 24l-20 3q-21 0 -29 -4.5 t-5 -11.5t9 -14t13 -12l7 -5q22 -10 43.5 -38t31.5 -51l10 -23q13 -38 44 -61.5t67 -30t69.5 -7t55.5 3.5l23 4q0 -38 0.5 -88.5t0.5 -54.5q0 -18 -13 -30t-40 -7q-232 77 -378.5 277.5t-146.5 451.5q0 209 103 385.5t279.5 279.5t385.5 103zM291 305q3 7 -7 12 q-10 3 -13 -2q-3 -7 7 -12q9 -6 13 2zM322 271q7 5 -2 16q-10 9 -16 3q-7 -5 2 -16q10 -10 16 -3zM352 226q9 7 0 19q-8 13 -17 6q-9 -5 0 -18t17 -7zM394 184q8 8 -4 19q-12 12 -20 3q-9 -8 4 -19q12 -12 20 -3zM451 159q3 11 -13 16q-15 4 -19 -7t13 -15q15 -6 19 6z M514 154q0 13 -17 11q-16 0 -16 -11q0 -13 17 -11q16 0 16 11zM572 164q-2 11 -18 9q-16 -3 -14 -15t18 -8t14 14z" />
|
||||
<glyph unicode="" horiz-adv-x="1664" d="M1664 960v-256q0 -26 -19 -45t-45 -19h-64q-26 0 -45 19t-19 45v256q0 106 -75 181t-181 75t-181 -75t-75 -181v-192h96q40 0 68 -28t28 -68v-576q0 -40 -28 -68t-68 -28h-960q-40 0 -68 28t-28 68v576q0 40 28 68t68 28h672v192q0 185 131.5 316.5t316.5 131.5 t316.5 -131.5t131.5 -316.5z" />
|
||||
<glyph unicode="" horiz-adv-x="1920" d="M1760 1408q66 0 113 -47t47 -113v-1216q0 -66 -47 -113t-113 -47h-1600q-66 0 -113 47t-47 113v1216q0 66 47 113t113 47h1600zM160 1280q-13 0 -22.5 -9.5t-9.5 -22.5v-224h1664v224q0 13 -9.5 22.5t-22.5 9.5h-1600zM1760 0q13 0 22.5 9.5t9.5 22.5v608h-1664v-608 q0 -13 9.5 -22.5t22.5 -9.5h1600zM256 128v128h256v-128h-256zM640 128v128h384v-128h-384z" />
|
||||
<glyph unicode="" horiz-adv-x="1408" d="M384 192q0 -80 -56 -136t-136 -56t-136 56t-56 136t56 136t136 56t136 -56t56 -136zM896 69q2 -28 -17 -48q-18 -21 -47 -21h-135q-25 0 -43 16.5t-20 41.5q-22 229 -184.5 391.5t-391.5 184.5q-25 2 -41.5 20t-16.5 43v135q0 29 21 47q17 17 43 17h5q160 -13 306 -80.5 t259 -181.5q114 -113 181.5 -259t80.5 -306zM1408 67q2 -27 -18 -47q-18 -20 -46 -20h-143q-26 0 -44.5 17.5t-19.5 42.5q-12 215 -101 408.5t-231.5 336t-336 231.5t-408.5 102q-25 1 -42.5 19.5t-17.5 43.5v143q0 28 20 46q18 18 44 18h3q262 -13 501.5 -120t425.5 -294 q187 -186 294 -425.5t120 -501.5z" />
|
||||
|
|
@ -363,7 +363,7 @@
|
|||
<glyph unicode="" horiz-adv-x="1792" d="M1280 640q0 37 -30 54l-512 320q-31 20 -65 2q-33 -18 -33 -56v-640q0 -38 33 -56q16 -8 31 -8q20 0 34 10l512 320q30 17 30 54zM1792 640q0 -96 -1 -150t-8.5 -136.5t-22.5 -147.5q-16 -73 -69 -123t-124 -58q-222 -25 -671 -25t-671 25q-71 8 -124.5 58t-69.5 123 q-14 65 -21.5 147.5t-8.5 136.5t-1 150t1 150t8.5 136.5t22.5 147.5q16 73 69 123t124 58q222 25 671 25t671 -25q71 -8 124.5 -58t69.5 -123q14 -65 21.5 -147.5t8.5 -136.5t1 -150z" />
|
||||
<glyph unicode="" horiz-adv-x="1792" d="M402 829l494 -305l-342 -285l-490 319zM1388 274v-108l-490 -293v-1l-1 1l-1 -1v1l-489 293v108l147 -96l342 284v2l1 -1l1 1v-2l343 -284zM554 1418l342 -285l-494 -304l-338 270zM1390 829l338 -271l-489 -319l-343 285zM1239 1418l489 -319l-338 -270l-494 304z" />
|
||||
<glyph unicode="" d="M1289 -96h-1118v480h-160v-640h1438v640h-160v-480zM347 428l33 157l783 -165l-33 -156zM450 802l67 146l725 -339l-67 -145zM651 1158l102 123l614 -513l-102 -123zM1048 1536l477 -641l-128 -96l-477 641zM330 65v159h800v-159h-800z" />
|
||||
<glyph unicode="" d="M1362 110v648h-135q20 -63 20 -131q0 -126 -64 -232.5t-174 -168.5t-240 -62q-197 0 -337 135.5t-140 327.5q0 68 20 131h-141v-648q0 -26 17.5 -43.5t43.5 -17.5h1069q25 0 43 17.5t18 43.5zM1078 643q0 124 -90.5 211.5t-218.5 87.5q-127 0 -217.5 -87.5t-90.5 -211.5 t90.5 -211.5t217.5 -87.5q128 0 218.5 87.5t90.5 211.5zM1362 1003v165q0 28 -20 48.5t-49 20.5h-174q-29 0 -49 -20.5t-20 -48.5v-165q0 -29 20 -49t49 -20h174q29 0 49 20t20 49zM1536 1211v-1142q0 -81 -58 -139t-139 -58h-1142q-81 0 -139 58t-58 139v1142q0 81 58 139 t139 58h1142q81 0 139 -58t58 -139z" />
|
||||
<glyph unicode="" d="M1024 640q0 106 -75 181t-181 75t-181 -75t-75 -181t75 -181t181 -75t181 75t75 181zM1162 640q0 -164 -115 -279t-279 -115t-279 115t-115 279t115 279t279 115t279 -115t115 -279zM1270 1050q0 -38 -27 -65t-65 -27t-65 27t-27 65t27 65t65 27t65 -27t27 -65zM768 1270 q-7 0 -76.5 0.5t-105.5 0t-96.5 -3t-103 -10t-71.5 -18.5q-50 -20 -88 -58t-58 -88q-11 -29 -18.5 -71.5t-10 -103t-3 -96.5t0 -105.5t0.5 -76.5t-0.5 -76.5t0 -105.5t3 -96.5t10 -103t18.5 -71.5q20 -50 58 -88t88 -58q29 -11 71.5 -18.5t103 -10t96.5 -3t105.5 0t76.5 0.5 t76.5 -0.5t105.5 0t96.5 3t103 10t71.5 18.5q50 20 88 58t58 88q11 29 18.5 71.5t10 103t3 96.5t0 105.5t-0.5 76.5t0.5 76.5t0 105.5t-3 96.5t-10 103t-18.5 71.5q-20 50 -58 88t-88 58q-29 11 -71.5 18.5t-103 10t-96.5 3t-105.5 0t-76.5 -0.5zM1536 640q0 -229 -5 -317 q-10 -208 -124 -322t-322 -124q-88 -5 -317 -5t-317 5q-208 10 -322 124t-124 322q-5 88 -5 317t5 317q10 208 124 322t322 124q88 5 317 5t317 -5q208 -10 322 -124t124 -322q5 -88 5 -317z" />
|
||||
<glyph unicode="" d="M1248 1408q119 0 203.5 -84.5t84.5 -203.5v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960zM698 640q0 88 -62 150t-150 62t-150 -62t-62 -150t62 -150t150 -62t150 62t62 150zM1262 640q0 88 -62 150 t-150 62t-150 -62t-62 -150t62 -150t150 -62t150 62t62 150z" />
|
||||
<glyph unicode="" d="M768 914l201 -306h-402zM1133 384h94l-459 691l-459 -691h94l104 160h522zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
|
||||
<glyph unicode="" horiz-adv-x="1408" d="M815 677q8 -63 -50.5 -101t-111.5 -6q-39 17 -53.5 58t-0.5 82t52 58q36 18 72.5 12t64 -35.5t27.5 -67.5zM926 698q-14 107 -113 164t-197 13q-63 -28 -100.5 -88.5t-34.5 -129.5q4 -91 77.5 -155t165.5 -56q91 8 152 84t50 168zM1165 1240q-20 27 -56 44.5t-58 22 t-71 12.5q-291 47 -566 -2q-43 -7 -66 -12t-55 -22t-50 -43q30 -28 76 -45.5t73.5 -22t87.5 -11.5q228 -29 448 -1q63 8 89.5 12t72.5 21.5t75 46.5zM1222 205q-8 -26 -15.5 -76.5t-14 -84t-28.5 -70t-58 -56.5q-86 -48 -189.5 -71.5t-202 -22t-201.5 18.5q-46 8 -81.5 18 t-76.5 27t-73 43.5t-52 61.5q-25 96 -57 292l6 16l18 9q223 -148 506.5 -148t507.5 148q21 -6 24 -23t-5 -45t-8 -37zM1403 1166q-26 -167 -111 -655q-5 -30 -27 -56t-43.5 -40t-54.5 -31q-252 -126 -610 -88q-248 27 -394 139q-15 12 -25.5 26.5t-17 35t-9 34t-6 39.5 t-5.5 35q-9 50 -26.5 150t-28 161.5t-23.5 147.5t-22 158q3 26 17.5 48.5t31.5 37.5t45 30t46 22.5t48 18.5q125 46 313 64q379 37 676 -50q155 -46 215 -122q16 -20 16.5 -51t-5.5 -54z" />
|
||||
|
|
@ -484,7 +484,7 @@
|
|||
<glyph unicode="" horiz-adv-x="2048" d="M1024 13q-20 0 -93 73.5t-73 93.5q0 32 62.5 54t103.5 22t103.5 -22t62.5 -54q0 -20 -73 -93.5t-93 -73.5zM1294 284q-2 0 -40 25t-101.5 50t-128.5 25t-128.5 -25t-101 -50t-40.5 -25q-18 0 -93.5 75t-75.5 93q0 13 10 23q78 77 196 121t233 44t233 -44t196 -121 q10 -10 10 -23q0 -18 -75.5 -93t-93.5 -75zM1567 556q-11 0 -23 8q-136 105 -252 154.5t-268 49.5q-85 0 -170.5 -22t-149 -53t-113.5 -62t-79 -53t-31 -22q-17 0 -92 75t-75 93q0 12 10 22q132 132 320 205t380 73t380 -73t320 -205q10 -10 10 -22q0 -18 -75 -93t-92 -75z M1838 827q-11 0 -22 9q-179 157 -371.5 236.5t-420.5 79.5t-420.5 -79.5t-371.5 -236.5q-11 -9 -22 -9q-17 0 -92.5 75t-75.5 93q0 13 10 23q187 186 445 288t527 102t527 -102t445 -288q10 -10 10 -23q0 -18 -75.5 -93t-92.5 -75z" />
|
||||
<glyph unicode="" horiz-adv-x="1792" d="M384 0q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM768 0q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM384 384q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5 t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM1152 0q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM768 384q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5 t37.5 90.5zM384 768q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM1152 384q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM768 768q0 53 -37.5 90.5t-90.5 37.5 t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM1536 0v384q0 52 -38 90t-90 38t-90 -38t-38 -90v-384q0 -52 38 -90t90 -38t90 38t38 90zM1152 768q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5z M1536 1088v256q0 26 -19 45t-45 19h-1280q-26 0 -45 -19t-19 -45v-256q0 -26 19 -45t45 -19h1280q26 0 45 19t19 45zM1536 768q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM1664 1408v-1536q0 -52 -38 -90t-90 -38 h-1408q-52 0 -90 38t-38 90v1536q0 52 38 90t90 38h1408q52 0 90 -38t38 -90z" />
|
||||
<glyph unicode="" d="M1519 890q18 -84 -4 -204q-87 -444 -565 -444h-44q-25 0 -44 -16.5t-24 -42.5l-4 -19l-55 -346l-2 -15q-5 -26 -24.5 -42.5t-44.5 -16.5h-251q-21 0 -33 15t-9 36q9 56 26.5 168t26.5 168t27 167.5t27 167.5q5 37 43 37h131q133 -2 236 21q175 39 287 144q102 95 155 246 q24 70 35 133q1 6 2.5 7.5t3.5 1t6 -3.5q79 -59 98 -162zM1347 1172q0 -107 -46 -236q-80 -233 -302 -315q-113 -40 -252 -42q0 -1 -90 -1l-90 1q-100 0 -118 -96q-2 -8 -85 -530q-1 -10 -12 -10h-295q-22 0 -36.5 16.5t-11.5 38.5l232 1471q5 29 27.5 48t51.5 19h598 q34 0 97.5 -13t111.5 -32q107 -41 163.5 -123t56.5 -196z" />
|
||||
<glyph unicode="" horiz-adv-x="1792" d="M602 949q19 -61 31 -123.5t17 -141.5t-14 -159t-62 -145q-21 81 -67 157t-95.5 127t-99 90.5t-78.5 57.5t-33 19q-62 34 -81.5 100t14.5 128t101 81.5t129 -14.5q138 -83 238 -177zM927 1236q11 -25 20.5 -46t36.5 -100.5t42.5 -150.5t25.5 -179.5t0 -205.5t-47.5 -209.5 t-105.5 -208.5q-51 -72 -138 -72q-54 0 -98 31q-57 40 -69 109t28 127q60 85 81 195t13 199.5t-32 180.5t-39 128t-22 52q-31 63 -8.5 129.5t85.5 97.5q34 17 75 17q47 0 88.5 -25t63.5 -69zM1248 567q-17 -160 -72 -311q-17 131 -63 246q25 174 -5 361q-27 178 -94 342 q114 -90 212 -211q9 -37 15 -80q26 -179 7 -347zM1520 1440q9 -17 23.5 -49.5t43.5 -117.5t50.5 -178t34 -227.5t5 -269t-47 -300t-112.5 -323.5q-22 -48 -66 -75.5t-95 -27.5q-39 0 -74 16q-67 31 -92.5 100t4.5 136q58 126 90 257.5t37.5 239.5t-3.5 213.5t-26.5 180.5 t-38.5 138.5t-32.5 90t-15.5 32.5q-34 65 -11.5 135.5t87.5 104.5q37 20 81 20q49 0 91.5 -25.5t66.5 -70.5z" />
|
||||
<glyph unicode="" horiz-adv-x="1792" d="M441 864q32 0 52 -26q266 -364 362 -774h-446q-127 441 -367 749q-12 16 -3 33.5t29 17.5h373zM1000 507q-49 -199 -125 -393q-79 310 -256 594q40 221 44 449q211 -340 337 -650zM1099 1216q235 -324 384.5 -698.5t184.5 -773.5h-451q-41 665 -553 1472h435zM1792 640 q0 -424 -101 -812q-67 560 -359 1083q-25 301 -106 584q-4 16 5.5 28.5t25.5 12.5h359q21 0 38.5 -13t22.5 -33q115 -409 115 -850z" />
|
||||
<glyph unicode="" horiz-adv-x="2304" d="M1975 546h-138q14 37 66 179l3 9q4 10 10 26t9 26l12 -55zM531 611l-58 295q-11 54 -75 54h-268l-2 -13q311 -79 403 -336zM710 960l-162 -438l-17 89q-26 70 -85 129.5t-131 88.5l135 -510h175l261 641h-176zM849 318h166l104 642h-166zM1617 944q-69 27 -149 27 q-123 0 -201 -59t-79 -153q-1 -102 145 -174q48 -23 67 -41t19 -39q0 -30 -30 -46t-69 -16q-86 0 -156 33l-22 11l-23 -144q74 -34 185 -34q130 -1 208.5 59t80.5 160q0 106 -140 174q-49 25 -71 42t-22 38q0 22 24.5 38.5t70.5 16.5q70 1 124 -24l15 -8zM2042 960h-128 q-65 0 -87 -54l-246 -588h174l35 96h212q5 -22 20 -96h154zM2304 1280v-1280q0 -52 -38 -90t-90 -38h-2048q-52 0 -90 38t-38 90v1280q0 52 38 90t90 38h2048q52 0 90 -38t38 -90z" />
|
||||
<glyph unicode="" horiz-adv-x="2304" d="M671 603h-13q-47 0 -47 -32q0 -22 20 -22q17 0 28 15t12 39zM1066 639h62v3q1 4 0.5 6.5t-1 7t-2 8t-4.5 6.5t-7.5 5t-11.5 2q-28 0 -36 -38zM1606 603h-12q-48 0 -48 -32q0 -22 20 -22q17 0 28 15t12 39zM1925 629q0 41 -30 41q-19 0 -31 -20t-12 -51q0 -42 28 -42 q20 0 32.5 20t12.5 52zM480 770h87l-44 -262h-56l32 201l-71 -201h-39l-4 200l-34 -200h-53l44 262h81l2 -163zM733 663q0 -6 -4 -42q-16 -101 -17 -113h-47l1 22q-20 -26 -58 -26q-23 0 -37.5 16t-14.5 42q0 39 26 60.5t73 21.5q14 0 23 -1q0 3 0.5 5.5t1 4.5t0.5 3 q0 20 -36 20q-29 0 -59 -10q0 4 7 48q38 11 67 11q74 0 74 -62zM889 721l-8 -49q-22 3 -41 3q-27 0 -27 -17q0 -8 4.5 -12t21.5 -11q40 -19 40 -60q0 -72 -87 -71q-34 0 -58 6q0 2 7 49q29 -8 51 -8q32 0 32 19q0 7 -4.5 11.5t-21.5 12.5q-43 20 -43 59q0 72 84 72 q30 0 50 -4zM977 721h28l-7 -52h-29q-2 -17 -6.5 -40.5t-7 -38.5t-2.5 -18q0 -16 19 -16q8 0 16 2l-8 -47q-21 -7 -40 -7q-43 0 -45 47q0 12 8 56q3 20 25 146h55zM1180 648q0 -23 -7 -52h-111q-3 -22 10 -33t38 -11q30 0 58 14l-9 -54q-30 -8 -57 -8q-95 0 -95 95 q0 55 27.5 90.5t69.5 35.5q35 0 55.5 -21t20.5 -56zM1319 722q-13 -23 -22 -62q-22 2 -31 -24t-25 -128h-56l3 14q22 130 29 199h51l-3 -33q14 21 25.5 29.5t28.5 4.5zM1506 763l-9 -57q-28 14 -50 14q-31 0 -51 -27.5t-20 -70.5q0 -30 13.5 -47t38.5 -17q21 0 48 13 l-10 -59q-28 -8 -50 -8q-45 0 -71.5 30.5t-26.5 82.5q0 70 35.5 114.5t91.5 44.5q26 0 61 -13zM1668 663q0 -18 -4 -42q-13 -79 -17 -113h-46l1 22q-20 -26 -59 -26q-23 0 -37 16t-14 42q0 39 25.5 60.5t72.5 21.5q15 0 23 -1q2 7 2 13q0 20 -36 20q-29 0 -59 -10q0 4 8 48 q38 11 67 11q73 0 73 -62zM1809 722q-14 -24 -21 -62q-23 2 -31.5 -23t-25.5 -129h-56l3 14q19 104 29 199h52q0 -11 -4 -33q15 21 26.5 29.5t27.5 4.5zM1950 770h56l-43 -262h-53l3 19q-23 -23 -52 -23q-31 0 -49.5 24t-18.5 64q0 53 27.5 92t64.5 39q31 0 53 -29z M2061 640q0 148 -72.5 273t-198 198t-273.5 73q-181 0 -328 -110q127 -116 171 -284h-50q-44 150 -158 253q-114 -103 -158 -253h-50q44 168 171 284q-147 110 -328 110q-148 0 -273.5 -73t-198 -198t-72.5 -273t72.5 -273t198 -198t273.5 -73q181 0 328 110 q-120 111 -165 264h50q46 -138 152 -233q106 95 152 233h50q-45 -153 -165 -264q147 -110 328 -110q148 0 273.5 73t198 198t72.5 273zM2304 1280v-1280q0 -52 -38 -90t-90 -38h-2048q-52 0 -90 38t-38 90v1280q0 52 38 90t90 38h2048q52 0 90 -38t38 -90z" />
|
||||
<glyph unicode="" horiz-adv-x="2304" d="M313 759q0 -51 -36 -84q-29 -26 -89 -26h-17v220h17q61 0 89 -27q36 -31 36 -83zM2089 824q0 -52 -64 -52h-19v101h20q63 0 63 -49zM380 759q0 74 -50 120.5t-129 46.5h-95v-333h95q74 0 119 38q60 51 60 128zM410 593h65v333h-65v-333zM730 694q0 40 -20.5 62t-75.5 42 q-29 10 -39.5 19t-10.5 23q0 16 13.5 26.5t34.5 10.5q29 0 53 -27l34 44q-41 37 -98 37q-44 0 -74 -27.5t-30 -67.5q0 -35 18 -55.5t64 -36.5q37 -13 45 -19q19 -12 19 -34q0 -20 -14 -33.5t-36 -13.5q-48 0 -71 44l-42 -40q44 -64 115 -64q51 0 83 30.5t32 79.5zM1008 604 v77q-37 -37 -78 -37q-49 0 -80.5 32.5t-31.5 82.5q0 48 31.5 81.5t77.5 33.5q43 0 81 -38v77q-40 20 -80 20q-74 0 -125.5 -50.5t-51.5 -123.5t51 -123.5t125 -50.5q42 0 81 19zM2240 0v527q-65 -40 -144.5 -84t-237.5 -117t-329.5 -137.5t-417.5 -134.5t-504 -118h1569 q26 0 45 19t19 45zM1389 757q0 75 -53 128t-128 53t-128 -53t-53 -128t53 -128t128 -53t128 53t53 128zM1541 584l144 342h-71l-90 -224l-89 224h-71l142 -342h35zM1714 593h184v56h-119v90h115v56h-115v74h119v57h-184v-333zM2105 593h80l-105 140q76 16 76 94q0 47 -31 73 t-87 26h-97v-333h65v133h9zM2304 1274v-1268q0 -56 -38.5 -95t-93.5 -39h-2040q-55 0 -93.5 39t-38.5 95v1268q0 56 38.5 95t93.5 39h2040q55 0 93.5 -39t38.5 -95z" />
|
||||
|
|
@ -626,7 +626,7 @@
|
|||
<glyph unicode="" horiz-adv-x="2304" d="M0 32v608h2304v-608q0 -66 -47 -113t-113 -47h-1984q-66 0 -113 47t-47 113zM640 256v-128h384v128h-384zM256 256v-128h256v128h-256zM2144 1408q66 0 113 -47t47 -113v-224h-2304v224q0 66 47 113t113 47h1984z" />
|
||||
<glyph unicode="" horiz-adv-x="1792" d="M1549 857q55 0 85.5 -28.5t30.5 -83.5t-34 -82t-91 -27h-136v-177h-25v398h170zM1710 267l-4 -11l-5 -10q-113 -230 -330.5 -366t-474.5 -136q-182 0 -348 71t-286 191t-191 286t-71 348t71 348t191 286t286 191t348 71q244 0 454.5 -124t329.5 -338l2 -4l8 -16 q-30 -15 -136.5 -68.5t-163.5 -84.5q-6 -3 -479 -268q384 -183 799 -366zM896 -234q250 0 462.5 132.5t322.5 357.5l-287 129q-72 -140 -206 -222t-292 -82q-151 0 -280 75t-204 204t-75 280t75 280t204 204t280 75t280 -73.5t204 -204.5l280 143q-116 208 -321 329 t-443 121q-119 0 -232.5 -31.5t-209 -87.5t-176.5 -137t-137 -176.5t-87.5 -209t-31.5 -232.5t31.5 -232.5t87.5 -209t137 -176.5t176.5 -137t209 -87.5t232.5 -31.5z" />
|
||||
<glyph unicode="" horiz-adv-x="1792" d="M1427 827l-614 386l92 151h855zM405 562l-184 116v858l1183 -743zM1424 697l147 -95v-858l-532 335zM1387 718l-500 -802h-855l356 571z" />
|
||||
<glyph unicode="" horiz-adv-x="1792" d="M640 528v224q0 16 -16 16h-96q-16 0 -16 -16v-224q0 -16 16 -16h96q16 0 16 16zM1152 528v224q0 16 -16 16h-96q-16 0 -16 -16v-224q0 -16 16 -16h96q16 0 16 16zM1664 496v-752h-640v320q0 80 -56 136t-136 56t-136 -56t-56 -136v-320h-640v752q0 16 16 16h96 q16 0 16 -16v-112h128v624q0 16 16 16h96q16 0 16 -16v-112h128v112q0 16 16 16h96q16 0 16 -16v-112h128v112q0 16 16 16h16v393q-32 19 -32 55q0 26 19 45t45 19t45 -19t19 -45q0 -36 -32 -55v-9h272q16 0 16 -16v-224q0 -16 -16 -16h-272v-128h16q16 0 16 -16v-112h128 v112q0 16 16 16h96q16 0 16 -16v-112h128v112q0 16 16 16h96q16 0 16 -16v-624h128v112q0 16 16 16h96q16 0 16 -16z" />
|
||||
<glyph unicode="" horiz-adv-x="1792" d="M640 528v224q0 16 -16 16h-96q-16 0 -16 -16v-224q0 -16 16 -16h96q16 0 16 16zM1152 528v224q0 16 -16 16h-96q-16 0 -16 -16v-224q0 -16 16 -16h96q16 0 16 16zM1664 496v-752h-640v320q0 80 -56 136t-136 56t-136 -56t-56 -136v-320h-640v752q0 16 16 16h96 q16 0 16 -16v-112h128v624q0 16 16 16h96q16 0 16 -16v-112h128v112q0 16 16 16h96q16 0 16 -16v-112h128v112q0 6 2.5 9.5t8.5 5t9.5 2t11.5 0t9 -0.5v391q-32 15 -32 50q0 23 16.5 39t38.5 16t38.5 -16t16.5 -39q0 -35 -32 -50v-17q45 10 83 10q21 0 59.5 -7.5t54.5 -7.5 q17 0 47 7.5t37 7.5q16 0 16 -16v-210q0 -15 -35 -21.5t-62 -6.5q-18 0 -54.5 7.5t-55.5 7.5q-40 0 -90 -12v-133q1 0 9 0.5t11.5 0t9.5 -2t8.5 -5t2.5 -9.5v-112h128v112q0 16 16 16h96q16 0 16 -16v-112h128v112q0 16 16 16h96q16 0 16 -16v-624h128v112q0 16 16 16h96 q16 0 16 -16z" />
|
||||
<glyph unicode="" horiz-adv-x="2304" d="M2288 731q16 -8 16 -27t-16 -27l-320 -192q-8 -5 -16 -5q-9 0 -16 4q-16 10 -16 28v128h-858q37 -58 83 -165q16 -37 24.5 -55t24 -49t27 -47t27 -34t31.5 -26t33 -8h96v96q0 14 9 23t23 9h320q14 0 23 -9t9 -23v-320q0 -14 -9 -23t-23 -9h-320q-14 0 -23 9t-9 23v96h-96 q-32 0 -61 10t-51 23.5t-45 40.5t-37 46t-33.5 57t-28.5 57.5t-28 60.5q-23 53 -37 81.5t-36 65t-44.5 53.5t-46.5 17h-360q-22 -84 -91 -138t-157 -54q-106 0 -181 75t-75 181t75 181t181 75q88 0 157 -54t91 -138h104q24 0 46.5 17t44.5 53.5t36 65t37 81.5q19 41 28 60.5 t28.5 57.5t33.5 57t37 46t45 40.5t51 23.5t61 10h107q21 57 70 92.5t111 35.5q80 0 136 -56t56 -136t-56 -136t-136 -56q-62 0 -111 35.5t-70 92.5h-107q-17 0 -33 -8t-31.5 -26t-27 -34t-27 -47t-24 -49t-24.5 -55q-46 -107 -83 -165h1114v128q0 18 16 28t32 -1z" />
|
||||
<glyph unicode="" horiz-adv-x="1792" d="M1150 774q0 -56 -39.5 -95t-95.5 -39h-253v269h253q56 0 95.5 -39.5t39.5 -95.5zM1329 774q0 130 -91.5 222t-222.5 92h-433v-896h180v269h253q130 0 222 91.5t92 221.5zM1792 640q0 -182 -71 -348t-191 -286t-286 -191t-348 -71t-348 71t-286 191t-191 286t-71 348 t71 348t191 286t286 191t348 71t348 -71t286 -191t191 -286t71 -348z" />
|
||||
<glyph unicode="" horiz-adv-x="2304" d="M1645 438q0 59 -34 106.5t-87 68.5q-7 -45 -23 -92q-7 -24 -27.5 -38t-44.5 -14q-12 0 -24 3q-31 10 -45 38.5t-4 58.5q23 71 23 143q0 123 -61 227.5t-166 165.5t-228 61q-134 0 -247 -73t-167 -194q108 -28 188 -106q22 -23 22 -55t-22 -54t-54 -22t-55 22 q-75 75 -180 75q-106 0 -181 -74.5t-75 -180.5t75 -180.5t181 -74.5h1046q79 0 134.5 55.5t55.5 133.5zM1798 438q0 -142 -100.5 -242t-242.5 -100h-1046q-169 0 -289 119.5t-120 288.5q0 153 100 267t249 136q62 184 221 298t354 114q235 0 408.5 -158.5t196.5 -389.5 q116 -25 192.5 -118.5t76.5 -214.5zM2048 438q0 -175 -97 -319q-23 -33 -64 -33q-24 0 -43 13q-26 17 -32 48.5t12 57.5q71 104 71 233t-71 233q-18 26 -12 57t32 49t57.5 11.5t49.5 -32.5q97 -142 97 -318zM2304 438q0 -244 -134 -443q-23 -34 -64 -34q-23 0 -42 13 q-26 18 -32.5 49t11.5 57q108 164 108 358q0 195 -108 357q-18 26 -11.5 57.5t32.5 48.5q26 18 57 12t49 -33q134 -198 134 -442z" />
|
||||
|
|
@ -641,15 +641,45 @@
|
|||
<glyph unicode="" d="M841 483l148 -148l-149 -149zM840 1094l149 -149l-148 -148zM710 -130l464 464l-306 306l306 306l-464 464v-611l-255 255l-93 -93l320 -321l-320 -321l93 -93l255 255v-611zM1429 640q0 -209 -32 -365.5t-87.5 -257t-140.5 -162.5t-181.5 -86.5t-219.5 -24.5 t-219.5 24.5t-181.5 86.5t-140.5 162.5t-87.5 257t-32 365.5t32 365.5t87.5 257t140.5 162.5t181.5 86.5t219.5 24.5t219.5 -24.5t181.5 -86.5t140.5 -162.5t87.5 -257t32 -365.5z" />
|
||||
<glyph unicode="" horiz-adv-x="1024" d="M596 113l173 172l-173 172v-344zM596 823l173 172l-173 172v-344zM628 640l356 -356l-539 -540v711l-297 -296l-108 108l372 373l-372 373l108 108l297 -296v711l539 -540z" />
|
||||
<glyph unicode="" d="M1280 256q0 52 -38 90t-90 38t-90 -38t-38 -90t38 -90t90 -38t90 38t38 90zM512 1024q0 52 -38 90t-90 38t-90 -38t-38 -90t38 -90t90 -38t90 38t38 90zM1536 256q0 -159 -112.5 -271.5t-271.5 -112.5t-271.5 112.5t-112.5 271.5t112.5 271.5t271.5 112.5t271.5 -112.5 t112.5 -271.5zM1440 1344q0 -20 -13 -38l-1056 -1408q-19 -26 -51 -26h-160q-26 0 -45 19t-19 45q0 20 13 38l1056 1408q19 26 51 26h160q26 0 45 -19t19 -45zM768 1024q0 -159 -112.5 -271.5t-271.5 -112.5t-271.5 112.5t-112.5 271.5t112.5 271.5t271.5 112.5 t271.5 -112.5t112.5 -271.5z" />
|
||||
<glyph unicode="" horiz-adv-x="1792" />
|
||||
<glyph unicode="" horiz-adv-x="1792" />
|
||||
<glyph unicode="" horiz-adv-x="1792" />
|
||||
<glyph unicode="" horiz-adv-x="1792" />
|
||||
<glyph unicode="" horiz-adv-x="1792" />
|
||||
<glyph unicode="" horiz-adv-x="1792" />
|
||||
<glyph unicode="" horiz-adv-x="1792" />
|
||||
<glyph unicode="" horiz-adv-x="1792" />
|
||||
<glyph unicode="" horiz-adv-x="1792" />
|
||||
<glyph unicode="" horiz-adv-x="1792" d="M104 830l792 -1015l-868 630q-18 13 -25 34.5t0 42.5l101 308v0zM566 830h660l-330 -1015v0zM368 1442l198 -612h-462l198 612q8 23 33 23t33 -23zM1688 830l101 -308q7 -21 0 -42.5t-25 -34.5l-868 -630l792 1015v0zM1688 830h-462l198 612q8 23 33 23t33 -23z" />
|
||||
<glyph unicode="" horiz-adv-x="1792" d="M384 704h160v224h-160v-224zM1221 372v92q-104 -36 -243 -38q-135 -1 -259.5 46.5t-220.5 122.5l1 -96q88 -80 212 -128.5t272 -47.5q129 0 238 49zM640 704h640v224h-640v-224zM1792 736q0 -187 -99 -352q89 -102 89 -229q0 -157 -129.5 -268t-313.5 -111 q-122 0 -225 52.5t-161 140.5q-19 -1 -57 -1t-57 1q-58 -88 -161 -140.5t-225 -52.5q-184 0 -313.5 111t-129.5 268q0 127 89 229q-99 165 -99 352q0 209 120 385.5t326.5 279.5t449.5 103t449.5 -103t326.5 -279.5t120 -385.5z" />
|
||||
<glyph unicode="" d="M515 625v-128h-252v128h252zM515 880v-127h-252v127h252zM1273 369v-128h-341v128h341zM1273 625v-128h-672v128h672zM1273 880v-127h-672v127h672zM1408 20v1240q0 8 -6 14t-14 6h-32l-378 -256l-210 171l-210 -171l-378 256h-32q-8 0 -14 -6t-6 -14v-1240q0 -8 6 -14 t14 -6h1240q8 0 14 6t6 14zM553 1130l185 150h-406zM983 1130l221 150h-406zM1536 1260v-1240q0 -62 -43 -105t-105 -43h-1240q-62 0 -105 43t-43 105v1240q0 62 43 105t105 43h1240q62 0 105 -43t43 -105z" />
|
||||
<glyph unicode="" horiz-adv-x="1792" d="M896 720q-104 196 -160 278q-139 202 -347 318q-34 19 -70 36q-89 40 -94 32t34 -38l39 -31q62 -43 112.5 -93.5t94.5 -116.5t70.5 -113t70.5 -131q9 -17 13 -25q44 -84 84 -153t98 -154t115.5 -150t131 -123.5t148.5 -90.5q153 -66 154 -60q1 3 -49 37q-53 36 -81 57 q-77 58 -179 211t-185 310zM549 177q-76 60 -132.5 125t-98 143.5t-71 154.5t-58.5 186t-52 209t-60.5 252t-76.5 289q273 0 497.5 -36t379 -92t271 -144.5t185.5 -172.5t110 -198.5t56 -199.5t12.5 -198.5t-9.5 -173t-20 -143.5t-13 -107l323 -327h-104l-281 285 q-22 -2 -91.5 -14t-121.5 -19t-138 -6t-160.5 17t-167.5 59t-179 111z" />
|
||||
<glyph unicode="" horiz-adv-x="1792" d="M1374 879q-6 26 -28.5 39.5t-48.5 7.5q-261 -62 -401 -62t-401 62q-26 6 -48.5 -7.5t-28.5 -39.5t7.5 -48.5t39.5 -28.5q194 -46 303 -58q-2 -158 -15.5 -269t-26.5 -155.5t-41 -115.5l-9 -21q-10 -25 1 -49t36 -34q9 -4 23 -4q44 0 60 41l8 20q54 139 71 259h42 q17 -120 71 -259l8 -20q16 -41 60 -41q14 0 23 4q25 10 36 34t1 49l-9 21q-28 71 -41 115.5t-26.5 155.5t-15.5 269q109 12 303 58q26 6 39.5 28.5t7.5 48.5zM1024 1024q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5z M1600 640q0 -143 -55.5 -273.5t-150 -225t-225 -150t-273.5 -55.5t-273.5 55.5t-225 150t-150 225t-55.5 273.5t55.5 273.5t150 225t225 150t273.5 55.5t273.5 -55.5t225 -150t150 -225t55.5 -273.5zM896 1408q-156 0 -298 -61t-245 -164t-164 -245t-61 -298t61 -298 t164 -245t245 -164t298 -61t298 61t245 164t164 245t61 298t-61 298t-164 245t-245 164t-298 61zM1792 640q0 -182 -71 -348t-191 -286t-286 -191t-348 -71t-348 71t-286 191t-191 286t-71 348t71 348t191 286t286 191t348 71t348 -71t286 -191t191 -286t71 -348z" />
|
||||
<glyph unicode="" d="M1438 723q34 -35 29 -82l-44 -551q-4 -42 -34.5 -70t-71.5 -28q-6 0 -9 1q-44 3 -72.5 36.5t-25.5 77.5l35 429l-143 -8q55 -113 55 -240q0 -216 -148 -372l-137 137q91 101 91 235q0 145 -102.5 248t-247.5 103q-134 0 -236 -92l-137 138q120 114 284 141l264 300 l-149 87l-181 -161q-33 -30 -77 -27.5t-73 35.5t-26.5 77t34.5 73l239 213q26 23 60 26.5t64 -14.5l488 -283q36 -21 48 -68q17 -67 -26 -117l-205 -232l371 20q49 3 83 -32zM1240 1180q-74 0 -126 52t-52 126t52 126t126 52t126.5 -52t52.5 -126t-52.5 -126t-126.5 -52z M613 -62q106 0 196 61l139 -139q-146 -116 -335 -116q-148 0 -273.5 73t-198.5 198t-73 273q0 188 116 336l139 -139q-60 -88 -60 -197q0 -145 102.5 -247.5t247.5 -102.5z" />
|
||||
<glyph unicode="" d="M880 336v-160q0 -14 -9 -23t-23 -9h-160q-14 0 -23 9t-9 23v160q0 14 9 23t23 9h160q14 0 23 -9t9 -23zM1136 832q0 -50 -15 -90t-45.5 -69t-52 -44t-59.5 -36q-32 -18 -46.5 -28t-26 -24t-11.5 -29v-32q0 -14 -9 -23t-23 -9h-160q-14 0 -23 9t-9 23v68q0 35 10.5 64.5 t24 47.5t39 35.5t41 25.5t44.5 21q53 25 75 43t22 49q0 42 -43.5 71.5t-95.5 29.5q-56 0 -95 -27q-29 -20 -80 -83q-9 -12 -25 -12q-11 0 -19 6l-108 82q-10 7 -12 20t5 23q122 192 349 192q129 0 238.5 -89.5t109.5 -214.5zM768 1280q-130 0 -248.5 -51t-204 -136.5 t-136.5 -204t-51 -248.5t51 -248.5t136.5 -204t204 -136.5t248.5 -51t248.5 51t204 136.5t136.5 204t51 248.5t-51 248.5t-136.5 204t-204 136.5t-248.5 51zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5 t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
|
||||
<glyph unicode="" horiz-adv-x="1408" d="M366 1225q-64 0 -110 45.5t-46 110.5q0 64 46 109.5t110 45.5t109.5 -45.5t45.5 -109.5q0 -65 -45.5 -110.5t-109.5 -45.5zM917 583q0 -50 -30 -67.5t-63.5 -6.5t-47.5 34l-367 438q-7 12 -14 15.5t-11 1.5l-3 -3q-7 -8 4 -21l122 -139l1 -354l-161 -457 q-67 -192 -92 -234q-16 -26 -28 -32q-50 -26 -103 -1q-29 13 -41.5 43t-9.5 57q2 17 197 618l5 416l-85 -164l35 -222q4 -24 -1 -42t-14 -27.5t-19 -16t-17 -7.5l-7 -2q-19 -3 -34.5 3t-24 16t-14 22t-7.5 19.5t-2 9.5l-46 299l211 381q23 34 113 34q75 0 107 -40l424 -521 q7 -5 14 -17l3 -3l-1 -1q7 -13 7 -29zM514 433q43 -113 88.5 -225t69.5 -168l24 -55q36 -93 42 -125q11 -70 -36 -97q-35 -22 -66 -16t-51 22t-29 35h-1q-6 16 -8 25l-124 351zM1338 -159q31 -49 31 -57q0 -5 -3 -7q-9 -5 -14.5 0.5t-15.5 26t-16 30.5q-114 172 -423 661 q3 -1 7 1t7 4l3 2q11 9 11 17z" />
|
||||
<glyph unicode="" horiz-adv-x="2304" d="M504 542h171l-1 265zM1530 641q0 87 -50.5 140t-146.5 53h-54v-388h52q91 0 145 57t54 138zM956 1018l1 -756q0 -14 -9.5 -24t-23.5 -10h-216q-14 0 -23.5 10t-9.5 24v62h-291l-55 -81q-10 -15 -28 -15h-267q-21 0 -30.5 18t3.5 35l556 757q9 14 27 14h332q14 0 24 -10 t10 -24zM1783 641q0 -193 -125.5 -303t-324.5 -110h-270q-14 0 -24 10t-10 24v756q0 14 10 24t24 10h268q200 0 326 -109t126 -302zM1939 640q0 -11 -0.5 -29t-8 -71.5t-21.5 -102t-44.5 -108t-73.5 -102.5h-51q38 45 66.5 104.5t41.5 112t21 98t9 72.5l1 27q0 8 -0.5 22.5 t-7.5 60t-20 91.5t-41 111.5t-66 124.5h43q41 -47 72 -107t45.5 -111.5t23 -96t10.5 -70.5zM2123 640q0 -11 -0.5 -29t-8 -71.5t-21.5 -102t-45 -108t-74 -102.5h-51q38 45 66.5 104.5t41.5 112t21 98t9 72.5l1 27q0 8 -0.5 22.5t-7.5 60t-19.5 91.5t-40.5 111.5t-66 124.5 h43q41 -47 72 -107t45.5 -111.5t23 -96t10.5 -70.5zM2304 640q0 -11 -0.5 -29t-8 -71.5t-21.5 -102t-44.5 -108t-73.5 -102.5h-51q38 45 66 104.5t41 112t21 98t9 72.5l1 27q0 8 -0.5 22.5t-7.5 60t-19.5 91.5t-40.5 111.5t-66 124.5h43q41 -47 72 -107t45.5 -111.5t23 -96 t9.5 -70.5z" />
|
||||
<glyph unicode="" horiz-adv-x="1408" d="M617 -153q0 11 -13 58t-31 107t-20 69q-1 4 -5 26.5t-8.5 36t-13.5 21.5q-15 14 -51 14q-23 0 -70 -5.5t-71 -5.5q-34 0 -47 11q-6 5 -11 15.5t-7.5 20t-6.5 24t-5 18.5q-37 128 -37 255t37 255q1 4 5 18.5t6.5 24t7.5 20t11 15.5q13 11 47 11q24 0 71 -5.5t70 -5.5 q36 0 51 14q9 8 13.5 21.5t8.5 36t5 26.5q2 9 20 69t31 107t13 58q0 22 -43.5 52.5t-75.5 42.5q-20 8 -45 8q-34 0 -98 -18q-57 -17 -96.5 -40.5t-71 -66t-46 -70t-45.5 -94.5q-6 -12 -9 -19q-49 -107 -68 -216t-19 -244t19 -244t68 -216q56 -122 83 -161q63 -91 179 -127 l6 -2q64 -18 98 -18q25 0 45 8q32 12 75.5 42.5t43.5 52.5zM776 760q-26 0 -45 19t-19 45.5t19 45.5q37 37 37 90q0 52 -37 91q-19 19 -19 45t19 45t45 19t45 -19q75 -75 75 -181t-75 -181q-21 -19 -45 -19zM957 579q-27 0 -45 19q-19 19 -19 45t19 45q112 114 112 272 t-112 272q-19 19 -19 45t19 45t45 19t45 -19q150 -150 150 -362t-150 -362q-18 -19 -45 -19zM1138 398q-27 0 -45 19q-19 19 -19 45t19 45q90 91 138.5 208t48.5 245t-48.5 245t-138.5 208q-19 19 -19 45t19 45t45 19t45 -19q109 -109 167 -249t58 -294t-58 -294t-167 -249 q-18 -19 -45 -19z" />
|
||||
<glyph unicode="" horiz-adv-x="2176" d="M192 352q-66 0 -113 -47t-47 -113t47 -113t113 -47t113 47t47 113t-47 113t-113 47zM704 352q-66 0 -113 -47t-47 -113t47 -113t113 -47t113 47t47 113t-47 113t-113 47zM704 864q-66 0 -113 -47t-47 -113t47 -113t113 -47t113 47t47 113t-47 113t-113 47zM1472 352 q-66 0 -113 -47t-47 -113t47 -113t113 -47t113 47t47 113t-47 113t-113 47zM1984 352q-66 0 -113 -47t-47 -113t47 -113t113 -47t113 47t47 113t-47 113t-113 47zM1472 864q-66 0 -113 -47t-47 -113t47 -113t113 -47t113 47t47 113t-47 113t-113 47zM1984 864 q-66 0 -113 -47t-47 -113t47 -113t113 -47t113 47t47 113t-47 113t-113 47zM1984 1376q-66 0 -113 -47t-47 -113t47 -113t113 -47t113 47t47 113t-47 113t-113 47zM384 192q0 -80 -56 -136t-136 -56t-136 56t-56 136t56 136t136 56t136 -56t56 -136zM896 192q0 -80 -56 -136 t-136 -56t-136 56t-56 136t56 136t136 56t136 -56t56 -136zM384 704q0 -80 -56 -136t-136 -56t-136 56t-56 136t56 136t136 56t136 -56t56 -136zM896 704q0 -80 -56 -136t-136 -56t-136 56t-56 136t56 136t136 56t136 -56t56 -136zM384 1216q0 -80 -56 -136t-136 -56 t-136 56t-56 136t56 136t136 56t136 -56t56 -136zM1664 192q0 -80 -56 -136t-136 -56t-136 56t-56 136t56 136t136 56t136 -56t56 -136zM896 1216q0 -80 -56 -136t-136 -56t-136 56t-56 136t56 136t136 56t136 -56t56 -136zM2176 192q0 -80 -56 -136t-136 -56t-136 56 t-56 136t56 136t136 56t136 -56t56 -136zM1664 704q0 -80 -56 -136t-136 -56t-136 56t-56 136t56 136t136 56t136 -56t56 -136zM2176 704q0 -80 -56 -136t-136 -56t-136 56t-56 136t56 136t136 56t136 -56t56 -136zM1664 1216q0 -80 -56 -136t-136 -56t-136 56t-56 136 t56 136t136 56t136 -56t56 -136zM2176 1216q0 -80 -56 -136t-136 -56t-136 56t-56 136t56 136t136 56t136 -56t56 -136z" />
|
||||
<glyph unicode="" horiz-adv-x="1792" d="M128 -192q0 -26 -19 -45t-45 -19t-45 19t-19 45t19 45t45 19t45 -19t19 -45zM320 0q0 -26 -19 -45t-45 -19t-45 19t-19 45t19 45t45 19t45 -19t19 -45zM365 365l256 -256l-90 -90l-256 256zM704 384q0 -26 -19 -45t-45 -19t-45 19t-19 45t19 45t45 19t45 -19t19 -45z M1411 704q0 -59 -11.5 -108.5t-37.5 -93.5t-44 -67.5t-53 -64.5q-31 -35 -45.5 -54t-33.5 -50t-26.5 -64t-7.5 -74q0 -159 -112.5 -271.5t-271.5 -112.5q-26 0 -45 19t-19 45t19 45t45 19q106 0 181 75t75 181q0 57 11.5 105.5t37 91t43.5 66.5t52 63q40 46 59.5 72 t37.5 74.5t18 103.5q0 185 -131.5 316.5t-316.5 131.5t-316.5 -131.5t-131.5 -316.5q0 -26 -19 -45t-45 -19t-45 19t-19 45q0 117 45.5 223.5t123 184t184 123t223.5 45.5t223.5 -45.5t184 -123t123 -184t45.5 -223.5zM896 576q0 -26 -19 -45t-45 -19t-45 19t-19 45t19 45 t45 19t45 -19t19 -45zM1184 704q0 -26 -19 -45t-45 -19t-45 19t-19 45q0 93 -65.5 158.5t-158.5 65.5q-92 0 -158 -65.5t-66 -158.5q0 -26 -19 -45t-45 -19t-45 19t-19 45q0 146 103 249t249 103t249 -103t103 -249zM1578 993q10 -25 -1 -49t-36 -34q-9 -4 -23 -4 q-19 0 -35.5 11t-23.5 30q-68 178 -224 295q-21 16 -25 42t12 47q17 21 43 25t47 -12q183 -137 266 -351zM1788 1074q9 -25 -1.5 -49t-35.5 -34q-11 -4 -23 -4q-44 0 -60 41q-92 238 -297 393q-22 16 -25.5 42t12.5 47q16 22 42 25.5t47 -12.5q235 -175 341 -449z" />
|
||||
<glyph unicode="" horiz-adv-x="2304" d="M1032 576q-59 2 -84 55q-17 34 -48 53.5t-68 19.5q-53 0 -90.5 -37.5t-37.5 -90.5q0 -56 36 -89l10 -8q34 -31 82 -31q37 0 68 19.5t48 53.5q25 53 84 55zM1600 704q0 56 -36 89l-10 8q-34 31 -82 31q-37 0 -68 -19.5t-48 -53.5q-25 -53 -84 -55q59 -2 84 -55 q17 -34 48 -53.5t68 -19.5q53 0 90.5 37.5t37.5 90.5zM1174 925q-17 -35 -55 -48t-73 4q-62 31 -134 31q-51 0 -99 -17q3 0 9.5 0.5t9.5 0.5q92 0 170.5 -50t118.5 -133q17 -36 3.5 -73.5t-49.5 -54.5q-18 -9 -39 -9q21 0 39 -9q36 -17 49.5 -54.5t-3.5 -73.5 q-40 -83 -118.5 -133t-170.5 -50h-6q-16 2 -44 4l-290 27l-239 -120q-14 -7 -29 -7q-40 0 -57 35l-160 320q-11 23 -4 47.5t29 37.5l209 119l148 267q17 155 91.5 291.5t195.5 236.5q31 25 70.5 21.5t64.5 -34.5t21.5 -70t-34.5 -65q-70 -59 -117 -128q123 84 267 101 q40 5 71.5 -19t35.5 -64q5 -40 -19 -71.5t-64 -35.5q-84 -10 -159 -55q46 10 99 10q115 0 218 -50q36 -18 49 -55.5t-5 -73.5zM2137 1085l160 -320q11 -23 4 -47.5t-29 -37.5l-209 -119l-148 -267q-17 -155 -91.5 -291.5t-195.5 -236.5q-26 -22 -61 -22q-45 0 -74 35 q-25 31 -21.5 70t34.5 65q70 59 117 128q-123 -84 -267 -101q-4 -1 -12 -1q-36 0 -63.5 24t-31.5 60q-5 40 19 71.5t64 35.5q84 10 159 55q-46 -10 -99 -10q-115 0 -218 50q-36 18 -49 55.5t5 73.5q17 35 55 48t73 -4q62 -31 134 -31q51 0 99 17q-3 0 -9.5 -0.5t-9.5 -0.5 q-92 0 -170.5 50t-118.5 133q-17 36 -3.5 73.5t49.5 54.5q18 9 39 9q-21 0 -39 9q-36 17 -49.5 54.5t3.5 73.5q40 83 118.5 133t170.5 50h6h1q14 -2 42 -4l291 -27l239 120q14 7 29 7q40 0 57 -35z" />
|
||||
<glyph unicode="" horiz-adv-x="1792" d="M1056 704q0 -26 19 -45t45 -19t45 19t19 45q0 146 -103 249t-249 103t-249 -103t-103 -249q0 -26 19 -45t45 -19t45 19t19 45q0 93 66 158.5t158 65.5t158 -65.5t66 -158.5zM835 1280q-117 0 -223.5 -45.5t-184 -123t-123 -184t-45.5 -223.5q0 -26 19 -45t45 -19t45 19 t19 45q0 185 131.5 316.5t316.5 131.5t316.5 -131.5t131.5 -316.5q0 -55 -18 -103.5t-37.5 -74.5t-59.5 -72q-34 -39 -52 -63t-43.5 -66.5t-37 -91t-11.5 -105.5q0 -106 -75 -181t-181 -75q-26 0 -45 -19t-19 -45t19 -45t45 -19q159 0 271.5 112.5t112.5 271.5q0 41 7.5 74 t26.5 64t33.5 50t45.5 54q35 41 53 64.5t44 67.5t37.5 93.5t11.5 108.5q0 117 -45.5 223.5t-123 184t-184 123t-223.5 45.5zM591 561l226 -226l-579 -579q-12 -12 -29 -12t-29 12l-168 168q-12 12 -12 29t12 29zM1612 1524l168 -168q12 -12 12 -29t-12 -30l-233 -233 l-26 -25l-71 -71q-66 153 -195 258l91 91l207 207q13 12 30 12t29 -12z" />
|
||||
<glyph unicode="" d="M866 1021q0 -27 -13 -94q-11 -50 -31.5 -150t-30.5 -150q-2 -11 -4.5 -12.5t-13.5 -2.5q-20 -2 -31 -2q-58 0 -84 49.5t-26 113.5q0 88 35 174t103 124q28 14 51 14q28 0 36.5 -16.5t8.5 -47.5zM1352 597q0 14 -39 75.5t-52 66.5q-21 8 -34 8q-91 0 -226 -77l-2 2 q3 22 27.5 135t24.5 178q0 233 -242 233q-24 0 -68 -6q-94 -17 -168.5 -89.5t-111.5 -166.5t-37 -189q0 -146 80.5 -225t227.5 -79q25 0 25 -3t-1 -5q-4 -34 -26 -117q-14 -52 -51.5 -101t-82.5 -49q-42 0 -42 47q0 24 10.5 47.5t25 39.5t29.5 28.5t26 20t11 8.5q0 3 -7 10 q-24 22 -58.5 36.5t-65.5 14.5q-35 0 -63.5 -34t-41 -75t-12.5 -75q0 -88 51.5 -142t138.5 -54q82 0 155 53t117.5 126t65.5 153q6 22 15.5 66.5t14.5 66.5q3 12 14 18q118 60 227 60q48 0 127 -18q1 -1 4 -1q5 0 9.5 4.5t4.5 8.5zM1536 1120v-960q0 -119 -84.5 -203.5 t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
|
||||
<glyph unicode="" horiz-adv-x="1535" d="M744 1231q0 24 -2 38.5t-8.5 30t-21 23t-37.5 7.5q-39 0 -78 -23q-105 -58 -159 -190.5t-54 -269.5q0 -44 8.5 -85.5t26.5 -80.5t52.5 -62.5t81.5 -23.5q4 0 18 -0.5t20 0t16 3t15 8.5t7 16q16 77 48 231.5t48 231.5q19 91 19 146zM1498 575q0 -7 -7.5 -13.5t-15.5 -6.5 l-6 1q-22 3 -62 11t-72 12.5t-63 4.5q-167 0 -351 -93q-15 -8 -21 -27q-10 -36 -24.5 -105.5t-22.5 -100.5q-23 -91 -70 -179.5t-112.5 -164.5t-154.5 -123t-185 -47q-135 0 -214.5 83.5t-79.5 219.5q0 53 19.5 117t63 116.5t97.5 52.5q38 0 120 -33.5t83 -61.5 q0 -1 -16.5 -12.5t-39.5 -31t-46 -44.5t-39 -61t-16 -74q0 -33 16.5 -53t48.5 -20q45 0 85 31.5t66.5 78t48 105.5t32.5 107t16 90v9q0 2 -3.5 3.5t-8.5 1.5h-10t-10 -0.5t-6 -0.5q-227 0 -352 122.5t-125 348.5q0 108 34.5 221t96 210t156 167.5t204.5 89.5q52 9 106 9 q374 0 374 -360q0 -98 -38 -273t-43 -211l3 -3q101 57 182.5 88t167.5 31q22 0 53 -13q19 -7 80 -102.5t61 -116.5z" />
|
||||
<glyph unicode="" horiz-adv-x="1664" d="M831 863q32 0 59 -18l222 -148q61 -40 110 -97l146 -170q40 -46 29 -106l-72 -413q-6 -32 -29.5 -53.5t-55.5 -25.5l-527 -56l-352 -32h-9q-39 0 -67.5 28t-28.5 68q0 37 27 64t65 32l260 32h-448q-41 0 -69.5 30t-26.5 71q2 39 32 65t69 26l442 1l-521 64q-41 5 -66 37 t-19 73q6 35 34.5 57.5t65.5 22.5h10l481 -60l-351 94q-38 10 -62 41.5t-18 68.5q6 36 33 58.5t62 22.5q6 0 20 -2l448 -96l217 -37q1 0 3 -0.5t3 -0.5q23 0 30.5 23t-12.5 36l-186 125q-35 23 -42 63.5t18 73.5q27 38 76 38zM761 661l186 -125l-218 37l-5 2l-36 38 l-238 262q-1 1 -2.5 3.5t-2.5 3.5q-24 31 -18.5 70t37.5 64q31 23 68 17.5t64 -33.5l142 -147l-4 -4t-5 -4q-32 -45 -23 -99t55 -85zM1648 1115l15 -266q4 -73 -11 -147l-48 -219q-12 -59 -67 -87l-106 -54q2 62 -39 109l-146 170q-53 61 -117 103l-222 148q-34 23 -76 23 q-51 0 -88 -37l-235 312q-25 33 -18 73.5t41 63.5q33 22 71.5 14t62.5 -40l266 -352l-262 455q-21 35 -10.5 75t47.5 59q35 18 72.5 6t57.5 -46l241 -420l-136 337q-15 35 -4.5 74t44.5 56q37 19 76 6t56 -51l193 -415l101 -196q8 -15 23 -17.5t27 7.5t11 26l-12 224 q-2 41 26 71t69 31q39 0 67 -28.5t30 -67.5z" />
|
||||
<glyph unicode="" horiz-adv-x="1792" d="M335 180q-2 0 -6 2q-86 57 -168.5 145t-139.5 180q-21 30 -21 69q0 9 2 19t4 18t7 18t8.5 16t10.5 17t10 15t12 15.5t11 14.5q184 251 452 365q-110 198 -110 211q0 19 17 29q116 64 128 64q18 0 28 -16l124 -229q92 19 192 19q266 0 497.5 -137.5t378.5 -369.5 q20 -31 20 -69t-20 -69q-91 -142 -218.5 -253.5t-278.5 -175.5q110 -198 110 -211q0 -20 -17 -29q-116 -64 -127 -64q-19 0 -29 16l-124 229l-64 119l-444 820l7 7q-58 -24 -99 -47q3 -5 127 -234t243 -449t119 -223q0 -7 -9 -9q-13 -3 -72 -3q-57 0 -60 7l-456 841 q-39 -28 -82 -68q24 -43 214 -393.5t190 -354.5q0 -10 -11 -10q-14 0 -82.5 22t-72.5 28l-106 197l-224 413q-44 -53 -78 -106q2 -3 18 -25t23 -34l176 -327q0 -10 -10 -10zM1165 282l49 -91q273 111 450 385q-180 277 -459 389q67 -64 103 -148.5t36 -176.5 q0 -106 -47 -200.5t-132 -157.5zM848 896q0 -20 14 -34t34 -14q86 0 147 -61t61 -147q0 -20 14 -34t34 -14t34 14t14 34q0 126 -89 215t-215 89q-20 0 -34 -14t-14 -34zM1214 961l-9 4l7 -7z" />
|
||||
<glyph unicode="" horiz-adv-x="1280" d="M1050 430q0 -215 -147 -374q-148 -161 -378 -161q-232 0 -378 161q-147 159 -147 374q0 147 68 270.5t189 196.5t268 73q96 0 182 -31q-32 -62 -39 -126q-66 28 -143 28q-167 0 -280.5 -123t-113.5 -291q0 -170 112.5 -288.5t281.5 -118.5t281 118.5t112 288.5 q0 89 -32 166q66 13 123 49q41 -98 41 -212zM846 619q0 -192 -79.5 -345t-238.5 -253l-14 -1q-29 0 -62 5q83 32 146.5 102.5t99.5 154.5t58.5 189t30 192.5t7.5 178.5q0 69 -3 103q55 -160 55 -326zM791 947v-2q-73 214 -206 440q88 -59 142.5 -186.5t63.5 -251.5z M1035 744q-83 0 -160 75q218 120 290 247q19 37 21 56q-42 -94 -139.5 -166.5t-204.5 -97.5q-35 54 -35 113q0 37 17 79t43 68q46 44 157 74q59 16 106 58.5t74 100.5q74 -105 74 -253q0 -109 -24 -170q-32 -77 -88.5 -130.5t-130.5 -53.5z" />
|
||||
<glyph unicode="" d="M1050 495q0 78 -28 147q-41 -25 -85 -34q22 -50 22 -114q0 -117 -77 -198.5t-193 -81.5t-193.5 81.5t-77.5 198.5q0 115 78 199.5t193 84.5q53 0 98 -19q4 43 27 87q-60 21 -125 21q-154 0 -257.5 -108.5t-103.5 -263.5t103.5 -261t257.5 -106t257.5 106.5t103.5 260.5z M872 850q2 -24 2 -71q0 -63 -5 -123t-20.5 -132.5t-40.5 -130t-68.5 -106t-100.5 -70.5q21 -3 42 -3h10q219 139 219 411q0 116 -38 225zM872 850q-4 80 -44 171.5t-98 130.5q92 -156 142 -302zM1207 955q0 102 -51 174q-41 -86 -124 -109q-69 -19 -109 -53.5t-40 -99.5 q0 -40 24 -77q74 17 140.5 67t95.5 115q-4 -52 -74.5 -111.5t-138.5 -97.5q52 -52 110 -52q51 0 90 37t60 90q17 43 17 117zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5 t84.5 -203.5z" />
|
||||
<glyph unicode="" d="M1279 388q0 22 -22 27q-67 15 -118 59t-80 108q-7 19 -7 25q0 15 19.5 26t43 17t43 20.5t19.5 36.5q0 19 -18.5 31.5t-38.5 12.5q-12 0 -32 -8t-31 -8q-4 0 -12 2q5 95 5 114q0 79 -17 114q-36 78 -103 121.5t-152 43.5q-199 0 -275 -165q-17 -35 -17 -114q0 -19 5 -114 q-4 -2 -14 -2q-12 0 -32 7.5t-30 7.5q-21 0 -38.5 -12t-17.5 -32q0 -21 19.5 -35.5t43 -20.5t43 -17t19.5 -26q0 -6 -7 -25q-64 -138 -198 -167q-22 -5 -22 -27q0 -46 137 -68q2 -5 6 -26t11.5 -30.5t23.5 -9.5q12 0 37.5 4.5t39.5 4.5q35 0 67 -15t54 -32.5t57.5 -32.5 t76.5 -15q43 0 79 15t57.5 32.5t53.5 32.5t67 15q14 0 39.5 -4t38.5 -4q16 0 23 10t11 30t6 25q137 22 137 68zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5 t103 -385.5z" />
|
||||
<glyph unicode="" horiz-adv-x="1664" d="M848 1408q134 1 240.5 -68.5t163.5 -192.5q27 -58 27 -179q0 -47 -9 -191q14 -7 28 -7q18 0 51 13.5t51 13.5q29 0 56 -18t27 -46q0 -32 -31.5 -54t-69 -31.5t-69 -29t-31.5 -47.5q0 -15 12 -43q37 -82 102.5 -150t144.5 -101q28 -12 80 -23q28 -6 28 -35 q0 -70 -219 -103q-7 -11 -11 -39t-14 -46.5t-33 -18.5q-20 0 -62 6.5t-64 6.5q-37 0 -62 -5q-32 -5 -63 -22.5t-58 -38t-58 -40.5t-76 -33.5t-99 -13.5q-52 0 -96.5 13.5t-75 33.5t-57.5 40.5t-58 38t-62 22.5q-26 5 -63 5q-24 0 -65.5 -7.5t-58.5 -7.5q-25 0 -35 18.5 t-14 47.5t-11 40q-219 33 -219 103q0 29 28 35q52 11 80 23q78 32 144.5 101t102.5 150q12 28 12 43q0 28 -31.5 47.5t-69.5 29.5t-69.5 31.5t-31.5 52.5q0 27 26 45.5t55 18.5q15 0 48 -13t53 -13q18 0 32 7q-9 142 -9 190q0 122 27 180q64 137 172 198t264 63z" />
|
||||
<glyph unicode="" d="M1280 388q0 22 -22 27q-67 14 -118 58t-80 109q-7 14 -7 25q0 15 19.5 26t42.5 17t42.5 20.5t19.5 36.5q0 19 -18.5 31.5t-38.5 12.5q-11 0 -31 -8t-32 -8q-4 0 -12 2q5 63 5 115q0 78 -17 114q-36 78 -102.5 121.5t-152.5 43.5q-198 0 -275 -165q-18 -38 -18 -115 q0 -38 6 -114q-10 -2 -15 -2q-11 0 -31.5 8t-30.5 8q-20 0 -37.5 -12.5t-17.5 -32.5q0 -21 19.5 -35.5t42.5 -20.5t42.5 -17t19.5 -26q0 -11 -7 -25q-64 -138 -198 -167q-22 -5 -22 -27q0 -47 138 -69q2 -5 6 -26t11 -30.5t23 -9.5q13 0 38.5 5t38.5 5q35 0 67.5 -15 t54.5 -32.5t57.5 -32.5t76.5 -15q43 0 79 15t57.5 32.5t54 32.5t67.5 15q13 0 39 -4.5t39 -4.5q15 0 22.5 9.5t11.5 31t5 24.5q138 22 138 69zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960 q119 0 203.5 -84.5t84.5 -203.5z" />
|
||||
<glyph unicode="" horiz-adv-x="2304" d="M2304 1536q-69 -46 -125 -92t-89 -81t-59.5 -71.5t-37.5 -57.5t-22 -44.5t-14 -29.5q-10 -18 -35.5 -136.5t-48.5 -164.5q-15 -29 -50 -60.5t-67.5 -50.5t-72.5 -41t-48 -28q-47 -31 -151 -231q-341 14 -630 -158q-92 -53 -303 -179q47 16 86 31t55 22l15 7 q71 27 163 64.5t133.5 53.5t108 34.5t142.5 31.5q186 31 465 -7q1 0 10 -3q11 -6 14 -17t-3 -22l-194 -345q-15 -29 -47 -22q-128 24 -354 24q-146 0 -402 -44.5t-392 -46.5q-82 -1 -149 13t-107 37t-61 40t-33 34l-1 1v2q0 6 6 6q138 0 371 55q192 366 374.5 524t383.5 158 q5 0 14.5 -0.5t38 -5t55 -12t61.5 -24.5t63 -39.5t54 -59t40 -82.5l102 177q2 4 21 42.5t44.5 86.5t61 109.5t84 133.5t100.5 137q66 82 128 141.5t121.5 96.5t92.5 53.5t88 39.5z" />
|
||||
<glyph unicode="" d="M1322 640q0 -45 -5 -76l-236 14l224 -78q-19 -73 -58 -141l-214 103l177 -158q-44 -61 -107 -108l-157 178l103 -215q-61 -37 -140 -59l-79 228l14 -240q-38 -6 -76 -6t-76 6l14 238l-78 -226q-74 19 -140 59l103 215l-157 -178q-59 43 -108 108l178 158l-214 -104 q-39 69 -58 141l224 79l-237 -14q-5 42 -5 76q0 35 5 77l238 -14l-225 79q19 73 58 140l214 -104l-177 159q46 61 107 108l158 -178l-103 215q67 39 140 58l77 -224l-13 236q36 6 75 6q38 0 76 -6l-14 -237l78 225q74 -19 140 -59l-103 -214l158 178q61 -47 107 -108 l-177 -159l213 104q37 -62 58 -141l-224 -78l237 14q5 -31 5 -77zM1352 640q0 160 -78.5 295.5t-213 214t-292.5 78.5q-119 0 -227 -46.5t-186.5 -125t-124.5 -187.5t-46 -229q0 -119 46 -228t124.5 -187.5t186.5 -125t227 -46.5q158 0 292.5 78.5t213 214t78.5 294.5z M1425 1023v-766l-657 -383l-657 383v766l657 383zM768 -183l708 412v823l-708 411l-708 -411v-823zM1536 1088v-896l-768 -448l-768 448v896l768 448z" />
|
||||
<glyph unicode="" horiz-adv-x="1664" d="M339 1318h691l-26 -72h-665q-110 0 -188.5 -79t-78.5 -189v-771q0 -95 60.5 -169.5t153.5 -93.5q23 -5 98 -5v-72h-45q-140 0 -239.5 100t-99.5 240v771q0 140 99.5 240t239.5 100zM1190 1536h247l-482 -1294q-23 -61 -40.5 -103.5t-45 -98t-54 -93.5t-64.5 -78.5 t-79.5 -65t-95.5 -41t-116 -18.5v195q163 26 220 182q20 52 20 105q0 54 -20 106l-285 733h228l187 -585zM1664 978v-1111h-795q37 55 45 73h678v1038q0 85 -49.5 155t-129.5 99l25 67q101 -34 163.5 -123.5t62.5 -197.5z" />
|
||||
<glyph unicode="" horiz-adv-x="1792" d="M852 1227q0 -29 -17 -52.5t-45 -23.5t-45 23.5t-17 52.5t17 52.5t45 23.5t45 -23.5t17 -52.5zM688 -149v114q0 30 -20.5 51.5t-50.5 21.5t-50 -21.5t-20 -51.5v-114q0 -30 20.5 -52t49.5 -22q30 0 50.5 22t20.5 52zM860 -149v114q0 30 -20 51.5t-50 21.5t-50.5 -21.5 t-20.5 -51.5v-114q0 -30 20.5 -52t50.5 -22q29 0 49.5 22t20.5 52zM1034 -149v114q0 30 -20.5 51.5t-50.5 21.5t-50.5 -21.5t-20.5 -51.5v-114q0 -30 20.5 -52t50.5 -22t50.5 22t20.5 52zM1208 -149v114q0 30 -20.5 51.5t-50.5 21.5t-50.5 -21.5t-20.5 -51.5v-114 q0 -30 20.5 -52t50.5 -22t50.5 22t20.5 52zM1476 535q-84 -160 -232 -259.5t-323 -99.5q-123 0 -229.5 51.5t-178.5 137t-113 197.5t-41 232q0 88 21 174q-104 -175 -104 -390q0 -162 65 -312t185 -251q30 57 91 57q56 0 86 -50q32 50 87 50q56 0 86 -50q32 50 87 50t87 -50 q30 50 86 50q28 0 52.5 -15.5t37.5 -40.5q112 94 177 231.5t73 287.5zM1326 564q0 75 -72 75q-17 0 -47 -6q-95 -19 -149 -19q-226 0 -226 243q0 86 30 204q-83 -127 -83 -275q0 -150 89 -260.5t235 -110.5q111 0 210 70q13 48 13 79zM884 1223q0 50 -32 89.5t-81 39.5 t-81 -39.5t-32 -89.5q0 -51 31.5 -90.5t81.5 -39.5t81.5 39.5t31.5 90.5zM1513 884q0 96 -37.5 179t-113 137t-173.5 54q-77 0 -149 -35t-127 -94q-48 -159 -48 -268q0 -104 45.5 -157t147.5 -53q53 0 142 19q36 6 53 6q51 0 77.5 -28t26.5 -80q0 -26 -4 -46 q75 68 117.5 165.5t42.5 200.5zM1792 667q0 -111 -33.5 -249.5t-93.5 -204.5q-58 -64 -195 -142.5t-228 -104.5l-4 -1v-114q0 -43 -29.5 -75t-72.5 -32q-56 0 -86 50q-32 -50 -87 -50t-87 50q-30 -50 -86 -50q-55 0 -87 50q-30 -50 -86 -50q-47 0 -75 33.5t-28 81.5 q-90 -68 -198 -68q-118 0 -211 80q54 1 106 20q-113 31 -182 127q32 -7 71 -7q89 0 164 46q-192 192 -240 306q-24 56 -24 160q0 57 9 125.5t31.5 146.5t55 141t86.5 105t120 42q59 0 81 -52q19 29 42 54q2 3 12 13t13 16q10 15 23 38t25 42t28 39q87 111 211.5 177 t260.5 66q35 0 62 -4q59 64 146 64q83 0 140 -57q5 -5 5 -12q0 -5 -6 -13.5t-12.5 -16t-16 -17l-10.5 -10.5q17 -6 36 -18t19 -24q0 -6 -16 -25q157 -138 197 -378q25 30 60 30q45 0 100 -49q90 -80 90 -279z" />
|
||||
<glyph unicode="" d="M917 631q0 33 -6 64h-362v-132h217q-12 -76 -74.5 -120.5t-142.5 -44.5q-99 0 -169 71.5t-70 170.5t70 170.5t169 71.5q93 0 153 -59l104 101q-108 100 -257 100q-160 0 -272 -112.5t-112 -271.5t112 -271.5t272 -112.5q165 0 266.5 105t101.5 270zM1262 585h109v110 h-109v110h-110v-110h-110v-110h110v-110h110v110zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
|
||||
<glyph unicode="" d="M1536 1024v-839q0 -48 -49 -62q-174 -52 -338 -52q-73 0 -215.5 29.5t-227.5 29.5q-164 0 -370 -48v-338h-160v1368q-63 25 -101 81t-38 124q0 91 64 155t155 64t155 -64t64 -155q0 -68 -38 -124t-101 -81v-68q190 44 343 44q99 0 198 -15q14 -2 111.5 -22.5t149.5 -20.5 q77 0 165 18q11 2 80 21t89 19q26 0 45 -19t19 -45z" />
|
||||
<glyph unicode="" horiz-adv-x="1792" />
|
||||
<glyph unicode="" horiz-adv-x="1792" />
|
||||
<glyph unicode="" horiz-adv-x="1792" />
|
||||
<glyph unicode="" horiz-adv-x="1792" />
|
||||
<glyph unicode="" horiz-adv-x="1792" />
|
||||
<glyph unicode="" horiz-adv-x="1792" />
|
||||
<glyph unicode="" horiz-adv-x="1792" />
|
||||
<glyph unicode="" horiz-adv-x="1792" />
|
||||
<glyph unicode="" horiz-adv-x="1792" />
|
||||
<glyph unicode="" horiz-adv-x="1792" />
|
||||
<glyph unicode="" horiz-adv-x="1792" />
|
||||
</font>
|
||||
</defs></svg>
|
||||
|
Before Width: | Height: | Size: 357 KiB After Width: | Height: | Size: 382 KiB |
BIN
assets/fonts/fontawesome-webfont.woff
Normal file
BIN
assets/fonts/fontawesome-webfont.woff2
Normal file
|
Before Width: | Height: | Size: 106 KiB After Width: | Height: | Size: 106 KiB |
BIN
assets/fonts/ubuntu.woff2
Normal file
|
Before Width: | Height: | Size: 2.1 KiB After Width: | Height: | Size: 2.1 KiB |
|
Before Width: | Height: | Size: 4.4 KiB After Width: | Height: | Size: 4.4 KiB |
|
|
@ -1,162 +0,0 @@
|
|||
/*
|
||||
* @Author: printempw
|
||||
* @Date: 2016-02-04 16:48:42
|
||||
* @Last Modified by: printempw
|
||||
* @Last Modified time: 2016-04-03 11:42:38
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
function uploadTexture(uname, type) {
|
||||
var ply = new Ply({
|
||||
el: '<h2>为该用户上传新的 ' + type + ' 材质:</h2>'+
|
||||
'<input type="file" id="file" accept="image/png">'+
|
||||
'<button id="upload" class="btn btn-primary fw">上传</button>',
|
||||
effect: "fade",
|
||||
onaction: function(){
|
||||
var form_data = new FormData();
|
||||
var file = $('#file').get(0).files[0];
|
||||
if (file) {
|
||||
form_data.append('file', file);
|
||||
$.ajax({
|
||||
type: 'POST',
|
||||
contentType: false,
|
||||
url: 'admin_ajax.php?action=upload&type='+type+'&uname='+uname,
|
||||
dataType: "json",
|
||||
data: form_data,
|
||||
processData: false,
|
||||
success: function(json) {
|
||||
if (json.errno == 0) {
|
||||
showAlert("上传成功。");
|
||||
// refresh image
|
||||
if (type == "steve") $('#'+uname+'-steve').prop('src',
|
||||
'../skin/'+uname+'-steve.png?'+Math.round(Math.random() * 1000000));
|
||||
if (type == "alex") $('#'+uname+'-alex').prop('src',
|
||||
'../skin/'+uname+'-alex.png?'+Math.round(Math.random() * 1000000));
|
||||
if (type == "cape") $('#'+uname+'-cape').prop('src',
|
||||
'../cape/'+uname+'-.png?'+Math.round(Math.random() * 1000000));
|
||||
} else {
|
||||
showAlert("上传材质的时候出错啦:\n" + json.msg);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
});
|
||||
ply.open();
|
||||
}
|
||||
|
||||
function deleteTexture(uname) {
|
||||
var ply = new Ply({
|
||||
el: '<h2>选择要删除的 '+uname+' 的当前材质:</h2>'+
|
||||
'<label><input id="steve" type="checkbox" checked="">Steve 模型</label>'+
|
||||
'<label><input id="alex" type="checkbox" checked="">Alex 模型</label>'+
|
||||
'<label><input id="cape" type="checkbox" checked="">披风</label>'+
|
||||
'<label style="margin: 6px 0 12px;"><input id="all" type="checkbox" checked="">全部</label>'+
|
||||
'<button id="confirm" class="btn btn-primary fw">确定</button>',
|
||||
effect: "fade",
|
||||
onaction: function(ui) {
|
||||
if (ui.state == true) {
|
||||
var steve = $('#steve').prop('checked');
|
||||
var alex = $('#alex').prop('checked');
|
||||
var cape = $('#cape').prop('checked');
|
||||
if ($('#all').prop('checked')) {
|
||||
steve = alex = cape = true;
|
||||
}
|
||||
$.ajax({
|
||||
type: "POST",
|
||||
url: "admin_ajax.php?action=deleteTexture&uname="+uname,
|
||||
dataType: "json",
|
||||
data: {
|
||||
"steve" : steve,
|
||||
"alex" : alex,
|
||||
"cape" : cape
|
||||
},
|
||||
success: function(json) {
|
||||
if (json.errno == 0) {
|
||||
showAlert(json.msg);
|
||||
// remove DOM
|
||||
if (steve) $('#' + uname + '-steve').remove();
|
||||
if (alex) $('#' + uname + '-alex ').remove();
|
||||
if (cape) $('#' + uname + '-cape ').remove();
|
||||
} else {
|
||||
showAlert(json.msg);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
});
|
||||
ply.open();
|
||||
}
|
||||
|
||||
function changePasswd(uname) {
|
||||
Ply.dialog("prompt", {
|
||||
title: "修改 "+uname+" 的登录密码:",
|
||||
form: { passwd: "新的密码" }
|
||||
}).done(function(ui){
|
||||
var passwd = ui.data.passwd;
|
||||
$.ajax({
|
||||
type: "POST",
|
||||
url: "admin_ajax.php?action=change&uname="+uname,
|
||||
dataType: "json",
|
||||
data: { "passwd": passwd },
|
||||
success: function(json) {
|
||||
if (json.errno == 0) {
|
||||
showAlert(json.msg);
|
||||
} else {
|
||||
showAlert(json.msg);
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function deleteAccount(uname) {
|
||||
Ply.dialog("prompt", {
|
||||
title: "确定要删除 "+uname+"?此操作不可恢复。",
|
||||
}).done(function(ui){
|
||||
$.ajax({
|
||||
type: "POST",
|
||||
url: "admin_ajax.php?action=deleteAccount&uname="+uname,
|
||||
dataType: "json",
|
||||
success: function(json) {
|
||||
if (json.errno == 0) {
|
||||
showAlert(json.msg, function(){
|
||||
location.reload();
|
||||
});
|
||||
} else {
|
||||
showAlert(json.msg);
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function changeModel(uname) {
|
||||
Ply.dialog("prompt", {
|
||||
title: "修改 "+uname+" 的优先皮肤模型:",
|
||||
form: { text: "输入 `slim` 或者 `default`" }
|
||||
}).done(function(ui){
|
||||
var model = ui.data.text;
|
||||
if (model == 'slim'| model == 'default') {
|
||||
$.ajax({
|
||||
type: "POST",
|
||||
url: "admin_ajax.php?action=model&uname="+uname,
|
||||
data: { "model": ui.data.text },
|
||||
dataType: "json",
|
||||
success: function(json) {
|
||||
if (json.errno == 0) {
|
||||
showAlert(json.msg, function(){
|
||||
location.reload();
|
||||
});
|
||||
} else {
|
||||
showAlert(json.msg);
|
||||
}
|
||||
}
|
||||
});
|
||||
} else {
|
||||
showAlert('只能输入 `slim` 或者 `default` 哦');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
@ -1,138 +0,0 @@
|
|||
/*
|
||||
* @Author: printempw
|
||||
* @Date: 2016-01-21 13:55:44
|
||||
* @Last Modified by: printempw
|
||||
* @Last Modified time: 2016-04-03 09:29:41
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
function login(silent) {
|
||||
var uname = $("#uname").val();
|
||||
var passwd = $("#passwd").val();
|
||||
if (checkForm("login", uname, passwd)) {
|
||||
$.ajax({
|
||||
type: "POST",
|
||||
url: "ajax.php?action=login",
|
||||
dataType: "json",
|
||||
data: { "uname": uname, "passwd": passwd },
|
||||
beforeSend: function() {
|
||||
$('#login-button').html('<i class="fa fa-spinner fa-spin"></i> 登录中').prop('disabled', 'disabled');
|
||||
},
|
||||
success: function(json) {
|
||||
if (json.errno == 0) {
|
||||
docCookies.setItem('uname', uname, null, '/');
|
||||
docCookies.setItem('token', json.token, null, '/');
|
||||
if ($('#keep').prop('checked')) {
|
||||
docCookies.setItem('uname', uname, 604800, '/');
|
||||
// 设置长效 cookie (7天)
|
||||
docCookies.setItem('token', json.token, 604800, '/');
|
||||
}
|
||||
if (!silent) showAlert(json.msg);
|
||||
window.setTimeout('window.location = "./user/index.php"', 1000);
|
||||
} else {
|
||||
showAlert(json.msg);
|
||||
$('#login-button').html('登录').prop('disabled', '');
|
||||
}
|
||||
},
|
||||
error: function(json) {
|
||||
showMsg('alert-danger', '出错啦,请联系作者!<br />详细信息:'+json.responseText);
|
||||
$('#login-button').html('登录').prop('disabled', '');
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function register() {
|
||||
var uname = $('#reg-uname').val();
|
||||
var passwd = $('#reg-passwd').val();
|
||||
if (checkForm('register', uname, passwd, $('#reg-passwd2').val())) {
|
||||
$.ajax({
|
||||
type: "POST",
|
||||
url: "ajax.php?action=register",
|
||||
dataType: "json",
|
||||
data: { 'uname': uname, 'passwd': passwd },
|
||||
beforeSend: function() {
|
||||
$('#register-button').html('<i class="fa fa-spinner fa-spin"></i> 注册中').prop('disabled', 'disabled');
|
||||
},
|
||||
success: function(json) {
|
||||
if (json.errno == 0) {
|
||||
showAlert(json.msg);
|
||||
showMsg('hide', '');
|
||||
$('[data-remodal-id=register-modal]').remodal().close();
|
||||
// Automatically login after registeration
|
||||
$('#uname').val(uname);
|
||||
$('#passwd').val(passwd);
|
||||
login(true);
|
||||
} else {
|
||||
showAlert(json.msg);
|
||||
$('#register-button').html('注册').prop('disabled', '');
|
||||
}
|
||||
},
|
||||
error: function(json) {
|
||||
showMsg('alert-danger', '出错啦,请联系作者!<br />详细信息:'+json.responseText);
|
||||
$('#register-button').html('注册').prop('disabled', '');
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function checkForm(type, uname, passwd, passwd2) {
|
||||
switch(type) {
|
||||
case "login":
|
||||
if (uname == "") {
|
||||
showMsg('alert-warning', '用户名不能为空哦');
|
||||
$("#uname").focus();
|
||||
return false;
|
||||
} else if (passwd == ""){
|
||||
showMsg('alert-warning', '密码不能为空哦');
|
||||
$('#passwd').focus();
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
case "register":
|
||||
if (uname == "") {
|
||||
showMsg('alert-warning', '用户名不能为空哦');
|
||||
$('#uname').focus();
|
||||
return false;
|
||||
} else if (passwd == ""){
|
||||
showMsg('alert-warning', '密码不能为空哦');
|
||||
$('#passwd').focus();
|
||||
return false;
|
||||
} else if (passwd2 == ""){
|
||||
showMsg('alert-warning', '确认密码不能为空');
|
||||
$('#cpasswd').focus();
|
||||
return false;
|
||||
} else if (passwd != passwd2){
|
||||
showMsg('alert-warning', '注册密码和确认密码不一样诶');
|
||||
$('#cpasswd').focus();
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
$('#login').click(function(){
|
||||
$('[data-remodal-id=login-modal]').remodal().open();
|
||||
})
|
||||
|
||||
$('#register').click(function(){
|
||||
$('[data-remodal-id=register-modal]').remodal().open();
|
||||
})
|
||||
|
||||
// Register Event
|
||||
$('body').on('keypress', '[data-remodal-id=register-modal]', function(event){
|
||||
if (event.which == 13) register();
|
||||
}).on('click', '#register-button', register);
|
||||
|
||||
// Login Event
|
||||
$('body').on('keypress', '[data-remodal-id=login-modal]', function(event){
|
||||
if (event.which == 13) login(false);
|
||||
}).on('click', '#login-button', function() { login(false); });
|
||||
|
||||
|
|
@ -1,40 +0,0 @@
|
|||
/*
|
||||
* @Author: printempw
|
||||
* @Date: 2016-04-03 13:44:36
|
||||
* @Last Modified by: printempw
|
||||
* @Last Modified time: 2016-04-11 17:16:30
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
$(document).ready(function() {
|
||||
$('pre').each(function(i, block) {
|
||||
hljs.highlightBlock(block);
|
||||
});
|
||||
});
|
||||
|
||||
$('#mod-select').change(function() {
|
||||
$('#version-select').children().each(function() { $(this).remove(); });
|
||||
|
||||
if ($(this).val() == "csl") {
|
||||
$('#version-select').append('<option value="13_1-upper">13.1 版及以上(推荐)</option>');
|
||||
$('#version-select').append('<option value="13_1-lower">13.1 版以下</option>');
|
||||
} else if ($(this).val() == "usm") {
|
||||
$('#version-select').append('<option value="1_4-upper">1.4 版及以上(推荐)</option>');
|
||||
$('#version-select').append('<option value="1_2-1_3">1.2 及 1.3 版</option>');
|
||||
$('#version-select').append('<option value="1_2-lower">1.2 版以下</option>');
|
||||
}
|
||||
|
||||
showConfig();
|
||||
});
|
||||
|
||||
function showConfig() {
|
||||
$('#config-13_1-upper').hide();
|
||||
$('#config-13_1-lower').hide();
|
||||
$('#config-1_4-upper').hide();
|
||||
$('#config-1_2-1_3').hide();
|
||||
$('#config-1_2-lower').hide();
|
||||
$('#config-'+$('#version-select').val()).show();
|
||||
}
|
||||
|
||||
$('#version-select').change(showConfig);
|
||||
|
|
@ -1,70 +0,0 @@
|
|||
/*
|
||||
* @Author: printempw
|
||||
* @Date: 2016-03-27 09:43:57
|
||||
* @Last Modified by: printempw
|
||||
* @Last Modified time: 2016-04-03 11:55:42
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
var preview_type = "3d";
|
||||
|
||||
function init3dCanvas() {
|
||||
if (preview_type == "2d") return;
|
||||
if ($(window).width() < 800) {
|
||||
var canvas = MSP.get3dSkinCanvas($('#skinpreview').width(), $('#skinpreview').width());
|
||||
$("#skinpreview").append($(canvas).prop("id", "canvas3d"));
|
||||
} else {
|
||||
var canvas = MSP.get3dSkinCanvas(400, 400);
|
||||
$("#skinpreview").append($(canvas).prop("id", "canvas3d"));
|
||||
}
|
||||
}
|
||||
$(document).ready(function(){
|
||||
$('#preview-2d').hide();
|
||||
$('#model-steve').prop('checked', true);
|
||||
|
||||
if (isMobile()) {
|
||||
show2dPreview();
|
||||
} else {
|
||||
init3dCanvas();
|
||||
MSP.setStatus("rotation", false);
|
||||
}
|
||||
});
|
||||
|
||||
// Auto resize canvas to fit responsive design
|
||||
$(window).resize(init3dCanvas);
|
||||
|
||||
// Change 3D preview status
|
||||
$('.fa-pause').click(function(){
|
||||
MSP.setStatus("movements", !MSP.getStatus("movements"));
|
||||
if ($(this).hasClass('fa-pause'))
|
||||
$(this).removeClass('fa-pause').addClass('fa-play');
|
||||
else
|
||||
$(this).removeClass('fa-play').addClass('fa-pause');
|
||||
});
|
||||
$('.fa-forward').click(function(){
|
||||
MSP.setStatus("running", !MSP.getStatus("running"));
|
||||
});
|
||||
$('.fa-repeat').click(function(){
|
||||
MSP.setStatus("rotation", !MSP.getStatus("rotation"));
|
||||
});
|
||||
|
||||
function show2dPreview() {
|
||||
preview_type = "2d";
|
||||
$('#canvas3d').remove();
|
||||
$('#preview-msg').remove();
|
||||
$('.operations').hide();
|
||||
$('#preview-2d').show();
|
||||
$('#preview').html('切换 3D 预览').attr('href', 'javascript:show3dPreview();');
|
||||
}
|
||||
|
||||
function show3dPreview() {
|
||||
if (isMobile() && preview_type == "2d") {
|
||||
$("#skinpreview").append($('<div id="preview-msg" class="alert alert-info alert-dismissible fade in"><button type="button" class="close" data-dismiss="alert" aria-label="Close"><span aria-hidden="true">×</span></button>手机上的 3D 预览可能会出现奇怪的问题(譬如空白一片),亟待解决。</div>'));
|
||||
}
|
||||
preview_type = "3d";
|
||||
init3dCanvas();
|
||||
$('#preview-2d').hide();
|
||||
$('.operations').show();
|
||||
$('#preview').html('切换 2D 预览').attr('href', 'javascript:show2dPreview();');
|
||||
}
|
||||
|
|
@ -1,103 +0,0 @@
|
|||
/*
|
||||
* @Author: printempw
|
||||
* @Date: 2016-02-03 17:21:46
|
||||
* @Last Modified by: printempw
|
||||
* @Last Modified time: 2016-03-19 10:08:49
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
$('#change').click(function(){
|
||||
var passwd = $("#passwd").val();
|
||||
var new_passwd = $("#new-passwd").val();
|
||||
if (checkForm(passwd, new_passwd, $("#confirm-pwd").val())) {
|
||||
$.ajax({
|
||||
type: "POST",
|
||||
url: "../ajax.php?action=change",
|
||||
dataType: "json",
|
||||
data: {"uname": docCookies.getItem('uname'), "passwd": passwd, "new_passwd": new_passwd},
|
||||
success: function(json) {
|
||||
if (json.errno == 0) {
|
||||
logout(function(){
|
||||
showAlert(json.msg, function(){
|
||||
window.location = "../index.php";
|
||||
});
|
||||
});
|
||||
} else {
|
||||
showAlert(json.msg);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
function checkForm(passwd, new_passwd, confirm_pwd) {
|
||||
if (passwd == ""){
|
||||
showAlert("原密码不能为空");
|
||||
$("#passwd").focus();
|
||||
return false;
|
||||
} else if (new_passwd == ""){
|
||||
showAlert("新密码要好好填哦");
|
||||
$("#new_passwd").focus();
|
||||
return false;
|
||||
} else if (confirm_pwd == ""){
|
||||
showAlert("确认密码不能为空");
|
||||
$("#confirm_pwd").focus();
|
||||
return false;
|
||||
} else if (new_passwd != confirm_pwd){
|
||||
console.log(new_passwd, confirm_pwd)
|
||||
showAlert("新密码和确认的密码不一样诶?");
|
||||
$("#confirm_pwd").focus();
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
$('#delete').click(function(){
|
||||
Ply.dialog("prompt", {
|
||||
title: "这是危险操作!输入密码来确认:",
|
||||
form: { passwd: "Password" }
|
||||
}).done(function(ui){
|
||||
var passwd = ui.data.passwd;
|
||||
$.ajax({
|
||||
type: "POST",
|
||||
url: "../ajax.php?action=delete",
|
||||
dataType: "json",
|
||||
data: { "uname": docCookies.getItem('uname'), "passwd": passwd },
|
||||
success: function(json) {
|
||||
if (json.errno == 0) {
|
||||
docCookies.removeItem("uname", "/");
|
||||
docCookies.removeItem("token", "/");
|
||||
showAlert(json.msg, function(){
|
||||
window.location = "../index.php";
|
||||
});
|
||||
} else {
|
||||
showAlert(json.msg);
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
$('#reset').click(function(){
|
||||
Ply.dialog("prompt", {
|
||||
title: "这是危险操作!输入密码来确认:",
|
||||
form: { passwd: "Password" }
|
||||
}).done(function(ui){
|
||||
var passwd = ui.data.passwd;
|
||||
$.ajax({
|
||||
type: "POST",
|
||||
url: "../ajax.php?action=reset",
|
||||
dataType: "json",
|
||||
data: { "uname": docCookies.getItem('uname'), "passwd": passwd },
|
||||
success: function(json) {
|
||||
if (json.errno == 0) {
|
||||
showAlert(json.msg);
|
||||
} else {
|
||||
showAlert(json.msg);
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
@ -1,56 +0,0 @@
|
|||
/*
|
||||
* @Author: printempw
|
||||
* @Date: 2016-03-18 21:58:09
|
||||
* @Last Modified by: printempw
|
||||
* @Last Modified time: 2016-04-03 10:18:30
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
$("#upload").click(function(){
|
||||
var model = $('#model-alex').prop('checked') ? "alex" : "steve";
|
||||
var skin_file = $('#skininput').get(0).files[0];
|
||||
var cape_file = $('#capeinput').get(0).files[0];
|
||||
var form_data = new FormData();
|
||||
if (skin_file) form_data.append('skin_file', skin_file);
|
||||
if (cape_file) form_data.append('cape_file', cape_file);
|
||||
form_data.append('uname', docCookies.getItem('uname'));
|
||||
// Ajax file upload
|
||||
if (skin_file || cape_file) {
|
||||
$.ajax({
|
||||
type: 'POST',
|
||||
url: '../ajax.php?action=upload&model='+model,
|
||||
contentType: false,
|
||||
dataType: "json",
|
||||
data: form_data,
|
||||
processData: false,
|
||||
beforeSend: function() {
|
||||
showCallout('callout-info', '正在上传。。');
|
||||
},
|
||||
success: function(json) {
|
||||
console.log(json);
|
||||
if (json.skin.errno == 0 && json.cape.errno == 0) {
|
||||
showCallout('callout-success', '上传成功!');
|
||||
}
|
||||
if (json.skin.errno != 0) {
|
||||
showCallout('callout-warning', '上传皮肤的时候出错了:\n'+json.skin.msg);
|
||||
}
|
||||
if (json.cape.errno != 0) {
|
||||
showCallout('callout-warning', '上传披风的时候出错了:\n'+json.cape.msg);
|
||||
}
|
||||
},
|
||||
error: function(json) {
|
||||
showCallout('callout-danger', '出错啦,请联系作者!<br />详细信息:'+json.responseText);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
showCallout('callout-warning', '你还没有选择任何文件哦');
|
||||
}
|
||||
});
|
||||
|
||||
$(document).ready(function() {
|
||||
$('input[type=radio]').iCheck({
|
||||
radioClass: 'iradio_square-blue'
|
||||
});
|
||||
$('input[type=file]').fileinput({'showUpload':false, 'language': 'zh'});
|
||||
});
|
||||
|
|
@ -1,87 +0,0 @@
|
|||
/*
|
||||
* @Author: printempw
|
||||
* @Date: 2016-01-21 13:56:40
|
||||
* @Last Modified by: printempw
|
||||
* @Last Modified time: 2016-03-27 09:47:10
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
$('body').on('change', '#skininput', function(){
|
||||
var files = $('#skininput').prop('files');
|
||||
handleFiles(files, 'skin');
|
||||
});
|
||||
|
||||
$('body').on('change', '#capeinput', function(){
|
||||
var files = $('#capeinput').prop('files');
|
||||
handleFiles(files, 'cape');
|
||||
});
|
||||
|
||||
// Real-time preview
|
||||
function handleFiles(files, type) {
|
||||
if(files.length > 0) {
|
||||
var file = files[0];
|
||||
if(file.type === "image/png") {
|
||||
var reader = new FileReader();
|
||||
reader.onload = function (e) {
|
||||
var img = new Image();
|
||||
img.onload = function () {
|
||||
if (type == "skin") {
|
||||
MSP.changeSkin(img.src);
|
||||
var model = $('#model-alex').prop('checked') ? "alex" : "steve";
|
||||
change2dTexture(model, img.src);
|
||||
} else {
|
||||
MSP.changeCape(img.src);
|
||||
change2dTexture('cape', img.src);
|
||||
}
|
||||
};
|
||||
img.onerror = function () {
|
||||
showCallout("alert-danger", "错误:这张图片编码不对哦");
|
||||
};
|
||||
img.src = this.result;
|
||||
};
|
||||
reader.readAsDataURL(file);
|
||||
} else {
|
||||
showCallout("alert-danger", "错误:皮肤文件必须为 PNG 格式");
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
function changeModel(uname) {
|
||||
showAlert('确定要更改优先皮肤模型吗?', function(){
|
||||
$.ajax({
|
||||
type: "POST",
|
||||
url: "../ajax.php?action=model",
|
||||
data: { "uname": docCookies.getItem('uname') },
|
||||
dataType: "json",
|
||||
success: function(json) {
|
||||
if (json.errno == 0) {
|
||||
showAlert(json.msg, function(){
|
||||
location.reload();
|
||||
});
|
||||
} else {
|
||||
showAlert(json.msg);
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function change2dTexture(type, file) {
|
||||
$('#'+type).attr('src', file);
|
||||
}
|
||||
|
||||
function onWindowResize() {
|
||||
if (preview_type == "3d") {
|
||||
camera.aspect = (window.innerWidth - sidebarWidth) / window.innerHeight;
|
||||
camera.updateProjectionMatrix();
|
||||
|
||||
var canvas3d = document.getElementById('canvas3d');
|
||||
canvas3d.width = 600;
|
||||
canvas3d.height = 350;
|
||||
|
||||
canvas3d.setSize(container.clientWidth, container.clientWidth/12*7);
|
||||
} else {
|
||||
show2dPreview();
|
||||
}
|
||||
}
|
||||
|
|
@ -1,49 +0,0 @@
|
|||
/*
|
||||
* @Author: printempw
|
||||
* @Date: 2016-02-03 18:23:21
|
||||
* @Last Modified by: printempw
|
||||
* @Last Modified time: 2016-04-03 08:17:08
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
function showMsg(type, msg) {
|
||||
$("[id=msg]").removeClass().addClass("alert").addClass(type).html(msg);
|
||||
}
|
||||
|
||||
function showCallout(type, msg) {
|
||||
$("[id=msg]").removeClass().addClass("callout").addClass(type).html(msg);
|
||||
}
|
||||
|
||||
function showAlert(msg, callback, callback2) {
|
||||
callback = callback ? callback : new Function;
|
||||
Ply.dialog("alert", msg).done(callback).fail(callback2);
|
||||
}
|
||||
|
||||
function isMobile() {
|
||||
if( /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent) ) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function logout(callback) {
|
||||
$.ajax({
|
||||
type: "POST",
|
||||
url: "../ajax.php?action=logout",
|
||||
dataType: "json",
|
||||
data: {"uname": docCookies.getItem('uname')},
|
||||
success: function(json) {
|
||||
docCookies.removeItem("uname", "/");
|
||||
docCookies.removeItem("token", "/");
|
||||
callback(json);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
$("#logout").click(function() {
|
||||
logout(function(json){
|
||||
showAlert(json.msg);
|
||||
window.setTimeout('window.location = "../index.php"', 1000);
|
||||
});
|
||||
});
|
||||
10
assets/libs/AdminLTE/.gitignore
vendored
|
|
@ -1,10 +0,0 @@
|
|||
*.DS_Store
|
||||
.idea
|
||||
/nbproject/private/
|
||||
/nbproject/
|
||||
/node_modules/
|
||||
TODO
|
||||
*.zip
|
||||
test.html
|
||||
*.log
|
||||
test.html
|
||||
|
|
@ -1,20 +0,0 @@
|
|||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2014-2015 almasaeed2010
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
|
@ -1,222 +0,0 @@
|
|||
Introduction
|
||||
============
|
||||
|
||||
**AdminLTE** -- is a fully responsive admin template. Based on **[Bootstrap 3](https://github.com/twbs/bootstrap)** framework. Highly customizable and easy to use. Fits many screen resolutions from small mobile devices to large desktops. Check out the live preview now and see for yourself.
|
||||
|
||||
**Download & Preview on [Almsaeed Studio](https://almsaeedstudio.com)**
|
||||
|
||||
Looking for Premium Templates?
|
||||
------------------------------
|
||||
**Almsaeed studio just opened a new premium templates page. Hand picked to insure the best quality and the most affordable prices. Visit https://almsaeedstudio.com/premium for more information.**
|
||||
|
||||
|
||||
!["AdminLTE Presentation"] (https://almsaeedstudio.com/AdminLTE2.png "AdminLTE Presentation")
|
||||
|
||||
**AdminLTE** has been carefully coded with clear comments in all of its JS, LESS and HTML files. LESS has been used to increase code customizability.
|
||||
|
||||
Installation
|
||||
------------
|
||||
There are multiple ways to install AdminLTE.
|
||||
|
||||
####Download:
|
||||
|
||||
Download from Github or [visit Almsaeed Studio](https://almsaeedstudio.com) and download the latest release.
|
||||
|
||||
####Using The Command Line:
|
||||
|
||||
**Github**
|
||||
|
||||
- Fork the repository ([here is the guide](https://help.github.com/articles/fork-a-repo/)).
|
||||
- Clone to your machine
|
||||
```
|
||||
git clone https://github.com/YOUR_USERNAME/AdminLTE.git
|
||||
```
|
||||
|
||||
**Bower**
|
||||
|
||||
```
|
||||
bower install admin-lte
|
||||
```
|
||||
|
||||
**Composer**
|
||||
|
||||
```
|
||||
composer require "almasaeed2010/adminlte=~2.0"
|
||||
```
|
||||
|
||||
Documentation
|
||||
-------------
|
||||
Visit the [online documentation](https://almsaeedstudio.com/themes/AdminLTE/documentation/index.html) for the most
|
||||
updated guide. Information will be added on a weekly basis.
|
||||
|
||||
Browser Support
|
||||
---------------
|
||||
- IE 9+
|
||||
- Firefox (latest)
|
||||
- Chrome (latest)
|
||||
- Safari (latest)
|
||||
- Opera (latest)
|
||||
|
||||
Contribution
|
||||
------------
|
||||
Contribution are always **welcome and recommended**! Here is how:
|
||||
|
||||
- Fork the repository ([here is the guide](https://help.github.com/articles/fork-a-repo/)).
|
||||
- Clone to your machine ```git clone https://github.com/YOUR_USERNAME/AdminLTE.git```
|
||||
- Make your changes
|
||||
- Create a pull request
|
||||
|
||||
#### Contribution Requirements:
|
||||
|
||||
- When you contribute, you agree to give a non-exclusive license to Almsaeed Studio to use that contribution in any context as we (Almsaeed Studio) see appropriate.
|
||||
- If you use content provided by another party, it must be appropriately licensed using an [open source](http://opensource.org/licenses) license.
|
||||
- Contributions are only accepted through Github pull requests.
|
||||
- Finally, contributed code must work in all supported browsers (see above for browser support).
|
||||
|
||||
License
|
||||
-------
|
||||
AdminLTE is an open source project by [Almsaeed Studio](https://almsaeedstudio.com) that is licensed under [MIT](http://opensource.org/licenses/MIT). Almsaeed Studio
|
||||
reserves the right to change the license of future releases.
|
||||
|
||||
Todo List
|
||||
---------
|
||||
- ~~Light sidebar colors~~ (Done v2.1.0)
|
||||
- ~~Right sidebar~~ (Done v2.1.0)
|
||||
- ~~Minified main-sidebar~~ (Done v2.1.0)
|
||||
- Right to left support
|
||||
- Custom pace style
|
||||
|
||||
Legacy Realeases
|
||||
----------------
|
||||
AdminLTE 1.x can be easily upgraded to 2.x using [this guide](https://almsaeedstudio.com/themes/AdminLTE/documentation/index.html#upgrade), but if you intend to keep using AdminLTE 1.x, you can download the latest release from the [releases](https://github.com/almasaeed2010/AdminLTE/releases) section above.
|
||||
|
||||
Change log
|
||||
----------
|
||||
**v2.3.0:**
|
||||
- Added social widgets (found in the widgets page)
|
||||
- Added profile page
|
||||
- Fix issue #430 (requires ```.hold-transition``` to be added to ```<body>```)
|
||||
- Fix issue #578
|
||||
- Fix issue #579
|
||||
|
||||
**v2.2.1:**
|
||||
- Bug Fixes
|
||||
- Removed many ```!important``` statements in css
|
||||
- Activate boxWidget automatically when created after the page has loaded
|
||||
- Activate sidebar menu treeview links automatically when created after the page has loaded
|
||||
- Updated Font Awesome thanks to @Dennis14e
|
||||
- Added JSHint to Grunt tasks (Find JS errors)
|
||||
- Added CSSLint to Grunt tasks (Find CSS errors)
|
||||
- Added Image to Grunt tasks (compress images)
|
||||
- Added Clean to Grunt tasks (remove unwanted files like uncompressed images)
|
||||
- Updated Bootstrap to 3.3.5
|
||||
|
||||
**v2.2.0:**
|
||||
- Bug fixes
|
||||
- Added support for [Select2](https://select2.github.io/)
|
||||
- Updated ChartJS
|
||||
|
||||
**v2.1.2:**
|
||||
- Added explicit BoxWidget activation function issue #450
|
||||
- Crushed some bugs
|
||||
|
||||
**v2.1.1:**
|
||||
- Fix version error
|
||||
|
||||
**v2.1.0:**
|
||||
- Update Ion Icons
|
||||
- Added right sidebar ```.control-sidebar```
|
||||
- Control sidebar has 2 open effects: slide over content and push content
|
||||
- Control sidebar converts to always slide over content on small screens
|
||||
- Added 6 new light sidebar skins
|
||||
- Updated demo menu
|
||||
- Added ChartJS preview page
|
||||
- Fixed some minor bugs
|
||||
- Added light control sidebar skin
|
||||
- Added expand on hover option for sidebar mini
|
||||
- Added fixed control sidebar layout
|
||||
|
||||
**v2.0.5:**
|
||||
- Fixed issue #288
|
||||
|
||||
**v2.0.4:**
|
||||
- Fixed bower.json to pick up newest release.
|
||||
|
||||
**v2.0.3**
|
||||
- Bug fixes
|
||||
- Fixed extra page when printing issue #264
|
||||
- Updated documentation and fixed links scrolling issue
|
||||
- Created print.less file (this makes it easier if you want to create a seperate CSS file for printing)
|
||||
- Fixed sidebar stretching issue #275
|
||||
- Fixed checkbox out of bounds issue in WYSIHTML5 editor.
|
||||
|
||||
**v2.0.2:**
|
||||
- Solved issue with hidden arrow in select inputs.
|
||||
|
||||
**v2.0.1:**
|
||||
- Updated README.md
|
||||
- Fixed versioning issue in CSS, LESS, and JS
|
||||
- Updated box-shadow for boxes
|
||||
- Updated docs
|
||||
|
||||
**v2.0.0:**
|
||||
|
||||
- Major layout bug fixes
|
||||
- Change in layout mark up
|
||||
- Added transitions to the sidebar
|
||||
- New skins and modified previous skins
|
||||
- Change in color scheme to a more complementing scheme
|
||||
- Added footer support
|
||||
- Removed pace.js from the main app.js
|
||||
- Added support for collapsed sidebar as an initial state (add .sidebar-collapse to the body tag)
|
||||
- Added boxed layout (.layout-boxed)
|
||||
- Enhanced consistency in padding and margining
|
||||
- Updated Bootstrap to 3.3.2
|
||||
- Fixed navbar dropdown menu on small screens positioning issues.
|
||||
- Updated Ion Icons to 2.0.0
|
||||
- Updated FontAwesome to 4.3.0
|
||||
- Added ChartJS 1.0.1
|
||||
- Removed iCheck dependency
|
||||
- Created Dashboard 2.0
|
||||
- Created new Chat widget (DirectChat)
|
||||
- Added transitions to DirectChat
|
||||
- Added contacts pane to DirectChat
|
||||
- Changed .right-side to .content-wrapper
|
||||
- Changed .navbar-right to .navbar-custom-menu
|
||||
- Removed unused files
|
||||
- Updated lockscreen style (HTML markup changed!)
|
||||
- Updated Login & Registration pages (HTML markup changed!)
|
||||
- Updated buttons style.
|
||||
- Enhanced border-radius consistency
|
||||
- Added mailbox: inbox, read, and compose pages
|
||||
- Bootstrap & jQuery are now hosted locally
|
||||
- Created documentation.
|
||||
|
||||
**ver 1.2.0:**
|
||||
|
||||
- Fixed the sidebar scroll issue when using the fixed layout.
|
||||
- Added [Bootstrap Social Buttons](http://lipis.github.io/bootstrap-social/ "Bootstrap Social") plugin.
|
||||
- Fixed RequireJS bug. Thanks to [StaticSphere](https://github.com/StaticSphere "github user").
|
||||
|
||||
**ver 1.1.0:**
|
||||
|
||||
- Added new skin. class: .skin-black
|
||||
- Added [pace](http://github.hubspot.com/pace/docs/welcome/ "pace") plugin.
|
||||
|
||||
Image Credits
|
||||
-------------
|
||||
[Pixeden](http://www.pixeden.com/psd-web-elements/flat-responsive-showcase-psd)
|
||||
|
||||
[Graphicsfuel](http://www.graphicsfuel.com/2013/02/13-high-resolution-blur-backgrounds/)
|
||||
|
||||
[Pickaface](http://pickaface.net/)
|
||||
|
||||
[Unsplash](https://unsplash.com/)
|
||||
|
||||
[Uifaces](http://uifaces.com/)
|
||||
|
||||
Donations
|
||||
---------
|
||||
Donations are **greatly appreciated!**
|
||||
|
||||
[](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=629XCUSXBHCBC "Donate")
|
||||
13
assets/libs/AdminLTE/dist/js/app.min.js
vendored
|
|
@ -1,23 +0,0 @@
|
|||
{
|
||||
"name": "admin-lte",
|
||||
"version": "2.3.0",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git://github.com/almasaeed2010/AdminLTE.git"
|
||||
},
|
||||
"license": "MIT",
|
||||
"devDependencies": {
|
||||
"R2": "^1.4.3",
|
||||
"grunt": "~0.4.5",
|
||||
"grunt-contrib-clean": "^0.6.0",
|
||||
"grunt-contrib-csslint": "^0.5.0",
|
||||
"grunt-contrib-cssmin": "^0.12.2",
|
||||
"grunt-contrib-jshint": "^0.11.2",
|
||||
"grunt-contrib-less": "^0.12.0",
|
||||
"grunt-contrib-uglify": "^0.7.0",
|
||||
"grunt-contrib-watch": "~0.6.1",
|
||||
"grunt-cssjanus": "^0.2.4",
|
||||
"grunt-image": "^1.0.5",
|
||||
"grunt-includes": "^0.4.5"
|
||||
}
|
||||
}
|
||||
23
assets/libs/app.min.css
vendored
Normal file
7
assets/libs/app.min.js
vendored
Normal file
|
|
@ -1,28 +0,0 @@
|
|||
Copyright (c) 2014 - 2015, Kartik Visweswaran
|
||||
Krajee.com
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
* Neither the names of Kartik Visweswaran or Krajee nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
|
@ -1,96 +0,0 @@
|
|||
bootstrap-fileinput
|
||||
===================
|
||||
|
||||
[](http://badge.fury.io/bo/bootstrap-fileinput)
|
||||
[](https://packagist.org/packages/kartik-v/bootstrap-fileinput)
|
||||
[](https://packagist.org/packages/kartik-v/bootstrap-fileinput)
|
||||
[](https://packagist.org/packages/kartik-v/bootstrap-fileinput)
|
||||
[](https://packagist.org/packages/kartik-v/bootstrap-fileinput)
|
||||
|
||||
An enhanced HTML 5 file input for Bootstrap 3.x with file preview for various files, offers multiple selection, and more. The plugin allows you a simple way to setup an advanced file picker/upload control built to work specially with Bootstrap CSS3 styles. It enhances the file input functionality further, by offering support to preview a wide variety of files i.e. images, text, html, video, audio, flash, and objects. In addition, it includes AJAX based uploads, dragging & dropping files, viewing upload progress, and selectively previewing, adding, or deleting files.
|
||||
|
||||

|
||||
|
||||
> NOTE: The latest version of the plugin is v4.3.1 (dev-master). Refer the [CHANGE LOG](https://github.com/kartik-v/bootstrap-fileinput/blob/master/CHANGE.md) for details.
|
||||
|
||||
## Documentation and Demo
|
||||
|
||||
View the [plugin documentation](http://plugins.krajee.com/file-input) and [plugin demos](http://plugins.krajee.com/file-input/demo) at Krajee JQuery plugins.
|
||||
|
||||
## Pre-requisites
|
||||
|
||||
1. [Bootstrap 3.x](http://getbootstrap.com/)
|
||||
2. Latest [JQuery](http://jquery.com/)
|
||||
3. Most modern browsers supporting HTML5 (inputs and FileReader API) including CSS3 & JQuery. For Internet Explorer, one must use IE versions 10 and above. IE9 and below will work as a normal file input, and will not support multiple file selection or the HTML 5 FileReader API.
|
||||
4. With release 4.0, AJAX uploads are supported. AJAX uploads require that the browser support HTML5 FormData and XHR2 (XMLHttpRequest 2). Most modern browsers support FormData and XHR2. The plugin will automatically degrade to normal form based submission for browsers not supporting AJAX uploads.
|
||||
|
||||
> NOTE: You can use the [sass branch](https://github.com/kartik-v/bootstrap-fileinput/tree/sass) for installation using `bootstrap-sass` dependency.
|
||||
The [master branch](https://github.com/kartik-v/bootstrap-fileinput/tree/master) can be used for installation using plain `bootstrap` dependency.
|
||||
|
||||
## Installation
|
||||
|
||||
### Using Bower
|
||||
You can use the `bower` package manager to install. Run:
|
||||
|
||||
bower install bootstrap-fileinput
|
||||
|
||||
### Using Composer
|
||||
You can use the `composer` package manager to install. Either run:
|
||||
|
||||
$ php composer.phar require kartik-v/bootstrap-fileinput "@dev"
|
||||
|
||||
or add:
|
||||
|
||||
"kartik-v/bootstrap-fileinput": "@dev"
|
||||
|
||||
to your composer.json file
|
||||
|
||||
### Manual Install
|
||||
|
||||
You can also manually install the plugin easily to your project. Just download the source [ZIP](https://github.com/kartik-v/bootstrap-fileinput/zipball/master) or [TAR ball](https://github.com/kartik-v/bootstrap-fileinput/tarball/master) and extract the plugin assets (css and js folders) into your project.
|
||||
|
||||
## Usage
|
||||
|
||||
Step 1: Load the following assets in your header.
|
||||
|
||||
```html
|
||||
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css" rel="stylesheet">
|
||||
<link href="path/to/css/fileinput.min.css" media="all" rel="stylesheet" type="text/css" />
|
||||
<script src="//ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
|
||||
<!-- canvas-to-blob.min.js is only needed if you wish to resize images before upload.
|
||||
This must be loaded before fileinput.min.js -->
|
||||
<script src="path/to/js/plugins/canvas-to-blob.min.js" type="text/javascript"></script>
|
||||
<script src="path/to/js/fileinput.min.js"></script>
|
||||
<!-- bootstrap.js below is only needed if you wish to the feature of viewing details
|
||||
of text file preview via modal dialog -->
|
||||
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/js/bootstrap.min.js" type="text/javascript"></script>
|
||||
<!-- optionally if you need translation for your language then include
|
||||
locale file as mentioned below -->
|
||||
<script src="path/to/js/fileinput_locale_<lang>.js"></script>
|
||||
```
|
||||
|
||||
If you noticed, you need to load the `jquery.min.js` and `bootstrap.min.css` in addition to the `fileinput.min.css` and `fileinput.min.js`. The locale file `fileinput_locale_<lang>.js` can be optionally included for translating for your language if needed.
|
||||
|
||||
NOTE: The `canvas-to-blob.min.js` file is the source for the [JavaScript-Canvas-to-Blob plugin by blueimp](https://github.com/blueimp/JavaScript-Canvas-to-Blob). It is required to be loaded before `fileinput.js` if you wish to use the image resize feature of the **bootstrap-fileinput** plugin. For ease of access, the plugin source for JavaScript-Canvas-to-Blob is included in the `js/plugins` folder of this project repository.
|
||||
|
||||
Step 2: Initialize the plugin on your page. For example,
|
||||
|
||||
```js
|
||||
// initialize with defaults
|
||||
$("#input-id").fileinput();
|
||||
|
||||
// with plugin options
|
||||
$("#input-id").fileinput({'showUpload':false, 'previewFileType':'any'});
|
||||
```
|
||||
|
||||
The `#input-id` is the identifier for the input (e.g. `type = file`) on your page, which is hidden automatically by the plugin.
|
||||
|
||||
Alternatively, you can directly call the plugin options by setting data attributes to your input field.
|
||||
|
||||
```html
|
||||
<input id="input-id" type="file" class="file" data-preview-file-type="text" >
|
||||
```
|
||||
|
||||
## License
|
||||
|
||||
**bootstrap-fileinput** is released under the BSD 3-Clause License. See the bundled `LICENSE.md` for details.
|
||||
|
|
@ -1,253 +0,0 @@
|
|||
/*!
|
||||
* @copyright Copyright © Kartik Visweswaran, Krajee.com, 2014 - 2015
|
||||
* @package bootstrap-fileinput
|
||||
* @version 4.3.1
|
||||
*
|
||||
* File input styling for Bootstrap 3.0
|
||||
* Built for Yii Framework 2.0
|
||||
* Author: Kartik Visweswaran
|
||||
* Year: 2015
|
||||
* For more Yii related demos visit http://demos.krajee.com
|
||||
*/
|
||||
.file-loading {
|
||||
top: 0;
|
||||
right: 0;
|
||||
width: 25px;
|
||||
height: 25px;
|
||||
font-size: 999px;
|
||||
text-align: right;
|
||||
color: #fff;
|
||||
background: transparent url('../img/loading.gif') top left no-repeat;
|
||||
border: none;
|
||||
}
|
||||
|
||||
.file-object {
|
||||
margin: 0 0 -5px 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.btn-file {
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.btn-file input[type=file] {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
min-width: 100%;
|
||||
min-height: 100%;
|
||||
text-align: right;
|
||||
opacity: 0;
|
||||
background: none repeat scroll 0 0 transparent;
|
||||
cursor: inherit;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.file-caption-name {
|
||||
display: inline-block;
|
||||
overflow: hidden;
|
||||
height: 20px;
|
||||
word-break: break-all;
|
||||
}
|
||||
|
||||
.input-group-lg .file-caption-name {
|
||||
height: 25px;
|
||||
}
|
||||
|
||||
.file-preview-detail-modal {
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.file-error-message {
|
||||
color: #a94442;
|
||||
background-color: #f2dede;
|
||||
margin: 5px;
|
||||
border: 1px solid #ebccd1;
|
||||
border-radius: 4px;
|
||||
padding: 15px;
|
||||
}
|
||||
|
||||
.file-error-message pre, .file-error-message ul {
|
||||
margin: 0;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.file-error-message pre {
|
||||
margin: 5px 0;
|
||||
}
|
||||
|
||||
.file-caption-disabled {
|
||||
background-color: #EEEEEE;
|
||||
cursor: not-allowed;
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.file-preview {
|
||||
border-radius: 5px;
|
||||
border: 1px solid #ddd;
|
||||
padding: 5px;
|
||||
width: 100%;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
.file-preview-frame {
|
||||
display: table;
|
||||
margin: 8px;
|
||||
height: 160px;
|
||||
border: 1px solid #ddd;
|
||||
box-shadow: 1px 1px 5px 0 #a2958a;
|
||||
padding: 6px;
|
||||
float: left;
|
||||
text-align: center;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.file-preview-frame:not(.file-preview-error):hover {
|
||||
box-shadow: 3px 3px 5px 0 #333;
|
||||
}
|
||||
|
||||
.file-preview-image {
|
||||
height: 160px;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.file-preview-text {
|
||||
text-align: left;
|
||||
width: 160px;
|
||||
margin-bottom: 2px;
|
||||
color: #428bca;
|
||||
background: #fff;
|
||||
overflow-x: hidden;
|
||||
}
|
||||
|
||||
.file-preview-other {
|
||||
display: table-cell;
|
||||
text-align: center;
|
||||
vertical-align: middle;
|
||||
width: 160px;
|
||||
height: 160px;
|
||||
border: 2px solid #999;
|
||||
border-radius: 30px;
|
||||
}
|
||||
|
||||
.file-preview-other:hover {
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
.file-actions, .file-other-error {
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.file-icon-lg {
|
||||
font-size: 1.2em;
|
||||
}
|
||||
|
||||
.file-icon-2x {
|
||||
font-size: 2.4em;
|
||||
}
|
||||
|
||||
.file-icon-4x {
|
||||
font-size: 4.8em;
|
||||
}
|
||||
|
||||
.file-input-new .file-preview, .file-input-new .close, .file-input-new .glyphicon-file,
|
||||
.file-input-new .fileinput-remove-button, .file-input-new .fileinput-upload-button,
|
||||
.file-input-ajax-new .fileinput-remove-button, .file-input-ajax-new .fileinput-upload-button {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.file-thumb-loading {
|
||||
background: transparent url('../img/loading.gif') no-repeat scroll center center content-box !important;
|
||||
}
|
||||
|
||||
.file-actions {
|
||||
margin-top: 15px;
|
||||
}
|
||||
|
||||
.file-footer-buttons {
|
||||
float: right;
|
||||
}
|
||||
|
||||
.file-upload-indicator {
|
||||
padding-top: 2px;
|
||||
cursor: default;
|
||||
opacity: 0.8;
|
||||
width: 60%;
|
||||
}
|
||||
|
||||
.file-upload-indicator:hover {
|
||||
font-weight: bold;
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.file-footer-caption {
|
||||
display: block;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
width: 160px;
|
||||
text-align: center;
|
||||
padding-top: 4px;
|
||||
font-size: 11px;
|
||||
color: #777;
|
||||
margin: 5px auto 10px auto;
|
||||
}
|
||||
|
||||
.file-preview-error {
|
||||
opacity: 0.65;
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
.file-preview-frame:not(.file-preview-error) .file-footer-caption:hover {
|
||||
color: #000;
|
||||
}
|
||||
|
||||
.file-drop-zone {
|
||||
border: 1px dashed #aaa;
|
||||
border-radius: 4px;
|
||||
height: 100%;
|
||||
text-align: center;
|
||||
vertical-align: middle;
|
||||
margin: 12px 15px 12px 12px;
|
||||
padding: 5px;
|
||||
}
|
||||
|
||||
.file-drop-zone-title {
|
||||
color: #aaa;
|
||||
font-size: 40px;
|
||||
padding: 85px 10px;
|
||||
}
|
||||
|
||||
.file-highlighted {
|
||||
border: 2px dashed #999 !important;
|
||||
background-color: #f0f0f0;
|
||||
}
|
||||
|
||||
.file-uploading {
|
||||
background: url('../img/loading-sm.gif') no-repeat center bottom 10px;
|
||||
opacity: 0.65;
|
||||
}
|
||||
|
||||
.file-thumb-progress .progress, .file-thumb-progress .progress-bar {
|
||||
height: 10px;
|
||||
font-size: 9px;
|
||||
line-height: 10px;
|
||||
}
|
||||
|
||||
.file-thumbnail-footer {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.file-thumb-progress {
|
||||
position: absolute;
|
||||
top: 22px;
|
||||
left: 0;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
/* IE 10 fix */
|
||||
.btn-file ::-ms-browse {
|
||||
width:100%;
|
||||
height:100%;
|
||||
}
|
||||
|
|
@ -1,11 +0,0 @@
|
|||
/*!
|
||||
* @copyright Copyright © Kartik Visweswaran, Krajee.com, 2014 - 2015
|
||||
* @package bootstrap-fileinput
|
||||
* @version 4.3.1
|
||||
*
|
||||
* File input styling for Bootstrap 3.0
|
||||
* Built for Yii Framework 2.0
|
||||
* Author: Kartik Visweswaran
|
||||
* Year: 2015
|
||||
* For more Yii related demos visit http://demos.krajee.com
|
||||
*/.file-preview-frame,.file-preview-image,.file-preview-other{height:160px;vertical-align:middle}.file-loading{top:0;right:0;width:25px;height:25px;font-size:999px;text-align:right;color:#fff;background:url(../img/loading.gif)top left no-repeat;border:none}.file-object{margin:0 0 -5px;padding:0}.btn-file{position:relative;overflow:hidden}.btn-file input[type=file]{position:absolute;top:0;right:0;min-width:100%;min-height:100%;text-align:right;opacity:0;background:0 0;cursor:inherit;display:block}.file-caption-name{display:inline-block;overflow:hidden;height:20px;word-break:break-all}.input-group-lg .file-caption-name{height:25px}.file-preview-detail-modal{text-align:left}.file-error-message{color:#a94442;background-color:#f2dede;margin:5px;border:1px solid #ebccd1;border-radius:4px;padding:15px}.file-error-message pre,.file-error-message ul{margin:0;text-align:left}.file-error-message pre{margin:5px 0}.file-caption-disabled{background-color:#EEE;cursor:not-allowed;opacity:1}.file-preview{border-radius:5px;border:1px solid #ddd;padding:5px;width:100%;margin-bottom:5px}.file-preview-frame{display:table;margin:8px;border:1px solid #ddd;box-shadow:1px 1px 5px 0 #a2958a;padding:6px;float:left;text-align:center}.file-preview-frame:not(.file-preview-error):hover{box-shadow:3px 3px 5px 0 #333}.file-preview-text{text-align:left;width:160px;margin-bottom:2px;color:#428bca;background:#fff;overflow-x:hidden}.file-preview-other{display:table-cell;text-align:center;width:160px;border:2px solid #999;border-radius:30px}.file-preview-other:hover{opacity:.8}.file-actions,.file-other-error{text-align:left}.file-icon-lg{font-size:1.2em}.file-icon-2x{font-size:2.4em}.file-icon-4x{font-size:4.8em}.file-input-ajax-new .fileinput-remove-button,.file-input-ajax-new .fileinput-upload-button,.file-input-new .close,.file-input-new .file-preview,.file-input-new .fileinput-remove-button,.file-input-new .fileinput-upload-button,.file-input-new .glyphicon-file{display:none}.file-thumb-loading{background:url(../img/loading.gif)center center no-repeat content-box!important}.file-actions{margin-top:15px}.file-footer-buttons{float:right}.file-upload-indicator{padding-top:2px;cursor:default;opacity:.8;width:60%}.file-upload-indicator:hover{font-weight:700;opacity:1}.file-footer-caption{display:block;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;width:160px;text-align:center;padding-top:4px;font-size:11px;color:#777;margin:5px auto 10px}.file-preview-error{opacity:.65;box-shadow:none}.file-preview-frame:not(.file-preview-error) .file-footer-caption:hover{color:#000}.file-drop-zone{border:1px dashed #aaa;border-radius:4px;height:100%;text-align:center;vertical-align:middle;margin:12px 15px 12px 12px;padding:5px}.file-drop-zone-title{color:#aaa;font-size:40px;padding:85px 10px}.file-highlighted{border:2px dashed #999!important;background-color:#f0f0f0}.file-uploading{background:url(../img/loading-sm.gif)center bottom 10px no-repeat;opacity:.65}.file-thumb-progress .progress,.file-thumb-progress .progress-bar{height:10px;font-size:9px;line-height:10px}.file-thumbnail-footer{position:relative}.file-thumb-progress{position:absolute;top:22px;left:0;right:0}.btn-file ::-ms-browse{width:100%;height:100%}
|
||||
|
Before Width: | Height: | Size: 2.6 KiB |
|
Before Width: | Height: | Size: 847 B |
|
|
@ -1,61 +0,0 @@
|
|||
/*!
|
||||
* FileInput Chinese Translations
|
||||
*
|
||||
* This file must be loaded after 'fileinput.js'. Patterns in braces '{}', or
|
||||
* any HTML markup tags in the messages must not be converted or translated.
|
||||
*
|
||||
* @see http://github.com/kartik-v/bootstrap-fileinput
|
||||
* @author kangqf <kangqingfei@gmail.com>
|
||||
*
|
||||
* NOTE: this file must be saved in UTF-8 encoding.
|
||||
*/
|
||||
(function ($) {
|
||||
"use strict";
|
||||
|
||||
$.fn.fileinputLocales['zh'] = {
|
||||
fileSingle: '文件',
|
||||
filePlural: '多个文件',
|
||||
browseLabel: '选择 …',
|
||||
removeLabel: '移除',
|
||||
removeTitle: '清除选中文件',
|
||||
cancelLabel: '取消',
|
||||
cancelTitle: '取消进行中的上传',
|
||||
uploadLabel: '上传',
|
||||
uploadTitle: '上传选中文件',
|
||||
msgNo: '没有',
|
||||
msgCancelled: '取消',
|
||||
msgZoomTitle: '查看详情',
|
||||
msgZoomModalHeading: '详细预览',
|
||||
msgSizeTooLarge: '文件 "{name}" (<b>{size} KB</b>) 超过了允许大小 <b>{maxSize} KB</b>.',
|
||||
msgFilesTooLess: '你必须选择最少 <b>{n}</b> {files} 来上传. ',
|
||||
msgFilesTooMany: '选择的上传文件个数 <b>({n})</b> 超出最大文件的限制个数 <b>{m}</b>.',
|
||||
msgFileNotFound: '文件 "{name}" 未找到!',
|
||||
msgFileSecured: '安全限制,为了防止读取文件 "{name}".',
|
||||
msgFileNotReadable: '文件 "{name}" 不可读.',
|
||||
msgFilePreviewAborted: '取消 "{name}" 的预览.',
|
||||
msgFilePreviewError: '读取 "{name}" 时出现了一个错误.',
|
||||
msgInvalidFileType: '不正确的类型 "{name}". 只支持 "{types}" 类型的文件.',
|
||||
msgInvalidFileExtension: '不正确的文件扩展名 "{name}". 只支持 "{extensions}" 的文件扩展名.',
|
||||
msgUploadAborted: '该文件上传被中止',
|
||||
msgValidationError: '验证错误',
|
||||
msgLoading: '加载第 {index} 文件 共 {files} …',
|
||||
msgProgress: '加载第 {index} 文件 共 {files} - {name} - {percent}% 完成.',
|
||||
msgSelected: '{n} {files} 选中',
|
||||
msgFoldersNotAllowed: '只支持拖拽文件! 跳过 {n} 拖拽的文件夹.',
|
||||
msgImageWidthSmall: '宽度的图像文件的"{name}"的必须是至少{size}像素.',
|
||||
msgImageHeightSmall: '图像文件的"{name}"的高度必须至少为{size}像素.',
|
||||
msgImageWidthLarge: '宽度的图像文件"{name}"不能超过{size}像素.',
|
||||
msgImageHeightLarge: '图像文件"{name}"的高度不能超过{size}像素.',
|
||||
msgImageResizeError: '无法获取的图像尺寸调整。',
|
||||
msgImageResizeException: '错误而调整图像大小。<pre>{errors}</pre>',
|
||||
dropZoneTitle: '拖拽文件到这里 …',
|
||||
fileActionSettings: {
|
||||
removeTitle: '删除文件',
|
||||
uploadTitle: '上传文件',
|
||||
indicatorNewTitle: '没有上传',
|
||||
indicatorSuccessTitle: '上传',
|
||||
indicatorErrorTitle: '上传错误',
|
||||
indicatorLoadingTitle: '上传 ...'
|
||||
}
|
||||
};
|
||||
})(window.jQuery);
|
||||
|
|
@ -1,95 +0,0 @@
|
|||
/*
|
||||
* JavaScript Canvas to Blob 2.0.5
|
||||
* https://github.com/blueimp/JavaScript-Canvas-to-Blob
|
||||
*
|
||||
* Copyright 2012, Sebastian Tschan
|
||||
* https://blueimp.net
|
||||
*
|
||||
* Licensed under the MIT license:
|
||||
* http://www.opensource.org/licenses/MIT
|
||||
*
|
||||
* Based on stackoverflow user Stoive's code snippet:
|
||||
* http://stackoverflow.com/q/4998908
|
||||
*/
|
||||
|
||||
/*jslint nomen: true, regexp: true */
|
||||
/*global window, atob, Blob, ArrayBuffer, Uint8Array, define */
|
||||
|
||||
(function (window) {
|
||||
'use strict';
|
||||
var CanvasPrototype = window.HTMLCanvasElement &&
|
||||
window.HTMLCanvasElement.prototype,
|
||||
hasBlobConstructor = window.Blob && (function () {
|
||||
try {
|
||||
return Boolean(new Blob());
|
||||
} catch (e) {
|
||||
return false;
|
||||
}
|
||||
}()),
|
||||
hasArrayBufferViewSupport = hasBlobConstructor && window.Uint8Array &&
|
||||
(function () {
|
||||
try {
|
||||
return new Blob([new Uint8Array(100)]).size === 100;
|
||||
} catch (e) {
|
||||
return false;
|
||||
}
|
||||
}()),
|
||||
BlobBuilder = window.BlobBuilder || window.WebKitBlobBuilder ||
|
||||
window.MozBlobBuilder || window.MSBlobBuilder,
|
||||
dataURLtoBlob = (hasBlobConstructor || BlobBuilder) && window.atob &&
|
||||
window.ArrayBuffer && window.Uint8Array && function (dataURI) {
|
||||
var byteString,
|
||||
arrayBuffer,
|
||||
intArray,
|
||||
i,
|
||||
mimeString,
|
||||
bb;
|
||||
if (dataURI.split(',')[0].indexOf('base64') >= 0) {
|
||||
// Convert base64 to raw binary data held in a string:
|
||||
byteString = atob(dataURI.split(',')[1]);
|
||||
} else {
|
||||
// Convert base64/URLEncoded data component to raw binary data:
|
||||
byteString = decodeURIComponent(dataURI.split(',')[1]);
|
||||
}
|
||||
// Write the bytes of the string to an ArrayBuffer:
|
||||
arrayBuffer = new ArrayBuffer(byteString.length);
|
||||
intArray = new Uint8Array(arrayBuffer);
|
||||
for (i = 0; i < byteString.length; i += 1) {
|
||||
intArray[i] = byteString.charCodeAt(i);
|
||||
}
|
||||
// Separate out the mime component:
|
||||
mimeString = dataURI.split(',')[0].split(':')[1].split(';')[0];
|
||||
// Write the ArrayBuffer (or ArrayBufferView) to a blob:
|
||||
if (hasBlobConstructor) {
|
||||
return new Blob(
|
||||
[hasArrayBufferViewSupport ? intArray : arrayBuffer],
|
||||
{type: mimeString}
|
||||
);
|
||||
}
|
||||
bb = new BlobBuilder();
|
||||
bb.append(arrayBuffer);
|
||||
return bb.getBlob(mimeString);
|
||||
};
|
||||
if (window.HTMLCanvasElement && !CanvasPrototype.toBlob) {
|
||||
if (CanvasPrototype.mozGetAsFile) {
|
||||
CanvasPrototype.toBlob = function (callback, type, quality) {
|
||||
if (quality && CanvasPrototype.toDataURL && dataURLtoBlob) {
|
||||
callback(dataURLtoBlob(this.toDataURL(type, quality)));
|
||||
} else {
|
||||
callback(this.mozGetAsFile('blob', type));
|
||||
}
|
||||
};
|
||||
} else if (CanvasPrototype.toDataURL && dataURLtoBlob) {
|
||||
CanvasPrototype.toBlob = function (callback, type, quality) {
|
||||
callback(dataURLtoBlob(this.toDataURL(type, quality)));
|
||||
};
|
||||
}
|
||||
}
|
||||
if (typeof define === 'function' && define.amd) {
|
||||
define(function () {
|
||||
return dataURLtoBlob;
|
||||
});
|
||||
} else {
|
||||
window.dataURLtoBlob = dataURLtoBlob;
|
||||
}
|
||||
}(window));
|
||||
|
|
@ -1 +0,0 @@
|
|||
!function(a){"use strict";var b=a.HTMLCanvasElement&&a.HTMLCanvasElement.prototype,c=a.Blob&&function(){try{return Boolean(new Blob)}catch(a){return!1}}(),d=c&&a.Uint8Array&&function(){try{return 100===new Blob([new Uint8Array(100)]).size}catch(a){return!1}}(),e=a.BlobBuilder||a.WebKitBlobBuilder||a.MozBlobBuilder||a.MSBlobBuilder,f=(c||e)&&a.atob&&a.ArrayBuffer&&a.Uint8Array&&function(a){var b,f,g,h,i,j;for(b=a.split(",")[0].indexOf("base64")>=0?atob(a.split(",")[1]):decodeURIComponent(a.split(",")[1]),f=new ArrayBuffer(b.length),g=new Uint8Array(f),h=0;h<b.length;h+=1)g[h]=b.charCodeAt(h);return i=a.split(",")[0].split(":")[1].split(";")[0],c?new Blob([d?g:f],{type:i}):(j=new e,j.append(f),j.getBlob(i))};a.HTMLCanvasElement&&!b.toBlob&&(b.mozGetAsFile?b.toBlob=function(a,c,d){a(d&&b.toDataURL&&f?f(this.toDataURL(c,d)):this.mozGetAsFile("blob",c))}:b.toDataURL&&f&&(b.toBlob=function(a,b,c){a(f(this.toDataURL(b,c)))})),"function"==typeof define&&define.amd?define(function(){return f}):a.dataURLtoBlob=f}(window);
|
||||