处理机调度图形界面1.0

处理机调度图形界面1.0版本

我一直觉得我效率很低…但还是画出来了,用的PyQt5这个库做的简陋界面,很多功能缺失…算法残疾…

这篇博文以一个算法实例来说一下大体思路

  • 代码
  • 思路
  • 演示
  • 不足
  • 改进
  • 对了我给搞上评论系统辽,虽然这人迹罕至,但俺还是希望阴差阳错戳进来的朋友可以互动一哈

惯例先给代码好吧

以最简单的FCFS算法为例子,总代码量可能有1000行左右

这个算法的代码比较短

from PyQt5.QtWidgets import (QWidget,QLineEdit,QHBoxLayout,QTableWidget,QPushButton,QApplication,QVBoxLayout,QTableWidgetItem,
QCheckBox,QAbstractItemView,QHeaderView,QLabel,QFrame)
from PyQt5 import QtWidgets, QtCore
from PyQt5.QtCore import Qt
from builtins import super, str, range
from PyQt5.QtGui import QFont,QColor
from faker import Factory
import random, sys, operator

# 引入数据结构
# 定义每个进程基本数据结构
class Process:
    def __init__(self, name, arrive_time, serve_time, static_class, ready=False, over=False):
        self.name = name                                    # 进程名称
        self.arrive_time = arrive_time                      # 到达时间
        self.serve_time = serve_time                        # 服务时间
        self.left_serve_time = serve_time                   # 剩余需要服务的时间
        self.finish_time = 0                                # 完成时间
        self.cycling_time = 0                               # 周转时间
        self.w_cycling_time = 0                             # 带权周转时间
        self.response_ratio = 0                             # 响应比
        self.pre_queue = 0                                  # 定义现在所在的队列
        self.pre_queue_tb = 0                               # 目前所在队列的时间片
        self.used_time = 0                                  # 已经使用的时间,也就是(服务时间 - 剩余	                                                                                         服务时间)
        self.ready = ready                                  # 记录就绪状态
        self.over = over                                    # 记录完成状态
        self.static_class = static_class                    # 人为赋予静态优先级

# 现来先服务作业调度算法
def fcfs(processes): # 到达时间小的优先
    sum_cycling_time = 0
    sum_w_cycling_time = 0
    number = len(processes)
    over_list = []
    min_key = 0
    fin_name = []
    name_string = ''
    time_string = '带权周转时间:'
    last_infor = []
    running_time = 0
    while processes:
        min = processes[0].arrive_time
        for i in range(len(processes)):
            if processes[i].arrive_time <= min:
                min = processes[i].arrive_time
                min_key = i
        running_time += processes[min_key].serve_time
        # 计算相关参数
        processes[min_key].cycling_time = running_time - processes[min_key].arrive_time
        processes[min_key].w_cycling_time = processes[min_key].cycling_time / processes[min_key].serve_time
        sum_cycling_time += processes[min_key].cycling_time
        sum_w_cycling_time += processes[min_key].w_cycling_time
        
        over_list.append(processes.pop(min_key))
    for i in range(len(over_list)):
        print(over_list[i].name)
        name_string += (over_list[i].name+'   ')
        fin_name.append(over_list[i].name)
    a_c_time = sum_cycling_time/number
    a_w_c_time = sum_w_cycling_time/number
    print('平均周转时间:' + str(a_c_time))
    print('平均带权周转时间:' + str(a_w_c_time/number))
    time_string += (str(a_c_time) + '    平均带权周转时间:' + str(a_w_c_time))
    last_infor.append(name_string)
    last_infor.append(time_string)
    # return fin_name
    return last_infor

class ui(QWidget):
    def __init__(self):
        super(ui, self).__init__()
        self.setupUI()
        self.id = 1
        self.lines = []
        self.editable = True
        self.des_sort = True
        self.faker = Factory.create()

        self.btn_add.clicked.connect(self.add_line)
        self.btn_del.clicked.connect(self.del_line)
        self.btn_modify.clicked.connect(self.modify_line)
        self.btn_set_middle.clicked.connect(self.middle)
        self.btn_get_info.clicked.connect(self.g_info)

        self.table.cellChanged.connect(self.cellchange)

        global original_processes                # 这里我们定义全局变量 - 原始进程列表,是一个二维列表

    def setupUI(self):
        self.setWindowTitle('数据测试')
        self.resize(720,420)
        
        self.table = QTableWidget(self)

        self.btn_add = QPushButton('增加')
        self.btn_del = QPushButton('删除')
        self.btn_modify = QPushButton('可以编辑')
        self.btn_set_middle = QPushButton('文字居中')
        self.btn_get_info = QPushButton('生成调度序列')
    
        # 弹簧控件
        self.spacerItem = QtWidgets.QSpacerItem(20, 20, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding)
        
        # 垂直布局,使用嵌套布局方式
        # 我们把所有按钮按照盒布局-垂直布局方式,构成嵌套布局的一个块
        # 按照设置的方式依此从上到下
        self.vbox = QVBoxLayout()
        self.vbox.addWidget(self.btn_add)
        self.vbox.addWidget(self.btn_del)
        self.vbox.addWidget(self.btn_modify)
        self.vbox.addWidget(self.btn_set_middle)
        self.vbox.addWidget(self.btn_get_info)
        self.vbox.addSpacerItem(self.spacerItem)            
        
        self.txt = QLabel()                             # 这是进行操作时显示在最左下角的提示信息
        self.txt.setMinimumHeight(50)                   # 限定控件大小

        self.lab_over = QLabel('调度顺序')               # 输出队列顺序
        self.lab_over.setMinimumHeight(20)
        self.over_Edit = QLineEdit(self)
        self.over_Edit.setMinimumHeight(25)

        self.lab_time = QLabel('平均周转时间和平均带权周转时间')
        self.avrtime_edit = QLineEdit(self)

        # 垂直布局
        # 把表格和下面的操作提示文本信息按照垂直布局设置,作为嵌套布局方式的另一部分
        self.vbox2 = QVBoxLayout()                          
        self.vbox2.addWidget(self.table)                    # 将表格和下面的操作提示放入垂直布局,先放表格
        self.vbox2.addWidget(self.lab_over)                 # 放输出队列
        self.vbox2.addWidget(self.over_Edit)
        self.vbox2.addWidget(self.lab_time)
        self.vbox2.addWidget(self.avrtime_edit)

        self.vbox2.addWidget(self.txt)                      # 再放文本框

        # 水平布局
        # 这是将上述两个布局方式作为整体布局的元素,vbox和vbox2共同放入水平布局
        self.hbox = QHBoxLayout()                          
        self.hbox.addLayout(self.vbox2)                     # 将这样就会自左向右,先放表格,
        self.hbox.addLayout(self.vbox)                      # 再放按钮

        # 将水平布局放入总体布局
        self.setLayout(self.hbox)

        # 表格基本属性设置   
        self.table.setColumnCount(6)                                    # 设置列数
        self.table.horizontalHeader().setDefaultAlignment(QtCore.Qt.AlignCenter)
        self.headers = ['ID','选择','进程名', '到达时间', '服务时间', '静态优先级']      # 设置每列标题
        self.table.setHorizontalHeaderLabels(self.headers)              # 导入
        self.table.verticalHeader().setVisible(False)                   # 隐藏垂直表头
        self.show()

    # 添加行
    def add_line(self):
        self.table.cellChanged.disconnect()
        row = self.table.rowCount()                                     # 获取目前所有行的数量
        self.table.setRowCount(row + 1)
        id = str(self.id)

        # 生成复选框, 并设置居中显示
        ck = QCheckBox()
        h = QHBoxLayout()
        h.setAlignment(Qt.AlignCenter)
        h.addWidget(ck)
        w = QWidget()
        w.setLayout(h)

        # 变量由faker自动生成
        name = self.faker.name()
        arr_time = str(random.randint(0,9))
        ser_time = str(random.randint(0,9))
        sta_class = str(random.randint(0,9))

        # 设置新建行的数据
        self.table.setItem(row,0,QTableWidgetItem(id))
        self.table.setCellWidget(row,1,w)
        self.table.setItem(row,2,QTableWidgetItem(name))
        self.table.setItem(row,3,QTableWidgetItem(arr_time))
        self.table.setItem(row,4,QTableWidgetItem(ser_time))
        self.table.setItem(row,5,QTableWidgetItem(sta_class))

        self.id += 1                                                        # 设置完不要忘记id加一
        self.lines.append([id,ck,name,arr_time,ser_time,sta_class])
        self.settext('自动生成随机一行数据!,checkbox设置为居中显示')
        self.table.cellChanged.connect(self.cellchange)

    # 删除行
    def del_line(self):
        removeline = []
        for line in self.lines:
            if line[1].isChecked():
                row = self.table.rowCount()
                for x in range(row,0,-1):
                    if line[0] == self.table.item(x - 1,0).text():
                        self.table.removeRow(x - 1)
                        removeline.append(line)
        for line in removeline:
            self.lines.remove(line)
        self.settext('删除checkbox中选中状态的行')

    def modify_line(self):
        if self.editable == True:
            self.table.setEditTriggers(QAbstractItemView.NoEditTriggers)
            self.btn_modify.setText('禁止编辑')
            self.editable = False
        else:
            self.table.setEditTriggers(QAbstractItemView.AllEditTriggers)
            self.btn_modify.setText('可以编辑')
            self.editable = True
        self.settext('设置是否可以编辑表格信息')

    def middle(self):
        row = self.table.rowCount()
        for x in range(row):
            for y in range(6):
                if y != 1:
                    item = self.table.item(x,y)
                    item.setTextAlignment(Qt.AlignCenter)
                else:
                    pass
        self.settext('将文字居中显示')  

    def cellchange(self,row,col):
        item = self.table.item(row,col)
        txt = item.text()
        self.settext('第%s行,第%s列 , 数据改变为:%s'%(row,col,txt))

    def g_info(self):
        # 我们每次使用这个功能时先把全变量原始进程列表 -- original_processes --清空好吧
        original_processes = []
        row = self.table.rowCount()

        for j in range(row):                            # 有几行就有几个进程
            na = self.table.item(j,2).text()
            at = int(self.table.item(j,3).text())
            st = int(self.table.item(j,4).text())
            sc = int(self.table.item(j,5).text())
            p = Process(na, at, st, sc)
            original_processes.append(p)
            print(na+' '+str(at)+' '+str(st)+' '+str(sc))

        '''
        由于第一个进程不一定就是到达时间最短的进程,所以我们先按照
        到达时间给进程排个序
        '''
        _sorted_processes = original_processes[:]
        _sorted_processes.sort(key=operator.attrgetter('arrive_time'))

        infor_list = fcfs(_sorted_processes)
        self.avrtime_edit.setText(str(infor_list[1]))
        self.over_Edit.setText(str(infor_list[0]))
        self.settext('获取表格信息,生成调度序列,计算平均、平均带权周转时间,并显示')
    
    def settext(self,txt):
        font = QFont('微软雅黑',10)
        self.txt.setFont(font)
        self.txt.setText(txt)  


