main
Jpl-hub 2 months ago
parent 11b4385f66
commit b47576ee7b

55
.gitignore vendored

@ -0,0 +1,55 @@
# Node/Vite
node_modules/
dist/
.vite/
*.log
# Python
__pycache__/
*.pyc
*.pyo
*.pyd
*.env
*.venv
env/
venv/
ENV/
env.bak/
venv.bak/
# IDE/编辑器
.idea/
.vscode/
*.sublime-workspace
*.sublime-project
# OS
.DS_Store
Thumbs.db
# 环境/依赖
.env
.env.*
*.local
# 依赖锁文件(如不需要提交)
# pnpm-lock.yaml
# Python 数据文件
*.sqlite3
*.db
*.sqlite
# 其他
npm-debug.log*
yarn-debug.log*
yarn-error.log*
package-lock.json
# 个人配置
*.iml
# 备份文件
*~
*.swp
*.bak

@ -0,0 +1,131 @@
# 开源生态数据分析可视化平台项目
这是一个前后端分离的开源生态数据分析可视化平台,前端使用 Vue 3 + Vite后端使用 Python (FastAPI)。
## 环境配置
### 1. 环境变量设置
项目使用环境变量管理敏感信息。请按以下步骤配置:
1. 复制环境变量示例文件:
```bash
cp env.example .env
```
2. 编辑 `.env` 文件,填入你的实际配置:
```
# 数据库配置
DB_HOST=localhost
DB_PORT=3306
DB_USER=your_db_user
DB_PASSWORD=your_db_password
DB_NAME=your_db_name
# JWT配置
JWT_SECRET_KEY=your_secret_key_here
JWT_ALGORITHM=HS256
JWT_EXPIRE_HOURS=30
# GitHub API配置
GITHUB_TOKEN=your_github_token_here
# 前端API配置
VITE_API_BASE_URL=http://127.0.0.1:7878
VITE_UPLOAD_URL_DEV=http://127.0.0.1:7777/api/Upload
VITE_UPLOAD_URL_PROD=https://your-domain.com/upload
VITE_REDIRECT_URL=https://your-redirect-url.com
```
### 2. 后端安装
1. 创建虚拟环境:
```bash
python -m venv venv
```
2. 激活虚拟环境:
- Windows: `venv\Scripts\activate`
- Linux/Mac: `source venv/bin/activate`
3. 安装依赖:
```bash
cd server
pip install -r req.txt
```
4. 运行后端服务:
```bash
python main.py
```
### 3. 前端安装
1. 安装依赖:
```bash
pnpm install
```
2. 运行开发服务器:
```bash
pnpm dev
```
3. 构建生产版本:
```bash
pnpm build
```
## 注意事项
- **不要将 `.env` 文件提交到版本控制系统**
- 确保所有敏感信息都通过环境变量管理
- 生产环境部署时,请使用强密码和安全的密钥
## 项目结构
```
dash_board/
├── server/ # 后端代码
├── src/ # 前端源码
├── venv/ # Python虚拟环境
├── .env # 环境变量文件(不提交)
├── env.example # 环境变量示例
└── README.md # 本文件
```
## 本地部署与运行
1. **安装依赖**
前端:进入 `src` 目录,执行
```sh
pnpm install
```
后端:进入 `server` 目录,执行
```sh
pip install -r req.txt
```
3. **启动数据库服务**
创建名为 `dashboard` 的数据库,可替换成自己密码
4. **生成测试数据**
运行后端提供的数据生成脚本,批量生成测试数据
5. **启动后端服务**
`server` 目录下运行:
```sh
uvicorn server.main:fast_app --reload --port 7878
```
6. **启动前端服务**
`src` 目录下运行:
```sh
pnpm dev
7. **访问系统**
打开浏览器访问前端地址 [http://localhost:7777](http://localhost:7777) 即可使用。
如有问题请及时沟通!
架构链接:[Deepwiki](https://deepwiki.com/Jpl-hub/diggboard) 您的任何感兴趣的开源项目也可以用[Deepwiki](https://deepwiki.com)

@ -0,0 +1,14 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<link rel="icon" href="/favicon.ico">
<meta name="viewport" content="user-scalable=no">
<meta name="color-scheme" content="light dark">
<title></title>
</head>
<body>
<div id="app"></div>
<script type="module" src="/src/main.js"></script>
</body>
</html>

@ -0,0 +1,31 @@
{
"name": "toupiao_client",
"version": "0.0.0",
"private": true,
"scripts": {
"dev": "vite",
"build": "vite build",
"preview": "vite preview"
},
"dependencies": {
"@element-plus/icons-vue": "^2.3.1",
"@vueuse/core": "^13.1.0",
"axios": "^1.6.0",
"crypto-js": "^4.2.0",
"dayjs": "^1.11.11",
"echarts": "^5.6.0",
"element-plus": "^2.9.7",
"lodash": "^4.17.21",
"pinia": "^2.1.6",
"pinia-plugin-persistedstate": "^3.2.0",
"vanilla-tilt": "^1.8.1",
"vue": "^3.3.4",
"vue-router": "^4.2.4"
},
"devDependencies": {
"@vitejs/plugin-vue": "^5.2.3",
"less": "^4.2.0",
"sass": "^1.69.7",
"vite": "6.2.5"
}
}

File diff suppressed because it is too large Load Diff

@ -0,0 +1,10 @@
import datetime
import requests
data = {
'start_datetime':'2025-04-09T15:30:00Z',
# 'end_datetime':'2025-04-09T15:30:00Z',
}
res = requests.post('http://127.0.0.1:9898/api/index', json=data)
print(res.json())

@ -0,0 +1,30 @@
import os
from dotenv import load_dotenv
from sqlalchemy import URL, create_engine
from sqlalchemy.ext.asyncio import create_async_engine, AsyncSession
from sqlalchemy.orm import declarative_base, sessionmaker
# 加载环境变量
load_dotenv()
# 从环境变量获取数据库配置
DB_USER = os.getenv('DB_USER', 'root')
DB_PASSWORD = os.getenv('DB_PASSWORD', 'abc123')
DB_HOST = os.getenv('DB_HOST', 'localhost')
DB_PORT = os.getenv('DB_PORT', '3306')
DB_NAME = os.getenv('DB_NAME', 'dashboard')
uri = f'mysql+pymysql://{DB_USER}:{DB_PASSWORD}@{DB_HOST}:{DB_PORT}/{DB_NAME}'
engine = create_engine(uri)
session = sessionmaker(bind=engine)
async_uri = f'mysql+aiomysql://{DB_USER}:{DB_PASSWORD}@{DB_HOST}:{DB_PORT}/{DB_NAME}'
async_engine = create_async_engine(async_uri)
asyncSession = sessionmaker(
bind=async_engine,
class_=AsyncSession,
expire_on_commit=False
)
Base = declarative_base()

@ -0,0 +1,126 @@
import os
import datetime
import json
import requests
from jose.constants import ALGORITHMS
from jose import jwt
from dotenv import load_dotenv
from server.conf import session
from server.models import User
# 加载环境变量
load_dotenv()
class Const:
# 从环境变量获取数据库配置
DB_USER = os.getenv('DB_USER', 'root')
DB_PASSWORD = os.getenv('DB_PASSWORD', 'abc123')
DB_HOST = os.getenv('DB_HOST', 'localhost')
DB_PORT = os.getenv('DB_PORT', '3306')
DB_NAME = os.getenv('DB_NAME', 'dashboard')
uri = f'mysql+aiomysql://{DB_USER}:{DB_PASSWORD}@{DB_HOST}:{DB_PORT}/{DB_NAME}'
# JWT配置
LOGIN_DELTA = datetime.timedelta(hours=int(os.getenv('JWT_EXPIRE_HOURS', '30')))
HEADER_PREFIX = 'Bearer '
ALGORITHM = os.getenv('JWT_ALGORITHM', ALGORITHMS.HS256)
SECRET_KEY = os.getenv('JWT_SECRET_KEY', 'django-insecure-l%mqno@^^-3+k-@7hh$_98r4nwe*qhv9!0bd6n)h(#vv=date2')
cache = {}
def create_token(payload, delta=datetime.timedelta(days=10)):
claims = payload.copy()
expire = datetime.datetime.now() + delta
# 添加失效时间
claims.update({"exp": expire})
token = jwt.encode(claims, Const.SECRET_KEY, algorithm=Const.ALGORITHM)
return token
def verify_token(token):
"""
验证token
:param token:
:return: 返回用户信息
"""
user = None
try:
token = token.removeprefix(Const.HEADER_PREFIX)
payload = jwt.decode(token, Const.SECRET_KEY, algorithms=Const.ALGORITHM)
with session() as db:
user = db.query(User).filter_by(userId=payload['userId'], flag=True).first()
return user
except:
pass
return user
def bad_res(msg='', code=400, ):
return {'code': code, 'message': msg}
def success_res(data=None, msg=None, code=0):
return {'code': code, 'message': msg, 'data': data}
def generate_year_month_array():
start_year = 2015
start_month = 1
now = datetime.datetime.now()
end_year = now.year
end_month = now.month
arr = []
for year in range(start_year, end_year + 1):
arr.append(year)
# 生成年份-月份数组
for year in range(start_year, end_year + 1):
month_start = start_month if year == start_year else 1
month_end = end_month if year == end_year else 12
for month in range(month_start, month_end + 1):
arr.append(f"{year}-{month:02d}")
return arr
class OpenDigger:
def __init__(self):
self.url = 'https://api.github.com/users/{username}/repos?per_page=100&page=1'
self.headers = {
'Authorization': f'Bearer {os.getenv("GITHUB_TOKEN", "")}'
}
def get_user_repos(self, username, platform='github'):
res = {
'total': 0,
'avatar': 0,
}
try:
if platform == 'github':
url = self.url.format(username=username)
all_repos = []
page = 1
while True:
resJ = requests.get(url, headers=self.headers, params={"per_page": 100, "page": page})
repos = resJ.json()
if not repos:
break
all_repos.extend(repos)
page += 1
print(len(all_repos))
total_stars = sum(repo["stargazers_count"] for repo in all_repos)
total_forks = sum(repo["forks_count"] for repo in all_repos)
print(total_stars)
print(total_forks)
else:
return {}
except:
return {}
openDigger = OpenDigger()

@ -0,0 +1,47 @@
import asyncio
import uvicorn
from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware
from starlette.middleware import Middleware
from starlette.middleware.base import BaseHTTPMiddleware
from starlette.requests import Request
from starlette.responses import JSONResponse,StreamingResponse
from starlette.staticfiles import StaticFiles
from server.const import verify_token
from server.urls import router
import os
class CustomMiddleware(BaseHTTPMiddleware):
async def dispatch(self, request: Request, call_next):
# 排除 docs 和 redoc 路径
if request.url.path in ['/docs', '/redoc', '/openapi.json']:
return await call_next(request)
if request.url.path.split('/')[-1][0].islower() and 'static' not in request.url.path:
token = request.headers.get('token')
user = verify_token(token)
request.state.user = user
if user is None:
return JSONResponse({'code': 401, 'message': '请重新登录'})
response = await call_next(request)
return response
middlewares = [
Middleware(CORSMiddleware, allow_origins=['*']),
Middleware(CustomMiddleware)
]
fast_app = FastAPI(middleware=middlewares)
fast_app.include_router(router, prefix='/api')
static_dir = os.path.join(os.path.dirname(__file__), "static")
fast_app.mount("/static", StaticFiles(directory=static_dir), name="static")
if __name__ == '__main__':
port = 7878
uvicorn.run('main:fast_app', port=port, reload=True)

@ -0,0 +1,203 @@
import json
from sqlalchemy import Column, String, Integer, BOOLEAN, Float, ForeignKey, select
from sqlalchemy.orm import relationship
from server.conf import Base, engine
url_prefix = f'http://127.0.0.1:7878/'
class Role(Base):
"""角色表"""
__tablename__ = 'role'
roleId = Column(Integer, primary_key=True)
roleName = Column(String(200), nullable=True)
flag = Column(BOOLEAN, default=True, nullable=True)
operateArr = Column(String(500), nullable=True)
user = relationship("User", back_populates="role")
operate = [
{'label': '后台管理', 'value': 'admin'},
{'label': '用户管理', 'value': 'userManager'},
{'label': '添加用户', 'value': 'addUser'},
{'label': '修改用户', 'value': 'updateUser'},
{'label': '删除用户', 'value': 'deleteUser'},
{'label': '角色管理', 'value': 'roleManager'},
{'label': '添加角色', 'value': 'addRole'},
{'label': '删除角色', 'value': 'deleteRole'},
{'label': '修改角色', 'value': 'updateRole'},
]
def to_dict(self):
tmp = []
if self.operateArr:
for i in self.operateArr.split(','):
for jj in self.operate:
if jj['value'] == i:
tmp.append(jj['label'])
break
ops = ', '.join(tmp)
else:
ops = ''
return {
'pk': self.roleId,
'roleName': self.roleName,
'operateArr': self.operateArr.split(',') if self.operateArr else [],
'auth': ops,
}
class User(Base):
"""用户表"""
__tablename__ = 'user'
userId = Column(Integer, primary_key=True)
username = Column(String(200), nullable=False)
avatar_url = Column(String(200), nullable=True)
password = Column(String(200), nullable=True)
roleId = Column(Integer, ForeignKey('role.roleId', ondelete='SET NULL'), nullable=True)
role = relationship("Role", back_populates="user")
flag = Column(BOOLEAN, nullable=True, default=True)
def to_dict(self):
return {
'pk': self.userId,
'username': self.username,
'avatar_url': self.avatar_url,
'roleId': self.roleId,
'roleName': self.role.roleName if self.role else '',
}
class Project(Base):
"""项目表"""
__tablename__ = 'project'
projectId = Column(Integer, primary_key=True)
name = Column(String(200), nullable=True)
platform = Column(String(200), nullable=True)
openRank = Column(Float, nullable=True)
activity = Column(Float, nullable=True)
stars = Column(Integer, nullable=True)
attention = Column(Integer, nullable=True)
technical_fork = Column(Integer, nullable=True)
proj_data = relationship("ProjData", back_populates="project")
user_proj_map = relationship("UserProjMap", back_populates="project")
class ProjData(Base):
"""项目数据表"""
__tablename__ = 'proj_data'
index = Column(Integer, primary_key=True)
projectId = Column(Integer, ForeignKey('project.projectId', ondelete='SET NULL'), nullable=False)
project = relationship("Project", back_populates="proj_data")
label = Column(String(200), nullable=True)
tt = Column(Integer, nullable=True)
ttType = Column(String(200), nullable=True, comment='时间类型y年m月')
openRank = Column(Float, nullable=True)
activity = Column(Float, nullable=True)
stars = Column(Integer, nullable=True)
attention = Column(Integer, nullable=True)
technical_fork = Column(Integer, nullable=True)
async def to_dict(self):
return {
'pk': self.projectId,
'label': self.label,
'item': 1,
'tt': self.tt,
'openRank': self.openRank,
'activity': self.activity,
'stars': self.stars,
'attention': self.attention,
'technical_fork': self.technical_fork,
}
class DevUser(Base):
"""开发者表"""
__tablename__ = 'devuser'
devUserId = Column(Integer, primary_key=True)
name = Column(String(200), nullable=True)
avatar_url = Column(String(500), nullable=True, comment='fork数')
platform = Column(String(200), nullable=True)
openRank = Column(Float, nullable=True)
activity = Column(Float, nullable=True)
repos = Column(Integer, nullable=True, comment='仓库总数')
stars = Column(Integer, nullable=True, comment='星标数')
technical_fork = Column(Integer, nullable=True, comment='被fork数')
forks = Column(Integer, nullable=True, comment='fork总数')
followers = Column(Integer, nullable=True, comment='关注人数')
following = Column(Integer, nullable=True, comment='粉丝人数')
template_count = Column(Integer, nullable=True, comment='模板数')
issues_count = Column(Integer, nullable=True, comment='模板数')
dev_user_data = relationship("DevUserData", back_populates="dev_user")
user_devuser_map = relationship("UserDevUserMap", back_populates="dev_user")
class DevUserData(Base):
"""开发者数据表"""
__tablename__ = 'devuser_data'
index = Column(Integer, primary_key=True)
devUserId = Column(Integer, ForeignKey('devuser.devUserId', ondelete='SET NULL'), nullable=False)
dev_user = relationship("DevUser", back_populates="dev_user_data")
label = Column(String(200), nullable=True)
tt = Column(Integer, nullable=True)
ttType = Column(String(200), nullable=True, comment='时间类型y年m月')
openRank = Column(Float, nullable=True)
activity = Column(Float, nullable=True)
async def to_dict(self):
return {
'index': self.index,
'pk': self.devUserId,
'avatar_url': url_prefix + (self.dev_user.avatar_url or ''),
'home': 'https://github.com/' + self.dev_user.name,
'item': 2,
'label': self.label,
'tt': self.tt,
'openRank': self.openRank,
'activity': self.activity,
}
class UserProjMap(Base):
"""用户项目映射"""
__tablename__ = 'user_proj_map'
userId = Column(Integer, ForeignKey('user.userId', ondelete='SET NULL'), primary_key=True,nullable=False)
projectId = Column(Integer, ForeignKey('project.projectId', ondelete='SET NULL'), primary_key=True,nullable=False)
project = relationship("Project", back_populates="user_proj_map")
flag = Column(BOOLEAN, nullable=True, default=True)
def to_dict(self):
return {
'pk': self.projectId,
'label': self.project.name,
'item': 1,
'openRank': self.project.openRank,
'activity': self.project.activity,
'stars': self.project.stars,
'attention': self.project.attention,
'technical_fork': self.project.technical_fork,
}
class UserDevUserMap(Base):
"""用户开发者映射"""
__tablename__ = 'user_devuser_map'
userId = Column(Integer, ForeignKey('user.userId', ondelete='SET NULL'), primary_key=True,nullable=False)
devUserId = Column(Integer, ForeignKey('devuser.devUserId',ondelete='SET NULL'), primary_key=True,nullable=False)
dev_user = relationship("DevUser", back_populates="user_devuser_map")
flag = Column(BOOLEAN, nullable=True, default=True)
def to_dict(self):
return {
'pk': self.devUserId,
'avatar_url': url_prefix + (self.dev_user.avatar_url or ''),
'item': 2,
'label': self.dev_user.name,
'openRank': self.dev_user.openRank,
'activity': self.dev_user.activity,
}
Base.metadata.create_all(engine)

File diff suppressed because it is too large Load Diff

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 104 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 58 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 50 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 77 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 81 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 66 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 118 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 209 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 326 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 45 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 203 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 104 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 122 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 45 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 192 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 97 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 260 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 96 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 164 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 84 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 125 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 44 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 212 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 921 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 157 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 155 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 50 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 39 KiB

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

Loading…
Cancel
Save