Python之路【第十八篇】Django小项目简单BBS论坛部分内容知识点
开发一个简单的BBS论坛
项目需求:
整体参考“抽屉新热榜” + “虎嗅网”
实现不同论坛版块
帖子列表展示
帖子评论数、点赞数展示
在线用户展示
允许登录用户发贴、评论、点赞
允许上传文件
帖子可被置顶
可进行多级评论
知识必备:(注:没有必备下面知识的同学,请返回去看会之后再看下面的内容防止蒙了~~!)
Django
HTML\CSS\JS
BootStrap
Jquery
设计表结构
1、表结构重要性
在开发任何项目的时候,设计到数据库,第一个事情要做的是设计表结构。表结构设计不好就不要写代码,表结构是体现了你业务逻辑关系的。你的数据都要往数据库里存,其实表结构你要理清了你的架构也就出来了!
2、设计表
#!/usr/bin/env python
#-*- coding:utf-8 -*- from __future__ import unicode_literals
from django.db import models
from django.contrib.auth.models import User # Create your models here. class Article(models.Model):
'''
帖子表
'''
#标题最大长度255,不能重名
title = models.CharField(u'文章标题',max_length=255,unique=True)
#发布办款-使用外键关联Category
category = models.ForeignKey("Category",verbose_name='板块名称')
'''
这里在admin中,title默认是显示英文的,我们可以在他的最前面加要给字段,在admin中就可以显示中文,他和verbose_name一样,什么时候必须使用
verbose_name呢?比如上面的{category = models.ForeignKey("Category",verbose_name='板块名称')} 这个字段第一个字段是关联的类,这里
就必须使用verbose_name
'''
#上传文件
head_img = models.ImageField(upload_to="uploads")
#文章内容(文章内容可能有很多,所以我们就不用"CharField"来写了,我们用TextField,不用规定他多长了,为可扩展长度)
content = models.TextField(u"内容")
#文章作者
author = models.ForeignKey("UserProfile",verbose_name="作者")
#发布日期
publish_date = models.DateTimeField(auto_now=True,verbose_name="发布日期")
#是否隐藏
hidden = models.BooleanField(default=False,verbose_name="是否隐藏")
#帖子的优先级
priority = models.IntegerField(default=1000,verbose_name="优先级") def __unicode__(self):
return "<%s,author:%s>" % (self.title,self.author) class Comment(models.Model):
'''
评论表
'''
#评论是基于文章的,并且一条评论只属于一个文章!对多的关系
#一个文章可以有多个评论,一个评论只属于一个文章
#评论文章
article = models.ForeignKey("Article")
#评论用户
user = models.ForeignKey("UserProfile")
#评论内容
comment = models.TextField(max_length=1000)
#评论时间
date = models.DateTimeField(auto_now=True) #多级评论,是不是评论评论的当前的表(自己表),所以就得和自己做一个关联!
#这里在关联自己的时候必须设置一个related_name否则会报错冲突
#这里parent_comment,必须设置为可以为空,因为如果他是第一评论他是没有父ID的
parent_comment = models.ForeignKey("self",related_name='p_comment',blank=True,null=True)
'''
prent self
Null 1
1 2
1 3
2 4
通过上面的这种方法来记录,评论的级别关系!
'''
def __unicode__(self):
return "<user:%s>" %(self.user)
class ThumbUp(models.Model):
'''
点赞
'''
#给那个文章点的
article = models.ForeignKey('Article')
#用户名
user = models.ForeignKey('UserProfile')
#时间
date = models.DateTimeField(auto_now=True) class Category(models.Model):
'''
板块表
'''
#板块名称
name = models.CharField(max_length=64,unique=True,verbose_name="板块名称")
#板块管理员
admin = models.ManyToManyField("UserProfile",verbose_name="模块管理员")
def __unicode__(self):
return self.name class UserProfile(models.Model):
'''
用户表
'''
#使用Django提供的用户表,直接继承就可以了.在原生的User表里扩展!(原生的User表里就有用户名和密码)
#一定要使用OneToOne,如果是正常的ForeignKey的话就表示User中的记录可以对应UserProfile中的多条记录!
#并且OneToOne的实现不是在SQL级别实现的而是在代码基本实现的!
user = models.OneToOneField(User)
#名字
name = models.CharField(max_length=32)
#属组
groups = models.ManyToManyField("UserGroup") def __unicode__(self):
return self.name class UserGroup(models.Model):
'''
用户组表
'''
name = models.CharField(max_length=64,unique=True)
def __unicode__(self):
return self.name
配置Django Admin
配置admin注册model,不要忘记创建Django 管理员用户
from django.contrib import admin
import models
# Register your models here. admin.site.register(models.Article)
admin.site.register(models.Category)
admin.site.register(models.Comment)
admin.site.register(models.ThumbUp)
admin.site.register(models.UserProfile)
admin.site.register(models.UserGroup)
我创建了几个板块,我在板块中查看的时候。只能看到下面简单的信息:

这里我想看到板块中的ID或其他信息怎么办?
#!/usr/bin/env python
#-*- coding:utf-8 -*- from django.contrib import admin
import models
# Register your models here. #给某个表专门的定制的类
class CategoryAdmin(admin.ModelAdmin):
list_display = ('id','name') class ArticleAdmin(admin.ModelAdmin):
list_display = ('id','title','author','hidden','publish_date') admin.site.register(models.Article,ArticleAdmin) #把自定义的类绑定到注册的类中
admin.site.register(models.Category,CategoryAdmin) #把自定义的类绑定到注册的类中
admin.site.register(models.Comment)
admin.site.register(models.ThumbUp)
admin.site.register(models.UserProfile)
admin.site.register(models.UserGroup)
效果如下:

前端页面&URLorViews配置
1、url别名使用
url里配置别名
url(r'^category/(\d+)/$',views.category,name='category'),
html里配置的时候就只认那个别名了
<li role="presentation"><a href="{% url 'category' 1 %}">欧美专区</a></li>
<li role="presentation"><a href="{% url 'category' 2 %}">日韩专区</a></li>
<li role="presentation"><a href="{% url 'category' 3 %}">印度专区</a></li>
别名的好处:如果说那天想修改url里的这个url名称了,是不是所有前端都得修改!并且在有好几层的时候怎么改使用别名就会非常方便了!
2、前端页面写完之后发现图片无法正常显示

出现这个问题的原因:他能找到uploads这个目录吗?他能直接访问这个目录吗?他不能直接访问不了!
- 一个是在Linux环境下做一个软连接连接过去
如果在settings里加入uploads这个目录,但是这个方法还是有问题!他会去找/static/uploads/uploads目录,看下面的图!

但是通过下面的方式就可以访问(原因就是因为:他去/static/uploads/uploads目录找了)

2.2、我们自己写上传的方法
定义form表单认证
#!/usr/bin/env python
#-*- coding:utf-8 -*-
# Tim Luo LuoTianShuai from django import forms class ArticleForm(forms.Form):
title = forms.CharField(max_length=255,min_length=5)
summary = forms.CharField(max_length=255,min_length=5)
head_img = forms.ImageField()
content = forms.CharField(min_length=10)
category_id = forms.IntegerField()
定义上传方法
#!/usr/bin/env python
#-*- coding:utf-8 -*-
# Tim Luo LuoTianShuai
import os def handle_upload_file(f,request): #f这里获取到文件句柄
base_img_upload_path = 'static/Uploads'
user_path = "%s/%s" % (base_img_upload_path,request.user.userprofile.id)
if not os.path.exists(user_path):
os.mkdir(user_path)
with open('%s/%s'% (user_path,f.name),'wb+') as destinations:
for chunk in f.chunks():
destinations.write(chunk)
#为了防止用户传送图片进行冲突,我们为每个用户进行创建用户 return "/static/Uploads/%s/%s" % (request.user.userprofile.id,f.name)
定义views
def new_article(request):
category_list = models.Category.objects.all()
if request.method == 'POST':
form = ArticleForm(request.POST,request.FILES)
if form.is_valid():
form_data = form.cleaned_data
form_data['author_id'] = request.user.userprofile.id #自定义图片上传
new_img_path = handle_upload_file(request.FILES['head_img'],request)
#但是在views也保存了一份,我们给他改掉改成我们自己的就行了
form_data['head_img'] = new_img_path #create只能返回成功失败,我想在创建完成之后返回文章的ID,直接下面那么写就可以
print form_data
new_article_obj = models.Article(**form_data)
new_article_obj.save()#这个对象就直接返回了
return render(request,'new_article.html',{'new_article_obj':new_article_obj}) #如果没有这个变量说明是创建新文章呢
else:
print form.errors return render(request,'new_article.html',{'category_list':category_list})
多级评论实现
用户可以直接对贴子进行评论,其它用户也可以对别的用户的评论再进行评论,也就是所谓的垒楼,如下图:

所有的评论都存在一张表中, 评论与评论之前又有从属关系,如何在前端 页面上把这种层级关系体现出来?
首先咱们在存储数据的时候是怎么来实现记录层级关系的呢?(下面的图是经过简化的把其他列隐藏了)

我们在上面创建数据库表结构的时候,就定义了一个外键为他们自己(parent_comment_id),如果他没有父级别的ID说明他们是第一层,如果有说明他包含在一个评论之内!(仔细看上面的表结构)
先把评论简化成一个这样的模型:
data = [
(None,'A'),
('A','A1'),
('A','A1-1'),
('A1','A2'),
('A1-1','A2-3'),
('A2-3','A3-4'),
('A1','A2-2'),
('A2','A3'),
('A2-2','A3-3'),
('A3','A4'),
(None,'B'),
('B','B1'),
('B1','B2'),
('B1','B2-2'),
('B2','B3'),
(None,'C'),
('C','C1'), ]
转换为字典之后:
data_dic = {
'A': {
'A1': {
'A2':{
'A3':{
'A4':{}
}
},
'A2-2':{
'A3-3':{}
}
}
},
'B':{
'B1':{
'B2':{
'B3':{}
},
'B2-2':{}
}
},
'C':{
'C1':{}
}
}
看上面的字典,我们能通过for循来获取他有多少层吗?当然不行,我们不知道他有多少层就没有办法进行找,或者通过while循环,最好是用递归进行一层一层的查找!
我们在前端展示的时候需要知道,那条数据是那一层的,不可能是垒下去的!因为他们是有层级关系的!
我们用后端来实现:咱们给前端返回一个字典这样是不行的,咱们在后端把层级关系建立起来~返回的时候直接返回一个完整的HTML
转换为字典之后就有层级关系了我们可以通过递归来实现了!上面再没有转换为字典的时候层级关系就不是很明确了!
在循环的过程中不断的创建字典,先建立最顶级的,然后在一层一层的建立
先通过一个简单的例子看下:
#!/usr/bin/env python
#-*- coding:utf-8 -*-
# Tim Luo LuoTianShuai data = [
(None,'A'),
('A','A1'),
('A','A1-1'),
('A1','A2'),
('A1-1','A2-3'),
('A2-3','A3-4'),
('A1','A2-2'),
('A2','A3'),
('A2-2','A3-3'),
('A3','A4'),
(None,'B'),
('B','B1'),
('B1','B2'),
('B1','B2-2'),
('B2','B3'),
(None,'C'),
('C','C1'), ] def tree_search(d_dic,parent,son):
#一层一层找,先拨第一层,一层一层往下找
for k,v in d_dic.items():
#举例来说我先遇到A,我就把A来个深度查询,A没有了在找B
if k == parent:#如果等于就找到了parent,就吧son加入到他下面
d_dic[k][son] = {} #son下面可能还有儿子
#这里找到就直接return了,你找到就直接退出就行了
return
else:
#如果没有找到,有可能还有更深的地方,的需要剥掉一层
tree_search(d_dic[k],parent,son) data_dic = {} for item in data:
# 每一个item代表两个值一个父亲一个儿子
parent,son = item
#先判断parent是否为空,如果为空他就是顶级的,直接吧他加到data_dic
if parent is None:
data_dic[son] = {} #这里如果为空,那么key就是他自己,他儿子就是一个空字典
else:
'''
如果不为空他是谁的儿子呢?举例来说A3他是A2的儿子,但是你能直接判断A3的父亲是A2你能直接判断他是否在A里面吗?你只能到第一层.key
所以咱们就得一层一层的找,我们知道A3他爹肯定在字典里了,所以就得一层一层的找,但是不能循环找,因为你不知道他有多少层,所以通过递归去找
直到找到位置
'''
tree_search(data_dic,parent,son) #因为你要一层一层找,你的把data_dic传进去,还的把parent和son传进去 for k,v in data_dic.items():
print(k,v)
执行结果:(完美)
('A', {'A1': {'A2': {'A3': {'A4': {}}}, 'A2-2': {'A3-3': {}}}, 'A1-1': {'A2-3': {'A3-4': {}}}})
('C', {'C1': {}})
('B', {'B1': {'B2-2': {}, 'B2': {'B3': {}}}})
2、前端返回
当咱们把这个字典往前端返回的时候,前端模板里是没有一个语法递归的功能的,虽然咱们的层级关系已经出来了!所以咱们需要自定义一个模板语言然后拼成一个html然后返回给前端展示!
2.1、配置前端吧数据传给simple_tag
{% load custom_tags %}
{% build_comment_tree article_obj.comment_set.select_related %}
2.2、simple_tag获取数据然后把用户穿过来的数据进行转换为字典
#!/usr/bin/env python
# -*- coding:utf-8 -*-
from django import template
from django.utils.safestring import mark_safe register = template.Library() def tree_search(d_dic,comment_obj):#这里不用传附近和儿子了因为他是一个对象,可以直接找到父亲和儿子
for k,v_dic in d_dic.items():
if k == comment_obj.parent_comment:#如果找到了
d_dic[k][comment_obj] = {} #如果找到父亲了,你的把自己存放在父亲下面,并把自己当做key,value为一个空字典
return
else:#如果找不到递归查找
tree_search(d_dic[k],comment_obj) @register.simple_tag
def build_comment_tree(comment_list):
'''
把评论传过来只是一个列表格式(如下),要把列别转换为字典,在把字典拼接为html
[<Comment: <A,user:罗天帅>>, <Comment: <A2-1,user:罗天帅>>, <Comment: <A3-1,user:罗天帅>>, <Comment: <A2-2,user:罗天帅>>,
<Comment: <A4-1,user:罗天帅>>, <Comment: <A4-2,user:罗天帅>>, <Comment: <A5-1,user:罗天帅>>, <Comment: <A3-2,user:罗天帅>>,
<Comment: <B2,user:罗天帅>>, <Comment: <B2-1,user:罗天帅>>]
:param comment_list:
:return:
'''
comment_dic = {}
#print(comment_list)
for comment_obj in comment_list: #每一个元素都是一个对象
if comment_obj.parent_comment is None: #如果没有父亲
comment_dic[comment_obj] = {}
else:
#通过递归找
tree_search(comment_dic,comment_obj) # #测试:
# for k,v in comment_dic.items():
# print(k,v) # 上面完成之后开始递归拼接字符串
2、3生成html标签
#!/usr/bin/env python
# -*- coding:utf-8 -*-
from django import template
from django.utils.safestring import mark_safe register = template.Library() def tree_search(d_dic,comment_obj):#这里不用传附近和儿子了因为他是一个对象,可以直接找到父亲和儿子
for k,v_dic in d_dic.items():
if k == comment_obj.parent_comment:#如果找到了
d_dic[k][comment_obj] = {} #如果找到父亲了,你的把自己存放在父亲下面,并把自己当做key,value为一个空字典
return
else:#如果找不到递归查找
tree_search(d_dic[k],comment_obj) def generate_comment_html(sub_comment_dic):
#先创建一个html默认为空
html = ""
for k,v_dic in sub_comment_dic.items():#循环穿过来的字典
html += "<div class='comment-node'>" + k.comment + "</div>"
#上面的只是把第一层加了他可能还有儿子,所以通过递归继续加
if v_dic:
html += generate_comment_html(v_dic)
return html @register.simple_tag
def build_comment_tree(comment_list):
'''
把评论传过来只是一个列表格式(如下),要把列别转换为字典,在把字典拼接为html
[<Comment: <A,user:罗天帅>>, <Comment: <A2-1,user:罗天帅>>, <Comment: <A3-1,user:罗天帅>>, <Comment: <A2-2,user:罗天帅>>,
<Comment: <A4-1,user:罗天帅>>, <Comment: <A4-2,user:罗天帅>>, <Comment: <A5-1,user:罗天帅>>, <Comment: <A3-2,user:罗天帅>>,
<Comment: <B2,user:罗天帅>>, <Comment: <B2-1,user:罗天帅>>]
:param comment_list:
:return:
'''
comment_dic = {}
#print(comment_list)
for comment_obj in comment_list: #每一个元素都是一个对象
if comment_obj.parent_comment is None: #如果没有父亲
comment_dic[comment_obj] = {}
else:
#通过递归找
tree_search(comment_dic,comment_obj) # #测试:
# for k,v in comment_dic.items():
# print(k,v) # 上面完成之后开始递归拼接字符串 #div框架
html = "<div class='comment-box'>"
margin_left = 0
for k,v in comment_dic.items():
#第一层的html
html += "<div class='comment-node'>" + k.comment + "</div>"
#通过递归把他儿子加上
html += generate_comment_html(v)
html += "</div>"
return mark_safe(html)
效果如下:

2.4、上面的看起来不是很好看怎么办?给他增加一个margin-left让他来显示层级效果,每次进行递归的时候给他加一个值!
#!/usr/bin/env python
# -*- coding:utf-8 -*-
from django import template
from django.utils.safestring import mark_safe register = template.Library() def tree_search(d_dic,comment_obj):#这里不用传附近和儿子了因为他是一个对象,可以直接找到父亲和儿子
for k,v_dic in d_dic.items():
if k == comment_obj.parent_comment:#如果找到了
d_dic[k][comment_obj] = {} #如果找到父亲了,你的把自己存放在父亲下面,并把自己当做key,value为一个空字典
return
else:#如果找不到递归查找
tree_search(d_dic[k],comment_obj) def generate_comment_html(sub_comment_dic,margin_left_val):
#先创建一个html默认为空
html = ""
for k,v_dic in sub_comment_dic.items():#循环穿过来的字典
html += "<div style='margin-left:%spx' class='comment-node'>" % margin_left_val + k.comment + "</div>"
#上面的只是把第一层加了他可能还有儿子,所以通过递归继续加
if v_dic:
html += generate_comment_html(v_dic,margin_left_val+15)
return html @register.simple_tag
def build_comment_tree(comment_list):
'''
把评论传过来只是一个列表格式(如下),要把列别转换为字典,在把字典拼接为html
[<Comment: <A,user:罗天帅>>, <Comment: <A2-1,user:罗天帅>>, <Comment: <A3-1,user:罗天帅>>, <Comment: <A2-2,user:罗天帅>>,
<Comment: <A4-1,user:罗天帅>>, <Comment: <A4-2,user:罗天帅>>, <Comment: <A5-1,user:罗天帅>>, <Comment: <A3-2,user:罗天帅>>,
<Comment: <B2,user:罗天帅>>, <Comment: <B2-1,user:罗天帅>>]
:param comment_list:
:return:
'''
comment_dic = {}
#print(comment_list)
for comment_obj in comment_list: #每一个元素都是一个对象
if comment_obj.parent_comment is None: #如果没有父亲
comment_dic[comment_obj] = {}
else:
#通过递归找
tree_search(comment_dic,comment_obj) # #测试:
# for k,v in comment_dic.items():
# print(k,v) # 上面完成之后开始递归拼接字符串 #div框架
html = "<div class='comment-box'>"
margin_left = 0
for k,v in comment_dic.items():
#第一层的html
html += "<div class='comment-node'>" + k.comment + "</div>"
#通过递归把他儿子加上
html += generate_comment_html(v,margin_left+15)
html += "</div>"
return mark_safe(html)
效果如下:

