Commit 39f70bd3 authored by jackfrued's avatar jackfrued

更新了Django第4天代码

parent a8428301
import pymysql
pymysql.install_as_MySQLdb()
\ No newline at end of file
"""
Django settings for car project.
Generated by 'django-admin startproject' using Django 2.0.5.
For more information on this file, see
https://docs.djangoproject.com/en/2.0/topics/settings/
For the full list of settings and their values, see
https://docs.djangoproject.com/en/2.0/ref/settings/
"""
import os
# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/2.0/howto/deployment/checklist/
# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = 'ol6dmf6im(w!l*z4w+_whm&)8@(c7%4&tlhd%uh6$lfx=pi*5e'
# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True
ALLOWED_HOSTS = []
# Application definition
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'search',
]
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
]
ROOT_URLCONF = 'car.urls'
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [os.path.join(BASE_DIR, 'templates')]
,
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
],
},
},
]
WSGI_APPLICATION = 'car.wsgi.application'
# Database
# https://docs.djangoproject.com/en/2.0/ref/settings/#databases
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': 'car',
'HOST': 'localhost',
'PORT': 3306,
'USER': 'root',
'PASSWORD': '123456',
}
}
# Password validation
# https://docs.djangoproject.com/en/2.0/ref/settings/#auth-password-validators
AUTH_PASSWORD_VALIDATORS = [
{
'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
},
]
# Internationalization
# https://docs.djangoproject.com/en/2.0/topics/i18n/
LANGUAGE_CODE = 'en-us'
TIME_ZONE = 'UTC'
USE_I18N = True
USE_L10N = True
USE_TZ = True
# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/2.0/howto/static-files/
STATICFILES_DIRS = [os.path.join(BASE_DIR, 'static')]
STATIC_URL = '/static/'
"""car URL Configuration
The `urlpatterns` list routes URLs to views. For more information please see:
https://docs.djangoproject.com/en/2.0/topics/http/urls/
Examples:
Function views
1. Add an import: from my_app import views
2. Add a URL to urlpatterns: path('', views.home, name='home')
Class-based views
1. Add an import: from other_app.views import Home
2. Add a URL to urlpatterns: path('', Home.as_view(), name='home')
Including another URLconf
1. Import the include() function: from django.urls import include, path
2. Add a URL to urlpatterns: path('blog/', include('blog.urls'))
"""
from django.contrib import admin
from django.conf.urls import url
from search import views
urlpatterns = [
url(r'^search$', views.search),
url(r'^search2$', views.ajax_search),
url(r'^add', views.add),
url(r'^admin/', admin.site.urls),
]
"""
WSGI config for car project.
It exposes the WSGI callable as a module-level variable named ``application``.
For more information on this file, see
https://docs.djangoproject.com/en/2.0/howto/deployment/wsgi/
"""
import os
from django.core.wsgi import get_wsgi_application
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "car.settings")
application = get_wsgi_application()
#!/usr/bin/env python
import os
import sys
if __name__ == "__main__":
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "car.settings")
try:
from django.core.management import execute_from_command_line
except ImportError as exc:
raise ImportError(
"Couldn't import Django. Are you sure it's installed and "
"available on your PYTHONPATH environment variable? Did you "
"forget to activate a virtual environment?"
) from exc
execute_from_command_line(sys.argv)
from django.contrib import admin
from search.models import CarRecord
class CarRecordAdmin(admin.ModelAdmin):
list_display = ('carno', 'reason', 'date', 'punish', 'isdone')
search_fields = ('carno', )
admin.site.register(CarRecord, CarRecordAdmin)
from django.apps import AppConfig
class SearchConfig(AppConfig):
name = 'search'
# -*- coding: utf-8 -*-
# Generated by Django 1.11 on 2018-05-24 01:16
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
initial = True
dependencies = [
]
operations = [
migrations.CreateModel(
name='CarRecord',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('carno', models.CharField(max_length=7)),
('reason', models.CharField(max_length=50)),
('date', models.DateTimeField(db_column='happen_date')),
('punlish', models.CharField(max_length=50)),
('isdone', models.BooleanField(default=False)),
],
options={
'db_table': 'tb_car_record',
},
),
]
# -*- coding: utf-8 -*-
# Generated by Django 1.11 on 2018-05-24 06:20
from __future__ import unicode_literals
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('search', '0001_initial'),
]
operations = [
migrations.AlterModelOptions(
name='carrecord',
options={'ordering': ('-date',)},
),
migrations.RenameField(
model_name='carrecord',
old_name='punlish',
new_name='punish',
),
]
from django.db import models
class CarRecord(models.Model):
carno = models.CharField(max_length=7)
reason = models.CharField(max_length=50)
date = models.DateTimeField(db_column='happen_date', auto_now_add=True)
punish = models.CharField(max_length=50)
isdone = models.BooleanField(default=False)
@property
def happen_date(self):
return self.date.strftime('%Y-%m-%d %H:%M:%S')
"""
return '%d年%02d月%02d日 %02d:%02d:%02d' % \
(self.date.year, self.date.month, self.date.day,
self.date.hour, self.date.minute, self.date.second)
"""
class Meta:
db_table = 'tb_car_record'
ordering = ('-date', )
from django.test import TestCase
# Create your tests here.
from json import JSONEncoder
from django import forms
from django.http import JsonResponse
from django.shortcuts import render
from search.models import CarRecord
# 序列化/串行化/腌咸菜 - 把对象按照某种方式处理成字节或者字符的序列
# 反序列化/反串行化 - 把字符或者字节的序列重新还原成对象
# Python实现序列化和反序列化的工具模块 - json / pickle / shelve
# return HttpResponse(json.dumps(obj), content_type='application/json')
# return JsonResponse(obj, encoder=, safe=False)
# from django.core.serializers import serialize
# return HttpResponse(serialize('json', obj), content_type='application/json; charset=utf-8')
class CarRecordEncoder(JSONEncoder):
def default(self, o):
del o.__dict__['_state']
o.__dict__['date'] = o.happen_date
return o.__dict__
def ajax_search(request):
if request.method == 'GET':
return render(request, 'search2.html')
else:
carno = request.POST['carno']
record_list = list(CarRecord.objects.filter(carno__icontains=carno))
# 第一个参数是要转换成JSON格式(序列化)的对象
# encoder参数要指定完成自定义对象序列化的编码器(JSONEncoder的子类型)
# safe参数的值如果为True那么传入的第一个参数只能是字典
# return HttpResponse(json.dumps(record_list), content_type='application/json; charset=utf-8')
return JsonResponse(record_list, encoder=CarRecordEncoder,
safe=False)
def search(request):
# 请求行中的请求命令
# print(request.method)
# 请求行中的路径
# print(request.path)
# 请求头(以HTTP_打头的键是HTTP请求的请求头)
# print(request.META)
# 查询参数: http://host/path/resource?a=b&c=d
# print(request.GET)
# 表单参数
# print(request.POST)
if request.method == 'GET':
ctx = {'show_result': False}
else:
carno = request.POST['carno']
ctx = {
'show_result': True,
'record_list': list(CarRecord.objects.filter(carno__contains=carno))}
return render(request, 'search.html', ctx)
class CarRecordForm(forms.Form):
carno = forms.CharField(min_length=7, max_length=7, label='车牌号', error_messages={'carno': '请输入有效的车牌号'})
reason = forms.CharField(max_length=50, label='违章原因')
punish = forms.CharField(max_length=50, required=False, label='处罚方式')
def add(request):
errors = []
if request.method == 'GET':
f = CarRecordForm()
else:
f = CarRecordForm(request.POST)
if f.is_valid():
CarRecord(**f.cleaned_data).save()
f = CarRecordForm()
else:
errors = f.errors.values()
return render(request, 'add.html', {'f': f, 'errors': errors})
<svg width="13" height="13" viewBox="0 0 1792 1792" xmlns="http://www.w3.org/2000/svg">
<path fill="#dd4646" d="M1277 1122q0-26-19-45l-181-181 181-181q19-19 19-45 0-27-19-46l-90-90q-19-19-46-19-26 0-45 19l-181 181-181-181q-19-19-45-19-27 0-46 19l-90 90q-19 19-19 46 0 26 19 45l181 181-181 181q-19 19-19 45 0 27 19 46l90 90q19 19 46 19 26 0 45-19l181-181 181 181q19 19 45 19 27 0 46-19l90-90q19-19 19-46zm387-226q0 209-103 385.5t-279.5 279.5-385.5 103-385.5-103-279.5-279.5-103-385.5 103-385.5 279.5-279.5 385.5-103 385.5 103 279.5 279.5 103 385.5z"/>
</svg>
<svg width="13" height="13" viewBox="0 0 1792 1792" xmlns="http://www.w3.org/2000/svg">
<path fill="#70bf2b" d="M1412 734q0-28-18-46l-91-90q-19-19-45-19t-45 19l-408 407-226-226q-19-19-45-19t-45 19l-91 90q-18 18-18 46 0 27 18 45l362 362q19 19 45 19 27 0 46-19l543-543q18-18 18-45zm252 162q0 209-103 385.5t-279.5 279.5-385.5 103-385.5-103-279.5-279.5-103-385.5 103-385.5 279.5-279.5 385.5-103 385.5 103 279.5 279.5 103 385.5z"/>
</svg>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>添加</title>
</head>
<body>
<h2>添加违章记录</h2>
<hr>
<p>
{% for err in errors %}
<div style="color: red; font-size: 12px;">{{ err }}</div>
{% endfor %}
</p>
<form action="/add" method="post">
<table>
{{ f.as_table }}
</table>
{% csrf_token %}
<input type="submit" value="添加">
</form>
</body>
</html>
\ No newline at end of file
<!DOCTYPE html>
{% load staticfiles %}
<html lang="en">
<head>
<meta charset="UTF-8">
<title>车辆违章查询</title>
<style>
* {
font: 18px/30px Arial;
}
#container {
width: 960px;
margin: 0 auto;
}
#container form {
width: 620px;
margin: 10px auto;
padding-top: 100px;
}
#container form input[type=search] {
display: inline-block;
width: 480px;
height: 30px;
}
#container form input[type=submit] {
display: inline-block;
width: 80px;
height: 40px;
border: None;
background-color: red;
color: white;
margin-left: 20px;
}
#container table {
width: 920px;
margin: 20px auto;
border-collapse: collapse;
}
#container table th {
font-weight: bolder;
border-bottom: 1px solid darkgray;
}
#container table td {
text-align: center;
height: 50px;
width: 180px;
}
</style>
</head>
<body>
<div id="container">
<form action="/search" method="post">
<!-- 跨站身份伪造: 利用浏览器存储的cookie中的用户身份标识冒充用户执行操作 -->
<!-- 防范跨站身份伪造最佳的做法就是在表单中放置随机令牌 -->
<!-- 除此之外通过设置令牌还可以防范表单重复提交以及重放攻击 -->
<!-- 隐藏域 / 隐式表单域: 页面上是无法看到该内容-->
{% csrf_token %}
<input type="search" name="carno" placeholder="请输入你的车牌号" required>
<input type="submit" value="搜索">
</form>
<hr>
{% if show_result %}
<table>
<tr>
<th>车牌号</th>
<th>违章原因</th>
<th>违章时间</th>
<th>处罚方式</th>
<th>是否受理</th>
</tr>
{% for record in record_list %}
<tr>
<td>{{ record.carno }}</td>
<td>{{ record.reason }}</td>
<td>{{ record.happen_date }}</td>
<td>{{ record.punish }}</td>
<td>
{% if record.isdone %}
<img src="{% static '/images/icon-yes.svg' %}">
{% else %}
<img src="{% static '/images/icon-no.svg' %}">
{% endif %}
</td>
</tr>
{% endfor %}
</table>
{% endif %}
</div>
</body>
</html>
\ No newline at end of file
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>车辆违章查询</title>
<style>
* {
font: 18px/30px Arial;
}
#container {
width: 960px;
margin: 0 auto;
}
#search {
width: 720px;
margin: 10px auto;
padding-top: 100px;
}
#search input[type=search] {
display: inline-block;
width: 480px;
height: 30px;
}
#search input[type=submit] {
display: inline-block;
width: 80px;
height: 40px;
border: None;
background-color: red;
color: white;
margin-left: 20px;
}
#result {
width: 920px;
margin: 20px auto;
border-collapse: collapse;
}
#result th {
font-weight: bolder;
border-bottom: 1px solid darkgray;
}
#result td, #result th {
text-align: center;
height: 50px;
width: 180px;
}
</style>
</head>
<body>
<div id="container">
<form id="search" action="/search" method="post">
<!-- 跨站身份伪造: 利用浏览器存储的cookie中的用户身份标识冒充用户执行操作 -->
<!-- 防范跨站身份伪造最佳的做法就是在表单中放置随机令牌 -->
<!-- 除此之外通过设置令牌还可以防范表单重复提交以及重放攻击 -->
<!-- 隐藏域 / 隐式表单域: 页面上是无法看到该内容-->
{% csrf_token %}
<input type="search" id="carno" name="carno" placeholder="请输入你的车牌号" required>
<input type="submit" value="搜索">
<a href="/add">添加新记录</a>
</form>
<hr>
<table id="result">
<thead>
<tr>
<th>车牌号</th>
<th>违章原因</th>
<th>违章时间</th>
<th>处罚方式</th>
<th>是否受理</th>
</tr>
</thead>
<tbody>
</tbody>
</table>
</div>
<script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.min.js"></script>
<script>
$(function() {
$('#search').on('submit', function(evt) {
evt.preventDefault();
var carno = $('#carno').val();
var token = $('#search input[type=hidden]').val()
$.ajax({
url: '/search2',
type: 'post',
data: {
'carno': carno,
'csrfmiddlewaretoken': token
},
dataType: 'json',
success: function(json) {
$('#result tbody').children().remove();
for (var i = 0; i < json.length; i += 1) {
var record = json[i];
var tr = $('<tr>').append($('<td>').text(record.carno))
.append($('<td>').text(record.reason))
.append($('<td>').text(record.date))
.append($('<td>').text(record.punish));
var imgName = record.isdone ? 'icon-yes.svg' : 'icon-no.svg';
tr.append($('<td>').append($('<img>').attr('src', '/static/images/' + imgName)));
$('#result tbody').append(tr);
}
}
});
});
});
</script>
</body>
</html>
\ No newline at end of file
# Generated by Django 2.0.5 on 2018-05-22 03:07
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
initial = True
dependencies = [
]
operations = [
migrations.CreateModel(
name='Dept',
fields=[
('no', models.IntegerField(primary_key=True, serialize=False)),
('name', models.CharField(max_length=20)),
('location', models.CharField(max_length=10)),
],
options={
'db_table': 'tb_dept',
},
),
migrations.CreateModel(
name='Emp',
fields=[
('no', models.IntegerField(primary_key=True, serialize=False)),
('name', models.CharField(max_length=20)),
('job', models.CharField(max_length=10)),
('mgr', models.IntegerField(null=True)),
('sal', models.DecimalField(decimal_places=2, max_digits=7)),
('comm', models.DecimalField(decimal_places=2, max_digits=7, null=True)),
('dept', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='hrs.Dept')),
],
options={
'db_table': 'tb_emp',
},
),
]
# Generated by Django 2.0.5 on 2018-05-23 01:23
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('hrs', '0001_initial'),
]
operations = [
migrations.AddField(
model_name='dept',
name='excellent',
field=models.BooleanField(default=0, verbose_name='是否优秀'),
),
migrations.AlterField(
model_name='dept',
name='location',
field=models.CharField(max_length=10, verbose_name='部门所在地'),
),
migrations.AlterField(
model_name='dept',
name='name',
field=models.CharField(max_length=20, verbose_name='部门名称'),
),
migrations.AlterField(
model_name='dept',
name='no',
field=models.IntegerField(primary_key=True, serialize=False, verbose_name='部门编号'),
),
migrations.AlterField(
model_name='emp',
name='comm',
field=models.DecimalField(blank=True, decimal_places=2, max_digits=7, null=True),
),
migrations.AlterField(
model_name='emp',
name='mgr',
field=models.IntegerField(blank=True, null=True),
),
]
# Generated by Django 2.0.5 on 2018-05-24 08:46
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('hrs', '0002_auto_20180523_0923'),
]
operations = [
migrations.AlterField(
model_name='emp',
name='mgr',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='hrs.Emp'),
),
]
...@@ -24,7 +24,8 @@ class Emp(models.Model): ...@@ -24,7 +24,8 @@ class Emp(models.Model):
no = models.IntegerField(primary_key=True) no = models.IntegerField(primary_key=True)
name = models.CharField(max_length=20) name = models.CharField(max_length=20)
job = models.CharField(max_length=10) job = models.CharField(max_length=10)
mgr = models.IntegerField(null=True, blank=True) mgr = models.ForeignKey('self', null=True, blank=True, on_delete=models.SET_NULL)
# mgr = models.IntegerField(null=True, blank=True)
sal = models.DecimalField(max_digits=7, decimal_places=2) sal = models.DecimalField(max_digits=7, decimal_places=2)
comm = models.DecimalField(max_digits=7, decimal_places=2, null=True, blank=True) comm = models.DecimalField(max_digits=7, decimal_places=2, null=True, blank=True)
dept = models.ForeignKey(Dept, on_delete=models.PROTECT) dept = models.ForeignKey(Dept, on_delete=models.PROTECT)
......
...@@ -4,6 +4,7 @@ from hrs import views ...@@ -4,6 +4,7 @@ from hrs import views
urlpatterns = [ urlpatterns = [
path('depts', views.depts, name='depts'), path('depts', views.depts, name='depts'),
path('depts/emps', views.emps, name='empsindept'), # url('depts/emps/(?P<no>[0-9]+)', views.emps, name='empsindept'),
path('deldepts', views.del_dept, name='ddel') path('depts/emps/<int:no>', views.emps, name='empsindept'),
path('deldept/<int:no>', views.del_dept, name='ddel')
] ]
from django.http import HttpResponse
from django.shortcuts import render, redirect from django.shortcuts import render, redirect
from django.urls import reverse from django.db.models import ObjectDoesNotExist
from json import dumps
from hrs.models import Dept, Emp from hrs.models import Dept, Emp
...@@ -11,13 +14,21 @@ def index(request): ...@@ -11,13 +14,21 @@ def index(request):
return render(request, 'index.html', context=ctx) return render(request, 'index.html', context=ctx)
def del_dept(request): def del_dept(request, no='0'):
# 重定向 - 重新请求一个指定的页面 try:
return redirect(reverse('depts')) Dept.objects.get(pk=no).delete()
ctx = {'code': 200}
except (ObjectDoesNotExist, ValueError):
ctx = {'code': 404}
return HttpResponse(
dumps(ctx), content_type='application/json; charset=utf-8')
# 重定向 - 给浏览器一个URL, 让浏览器重新请求指定的页面
# return redirect(reverse('depts'))
# return depts(request)
def emps(request): def emps(request, no='0'):
no = request.GET['no'] # no = request.GET['no']
# dept = Dept.objects.get(no=no) # dept = Dept.objects.get(no=no)
# ForeignKey(Dept, on_delete=models.PROTECT, related_name='emps') # ForeignKey(Dept, on_delete=models.PROTECT, related_name='emps')
# dept.emps.all() # dept.emps.all()
......
...@@ -5,6 +5,11 @@ ...@@ -5,6 +5,11 @@
<meta charset="UTF-8"> <meta charset="UTF-8">
<title>部门</title> <title>部门</title>
<link href="{% static 'css/bootstrap.min.css' %}" rel="stylesheet"> <link href="{% static 'css/bootstrap.min.css' %}" rel="stylesheet">
<style>
#dept td, #dept th {
text-align: center;
}
</style>
</head> </head>
<body> <body>
<div class="container"> <div class="container">
...@@ -14,6 +19,7 @@ ...@@ -14,6 +19,7 @@
<hr> <hr>
</div> </div>
</div> </div>
<div class="row clearfix"> <div class="row clearfix">
<div class="col-md-8 column"> <div class="col-md-8 column">
<table id="dept" class="table table-striped table-hover"> <table id="dept" class="table table-striped table-hover">
...@@ -32,7 +38,7 @@ ...@@ -32,7 +38,7 @@
<td>{{ dept.no }}</td> <td>{{ dept.no }}</td>
<td> <td>
<!-- 写代码时要尽量避免使用硬编码(hard code) --> <!-- 写代码时要尽量避免使用硬编码(hard code) -->
<a href="{% url 'empsindept' %}?no={{ dept.no }}">{{ dept.name }}</a> <a href="{% url 'empsindept' dept.no %}">{{ dept.name }}</a>
</td> </td>
<td>{{ dept.location }}</td> <td>{{ dept.location }}</td>
<td> <td>
...@@ -43,7 +49,7 @@ ...@@ -43,7 +49,7 @@
{% endif %} {% endif %}
</td> </td>
<td> <td>
<a href="{% url 'ddel' %}?dno={{ dept.no }}" class="btn btn-xs btn-warning">删除</a> <a id="{{ dept.no }}" href="javascript:void(0);" class="btn btn-xs btn-warning">删除</a>
</td> </td>
</tr> </tr>
{% endfor %} {% endfor %}
...@@ -60,6 +66,18 @@ ...@@ -60,6 +66,18 @@
$(function() { $(function() {
$('#dept tbody tr:even').addClass('info'); $('#dept tbody tr:even').addClass('info');
$('#dept tbody tr:odd').addClass('warning'); $('#dept tbody tr:odd').addClass('warning');
$('#dept a[id]').on('click', function(evt) {
var a = $(evt.target);
if (confirm('确定要删除吗?')) {
$.getJSON('/hrs/deldept/' + a.attr('id'), function(json) {
if (json.code == 200) {
a.parent().parent().remove();
$('#dept tbody tr:even').addClass('info');
$('#dept tbody tr:odd').addClass('warning');
}
});
}
});
}); });
</script> </script>
</body> </body>
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment