软件规格需求说明书
引言
编写目的
软件规格需求说明书书了“2048俄罗斯方块”1.0版本的软件功能性需求和非功能性需求。
文档约定
描述编写文档时所采用的标准或排版约定,包括正文风格,提示区或重要符号。例如,说明高层需求的优先级是否可以被所有细化分需求所继承,或者每个需求陈述是否都有优先级。
读者对象和阅读建议
该软件需求规格说明书针对开发人员、测试人员等,用于开发初期确定软件的系统设计,详细设计。本文内容包括面向用户分析、功能性需求、技术需求,阐述了系统的真实性、可用性以及价值所在。
项目范围
“2048俄罗斯方块”是在软件工程第三次大作业由C++*队提出来的一个项目,主要目的是供队员学习软件工程的开发过程,并通过此次开发,对C++掌握更加牢固。该游戏软件适用于大多数学生和上班族打发零散的空闲时间。
预期用户数量
我们预计的用户数量是1000人以上。
总体描述
产品前景
“2048俄罗斯方块”1.0版本是由微信小程序“我的方块2048”的改进版,增加了一些新的功能来吸引更多用户。
产品的简述
游戏规则:合并相同数字方块,合成2048或更大数字获得胜利,格子填满或方块超出上界游戏失败
得分规则:合成块对应分值 - 游戏时间
具体操作:左右控制方块移动,下键使悬空方块立刻落下
真实性
2048和俄罗斯方块都是两款很火很有意思的游戏,相信两者的结合体“2048俄罗斯方块”将会获得用户的青睐。
可用性
“2048俄罗斯方块”的玩法十分简单,只要曾经玩过2048和俄罗斯方块,就能很快入手。
价值所在
- 满足人们休闲娱乐的需求
- 两款经典游戏的结合,给用户不一样的体验
运行环境
Linux/X11、Mac、Windows、Embedded Linux、Windows CE / Mobile、Symbian、Meego、Wayland、Android、IOS、Amazon Kindle DX… QT For Everywhere!
设计和实现上的约束
为了确保可移植性,本项目使用C++进行编写,图形库、网络库使用QT内置的实现。 开发规范:
- 禁止使用宏
- 分号以前不加空格
- 行宽原则上不超过80
- 一行只定义一个变量
- 大括号换行
- return 后面的数值不加 ( )
- 每个文件应该含有版权信息及作者
- 左圆括号之后和右圆括号之前无空格
- 一目运算符与变量之间不加空格符隔开
- 函数名与参数同行
- 换行代码缩进4个空格,并且使用四个空格符取代制表符
- 二目以上的运算符与变量,常量之间用空格隔开(各类括号除外)
- 不论控制语句,循环语句后面的循环体有多少行,都必须使用花括号
- 普通函数,类型(含类与结构体,枚举类型),常量等使用大小写混合,可包含下划线
- 除函数定义的左大括号可置于行首以外,包括函数/类/结构体/枚举声明,各种语句的左大括号必须置于行末,所有右大括号独立成行
硬件限制
- 键盘输入设备
- 显示屏
- 具体硬件配置需求待测试
系统功能
图形界面
分数统计
障碍块
难度调整
在线排名
外部接口需求
用户界面
总体界面:包括方块,背景板,计分板,开始按钮,暂停按钮,结束按钮。
硬件接口
描述系统中硬件每个接口的特征。可能包括支持的硬件类型、软硬件之间交流的数据和控制信息的性质以及所使用的通信协议
软件接口
描述产品与其它外部组件的连接,包括数据库,操作系统,工具库和集成的商业组件。明确并描述在软件组件之间交换数据或信息的目的,描述所需要的服务及内部组件通信的性质,确定将在组件之间共享的数据。如果必须用一种特殊的方法来实现数据共享机制,那么就必须把它定义为一种实现上的限制
通信接口
描述与产品所使用的通信功能相关的需求,包括电子邮件、WEB浏览器、网络通信标准或协议及电子表格等,定义相关的信息格式、规定通信安全或加密问题、数据传输速率和同步通信机制
非功能性需求
性能需求
点击开始,暂停,结束按钮时,立刻(1S内)出现相应的反应。 用户用键盘控制方块左右移动,按下键盘←→键,在2ms内方块移动,让用户感觉不到延迟。 按↓键,方块应在5ms内到达底部。 还要定义容量需求,例如存储器和磁盘空间的需求或者存储在数据库中表的最大行数。也可能需要针对每个功能需求或特性分别陈述其性能需求
软件质量属性
可用性:程序用户界面运行时不崩溃,按钮布局合理有效、易学容易掌握,在满足配置条件下能全程无明显卡顿的运行,联机时比分状态双机同步。在整个过程中尽量为用户带来丝滑顺畅的操作体验。 健壮性:图形界面上若布局排列异常则根据内存数据重置界面
制定团队计划
将团队的任务计划添加到码云(Github)的团队项目issues里面(Done)
提供issues截图(Done)
给出团队项目的时间安排表(Todo)
原本时间安排(done)
时间 | 安排 |
---|---|
10.14 - 10.20 | 分析需求,完成规格说明书,学习团体开发需要用到的技术 |
10.21 - 10.27 | 改进需求,进行系统设计、制定详细的开发计划 |
10.28 - 11.3 | Alpha 冲刺 |
11.4 - 11.10 | 用户测试 + 改进,收尾 |
11.11 - end | 总结 |
校正后的安排(Todo)
其他
排版(Todo)
团队分工 & 绩效算法
团队分工
- 湖倩:文档
- yy:图形界面
- 泽翰:图形界面
- 秉坤:数字类、图形界面
- 育招:控制类控制方向
- 绿猪:控制类判断方向
绩效算法
成员的绩效 = 团队获得的分数 + 个人的团队贡献分
在项目alpha 和 beta 阶段评审后, 团队会得到一个项目分数(每个成员都会得到同样的分数,做为自己的原始分数的一部分)。团队成员的努力程度不同,达成目标的程度不同,帮助同伴的付出不同,那就要在“团队贡献分” 上有所区分。 所有人贡献分的总和为 20N,其中N为团队的人数。 在alpha/beta 之后,团队按照自己制定的规则,把 (20N)瓜分给每人,这就是 “团队贡献分”。
要求:请每人阅读教材 “人、绩效和职业道德”一章,然后团队开一个讨论会,协商讨论团队贡献分的分配规则。每人得分为自然数,并且每个人分数不能相同。 请写一个团队博客详细说明每个团队的成员计划如何帮助团队完成任务,以及团队贡献分的分配规则。
每个人的完成情况(Todo)
每个人的感想(Todo)
育招:在这一周,我们团队完成了需求规格说明书,并制定了团队计划。假如一个人开发一个项目的话,大部分情况下只能自己拿定主意,但是团队开发就不一样了,可以进行头脑风暴,进行思维的碰撞,从而产生更好的想法,开发出更好的产品。另外,由于我比较菜,所以在这一周里,我去学习了一下团队git的协作方式,弄懂了issue和branch的基础操作,为接下来的团队开发做好准备。
泽翰:这周主要还是参加讨论与前期知识的学习与储备,图形界面设计方面之前仅仅是接触了MFC框架与C#相关的皮毛。借着此次团队项目的学习实践,之前也很想了解的Qt编程也有机会学习与实战了。这周里也是看了很多Qt的编程教程与相关书籍,由于是第一次接触,目前尚且在进行一些实例的练手。总的而言,此次的团队项目无论是从个人编程经验的积累还是团队的合作成长,都是十分令人期待的。
秉坤:因为我的任务是兼项的,负责界面的同时也负责数字类模块,念及接下来的开发都是基于这个类进行开发,并且这个模块的内容并不难, 所以这一周我提前了一点点将这个模块基本上完成,相信能够跟其他人有更好的对接.
绿猪:了解并实践了软件工程中项目需求分析与团队分工相关的知识,深深感到用户需求对软件的重要性。成功的软件产品是建立在成功的需求基础之上的,而高质量的需求来源于用户与开发人员之间有效的沟通与合作。当用户有一个问题可以用计算机系统来解决,而开发人员开始帮助用户解决这个问题,沟通就开始了。
需求获取可能是最困难、最关键、最易出错及最需要沟通交流的活动。对需求的获取往往有错误的认识:用户知道需求是什么,我们所要做的就是和他们交谈从他们那里得到需求,只要问用户系统的目标特征,什么是要完成的,什么样的系统能适合商业需要就可以了,但是实际上需求获取并不是想象的这样简单,这条沟通之路布满了荆棘。首先需求获取要定义问题范围,系统的边界往往是很难明确的,用户不了解技术实现的细节,这样造成了系统目标的混淆。
其次是对问题的理解,用户对计算机系统的能力和限制缺乏了解,任何一个系统都会有很多的用户或者不同类型的用户,每个用户只知道自己需要的系统,而不知道系统的整体情况,他们不知道系统作为一个整体怎么样工作效率更好,也不太清楚那些工作可以交给软件完成,他们不清楚需求是什么,或者说如何以一种精确的方式来描述需求,他们需要开发人员的协助和指导,但是用户与开发人员之间的交流很容易出现障碍,忽略了那些被认为是"很明显"的信息。最后是需求的确认,因为需求的不稳定性往往随着时间的推移产生变动,使之难以确认。为了克服以上的问题,必须有组织的执行需求的获取活动。
叶钰羽:第一次团队合作写一个小游戏,队友都是精通C++,作为只了解Java的我,代码编写对我来说相对较难。因此,在这次合作中,我担任UI设计的角色。ui对我来说也是比较新的领域,之前仅仅是手画用户故事,用文档实现demo,这次会尝试用画图软件设计UI。 叶湖倩:在这次团队合作中,我负责文档编辑,进度统计以及博客发表工作。我的工作基本不涉及技术编程类,但我希望在这次的团队任务中,能够向其他队友们学习一些技术,让自己的编程能力有所提高。和团队成员初步接触,我发现沟通很重要,有效的沟通能提高大家的效率,避免在合作过程中出现误会。 ---恢复内容结束---
软件规格需求说明书
引言
编写目的
软件规格需求说明书书了“2048俄罗斯方块”1.0版本的软件功能性需求和非功能性需求。
文档约定
描述编写文档时所采用的标准或排版约定,包括正文风格,提示区或重要符号。例如,说明高层需求的优先级是否可以被所有细化分需求所继承,或者每个需求陈述是否都有优先级。
读者对象和阅读建议
该软件需求规格说明书针对开发人员、测试人员等,用于开发初期确定软件的系统设计,详细设计。本文内容包括面向用户分析、功能性需求、技术需求,阐述了系统的真实性、可用性以及价值所在。
项目范围
“2048俄罗斯方块”是在软件工程第三次大作业由C++*队提出来的一个项目,主要目的是供队员学习软件工程的开发过程,并通过此次开发,对C++掌握更加牢固。该游戏软件适用于大多数学生和上班族打发零散的空闲时间。
预期用户数量
我们预计的用户数量是1000人以上。
总体描述
产品前景
“2048俄罗斯方块”1.0版本是由微信小程序“我的方块2048”的改进版,增加了一些新的功能来吸引更多用户。
产品的简述
游戏规则:合并相同数字方块,合成2048或更大数字获得胜利,格子填满或方块超出上界游戏失败
得分规则:合成块对应分值 - 游戏时间
具体操作:左右控制方块移动,下键使悬空方块立刻落下
真实性
2048和俄罗斯方块都是两款很火很有意思的游戏,相信两者的结合体“2048俄罗斯方块”将会获得用户的青睐。
可用性
“2048俄罗斯方块”的玩法十分简单,只要曾经玩过2048和俄罗斯方块,就能很快入手。
价值所在
- 满足人们休闲娱乐的需求
- 两款经典游戏的结合,给用户不一样的体验
运行环境
Linux/X11、Mac、Windows、Embedded Linux、Windows CE / Mobile、Symbian、Meego、Wayland、Android、IOS、Amazon Kindle DX… QT For Everywhere!
设计和实现上的约束
为了确保可移植性,本项目使用C++进行编写,图形库、网络库使用QT内置的实现。 开发规范:
- 禁止使用宏
- 分号以前不加空格
- 行宽原则上不超过80
- 一行只定义一个变量
- 大括号换行
- return 后面的数值不加 ( )
- 每个文件应该含有版权信息及作者
- 左圆括号之后和右圆括号之前无空格
- 一目运算符与变量之间不加空格符隔开
- 函数名与参数同行
- 换行代码缩进4个空格,并且使用四个空格符取代制表符
- 二目以上的运算符与变量,常量之间用空格隔开(各类括号除外)
- 不论控制语句,循环语句后面的循环体有多少行,都必须使用花括号
- 普通函数,类型(含类与结构体,枚举类型),常量等使用大小写混合,可包含下划线
- 除函数定义的左大括号可置于行首以外,包括函数/类/结构体/枚举声明,各种语句的左大括号必须置于行末,所有右大括号独立成行
硬件限制
- 键盘输入设备
- 显示屏
- 具体硬件配置需求待测试
系统功能
图形界面
分数统计
障碍块
难度调整
在线排名
外部接口需求
用户界面
总体界面:包括方块,背景板,计分板,开始按钮,暂停按钮,结束按钮。
硬件接口
描述系统中硬件每个接口的特征。可能包括支持的硬件类型、软硬件之间交流的数据和控制信息的性质以及所使用的通信协议
软件接口
描述产品与其它外部组件的连接,包括数据库,操作系统,工具库和集成的商业组件。明确并描述在软件组件之间交换数据或信息的目的,描述所需要的服务及内部组件通信的性质,确定将在组件之间共享的数据。如果必须用一种特殊的方法来实现数据共享机制,那么就必须把它定义为一种实现上的限制
通信接口
描述与产品所使用的通信功能相关的需求,包括电子邮件、WEB浏览器、网络通信标准或协议及电子表格等,定义相关的信息格式、规定通信安全或加密问题、数据传输速率和同步通信机制
非功能性需求
性能需求
点击开始,暂停,结束按钮时,立刻(1S内)出现相应的反应。 用户用键盘控制方块左右移动,按下键盘←→键,在2ms内方块移动,让用户感觉不到延迟。 按↓键,方块应在5ms内到达底部。 还要定义容量需求,例如存储器和磁盘空间的需求或者存储在数据库中表的最大行数。也可能需要针对每个功能需求或特性分别陈述其性能需求
软件质量属性
可用性:程序用户界面运行时不崩溃,按钮布局合理有效、易学容易掌握,在满足配置条件下能全程无明显卡顿的运行,联机时比分状态双机同步。在整个过程中尽量为用户带来丝滑顺畅的操作体验。 健壮性:图形界面上若布局排列异常则根据内存数据重置界面
制定团队计划
将团队的任务计划添加到码云(Github)的团队项目issues里面(Done)
提供issues截图(Done)
给出团队项目的时间安排表(Todo)
原本时间安排(done)
时间 | 安排 |
---|---|
10.14 - 10.20 | 分析需求,完成规格说明书,学习团体开发需要用到的技术 |
10.21 - 10.27 | 改进需求,进行系统设计、制定详细的开发计划 |
10.28 - 11.3 | Alpha 冲刺 |
11.4 - 11.10 | 用户测试 + 改进,收尾 |
11.11 - end | 总结 |
校正后的安排(Todo)
其他
排版(Todo)
团队分工 & 绩效算法
团队分工
- 湖倩:文档
- yy:图形界面
- 泽翰:图形界面
- 秉坤:数字类、图形界面
- 育招:控制类控制方向
- 绿猪:控制类判断方向
绩效算法
成员的绩效 = 团队获得的分数 + 个人的团队贡献分
在项目alpha 和 beta 阶段评审后, 团队会得到一个项目分数(每个成员都会得到同样的分数,做为自己的原始分数的一部分)。团队成员的努力程度不同,达成目标的程度不同,帮助同伴的付出不同,那就要在“团队贡献分” 上有所区分。 所有人贡献分的总和为 20N,其中N为团队的人数。 在alpha/beta 之后,团队按照自己制定的规则,把 (20N)瓜分给每人,这就是 “团队贡献分”。
要求:请每人阅读教材 “人、绩效和职业道德”一章,然后团队开一个讨论会,协商讨论团队贡献分的分配规则。每人得分为自然数,并且每个人分数不能相同。 请写一个团队博客详细说明每个团队的成员计划如何帮助团队完成任务,以及团队贡献分的分配规则。
每个人的完成情况(Todo)
每个人的感想(Todo)
育招:在这一周,我们团队完成了需求规格说明书,并制定了团队计划。假如一个人开发一个项目的话,大部分情况下只能自己拿定主意,但是团队开发就不一样了,可以进行头脑风暴,进行思维的碰撞,从而产生更好的想法,开发出更好的产品。另外,由于我比较菜,所以在这一周里,我去学习了一下团队git的协作方式,弄懂了issue和branch的基础操作,为接下来的团队开发做好准备。
泽翰:这周主要还是参加讨论与前期知识的学习与储备,图形界面设计方面之前仅仅是接触了MFC框架与C#相关的皮毛。借着此次团队项目的学习实践,之前也很想了解的Qt编程也有机会学习与实战了。这周里也是看了很多Qt的编程教程与相关书籍,由于是第一次接触,目前尚且在进行一些实例的练手。总的而言,此次的团队项目无论是从个人编程经验的积累还是团队的合作成长,都是十分令人期待的。
秉坤:因为我的任务是兼项的,负责界面的同时也负责数字类模块,念及接下来的开发都是基于这个类进行开发,并且这个模块的内容并不难, 所以这一周我提前了一点点将这个模块基本上完成,相信能够跟其他人有更好的对接.
绿猪:了解并实践了软件工程中项目需求分析与团队分工相关的知识,深深感到用户需求对软件的重要性。成功的软件产品是建立在成功的需求基础之上的,而高质量的需求来源于用户与开发人员之间有效的沟通与合作。当用户有一个问题可以用计算机系统来解决,而开发人员开始帮助用户解决这个问题,沟通就开始了。
需求获取可能是最困难、最关键、最易出错及最需要沟通交流的活动。对需求的获取往往有错误的认识:用户知道需求是什么,我们所要做的就是和他们交谈从他们那里得到需求,只要问用户系统的目标特征,什么是要完成的,什么样的系统能适合商业需要就可以了,但是实际上需求获取并不是想象的这样简单,这条沟通之路布满了荆棘。首先需求获取要定义问题范围,系统的边界往往是很难明确的,用户不了解技术实现的细节,这样造成了系统目标的混淆。
其次是对问题的理解,用户对计算机系统的能力和限制缺乏了解,任何一个系统都会有很多的用户或者不同类型的用户,每个用户只知道自己需要的系统,而不知道系统的整体情况,他们不知道系统作为一个整体怎么样工作效率更好,也不太清楚那些工作可以交给软件完成,他们不清楚需求是什么,或者说如何以一种精确的方式来描述需求,他们需要开发人员的协助和指导,但是用户与开发人员之间的交流很容易出现障碍,忽略了那些被认为是"很明显"的信息。最后是需求的确认,因为需求的不稳定性往往随着时间的推移产生变动,使之难以确认。为了克服以上的问题,必须有组织的执行需求的获取活动。
叶钰羽:第一次团队合作写一个小游戏,队友都是精通C++,作为只了解Java的我,代码编写对我来说相对较难。因此,在这次合作中,我担任UI设计的角色。ui对我来说也是比较新的领域,之前仅仅是手画用户故事,用文档实现demo,这次会尝试用画图软件设计UI。
叶湖倩:在这次团队合作中,我负责文档编辑,进度统计以及博客发表工作。我的工作基本不涉及技术编程类,但我希望在这次的团队任务中,能够向其他队友们学习一些技术,让自己的编程能力有所提高。和团队成员初步接触,我发现沟通很重要,有效的沟通能提高大家的效率,避免在合作过程中出现误会。
blockquote:first-child, #write > div:first-child, #write > figure:first-child, #write > ol:first-child, #write > p:first-child, #write > pre:first-child, #write > ul:first-child { margin-top: 30px; }
#write li > figure:first-child { margin-top: -20px; }
#write ol, #write ul { position: relative; }
img { max-width: 100%; vertical-align: middle; }
button, input, select, textarea { color: inherit; font-style: inherit; font-variant: inherit; font-weight: inherit; font-stretch: inherit; font-size: inherit; line-height: inherit; font-family: inherit; }
input[type="checkbox"], input[type="radio"] { line-height: normal; padding: 0px; }
*, ::after, ::before { box-sizing: border-box; }
#write h1, #write h2, #write h3, #write h4, #write h5, #write h6, #write p, #write pre { width: inherit; }
#write h1, #write h2, #write h3, #write h4, #write h5, #write h6, #write p { position: relative; }
h1, h2, h3, h4, h5, h6 { break-after: avoid-page; break-inside: avoid; orphans: 2; }
p { orphans: 4; }
h1 { font-size: 2rem; }
h2 { font-size: 1.8rem; }
h3 { font-size: 1.6rem; }
h4 { font-size: 1.4rem; }
h5 { font-size: 1.2rem; }
h6 { font-size: 1rem; }
.md-math-block, .md-rawblock, h1, h2, h3, h4, h5, h6, p { margin-top: 1rem; margin-bottom: 1rem; }
.hidden { display: none; }
.md-blockmeta { color: rgb(204, 204, 204); font-weight: 700; font-style: italic; }
a { cursor: pointer; }
sup.md-footnote { padding: 2px 4px; background-color: rgba(238, 238, 238, 0.7); color: rgb(85, 85, 85); border-radius: 4px; cursor: pointer; }
sup.md-footnote a, sup.md-footnote a:hover { color: inherit; text-transform: inherit; text-decoration: inherit; }
#write input[type="checkbox"] { cursor: pointer; width: inherit; height: inherit; }
figure { overflow-x: auto; margin: 1.2em 0px; max-width: calc(100% + 16px); padding: 0px; }
figure > table { margin: 0px !important; }
tr { break-inside: avoid; break-after: auto; }
thead { display: table-header-group; }
table { border-collapse: collapse; border-spacing: 0px; width: 100%; overflow: auto; break-inside: auto; text-align: left; }
table.md-table td { min-width: 80px; }
.CodeMirror-gutters { border-right: 0px; background-color: inherit; }
.CodeMirror { text-align: left; }
.CodeMirror-placeholder { opacity: 0.3; }
.CodeMirror pre { padding: 0px 4px; }
.CodeMirror-lines { padding: 0px; }
div.hr:focus { cursor: none; }
#write pre { white-space: pre-wrap; }
#write.fences-no-line-wrapping pre { white-space: pre; }
#write pre.ty-contain-cm { white-space: normal; }
.CodeMirror-gutters { margin-right: 4px; }
.md-fences { font-size: 0.9rem; display: block; break-inside: avoid; text-align: left; overflow: visible; white-space: pre; background: inherit; position: relative !important; }
.md-diagram-panel { width: 100%; margin-top: 10px; text-align: center; padding-top: 0px; padding-bottom: 8px; overflow-x: auto; }
#write .md-fences.mock-cm { white-space: pre-wrap; }
.md-fences.md-fences-with-lineno { padding-left: 0px; }
#write.fences-no-line-wrapping .md-fences.mock-cm { white-space: pre; overflow-x: auto; }
.md-fences.mock-cm.md-fences-with-lineno { padding-left: 8px; }
.CodeMirror-line, twitterwidget { break-inside: avoid; }
.footnotes { opacity: 0.8; font-size: 0.9rem; margin-top: 1em; margin-bottom: 1em; }
.footnotes + .footnotes { margin-top: 0px; }
.md-reset { margin: 0px; padding: 0px; border: 0px; outline: 0px; vertical-align: top; background: 0px 0px; text-decoration: none; text-shadow: none; float: none; position: static; width: auto; height: auto; white-space: nowrap; cursor: inherit; -webkit-tap-highlight-color: transparent; line-height: normal; font-weight: 400; text-align: left; box-sizing: content-box; direction: ltr; }
li div { padding-top: 0px; }
blockquote { margin: 1rem 0px; }
li .mathjax-block, li p { margin: 0.5rem 0px; }
li { margin: 0px; position: relative; }
blockquote > :last-child { margin-bottom: 0px; }
blockquote > :first-child, li > :first-child { margin-top: 0px; }
.footnotes-area { color: rgb(136, 136, 136); margin-top: 0.714rem; padding-bottom: 0.143rem; white-space: normal; }
#write .footnote-line { white-space: pre-wrap; }
@media print {
body, html { border: 1px solid transparent; height: 99%; break-after: avoid; break-before: avoid; }
#write { margin-top: 0px; border-color: transparent !important; }
.typora-export * { -webkit-print-color-adjust: exact; }
html.blink-to-pdf { font-size: 13px; }
.typora-export #write { padding-left: 1cm; padding-right: 1cm; padding-bottom: 0px; break-after: avoid; }
.typora-export #write::after { height: 0px; }
@page { margin: 20mm 0px; }
}
.footnote-line { margin-top: 0.714em; font-size: 0.7em; }
a img, img a { cursor: pointer; }
pre.md-meta-block { font-size: 0.8rem; min-height: 0.8rem; white-space: pre-wrap; background: rgb(204, 204, 204); display: block; overflow-x: hidden; }
p > img:only-child { display: block; margin: auto; }
p > .md-image:only-child { display: inline-block; width: 100%; text-align: center; }
#write .MathJax_Display { margin: 0.8em 0px 0px; }
.md-math-block { width: 100%; }
.md-math-block:not(:empty)::after { display: none; }
[contenteditable="true"]:active, [contenteditable="true"]:focus { outline: 0px; box-shadow: none; }
.md-task-list-item { position: relative; list-style-type: none; }
.task-list-item.md-task-list-item { padding-left: 0px; }
.md-task-list-item > input { position: absolute; top: 0px; left: 0px; margin-left: -1.2em; margin-top: calc(1em - 10px); }
.math { font-size: 1rem; }
.md-toc { min-height: 3.58rem; position: relative; font-size: 0.9rem; border-radius: 10px; }
.md-toc-content { position: relative; margin-left: 0px; }
.md-toc-content::after, .md-toc::after { display: none; }
.md-toc-item { display: block; color: rgb(65, 131, 196); }
.md-toc-item a { text-decoration: none; }
.md-toc-inner:hover { }
.md-toc-inner { display: inline-block; cursor: pointer; }
.md-toc-h1 .md-toc-inner { margin-left: 0px; font-weight: 700; }
.md-toc-h2 .md-toc-inner { margin-left: 2em; }
.md-toc-h3 .md-toc-inner { margin-left: 4em; }
.md-toc-h4 .md-toc-inner { margin-left: 6em; }
.md-toc-h5 .md-toc-inner { margin-left: 8em; }
.md-toc-h6 .md-toc-inner { margin-left: 10em; }
@media screen and (max-width: 48em) {
.md-toc-h3 .md-toc-inner { margin-left: 3.5em; }
.md-toc-h4 .md-toc-inner { margin-left: 5em; }
.md-toc-h5 .md-toc-inner { margin-left: 6.5em; }
.md-toc-h6 .md-toc-inner { margin-left: 8em; }
}
a.md-toc-inner { font-size: inherit; font-style: inherit; font-weight: inherit; line-height: inherit; }
.footnote-line a:not(.reversefootnote) { color: inherit; }
.md-attr { display: none; }
.md-fn-count::after { content: "."; }
code, pre, samp, tt { font-family: var(--monospace); }
kbd { margin: 0px 0.1em; padding: 0.1em 0.6em; font-size: 0.8em; color: rgb(36, 39, 41); background: rgb(255, 255, 255); border: 1px solid rgb(173, 179, 185); border-radius: 3px; box-shadow: rgba(12, 13, 14, 0.2) 0px 1px 0px, rgb(255, 255, 255) 0px 0px 0px 2px inset; white-space: nowrap; vertical-align: middle; }
.md-comment { color: rgb(162, 127, 3); opacity: 0.8; font-family: var(--monospace); }
code { text-align: left; vertical-align: initial; }
a.md-print-anchor { white-space: pre !important; border-width: initial !important; border-style: none !important; border-color: initial !important; display: inline-block !important; position: absolute !important; width: 1px !important; right: 0px !important; outline: 0px !important; background: 0px 0px !important; text-decoration: initial !important; text-shadow: initial !important; }
.md-inline-math .MathJax_SVG .noError { display: none !important; }
.md-math-block .MathJax_SVG_Display { text-align: center; margin: 0px; position: relative; text-indent: 0px; max-width: none; max-height: none; min-height: 0px; min-width: 100%; width: auto; overflow-y: hidden; display: block !important; }
.MathJax_SVG_Display, .md-inline-math .MathJax_SVG_Display { width: auto; margin: inherit; display: inline-block !important; }
.MathJax_SVG .MJX-monospace { font-family: var(--monospace); }
.MathJax_SVG .MJX-sans-serif { font-family: sans-serif; }
.MathJax_SVG { display: inline; font-style: normal; font-weight: 400; line-height: normal; zoom: 90%; text-indent: 0px; text-align: left; text-transform: none; letter-spacing: normal; word-spacing: normal; word-wrap: normal; white-space: nowrap; float: none; direction: ltr; max-width: none; max-height: none; min-width: 0px; min-height: 0px; border: 0px; padding: 0px; margin: 0px; }
.MathJax_SVG * { transition: none; }
.MathJax_SVG_Display svg { vertical-align: middle !important; margin-bottom: 0px !important; }
.os-windows.monocolor-emoji .md-emoji { font-family: "Segoe UI Symbol", sans-serif; }
.md-diagram-panel > svg { max-width: 100%; }
[lang="mermaid"] svg, [lang="flow"] svg { max-width: 100%; }
[lang="mermaid"] .node text { font-size: 1rem; }
table tr th { border-bottom: 0px; }
video { max-width: 100%; display: block; margin: 0px auto; }
iframe { max-width: 100%; width: 100%; border: none; }
.highlight td, .highlight tr { border: 0px; }
:root { --side-bar-bg-color: #fafafa; --control-text-color: #777; }
@font-face { font-family: "Open Sans"; font-style: normal; font-weight: normal; src: local("Open Sans Regular"), url("./github/400.woff") format("woff"); }
@font-face { font-family: "Open Sans"; font-style: italic; font-weight: normal; src: local("Open Sans Italic"), url("./github/400i.woff") format("woff"); }
@font-face { font-family: "Open Sans"; font-style: normal; font-weight: bold; src: local("Open Sans Bold"), url("./github/700.woff") format("woff"); }
@font-face { font-family: "Open Sans"; font-style: italic; font-weight: bold; src: local("Open Sans Bold Italic"), url("./github/700i.woff") format("woff"); }
html { font-size: 16px; }
body { font-family: "Open Sans", "Clear Sans", "Helvetica Neue", Helvetica, Arial, sans-serif; color: rgb(51, 51, 51); line-height: 1.6; }
#write { max-width: 860px; margin: 0px auto; padding: 20px 30px 100px; }
#write > ul:first-child, #write > ol:first-child { margin-top: 30px; }
body > :first-child { margin-top: 0px !important; }
body > :last-child { margin-bottom: 0px !important; }
a { color: rgb(65, 131, 196); }
h1, h2, h3, h4, h5, h6 { position: relative; margin-top: 1rem; margin-bottom: 1rem; font-weight: bold; line-height: 1.4; cursor: text; }
h1:hover a.anchor, h2:hover a.anchor, h3:hover a.anchor, h4:hover a.anchor, h5:hover a.anchor, h6:hover a.anchor { text-decoration: none; }
h1 tt, h1 code { font-size: inherit; }
h2 tt, h2 code { font-size: inherit; }
h3 tt, h3 code { font-size: inherit; }
h4 tt, h4 code { font-size: inherit; }
h5 tt, h5 code { font-size: inherit; }
h6 tt, h6 code { font-size: inherit; }
h1 { padding-bottom: 0.3em; font-size: 2.25em; line-height: 1.2; border-bottom: 1px solid rgb(238, 238, 238); }
h2 { padding-bottom: 0.3em; font-size: 1.75em; line-height: 1.225; border-bottom: 1px solid rgb(238, 238, 238); }
h3 { font-size: 1.5em; line-height: 1.43; }
h4 { font-size: 1.25em; }
h5 { font-size: 1em; }
h6 { font-size: 1em; color: rgb(119, 119, 119); }
p, blockquote, ul, ol, dl, table { margin: 0.8em 0px; }
li > ol, li > ul { margin: 0px; }
hr { height: 2px; padding: 0px; margin: 16px 0px; background-color: rgb(231, 231, 231); border: 0px none; overflow: hidden; box-sizing: content-box; }
body > h2:first-child { margin-top: 0px; padding-top: 0px; }
body > h1:first-child { margin-top: 0px; padding-top: 0px; }
body > h1:first-child + h2 { margin-top: 0px; padding-top: 0px; }
body > h3:first-child, body > h4:first-child, body > h5:first-child, body > h6:first-child { margin-top: 0px; padding-top: 0px; }
a:first-child h1, a:first-child h2, a:first-child h3, a:first-child h4, a:first-child h5, a:first-child h6 { margin-top: 0px; padding-top: 0px; }
h1 p, h2 p, h3 p, h4 p, h5 p, h6 p { margin-top: 0px; }
li p.first { display: inline-block; }
ul, ol { padding-left: 30px; }
ul:first-child, ol:first-child { margin-top: 0px; }
ul:last-child, ol:last-child { margin-bottom: 0px; }
blockquote { border-left: 4px solid rgb(223, 226, 229); padding: 0px 15px; color: rgb(119, 119, 119); }
blockquote blockquote { padding-right: 0px; }
table { padding: 0px; word-break: initial; }
table tr { border-top: 1px solid rgb(223, 226, 229); margin: 0px; padding: 0px; }
table tr:nth-child(2n), thead { background-color: rgb(248, 248, 248); }
table tr th { font-weight: bold; border-width: 1px 1px 0px; border-top-style: solid; border-right-style: solid; border-left-style: solid; border-top-color: rgb(223, 226, 229); border-right-color: rgb(223, 226, 229); border-left-color: rgb(223, 226, 229); border-image: initial; border-bottom-style: initial; border-bottom-color: initial; text-align: left; margin: 0px; padding: 6px 13px; }
table tr td { border: 1px solid rgb(223, 226, 229); text-align: left; margin: 0px; padding: 6px 13px; }
table tr th:first-child, table tr td:first-child { margin-top: 0px; }
table tr th:last-child, table tr td:last-child { margin-bottom: 0px; }
.CodeMirror-lines { padding-left: 4px; }
.code-tooltip { box-shadow: rgba(0, 28, 36, 0.3) 0px 1px 1px 0px; border-top: 1px solid rgb(238, 242, 242); }
.md-fences, code, tt { border: 1px solid rgb(231, 234, 237); background-color: rgb(248, 248, 248); border-radius: 3px; padding: 2px 4px 0px; font-size: 0.9em; }
code { background-color: rgb(243, 244, 244); padding: 0px 4px 2px; }
.md-fences { margin-bottom: 15px; margin-top: 15px; padding: 8px 1em 6px; }
.md-task-list-item > input { margin-left: -1.3em; }
@media screen and (min-width: 914px) {
}
@media print {
html { font-size: 13px; }
table, pre { break-inside: avoid; }
pre { word-wrap: break-word; }
}
.md-fences { background-color: rgb(248, 248, 248); }
#write pre.md-meta-block { padding: 1rem; font-size: 85%; line-height: 1.45; background-color: rgb(247, 247, 247); border: 0px; border-radius: 3px; color: rgb(119, 119, 119); margin-top: 0px !important; }
.mathjax-block > .code-tooltip { bottom: 0.375rem; }
.md-mathjax-midline { background: rgb(250, 250, 250); }
#write > h3.md-focus::before { left: -1.5625rem; top: 0.375rem; }
#write > h4.md-focus::before { left: -1.5625rem; top: 0.285714rem; }
#write > h5.md-focus::before { left: -1.5625rem; top: 0.285714rem; }
#write > h6.md-focus::before { left: -1.5625rem; top: 0.285714rem; }
.md-image > .md-meta { border-radius: 3px; padding: 2px 0px 0px 4px; font-size: 0.9em; color: inherit; }
.md-tag { color: rgb(167, 167, 167); opacity: 1; }
.md-toc { margin-top: 20px; padding-bottom: 20px; }
.sidebar-tabs { border-bottom: none; }
#typora-quick-open { border: 1px solid rgb(221, 221, 221); background-color: rgb(248, 248, 248); }
#typora-quick-open-item { background-color: rgb(250, 250, 250); border-color: rgb(254, 254, 254) rgb(229, 229, 229) rgb(229, 229, 229) rgb(238, 238, 238); border-style: solid; border-width: 1px; }
.on-focus-mode blockquote { border-left-color: rgba(85, 85, 85, 0.12); }
header, .context-menu, .megamenu-content, footer { font-family: "Segoe UI", Arial, sans-serif; }
.file-node-content:hover .file-node-icon, .file-node-content:hover .file-node-open-state { visibility: visible; }
.mac-seamless-mode #typora-sidebar { background-color: var(--side-bar-bg-color); }
.md-lang { color: rgb(180, 101, 77); }
.html-for-mac .context-menu { --item-hover-bg-color: #E6F0FE; }
.typora-export p, .typora-export .footnote-line {white-space: normal;}
-->