if __name__ == '__main__':
    app = QApplication(sys.argv)
    ui = ui()
    sys.exit(app.exec_())

大体思路

数据结构定义及功能算法部分

#  引入数据结构
# 定义每个进程基本数据结构
class Process:
    def __init__(self, name, arrive_time, serve_time, static_class, ready=False, over=False):
        self.name = name                                    # 进程名称
        self.arrive_time = arrive_time                      # 到达时间
        self.serve_time = serve_time                        # 服务时间
        self.left_serve_time = serve_time                   # 剩余需要服务的时间
        self.finish_time = 0                                # 完成时间
        self.cycling_time = 0                               # 周转时间
        self.w_cycling_time = 0                             # 带权周转时间
        self.response_ratio = 0                             # 响应比
        self.pre_queue = 0                                  # 定义现在所在的队列
        self.pre_queue_tb = 0                               # 目前所在队列的时间片
        self.used_time = 0                                  # 已经使用的时间,也就是(服务时间 - 剩余服务时间)
        self.ready = ready                                  # 记录就绪状态
        self.over = over                                    # 记录完成状态
        self.static_class = static_class                    # 人为赋予静态优先级


# 现来先服务作业调度算法
def fcfs(processes): # 到达时间小的优先
   
    sum_cycling_time = 0
    sum_w_cycling_time = 0
    number = len(processes)
    over_list = []
    min_key = 0
    fin_name = []
    name_string = ''
    time_string = '带权周转时间:'
    last_infor = []
    running_time = 0
    while processes:
        min = processes[0].arrive_time
        for i in range(len(processes)):
            if processes[i].arrive_time <= min:
                min = processes[i].arrive_time
                min_key = i

        running_time += processes[min_key].serve_time
        processes[min_key].cycling_time = running_time - processes[min_key].arrive_time
        processes[min_key].w_cycling_time = processes[min_key].cycling_time / processes[min_key].serve_time
        sum_cycling_time += processes[min_key].cycling_time
        sum_w_cycling_time += processes[min_key].w_cycling_time

        over_list.append(processes.pop(min_key))
    for i in range(len(over_list)):
        print(over_list[i].name)
        name_string += (over_list[i].name+'   ')
        fin_name.append(over_list[i].name)

    a_c_time = sum_cycling_time/number
    a_w_c_time = sum_w_cycling_time/number
    print('平均周转时间:' + str(a_c_time))
    print('平均带权周转时间:' + str(a_w_c_time/number))
    time_string += (str(a_c_time) + '    平均带权周转时间:' + str(a_w_c_time))

    last_infor.append(name_string)
    last_infor.append(time_string)
    # return fin_name
    return last_infor

