1*4882a593Smuzhiyun# 2*4882a593Smuzhiyun# BitBake Toaster Implementation 3*4882a593Smuzhiyun# 4*4882a593Smuzhiyun# Copyright (C) 2013 Intel Corporation 5*4882a593Smuzhiyun# 6*4882a593Smuzhiyun# SPDX-License-Identifier: GPL-2.0-only 7*4882a593Smuzhiyun# 8*4882a593Smuzhiyun 9*4882a593Smuzhiyun# Django settings for Toaster project. 10*4882a593Smuzhiyun 11*4882a593Smuzhiyunimport os 12*4882a593Smuzhiyun 13*4882a593SmuzhiyunDEBUG = True 14*4882a593Smuzhiyun 15*4882a593Smuzhiyun# Set to True to see the SQL queries in console 16*4882a593SmuzhiyunSQL_DEBUG = False 17*4882a593Smuzhiyunif os.environ.get("TOASTER_SQLDEBUG", None) is not None: 18*4882a593Smuzhiyun SQL_DEBUG = True 19*4882a593Smuzhiyun 20*4882a593Smuzhiyun 21*4882a593SmuzhiyunADMINS = ( 22*4882a593Smuzhiyun # ('Your Name', 'your_email@example.com'), 23*4882a593Smuzhiyun) 24*4882a593Smuzhiyun 25*4882a593SmuzhiyunMANAGERS = ADMINS 26*4882a593Smuzhiyun 27*4882a593SmuzhiyunTOASTER_SQLITE_DEFAULT_DIR = os.environ.get('TOASTER_DIR') 28*4882a593Smuzhiyun 29*4882a593SmuzhiyunDATABASES = { 30*4882a593Smuzhiyun 'default': { 31*4882a593Smuzhiyun # Add 'postgresql_psycopg2', 'mysql', 'sqlite3' or 'oracle'. 32*4882a593Smuzhiyun 'ENGINE': 'django.db.backends.sqlite3', 33*4882a593Smuzhiyun # DB name or full path to database file if using sqlite3. 34*4882a593Smuzhiyun 'NAME': "%s/toaster.sqlite" % TOASTER_SQLITE_DEFAULT_DIR, 35*4882a593Smuzhiyun 'USER': '', 36*4882a593Smuzhiyun 'PASSWORD': '', 37*4882a593Smuzhiyun #'HOST': '127.0.0.1', # e.g. mysql server 38*4882a593Smuzhiyun #'PORT': '3306', # e.g. mysql port 39*4882a593Smuzhiyun } 40*4882a593Smuzhiyun} 41*4882a593Smuzhiyun 42*4882a593Smuzhiyun# New in Django 3.2 43*4882a593SmuzhiyunDEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField' 44*4882a593Smuzhiyun 45*4882a593Smuzhiyun# Needed when Using sqlite especially to add a longer timeout for waiting 46*4882a593Smuzhiyun# for the database lock to be released 47*4882a593Smuzhiyun# https://docs.djangoproject.com/en/1.6/ref/databases/#database-is-locked-errors 48*4882a593Smuzhiyunif 'sqlite' in DATABASES['default']['ENGINE']: 49*4882a593Smuzhiyun DATABASES['default']['OPTIONS'] = { 'timeout': 20 } 50*4882a593Smuzhiyun 51*4882a593Smuzhiyun# Update as of django 1.8.16 release, the '*' is needed to allow us to connect while running 52*4882a593Smuzhiyun# on hosts without explicitly setting the fqdn for the toaster server. 53*4882a593Smuzhiyun# See https://docs.djangoproject.com/en/dev/ref/settings/ for info on ALLOWED_HOSTS 54*4882a593Smuzhiyun# Previously this setting was not enforced if DEBUG was set but it is now. 55*4882a593Smuzhiyun# The previous behavior was such that ALLOWED_HOSTS defaulted to ['localhost','127.0.0.1','::1'] 56*4882a593Smuzhiyun# and if you bound to 0.0.0.0:<port #> then accessing toaster as localhost or fqdn would both work. 57*4882a593Smuzhiyun# To have that same behavior, with a fqdn explicitly enabled you would set 58*4882a593Smuzhiyun# ALLOWED_HOSTS= ['localhost','127.0.0.1','::1','myserver.mycompany.com'] for 59*4882a593Smuzhiyun# Django >= 1.8.16. By default, we are not enforcing this restriction in 60*4882a593Smuzhiyun# DEBUG mode. 61*4882a593Smuzhiyunif DEBUG is True: 62*4882a593Smuzhiyun # this will allow connection via localhost,hostname, or fqdn 63*4882a593Smuzhiyun ALLOWED_HOSTS = ['*'] 64*4882a593Smuzhiyun 65*4882a593Smuzhiyun# Local time zone for this installation. Choices can be found here: 66*4882a593Smuzhiyun# http://en.wikipedia.org/wiki/List_of_tz_zones_by_name 67*4882a593Smuzhiyun# although not all choices may be available on all operating systems. 68*4882a593Smuzhiyun# In a Windows environment this must be set to your system time zone. 69*4882a593Smuzhiyun 70*4882a593Smuzhiyun# Always use local computer's time zone, find 71*4882a593Smuzhiyunimport hashlib 72*4882a593Smuzhiyunif 'TZ' in os.environ: 73*4882a593Smuzhiyun TIME_ZONE = os.environ['TZ'] 74*4882a593Smuzhiyunelse: 75*4882a593Smuzhiyun # need to read the /etc/localtime file which is the libc standard 76*4882a593Smuzhiyun # and do a reverse-mapping to /usr/share/zoneinfo/; 77*4882a593Smuzhiyun # since the timezone may match any number of identical timezone definitions, 78*4882a593Smuzhiyun 79*4882a593Smuzhiyun zonefilelist = {} 80*4882a593Smuzhiyun ZONEINFOPATH = '/usr/share/zoneinfo/' 81*4882a593Smuzhiyun for dirpath, dirnames, filenames in os.walk(ZONEINFOPATH): 82*4882a593Smuzhiyun for fn in filenames: 83*4882a593Smuzhiyun filepath = os.path.join(dirpath, fn) 84*4882a593Smuzhiyun zonename = filepath.lstrip(ZONEINFOPATH).strip() 85*4882a593Smuzhiyun try: 86*4882a593Smuzhiyun import pytz 87*4882a593Smuzhiyun from pytz.exceptions import UnknownTimeZoneError 88*4882a593Smuzhiyun try: 89*4882a593Smuzhiyun if pytz.timezone(zonename) is not None: 90*4882a593Smuzhiyun zonefilelist[hashlib.md5(open(filepath, 'rb').read()).hexdigest()] = zonename 91*4882a593Smuzhiyun except UnknownTimeZoneError as ValueError: 92*4882a593Smuzhiyun # we expect timezone failures here, just move over 93*4882a593Smuzhiyun pass 94*4882a593Smuzhiyun except ImportError: 95*4882a593Smuzhiyun zonefilelist[hashlib.md5(open(filepath, 'rb').read()).hexdigest()] = zonename 96*4882a593Smuzhiyun 97*4882a593Smuzhiyun TIME_ZONE = zonefilelist[hashlib.md5(open('/etc/localtime', 'rb').read()).hexdigest()] 98*4882a593Smuzhiyun 99*4882a593Smuzhiyun# Language code for this installation. All choices can be found here: 100*4882a593Smuzhiyun# http://www.i18nguy.com/unicode/language-identifiers.html 101*4882a593SmuzhiyunLANGUAGE_CODE = 'en-us' 102*4882a593Smuzhiyun 103*4882a593SmuzhiyunSITE_ID = 1 104*4882a593Smuzhiyun 105*4882a593Smuzhiyun# If you set this to False, Django will make some optimizations so as not 106*4882a593Smuzhiyun# to load the internationalization machinery. 107*4882a593SmuzhiyunUSE_I18N = True 108*4882a593Smuzhiyun 109*4882a593Smuzhiyun# If you set this to False, Django will not format dates, numbers and 110*4882a593Smuzhiyun# calendars according to the current locale. 111*4882a593SmuzhiyunUSE_L10N = True 112*4882a593Smuzhiyun 113*4882a593Smuzhiyun# If you set this to False, Django will not use timezone-aware datetimes. 114*4882a593SmuzhiyunUSE_TZ = True 115*4882a593Smuzhiyun 116*4882a593Smuzhiyun# Absolute filesystem path to the directory that will hold user-uploaded files. 117*4882a593Smuzhiyun# Example: "/var/www/example.com/media/" 118*4882a593SmuzhiyunMEDIA_ROOT = '' 119*4882a593Smuzhiyun 120*4882a593Smuzhiyun# URL that handles the media served from MEDIA_ROOT. Make sure to use a 121*4882a593Smuzhiyun# trailing slash. 122*4882a593Smuzhiyun# Examples: "http://example.com/media/", "http://media.example.com/" 123*4882a593SmuzhiyunMEDIA_URL = '' 124*4882a593Smuzhiyun 125*4882a593Smuzhiyun# Absolute path to the directory static files should be collected to. 126*4882a593Smuzhiyun# Don't put anything in this directory yourself; store your static files 127*4882a593Smuzhiyun# in apps' "static/" subdirectories and in STATICFILES_DIRS. 128*4882a593Smuzhiyun# Example: "/var/www/example.com/static/" 129*4882a593SmuzhiyunSTATIC_ROOT = '' 130*4882a593Smuzhiyun 131*4882a593Smuzhiyun# URL prefix for static files. 132*4882a593Smuzhiyun# Example: "http://example.com/static/", "http://static.example.com/" 133*4882a593SmuzhiyunSTATIC_URL = '/static/' 134*4882a593Smuzhiyun 135*4882a593Smuzhiyun# Additional locations of static files 136*4882a593SmuzhiyunSTATICFILES_DIRS = ( 137*4882a593Smuzhiyun # Put strings here, like "/home/html/static" or "C:/www/django/static". 138*4882a593Smuzhiyun # Always use forward slashes, even on Windows. 139*4882a593Smuzhiyun # Don't forget to use absolute paths, not relative paths. 140*4882a593Smuzhiyun) 141*4882a593Smuzhiyun 142*4882a593Smuzhiyun# List of finder classes that know how to find static files in 143*4882a593Smuzhiyun# various locations. 144*4882a593SmuzhiyunSTATICFILES_FINDERS = ( 145*4882a593Smuzhiyun 'django.contrib.staticfiles.finders.FileSystemFinder', 146*4882a593Smuzhiyun 'django.contrib.staticfiles.finders.AppDirectoriesFinder', 147*4882a593Smuzhiyun# 'django.contrib.staticfiles.finders.DefaultStorageFinder', 148*4882a593Smuzhiyun) 149*4882a593Smuzhiyun 150*4882a593Smuzhiyun# Make this unique, and don't share it with anybody. 151*4882a593SmuzhiyunSECRET_KEY = 'NOT_SUITABLE_FOR_HOSTED_DEPLOYMENT' 152*4882a593Smuzhiyun 153*4882a593Smuzhiyunclass InvalidString(str): 154*4882a593Smuzhiyun def __mod__(self, other): 155*4882a593Smuzhiyun from django.template.base import TemplateSyntaxError 156*4882a593Smuzhiyun raise TemplateSyntaxError( 157*4882a593Smuzhiyun "Undefined variable or unknown value for: \"%s\"" % other) 158*4882a593Smuzhiyun 159*4882a593SmuzhiyunTEMPLATES = [ 160*4882a593Smuzhiyun { 161*4882a593Smuzhiyun 'BACKEND': 'django.template.backends.django.DjangoTemplates', 162*4882a593Smuzhiyun 'DIRS': [ 163*4882a593Smuzhiyun # Put strings here, like "/home/html/django_templates" or "C:/www/django/templates". 164*4882a593Smuzhiyun # Always use forward slashes, even on Windows. 165*4882a593Smuzhiyun # Don't forget to use absolute paths, not relative paths. 166*4882a593Smuzhiyun ], 167*4882a593Smuzhiyun 'OPTIONS': { 168*4882a593Smuzhiyun 'context_processors': [ 169*4882a593Smuzhiyun # Insert your TEMPLATE_CONTEXT_PROCESSORS here or use this 170*4882a593Smuzhiyun # list if you haven't customized them: 171*4882a593Smuzhiyun 'django.contrib.auth.context_processors.auth', 172*4882a593Smuzhiyun 'django.template.context_processors.debug', 173*4882a593Smuzhiyun 'django.template.context_processors.i18n', 174*4882a593Smuzhiyun 'django.template.context_processors.media', 175*4882a593Smuzhiyun 'django.template.context_processors.static', 176*4882a593Smuzhiyun 'django.template.context_processors.tz', 177*4882a593Smuzhiyun 'django.contrib.messages.context_processors.messages', 178*4882a593Smuzhiyun # Custom 179*4882a593Smuzhiyun 'django.template.context_processors.request', 180*4882a593Smuzhiyun 'toastergui.views.managedcontextprocessor', 181*4882a593Smuzhiyun 182*4882a593Smuzhiyun ], 183*4882a593Smuzhiyun 'loaders': [ 184*4882a593Smuzhiyun # List of callables that know how to import templates from various sources. 185*4882a593Smuzhiyun 'django.template.loaders.filesystem.Loader', 186*4882a593Smuzhiyun 'django.template.loaders.app_directories.Loader', 187*4882a593Smuzhiyun #'django.template.loaders.eggs.Loader', 188*4882a593Smuzhiyun ], 189*4882a593Smuzhiyun 'string_if_invalid': InvalidString("%s"), 190*4882a593Smuzhiyun 'debug': DEBUG, 191*4882a593Smuzhiyun }, 192*4882a593Smuzhiyun }, 193*4882a593Smuzhiyun] 194*4882a593Smuzhiyun 195*4882a593SmuzhiyunMIDDLEWARE = [ 196*4882a593Smuzhiyun 'django.middleware.common.CommonMiddleware', 197*4882a593Smuzhiyun 'django.contrib.sessions.middleware.SessionMiddleware', 198*4882a593Smuzhiyun 'django.middleware.csrf.CsrfViewMiddleware', 199*4882a593Smuzhiyun 'django.contrib.auth.middleware.AuthenticationMiddleware', 200*4882a593Smuzhiyun 'django.contrib.messages.middleware.MessageMiddleware', 201*4882a593Smuzhiyun 'django.contrib.auth.middleware.AuthenticationMiddleware', 202*4882a593Smuzhiyun 'django.contrib.messages.middleware.MessageMiddleware', 203*4882a593Smuzhiyun 'django.contrib.sessions.middleware.SessionMiddleware', 204*4882a593Smuzhiyun] 205*4882a593Smuzhiyun 206*4882a593SmuzhiyunCACHES = { 207*4882a593Smuzhiyun # 'default': { 208*4882a593Smuzhiyun # 'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache', 209*4882a593Smuzhiyun # 'LOCATION': '127.0.0.1:11211', 210*4882a593Smuzhiyun # }, 211*4882a593Smuzhiyun 'default': { 212*4882a593Smuzhiyun 'BACKEND': 'django.core.cache.backends.filebased.FileBasedCache', 213*4882a593Smuzhiyun 'LOCATION': '/tmp/toaster_cache_%d' % os.getuid(), 214*4882a593Smuzhiyun 'TIMEOUT': 1, 215*4882a593Smuzhiyun } 216*4882a593Smuzhiyun } 217*4882a593Smuzhiyun 218*4882a593Smuzhiyun 219*4882a593Smuzhiyunfrom os.path import dirname as DN 220*4882a593SmuzhiyunSITE_ROOT=DN(DN(os.path.abspath(__file__))) 221*4882a593Smuzhiyun 222*4882a593Smuzhiyunimport subprocess 223*4882a593SmuzhiyunTOASTER_BRANCH = subprocess.Popen('git branch | grep "^* " | tr -d "* "', cwd = SITE_ROOT, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE).communicate()[0] 224*4882a593SmuzhiyunTOASTER_REVISION = subprocess.Popen('git rev-parse HEAD ', cwd = SITE_ROOT, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE).communicate()[0] 225*4882a593Smuzhiyun 226*4882a593SmuzhiyunROOT_URLCONF = 'toastermain.urls' 227*4882a593Smuzhiyun 228*4882a593Smuzhiyun# Python dotted path to the WSGI application used by Django's runserver. 229*4882a593SmuzhiyunWSGI_APPLICATION = 'toastermain.wsgi.application' 230*4882a593Smuzhiyun 231*4882a593Smuzhiyun 232*4882a593SmuzhiyunINSTALLED_APPS = ( 233*4882a593Smuzhiyun 'django.contrib.auth', 234*4882a593Smuzhiyun 'django.contrib.contenttypes', 235*4882a593Smuzhiyun 'django.contrib.messages', 236*4882a593Smuzhiyun 'django.contrib.sessions', 237*4882a593Smuzhiyun 'django.contrib.admin', 238*4882a593Smuzhiyun 'django.contrib.staticfiles', 239*4882a593Smuzhiyun 240*4882a593Smuzhiyun # Uncomment the next line to enable admin documentation: 241*4882a593Smuzhiyun # 'django.contrib.admindocs', 242*4882a593Smuzhiyun 'django.contrib.humanize', 243*4882a593Smuzhiyun 'bldcollector', 244*4882a593Smuzhiyun 'toastermain', 245*4882a593Smuzhiyun) 246*4882a593Smuzhiyun 247*4882a593Smuzhiyun 248*4882a593SmuzhiyunINTERNAL_IPS = ['127.0.0.1', '192.168.2.28'] 249*4882a593Smuzhiyun 250*4882a593Smuzhiyun# Load django-fresh is TOASTER_DEVEL is set, and the module is available 251*4882a593SmuzhiyunFRESH_ENABLED = False 252*4882a593Smuzhiyunif os.environ.get('TOASTER_DEVEL', None) is not None: 253*4882a593Smuzhiyun try: 254*4882a593Smuzhiyun import fresh 255*4882a593Smuzhiyun MIDDLEWARE = ["fresh.middleware.FreshMiddleware",] + MIDDLEWARE 256*4882a593Smuzhiyun INSTALLED_APPS = INSTALLED_APPS + ('fresh',) 257*4882a593Smuzhiyun FRESH_ENABLED = True 258*4882a593Smuzhiyun except: 259*4882a593Smuzhiyun pass 260*4882a593Smuzhiyun 261*4882a593SmuzhiyunDEBUG_PANEL_ENABLED = False 262*4882a593Smuzhiyunif os.environ.get('TOASTER_DEVEL', None) is not None: 263*4882a593Smuzhiyun try: 264*4882a593Smuzhiyun import debug_toolbar, debug_panel 265*4882a593Smuzhiyun MIDDLEWARE = ['debug_panel.middleware.DebugPanelMiddleware',] + MIDDLEWARE 266*4882a593Smuzhiyun #MIDDLEWARE = MIDDLEWARE + ['debug_toolbar.middleware.DebugToolbarMiddleware',] 267*4882a593Smuzhiyun INSTALLED_APPS = INSTALLED_APPS + ('debug_toolbar','debug_panel',) 268*4882a593Smuzhiyun DEBUG_PANEL_ENABLED = True 269*4882a593Smuzhiyun 270*4882a593Smuzhiyun # this cache backend will be used by django-debug-panel 271*4882a593Smuzhiyun CACHES['debug-panel'] = { 272*4882a593Smuzhiyun 'BACKEND': 'django.core.cache.backends.filebased.FileBasedCache', 273*4882a593Smuzhiyun 'LOCATION': '/var/tmp/debug-panel-cache', 274*4882a593Smuzhiyun 'TIMEOUT': 300, 275*4882a593Smuzhiyun 'OPTIONS': { 276*4882a593Smuzhiyun 'MAX_ENTRIES': 200 277*4882a593Smuzhiyun } 278*4882a593Smuzhiyun } 279*4882a593Smuzhiyun 280*4882a593Smuzhiyun except: 281*4882a593Smuzhiyun pass 282*4882a593Smuzhiyun 283*4882a593Smuzhiyun 284*4882a593SmuzhiyunSOUTH_TESTS_MIGRATE = False 285*4882a593Smuzhiyun 286*4882a593Smuzhiyun 287*4882a593Smuzhiyun# We automatically detect and install applications here if 288*4882a593Smuzhiyun# they have a 'models.py' or 'views.py' file 289*4882a593Smuzhiyunimport os 290*4882a593Smuzhiyuncurrentdir = os.path.dirname(__file__) 291*4882a593Smuzhiyunfor t in os.walk(os.path.dirname(currentdir)): 292*4882a593Smuzhiyun modulename = os.path.basename(t[0]) 293*4882a593Smuzhiyun #if we have a virtualenv skip it to avoid incorrect imports 294*4882a593Smuzhiyun if 'VIRTUAL_ENV' in os.environ and os.environ['VIRTUAL_ENV'] in t[0]: 295*4882a593Smuzhiyun continue 296*4882a593Smuzhiyun 297*4882a593Smuzhiyun if ("views.py" in t[2] or "models.py" in t[2]) and not modulename in INSTALLED_APPS: 298*4882a593Smuzhiyun INSTALLED_APPS = INSTALLED_APPS + (modulename,) 299*4882a593Smuzhiyun 300*4882a593Smuzhiyun# A sample logging configuration. The only tangible logging 301*4882a593Smuzhiyun# performed by this configuration is to send an email to 302*4882a593Smuzhiyun# the site admins on every HTTP 500 error when DEBUG=False. 303*4882a593Smuzhiyun# See http://docs.djangoproject.com/en/dev/topics/logging for 304*4882a593Smuzhiyun# more details on how to customize your logging configuration. 305*4882a593SmuzhiyunLOGGING = { 306*4882a593Smuzhiyun 'version': 1, 307*4882a593Smuzhiyun 'disable_existing_loggers': False, 308*4882a593Smuzhiyun 'filters': { 309*4882a593Smuzhiyun 'require_debug_false': { 310*4882a593Smuzhiyun '()': 'django.utils.log.RequireDebugFalse' 311*4882a593Smuzhiyun } 312*4882a593Smuzhiyun }, 313*4882a593Smuzhiyun 'formatters': { 314*4882a593Smuzhiyun 'datetime': { 315*4882a593Smuzhiyun 'format': '%(asctime)s %(levelname)s %(message)s' 316*4882a593Smuzhiyun } 317*4882a593Smuzhiyun }, 318*4882a593Smuzhiyun 'handlers': { 319*4882a593Smuzhiyun 'mail_admins': { 320*4882a593Smuzhiyun 'level': 'ERROR', 321*4882a593Smuzhiyun 'filters': ['require_debug_false'], 322*4882a593Smuzhiyun 'class': 'django.utils.log.AdminEmailHandler' 323*4882a593Smuzhiyun }, 324*4882a593Smuzhiyun 'console': { 325*4882a593Smuzhiyun 'level': 'DEBUG', 326*4882a593Smuzhiyun 'class': 'logging.StreamHandler', 327*4882a593Smuzhiyun 'formatter': 'datetime', 328*4882a593Smuzhiyun } 329*4882a593Smuzhiyun }, 330*4882a593Smuzhiyun 'loggers': { 331*4882a593Smuzhiyun 'toaster' : { 332*4882a593Smuzhiyun 'handlers': ['console'], 333*4882a593Smuzhiyun 'level': 'DEBUG', 334*4882a593Smuzhiyun }, 335*4882a593Smuzhiyun 'django.request': { 336*4882a593Smuzhiyun 'handlers': ['console'], 337*4882a593Smuzhiyun 'level': 'WARN', 338*4882a593Smuzhiyun 'propagate': True, 339*4882a593Smuzhiyun }, 340*4882a593Smuzhiyun } 341*4882a593Smuzhiyun} 342*4882a593Smuzhiyun 343*4882a593Smuzhiyunif DEBUG and SQL_DEBUG: 344*4882a593Smuzhiyun LOGGING['loggers']['django.db.backends'] = { 345*4882a593Smuzhiyun 'level': 'DEBUG', 346*4882a593Smuzhiyun 'handlers': ['console'], 347*4882a593Smuzhiyun } 348*4882a593Smuzhiyun 349*4882a593Smuzhiyun 350*4882a593Smuzhiyun# If we're using sqlite, we need to tweak the performance a bit 351*4882a593Smuzhiyunfrom django.db.backends.signals import connection_created 352*4882a593Smuzhiyundef activate_synchronous_off(sender, connection, **kwargs): 353*4882a593Smuzhiyun if connection.vendor == 'sqlite': 354*4882a593Smuzhiyun cursor = connection.cursor() 355*4882a593Smuzhiyun cursor.execute('PRAGMA synchronous = 0;') 356*4882a593Smuzhiyunconnection_created.connect(activate_synchronous_off) 357*4882a593Smuzhiyun# 358*4882a593Smuzhiyun 359