6 Commits

Author SHA1 Message Date
Eason010212
622070db51 Admin features update 2023-02-22 22:26:49 +08:00
Eason010212
0c20eefdc2 Fix timing broadcast 2023-02-19 21:33:15 +08:00
Eason010212
68b1ca15f2 0218 2023-02-18 12:00:14 +08:00
Eason010212
4ca5553815 1.9.5 2023-02-04 12:08:14 +08:00
Eason010212
be042c4a60 0113-2 2023-01-13 12:27:33 +08:00
Eason010212
9dcb1f5e50 0113 2023-01-13 12:24:07 +08:00
602 changed files with 578 additions and 190 deletions

View File

@@ -4,13 +4,13 @@
"HTTPS_PRIVATE_PEM": "./certs/private.pem",
"HTTPS_CRT_FILE": "./certs/file.crt",
"MAX_PROJECT_NUM_PER_USER": 20,
"MAX_MESSAGE_PER_USER": 1000,
"MAX_MESSAGE_PER_SECOND": 5,
"ALLOW_REGISTER": true,
"ALLOW_HOOK": true,
"OFFLINE_MODE": true,
"BAIDU_MAP_AK": "",
"BAIDU_MAP_SERVER_AK": "",
"ADMIN_USERNAME":"admin",
"ADMIN_PASSWORD":"public",
"MAX_MESSAGE_COUNT":1000,
"MIN_PUBLISH_INTERVAL": 200
"ADMIN_PASSWORD":"public"
}

View File