Python之路【第十八篇】Django小项目简单BBS论坛部分内容知识点的更多相关文章
- Django小项目简单BBS论坛
开发一个简单的BBS论坛 项目需求: 1 整体参考"抽屉新热榜" + "虎嗅网" 2 实现不同论坛版块 3 帖子列表展示 4 帖子评论数.点赞数展示 5 在线用 ...
- Python之路(第二十八篇) 面向对象进阶:类的装饰器、元类
一.类的装饰器 类作为一个对象,也可以被装饰. 例子 def wrap(obj): print("装饰器-----") obj.x = 1 obj.y = 3 obj.z = 5 ...
- Python之路(第十八篇)shutil 模块、zipfile模块、configparser模块
一.shutil 模块 1.shutil.copyfileobj(fsrc, fdst[, length]) 将文件内容拷贝到另一个文件中,需要打开文件 import shutil shutil.co ...
- Python之路【第八篇】:堡垒机实例以及数据库操作
Python之路[第八篇]:堡垒机实例以及数据库操作 堡垒机前戏 开发堡垒机之前,先来学习Python的paramiko模块,该模块机遇SSH用于连接远程服务器并执行相关操作 SSHClient ...
- Python开发【第十八篇】Web框架之Django【基础篇】
一.简介 Python下有许多款不同的 Web 框架,Django 是重量级选手中最有代表性的一位,许多成功的网站和APP都基于 Django. Django 是一个开放源代码的Web应用框架,由 P ...
- Python自动化 【第十八篇】:JavaScript 正则表达式及Django初识
本节内容 JavaScript 正则表达式 Django初识 正则表达式 1.定义正则表达式 /.../ 用于定义正则表达式 /.../g 表示全局匹配 /.../i 表示不区分大小写 /.../m ...
- Python之路【第八篇】:Python模块
阅读目录 一.模块和包 模块(module)的概念: 在计算机程序的开发过程中,随着程序代码越写越多,在一个文件里代码会越来越长,越来越不容易维护. 为了编写可维护的代码,我们把很多函数分组,分别放到 ...
- Python之路【第八篇】:面向对象的程序设计
阅读目录 一 面向对象的程序设计的由来二 什么是面向对象的程序设计及为什么要有它三 类和对象3.1 什么是对象,什么是类3.2 类相关知识3.3 对象相关知识3.4 对象之间的交互3.5 类名称空间与 ...
- 【Python之路】第二十三篇--Django【进阶篇】
文件配置 1.模版Templates文件配置: TEMPLATE_DIRS = ( os.path.join(BASE_DIR,'templates'), ) 2.静态文件static配置: STAT ...
随机推荐
- Spring MVC拦截器+注解方式实现防止表单重复提交
原理:在新建页面中Session保存token随机码,当保存时验证,通过后删除,当再次点击保存时由于服务器端的Session中已经不存在了,所有无法验证通过. 注,如果是集群的方式,则需要将token ...
- shell统计指定范围内的所有质数以及它们的和
#!bin/bash a= $) ;do n= $x);do ];then n=$[$n+] fi done ];then { echo -n -e "$x\t" sum=$[$s ...
- [python]爬虫学习(二)
---恢复内容开始--- #python2 import urllib2 #python3 import urllib.request html=urllib.request.urlopen('htt ...
- 域用户执行金蝶K/3报错解决方法
自从上星期测试加域意外将公司考勤系统整出事后,就再也不敢在物理机测试了. 装好虚拟机和装好金蝶K/3系统后,被这条报错信息折腾了好几天,一方面是不熟悉该软件,另一方面是几乎搜不到相关的文章. 一.问题 ...
- 【小白的CFD之旅】16 流程
那天听了小牛师兄关于CFD应用的四种境界的说法后,小白发现自己连第一种境界都算不上,自己对于CFD还只是停留在做了少数几个案例的基础上,可以说是对其一无所知.不过小白不是那种遇到挫折就退缩的人,他决定 ...
- [WPF系列]-数据邦定之DataTemplate 根据对象属性切换模板
引言 书接上回[WPF系列-数据邦定之DataTemplate],本篇介绍如何根据属性切换模板(DataTemplate) 切换模板的两种方式: 使用DataTemplateSelecto ...
- MMORPG大型游戏设计与开发(服务器 游戏场景 掉落与网络连接)
时间一点点的消逝,伴着自己空闲日子将要结束的时候我尽量的学习和分享场景和AI的知识给朋友们,不过很遗憾的是这些文章还有不足的地方,就是有的难点没有完全的分析到.掉落在游戏中必不可少的,同时网络连接也是 ...
- 与JSP的初次邂逅……
JSP是可以内嵌在网页中,由服务器端来执行与解释的程序,是一种动态网页技术标准. 在传统的HTML文件(*.htm或*.html)中加入Java程序片段和JSP标记,就构成了JSP网页(*.jsp). ...
- HTML中的div,section,article的区别
刚开始看到标签的就有些疑惑,觉得为什么有那么多相同用途的标签,多方查询资料细细比较之后才发现原来各有千秋,结合自己的想法总结如下: div在HTML早期版本就支持了,section和article是H ...
- BZOJ 2330: [SCOI2011]糖果 [差分约束系统] 【学习笔记】
2330: [SCOI2011]糖果 Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 5395 Solved: 1750[Submit][Status ...