Upload All
25
ServerStatus.js
Normal file
@ -0,0 +1,25 @@
|
||||
const fileSystem = require("fs");
|
||||
|
||||
/**
|
||||
* 讀取伺服器狀態檔案。
|
||||
* @param {CallbackFunction} callback 回呼函式。
|
||||
*/
|
||||
function LoadStatus(callback) {
|
||||
fileSystem.readFile("status.json", {encoding: "utf8" }, (err, data) => {
|
||||
if (err) return callback(err, false);
|
||||
module.exports.status = JSON.parse(data);
|
||||
callback(null, true);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 儲存伺服器狀態檔案。
|
||||
* @param {CallbackFunction} callback 回呼函式。
|
||||
*/
|
||||
function SaveStatus(callback) {
|
||||
let data = module.exports.status;
|
||||
fileSystem.writeFile("status.json", JSON.stringify(data), { encoding: "utf8" }, callback);
|
||||
}
|
||||
|
||||
module.exports.LoadStatus = LoadStatus;
|
||||
module.exports.SaveStatus = SaveStatus;
|
BIN
_form/Pug_Record.pages
Normal file
BIN
_form/Restore Data.pages
Normal file
BIN
_form/總表.numbers
Normal file
48
_preserved/OldLoginStrategy.js
Normal file
@ -0,0 +1,48 @@
|
||||
/**
|
||||
* 在「登入」頁面下,處理、驗證使用者所傳的帳號、密碼是否正確。
|
||||
*/
|
||||
router.post("/login", (req, res) => {
|
||||
req.checkBody("username")
|
||||
.notEmpty().withMessage("請輸入登入的使用者名稱。");
|
||||
req.checkBody("password")
|
||||
.notEmpty().withMessage("請輸入登入的密碼。");
|
||||
// 取得錯誤物件結果
|
||||
req.getValidationResult().then((result) => {
|
||||
let errors = result.mapped();
|
||||
let responseMsg = {isOK : result.isEmpty()};
|
||||
// 取得資料插值物件
|
||||
dataRender.DataRender("login", req.session, (err, dataObj) => {
|
||||
if (err) {
|
||||
res.setHeader("Content-Type", "text/plain");
|
||||
res.status(500);
|
||||
res.end("Server side error : 500\n" + err);
|
||||
return;
|
||||
}
|
||||
// 若驗證、檢查成功,則從資料庫中比對帳號、密碼資訊
|
||||
if (responseMsg.isOK) {
|
||||
User.AccountComparison(req.body.username, req.body.password, (err, result) => {
|
||||
// 若帳號密碼比對不成功 或 找不到使用者,則送出錯誤訊息
|
||||
if (!result) {
|
||||
dataObj.isLoginFailed = true;
|
||||
dataObj.loginMessage = "錯誤的帳號名稱或密碼,請重新輸入。";
|
||||
res.render("login", dataObj);
|
||||
return;
|
||||
}
|
||||
else if (err) {
|
||||
dataObj.isLoginFailed = true;
|
||||
dataObj.loginMessage = "很抱歉!伺服端處理時發生錯誤,請稍候重試!";
|
||||
res.render("login", dataObj);
|
||||
return;
|
||||
}
|
||||
res.send(responseMsg);
|
||||
});
|
||||
}
|
||||
else {
|
||||
let firstErr = Object.values(errors)[0]; // 取得第一個錯誤訊息物件
|
||||
dataObj.isLoginFailed = true;
|
||||
dataObj.loginMessage = firstErr.msg; // 將錯誤訊息新增到回應物件的message屬性
|
||||
res.render("login", dataObj);
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
BIN
_preserved/images/3b337a06-7ed5-47f2-93d9-3d04a1724441.png
Normal file
After Width: | Height: | Size: 30 KiB |
BIN
_preserved/images/5063c4d3-9108-4d2e-9690-d110c34fd7e7.png
Normal file
After Width: | Height: | Size: 181 KiB |
BIN
_preserved/images/59492b35-b4b2-46e2-a608-1b52cfddeb58.png
Normal file
After Width: | Height: | Size: 82 KiB |
BIN
_preserved/images/8ada1da7-5f3a-4452-9fef-f6e65de2f004.png
Normal file
After Width: | Height: | Size: 24 KiB |
BIN
_preserved/images/a5d19465-3f8e-43bb-9e75-b8fa44f12cd1.png
Normal file
After Width: | Height: | Size: 33 KiB |
BIN
_preserved/images/cbc3c3d0-8be5-4114-8904-0faded560e8f.png
Normal file
After Width: | Height: | Size: 289 KiB |
BIN
_preserved/images/d6d98d30-d1b5-4528-b2d5-2977290e3687.png
Normal file
After Width: | Height: | Size: 116 KiB |
BIN
_preserved/images/edca9118-e254-4671-bd8c-6ae3a507d4b5.png
Normal file
After Width: | Height: | Size: 607 KiB |
BIN
_preserved/images/f514a6da-a8e8-42df-8ec0-32f98b4d00b7.png
Normal file
After Width: | Height: | Size: 771 KiB |
37
db/default_themes.json
Normal file
@ -0,0 +1,37 @@
|
||||
[
|
||||
{
|
||||
"title": "Nature",
|
||||
"narrative": "繪出您對大自然的熱愛、喜好與印象吧!",
|
||||
"image": "/images/Example.png",
|
||||
"sponsor": "JMuseum",
|
||||
"votes": 0
|
||||
},
|
||||
{
|
||||
"title": "Sunset",
|
||||
"narrative": "想一想,當你坐在山丘上、沙灘上或大樓裡,望著漂亮的落日夕陽,心中是否有種暖暖的感覺呢?繪出你心目中最美麗的落日景象吧!",
|
||||
"image": "/images/Example.png",
|
||||
"sponsor": "JMuseum",
|
||||
"votes": 0
|
||||
},
|
||||
{
|
||||
"title": "Forest",
|
||||
"narrative": "還記得你上次至森林時是什麼時候嗎?回想一下,並將印象最漂亮、最令人印象深刻的森林畫出來吧!",
|
||||
"image": "/images/Example.png",
|
||||
"sponsor": "JMuseum",
|
||||
"votes": 0
|
||||
},
|
||||
{
|
||||
"title": "Voyage",
|
||||
"narrative": "旅遊!還記得你上次旅遊是去哪裡嗎?東京?大阪?香港?或是歐美地區呢?請畫出最令你印象深刻的旅遊場景吧!",
|
||||
"image": "/images/Example.png",
|
||||
"sponsor": "JMuseum",
|
||||
"votes": 0
|
||||
},
|
||||
{
|
||||
"title": "Abstract Art",
|
||||
"narrative": "來談談看不見的事物吧!像是心情、能力、香氣或是感受等等之類的抽象的東西,是否能透過你的創意,將其具象化出來呢?",
|
||||
"image": "/images/Example.png",
|
||||
"sponsor": "JMuseum",
|
||||
"votes": 0
|
||||
}
|
||||
]
|
BIN
db/paintings/300b113f-fa3a-4c95-bda7-76a18b44a1b8.png
Normal file
After Width: | Height: | Size: 228 KiB |
BIN
db/paintings/3b337a06-7ed5-47f2-93d9-3d04a1724441.png
Normal file
After Width: | Height: | Size: 30 KiB |
BIN
db/paintings/4e342214-8e8c-4509-a17f-c1e6e11c05bf.png
Normal file
After Width: | Height: | Size: 454 KiB |
BIN
db/paintings/5063c4d3-9108-4d2e-9690-d110c34fd7e7.png
Normal file
After Width: | Height: | Size: 181 KiB |
BIN
db/paintings/59492b35-b4b2-46e2-a608-1b52cfddeb58.png
Normal file
After Width: | Height: | Size: 82 KiB |
BIN
db/paintings/6432d7a6-e27a-4e1d-bd5d-48031ca8d008.png
Normal file
After Width: | Height: | Size: 74 KiB |
BIN
db/paintings/8a91c903-0ede-4828-aba7-831dd77fcd0d.png
Normal file
After Width: | Height: | Size: 83 KiB |
BIN
db/paintings/8ada1da7-5f3a-4452-9fef-f6e65de2f004.png
Normal file
After Width: | Height: | Size: 24 KiB |
BIN
db/paintings/a5d19465-3f8e-43bb-9e75-b8fa44f12cd1.png
Normal file
After Width: | Height: | Size: 33 KiB |
BIN
db/paintings/cbc3c3d0-8be5-4114-8904-0faded560e8f.png
Normal file
After Width: | Height: | Size: 289 KiB |
BIN
db/paintings/d6d98d30-d1b5-4528-b2d5-2977290e3687.png
Normal file
After Width: | Height: | Size: 116 KiB |
BIN
db/paintings/edca9118-e254-4671-bd8c-6ae3a507d4b5.png
Normal file
After Width: | Height: | Size: 607 KiB |
BIN
db/paintings/f514a6da-a8e8-42df-8ec0-32f98b4d00b7.png
Normal file
After Width: | Height: | Size: 771 KiB |
432
db/restore_datas.json
Normal file
@ -0,0 +1,432 @@
|
||||
{
|
||||
"User":
|
||||
[
|
||||
{
|
||||
"username": "JMuseum",
|
||||
"password": "ze2bu6mo9_z",
|
||||
"personalInfo":
|
||||
{
|
||||
"email": "jmuseum@email.com",
|
||||
"lastName": "Museum",
|
||||
"firstName": "John",
|
||||
"nickname": "JMuseum",
|
||||
"motto": "Always do my best!",
|
||||
"photo": "/images/Example.png"
|
||||
},
|
||||
"tags": [],
|
||||
"paintings": [],
|
||||
"siteMsg": [],
|
||||
"siteMail": [],
|
||||
"notices": 0,
|
||||
"friendList": [],
|
||||
"autoSaveEnable": false,
|
||||
"hasPostFeedback": false,
|
||||
"hasPostNewTheme": false,
|
||||
"hasVotedNewTheme": false
|
||||
},
|
||||
{
|
||||
"username": "Dummy",
|
||||
"password": "my7br5cw3",
|
||||
"personalInfo":
|
||||
{
|
||||
"email": "dummy@email.com",
|
||||
"lastName": "Dummy",
|
||||
"firstName": "Mommy",
|
||||
"nickname": "Dummy",
|
||||
"motto": "I’m dummy!",
|
||||
"photo": "/images/Example.png"
|
||||
},
|
||||
"tags": [],
|
||||
"paintings": [],
|
||||
"siteMsg": [],
|
||||
"siteMail": [],
|
||||
"notices": 0,
|
||||
"friendList": [],
|
||||
"autoSaveEnable": false,
|
||||
"hasPostFeedback": false,
|
||||
"hasPostNewTheme": false,
|
||||
"hasVotedNewTheme": false
|
||||
},
|
||||
{
|
||||
"username": "Alterna",
|
||||
"password": "ze3ct5bu7",
|
||||
"personalInfo":
|
||||
{
|
||||
"email": "alterna@email.com",
|
||||
"lastName": "Dummy",
|
||||
"firstName": "Alternative",
|
||||
"nickname": "Alterna",
|
||||
"motto": "I’m alternative dummy!",
|
||||
"photo": "/images/Example.png"
|
||||
},
|
||||
"tags": [],
|
||||
"paintings": [],
|
||||
"siteMsg": [],
|
||||
"siteMail": [],
|
||||
"notices": 0,
|
||||
"friendList": [],
|
||||
"autoSaveEnable": false,
|
||||
"hasPostFeedback": false,
|
||||
"hasPostNewTheme": false,
|
||||
"hasVotedNewTheme": false
|
||||
}
|
||||
],
|
||||
"Painting":
|
||||
[
|
||||
{
|
||||
"id": "3b337a06-7ed5-47f2-93d9-3d04a1724441",
|
||||
"links": "/db/paintings/3b337a06-7ed5-47f2-93d9-3d04a1724441.png",
|
||||
"name": "Your JMuseum",
|
||||
"description": "The place you can draw!",
|
||||
"artist": "JMuseum",
|
||||
"tags": [],
|
||||
"activity": null,
|
||||
"viewAuthority": 0,
|
||||
"totalScore": 0,
|
||||
"ratings": [],
|
||||
"comments": [],
|
||||
"isFinished": true,
|
||||
"isLocked": false
|
||||
},
|
||||
{
|
||||
"id": "59492b35-b4b2-46e2-a608-1b52cfddeb58",
|
||||
"links": "/db/paintings/59492b35-b4b2-46e2-a608-1b52cfddeb58.png",
|
||||
"name": "The Night Sky",
|
||||
"description": "A beautiful night sky impressed me!",
|
||||
"artist": "JMuseum",
|
||||
"tags": [],
|
||||
"activity": null,
|
||||
"viewAuthority": 0,
|
||||
"totalScore": 0,
|
||||
"ratings": [],
|
||||
"comments": [],
|
||||
"isFinished": true,
|
||||
"isLocked": false
|
||||
},
|
||||
{
|
||||
"id": "cbc3c3d0-8be5-4114-8904-0faded560e8f",
|
||||
"links": "/db/paintings/cbc3c3d0-8be5-4114-8904-0faded560e8f.png",
|
||||
"name": "Bubbles",
|
||||
"description": "Some white bubbles!",
|
||||
"artist": "JMuseum",
|
||||
"tags": [],
|
||||
"activity": null,
|
||||
"viewAuthority": 0,
|
||||
"totalScore": 0,
|
||||
"ratings": [],
|
||||
"comments": [],
|
||||
"isFinished": true,
|
||||
"isLocked": false
|
||||
},
|
||||
{
|
||||
"id": "a5d19465-3f8e-43bb-9e75-b8fa44f12cd1",
|
||||
"links": "/db/paintings/a5d19465-3f8e-43bb-9e75-b8fa44f12cd1.png",
|
||||
"name": "Our JMuseum!",
|
||||
"description": "The place you can enjoy!",
|
||||
"artist": "Dummy",
|
||||
"tags": [],
|
||||
"activity": null,
|
||||
"viewAuthority": 0,
|
||||
"totalScore": 0,
|
||||
"ratings": [],
|
||||
"comments": [],
|
||||
"isFinished": true,
|
||||
"isLocked": false
|
||||
},
|
||||
{
|
||||
"id": "edca9118-e254-4671-bd8c-6ae3a507d4b5",
|
||||
"links": "/db/paintings/edca9118-e254-4671-bd8c-6ae3a507d4b5.png",
|
||||
"name": "Night City",
|
||||
"description": "Abstract. Light and night.",
|
||||
"artist": "Dummy",
|
||||
"tags": [],
|
||||
"activity": null,
|
||||
"viewAuthority": 0,
|
||||
"totalScore": 0,
|
||||
"ratings": [],
|
||||
"comments": [],
|
||||
"isFinished": true,
|
||||
"isLocked": false
|
||||
},
|
||||
{
|
||||
"id": "f514a6da-a8e8-42df-8ec0-32f98b4d00b7",
|
||||
"links": "/db/paintings/f514a6da-a8e8-42df-8ec0-32f98b4d00b7.png",
|
||||
"name": "Line and white",
|
||||
"description": "White line movement. And black space.",
|
||||
"artist": "Dummy",
|
||||
"tags": [],
|
||||
"activity": null,
|
||||
"viewAuthority": 0,
|
||||
"totalScore": 0,
|
||||
"ratings": [],
|
||||
"comments": [],
|
||||
"isFinished": true,
|
||||
"isLocked": false
|
||||
},
|
||||
{
|
||||
"id": "8ada1da7-5f3a-4452-9fef-f6e65de2f004",
|
||||
"links": "/db/paintings/8ada1da7-5f3a-4452-9fef-f6e65de2f004.png",
|
||||
"name": "JMuseum!",
|
||||
"description": "Hola! Our JMuseum!",
|
||||
"artist": "Alterna",
|
||||
"tags": [],
|
||||
"activity": null,
|
||||
"viewAuthority": 0,
|
||||
"totalScore": 0,
|
||||
"ratings": [],
|
||||
"comments": [],
|
||||
"isFinished": true,
|
||||
"isLocked": false
|
||||
},
|
||||
{
|
||||
"_id": "<MongoDB Given>",
|
||||
"id": "d6d98d30-d1b5-4528-b2d5-2977290e3687",
|
||||
"links": "/db/paintings/d6d98d30-d1b5-4528-b2d5-2977290e3687.png",
|
||||
"name": "Night Light Raining",
|
||||
"description": "What a beautiful night!",
|
||||
"artist": "Alterna",
|
||||
"tags": [],
|
||||
"activity": null,
|
||||
"viewAuthority": 0,
|
||||
"totalScore": 0,
|
||||
"ratings": [],
|
||||
"comments": [],
|
||||
"isFinished": true,
|
||||
"isLocked": false
|
||||
},
|
||||
{
|
||||
"_id": "<MongoDB Given>",
|
||||
"id": "5063c4d3-9108-4d2e-9690-d110c34fd7e7",
|
||||
"links": "/db/paintings/5063c4d3-9108-4d2e-9690-d110c34fd7e7.png",
|
||||
"name": "Spirits and devils eye",
|
||||
"description": "A secret ... something.",
|
||||
"artist": "Alterna",
|
||||
"tags": [],
|
||||
"activity": null,
|
||||
"viewAuthority": 0,
|
||||
"totalScore": 0,
|
||||
"ratings": [],
|
||||
"comments": [],
|
||||
"isFinished": true,
|
||||
"isLocked": false
|
||||
}
|
||||
],
|
||||
"Season":
|
||||
[
|
||||
{
|
||||
"nth": 1,
|
||||
"themes": []
|
||||
}
|
||||
],
|
||||
"Theme":
|
||||
[
|
||||
{
|
||||
"order": 0,
|
||||
"title": "JMuseum",
|
||||
"narrative": "Show your love to JMuseum!",
|
||||
"image": "/images/Example.png",
|
||||
"originator": "JMuseum",
|
||||
"participants": [],
|
||||
"views": 32,
|
||||
"commentCount": 0
|
||||
},
|
||||
{
|
||||
"order": 1,
|
||||
"title": "Night View",
|
||||
"narrative": "What is your favorite night view?",
|
||||
"image": "/images/Example.png",
|
||||
"originator": "JMuseum",
|
||||
"participants": [],
|
||||
"views": 32,
|
||||
"commentCount": 0
|
||||
},
|
||||
{
|
||||
"order": 2,
|
||||
"title": "Abstract Art",
|
||||
"narrative": "Very cool and special ideas present in art.",
|
||||
"image": "/images/Example.png",
|
||||
"originator": "JMuseum",
|
||||
"participants": [],
|
||||
"views": 32,
|
||||
"commentCount": 0
|
||||
}
|
||||
],
|
||||
"ParticipantInfo":
|
||||
[
|
||||
{
|
||||
"id": "3b337a06-7ed5-47f2-93d9-3d04a1724441",
|
||||
"links": "/images/seasons/1/3b337a06-7ed5-47f2-93d9-3d04a1724441.png",
|
||||
"rank": 1,
|
||||
"artist": "JMuseum",
|
||||
"paintingName": "Your JMuseum",
|
||||
"description": "The place you can draw!",
|
||||
"totalScore": 5,
|
||||
"ratings": [],
|
||||
"comments": []
|
||||
},
|
||||
{
|
||||
"id": "59492b35-b4b2-46e2-a608-1b52cfddeb58",
|
||||
"links": "/images/seasons/1/59492b35-b4b2-46e2-a608-1b52cfddeb58.png",
|
||||
"rank": 1,
|
||||
"artist": "JMuseum",
|
||||
"paintingName": "The Night Sky",
|
||||
"description": "A beautiful night sky impressed me!",
|
||||
"totalScore": 5,
|
||||
"ratings": [],
|
||||
"comments": []
|
||||
},
|
||||
{
|
||||
"id": "cbc3c3d0-8be5-4114-8904-0faded560e8f",
|
||||
"links": "/images/seasons/1/cbc3c3d0-8be5-4114-8904-0faded560e8f.png",
|
||||
"rank": 1,
|
||||
"artist": "JMuseum",
|
||||
"paintingName": "Bubbles",
|
||||
"description": "Some white bubbles!",
|
||||
"totalScore": 5,
|
||||
"ratings": [],
|
||||
"comments": []
|
||||
},
|
||||
{
|
||||
"id": "a5d19465-3f8e-43bb-9e75-b8fa44f12cd1",
|
||||
"links": "/images/seasons/1/a5d19465-3f8e-43bb-9e75-b8fa44f12cd1.png",
|
||||
"rank": 2,
|
||||
"artist": "Dummy",
|
||||
"paintingName": "Our JMuseum!",
|
||||
"description": "The place you can enjoy!",
|
||||
"totalScore": 4,
|
||||
"ratings": [],
|
||||
"comments": []
|
||||
},
|
||||
{
|
||||
"id": "edca9118-e254-4671-bd8c-6ae3a507d4b5",
|
||||
"links": "/images/seasons/1/edca9118-e254-4671-bd8c-6ae3a507d4b5.png",
|
||||
"rank": 2,
|
||||
"artist": "Dummy",
|
||||
"paintingName": "Night City",
|
||||
"description": "Abstract. Light and night.",
|
||||
"totalScore": 4,
|
||||
"ratings": [],
|
||||
"comments": []
|
||||
},
|
||||
{
|
||||
"id": "f514a6da-a8e8-42df-8ec0-32f98b4d00b7",
|
||||
"links": "/images/seasons/1/f514a6da-a8e8-42df-8ec0-32f98b4d00b7.png",
|
||||
"rank": 2,
|
||||
"artist": "Dummy",
|
||||
"paintingName": "Line and white",
|
||||
"description": "White line movement. And black space.",
|
||||
"totalScore": 4,
|
||||
"ratings": [],
|
||||
"comments": []
|
||||
},
|
||||
{
|
||||
"id": "8ada1da7-5f3a-4452-9fef-f6e65de2f004",
|
||||
"links": "/images/seasons/1/8ada1da7-5f3a-4452-9fef-f6e65de2f004.png",
|
||||
"rank": 3,
|
||||
"artist": "Alterna",
|
||||
"paintingName": "JMuseum!",
|
||||
"description": "Hola! Our JMuseum!",
|
||||
"totalScore": 3,
|
||||
"ratings": [],
|
||||
"comments": []
|
||||
},
|
||||
{
|
||||
"id": "d6d98d30-d1b5-4528-b2d5-2977290e3687",
|
||||
"links": "/images/seasons/1/d6d98d30-d1b5-4528-b2d5-2977290e3687.png",
|
||||
"rank": 3,
|
||||
"artist": "Alterna",
|
||||
"paintingName": "Night Light Raining",
|
||||
"description": "What a beautiful night!",
|
||||
"totalScore": 3,
|
||||
"ratings": [],
|
||||
"comments": []
|
||||
},
|
||||
{
|
||||
"id": "f514a6da-a8e8-42df-8ec0-32f98b4d00b7",
|
||||
"links": "/images/seasons/1/f514a6da-a8e8-42df-8ec0-32f98b4d00b7.png",
|
||||
"rank": 3,
|
||||
"artist": "Alterna",
|
||||
"paintingName": "Spirits and devils eye",
|
||||
"description": "A secret ... something.",
|
||||
"totalScore": 3,
|
||||
"ratings": [],
|
||||
"comments": []
|
||||
}
|
||||
],
|
||||
"Participation":
|
||||
[
|
||||
{
|
||||
"nthSeason": 1,
|
||||
"themeName": "JMuseum",
|
||||
"activityRank": 1
|
||||
},
|
||||
{
|
||||
"nthSeason": 1,
|
||||
"themeName": "Night View",
|
||||
"activityRank": 1
|
||||
},
|
||||
{
|
||||
"nthSeason": 1,
|
||||
"themeName": "Abstract Art",
|
||||
"activityRank": 1
|
||||
},
|
||||
{
|
||||
"nthSeason": 1,
|
||||
"themeName": "JMuseum",
|
||||
"activityRank": 2
|
||||
},
|
||||
{
|
||||
"nthSeason": 1,
|
||||
"themeName": "Night View",
|
||||
"activityRank": 2
|
||||
},
|
||||
{
|
||||
"nthSeason": 1,
|
||||
"themeName": "Abstract Art",
|
||||
"activityRank": 2
|
||||
},
|
||||
{
|
||||
"nthSeason": 1,
|
||||
"themeName": "JMuseum",
|
||||
"activityRank": 3
|
||||
},
|
||||
{
|
||||
"nthSeason": 1,
|
||||
"themeName": "Night View",
|
||||
"activityRank": 3
|
||||
},
|
||||
{
|
||||
"nthSeason": 1,
|
||||
"themeName": "Abstract Art",
|
||||
"activityRank": 3
|
||||
}
|
||||
],
|
||||
"PaintingSpotlight":
|
||||
[
|
||||
{
|
||||
"relation": "index",
|
||||
"paintings": []
|
||||
},
|
||||
{
|
||||
"relation": "gallery",
|
||||
"paintings": []
|
||||
}
|
||||
],
|
||||
"ServerMessage":
|
||||
[
|
||||
{
|
||||
"title": "歡迎你們來到JMuseum!",
|
||||
"content": "現在你可以自由自在地創作,用你的創意、想法去繪畫出你所想要的圖畫出來吧!也可以去「活動藝廊」看看,有哪些是你中意、喜歡的畫作主題,有的話就選定它吧,以指定的主題作為目標,繪製出想要與大家分享、表達的作品吧!"
|
||||
}
|
||||
],
|
||||
"ServerStatus":
|
||||
{
|
||||
"submitThemeEvent": false,
|
||||
"voteThemeEvent": false,
|
||||
"currentSeason": 2,
|
||||
"voteCount": 1,
|
||||
"promotionCount": 5,
|
||||
"onSchedule": false,
|
||||
"autoSaveStatus": false
|
||||
}
|
||||
}
|
96
index.js
Normal file
@ -0,0 +1,96 @@
|
||||
const http = require("http");
|
||||
const path = require('path');
|
||||
const lineReader = require('readline').createInterface({input : process.stdin, output : process.stdout});
|
||||
const bodyParser = require('body-parser');
|
||||
const cookieParser = require('cookie-parser');
|
||||
const express = require("express");
|
||||
const expressValidator = require('express-validator');
|
||||
const session = require('express-session');
|
||||
const passport = require('passport');
|
||||
const flash = require("connect-flash");
|
||||
const mongodb = require("mongodb");
|
||||
const mongoose = require("mongoose");
|
||||
const MongoStore = require('connect-mongo')(session);
|
||||
const pug = require("pug"); // *** Pug的版本為 2.0.0-beta6 ,原先所安裝的Pug無法使用"include" 與 "extended" 指令
|
||||
|
||||
const ServerStatus = require("./ServerStatus");
|
||||
const ResourceManager = require("./models/ResourceManager");
|
||||
|
||||
// 讀取伺服器狀態檔案
|
||||
ServerStatus.LoadStatus((err) => {
|
||||
console.log(err ? "Read server status file failed. Please confirm whether the file is in the root directory.\n" :
|
||||
"Server status file read.\n");
|
||||
});
|
||||
|
||||
// 伺服與網頁應用的變數定義
|
||||
var mongoConnection, database;
|
||||
let port = 12001;
|
||||
let app = express();
|
||||
|
||||
global.__dirname = __dirname; // 在全域之下定義這個專案的根目錄路徑
|
||||
|
||||
// Connect to Database
|
||||
mongoose.Promise = Promise;
|
||||
mongoose.connect('mongodb://localhost/JMuseum', { useMongoClient: true });
|
||||
mongoConnection = mongoose.connection;
|
||||
mongoConnection.on('error', console.error.bind(console, 'connection error:'));
|
||||
mongoConnection.once('open', function() {
|
||||
console.log("Connected to MongoDB.\n");
|
||||
database = mongoose.connection.db;
|
||||
});
|
||||
|
||||
// Initialize Web Server Application
|
||||
app.set("views", "./views");
|
||||
app.set("view engine", "pug");
|
||||
app.use("/", express.static(__dirname + "/public"));
|
||||
app.use(bodyParser.json({ limit: "5mb" }));
|
||||
app.use(bodyParser.urlencoded({ extended: false })); // bodyParser的urlencoded 模組會與 formidable 相衝突
|
||||
app.use(cookieParser());
|
||||
app.use(expressValidator());
|
||||
app.use(flash());
|
||||
app.use(session({
|
||||
secret: "secret",
|
||||
cookie: { maxAge: null },
|
||||
resave: true,
|
||||
store: new MongoStore({ mongooseConnection: mongoose.connection }),
|
||||
saveUninitialized: true
|
||||
}));
|
||||
app.use(passport.initialize());
|
||||
app.use(passport.session());
|
||||
app.use(ResourceManager(__dirname + "/db"));
|
||||
|
||||
// Setting Server Routes
|
||||
app.use("/", require("./routes/main"));
|
||||
|
||||
// Start Server
|
||||
let server = http.createServer(app);
|
||||
server.listen(port, () => {
|
||||
console.log("Server is listening on *:" + port + " ...\n");
|
||||
});
|
||||
|
||||
// Terminal Controls
|
||||
lineReader.on("line", require("./models/ServerControl")(ExitApplication));
|
||||
|
||||
// Process Events
|
||||
function ExitApplication() {
|
||||
// 將文字介面輸入關閉
|
||||
lineReader.close();
|
||||
|
||||
// 把伺服器關閉
|
||||
server.close(() => {
|
||||
console.log("Server closed ..\n");
|
||||
|
||||
// 與MongoDB結束連線
|
||||
mongoose.connection.close().then(() => {
|
||||
console.log("MongoDB disconnected ..\n");
|
||||
});
|
||||
|
||||
// 儲存伺服器狀態檔案
|
||||
ServerStatus.SaveStatus((err) => {
|
||||
console.log(err ? "Save server status file failed. Please confirm whether the file is in the root directory of this project.\n" :
|
||||
"Successfully saved server status file.\n");
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
process.on("exit", ExitApplication);
|
68
models/DataRender.js
Normal file
@ -0,0 +1,68 @@
|
||||
const User = require("./mongooseSchemas/User"); // 引入「使用者 (User)」資料庫表。
|
||||
|
||||
const ServerStatus = require("../ServerStatus");
|
||||
|
||||
/**
|
||||
* 插值來源對應表。可以迅速的比對使用者要求的頁面需要什麼樣的插值。
|
||||
*/
|
||||
const renderList = {
|
||||
"index": require("./renderModels/index"),
|
||||
"gallery": require("./renderModels/gallery"),
|
||||
"theme": require("./renderModels/theme"),
|
||||
"feedback": require("./renderModels/feedback"),
|
||||
"login": require("./renderModels/login"),
|
||||
"signup": require("./renderModels/signup"),
|
||||
"message_form": require("./renderModels/message_form"),
|
||||
"personal_page": require("./renderModels/personal_page"),
|
||||
"edit_personal_info": require("./renderModels/edit_personal_info"),
|
||||
"write_message": require("./renderModels/write_message"),
|
||||
"change_password": require("./renderModels/change_password"),
|
||||
"drawing": require("./renderModels/drawing"),
|
||||
"showcase": require("./renderModels/showcase"),
|
||||
"submit_theme": require("./renderModels/submit_theme"),
|
||||
"vote_theme": require("./renderModels/vote_theme")
|
||||
};
|
||||
|
||||
/**
|
||||
* 插值資料給予者。
|
||||
* 依照使用者所給的路由位置,此函式就會回傳相對應的插值物件。
|
||||
* @param {string} source 頁面的模板來源名稱(Pug Template)。
|
||||
* @param {string} route 路由路徑。
|
||||
* @param {Express.Session} session Express 的 Session物件。
|
||||
* @param {CallbackFunction} callback 回呼函式。傳回錯誤訊息與插值資料。
|
||||
*/
|
||||
function DataRender(source, route, session, callback) {
|
||||
// 檢查Session中是否有passport欄位,若有,則嘗試取得user(資料庫中的_id);若無,則設為null。
|
||||
let _id = session.passport ? session.passport.user : null;
|
||||
// 建構 dataObject 物件
|
||||
let dataObject = {
|
||||
source: source,
|
||||
extendedStyle: source + "_extended.css",
|
||||
title: route,
|
||||
hasLogin: (_id !== undefined && _id !== null),
|
||||
username: null,
|
||||
notices: null,
|
||||
datas: {},
|
||||
haveSubmitThemeEvent: ServerStatus.status.submitThemeEvent,
|
||||
haveVoteThemeEvent: ServerStatus.status.voteThemeEvent
|
||||
};
|
||||
// 嘗試取得資料來設定與目標使用者有關的基本資料(Username與通知數)
|
||||
User.SetBasicInformation(_id, dataObject, function (err, dataObject) {
|
||||
// 若該路由有在清單中,則透過指定的插值方法來為dataObject加入其所需要的資料
|
||||
if (source in renderList) {
|
||||
// 透過source來取得該頁面的插值資料,也就是設定 dataObject.datas 內容。
|
||||
renderList[source].Render(dataObject, route, session, function (err, isSuccess) {
|
||||
if (err)
|
||||
callback(err, null);
|
||||
else
|
||||
callback(null, dataObject);
|
||||
});
|
||||
}
|
||||
// 若不包含在清單中的,則視為例外
|
||||
else {
|
||||
callback(new Error("找不到對應的插值物件或Pug模板。"), null);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
module.exports.DataRender = DataRender;
|
98
models/DataRender.ts
Normal file
@ -0,0 +1,98 @@
|
||||
|
||||
const User = require("./mongooseSchemas/User"); // 引入「使用者 (User)」資料庫表。
|
||||
|
||||
/**
|
||||
* A Callback function.
|
||||
* @callback CallbackFunction
|
||||
* @param {Object} err 錯誤資訊物件。
|
||||
* @param {Object} obj 成功時所回傳的物件。
|
||||
*/
|
||||
interface CallbackFunction { (err: Object, obj: Object) : void }
|
||||
|
||||
/**
|
||||
* Standard data render layout
|
||||
*/
|
||||
interface BasicLayout {
|
||||
/** 紀錄使用者目前在哪個頁面上。 */
|
||||
source : string,
|
||||
|
||||
/** 延伸的CSS檔案名稱。 */
|
||||
extendedStyle : string,
|
||||
|
||||
/** 網頁的標題名稱。 */
|
||||
title : string,
|
||||
|
||||
/** 紀錄使用者是否登入網站。 */
|
||||
hasLogin : boolean,
|
||||
|
||||
/** 使用者的名稱。 */
|
||||
username : string,
|
||||
|
||||
/** 使用者的通知數。 */
|
||||
notices : number,
|
||||
|
||||
/** 放置主要資料的物件。 */
|
||||
datas : any,
|
||||
|
||||
/** 是否有「投稿主題」的活動、頁面在進行。 */
|
||||
haveSubmitThemeEvent : boolean,
|
||||
|
||||
/** 是否有「投票主題」的活動、頁面在進行。 */
|
||||
haveVoteThemeEvent : boolean
|
||||
}
|
||||
|
||||
/**
|
||||
* 插值來源對應表。可以迅速的比對使用者要求的頁面需要什麼樣的插值。
|
||||
*/
|
||||
const renderList =
|
||||
{
|
||||
"index" : require("./renderModels/index"),
|
||||
"gallery" : require("./renderModels/gallery"),
|
||||
"theme": require("./renderModels/theme"),
|
||||
"feedback": require("./renderModels/feedback"),
|
||||
"login": require("./renderModels/login"),
|
||||
"signup": require("./renderModels/signup")
|
||||
};
|
||||
|
||||
/**
|
||||
* 轉跳頁面、訊息頁面所用的插值,比起renderList中的差值,這有較大的靈活性。
|
||||
*/
|
||||
const messageRender = require("./renderModels/message_form");
|
||||
|
||||
/**
|
||||
* 插值資料給予者。
|
||||
* 依照使用者所給的路由位置,此函式就會回傳相對應的插值物件。
|
||||
* @param {string} source 頁面的模板來源名稱(Pug Template)。
|
||||
* @param {string} route 路由路徑。
|
||||
* @param {any} session Express 的 Session物件。
|
||||
* @param {CallbackFunction} callback 回呼函式。傳回錯誤訊息與插值資料。
|
||||
*/
|
||||
function DataRender(source: string, route : string, session : any, callback : CallbackFunction) : void
|
||||
{
|
||||
// 檢查Session中是否有passport欄位,若有,則嘗試取得user(資料庫中的_id);若無,則設為null。
|
||||
let _id = session.passport ? session.passport.user : null;
|
||||
// 建構 dataObject 物件
|
||||
let dataObject : BasicLayout = {
|
||||
source : source,
|
||||
extendedStyle : source + "_extended.css",
|
||||
title : route,
|
||||
hasLogin : (_id !== undefined && _id !== null),
|
||||
username : null,
|
||||
notices : null,
|
||||
datas : {},
|
||||
haveSubmitThemeEvent : false,
|
||||
haveVoteThemeEvent : false
|
||||
};
|
||||
// 嘗試取得資料來設定與目標使用者有關的基本資料(Username與通知數)
|
||||
User.SetBasicInformation(_id, dataObject, (err, dataObject) => {
|
||||
// 透過route來取得該頁面的插值資料,也就是設定 dataObject.datas 內容。
|
||||
renderList[source].Render(dataObject, (err, isSuccess) => {
|
||||
if (err)
|
||||
callback(err, null);
|
||||
else
|
||||
callback(null, dataObject);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
module.exports.DataRender = DataRender;
|
57
models/ResourceManager.js
Normal file
@ -0,0 +1,57 @@
|
||||
const User = require("./mongooseSchemas/User");
|
||||
const Painting = require("./mongooseSchemas/Painting");
|
||||
|
||||
const router = require("express").Router();
|
||||
|
||||
let sourceDir;
|
||||
|
||||
/**
|
||||
* 用於初始化的函式。
|
||||
* @param {string} sourceDirectory 被管理的資源的根目錄。
|
||||
*/
|
||||
function Initialize(sourceDirectory) {
|
||||
sourceDir = sourceDirectory;
|
||||
return router;
|
||||
}
|
||||
|
||||
/**
|
||||
* 檢查使用者是否登入。如果已登入,則進行下一步;反之,則回送403狀態碼。
|
||||
* @param {Express.Request} req Express的Request物件。
|
||||
* @param {Express.Response} res Express的Response物件。
|
||||
* @param {Function} next 導向函式。
|
||||
*/
|
||||
function CheckUserLogin(req, res, next) {
|
||||
if (req.session.passport && req.session.passport.user) {
|
||||
next();
|
||||
}
|
||||
else {
|
||||
res.state(403).send("Forbidden");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 嘗試取得指定的圖畫影像。經過登入檢查之後,還要再檢查該項圖畫是否存在或屬於使用者。
|
||||
*/
|
||||
router.get("/db/paintings/:painting_file", (req, res) => {
|
||||
let user_id = (req.session.passport && req.session.passport.user) ? req.session.passport.user : null;
|
||||
let fileName = req.params.painting_file; // 取得URL參數中的檔案名稱
|
||||
let painting_id = fileName.substr(0, fileName.length - 4); // 去掉後面的".png"
|
||||
|
||||
// 檢查使用者是否有足夠的權限訪問此畫作
|
||||
Painting.CheckViewAuthority(painting_id, user_id, (err, result) => {
|
||||
if (err) {
|
||||
res.state(500).send("Internal Server Error");
|
||||
return;
|
||||
}
|
||||
// 若權限足夠,則將圖畫檔案送至客戶端;若無則回送403。
|
||||
if (result) {
|
||||
res.status(200).sendFile(sourceDir + "/paintings/" + fileName);
|
||||
}
|
||||
else {
|
||||
res.status(403).send("Forbidden");
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
module.exports = Initialize;
|
1027
models/ServerControl.js
Normal file
28
models/mongooseSchemas/Comment.js
Normal file
@ -0,0 +1,28 @@
|
||||
const mongoose = require("mongoose");
|
||||
const Schema = mongoose.Schema;
|
||||
|
||||
let CommentSchema = Schema({
|
||||
username : String,
|
||||
photo : String,
|
||||
comment : String,
|
||||
time : {type : Date, default : new Date()},
|
||||
fromActivity : {type : Boolean, default : false}
|
||||
});
|
||||
|
||||
CommentSchema.statics.createNewComment = function (data, callback) {
|
||||
let newComment = this({
|
||||
username: data.username,
|
||||
photo: data.photo,
|
||||
comment: data.comment,
|
||||
time: new Date(),
|
||||
fromActivity: data.fromActivity
|
||||
});
|
||||
newComment.save((err, comment) => {
|
||||
if (err)
|
||||
callback(err, null);
|
||||
else
|
||||
callback(null, comment._id);
|
||||
});
|
||||
}
|
||||
|
||||
module.exports = mongoose.model("Comment", CommentSchema);
|
73
models/mongooseSchemas/NewTheme.js
Normal file
@ -0,0 +1,73 @@
|
||||
const mongoose = require("mongoose");
|
||||
const Schema = mongoose.Schema;
|
||||
|
||||
const User = require("./User");
|
||||
|
||||
const Error_HaveSameThemeTitle = new Error("已經存在相同的主題名稱。");
|
||||
const Error_ExistSameSponser = new Error("使用者已經在先前發起過一次主題了。");
|
||||
|
||||
let NewTheme = Schema({
|
||||
title: String,
|
||||
narrative: String,
|
||||
image: String, // Image URL
|
||||
sponsor: String,
|
||||
votes: [String],
|
||||
createdTime: { type: Date, default: Date.now }
|
||||
});
|
||||
|
||||
/**
|
||||
* 外部傳進來的新主題的必要資料項。
|
||||
* @typedef NewThemeDatas
|
||||
* @prop {string} title 新主題的主題名稱。
|
||||
* @prop {string} narrative 新主題的主題敘述。
|
||||
* @prop {string} image 新主題的圖示的連結位置。
|
||||
* @prop {string} sponsor 此新主題的發起人之使用者名稱。
|
||||
*/
|
||||
/**
|
||||
* 建立一個新的「新主題」資料。
|
||||
* @param {NewThemeDatas} datas 原初的資料集合。
|
||||
* @param {CallbackFunction} callback 回呼函式。成功時回呼_id。
|
||||
*/
|
||||
NewTheme.statics.createNew_NewTheme = function(datas, callback) {
|
||||
// 先檢查是否已有存在了相同的主題名稱 或 發起人在先前已經有發起過一次了
|
||||
this.findOne({title: datas.title}, (err, docs) => {
|
||||
if (err) return callback(err, null);
|
||||
if (docs) return callback(Error_HaveSameThemeTitle, null); // 若使用者發起的主題名稱,別人已經發起過,則回呼錯誤
|
||||
|
||||
// 建立新的主題名稱資料
|
||||
let new_NewTheme = this({
|
||||
title: datas.title,
|
||||
narrative: datas.narrative,
|
||||
image: datas.image,
|
||||
sponsor: datas.sponsor,
|
||||
votes: [],
|
||||
createdTime: new Date()
|
||||
});
|
||||
|
||||
// 將其儲存後並回呼
|
||||
new_NewTheme.save((err) => {
|
||||
if (err) return callback(err, null);
|
||||
callback(null, new_NewTheme._id);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 檢查是否為「已經存在相同的主題名稱」之錯誤。
|
||||
* @param {Error} error 欲進行檢查的錯誤。
|
||||
* @return {boolean} 檢查之結果。
|
||||
*/
|
||||
NewTheme.statics.IsError_HaveSameThemeTitle = function (error) {
|
||||
return error === Error_HaveSameThemeTitle;
|
||||
}
|
||||
|
||||
/**
|
||||
* 檢查是否為「已經存在相同的主題名稱」之錯誤。
|
||||
* @param {Error} error 欲進行檢查的錯誤。
|
||||
* @return {boolean} 檢查之結果。
|
||||
*/
|
||||
NewTheme.statics.IsError_ExistSameSponser = function (error) {
|
||||
return error === Error_ExistSameSponser;
|
||||
}
|
||||
|
||||
module.exports = mongoose.model("NewTheme", NewTheme);
|
392
models/mongooseSchemas/Painting.js
Normal file
@ -0,0 +1,392 @@
|
||||
const mongoose = require("mongoose");
|
||||
const Jimp = require("jimp");
|
||||
const uuid = require("uuid/v4");
|
||||
|
||||
const Participation = require("./Participation");
|
||||
const Rating = require("./Rating");
|
||||
const Comment = require("./Comment");
|
||||
let User;
|
||||
|
||||
const Schema = mongoose.Schema;
|
||||
|
||||
const Error_PaintingNotExist = new Error("尋找的目標畫作不存在。");
|
||||
const Error_PaintingIsLocked = new Error("此畫作已被鎖定,無法對其做任何修改。");
|
||||
const Error_PaintingHasFinished = new Error("此畫作已經完成,無法再做一次完成的動作。");
|
||||
|
||||
let PaintingSchema = Schema({
|
||||
id: String,
|
||||
links: String,
|
||||
name: String,
|
||||
description: String,
|
||||
artist: String,
|
||||
createdTime: {type : Date, default : Date.now },
|
||||
lastModified: {type : Date, default : Date.now },
|
||||
tags: [{type : String}],
|
||||
activity: {type : Schema.Types.ObjectId, ref: "Participation"},
|
||||
viewAuthority: Number,
|
||||
totalScore: Number,
|
||||
ratings: [{type : Schema.Types.ObjectId, ref: "Rating"}],
|
||||
comments: [{type : Schema.Types.ObjectId, ref: "Comment"}],
|
||||
isFinished: Boolean,
|
||||
isLocked: Boolean
|
||||
});
|
||||
|
||||
/**
|
||||
* 交叉引入,由User來呼叫。
|
||||
*/
|
||||
PaintingSchema.statics.crossInitByUser = function () {
|
||||
User = Object.freeze(require("./User"));
|
||||
}
|
||||
|
||||
/**
|
||||
* 建立新畫作的基本必要資料。
|
||||
* @typedef NewPaintingData
|
||||
* @prop {string} name 作品名稱。
|
||||
* @prop {string} description 作品的敘述。
|
||||
* @prop {string} artist 畫作的作者。即使用者名稱。
|
||||
* @prop {string[]} tags 此畫作的標籤。
|
||||
* @prop {number} viewAuthority 作品的訪問權限。0=公開;1=半公開;2=私人。
|
||||
* @prop {boolean} isFinished 作品是否完成。
|
||||
*/
|
||||
/**
|
||||
* 建立一個新的畫作。
|
||||
* @param {NewPaintingData} data 用於建立新畫作的基本資料。
|
||||
* @param {CallbackFunction} callback 回呼函式。成功時回呼畫作的_id。
|
||||
*/
|
||||
PaintingSchema.statics.createNewPainting = function (data, callback) {
|
||||
let createdDate = new Date();
|
||||
let paintingUUID = uuid();
|
||||
let newPainting = this({
|
||||
id : paintingUUID,
|
||||
links : "/db/paintings/" + paintingUUID + ".png",
|
||||
name : data.name,
|
||||
description : data.description,
|
||||
artist : data.artist,
|
||||
createdTime : createdDate,
|
||||
lastModified : createdDate,
|
||||
tags : data.tags,
|
||||
activity : null,
|
||||
viewAuthority : data.viewAuthority,
|
||||
totalScore : 0,
|
||||
ratings : [],
|
||||
comments : [],
|
||||
isFinished : data.isFinished,
|
||||
isLocked : false
|
||||
});
|
||||
newPainting.save((err, painting) => {
|
||||
if (err)
|
||||
callback(err, null);
|
||||
else
|
||||
callback(null, {_id: painting._id, id: paintingUUID, lastModified: createdDate});
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 一個包含所有要更新的圖畫資訊的物件。
|
||||
* @typedef NewPaintingInfo
|
||||
* @prop {string} name 作品名稱
|
||||
* @prop {string} description 作品的敘述。
|
||||
* @prop {string[]} taglist 標籤清單。
|
||||
* @prop {number} view_authority 作品的訪問權限。
|
||||
* @prop {boolean} isFinished 作品是否完成。
|
||||
*/
|
||||
/**
|
||||
* 透過傳入的圖畫id尋找目標的圖畫資料,以new_info來更新其資訊。
|
||||
* @param {NewPaintingInfo} new_info 要更新目標圖畫資訊的物件。
|
||||
* @param {string} id 目標圖畫資料的ID。
|
||||
* @param {Jimp.Jimp} image Jimp影像物件。用來更新圖畫資料。
|
||||
* @param {CallbackFunction} callback 回呼函式。若成功則回呼圖畫的_id與最後更新時間;其餘皆為錯誤。
|
||||
*/
|
||||
PaintingSchema.statics.UpdateInfoById = function (new_info, id, image, callback) {
|
||||
// 以圖畫id來取得目標資料
|
||||
this.findOne({"id": id}, (err, paintingDocs) => {
|
||||
if (err) return callback(err, null);
|
||||
if (!paintingDocs) return callback(Error_PaintingNotExist, null); // 若找不到畫作資料,則回呼錯誤
|
||||
if (paintingDocs.isLocked) return callback(Error_PaintingIsLocked, null); // 若目標畫作為「鎖定」狀態,則回乎錯誤
|
||||
let isFinished_before = paintingDocs.isFinished; // 取得更改之前的isFinished的狀態
|
||||
let newLastModified = new Date(); // 更新「最後修改日期」的時間
|
||||
|
||||
// 若目前作品已完成 且 使用者還想再次「完成」此作品,則回報錯誤
|
||||
if (isFinished_before && new_info.isFinished) return callback(Error_PaintingHasFinished, null);
|
||||
|
||||
// 更新資料
|
||||
paintingDocs.name = new_info.name;
|
||||
paintingDocs.description = new_info.description;
|
||||
paintingDocs.tags = new_info.taglist;
|
||||
paintingDocs.viewAuthority = new_info.view_authority;
|
||||
|
||||
// 「最後修改日期」是隨著圖畫內容是否更動而變的
|
||||
if (!isFinished_before)
|
||||
paintingDocs.lastModified = newLastModified;
|
||||
|
||||
// 一但完成作品之後,就不會再回到「沒有完成」的狀態了。
|
||||
paintingDocs.isFinished = isFinished_before || new_info.isFinished;
|
||||
|
||||
// 將圖畫資料儲存後並回呼
|
||||
paintingDocs.save((err) => {
|
||||
if (err) return callback(err, null);
|
||||
|
||||
/**
|
||||
* 幾本上針對「作品完成」狀態與動作有四種情況:
|
||||
* 儲存前 儲存動作
|
||||
* 1. 未完成 不完成 : 作品未完成情況下,執行一般的「儲存」動作。
|
||||
* 2. 未完成 完成 : 作品未完成情況下,執行「完成圖畫」的動作。
|
||||
* 3. 已完成 不完成 : 作品已完成情況下,執行一般的「儲存」動作。也就是不更改畫作影像,僅變更畫作的相關資訊。動作完成後,圖畫仍為「完成」狀態。
|
||||
* 4. 已完成 完成 : 作品已完成情況下,執行「完成圖畫」的動作。這是不被允許的,一個作品完成之後就不能再「完成」第二次。
|
||||
* 在上頭的程式碼 "if (isFinished_before && new_info.isFinished) ..." 中,已將第4種情況剔除,
|
||||
* 因此以下拿 paintingDocs.isFinished 來判斷是否更新圖畫影像。
|
||||
*/
|
||||
if (!isFinished_before) {
|
||||
// 將新的影像複寫在舊的影像之上
|
||||
image.write("./db/paintings/" + paintingDocs.id + ".png", (err) => {
|
||||
if (err) return callback(err, null);
|
||||
callback(null, {_id: paintingDocs._id, lastModified: newLastModified});
|
||||
});
|
||||
}
|
||||
else {
|
||||
callback(null, {_id: paintingDocs._id, lastModified: newLastModified});
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 確認使用者(user_id)對於畫作(paintingId)的訪問權限是否足夠。
|
||||
* 若訪問權限足夠,回呼圖畫id;反之,則回呼false。
|
||||
* @param {string} paintingId 畫作的Id。
|
||||
* @param {string} user_id 使用者的_id。
|
||||
* @param {CallbackFunction} callback 回呼函式。
|
||||
*/
|
||||
PaintingSchema.statics.CheckViewAuthority = function (paintingId, user_id, callback) {
|
||||
this.findOne({"id": paintingId})
|
||||
.select("id artist link viewAuthority")
|
||||
.exec((err, paintingDocs) => {
|
||||
if (err) return callback(err, null);
|
||||
if (!paintingDocs) return callback(null, false); // 若尋找的圖畫Id不存在,則回乎false。
|
||||
|
||||
// 當訪問權限為「公開」時,則直接回呼
|
||||
if (paintingDocs.viewAuthority == 0) {
|
||||
callback(null, paintingId);
|
||||
}
|
||||
// 當訪問權限為「半公開」或「私人」時,且使用者有登入時,則近一步判斷。
|
||||
else if (user_id){
|
||||
// 取得圖畫作者的資料,判斷使用者是否正為圖畫作者 或 圖畫作者的好友。
|
||||
User.findOne({"username": paintingDocs.artist}, "_id friendList", (err, artistDocs) => {
|
||||
if (err) return callback(err, null);
|
||||
let isArtist = user_id == artistDocs._id; // 使用者是否為圖畫作者
|
||||
let isFriend = artistDocs.IsUsersFriend(user_id); // 使用者是否為圖畫作者的好友
|
||||
let check = isArtist || (paintingDocs.viewAuthority == 1 && isFriend); // 只要是圖畫作者 或 圖畫作者的朋友且訪問權限為「半公開」,則可以瀏覽此圖畫。
|
||||
let result = check ? paintingId : false; // 依 check 取得結果
|
||||
callback(null, result);
|
||||
});
|
||||
}
|
||||
// 若圖畫訪問權限不為「公開」,且使用者又沒登入,則回呼false。
|
||||
else {
|
||||
callback(null, false);
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* 透過畫作Id取得在「繪圖創作」頁面上所需要的畫作資料。
|
||||
* @param {string} paintingId 指定的畫作Id。
|
||||
* @param {CallbackFunction} 回呼函式。若成功找到,則將畫作資料回呼;若失敗則為null。
|
||||
*/
|
||||
PaintingSchema.statics.GetDrawingPageInfoById = function (paintingId, callback) {
|
||||
this.findOne({ "id": paintingId })
|
||||
.populate({ path: "activity", select: { "nthSeason": 1, "themeName": 1 } })
|
||||
.exec((err, paintingDocs) => {
|
||||
if (err) return callback(err, null);
|
||||
if (!paintingDocs) return callback(null, null);
|
||||
|
||||
paintingDocs.paintingName = paintingDocs.name; // 差值需求表定義之中,與Painting資料表唯一不一樣的地方。 paintingName: paintingDocs.name
|
||||
callback(null, paintingDocs);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* 判斷錯誤是否為「指定的畫作不存在」。
|
||||
* @return {boolean} 檢查的結果。
|
||||
*/
|
||||
PaintingSchema.statics.IsError_PaintingNotExist = function (error) {
|
||||
return error == Error_PaintingNotExist;
|
||||
}
|
||||
|
||||
/**
|
||||
* 判斷錯誤是否為「畫作已被鎖定無法更改」。
|
||||
* @return {boolean} 檢查結果。
|
||||
*/
|
||||
PaintingSchema.statics.IsError_PaintingIsLocked = function (error) {
|
||||
return error == Error_PaintingIsLocked;
|
||||
}
|
||||
|
||||
/**
|
||||
* 判斷錯誤是否為「畫作已完成無法做二次完成動作」
|
||||
* @return {boolean} 檢查結果。
|
||||
*/
|
||||
PaintingSchema.statics.IsError_PaintingHasFinished = function (error) {
|
||||
return error == Error_PaintingHasFinished;
|
||||
}
|
||||
|
||||
/**
|
||||
* 取得「找不到指定畫作」的錯誤。
|
||||
* @return {Error} 錯誤 Error_PaintingNotExist 。
|
||||
*/
|
||||
PaintingSchema.statics.GetError_PaintingNotExist = function () {
|
||||
return Error_PaintingNotExist;
|
||||
}
|
||||
|
||||
/**
|
||||
* 移除所有與圖畫有關聯的「留言(Comment)」、「評分(Rating)」與「參與活動(Participation)」
|
||||
* @param {CallbackFunction} callback 回呼函式。
|
||||
*/
|
||||
PaintingSchema.methods.RemoveAllReferenceInfo = function (callback) {
|
||||
Participation.remove({"_id": this.activity}, (err) => {
|
||||
if (err) return callback(err, null);
|
||||
|
||||
Rating.remove({"_id": { $in: this.ratings } }, (err) => {
|
||||
if (err) return callback(err, null);
|
||||
|
||||
Comment.remove({"_id": { $in: this.comments }}, (err) => {
|
||||
if (err) return callback(err, null);
|
||||
callback(null, true);
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 尋找使用者(Username)對這幅畫作的評分。若沒有,則回傳0。
|
||||
* 注意,畫作資料必須要對ratings欄位做Populate之後,此函式執行才會有正確的結果。
|
||||
* @param {string} username 使用者名稱。
|
||||
* @return {number} 目標使用者的評分分數。
|
||||
*/
|
||||
PaintingSchema.methods.FindRatingScoreByUsername = function (username) {
|
||||
for (let rating of this.ratings) {
|
||||
if (rating.username == username)
|
||||
return rating.score;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 透過畫作Id尋找指定的畫作資料,將留言新增到其中。
|
||||
* @param {string} paintingId 指定的畫作Id。
|
||||
* @param {string} username 留言的使用者。
|
||||
* @param {string} userPhotoURL 留言使用者的個人圖像。
|
||||
* @param {string} comment 留言內容。
|
||||
* @param {CallbackFunction} callback 回呼函式。
|
||||
*/
|
||||
PaintingSchema.statics.PushNewComment = function (paintingId, username, userPhotoURL, comment, callback) {
|
||||
// 尋找目標畫作
|
||||
this.findOne({"id": paintingId}, "comments", (err, paintingDocs) => {
|
||||
if (err) return callback(err, null);
|
||||
if (!paintingDocs) return callback(Error_PaintingNotExist, null);
|
||||
|
||||
// 定義留言資料
|
||||
let newComment = {
|
||||
username: username,
|
||||
photo: userPhotoURL,
|
||||
comment: comment,
|
||||
time: new Date()
|
||||
};
|
||||
|
||||
// 新增留言
|
||||
Comment.createNewComment(newComment, (err, _id) => {
|
||||
if (err) return callback(err, null);
|
||||
|
||||
// 將該項留言連結至目標畫作
|
||||
paintingDocs.comments.push(_id);
|
||||
paintingDocs.save((err) => {
|
||||
if (err)
|
||||
callback(err, null);
|
||||
else
|
||||
callback(null, _id);
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 以使用者名稱(username)來尋找對應的評分(Rating)。
|
||||
* 注意,必須要先連結(Populate)過ratings欄位之後,才能使用此函式。
|
||||
* @param {string} username 目標使用者名稱。
|
||||
* @return {Rating?} 評分資料。
|
||||
*/
|
||||
PaintingSchema.methods.FindRatingByUsername = function (username) {
|
||||
for (let docs of this.ratings) {
|
||||
if (docs.username == username)
|
||||
return docs;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新totalScore欄位。注意,必須要先連結(Populate)過ratings欄位之後,才能使用此函式。
|
||||
*/
|
||||
PaintingSchema.methods.UpdateTotalScore = function () {
|
||||
let sum = 0;
|
||||
for (let docs of this.ratings) {
|
||||
sum += docs.score;
|
||||
}
|
||||
this.totalScore = sum / this.ratings.length;
|
||||
}
|
||||
|
||||
/**
|
||||
* 透過畫作Id尋找指定的畫作,將評分分數更新到其上。
|
||||
* @param {string} paintingId 指定的畫作Id。
|
||||
* @param {string} username 評分的使用者名稱。
|
||||
* @param {number} score 評分分數。
|
||||
* @param {CallbackFunction} callback 回呼函式。
|
||||
*/
|
||||
PaintingSchema.statics.UpdateRatingById = function (paintingId, username, score, callback) {
|
||||
// 以圖畫Id,尋找指定的畫作資料
|
||||
this.findOne({"id": paintingId})
|
||||
.select("ratings totalScore")
|
||||
.populate("ratings")
|
||||
.exec((err, paintingDocs) => {
|
||||
if (err) return callback(err, null);
|
||||
if (!paintingDocs) return callback(Error_PaintingNotExist, null);
|
||||
let datas = { username: username, score: score }; // Rating建立新資料
|
||||
|
||||
// 檢查使用者在之前是否已有做過評分
|
||||
let ratingDocs = paintingDocs.FindRatingByUsername(username);
|
||||
|
||||
// 若在先前已有評分過,則
|
||||
if (ratingDocs) {
|
||||
ratingDocs.score = score; // 更新評分分數
|
||||
paintingDocs.UpdateTotalScore(); // 更新totalScore欄位
|
||||
|
||||
// 儲存評分資料
|
||||
ratingDocs.save((err) => {
|
||||
if (err) return callback(err, null);
|
||||
|
||||
// 儲存畫作資料
|
||||
paintingDocs.save((err) => {
|
||||
if (err) return callback(err, null);
|
||||
callback(null, paintingDocs._id);
|
||||
});
|
||||
});
|
||||
}
|
||||
else {
|
||||
// 創立一個新的評分
|
||||
Rating.createNewRating(datas, (err, ratingDocs) => {
|
||||
if (err) return callback(err, null);
|
||||
paintingDocs.ratings.push(ratingDocs); // 將新的評分加入
|
||||
paintingDocs.UpdateTotalScore(); // 更新總評分
|
||||
|
||||
// 儲存畫作資料
|
||||
paintingDocs.save((err) => {
|
||||
if (err) return callback(err, null);
|
||||
callback(null, paintingDocs._id);
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
module.exports = mongoose.model("Painting", PaintingSchema);
|
65
models/mongooseSchemas/PaintingSpotlight.js
Normal file
@ -0,0 +1,65 @@
|
||||
const mongoose = require("mongoose")
|
||||
const Schema = mongoose.Schema;
|
||||
|
||||
/**
|
||||
* 回呼函式,表示是否成功,並回傳物件。
|
||||
* @callback CallbackFunction
|
||||
* @param {Object} err 表示是否失敗。
|
||||
* @param {Object} obj 表示回呼的物件。
|
||||
*/
|
||||
|
||||
/**
|
||||
* 精選集的模板定義。
|
||||
* @property {String} relation 表示此精選集的所屬。如首頁的精選集、藝廊的精選輯。
|
||||
* @property {Schema.Types.ObjectId[]} paintings 表示此精選集所有連接的圖畫。
|
||||
*/
|
||||
let PaintingSpotlightSchema = Schema({
|
||||
relation : {type : String, required : true},
|
||||
paintings : [{type : Schema.Types.ObjectId, ref : "Painting"}]
|
||||
});
|
||||
|
||||
/**
|
||||
* 建立一個新的精選集。
|
||||
* @param {Object} data 包含要設定精選輯的資料。
|
||||
* @param {function} callback 回呼函式。
|
||||
*/
|
||||
PaintingSpotlightSchema.statics.createNewPaintingSpotlight = function (data, callback) {
|
||||
let newPaintingSpotlight = { relation : data.relation, paintings : data.paintings };
|
||||
newPaintingSpotlight.save((err, paintingSpotlight) => {
|
||||
if (err)
|
||||
callback(err, null);
|
||||
else
|
||||
callback(null, paintingSpotlight._id);
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 指定一個精選集,將新畫作加入進去。
|
||||
* @param {string} collName 要加入新畫作的精選集。
|
||||
* @param {objectId} painting 要加入的新畫作的Id。
|
||||
* @param {function} callback 回呼函式(Error, IsSuccess)。
|
||||
*/
|
||||
PaintingSpotlightSchema.statics.addNewPaintingToCollection = function (collName, painting, callback) {
|
||||
this.findOne({relation : collName}, (err, obj) => {
|
||||
if (err) {
|
||||
callback(err, null);
|
||||
return;
|
||||
}
|
||||
obj.paintings.push(painting);
|
||||
obj.save((err, RObj) => {
|
||||
callback(err, RObj != null && RObj != undefined);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 取得畫作展示所要的資訊
|
||||
* @param {string} collName 精選集的名稱
|
||||
* @param {function} callback 回呼函式(Error, IsSuccess)。
|
||||
*/
|
||||
PaintingSpotlightSchema.statics.GetCarouselInfo = function (collName, callback) {
|
||||
let query = {path : "paintings", select : {links : 1, name : 1, description : 1, artist : 1}};
|
||||
this.findOne({"relation" : collName}).populate(query).exec(callback);
|
||||
};
|
||||
|
||||
module.exports = mongoose.model("PaintingSpotlight", PaintingSpotlightSchema);
|
35
models/mongooseSchemas/ParticipantInfo.js
Normal file
@ -0,0 +1,35 @@
|
||||
const mongoose = require("mongoose");
|
||||
const Schema = mongoose.Schema;
|
||||
|
||||
let ParticipantInfoSchema = Schema({
|
||||
links: String,
|
||||
rank: Number,
|
||||
artist: String,
|
||||
paintingName: { type: String, minlength: 1 },
|
||||
description: { type: String, default: ""},
|
||||
totalScore: { type: Number, default: 0},
|
||||
ratings: [{type: Schema.Types.ObjectId, ref: "Rating"}],
|
||||
comment: [{type: Schema.Types.ObjectId, ref: "Comment"}],
|
||||
postTime : { type: Date, default: Date.now }
|
||||
});
|
||||
|
||||
ParticipantInfoSchema.statics.createNewParticipantInfo = function (data, callback) {
|
||||
let newPartInfo = this({
|
||||
links : data.links,
|
||||
rank : data.rank,
|
||||
artist : data.artist,
|
||||
paintingName : data.paintingName,
|
||||
description : data.description,
|
||||
totalScore : data.totalScore,
|
||||
ratings : data.ratings,
|
||||
postTime : data.postTime
|
||||
});
|
||||
newPartInfo.save((err, partInfo) => {
|
||||
if (err)
|
||||
callback(err, null);
|
||||
else
|
||||
callback(null, partInfo._id);
|
||||
});
|
||||
};
|
||||
|
||||
module.exports = mongoose.model("ParticipantInfo", ParticipantInfoSchema);
|
26
models/mongooseSchemas/Participation.js
Normal file
@ -0,0 +1,26 @@
|
||||
const mongoose = require("mongoose");
|
||||
const Schema = mongoose.Schema;
|
||||
|
||||
let ParticipationSchema = Schema({
|
||||
nthSeason : Number,
|
||||
themeName : String,
|
||||
activityRank : Number,
|
||||
postTime : { type: Date, default: Date.now }
|
||||
});
|
||||
|
||||
ParticipationSchema.statics.createNewParticipation = function (data, callback) {
|
||||
let newParticipation = this({
|
||||
nthSeason : data.nthSeason,
|
||||
themeName : data.themeName,
|
||||
activityRank : data.activityRank,
|
||||
postTime : data.postTime
|
||||
});
|
||||
newParticipation.save((err, obj) => {
|
||||
if (err)
|
||||
callback(err, null);
|
||||
else
|
||||
callback(null, obj._id);
|
||||
});
|
||||
};
|
||||
|
||||
module.exports = mongoose.model("Participation", ParticipationSchema);
|
22
models/mongooseSchemas/Rating.js
Normal file
@ -0,0 +1,22 @@
|
||||
const mongoose = require("mongoose");
|
||||
const Schema = mongoose.Schema;
|
||||
|
||||
let RatingSchema = Schema({
|
||||
username : String,
|
||||
score : {type : Number, min: 1, max: 5}
|
||||
});
|
||||
|
||||
RatingSchema.statics.createNewRating = function(data, callback) {
|
||||
let newRating = this({
|
||||
username : data.username,
|
||||
score : data.score
|
||||
});
|
||||
newRating.save((err, rating) => {
|
||||
if (err)
|
||||
callback(err, null);
|
||||
else
|
||||
callback(null, rating);
|
||||
});
|
||||
}
|
||||
|
||||
module.exports = mongoose.model("Rating", RatingSchema);
|
169
models/mongooseSchemas/Season.js
Normal file
@ -0,0 +1,169 @@
|
||||
const mongoose = require("mongoose");
|
||||
const Schema = mongoose.Schema;
|
||||
|
||||
const ServerStatus = require("../../ServerStatus");
|
||||
const Theme = require("./Theme");
|
||||
const NewTheme = require("./NewTheme");
|
||||
|
||||
/**
|
||||
* 回呼函式。
|
||||
* @callback CallbackFunction
|
||||
* @param {Object} err 錯誤資訊物件。
|
||||
* @param {Object} obj 傳回的物件。
|
||||
*/
|
||||
|
||||
/**
|
||||
* 「季」的模板定義。
|
||||
* @prop {number} nth 表示目前的資料是第nth季
|
||||
* @prop {Schema.Types.ObjectId[]} themes 這一季的所有主題。
|
||||
* @prop {Date} startTime 這一季的開始時間。
|
||||
* @prop {Date} endTime 這一季的結束時間。
|
||||
*/
|
||||
let SeasonSchema = Schema({
|
||||
nth: Number,
|
||||
themes: [{type : Schema.Types.ObjectId, ref : "Theme"}],
|
||||
startTime: {type : Date, default : Date.now},
|
||||
endTime: Date
|
||||
});
|
||||
|
||||
/**
|
||||
* 新一季的必要的基本資料。
|
||||
* @typedef NewSeasonData
|
||||
* @prop {number} nth 紀錄此資料為第nth季。
|
||||
* @prop {ObjectId[]} themes 這一季所有的活動。以ObjectId做關聯。
|
||||
* @prop {Date} startTime 開始這一季時的時間。
|
||||
*/
|
||||
/**
|
||||
* 建立一個新的「季」資料。
|
||||
* @param {Object} data 欲儲存的原始資料。
|
||||
* @param {function} callback 回呼函式(Error, ObjectId)。
|
||||
*/
|
||||
SeasonSchema.statics.createNewSeason = function (data, callback) {
|
||||
let newSeason = this({
|
||||
nth: data.nth,
|
||||
themes: data.themes,
|
||||
startTime: data.startTime,
|
||||
endTime: null
|
||||
});
|
||||
newSeason.save((err, season) => {
|
||||
if (err) return callback(err, null);
|
||||
callback(null, season._id);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 取得「傑作藝廊」頁面所需的資料。
|
||||
* 注意: 要取用相關資料時,必須先將Theme與ParticipantInfo資料表引入。
|
||||
* @param {CallbackFunction} callback 回呼函式。含有錯誤訊息物件或資料物件。
|
||||
*/
|
||||
SeasonSchema.statics.GetGalleryNeedInfo = function (callback) {
|
||||
// 取得一季之中所有的「主題 (themes)」與「季次 (nth)」
|
||||
// 所有主題中的「編號 (order)」、「標題 (title)」與「參加作品 (participants)」
|
||||
// 參加作品中的「排行 (rank)」、「作者 (artist)」、「作品敘述 (description)」與「投稿時間 (postTime)」
|
||||
let curNthSeason = ServerStatus.status.currentSeason;
|
||||
let populateQuery = {
|
||||
path : "themes",
|
||||
select : {"order": 1, "title": 1, "participants": 1},
|
||||
populate : {
|
||||
path : "participants",
|
||||
select : {"rank": 1, "artist": 1, "description": 1, "postTime": 1}
|
||||
}
|
||||
};
|
||||
// {"nth": {$lt: curNthSeason}} 中的 $lt: curNthSeason 表示不要選取到最新一季。
|
||||
this.find({"nth": {$lt: curNthSeason}}).sort({nth: -1}).select("nth themes").populate(populateQuery).exec(callback);
|
||||
}
|
||||
|
||||
/**
|
||||
* 取得在「畫作主題」頁面下所需要的插值資料。
|
||||
* @param {CallbackFunction} callback 回呼函式。含有錯誤訊息物件或資料物件。
|
||||
*/
|
||||
SeasonSchema.statics.GetThemePageNeedInfo = function (callback) {
|
||||
let result = {currentSeason: null, lastSeason: null};
|
||||
let currentSeasonPopulate = {path: "themes", select: {"order": 1, "title": 1, "narrative": 1, "imageURL": 1, "originator": 1, "participentCount": 1, "views": 1, "commentCount": 1}};
|
||||
let lastSeasonPopulate = {path: "themes", select: {"order": 1, "title": 1, "originator": 1}};
|
||||
let currentNthSeason = ServerStatus.status.currentSeason;
|
||||
// 以nth尋找最新的一季,在選擇其中的「nth」與「themes」欄位
|
||||
// 並對「themes」展開,選擇其中的指定欄位,然後執行以上動作。
|
||||
this.findOne({"nth": currentNthSeason})
|
||||
.select("nth themes")
|
||||
.populate(currentSeasonPopulate)
|
||||
.exec((err, curSeason) => {
|
||||
if (err) {
|
||||
callback(err, null);
|
||||
return;
|
||||
}
|
||||
result.currentSeason = curSeason;
|
||||
// 接著尋找上一季,指定「nth」、「endTime」與「themes」欄位
|
||||
// 並對「themes」展開,選擇其中的指定欄位,然後執行以上動作。
|
||||
this.findOne({"nth": currentNthSeason - 1})
|
||||
.select("nth endTime themes")
|
||||
.populate(lastSeasonPopulate)
|
||||
.exec((err, lastSeason) => {
|
||||
if (err) {
|
||||
callback(err, null);
|
||||
return;
|
||||
}
|
||||
result.lastSeason = lastSeason;
|
||||
callback(null, result);
|
||||
return;
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 將畫作主題活動推進新的一季。
|
||||
* 注意,ServerStatus.status中的currentSeason必須要先推進到新的一季,否則會相衝。
|
||||
* @param {CallbackFunction} callback 回呼函式。
|
||||
*/
|
||||
SeasonSchema.statics.PushNewSeason = function (callback) {
|
||||
let promotionCount = ServerStatus.status.promotionCount; // 取得要選取多少個候選主題至正規主題中
|
||||
let curNthSeason = ServerStatus.status.currentSeason;
|
||||
let Season = this;
|
||||
// 首先先更新上一季的結束時間
|
||||
Season.update({ nth: curNthSeason - 1 }, { $set: { "endTime": new Date() } }, (err, seasonDocs) => {
|
||||
if(err) return callback(err, "\n更新前一季的時間時\n");
|
||||
});
|
||||
// 做統合,取NewTheme中所有的欄位,並建立一個 "voteCount" 欄位來記錄 votes 中有有多少個項目
|
||||
// 然後再先後以投票數量(voteCount)與投稿時間(createdTime)來做排序,並選取前N個(promotionCount)作為新一季的新主題。
|
||||
NewTheme.aggregate(
|
||||
[
|
||||
{ "$project": {
|
||||
title: 1,
|
||||
narrative: 1,
|
||||
image: 1,
|
||||
sponsor: 1,
|
||||
votes: 1,
|
||||
createdTime: 1,
|
||||
voteCount: { "$size": "$votes" }
|
||||
}},
|
||||
{ "$sort": { "voteCount": -1 } },
|
||||
{ "$sort": { "createdTime": 1 } },
|
||||
{ "$limit": promotionCount }
|
||||
],
|
||||
function (err, docsList) {
|
||||
if (err) return callback(err, "\n取得指定候選主題時發生了錯誤。請確認是否有連接MongoDB並重新嘗試。\n");
|
||||
// 將指定的候選主題轉換到正規的主題(Theme)中。其中處理完成後回呼_id清單。
|
||||
Theme.TransferFromNewTheme(docsList, (err, _idList) => {
|
||||
if (err) return callback(err, "\n將候選主題轉換至正規主題時發生了錯誤。請確認是否有連接MongoDB並重新嘗試。\n");
|
||||
|
||||
// 建立基本新的一季(Season)的資料
|
||||
let data = {
|
||||
nth: ServerStatus.status.currentSeason,
|
||||
themes: _idList,
|
||||
startTime: new Date()
|
||||
};
|
||||
// 利用data建立最新一季的資料
|
||||
Season.createNewSeason(data, (err, _id) => {
|
||||
if (err) return callback(err, "\n建立新一季的活動資料時發生了錯誤。請確認是否有連接MongoDB並重新嘗試。\n");
|
||||
// 將所有的候選主題都清空
|
||||
NewTheme.remove({}, (err) => {
|
||||
if (err) return callback(err, "\n在清空NewTheme中所有資料時發生了錯誤。請改用手動的方式刪除或檢查是否有連接MongoDB。\n");
|
||||
callback(null, true);
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
module.exports = mongoose.model("Season", SeasonSchema);
|
28
models/mongooseSchemas/ServerMessage.js
Normal file
@ -0,0 +1,28 @@
|
||||
const mongoose = require("mongoose");
|
||||
const Schema = mongoose.Schema;
|
||||
|
||||
let ServerMessageSchema = Schema({
|
||||
title: String,
|
||||
content: String
|
||||
});
|
||||
|
||||
/**
|
||||
* @typedef NewServerMessageData
|
||||
* @param {string} title 訊息主題。
|
||||
* @param {string} content 訊息內容。
|
||||
*/
|
||||
|
||||
/**
|
||||
* 建立一個新的伺服訊息資料。
|
||||
* @param {NewServerMessageData} data 建立一個新的伺服訊息資料的必要資料。
|
||||
* @param {CallbackFunction} callback 回呼函式。
|
||||
*/
|
||||
ServerMessageSchema.statics.createNewServerMessage = function (data, callback) {
|
||||
let newServMsg = this({ title: data.title, content: data.content });
|
||||
newServMsg.save((err) => {
|
||||
if (err) return callback(err, null);
|
||||
callback(null, newServMsg._id);
|
||||
});
|
||||
}
|
||||
|
||||
module.exports = mongoose.model("ServerMessage", ServerMessageSchema);
|
37
models/mongooseSchemas/SiteMail.js
Normal file
@ -0,0 +1,37 @@
|
||||
const mongoose = require("mongoose");
|
||||
const Schema = mongoose.Schema;
|
||||
|
||||
/**
|
||||
* 站內信件。一封信件中內有基本的主旨、內容、寄件者等等資訊。
|
||||
* @prop {String} title 主旨。
|
||||
* @prop {String} content 內文。
|
||||
* @prop {String} sender 寄件者。
|
||||
* @prop {String} isPrivate 是否為私人信件。若為是,表示只有收件者看得到;反之則否。
|
||||
* @prop {Date} sendTime 寄件時間。
|
||||
*/
|
||||
let SiteMailSchema = Schema({
|
||||
title: String,
|
||||
content: String,
|
||||
sender: String,
|
||||
isPrivate: Boolean,
|
||||
sendTime: {type: Date, default: new Date()}
|
||||
});
|
||||
|
||||
// 建立一個新的站內信件。回傳站內信的_id。
|
||||
SiteMailSchema.statics.createNewSiteMail = function (data, callback) {
|
||||
let newSiteMail = this({
|
||||
title: data.title,
|
||||
content: data.content,
|
||||
sender: data.sender,
|
||||
isPrivate: data.isPrivate,
|
||||
sendTime: data.sendTime
|
||||
});
|
||||
newSiteMail.save((err, siteMail) => {
|
||||
if (err)
|
||||
callback(err, null);
|
||||
else
|
||||
callback(null, siteMail._id);
|
||||
});
|
||||
}
|
||||
|
||||
module.exports = mongoose.model("SiteMail", SiteMailSchema);
|
46
models/mongooseSchemas/SiteMessage.js
Normal file
@ -0,0 +1,46 @@
|
||||
const mongoose = require("mongoose");
|
||||
const Schema = mongoose.Schema;
|
||||
|
||||
let SiteMessageSchema = Schema({
|
||||
from : { type : String, enum : ["server", "personal"] },
|
||||
title : { type : String, default : "Title" },
|
||||
content : { type : String, default : "" },
|
||||
refId : { type : Schema.Types.ObjectId, ref : "ServerMessage" },
|
||||
id : { type : Number },
|
||||
isSeen : { type : Boolean, default : false },
|
||||
isPrivate : { type : Boolean, default : false }
|
||||
});
|
||||
|
||||
/**
|
||||
* @typedef NewSiteMessageData
|
||||
* @prop {string} from 表示來自「伺服公告」(“server”) 或是「個人訊息」(“personal”)。
|
||||
* @prop {string} title 訊息標題。
|
||||
* @prop {string?} content 訊息內容 (可為HTML格式。當 from 為 “personal”時此項才會有內容)。
|
||||
* @prop {string?} refId 訊息參考 (參考NoticeBoard中的訊息,當 from 為 “server” 時此項才會有內容)。
|
||||
* @prop {number} id 訊息編號。
|
||||
* @prop {boolean} isPrivate 是否為私人訊息。
|
||||
*/
|
||||
/**
|
||||
* 建立一個主頁訊息資料。
|
||||
* @param {NewSiteMessageData} data 建立一個新的主頁訊息所需的基本資料。
|
||||
* @param {CallbackFunction} callback 回呼函式。
|
||||
*/
|
||||
SiteMessageSchema.statics.createNewSiteMessage = function (data, callback) {
|
||||
let newSiteMsg = this({
|
||||
from : data.from,
|
||||
title : data.title,
|
||||
content : data.content,
|
||||
refId : data.refId,
|
||||
id : data.id,
|
||||
isSeen : false,
|
||||
isPrivate : data.isPrivate
|
||||
});
|
||||
newSiteMsg.save((err, siteMsg) => {
|
||||
if (err)
|
||||
callback(err, null);
|
||||
else
|
||||
callback(err, siteMsg._id);
|
||||
});
|
||||
};
|
||||
|
||||
module.exports = mongoose.model("SiteMessage", SiteMessageSchema);
|
89
models/mongooseSchemas/Theme.js
Normal file
@ -0,0 +1,89 @@
|
||||
const fileSystem = require("fs");
|
||||
const mongoose = require("mongoose");
|
||||
const Schema = mongoose.Schema;
|
||||
|
||||
const ServerStatus = require("../../ServerStatus");
|
||||
|
||||
// 建立「主題」樣板
|
||||
let ThemeSchema = Schema({
|
||||
order : Number,
|
||||
title : String,
|
||||
narrative : String,
|
||||
image : String, // URL
|
||||
originator : String,
|
||||
participants : [{ type : Schema.Types.ObjectId, ref : "ParticipantInfo" }],
|
||||
views : Number,
|
||||
commentCount : Number
|
||||
});
|
||||
|
||||
// 透過參數data來建立「主題」資料於表中。
|
||||
ThemeSchema.statics.createNewTheme = function (data, callback) {
|
||||
let newTheme = this({
|
||||
order : data.order,
|
||||
title : data.title,
|
||||
narrative : data.narrative,
|
||||
image : data.image, // URL
|
||||
originator : data.originator,
|
||||
participants : data.participants,
|
||||
views : data.views,
|
||||
commentCount : data.commentCount
|
||||
});
|
||||
newTheme.save((err, theme) => {
|
||||
if (err)
|
||||
callback(err, null);
|
||||
else
|
||||
callback(null, theme._id);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 轉移完成後回呼的函式定義。
|
||||
* @callback TransferCallback
|
||||
* @param {Error?} error 錯誤訊息物件。
|
||||
* @param {ObjectId[]?} docs_id 轉換後的所有主題對應的_id。
|
||||
*/
|
||||
/**
|
||||
* 自候選主題(NewTheme)轉移到主題(Theme)。當活動狀態要推向新的一季時所會用到的函式。
|
||||
* @param {NewTheme[]} newThemeDocs 要轉移的候選主題。
|
||||
* @param {TransferCallback} callback 回呼函式。
|
||||
*/
|
||||
ThemeSchema.statics.TransferFromNewTheme = function (newThemeDocs, callback) {
|
||||
let projectRoot = global.__dirname; // 此專案的根目錄
|
||||
let curNthSeason = ServerStatus.status.currentSeason; // 取得目前最新一季的季數
|
||||
let newThemeDatas = []; // 用來新增Theme資料的集合清單
|
||||
|
||||
// 為每一個選中的候選主題建立Theme資料
|
||||
newThemeDatas.forEach((docs, index) => {
|
||||
let routePath = docs.image.split("/"); // 以字元"/"分解字串,取得路徑
|
||||
let fileName = routePath[routePath.length - 1]; // 取得檔案名稱
|
||||
let URLFilePath = "/images/seasons/" + curNthSeason + "/" + fileName; // 找資源用的URL檔案路徑
|
||||
let newFilePath = "/public" + URLFilePath; // 儲存用的相對檔案路徑
|
||||
|
||||
// 將建立主題的基本資料加入至newThemeDatas中
|
||||
newThemeDatas.push({
|
||||
order: index,
|
||||
title: docs.title,
|
||||
narrative: docs.narrative,
|
||||
image: "/images/seasons/" + curNthSeason + "/" + fileName,
|
||||
originator: docs.sponsor,
|
||||
participants: [],
|
||||
views: 0,
|
||||
commentCount: 0
|
||||
});
|
||||
|
||||
// 將檔案移動至新的資料夾中。
|
||||
// 從位置 "/public/images/newtheme" 轉移到 "/public/images/seasons/[currentNthSeason]" 之下
|
||||
// 其中檔案名稱不變。
|
||||
fileSystem.rename(projectRoot + "/public" + docs.image, projectRoot + newFilePath, (err) => {
|
||||
console.log("「轉移候選主題」: 在移動檔案\"%s\"至\"%s\"時發生了錯誤。", "/public" + docs.image, newFilePath);
|
||||
});
|
||||
});
|
||||
|
||||
// 將所有選取的候選主題資料,插入、新增到Theme之中,並且回呼這些資料的_id,組成ObjectId清單。
|
||||
this.insertMany(newThemeDatas, (err, docsList) => {
|
||||
if (err) return callback(err, null);
|
||||
callback(null, docsList.map(docs => docs._id));
|
||||
});
|
||||
}
|
||||
|
||||
module.exports = mongoose.model("Theme", ThemeSchema);
|
624
models/mongooseSchemas/User.js
Normal file
@ -0,0 +1,624 @@
|
||||
const fileSystem = require("fs");
|
||||
const bcrypt = require("bcryptjs");
|
||||
const mongoose = require("mongoose");
|
||||
const SiteMail = require("../mongooseSchemas/SiteMail");
|
||||
|
||||
const Painting = require("./Painting");
|
||||
const Schema = mongoose.Schema;
|
||||
|
||||
const saltNumber = 8; // 在進行雜湊之前,將要被雜湊的資料「加鹽」,其中長度固定為8。
|
||||
|
||||
const Error_ExistSameUsername = new Error("已有存在相同使用者名稱。");
|
||||
const Error_ExistSameEmail = new Error("已有存在相同電子郵件。");
|
||||
const Error_UserNotExist = new Error("目標使用者不存在。");
|
||||
const Error_IlligelPhotoImageFormat = new Error("錯誤的影像檔案格式。");
|
||||
|
||||
/**
|
||||
* 定義在「使用者」資料表中,儲存「個人資訊」的子資料表。
|
||||
* @prop {String} email 使用者的電子郵件信箱。
|
||||
* @prop {String} lastName 使用者的姓。
|
||||
* @prop {String} firstName 使用者的名。
|
||||
* @prop {String} nickName 使用者的暱稱。
|
||||
* @prop {String} motto 使用者的個人短語。
|
||||
* @prop {String} photo 使用者的照片。儲存形式為URL。
|
||||
*/
|
||||
let PersonalInfo = Schema({
|
||||
email : String,
|
||||
lastName : String,
|
||||
firstName : String,
|
||||
nickname : String,
|
||||
motto : String,
|
||||
photo : String, // URL
|
||||
});
|
||||
|
||||
/**
|
||||
* 定義在「使用者」資料表中,儲存「主頁訊息」的子資料表。
|
||||
* @prop {Boolean} isServerMessage 是否為伺服廣播訊息。
|
||||
* @prop {String?} title 訊息標題。在isServerMessage = true時,此項為空。
|
||||
* @prop {String?} content 訊息內容。在isServerMessage = true時,此項為空.
|
||||
* @prop {ObjectId} refId 訊息參考_id。當isServerMessage = false時,此項會連接到一個假的伺服訊息。
|
||||
* @prop {Date} postTime 輸出此訊息時的時間日期。
|
||||
* @prop {Boolean} isSeen 此訊息是否已被使用者讀過了。
|
||||
* @prop {Boolean} isPrivate 訊息是否僅能被使用者看見。
|
||||
*/
|
||||
let SiteMessage = Schema({
|
||||
isServerMessage: Boolean,
|
||||
title: String,
|
||||
content: String,
|
||||
refId: {type: Schema.Types.ObjectId, ref: "ServerMessage"},
|
||||
postTime: {type: Schema.Types.Date, default: Date.now },
|
||||
isSeen: {type: Schema.Types.Boolean, default: false},
|
||||
isPrivate: Boolean
|
||||
});
|
||||
|
||||
/**
|
||||
* 定義「使用者」資料表。
|
||||
* @prop {String} username 使用者的名稱。
|
||||
* @prop {String} password 使用者的密碼。以雜湊的方式來儲存。
|
||||
* @prop {PersonalInfo} personalInfo 使用者的個人資料。
|
||||
* @prop {String[]} tags 使用者所定義的標籤。
|
||||
* @prop {ObjectId[] -> Painting} paintings 儲存使用者的作畫資料。以連結的方式儲存。
|
||||
* @prop {SiteMessage[]} siteMsg 站內訊息。以連結的方式儲存。
|
||||
* @prop {ObjectId[] -> SiteMail} siteMail 站內信。以連結的方式儲存。
|
||||
* @prop {Number} notices 通知數。表示使用者未讀的站內訊息數量。
|
||||
* @prop {ObjectId[] -> User} friendList 好友清單。以連結的方式儲存。
|
||||
* @prop {Boolean} autoSaveEnable 選項。是否在作畫的時候自動儲存。
|
||||
* @prop {Boolean} hasPostFeedback 表示此使用者是否有在這個月內回饋。
|
||||
* @prop {Boolean} hasPostNewTheme 表示使用者是否有投稿過新主題。
|
||||
* @prop {Boolean} hasVotedNewTheme 表示使用者是否有為新主題投過票。
|
||||
*/
|
||||
let UserSchema = Schema({
|
||||
id : String,
|
||||
username : String,
|
||||
password : String,
|
||||
personalInfo : PersonalInfo,
|
||||
tags : [{type: String}],
|
||||
paintings : [{type : Schema.Types.ObjectId, ref : "Painting"}],
|
||||
siteMsg : [{type: SiteMessage}],
|
||||
siteMail : [{type : Schema.Types.ObjectId, ref : "SiteMail"}],
|
||||
notices : Number,
|
||||
friendList : [{type : Schema.Types.ObjectId, ref : "User"}],
|
||||
autoSaveEnable : Boolean,
|
||||
hasPostFeedback : Boolean,
|
||||
hasPostNewTheme : Boolean,
|
||||
hasVotedNewTheme : Boolean
|
||||
});
|
||||
|
||||
/**
|
||||
* @typedef NewUserDataSet
|
||||
* @prop {String} lastName 新使用者的「姓」字串資料。
|
||||
* @prop {String} firstName 新使用者的「名」字串資料。
|
||||
* @prop {String} email 新使用者的「Email」字串資料。
|
||||
* @prop {String} username 新使用者的「使用者名稱」字串資料。
|
||||
* @prop {String} password 新使用者的「密碼」字串資料。
|
||||
* @prop {String?} confirmPassword 新使用者的「確認密碼」字串資料。
|
||||
*/
|
||||
/**
|
||||
* 以輸入的資料,建立新的使用者資料。
|
||||
* @param {NewUserDataSet} data 紀錄要新增使用者的來源資料.
|
||||
* @param {CallbackFunction} 回呼函式。決定資料儲存是否成功或發生錯誤。
|
||||
*/
|
||||
UserSchema.statics.createNewUser = function (data, callback) {
|
||||
let _User = this;
|
||||
// 檢查輸入的使用者名稱與信箱是否與現存使用者的相衝
|
||||
this.findOne({ $or: [{"username": data.username}, {"personalInfo.email": data.email}]})
|
||||
.exec((err, user) => {
|
||||
if (err) { // 如果發生錯誤,則回傳錯誤訊息
|
||||
callback(err, null);
|
||||
return;
|
||||
} // 若有找到相符的信箱或名稱,則回呼錯誤訊息
|
||||
else if (user) {
|
||||
if (user.username == data.username) {
|
||||
callback(Error_ExistSameUsername, null);
|
||||
}
|
||||
else {
|
||||
callback(Error_ExistSameEmail, null);
|
||||
}
|
||||
return;
|
||||
}
|
||||
// 若欲新增的使用者不存在,則可以新增。首先,先對密碼做加密動作。
|
||||
bcrypt.hash(data.password, saltNumber, (err, hash) => {
|
||||
// 若密碼雜湊過程有錯誤,則直接回呼。
|
||||
if (err) {
|
||||
callback(err, null);
|
||||
return;
|
||||
}
|
||||
// 以自身(模組)建立一個新的資料
|
||||
let newUser = _User({
|
||||
username : data.username,
|
||||
password : hash,
|
||||
personalInfo : {
|
||||
email : data.email,
|
||||
lastName : data.lastName,
|
||||
firstName : data.firstName,
|
||||
nickname : "",
|
||||
motto : "",
|
||||
photo : "/sample/Example.png"
|
||||
},
|
||||
tags : [],
|
||||
paintings : [],
|
||||
siteMsg : [],
|
||||
siteMail : [],
|
||||
notices : 0,
|
||||
friendList : [],
|
||||
autoSaveEnable : true,
|
||||
hasPostFeedback : false,
|
||||
hasPostNewTheme: false,
|
||||
hasVotedNewTheme: false
|
||||
});
|
||||
// 將新建立的使用者資料儲存。並回呼結果。
|
||||
newUser.save(callback);
|
||||
});
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* 判斷「相同使用者名稱」錯誤物件。
|
||||
* @param {Error} error 要判斷的錯誤物件。
|
||||
* @return {Boolean} 回傳布林值,判斷錯誤是否為「相同使用者名稱或信箱」。
|
||||
*/
|
||||
UserSchema.statics.IsExistSameUsername = function (error) {
|
||||
return error === Error_ExistSameUsername;
|
||||
}
|
||||
|
||||
/**
|
||||
* 判斷「相同信箱」錯誤物件。
|
||||
* @param {Error} error 要判斷的錯誤物件。
|
||||
* @return {Boolean} 回傳布林值,判斷錯誤是否為「相同使用者名稱或信箱」。
|
||||
*/
|
||||
UserSchema.statics.IsExistSameEmail = function (error) {
|
||||
return error === Error_ExistSameEmail;
|
||||
}
|
||||
|
||||
/**
|
||||
* 判斷「使用者不存在」錯誤物件。
|
||||
* @param {Error} error 要判斷的錯誤訊息物件。
|
||||
* @return {Boolean} 回傳布林值,判斷錯誤是否為「目標使用者不存在。」。
|
||||
*/
|
||||
UserSchema.statics.IsUserNotExist = function (error) {
|
||||
return error === Error_UserNotExist;
|
||||
}
|
||||
|
||||
/**
|
||||
* 取得「使用者不存在」錯誤物件。
|
||||
* @return {Error} 回傳「使用者不存在」錯誤物件。
|
||||
*/
|
||||
UserSchema.statics.Error_UserNotExist = function () {
|
||||
return Error_UserNotExist;
|
||||
};
|
||||
|
||||
/**
|
||||
* 比對登入的帳號與密碼。
|
||||
* @param {String} username 使用者名稱。
|
||||
* @param {String} password 要進行比對的密碼。
|
||||
* @param {CallbackFunction} callback 回呼函式。
|
||||
*/
|
||||
UserSchema.statics.AccountComparison = function (username, password, callback) {
|
||||
// 尋找指定的使用者帳號是否存在
|
||||
this.findOne({"username" : username})
|
||||
.exec((err, user) => {
|
||||
if (err) {
|
||||
callback(err, null);
|
||||
return;
|
||||
}
|
||||
if (!user) {
|
||||
callback(null, false);
|
||||
return;
|
||||
}
|
||||
// 比對輸入的帳號與儲存於資料庫中的密碼雜湊
|
||||
bcrypt.compare(password, user.password, (err, result) => {
|
||||
if (result)
|
||||
callback(err, user);
|
||||
else
|
||||
callback(err, false);
|
||||
});
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* 以傳入的資料庫識別ID來尋找指定使用者資料,將需要的基本訊息(使用者名稱、通知數)設定至標準插值物件上。
|
||||
* @param {String?} user_Id 為資料庫中的識別Id,用來尋找使用者資料所用。若此項不存在則直接回呼。
|
||||
* @param {BasicLayout} dataObject 基本插值物件。
|
||||
* @param {CallbackFunction} callback 回呼函式。
|
||||
*/
|
||||
UserSchema.statics.SetBasicInformation = function (user_Id, dataObject, callback) {
|
||||
// 若傳入的 user_Id 不為空,則嘗試尋找該目標使用者並取得需要的基本插值資料
|
||||
if (user_Id) {
|
||||
// 以 user_Id 取得目標使用者資料。
|
||||
this.findOne({_id: user_Id})
|
||||
.exec((err, user) => {
|
||||
if (err) {
|
||||
callback(err, null);
|
||||
return;
|
||||
}
|
||||
if (!user) {
|
||||
callback(Error_UserNotExist, null);
|
||||
return;
|
||||
}
|
||||
// 若資料庫存取無錯誤、有找到目標使用者,則將使用者名稱與通知數的資訊,加入到基本插值物件中。
|
||||
dataObject.username = user.username;
|
||||
dataObject.notices = user.notices;
|
||||
callback(null, dataObject);
|
||||
}
|
||||
);
|
||||
}
|
||||
// 如果 user_Id 為空的話,則直接回呼。
|
||||
else {
|
||||
callback(null, dataObject);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 嘗試以傳入的_id來去尋找目標使用者資料,若目標資料中的使用者名稱與參數username一樣,則回呼true;否則false。
|
||||
* @param {string} user_Id 目標要尋找的使用者的_id。
|
||||
* @param {string} username 要比對的使用者名稱。
|
||||
* @param {CallbackFunction} callback 回呼函式。回傳錯誤訊息或結果。
|
||||
*/
|
||||
UserSchema.statics.CheckUsernameBy_Id = function (user_Id, username, callback) {
|
||||
// 以 user_Id 來尋找目標使用者。
|
||||
this.findOne({"_id": user_Id})
|
||||
.exec((err, user) => {
|
||||
// 若資料庫有發生錯誤則直接將錯誤回呼。
|
||||
if (err) return callback(err, null);
|
||||
|
||||
// 若使用者存在,則回呼比較結果。
|
||||
if (user) {
|
||||
return callback(null, user.username == username);
|
||||
}
|
||||
// 若不存在,則回呼「使用者不存在」錯誤。
|
||||
else {
|
||||
return callback(Error_UserNotExist, null);
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新個人資料。
|
||||
* 更新完資料,若無問題則回呼callback(null, true);若有錯誤,則回呼callback(err, false)。
|
||||
* @param {string} user_id 對應至使用者資料的 ObjectId 字串。
|
||||
* @param {PersonalInfo} textDatas 存放姓、名、暱稱、短言的物件。
|
||||
* @param {Multer.FileInfo?} photoInfo 使用者傳送至伺服端的初始影像檔案。若此項為null,則不更新圖像資料。
|
||||
* @param {CallbackFunction} callback 回呼函式。
|
||||
*/
|
||||
UserSchema.statics.UpdatePersonalInfo = function (user_id, textDatas, photoInfo, callback) {
|
||||
// 先尋找目標使用者的資料
|
||||
this.findOne({ "_id": user_id })
|
||||
.exec((err, userDocs) => {
|
||||
// 若資料庫尋找時出現錯誤,將其錯誤資料回呼
|
||||
if (err) return callback(err, null);
|
||||
|
||||
// 若找不到使用者時,將「使用者不存在」回呼。
|
||||
if (!userDocs) return callback(Error_UserNotExist, null);
|
||||
|
||||
// 更新文字部分的個人資料
|
||||
userDocs.personalInfo.lastName = textDatas.lastName;
|
||||
userDocs.personalInfo.firstName = textDatas.firstName;
|
||||
userDocs.personalInfo.nickname = textDatas.nickname;
|
||||
userDocs.personalInfo.motto = textDatas.motto;
|
||||
|
||||
// 若有圖像資訊,表示使用者上傳了新的圖像,需要對此資料項更新
|
||||
if (photoInfo) {
|
||||
|
||||
let fileName = userDocs.username + (photoInfo.mimetype == "image/jpeg" ? ".jpg" : ".png"); // 定義新圖檔名稱
|
||||
let publicPath = "/images/user_photos/" + fileName; // 外部、瀏覽器端可看得到的路徑
|
||||
let dstFilePath = "public" + publicPath; // 複製檔案的目的路徑
|
||||
|
||||
// 將暫存的圖片檔案複製到指定的位置
|
||||
fileSystem.copyFile(photoInfo.path, dstFilePath, (err) => {
|
||||
// 若發生錯誤,則將錯誤回呼
|
||||
if (err) return callback(err, null);
|
||||
|
||||
// 更新個人頭像路徑
|
||||
userDocs.personalInfo.photo = publicPath;
|
||||
|
||||
// 將暫存的圖片刪除
|
||||
fileSystem.unlink(photoInfo.path, (err) => { if (err) console.log(err); });
|
||||
|
||||
// 儲存更變後的個人資料
|
||||
userDocs.save((err) => {
|
||||
// 若發生錯誤,則將錯誤回呼
|
||||
if (err) return callback(err, null);
|
||||
// 若無,則回呼 callback(null, true) 以表示完成
|
||||
callback(null, true);
|
||||
});
|
||||
});
|
||||
}
|
||||
// 若無,則直接儲存資料
|
||||
else {
|
||||
// 儲存更變後的個人資料
|
||||
userDocs.save((err) => {
|
||||
// 若發生錯誤,則將錯誤回呼
|
||||
if (err) return callback(err, null);
|
||||
// 若無,則回呼 callback(null, true) 以表示完成
|
||||
callback(null, true);
|
||||
});
|
||||
}
|
||||
})
|
||||
;
|
||||
}
|
||||
|
||||
/**
|
||||
* 傳入使用者名稱,檢查該名使用者是否存在於資料庫中。
|
||||
* 若存在,則回呼 true ;若否,則回呼 false。
|
||||
* @param {string} username 欲查詢的使用者名稱。
|
||||
* @param {CallbackFucntion} callback 回呼函式。
|
||||
*/
|
||||
UserSchema.statics.CheckUserIsExistByUsername = function (username, callback) {
|
||||
this.findOne({"username": username})
|
||||
.exec((err, docs) => {
|
||||
if (err) return callback(err, null);
|
||||
callback(null, docs !== null && docs !== undefined);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @typedef {Object} MailData 信件資料。
|
||||
* @prop {string} recipient 收件者的使用者名稱。
|
||||
* @prop {string} subject 信件的主旨。
|
||||
* @prop {string} content 信件的內容。
|
||||
* @prop {Boolean} isPrivate 表示此信件是否為「私人觀看」的。
|
||||
*/
|
||||
/**
|
||||
* 使用者sender傳送站內訊息給目標使用者。
|
||||
* @param {string} sender 寄件者的使用者_id。
|
||||
* @param {MailData} mailInfo 信件內容。
|
||||
* @param {CallbackFunction} callback 回呼函式。
|
||||
*/
|
||||
UserSchema.statics.SendSiteMail = function (sender_id, mailInfo, callback) {
|
||||
// 檢測目標收件者是否存在
|
||||
this.findOne({"username": mailInfo.recipient}).exec((err, recipientDocs) => {
|
||||
if (err) return callback(err, null); // 若資料庫有錯誤,則直接回呼
|
||||
if (!recipientDocs) return callback(Error_UserNotExist, null); // 若找不到收件者,則回呼「目標使用者不存在。」錯誤。
|
||||
|
||||
// 尋找寄件者的使用者名稱
|
||||
this.findOne({"_id": sender_id}).select("username").exec((err, senderDocs) => {
|
||||
if (err) return callback(err, null); // 若資料庫有錯誤,則直接回呼
|
||||
|
||||
// 建立SiteMail資料
|
||||
let data = {
|
||||
title: mailInfo.subject,
|
||||
content: mailInfo.content,
|
||||
sender: senderDocs.username,
|
||||
isPrivate: mailInfo.isPrivate,
|
||||
sendTime: new Date()
|
||||
}
|
||||
|
||||
// 建立站內信,並將其站內信連接到收件者的siteMail中
|
||||
SiteMail.createNewSiteMail(data, (err, _id) => {
|
||||
if (err) return callback(err, null); // 若資料庫有錯誤,則直接回呼
|
||||
recipientDocs.siteMail.push(_id); // 將新增的站內信的_id,加入到收件者的siteMail中。
|
||||
|
||||
// 也許多新增一下站內訊息?
|
||||
|
||||
// 儲存更動結果
|
||||
recipientDocs.save((err) => {
|
||||
if (err) return callback(err, null); // 若資料庫有錯誤,則直接回呼
|
||||
callback(null, true);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 更變指定使用者的密碼。先驗證舊有密碼,若成功則更新密碼。
|
||||
* @param {string} _id 要更改使用者密碼的目標使用者的_id。
|
||||
* @param {string} old_password 使用者輸入的舊密碼。
|
||||
* @param {string} new_password 使用者輸入的新密碼。
|
||||
* @param {CallbackFunction} callback 回呼函式。若輸入的舊密碼與新密碼不相符,則回呼false;若相符且成功更改,則回呼true。
|
||||
*/
|
||||
UserSchema.statics.ChangePassword = function (_id, old_password, new_password, callback) {
|
||||
// 以_id尋找指定的使用者資料
|
||||
this.findOne({"_id": _id}).exec((err, userDocs) => {
|
||||
if (err) return callback(err, null);
|
||||
if (!userDocs) return callback(Error_UserNotExist, null);
|
||||
|
||||
// 比對舊密碼,若result = true表示正確,則繼續更新密碼動作;反之,則回呼false。
|
||||
bcrypt.compare(old_password ,userDocs.password, (err, result) => {
|
||||
if (err) return callback(err, null);
|
||||
if (!result) return callback(null, false);
|
||||
|
||||
// 對新密碼做雜湊演算,取得雜湊後的密碼
|
||||
bcrypt.hash(new_password, saltNumber, (err, hashedPW) => {
|
||||
userDocs.password = hashedPW; // 更新密碼
|
||||
|
||||
// 將更動過後的使用者資料儲存
|
||||
userDocs.save((err) => {
|
||||
if (err) return callback(err, null);
|
||||
|
||||
// 回呼 true,表示成功
|
||||
callback(null, true);
|
||||
});
|
||||
})
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 確認傳入的標籤清單中所有的標籤,是否皆在使用者定義的標籤清單之中。
|
||||
* @param {string} user_id 目標使用者的_id。
|
||||
* @param {string[]} tagsList 要進行檢查的目標標籤清單。
|
||||
* @param {CallbackFunction} callback 回呼函式。若驗證成功則回呼true;反之則false。
|
||||
*/
|
||||
UserSchema.statics.IsInUsersTagsList = function (user_id, tagsList, callback) {
|
||||
this.findOne({"_id": user_id}).exec((err, userDocs) => {
|
||||
if (err) return callback(err, null);
|
||||
if (!userDocs) return callback(Error_UserNotExist, null);
|
||||
if (tagsList === null || tagsList == undefined) return callback(null, false);
|
||||
|
||||
// 檢查tagsList中所有的標籤是否皆在使用者定義的標籤之中。
|
||||
for (let tag of tagsList) {
|
||||
// 若其中一個標前不在使用者的定義之中時,則回呼false。
|
||||
if (userDocs.tags.indexOf(tag) < 0)
|
||||
return callback(null, false);
|
||||
}
|
||||
|
||||
// 經檢查後,若皆在定義之中,則回呼true。
|
||||
callback(null, true);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 確認傳入的標籤清單中所有的標籤,是否接載使用者定義的標籤清單中。
|
||||
* @param {string[]} tagsList 要進行檢查的目標標籤清單。
|
||||
* @return {boolean} 是否皆在使用者定義的標籤清單中。
|
||||
*/
|
||||
UserSchema.methods.IsInTagsList = function (tagsList) {
|
||||
let tagsByUser = this.tags;
|
||||
// 檢查tagsList中所有的標籤是否皆在使用者定義的標籤之中。
|
||||
for (let tag of tagsList) {
|
||||
// 若其中一個標前不在使用者的定義之中時,則回呼false。
|
||||
if (tagsByUser.indexOf(tag) < 0)
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 確認這個畫作是否為此使用者所擁有。
|
||||
* @param {string} paintingId 欲檢查的畫作的id (為UUID)。
|
||||
* @return {boolean} 代表檢查的畫作是否為使用者擁有。
|
||||
*/
|
||||
UserSchema.methods.IsPaintingsOwner = function (paintingId) {
|
||||
let usersPaintings = this.paintings;
|
||||
for (let painting of usersPaintings) {
|
||||
if (painting.id === paintingId)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 嘗試以畫作Id取得使用者的畫作資料。
|
||||
*
|
||||
* @param {string} 畫作Id。
|
||||
* @return {Painting?} 目標畫作的資料。若找不到畫作則回傳null。
|
||||
*/
|
||||
UserSchema.methods.GetPaintingById = function (paintingId) {
|
||||
for (let painting of this.paintings) {
|
||||
if (painting.id == paintingId)
|
||||
return painting;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 檢查圖畫ID(paintingId)是否為目標使用者(user_id)所擁有。
|
||||
* 若擁有,則回呼paintingId;若否,則回呼false。
|
||||
* @param {string} paintingId 要檢查的圖畫的Id。
|
||||
* @param {string} user_id 目標使用者的_id。
|
||||
* @param {CallbackFunction} callback 回呼函式。
|
||||
*/
|
||||
UserSchema.statics.CheckPaintingId = function (paintingId, user_id, callback) {
|
||||
this.findOne({"_id": user_id})
|
||||
.populate({ path: "paintings", select: { "id": 1 } })
|
||||
.exec((err, userDocs) => {
|
||||
if (err) return callback(err, null);
|
||||
if (userDocs.IsPaintingsOwner(paintingId)) {
|
||||
callback(null, paintingId);
|
||||
}
|
||||
else {
|
||||
callback(null, false);
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查詢目標使用者(user_id)是否為此使用者的好友。
|
||||
* @param {string} user_id 目標使用者的_id。
|
||||
* @return {boolean} 是否為使用者的好友。
|
||||
*/
|
||||
UserSchema.methods.IsUsersFriend = function (user_id) {
|
||||
let list = this.friendList;
|
||||
for (let _id of list) {
|
||||
if (_id.equals(user_id))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 對所有的使用者做訊息廣播。
|
||||
* @param {string} servMsg_id 目標的伺服器訊息的_id.
|
||||
* @param {CallbackFunction} callback 回呼函式。
|
||||
*/
|
||||
UserSchema.statics.BroadcastServerMessage = function (servMsg_id, callback) {
|
||||
// 建立站內資料
|
||||
let newSiteMsg = {
|
||||
isServerMessage: true,
|
||||
refId: servMsg_id,
|
||||
postTime: new Date(),
|
||||
isSeen: false,
|
||||
isPrivate: false
|
||||
};
|
||||
// 取得每一個使用者的資料,並選取其中的notices與siteMsg欄位
|
||||
this.find({}, "notices siteMsg", (err, userDocs) => {
|
||||
if (err) return callback(err, null);
|
||||
|
||||
// 循每一位使用者,將新的站內訊息資料加入到使用者資料中
|
||||
let index = -1, length = userDocs.length;
|
||||
function SaveUserDocs(err) {
|
||||
if (err) return callback(err, null);
|
||||
index += 1;
|
||||
// 若尚未儲存完畢,也就是還未到最後一個時,則繼續儲存
|
||||
if (index < length) {
|
||||
userDocs[index].notices += 1;
|
||||
userDocs[index].siteMsg.push(newSiteMsg);
|
||||
userDocs[index].save(SaveUserDocs);
|
||||
}
|
||||
// 若已完成則回呼
|
||||
else {
|
||||
callback(null, true);
|
||||
}
|
||||
}
|
||||
// 回呼式地做更改、儲存的動作。
|
||||
SaveUserDocs(false);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 以指定的標題、內容、隱私設定來獨立新增一個站內訊息。
|
||||
* @param {string} title 訊息的標題。
|
||||
* @param {string} content 訊息的內容。
|
||||
* @param {CallbackFunction} callback 回呼函式。
|
||||
*/
|
||||
UserSchema.methods.AddNewSiteMessage = function (title, content, isPrivate) {
|
||||
this.siteMsg.push({
|
||||
isServerMessage: false,
|
||||
title: title,
|
||||
content: content,
|
||||
refId: null,
|
||||
postTime: new Date(),
|
||||
isSeen: false,
|
||||
isPrivate: isPrivate
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 將所有使用者的「hasPostNewTheme」欄位設定為false。
|
||||
* @param {CallbackFunction} callback 回呼函式。
|
||||
*/
|
||||
UserSchema.statics.Refresh_HasPostNewTheme = function (callback) {
|
||||
// 嘗試將所有使用者資料中的 hasPostNewTheme 欄位更新成 false。
|
||||
this.updateMany({}, { $set: { "hasPostNewTheme": false } }, callback);
|
||||
}
|
||||
|
||||
/**
|
||||
* 將所也使用者的「hasVotedNewTheme」欄位設定為false。
|
||||
* @param {CallbackFunction} callback 回呼函式。
|
||||
*/
|
||||
UserSchema.statics.Refresh_HasVotedNewTheme = function (callback) {
|
||||
// 嘗試將所有使用者資料中的 hasVotedNewTheme 欄位更新成 false。
|
||||
this.updateMany({}, { $set: { "hasVotedNewTheme": false } }, callback);
|
||||
}
|
||||
|
||||
module.exports = mongoose.model("User", UserSchema);
|
||||
|
||||
// 交叉引入下,替Painting引入User。
|
||||
Painting.crossInitByUser();
|
16
models/renderModels/change_password.js
Normal file
@ -0,0 +1,16 @@
|
||||
|
||||
const User = require("../mongooseSchemas/User");
|
||||
|
||||
/**
|
||||
* 頁面「更變密碼」的插值函式。
|
||||
* @param {BasicLayout} renderData 基本插值物件。
|
||||
* @param {string} route 路由路徑。
|
||||
* @param {Express.Session} session Express的Session物件。
|
||||
* @param {CallbackFunction} callback 回呼函式。
|
||||
*/
|
||||
function ChangePasswordRender(renderData, route, session, callback) {
|
||||
// 頁面「更變密碼」不需要任何插值。
|
||||
callback(null, true);
|
||||
}
|
||||
|
||||
module.exports.Render = ChangePasswordRender;
|
72
models/renderModels/drawing.js
Normal file
@ -0,0 +1,72 @@
|
||||
|
||||
const User = require("../mongooseSchemas/User");
|
||||
const Painting = require("../mongooseSchemas/Painting");
|
||||
const Participation = require("../mongooseSchemas/Participation");
|
||||
|
||||
/** 預設的新畫作基本資料。 */
|
||||
const defaultPaintingData = {
|
||||
id: null,
|
||||
paintingName: "",
|
||||
description: "",
|
||||
tags: [],
|
||||
viewAuthority: 0,
|
||||
createdTime: "無",
|
||||
lastModified: "無",
|
||||
activity: null,
|
||||
isFinished: false,
|
||||
isLocked: false
|
||||
};
|
||||
|
||||
/**
|
||||
* 頁面「繪圖創作」的插值函式。
|
||||
* @param {BasicLayout} renderData 基本插值資料物件。
|
||||
* @param {string} route 路由路徑。
|
||||
* @param {Express.Session} session Express的Session物件。
|
||||
* @param {CallbackFunction} callback 回呼函式。
|
||||
*/
|
||||
function DrawingRender(renderData, route, session, callback) {
|
||||
let paintingId = route.substr(9);
|
||||
let datas = renderData.datas;
|
||||
// 若使用者有登入
|
||||
if (renderData.hasLogin) {
|
||||
// 先尋找使用者資料
|
||||
User.findOne({"username": renderData.username})
|
||||
.select("autoSaveEnable tags paintings")
|
||||
.populate({ path: "paintings", select: { "id": 1 } })
|
||||
.exec((err, userDocs) => {
|
||||
if (err) return callback(err, null);
|
||||
// 先將使用者的自動儲存設定、所有標填上
|
||||
datas.isAutoSave = userDocs.autoSaveEnable;
|
||||
datas.userTags = userDocs.tags;
|
||||
|
||||
// 若沒有指定圖畫ID,將預設的畫作資料填上後回呼。
|
||||
if (!paintingId) {
|
||||
datas.painting = defaultPaintingData;
|
||||
return callback(null, true);
|
||||
}
|
||||
|
||||
// 若該圖畫不屬於使用者的話,就回乎錯誤Error_PaintingNotExist。
|
||||
if (!userDocs.IsPaintingsOwner(paintingId)) {
|
||||
return callback(Painting.GetError_PaintingNotExist(), null);
|
||||
}
|
||||
|
||||
// 若該圖畫屬於使用者,則將目標畫作的基本資料填入,然後回呼true。
|
||||
Painting.GetDrawingPageInfoById(paintingId, (err, paintingInfo) => {
|
||||
if (err) return callback(err, null);
|
||||
datas.painting = paintingInfo;
|
||||
callback(null, true);
|
||||
});
|
||||
}
|
||||
);
|
||||
}
|
||||
// 若使用者沒有登入
|
||||
else {
|
||||
datas.isAutoSave = false;
|
||||
datas.userTags = [];
|
||||
datas.painting = defaultPaintingData;
|
||||
callback(null, true);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
module.exports.Render = DrawingRender;
|
26
models/renderModels/edit_personal_info.js
Normal file
@ -0,0 +1,26 @@
|
||||
|
||||
const User = require("../mongooseSchemas/User");
|
||||
|
||||
/**
|
||||
* 頁面「編輯個人資料」的插值函式。
|
||||
* @param {BasicLayout} renderData 插值物件。
|
||||
* @param {string} route 路由路徑。
|
||||
* @param {Express.Session} session Express的Session物件。
|
||||
* @param {CallbackFunction} callback 回呼函式。
|
||||
*/
|
||||
function EditPersonalInfoRender(renderData, route, session, callback) {
|
||||
User.findOne({"username": renderData.username})
|
||||
.exec((err, userDocs) => {
|
||||
if (err) return callback(err, null);
|
||||
if (userDocs) {
|
||||
renderData.datas = userDocs.personalInfo;
|
||||
callback(null, true);
|
||||
}
|
||||
else {
|
||||
callback(User.Error_UserNotExist(), null);
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
module.exports.Render = EditPersonalInfoRender;
|
27
models/renderModels/feedback.js
Normal file
@ -0,0 +1,27 @@
|
||||
var User = require("../mongooseSchemas/User");
|
||||
/**
|
||||
* 頁面「意見回饋」的插值函式。
|
||||
* @param {BasicLayout} renderData 基本插值物件。
|
||||
* @param {string} route 路由路徑。
|
||||
* @param {Express.Session} session Express的Session物件。
|
||||
* @param {CallbackFunction} callback 回呼函式。
|
||||
*/
|
||||
function FeedBackRender(renderData, route, session, callback) {
|
||||
renderData.datas.currentDate = (new Date()).toLocaleDateString();
|
||||
// 如果使用者沒有登入,則設定hasPostFeedback為false,並呼叫回呼函式。
|
||||
if (!renderData.hasLogin) {
|
||||
renderData.datas.hasPostFeedback = false;
|
||||
callback(null, true);
|
||||
return;
|
||||
}
|
||||
// 如果使用者有登入,則尋找資料庫中指定的使用者資料的「hasPostFeedback」欄位。
|
||||
User.findOne({ "username": renderData.username }).select("hasPostFeedback").exec(function (err, userDoc) {
|
||||
if (err) {
|
||||
callback(err, null);
|
||||
return;
|
||||
}
|
||||
renderData.datas.hasPostFeedback = userDoc.hasPostFeedback;
|
||||
callback(null, true);
|
||||
});
|
||||
}
|
||||
module.exports.Render = FeedBackRender;
|
30
models/renderModels/gallery.js
Normal file
@ -0,0 +1,30 @@
|
||||
let PaintingSpotlight = require("../mongooseSchemas/PaintingSpotlight");
|
||||
let Season = require("../mongooseSchemas/Season");
|
||||
/**
|
||||
* 頁面「傑作藝廊」的插值函式。
|
||||
* @param {BasicLayout} renderData 基本插值物件。
|
||||
* @param {string} route 路由路徑。
|
||||
* @param {Express.Session} session Express的Session物件。
|
||||
* @param {CallbackFunction} callback 回呼函式。傳回錯誤訊息或資料插值設定是否成功。
|
||||
*/
|
||||
function GalleryRender(renderData, route, session, callback) {
|
||||
// 先取得傑作藝廊中的精選輯
|
||||
PaintingSpotlight.GetCarouselInfo("gallery", function (err, carouselInfo) {
|
||||
if (err || !carouselInfo) {
|
||||
callback(err, null);
|
||||
return;
|
||||
}
|
||||
renderData.datas.paintings = carouselInfo.paintings;
|
||||
// 再取得活動相關的訊息
|
||||
Season.GetGalleryNeedInfo(function (err, seasonsInfo) {
|
||||
if (err) {
|
||||
callback(err, null);
|
||||
}
|
||||
else {
|
||||
renderData.datas.seasons = seasonsInfo;
|
||||
callback(err, true);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
module.exports.Render = GalleryRender;
|
20
models/renderModels/index.js
Normal file
@ -0,0 +1,20 @@
|
||||
var PaintingSpotlight = require("../mongooseSchemas/PaintingSpotlight");
|
||||
/**
|
||||
* 取得首頁的插值資料。
|
||||
* @param {BasicLayout} renderData 插值物件。
|
||||
* @param {string} route 路由路徑。
|
||||
* @param {Express.Session} session Express的Session物件。
|
||||
* @param {CallbackFunction} callback 回呼函式。
|
||||
*/
|
||||
function IndexRender(renderData, route, session, callback) {
|
||||
PaintingSpotlight.GetCarouselInfo("index", function (err, infos) {
|
||||
if (err) {
|
||||
callback(err, null);
|
||||
}
|
||||
else {
|
||||
renderData.datas = infos;
|
||||
callback(null, true);
|
||||
}
|
||||
});
|
||||
}
|
||||
module.exports.Render = IndexRender;
|
12
models/renderModels/login.js
Normal file
@ -0,0 +1,12 @@
|
||||
/**
|
||||
* 頁面「登入」的插值函式。
|
||||
* @param {BasicLayout} renderData 基本插值物件。
|
||||
* @param {string} route 路由路徑。
|
||||
* @param {Express.Session} session Express的Session物件。
|
||||
* @param {CallbackFunction} callback 回呼函式。
|
||||
*/
|
||||
function LoginRender(renderData, route, session, callback) {
|
||||
// 登入頁面目前不需要做任何插值
|
||||
callback(null, true);
|
||||
}
|
||||
module.exports.Render = LoginRender;
|
101
models/renderModels/message_form.js
Normal file
@ -0,0 +1,101 @@
|
||||
|
||||
/**
|
||||
* 設定轉跳訊息頁面下的插值處理。
|
||||
* @param {BasicLayout} renderData 插值物件。
|
||||
* @param {string} route 路由路徑。
|
||||
* @param {Express.Session} session Express的Session物件。
|
||||
* @param {CallbackFunction} callback 回呼函式。
|
||||
*/
|
||||
function MessageFormRender(renderData, route, session, callback) {
|
||||
switch(true) {
|
||||
case route == "/signupmsg": // 註冊成功的轉跳頁面
|
||||
renderData.datas.title = "註冊成功!";
|
||||
renderData.datas.content = "您現在可以用您所註冊的帳號登入了!";
|
||||
renderData.datas.button1 = "登入";
|
||||
renderData.datas.script = "$('#btnAction1').on('click', () => window.location.replace('/login'));";
|
||||
break;
|
||||
case route.includes("/homenotexist/"): // 在「個人頁面」下找不到目標使用者時的轉跳頁面
|
||||
// 確認使用者名稱存在於路徑中
|
||||
if (route.length > 14) {
|
||||
let username = route.substr(14); // 取得找不到的「使用者名稱」
|
||||
renderData.datas.title = "找不到 “" + username + "” 的個人頁面!"
|
||||
}
|
||||
else {
|
||||
renderData.datas.title = "找不到指定使用者的個人頁面!";
|
||||
}
|
||||
renderData.datas.content = "很抱歉,您所尋找的使用者並不存在!";
|
||||
renderData.datas.button1 = "首頁";
|
||||
renderData.datas.script = "$('#btnAction1').on('click', () => window.location.replace('/'));";
|
||||
break;
|
||||
|
||||
case route == "/personalinfo_updated": // 在「編輯個人資料」頁面下,成功編輯個人資料後的跳轉提示頁面
|
||||
renderData.datas.title = "個人資料修改成功!";
|
||||
renderData.datas.content = "您的個人資料已成功更新!";
|
||||
renderData.datas.button1 = "返回";
|
||||
renderData.datas.script = "$('#btnAction1').on('click', () => window.location.replace('/home/" + renderData.username + "'));";
|
||||
break;
|
||||
|
||||
case route == "/send_sitemail_successfully": // 在「撰寫站內訊息」頁面下,成功編輯個人資料後的轉跳頁面。
|
||||
renderData.datas.title = "站內信發送成功!";
|
||||
renderData.datas.content = "您的站內信件已成功寄送!";
|
||||
renderData.datas.button1 = "返回";
|
||||
renderData.datas.script = "$('#btnAction1').on('click', () => window.location.replace('/home/" + renderData.username + "'));";
|
||||
break;
|
||||
case route == "/newpw_success": // 在「更變密碼」頁面下,成功更改密碼後的轉跳頁面。
|
||||
renderData.datas.title = "密碼更改成功!";
|
||||
renderData.datas.content = "您的密碼已經更改成功!";
|
||||
renderData.datas.button1 = "返回";
|
||||
renderData.datas.script = "$('#btnAction1').on('click', () => window.location.replace('/home/" + renderData.username + "'));";
|
||||
break;
|
||||
case route == "/painting_finished": // 在「繪圖創作」頁面下,成功完成畫作之後的跳轉頁面。
|
||||
renderData.datas.title = "作品已完成!";
|
||||
renderData.datas.content = "您的畫作已經完成,您可以返回去欣賞您的畫作!";
|
||||
renderData.datas.button1 = "返回";
|
||||
renderData.datas.script = "$('#btnAction1').on('click', () => window.location.replace('/home/" + renderData.username + "'));";
|
||||
break;
|
||||
case route == "/painting_not_exist": // 在找不到指定的圖畫作品之下的跳轉頁面
|
||||
renderData.datas.title = "找不到您的圖畫作品!";
|
||||
renderData.datas.content = "請確認您所指定的圖畫作品是否所屬於您,或是該作品是否存在。";
|
||||
renderData.datas.button1 = "返回";
|
||||
renderData.datas.script = "$('#btnAction1').on('click', () => window.location.replace('/home/" + renderData.username + "'));";
|
||||
break;
|
||||
case route == "/painting_deleted": // 成功刪除指定圖畫作品後的跳轉頁面
|
||||
renderData.datas.title = "圖畫作品刪除成功!";
|
||||
renderData.datas.content = "您指定的圖畫作品已刪除成功!" + (session.paintingDeleted_Activity ? "請注意,投稿至活動上的圖畫不會被刪除!" : "");
|
||||
renderData.datas.button1 = "返回";
|
||||
renderData.datas.script = "$('#btnAction1').on('click', () => window.location.replace('/home/" + renderData.username + "'));";
|
||||
// 若有被標記,則刪除paintingDeleted_Activity
|
||||
if (session.paintingDeleted_Activity)
|
||||
delete session.paintingDeleted_Activity;
|
||||
break;
|
||||
case route == "/newtheme/successful": // 當成功處理了「投稿新主題」後的轉跳頁面
|
||||
renderData.datas.title = "新主題投稿成功!";
|
||||
renderData.datas.content = "您所投稿的新主題已成功地上傳!請等待最新一季的結果。";
|
||||
renderData.datas.button1 = "返回首頁";
|
||||
renderData.datas.script = "$('#btnAction1').on('click', () => window.location.replace('/'));";
|
||||
break;
|
||||
case route == "/newtheme": // 當使用者在「投稿主題」路由上,但卻已經有投稿過主題的轉跳頁面
|
||||
renderData.datas.title = "您已經投稿過新主題了!";
|
||||
renderData.datas.content = "請等待下一次的「投稿主題」活動再進行發起主題的動作!。";
|
||||
renderData.datas.button1 = "返回";
|
||||
renderData.datas.script = "$('#btnAction1').on('click', () => window.history.back() );";
|
||||
break;
|
||||
case route == "/votetheme/success": // 當成功處理了「主題票選」後的轉跳頁面
|
||||
renderData.datas.title = "候選主題投票成功!";
|
||||
renderData.datas.content = "您的投票資料已經成功送出!請等待下一次的主題投票。";
|
||||
renderData.datas.button1 = "返回首頁";
|
||||
renderData.datas.script = "$('#btnAction1').on('click', () => window.location.replace('/'));";
|
||||
break;
|
||||
case route == "/votetheme": // 當使用者在「主題票選」路由上,但卻已經有票選過主題之後的跳轉頁面
|
||||
renderData.datas.title = "您已經對候選主題票選過了!";
|
||||
renderData.datas.content = "請等待下一次的「主題票選」活動再進行主題票選的動作!";
|
||||
renderData.datas.button1 = "返回";
|
||||
renderData.datas.script = "$('#btnAction1').on('click', () => window.history.back() );";
|
||||
break;
|
||||
default: // 其他未定義的伺服器訊息
|
||||
return callback(new Error("未定義的對應伺服訊息插值資料。"), null);
|
||||
}
|
||||
return callback(false, true);
|
||||
}
|
||||
|
||||
module.exports.Render = MessageFormRender;
|
89
models/renderModels/personal_page.js
Normal file
@ -0,0 +1,89 @@
|
||||
|
||||
const User = require("../mongooseSchemas/User");
|
||||
const Painting = require("../mongooseSchemas/Painting");
|
||||
const SiteMail = require("../mongooseSchemas/SiteMail");
|
||||
|
||||
/**
|
||||
* 取得「個人頁面」的插值資料。
|
||||
* @param {BasicLayout} renderData 插值物件。
|
||||
* @param {string} route 路由路徑。
|
||||
* @param {Express.Session} session Express的Session物件。
|
||||
* @param {CallbackFunction} callback 回呼函式。
|
||||
*/
|
||||
function PersonalPageRender(renderData, route, session, callback) {
|
||||
let paramUsername = route.substr(6); // 取得路徑中所選的目標個人頁面的使用者名稱
|
||||
|
||||
// 初步地檢查是否為合法的使用者名稱長度。若是,則進一步地去查詢相關資料
|
||||
if (4 <= paramUsername.length && paramUsername.length <= 16) {
|
||||
// 定義Populate Query : 套用的有paintings, siteMsg, siteMail 與 friendList
|
||||
let populateQuery = [
|
||||
{ path: "paintings", select: { "id": 1, "name": 1, "links": 1, "description": 1, "viewAuthority": 1, "tags": 1 } },
|
||||
{ path: "friendList", select: { "username": 1 } },
|
||||
{ path: "siteMsg.refId" },
|
||||
{ path: "siteMail" }
|
||||
];
|
||||
|
||||
// 嘗試尋找指定的使用者,並做populate來取得相關連的資料
|
||||
User.findOne({"username": paramUsername})
|
||||
.populate(populateQuery)
|
||||
.exec((err, userDocs) => {
|
||||
// 如果找到使用者的話,將需要的資料填入插值物件中
|
||||
if (userDocs) {
|
||||
// 定義 datas 物件,並將一些不需要過濾的資料先加入
|
||||
let datas = {
|
||||
isOwner: (renderData.username == userDocs.username), // 若目前正瀏覽的使用者與目標使用者的相同,則為這個個人頁面的擁有者(true),反之為否(false)
|
||||
username: userDocs.username, // 使用者名稱
|
||||
nickname: userDocs.personalInfo.nickname, // 暱稱
|
||||
motto: userDocs.personalInfo.motto, // 短言
|
||||
userPhotoURL: userDocs.personalInfo.photo, // 個人相片 (連結路徑)
|
||||
autoSaveEnable: userDocs.autoSaveEnable, // 自動儲存
|
||||
userTags: userDocs.tags, // 作品標籤
|
||||
friendList: [], // 好友清單
|
||||
siteMsg: [], // 網站訊息
|
||||
paintings: [], // 作品集
|
||||
siteMail: null // 站內信
|
||||
};
|
||||
|
||||
// 循環將 friendList 加入 datas 中
|
||||
for (let i = 0, list = userDocs.friendList; i < list.length; i++)
|
||||
datas.friendList.push(list[i].username);
|
||||
|
||||
// 循環將 siteMail 加入 datas 中
|
||||
for (let list = userDocs.siteMsg, i = list.length - 1; i >= 0; i--) {
|
||||
// 若為伺服訊息,則引用連接的伺服訊息資料
|
||||
if (list[i].isServerMessage) {
|
||||
datas.siteMsg.push({ title: list[i].refId.title, content: list[i].refId.content });
|
||||
}
|
||||
else {
|
||||
datas.siteMsg.push({ title: list[i].title, content: list[i].content });
|
||||
}
|
||||
}
|
||||
|
||||
datas.siteMail = userDocs.siteMail; // 將 siteMail 加入 datas 中
|
||||
|
||||
// 循環將 paintings 加入 datas 中
|
||||
let isFriend = userDocs.IsUsersFriend(session.passport.user); // 取得目前使用者對目標使用者而言的權限
|
||||
for (let i = 0, list = userDocs.paintings; i < list.length; i++) {
|
||||
// 若 觀看權限為「公開」 或 使用者為目標使用者的朋友且觀看權限為「半公開」 或 該使用者即為擁有者,則將幅畫資訊加入
|
||||
if (list[i].viewAuthority == 0 || isFriend && list[i].viewAuthority == 1 || datas.isOwner) {
|
||||
datas.paintings.push(list[i]);
|
||||
}
|
||||
}
|
||||
|
||||
renderData.datas = datas; // 最後將 datas 複寫至 renderData.datas
|
||||
callback(null, true);
|
||||
}
|
||||
// 若沒有找到,則將錯誤「找不到目標使用者」回呼至上層路由
|
||||
else {
|
||||
callback(User.Error_UserNotExist(), null);
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
// 如果不為合法的使用者名稱長度,則將錯誤「找不到目標使用者」回呼至上層路由。
|
||||
else {
|
||||
callback(User.Error_UserNotExist(), null);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports.Render = PersonalPageRender;
|
166
models/renderModels/showcase.js
Normal file
@ -0,0 +1,166 @@
|
||||
|
||||
const User = require("../mongooseSchemas/User");
|
||||
const Painting = require("../mongooseSchemas/Painting");
|
||||
const ParticipantInfo = require("../mongooseSchemas/ParticipantInfo");
|
||||
|
||||
/**
|
||||
* 以主使用者與被檢查的使用者之間的關係,取得觀看權限數值。
|
||||
* @param {User} mainUser 主要使用者的資料。
|
||||
* @param {string} otherUser_id 目標要查詢的使用者_id。
|
||||
* @return {number} 觀看權限數值。
|
||||
*/
|
||||
function GetAuthorityNumber(mainUser, otherUser_id) {
|
||||
if (mainUser._id.equals(otherUser_id)) { // 若mainUser與otherUser為同一人,則回傳2。
|
||||
return 2;
|
||||
}
|
||||
else if (mainUser.IsUsersFriend(otherUser_id)) { // 若otherUser為mainUser的好友,則回傳1。
|
||||
return 1;
|
||||
}
|
||||
else { // 若不為好友,則回傳0。
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @typedef PaintingRange
|
||||
* @prop {number} n 表示第n個區間。
|
||||
* @prop {string[]} range_id 表示在第n個區間中的圖畫Id。
|
||||
*/
|
||||
/**
|
||||
* 取得目標要尋找的圖畫Id座落的區間與該區間中第一個圖畫Id。
|
||||
* @param {Painting[]} list 全域的資料。為圖畫陣列。
|
||||
* @param {string} id 要尋找座落在哪區間的資料。為圖畫Id。
|
||||
* @param {number} viewAutho 觀看權限數值。
|
||||
* @return {PaintingRange} 回傳第N個區間整數與該區間中的第一個圖畫Id。為 {n, range_id}。
|
||||
*/
|
||||
function GetRangeIndex(list, id, viewAutho) {
|
||||
let viewList = list.filter((docs => docs.viewAuthority <= viewAutho)); // 用「訪問權限」與觀看權限數值,過濾原本的畫作清單,成新的畫作清單。
|
||||
let length = viewList.length; // 取得清單內容長度
|
||||
// 尋找目標畫作在清單中的索引位置
|
||||
for (let i = 0; i < length; i++) {
|
||||
if (list[i].id == id) {
|
||||
// 以十個畫作為一組,取得目前在第n組
|
||||
let n = Math.floor(i / 10);
|
||||
|
||||
// 回傳n,與第n組中 (n * 10) ~ (n * 10 + 9) 之間的畫作_id清單。
|
||||
return { n: n, range_id: list.slice(n * 10, n * 10 + 10).filter(docs => docs._id) };
|
||||
}
|
||||
}
|
||||
// 若沒找到則回傳null。
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 為「個人藝廊」模式下的插值方法。
|
||||
* @param {BasicLayout} renderData 基本差值物件。
|
||||
* @param {string[]} params 路由路徑中的每項參數。
|
||||
* @param {Express.Session} session Express的Session物件。
|
||||
* @param {CallbackFunction} callback 回呼函式。
|
||||
*/
|
||||
function PersonalShowcaseRender(renderData, params, session, callback) {
|
||||
let username = params[2]; // 此個人藝廊的使用者
|
||||
let paintingId = params[3]; // 指定要瀏覽的畫作Id
|
||||
let tag = params[4]; // 指定畫作的標籤群組(可有可無)
|
||||
let datas = renderData.datas;
|
||||
|
||||
datas.isActivity = false;
|
||||
datas.themeTitle = null;
|
||||
datas.themeOriginator = null;
|
||||
datas.artist = username;
|
||||
datas.tag = tag;
|
||||
datas.paintings = []; // 建立畫作清單欄位
|
||||
|
||||
// 建立 Populate Query
|
||||
let populateQuery = {
|
||||
path: "paintings",
|
||||
select: { "id": 1, "viewAuthority": 1 },
|
||||
match: { "isLocked": false }
|
||||
};
|
||||
|
||||
// 如果有指定tag,則將其加入到populateQuery之中作為條件
|
||||
// 比對每個畫作的標籤中是否有包含tag。
|
||||
if (tag)
|
||||
populateQuery.match.tags = tag;
|
||||
|
||||
// 以username尋找目標使用者的資料,其中選取paintings欄位,然後再以populateQuery做畫作連結
|
||||
User.findOne({"username": username})
|
||||
.select("personalInfo.photo paintings friendList")
|
||||
.populate(populateQuery)
|
||||
.exec((err, userDocs) => {
|
||||
if (err) callback(err, null);
|
||||
if (!userDocs) callback(User.Error_UserNotExist(), null); // 若找不到使用者,則帶著相對應的錯誤回呼
|
||||
let ownersPhotoURL = userDocs.personalInfo.photo; // 擁有此展示藝廊的人的頭像照片
|
||||
let paintingList = userDocs.paintings; // 取得畫作Id清單
|
||||
let viewAuth = GetAuthorityNumber(userDocs, session.passport.user); // 取得觀看權限數值
|
||||
let rangeInfo = GetRangeIndex(paintingList, paintingId, viewAuth); // 取得區間資料
|
||||
|
||||
// 如果目標畫作不在清單之中的話,則回呼錯誤 **仍要再改
|
||||
if (!rangeInfo) return callback(new Error("找不到對應的畫作。"), null);
|
||||
|
||||
// 以區間尋找畫作資訊
|
||||
Painting.find({ "_id": { $in: rangeInfo.range_id } })
|
||||
.populate([{path: "ratings"}, {path: "comments"}])
|
||||
.exec((err, paintingDocs) => {
|
||||
if (err) callback(err, null);
|
||||
|
||||
// 循每一個畫作資料,取其中的欄位資料加入至 datas.paintings 中
|
||||
paintingDocs.forEach((docs) => {
|
||||
datas.paintings.push({
|
||||
id: docs.id,
|
||||
links: docs.links,
|
||||
name: docs.name,
|
||||
description: docs.description,
|
||||
artistInfo: { name: username, photoURL: ownersPhotoURL},
|
||||
totalScore: docs.totalScore,
|
||||
userScore: docs.FindRatingScoreByUsername(renderData.username),
|
||||
comments: docs.comments
|
||||
});
|
||||
});
|
||||
|
||||
// 最後,取得當前使用者的個人照片
|
||||
User.findOne({"_id": session.passport.user}, "personalInfo.photo", (err, guestUserDocs) => {
|
||||
if (err) return callback(err, null);
|
||||
if (!guestUserDocs) return callback(User.Error_UserNotExist(), null);
|
||||
datas.photoURL = guestUserDocs.personalInfo.photo; // 取得當前使用者的個人照片
|
||||
|
||||
callback(null, true);
|
||||
});
|
||||
}
|
||||
);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* 為「活動藝廊」模式下的差值方法。
|
||||
* @param {BasicLayout} renderData 基本插值物件。
|
||||
* @param {string[]} params 路由路徑中的每項參數。
|
||||
* @param {Express.Session} session Express的Session物件。
|
||||
* @param {CallbackFunction} callback 回呼函式。
|
||||
*/
|
||||
function ActivityShowcaseRender(renderData, params, session, callback) {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {BasicLayout} renderData 基本插值物件。
|
||||
* @param {string} route 路由路徑。
|
||||
* @param {Express.Session} session Express的Session物件。
|
||||
* @param {CallbackFunction} callback 回呼函式。
|
||||
*/
|
||||
function ShowcaseRender(renderData, route, session, callback) {
|
||||
let params = route.split("/").slice(1);
|
||||
switch(params[1]) {
|
||||
case "personal":
|
||||
PersonalShowcaseRender(renderData, params, session, callback);
|
||||
break;
|
||||
case "activity":
|
||||
ActivityShowcaseRender(renderData, params, session, callback);
|
||||
break;
|
||||
default:
|
||||
callback(new Error("未定義的展示藝廊模式。"), null);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports.Render = ShowcaseRender;
|
12
models/renderModels/signup.js
Normal file
@ -0,0 +1,12 @@
|
||||
/**
|
||||
* 頁面「註冊」的插值函式。
|
||||
* @param {BasicLayout} renderData 基本插值物件。
|
||||
* @param {string} route 路由路徑。
|
||||
* @param {Express.Session} session Express的Session物件。
|
||||
* @param {CallbackFunction} callback 回呼函式。
|
||||
*/
|
||||
function SignUpRender(renderData, route, session, callback) {
|
||||
// 登入頁面目前不需要做任何插值
|
||||
callback(null, true);
|
||||
}
|
||||
module.exports.Render = SignUpRender;
|
14
models/renderModels/submit_theme.js
Normal file
@ -0,0 +1,14 @@
|
||||
|
||||
/**
|
||||
* 以基本插值資料、路由路徑做資料源,設定在submit_theme頁面下該插入什麼資料值。
|
||||
* @param {BasicLayout} renderData 插值物件。
|
||||
* @param {string} route 路由路徑。
|
||||
* @param {Express.Session} session Express的Session物件。
|
||||
* @param {CallbackFunction} callback 回呼函式。
|
||||
*/
|
||||
function SubmitThemeRender(renderData, route, session, callback) {
|
||||
// 此頁面不需要任何插值資料
|
||||
callback(null, true);
|
||||
}
|
||||
|
||||
module.exports.Render = SubmitThemeRender;
|
21
models/renderModels/theme.js
Normal file
@ -0,0 +1,21 @@
|
||||
var Season = require("../mongooseSchemas/Season");
|
||||
/**
|
||||
* 頁面「畫作主題」的插值函式。
|
||||
* @param {BasicLayout} renderData 基本插值物件。
|
||||
* @param {string} route 路由路徑。
|
||||
* @param {Express.Session} session Express的Session物件。
|
||||
* @param {CallbackFunction} callback 回呼函式。
|
||||
*/
|
||||
function ThemeRender(renderData, route, session, callback) {
|
||||
// 先取得「畫作主題」頁面所需要的季資訊
|
||||
// 若出現錯誤,則回呼錯誤訊息;若取得成功,則回呼true已表示成功。
|
||||
Season.GetThemePageNeedInfo(function (err, seasonDatas) {
|
||||
if (err) {
|
||||
callback(err, null);
|
||||
return;
|
||||
}
|
||||
renderData.datas = seasonDatas;
|
||||
callback(null, true);
|
||||
});
|
||||
}
|
||||
module.exports.Render = ThemeRender;
|
42
models/renderModels/typescripts/feedback.ts
Normal file
@ -0,0 +1,42 @@
|
||||
|
||||
const User : any = require("../mongooseSchemas/User");
|
||||
|
||||
/**
|
||||
* 由DataRender所定義的基本差值物件。這裡僅列出必要的datas屬性與會用到的屬性。
|
||||
*/
|
||||
interface BasicLayout {datas: any, hasLogin: boolean, username: string}
|
||||
|
||||
/**
|
||||
* A Callback function.
|
||||
* @callback CallbackFunction
|
||||
* @param {Object} err 錯誤資訊物件。
|
||||
* @param {Object} obj 成功時所回傳的物件。
|
||||
*/
|
||||
interface CallbackFunction { (err: Object, obj: Object) : void }
|
||||
|
||||
/**
|
||||
* 頁面「意見回饋」的插值函式。
|
||||
* @param {BasicLayout} renderData 基本插值物件。
|
||||
* @param {CallbackFunction} callback 回呼函式。
|
||||
*/
|
||||
function FeedBackRender(renderData: BasicLayout, callback: CallbackFunction) : void
|
||||
{
|
||||
renderData.datas.currentDate = (new Date()).toLocaleDateString();
|
||||
// 如果使用者沒有登入,則設定hasPostFeedback為false,並呼叫回呼函式。
|
||||
if (!renderData.hasLogin) {
|
||||
renderData.datas.hasPostFeedback = false;
|
||||
callback(null, true);
|
||||
return;
|
||||
}
|
||||
// 如果使用者有登入,則尋找資料庫中指定的使用者資料的「hasPostFeedback」欄位。
|
||||
User.findOne({"username" : renderData.username}).select("hasPostFeedback").exec((err, property) => {
|
||||
if (err) {
|
||||
callback(err, null);
|
||||
return;
|
||||
}
|
||||
renderData.datas.hasPostFeedback = property;
|
||||
callback(null, true);
|
||||
});
|
||||
}
|
||||
|
||||
module.exports.Render = FeedBackRender;
|
94
models/renderModels/typescripts/gallery.ts
Normal file
@ -0,0 +1,94 @@
|
||||
|
||||
const PaintingSpotlight = require("../mongooseSchemas/PaintingSpotlight");
|
||||
const Season = require("../mongooseSchemas/Season");
|
||||
|
||||
/**
|
||||
* 由DataRender所定義的基本差值物件。這裡僅列出必要的datas屬性
|
||||
*/
|
||||
interface BasicLayout {datas: any}
|
||||
|
||||
/**
|
||||
* A Callback function.
|
||||
* @callback CallbackFunction
|
||||
* @param {Object} err 錯誤資訊物件。
|
||||
* @param {Object} obj 成功時所回傳的物件。
|
||||
*/
|
||||
interface CallbackFunction { (err: Object, obj: Object) : void }
|
||||
|
||||
/**
|
||||
* 繪圖展示上的簡短訊息。
|
||||
* @prop {string} links 此畫作的圖片連結。
|
||||
* @prop {string} name 此畫作的名稱。
|
||||
* @prop {string} description 此畫作的敘述。
|
||||
* @prop {string} artist 畫作的作者。
|
||||
*/
|
||||
interface PaintingInfo {
|
||||
links : string
|
||||
name : string,
|
||||
description : string,
|
||||
artist : string
|
||||
}
|
||||
|
||||
/**
|
||||
* 表示畫作的參賽相關訊息。
|
||||
* @prop {number} rank 此畫作的名次。
|
||||
* @prop {string} artist 畫作的作者。
|
||||
* @prop {string} paintingName 畫作的名稱。
|
||||
* @prop {Date} postTime 此畫作的參賽時間。
|
||||
*/
|
||||
interface ParticipantInfo {
|
||||
rank : number,
|
||||
artist : string,
|
||||
paintingName : string,
|
||||
postTime : Date
|
||||
}
|
||||
|
||||
/**
|
||||
* 有關主題的相關訊息。
|
||||
* @prop {number} order 主題與主題之間的識別號碼(用於版面先後排序用)。
|
||||
* @prop {string} title 主題的標題。
|
||||
* @prop {ParticipantInfo[]} participants 此主題的所有參賽畫作資訊。
|
||||
*/
|
||||
interface ThemeInfo {
|
||||
order : number,
|
||||
title : string,
|
||||
participants : ParticipantInfo[]
|
||||
}
|
||||
|
||||
/**
|
||||
* 有關一季活動之中的相關訊息。
|
||||
* @prop {number} nth 表示目前是第nth季
|
||||
* @prop {ThemeInfo[]} 儲存這一季之中所有的活動。
|
||||
*/
|
||||
interface SeasonInfo {
|
||||
nth : number,
|
||||
themes : ThemeInfo[]
|
||||
}
|
||||
|
||||
/**
|
||||
* 頁面「傑作藝廊」的插值函式。
|
||||
* @param {BasicLayout} renderData 基本插值物件。
|
||||
* @param {CallbackFunction} callback 回呼函式。傳回錯誤訊息或資料插值設定是否成功。
|
||||
*/
|
||||
function GalleryRender(renderData : BasicLayout, callback : CallbackFunction) : void {
|
||||
// 先取得傑作藝廊中的精選輯
|
||||
PaintingSpotlight.GetCarouselInfo("gallery", (err, carouselInfo) => {
|
||||
if (err || !carouselInfo) {
|
||||
callback(err, null);
|
||||
return;
|
||||
}
|
||||
renderData.datas.paintings = carouselInfo.paintings;
|
||||
// 再取得活動相關的訊息
|
||||
Season.GetGalleryNeedInfo((err, seasonsInfo) => {
|
||||
if (err){
|
||||
callback(err, null);
|
||||
}
|
||||
else {
|
||||
renderData.datas.seasons = seasonsInfo;
|
||||
callback(err, true);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
module.exports.Render = GalleryRender;
|
50
models/renderModels/typescripts/index.ts
Normal file
@ -0,0 +1,50 @@
|
||||
let PaintingSpotlight = require("../mongooseSchemas/PaintingSpotlight");
|
||||
|
||||
/**
|
||||
* 由DataRender所定義的基本差值物件。這裡僅列出必要的datas屬性。
|
||||
*/
|
||||
interface BasicLayout {datas: any}
|
||||
|
||||
/**
|
||||
* A Callback function.
|
||||
* @callback CallbackFunction
|
||||
* @param {Object} err 錯誤資訊物件。
|
||||
* @param {Object} obj 成功時所回傳的物件。
|
||||
*/
|
||||
interface CallbackFunction { (err: Object, obj: Object) : void }
|
||||
|
||||
/**
|
||||
* Painting Information Interface
|
||||
*/
|
||||
interface PaintingInfo {
|
||||
links : string
|
||||
name : string,
|
||||
description : string,
|
||||
artist : string
|
||||
}
|
||||
|
||||
/**
|
||||
* Data layout of index.
|
||||
*/
|
||||
interface IndexLayout {
|
||||
paintings : PaintingInfo[]
|
||||
}
|
||||
|
||||
/**
|
||||
* 取得首頁的插值資料。
|
||||
* @param {BasicLayout} renderData 插值物件。
|
||||
* @param {CallbackFunction} callback 回呼函式。
|
||||
*/
|
||||
function IndexRender(renderData : BasicLayout, callback : CallbackFunction) : void {
|
||||
PaintingSpotlight.GetCarouselInfo("index", (err, infos) => {
|
||||
if (err) {
|
||||
callback(err, null);
|
||||
}
|
||||
else {
|
||||
renderData.datas = infos;
|
||||
callback(null, true);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
module.exports.Render = IndexRender;
|
26
models/renderModels/typescripts/login.ts
Normal file
@ -0,0 +1,26 @@
|
||||
|
||||
/**
|
||||
* 由DataRender所定義的基本差值物件。這裡僅列出必要的datas屬性。
|
||||
*/
|
||||
interface BasicLayout {datas: any}
|
||||
|
||||
/**
|
||||
* A Callback function.
|
||||
* @callback CallbackFunction
|
||||
* @param {Object} err 錯誤資訊物件。
|
||||
* @param {Object} obj 成功時所回傳的物件。
|
||||
*/
|
||||
interface CallbackFunction { (err: Object, obj: Object) : void }
|
||||
|
||||
/**
|
||||
* 頁面「登入」的插值函式。
|
||||
* @param {BasicLayout} renderData 基本插值物件。
|
||||
* @param {CallbackFunction} callback 回呼函式。
|
||||
*/
|
||||
function LoginRender(renderData: BasicLayout, callback: CallbackFunction) : void
|
||||
{
|
||||
// 登入頁面目前不需要做任何插值
|
||||
callback(null, true);
|
||||
}
|
||||
|
||||
module.exports.Render = LoginRender;
|
26
models/renderModels/typescripts/signup.ts
Normal file
@ -0,0 +1,26 @@
|
||||
|
||||
/**
|
||||
* 由DataRender所定義的基本差值物件。這裡僅列出必要的datas屬性。
|
||||
*/
|
||||
interface BasicLayout {datas: any}
|
||||
|
||||
/**
|
||||
* A Callback function.
|
||||
* @callback CallbackFunction
|
||||
* @param {Object} err 錯誤資訊物件。
|
||||
* @param {Object} obj 成功時所回傳的物件。
|
||||
*/
|
||||
interface CallbackFunction { (err: Object, obj: Object) : void }
|
||||
|
||||
/**
|
||||
* 頁面「註冊」的插值函式。
|
||||
* @param {BasicLayout} renderData 基本插值物件。
|
||||
* @param {CallbackFunction} callback 回呼函式。
|
||||
*/
|
||||
function SignUpRender(renderData: BasicLayout, callback: CallbackFunction) : void
|
||||
{
|
||||
// 登入頁面目前不需要做任何插值
|
||||
callback(null, true);
|
||||
}
|
||||
|
||||
module.exports.Render = SignUpRender;
|
70
models/renderModels/typescripts/theme.ts
Normal file
@ -0,0 +1,70 @@
|
||||
|
||||
const Season : any = require("../mongooseSchemas/Season");
|
||||
|
||||
/**
|
||||
* 由DataRender所定義的基本差值物件。這裡僅列出必要的datas屬性
|
||||
*/
|
||||
interface BasicLayout {datas: any}
|
||||
|
||||
/**
|
||||
* A Callback function.
|
||||
* @callback CallbackFunction
|
||||
* @param {Object} err 錯誤資訊物件。
|
||||
* @param {Object} obj 成功時所回傳的物件。
|
||||
*/
|
||||
interface CallbackFunction { (err: Object, obj: Object) : void }
|
||||
|
||||
/**
|
||||
* 有關主題的相關訊息。
|
||||
* @prop {number} order 主題與主題之間的識別號碼(用於版面先後排序用)。
|
||||
* @prop {string} title 主題的標題。
|
||||
* @prop {string} narrative 主題的敘述。
|
||||
* @prop {string} imageURL 主題縮圖連結。
|
||||
* @prop {string} originator 主題發起人。
|
||||
* @prop {number} participantCount 投稿人數。
|
||||
* @prop {number} views 瀏覽此主題的人次數。
|
||||
* @prop {number} commentCount 主題中相關留言人數。
|
||||
*/
|
||||
interface ThemeInfo {
|
||||
order : number,
|
||||
title : string,
|
||||
narrative : string,
|
||||
imageURL : string,
|
||||
originator : string,
|
||||
participantCount : number,
|
||||
views : number,
|
||||
commentCount : number
|
||||
}
|
||||
|
||||
/**
|
||||
* 有關一季活動之中的相關訊息。
|
||||
* @prop {number} nth 表示目前是第nth季
|
||||
* @prop {Date} endTime 表示該季的結束時間。在資料取得中只有上一季有這個欄位
|
||||
* @prop {ThemeInfo[]} 儲存這一季之中所有的活動。
|
||||
*/
|
||||
interface SeasonInfo {
|
||||
nth : number,
|
||||
endTime : Date,
|
||||
themes : ThemeInfo[]
|
||||
}
|
||||
|
||||
/**
|
||||
* 頁面「畫作主題」的插值函式。
|
||||
* @param renderData 基本插值物件。
|
||||
* @param callback 回呼函式。
|
||||
*/
|
||||
function ThemeRender(renderData: BasicLayout, callback: CallbackFunction) : void
|
||||
{
|
||||
// 先取得「畫作主題」頁面所需要的季資訊
|
||||
// 若出現錯誤,則回呼錯誤訊息;若取得成功,則回呼true已表示成功。
|
||||
Season.GetThemePageNeedInfo((err, seasonDatas) => {
|
||||
if (err) {
|
||||
callback(err, null);
|
||||
return;
|
||||
}
|
||||
renderData.datas = seasonDatas;
|
||||
callback(null, true);
|
||||
});
|
||||
}
|
||||
|
||||
module.exports.Render = ThemeRender;
|
44
models/renderModels/vote_theme.js
Normal file
@ -0,0 +1,44 @@
|
||||
|
||||
const NewTheme = require("../mongooseSchemas/NewTheme");
|
||||
const ServerStatus = require("../../ServerStatus");
|
||||
|
||||
/**
|
||||
* 以基本插值資料、路由路徑做資料源,設定在write_message頁面下該插入什麼資料值。
|
||||
* @param {BasicLayout} renderData 基本插值物件。
|
||||
* @param {string} route 路由路徑。
|
||||
* @param {Express.Session} session Express的Session物件。
|
||||
* @param {CallbackFunction} callback 回呼函式。
|
||||
*/
|
||||
function VoteThemeRenderer(renderData, route, session, callback) {
|
||||
let status = ServerStatus.status; // 取得伺服器的狀態資料
|
||||
let datas = renderData.datas;
|
||||
|
||||
datas.title = "第" + (status.currentSeason + 1) + "季主題票選";
|
||||
datas.voteCount = status.voteCount; // 取得在主題候選之中,使用者的手中有多少票
|
||||
|
||||
// 將候選主題全部找出,並依建立時間來進行排列
|
||||
NewTheme.find({})
|
||||
.sort({ "createdTime": 1 })
|
||||
.exec((err, newThemeDocs) => {
|
||||
if (err) return callback(err, null);
|
||||
|
||||
// 將所有頁面所要的候選主題資料加入到 themes 中
|
||||
let themes = [];
|
||||
newThemeDocs.forEach((docs, index) => {
|
||||
themes.push({
|
||||
id: index,
|
||||
title: docs.title,
|
||||
narrative: docs.narrative,
|
||||
imageURL: docs.image,
|
||||
originator: docs.sponsor
|
||||
});
|
||||
});
|
||||
|
||||
// 隨後再將 themes 加入到 datas 之上
|
||||
datas.themes = themes;
|
||||
callback(null, true);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
module.exports.Render = VoteThemeRenderer;
|
35
models/renderModels/write_message.js
Normal file
@ -0,0 +1,35 @@
|
||||
|
||||
let User = require("../mongooseSchemas/User");
|
||||
|
||||
/**
|
||||
* 以基本插值資料、路由路徑做資料源,設定在write_message頁面下該插入什麼資料值。
|
||||
* @param {BasicLayout} renderData 插值物件。
|
||||
* @param {string} route 路由路徑。
|
||||
* @param {Express.Session} session Express的Session物件。
|
||||
* @param {CallbackFunction} callback 回呼函式。
|
||||
*/
|
||||
function WriteMessageRender(renderData, route, session, callback) {
|
||||
let populateQuery = { path: "friendList", select: { "username": 1 } }; // 建立Populate Query,連結好友清單中的「Username」欄位。
|
||||
let recipient = route.substr(15); // 取得指定的使用者
|
||||
|
||||
// 尋找目前使用者的好友清單內的所有好友的使用者名稱
|
||||
User.findOne({"username": renderData.username})
|
||||
.populate(populateQuery)
|
||||
.exec((err, docs) => {
|
||||
// 若有錯誤,則將錯誤回呼並返回
|
||||
if (err) return callback(err);
|
||||
|
||||
// 將收件者加入插值物件中
|
||||
renderData.datas.recipient = recipient;
|
||||
|
||||
// 循環取得好友清單所有的使用者名稱
|
||||
let friendsUsernames = [];
|
||||
for (let friend of docs.friendList)
|
||||
friendsUsernames.push(friend.username);
|
||||
renderData.datas.friendList = friendsUsernames;
|
||||
callback(null, true);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
module.exports.Render = WriteMessageRender;
|
2281
package-lock.json
generated
Normal file
35
package.json
Normal file
@ -0,0 +1,35 @@
|
||||
{
|
||||
"name": "jmuseum",
|
||||
"version": "1.0.0",
|
||||
"description": "一個讓喜好簡易繪圖的人創作、分享的網站。同時也是我練習前、後端的作品。",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1",
|
||||
"start": "node index.js"
|
||||
},
|
||||
"author": "Nebula3122",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"bcrypt": "^1.0.3",
|
||||
"bcryptjs": "^2.4.3",
|
||||
"body-parser": "*",
|
||||
"connect-flash": "*",
|
||||
"connect-mongo": "*",
|
||||
"cookie-parser": "*",
|
||||
"express": "*",
|
||||
"express-messages": "*",
|
||||
"express-session": "*",
|
||||
"express-validator": "*",
|
||||
"jimp": "*",
|
||||
"mongodb": "*",
|
||||
"mongoose": "*",
|
||||
"multer": "*",
|
||||
"node-schedule": "*",
|
||||
"nodemailer": "*",
|
||||
"passport": "*",
|
||||
"passport-http": "*",
|
||||
"passport-local": "*",
|
||||
"pug": "^2.0.0-beta6",
|
||||
"uuid": "^3.2.1"
|
||||
}
|
||||
}
|
470
public/css/bootstrap-theme.css
vendored
Normal file
@ -0,0 +1,470 @@
|
||||
/*!
|
||||
* Bootstrap v3.3.1 (http://getbootstrap.com)
|
||||
* Copyright 2011-2014 Twitter, Inc.
|
||||
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
|
||||
*/
|
||||
|
||||
.btn-default,
|
||||
.btn-primary,
|
||||
.btn-success,
|
||||
.btn-info,
|
||||
.btn-warning,
|
||||
.btn-danger {
|
||||
text-shadow: 0 -1px 0 rgba(0, 0, 0, .2);
|
||||
-webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, .15), 0 1px 1px rgba(0, 0, 0, .075);
|
||||
box-shadow: inset 0 1px 0 rgba(255, 255, 255, .15), 0 1px 1px rgba(0, 0, 0, .075);
|
||||
}
|
||||
.btn-default:active,
|
||||
.btn-primary:active,
|
||||
.btn-success:active,
|
||||
.btn-info:active,
|
||||
.btn-warning:active,
|
||||
.btn-danger:active,
|
||||
.btn-default.active,
|
||||
.btn-primary.active,
|
||||
.btn-success.active,
|
||||
.btn-info.active,
|
||||
.btn-warning.active,
|
||||
.btn-danger.active {
|
||||
-webkit-box-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);
|
||||
box-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);
|
||||
}
|
||||
.btn-default .badge,
|
||||
.btn-primary .badge,
|
||||
.btn-success .badge,
|
||||
.btn-info .badge,
|
||||
.btn-warning .badge,
|
||||
.btn-danger .badge {
|
||||
text-shadow: none;
|
||||
}
|
||||
.btn:active,
|
||||
.btn.active {
|
||||
background-image: none;
|
||||
}
|
||||
.btn-default {
|
||||
text-shadow: 0 1px 0 #fff;
|
||||
background-image: -webkit-linear-gradient(top, #fff 0%, #e0e0e0 100%);
|
||||
background-image: -o-linear-gradient(top, #fff 0%, #e0e0e0 100%);
|
||||
background-image: -webkit-gradient(linear, left top, left bottom, from(#fff), to(#e0e0e0));
|
||||
background-image: linear-gradient(to bottom, #fff 0%, #e0e0e0 100%);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#ffe0e0e0', GradientType=0);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
|
||||
background-repeat: repeat-x;
|
||||
border-color: #dbdbdb;
|
||||
border-color: #ccc;
|
||||
}
|
||||
.btn-default:hover,
|
||||
.btn-default:focus {
|
||||
background-color: #e0e0e0;
|
||||
background-position: 0 -15px;
|
||||
}
|
||||
.btn-default:active,
|
||||
.btn-default.active {
|
||||
background-color: #e0e0e0;
|
||||
border-color: #dbdbdb;
|
||||
}
|
||||
.btn-default:disabled,
|
||||
.btn-default[disabled] {
|
||||
background-color: #e0e0e0;
|
||||
background-image: none;
|
||||
}
|
||||
.btn-primary {
|
||||
background-image: -webkit-linear-gradient(top, #337ab7 0%, #265a88 100%);
|
||||
background-image: -o-linear-gradient(top, #337ab7 0%, #265a88 100%);
|
||||
background-image: -webkit-gradient(linear, left top, left bottom, from(#337ab7), to(#265a88));
|
||||
background-image: linear-gradient(to bottom, #337ab7 0%, #265a88 100%);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff265a88', GradientType=0);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
|
||||
background-repeat: repeat-x;
|
||||
border-color: #245580;
|
||||
}
|
||||
.btn-primary:hover,
|
||||
.btn-primary:focus {
|
||||
background-color: #265a88;
|
||||
background-position: 0 -15px;
|
||||
}
|
||||
.btn-primary:active,
|
||||
.btn-primary.active {
|
||||
background-color: #265a88;
|
||||
border-color: #245580;
|
||||
}
|
||||
.btn-primary:disabled,
|
||||
.btn-primary[disabled] {
|
||||
background-color: #265a88;
|
||||
background-image: none;
|
||||
}
|
||||
.btn-success {
|
||||
background-image: -webkit-linear-gradient(top, #5cb85c 0%, #419641 100%);
|
||||
background-image: -o-linear-gradient(top, #5cb85c 0%, #419641 100%);
|
||||
background-image: -webkit-gradient(linear, left top, left bottom, from(#5cb85c), to(#419641));
|
||||
background-image: linear-gradient(to bottom, #5cb85c 0%, #419641 100%);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5cb85c', endColorstr='#ff419641', GradientType=0);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
|
||||
background-repeat: repeat-x;
|
||||
border-color: #3e8f3e;
|
||||
}
|
||||
.btn-success:hover,
|
||||
.btn-success:focus {
|
||||
background-color: #419641;
|
||||
background-position: 0 -15px;
|
||||
}
|
||||
.btn-success:active,
|
||||
.btn-success.active {
|
||||
background-color: #419641;
|
||||
border-color: #3e8f3e;
|
||||
}
|
||||
.btn-success:disabled,
|
||||
.btn-success[disabled] {
|
||||
background-color: #419641;
|
||||
background-image: none;
|
||||
}
|
||||
.btn-info {
|
||||
background-image: -webkit-linear-gradient(top, #5bc0de 0%, #2aabd2 100%);
|
||||
background-image: -o-linear-gradient(top, #5bc0de 0%, #2aabd2 100%);
|
||||
background-image: -webkit-gradient(linear, left top, left bottom, from(#5bc0de), to(#2aabd2));
|
||||
background-image: linear-gradient(to bottom, #5bc0de 0%, #2aabd2 100%);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff2aabd2', GradientType=0);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
|
||||
background-repeat: repeat-x;
|
||||
border-color: #28a4c9;
|
||||
}
|
||||
.btn-info:hover,
|
||||
.btn-info:focus {
|
||||
background-color: #2aabd2;
|
||||
background-position: 0 -15px;
|
||||
}
|
||||
.btn-info:active,
|
||||
.btn-info.active {
|
||||
background-color: #2aabd2;
|
||||
border-color: #28a4c9;
|
||||
}
|
||||
.btn-info:disabled,
|
||||
.btn-info[disabled] {
|
||||
background-color: #2aabd2;
|
||||
background-image: none;
|
||||
}
|
||||
.btn-warning {
|
||||
background-image: -webkit-linear-gradient(top, #f0ad4e 0%, #eb9316 100%);
|
||||
background-image: -o-linear-gradient(top, #f0ad4e 0%, #eb9316 100%);
|
||||
background-image: -webkit-gradient(linear, left top, left bottom, from(#f0ad4e), to(#eb9316));
|
||||
background-image: linear-gradient(to bottom, #f0ad4e 0%, #eb9316 100%);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff0ad4e', endColorstr='#ffeb9316', GradientType=0);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
|
||||
background-repeat: repeat-x;
|
||||
border-color: #e38d13;
|
||||
}
|
||||
.btn-warning:hover,
|
||||
.btn-warning:focus {
|
||||
background-color: #eb9316;
|
||||
background-position: 0 -15px;
|
||||
}
|
||||
.btn-warning:active,
|
||||
.btn-warning.active {
|
||||
background-color: #eb9316;
|
||||
border-color: #e38d13;
|
||||
}
|
||||
.btn-warning:disabled,
|
||||
.btn-warning[disabled] {
|
||||
background-color: #eb9316;
|
||||
background-image: none;
|
||||
}
|
||||
.btn-danger {
|
||||
background-image: -webkit-linear-gradient(top, #d9534f 0%, #c12e2a 100%);
|
||||
background-image: -o-linear-gradient(top, #d9534f 0%, #c12e2a 100%);
|
||||
background-image: -webkit-gradient(linear, left top, left bottom, from(#d9534f), to(#c12e2a));
|
||||
background-image: linear-gradient(to bottom, #d9534f 0%, #c12e2a 100%);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9534f', endColorstr='#ffc12e2a', GradientType=0);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
|
||||
background-repeat: repeat-x;
|
||||
border-color: #b92c28;
|
||||
}
|
||||
.btn-danger:hover,
|
||||
.btn-danger:focus {
|
||||
background-color: #c12e2a;
|
||||
background-position: 0 -15px;
|
||||
}
|
||||
.btn-danger:active,
|
||||
.btn-danger.active {
|
||||
background-color: #c12e2a;
|
||||
border-color: #b92c28;
|
||||
}
|
||||
.btn-danger:disabled,
|
||||
.btn-danger[disabled] {
|
||||
background-color: #c12e2a;
|
||||
background-image: none;
|
||||
}
|
||||
.thumbnail,
|
||||
.img-thumbnail {
|
||||
-webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, .075);
|
||||
box-shadow: 0 1px 2px rgba(0, 0, 0, .075);
|
||||
}
|
||||
.dropdown-menu > li > a:hover,
|
||||
.dropdown-menu > li > a:focus {
|
||||
background-color: #e8e8e8;
|
||||
background-image: -webkit-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%);
|
||||
background-image: -o-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%);
|
||||
background-image: -webkit-gradient(linear, left top, left bottom, from(#f5f5f5), to(#e8e8e8));
|
||||
background-image: linear-gradient(to bottom, #f5f5f5 0%, #e8e8e8 100%);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#ffe8e8e8', GradientType=0);
|
||||
background-repeat: repeat-x;
|
||||
}
|
||||
.dropdown-menu > .active > a,
|
||||
.dropdown-menu > .active > a:hover,
|
||||
.dropdown-menu > .active > a:focus {
|
||||
background-color: #2e6da4;
|
||||
background-image: -webkit-linear-gradient(top, #337ab7 0%, #2e6da4 100%);
|
||||
background-image: -o-linear-gradient(top, #337ab7 0%, #2e6da4 100%);
|
||||
background-image: -webkit-gradient(linear, left top, left bottom, from(#337ab7), to(#2e6da4));
|
||||
background-image: linear-gradient(to bottom, #337ab7 0%, #2e6da4 100%);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2e6da4', GradientType=0);
|
||||
background-repeat: repeat-x;
|
||||
}
|
||||
.navbar-default {
|
||||
background-image: -webkit-linear-gradient(top, #fff 0%, #f8f8f8 100%);
|
||||
background-image: -o-linear-gradient(top, #fff 0%, #f8f8f8 100%);
|
||||
background-image: -webkit-gradient(linear, left top, left bottom, from(#fff), to(#f8f8f8));
|
||||
background-image: linear-gradient(to bottom, #fff 0%, #f8f8f8 100%);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#fff8f8f8', GradientType=0);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
|
||||
background-repeat: repeat-x;
|
||||
border-radius: 4px;
|
||||
-webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, .15), 0 1px 5px rgba(0, 0, 0, .075);
|
||||
box-shadow: inset 0 1px 0 rgba(255, 255, 255, .15), 0 1px 5px rgba(0, 0, 0, .075);
|
||||
}
|
||||
.navbar-default .navbar-nav > .open > a,
|
||||
.navbar-default .navbar-nav > .active > a {
|
||||
background-image: -webkit-linear-gradient(top, #dbdbdb 0%, #e2e2e2 100%);
|
||||
background-image: -o-linear-gradient(top, #dbdbdb 0%, #e2e2e2 100%);
|
||||
background-image: -webkit-gradient(linear, left top, left bottom, from(#dbdbdb), to(#e2e2e2));
|
||||
background-image: linear-gradient(to bottom, #dbdbdb 0%, #e2e2e2 100%);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdbdbdb', endColorstr='#ffe2e2e2', GradientType=0);
|
||||
background-repeat: repeat-x;
|
||||
-webkit-box-shadow: inset 0 3px 9px rgba(0, 0, 0, .075);
|
||||
box-shadow: inset 0 3px 9px rgba(0, 0, 0, .075);
|
||||
}
|
||||
.navbar-brand,
|
||||
.navbar-nav > li > a {
|
||||
text-shadow: 0 1px 0 rgba(255, 255, 255, .25);
|
||||
}
|
||||
.navbar-inverse {
|
||||
background-image: -webkit-linear-gradient(top, #3c3c3c 0%, #222 100%);
|
||||
background-image: -o-linear-gradient(top, #3c3c3c 0%, #222 100%);
|
||||
background-image: -webkit-gradient(linear, left top, left bottom, from(#3c3c3c), to(#222));
|
||||
background-image: linear-gradient(to bottom, #3c3c3c 0%, #222 100%);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff3c3c3c', endColorstr='#ff222222', GradientType=0);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
|
||||
background-repeat: repeat-x;
|
||||
}
|
||||
.navbar-inverse .navbar-nav > .open > a,
|
||||
.navbar-inverse .navbar-nav > .active > a {
|
||||
background-image: -webkit-linear-gradient(top, #080808 0%, #0f0f0f 100%);
|
||||
background-image: -o-linear-gradient(top, #080808 0%, #0f0f0f 100%);
|
||||
background-image: -webkit-gradient(linear, left top, left bottom, from(#080808), to(#0f0f0f));
|
||||
background-image: linear-gradient(to bottom, #080808 0%, #0f0f0f 100%);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff080808', endColorstr='#ff0f0f0f', GradientType=0);
|
||||
background-repeat: repeat-x;
|
||||
-webkit-box-shadow: inset 0 3px 9px rgba(0, 0, 0, .25);
|
||||
box-shadow: inset 0 3px 9px rgba(0, 0, 0, .25);
|
||||
}
|
||||
.navbar-inverse .navbar-brand,
|
||||
.navbar-inverse .navbar-nav > li > a {
|
||||
text-shadow: 0 -1px 0 rgba(0, 0, 0, .25);
|
||||
}
|
||||
.navbar-static-top,
|
||||
.navbar-fixed-top,
|
||||
.navbar-fixed-bottom {
|
||||
border-radius: 0;
|
||||
}
|
||||
@media (max-width: 767px) {
|
||||
.navbar .navbar-nav .open .dropdown-menu > .active > a,
|
||||
.navbar .navbar-nav .open .dropdown-menu > .active > a:hover,
|
||||
.navbar .navbar-nav .open .dropdown-menu > .active > a:focus {
|
||||
color: #fff;
|
||||
background-image: -webkit-linear-gradient(top, #337ab7 0%, #2e6da4 100%);
|
||||
background-image: -o-linear-gradient(top, #337ab7 0%, #2e6da4 100%);
|
||||
background-image: -webkit-gradient(linear, left top, left bottom, from(#337ab7), to(#2e6da4));
|
||||
background-image: linear-gradient(to bottom, #337ab7 0%, #2e6da4 100%);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2e6da4', GradientType=0);
|
||||
background-repeat: repeat-x;
|
||||
}
|
||||
}
|
||||
.alert {
|
||||
text-shadow: 0 1px 0 rgba(255, 255, 255, .2);
|
||||
-webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, .25), 0 1px 2px rgba(0, 0, 0, .05);
|
||||
box-shadow: inset 0 1px 0 rgba(255, 255, 255, .25), 0 1px 2px rgba(0, 0, 0, .05);
|
||||
}
|
||||
.alert-success {
|
||||
background-image: -webkit-linear-gradient(top, #dff0d8 0%, #c8e5bc 100%);
|
||||
background-image: -o-linear-gradient(top, #dff0d8 0%, #c8e5bc 100%);
|
||||
background-image: -webkit-gradient(linear, left top, left bottom, from(#dff0d8), to(#c8e5bc));
|
||||
background-image: linear-gradient(to bottom, #dff0d8 0%, #c8e5bc 100%);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdff0d8', endColorstr='#ffc8e5bc', GradientType=0);
|
||||
background-repeat: repeat-x;
|
||||
border-color: #b2dba1;
|
||||
}
|
||||
.alert-info {
|
||||
background-image: -webkit-linear-gradient(top, #d9edf7 0%, #b9def0 100%);
|
||||
background-image: -o-linear-gradient(top, #d9edf7 0%, #b9def0 100%);
|
||||
background-image: -webkit-gradient(linear, left top, left bottom, from(#d9edf7), to(#b9def0));
|
||||
background-image: linear-gradient(to bottom, #d9edf7 0%, #b9def0 100%);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9edf7', endColorstr='#ffb9def0', GradientType=0);
|
||||
background-repeat: repeat-x;
|
||||
border-color: #9acfea;
|
||||
}
|
||||
.alert-warning {
|
||||
background-image: -webkit-linear-gradient(top, #fcf8e3 0%, #f8efc0 100%);
|
||||
background-image: -o-linear-gradient(top, #fcf8e3 0%, #f8efc0 100%);
|
||||
background-image: -webkit-gradient(linear, left top, left bottom, from(#fcf8e3), to(#f8efc0));
|
||||
background-image: linear-gradient(to bottom, #fcf8e3 0%, #f8efc0 100%);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffcf8e3', endColorstr='#fff8efc0', GradientType=0);
|
||||
background-repeat: repeat-x;
|
||||
border-color: #f5e79e;
|
||||
}
|
||||
.alert-danger {
|
||||
background-image: -webkit-linear-gradient(top, #f2dede 0%, #e7c3c3 100%);
|
||||
background-image: -o-linear-gradient(top, #f2dede 0%, #e7c3c3 100%);
|
||||
background-image: -webkit-gradient(linear, left top, left bottom, from(#f2dede), to(#e7c3c3));
|
||||
background-image: linear-gradient(to bottom, #f2dede 0%, #e7c3c3 100%);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2dede', endColorstr='#ffe7c3c3', GradientType=0);
|
||||
background-repeat: repeat-x;
|
||||
border-color: #dca7a7;
|
||||
}
|
||||
.progress {
|
||||
background-image: -webkit-linear-gradient(top, #ebebeb 0%, #f5f5f5 100%);
|
||||
background-image: -o-linear-gradient(top, #ebebeb 0%, #f5f5f5 100%);
|
||||
background-image: -webkit-gradient(linear, left top, left bottom, from(#ebebeb), to(#f5f5f5));
|
||||
background-image: linear-gradient(to bottom, #ebebeb 0%, #f5f5f5 100%);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffebebeb', endColorstr='#fff5f5f5', GradientType=0);
|
||||
background-repeat: repeat-x;
|
||||
}
|
||||
.progress-bar {
|
||||
background-image: -webkit-linear-gradient(top, #337ab7 0%, #286090 100%);
|
||||
background-image: -o-linear-gradient(top, #337ab7 0%, #286090 100%);
|
||||
background-image: -webkit-gradient(linear, left top, left bottom, from(#337ab7), to(#286090));
|
||||
background-image: linear-gradient(to bottom, #337ab7 0%, #286090 100%);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff286090', GradientType=0);
|
||||
background-repeat: repeat-x;
|
||||
}
|
||||
.progress-bar-success {
|
||||
background-image: -webkit-linear-gradient(top, #5cb85c 0%, #449d44 100%);
|
||||
background-image: -o-linear-gradient(top, #5cb85c 0%, #449d44 100%);
|
||||
background-image: -webkit-gradient(linear, left top, left bottom, from(#5cb85c), to(#449d44));
|
||||
background-image: linear-gradient(to bottom, #5cb85c 0%, #449d44 100%);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5cb85c', endColorstr='#ff449d44', GradientType=0);
|
||||
background-repeat: repeat-x;
|
||||
}
|
||||
.progress-bar-info {
|
||||
background-image: -webkit-linear-gradient(top, #5bc0de 0%, #31b0d5 100%);
|
||||
background-image: -o-linear-gradient(top, #5bc0de 0%, #31b0d5 100%);
|
||||
background-image: -webkit-gradient(linear, left top, left bottom, from(#5bc0de), to(#31b0d5));
|
||||
background-image: linear-gradient(to bottom, #5bc0de 0%, #31b0d5 100%);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff31b0d5', GradientType=0);
|
||||
background-repeat: repeat-x;
|
||||
}
|
||||
.progress-bar-warning {
|
||||
background-image: -webkit-linear-gradient(top, #f0ad4e 0%, #ec971f 100%);
|
||||
background-image: -o-linear-gradient(top, #f0ad4e 0%, #ec971f 100%);
|
||||
background-image: -webkit-gradient(linear, left top, left bottom, from(#f0ad4e), to(#ec971f));
|
||||
background-image: linear-gradient(to bottom, #f0ad4e 0%, #ec971f 100%);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff0ad4e', endColorstr='#ffec971f', GradientType=0);
|
||||
background-repeat: repeat-x;
|
||||
}
|
||||
.progress-bar-danger {
|
||||
background-image: -webkit-linear-gradient(top, #d9534f 0%, #c9302c 100%);
|
||||
background-image: -o-linear-gradient(top, #d9534f 0%, #c9302c 100%);
|
||||
background-image: -webkit-gradient(linear, left top, left bottom, from(#d9534f), to(#c9302c));
|
||||
background-image: linear-gradient(to bottom, #d9534f 0%, #c9302c 100%);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9534f', endColorstr='#ffc9302c', GradientType=0);
|
||||
background-repeat: repeat-x;
|
||||
}
|
||||
.progress-bar-striped {
|
||||
background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);
|
||||
background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);
|
||||
background-image: linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);
|
||||
}
|
||||
.list-group {
|
||||
border-radius: 4px;
|
||||
-webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, .075);
|
||||
box-shadow: 0 1px 2px rgba(0, 0, 0, .075);
|
||||
}
|
||||
.list-group-item.active,
|
||||
.list-group-item.active:hover,
|
||||
.list-group-item.active:focus {
|
||||
text-shadow: 0 -1px 0 #286090;
|
||||
background-image: -webkit-linear-gradient(top, #337ab7 0%, #2b669a 100%);
|
||||
background-image: -o-linear-gradient(top, #337ab7 0%, #2b669a 100%);
|
||||
background-image: -webkit-gradient(linear, left top, left bottom, from(#337ab7), to(#2b669a));
|
||||
background-image: linear-gradient(to bottom, #337ab7 0%, #2b669a 100%);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2b669a', GradientType=0);
|
||||
background-repeat: repeat-x;
|
||||
border-color: #2b669a;
|
||||
}
|
||||
.list-group-item.active .badge,
|
||||
.list-group-item.active:hover .badge,
|
||||
.list-group-item.active:focus .badge {
|
||||
text-shadow: none;
|
||||
}
|
||||
.panel {
|
||||
-webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, .05);
|
||||
box-shadow: 0 1px 2px rgba(0, 0, 0, .05);
|
||||
}
|
||||
.panel-default > .panel-heading {
|
||||
background-image: -webkit-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%);
|
||||
background-image: -o-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%);
|
||||
background-image: -webkit-gradient(linear, left top, left bottom, from(#f5f5f5), to(#e8e8e8));
|
||||
background-image: linear-gradient(to bottom, #f5f5f5 0%, #e8e8e8 100%);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#ffe8e8e8', GradientType=0);
|
||||
background-repeat: repeat-x;
|
||||
}
|
||||
.panel-primary > .panel-heading {
|
||||
background-image: -webkit-linear-gradient(top, #337ab7 0%, #2e6da4 100%);
|
||||
background-image: -o-linear-gradient(top, #337ab7 0%, #2e6da4 100%);
|
||||
background-image: -webkit-gradient(linear, left top, left bottom, from(#337ab7), to(#2e6da4));
|
||||
background-image: linear-gradient(to bottom, #337ab7 0%, #2e6da4 100%);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2e6da4', GradientType=0);
|
||||
background-repeat: repeat-x;
|
||||
}
|
||||
.panel-success > .panel-heading {
|
||||
background-image: -webkit-linear-gradient(top, #dff0d8 0%, #d0e9c6 100%);
|
||||
background-image: -o-linear-gradient(top, #dff0d8 0%, #d0e9c6 100%);
|
||||
background-image: -webkit-gradient(linear, left top, left bottom, from(#dff0d8), to(#d0e9c6));
|
||||
background-image: linear-gradient(to bottom, #dff0d8 0%, #d0e9c6 100%);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdff0d8', endColorstr='#ffd0e9c6', GradientType=0);
|
||||
background-repeat: repeat-x;
|
||||
}
|
||||
.panel-info > .panel-heading {
|
||||
background-image: -webkit-linear-gradient(top, #d9edf7 0%, #c4e3f3 100%);
|
||||
background-image: -o-linear-gradient(top, #d9edf7 0%, #c4e3f3 100%);
|
||||
background-image: -webkit-gradient(linear, left top, left bottom, from(#d9edf7), to(#c4e3f3));
|
||||
background-image: linear-gradient(to bottom, #d9edf7 0%, #c4e3f3 100%);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9edf7', endColorstr='#ffc4e3f3', GradientType=0);
|
||||
background-repeat: repeat-x;
|
||||
}
|
||||
.panel-warning > .panel-heading {
|
||||
background-image: -webkit-linear-gradient(top, #fcf8e3 0%, #faf2cc 100%);
|
||||
background-image: -o-linear-gradient(top, #fcf8e3 0%, #faf2cc 100%);
|
||||
background-image: -webkit-gradient(linear, left top, left bottom, from(#fcf8e3), to(#faf2cc));
|
||||
background-image: linear-gradient(to bottom, #fcf8e3 0%, #faf2cc 100%);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffcf8e3', endColorstr='#fffaf2cc', GradientType=0);
|
||||
background-repeat: repeat-x;
|
||||
}
|
||||
.panel-danger > .panel-heading {
|
||||
background-image: -webkit-linear-gradient(top, #f2dede 0%, #ebcccc 100%);
|
||||
background-image: -o-linear-gradient(top, #f2dede 0%, #ebcccc 100%);
|
||||
background-image: -webkit-gradient(linear, left top, left bottom, from(#f2dede), to(#ebcccc));
|
||||
background-image: linear-gradient(to bottom, #f2dede 0%, #ebcccc 100%);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2dede', endColorstr='#ffebcccc', GradientType=0);
|
||||
background-repeat: repeat-x;
|
||||
}
|
||||
.well {
|
||||
background-image: -webkit-linear-gradient(top, #e8e8e8 0%, #f5f5f5 100%);
|
||||
background-image: -o-linear-gradient(top, #e8e8e8 0%, #f5f5f5 100%);
|
||||
background-image: -webkit-gradient(linear, left top, left bottom, from(#e8e8e8), to(#f5f5f5));
|
||||
background-image: linear-gradient(to bottom, #e8e8e8 0%, #f5f5f5 100%);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffe8e8e8', endColorstr='#fff5f5f5', GradientType=0);
|
||||
background-repeat: repeat-x;
|
||||
border-color: #dcdcdc;
|
||||
-webkit-box-shadow: inset 0 1px 3px rgba(0, 0, 0, .05), 0 1px 0 rgba(255, 255, 255, .1);
|
||||
box-shadow: inset 0 1px 3px rgba(0, 0, 0, .05), 0 1px 0 rgba(255, 255, 255, .1);
|
||||
}
|
||||
/*# sourceMappingURL=bootstrap-theme.css.map */
|
1
public/css/bootstrap-theme.css.map
Normal file
5
public/css/bootstrap-theme.min.css
vendored
Normal file
83
public/css/bootstrap-toggle.css
vendored
Executable file
@ -0,0 +1,83 @@
|
||||
/*! ========================================================================
|
||||
* Bootstrap Toggle: bootstrap-toggle.css v2.2.0
|
||||
* http://www.bootstraptoggle.com
|
||||
* ========================================================================
|
||||
* Copyright 2014 Min Hur, The New York Times Company
|
||||
* Licensed under MIT
|
||||
* ======================================================================== */
|
||||
|
||||
|
||||
.checkbox label .toggle,
|
||||
.checkbox-inline .toggle {
|
||||
margin-left: -20px;
|
||||
margin-right: 5px;
|
||||
}
|
||||
|
||||
.toggle {
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
.toggle input[type="checkbox"] {
|
||||
display: none;
|
||||
}
|
||||
.toggle-group {
|
||||
position: absolute;
|
||||
width: 200%;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
transition: left 0.35s;
|
||||
-webkit-transition: left 0.35s;
|
||||
-moz-user-select: none;
|
||||
-webkit-user-select: none;
|
||||
}
|
||||
.toggle.off .toggle-group {
|
||||
left: -100%;
|
||||
}
|
||||
.toggle-on {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 50%;
|
||||
margin: 0;
|
||||
border: 0;
|
||||
border-radius: 0;
|
||||
}
|
||||
.toggle-off {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 50%;
|
||||
right: 0;
|
||||
margin: 0;
|
||||
border: 0;
|
||||
border-radius: 0;
|
||||
}
|
||||
.toggle-handle {
|
||||
position: relative;
|
||||
margin: 0 auto;
|
||||
padding-top: 0px;
|
||||
padding-bottom: 0px;
|
||||
height: 100%;
|
||||
width: 0px;
|
||||
border-width: 0 1px;
|
||||
}
|
||||
|
||||
.toggle.btn { min-width: 59px; min-height: 34px; }
|
||||
.toggle-on.btn { padding-right: 24px; }
|
||||
.toggle-off.btn { padding-left: 24px; }
|
||||
|
||||
.toggle.btn-lg { min-width: 79px; min-height: 45px; }
|
||||
.toggle-on.btn-lg { padding-right: 31px; }
|
||||
.toggle-off.btn-lg { padding-left: 31px; }
|
||||
.toggle-handle.btn-lg { width: 40px; }
|
||||
|
||||
.toggle.btn-sm { min-width: 50px; min-height: 30px;}
|
||||
.toggle-on.btn-sm { padding-right: 20px; }
|
||||
.toggle-off.btn-sm { padding-left: 20px; }
|
||||
|
||||
.toggle.btn-xs { min-width: 35px; min-height: 22px;}
|
||||
.toggle-on.btn-xs { padding-right: 12px; }
|
||||
.toggle-off.btn-xs { padding-left: 12px; }
|
||||
|
28
public/css/bootstrap-toggle.min.css
vendored
Executable file
@ -0,0 +1,28 @@
|
||||
/*! ========================================================================
|
||||
* Bootstrap Toggle: bootstrap-toggle.css v2.2.0
|
||||
* http://www.bootstraptoggle.com
|
||||
* ========================================================================
|
||||
* Copyright 2014 Min Hur, The New York Times Company
|
||||
* Licensed under MIT
|
||||
* ======================================================================== */
|
||||
.checkbox label .toggle,.checkbox-inline .toggle{margin-left:-20px;margin-right:5px}
|
||||
.toggle{position:relative;overflow:hidden}
|
||||
.toggle input[type=checkbox]{display:none}
|
||||
.toggle-group{position:absolute;width:200%;top:0;bottom:0;left:0;transition:left .35s;-webkit-transition:left .35s;-moz-user-select:none;-webkit-user-select:none}
|
||||
.toggle.off .toggle-group{left:-100%}
|
||||
.toggle-on{position:absolute;top:0;bottom:0;left:0;right:50%;margin:0;border:0;border-radius:0}
|
||||
.toggle-off{position:absolute;top:0;bottom:0;left:50%;right:0;margin:0;border:0;border-radius:0}
|
||||
.toggle-handle{position:relative;margin:0 auto;padding-top:0;padding-bottom:0;height:100%;width:0;border-width:0 1px}
|
||||
.toggle.btn{min-width:59px;min-height:34px}
|
||||
.toggle-on.btn{padding-right:24px}
|
||||
.toggle-off.btn{padding-left:24px}
|
||||
.toggle.btn-lg{min-width:79px;min-height:45px}
|
||||
.toggle-on.btn-lg{padding-right:31px}
|
||||
.toggle-off.btn-lg{padding-left:31px}
|
||||
.toggle-handle.btn-lg{width:40px}
|
||||
.toggle.btn-sm{min-width:50px;min-height:30px}
|
||||
.toggle-on.btn-sm{padding-right:20px}
|
||||
.toggle-off.btn-sm{padding-left:20px}
|
||||
.toggle.btn-xs{min-width:35px;min-height:22px}
|
||||
.toggle-on.btn-xs{padding-right:12px}
|
||||
.toggle-off.btn-xs{padding-left:12px}
|
6332
public/css/bootstrap.css
vendored
Normal file
1
public/css/bootstrap.css.map
Normal file
5
public/css/bootstrap.min.css
vendored
Normal file
23
public/css/change_password_extended.css
Normal file
@ -0,0 +1,23 @@
|
||||
html, body {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
body {
|
||||
background: url("../images/Abstract_4.png") no-repeat center center fixed;
|
||||
-webkit-background-size: cover;
|
||||
-moz-background-size: cover;
|
||||
-o-background-size: cover;
|
||||
background-size: cover;
|
||||
}
|
||||
|
||||
div.signInOptions { position: relative; }
|
||||
div.inlineCheckbox { display: inline-block; }
|
||||
a.forgetPassword { position: absolute; right: 0; margin: 10px 0 10px 0; }
|
||||
|
||||
footer {
|
||||
position: absolute;
|
||||
left: 0; right: 0;
|
||||
bottom: 0;
|
||||
}
|
57
public/css/custom_styles.css
Normal file
@ -0,0 +1,57 @@
|
||||
@keyframes trans-blue-black {
|
||||
0% { color: black; }
|
||||
45% { color: #5fb0fc; }
|
||||
55% { color: #5fb0fc; }
|
||||
100% { color: black; }
|
||||
}
|
||||
|
||||
.container-table {
|
||||
height: 100%;
|
||||
display: table;
|
||||
}
|
||||
.vertical-center-row {
|
||||
display: table-cell;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
p.footerAnnounce { margin-bottom: 10px; }
|
||||
|
||||
.relative { position: relative; }
|
||||
|
||||
div.verticalLine { display: inline-flex; height: 2em; margin: 5px 5px 0 5px; padding: 0; border-left-width: 1px; border-left-style: solid; border-left-color: gray; vertical-align: center; }
|
||||
|
||||
.text-bigtitle { font-size: 48px; }
|
||||
.text-extralargetext { font-size: 42px; }
|
||||
.text-extrabigtext { font-size: 38px; }
|
||||
.text-largetext { font-size: 32px; }
|
||||
.text-bigtext { font-size: 26px; }
|
||||
.text-subbigtext { font-size: 22px; }
|
||||
.text-normal { font-size: 16px; }
|
||||
|
||||
.pb-20 { padding-bottom: 20px; }
|
||||
.pt-20 { padding-top: 20px; }
|
||||
.mt-20 { margin-top: 20px; }
|
||||
.mr-20 { margin-right: 20px; }
|
||||
.ml-20 { margin-left: 20px; }
|
||||
.mt-10 { margin-top: 10px; }
|
||||
.mtb-10 { margin-top: 10px; margin-bottom: 10px; }
|
||||
.ml-10 { margin-left: 10px; }
|
||||
.noMargin { margin: 0; }
|
||||
|
||||
.bg-whaleBlue { background-color: #7ca3ff; }
|
||||
.bg-grassGreen { background-color: #2fad29; }
|
||||
|
||||
.bg-transparent-lightRed { background-color: rgba(255, 170, 160, 0.6); }
|
||||
.bg-transparent-lightOrange { background-color: rgba(255, 209, 150, 0.6); }
|
||||
.bg-transparent-dodgeBlue { background-color: rgba(146, 199, 252, 0.6); }
|
||||
.bg-transparent-lightGreen { background-color: rgba(195, 255, 160, 0.6); }
|
||||
|
||||
.color-white { color: white !important; }
|
||||
.color-deepOrange { color: #bc8d00 !important; }
|
||||
|
||||
.text-shadow-extra { text-shadow: 3px 3px 5px black; }
|
||||
.text-shadow { text-shadow: 2px 2px 3px black; }
|
||||
.text-shadow-white-extra { text-shadow: 3px 3px 5px white; }
|
||||
.text-shadow-white { text-shadow: 2px 2px 3px white; }
|
||||
|
||||
.block-generalShadow { box-shadow: 2px 2px 3px black; }
|
190
public/css/drawing_extended.css
Normal file
@ -0,0 +1,190 @@
|
||||
body {
|
||||
background: url("../images/Horizon.jpg") no-repeat center center fixed;
|
||||
-webkit-background-size: cover;
|
||||
-moz-background-size: cover;
|
||||
-o-background-size: cover;
|
||||
background-size: cover;
|
||||
}
|
||||
|
||||
canvas {
|
||||
width: 800px;
|
||||
height: 540px;
|
||||
border: 1px solid black;
|
||||
background-color: white;
|
||||
box-shadow: 3px 3px 5px rgba(0, 0, 0, 0.5);
|
||||
}
|
||||
|
||||
div.form-group {
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
div.whiteTransparent {
|
||||
background-color: rgba(255, 255, 255, 0.7);
|
||||
}
|
||||
|
||||
textarea {
|
||||
resize: none;
|
||||
}
|
||||
|
||||
div.relative { position: relative; }
|
||||
|
||||
/* 繪圖區 */
|
||||
div.tool-bars {
|
||||
padding: 10px;
|
||||
margin: 20px auto 0 auto;
|
||||
}
|
||||
|
||||
/* 自製按鈕元件 */
|
||||
input.myBtn {
|
||||
display: inline-block;
|
||||
height: 35px; width: 55px;
|
||||
border: 1px solid gray;
|
||||
border-radius: 10px;
|
||||
background-color: white;
|
||||
cursor: default;
|
||||
outline: none;
|
||||
|
||||
transition-duration: 0.25s;
|
||||
}
|
||||
input.myBtn:hover { background-color: lightgray; }
|
||||
|
||||
/* 顏色選取元件 */
|
||||
div.main-color-picker, div.sub-color-picker {
|
||||
display: inline-block;
|
||||
padding: 0 0 0 10px;
|
||||
border: 1px solid gray;
|
||||
border-radius: 10px;
|
||||
background-color: white;
|
||||
cursor: default;
|
||||
user-select: none;
|
||||
}
|
||||
div.sub-color-picker {
|
||||
background-color: #cdffa5;
|
||||
cursor: pointer;
|
||||
|
||||
transition-duration: 0.25s;
|
||||
}
|
||||
|
||||
input.color-btn {
|
||||
background-color: white;
|
||||
height: 35px; width: 45px;
|
||||
padding: 3px;
|
||||
border-width: 0 0 0 1px;
|
||||
border-style: solid;
|
||||
border-color: gray;
|
||||
border-radius: 10px;
|
||||
margin-left: 5px;
|
||||
cursor: pointer;
|
||||
|
||||
transition-duration: 0.25s;
|
||||
}
|
||||
input.color-btn:hover { background-color: lightgray; }
|
||||
|
||||
/* 比刷大小調整元件 */
|
||||
div.size-group {
|
||||
display: inline-block;
|
||||
position: relative;
|
||||
}
|
||||
input#sizeDown, input#sizeUp, input#sizeDown10, input#sizeUp10,
|
||||
input#strokeSizeDown, input#strokeSizeUp, input#strokeSizeDown10, input#strokeSizeUp10 {
|
||||
background-color: white;
|
||||
height: 35px; width: 30px;
|
||||
border-color: gray;
|
||||
border-style: solid;
|
||||
padding: 3px;
|
||||
margin: 0;
|
||||
cursor: pointer;
|
||||
outline: none;
|
||||
|
||||
transition-duration: 0.25s;
|
||||
}
|
||||
input#sizeDown, input#strokeSizeDown { border-width: 1px 1px 1px 0; }
|
||||
input#sizeUp, input#strokeSizeUp { border-width: 1px 0 1px 1px; }
|
||||
input#sizeUp10, input#strokeSizeUp10 { border-radius: 0 10px 10px 0; border-width: 1px; font-weight: 900; color:red; }
|
||||
input#sizeDown10, input#strokeSizeDown10 { border-radius: 10px 0 0 10px; border-width: 1px; font-weight: 900; color:red; }
|
||||
input#sizeDown:hover, input#sizeUp:hover, input#sizeDown10:hover, input#sizeUp10:hover,
|
||||
input#strokeSizeDown:hover, input#strokeSizeUp:hover, input#strokeSizeDown10:hover, input#strokeSizeUp10:hover { background-color: lightgray; }
|
||||
label#sizeGroupText, label#strokeSizeGroupText {
|
||||
display: inline-block;
|
||||
background-color: white;
|
||||
height: 35px;
|
||||
padding: 6px 10px 0 10px;
|
||||
border-width: 1px 0;
|
||||
border-style: solid;
|
||||
border-color: gray;
|
||||
margin: 0;
|
||||
text-align: center;
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
/* 比刷模式 */
|
||||
div.brush-group { display: inline-block; margin: 10px 0; }
|
||||
div.brush-caption, div.brush-group > input {
|
||||
display: inline-block;
|
||||
height: 35px;
|
||||
padding: 0 7px 0 7px;
|
||||
border-color: gray;
|
||||
border-style: solid;
|
||||
background-color: white;
|
||||
outline: none;
|
||||
|
||||
transition-duration: 0.25s;
|
||||
}
|
||||
div.brush-caption { border-width: 1px; border-radius: 10px 0 0 10px; padding-top: 6px; font-weight: 900; }
|
||||
div.brush-group > input { border-width: 1px 1px 1px 0; cursor: pointer; }
|
||||
div.brush-group > input:last-child { border-width: 1px 1px 1px 0; border-radius: 0 10px 10px 0; cursor: pointer }
|
||||
div.brush-group > input:hover { background-color: lightgray; }
|
||||
div.brush-group > input.active{ background-color: #cdffa5; }
|
||||
|
||||
#canvasContainer {
|
||||
min-height: 450px;
|
||||
}
|
||||
|
||||
/* 作品最後調整設定區 */
|
||||
/* 標籤區塊設定 */
|
||||
div#tagPanel {
|
||||
padding: 10px;
|
||||
}
|
||||
/* 標籤元素 */
|
||||
div.labelTag {
|
||||
display: inline-block;
|
||||
padding: 10px;
|
||||
border-radius: 10px;
|
||||
margin: 5px 0 5px 2px;
|
||||
background-color: lightgray;
|
||||
-ms-user-select: none;
|
||||
-moz-user-select: none;
|
||||
-webkit-user-select: none;
|
||||
user-select: none;
|
||||
cursor: pointer;
|
||||
|
||||
transition-duration: 0.25s;
|
||||
}
|
||||
div.labelTag.active, div.labelTag.active:hover { background-color: #3281ff; color: white; }
|
||||
div.labelTag:hover { background-color: #fffbb2; }
|
||||
/* 檢視作品的權限 */
|
||||
div.view-authority {
|
||||
min-width: 240px;
|
||||
}
|
||||
/* 作品資訊 */
|
||||
table.table {
|
||||
margin-bottom: 0px;
|
||||
}
|
||||
|
||||
table.table tbody tr:first-child td,
|
||||
table.table tbody tr:first-child th {
|
||||
border-width: 0;
|
||||
}
|
||||
|
||||
/* 屏蔽版面 */
|
||||
div.barrierPanel {
|
||||
position: absolute;
|
||||
top: -20px; bottom: 0; left: 0px;
|
||||
width: 100%;
|
||||
background-color: rgba(32, 32, 32, 0.7);
|
||||
z-index: 65536;
|
||||
}
|
||||
|
||||
#btnDelete { display: none; }
|
||||
|
||||
canvas#cvsCanvas { width: 800px; height: 450px; }
|
31
public/css/edit_personal_info_extended.css
Normal file
@ -0,0 +1,31 @@
|
||||
html { height: 100%; }
|
||||
|
||||
body {
|
||||
background: url("../images/Abstract_2.jpg") no-repeat center center fixed;
|
||||
-webkit-background-size: cover;
|
||||
-moz-background-size: cover;
|
||||
-o-background-size: cover;
|
||||
background-size: cover;
|
||||
|
||||
position: relative;
|
||||
margin: 0;
|
||||
padding-bottom: 6rem;
|
||||
min-height: 100%;
|
||||
}
|
||||
|
||||
input.hidden {
|
||||
display: none;
|
||||
}
|
||||
|
||||
input.form-control[disabled] {
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
h4 {
|
||||
margin: 0 0 10px 0;
|
||||
}
|
||||
|
||||
footer {
|
||||
position: absolute;
|
||||
bottom:0; left: 0; right: 0;
|
||||
}
|
22
public/css/feedback_extended.css
Normal file
@ -0,0 +1,22 @@
|
||||
body {
|
||||
background: url("../images/BlueWater_2.jpg") no-repeat center center fixed;
|
||||
-webkit-background-size: cover;
|
||||
-moz-background-size: cover;
|
||||
-o-background-size: cover;
|
||||
background-size: cover;
|
||||
}
|
||||
|
||||
textarea {
|
||||
resize: none;
|
||||
}
|
||||
|
||||
div.relative { position: relative; }
|
||||
|
||||
/* 屏蔽版面 */
|
||||
div.barrierPanel {
|
||||
position: absolute;
|
||||
top: -20px; bottom: 0; left: 0px;
|
||||
width: 100%;
|
||||
background-color: rgba(32, 32, 32, 0.7);
|
||||
z-index: 65536;
|
||||
}
|
123
public/css/gallery_extended.css
Normal file
@ -0,0 +1,123 @@
|
||||
body {
|
||||
background: url("../images/Spotlight.jpg") no-repeat center center fixed;
|
||||
-webkit-background-size: cover;
|
||||
-moz-background-size: cover;
|
||||
-o-background-size: cover;
|
||||
background-size: cover;
|
||||
}
|
||||
|
||||
.container-table {
|
||||
height: 100%;
|
||||
display: table;
|
||||
}
|
||||
.vertical-center-row {
|
||||
display: table-cell;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.bg-sunset {
|
||||
-webkit-background-size: cover;
|
||||
-moz-background-size: cover;
|
||||
-o-background-size: cover;
|
||||
background-size: cover;
|
||||
background-attachment: fixed;
|
||||
}
|
||||
.bg-sunset { background-image: url("../images/Sunset.jpg"); }
|
||||
|
||||
.layout-title {
|
||||
min-height: 340px;
|
||||
}
|
||||
|
||||
div.panel {
|
||||
background-color: rgba(255, 255, 255, 0.8);
|
||||
}
|
||||
|
||||
/* 前一季的第一名作品展示 */
|
||||
h1.carouselSubtitle {
|
||||
padding-top: 10px;
|
||||
padding-bottom: 10px;
|
||||
margin-top: 30px;
|
||||
margin-bottom: 30px;
|
||||
background-color: rgba(252, 231, 118, 0.7);
|
||||
}
|
||||
|
||||
div.masterCarousel {
|
||||
padding-bottom: 40px;
|
||||
background-color: rgba(128, 128, 128, 0.5);
|
||||
}
|
||||
|
||||
/* 前一季的排行名單 */
|
||||
h2.rankingSubtitle {
|
||||
text-align: center;
|
||||
padding: 10px 0 10px 0;
|
||||
margin-top: 0px;
|
||||
margin-bottom: 30px;
|
||||
background-color: rgba(216, 255, 127, 0.5);
|
||||
color: white;
|
||||
}
|
||||
|
||||
div.rankingGroup {
|
||||
margin-top: 30px;
|
||||
}
|
||||
|
||||
div.rankingList {
|
||||
min-height: 500px;
|
||||
}
|
||||
|
||||
div.hr-line {
|
||||
width: 100%;
|
||||
border-top-width: 2px;
|
||||
border-top-color: lightgray;
|
||||
border-top-style: solid;
|
||||
margin: 5px 0 10px 0;
|
||||
}
|
||||
|
||||
span.rank {
|
||||
display: inline-block;
|
||||
width: 30px;
|
||||
font-style: italic;
|
||||
font-weight: 900;
|
||||
}
|
||||
|
||||
@media (min-width: 1200px) {
|
||||
span.artist {
|
||||
display: inline-block;
|
||||
min-width: 17.5%;
|
||||
padding-right: 10px;
|
||||
font-weight: 900;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 1199px) {
|
||||
span.artist {
|
||||
display: inline-block;
|
||||
min-width: 22.5%;
|
||||
padding-right: 10px;
|
||||
font-weight: 900;
|
||||
}
|
||||
}
|
||||
|
||||
span.postTime {
|
||||
margin-top: 0.1em;
|
||||
font-weight: 900;
|
||||
float: right;
|
||||
font-size: 0.9em;
|
||||
}
|
||||
|
||||
|
||||
/* 歷屆的前三名 */
|
||||
div.previouslyList {
|
||||
min-height: 500px;
|
||||
}
|
||||
|
||||
h2.previouslySubtitle {
|
||||
text-align: center;
|
||||
margin-top: 30px;
|
||||
margin-bottom: 30px;
|
||||
color: white;
|
||||
}
|
||||
|
||||
li.prevSeasonBtn > a {background-color: rgba(255, 255, 255, 0.7); }
|
||||
li.prevSeasonBtn > a:hover { background-color: rgba(255, 255, 255, 1); }
|
||||
li.prevSeasonBtn.active > a { background-color: rgba(0, 124, 181, 1); }
|
||||
li.prevSeasonBtn.active > a:hover { background-color: rgba(0, 124, 181, 1); }
|
33
public/css/index_extended.css
Normal file
@ -0,0 +1,33 @@
|
||||
body {
|
||||
background: url("../images/Background.jpg") no-repeat center center fixed;
|
||||
-webkit-background-size: cover;
|
||||
-moz-background-size: cover;
|
||||
-o-background-size: cover;
|
||||
background-size: cover;
|
||||
}
|
||||
|
||||
.thumbnail-feature {
|
||||
min-height: 500px;
|
||||
max-width: 368px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.blockShadow {
|
||||
border-color: rgba(0, 0, 0, 0.75);
|
||||
border-style: solid;
|
||||
border-width: 4px;
|
||||
box-shadow: 3px 3px 7px black;
|
||||
}
|
||||
|
||||
.bg-image-paint {
|
||||
background: url("../images/DoPainting.jpg") no-repeat center center fixed;
|
||||
-webkit-background-size: cover;
|
||||
-moz-background-size: cover;
|
||||
-o-background-size: cover;
|
||||
background-size: cover;
|
||||
background-attachment: fixed;
|
||||
}
|
||||
|
||||
img {
|
||||
width: 100%;
|
||||
}
|
28
public/css/login_extended.css
Normal file
@ -0,0 +1,28 @@
|
||||
html, body {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
body {
|
||||
background: url("../images/Abstract_4.png") no-repeat center center fixed;
|
||||
-webkit-background-size: cover;
|
||||
-moz-background-size: cover;
|
||||
-o-background-size: cover;
|
||||
background-size: cover;
|
||||
}
|
||||
|
||||
form.form-signin {
|
||||
margin: 20px auto 20px auto;
|
||||
width: 350px;
|
||||
}
|
||||
|
||||
div.signInOptions { position: relative; }
|
||||
div.inlineCheckbox { display: inline-block; }
|
||||
a.forgetPassword { position: absolute; right: 0; margin: 10px 0 10px 0; }
|
||||
|
||||
footer {
|
||||
position: absolute;
|
||||
left: 0; right: 0;
|
||||
bottom: 0;
|
||||
}
|
32
public/css/message_form_extended.css
Normal file
@ -0,0 +1,32 @@
|
||||
html { height: 100%; }
|
||||
|
||||
body {
|
||||
background: url("../images/Abstract_4.png") no-repeat center center fixed;
|
||||
-webkit-background-size: cover;
|
||||
-moz-background-size: cover;
|
||||
-o-background-size: cover;
|
||||
background-size: cover;
|
||||
|
||||
position: relative;
|
||||
margin: 0;
|
||||
padding-bottom: 6rem;
|
||||
min-height: 100%;
|
||||
}
|
||||
|
||||
input.hidden {
|
||||
display: none;
|
||||
}
|
||||
|
||||
input.form-control[disabled] {
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
h4, h3, h2 {
|
||||
margin: 0 0 10px 0;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
footer {
|
||||
position: absolute;
|
||||
bottom:0; left: 0; right: 0;
|
||||
}
|
104
public/css/personal_page_extended.css
Normal file
@ -0,0 +1,104 @@
|
||||
html { height: 100%; box-sizing: border-box; }
|
||||
*, *:before, *:after { box-sizing: inherit; }
|
||||
|
||||
body {
|
||||
background: url("../images/Abstract_2.jpg") no-repeat center center fixed;
|
||||
-webkit-background-size: cover;
|
||||
-moz-background-size: cover;
|
||||
-o-background-size: cover;
|
||||
background-size: cover;
|
||||
|
||||
position: relative;
|
||||
margin: 0;
|
||||
padding-bottom: 6rem;
|
||||
min-height: 100%;
|
||||
}
|
||||
|
||||
hr { margin: 10px 0 10px 0; }
|
||||
|
||||
/* 頁面內容 */
|
||||
div.container {
|
||||
padding-bottom: 32px;
|
||||
}
|
||||
|
||||
/* 個人簡易資訊面板 */
|
||||
div.personal-info-panel {
|
||||
position: sticky;
|
||||
position: -webkit-sticky;
|
||||
top: 20px;
|
||||
}
|
||||
div.tag-list::before, div.tag-list::after {
|
||||
display: table;
|
||||
content: " ";
|
||||
}
|
||||
div.tag-list::after {
|
||||
clear: both;
|
||||
}
|
||||
div.thumbnail.personalInfo { margin-bottom: 10px; }
|
||||
button > a,
|
||||
button > a:hover,
|
||||
button > a:active,
|
||||
button > a:focus {
|
||||
width: 100%;
|
||||
color: white;
|
||||
font-style: normal;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
/* 個人好友清單 */
|
||||
div.friendList {
|
||||
height: 250px;
|
||||
border: 1px solid gray;
|
||||
border-radius: 5px;
|
||||
margin-top: 0px;
|
||||
overflow: auto;overflow: auto;
|
||||
}
|
||||
button.removeFriendBtn { position: absolute; right: 10px; }
|
||||
|
||||
/* 文章版面 */
|
||||
div.panel-body { position: relative; width: 100%; }
|
||||
div.panel-body > img { max-width: 100%; }
|
||||
p, p.tag, p.state { margin: 0; }
|
||||
label { margin: 0; }
|
||||
|
||||
/* Flex屬性 */
|
||||
.flew-container { display: flex; flex-direction: column; }
|
||||
.withFlex-1 { display: flex; flex: 1; }
|
||||
.withFlex-1 > button { margin-right: 10px; }
|
||||
.withFlex-1 > button:last-of-type { margin-right: 0; }
|
||||
@media (min-width: 1200px) {
|
||||
.withFlex-1 > a { margin-right: 10px; }
|
||||
.withFlex-1 > a:last-of-type { margin-right: 0; }
|
||||
}
|
||||
|
||||
@media (max-width: 1199px) {
|
||||
.withFlex-1 > a {
|
||||
padding: 1px 5px;
|
||||
font-size: 12px;
|
||||
line-height: 1.5;
|
||||
border-radius: 3px;
|
||||
margin-right: 10px;
|
||||
}
|
||||
.withFlex-1 > a:last-of-type {
|
||||
margin-right: 0;
|
||||
}
|
||||
}
|
||||
.flex-1 { flex: 1; }
|
||||
|
||||
/* 面板(Panel)之版面調整 */
|
||||
div.panel-body > p { margin-top: 5px; }
|
||||
div.mainPanel { overflow-y: auto; overflow-x: hidden; }
|
||||
div.tab-panel { padding: 0 20px 20px 20px; }
|
||||
|
||||
/* 儲存設定的按鈕 */
|
||||
button.saveSettingBtn {
|
||||
display: block;
|
||||
margin: 10px 0;
|
||||
}
|
||||
|
||||
/* 頁尾 */
|
||||
.footer {
|
||||
position: absolute;
|
||||
right: 0; bottom: 0;
|
||||
left: 0;
|
||||
}
|
173
public/css/showcase_extended.css
Normal file
@ -0,0 +1,173 @@
|
||||
@keyframes flashBk {
|
||||
0% {background-color: rgba(153, 153, 255, 0.5); }
|
||||
16.667% {background-color: rgba(153, 255, 255, 0.5); }
|
||||
33.333% {background-color: rgba(153, 255, 153, 0.5); }
|
||||
50% {background-color: rgba(255, 255, 153, 0.5); }
|
||||
66.667% {background-color: rgba(255, 153, 153, 0.5); }
|
||||
83.333% {background-color: rgba(255, 153, 255, 0.5); }
|
||||
100% {background-color: rgba(153, 153, 255, 0.5); }
|
||||
}
|
||||
|
||||
@keyframes artistName {
|
||||
0% {color: rgb(255, 255, 255); }
|
||||
50% {color: rgb(145, 230, 255); }
|
||||
100% {color: rgb(255, 255, 255); }
|
||||
}
|
||||
|
||||
hr { margin: 20px; }
|
||||
|
||||
body {
|
||||
background: url("../images/Abstract_11.jpg") no-repeat center center fixed;
|
||||
-webkit-background-size: cover;
|
||||
-moz-background-size: cover;
|
||||
-o-background-size: cover;
|
||||
background-size: cover;
|
||||
}
|
||||
|
||||
/* 主題的標題樣式 */
|
||||
div.titleBackground {
|
||||
margin-bottom: 20px;
|
||||
padding: 10px 0;
|
||||
background-color: rgba(153, 153, 255, 0.5);;
|
||||
|
||||
animation-name: flashBk;
|
||||
animation-duration: 60s;
|
||||
animation-iteration-count: infinite;
|
||||
}
|
||||
h1.themeTitle {
|
||||
margin: 10px 0 0 0;
|
||||
text-align: center;
|
||||
text-shadow: 0 0 10px rgba(0, 0, 0, 0.7);
|
||||
color: white;
|
||||
}
|
||||
h4.originator {
|
||||
margin: 15px 0 10px 0;
|
||||
text-align: center;
|
||||
text-shadow: 0 0 10px rgba(0, 0, 0, 0.7);
|
||||
color: white;
|
||||
}
|
||||
|
||||
/* 畫作展示台 */
|
||||
div.displayStand {
|
||||
padding: 20px 0;
|
||||
background-color: rgba(64, 64, 64, 0.5);
|
||||
}
|
||||
ol.disableIndicators > li {
|
||||
display: none;
|
||||
border: none;
|
||||
}
|
||||
ol.disableIndicators > li.active {
|
||||
display: none;
|
||||
background-color: rgba(255, 255, 255, 0);
|
||||
}
|
||||
div.carousel > button {
|
||||
position: absolute;
|
||||
width: 5%;
|
||||
font-size: 1em;
|
||||
color: #fff;
|
||||
text-shadow: 0 1px 2px rgba(0, 0, 0, .6);
|
||||
opacity: .5;
|
||||
|
||||
transition-duration: 0.3s;
|
||||
}
|
||||
div.carousel > button:hover,
|
||||
div.carousel > button:focus {
|
||||
color: #fff;
|
||||
opacity: 1;
|
||||
}
|
||||
div.carousel > button.left , div.carousel > button.right,
|
||||
div.carousel > button.left:hover , div.carousel > button.right:hover,
|
||||
div.carousel > button.left:active , div.carousel > button.right:active { outline: none; }
|
||||
div.carousel > button.left {
|
||||
top: 30%; bottom: 30%; left: -6%;
|
||||
outline: none;
|
||||
}
|
||||
div.carousel > button.right {
|
||||
top: 30%; bottom: 30%; left: auto; right: -6%;
|
||||
outline: none;
|
||||
}
|
||||
div.pagerWall {
|
||||
margin-top: 20px;
|
||||
margin-bottom: 5px;;
|
||||
text-align: center;
|
||||
background-image: none;
|
||||
background-color: rgba(255, 255, 255, 0.7);
|
||||
}
|
||||
ul.pager-ul {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
/* 作品資訊 */
|
||||
div.informationSection {
|
||||
background-color: rgba(178, 195, 216, 0.5);
|
||||
padding-top: 20px;
|
||||
}
|
||||
div.thumbnail > a {
|
||||
cursor: pointer;
|
||||
}
|
||||
div.caption > h4 {
|
||||
margin: 0;
|
||||
text-shadow: 0px 0px 8px rgba(0, 0, 0, 0.5), 0px 0px 16px rgba(0, 0, 0, 0.5), 0px 0px 16px rgba(0, 0, 0, 0.5);
|
||||
animation: artistName 4s infinite;
|
||||
}
|
||||
|
||||
div[data-artist-thumbnail] { display: none; }
|
||||
div[data-artist-thumbnail="0"] { display: block; }
|
||||
|
||||
div[data-works-info] { display: none; }
|
||||
div[data-works-info="0"] { display: block; }
|
||||
|
||||
/* 評論區 */
|
||||
div.media {
|
||||
position: relative;
|
||||
}
|
||||
div.media-left { position: relative; width: 140px; overflow: auto; }
|
||||
div.media-body { position: relative; width: 80%;}
|
||||
div.media-right { position: absolute; left: auto; right: 20px; bottom: 0px; font-style: italic; }
|
||||
div.media-button { display: table-cell; position: relative; width: 10%;}
|
||||
div.media-left img.media-object {
|
||||
max-width: 120px;
|
||||
max-height: 120px;
|
||||
}
|
||||
textarea#txtaComment {
|
||||
resize: none;
|
||||
}
|
||||
button#btnSendComment {
|
||||
display: block;
|
||||
position: absolute;
|
||||
top: 25px; bottom: 5px; right: 0;
|
||||
}
|
||||
|
||||
h3.comment-group-title {
|
||||
margin: 0 0 20px 0;
|
||||
padding: 5px 0;
|
||||
text-align: center;
|
||||
background-color: rgba(160, 160, 160, 0.3);
|
||||
}
|
||||
div.comment-item {
|
||||
position: relative;
|
||||
min-height: 130px;
|
||||
padding-bottom: 16px;
|
||||
}
|
||||
img.userImage {
|
||||
position: absolute;
|
||||
width: 120px;
|
||||
height: 120px;
|
||||
}
|
||||
div.userComment {
|
||||
margin-left: 130px;
|
||||
}
|
||||
label.commentTime {
|
||||
position: absolute;
|
||||
margin-bottom: 0;
|
||||
left: auto; right: 10px; bottom: 0;
|
||||
font-size: 12px;
|
||||
font-style: italic;
|
||||
font-weight: normal;
|
||||
}
|
||||
label.commentTime > a.report {
|
||||
padding-right: 10px;
|
||||
}
|
||||
|
||||
div[data-comment-group-index] { display: none; }
|
||||
div[data-comment-group-index="0"] { display: block; }
|
42
public/css/signup_extended.css
Normal file
@ -0,0 +1,42 @@
|
||||
/* 初始化版面 */
|
||||
html, body {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
/* 設定變景圖 */
|
||||
body {
|
||||
background: url("../images/Abstract_4.png") no-repeat center center fixed;
|
||||
-webkit-background-size: cover;
|
||||
-moz-background-size: cover;
|
||||
-o-background-size: cover;
|
||||
background-size: cover;
|
||||
}
|
||||
|
||||
/* 調整輸入 */
|
||||
form.form-signin {
|
||||
position: relative;
|
||||
margin: 20px auto 20px auto;
|
||||
width: 600px;
|
||||
}
|
||||
|
||||
div.flexContainer { display: flex; position: relative; }
|
||||
div.flex-1 { display: flex; width: auto; flex: 1; }
|
||||
div.flex-2 { display: flex; width: auto; flex: 2; }
|
||||
|
||||
hr { border-top-width: 2px; border-color: white; box-shadow: 2px 2px 3px rgba(0, 0, 0, 0.5); }
|
||||
|
||||
a.rightSideText {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
margin-right: 15px;
|
||||
}
|
||||
|
||||
/* 將尾版設置為絕對位置 */
|
||||
footer {
|
||||
position: absolute;
|
||||
left: 0; right: 0;
|
||||
bottom: 0;
|
||||
}
|
||||
|
10
public/css/star-rating.min.css
vendored
Executable file
@ -0,0 +1,10 @@
|
||||
/*!
|
||||
* bootstrap-star-rating v4.0.2
|
||||
* http://plugins.krajee.com/star-rating
|
||||
*
|
||||
* Author: Kartik Visweswaran
|
||||
* Copyright: 2013 - 2017, Kartik Visweswaran, Krajee.com
|
||||
*
|
||||
* Licensed under the BSD 3-Clause
|
||||
* https://github.com/kartik-v/bootstrap-star-rating/blob/master/LICENSE.md
|
||||
*/.rating-loading{width:25px;height:25px;font-size:0;color:#fff;background:url(../images/loading.gif) top left no-repeat;border:none}.rating-container .rating-stars{position:relative;cursor:pointer;vertical-align:middle;display:inline-block;overflow:hidden;white-space:nowrap}.rating-container .rating-input{position:absolute;cursor:pointer;width:100%;height:1px;bottom:0;left:0;font-size:1px;border:none;background:0 0;padding:0;margin:0}.rating-disabled .rating-input,.rating-disabled .rating-stars{cursor:not-allowed}.rating-container .star{display:inline-block;margin:0 3px;text-align:center}.rating-container .empty-stars{color:#aaa}.rating-container .filled-stars{position:absolute;left:0;top:0;margin:auto;color:#fde16d;white-space:nowrap;overflow:hidden;-webkit-text-stroke:1px #777;text-shadow:1px 1px #999}.rating-rtl{float:right}.rating-animate .filled-stars{transition:width .25s ease;-o-transition:width .25s ease;-moz-transition:width .25s ease;-webkit-transition:width .25s ease}.rating-rtl .filled-stars{left:auto;right:0;-moz-transform:matrix(-1,0,0,1,0,0) translate3d(0,0,0);-webkit-transform:matrix(-1,0,0,1,0,0) translate3d(0,0,0);-o-transform:matrix(-1,0,0,1,0,0) translate3d(0,0,0);transform:matrix(-1,0,0,1,0,0) translate3d(0,0,0)}.rating-rtl.is-star .filled-stars{right:.06em}.rating-rtl.is-heart .empty-stars{margin-right:.07em}.rating-lg{font-size:3.91em}.rating-md{font-size:3.13em}.rating-sm{font-size:2.5em}.rating-xs{font-size:2em}.rating-xl{font-size:4.89em}.rating-container .clear-rating{color:#aaa;cursor:not-allowed;display:inline-block;vertical-align:middle;font-size:60%;padding-right:5px}.clear-rating-active{cursor:pointer!important}.clear-rating-active:hover{color:#843534}.rating-container .caption{color:#999;display:inline-block;vertical-align:middle;font-size:60%;margin-top:-.6em;margin-left:5px;margin-right:0}.rating-rtl .caption{margin-right:5px;margin-left:0}@media print{.rating-container .clear-rating{display:none}}
|
41
public/css/submit_theme_extended.css
Normal file
@ -0,0 +1,41 @@
|
||||
html { height: 100%; }
|
||||
|
||||
body {
|
||||
background: url("../images/Abstract.jpg") no-repeat center center fixed;
|
||||
-webkit-background-size: cover;
|
||||
-moz-background-size: cover;
|
||||
-o-background-size: cover;
|
||||
background-size: cover;
|
||||
|
||||
position: relative;
|
||||
margin: 0;
|
||||
padding-bottom: 6rem;
|
||||
min-height: 100%;
|
||||
}
|
||||
|
||||
input[type="file"] {
|
||||
width: 0.1px;
|
||||
height: 0.1px;
|
||||
opacity: 0;
|
||||
overflow: hidden;
|
||||
position: absolute;
|
||||
outline: none;
|
||||
z-index: -1;
|
||||
}
|
||||
|
||||
input.form-control {
|
||||
margin-right: 20px;
|
||||
}
|
||||
|
||||
input.form-control[disabled] {
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
textarea {
|
||||
resize: none;
|
||||
}
|
||||
|
||||
footer {
|
||||
position: absolute;
|
||||
bottom:0; left: 0; right: 0;
|
||||
}
|
75
public/css/theme_extended.css
Normal file
@ -0,0 +1,75 @@
|
||||
body {
|
||||
background: url("../images/ArtMuseum.jpg") no-repeat center center fixed;
|
||||
-webkit-background-size: cover;
|
||||
-moz-background-size: cover;
|
||||
-o-background-size: cover;
|
||||
background-size: cover;
|
||||
}
|
||||
|
||||
.container-table {
|
||||
height: 100%;
|
||||
display: table;
|
||||
}
|
||||
.vertical-center-row {
|
||||
display: table-cell;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.bg-themes, .bg-finishedThemes {
|
||||
-webkit-background-size: cover;
|
||||
-moz-background-size: cover;
|
||||
-o-background-size: cover;
|
||||
background-size: cover;
|
||||
background-attachment: fixed;
|
||||
}
|
||||
|
||||
.bg-themes { background: url("../images/Underwater.jpg") no-repeat center center fixed; }
|
||||
.bg-finishedThemes { background: url("../images/BlueWater_2.jpg") no-repeat center center fixed; }
|
||||
|
||||
.layout-title {
|
||||
min-height: 340px;
|
||||
}
|
||||
|
||||
/* 主題版面樣式設定 */
|
||||
|
||||
div.col-sm-6.col-xs-12 { padding-bottom: 20px; }
|
||||
|
||||
div.panel.panel-default img{ width: 100%; box-shadow: 3px 3px 5px black; }
|
||||
div.panel.panel-default h3 { margin-top: 10px; }
|
||||
div.panel.panel-default { position: relative; height: 100%; }
|
||||
|
||||
div.panel-footer { position: absolute; width: 100%; bottom: 0; }
|
||||
|
||||
div.panel-body.text-normal.popular-theme { padding-bottom: 80px; }
|
||||
div.panel-body { padding-bottom: 60px; }
|
||||
|
||||
.row-eq-height {
|
||||
display: -webkit-box;
|
||||
display: -webkit-flex;
|
||||
display: -ms-flexbox;
|
||||
display: flex;
|
||||
}
|
||||
|
||||
/* 已結束的活動 */
|
||||
|
||||
div.finished-list {
|
||||
background-color: rgba(84, 84, 84, 0.7);
|
||||
height: 500px;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
a.list-group-item {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
a.list-group-item label.author {
|
||||
width: 100px;
|
||||
margin-bottom: 0;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.to-right {
|
||||
position: absolute;
|
||||
right: 20px;
|
||||
cursor: pointer;
|
||||
}
|
65
public/css/vote_theme_extended.css
Normal file
@ -0,0 +1,65 @@
|
||||
html { height: 100%; }
|
||||
|
||||
body {
|
||||
background: url("../images/Abstract.jpg") no-repeat center center fixed;
|
||||
-webkit-background-size: cover;
|
||||
-moz-background-size: cover;
|
||||
-o-background-size: cover;
|
||||
background-size: cover;
|
||||
|
||||
position: relative;
|
||||
margin: 0;
|
||||
padding-bottom: 6rem;
|
||||
min-height: 100%;
|
||||
}
|
||||
|
||||
/* 標題 */
|
||||
h1.title {
|
||||
padding: 10px 0;
|
||||
margin: 10px 0 20px 0;
|
||||
text-align: center;
|
||||
background-color: rgba(252, 213, 103, 0.5);
|
||||
}
|
||||
|
||||
/* Panel 主題 */
|
||||
div.panel-heading {
|
||||
position: relative;
|
||||
}
|
||||
h4.panel-title > a.themeTitle {
|
||||
font-size: 1.2em;
|
||||
text-align: center;
|
||||
text-decoration: none;
|
||||
transition-duration: 0.3s;
|
||||
}
|
||||
h4.panel-title > a.themeTitle:hover {
|
||||
color: #5a9ced;
|
||||
}
|
||||
|
||||
/* 選擇按鈕 */
|
||||
input.btn-selection {
|
||||
position: absolute;
|
||||
top: 5px; right: 5px;
|
||||
}
|
||||
input.btn-selected, input.btn-selected:hover, input.btn-selected:active, input.btn-selected:focus {
|
||||
background: #994c00; /* Old browsers */
|
||||
background: -moz-linear-gradient(top, #994c00 0%, #d87e00 100%); /* FF3.6-15 */
|
||||
background: -webkit-linear-gradient(top, #994c00 0%,#d87e00 100%); /* Chrome10-25,Safari5.1-6 */
|
||||
background: linear-gradient(to bottom, #994c00 0%,#d87e00 100%); /* W3C, IE10+, FF16+, Chrome26+, Opera12+, Safari7+ */
|
||||
color: white;
|
||||
}
|
||||
|
||||
/* 發起者 */
|
||||
div.originator {
|
||||
font-weight: bold;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
span.originator {
|
||||
font-size: 1.2em;
|
||||
font-weight: 900;
|
||||
animation: trans-blue-black 5s infinite;
|
||||
}
|
||||
|
||||
footer {
|
||||
position: absolute;
|
||||
bottom:0; left: 0; right: 0;
|
||||
}
|
46
public/css/write_message_extended.css
Normal file
@ -0,0 +1,46 @@
|
||||
html { height: 100%; box-sizing: border-box; }
|
||||
*, *:before, *:after { box-sizing: inherit; }
|
||||
|
||||
body {
|
||||
background: url("../images/Abstract_2.jpg") no-repeat center center fixed;
|
||||
-webkit-background-size: cover;
|
||||
-moz-background-size: cover;
|
||||
-o-background-size: cover;
|
||||
background-size: cover;
|
||||
|
||||
position: relative;
|
||||
margin: 0;
|
||||
padding-bottom: 6rem;
|
||||
min-height: 100%;
|
||||
}
|
||||
|
||||
input[disabled] { cursor: default; }
|
||||
|
||||
div.form-group { position: relative; }
|
||||
|
||||
div.form-group button.dropdown-toggle {
|
||||
position: absolute;
|
||||
top: 0; left: 12;
|
||||
border-radius: 5px 0 0 5px;
|
||||
width: 100px;
|
||||
}
|
||||
|
||||
div.form-group input.dropdown-textbox {
|
||||
width: calc(100% - 100px);
|
||||
border-radius: 0 5px 5px 0;
|
||||
margin-left: 100px;
|
||||
}
|
||||
|
||||
textarea {
|
||||
resize: none;
|
||||
}
|
||||
|
||||
label.checkbox-inline {
|
||||
padding: 0 10px 0 0;
|
||||
}
|
||||
|
||||
.footer {
|
||||
position: absolute;
|
||||
right: 0; bottom: 0;
|
||||
left: 0;
|
||||
}
|
BIN
public/fonts/glyphicons-halflings-regular.eot
Normal file
229
public/fonts/glyphicons-halflings-regular.svg
Normal file
@ -0,0 +1,229 @@
|
||||
<?xml version="1.0" standalone="no"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" >
|
||||
<svg xmlns="http://www.w3.org/2000/svg">
|
||||
<metadata></metadata>
|
||||
<defs>
|
||||
<font id="glyphicons_halflingsregular" horiz-adv-x="1200" >
|
||||
<font-face units-per-em="1200" ascent="960" descent="-240" />
|
||||
<missing-glyph horiz-adv-x="500" />
|
||||
<glyph />
|
||||
<glyph />
|
||||
<glyph unicode="
" />
|
||||
<glyph unicode=" " />
|
||||
<glyph unicode="*" d="M100 500v200h259l-183 183l141 141l183 -183v259h200v-259l183 183l141 -141l-183 -183h259v-200h-259l183 -183l-141 -141l-183 183v-259h-200v259l-183 -183l-141 141l183 183h-259z" />
|
||||
<glyph unicode="+" d="M0 400v300h400v400h300v-400h400v-300h-400v-400h-300v400h-400z" />
|
||||
<glyph unicode=" " />
|
||||
<glyph unicode=" " horiz-adv-x="652" />
|
||||
<glyph unicode=" " horiz-adv-x="1304" />
|
||||
<glyph unicode=" " horiz-adv-x="652" />
|
||||
<glyph unicode=" " horiz-adv-x="1304" />
|
||||
<glyph unicode=" " horiz-adv-x="434" />
|
||||
<glyph unicode=" " horiz-adv-x="326" />
|
||||
<glyph unicode=" " horiz-adv-x="217" />
|
||||
<glyph unicode=" " horiz-adv-x="217" />
|
||||
<glyph unicode=" " horiz-adv-x="163" />
|
||||
<glyph unicode=" " horiz-adv-x="260" />
|
||||
<glyph unicode=" " horiz-adv-x="72" />
|
||||
<glyph unicode=" " horiz-adv-x="260" />
|
||||
<glyph unicode=" " horiz-adv-x="326" />
|
||||
<glyph unicode="€" d="M100 500l100 100h113q0 47 5 100h-218l100 100h135q37 167 112 257q117 141 297 141q242 0 354 -189q60 -103 66 -209h-181q0 55 -25.5 99t-63.5 68t-75 36.5t-67 12.5q-24 0 -52.5 -10t-62.5 -32t-65.5 -67t-50.5 -107h379l-100 -100h-300q-6 -46 -6 -100h406l-100 -100 h-300q9 -74 33 -132t52.5 -91t62 -54.5t59 -29t46.5 -7.5q29 0 66 13t75 37t63.5 67.5t25.5 96.5h174q-31 -172 -128 -278q-107 -117 -274 -117q-205 0 -324 158q-36 46 -69 131.5t-45 205.5h-217z" />
|
||||
<glyph unicode="−" d="M200 400h900v300h-900v-300z" />
|
||||
<glyph unicode="◼" horiz-adv-x="500" d="M0 0z" />
|
||||
<glyph unicode="☁" d="M-14 494q0 -80 56.5 -137t135.5 -57h750q120 0 205 86.5t85 207.5t-85 207t-205 86q-46 0 -90 -14q-44 97 -134.5 156.5t-200.5 59.5q-152 0 -260 -107.5t-108 -260.5q0 -25 2 -37q-66 -14 -108.5 -67.5t-42.5 -122.5z" />
|
||||
<glyph unicode="✉" d="M0 100l400 400l200 -200l200 200l400 -400h-1200zM0 300v600l300 -300zM0 1100l600 -603l600 603h-1200zM900 600l300 300v-600z" />
|
||||
<glyph unicode="✏" d="M-13 -13l333 112l-223 223zM187 403l214 -214l614 614l-214 214zM887 1103l214 -214l99 92q13 13 13 32.5t-13 33.5l-153 153q-15 13 -33 13t-33 -13z" />
|
||||
<glyph unicode="" d="M0 1200h1200l-500 -550v-550h300v-100h-800v100h300v550z" />
|
||||
<glyph unicode="" d="M14 84q18 -55 86 -75.5t147 5.5q65 21 109 69t44 90v606l600 155v-521q-64 16 -138 -7q-79 -26 -122.5 -83t-25.5 -111q18 -55 86 -75.5t147 4.5q70 23 111.5 63.5t41.5 95.5v881q0 10 -7 15.5t-17 2.5l-752 -193q-10 -3 -17 -12.5t-7 -19.5v-689q-64 17 -138 -7 q-79 -25 -122.5 -82t-25.5 -112z" />
|
||||
<glyph unicode="" d="M23 693q0 200 142 342t342 142t342 -142t142 -342q0 -142 -78 -261l300 -300q7 -8 7 -18t-7 -18l-109 -109q-8 -7 -18 -7t-18 7l-300 300q-119 -78 -261 -78q-200 0 -342 142t-142 342zM176 693q0 -136 97 -233t234 -97t233.5 96.5t96.5 233.5t-96.5 233.5t-233.5 96.5 t-234 -97t-97 -233z" />
|
||||
<glyph unicode="" d="M100 784q0 64 28 123t73 100.5t104.5 64t119 20.5t120 -38.5t104.5 -104.5q48 69 109.5 105t121.5 38t118.5 -20.5t102.5 -64t71 -100.5t27 -123q0 -57 -33.5 -117.5t-94 -124.5t-126.5 -127.5t-150 -152.5t-146 -174q-62 85 -145.5 174t-149.5 152.5t-126.5 127.5 t-94 124.5t-33.5 117.5z" />
|
||||
<glyph unicode="" d="M-72 800h479l146 400h2l146 -400h472l-382 -278l145 -449l-384 275l-382 -275l146 447zM168 71l2 1z" />
|
||||
<glyph unicode="" d="M-72 800h479l146 400h2l146 -400h472l-382 -278l145 -449l-384 275l-382 -275l146 447zM168 71l2 1zM237 700l196 -142l-73 -226l192 140l195 -141l-74 229l193 140h-235l-77 211l-78 -211h-239z" />
|
||||
<glyph unicode="" d="M0 0v143l400 257v100q-37 0 -68.5 74.5t-31.5 125.5v200q0 124 88 212t212 88t212 -88t88 -212v-200q0 -51 -31.5 -125.5t-68.5 -74.5v-100l400 -257v-143h-1200z" />
|
||||
<glyph unicode="" d="M0 0v1100h1200v-1100h-1200zM100 100h100v100h-100v-100zM100 300h100v100h-100v-100zM100 500h100v100h-100v-100zM100 700h100v100h-100v-100zM100 900h100v100h-100v-100zM300 100h600v400h-600v-400zM300 600h600v400h-600v-400zM1000 100h100v100h-100v-100z M1000 300h100v100h-100v-100zM1000 500h100v100h-100v-100zM1000 700h100v100h-100v-100zM1000 900h100v100h-100v-100z" />
|
||||
<glyph unicode="" d="M0 50v400q0 21 14.5 35.5t35.5 14.5h400q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-400q-21 0 -35.5 14.5t-14.5 35.5zM0 650v400q0 21 14.5 35.5t35.5 14.5h400q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-400 q-21 0 -35.5 14.5t-14.5 35.5zM600 50v400q0 21 14.5 35.5t35.5 14.5h400q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-400q-21 0 -35.5 14.5t-14.5 35.5zM600 650v400q0 21 14.5 35.5t35.5 14.5h400q21 0 35.5 -14.5t14.5 -35.5v-400 q0 -21 -14.5 -35.5t-35.5 -14.5h-400q-21 0 -35.5 14.5t-14.5 35.5z" />
|
||||
<glyph unicode="" d="M0 50v200q0 21 14.5 35.5t35.5 14.5h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5zM0 450v200q0 21 14.5 35.5t35.5 14.5h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200 q-21 0 -35.5 14.5t-14.5 35.5zM0 850v200q0 21 14.5 35.5t35.5 14.5h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5zM400 50v200q0 21 14.5 35.5t35.5 14.5h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5 t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5zM400 450v200q0 21 14.5 35.5t35.5 14.5h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5zM400 850v200q0 21 14.5 35.5t35.5 14.5h200q21 0 35.5 -14.5t14.5 -35.5 v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5zM800 50v200q0 21 14.5 35.5t35.5 14.5h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5zM800 450v200q0 21 14.5 35.5t35.5 14.5h200 q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5zM800 850v200q0 21 14.5 35.5t35.5 14.5h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5z" />
|
||||
<glyph unicode="" d="M0 50v200q0 21 14.5 35.5t35.5 14.5h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5zM0 450q0 -21 14.5 -35.5t35.5 -14.5h200q21 0 35.5 14.5t14.5 35.5v200q0 21 -14.5 35.5t-35.5 14.5h-200q-21 0 -35.5 -14.5 t-14.5 -35.5v-200zM0 850v200q0 21 14.5 35.5t35.5 14.5h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5zM400 50v200q0 21 14.5 35.5t35.5 14.5h700q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5 t-35.5 -14.5h-700q-21 0 -35.5 14.5t-14.5 35.5zM400 450v200q0 21 14.5 35.5t35.5 14.5h700q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-700q-21 0 -35.5 14.5t-14.5 35.5zM400 850v200q0 21 14.5 35.5t35.5 14.5h700q21 0 35.5 -14.5t14.5 -35.5 v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-700q-21 0 -35.5 14.5t-14.5 35.5z" />
|
||||
<glyph unicode="" d="M29 454l419 -420l818 820l-212 212l-607 -607l-206 207z" />
|
||||
<glyph unicode="" d="M106 318l282 282l-282 282l212 212l282 -282l282 282l212 -212l-282 -282l282 -282l-212 -212l-282 282l-282 -282z" />
|
||||
<glyph unicode="" d="M23 693q0 200 142 342t342 142t342 -142t142 -342q0 -142 -78 -261l300 -300q7 -8 7 -18t-7 -18l-109 -109q-8 -7 -18 -7t-18 7l-300 300q-119 -78 -261 -78q-200 0 -342 142t-142 342zM176 693q0 -136 97 -233t234 -97t233.5 96.5t96.5 233.5t-96.5 233.5t-233.5 96.5 t-234 -97t-97 -233zM300 600v200h100v100h200v-100h100v-200h-100v-100h-200v100h-100z" />
|
||||
<glyph unicode="" d="M23 694q0 200 142 342t342 142t342 -142t142 -342q0 -141 -78 -262l300 -299q7 -7 7 -18t-7 -18l-109 -109q-8 -8 -18 -8t-18 8l-300 300q-119 -78 -261 -78q-200 0 -342 142t-142 342zM176 694q0 -136 97 -233t234 -97t233.5 97t96.5 233t-96.5 233t-233.5 97t-234 -97 t-97 -233zM300 601h400v200h-400v-200z" />
|
||||
<glyph unicode="" d="M23 600q0 183 105 331t272 210v-166q-103 -55 -165 -155t-62 -220q0 -177 125 -302t302 -125t302 125t125 302q0 120 -62 220t-165 155v166q167 -62 272 -210t105 -331q0 -118 -45.5 -224.5t-123 -184t-184 -123t-224.5 -45.5t-224.5 45.5t-184 123t-123 184t-45.5 224.5 zM500 750q0 -21 14.5 -35.5t35.5 -14.5h100q21 0 35.5 14.5t14.5 35.5v400q0 21 -14.5 35.5t-35.5 14.5h-100q-21 0 -35.5 -14.5t-14.5 -35.5v-400z" />
|
||||
<glyph unicode="" d="M100 1h200v300h-200v-300zM400 1v500h200v-500h-200zM700 1v800h200v-800h-200zM1000 1v1200h200v-1200h-200z" />
|
||||
<glyph unicode="" d="M26 601q0 -33 6 -74l151 -38l2 -6q14 -49 38 -93l3 -5l-80 -134q45 -59 105 -105l133 81l5 -3q45 -26 94 -39l5 -2l38 -151q40 -5 74 -5q27 0 74 5l38 151l6 2q46 13 93 39l5 3l134 -81q56 44 104 105l-80 134l3 5q24 44 39 93l1 6l152 38q5 40 5 74q0 28 -5 73l-152 38 l-1 6q-16 51 -39 93l-3 5l80 134q-44 58 -104 105l-134 -81l-5 3q-45 25 -93 39l-6 1l-38 152q-40 5 -74 5q-27 0 -74 -5l-38 -152l-5 -1q-50 -14 -94 -39l-5 -3l-133 81q-59 -47 -105 -105l80 -134l-3 -5q-25 -47 -38 -93l-2 -6l-151 -38q-6 -48 -6 -73zM385 601 q0 88 63 151t152 63t152 -63t63 -151q0 -89 -63 -152t-152 -63t-152 63t-63 152z" />
|
||||
<glyph unicode="" d="M100 1025v50q0 10 7.5 17.5t17.5 7.5h275v100q0 41 29.5 70.5t70.5 29.5h300q41 0 70.5 -29.5t29.5 -70.5v-100h275q10 0 17.5 -7.5t7.5 -17.5v-50q0 -11 -7 -18t-18 -7h-1050q-11 0 -18 7t-7 18zM200 100v800h900v-800q0 -41 -29.5 -71t-70.5 -30h-700q-41 0 -70.5 30 t-29.5 71zM300 100h100v700h-100v-700zM500 100h100v700h-100v-700zM500 1100h300v100h-300v-100zM700 100h100v700h-100v-700zM900 100h100v700h-100v-700z" />
|
||||
<glyph unicode="" d="M1 601l656 644l644 -644h-200v-600h-300v400h-300v-400h-300v600h-200z" />
|
||||
<glyph unicode="" d="M100 25v1150q0 11 7 18t18 7h475v-500h400v-675q0 -11 -7 -18t-18 -7h-850q-11 0 -18 7t-7 18zM700 800v300l300 -300h-300z" />
|
||||
<glyph unicode="" d="M4 600q0 162 80 299t217 217t299 80t299 -80t217 -217t80 -299t-80 -299t-217 -217t-299 -80t-299 80t-217 217t-80 299zM186 600q0 -171 121.5 -292.5t292.5 -121.5t292.5 121.5t121.5 292.5t-121.5 292.5t-292.5 121.5t-292.5 -121.5t-121.5 -292.5zM500 500v400h100 v-300h200v-100h-300z" />
|
||||
<glyph unicode="" d="M-100 0l431 1200h209l-21 -300h162l-20 300h208l431 -1200h-538l-41 400h-242l-40 -400h-539zM488 500h224l-27 300h-170z" />
|
||||
<glyph unicode="" d="M0 0v400h490l-290 300h200v500h300v-500h200l-290 -300h490v-400h-1100zM813 200h175v100h-175v-100z" />
|
||||
<glyph unicode="" d="M1 600q0 122 47.5 233t127.5 191t191 127.5t233 47.5t233 -47.5t191 -127.5t127.5 -191t47.5 -233t-47.5 -233t-127.5 -191t-191 -127.5t-233 -47.5t-233 47.5t-191 127.5t-127.5 191t-47.5 233zM188 600q0 -170 121 -291t291 -121t291 121t121 291t-121 291t-291 121 t-291 -121t-121 -291zM350 600h150v300h200v-300h150l-250 -300z" />
|
||||
<glyph unicode="" d="M4 600q0 162 80 299t217 217t299 80t299 -80t217 -217t80 -299t-80 -299t-217 -217t-299 -80t-299 80t-217 217t-80 299zM186 600q0 -171 121.5 -292.5t292.5 -121.5t292.5 121.5t121.5 292.5t-121.5 292.5t-292.5 121.5t-292.5 -121.5t-121.5 -292.5zM350 600l250 300 l250 -300h-150v-300h-200v300h-150z" />
|
||||
<glyph unicode="" d="M0 25v475l200 700h800l199 -700l1 -475q0 -11 -7 -18t-18 -7h-1150q-11 0 -18 7t-7 18zM200 500h200l50 -200h300l50 200h200l-97 500h-606z" />
|
||||
<glyph unicode="" d="M4 600q0 162 80 299t217 217t299 80t299 -80t217 -217t80 -299t-80 -299t-217 -217t-299 -80t-299 80t-217 217t-80 299zM186 600q0 -172 121.5 -293t292.5 -121t292.5 121t121.5 293q0 171 -121.5 292.5t-292.5 121.5t-292.5 -121.5t-121.5 -292.5zM500 397v401 l297 -200z" />
|
||||
<glyph unicode="" d="M23 600q0 -118 45.5 -224.5t123 -184t184 -123t224.5 -45.5t224.5 45.5t184 123t123 184t45.5 224.5h-150q0 -177 -125 -302t-302 -125t-302 125t-125 302t125 302t302 125q136 0 246 -81l-146 -146h400v400l-145 -145q-157 122 -355 122q-118 0 -224.5 -45.5t-184 -123 t-123 -184t-45.5 -224.5z" />
|
||||
<glyph unicode="" d="M23 600q0 118 45.5 224.5t123 184t184 123t224.5 45.5q198 0 355 -122l145 145v-400h-400l147 147q-112 80 -247 80q-177 0 -302 -125t-125 -302h-150zM100 0v400h400l-147 -147q112 -80 247 -80q177 0 302 125t125 302h150q0 -118 -45.5 -224.5t-123 -184t-184 -123 t-224.5 -45.5q-198 0 -355 122z" />
|
||||
<glyph unicode="" d="M100 0h1100v1200h-1100v-1200zM200 100v900h900v-900h-900zM300 200v100h100v-100h-100zM300 400v100h100v-100h-100zM300 600v100h100v-100h-100zM300 800v100h100v-100h-100zM500 200h500v100h-500v-100zM500 400v100h500v-100h-500zM500 600v100h500v-100h-500z M500 800v100h500v-100h-500z" />
|
||||
<glyph unicode="" d="M0 100v600q0 41 29.5 70.5t70.5 29.5h100v200q0 82 59 141t141 59h300q82 0 141 -59t59 -141v-200h100q41 0 70.5 -29.5t29.5 -70.5v-600q0 -41 -29.5 -70.5t-70.5 -29.5h-900q-41 0 -70.5 29.5t-29.5 70.5zM400 800h300v150q0 21 -14.5 35.5t-35.5 14.5h-200 q-21 0 -35.5 -14.5t-14.5 -35.5v-150z" />
|
||||
<glyph unicode="" d="M100 0v1100h100v-1100h-100zM300 400q60 60 127.5 84t127.5 17.5t122 -23t119 -30t110 -11t103 42t91 120.5v500q-40 -81 -101.5 -115.5t-127.5 -29.5t-138 25t-139.5 40t-125.5 25t-103 -29.5t-65 -115.5v-500z" />
|
||||
<glyph unicode="" d="M0 275q0 -11 7 -18t18 -7h50q11 0 18 7t7 18v300q0 127 70.5 231.5t184.5 161.5t245 57t245 -57t184.5 -161.5t70.5 -231.5v-300q0 -11 7 -18t18 -7h50q11 0 18 7t7 18v300q0 116 -49.5 227t-131 192.5t-192.5 131t-227 49.5t-227 -49.5t-192.5 -131t-131 -192.5 t-49.5 -227v-300zM200 20v460q0 8 6 14t14 6h160q8 0 14 -6t6 -14v-460q0 -8 -6 -14t-14 -6h-160q-8 0 -14 6t-6 14zM800 20v460q0 8 6 14t14 6h160q8 0 14 -6t6 -14v-460q0 -8 -6 -14t-14 -6h-160q-8 0 -14 6t-6 14z" />
|
||||
<glyph unicode="" d="M0 400h300l300 -200v800l-300 -200h-300v-400zM688 459l141 141l-141 141l71 71l141 -141l141 141l71 -71l-141 -141l141 -141l-71 -71l-141 141l-141 -141z" />
|
||||
<glyph unicode="" d="M0 400h300l300 -200v800l-300 -200h-300v-400zM700 857l69 53q111 -135 111 -310q0 -169 -106 -302l-67 54q86 110 86 248q0 146 -93 257z" />
|
||||
<glyph unicode="" d="M0 401v400h300l300 200v-800l-300 200h-300zM702 858l69 53q111 -135 111 -310q0 -170 -106 -303l-67 55q86 110 86 248q0 145 -93 257zM889 951l7 -8q123 -151 123 -344q0 -189 -119 -339l-7 -8l81 -66l6 8q142 178 142 405q0 230 -144 408l-6 8z" />
|
||||
<glyph unicode="" d="M0 0h500v500h-200v100h-100v-100h-200v-500zM0 600h100v100h400v100h100v100h-100v300h-500v-600zM100 100v300h300v-300h-300zM100 800v300h300v-300h-300zM200 200v100h100v-100h-100zM200 900h100v100h-100v-100zM500 500v100h300v-300h200v-100h-100v-100h-200v100 h-100v100h100v200h-200zM600 0v100h100v-100h-100zM600 1000h100v-300h200v-300h300v200h-200v100h200v500h-600v-200zM800 800v300h300v-300h-300zM900 0v100h300v-100h-300zM900 900v100h100v-100h-100zM1100 200v100h100v-100h-100z" />
|
||||
<glyph unicode="" d="M0 200h100v1000h-100v-1000zM100 0v100h300v-100h-300zM200 200v1000h100v-1000h-100zM500 0v91h100v-91h-100zM500 200v1000h200v-1000h-200zM700 0v91h100v-91h-100zM800 200v1000h100v-1000h-100zM900 0v91h200v-91h-200zM1000 200v1000h200v-1000h-200z" />
|
||||
<glyph unicode="" d="M0 700l1 475q0 10 7.5 17.5t17.5 7.5h474l700 -700l-500 -500zM148 953q0 -42 29 -71q30 -30 71.5 -30t71.5 30q29 29 29 71t-29 71q-30 30 -71.5 30t-71.5 -30q-29 -29 -29 -71z" />
|
||||
<glyph unicode="" d="M1 700l1 475q0 11 7 18t18 7h474l700 -700l-500 -500zM148 953q0 -42 30 -71q29 -30 71 -30t71 30q30 29 30 71t-30 71q-29 30 -71 30t-71 -30q-30 -29 -30 -71zM701 1200h100l700 -700l-500 -500l-50 50l450 450z" />
|
||||
<glyph unicode="" d="M100 0v1025l175 175h925v-1000l-100 -100v1000h-750l-100 -100h750v-1000h-900z" />
|
||||
<glyph unicode="" d="M200 0l450 444l450 -443v1150q0 20 -14.5 35t-35.5 15h-800q-21 0 -35.5 -15t-14.5 -35v-1151z" />
|
||||
<glyph unicode="" d="M0 100v700h200l100 -200h600l100 200h200v-700h-200v200h-800v-200h-200zM253 829l40 -124h592l62 124l-94 346q-2 11 -10 18t-18 7h-450q-10 0 -18 -7t-10 -18zM281 24l38 152q2 10 11.5 17t19.5 7h500q10 0 19.5 -7t11.5 -17l38 -152q2 -10 -3.5 -17t-15.5 -7h-600 q-10 0 -15.5 7t-3.5 17z" />
|
||||
<glyph unicode="" d="M0 200q0 -41 29.5 -70.5t70.5 -29.5h1000q41 0 70.5 29.5t29.5 70.5v600q0 41 -29.5 70.5t-70.5 29.5h-150q-4 8 -11.5 21.5t-33 48t-53 61t-69 48t-83.5 21.5h-200q-41 0 -82 -20.5t-70 -50t-52 -59t-34 -50.5l-12 -20h-150q-41 0 -70.5 -29.5t-29.5 -70.5v-600z M356 500q0 100 72 172t172 72t172 -72t72 -172t-72 -172t-172 -72t-172 72t-72 172zM494 500q0 -44 31 -75t75 -31t75 31t31 75t-31 75t-75 31t-75 -31t-31 -75zM900 700v100h100v-100h-100z" />
|
||||
<glyph unicode="" d="M53 0h365v66q-41 0 -72 11t-49 38t1 71l92 234h391l82 -222q16 -45 -5.5 -88.5t-74.5 -43.5v-66h417v66q-34 1 -74 43q-18 19 -33 42t-21 37l-6 13l-385 998h-93l-399 -1006q-24 -48 -52 -75q-12 -12 -33 -25t-36 -20l-15 -7v-66zM416 521l178 457l46 -140l116 -317h-340 z" />
|
||||
<glyph unicode="" d="M100 0v89q41 7 70.5 32.5t29.5 65.5v827q0 28 -1 39.5t-5.5 26t-15.5 21t-29 14t-49 14.5v71l471 -1q120 0 213 -88t93 -228q0 -55 -11.5 -101.5t-28 -74t-33.5 -47.5t-28 -28l-12 -7q8 -3 21.5 -9t48 -31.5t60.5 -58t47.5 -91.5t21.5 -129q0 -84 -59 -156.5t-142 -111 t-162 -38.5h-500zM400 200h161q89 0 153 48.5t64 132.5q0 90 -62.5 154.5t-156.5 64.5h-159v-400zM400 700h139q76 0 130 61.5t54 138.5q0 82 -84 130.5t-239 48.5v-379z" />
|
||||
<glyph unicode="" d="M200 0v57q77 7 134.5 40.5t65.5 80.5l173 849q10 56 -10 74t-91 37q-6 1 -10.5 2.5t-9.5 2.5v57h425l2 -57q-33 -8 -62 -25.5t-46 -37t-29.5 -38t-17.5 -30.5l-5 -12l-128 -825q-10 -52 14 -82t95 -36v-57h-500z" />
|
||||
<glyph unicode="" d="M-75 200h75v800h-75l125 167l125 -167h-75v-800h75l-125 -167zM300 900v300h150h700h150v-300h-50q0 29 -8 48.5t-18.5 30t-33.5 15t-39.5 5.5t-50.5 1h-200v-850l100 -50v-100h-400v100l100 50v850h-200q-34 0 -50.5 -1t-40 -5.5t-33.5 -15t-18.5 -30t-8.5 -48.5h-49z " />
|
||||
<glyph unicode="" d="M33 51l167 125v-75h800v75l167 -125l-167 -125v75h-800v-75zM100 901v300h150h700h150v-300h-50q0 29 -8 48.5t-18 30t-33.5 15t-40 5.5t-50.5 1h-200v-650l100 -50v-100h-400v100l100 50v650h-200q-34 0 -50.5 -1t-39.5 -5.5t-33.5 -15t-18.5 -30t-8 -48.5h-50z" />
|
||||
<glyph unicode="" d="M0 50q0 -20 14.5 -35t35.5 -15h1100q21 0 35.5 15t14.5 35v100q0 21 -14.5 35.5t-35.5 14.5h-1100q-21 0 -35.5 -14.5t-14.5 -35.5v-100zM0 350q0 -20 14.5 -35t35.5 -15h800q21 0 35.5 15t14.5 35v100q0 21 -14.5 35.5t-35.5 14.5h-800q-21 0 -35.5 -14.5t-14.5 -35.5 v-100zM0 650q0 -20 14.5 -35t35.5 -15h1000q21 0 35.5 15t14.5 35v100q0 21 -14.5 35.5t-35.5 14.5h-1000q-21 0 -35.5 -14.5t-14.5 -35.5v-100zM0 950q0 -20 14.5 -35t35.5 -15h600q21 0 35.5 15t14.5 35v100q0 21 -14.5 35.5t-35.5 14.5h-600q-21 0 -35.5 -14.5 t-14.5 -35.5v-100z" />
|
||||
<glyph unicode="" d="M0 50q0 -20 14.5 -35t35.5 -15h1100q21 0 35.5 15t14.5 35v100q0 21 -14.5 35.5t-35.5 14.5h-1100q-21 0 -35.5 -14.5t-14.5 -35.5v-100zM0 650q0 -20 14.5 -35t35.5 -15h1100q21 0 35.5 15t14.5 35v100q0 21 -14.5 35.5t-35.5 14.5h-1100q-21 0 -35.5 -14.5t-14.5 -35.5 v-100zM200 350q0 -20 14.5 -35t35.5 -15h700q21 0 35.5 15t14.5 35v100q0 21 -14.5 35.5t-35.5 14.5h-700q-21 0 -35.5 -14.5t-14.5 -35.5v-100zM200 950q0 -20 14.5 -35t35.5 -15h700q21 0 35.5 15t14.5 35v100q0 21 -14.5 35.5t-35.5 14.5h-700q-21 0 -35.5 -14.5 t-14.5 -35.5v-100z" />
|
||||
<glyph unicode="" d="M0 50v100q0 21 14.5 35.5t35.5 14.5h1100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-1100q-21 0 -35.5 15t-14.5 35zM100 650v100q0 21 14.5 35.5t35.5 14.5h1000q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-1000q-21 0 -35.5 15 t-14.5 35zM300 350v100q0 21 14.5 35.5t35.5 14.5h800q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-800q-21 0 -35.5 15t-14.5 35zM500 950v100q0 21 14.5 35.5t35.5 14.5h600q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-600 q-21 0 -35.5 15t-14.5 35z" />
|
||||
<glyph unicode="" d="M0 50v100q0 21 14.5 35.5t35.5 14.5h1100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-1100q-21 0 -35.5 15t-14.5 35zM0 350v100q0 21 14.5 35.5t35.5 14.5h1100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-1100q-21 0 -35.5 15 t-14.5 35zM0 650v100q0 21 14.5 35.5t35.5 14.5h1100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-1100q-21 0 -35.5 15t-14.5 35zM0 950v100q0 21 14.5 35.5t35.5 14.5h1100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-1100 q-21 0 -35.5 15t-14.5 35z" />
|
||||
<glyph unicode="" d="M0 50v100q0 21 14.5 35.5t35.5 14.5h100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-100q-21 0 -35.5 15t-14.5 35zM0 350v100q0 21 14.5 35.5t35.5 14.5h100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-100q-21 0 -35.5 15 t-14.5 35zM0 650v100q0 21 14.5 35.5t35.5 14.5h100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-100q-21 0 -35.5 15t-14.5 35zM0 950v100q0 21 14.5 35.5t35.5 14.5h100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-100q-21 0 -35.5 15 t-14.5 35zM300 50v100q0 21 14.5 35.5t35.5 14.5h800q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-800q-21 0 -35.5 15t-14.5 35zM300 350v100q0 21 14.5 35.5t35.5 14.5h800q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-800 q-21 0 -35.5 15t-14.5 35zM300 650v100q0 21 14.5 35.5t35.5 14.5h800q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-800q-21 0 -35.5 15t-14.5 35zM300 950v100q0 21 14.5 35.5t35.5 14.5h800q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15 h-800q-21 0 -35.5 15t-14.5 35z" />
|
||||
<glyph unicode="" d="M-101 500v100h201v75l166 -125l-166 -125v75h-201zM300 0h100v1100h-100v-1100zM500 50q0 -20 14.5 -35t35.5 -15h600q20 0 35 15t15 35v100q0 21 -15 35.5t-35 14.5h-600q-21 0 -35.5 -14.5t-14.5 -35.5v-100zM500 350q0 -20 14.5 -35t35.5 -15h300q20 0 35 15t15 35 v100q0 21 -15 35.5t-35 14.5h-300q-21 0 -35.5 -14.5t-14.5 -35.5v-100zM500 650q0 -20 14.5 -35t35.5 -15h500q20 0 35 15t15 35v100q0 21 -15 35.5t-35 14.5h-500q-21 0 -35.5 -14.5t-14.5 -35.5v-100zM500 950q0 -20 14.5 -35t35.5 -15h100q20 0 35 15t15 35v100 q0 21 -15 35.5t-35 14.5h-100q-21 0 -35.5 -14.5t-14.5 -35.5v-100z" />
|
||||
<glyph unicode="" d="M1 50q0 -20 14.5 -35t35.5 -15h600q20 0 35 15t15 35v100q0 21 -15 35.5t-35 14.5h-600q-21 0 -35.5 -14.5t-14.5 -35.5v-100zM1 350q0 -20 14.5 -35t35.5 -15h300q20 0 35 15t15 35v100q0 21 -15 35.5t-35 14.5h-300q-21 0 -35.5 -14.5t-14.5 -35.5v-100zM1 650 q0 -20 14.5 -35t35.5 -15h500q20 0 35 15t15 35v100q0 21 -15 35.5t-35 14.5h-500q-21 0 -35.5 -14.5t-14.5 -35.5v-100zM1 950q0 -20 14.5 -35t35.5 -15h100q20 0 35 15t15 35v100q0 21 -15 35.5t-35 14.5h-100q-21 0 -35.5 -14.5t-14.5 -35.5v-100zM801 0v1100h100v-1100 h-100zM934 550l167 -125v75h200v100h-200v75z" />
|
||||
<glyph unicode="" d="M0 275v650q0 31 22 53t53 22h750q31 0 53 -22t22 -53v-650q0 -31 -22 -53t-53 -22h-750q-31 0 -53 22t-22 53zM900 600l300 300v-600z" />
|
||||
<glyph unicode="" d="M0 44v1012q0 18 13 31t31 13h1112q19 0 31.5 -13t12.5 -31v-1012q0 -18 -12.5 -31t-31.5 -13h-1112q-18 0 -31 13t-13 31zM100 263l247 182l298 -131l-74 156l293 318l236 -288v500h-1000v-737zM208 750q0 56 39 95t95 39t95 -39t39 -95t-39 -95t-95 -39t-95 39t-39 95z " />
|
||||
<glyph unicode="" d="M148 745q0 124 60.5 231.5t165 172t226.5 64.5q123 0 227 -63t164.5 -169.5t60.5 -229.5t-73 -272q-73 -114 -166.5 -237t-150.5 -189l-57 -66q-10 9 -27 26t-66.5 70.5t-96 109t-104 135.5t-100.5 155q-63 139 -63 262zM342 772q0 -107 75.5 -182.5t181.5 -75.5 q107 0 182.5 75.5t75.5 182.5t-75.5 182t-182.5 75t-182 -75.5t-75 -181.5z" />
|
||||
<glyph unicode="" d="M1 600q0 122 47.5 233t127.5 191t191 127.5t233 47.5t233 -47.5t191 -127.5t127.5 -191t47.5 -233t-47.5 -233t-127.5 -191t-191 -127.5t-233 -47.5t-233 47.5t-191 127.5t-127.5 191t-47.5 233zM173 600q0 -177 125.5 -302t301.5 -125v854q-176 0 -301.5 -125 t-125.5 -302z" />
|
||||
<glyph unicode="" d="M117 406q0 94 34 186t88.5 172.5t112 159t115 177t87.5 194.5q21 -71 57.5 -142.5t76 -130.5t83 -118.5t82 -117t70 -116t50 -125.5t18.5 -136q0 -89 -39 -165.5t-102 -126.5t-140 -79.5t-156 -33.5q-114 6 -211.5 53t-161.5 139t-64 210zM243 414q14 -82 59.5 -136 t136.5 -80l16 98q-7 6 -18 17t-34 48t-33 77q-15 73 -14 143.5t10 122.5l9 51q-92 -110 -119.5 -185t-12.5 -156z" />
|
||||
<glyph unicode="" d="M0 400v300q0 165 117.5 282.5t282.5 117.5q366 -6 397 -14l-186 -186h-311q-41 0 -70.5 -29.5t-29.5 -70.5v-500q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5v125l200 200v-225q0 -165 -117.5 -282.5t-282.5 -117.5h-300q-165 0 -282.5 117.5 t-117.5 282.5zM436 341l161 50l412 412l-114 113l-405 -405zM995 1015l113 -113l113 113l-21 85l-92 28z" />
|
||||
<glyph unicode="" d="M0 400v300q0 165 117.5 282.5t282.5 117.5h261l2 -80q-133 -32 -218 -120h-145q-41 0 -70.5 -29.5t-29.5 -70.5v-500q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5l200 153v-53q0 -165 -117.5 -282.5t-282.5 -117.5h-300q-165 0 -282.5 117.5t-117.5 282.5 zM423 524q30 38 81.5 64t103 35.5t99 14t77.5 3.5l29 -1v-209l360 324l-359 318v-216q-7 0 -19 -1t-48 -8t-69.5 -18.5t-76.5 -37t-76.5 -59t-62 -88t-39.5 -121.5z" />
|
||||
<glyph unicode="" d="M0 400v300q0 165 117.5 282.5t282.5 117.5h300q61 0 127 -23l-178 -177h-349q-41 0 -70.5 -29.5t-29.5 -70.5v-500q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5v69l200 200v-169q0 -165 -117.5 -282.5t-282.5 -117.5h-300q-165 0 -282.5 117.5 t-117.5 282.5zM342 632l283 -284l567 567l-137 137l-430 -431l-146 147z" />
|
||||
<glyph unicode="" d="M0 603l300 296v-198h200v200h-200l300 300l295 -300h-195v-200h200v198l300 -296l-300 -300v198h-200v-200h195l-295 -300l-300 300h200v200h-200v-198z" />
|
||||
<glyph unicode="" d="M200 50v1000q0 21 14.5 35.5t35.5 14.5h100q21 0 35.5 -14.5t14.5 -35.5v-437l500 487v-1100l-500 488v-438q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5z" />
|
||||
<glyph unicode="" d="M0 50v1000q0 21 14.5 35.5t35.5 14.5h100q21 0 35.5 -14.5t14.5 -35.5v-437l500 487v-487l500 487v-1100l-500 488v-488l-500 488v-438q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5z" />
|
||||
<glyph unicode="" d="M136 550l564 550v-487l500 487v-1100l-500 488v-488z" />
|
||||
<glyph unicode="" d="M200 0l900 550l-900 550v-1100z" />
|
||||
<glyph unicode="" d="M200 150q0 -21 14.5 -35.5t35.5 -14.5h200q21 0 35.5 14.5t14.5 35.5v800q0 21 -14.5 35.5t-35.5 14.5h-200q-21 0 -35.5 -14.5t-14.5 -35.5v-800zM600 150q0 -21 14.5 -35.5t35.5 -14.5h200q21 0 35.5 14.5t14.5 35.5v800q0 21 -14.5 35.5t-35.5 14.5h-200 q-21 0 -35.5 -14.5t-14.5 -35.5v-800z" />
|
||||
<glyph unicode="" d="M200 150q0 -20 14.5 -35t35.5 -15h800q21 0 35.5 15t14.5 35v800q0 21 -14.5 35.5t-35.5 14.5h-800q-21 0 -35.5 -14.5t-14.5 -35.5v-800z" />
|
||||
<glyph unicode="" d="M0 0v1100l500 -487v487l564 -550l-564 -550v488z" />
|
||||
<glyph unicode="" d="M0 0v1100l500 -487v487l500 -487v437q0 21 14.5 35.5t35.5 14.5h100q21 0 35.5 -14.5t14.5 -35.5v-1000q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v438l-500 -488v488z" />
|
||||
<glyph unicode="" d="M300 0v1100l500 -487v437q0 21 14.5 35.5t35.5 14.5h100q21 0 35.5 -14.5t14.5 -35.5v-1000q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v438z" />
|
||||
<glyph unicode="" d="M100 250v100q0 21 14.5 35.5t35.5 14.5h1000q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-1000q-21 0 -35.5 14.5t-14.5 35.5zM100 500h1100l-550 564z" />
|
||||
<glyph unicode="" d="M185 599l592 -592l240 240l-353 353l353 353l-240 240z" />
|
||||
<glyph unicode="" d="M272 194l353 353l-353 353l241 240l572 -571l21 -22l-1 -1v-1l-592 -591z" />
|
||||
<glyph unicode="" d="M3 600q0 162 80 299.5t217.5 217.5t299.5 80t299.5 -80t217.5 -217.5t80 -299.5t-80 -299.5t-217.5 -217.5t-299.5 -80t-299.5 80t-217.5 217.5t-80 299.5zM300 500h200v-200h200v200h200v200h-200v200h-200v-200h-200v-200z" />
|
||||
<glyph unicode="" d="M3 600q0 162 80 299.5t217.5 217.5t299.5 80t299.5 -80t217.5 -217.5t80 -299.5t-80 -299.5t-217.5 -217.5t-299.5 -80t-299.5 80t-217.5 217.5t-80 299.5zM300 500h600v200h-600v-200z" />
|
||||
<glyph unicode="" d="M3 600q0 162 80 299.5t217.5 217.5t299.5 80t299.5 -80t217.5 -217.5t80 -299.5t-80 -299.5t-217.5 -217.5t-299.5 -80t-299.5 80t-217.5 217.5t-80 299.5zM246 459l213 -213l141 142l141 -142l213 213l-142 141l142 141l-213 212l-141 -141l-141 142l-212 -213l141 -141 z" />
|
||||
<glyph unicode="" d="M3 600q0 162 80 299.5t217.5 217.5t299.5 80t299.5 -80t217.5 -217.5t80 -299.5t-80 -299.5t-217.5 -217.5t-299.5 -80t-299.5 80t-217.5 217.5t-80 299.5zM270 551l276 -277l411 411l-175 174l-236 -236l-102 102z" />
|
||||
<glyph unicode="" d="M3 600q0 162 80 299.5t217.5 217.5t299.5 80t299.5 -80t217.5 -217.5t80 -299.5t-80 -299.5t-217.5 -217.5t-299.5 -80t-299.5 80t-217.5 217.5t-80 299.5zM364 700h143q4 0 11.5 -1t11 -1t6.5 3t3 9t1 11t3.5 8.5t3.5 6t5.5 4t6.5 2.5t9 1.5t9 0.5h11.5h12.5 q19 0 30 -10t11 -26q0 -22 -4 -28t-27 -22q-5 -1 -12.5 -3t-27 -13.5t-34 -27t-26.5 -46t-11 -68.5h200q5 3 14 8t31.5 25.5t39.5 45.5t31 69t14 94q0 51 -17.5 89t-42 58t-58.5 32t-58.5 15t-51.5 3q-50 0 -90.5 -12t-75 -38.5t-53.5 -74.5t-19 -114zM500 300h200v100h-200 v-100z" />
|
||||
<glyph unicode="" d="M3 600q0 162 80 299.5t217.5 217.5t299.5 80t299.5 -80t217.5 -217.5t80 -299.5t-80 -299.5t-217.5 -217.5t-299.5 -80t-299.5 80t-217.5 217.5t-80 299.5zM400 300h400v100h-100v300h-300v-100h100v-200h-100v-100zM500 800h200v100h-200v-100z" />
|
||||
<glyph unicode="" d="M0 500v200h195q31 125 98.5 199.5t206.5 100.5v200h200v-200q54 -20 113 -60t112.5 -105.5t71.5 -134.5h203v-200h-203q-25 -102 -116.5 -186t-180.5 -117v-197h-200v197q-140 27 -208 102.5t-98 200.5h-194zM290 500q24 -73 79.5 -127.5t130.5 -78.5v206h200v-206 q149 48 201 206h-201v200h200q-25 74 -75.5 127t-124.5 77v-204h-200v203q-75 -23 -130 -77t-79 -126h209v-200h-210z" />
|
||||
<glyph unicode="" d="M4 600q0 162 80 299t217 217t299 80t299 -80t217 -217t80 -299t-80 -299t-217 -217t-299 -80t-299 80t-217 217t-80 299zM186 600q0 -171 121.5 -292.5t292.5 -121.5t292.5 121.5t121.5 292.5t-121.5 292.5t-292.5 121.5t-292.5 -121.5t-121.5 -292.5zM356 465l135 135 l-135 135l109 109l135 -135l135 135l109 -109l-135 -135l135 -135l-109 -109l-135 135l-135 -135z" />
|
||||
<glyph unicode="" d="M4 600q0 162 80 299t217 217t299 80t299 -80t217 -217t80 -299t-80 -299t-217 -217t-299 -80t-299 80t-217 217t-80 299zM186 600q0 -171 121.5 -292.5t292.5 -121.5t292.5 121.5t121.5 292.5t-121.5 292.5t-292.5 121.5t-292.5 -121.5t-121.5 -292.5zM322 537l141 141 l87 -87l204 205l142 -142l-346 -345z" />
|
||||
<glyph unicode="" d="M4 600q0 162 80 299t217 217t299 80t299 -80t217 -217t80 -299t-80 -299t-217 -217t-299 -80t-299 80t-217 217t-80 299zM186 600q0 -115 62 -215l568 567q-100 62 -216 62q-171 0 -292.5 -121.5t-121.5 -292.5zM391 245q97 -59 209 -59q171 0 292.5 121.5t121.5 292.5 q0 112 -59 209z" />
|
||||
<glyph unicode="" d="M0 547l600 453v-300h600v-300h-600v-301z" />
|
||||
<glyph unicode="" d="M0 400v300h600v300l600 -453l-600 -448v301h-600z" />
|
||||
<glyph unicode="" d="M204 600l450 600l444 -600h-298v-600h-300v600h-296z" />
|
||||
<glyph unicode="" d="M104 600h296v600h300v-600h298l-449 -600z" />
|
||||
<glyph unicode="" d="M0 200q6 132 41 238.5t103.5 193t184 138t271.5 59.5v271l600 -453l-600 -448v301q-95 -2 -183 -20t-170 -52t-147 -92.5t-100 -135.5z" />
|
||||
<glyph unicode="" d="M0 0v400l129 -129l294 294l142 -142l-294 -294l129 -129h-400zM635 777l142 -142l294 294l129 -129v400h-400l129 -129z" />
|
||||
<glyph unicode="" d="M34 176l295 295l-129 129h400v-400l-129 130l-295 -295zM600 600v400l129 -129l295 295l142 -141l-295 -295l129 -130h-400z" />
|
||||
<glyph unicode="" d="M23 600q0 118 45.5 224.5t123 184t184 123t224.5 45.5t224.5 -45.5t184 -123t123 -184t45.5 -224.5t-45.5 -224.5t-123 -184t-184 -123t-224.5 -45.5t-224.5 45.5t-184 123t-123 184t-45.5 224.5zM456 851l58 -302q4 -20 21.5 -34.5t37.5 -14.5h54q20 0 37.5 14.5 t21.5 34.5l58 302q4 20 -8 34.5t-32 14.5h-207q-21 0 -33 -14.5t-8 -34.5zM500 300h200v100h-200v-100z" />
|
||||
<glyph unicode="" d="M0 800h100v-200h400v300h200v-300h400v200h100v100h-111q1 1 1 6.5t-1.5 15t-3.5 17.5l-34 172q-11 39 -41.5 63t-69.5 24q-32 0 -61 -17l-239 -144q-22 -13 -40 -35q-19 24 -40 36l-238 144q-33 18 -62 18q-39 0 -69.5 -23t-40.5 -61l-35 -177q-2 -8 -3 -18t-1 -15v-6 h-111v-100zM100 0h400v400h-400v-400zM200 900q-3 0 14 48t36 96l18 47l213 -191h-281zM700 0v400h400v-400h-400zM731 900l202 197q5 -12 12 -32.5t23 -64t25 -72t7 -28.5h-269z" />
|
||||
<glyph unicode="" d="M0 -22v143l216 193q-9 53 -13 83t-5.5 94t9 113t38.5 114t74 124q47 60 99.5 102.5t103 68t127.5 48t145.5 37.5t184.5 43.5t220 58.5q0 -189 -22 -343t-59 -258t-89 -181.5t-108.5 -120t-122 -68t-125.5 -30t-121.5 -1.5t-107.5 12.5t-87.5 17t-56.5 7.5l-99 -55z M238.5 300.5q19.5 -6.5 86.5 76.5q55 66 367 234q70 38 118.5 69.5t102 79t99 111.5t86.5 148q22 50 24 60t-6 19q-7 5 -17 5t-26.5 -14.5t-33.5 -39.5q-35 -51 -113.5 -108.5t-139.5 -89.5l-61 -32q-369 -197 -458 -401q-48 -111 -28.5 -117.5z" />
|
||||
<glyph unicode="" d="M111 408q0 -33 5 -63q9 -56 44 -119.5t105 -108.5q31 -21 64 -16t62 23.5t57 49.5t48 61.5t35 60.5q32 66 39 184.5t-13 157.5q79 -80 122 -164t26 -184q-5 -33 -20.5 -69.5t-37.5 -80.5q-10 -19 -14.5 -29t-12 -26t-9 -23.5t-3 -19t2.5 -15.5t11 -9.5t19.5 -5t30.5 2.5 t42 8q57 20 91 34t87.5 44.5t87 64t65.5 88.5t47 122q38 172 -44.5 341.5t-246.5 278.5q22 -44 43 -129q39 -159 -32 -154q-15 2 -33 9q-79 33 -120.5 100t-44 175.5t48.5 257.5q-13 -8 -34 -23.5t-72.5 -66.5t-88.5 -105.5t-60 -138t-8 -166.5q2 -12 8 -41.5t8 -43t6 -39.5 t3.5 -39.5t-1 -33.5t-6 -31.5t-13.5 -24t-21 -20.5t-31 -12q-38 -10 -67 13t-40.5 61.5t-15 81.5t10.5 75q-52 -46 -83.5 -101t-39 -107t-7.5 -85z" />
|
||||
<glyph unicode="" d="M-61 600l26 40q6 10 20 30t49 63.5t74.5 85.5t97 90t116.5 83.5t132.5 59t145.5 23.5t145.5 -23.5t132.5 -59t116.5 -83.5t97 -90t74.5 -85.5t49 -63.5t20 -30l26 -40l-26 -40q-6 -10 -20 -30t-49 -63.5t-74.5 -85.5t-97 -90t-116.5 -83.5t-132.5 -59t-145.5 -23.5 t-145.5 23.5t-132.5 59t-116.5 83.5t-97 90t-74.5 85.5t-49 63.5t-20 30zM120 600q7 -10 40.5 -58t56 -78.5t68 -77.5t87.5 -75t103 -49.5t125 -21.5t123.5 20t100.5 45.5t85.5 71.5t66.5 75.5t58 81.5t47 66q-1 1 -28.5 37.5t-42 55t-43.5 53t-57.5 63.5t-58.5 54 q49 -74 49 -163q0 -124 -88 -212t-212 -88t-212 88t-88 212q0 85 46 158q-102 -87 -226 -258zM377 656q49 -124 154 -191l105 105q-37 24 -75 72t-57 84l-20 36z" />
|
||||
<glyph unicode="" d="M-61 600l26 40q6 10 20 30t49 63.5t74.5 85.5t97 90t116.5 83.5t132.5 59t145.5 23.5q61 0 121 -17l37 142h148l-314 -1200h-148l37 143q-82 21 -165 71.5t-140 102t-109.5 112t-72 88.5t-29.5 43zM120 600q210 -282 393 -336l37 141q-107 18 -178.5 101.5t-71.5 193.5 q0 85 46 158q-102 -87 -226 -258zM377 656q49 -124 154 -191l47 47l23 87q-30 28 -59 69t-44 68l-14 26zM780 161l38 145q22 15 44.5 34t46 44t40.5 44t41 50.5t33.5 43.5t33 44t24.5 34q-97 127 -140 175l39 146q67 -54 131.5 -125.5t87.5 -103.5t36 -52l26 -40l-26 -40 q-7 -12 -25.5 -38t-63.5 -79.5t-95.5 -102.5t-124 -100t-146.5 -79z" />
|
||||
<glyph unicode="" d="M-97.5 34q13.5 -34 50.5 -34h1294q37 0 50.5 35.5t-7.5 67.5l-642 1056q-20 34 -48 36.5t-48 -29.5l-642 -1066q-21 -32 -7.5 -66zM155 200l445 723l445 -723h-345v100h-200v-100h-345zM500 600l100 -300l100 300v100h-200v-100z" />
|
||||
<glyph unicode="" d="M100 262v41q0 20 11 44.5t26 38.5l363 325v339q0 62 44 106t106 44t106 -44t44 -106v-339l363 -325q15 -14 26 -38.5t11 -44.5v-41q0 -20 -12 -26.5t-29 5.5l-359 249v-263q100 -91 100 -113v-64q0 -20 -13 -28.5t-32 0.5l-94 78h-222l-94 -78q-19 -9 -32 -0.5t-13 28.5 v64q0 22 100 113v263l-359 -249q-17 -12 -29 -5.5t-12 26.5z" />
|
||||
<glyph unicode="" d="M0 50q0 -20 14.5 -35t35.5 -15h1000q21 0 35.5 15t14.5 35v750h-1100v-750zM0 900h1100v150q0 21 -14.5 35.5t-35.5 14.5h-150v100h-100v-100h-500v100h-100v-100h-150q-21 0 -35.5 -14.5t-14.5 -35.5v-150zM100 100v100h100v-100h-100zM100 300v100h100v-100h-100z M100 500v100h100v-100h-100zM300 100v100h100v-100h-100zM300 300v100h100v-100h-100zM300 500v100h100v-100h-100zM500 100v100h100v-100h-100zM500 300v100h100v-100h-100zM500 500v100h100v-100h-100zM700 100v100h100v-100h-100zM700 300v100h100v-100h-100zM700 500 v100h100v-100h-100zM900 100v100h100v-100h-100zM900 300v100h100v-100h-100zM900 500v100h100v-100h-100z" />
|
||||
<glyph unicode="" d="M0 200v200h259l600 600h241v198l300 -295l-300 -300v197h-159l-600 -600h-341zM0 800h259l122 -122l141 142l-181 180h-341v-200zM678 381l141 142l122 -123h159v198l300 -295l-300 -300v197h-241z" />
|
||||
<glyph unicode="" d="M0 400v600q0 41 29.5 70.5t70.5 29.5h1000q41 0 70.5 -29.5t29.5 -70.5v-600q0 -41 -29.5 -70.5t-70.5 -29.5h-596l-304 -300v300h-100q-41 0 -70.5 29.5t-29.5 70.5z" />
|
||||
<glyph unicode="" d="M100 600v200h300v-250q0 -113 6 -145q17 -92 102 -117q39 -11 92 -11q37 0 66.5 5.5t50 15.5t36 24t24 31.5t14 37.5t7 42t2.5 45t0 47v25v250h300v-200q0 -42 -3 -83t-15 -104t-31.5 -116t-58 -109.5t-89 -96.5t-129 -65.5t-174.5 -25.5t-174.5 25.5t-129 65.5t-89 96.5 t-58 109.5t-31.5 116t-15 104t-3 83zM100 900v300h300v-300h-300zM800 900v300h300v-300h-300z" />
|
||||
<glyph unicode="" d="M-30 411l227 -227l352 353l353 -353l226 227l-578 579z" />
|
||||
<glyph unicode="" d="M70 797l580 -579l578 579l-226 227l-353 -353l-352 353z" />
|
||||
<glyph unicode="" d="M-198 700l299 283l300 -283h-203v-400h385l215 -200h-800v600h-196zM402 1000l215 -200h381v-400h-198l299 -283l299 283h-200v600h-796z" />
|
||||
<glyph unicode="" d="M18 939q-5 24 10 42q14 19 39 19h896l38 162q5 17 18.5 27.5t30.5 10.5h94q20 0 35 -14.5t15 -35.5t-15 -35.5t-35 -14.5h-54l-201 -961q-2 -4 -6 -10.5t-19 -17.5t-33 -11h-31v-50q0 -20 -14.5 -35t-35.5 -15t-35.5 15t-14.5 35v50h-300v-50q0 -20 -14.5 -35t-35.5 -15 t-35.5 15t-14.5 35v50h-50q-21 0 -35.5 15t-14.5 35q0 21 14.5 35.5t35.5 14.5h535l48 200h-633q-32 0 -54.5 21t-27.5 43z" />
|
||||
<glyph unicode="" d="M0 0v800h1200v-800h-1200zM0 900v100h200q0 41 29.5 70.5t70.5 29.5h300q41 0 70.5 -29.5t29.5 -70.5h500v-100h-1200z" />
|
||||
<glyph unicode="" d="M1 0l300 700h1200l-300 -700h-1200zM1 400v600h200q0 41 29.5 70.5t70.5 29.5h300q41 0 70.5 -29.5t29.5 -70.5h500v-200h-1000z" />
|
||||
<glyph unicode="" d="M302 300h198v600h-198l298 300l298 -300h-198v-600h198l-298 -300z" />
|
||||
<glyph unicode="" d="M0 600l300 298v-198h600v198l300 -298l-300 -297v197h-600v-197z" />
|
||||
<glyph unicode="" d="M0 100v100q0 41 29.5 70.5t70.5 29.5h1000q41 0 70.5 -29.5t29.5 -70.5v-100q0 -41 -29.5 -70.5t-70.5 -29.5h-1000q-41 0 -70.5 29.5t-29.5 70.5zM31 400l172 739q5 22 23 41.5t38 19.5h672q19 0 37.5 -22.5t23.5 -45.5l172 -732h-1138zM800 100h100v100h-100v-100z M1000 100h100v100h-100v-100z" />
|
||||
<glyph unicode="" d="M-101 600v50q0 24 25 49t50 38l25 13v-250l-11 5.5t-24 14t-30 21.5t-24 27.5t-11 31.5zM100 500v250v8v8v7t0.5 7t1.5 5.5t2 5t3 4t4.5 3.5t6 1.5t7.5 0.5h200l675 250v-850l-675 200h-38l47 -276q2 -12 -3 -17.5t-11 -6t-21 -0.5h-8h-83q-20 0 -34.5 14t-18.5 35 q-55 337 -55 351zM1100 200v850q0 21 14.5 35.5t35.5 14.5q20 0 35 -14.5t15 -35.5v-850q0 -20 -15 -35t-35 -15q-21 0 -35.5 15t-14.5 35z" />
|
||||
<glyph unicode="" d="M74 350q0 21 13.5 35.5t33.5 14.5h18l117 173l63 327q15 77 76 140t144 83l-18 32q-6 19 3 32t29 13h94q20 0 29 -10.5t3 -29.5q-18 -36 -18 -37q83 -19 144 -82.5t76 -140.5l63 -327l118 -173h17q20 0 33.5 -14.5t13.5 -35.5q0 -20 -13 -40t-31 -27q-8 -3 -23 -8.5 t-65 -20t-103 -25t-132.5 -19.5t-158.5 -9q-125 0 -245.5 20.5t-178.5 40.5l-58 20q-18 7 -31 27.5t-13 40.5zM497 110q12 -49 40 -79.5t63 -30.5t63 30.5t39 79.5q-48 -6 -102 -6t-103 6z" />
|
||||
<glyph unicode="" d="M21 445l233 -45l-78 -224l224 78l45 -233l155 179l155 -179l45 233l224 -78l-78 224l234 45l-180 155l180 156l-234 44l78 225l-224 -78l-45 233l-155 -180l-155 180l-45 -233l-224 78l78 -225l-233 -44l179 -156z" />
|
||||
<glyph unicode="" d="M0 200h200v600h-200v-600zM300 275q0 -75 100 -75h61q124 -100 139 -100h250q46 0 83 57l238 344q29 31 29 74v100q0 44 -30.5 84.5t-69.5 40.5h-328q28 118 28 125v150q0 44 -30.5 84.5t-69.5 40.5h-50q-27 0 -51 -20t-38 -48l-96 -198l-145 -196q-20 -26 -20 -63v-400z M400 300v375l150 213l100 212h50v-175l-50 -225h450v-125l-250 -375h-214l-136 100h-100z" />
|
||||
<glyph unicode="" d="M0 400v600h200v-600h-200zM300 525v400q0 75 100 75h61q124 100 139 100h250q46 0 83 -57l238 -344q29 -31 29 -74v-100q0 -44 -30.5 -84.5t-69.5 -40.5h-328q28 -118 28 -125v-150q0 -44 -30.5 -84.5t-69.5 -40.5h-50q-27 0 -51 20t-38 48l-96 198l-145 196 q-20 26 -20 63zM400 525l150 -212l100 -213h50v175l-50 225h450v125l-250 375h-214l-136 -100h-100v-375z" />
|
||||
<glyph unicode="" d="M8 200v600h200v-600h-200zM308 275v525q0 17 14 35.5t28 28.5l14 9l362 230q14 6 25 6q17 0 29 -12l109 -112q14 -14 14 -34q0 -18 -11 -32l-85 -121h302q85 0 138.5 -38t53.5 -110t-54.5 -111t-138.5 -39h-107l-130 -339q-7 -22 -20.5 -41.5t-28.5 -19.5h-341 q-7 0 -90 81t-83 94zM408 289l100 -89h293l131 339q6 21 19.5 41t28.5 20h203q16 0 25 15t9 36q0 20 -9 34.5t-25 14.5h-457h-6.5h-7.5t-6.5 0.5t-6 1t-5 1.5t-5.5 2.5t-4 4t-4 5.5q-5 12 -5 20q0 14 10 27l147 183l-86 83l-339 -236v-503z" />
|
||||
<glyph unicode="" d="M-101 651q0 72 54 110t139 38l302 -1l-85 121q-11 16 -11 32q0 21 14 34l109 113q13 12 29 12q11 0 25 -6l365 -230q7 -4 17 -10.5t26.5 -26t16.5 -36.5v-526q0 -13 -86 -93.5t-94 -80.5h-341q-16 0 -29.5 20t-19.5 41l-130 339h-107q-84 0 -139 39t-55 111zM-1 601h222 q15 0 28.5 -20.5t19.5 -40.5l131 -339h293l107 89v502l-343 237l-87 -83l145 -184q10 -11 10 -26q0 -11 -5 -20q-1 -3 -3.5 -5.5l-4 -4t-5 -2.5t-5.5 -1.5t-6.5 -1t-6.5 -0.5h-7.5h-6.5h-476v-100zM1000 201v600h200v-600h-200z" />
|
||||
<glyph unicode="" d="M97 719l230 -363q4 -6 10.5 -15.5t26 -25t36.5 -15.5h525q13 0 94 83t81 90v342q0 15 -20 28.5t-41 19.5l-339 131v106q0 84 -39 139t-111 55t-110 -53.5t-38 -138.5v-302l-121 84q-15 12 -33.5 11.5t-32.5 -13.5l-112 -110q-22 -22 -6 -53zM172 739l83 86l183 -146 q22 -18 47 -5q3 1 5.5 3.5l4 4t2.5 5t1.5 5.5t1 6.5t0.5 6.5v7.5v6.5v456q0 22 25 31t50 -0.5t25 -30.5v-202q0 -16 20 -29.5t41 -19.5l339 -130v-294l-89 -100h-503zM400 0v200h600v-200h-600z" />
|
||||
<glyph unicode="" d="M2 585q-16 -31 6 -53l112 -110q13 -13 32 -13.5t34 10.5l121 85q0 -51 -0.5 -153.5t-0.5 -148.5q0 -84 38.5 -138t110.5 -54t111 55t39 139v106l339 131q20 6 40.5 19.5t20.5 28.5v342q0 7 -81 90t-94 83h-525q-17 0 -35.5 -14t-28.5 -28l-10 -15zM77 565l236 339h503 l89 -100v-294l-340 -130q-20 -6 -40 -20t-20 -29v-202q0 -22 -25 -31t-50 0t-25 31v456v14.5t-1.5 11.5t-5 12t-9.5 7q-24 13 -46 -5l-184 -146zM305 1104v200h600v-200h-600z" />
|
||||
<glyph unicode="" d="M5 597q0 122 47.5 232.5t127.5 190.5t190.5 127.5t232.5 47.5q162 0 299.5 -80t217.5 -218t80 -300t-80 -299.5t-217.5 -217.5t-299.5 -80t-300 80t-218 217.5t-80 299.5zM298 701l2 -201h300l-2 -194l402 294l-402 298v-197h-300z" />
|
||||
<glyph unicode="" d="M0 597q0 122 47.5 232.5t127.5 190.5t190.5 127.5t231.5 47.5q122 0 232.5 -47.5t190.5 -127.5t127.5 -190.5t47.5 -232.5q0 -162 -80 -299.5t-218 -217.5t-300 -80t-299.5 80t-217.5 217.5t-80 299.5zM200 600l402 -294l-2 194h300l2 201h-300v197z" />
|
||||
<glyph unicode="" d="M5 597q0 122 47.5 232.5t127.5 190.5t190.5 127.5t232.5 47.5q162 0 299.5 -80t217.5 -218t80 -300t-80 -299.5t-217.5 -217.5t-299.5 -80t-300 80t-218 217.5t-80 299.5zM300 600h200v-300h200v300h200l-300 400z" />
|
||||
<glyph unicode="" d="M5 597q0 122 47.5 232.5t127.5 190.5t190.5 127.5t232.5 47.5q162 0 299.5 -80t217.5 -218t80 -300t-80 -299.5t-217.5 -217.5t-299.5 -80t-300 80t-218 217.5t-80 299.5zM300 600l300 -400l300 400h-200v300h-200v-300h-200z" />
|
||||
<glyph unicode="" d="M5 597q0 122 47.5 232.5t127.5 190.5t190.5 127.5t232.5 47.5q121 0 231.5 -47.5t190.5 -127.5t127.5 -190.5t47.5 -232.5q0 -162 -80 -299.5t-217.5 -217.5t-299.5 -80t-300 80t-218 217.5t-80 299.5zM254 780q-8 -33 5.5 -92.5t7.5 -87.5q0 -9 17 -44t16 -60 q12 0 23 -5.5t23 -15t20 -13.5q24 -12 108 -42q22 -8 53 -31.5t59.5 -38.5t57.5 -11q8 -18 -15 -55t-20 -57q42 -71 87 -80q0 -6 -3 -15.5t-3.5 -14.5t4.5 -17q104 -3 221 112q30 29 47 47t34.5 49t20.5 62q-14 9 -37 9.5t-36 7.5q-14 7 -49 15t-52 19q-9 0 -39.5 -0.5 t-46.5 -1.5t-39 -6.5t-39 -16.5q-50 -35 -66 -12q-4 2 -3.5 25.5t0.5 25.5q-6 13 -26.5 17t-24.5 7q2 22 -2 41t-16.5 28t-38.5 -20q-23 -25 -42 4q-19 28 -8 58q6 16 22 22q6 -1 26 -1.5t33.5 -4t19.5 -13.5q12 -19 32 -37.5t34 -27.5l14 -8q0 3 9.5 39.5t5.5 57.5 q-4 23 14.5 44.5t22.5 31.5q5 14 10 35t8.5 31t15.5 22.5t34 21.5q-6 18 10 37q8 0 23.5 -1.5t24.5 -1.5t20.5 4.5t20.5 15.5q-10 23 -30.5 42.5t-38 30t-49 26.5t-43.5 23q11 39 2 44q31 -13 58 -14.5t39 3.5l11 4q7 36 -16.5 53.5t-64.5 28.5t-56 23q-19 -3 -37 0 q-15 -12 -36.5 -21t-34.5 -12t-44 -8t-39 -6q-15 -3 -45.5 0.5t-45.5 -2.5q-21 -7 -52 -26.5t-34 -34.5q-3 -11 6.5 -22.5t8.5 -18.5q-3 -34 -27.5 -90.5t-29.5 -79.5zM518 916q3 12 16 30t16 25q10 -10 18.5 -10t14 6t14.5 14.5t16 12.5q0 -24 17 -66.5t17 -43.5 q-9 2 -31 5t-36 5t-32 8t-30 14zM692 1003h1h-1z" />
|
||||
<glyph unicode="" d="M0 164.5q0 21.5 15 37.5l600 599q-33 101 6 201.5t135 154.5q164 92 306 -9l-259 -138l145 -232l251 126q13 -175 -151 -267q-123 -70 -253 -23l-596 -596q-15 -16 -36.5 -16t-36.5 16l-111 110q-15 15 -15 36.5z" />
|
||||
<glyph unicode="" horiz-adv-x="1220" d="M0 196v100q0 41 29.5 70.5t70.5 29.5h1000q41 0 70.5 -29.5t29.5 -70.5v-100q0 -41 -29.5 -70.5t-70.5 -29.5h-1000q-41 0 -70.5 29.5t-29.5 70.5zM0 596v100q0 41 29.5 70.5t70.5 29.5h1000q41 0 70.5 -29.5t29.5 -70.5v-100q0 -41 -29.5 -70.5t-70.5 -29.5h-1000 q-41 0 -70.5 29.5t-29.5 70.5zM0 996v100q0 41 29.5 70.5t70.5 29.5h1000q41 0 70.5 -29.5t29.5 -70.5v-100q0 -41 -29.5 -70.5t-70.5 -29.5h-1000q-41 0 -70.5 29.5t-29.5 70.5zM600 596h500v100h-500v-100zM800 196h300v100h-300v-100zM900 996h200v100h-200v-100z" />
|
||||
<glyph unicode="" d="M100 1100v100h1000v-100h-1000zM150 1000h900l-350 -500v-300l-200 -200v500z" />
|
||||
<glyph unicode="" d="M0 200v200h1200v-200q0 -41 -29.5 -70.5t-70.5 -29.5h-1000q-41 0 -70.5 29.5t-29.5 70.5zM0 500v400q0 41 29.5 70.5t70.5 29.5h300v100q0 41 29.5 70.5t70.5 29.5h200q41 0 70.5 -29.5t29.5 -70.5v-100h300q41 0 70.5 -29.5t29.5 -70.5v-400h-500v100h-200v-100h-500z M500 1000h200v100h-200v-100z" />
|
||||
<glyph unicode="" d="M0 0v400l129 -129l200 200l142 -142l-200 -200l129 -129h-400zM0 800l129 129l200 -200l142 142l-200 200l129 129h-400v-400zM729 329l142 142l200 -200l129 129v-400h-400l129 129zM729 871l200 200l-129 129h400v-400l-129 129l-200 -200z" />
|
||||
<glyph unicode="" d="M0 596q0 162 80 299t217 217t299 80t299 -80t217 -217t80 -299t-80 -299t-217 -217t-299 -80t-299 80t-217 217t-80 299zM182 596q0 -172 121.5 -293t292.5 -121t292.5 121t121.5 293q0 171 -121.5 292.5t-292.5 121.5t-292.5 -121.5t-121.5 -292.5zM291 655 q0 23 15.5 38.5t38.5 15.5t39 -16t16 -38q0 -23 -16 -39t-39 -16q-22 0 -38 16t-16 39zM400 850q0 22 16 38.5t39 16.5q22 0 38 -16t16 -39t-16 -39t-38 -16q-23 0 -39 16.5t-16 38.5zM514 609q0 32 20.5 56.5t51.5 29.5l122 126l1 1q-9 14 -9 28q0 22 16 38.5t39 16.5 q22 0 38 -16t16 -39t-16 -39t-38 -16q-14 0 -29 10l-55 -145q17 -22 17 -51q0 -36 -25.5 -61.5t-61.5 -25.5t-61.5 25.5t-25.5 61.5zM800 655q0 22 16 38t39 16t38.5 -15.5t15.5 -38.5t-16 -39t-38 -16q-23 0 -39 16t-16 39z" />
|
||||
<glyph unicode="" d="M-40 375q-13 -95 35 -173q35 -57 94 -89t129 -32q63 0 119 28q33 16 65 40.5t52.5 45.5t59.5 64q40 44 57 61l394 394q35 35 47 84t-3 96q-27 87 -117 104q-20 2 -29 2q-46 0 -78.5 -16.5t-67.5 -51.5l-389 -396l-7 -7l69 -67l377 373q20 22 39 38q23 23 50 23 q38 0 53 -36q16 -39 -20 -75l-547 -547q-52 -52 -125 -52q-55 0 -100 33t-54 96q-5 35 2.5 66t31.5 63t42 50t56 54q24 21 44 41l348 348q52 52 82.5 79.5t84 54t107.5 26.5q25 0 48 -4q95 -17 154 -94.5t51 -175.5q-7 -101 -98 -192l-252 -249l-253 -256l7 -7l69 -60 l517 511q67 67 95 157t11 183q-16 87 -67 154t-130 103q-69 33 -152 33q-107 0 -197 -55q-40 -24 -111 -95l-512 -512q-68 -68 -81 -163z" />
|
||||
<glyph unicode="" d="M80 784q0 131 98.5 229.5t230.5 98.5q143 0 241 -129q103 129 246 129q129 0 226 -98.5t97 -229.5q0 -46 -17.5 -91t-61 -99t-77 -89.5t-104.5 -105.5q-197 -191 -293 -322l-17 -23l-16 23q-43 58 -100 122.5t-92 99.5t-101 100q-71 70 -104.5 105.5t-77 89.5t-61 99 t-17.5 91zM250 784q0 -27 30.5 -70t61.5 -75.5t95 -94.5l22 -22q93 -90 190 -201q82 92 195 203l12 12q64 62 97.5 97t64.5 79t31 72q0 71 -48 119.5t-105 48.5q-74 0 -132 -83l-118 -171l-114 174q-51 80 -123 80q-60 0 -109.5 -49.5t-49.5 -118.5z" />
|
||||
<glyph unicode="" d="M57 353q0 -95 66 -159l141 -142q68 -66 159 -66q93 0 159 66l283 283q66 66 66 159t-66 159l-141 141q-8 9 -19 17l-105 -105l212 -212l-389 -389l-247 248l95 95l-18 18q-46 45 -75 101l-55 -55q-66 -66 -66 -159zM269 706q0 -93 66 -159l141 -141q7 -7 19 -17l105 105 l-212 212l389 389l247 -247l-95 -96l18 -17q47 -49 77 -100l29 29q35 35 62.5 88t27.5 96q0 93 -66 159l-141 141q-66 66 -159 66q-95 0 -159 -66l-283 -283q-66 -64 -66 -159z" />
|
||||
<glyph unicode="" d="M200 100v953q0 21 30 46t81 48t129 38t163 15t162 -15t127 -38t79 -48t29 -46v-953q0 -41 -29.5 -70.5t-70.5 -29.5h-600q-41 0 -70.5 29.5t-29.5 70.5zM300 300h600v700h-600v-700zM496 150q0 -43 30.5 -73.5t73.5 -30.5t73.5 30.5t30.5 73.5t-30.5 73.5t-73.5 30.5 t-73.5 -30.5t-30.5 -73.5z" />
|
||||
<glyph unicode="" d="M0 0l303 380l207 208l-210 212h300l267 279l-35 36q-15 14 -15 35t15 35q14 15 35 15t35 -15l283 -282q15 -15 15 -36t-15 -35q-14 -15 -35 -15t-35 15l-36 35l-279 -267v-300l-212 210l-208 -207z" />
|
||||
<glyph unicode="" d="M295 433h139q5 -77 48.5 -126.5t117.5 -64.5v335q-6 1 -15.5 4t-11.5 3q-46 14 -79 26.5t-72 36t-62.5 52t-40 72.5t-16.5 99q0 92 44 159.5t109 101t144 40.5v78h100v-79q38 -4 72.5 -13.5t75.5 -31.5t71 -53.5t51.5 -84t24.5 -118.5h-159q-8 72 -35 109.5t-101 50.5 v-307l64 -14q34 -7 64 -16.5t70 -31.5t67.5 -52t47.5 -80.5t20 -112.5q0 -139 -89 -224t-244 -96v-77h-100v78q-152 17 -237 104q-40 40 -52.5 93.5t-15.5 139.5zM466 889q0 -29 8 -51t16.5 -34t29.5 -22.5t31 -13.5t38 -10q7 -2 11 -3v274q-61 -8 -97.5 -37.5t-36.5 -102.5 zM700 237q170 18 170 151q0 64 -44 99.5t-126 60.5v-311z" />
|
||||
<glyph unicode="" d="M100 600v100h166q-24 49 -44 104q-10 26 -14.5 55.5t-3 72.5t25 90t68.5 87q97 88 263 88q129 0 230 -89t101 -208h-153q0 52 -34 89.5t-74 51.5t-76 14q-37 0 -79 -14.5t-62 -35.5q-41 -44 -41 -101q0 -28 16.5 -69.5t28 -62.5t41.5 -72h241v-100h-197q8 -50 -2.5 -115 t-31.5 -94q-41 -59 -99 -113q35 11 84 18t70 7q33 1 103 -16t103 -17q76 0 136 30l50 -147q-41 -25 -80.5 -36.5t-59 -13t-61.5 -1.5q-23 0 -128 33t-155 29q-39 -4 -82 -17t-66 -25l-24 -11l-55 145l16.5 11t15.5 10t13.5 9.5t14.5 12t14.5 14t17.5 18.5q48 55 54 126.5 t-30 142.5h-221z" />
|
||||
<glyph unicode="" d="M2 300l298 -300l298 300h-198v900h-200v-900h-198zM602 900l298 300l298 -300h-198v-900h-200v900h-198z" />
|
||||
<glyph unicode="" d="M2 300h198v900h200v-900h198l-298 -300zM700 0v200h100v-100h200v-100h-300zM700 400v100h300v-200h-99v-100h-100v100h99v100h-200zM700 700v500h300v-500h-100v100h-100v-100h-100zM801 900h100v200h-100v-200z" />
|
||||
<glyph unicode="" d="M2 300h198v900h200v-900h198l-298 -300zM700 0v500h300v-500h-100v100h-100v-100h-100zM700 700v200h100v-100h200v-100h-300zM700 1100v100h300v-200h-99v-100h-100v100h99v100h-200zM801 200h100v200h-100v-200z" />
|
||||
<glyph unicode="" d="M2 300l298 -300l298 300h-198v900h-200v-900h-198zM800 100v400h300v-500h-100v100h-200zM800 1100v100h200v-500h-100v400h-100zM901 200h100v200h-100v-200z" />
|
||||
<glyph unicode="" d="M2 300l298 -300l298 300h-198v900h-200v-900h-198zM800 400v100h200v-500h-100v400h-100zM800 800v400h300v-500h-100v100h-200zM901 900h100v200h-100v-200z" />
|
||||
<glyph unicode="" d="M2 300l298 -300l298 300h-198v900h-200v-900h-198zM700 100v200h500v-200h-500zM700 400v200h400v-200h-400zM700 700v200h300v-200h-300zM700 1000v200h200v-200h-200z" />
|
||||
<glyph unicode="" d="M2 300l298 -300l298 300h-198v900h-200v-900h-198zM700 100v200h200v-200h-200zM700 400v200h300v-200h-300zM700 700v200h400v-200h-400zM700 1000v200h500v-200h-500z" />
|
||||
<glyph unicode="" d="M0 400v300q0 165 117.5 282.5t282.5 117.5h300q162 0 281 -118.5t119 -281.5v-300q0 -165 -118.5 -282.5t-281.5 -117.5h-300q-165 0 -282.5 117.5t-117.5 282.5zM200 300q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5v500q0 41 -29.5 70.5t-70.5 29.5 h-500q-41 0 -70.5 -29.5t-29.5 -70.5v-500z" />
|
||||
<glyph unicode="" d="M0 400v300q0 163 119 281.5t281 118.5h300q165 0 282.5 -117.5t117.5 -282.5v-300q0 -165 -117.5 -282.5t-282.5 -117.5h-300q-163 0 -281.5 117.5t-118.5 282.5zM200 300q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5v500q0 41 -29.5 70.5t-70.5 29.5 h-500q-41 0 -70.5 -29.5t-29.5 -70.5v-500zM400 300l333 250l-333 250v-500z" />
|
||||
<glyph unicode="" d="M0 400v300q0 163 117.5 281.5t282.5 118.5h300q163 0 281.5 -119t118.5 -281v-300q0 -165 -117.5 -282.5t-282.5 -117.5h-300q-165 0 -282.5 117.5t-117.5 282.5zM200 300q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5v500q0 41 -29.5 70.5t-70.5 29.5 h-500q-41 0 -70.5 -29.5t-29.5 -70.5v-500zM300 700l250 -333l250 333h-500z" />
|
||||
<glyph unicode="" d="M0 400v300q0 165 117.5 282.5t282.5 117.5h300q165 0 282.5 -117.5t117.5 -282.5v-300q0 -162 -118.5 -281t-281.5 -119h-300q-165 0 -282.5 118.5t-117.5 281.5zM200 300q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5v500q0 41 -29.5 70.5t-70.5 29.5 h-500q-41 0 -70.5 -29.5t-29.5 -70.5v-500zM300 400h500l-250 333z" />
|
||||
<glyph unicode="" d="M0 400v300h300v200l400 -350l-400 -350v200h-300zM500 0v200h500q41 0 70.5 29.5t29.5 70.5v500q0 41 -29.5 70.5t-70.5 29.5h-500v200h400q165 0 282.5 -117.5t117.5 -282.5v-300q0 -165 -117.5 -282.5t-282.5 -117.5h-400z" />
|
||||
<glyph unicode="" d="M217 519q8 -19 31 -19h302q-155 -438 -160 -458q-5 -21 4 -32l9 -8h9q14 0 26 15q11 13 274.5 321.5t264.5 308.5q14 19 5 36q-8 17 -31 17l-301 -1q1 4 78 219.5t79 227.5q2 15 -5 27l-9 9h-9q-15 0 -25 -16q-4 -6 -98 -111.5t-228.5 -257t-209.5 -237.5q-16 -19 -6 -41 z" />
|
||||
<glyph unicode="" d="M0 400q0 -165 117.5 -282.5t282.5 -117.5h300q47 0 100 15v185h-500q-41 0 -70.5 29.5t-29.5 70.5v500q0 41 29.5 70.5t70.5 29.5h500v185q-14 4 -114 7.5t-193 5.5l-93 2q-165 0 -282.5 -117.5t-117.5 -282.5v-300zM600 400v300h300v200l400 -350l-400 -350v200h-300z " />
|
||||
<glyph unicode="" d="M0 400q0 -165 117.5 -282.5t282.5 -117.5h300q163 0 281.5 117.5t118.5 282.5v98l-78 73l-122 -123v-148q0 -41 -29.5 -70.5t-70.5 -29.5h-500q-41 0 -70.5 29.5t-29.5 70.5v500q0 41 29.5 70.5t70.5 29.5h156l118 122l-74 78h-100q-165 0 -282.5 -117.5t-117.5 -282.5 v-300zM496 709l353 342l-149 149h500v-500l-149 149l-342 -353z" />
|
||||
<glyph unicode="" d="M4 600q0 162 80 299t217 217t299 80t299 -80t217 -217t80 -299t-80 -299t-217 -217t-299 -80t-299 80t-217 217t-80 299zM186 600q0 -171 121.5 -292.5t292.5 -121.5t292.5 121.5t121.5 292.5t-121.5 292.5t-292.5 121.5t-292.5 -121.5t-121.5 -292.5zM406 600 q0 80 57 137t137 57t137 -57t57 -137t-57 -137t-137 -57t-137 57t-57 137z" />
|
||||
<glyph unicode="" d="M0 0v275q0 11 7 18t18 7h1048q11 0 19 -7.5t8 -17.5v-275h-1100zM100 800l445 -500l450 500h-295v400h-300v-400h-300zM900 150h100v50h-100v-50z" />
|
||||
<glyph unicode="" d="M0 0v275q0 11 7 18t18 7h1048q11 0 19 -7.5t8 -17.5v-275h-1100zM100 700h300v-300h300v300h295l-445 500zM900 150h100v50h-100v-50z" />
|
||||
<glyph unicode="" d="M0 0v275q0 11 7 18t18 7h1048q11 0 19 -7.5t8 -17.5v-275h-1100zM100 705l305 -305l596 596l-154 155l-442 -442l-150 151zM900 150h100v50h-100v-50z" />
|
||||
<glyph unicode="" d="M0 0v275q0 11 7 18t18 7h1048q11 0 19 -7.5t8 -17.5v-275h-1100zM100 988l97 -98l212 213l-97 97zM200 400l697 1l3 699l-250 -239l-149 149l-212 -212l149 -149zM900 150h100v50h-100v-50z" />
|
||||
<glyph unicode="" d="M0 0v275q0 11 7 18t18 7h1048q11 0 19 -7.5t8 -17.5v-275h-1100zM200 612l212 -212l98 97l-213 212zM300 1200l239 -250l-149 -149l212 -212l149 148l249 -237l-1 697zM900 150h100v50h-100v-50z" />
|
||||
<glyph unicode="" d="M23 415l1177 784v-1079l-475 272l-310 -393v416h-392zM494 210l672 938l-672 -712v-226z" />
|
||||
<glyph unicode="" d="M0 150v1000q0 20 14.5 35t35.5 15h250v-300h500v300h100l200 -200v-850q0 -21 -15 -35.5t-35 -14.5h-150v400h-700v-400h-150q-21 0 -35.5 14.5t-14.5 35.5zM600 1000h100v200h-100v-200z" />
|
||||
<glyph unicode="" d="M0 150v1000q0 20 14.5 35t35.5 15h250v-300h500v300h100l200 -200v-218l-276 -275l-120 120l-126 -127h-378v-400h-150q-21 0 -35.5 14.5t-14.5 35.5zM581 306l123 123l120 -120l353 352l123 -123l-475 -476zM600 1000h100v200h-100v-200z" />
|
||||
<glyph unicode="" d="M0 150v1000q0 20 14.5 35t35.5 15h250v-300h500v300h100l200 -200v-269l-103 -103l-170 170l-298 -298h-329v-400h-150q-21 0 -35.5 14.5t-14.5 35.5zM600 1000h100v200h-100v-200zM700 133l170 170l-170 170l127 127l170 -170l170 170l127 -128l-170 -169l170 -170 l-127 -127l-170 170l-170 -170z" />
|
||||
<glyph unicode="" d="M0 150v1000q0 20 14.5 35t35.5 15h250v-300h500v300h100l200 -200v-300h-400v-200h-500v-400h-150q-21 0 -35.5 14.5t-14.5 35.5zM600 300l300 -300l300 300h-200v300h-200v-300h-200zM600 1000v200h100v-200h-100z" />
|
||||
<glyph unicode="" d="M0 150v1000q0 20 14.5 35t35.5 15h250v-300h500v300h100l200 -200v-402l-200 200l-298 -298h-402v-400h-150q-21 0 -35.5 14.5t-14.5 35.5zM600 300h200v-300h200v300h200l-300 300zM600 1000v200h100v-200h-100z" />
|
||||
<glyph unicode="" d="M0 250q0 -21 14.5 -35.5t35.5 -14.5h1100q21 0 35.5 14.5t14.5 35.5v550h-1200v-550zM0 900h1200v150q0 21 -14.5 35.5t-35.5 14.5h-1100q-21 0 -35.5 -14.5t-14.5 -35.5v-150zM100 300v200h400v-200h-400z" />
|
||||
<glyph unicode="" d="M0 400l300 298v-198h400v-200h-400v-198zM100 800v200h100v-200h-100zM300 800v200h100v-200h-100zM500 800v200h400v198l300 -298l-300 -298v198h-400zM800 300v200h100v-200h-100zM1000 300h100v200h-100v-200z" />
|
||||
<glyph unicode="" d="M100 700v400l50 100l50 -100v-300h100v300l50 100l50 -100v-300h100v300l50 100l50 -100v-400l-100 -203v-447q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v447zM800 597q0 -29 10.5 -55.5t25 -43t29 -28.5t25.5 -18l10 -5v-397q0 -21 14.5 -35.5 t35.5 -14.5h200q21 0 35.5 14.5t14.5 35.5v1106q0 31 -18 40.5t-44 -7.5l-276 -116q-25 -17 -43.5 -51.5t-18.5 -65.5v-359z" />
|
||||
<glyph unicode="" d="M100 0h400v56q-75 0 -87.5 6t-12.5 44v394h500v-394q0 -38 -12.5 -44t-87.5 -6v-56h400v56q-4 0 -11 0.5t-24 3t-30 7t-24 15t-11 24.5v888q0 22 25 34.5t50 13.5l25 2v56h-400v-56q75 0 87.5 -6t12.5 -44v-394h-500v394q0 38 12.5 44t87.5 6v56h-400v-56q4 0 11 -0.5 t24 -3t30 -7t24 -15t11 -24.5v-888q0 -22 -25 -34.5t-50 -13.5l-25 -2v-56z" />
|
||||
<glyph unicode="" d="M0 300q0 -41 29.5 -70.5t70.5 -29.5h300q41 0 70.5 29.5t29.5 70.5v500q0 41 -29.5 70.5t-70.5 29.5h-300q-41 0 -70.5 -29.5t-29.5 -70.5v-500zM100 100h400l200 200h105l295 98v-298h-425l-100 -100h-375zM100 300v200h300v-200h-300zM100 600v200h300v-200h-300z M100 1000h400l200 -200v-98l295 98h105v200h-425l-100 100h-375zM700 402v163l400 133v-163z" />
|
||||
<glyph unicode="" d="M16.5 974.5q0.5 -21.5 16 -90t46.5 -140t104 -177.5t175 -208q103 -103 207.5 -176t180 -103.5t137 -47t92.5 -16.5l31 1l163 162q17 18 13.5 41t-22.5 37l-192 136q-19 14 -45 12t-42 -19l-118 -118q-142 101 -268 227t-227 268l118 118q17 17 20 41.5t-11 44.5 l-139 194q-14 19 -36.5 22t-40.5 -14l-162 -162q-1 -11 -0.5 -32.5z" />
|
||||
<glyph unicode="" d="M0 50v212q0 20 10.5 45.5t24.5 39.5l365 303v50q0 4 1 10.5t12 22.5t30 28.5t60 23t97 10.5t97 -10t60 -23.5t30 -27.5t12 -24l1 -10v-50l365 -303q14 -14 24.5 -39.5t10.5 -45.5v-212q0 -21 -14.5 -35.5t-35.5 -14.5h-1100q-20 0 -35 14.5t-15 35.5zM0 712 q0 -21 14.5 -33.5t34.5 -8.5l202 33q20 4 34.5 21t14.5 38v146q141 24 300 24t300 -24v-146q0 -21 14.5 -38t34.5 -21l202 -33q20 -4 34.5 8.5t14.5 33.5v200q-6 8 -19 20.5t-63 45t-112 57t-171 45t-235 20.5q-92 0 -175 -10.5t-141.5 -27t-108.5 -36.5t-81.5 -40 t-53.5 -36.5t-31 -27.5l-9 -10v-200z" />
|
||||
<glyph unicode="" d="M100 0v100h1100v-100h-1100zM175 200h950l-125 150v250l100 100v400h-100v-200h-100v200h-200v-200h-100v200h-200v-200h-100v200h-100v-400l100 -100v-250z" />
|
||||
<glyph unicode="" d="M100 0h300v400q0 41 -29.5 70.5t-70.5 29.5h-100q-41 0 -70.5 -29.5t-29.5 -70.5v-400zM500 0v1000q0 41 29.5 70.5t70.5 29.5h100q41 0 70.5 -29.5t29.5 -70.5v-1000h-300zM900 0v700q0 41 29.5 70.5t70.5 29.5h100q41 0 70.5 -29.5t29.5 -70.5v-700h-300z" />
|
||||
<glyph unicode="" d="M-100 300v500q0 124 88 212t212 88h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212zM100 200h900v700h-900v-700zM200 300h300v300h-200v100h200v100h-300v-300h200v-100h-200v-100zM600 300h200v100h100v300h-100v100h-200v-500 zM700 400v300h100v-300h-100z" />
|
||||
<glyph unicode="" d="M-100 300v500q0 124 88 212t212 88h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212zM100 200h900v700h-900v-700zM200 300h100v200h100v-200h100v500h-100v-200h-100v200h-100v-500zM600 300h200v100h100v300h-100v100h-200v-500 zM700 400v300h100v-300h-100z" />
|
||||
<glyph unicode="" d="M-100 300v500q0 124 88 212t212 88h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212zM100 200h900v700h-900v-700zM200 300h300v100h-200v300h200v100h-300v-500zM600 300h300v100h-200v300h200v100h-300v-500z" />
|
||||
<glyph unicode="" d="M-100 300v500q0 124 88 212t212 88h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212zM100 200h900v700h-900v-700zM200 550l300 -150v300zM600 400l300 150l-300 150v-300z" />
|
||||
<glyph unicode="" d="M-100 300v500q0 124 88 212t212 88h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212zM100 200h900v700h-900v-700zM200 300v500h700v-500h-700zM300 400h130q41 0 68 42t27 107t-28.5 108t-66.5 43h-130v-300zM575 549 q0 -65 27 -107t68 -42h130v300h-130q-38 0 -66.5 -43t-28.5 -108z" />
|
||||
<glyph unicode="" d="M-100 300v500q0 124 88 212t212 88h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212zM100 200h900v700h-900v-700zM200 300h300v300h-200v100h200v100h-300v-300h200v-100h-200v-100zM601 300h100v100h-100v-100zM700 700h100 v-400h100v500h-200v-100z" />
|
||||
<glyph unicode="" d="M-100 300v500q0 124 88 212t212 88h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212zM100 200h900v700h-900v-700zM200 300h300v400h-200v100h-100v-500zM301 400v200h100v-200h-100zM601 300h100v100h-100v-100zM700 700h100 v-400h100v500h-200v-100z" />
|
||||
<glyph unicode="" d="M-100 300v500q0 124 88 212t212 88h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212zM100 200h900v700h-900v-700zM200 700v100h300v-300h-99v-100h-100v100h99v200h-200zM201 300v100h100v-100h-100zM601 300v100h100v-100h-100z M700 700v100h200v-500h-100v400h-100z" />
|
||||
<glyph unicode="" d="M4 600q0 162 80 299t217 217t299 80t299 -80t217 -217t80 -299t-80 -299t-217 -217t-299 -80t-299 80t-217 217t-80 299zM186 600q0 -171 121.5 -292.5t292.5 -121.5t292.5 121.5t121.5 292.5t-121.5 292.5t-292.5 121.5t-292.5 -121.5t-121.5 -292.5zM400 500v200 l100 100h300v-100h-300v-200h300v-100h-300z" />
|
||||
<glyph unicode="" d="M0 600q0 162 80 299t217 217t299 80t299 -80t217 -217t80 -299t-80 -299t-217 -217t-299 -80t-299 80t-217 217t-80 299zM182 600q0 -171 121.5 -292.5t292.5 -121.5t292.5 121.5t121.5 292.5t-121.5 292.5t-292.5 121.5t-292.5 -121.5t-121.5 -292.5zM400 400v400h300 l100 -100v-100h-100v100h-200v-100h200v-100h-200v-100h-100zM700 400v100h100v-100h-100z" />
|
||||
<glyph unicode="" d="M-14 494q0 -80 56.5 -137t135.5 -57h222v300h400v-300h128q120 0 205 86.5t85 207.5t-85 207t-205 86q-46 0 -90 -14q-44 97 -134.5 156.5t-200.5 59.5q-152 0 -260 -107.5t-108 -260.5q0 -25 2 -37q-66 -14 -108.5 -67.5t-42.5 -122.5zM300 200h200v300h200v-300h200 l-300 -300z" />
|
||||
<glyph unicode="" d="M-14 494q0 -80 56.5 -137t135.5 -57h8l414 414l403 -403q94 26 154.5 104.5t60.5 178.5q0 120 -85 206.5t-205 86.5q-46 0 -90 -14q-44 97 -134.5 156.5t-200.5 59.5q-152 0 -260 -107.5t-108 -260.5q0 -25 2 -37q-66 -14 -108.5 -67.5t-42.5 -122.5zM300 200l300 300 l300 -300h-200v-300h-200v300h-200z" />
|
||||
<glyph unicode="" d="M100 200h400v-155l-75 -45h350l-75 45v155h400l-270 300h170l-270 300h170l-300 333l-300 -333h170l-270 -300h170z" />
|
||||
<glyph unicode="" d="M121 700q0 -53 28.5 -97t75.5 -65q-4 -16 -4 -38q0 -74 52.5 -126.5t126.5 -52.5q56 0 100 30v-306l-75 -45h350l-75 45v306q46 -30 100 -30q74 0 126.5 52.5t52.5 126.5q0 24 -9 55q50 32 79.5 83t29.5 112q0 90 -61.5 155.5t-150.5 71.5q-26 89 -99.5 145.5 t-167.5 56.5q-116 0 -197.5 -81.5t-81.5 -197.5q0 -4 1 -11.5t1 -11.5q-14 2 -23 2q-74 0 -126.5 -52.5t-52.5 -126.5z" />
|
||||
</font>
|
||||
</defs></svg>
|
After Width: | Height: | Size: 62 KiB |
BIN
public/fonts/glyphicons-halflings-regular.ttf
Normal file
BIN
public/fonts/glyphicons-halflings-regular.woff
Normal file
BIN
public/fonts/glyphicons/glyphicons-1-glass.png
Normal file
After Width: | Height: | Size: 1.4 KiB |