@@ -229,6 +229,8 @@ input[type="search"]{
.prj_blk:hover{
box-shadow: 1px 1px 40px lightgray;
transform: scale(1.05);
transition: all 0.2s;
box-shadow: #4e73df 0px 0px 60px;
}
.laydiv{
@@ -272,7 +274,7 @@ input[type="search"]{
margin:6px 5px;
user-select: none;
background-color:white;
width:250px;height:50px;border-radius:25px;border:solid #4e73df 2px;display:flex;align-items:center;justify-content:space-between
width:250px;height:50px;border:solid #4e73df 2px;border-radius:10px;display:flex;align-items:center;justify-content:space-between
}
.widget_div div{
display:flex;align-items:center;justify-content:center;margin:10px
@@ -464,10 +466,7 @@ input{
opacity: .6;
}
}
.ui-dialog-content{
padding: 0px !important;
overflow: visible !important;
}
padding:0 !important;
overflow: visible !important;
}

File diff suppressed because one or more lines are too long

View File

@@ -40,7 +40,6 @@
<script src="js/flatpkr.js"></script>
<script src="js/dataTables.bootstrap4.min.js"></script>
<script src="js/tools.js"></script>
<script>var MAX_MESSAGE_COUNT = '<%=configs['MAX_MESSAGE_COUNT']%>'</script>
<script src="js/data.js?v=6"></script>
</head>
<body id="page-top" class="sidebar-toggled">

147
src/ejs/index.ejs Normal file
View File

@@ -0,0 +1,147 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<meta name="description" content="">
<meta name="author" content="">
<title>爱上米思齐MixIO</title>
<link rel="shortcut icon" href="img/shortcut.png"/>
<link href="css/font-awesome.min.css" rel="stylesheet">
<link href="css/nunito.css" rel="stylesheet">
<link href="css/sb-admin-2.min.css?v=2" rel="stylesheet">
<link rel="stylesheet" href="css/muuri.css?v=2">
<link rel="preload" href="fonts/fontawesome-webfont.ttf" as="font" type="font/woff" crossorigin="anonymous">
<script src="js/jquery.min.js"></script>
<script src="js/lang.js?v=5"></script>
<script src="js/lang2.js?v=5"></script>
<script src="js/tools.js?v=10"></script>
<script src="js/login.js?v=22"></script>
</head>
<body id="body" class="bg-gradient-light" style="height:100vh">
<style>
.translate{
width:50px;
padding: 0;
margin-left:5px;
}
</style>
<div style="position:fixed;right:10px;top:10px;display:flex;align-items:center;justify-content:center">
<i class="fa fa-globe" style="color:#4e73df;margin-right:5px;font-size:2rem"></i>
<button class="translate btn btn-secondary" id="zh">简</button>
<button class="translate btn btn-secondary" id="tw">繁</button>
<button class="translate btn btn-secondary" id="en">EN</button>
</div>
<div style="height:calc(100vh - 40px);display:flex;align-items:center;justify-content:center">
<div class="container" style="opacity: 0.9;margin-top:20px">
<!-- Outer Row -->
<div class="row justify-content-center">
<div class="col-xl-10 col-lg-12 col-md-9">
<div id="cd" class="card o-hidden border-0 shadow-lg my-5" style="margin-top:0!important">
<div class="card-body p-0">
<!-- Nested Row within Card Body -->
<div class="row">
<div class="d-md-none" style="display: flex;width:100%;align-items: center;justify-content: center;margin-top:25px;margin-bottom:-0.5rem">
<img src="img/shortcut.png" style="width:40px" alt="">
<span style="font-size:30px;font-weight:bold;color:#4e73df;margin-left:10px">MixIO</span>
</div>
<div id="lg_img" class="col-lg-6 d-none d-lg-block bg-login-image" style="margin-right:-0.375rem"></div>
<div class="col-lg-6">
<div class="p-5">
<div style="margin-left:-1rem;margin-right:-1rem;margin-top:-1.5rem;display:flex;margin-bottom:1.5rem;justify-content:center">
<a class="btn btn-lg btn-primary btn-circle" style="border:solid #d1d3e2 1px;margin-right:.5rem" id="switch1" onclick="mixioLogin()">
<i class="fa fa-user-o"></i>
</a>
<a class="btn btn-lg btn-light btn-circle" style="border:solid #d1d3e2 1px;margin-left:.5rem;margin-right:.5rem" id="switch2" onclick="mixlyLogin()">
<i class="fa fa-key"></i>
</a>
<a class="btn btn-lg btn-light btn-circle" style="border:solid #d1d3e2 1px;margin-left:.5rem" id="switch3" onclick="projLogin()">
<i class="fa fa-cube"></i>
</a>
</div>
<form class="user" id="form_login" method="post">
<div class="form-group">
<input type="email" class="form-control form-control-user lang" key="EMAIL"
aria-describedby="emailHelp" name="userName" style="min-width:0;text-align:center;"
placeholder="请输入电子邮箱地址">
</div>
<div class="form-group" id="ref1">
<input type="password" name="password" class="form-control form-control-user lang" key="PASSWORD" style="min-width:0;text-align:center;"
placeholder="请输入密码">
</div>
<div style="display:flex;align-items: center;justify-content: center;">
<button type="submit" class="btn btn-primary btn-icon-split"><span class="icon"><i class="fa fa-arrow-right" style="margin-top:5px;width:1rem;height:1rem"></i></span><span class="text lang" key="LOGIN" style="margin-top:1px">登录MixIO</span></button>
</div>
</form>
<form class="user" id="form_login_2" method="post" hidden>
<div class="form-group">
<input class="form-control form-control-user lang" key="MIXLYKEY"
aria-describedby="emailHelp" name="userName" style="min-width:0;text-align:center;"
placeholder="请输入Mixly Key">
</div>
<div style="display:flex;align-items: center;justify-content: center;">
<button type="submit" class="btn btn-primary btn-icon-split"><span class="icon"><i class="fa fa-arrow-right" style="margin-top:5px;width:1rem;height:1rem"></i></span><span class="text lang" style="margin-top:1px" key="LOGIN2">登录MixIO</span></button>
</div>
</form>
<div class="user" id="form_login_3" hidden>
<div class="form-group">
<input class="form-control form-control-user lang" key="VFCODE"
aria-describedby="emailHelp" id="vfCode" name="vfCode" style="min-width:0;text-align:center;font-size: .8rem;border-radius: 10rem;padding: 1.5rem 1rem;"
placeholder="请输入项目授权码">
</div>
<div style="display:flex;align-items: center;justify-content: center;">
<button id="submit3" onclick="guestLogin()" class="btn btn-primary btn-icon-split"><span class="icon"><i class="fa fa-arrow-right" style="margin-top:5px;width:1rem;height:1rem"></i></span><span class="text lang" style="margin-top:1px" key="BROWSE">访问MixIO项目</span></button>
</div>
</div>
<hr>
<div style="display:flex;flex-wrap:wrap;align-items:center;justify-content:center;margin-bottom:-1.5rem">
<div class="text-center" style="margin-bottom:10px;padding-left: 5px;padding-right: 5px;" id="reset_text">
<a class="btn btn-light btn-icon-split" href="forgot"><span class="icon"><i class="fa fa-refresh" style="margin-top:5px;width:1rem;height:1rem"></i></span><span class="text lang" style="margin-top:1px" key="RESET">重置密码</span></a>
</div>
<div class="text-center" style="margin-bottom:10px;padding-left: 5px;padding-right: 5px;" id="register_text">
<a class="btn btn-light btn-icon-split" href="register" ><span class="icon"><i class="fa fa-flag" style="margin-top:5px;width:1rem;height:1rem"></i></span><span class="text lang" style="margin-top:1px" key="SIGNUP">注册账号</span></a>
</div>
<div class="text-center" style="margin-bottom:10px;padding-left: 5px;padding-right: 5px;" id="documentation_text">
<a class="btn btn-light btn-icon-split" href="documentation/"><span class="icon"><i class="fa fa-compass" style="margin-top:5px;width:1rem;height:1rem"></i></span><span class="text lang" style="margin-top:1px" key="GUIDE">入门指南</span></a>
</div>
<div class="text-center" style="margin-bottom:10px;padding-left: 5px;padding-right: 5px;" id="android_text">
<a class="btn btn-light btn-icon-split" href="android"><span class="icon"><i class="fa fa-android" style="margin-top:5px;width:1rem;height:1rem"></i></span><span class="text lang" style="margin-top:1px" key="ANDROID">安卓微端</span></a>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<footer id="footer" style="height:40px;font-size:0.8rem;text-align:center">
<% if (main) { %>
<a href="https://beian.miit.gov.cn/">京ICP备13037033号-1</a>&nbsp;
<% } %>
<% if (mixly) { %>
<a href="/mixly">Mixly Lite</a>&nbsp;
<% } %>
<a href="https://gitee.com/mixly2/mixio" class="lang" key="OPENSRC"></a>&nbsp;
<a id="admin" class="lang" key="ADMINDASH"></a>
&nbsp;MixIO © Mixly Team
</footer>
<!-- Bootstrap core JavaScript-->
</body>
</html>

View File

@@ -128,6 +128,21 @@
<div class="card shadow" style="margin-top:1.5rem;border-radius:10px">
<div class="card-body" style="display: flex;align-items: center;justify-content: center;flex-direction: column;">
<table>
<tr>
<td>
<span>管理员账号:</span>
</td>
<td>
<input type="text" id="ADMIN_USERNAME">
</td>
</tr>
<tr>
<td>
<span>管理员密码:</span>
</td>
<td>
<input type="password" id="ADMIN_PASSWORD">
</td>
<tr>
<td>
<span>离线模式:</span>
@@ -197,7 +212,15 @@
<span>单用户最大消息数:</span>
</td>
<td>
<input type="text" id="MAX_MESSAGE_COUNT">
<input type="text" id="MAX_MESSAGE_PER_USER">
</td>
</tr>
<tr>
<td>
<span>消息频率限制(次/秒):</span>
</td>
<td>
<input type="text" id="MAX_MESSAGE_PER_SECOND">
</td>
</tr>
<tr>
@@ -251,7 +274,7 @@
<td style="min-width:100px">
消息量
</td>
<td style="min-width:100px">
<td style="min-width:300px">
执行操作
</td>
</thead>
@@ -293,6 +316,73 @@
}
})
}
var clearProject = function(userName){
$.get('clearMessage',{
"userName":userName
},function(res){
if(res == 1)
{
$.get('clearProject',{
"userName":userName
},function(res){
if(res == 1)
{
showtext("操作成功!")
setTimeout(function(){
window.location.href = window.location.href
},1000)
}
else
{
showtext("操作失败")
}
})
}
else
{
showtext("操作失败")
}
})
}
var clearUser = function(userName){
$.get('clearMessage',{
"userName":userName
},function(res){
if(res == 1)
{
$.get('clearProject',{
"userName":userName
},function(res){
if(res == 1)
{
$.get('clearUser',{
"userName":userName
},function(res){
if(res == 1)
{
showtext("操作成功!")
setTimeout(function(){
window.location.href = window.location.href
},1000)
}
else
{
showtext("操作失败")
}
})
}
else
{
showtext("操作失败")
}
})
}
else
{
showtext("操作失败")
}
})
}
$("#time").html(new Date().toLocaleTimeString())
setInterval(() => {
$("#time").html(new Date().toLocaleTimeString())
@@ -302,12 +392,15 @@
var HTTPS_PRIVATE_PEM = "<%=configs["HTTPS_PRIVATE_PEM"]%>"
var HTTPS_CRT_FILE = "<%=configs["HTTPS_CRT_FILE"]%>"
var MAX_PROJECT_NUM_PER_USER = "<%=configs["MAX_PROJECT_NUM_PER_USER"]%>"
var MAX_MESSAGE_COUNT = "<%=configs["MAX_MESSAGE_COUNT"]%>"
var MAX_MESSAGE_PER_USER = "<%=configs["MAX_MESSAGE_PER_USER"]%>"
var MAX_MESSAGE_PER_SECOND= "<%=configs["MAX_MESSAGE_PER_SECOND"]%>"
var ALLOW_REGISTER = <%=configs["ALLOW_REGISTER"]%>
var ALLOW_HOOK = <%=configs["ALLOW_HOOK"]%>
var OFFLINE_MODE = <%=configs["OFFLINE_MODE"]%>
var BAIDU_MAP_AK = "<%=configs["BAIDU_MAP_AK"]%>"
var BAIDU_MAP_SERVER_AK = "<%=configs["BAIDU_MAP_SERVER_AK"]%>"
var ADMIN_USERNAME = "<%=configs["ADMIN_USERNAME"]%>"
var ADMIN_PASSWORD = "<%=configs["ADMIN_PASSWORD"]%>"
$("#OFFLINE_MODE").bind('change',function(){
if($("#OFFLINE_MODE").prop("checked"))
{
@@ -331,7 +424,10 @@
$("#BAIDU_MAP_AK").val(BAIDU_MAP_AK)
$("#BAIDU_MAP_SERVER_AK").val(BAIDU_MAP_SERVER_AK)
$("#MAX_PROJECT_NUM_PER_USER").val(MAX_PROJECT_NUM_PER_USER)
$("#MAX_MESSAGE_COUNT").val(MAX_MESSAGE_COUNT)
$("#MAX_MESSAGE_PER_USER").val(MAX_MESSAGE_PER_USER)
$("#MAX_MESSAGE_PER_SECOND").val(MAX_MESSAGE_PER_SECOND)
$("#ADMIN_USERNAME").val(ADMIN_USERNAME)
$("#ADMIN_PASSWORD").val(ADMIN_PASSWORD)
if($("#OFFLINE_MODE").prop("checked"))
{
$("#BAIDU_MAP_AK").attr("disabled","true")
@@ -354,12 +450,15 @@
configs["HTTPS_PRIVATE_PEM"] = $("#HTTPS_PRIVATE_PEM").val()
configs["HTTPS_CRT_FILE"] = $("#HTTPS_CRT_FILE").val()
configs["MAX_PROJECT_NUM_PER_USER"] = parseInt($("#MAX_PROJECT_NUM_PER_USER").val())
configs["MAX_MESSAGE_PER_USER"] = parseInt($("#MAX_MESSAGE_PER_USER").val())
configs["MAX_MESSAGE_PER_SECOND"] = parseInt($("#MAX_MESSAGE_PER_SECOND").val())
configs["ALLOW_REGISTER"] = $("#ALLOW_REGISTER").prop("checked")
configs["ALLOW_HOOK"] = $("#ALLOW_HOOK").prop("checked")
configs["OFFLINE_MODE"] = $("#OFFLINE_MODE").prop("checked")
configs["BAIDU_MAP_AK"] = $("#BAIDU_MAP_AK").val()
configs["BAIDU_MAP_SERVER_AK"] = $("#BAIDU_MAP_SERVER_AK").val()
configs["MAX_MESSAGE_COUNT"] = parseInt($("#MAX_MESSAGE_COUNT").val())
configs["ADMIN_USERNAME"] = $("#ADMIN_USERNAME").val()
configs["ADMIN_PASSWORD"] = $("#ADMIN_PASSWORD").val()
$.get('/saveAndRestart',{'configs':JSON.stringify(configs,null,2)},function(res){
if(res=="1")
{

View File

@@ -8,9 +8,11 @@ function get_data() {
$.getJSON('getData', {
}, function(res) {
$("#prj_num").html(res['count'] + " / " + MAX_MESSAGE_COUNT)
var max = res["max"]
$("#prj_num").html(res['count'] + " / " + max)
$("#prj_num_bar").attr("aria-valuenow", res['count'])
$("#prj_num_bar").css("width", (res['count'] * 100 / MAX_MESSAGE_COUNT) + "%")
$("#prj_num_bar").attr("aria-valuemax", max)
$("#prj_num_bar").css("width", (res['count'] * 100 / max) + "%")
globalRows = res["rows"]
init_table(res["rows"])
sync_chart()

View File

@@ -97,7 +97,7 @@ var JSLang = {
"dataMap": "数据地图",
"dashboard": "仪表盘",
"weather": "实时气象仪",
"text": "- 文本 -",
"text": "- 媒体 -",
"keyboard": "文本输入",
"screen": "文本显示屏",
"decorate": "- 装饰 -",
@@ -289,7 +289,7 @@ var JSLang = {
"dataMap": "數據地圖",
"dashboard": "儀表盤",
"weather": "實時氣象儀",
"text": "- 文本 -",
"text": "- 媒體 -",
"keyboard": "文本輸入",
"screen": "文本顯示屏",
"decorate": "- 裝飾 -",
@@ -477,7 +477,7 @@ var JSLang = {
"dataMap": "Map",
"dashboard": "Dashboard",
"weather": "Weather",
"text": "- Text -",
"text": "- Media -",
"keyboard": "Input",
"screen": "Text Screen",
"decorate": "- Decoration -",
@@ -639,7 +639,7 @@ var arrLang = {
"TOPIC": "主题",
"MESSAGE": "消息",
"TIME": "时间",
"DATAMANAGE": "数据",
"DATAMANAGE": "数据管理",
"ADMIN": "管理",
"BASICADMIN": "基础设置",
"USERADMIN": "批量注册",
@@ -657,13 +657,13 @@ var arrLang = {
"GUIDE": "入门指南",
"ANDROID": "安卓微端",
"MANAGE": "管理",
"PROJECTSMANAGE": "项目",
"STORAGEMANAGE": "存储",
"SHAREMANAGE": "共享",
"PROJECTSMANAGE": "项目管理",
"STORAGEMANAGE": "数据管理",
"SHAREMANAGE": "共享管理",
"SETTINGS": "设置",
"LOGOUT": "退出登录",
"IMPORT": "导入用户项目",
"EXPORT": "导出用户项目",
"IMPORT": "导入项目",
"EXPORT": "导出项目",
"CONNECTINGSERVER": "正在连接服务器",
"MANAGECOUNT": "管理项目数",
"OFFLINECOUNT": "离线消息数",

View File

@@ -2,7 +2,7 @@ $(function(){
$.getJSON("queryData",function(res){
for(var i = 0;i<=res.length-1;i = i+1)
{
$("#tbody").append("<tr><td>"+res[i]["username"]+"</td><td>"+res[i]["projects"]+"</td><td>"+res[i]["messages"]+"</td><td>"+ "<a class='btn btn-primary' style='cursor:pointer;' onclick=\"clearMessage('"+res[i]["username"]+"')\" >清空消息</a>"+"</td></tr>")
$("#tbody").append("<tr><td>"+res[i]["username"]+"</td><td>"+res[i]["projects"]+"</td><td>"+res[i]["messages"]+"</td><td>"+ "<a class='btn btn-primary' style='cursor:pointer;margin-right:5px' onclick=\"clearMessage('"+res[i]["username"]+"')\" >清空消息</a>"+"<a class='btn btn-primary' style='cursor:pointer;margin-right:5px' onclick=\"clearProject('"+res[i]["username"]+"')\" >清空项目</a>"+"<a class='btn btn-primary' style='cursor:pointer;' onclick=\"clearUser('"+res[i]["username"]+"')\" >删除用户</a>"+"</td></tr>")
}
datatable = $("#table").DataTable({
"order": [[ 2, "desc" ]],

View File

@@ -23,15 +23,17 @@ $(function() {
save_layout();
}
};
if (Math.random() > 0.75) {
/*
if (Math.random() > 0.6) {
var d = dialog({
title: '限时推广',
content: '<div style="width:250px">MixIO正处于不断迭代的阶段有稳定应用、持续改进、私有部署MixIO平台的一线教师或个人开发者欢迎加QQ群742608657以向我们提供建议并得到技术支持谢谢</div>',
cancelValue: '确定',
content: '<div style="width:250px">尊敬的MixIO用户,您好!<br>现邀请您参与《MixIO平台技术接受度调查》共计10题预计用时5-8分钟。您的作答数据将被用于科学研究和平台改进设计感谢您的参与 <a href="https://wj.qq.com/s2/11118283/89a9/">点击此处进入调查</a></div>',
cancelValue: '我知道了',
cancel: function() {}
});
d.showModal();
}
*/
})
const DATA_MODE = 0;
@@ -893,6 +895,25 @@ function view_project(projectName, projectType) {
} else if (topic1.split('/').length == 3 && !isMixly) {
var tp = stringendecoder.encodeHtml(topic1.split('/')[2])
var ms = message1.toString()
if(isJSON(ms))
{
var msJSON = JSON.parse(ms)
if(("clientid" in msJSON)&&("long" in msJSON)&&("lat" in msJSON)&&("message" in msJSON))
{
var newJSON = {}
var clientid = msJSON["clientid"]
newJSON[clientid+"-"+"long"] = msJSON["long"]
newJSON[clientid+"-"+"lat"] = msJSON["lat"]
var msg = msJSON["message"]
if(typeof msg == "string")
msg = JSON.parse(msg)
for(item of msg)
{
newJSON[clientid+"-"+item["label"]] = item["value"]
}
ms = JSON.stringify(newJSON)
}
}
if (globalTableProjectInfo.received[tp]) {
globalTableProjectInfo.received[tp].unshift({
'时间': timeStamp2String(),
@@ -917,6 +938,25 @@ function view_project(projectName, projectType) {
} else if (topic1.split('/').length == 4 && isMixly) {
var tp = stringendecoder.encodeHtml(topic1.split('/')[3])
var ms = message1.toString()
if(isJSON(ms))
{
var msJSON = JSON.parse(ms)
if(("clientid" in msJSON)&&("long" in msJSON)&&("lat" in msJSON)&&("message" in msJSON))
{
var newJSON = {}
var clientid = msJSON["clientid"]
newJSON[clientid+"-"+"long"] = msJSON["long"]
newJSON[clientid+"-"+"lat"] = msJSON["lat"]
var msg = msJSON["message"]
if(typeof msg == "string")
msg = JSON.parse(msg)
for(item of msg)
{
newJSON[clientid+"-"+item["label"]] = item["value"]
}
ms = JSON.stringify(newJSON)
}
}
if (globalTableProjectInfo.received[tp]) {
globalTableProjectInfo.received[tp].unshift({
'时间': timeStamp2String(),
@@ -1074,6 +1114,19 @@ function view_project(projectName, projectType) {
grid2.append(topicOuterDiv2)
var dataset = []
chart = echarts.init(rightCardBodyDiv[0])
chart.setOption({
tooltip:{
trigger: "axis",
formatter: function(params){
let str = '';
params.forEach((item, idx) => {
str += "<div style='margin:0;display:flex;justify-content:space-between;align-items:center'><div>" + `${item.marker}${item.seriesName}:&nbsp;&nbsp;&nbsp;</div><b>${chart.getOption().series[item.seriesIndex].oriData[item.dataIndex]}</b>` + "</div>"
})
return str
}
}
})
init_table = function() {
var fields = ["时间"]
for (dataitem in dataset) {
@@ -1168,7 +1221,8 @@ function view_project(projectName, projectType) {
type: 'line',
name: tableFields[tableField].name,
data: [],
connectNulls: true,
oriData:[],
connectNulls: true
})
}
for (dataitem in dataset) {
@@ -1179,18 +1233,27 @@ function view_project(projectName, projectType) {
var seryName = series[sery].name
if (seryName != JSLang[lang].time)
if (json_parsed[seryName] || json_parsed[seryName] === 0) {
series[sery].data.unshift(json_parsed[seryName])
series[sery].data.unshift(parseFloat(json_parsed[seryName]))
series[sery].oriData.unshift(json_parsed[seryName])
} else
{
series[sery].data.unshift(NaN)
series[sery].oriData.unshift("-")
}
}
} else {
for (sery in series) {
var seryName = series[sery].name
if (seryName != JSLang[lang].time)
if (seryName == JSLang[lang].value)
series[sery].data.unshift(dataset[dataitem][JSLang[lang].value])
if (seryName == JSLang[lang].value){
series[sery].data.unshift(parseFloat(dataset[dataitem][JSLang[lang].value]))
series[sery].oriData.unshift(dataset[dataitem][JSLang[lang].value])
}
else
{
series[sery].data.unshift(NaN)
series[sery].oriData.unshift("-")
}
}
}
}
@@ -1203,9 +1266,19 @@ function view_project(projectName, projectType) {
xAxis: xAxis,
yAxis: yAxis,
series: series,
tooltip: {
trigger: 'axis'
}
tooltip:{
trigger: "axis",
formatter: function(params){
let str = '';
params.forEach((item, idx) => {
str += "<div style='margin:0;display:flex;justify-content:space-between;align-items:center'><div>" + `${item.marker}${item.seriesName}:&nbsp;&nbsp;&nbsp;</div><b>${chart.getOption().series[item.seriesIndex].oriData[item.dataIndex]}</b>` + "</div>"
})
return str
}
}
})
sync_export()
}
@@ -1218,6 +1291,7 @@ function view_project(projectName, projectType) {
var bottomCardTitle = $('<div class="card-header py-3" style="display:flex">')
bottomCard.append(bottomCardTitle)
bottomCardTitle.append($('<h6 class="m-0 font-weight-bold text-primary">' + JSLang[lang].sendString + '</h6>'))
bottomCardTitle.append($('<input type="checkbox" id="sendClear" style="min-width:0px!important;margin-left:20px;margin-right:3px"/><label style="margin:0;padding:0;font-size:small">发送后清空</label>'))
var bottomCardBody = $('<div class="card-body">')
bottomCard.append(bottomCardBody)
var bottomCardBodyDiv = $('<div style="display:flex;align-items:center"></div>')
@@ -1226,7 +1300,9 @@ function view_project(projectName, projectType) {
messageInput.bind('input', function() {
globalTableProjectInfo['toBeSent'] = stringendecoder.encodeHtml(messageInput.val())
})
var messageSendButton = $('<a class="btn btn-primary btn-circle btn-lg" style="margin-left:10px"><i class="fa fa-paper-plane" style="margin-right:3px"></i></a>')
var messageSendButton = $('<a class="btn btn-primary btn-circle btn-lg" style="margin-left:10px"></a>')
var messageSendIcon = $('<i class="fa fa-paper-plane" style="margin-right:3px"></i>')
messageSendButton.append(messageSendIcon)
bottomCardBodyDiv.append(messageInput)
bottomCardBodyDiv.append(messageSendButton)
messageSendButton.click(function() {
@@ -1234,6 +1310,14 @@ function view_project(projectName, projectType) {
publish(stringendecoder.decodeHtml(globalTableProjectInfo.currentTp2), messageInput.val(), true)
else
showtext(JSLang[lang].topicUnset)
messageSendButton.removeClass("btn-primary")
messageSendButton.addClass("btn-success")
setTimeout(function(){
messageSendButton.addClass("btn-primary")
messageSendButton.removeClass("btn-success")
},200)
if($("#sendClear").prop("checked"))
messageInput.val("")
})
var bottomDiv2 = $("<div class='col-xl-6'></div>")
@@ -1449,7 +1533,6 @@ function add_widget() {
widget_list.append(input_keyboard_add)
var output_text_add = $("<div class='widget_div'><div><img src='icons/output_text.svg'><span>" + JSLang[lang].screen + "</span></div><a class='btn btn-success btn-block'><i class='fa fa-plus'></i></a></div>")
widget_list.append(output_text_add)
widget_list.append($("<h5 style='width:100%;text-align:center;margin-bottom:5px;margin-top:10px;color:#4e73df;font-size:1.3rem;font-weight:bold'>" + JSLang[lang].decorate + "</h5>"))
var decorate_text_add = $("<div class='widget_div'><div><img src='icons/decorate_text.svg'><span>" + JSLang[lang].label + "</span></div><a class='btn btn-success btn-block'><i class='fa fa-plus'></i></a></div>")
widget_list.append(decorate_text_add)
var decorate_pic_add = $("<div class='widget_div'><div><img src='icons/decorate_pic.svg'><span>" + JSLang[lang].picture + "</span></div><a class='btn btn-success btn-block'><i class='fa fa-plus'></i></a></div>")

View File

@@ -1198,6 +1198,7 @@ function add_trigger(user_title, user_topic, user_content, user_style) {
var dstMessage = user_content.split("$$$")[6]
var itemdiv = add_block(1, 1, contents, attrs)
var relationLogic = function(message, condition_1, condition_2) {
var condition_2 = parseFloat(condition_2)
if (condition_1 == ">")
return message > condition_2
else if (condition_1 == "≥")
@@ -1215,10 +1216,10 @@ function add_trigger(user_title, user_topic, user_content, user_style) {
}
MixIO.triggers[title.text()] = function() {
MixIO.onMessage(function(topic1, message) {
var message = String(message)
if (topic1 == topic.text()) {
if (conditionRelation == "AND") {
if (relationLogic(message, condition1_1, condition1_2) && relationLogic(message, condition2_1, condition2_2)) {
itemdiv.addClass("triggered")
setTimeout(function() {
itemdiv.removeClass("triggered")
@@ -2265,8 +2266,9 @@ function add_map(user_title, user_topic, user_content, user_style) {
if (topic1.split("/")[(isMixly ? 3 : 2)] == topic.text()) {
var label = (new Date().getHours() + ":" + (new Date().getMinutes() < 10 ? "0" : "") + new Date().getMinutes() + ":" + (new Date().getSeconds() < 10 ? "0" : "") + new Date().getSeconds())
if (isJSON(String(message1)) && JSON.parse(String(message1)).long && JSON.parse(String(message1)).lat && JSON.parse(String(message1)).clientid) {
if (isJSON(String(message1)) && ("long" in JSON.parse(String(message1))) && ("lat" in JSON.parse(String(message1))) && JSON.parse(String(message1)).clientid) {
var jsonMessage = JSON.parse(String(message1))
console.log(jsonMessage)
itemdiv.trigger(MixIO.eventTags.DATA_MAP_CHANGED, [jsonMessage.clientid, jsonMessage.long, jsonMessage.lat, jsonMessage.message])
var newOrNot = true
var markerIndex = -1
@@ -2279,6 +2281,8 @@ function add_map(user_title, user_topic, user_content, user_style) {
}
if (newOrNot) {
var msgstr = ""
if (typeof jsonMessage.message == "string")
jsonMessage.message = JSON.parse(jsonMessage.message)
for (msg in jsonMessage.message) {
msgstr = msgstr + jsonMessage.message[msg].label + ":" + jsonMessage.message[msg].value + "<br>"
}
@@ -2287,6 +2291,7 @@ function add_map(user_title, user_topic, user_content, user_style) {
markerIndex = markers.length
var bubble = create_a_map_bubble(msgstr, label, point)
newMarker.bubble = bubble
console.log(msgstr)
markers.push({
"clientid": jsonMessage.clientid,
"long": jsonMessage.long,
@@ -2310,6 +2315,8 @@ function add_map(user_title, user_topic, user_content, user_style) {
} else {
markers[markerIndex].time = label
var msgstr = ""
if (typeof jsonMessage.message == "string")
jsonMessage.message = JSON.parse(jsonMessage.message)
for (msg in jsonMessage.message) {
msgstr = msgstr + jsonMessage.message[msg].label + ":" + jsonMessage.message[msg].value + "<br>"
}

View File

@@ -17,11 +17,21 @@ const { execPath } = require('process');
var { JSLang, arrLang, lang } = require("./js/lang.js")
const path = require('path');
var VERSION = JSON.parse(fs.readFileSync("../version.json", "utf-8"))["version"]
var configs = fs.readFileSync('./config.json');
var versionPath = "../version.json"
if(!fs.existsSync(versionPath)){
versionPath = path.join(__dirname,"../version.json")
}
var VERSION = JSON.parse(fs.readFileSync(versionPath), "utf-8")["version"]
var configPath = "./config.json"
if(!fs.existsSync(configPath)){
configPath = path.join(__dirname,"./config.json")
}
var configs = fs.readFileSync(configPath);
configs = JSON.parse(configs.toString());
var MAX_MESSAGE_PER_USER = configs["MAX_MESSAGE_COUNT"] ? configs["MAX_MESSAGE_COUNT"] : 1000
var minInterval = configs["MIN_PUBLISH_INTERVAL"] ? configs["MIN_PUBLISH_INTERVAL"] : 100
var MAX_MESSAGE_PER_USER = configs["MAX_MESSAGE_PER_USER"]
var MAX_MESSAGE_PER_SECOND = configs["MAX_MESSAGE_PER_SECOND"]
var serverStatus = true
@@ -210,6 +220,40 @@ async function daemon_start() {
res.send('-1')
})
app.get('/clearProject', function(req, res){
if(req.session.admin){
var userName = req.query.userName
if(userName){
db.run("delete from `project` where userName=?", [userName, ], function(err){
if(err){
console.log(err.message)
res.send('-1')
}else{
res.send('1')
}
})
}else
res.send('-1')
}
})
app.get('/clearUser', function(req, res){
if(req.session.admin){
var userName = req.query.userName
if(userName){
db.run("delete from `user` where username=?", [userName, ], function(err){
if(err){
console.log(err.message)
res.send('-1')
}else{
res.send('1')
}
})
}else
res.send('-1')
}
})
app.post('/adminLogin', function(req, res) {
if (req.body.userName == (configs["ADMIN_USERNAME"] ? configs["ADMIN_USERNAME"] : "admin") && req.body.password == (configs["ADMIN_PASSWORD"] ? configs["ADMIN_PASSWORD"] : "public")) {
req.session.admin = true
@@ -222,9 +266,8 @@ async function daemon_start() {
app.get('/saveAndRestart', async function(req, res) {
newConfig = req.query.configs
if (newConfig) {
fs.writeFileSync('./config.json', newConfig)
fs.writeFileSync(configPath, newConfig)
configs = JSON.parse(newConfig)
MAX_MESSAGE_PER_USER = configs["MAX_MESSAGE_COUNT"] ? configs["MAX_MESSAGE_COUNT"] : 1000
console.log("[INFO] Shutting down MixIO Server...")
await mixio.stop();
serverStatus = false;
@@ -300,12 +343,26 @@ async function daemon_start() {
}
var mixioServer = function() {
var privateKey = fs.readFileSync(configs['HTTPS_PRIVATE_PEM'], 'utf8');
var certificate = fs.readFileSync(configs['HTTPS_CRT_FILE'], 'utf8');
var keyPath = "./certs/private.pem"
if(!fs.existsSync(keyPath))
keyPath = path.join(__dirname,"./certs/private.pem")
var crtPath = "./certs/file.crt"
if(!fs.existsSync(crtPath))
crtPath = path.join(__dirname,"./certs/file.crt")
var privateKey = fs.readFileSync(keyPath, 'utf8');
var certificate = fs.readFileSync(crtPath, 'utf8');
var credentials = {
key: privateKey,
cert: certificate
};
var chainPath = "./certs/chain.crt"
if(!fs.existsSync(chainPath))
chainPath = path.join(__dirname,"./certs/chain.crt")
if(fs.existsSync(chainPath))
credentials['ca'] = fs.readFileSync(chainPath, 'utf8')
aedes = aedesmodule()
const httpServer = http.createServer()
var tasks = {};
@@ -416,6 +473,7 @@ var mixioServer = function() {
server: httpsServer
}, aedes.handle)
aedes.authenticate = function(client, username, password, callback) {
if (username == "MixIO_public" && password == "MixIO_public") {
client.user = "MixIO"
@@ -440,15 +498,19 @@ var mixioServer = function() {
return callback(new Error('wrong topic'))
else
{
/*
if(globalConnectionControl[client.id])
{
if(Date.now() - globalConnectionControl[client.id] < minInterval)
if(Date.now() - globalConnectionControl[client.id][0] > 1000)
{
globalConnectionControl[client.id][0] = Date.now()
globalConnectionControl[client.id][1] = 0
}
else if(globalConnectionControl[client.id][1] > MAX_MESSAGE_PER_SECOND)
{
delete globalConnectionControl[client.id]
return callback(new Error('too fast'))
}
}
*/
callback(null)
}
}
@@ -472,8 +534,15 @@ var mixioServer = function() {
},10000)
aedes.on('publish', function(packet, client) {
if(client)
globalConnectionControl[client.id] = Date.now()
{
if(globalConnectionControl[client.id])
globalConnectionControl[client.id][1] = globalConnectionControl[client.id][1] + 1
else
globalConnectionControl[client.id] = [Date.now(),1]
}
var topic = packet.topic.split('/')
var payload = String(packet.payload)
if (topic.length == 3) {
@@ -485,7 +554,7 @@ var mixioServer = function() {
} else if (configs["ALLOW_HOOK"] && reserveJSON[topic[0]] && topic[0] != "$SYS") {
var userName = topic[0]
var reserveTopic = topic[1] + "/" + topic[2]
var hash = 0, i, chr;
var hash = 0,i, chr;
for (i = 0; i < userName.length; i++) {
chr = userName.charCodeAt(i);
hash = ((hash << 5) - hash) + chr;
@@ -496,33 +565,33 @@ var mixioServer = function() {
if (err) {
console.log(err.message)
} else {
if (row && row["count(*)"] < MAX_MESSAGE_PER_USER - 1) {
if (row && row["count(*)"] < MAX_MESSAGE_PER_USER) {
targetDB.run("insert into 'reserve' (userName, topic, message) values (?,?,?)", [userName, reserveTopic, payload], function(err) {
if (err) {
console.log(err.message)
}
})
} else if (row["count(*)"] >= MAX_MESSAGE_PER_USER - 1) {
targetDB.get("select id from 'reserve' where userName = ? order by id asc limit 1", [userName, ], function(err, row) {
if (err) {
console.log(err.message)
} else {
console.log(row)
if (row && row["id"]) {
targetDB.run("delete from 'reserve' where id = ?", [row["id"], ], function(err) {
if (err) {
console.log(err.message)
} else {
targetDB.run("insert into 'reserve' (userName, topic, message) values (?,?,?)", [userName, reserveTopic, payload], function(err) {
if (err) {
console.log(err.message)
}
})
}
})
} else if (row["count(*)"] >= MAX_MESSAGE_PER_USER) {
targetDB.get("select id from 'reserve' where userName = ? order by id asc limit 1", [userName, ], function(err, row) {
if (err) {
console.log(err.message)
} else {
if (row && row["id"]) {
targetDB.run("delete from 'reserve' where id = ?", [row["id"], ], function(err) {
if (err) {
console.log(err.message)
}
else{
targetDB.run("insert into 'reserve' (userName, topic, message) values (?,?,?)", [userName, reserveTopic, payload], function(err) {
if (err) {
console.log(err.message)
}
})
}
})
}
}
}
})
})
}
}
})
@@ -554,11 +623,21 @@ var mixioServer = function() {
app.set('trust proxy', 1)
app.get('/', function(req, res) {
res.sendFile(__dirname + "/" + "ejs/index.html");
ejs.renderFile(__dirname + '/ejs/index.ejs', {
'main':fs.existsSync(__dirname + "/certs/chain.crt"),
'mixly':fs.existsSync(__dirname + "/mixly")
}, function(err, data) {
res.send(data)
})
})
app.get('/index', function(req, res) {
res.sendFile(__dirname + "/" + "ejs/index.html");
ejs.renderFile(__dirname + '/ejs/index.ejs', {
'main':fs.existsSync(__dirname + "/certs/chain.crt"),
'mixly':fs.existsSync(__dirname + "/mixly")
}, function(err, data) {
res.send(data)
})
})
app.get('/observe', function(req, res) {
@@ -830,7 +909,7 @@ var mixioServer = function() {
app.get('/getData', function(req, res) {
if (req.session.userName) {
var userName = req.session.userName
var hash = 0, i, chr;
var hash = 0,i, chr;
for (i = 0; i < userName.length; i++) {
chr = userName.charCodeAt(i);
hash = ((hash << 5) - hash) + chr;
@@ -843,7 +922,8 @@ var mixioServer = function() {
if (rows) {
res.send({
"count": rows.length,
"rows": rows
"rows": rows,
"max": configs['MAX_MESSAGE_PER_USER']
})
}
}
@@ -1341,7 +1421,10 @@ var mixioServer = function() {
app.get('/time.php', function(req, res) {
var date = new Date()
res.send([date.getFullYear(), date.getMonth() + 1, date.getDate(), date.getHours(), date.getMinutes(), date.getSeconds(), date.getDay()].join(','))
var day = date.getDay() - 1
if (day < 0)
day = 6
res.send([date.getFullYear(), date.getMonth() + 1, date.getDate(), date.getHours(), date.getMinutes(), date.getSeconds(), day].join(','))
})
app.get('/mixio-php/sharekey.php', function(req, res) {
@@ -1387,10 +1470,13 @@ var mixioServer = function() {
}
})
var filterPath = "./reserve/filter.json"
if(!fs.existsSync(filterPath))
filterPath = path.join(__dirname,'./reserve/filter.json')
app.get('/startHook', function(req, res) {
if (req.session.userName) {
reserveJSON[req.session.userName] = true
fs.writeFileSync('./reserve/filter.json', JSON.stringify(reserveJSON, false, 4))
fs.writeFileSync(filterPath, JSON.stringify(reserveJSON, false, 4))
res.send('1')
} else {
res.send('0')
@@ -1400,7 +1486,7 @@ var mixioServer = function() {
app.get('/stopHook', function(req, res) {
if (req.session.userName) {
reserveJSON[req.session.userName] = false
fs.writeFileSync('./reserve/filter.json', JSON.stringify(reserveJSON, false, 4))
fs.writeFileSync(filterPath, JSON.stringify(reserveJSON, false, 4))
res.send('1')
} else {
res.send('0')
@@ -1454,10 +1540,20 @@ var mixioServer = function() {
app.use('/documentation', express.static(path.join(__dirname, 'documentation')));
app.use('/mixly', express.static(path.join(__dirname, 'mixly')));
var mixlyPath = "./mixly"
if(!fs.existsSync(mixlyPath)) {
mixlyPath = path.join(__dirname,'./mixly')
}
if(fs.existsSync(mixlyPath)){
app.use('/mixly', express.static(mixlyPath));
}
var dbPath = "./mixio.db"
if(!fs.existsSync(dbPath)) {
dbPath = path.join(__dirname,'./mixio.db')
}
db = new sqlite3.Database(
'./mixio.db',
dbPath,
sqlite3.OPEN_READWRITE,
function(err) {
if (err) {
@@ -1470,9 +1566,13 @@ var mixioServer = function() {
reserveDBs = []
for (var i = 1; i <= 8; i = i + 1) {
var dbPath = "./reserve/" + i + ".db"
if(!fs.existsSync(dbPath)) {
dbPath = path.join(__dirname,'./reserve/' + i + ".db")
}
reserveDBs.push(
new sqlite3.Database(
'./reserve/' + i + ".db",
dbPath,
sqlite3.OPEN_READWRITE,
function(err) {
if (err)
@@ -1481,8 +1581,7 @@ var mixioServer = function() {
)
)
}
var reserveJSON = JSON.parse(fs.readFileSync('./reserve/filter.json'), "utf8")
var reserveJSON = JSON.parse(fs.readFileSync(filterPath), "utf8")
return new Promise(resolve => {
@@ -1502,14 +1601,19 @@ var mixioServer = function() {
return new Promise(resolve => {
//MQTT
plainServer.close(function() {
console.log("[INFO] Plain MQTT server closed")
//MQTT Websocket
httpServer.close(function() {
console.log("[INFO] WebSocket MQTT server closed")
//MixIO HTTP
httpServer2.close(function() {
console.log("[INFO] MixIO server closed")
//MQTT WebsocketS
httpsServer.close(function() {
console.log("[INFO] WebSocketS MQTT server closed")
//MixIO HTTPS
httpsServer2.close(function() {
console.log("[INFO] MixIO server (HTTPS) closed")
resolve("1")
})
})
@@ -2371,9 +2475,51 @@ var MixIOclosure = function(userName, projectName, projectPass, dataStorage, dom
['user-content', user_content]
]
var itemdiv = add_block(2, 2, contents, attrs)
var sync_weather = function(){
var dsc_code = title.parent().parent().attr('user-content').split(',')[0].split('w')[0]
if(globalWeather[dsc_code] && globalWeather[dsc_code].time && (new Date().getTime() - globalWeather[dsc_code].time) < 600000) {
var result = globalWeather[dsc_code].data
var resJSON = JSON.parse(result)
weather_type = resJSON.result.now.text
temperature = resJSON.result.now.temp
humidity = resJSON.result.now.rh
wind_dir = resJSON.result.now.wind_dir
wind_class = resJSON.result.now.wind_class
district = resJSON.result.location.name
title.parent().parent().attr('user-content', [title.parent().parent().attr('user-content').split(',')[0], district, weather_type, temperature, humidity, wind_dir, wind_class].join(','))
itemdiv.trigger(MixIO.eventTags.WEATHER_SYNCED, [district, weather_type, temperature, humidity, wind_dir, wind_class])
} else {
http.get('http://api.map.baidu.com/weather/v1/?district_id=' + dsc_code + '&data_type=now&ak=' + configs["BAIDU_MAP_SERVER_AK"], function(req2, res2) {
var html = ''
req2.on('data', function(data) {
html += data;
});
req2.on('end', function() {
globalWeather[dsc_code] = {
time: new Date().getTime(),
data: html
}
var result = html
var resJSON = JSON.parse(result)
if(resJSON.result && resJSON.result.now)
{
weather_type = resJSON.result.now.text
temperature = resJSON.result.now.temp
humidity = resJSON.result.now.rh
wind_dir = resJSON.result.now.wind_dir
wind_class = resJSON.result.now.wind_class
district = resJSON.result.location.name
title.parent().parent().attr('user-content', [title.parent().parent().attr('user-content').split(',')[0], district, weather_type, temperature, humidity, wind_dir, wind_class].join(','))
itemdiv.trigger(MixIO.eventTags.WEATHER_SYNCED, [district, weather_type, temperature, humidity, wind_dir, wind_class])
}
});
})
}
}
itemdiv.bind(MixIO.actionTags.WEATHER_SYNC, function() {
sync_weather()
})
sync_weather()
itemdiv.bind(MixIO.actionTags.WEATHER_SEND, function() {
var weather = {
'district': district,
@@ -2383,7 +2529,8 @@ var MixIOclosure = function(userName, projectName, projectPass, dataStorage, dom
'wind_dir': wind_dir,
'wind_class': wind_class
}
publish(topic.text(), JSON.stringify(weather))
MixIO.publish(topic.text(), JSON.stringify(weather))
itemdiv.trigger(MixIO.eventTags.WEATHER_SENT, [district, weather_type, temperature, humidity, wind_dir, wind_class])
})
},
'trigger': function() {

Binary file not shown.

Before

Width:  |  Height:  |  Size: 43 B

View File

@@ -1,9 +0,0 @@
.blocklyTable {
vertical-align: top;
}
.blocklyTree .blocklyActiveDescendant > label,
.blocklyTree .blocklyActiveDescendant > div > label,
.blocklyActiveDescendant > button,
.blocklyActiveDescendant > input {
outline: 2px dotted #00f;
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 207 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 106 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 330 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 561 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 298 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 444 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 45 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 528 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 606 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 94 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 487 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 142 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 676 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 138 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 173 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 97 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 138 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 561 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 811 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 350 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 236 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 599 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 326 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 766 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 198 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.4 KiB

View File

@@ -1,11 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 14 32 18" width="32" height="4" fill="#f20" preserveAspectRatio="none">
<path opacity="0.8" transform="translate(0 0)" d="M2 14 V18 H6 V14z">
<animateTransform attributeName="transform" type="translate" values="0 0; 24 0; 0 0" dur="2s" begin="0" repeatCount="indefinite" keySplines="0.2 0.2 0.4 0.8;0.2 0.2 0.4 0.8" calcMode="spline" />
</path>
<path opacity="0.5" transform="translate(0 0)" d="M0 14 V18 H8 V14z">
<animateTransform attributeName="transform" type="translate" values="0 0; 24 0; 0 0" dur="2s" begin="0.1s" repeatCount="indefinite" keySplines="0.2 0.2 0.4 0.8;0.2 0.2 0.4 0.8" calcMode="spline" />
</path>
<path opacity="0.25" transform="translate(0 0)" d="M0 14 V18 H8 V14z">
<animateTransform attributeName="transform" type="translate" values="0 0; 24 0; 0 0" dur="2s" begin="0.2s" repeatCount="indefinite" keySplines="0.2 0.2 0.4 0.8;0.2 0.2 0.4 0.8" calcMode="spline" />
</path>
</svg>

Before

Width:  |  Height:  |  Size: 980 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 874 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 954 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 576 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 513 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 946 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 729 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 465 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 389 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

Some files were not shown because too many files have changed in this diff Show More