这部分内容在之前的博客中有大体的讲,不过好像是重构了,过段时间应该还要重构。

这里要注意返回的列表有两项,分别是调度完之后的作业or进程名称顺序字符串,还有平均周转时间和平均带权周转时间的时间参数字符串。就不多讲了。

在每次执行完一个作业or进程之后,会进行一个周转时间和带权周转时间的计算,方便计算性能。

其余和之前差不多。

GUI部分

引入的库和模块

from PyQt5.QtWidgets import (QWidget,QLineEdit,QHBoxLayout,QTableWidget,QPushButton,QApplication,QVBoxLayout,QTableWidgetItem,QCheckBox,QAbstractItemView,QHeaderView,QLabel,QFrame)
from PyQt5 import QtWidgets, QtCore
from PyQt5.QtCore import Qt
from builtins import super, str, range
from PyQt5.QtGui import QFont,QColor
from faker import Factory
import random, sys, operator

主要用了是PyQt5的模块,另外加一些内置的计算模块,像后面的算法还用到numpy等科学计算模块

语法、思路、排版、实现

直接往代码里写了啊

class ui(QWidget):                             # 继承QWidget
    def __init__(self):
        super(ui, self).__init__()
        self.setupUI()
        self.id = 1
        self.lines = []
        self.editable = True
        self.des_sort = True
        self.faker = Factory.create()			# faker库是数据伪造生成器,后续会搬运一篇博文讲

        '''
        这里面主要使用了 
        按钮-button
        标签-lable
        编辑单行文本框-editline
        表格-table
        这几个控件
        我觉得难点主要在于不熟悉这些控件的方法,英语又不好官方文档看明白是不可能的...对了6级第一次裸考没过
        '''
        # 按钮绑定事件 
        '''
        主要事件
        add_line 表格添加行
        del_line 表格删除行
        modify_line 控制表格是否可以被编辑
        middle 设置表格文字居中显示
        cellchange 根据相关触发的操作提示你的操作是干嘛的
        '''
        self.btn_add.clicked.connect(self.add_line)
        self.btn_del.clicked.connect(self.del_line)
        self.btn_modify.clicked.connect(self.modify_line)
        self.btn_set_middle.clicked.connect(self.middle)
        self.btn_get_info.clicked.connect(self.g_info)

        self.table.cellChanged.connect(self.cellchange)

        global original_processes               # 这里我们定义全局变量 - 原始进程列表,是一个二维列表


    def setupUI(self):
        # 控件的排版,做的时候嵌套布局那一块觉得自己是真的学到了,很有趣,基本设置Google Baidu都可找到
        self.setWindowTitle('数据测试')
        self.resize(720,420)

        self.table = QTableWidget(self)

        self.btn_add = QPushButton('增加')
        self.btn_del = QPushButton('删除')
        self.btn_modify = QPushButton('可以编辑')
        self.btn_set_middle = QPushButton('文字居中')
        self.btn_get_info = QPushButton('生成调度序列')
    
        # 弹簧控件,这个不是很明白
        self.spacerItem = QtWidgets.QSpacerItem(20, 20, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding)
        
        # 垂直布局,使用嵌套布局方式
        # 我们把所有按钮按照盒布局-垂直布局方式,构成嵌套布局的一个块
        # 按照设置的方式依此从上到下
        self.vbox = QVBoxLayout()
        self.vbox.addWidget(self.btn_add)
        self.vbox.addWidget(self.btn_del)
        self.vbox.addWidget(self.btn_modify)
        self.vbox.addWidget(self.btn_set_middle)
        self.vbox.addWidget(self.btn_get_info)
        self.vbox.addSpacerItem(self.spacerItem)            
        
        self.txt = QLabel()                             # 这是进行操作时显示在最左下角的提示信息
        self.txt.setMinimumHeight(50)                   # 限定控件大小

        self.lab_over = QLabel('调度顺序')               # 输出队列顺序
        self.lab_over.setMinimumHeight(20)
        self.over_Edit = QLineEdit(self)
        self.over_Edit.setMinimumHeight(25)

        self.lab_time = QLabel('平均周转时间和平均带权周转时间')
        self.avrtime_edit = QLineEdit(self)

        # 垂直布局
        # 把表格和下面的操作提示文本信息按照垂直布局设置,作为嵌套布局方式的另一部分
        self.vbox2 = QVBoxLayout()                          
        self.vbox2.addWidget(self.table)                    # 将表格和下面的操作提示放入垂直布局,先放表格
        self.vbox2.addWidget(self.lab_over)                 # 放输出队列
        self.vbox2.addWidget(self.over_Edit)
        self.vbox2.addWidget(self.lab_time)
        self.vbox2.addWidget(self.avrtime_edit)

        self.vbox2.addWidget(self.txt)                      # 再放文本框

        # 水平布局
        # 这是将上述两个布局方式作为整体布局的元素,vbox和vbox2共同放入水平布局
        self.hbox = QHBoxLayout()                          
        self.hbox.addLayout(self.vbox2)                     # 将这样就会自左向右,先放表格,
        self.hbox.addLayout(self.vbox)                      # 再放按钮

        # 将水平布局放入总体布局
        self.setLayout(self.hbox)

        # 表格基本属性设置   
        self.table.setColumnCount(6)                                    # 设置列数
        self.table.horizontalHeader().setDefaultAlignment(QtCore.Qt.AlignCenter)
        self.headers = ['ID','选择','进程名', '到达时间', '服务时间', '静态优先级']      # 设置每列标题
        self.table.setHorizontalHeaderLabels(self.headers)              # 导入
        self.table.verticalHeader().setVisible(False)                   # 隐藏垂直表头
        self.show()

    # 添加行
    def add_line(self):
        self.table.cellChanged.disconnect()
        row = self.table.rowCount()                                     # 获取目前所有行的数量
        self.table.setRowCount(row + 1)
        id = str(self.id)

        # 生成复选框, 并设置居中显示
        ck = QCheckBox()
        h = QHBoxLayout()
        h.setAlignment(Qt.AlignCenter)
        h.addWidget(ck)
        w = QWidget()
        w.setLayout(h)

        # 变量由faker自动生成
        name = self.faker.name()
        arr_time = str(random.randint(0,9))
        ser_time = str(random.randint(0,9))
        sta_class = str(random.randint(0,9))

        # 设置新建行的数据
        self.table.setItem(row,0,QTableWidgetItem(id))
        self.table.setCellWidget(row,1,w)
        self.table.setItem(row,2,QTableWidgetItem(name))
        self.table.setItem(row,3,QTableWidgetItem(arr_time))
        self.table.setItem(row,4,QTableWidgetItem(ser_time))
        self.table.setItem(row,5,QTableWidgetItem(sta_class))

        self.id += 1                                                        # 设置完不要忘记id加一
        self.lines.append([id,ck,name,arr_time,ser_time,sta_class])
        self.settext('自动生成随机一行数据!,checkbox设置为居中显示')
        self.table.cellChanged.connect(self.cellchange)

    # 删除行
    def del_line(self):
        removeline = []
        for line in self.lines:
            if line[1].isChecked():
                row = self.table.rowCount()
                for x in range(row,0,-1):
                    if line[0] == self.table.item(x - 1,0).text():
                        self.table.removeRow(x - 1)
                        removeline.append(line)
        for line in removeline:
            self.lines.remove(line)
        self.settext('删除checkbox中选中状态的行')

    def modify_line(self):
        if self.editable == True:
            self.table.setEditTriggers(QAbstractItemView.NoEditTriggers)
            self.btn_modify.setText('禁止编辑')
            self.editable = False
        else:
            self.table.setEditTriggers(QAbstractItemView.AllEditTriggers)
            self.btn_modify.setText('可以编辑')
            self.editable = True
        self.settext('设置是否可以编辑表格信息')

    def middle(self):
        row = self.table.rowCount()
        for x in range(row):
            for y in range(6):
                if y != 1:
                    item = self.table.item(x,y)
                    item.setTextAlignment(Qt.AlignCenter)
                else:
                    pass
        self.settext('将文字居中显示')  

    def cellchange(self,row,col):
        item = self.table.item(row,col)
        txt = item.text()
        self.settext('第%s行,第%s列 , 数据改变为:%s'%(row,col,txt))

    def g_info(self):
        # 我们每次使用这个功能时先把全变量原始进程列表 -- original_processes --清空好吧
        # 这个函数获取表格数据存入队列,初始化进程信息加入列表,最后调主算法函数进行模拟调度,最后返回信息
        original_processes = []
        row = self.table.rowCount()

        for j in range(row):                            # 有几行就有几个进程
            na = self.table.item(j,2).text()
            at = int(self.table.item(j,3).text())
            st = int(self.table.item(j,4).text())
            sc = int(self.table.item(j,5).text())
            p = Process(na, at, st, sc)
            original_processes.append(p)
            print(na+' '+str(at)+' '+str(st)+' '+str(sc))

        '''
        由于第一个进程不一定就是到达时间最短的进程,所以我们先按照
        到达时间给进程排个序
        这是后来才想到的,还有很多诸如此类的bug...脑壳疼
        '''
        _sorted_processes = original_processes[:]
        _sorted_processes.sort(key=operator.attrgetter('arrive_time'))

        infor_list = fcfs(_sorted_processes)
        # 讲返回的信息填入文本框
        self.avrtime_edit.setText(str(infor_list[1]))
        self.over_Edit.setText(str(infor_list[0]))
        self.settext('获取表格信息,生成调度序列,计算平均、平均带权周转时间,并显示')
    # 提示字体的设置
    def settext(self,txt):
        font = QFont('微软雅黑',10)
        self.txt.setFont(font)
        self.txt.setText(txt)  

最后就…

if __name__ == '__main__':
    app = QApplication(sys.argv)
    ui = ui()
    sys.exit(app.exec_())

大体框架写完之后觉得好多东西并没有那么难,只是你没有见过所以觉得很唬人,然而我觉得我coding效率还是太低了,诶

演示

  • 主页面

  • 添加行并自动生成数据

  • 更改数据

  • 居中对齐

  • 生成序列并显示调度顺序和时间效率

  • 删除选中行

    完事了就,太简陋···但是一想这东西用c/c++写就也太麻烦了吧,python真好~

不足与改进思路

不足

  • 算法有问题,数据容错率极低,经常因为数据不规范就原地崩
  • 没有实现 作业/进程 数据可从外部导入的功能
  • 没实现 单步执行 的功能,我想这是最要紧的…
  • 没有 相同进程不同算法性能数据比较 功能
  • 不够集成

总体看来,就是只实现了一个大体的demo,还有很多需要改进

改进思路

  • 算法重构,昨天调的时候觉得太乱了,而且如果要单步执行的话目前算法应该不能达到要求
  • 优化GUI
  • 还是算法吧,数据容错性太差
  • 添加从外部文件导入数据功能

题外话:最近有些焦虑,铺天盖地的说2019计算机考研哪哪都炸,初试神仙打架复试百里挑一,985211各路神仙跨考计算机的数不过来,感觉350都不叫分了。就一股脑都来吃计算机这碗饭,就连调剂的生源都不错,更何况一堆搞ACM的、手里拿着一大堆项目、顶级论文发了好几篇的神仙也…越来越觉得路难走,实力又真是差十万八千里,就越发急于求成,想很快可以出成绩看到结果。输在了起跑线上在后面得付出更多的努力,然而更多时候只是停留嘴面实际行动又不及十分之一。可能就不具备那种潜质再者说没有足够的动力一直激励自己。但,但行好事莫问前程吧。今天20了…真快,可以再加把劲

写的太晚了难免有纰漏,望海涵

源码地址

自认为是幻象波普星的来客
Built with Hugo
主题 StackJimmy 设计