Mn=X#1k!Cr0Qoa9|2{mhI~VZD|0WbMt5 zmCD|NY-{C8Grqjvxxa9C=f#!%2an#YJkU#5_1e7~;ohU$3yl}ez3+Aw^{wWMg?@17 zZC|UU;gs!Ah)BK;IGS<09e3=Ud6f_F>duh68K;iH?=bFQa~!bQZh{*T{FP}`Z^zEz z@hp_DN4O7(L(tc|qf +=$@eCL)o7NOB_KHNw3x zj6{3rc 8myKHBLnh{_Pf2fi7>=SMaHY^L;i!A58>^} zSAB_{djjkqlg&P>Zt~7@)ybj8Q47@hkMTxRN9(s;m~`f2x&oT>Or1J}7V5)=1}m@5 z9U^4*a zI+oZ9d=rN6t`NSt4l-ueH}*12Enc&^w{}%+32^{QF*1}Lc6%6IncZ= zAo_x-{tlDPbZ}8aqbcHrTCG|$qe$+{= LJ!stoRK}qNtfo8-91lM7v_$EHe zBpeDRb1BWKj-=`aEhMd)1(Zf;kTQIX4IKP>NCvaEd;LyF_UwG9nlU0&GoU#km;1{Q z3Omb5f$c9VK2sBH+}F!yCe_wmyTzt)^$MRNFq)TDnF8w@n-7kn4+(=~X%Pan$T9tI z)bK?P&;Kj(;1v3mNc_hYd6Bc{f4(%;_ynq5<;OKV7VqF;+AcIz+_{+YU`F}E n?B?H52vGo8FLAh( v}7tDtE(2s6- z-OTaa-6;Av<4eV~f8`L>3+2s{gP@o$fY)?@aW&UrEPLH4l@Me|x@JC1;Np zjJNfITlZ^QXvu3P7N8X?Y>ZKmKsAJ`hL+u+*)5=}TSKr=c8Vpl zw8rTKG~YCAcLJJ)D!C?YhWtLzH50)R+~CtGsnpOwW~3ftl>26T3rDZoHU}8a(_VlU zc{?xFOC5K&le1`>d$F7C0Bv{AjJI)2^2w|0?pu>X58JWmNAg>4$kbo)m>J7vvg6sY zjFrhuT7zr$=$r)%;8}A`TF1xdtQqSx?h`5HxHY&y&CGyuaw@}mSSmX;$y#xbL;u9h zi7dlMR Z9$%7q?G)M|;h!Hyr1cT(WoKf_<( zz+d9R4}h6*(+1&n)-&Hc_M4ea>36&F>wEp<2yUJ(eP7Yf{!{<~y$WK0M1ij$alm zG3r2Ef}{+7xzI}xS0GsezjCWrMX%oKHPLH@UWT|1?>SQi;s*E)Ig8{b_)U?QAZ|g@ z2EPr;I1p69C D@LM(SWH5G~Ku20NHCL>-8_3vNvbY%L&dK`8JxRY#D;s1-0Z zh*lt2g 6B9NZLeO~9==xGmtifID+=R|szixHkvyiRY$(_Zb|wz~2Hx zZyT-wo|6(h0MmqM8zxJT|4?kB`u8Q>jzm7>$V(;OsdV+U|A@vI{-LMukc3rM(@{JN z43 @< zq98=H4YouRw?BCL*zF;ciYCQ@i7RF6>C{U6hyWHwS(sXG&iPFcAH}q$dTeZm4aAul z>FEH!Voy4G17Mr%XGe!87pKSG*_)%|(;~vU`bwkDg-8#V$g2SQyCfq2%YsO!<7_a> z(o3nzBMdy5$nrmC%)?KfjF9OvGmm>E DWpWGK>5FB^@lx zvY^0MLGHs_o|xq0LPg+#dfX?EvwJ*fkJ~MWeIQmR)Gx2aNRzgOyCDrT=~b9#skGuy zdebK_xZCUjsYfq{oXQRl`9g*kbB$R(d~NImv+1zt*^p~|mS{^iPvjwU8%)0mm6u5t p%wluEowNhmHl402R>Ntjmg=sos*c)LtFkr}trG8hwYJkye*q<23f}+# literal 0 HcmV?d00001 diff --git a/hulu/wsgi.py b/hulu/wsgi.py new file mode 100644 index 0000000..012ac84 --- /dev/null +++ b/hulu/wsgi.py @@ -0,0 +1,32 @@ +""" +WSGI config for hulu project. + +This module contains the WSGI application used by Django's development server +and any production WSGI deployments. It should expose a module-level variable +named ``application``. Django's ``runserver`` and ``runfcgi`` commands discover +this application via the ``WSGI_APPLICATION`` setting. + +Usually you will have the standard Django WSGI application here, but it also +might make sense to replace the whole Django WSGI application with a custom one +that later delegates to the Django one. For example, you could introduce WSGI +middleware here, or combine a Django application with an application of another +framework. + +""" +import os + +# We defer to a DJANGO_SETTINGS_MODULE already in the environment. This breaks +# if running multiple sites in the same mod_wsgi process. To fix this, use +# mod_wsgi daemon mode with each site in its own daemon process, or use +# os.environ["DJANGO_SETTINGS_MODULE"] = "hulu.settings" +os.environ.setdefault("DJANGO_SETTINGS_MODULE", "hulu.settings") + +# This application object is used by any WSGI server configured to use this +# file. This includes Django's development server, if the WSGI_APPLICATION +# setting points here. +from django.core.wsgi import get_wsgi_application +application = get_wsgi_application() + +# Apply WSGI middleware here. +# from helloworld.wsgi import HelloWorldApplication +# application = HelloWorldApplication(application) diff --git a/hulu/wsgi.pyc b/hulu/wsgi.pyc new file mode 100644 index 0000000000000000000000000000000000000000..fc661eb2149e6576e97bbf4c59a405fc55fc3892 GIT binary patch literal 1043 zcmZWoQE$^Q5O%h;Kwx4Li06Bw4=g_bp^37Nsc3W)?SwQcC2o9e+&Ok+JMH?sNB#)E zju(CaoRbQQ7A05veD~ew`>y-H4&$Fco_x#M_SvW3_w>0BWCUY3WFsc_n2Oj<#4uvZ zJ+|Cug5CpmzsI6*++pf~l^u4|VG(xNJ>_*n(zw?RSl{;;i@%P~hmadRmkXF13q`GJ zsH|CH?vps46w*OyM6EDHc`mgBUm!GjysDJUxtB&m?NGpM1A`^k3-j86z!fS}m8d;9 zv@5hR*8;fS1bk8FO R@_QHQy6PrQpqga zVUcCYKLS~1Yu#4PGO8P5$urLvlJ>bNOY#v<>2ed;`Eb`AFjz_6+%?Mr%d~%Wbum2c zPllHx%6I6!)C=m-wX3;O8`zi{)>0`b_zIgu=cxj>V$11a(+afs24=Mf>47U};!-XO z4<)}vszB_)8?e+Kp0|+e!jKeglON)(r7x&odF{L@!DysQaSw`nv?Pea1+7Rx)6m LAk=Z?}alA^l%l&78zA zG( @BrX{-$T-U(sj|KJ`cEm+AOyG8vA}$LZ(G!S%(NJEWs9pUJlOt{0KV zza+CjpRV0PraQ%ZkHTp%X(~*frk)0#8P~W_ucW1cj>$!E0_VI|-XGCcG!vZU#$pmM zzcf{z(#bA3ZCUTHaVNAqeLKCTd2`dgD5aLpTkegW4$$3tQ%zgkX}H00$sI}3tf!$y bQf>TWf_T^d*G`_(+66~9de(i>Ig0)O>qSZ! literal 0 HcmV?d00001 diff --git a/item/__init__.py b/item/__init__.py new file mode 100644 index 0000000..992c0f7 --- /dev/null +++ b/item/__init__.py @@ -0,0 +1,92 @@ +# -*- coding: utf-8 -*- +import sys +reload(sys) +sys.setdefaultencoding('utf8') + +import os +from django.conf import settings +import shutil +import re +from hulu import * +from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger +from datetime import datetime, timedelta + +def deletedir(dir): + try: + shutil.rmtree(dir) + except: + deletedir(dir) + +def img2svg(contentattachment): + if 'image' in contentattachment.contenttype and checkmodule('PIL'): + from PIL import Image + contentattachmentfile = os.path.join(settings.MEDIA_ROOT, str(contentattachment.file)) + contentattachment.contenttype = 'svg' + contentattachment.file = None + contentattachment.save() + im = Image.open(contentattachmentfile) + im = im.convert('RGB') + im.save(contentattachmentfile + '.pgm') + im.close() + os.system('chmod +x ' + os.path.join(settings.MEDIA_ROOT, 'tool', 'potrace', 'potrace')) + os.system(os.path.join(settings.MEDIA_ROOT, 'tool', 'potrace', 'potrace ') + contentattachmentfile + '.pgm -s -o ' + contentattachmentfile + '.svg') + fo = open(contentattachmentfile + '.svg') + contentattachment.content = re.sub(' [\s\S]* ', '', fo.read()) + fo.close() + contentattachment.save() + #deletedir(os.path.dirname(contentattachmentfile)) + try: + shutil.rmtree(os.path.join(settings.MEDIA_ROOT, 'file')) + except: + pass + +def sort_items(items, page): + itemlist = [] + + for item in items: + #itemcontent = ItemContent.objects.filter(item=item) + itemcontent = item.itemcontent_set.all() + if itemcontent: + item.create = itemcontent[0].create + #取第一个内容首行作为标题 + #if itemcontent[0].content: + # item.title = itemcontent[0].content.strip().splitlines()[0] + #else: + # contentattachment = itemcontent[0].contentattachment_set.all() + # if contentattachment: + # item.title = contentattachment[0].title + # else: + # item.title = str(item.id) + + #取最后一个内容首行作为标题 + if itemcontent.last().content: + item.title = itemcontent.last().content.strip().splitlines()[0] + else: + contentattachment = itemcontent.last().contentattachment_set.all() + if contentattachment: + item.title = contentattachment[0].title + else: + item.title = str(item.id) + + subitem = item.get_all_items(include_self=False) + if subitem: + subitem.sort(key=lambda item:item.create, reverse=True) + #itemcontent = ItemContent.objects.filter(item=subitem[0]).reverse() + itemcontent = subitem[0].itemcontent_set.all().reverse() + item.subitemcount = len(subitem) + item.lastsubitem = subitem[0] + else: + item.lastsubitem = itemcontent.last() + itemlist.append(item) + + itemlist = sorted(itemlist, key=lambda item:item.lastsubitem.create, reverse=True) + + paginator = Paginator(itemlist, 30) + try: + items = paginator.page(page) + except PageNotAnInteger: + items = paginator.page(1) + except EmptyPage: + items = paginator.page(paginator.num_pages) + + return items diff --git a/item/__init__.pyc b/item/__init__.pyc new file mode 100644 index 0000000000000000000000000000000000000000..eeb1f5c344d7ac6999c05ded8d8803de550578d8 GIT binary patch literal 3243 zcmb_e+iny`5UrlIckT7AZ(NK+6gfd83kZ`$ii9GBxF)ic7&ImVEsIvePTQXKT$Y($ zgeCjQ{6nOCL7wxLmwZxQ@&U;?)oTL^kM??cs=KGqnWQ<6 9&>n*up@+c!G~gqy)oS?7{`r}8UYzS^mgIg8 OV%xV zp4}|m-Fzc=cE^?-x=BUGk+UwztR5l}+tft^%H~7q_wiI$FzhdhgYS$Sct<|Xm&6$3 zg5!nU$TPTPOYPhArqy|RckGhXkt{P;TCWY7tg~@a`s+{?CwPet)jd%6zwiB0*|O^0 zjk6?ADp&G~y$811bH%6^52Jji= uaEXax^x~-MHh;x znI$}W!)eSLc=U#2+!rCh-G(B2btzvNXC`R^I!1mV=z(N4IYbsAJi}=j*2OhsIKvR| zWRppC6v!bGY?>>52o)uox}haUu;IYSuq_9gf`>IZsL60%;yMpcrY&-jEGt+t Vr7#r7|WJ14{Q|FdtAUg2GyzIuh6F&Lla>YJ_35<;-)7>p!i#xfHg zZ~UY%@VPbo+U)>TSKadh5o?3LpU4RIr_-wzI++g$)W| zD|c>xWc_^C4)$QrIJIFL{E#^atcVnq9v?++SBYVf 2)h|K=^f5}j74Xtp2Vx$E>0cEYHpJ4e2XyAC6#J07tNyi+|1(F zGz<7G;eEw?ht TeGeMtLIpjJpfV?jO ziz(KIRrC#Dv5ygGs1XfAu+tBws0v&Mn6;j)@<2oKJMV3pVG*Txl!$35f8(g)8!8^V zm$je(_F7Q92v&hP79>ZknZvpqph}%H7*R}Otxs>Eb6VUyHUwm-)Z^Ru8bVwz@+i |PU{CV(@6f3g}{1{<=Eqo|PQ z1vL)>4n>~k_hibg$X-**Us(%0A4Sdc^Gje~Q1+ki*xa;wyaRm(0o&>@T{ja9^a;vG zK1j#0?N>J4R`BfE{Q-e>{A_`)h!$3?ca2K1$GjK-70&vaL%gwH@yLYAs#h4 z`3zJ-_jNwO;1)QA6_Z+sKsb# `ijQUhn_z5dkH^8DK;{W6~2m;cv6mS_%%<~Fr+AH%$tet2E`a9 z?i+HM4ABU+HTGo`=WQJFjEWhdO@*{Rq;&mu%Ewus%T Mh^mZ!;6C3m95xI_;o^_S3?zX+DK_X6v&n{{a^bqRRjP literal 0 HcmV?d00001 diff --git a/item/forms.py b/item/forms.py new file mode 100644 index 0000000..1e4b9e9 --- /dev/null +++ b/item/forms.py @@ -0,0 +1,45 @@ +from django import forms + +from item.models import * + +import datetime +from django.utils.timezone import utc + +class ItemContentForm(forms.ModelForm): + content = forms.CharField(required=False, widget=forms.Textarea) + + class Meta: + model = ItemContent + fields = ('content',) + +class ContentAttachmentForm(forms.ModelForm): + file = forms.FileField() + + class Meta: + model = ContentAttachment + fields = ('file',) + + def clean_file(self): + file = self.cleaned_data['file'] + if file: + if file._size > 2*1024*1024: + #raise ValidationError("Image file too large ( > 200KB ).") + return None + else: + if str(file.content_type.split('/')[0]) == 'image': + return file + else: + return None + else: + #raise ValidationError("Couldn't read uploaded image.") + return None + +class LinkForm(forms.ModelForm): + url = forms.CharField(required=True) + logo = forms.CharField(required=False) + title = forms.CharField(required=True) + description = forms.CharField(required=False) + + class Meta: + model = Link + fields = ('url', 'logo', 'title', 'description',) diff --git a/item/forms.pyc b/item/forms.pyc new file mode 100644 index 0000000000000000000000000000000000000000..e960b7b378a63151d0ead33f823a50e1457a7ffb GIT binary patch literal 2417 zcmcIl-)|d55S~4s&yGoGTA)${f=~%$wQ9-}4+sGzC=ybehjVzqwRAf9*2y}1ckb<4 z(5gHc{ull_UibrGzS(f+wogcjlbxIWaW~)0d^6kodvEmDpF7XyboJ};^E)2y4;BUg zE3!nTqNyT {X!P^7X>{Qep8R5p zbM1Z1>Qn9W)*=v!#rIihEh2Cn)fnH4c*74^%mZNYCdEQ$D$A<8)LG_7yqslaU92sp zh|ZR;5+2^vRxmA$wuKw>8R~@lmZ!&G&3 |$-#56j$n-OLO}bS9BMTD?f&F>E{do2W#E?;|Ryh#hD=$U{56$eR;@5r8MTby^~L zrhoN$qjT|AKHA|F?OMQs7yxwz_QS}308Am;k3A>rqI{Dmct_Iq1uJdZm?#@24Rb;& zfK&J%zxyByPnb2FQba}E`M)&4iwk3Q;J|I32?x5EdaS(#Jw-0kT^#4JC9WlYNcJ5b zZL;SeHE4?{9b@Mii&sQTX&DE qqnOmJ#y2y&$ z=R&~DnU`8h^|Y=uBVrGH6V3)!Wd6lU%UQRw#)le3a-6mc!O;c!I$|t!EjTlz|1K=; zvmmv{#dRx+qkAfj2EAYvy`iH-S7s;ts+5@^6auCn@!1ZmXx9Na1v+$EhcG8 U%hy^iqAQg&XJxyRILF*_H>CL5=$ddMD|}aMwPl r}Z>&4Q>PxQa6kS5Do~O7C mLC6%D722i%a04|V*uD;T^EYTt4&7%z8b!NmKROs3-2E3==jH7H literal 0 HcmV?d00001 diff --git a/item/models.py b/item/models.py new file mode 100644 index 0000000..94042c5 --- /dev/null +++ b/item/models.py @@ -0,0 +1,130 @@ +from django.db import models + +# Create your models here. +from django.contrib.auth.models import User +from django.core.files.storage import FileSystemStorage +from django.conf import settings +import os +import datetime + +from tag.models import * + +def attachment_file(instance, filename): + return os.path.join('file', str(datetime.datetime.now().strftime('%Y%m%d%H%M%S%f')), filename) + #if len(filename.split('.')) > 1: + # return os.path.join('file', str(datetime.datetime.now().strftime('%Y%m%d%H%M%S%f')) + '.' + filename.split('.')[-1]) + #else: + # return os.path.join('file', str(datetime.datetime.now().strftime('%Y%m%d%H%M%S%f'))) + +class UserItemRelationship(models.Model): + user = models.ForeignKey(User) + type = models.CharField(max_length=30) + +class Item(models.Model): + user = models.ForeignKey(User) + status = models.CharField(max_length=30) + credit = models.BigIntegerField(default=0) + useritemrelationship = models.ManyToManyField(UserItemRelationship) + belong = models.ManyToManyField('self', symmetrical=False, blank=True) + tag = models.ManyToManyField(Tag) + + def get_all_items_old(self, include_self=True): + items = [] + if include_self: + item = self + itemcontent = item.itemcontent_set.all() + item.create = itemcontent[0].create + item.update = itemcontent.reverse().create + items.append(item) + #for item in Item.objects.filter(belong=self).prefetch_related('itemcontent_set'): + for item in self.item_set.prefetch_related('itemcontent_set'): + itemcontent = item.itemcontent_set.all() + item.create = itemcontent[0].create + item.update = itemcontent.reverse().create + if item not in items: + items.append(item) + for subitem in item.get_all_items(include_self=False): + itemcontent = subitem.itemcontent_set.all() + subitem.create = itemcontent[0].create + subitem.update = itemcontent.reverse().create + if subitem not in items: + items.append(subitem) + return items + + def get_all_items(self, include_self=True): + items = [] + queue = [] + queue.append(self) + while queue: + node = queue.pop(0) + if include_self: + item = node + itemcontent = item.itemcontent_set.all() + item.create = itemcontent[0].create + item.update = itemcontent.reverse().create + if item not in items: + items.append(item) + for item in node.item_set.all(): + queue.append(item) + itemcontent = item.itemcontent_set.all() + item.create = itemcontent[0].create + item.update = itemcontent.reverse().create + if item not in items: + items.append(item) + return items + + def get_root_items_old(self): + rootitems = [] + if self.belong.all(): + for belongitem in self.belong.all().prefetch_related('itemcontent_set'): + for rootitem in belongitem.get_root_items(): + if rootitem not in rootitems: + rootitems.append(rootitem) + else: + rootitems.append(self) + return rootitems + + def get_root_items(self): + rootitems = [] + queue = [] + queue.append(self) + while queue: + node = queue.pop(0) + if node.belong.all(): + for belongitem in node.belong.all().prefetch_related('itemcontent_set'): + queue.append(belongitem) + else: + if node not in rootitems: + rootitems.append(node) + return rootitems + +class ItemContent(models.Model): + item = models.ForeignKey(Item) + create = models.DateTimeField(auto_now_add=True) + content = models.TextField() + ip = models.CharField(max_length=255) + ua = models.CharField(max_length=255) + + class Meta: + ordering = ['id'] + +class ContentAttachment(models.Model): + itemcontent = models.ForeignKey(ItemContent) + title = models.CharField(max_length=30) + file = models.FileField(storage=FileSystemStorage(location=settings.MEDIA_ROOT), upload_to=attachment_file) + content = models.TextField() + contenttype = models.CharField(max_length=30) + +class Link(models.Model): + url = models.TextField() + logo = models.TextField() + title = models.TextField() + description = models.TextField() + status = models.CharField(max_length=30) + unreachable = models.BigIntegerField(default=0) + lastcheck = models.DateTimeField(auto_now=True) + +class Coin(models.Model): + user = models.ForeignKey(User) + cointype = models.TextField() + coinhold = models.TextField() diff --git a/item/models.pyc b/item/models.pyc new file mode 100644 index 0000000000000000000000000000000000000000..41e45faebdfd5a0dee78c07afa24a7e3355eb72a GIT binary patch literal 5568 zcmcIoU2`Kx6}=-_l4Z*uYi~9&S=bO_5P>)W3Mf7*Wyj9eZn1W#u_@OIyTn-2lExm* z$TO|PuJRTS-q*bF!qf81U*Lg%kQaVNUU=aLgmZ37vNpR(QNflq?e4y<{~*cx)FWE=aE^jiPH8C7zOANg5^Bo|3pM zy^1s{u3eINS{l NA-Co^Y zZPzQDl*^>Kj_U`utCiz4O0WXfwVCB6!@wFF^^A5V=_lF=VVj+GPN6+flG`9@8EtUY zB!C!F(IQ_*ZS&U$)J=Y{5%!`a!XyDya U(+ z@gPRiM@zKtewvx6ll;z{`-&UdW`M2QDk_`ZAiE!#I8+PR^Ztb5u1|aZB9>allXLO1 zx8Uh=RMuEQgtIE>Z>ao_3ZlxuXkfDlJbGX>dqC7#)hURn&2WkYGT?Ao%sfPe#=>ai zqK>@9e)<4d0vtqrTI {y&A;UZGWHu|=N@Q(IUfIyCKI5Zee ;aociW ze%=Fwv#1rsmdrYegXBcH#v^m+CP)1U#_5PWDUeFpu3VsAl#8MqD*-RjoRSNi#FG`U z5rQU4P?1L`KiPv3IB|(}fXYim&i=)j0IcK6kgQvW|NLe%V>bmksYv#Z7gy=%PGJjp zh$?Ndb+{`}u#wVN?Z5QG{?UW|<2P=V&qk}j*WfItp9#MEr)}BCfZaM3x8u}JZj!F8 zG_fQnog2v+C9QZ68nokfo%Ha(jY7Ri5Xb63TbZGgp#?MZF&u=^?m=ID4-FLb`z8sU zqrn =@g`)J^UtS8Lx7;@s3Zk^e0gB(DnG5T1fHMask( zbVvE%h+Wt1$_U)&Hrh<%@E$sIUCAr!--5U3EqRND6|j}H8p^BsYn~#QdMn~l1Xsrh zCXPqg1^Q^dv(Jf;Y|2B4`vfRPFA)u}e@Yw=!2 N{%Q_U(2whrGMLJ2^j@7W+?2npxmPB#SK{nItsPv%A >_wbaF^9rUWC)RC61#7&~qoknvcyk=9_r5CnFvOYp@ zPA4R4kbB-T==pkK&KZFR9h35}XgDLV#4X`yG9=|EY-fMb-Z3d1b4RSmayfgX-hI>q z?YppV>u^~q?55N>#yfqi9DsR-2D__P0W*gNyDLf&8i$*76uGjHYTkbb68}9GN)lR0 z?dMqWQwr8tyvyQel;XKg3j74q?c>SsaAF0%qrif9&%0fydAGefMLrGWGqllw%V!*@ zVV3_2YaF7OLxgGvxkiy6M4gAYr#faBc=2w)H55ix#oIx0zL&DpxJ*MQ4KEq95pR0m z48u$R2V8)R+sg( <&P^i6HyHlOjJMJM)u<7pU7RKp^IMC29M#X$>Y-}nT=pji1=on~71K}R( z$lL&6WFrUzUEDX>gV3+Y7!Z-*(_uz8&p?j4*H9rC*tCfhqZx#ui|oFjh??Cti2Ctg zKXh`sRbHZQt04%6u(81TDAwF23KiW~@X!Dv%|h5P>D-9^*ReJgs3}R=b89d(y4u79 zMrkd*K{RgJLIksiq{>0=H x8=j*I$w;6dQ8qje)Edmj@+ z*OJ#zIAqm`u7af%hG^OtCud`0l^|7PouKmdxMDn_ITx{{DTTr70c2-0gcd|V4idgg zDd1HA#~_UW_FNh wADTQam~L z b9!aeJWdvSe3BE;sJ4Xx+Wsah4pVf>+7m ztd6PC2Ot%swbcbYZ!3QVJ8)UWG-@NaP=6VZs7&>;gDloF#c3z?AF-F(4Ncz4zz(=- zwVTh7%Kzm^JV=mww7S7jZ2V11$U3!Xj295Cu4$dz2$_D5Wj@BEuV%_Hhx? \d+)/$', views.View, name='view'), + url(r'^update/(?P \d+)/$', views.Update, name='update'), + url(r'^link/$', views.LinkClass, name='link'), +] diff --git a/item/urls.pyc b/item/urls.pyc new file mode 100644 index 0000000000000000000000000000000000000000..2dcf27b8d85ad07a0e8d99c33ab7fb440c816148 GIT binary patch literal 585 zcmY+9%}&BV5XYx21 8oZboV=#EYhNNLvEc7d#tsiF}!I$vqy!Ze* zGldwpyR-ZM&F=I+&Ud%<_31sVU^hJ4&uQTY1x3?>7$C7=VS&ZkhS-M0frSH>wm> @r-tu<$_j;LblFU(pW@-=dRo zD3nE9375okq+bwiIxUB$Mq3&t+HfXHm3~ETaJedUX!Oa@)JatWdz|pkZpV?D1nTIJ zviw}?4LDckiXZ*I!Ud`XHuzE;rQ6+0KHm5(qNYzlZNhY&jaFIuI3mY5BL?z|$mnDy z-LTCowkgJ@;!>{MQ&+;~V#072*HnKRhlr+4ic038F}g_6CkcN6CnTq*!5npg!G%hq zG(uB^CM$wVja!rDL1iv@D&z7v36aVK>?&ZRqx{V@sl+(RR2l0DJH-x#zTI~QR`vY? D*N1>k literal 0 HcmV?d00001 diff --git a/item/views.py b/item/views.py new file mode 100644 index 0000000..8184b4e --- /dev/null +++ b/item/views.py @@ -0,0 +1,641 @@ +# -*- coding: utf-8 -*- +import sys +reload(sys) +sys.setdefaultencoding('utf8') +# Create your views here. + +from django.template import RequestContext +from django.http import HttpResponse +from django.shortcuts import redirect, render +import datetime +from django.utils.timezone import utc +import urllib2 +import json +from item.models import * +from item.forms import * +from tag.models import * +from django.forms.utils import ErrorList +from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger +from user.models import * +from hulu import * +from main.__init__ import * +from item.__init__ import * +from django.forms.models import inlineformset_factory +from django.db.models import Q +import ssl +import HTMLParser +import threading + +def Index(request): + if request.user.is_authenticated(): + items, belongitems = get_item_by_user(request.user, request) + + content = { + 'items': items, + 'belongitems': belongitems + } + if request.GET.get('type') == 'json': + content = { + 'page': items.number, + 'items': [] + } + for item in items: + content['items'].append({ + 'id': item.id + }) + return HttpResponse(json.dumps(content, encoding='utf-8', ensure_ascii=False, indent=4), content_type="application/json; charset=utf-8") + return render(request, 'item/index.html', content) + else: + return redirectlogin(request) + +def Create(request): + if request.user.is_authenticated(): + if request.GET.get('t'): + tagname = request.GET.get('t').strip() + if tagname: + try: + tag = Tag.objects.filter(name=tagname)[:1].get() + except Tag.DoesNotExist: + tag = None + else: + tag = None + else: + tagname = None + tag = None + + if request.method == 'GET': + if request.GET.get('t') == '': + return redirect('/i/create/') + + content = { + 'tagname': tagname + } + return render(request, 'item/create.html', content) + + if request.method == 'POST': + if ((not request.POST.get('content') or request.POST.get('content').strip() == '') and (not request.FILES or 'VCAP_SERVICES' in os.environ)): + content = { + + } + return render(request, 'item/create.html', content) + + form = ItemContentForm(request.POST) + if form.is_valid(): + ItemContentInlineFormSet = inlineformset_factory(ItemContent, ContentAttachment, form=ItemContentForm) + for attachmentfile in request.FILES.getlist('file'): + attachmentform = ContentAttachmentForm(request.POST, request.FILES) + if attachmentform.is_valid(): + pass + else: + content = { + 'form': form + } + return render(request, 'item/create.html', content) + + item = Item(user=request.user) + item.save() + itemcontent = ItemContent(item=item) + itemcontentform = ItemContentForm(request.POST, instance=itemcontent) + itemcontent = itemcontentform.save() + itemcontent.save() + + if tagname: + if not tag: + tag = Tag() + tag.name = tagname + tag.save() + item.tag.add(tag) + item.save() + + + if 'VCAP_SERVICES' not in os.environ: + #attach save + for attachmentfile in request.FILES.getlist('file'): + attachment = ContentAttachment(itemcontent=itemcontent) + attachmentform = ContentAttachmentForm(request.POST, request.FILES, instance=attachment) + if attachmentform.is_valid(): + contentattachment = attachmentform.save() + contentattachment.title = attachmentfile.name + contentattachment.contenttype = str(attachmentfile.content_type) + contentattachment.save() + + #convert img to svg + img2svg(contentattachment) + + x_forwarded_for = request.META.get('HTTP_X_FORWARDED_FOR') + ip = request.META['REMOTE_ADDR'] + if x_forwarded_for: + ip = x_forwarded_for.split(', ')[-1] + + itemcontent.ip = ip + itemcontent.ua = request.META['HTTP_USER_AGENT'] + + itemcontent.save() + else: + content = { + 'item': item, + 'reply': reply, + 'form': form + } + return render(request, 'item/create.html', content) + + return redirect('/i/' + str(item.id) + '/') + else: + return redirectlogin(request) + +def View(request, id): + try: + item = Item.objects.filter(useritemrelationship__isnull=True).filter(Q(belong__isnull=True)).get(id=id) + #itemcontent = ItemContent.objects.filter(item=item) + itemcontent = item.itemcontent_set.all() + #取第一个内容首行作为标题 + #if itemcontent[0].content: + # item.title = itemcontent[0].content.strip().splitlines()[0] + #else: + # contentattachment = itemcontent[0].contentattachment_set.all() + # if contentattachment: + # item.title = contentattachment[0].title + # else: + # item.title = str(item.id) + #item.firstcontent = ''.join(itemcontent[0].content.strip().splitlines(True)[1:]) + + #取最后一个内容首行作为标题 + if itemcontent.last().content: + item.title = itemcontent.last().content.strip().splitlines()[0] + else: + contentattachment = itemcontent.last().contentattachment_set.all() + if contentattachment: + item.title = contentattachment[0].title + else: + item.title = str(item.id) + item.firstcontent = ''.join(itemcontent.last().content.strip().splitlines(True)[1:]) + except Item.DoesNotExist: + item = None + if not item: + return redirect('/') + + try: + items = item.get_all_items(include_self=False) + items.sort(key=lambda item:item.create, reverse=False) + paginator = Paginator(items, 100) + page = request.GET.get('page') + try: + items = paginator.page(page) + except PageNotAnInteger: + items = paginator.page(1) + except EmptyPage: + items = paginator.page(paginator.num_pages) + except Item.DoesNotExist: + items = None + + if request.method == 'GET': + try: + UserNotify.objects.filter(user=request.user.id).filter(item=item).delete() + UserNotify.objects.filter(user=request.user.id).filter(item__in=set(item.id for item in items)).delete() + except UserNotify.DoesNotExist: + pass + + reply = None + if request.GET.get('reply'): + replyid = str(request.GET.get('reply')) + try: + reply = Item.objects.get(id=replyid) + except UserNotify.DoesNotExist: + pass + + if not item or (item.status == 'private' and item.user != request.user): + content = { + 'item': None + } + return render(request, 'item/view.html', content) + + try: + tags = Tag.objects.all().order_by('?')[:10] + except Tag.DoesNotExist: + tags = None + + content = { + 'item': item, + 'items': items, + 'reply': reply, + 'tags': tags + } + return render(request, 'item/view.html', content) + if request.method == 'POST': + if not item or (item.status == 'private' and item.user != request.user): + content = { + 'item': None + } + return render(request, 'item/view.html', content) + if request.user.is_authenticated(): + #把信息改为只有私有 + if request.user.id == 1 and request.POST.get('status') == 'private': + item.status = 'private' + item.save() + return redirect('/') + + if item.user == request.user and request.POST.get('tagname'): + tagname = request.POST.get('tagname').strip() + if tagname != '': + if request.POST.get('operate') == 'remove': + try: + tags = Tag.objects.filter(name=tagname).all() + for tag in tags: + item.tag.remove(tag) + item.save() + except: + pass + else: + try: + tag = Tag.objects.filter(name=tagname)[:1].get() + except Tag.DoesNotExist: + tag = Tag() + tag.name = tagname + tag.save() + if tag not in item.tag.all(): + item.tag.add(tag) + item.save() + if request.POST.get('type') == 'json': + content = str(tag.id) + return HttpResponse(json.dumps(content, encoding='utf-8', ensure_ascii=False, indent=4), content_type="application/json; charset=utf-8") + return redirect('/i/' + id + '/') + + reply = None + if request.POST.get('reply'): + replyid = str(request.POST.get('reply')) + try: + reply = Item.objects.get(id=replyid) + except UserNotify.DoesNotExist: + pass + + if (not request.POST.get('content') or request.POST.get('content').strip() == '') and (not request.FILES or 'VCAP_SERVICES' in os.environ): + content = { + 'item': item, + 'items': items, + 'reply': reply + } + return render(request, 'item/view.html', content) + + form = ItemContentForm(request.POST) + if form.is_valid(): + ItemContentInlineFormSet = inlineformset_factory(ItemContent, ContentAttachment, form=ItemContentForm) + for attachmentfile in request.FILES.getlist('file'): + attachmentform = ContentAttachmentForm(request.POST, request.FILES) + if attachmentform.is_valid(): + pass + else: + content = { + 'item': item, + 'items': items, + 'reply': reply, + 'form': form + } + return render(request, 'item/view.html', content) + + new_item = Item(user=request.user) + new_item.save() + if reply: + new_item.belong.add(reply) + else: + new_item.belong.add(item) + + itemcontent = ItemContent(item=new_item) + itemcontentform = ItemContentForm(request.POST, instance=itemcontent) + itemcontent = itemcontentform.save() + itemcontent.save() + + if 'VCAP_SERVICES' not in os.environ: + #attach save + for attachmentfile in request.FILES.getlist('file'): + attachment = ContentAttachment(itemcontent=itemcontent) + attachmentform = ContentAttachmentForm(request.POST, request.FILES, instance=attachment) + if attachmentform.is_valid(): + contentattachment = attachmentform.save() + contentattachment.title = attachmentfile.name + contentattachment.contenttype = str(attachmentfile.content_type) + contentattachment.save() + + #convert img to svg + img2svg(contentattachment) + + x_forwarded_for = request.META.get('HTTP_X_FORWARDED_FOR') + ip = request.META['REMOTE_ADDR'] + if x_forwarded_for: + ip = x_forwarded_for.split(', ')[-1] + + itemcontent.ip = ip + + itemcontent.ua = request.META['HTTP_USER_AGENT'] + + itemcontent.save() + + if reply: + if request.user != reply.user: + notify = UserNotify(user=reply.user, item=new_item) + notify.save() + else: + if request.user != item.user: + notify = UserNotify(user=item.user, item=new_item) + notify.save() + + return redirect('/i/' + id + '/#' + str(new_item.id)) + else: + content = { + 'item': item, + 'reply': reply, + 'form': form + } + return render(request, 'item/view.html', content) + else: + return redirectlogin(request) + +def Update(request, id): + if request.user.is_authenticated(): + try: + item = Item.objects.filter(useritemrelationship__isnull=True).filter(Q(belong__isnull=True)).get(id=id) + if item.user.username != request.user.username: + item = None + else: + itemcontent = item.itemcontent_set.all() + #取第一个内容首行作为标题 + #if itemcontent[0].content: + # item.title = itemcontent[0].content.strip().splitlines()[0] + #else: + # contentattachment = itemcontent[0].contentattachment_set.all() + # if contentattachment: + # item.title = contentattachment[0].title + # else: + # item.title = str(item.id) + #item.firstcontent = ''.join(itemcontent[0].content.strip().splitlines(True)[1:]) + #取最后一个内容首行作为标题 + + if itemcontent.last().content: + item.title = itemcontent.last().content.strip().splitlines()[0] + else: + contentattachment = itemcontent.last().contentattachment_set.all() + if contentattachment: + item.title = contentattachment[0].title + else: + item.title = str(item.id) + item.firstcontent = ''.join(itemcontent.last().content.strip().splitlines(True)[1:]) + except Item.DoesNotExist: + item = None + if not item: + return redirect('/i/' + id) + if request.method == 'GET': + content = { + 'item': item + } + return render(request, 'item/update.html', content) + if request.method == 'POST': + if item: + if request.POST.get('content').strip() == '' and (not request.FILES or 'VCAP_SERVICES' in os.environ): + content = { + 'item': item + } + return render(request, 'item/update.html', content) + + form = ItemContentForm(request.POST) + if form.is_valid(): + ItemContentInlineFormSet = inlineformset_factory(ItemContent, ContentAttachment, form=ItemContentForm) + for attachmentfile in request.FILES.getlist('file'): + attachmentform = ContentAttachmentForm(request.POST, request.FILES) + if attachmentform.is_valid(): + pass + else: + content = { + 'item': item, + 'form': form + } + return render(request,'item/update.html', content) + + itemcontent = ItemContent(item=item) + itemcontentform = ItemContentForm(request.POST, instance=itemcontent) + itemcontent = itemcontentform.save() + itemcontent.save() + + if 'VCAP_SERVICES' not in os.environ: + #attach save + for attachmentfile in request.FILES.getlist('file'): + attachment = ContentAttachment(itemcontent=itemcontent) + attachmentform = ContentAttachmentForm(request.POST, request.FILES, instance=attachment) + if attachmentform.is_valid(): + contentattachment = attachmentform.save() + contentattachment.title = attachmentfile.name + contentattachment.contenttype = str(attachmentfile.content_type) + contentattachment.save() + + #convert img to svg + img2svg(contentattachment) + + x_forwarded_for = request.META.get('HTTP_X_FORWARDED_FOR') + ip = request.META['REMOTE_ADDR'] + if x_forwarded_for: + ip = x_forwarded_for.split(', ')[-1] + + itemcontent.ip = ip + + itemcontent.ua = request.META['HTTP_USER_AGENT'] + + itemcontent.save() + + return redirect('/i/' + id) + + else: + content = { + 'form': form + } + return render(request,'item/update.html', content) + else: + return redirect('/i/' + id) + else: + return redirect('/u/login/?next=/i/update/' + id) + +def Cancel(request, id): + if request.user.is_authenticated(): + try: + item = Item.objects.get(id=id) + if item.user.username == request.user.username: + item.status = 'cancel' + item.save() + except Item.DoesNotExist: + pass + return redirect('/i/' + id) + else: + return redirect('/u/login/?next=/i/update/' + id) + +if 'weibo_username' in os.environ: + from weibo import Client + +def wbimg(request): + if 'weibo_username' in os.environ: + if request.method == 'POST': + url = 'https://upload.api.weibo.com/2/statuses/upload.json' + weiboclient = Client(os.environ['weibo_appkey'], os.environ['weibo_appsecret'], 'hulu.im', username=os.environ['weibo_username'], password=os.environ['weibo_password']) + content = weiboclient.post('statuses/upload', status='http://hulu.im', pic=request.FILES['file']) + return jsonp(request, content) + else: + return redirect('/') + +regex = re.compile( +r'^(?:http|ftp)s?://' +r'(?:(?:[A-Z0-9](?:[A-Z0-9-]{0,61}[A-Z0-9])?\.)+(?:[A-Z]{2,6}\.?|[A-Z0-9-]{2,}\.?)|' +r'localhost|' +r'\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})' +r'(?::\d+)?' +r'(?:\/?)$', re.IGNORECASE) + +ctx = ssl.create_default_context() +ctx.check_hostname = False +ctx.verify_mode = ssl.CERT_NONE + +hdr = { + 'User-Agent': 'hulu' +} + +urlblist = [] + +def checklink(url, checktimes): + try: + links = Link.objects.filter(url=url).all() + except: + links = None + for link in links: + if link.url[-1] == '/': + link.url = link.url[:-1] + link.save() + + if link.url.split('://')[1] in urlblist: + link.delete() + continue + + #if link.logo and not re.match(regex, link.logo): + # link.logo = '' + # link.save() + + title = '' + logo = '' + try: + req = urllib2.Request(link.url, headers=hdr) + content = urllib2.urlopen(req, context=ctx, timeout=10).read() + hp = HTMLParser.HTMLParser() + title = hp.unescape(content.split(' ')[1].split(' ')[0]).encode("utf-8") + if '')[0].split('href="')[1].split('"')[0]).encode("utf-8") + elif '')[0].split('href="')[1].split('"')[0]).encode("utf-8") + else: + logo = '' + if logo != '': + if logo[0] == '/': + if logo[1] != '/': + logo = url + logo + else: + logo = url + '/' + logo + if 'data:' in logo: + logo = '' + else: + req = urllib2.Request(url + '/favicon.ico', headers=hdr) + status = urllib2.urlopen(req, context=ctx, timeout=10).getcode() + if status == 200: + logo = url + '/favicon.ico' + if title: + link.title = title + if 'data:' in logo: + logo = '' + link.logo = logo + link.unreachable = 0 + link.save() + else: + link.delete() + except: + if checktimes < 3: + checklink(url, checktimes + 1) + else: + if not link.unreachable: + link.unreachable = 1 + else: + link.unreachable = int(link.unreachable) + 1 + link.save() + if int(link.unreachable) > 10: + link.delete() + +def LinkClass(request): + try: + links = Link.objects.all().order_by('?')[:100] + except Link.DoesNotExist: + links = None + + if request.method == 'GET': + if request.GET.get('type') == 'fetch': + if request.GET.get('url'): + url = request.GET.get('url').strip() + if re.match(regex, url): + title = '' + logo = '' + try: + req = urllib2.Request(url, headers=hdr) + content = urllib2.urlopen(req, context=ctx, timeout=10).read() + hp = HTMLParser.HTMLParser() + title = hp.unescape(content.split('')[1].split(' ')[0]).encode("utf-8") + if '')[0].split('href="')[1].split('"')[0]).encode("utf-8") + elif '')[0].split('href="')[1].split('"')[0]).encode("utf-8") + else: + logo = '' + if logo != '': + if logo[0] == '/': + if logo[1] != '/': + logo = url + logo + else: + logo = url + '/' + logo + if 'data:' in logo: + logo = '' + else: + req = urllib2.Request(url + '/favicon.ico', headers=hdr) + status = urllib2.urlopen(req, context=ctx, timeout=10).getcode() + if status == 200: + logo = url + '/favicon.ico' + except: + pass + content = { + 'title': title, + 'logo': logo + } + return jsonp(request, content) + else: + return redirect('/i/link/') + else: + return redirect('/i/link/') + + if request.GET.get('f'): + url = request.GET.get('f').strip() + if request.GET.get('check') == 'true': + checklink(url, 0) + if re.match(regex, url): + return redirect(url) + else: + return redirect('/i/link/') + + content = { + 'links': links + } + return render(request, 'item/link.html', content) + + if request.method == 'POST': + form = LinkForm(request.POST) + + if form.is_valid() and re.match(regex, form.cleaned_data['url']): + url = request.POST.get('url').strip() + if url[-1] == '/': + url = url[:-1] + hostname = url.split('://')[1].split('/')[0] + if not Link.objects.all().filter(Q(url__icontains=hostname)): + link = form.save(commit=False) + #link.lastcheck = timezone.now() + link.save() + + return redirect('/i/link/') + else: + return render(request, 'item/link.html', { 'links': links, 'form': form }) diff --git a/item/views.pyc b/item/views.pyc new file mode 100644 index 0000000000000000000000000000000000000000..40e5e5dcebd4401728ac28f0e52c85098d8f5ccd GIT binary patch literal 15413 zcmcIrTWlQHc|J3rBXwa9w zwBPrincXENt9Gl9+_UF?{_~&z{MSS4C*7U@_Vvt1iYorG@cj%v;eQ!QIruYFS*azZ zTtm4^-7%Dbuac=8Qwr>2sj{UiDYcYR2Foc`Zc~-CT1xA3n<}@fN{3qNP?d~Y%II25 z+^Lp2Ws$Th?^2a6wba#U>sCwM2>?B6sYmkds@$s rmx>RT)rA1A3N> zD(_L1LA5lfDnn{%NL7Z_(y(sB_`QwsBaPg?MsB~(b*l11s`9W}dRUL!rOJ<}$^o@> zpaE%CEoBo(N7d43l0T@H4l1WheG2$Hq?~Ta99B+`WR57OS2B+(r%y7EDQCBGbE-6^ zZl+c6dBJ7BDj!vqV`}M`GJNcNK)N1R?g>>ISI!>EOsG4iS~{uRtSX&Scd*`R<(^UQ zX_Y@Km5)n)QhA1Q29-0UCYPR2H_-1% V0q?)@GZ&?htw*a* z=0FiD>Oo?=>vcDbrmKGBZbZ7i3-y T z%cj~g)Rw6{)B~l4n!GJHVsgupj+QE=crS2WoRqq0s^FctZ>dc=ZE6y@=O}dF7~>Q( z*GJV>O5L_tJyJ^Zq;98Fsa-i~HOX7IzOEL5PVBwZDgDsYp`470b}0w9Xcrc T5-!&|AsE}%%jbkD~DeS zanP)(5#2mj&ykaL{bJSe{2L)B0*Rb>63c>B_+dS8^M$bJd2;9;&fJeYnUo!hBpg4= zbA|8#Dhjn)*((+zuj)^5wGU*AYlQ#@_O#3z5?lf{!I?J3*P==}M?%!J8M=WGffwcr z^=OStVJ_E^N vZHvYl?UCInutf u?1Sz#(NjY30DqvN|Nv*a?|IQUjmfj z@|08Ye9(VDieH{_!<$jHw(OJ&{*CJLTD@F9Q7MFx8!U5@ ;9l{jeM@dcT4 wR5>>w*buRDOVl0 zyPwzye%^`(RJ2D$;LKeL-R_viR-4-Ri1hDKr6GN(!6cqlTWJ*y#}g5}9`d8Dc6GZw zneH89{fmZXADE6TW+x NnFWJx4 PMRTF=U+ybz7P$&imi9;0@iy8>&ku7lEZWR qq2wK80qzt6Wz0Z_VV6W@|czukE4Lc)h7~k`Lr;2i1 zhy`4v`P@F-^|?sIx$q&sP;o&qU{h>~@KIqWk_m637`R}i6T;AqcS6 zGS7=w=NIgQXoa*<>gDOF7xVM8_RCkMXXmAzQdnoavTF~ck9~-}sU>)R7!~}YE24`gE*ksCuv1GASoqQKsdL WcS3{ZG^>29rgd@Sf z0vw2j uhxuuo^H}dHJN+EDuhdFx=bt1 h zKkLENAtO@YnUE`8%73P%6WDD#o2gBwRPcLD*|h{-uY32?h~b*O Z zO!XbQ`=_+PW0Prs!qEmUPr05J`7j~~(~3j8+8juPmQ0Vi7X1$boc#jJmkEm&Y5*C_ zquoD*=7*&DPn*r`^l;JxVDH$}_t}$b7shi_*zF@!8K`2tW^I;KbRaos=n81f3PR<$ zDR?2(ksswz829VCTSbtV{X_!xJp+jO*BH9!?*Z^wN~78{0TtmPWYAf#uEx#)hXvm@ zd9>RriGz&V97!ls)1FotI-rPt+iaQtFF8M|u2DvtQ11Sd+Kd+9+ < zoPY* t~qfxSR~E{&a;B^QQ7v}ZKQupEv${?IIf}zRXRy>ba2l= z1&7ImoFmG46ay^>UZ)%~#ylpa;xF!qVH}d^j?HVP4_IHbv+4MnwN(CZ*X(S%<(i#L z6QgI-a?Kh$Im(@Mg>JgJIjPd;9@|~tkk(V^_p!8dOhu 5SN2-$+wkzSniR$F+>k z#uy~nKpCv8$A!M#Of;#YCsYK_*l~q!G#`4^Mos#kQYARbP7uzS>&t4ZPeteAi3l@% zZ(!OmNOmXF4YjZTYx-TUF`Sym?|F?eXc6*-Rv4zm2}5S|tK0nv&43RCueG!M0aXHl zKwN@ueX!j|mA0y|6Eb5Ong%VwWZTZTSivymAWa71Y0-faP~X%hZb6Le9kB_v4FNF0 zfB+zBLMFosFk-jkgX_Tb0S;TS^5b@5NY W}5Jh3oLM> z>pyPC-(q|XE(+^8$(AkfT_EhDa!$e08dA3hRq*>ANK4Ns=QMjbXQY8c(QK*wR5Ic$ z)CrV7*n$J1xi@Bb$m1Z$b1r2dkF y^ z40uEYgbj1r6-!N5Ta!{29sL0-(;Zmie7R6raS9jSLO#SNan#*{$IbPC9c9yq(l+1@ z`xJNrB7E5rm0x~1M@TIgTe{v8JHW8FmyLBe%eL=Pu&2G^96EmTr?AP8+W7e!uJ3Nt zf(w66=(tu|iIF8{SuOBx!J-d&ygd5}x(>Ao&-1wG(Et*krC4q-{z7fA@`zxfNA*w) zGnuSfbK#%VW^UkCs @Z%sXf3^4fn83W8N0Ge2O_5kMGF=Y@s78c5MhA< $A5n_<3N>$I7`?Kl=VHA(BpJbn>m~iLf zPN5?k>x(lxwCOdM@gd?NHfdWEt&p!AAxS|ZC2(%%>A4T>bF5+`UCeM+c&nS@_z*XR z BK4|*`OwKcT zn#lzwba#s*!+wUjDJCCeGL1w)(h&)v68kx}e2B^OOkQ9z$K)!LERvjnHOiuR?+-C2 zbny~%bV&(5fD0W*(s!Ni2O(zh4Z*i^kiCmca!h1*LTxXy_+chC5s_#UeUV(mi z0q8fdi~)N7@!7{#cnB=xm~j#L6ubfSD_H2+XSAC+ sVT|pP@%zP}z_r>jnm!8p7<%AyfR_P1dW~_!9=5Oc9DD28@A6tC>uTQx_eReK zeHwuOem)EIqmP5T>H|LZ!dG&j;lmiv9*iE~E{zXKE^Gr{wQPz5e?PG{GX~sL2wTAS zPlpDTd;@u$Egc$CgluJ;1IkmYLjy8S+ozJD-mogM3 =u&%`;GU z+f+0{Jj3$=vzA73+;^AsHBtaD_>sh8_6cSIAW$rbh>d_BO7LYrjDU9x1U#Y4z?H$E z`48{E5Iy{WYab`1a|JFCc>7`2zHLQW6^)87qK9sD9W~fkk^YENz;F@`Z07nL9S_>f zXXF6W!Rm$Duj3$kx(}J_qb7sHddpY`o|Aj+9NiYNEbxM^v5ua=Nd1t$rzG5RgpkJ6 zBKelBLr0%a!X(?Eg^mtrVfjJ-#$?dZ5hf8IMFV)Qqr)VvTlkL2u#R36gaz&QQPIeu z@q?C7gg-#*=rE CV>eIq#e~^5*WT+D)_906b5)p zn50|6Bxr_C4(mXVV3-7DSUjNHc*Sj0$GF$KBm3X2?KHY>q G>yeBHTnx711}t1sZydeS^iOPD2S!g`XiDty-+H1Gi *xT_r0L7IMaIh(?jfu1C7vI! zOr{ihNzVOeA&|pQqDWso z<@=U~jN2*2;H%dCb$I x%|vjMl# zdaS6a4U&~7MLUS-r$7zUvXj3cHPGzQ)G$bDFm^*1N*O)$Rx9<2>#bDfZ3?eu(;l8K zdx+l^sop^`X$D$;69wuba)cCmpOX`Us4+!=euW6fTMSq%x(}6sIM=2|;H-q0j>~v# z#HfT!1tBzY$1>x940H&%4B=>&Cq*Oy_;-8I!!YSclE?%lim3z4;O-(Hb%2?iaL)b& zQsIB$8RXXRI4nFj0p?Y%7M$@y%^R1Uj~A v~ B2AZFaF$dQX;UMqy*D==7EFq~A$YoZ;?37LpZOfUguJfT>9HLs{GO>QIC z!CjqaBBqS6zt>O{YpjMquCPFfc5)9j;gUI?ppcx*SP#k)GnK6r<(!56K42>3)p}(G zf!Mzz5t7zOguO5d&KU=x6o crB?6Hi@lW=~vy z_2lu%Q(H;P*u~}Xv14)j^;b_HpWIp=zj!-tM(@+dSuu9ITrC#LYe3EIW#`pX$Iqbl zT{B~t@7%I;Z0sU3%M%yJ4hv#=9`YuErt66*xHuwVZsY*;DG7611*_XU5R C>m0grQ!iz2*m?&H6Ri^j|HgF zpndU6LOC4)@$pK2N!l1>g12stm3je4R|&)aFwr%y4M!dIDZY>bM3U_n;n15AG +qZfAV7tK(hd+<5S1C4F|I3POSrhmaD8}` z+Xcc+d2!PiEtfYLjrlPZMsq5>M{3S18r)s;B1BlAIu}p PoBq5Y zABTdzgLppkUQPvj!%2wVjJO_6o!7ZG$1`vWC=i4G8xtwX2jP{*%5TLhvyYHf9sy#l z?uuhNp)z^wiAXppX%VCZu?q1Cg%wI#U{RsvUgd;_!HkXdk6NUvA^0UNAf3w&DSwDB zCv?3&&0*cZDoxJY+B?-vz^!MBiTI-y7QcqiqSMrne*rg79^BYujUu$cKeS``G1Q1( zWz8+XZ=@f%h<|HCKT3(bid(Hm;&2oueqLUdTnNcw&rj%rXx&W*qUhM?;byy;h12@! zgB~V4DDQYKgw!6^0(bRkU2#x!hnBwK8eCgEAyuj7(ZQvioYg|`*A1Q8N zG*m^()P2l_2em73@MX|YTyu*zi9=Zr?#G zE|N gVnMeWg i;&i=);UdLOen?LViq y3r55^>ng-Q1d%{Ns(mx Wnm9d4y8{cHzB!RG{k0*Vz~c8u-PgLgz;{3ruR z37<>RcXp6ZETTi`L#G>DY^Xth!A|2O@N5fPaz>MXB>^5V7OyfU=@ 1Y#OBvC`e^n>I@)Rt;T zfiH~7&tY#?yhuE8xx*;i45Mh-E@HjTqBsjgz>9$=2p6ZqS+t6 =t}HJSAc!im4ravmDFNV2;8|yEuq1O&ph*qvW=Khlx1LewR7WSp2+}OVUsi zC*jvn$l>z 5FLS2WM_>7gIntq6A3iQGEB+z%GX9^!W%DUy3 zb0F-4d03M?i|sX!NNu-~#k~D!=`?c;O^PZLZfg2~VhINYyxf4!jU0EiP{%9p_+OpG z1EK#5XB^S<8Xiu#Hnj!OwBiPu(-Hxd|3Hc>6ZJFH$J{t!x{9f6NyIqr3$3^uj V{g4ga#T Vo(X+2avR09V!y_^&oKD|HgMCp{x!Y~ z=f18yJ9pKdou0x!3H%}3>44VHQ1bD)=VOaS-(g-YVJpIu^2tpR2&ZT5h5X#rxmiIL zUX&oZp66~gBlrS_>bw0Ga?NWcxd-xEoJV#Z3)ai-1>7tZE+9da6mPq!0}nyR?ZbyP s{OvQSIVXAD(q(3bGWpD3WmYqYB@dXHPF%vaE|a=)7q5|(HZxQI1BS$ey8r+H literal 0 HcmV?d00001 diff --git a/main/__init__.py b/main/__init__.py new file mode 100644 index 0000000..c814ebf --- /dev/null +++ b/main/__init__.py @@ -0,0 +1,26 @@ +from django.shortcuts import redirect +import math + +def redirectlogin(request): + if request.META['QUERY_STRING']: + return redirect('/u/login/?next=' + request.path + '?' + request.META['QUERY_STRING']) + else: + return redirect('/u/login/?next=' + request.path) + +def deg2rad(deg): + return deg * (math.pi / 180) + +def geotod(lat1, lon1, lat2, lon2): + R = 6378.137 + dLat = deg2rad(lat2-lat1) + dLon = deg2rad(lon2-lon1) + a = math.sin(dLat/2) * math.sin(dLat/2) + math.cos(deg2rad(lat1)) * math.cos(deg2rad(lat2)) * math.sin(dLon/2) * math.sin(dLon/2) + c = 2 * math.atan2(math.sqrt(a), math.sqrt(1-a)) + d = R * c + return int(d * 1000) + +def deltatime2second(deltatime): + if hasattr(deltatime, "total_seconds"): + return deltatime.total_seconds() + else: + return (deltatime.microseconds + (deltatime.seconds + deltatime.days * 24 * 3600) * 10**6) / 10**6 \ No newline at end of file diff --git a/main/__init__.pyc b/main/__init__.pyc new file mode 100644 index 0000000000000000000000000000000000000000..2af7012cd10517184a74e2b05c9b4aab72344ca6 GIT binary patch literal 1643 zcmb_c&2AGx4EAh(H)?5wQqsZAOfAiXIWre<37@#HKw^B1NO!RWfCN(j7;l(&kjI zoOuNvfCEp$GawFJcmS}yDdp#ywBz-7Jf6>=JyZFy-1`2}eI3C3=g@bDhCLt=(!YWj zAW?9lK=Isx*ntxV!V0_tIH^Eb6{QMcO_Umhby4c<-1iz3$o! Z(DXVb`{$IBuF z?*7BUv5j&&*bNht8jHEcEFT<1_6=r}L3pauQ8pM) 1t-{ac#%qNnfN;(N8fV?m c*6(|(Qyw0Vkq8HRq z4y=;Pzw-_oDzXiL*5@vz#hF{giK0k1a+LoK-C2W=;AjMjWDSbOWi&dSFf|0zg#(>g z6N)MnP10PzIutJ7fDQ%jdo@a}H+ugey?*!G=N-cg7;Z1~l~|XH;4>9IQ-xdzYf||J znMK~LQKwr{H+z<&ERl!Do5UJxd{8P`I#)E78{&+1@?pL>gwHk3l`Ivz78!^P7his^ z? oes!e~fx~EzyU~oLRBcv1dNZ}rkejsl1b-CwMNV>x1jb};plce{B z*r!@_y7az~XuxWD*P9fkCsznF)bY?pL6(NrtdZTc35a3-3 9W=C8tvYB|zTD30>R zY}j#@V=zT4516!>&uN!kcaya{B(A`Uwx~yp>+mSa!f6~m;W}HUy{(oUx9(P4_ZN-( BSa$#b literal 0 HcmV?d00001 diff --git a/main/forms.py b/main/forms.py new file mode 100644 index 0000000..5415a57 --- /dev/null +++ b/main/forms.py @@ -0,0 +1,22 @@ +from django import forms +from main.models import * + +class FileUploadForm(forms.Form): + file = forms.FileField(required=True) + + def clean_file(self): + file = self.cleaned_data['file'] + if file: + try: + if file.content_type.split('/')[0] != 'image': + return None + if file._size > 2 * 1024 * 1024: + #raise ValidationError("Image file too large ( > 200KB ).") + return None + else: + return file + except: + return None + else: + #raise ValidationError("Couldn't read uploaded image.") + return None diff --git a/main/forms.pyc b/main/forms.pyc new file mode 100644 index 0000000000000000000000000000000000000000..4a987db59b5f345776b3a7197633d7638efa7cb8 GIT binary patch literal 937 zcmcIi!H&}~5FICJw_7M64oE9;K;jZ1vD`oc1PhBQap|Gm6;L9DsGcrvouq5Khoa@Q zd< AXo{{d+Ebn8l`GF@_h(ZsrY+dcUspRg3YrwIwe7do1rN=1$ z#o;B&{w{z?T5}@J(4RAOQuCe=L)Uqqrn5Z3x-bAZKHnP0dLca|D{_u8JhsvW(JCrB z_^jwckt=BTM1mFGM5J9pO-ct)v`)!Al!h~@L)U=T8M)WLQ?obcA4n;&WcIc}9bXyw zJ{nCz23$g25F!r@ptHf$)fpRMW(aExfi N8$Rlve>)vzvg6{;@LHi4T^hTVpv zmwsbSh%F{<)1^vpK5^%RwDxS5Qweg64*YXO$B&Cs&(0SwbZr{rgR4U8idXE{q1_aE zRW)aA@o{Un_v^|Bc12y8rih1kxY>mv{t@|=B5n^ee+xirr1~mVw^gRDCs{H;JV HL?A+nLaDyMnnma0tq5ePkzBHU8i~5Q}a-?fiKrSH}y%8)}&R1R7VztN;K2 literal 0 HcmV?d00001 diff --git a/main/models.py b/main/models.py new file mode 100644 index 0000000..d49766e --- /dev/null +++ b/main/models.py @@ -0,0 +1,3 @@ +from django.db import models + +# Create your models here. \ No newline at end of file diff --git a/main/models.pyc b/main/models.pyc new file mode 100644 index 0000000000000000000000000000000000000000..6caa9cc718000a5bc89afcd559333688037ba11a GIT binary patch literal 207 zcmY*TF%H5o40KuvQ6x4Vk%c}0Ayfo21BeB@1QJ0YX{tCK_z|yT;Q`>PES&7KPnOTl z-{aBiSsc&sL&mk@qzRMe5a0m3fP(;`GuX+T2lm5|g1a #L zZCQZ)C#qPlX1FI4376X2+ER)tg@|iI_Y@lJ4e;8!cIp)+6VWSMV}Ge^9%;xXbC#_$ Ji|!HPgfEzpG2{RM literal 0 HcmV?d00001 diff --git a/main/urls.py b/main/urls.py new file mode 100644 index 0000000..df6c822 --- /dev/null +++ b/main/urls.py @@ -0,0 +1,7 @@ +from django.conf.urls import url + +from main import views + +urlpatterns = [ + url(r'^$', views.index, name='index'), +] diff --git a/main/urls.pyc b/main/urls.pyc new file mode 100644 index 0000000000000000000000000000000000000000..eaa4508e382d9439cb4a1617e2bf0067c237945a GIT binary patch literal 332 zcmYLD%TB~F40M|9@)A-%f iYO<1xtX;r&C&io8t$Au4o35$f~ zj6IGs6a96#|M{_Zx1zr&QO|Ms4B(K8I-;m(sYqpBP*+gYwA7@$BB#k~+RVryOL{NV z8oMRAIo;Gd& pSn8t2Pve9$!FU$qH`y-j5Bpbctn~ df?g~5vWF>wt_|G*2-%M)|Ueq?juVn~5yw9=2}%JY-- ngV|b{$Ell+qh-jL>|wHPGrY+zBu-=Rrp_<2FXxX}MWufLb7o0y literal 0 HcmV?d00001 diff --git a/main/views.py b/main/views.py new file mode 100644 index 0000000..58221e8 --- /dev/null +++ b/main/views.py @@ -0,0 +1,691 @@ +# -*- coding: utf-8 -*- +import sys +reload(sys) +sys.setdefaultencoding('utf8') +# Create your views here. + +from django.template import RequestContext +from django.http import HttpResponse +from django.shortcuts import redirect, render +from datetime import datetime, timedelta +from django.utils.timezone import utc +import urllib2 +import urllib +import json +import re +import os +import time +import HTMLParser +from django.contrib.auth.models import User +from django.contrib.sites.models import Site +from hulu import * +from main.forms import * +from user.models import * +from user.forms import * +from item.models import * +from item.forms import * +from tag.models import * +from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger +from django.core import serializers +from main.__init__ import * +from django.db.models import Q +from django.utils.translation import ugettext +from collections import namedtuple +from django.utils import timezone +from django.core.cache import cache +from django.views.decorators.csrf import csrf_exempt +from django.core import serializers +from django.core.serializers.json import DjangoJSONEncoder +from django.utils.html import escape +from django.core.mail import EmailMessage +import hashlib +import ssl +from django.contrib.sites.shortcuts import get_current_site + +ctx = ssl.create_default_context() +ctx.check_hostname = False +ctx.verify_mode = ssl.CERT_NONE + +def index(request): + #try: + # if Site.objects.all(): + # site = Site.objects.get_current() + # if site.domain != request.get_host(): + # site.domain = request.get_host() + # site.save() + # else: + # site = Site() + # site.domain = request.get_host() + # site.save() + #except Site.DoesNotExist: + # pass + + x_forwarded_for = request.META.get('HTTP_X_FORWARDED_FOR') + ip = request.META['REMOTE_ADDR'] + if x_forwarded_for: + ip = x_forwarded_for.split(', ')[-1] + + q = request.GET.get('q') + if q == '': + return redirect('/') + if q: + if q != q.strip(): + q = q.strip() + if q == '': + return redirect('/') + else: + return redirect('/?q=' + q) + + try: + items = Item.objects.select_related('user').filter(useritemrelationship__isnull=True).filter(Q(belong__isnull=True)).filter(Q(status__isnull=True) | Q(status__exact='') | (Q(status__exact='private') & Q(user__id=request.user.id))).all().prefetch_related('itemcontent_set', 'itemcontent_set__contentattachment_set') + if q: + items = items.filter(Q(itemcontent__content__icontains=q)).distinct() + + items = sort_items(items, request.GET.get('page')) + + currentpage = items.number + pitems = items + + itemlist = [] + for item in items: + itemlist.append(item) + + fetchitems = [] + fetchitem = namedtuple('fetchitem', 'user title url lastsubitem tags') + fetchuser = namedtuple('fetchuser', 'username userprofile') + fetchprofile = namedtuple('fetchprofile', 'openid avatar') + fetchcreate = namedtuple('fetchcreate', 'create') + + cacheitems = cache.get('cacheitems') + if cacheitems and not request.GET.get('nocache') and not request.GET.get('page'): + cacheitems = json.loads(cacheitems) + if cacheitems and cacheitems.has_key('datetime') and cacheitems.has_key('items') and cacheitems['datetime']: + cacheitems['datetime'] = datetime.datetime.strptime(cacheitems['datetime'].split('.')[0], '%Y-%m-%d %H:%M:%S') + if cacheitems['datetime'] + timedelta(hours=1) > datetime.datetime.now(): + for item in cacheitems['items']: + item['lastsubitem']['create'] = datetime.datetime.strptime(item['lastsubitem']['create'].split('+')[0], '%Y-%m-%d %H:%M:%S') + cacheitem = fetchitem(user=fetchuser(username=item['user']['username'], userprofile=fetchprofile(openid=item['user']['userprofile']['openid'], avatar=item['user']['userprofile']['avatar'])), title=item['title'], url=item['url'], lastsubitem=fetchcreate(create=timezone.make_aware(item['lastsubitem']['create'], timezone.get_default_timezone())), tags=item['tags']) + itemlist.append(cacheitem) + else: + def updatecache(): + cache.delete('cacheitems') + cacheitems = { + "datetime": str(timezone.make_aware(datetime.datetime.now(), timezone.get_default_timezone())), + "items": [] + } + for item in fetchitems: + cacheitems['items'].append({ + 'title': item.title.decode().encode('utf-8'), + 'url': item.url.encode('utf-8'), + 'user': { + 'username': item.user.username.encode('utf-8'), + 'userprofile': { + 'openid': item.user.userprofile.openid.encode('utf-8'), + 'avatar': item.user.userprofile.avatar.encode('utf-8') + } + }, + 'lastsubitem': { + 'create': str(item.lastsubitem.create) + } + }) + cache.set('cacheitems', json.dumps(cacheitems, encoding='utf-8', ensure_ascii=False, indent=4), 3600) + + #try: + if request.user.id == 1 and ('VCAP_SERVICES' in os.environ or 'getnews' in os.environ): + #if 'VCAP_SERVICES' in os.environ: + hdr = { + 'User-Agent': 'hulu' + } + #Zhihu + #for fetchdate in [[str((datetime.datetime.now() + timedelta(days=1)).strftime('%Y%m%d')), str(datetime.datetime.now().strftime('%Y%m%d'))], [str(datetime.datetime.now().strftime('%Y%m%d')), str((datetime.datetime.now() - timedelta(days=1)).strftime('%Y%m%d'))], [str((datetime.datetime.now() - timedelta(days=1)).strftime('%Y%m%d')), str((datetime.datetime.now() - timedelta(days=2)).strftime('%Y%m%d'))]]: + # zhihuurl = 'http://news.at.zhihu.com/api/3/news/before/' + fetchdate[0] + if request.GET.get('page') and request.GET.get('page').isdigit(): + page = int(request.GET.get('page')) + else: + page = 1 + fetchdate = datetime.datetime.now() + timedelta(days=(2 - page)) + #fetchdate = datetime.datetime.now() + timedelta(hours=(8 + (1 - page) * 24)) + #zhihuurl = 'http://news.at.zhihu.com/api/3/news/before/' + str(fetchdate.strftime('%Y%m%d')) + zhihuurl = 'http://news-at.zhihu.com/api/4/news/before/' + str(fetchdate.strftime('%Y%m%d')) + #print(str(datetime.datetime.now())) + #print(zhihuurl) + try: + req = urllib2.Request(zhihuurl, headers=hdr) + zhihujson = json.loads(urllib2.urlopen(req, context=ctx).read()) + zhihudate = zhihujson['date'] + #if int(zhihudate) == int(fetchdate[1]): + zhihucontent = zhihujson['stories'] + for i in zhihucontent: + zhihuitem = fetchitem(user=fetchuser(username=u'知乎日报', userprofile=fetchprofile(openid='Zhihu', avatar='https://www.zhihu.com/favicon.ico')), title=i['title'], url='http://daily.zhihu.com/story/'+str(i['id']), lastsubitem=fetchcreate(create=timezone.make_aware(datetime.datetime.strptime(zhihudate[:4] + i['ga_prefix'], '%Y%m%d%H'), timezone.get_default_timezone())), tags=None) + itemlist.append(zhihuitem) + fetchitems.append(zhihuitem) + except: + pass + + if not request.GET.get('page'): + #V2EX + v2exurl = 'https://www.v2ex.com/api/topics/hot.json' + try: + req = urllib2.Request(v2exurl, headers=hdr) + v2exjson = json.loads(urllib2.urlopen(req, context=ctx).read()) + for i in v2exjson: + v2exitem = fetchitem(user=fetchuser(username='V2EX', userprofile=fetchprofile(openid='V2EX', avatar='https://www.v2ex.com/static/img/v2ex_192.png')), title=i['title'], url=i['url'].replace('http://', 'https://'), lastsubitem=fetchcreate(create=timezone.make_aware(datetime.datetime.fromtimestamp(int(i['created'])), timezone.get_default_timezone())), tags=None) + itemlist.append(v2exitem) + fetchitems.append(v2exitem) + except: + pass + + #Google News + newsurl = 'https://news.google.com/news?output=rss&hl=zh-CN' + try: + req = urllib2.Request(newsurl) + result = urllib2.urlopen(req, context=ctx).read() + items = re.split(' - |
- |
', result) + items.pop(0) + items.pop(-1) + for item in items: + hp = HTMLParser.HTMLParser() + title = hp.unescape(re.split('| | ', item)[1]).encode("utf-8") + newstime = re.split('| | ', item)[1] + url = re.split('| |', item)[1].split('url=')[1] + newsitem = fetchitem(user=fetchuser(username='Google News', userprofile=fetchprofile(openid='Google News', avatar='https://mail.qq.com/favicon.ico')), title=title, url=url, lastsubitem=fetchcreate(create=timezone.make_aware(datetime.datetime.strptime(newstime, '%a, %d %b %Y %H:%M:%S GMT'), timezone.get_default_timezone())), tags=None) + itemlist.append(newsitem) + fetchitems.append(newsitem) + except: + pass + + # if not request.GET.get('page'): + # updatecache() + # else: + # pass + #except: + # if not request.GET.get('page'): + # updatecache() + # else: + # pass + items = itemlist + items = sorted(items, key=lambda item:item.lastsubitem.create, reverse=True) + except Item.DoesNotExist: + items = None + + try: + tags = Tag.objects.all().order_by('?')[:10] + except Tag.DoesNotExist: + tags = None + + content = { + 'items': items, + 'tags': tags, + 'pitems': pitems, + 'getnews': 'True' if ('VCAP_SERVICES' in os.environ or 'getnews' in os.environ) else None + } + if request.GET.get('type') == 'json': + content = { + 'page': currentpage, + 'items': [] + } + + return HttpResponse(json.dumps(content, encoding='utf-8', ensure_ascii=False, indent=4), content_type="application/json; charset=utf-8") + return render(request, 'main/index.html', content) + +def ttt(request): + return render(request, 'other/ttt.html', {}) + +def sitemap(request): + try: + tags = Tag.objects.all().order_by('?')[:10] + except Tag.DoesNotExist: + tags = None + content = '' + for tag in tags: + content += ('https://' if request.is_secure else 'http://') + request.get_host() + '/t/' + str(tag.id) + '/\r\n' + return HttpResponse(content) + +@csrf_exempt +def jk(request, username): + try: + user = User.objects.get(username=username) + except User.DoesNotExist: + user = None + return redirect('/') + + jkimg = os.path.join(os.path.dirname(os.path.dirname(__file__)), 'jk', username, username + '.jpg') + + if request.method == 'GET': + if request.user.is_authenticated(): + if request.user.username == username: + content = { + + } + if os.path.isfile(jkimg): + mtime_delta = datetime.datetime.now() - datetime.datetime.fromtimestamp(os.path.getmtime(jkimg)) + if request.GET.get('type') == 'json': + content = { + 'mtime': mtime_delta.total_seconds() + } + + return HttpResponse(json.dumps(content, encoding='utf-8', ensure_ascii=False, indent=4), content_type="application/json; charset=utf-8") + if request.GET.get('type') == 'jkimg': + try: + with open(jkimg, "rb") as destination: + return HttpResponse(destination.read(), content_type="image/jpeg") + except: + return HttpResponse() + content['mtime'] = mtime_delta.total_seconds() + return render(request, 'other/jk.html', content) + else: + return redirect('/') + else: + return redirectlogin(request) + if request.method == 'POST': + try: + os.system('chmod +x ' + os.path.join(settings.MEDIA_ROOT, 'avatar')) + os.system('mkdir -p ' + os.path.dirname(jkimg)) + os.system('chmod +x ' + os.path.dirname(jkimg)) + except: + pass + form = FileUploadForm(request.POST, request.FILES) + if form.is_valid(): + with open(jkimg, 'wb+') as destination: + for chunk in request.FILES['file'].chunks(): + destination.write(chunk) + try: + monitoremail = EmailMessage( + '[Hulu Monitor] - ' + username + ' - ' + str(datetime.datetime.now()), + '', + os.environ['system_mail_username'], + [os.environ['receive_mail']], + [], + reply_to=[], + headers={}, + ) + monitoremail.attach_file(jkimg) + monitoremail.send(fail_silently=False) + except: + pass + + return render(request, 'other/jk.html', {}) + +def app(request): + if request.user.is_authenticated(): + content = { + + } + if request.method == 'GET': + if request.GET.get('type') == 'json': + messagelist = [] + ursession = [] + + def getuir(): + useritemrelationship = None + if request.GET.get('uirid'): + try: + useritemrelationship = UserItemRelationship.objects.filter(type="message").filter(user=request.user).filter(id__gt=request.GET.get('uirid')).order_by('-id').prefetch_related('item_set', 'item_set__useritemrelationship', 'item_set__useritemrelationship__user', 'item_set__itemcontent_set') + except Object.DoesNotExist: + useritemrelationship = None + else: + try: + useritemrelationship = UserItemRelationship.objects.filter(type="message").filter(user=request.user).order_by('-id').prefetch_related('item_set', 'item_set__useritemrelationship', 'item_set__useritemrelationship__user', 'item_set__itemcontent_set') + except Object.DoesNotExist: + useritemrelationship = None + + if useritemrelationship: + paginator = Paginator(useritemrelationship, 100) + page = request.GET.get('page') + try: + useritemrelationship = paginator.page(page).object_list + except PageNotAnInteger: + useritemrelationship = paginator.page(1).object_list + except EmptyPage: + useritemrelationship = paginator.page(paginator.num_pages).object_list + + for ur in useritemrelationship: + if not ur: + return None + for message in ur.item_set.all(): + if not message: + return None + urusers = [] + murs = message.useritemrelationship.all() + for mur in murs: + if mur.user not in urusers: + urusers.append(mur.user) + if len(urusers) != len(murs): + return None + return useritemrelationship + + useritemrelationship = getuir() + + for i in range(30): + if not useritemrelationship: + time.sleep(1) + useritemrelationship = getuir() + + for ur in useritemrelationship: + for message in ur.item_set.all(): + urusers = [] + for mur in message.useritemrelationship.all(): + if mur.user not in urusers: + urusers.append(mur.user) + if len(urusers) == 2 and request.user in urusers: + urusers.remove(request.user) + urusers = sorted(urusers, key=lambda user: user.username) + + #itemcontent = ItemContent.objects.filter(item=message) + itemcontent = message. itemcontent_set.all() + message.create = itemcontent[0].create + message.title = itemcontent[0].content.strip().splitlines()[0] + message.lastsubitem = itemcontent[0] + + #subitem = message.get_all_items(include_self=False) + #if subitem: + # subitem.sort(key=lambda item:item.create, reverse=True) + # #itemcontent = ItemContent.objects.filter(item=subitem[0]).reverse() + # itemcontent = subitem[0].itemcontent_set.all().reverse() + # message.subitemcount = len(subitem) + # message.lastsubitem = subitem[0] + #else: + # message.lastsubitem = itemcontent[0] + + messagesession = { + 'urusers': urusers + } + if urusers not in ursession: + ursession.append(urusers) + messagesession['messages'] = [message] + messagelist.append(messagesession) + else: + for ms in messagelist: + if ms['urusers'] == urusers: + if message not in ms['messages']: + ms['messages'].append(message) + + messagelist = sorted(messagelist, key=lambda item:item['messages'][0].lastsubitem.create, reverse=False) + + messagesessions = [] + for ms in messagelist: + urusers = [] + for uruser in ms['urusers']: + urusers.append({ + 'username': uruser.username, + 'info': escape(uruser.userprofile.info), + 'avatar': (uruser.userprofile.openid and '//' in str(uruser.userprofile.avatar)) and str(uruser.userprofile.avatar) or ((uruser.userprofile.avatar) and '/s/' + str(uruser.userprofile.avatar) or '/s/avatar/n.png'), + 'profile': escape(uruser.userprofile.profile), + 'page': escape(uruser.userprofile.page), + }) + + lastmessage = { + 'content': escape(ms['messages'][0].lastsubitem.content), + 'datetime': str(ms['messages'][0].lastsubitem.create + timedelta(hours=8)) + } + + messages = [] + for message in sorted(ms['messages'], key=lambda item:item.lastsubitem.create, reverse=False)[-100:]: + clientcreate = '' + if cache.get('cachemessages' + str(message.id)): + clientcreate = cache.get('cachemessages' + str(message.id)) + + messages.append({ + 'id': str(message.id), + 'user': { + 'username': message.user.username, + 'info': escape(message.user.userprofile.info), + 'avatar': (message.user.userprofile.openid and '//' in str(message.user.userprofile.avatar)) and str(message.user.userprofile.avatar) or ((message.user.userprofile.avatar) and '/s/' + str(message.user.userprofile.avatar) or '/s/avatar/n.png'), + 'profile': escape(message.user.userprofile.profile), + 'page': escape(message.user.userprofile.page), + }, + 'create': str(message.lastsubitem.create + timedelta(hours=8)), + 'content': escape(message.lastsubitem.content), + 'clientcreate': clientcreate + }) + + messagesession = { + 'urusers': urusers, + 'lastmessage': lastmessage, + 'messages': messages + } + messagesessions.append(messagesession) + + uirid = request.GET.get('uirid') + if useritemrelationship: + uirid = str(useritemrelationship[0].id) + + content = { + 'status': 'success', + 'messagesessions': messagesessions, + 'uirid': uirid + } + return jsonp(request, content) + + if request.method == 'POST': + if request.POST.get('usernames'): + usernames = request.POST.get('usernames').split(',') + users = [] + for username in usernames: + try: + user = User.objects.get(username=username) + if user not in users: + users.append(user) + except User.DoesNotExist: + user = None + if not users: + return redirect('/') + if len(users) > 1 and request.user not in users: + return redirect('/') + if request.user not in users: + users.append(User.objects.get(username=request.user)) + users = sorted(users, key=lambda user: user.username) + if request.POST.get('content').strip(): + form = ItemContentForm(request.POST) + if form.is_valid(): + item = Item(user=request.user) + item.save() + + cache.set('cachemessages' + str(item.id), request.POST.get('clientcreate').strip()) + + itemcontent = ItemContent(item=item) + itemcontentform = ItemContentForm(request.POST, instance=itemcontent) + itemcontent = itemcontentform.save() + + x_forwarded_for = request.META.get('HTTP_X_FORWARDED_FOR') + ip = request.META['REMOTE_ADDR'] + if x_forwarded_for: + ip = x_forwarded_for.split(', ')[-1] + + itemcontent.ip = ip + itemcontent.ua = request.META['HTTP_USER_AGENT'] + itemcontent.save() + + uirs = [] + for user in users: + useritemrelationship = UserItemRelationship(user=user) + useritemrelationship.type = 'message' + useritemrelationship.save() + uirs.append(useritemrelationship) + item.useritemrelationship.add(*uirs) + item.save() + + content = { + 'status': 'success', + 'id': str(item.id) + } + return jsonp(request, content) + + if request.POST.get('newusernames'): + newusernames = request.POST.get('newusernames').split(',') + newusers = [] + for newusername in newusernames: + try: + newuser = User.objects.get(username=newusername) + if newuser not in newusers: + newusers.append(newuser) + except User.DoesNotExist: + newuser = None + if not newusers: + return redirect('/') + if len(newusers) > 1 and request.user not in newusers: + return redirect('/') + if request.user not in newusers: + newusers.append(User.objects.get(username=request.user)) + if len(newusers) == 2 and request.user in newusers: + newusers.remove(request.user) + newusers = sorted(newusers, key=lambda newuser: newuser.username) + + newurusers = [] + for uruser in newusers: + newurusers.append({ + 'username': uruser.username, + 'info': escape(uruser.userprofile.info), + 'avatar': (uruser.userprofile.openid and '//' in str(uruser.userprofile.avatar)) and str(uruser.userprofile.avatar) or ((uruser.userprofile.avatar) and '/s/' + str(uruser.userprofile.avatar) or '/s/avatar/n.png'), + 'profile': escape(uruser.userprofile.profile), + 'page': escape(uruser.userprofile.page), + }) + + newmessagesession = { + 'urusers': newurusers, + 'lastmessage': { + 'content': '', + 'datetime': '' + }, + 'messages': [] + } + content['newmessagesession'] = json.dumps(newmessagesession, encoding='utf-8', ensure_ascii=False, indent=4) + return render(request, 'main/app.html', content) + else: + if request.GET.get('type') == 'json': + content = { + 'status': 'error' + } + return jsonp(request, content) + return redirectlogin(request) + +@csrf_exempt +def weixin(request): + def get_access_token(): + apiurl = 'https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=' + os.environ['weixin_appid_yh'] + '&secret=' + os.environ['weixin_secret_yh'] + print(apiurl) + access_token_result = json.loads(urllib2.urlopen(apiurl, context=ctx).read()) + if 'access_token' in access_token_result: + return access_token_result['access_token'] + else: + return get_access_token() + + def get_user_info(openid): + if cache.get('access_token'): + apiurl = 'https://api.weixin.qq.com/cgi-bin/user/info?access_token=' + cache.get('access_token') + '&openid=' + openid + '&lang=zh_CN' + print(apiurl) + user_info_result = json.loads(urllib2.urlopen(apiurl, context=ctx).read()) + if 'openid' in user_info_result: + return user_info_result + else: + cache.set('access_token', get_access_token(), 7200) + return get_user_info(openid) + else: + cache.set('access_token', get_access_token(), 7200) + return get_user_info(openid) + + token = 'weixin' + + if request.method == 'GET': + signature = request.GET.get('signature') + timestamp = request.GET.get('timestamp') + nonce = request.GET.get('nonce') + echostr = request.GET.get('echostr') + + if signature and timestamp and nonce and echostr: + tmparray = [token, timestamp, nonce] + tmparray.sort() + tmpstr = ''.join(tmparray) + tmpstr = hashlib.sha1(tmpstr).hexdigest() + if tmpstr == signature: + return HttpResponse(echostr) + else: + return redirect('/') + else: + if request.user.is_authenticated() and request.user.id == 1: + if cache.get('last_msg'): + return HttpResponse(cache.get('last_msg')) + else: + return HttpResponse('') + else: + return redirect('/') + + if request.method == 'POST': + body = request.body + if body: + fromuser = body.split('')[0] + msgtype = body.split(' ')[0] + msgid = body.split(' ')[1].split(' ')[0] + + if fromuser: + #user_info_result = get_user_info(fromuser) + #if 'openid' in user_info_result: + # nickname = user_info_result['nickname'] + # headimgurl = user_info_result['headimgurl'] + + if msgtype == 'text': + content = body.split('')[0] + #cache.set('last_msg', nickname + headimgurl + content, 3600) + cache.set('last_msg', content, 3600) + elif msgtype == 'image': + pilurl = body.split(' ')[0] + mediaid = body.split(' ')[0] + cache.set('last_msg', pilurl, 3600) + + return HttpResponse('') + +def coin(request): + if request.method == 'GET': + if request.user.is_authenticated(): + try: + coins = Coin.objects.filter(user=request.user).all() + except Coin.DoesNotExist: + coins = None + else: + coins = None + + apiurl = 'https://api.coinmarketcap.com/v1/ticker/?convert=CNY' + try: + req = urllib2.Request(apiurl) + markets = json.loads(urllib2.urlopen(req, context=ctx).read()) + except: + markets = None + + content = { + 'coins': coins, + 'markets': markets + } + if request.GET.get('type') == 'json': + coinlist = [] + if coins: + for coin in coins: + coinlist.append({ + 'type': coin.cointype, + 'hold': coin.coinhold + }) + content = { + 'coins': coinlist, + 'markets': markets + } + return jsonp(request, content) + return render(request, 'other/coin.html', content) + if request.method == 'POST': + if request.user.is_authenticated(): + if request.POST.get('cointype'): + cointype = request.POST.get('cointype') + if request.POST.get('operate') == 'add' and request.POST.get('coinhold'): + coinhold = request.POST.get('coinhold') + try: + coin = Coin.objects.get(user=request.user, cointype=cointype) + except Coin.DoesNotExist: + coin = Coin(user=request.user) + coin.cointype = cointype + coin.coinhold = coinhold + coin.save() + if request.POST.get('operate') == 'del': + try: + coin = Coin.objects.get(user=request.user, cointype=cointype) + coin.delete() + except Coin.DoesNotExist: + pass + return render(request, 'other/coin.html', {}) diff --git a/main/views.pyc b/main/views.pyc new file mode 100644 index 0000000000000000000000000000000000000000..cf989c440fd091300952fbacf6d8a7057ade0681 GIT binary patch literal 21099 zcmc(H3v68Hb>_J H*XpmsL$Sx9W_t6%~c3&ux zw!i{i?0(<*@0}Uak2Zj|Ym>kJ$N699od5jioc~-Vf83S+pTCxRJulIJ3H ;0qHJT*kx+lrPwK@E?MX@WlX 6V4=INu`+J#l`IEbNK% zy|U07=lf)#FV63kg}s{Zkm5cm^~*xPnIk2|0V(a5h5e?Smg1n?=1!11P|qE#=ML3# zhwHf`_1saD+a<+}l!jzsNJ__K;h2<;%ffLpL#Gr^NNHFWhU+t)G`+f{_?VPNWMRa# z?3Uu=QaU9Ir%bt9il?P?Mi$PPa*q^8r8FiBW2U@EisMo`D+^~$xmSwkq;y^u&YSYi znfs*pgp{6?g(pq>UMW5$r3qP>Fy(zxd|FBuWZ{A-gC5Vw!ZR^WFUrD2&G$?3St(7* z!Xy~vq7*L4L$J+daj%GbS+dUwE3az)d2t5hGiaR>XTN5q#TnGhjJW5;Ilw$PZQ+_Y z2etmX)*p)NZ-{eP>u-`j=SGfzVZHx@|7OD$WY@xb7e*{(!re%0x3=a6;Z&s@y6d5- z??nBLFs#~cP_2{$cZ6&ob|CRx$MfBM7`ADl?6`iT(aD8w=#|_sMQ~&sw;1NkkV#an zg?UrpDqaoHRae2%oEN&L#Hv#x1lM6+&MkZ8Tv+k7G*haE8>n)_9sn>iTM4h0Z({As z@o>A)g0a0^(R {p}2)NE9I!B6*c)>ekCe$ zntb5j%ew0>R%OQCgUabbuDo1%VeX~bnR32D1nDk`FgM8Os!@O9c&3!|inrV#z(x!d zw}rK3^J~8EmcwiSyyV&cB!1aQ!~~N-@Fv6zek_t0%&=ueH4r?5TM5~;#DA74Wl@q4 zPK!2_P1mG$ZPl(x*-VPlCaVeY^8y}m+F3t`TK}tT!%qRABCBzYDQ-3Q{8Cd-j?uwx z101LJRl%$qpJ@lz6xyZGAx?@D6jBr+VHzV_$cMYc*%cK{D{DHV8s@vWN&r6}6?U`0 ze7A1CQwm+IdG2|3XQLD#4j~2i$iswewQxoLU2C(2Q?p+$YtV!6J%k4gmKyF6z!1X* zO?_N#Gy?ke%2q1@w%TMFUD{>+AdAzBeX@mJV~2gR*}* 9#ZtadK4u&Je|9N7*_I|R~*HJFFyd`oE*cy|c2cI-CDKNyt*4N>T zOPG z@Fz* ))4}H&xb6zI4dUmp-Khe_Q03~+;1c8K}XbF$+1SawKNV$!q zL8h59B-s< xUy|RLCrVzM<&DW aRX z3bj9OZN`anQ??GvMlNO+6;Nc8k6@6kBNC43P4$9oLMj jdH_-xl(BhRQT4YFp&0`;dcZk#>aqN#}LJ-DWCC7Ew5fhq1Ezv$dU+d`r z6C%AsX@h&co%dJx1TQ0JPMq6R0-aa&0<{uonlB%a7GA Wr0#uQGFvC2&Hyl-KNojCp`AV4mzedaOl+PI2*`;|2%9@Hu}#4JtB!2~ z?)N*K*Q5;91FJj>83*}Wzj7CJ=GRqBo=JJQXj;YTlL=g=oCL7p(<*i@$R>o;T@u$> zln|=-Pw}Kbw31F%oHvlM=E92{*~t;~VG M U;O8XR8{E zNdWGI-Du!!d1~=g8=>A(W86`f%|-yZFoY&sib0R=0FA*gHaq0Ja-h4bQuC&Af6oo` zD;zvvSMD_vdSTJctog-EF&Biv+7g>HVQx8S^dMkBtTRK6JHt%XuiW#BZb*$-2aYNN zBA`-r%bt_TVb3{V38Nr+-z5^-01;)W#H)I)%TiR8D_UVwa}SxACQ@+BLm~n7_2Jh> zhfAZwPG 9Dxu&P)KpaTd9v1s0(Wi)ODkqKu{&j8A;-d zh^&88AU38Ke=D*NoFp!V4&h-{^}9gbTME#eRI)m)IJankB3-X)lL?+a)Iw?8-PF+D z+|W(^xzVY^jDsF%*wfUIf<#E;cNaS2t}z2c&rk&hy8Z-o{0R#D+D)0~{-I0&4*D 4*xe?-S)*eHuRJYF(m&7}a-q8#8Gi 6s~F`$&UX!K5};gppz?^upX1)ktrf#;Y=0Uas^TO#x`SwN8kd^Y zMY?8Rx(D5yZmF?DZb>(1)&l{-WfuaRZ{o*UD^&x{UCR|Ci(m1mU_3a+K;`-yr+)+` z39cZSx_I|hp6osw7fuwNSOcc ma?-}2r2p8Fse zt8SPRRHX+&&n#{;2{K5;>avp7h?P!sAvb9Cq12DxL2D?Pw2mf23W-lnU41z_H)DVD z=G4rb9(|y(jFENmoHXFNxxmq@%OIK7JGqSjtc{6IBUypJ a zr8J(adgD)O{rHl5uj0Go0gw0aYr~~sM<-ixb1?G*&8vW2k0${2DYFBh!gGT)O1K~X z%9sD-cRu%nU;6S7-ubfPdx0|rL(viftl`0f2Tk+e%iX6G9zzlwj-UYKz;&?E1jacw z#&M#+i;l9S%H8E$w(7h0y!C(=hFSFRjevyXj^pX>pLf^my9L3#d@#OJ3CEN_$S9vY zKXWHI^HIHcO?mloue3bQk+SEWIX_k{F9+Owgjk(Fp3 -dq`-npI3pk}WT9PLAupne9cz=%n6C1TmS+&WeU?2p-2W zCaY^p)8Ik&h_jgwt2FZ$z49tS_210owxa3 OPN`0N3YCyzjOeN)oQxe zW $aZYRd*xL>nZ-7LteR@Iuw5B_+#6w`sY-l>G9V} z`$e?q;eB)`nEW+a%$1g$+~x0ZG58fFwC~=>@o@FxyyEdBs@STU>zLei+h23_Ookg( z*S>)ody>f|CYO<@{Ed{CEP)h@xoWlO E=N zRXq %gh5;dX9WdsTeM>+I5o%?a$AOkQ9@wir2yBwCkx##Omq&qDI! z#&%qXIU{DP_CfZd{L=d?a@tZ$wzI4xqDa0X7NAGYrjW5uG2xwKQ=pn#HicYWeYJ0) zq$^%=e0ziiwkx-&lbr+W4MioAoa(zZ1<^_s+U%eu?Lc&BDLO-X7QIFnu2MHm@y$Uw z1M@moT&P1)EE9?d_i?cmL&eBS)#xXLCy25f)h!*4H5|d#BS`Lw7BhmZ7`gNb _t)`{R zdMB<;vaZ`Yh!s$)>B1^Tpw%3=DiK6_SDSUz>cMD9D--?OZt?%I#D4T`x6;YeR$cy+ zZ+VIXiWO+h)RZmpU=z^TC6mtvP*0^2uDJeq7=}g^@_H~luer~nXh?y~qoD#>6Vv^W z<8c{c*39*iK)U8HAVb%K-dS+CJVXXQ0rfe;n#tg0!}u*w-=cmCyrCJtg{7_s7&UnC zSieRiWqR?l@Kpka1;E?HU!uW49|Ju0s8LI40IvuGU`hD?@eTlMV*n2x15aa++6%Bc z((I1fxe@a5to>6+_13ZvA-7GB*{0xdv*Y1-p#OHIM|khsZ!rNS#4a*HYud1$9@kvJ@~L5A2H2%F!h|~s{fT)@|1w* zln-%Ax~xenPh#?hqFkB6Z!m*hZwxl52>O8>@FxSS^W`D9os_I}JJrbta~4h=gX=qx zCFX4?%HWB_)F1;Z)vyC7tK)*E0}t^4gEEGNt=g)NqVHNPM$bUv|6W{#i{4UzZ(1M) zePm{6c;xkI%>NAwH!>|)JQM-3Cf^%_!S$ aBzU4vV{8hrVRNpoNpF zfEOMdKUlz=r=ON8-dgAz)7LJ(a1HWR3x+OzR4{0}k+J4>j@qN6e$m=EFCn~z;9z~k z`ut%&J7HY-*9v$a!c-Un7BGgGcSK&fGhh26j)w&hG|t_DB~@P)SJ5GpsDh6Q6T+c} zDhi1PA!^^X-~vV?PXId`1n<@5TupA|6e~yglGPv?{H__kXTjad7e9+F02zou@M5DF zY;LUg-`3dVSr3PF@?)C9?Fp}NyShaAyd?g)WQ3RfZ2J6p;$ )N zh<-yzQdpNBR>B VXiavRjJqN*ID;o+)YsdR~RBlbQlLV z0V6@+OE>I;_36@d4XW>#3=6qrlM#$#w3$btPTF6=Xn&61V1?sCD;tDX)@JQWJPqxz z8+u$@ve!CoQ8(*>X2ySeabqT}UGP}-B)Z_e>PG3fb=Vrhzb()XI{|UP8bB#&9l LgWqZ?r;G;XY=Xl(%3|;Pz_Kw`qO7!GO5l)}PR88Sx%er-mt3ae)M-NR~4K!#v0t z@LEamGr#_h1*qx8pS2hdv0?G)szcQ)ir^IskNuoBCF{>n3d8YC)r)N-jDNs`J~jnu zx!NxNcT|S%iYhrc~BW3sEF>|aeaj}{h;fOtGMloFvNb8vAFzk^J=KTXLzew zl+joLJkz=Ygj+ClAdL$HkL(?iMH-dixyH>3T*5t#!w(R)?~U78*eAU9F#$Z dwNJIq=5XG1bBx>Kc@H3C0=4)R9p0H C>>)%W0g#S8$ zaFU2FzpK+==IO<+Yp?>Yu3h3m-vOrJZts?f5Q+>68WKV(^uWz;$_K^&mkDSnywOaJ zzWE}m0rfj7tACoP!}vc)KzZ2#FaQXsCJ2{lno)yQpma1 rExC0<#kD_FctiNRulTjaFQ={$b*o0nibb4`# ztPRZoVG~eTV4*-a;7s7KW1N|z`rl1{WE=WX%hE>@AiKFMA3BMD3 ;9gs4~6X))IljgRrrU+b%%YKdmh8vmzTB8qJ9J^;8TqSPC=(WPEnCk-?sMLb$S ziw{BgkfEq)uhR;#Cx|aHg#BD{-h-lV&KN>Y5MeX{eDSr2Cr;m_; Ti3R+TwZIK~7AZWOQ-+A;1#@a#zBb;WZIf_hJ zB;ahs_aO-DwKlF2+cHzU)n(;hi=!ck>br09F~ThKB<|Jz)Pc6f+d9`-rj#ExKwW zK!Kd_bku~-4EEVCh)#i2^)GaUqg0^lqci#jtT@J2i{}P`ALdM<)|{!vBw99;fJ|0+ zmca*%)B!GGYQ>Wx1Pel)D}<_lAQ~J19O#@ da zyf*O2qIs8O&&NHUfXqf2(HFbo#Z$5#mi0?S)AZs~0_uiOa<8N)76^7k+*PY&pJE#A zcoV^9pt;_^R_(Xj=ZOqlj}wBHzXOyskOO%aF)x`r#*W5E>|o#8vkVYvpzSH{#cyU} zt!c3A5oOt<%Cbic%Vs{nvKie4%ryKQRhIoH9gM-j@`pG9@89{_T1OMhek%?e84@(y z!S6hJ1pm2XJIfmRVOX{^WmqGcqBGS1-PUj^W#;}^mc?-}V;ifz)-*Qms+tb*AsWO{ zW%G%c&DH4JIwtG?jKjqj=CPmb!u*TWhhLa~ks>vlZqe$2biL>gq(AJ!JdkdZ&8F)% z!ECDPQkk@=y_-_GdQ5c}veIF_CixF;K}uQhuS(hD47Mp;kWCoYPcym?fqc*?9K^Oi z3pytuBN3!GS$i)Hf+GY6WI?zdB`1tp(&&S_=pUt_Hz9hDl6R-9MYs++VU5Nh=JWFG z4zo9pI_bbKjT1h&2g7hlIXG{I%Mq@C4PgP`@^@w9bq$k13>i)w>fwt(#4++MdL$S} zp~Y4$HuYtFy9OPj5^@fCq_~OTk%Ie)-2G#?wxB7c)ie3|*fWV3p&!eg@*A=-^*5OM z FLFg?l(A{g0E>iB_uQ)P^K>ep%>>Yy<2J-7>AEqAiNR3O(O%&H(D3Q4yk?H!p}S+ zM2y5_Mq3!F{=Uvpdmozd&sy`8*>te%2D{9v>A2?ko}<1LweIok#7KNnY (A22k$iY9AZ$f{F =Ju$doSrTrg2BBvwDOr%$WzytiD?@ zz`~}lMZMK{gUs@QE3m)K`XcN1BB57iCj#`PQoYo0zNj cb5tBUVjBAX=-tQBN92u TY;`UV~kj3x%O8s}gN z@UcfW&{yR%_F>e05NZFvc>ND!Wa$gM5#oqv&6V@6O~Gp);FihgafmNtHZ(5yRm7BK zuU?;-y=^2Dr669h>-+u5H>voIhWLMQuJ>XadaghIF#z8;=|*-?lq{s-GKi}&o_%Up zuJ2cT4Vy7{$Tv`Df1L^a)VAI~g!A#)TNK2@xDZwaMc1u1E((?YCVb`Jp;h_IcT1J~ zuKjZyYM2Rm)ttg*!tkhRU=D(-aOr3O=Mw~Zfr&bg^+KFr@jo(on#praG_vzQF-KIJ z*q1)$=8@ TujiTLPP1iI3u zV`l$%LXZ(ysY?p%|AFENexrMmczP6$enXLJ^(hLC8%P9qd0Vm@cRGCYiSCoBL?3cp z^y%xp->*0R5WM{R0M%n &}&fg0m-p?^xYHde_Tjw@|Os7y7p zemHbstwCyD)9s*$r-5DC@0x`-Jnl}7H~$$6!!*}$6jWg`(Rhu)jfqo$p4O#9{X&Af z-mRadc8LG!1U 9V-VQ4? zrL&|N9zYxn#xwH$p+2H|26aY!+lsxyrwhvz2*6W*5}t`qCHR5oppJmNne#yN2#9=$ z)`ZVtO}l=H7Oz=7+d2c@KI${TlV6{q_UQz$)xe`e9h?$uHjhL<#^4pk`$8Z6p!qU{ z1+zl^9RObrL`8g7Jpf}Gh`xRU5)`b0`vA@bRDeGrN8xoe+<_&7nc;{9gYji#kr@;R z=_3Iz7 Rbz33$xk!E=0)G6&0h!LWrAHWWRM7L9u3j2j2~2UM;E~esAd3_@{dBc z+ntc-Pf|mo9w!jhtq9obv^o-b3i>2|>lFXTC`9x%PNa88_vRX90c>*sVrhUf%GybP z(DsA$$FT &ydMXmyi01%+9_UK)RO*s z=HcCr$mn~OE6wP>WZ1%dy<~#dPZputA?`jqHLDz VlRA=R%z%WBadhLe|6*uV@PO9>0Fp!4sOup>pU-gSk-FUQg1yM`1 zQvBJF9G1}7Tw|qC(+F*nopuG41qO86UqePQi_rEJ#F`tGdnI>H$*|(CBTO9uA|^(L zC%MU1p|)>6%HnWK6=%aJ``1w#p-Q4!w(d;jo81G>u=g e4L&x1QxX~JHA zIk9mjW|@yz0nyB7UV(G}ml93P^Dftdsynq`PSn1nN?wdx$WG!G%rvLsCVEw())zd9 zr1{RwBj&G^^H=eOPOhroXWc)CugLPNxHPZ8hQ=pN;iakB*Nl$D!@wTq3mVfeXo}LL z DvDbc@;lw TE)$;xZ z0XfkW0GmAjMS{V=ie3#=Nqdt;iUo69Z`auxjveEyd5lu&aVCGx9-PAXO#YHNKF>A9 z^PM0ZuXg(v**eVJd&t$dpxz6P!Ts3vv5gc&^`nt}qnH=6LV`CqBqSTd?~cL1?MmnXz8uqlp^Gi+Y`@iWF4_E4U2vYhhp_ zRh1HCJ@sutp45k33%z16M)ib$z{(~+sdlc5!~KIR)R6zvY=H_Y_Mb7qd1APEeH=QA zd~a!t!K`Bl>~)KQI?3=?V?F@Gj|PGmNEO4EIU4T@dKJg$05Z-U-jflaHfy=jOs7$E zvzARW2g4^1ack3#^Y}7%tnsR}3xN7+WmD5omr{g70@}M-$rfE1{>}k{j}gk-gPI7; zS&FwpY9Xww-V)&!Mpt0|wu8-XIz_%x H6gAl9Uy^Snc&Hh!i+V3;@hfKc0qz%inso2;&;SHgoxksTjshpa`{A)$` zG6aYOOGuz0SzSrG^7`?A5454?|5=~j_WvQRVg1hk*{=ug!4w>Esc)o`sdV?%)c@{& G@&5wX-VAyG literal 0 HcmV?d00001 diff --git a/manage.py b/manage.py new file mode 100644 index 0000000..a2a7b33 --- /dev/null +++ b/manage.py @@ -0,0 +1,10 @@ +#!/usr/bin/env python +import os +import sys + +if __name__ == "__main__": + os.environ.setdefault("DJANGO_SETTINGS_MODULE", "hulu.settings") + + from django.core.management import execute_from_command_line + + execute_from_command_line(sys.argv) diff --git a/manifest.yml b/manifest.yml new file mode 100644 index 0000000..f32cbd3 --- /dev/null +++ b/manifest.yml @@ -0,0 +1,10 @@ +applications: +- disk_quota: 1024M + buildpack: python_buildpack + host: hulu + name: hulu + path: . + domain: mybluemix.net + instances: 2 + memory: 256M + command: python runserver.py diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..7861236 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,9 @@ +Django==1.10.2 +dj-database-url==0.3.0 +https://pypi.python.org/packages/source/P/Pillow/Pillow-3.0.0.tar.gz +https://pypi.python.org/packages/86/fd/cc8315be63a41fe000cce20482a917e874cdc1151e62cb0141f5e55f711e/psycopg2-2.6.1.tar.gz +https://pypi.python.org/packages/source/i/ibm_db_django/ibm_db_django-1.0.7.tar.gz +https://pypi.python.org/packages/74/bd/3f06dd32f9d50705633ee7d45501915c5dd4a2a5919aa6d06c1da5a55ec6/python-swiftclient-3.0.0.tar.gz +https://pypi.python.org/packages/45/9e/de957806f2f04f195ebb6dda5e963335c1c2050d4c4ad1069e9695d0b67a/python-keystoneclient-3.1.0.tar.gz +https://pypi.python.org/packages/55/37/63359f39566e8444c0b037248a8707c6a070239c68d7fd30b94731136e88/weibo-0.2.2.tar.gz +https://pypi.python.org/packages/56/6a/04bf00a0b962c0feb0f0cca44e38aa3bae5446d28f3f1168efc6d71fd836/cloudant-2.3.1.tar.gz diff --git a/runserver.py b/runserver.py new file mode 100644 index 0000000..f38f051 --- /dev/null +++ b/runserver.py @@ -0,0 +1,12 @@ +import os + +os.system('python manage.py migrate --run-syncdb') +os.system('python manage.py makemigrations') +os.system('python manage.py migrate') + +port = '80' + +if 'PORT' in os.environ: + port = os.environ['PORT'] +#os.system('python cron.py &') +os.system('python manage.py runserver --insecure 0.0.0.0:' + port) diff --git a/static/alipay.png b/static/alipay.png new file mode 100644 index 0000000000000000000000000000000000000000..204d616a83879fad368bb64e4019c3b508e078c1 GIT binary patch literal 85262 zcmdqIbySv1|1W$4($d{6-5@PUcXxM5NjFGHcPZW7NSAbjgmjlkhX_b`F2L>HKF>a9 z{mwdnylcJpJ 6> z0Hc3)f>2< $G`Bi9_6 zSiZ9|+f1VBMLG(Gc}^ms37;`()Rh0I4iu*ihFE3_5lIHL!_uD ^JMnN%^$u9Dc@}c7@Cj8c%nsZwmr7yL+Kfr-uD}%_t%^7I`2-U^ZdbD3ow|q M;fQN>UDc9@&Ck3bZ19ihf9lf@e&k!UXf)7mlu=Kg zm<0ZxK<{yjA$aTxraS1n->Bnf$b;2*kL*Csc*A_LhZ)mq3B)@hwkKCXEv_K0oNw{# zvOI-H$Z9ecVK@wtszKQjrOgwr)yOJ_X@cElABleVol9%s(|0>5?2>-E=M|Jzl&zQE zJw|I2^RA(4@41n6=|hy74N+ecO+XO!yaan~wO!Izhf}3&ArWTas>vrKVZy0?+`>r~ z4^qeUS|#-wdy!3Xp}$kX-9_3m2gb^GoNT9j$h^7EJUrJ(z`-DjE5yZ010Z^s4FE`I z!nr}!?heP8ZvB5)4!ipYdfnh)5J;T9br;3 (ak%PdP5?xFA(h*t0 zE;6&Pwx^*hdfp72gYY=^mwk0yRwG@A!_S-h71~ar$<#^&Kko$lf}Z#-EN5X}pf@*B zFbs<&V3#MLe%8NozV(COD=?zj_642u)19-NwVU;Q2mOIJYU~>k-u|ybKzxKE7T0O& zhqWDFt@Y3vwO0rsxjuVX-%WXa$Gr*W^6`(2wva3Fo80*r4SLe4v0nMzm2;4B*)Qx% ziaKFCCN$*~$ZDm=9n5LPk89D7b^3@z^tvBELbnWFEt?bsLWQ?=571gvJlu(IW+qfN zY*Lm|@vCn$^SwirbCxq$ihzld@(sTHP`l(E4D$=W-oSU{C134L?pP0Ofw6rs)TQ`@ zgJ|#-YhiFBQy%?s`u-TyB`h!HXNj2k@zw2P-#kq$xpOV9z5*R+jHcYA%f|-ZX1l^Z zHt{6+SxOCkalw78rkjq7jW~HP%Hid5zy&~Pux6oMbF2S@1B0<%d7MYHCm3H+2B%p5 zffmf{_|Mg35pp?YJ*oKsqCMBwyhTRY_14%m`QkkmwNFcc7>9)zL>tpWzjQyAS}I|> zG-_kUDUWIRDL)8@C=x4>hKp>PH_-3p3r%&zqX`h=o;{5+d})z1L(QO~6ft}o+tlL~ zeqUqHZKEANQC=5{p08uBnBbHpsWKhtzE6d3f_3y# v3TYwRiux9={aUtG_|53@fg-0}_Ii24c^wVvrq=N8{1 zrgQ>YKmOp}LVb8##dch&T6jCw@rq$p*@<3(hM;LWP)v0_aGkLlg6I^~yh`JOefk=E z+iEd1=&IpAp#ey(ahXhILHH(b_D=Ney#yWwiOwZijg>;oVhjqw01C=~|4ih3x!RX2 zk&)!RlxudC;KF1p*NH%U7JSi=%{65OsW<0B55ML5W?C}mCYJsRwS(F2RT7l2;`7h) z!(vWVBrJ-sIZ=l^op8P6LW&<7M?xEwMYa^m9F*_5lP>y&t9r8Q0FA@BILEGL+@}qm z3?>@zf-jK646R$zrpGZfD-w?G$U@OLWP5oz5pe0Eygydw{v9ZQeo5aGHmOtV HzdVSI>U{0R-kR{H`b48MD`zp;@_O(Wg})e42GOkQa{^Naf~UdFX=DsLG!9ml zsWEZHC_h2OkZtFa@-QvM?B$l>jPPP5o#{vUIdXCPmxEMSM_F!P^))VhLoRrK1Sd6T z6Ib2Z(Rs^!&765zA|qszpNWh6VT$eH3wk^~mG^);2S;byvYr`LuA1@&zZ5P^EP;A< zf)mRtw9s|dE!~c7H5~JHF;W{LrL*eOS7y5%W056lESHx`DMreh;ptnGqW2?t5TS&P z8d$o}dhcueM{oHR> 5Y_B=m&ZRn(_TQme8&+pif0L%R#%h+#~`7vg5r-h*`V(JhMq@ z+iA>VIJi1{$>z^BJXInVyU@!Y>IZNzH*A+c+O`i3C1OVwU{lxnU|*($TbEEkIABp% zAf4l1?48UCMK#Mp9Ih8Myw8l8pi(Gpt5%sP7(KxHvUlA38@e9v{KxalO0E}~5T>^& zpWq?-cUIisI8t44WWsnuyv_*%*Oi^I!hcv6Syr9isvyx1V6u1b1*Q4Ic2!v;c?`H_ zlt;~|@#t+_zjWhF*O1P5cRCiQ1J60E%`L4Cg1L*vzN3Lb%JC|%;mm0|0gt?Ry|rto zU2&ch-inF)>J)+6 aImV2kh?vQR zZ3 z>~zHuF2AQsXIXIo_kT4w$5qIJmh4Zr#~S>%4BPidd*jgc<^zFgX_GV}t+6T-dWS>j zw4w%HtSAu&vNJS@>#{UXyo2WBm%zE(l`g(vf6eVV@aBRM4|kTO%Wr)kuAd;}o1n^}1tC{y-1N=CjDD=DH>4hL5`5u=OY7xL73K6^?D)8dn)7^`oJ f ndmtm1R!kX?(Et}rn4ADNbk+mKv= )DNb4X~Va2L%M!3*yqs=-=q?fXkVG#Q{LrmX8=83 z5fJ2~7Qx3eEPOy5uj4>PCM$*XBxG(0SvYO{i3Sf9E`q>QxCln|atofcyLOIx5=kEV zHN9+b9y6tLme=hT<39#(j?)bg0}hCDlAnFo{TgSvF7=U(deUFxI)JiSl8zL%Ih}?{ zr|?3XV3bOo7wyz9Ys`)q+Aw35xOMG`!u!{7E65?y*grwhkSlCcBIz8mJ8xdZQBAE- zzG_nIU44sSoSVCY8?3*>+C)rNY $fteC$-BI^dxX=${Z`HqLfSH zru>M=JzSMqA6}&23+J4XAxEI4DFXcT)-MD#TQd_R^aM=zm4R4ug|p8mwcU@kKZwaD zZa(Sq@8t-*@9(U1>_%>-yWMm`?7Hv;?deh45%4WSiyYu5VY+oIsV!@YH%*-J hC+OjKjslYtG3|5PQgUBd7ZqCXIggi{1FYr=a-z?JZstKuYahJ)x3)z+1b z3x;4nt0HS0Y^NuJJlQMgTJ *<6zHf|turK3c8|qs^G%VOH z(8y~_VCcS=5}%p(UD(3j>vbxzr(>3#a$s?$_&AZJ#2 pOz&GMzX)U zK}&Dx#$om&XY!*UuEg*$&8<#sNN4E?*`UMDxWHjvy;}qIqKG-~*D<5DYebR44ejyi z6{(kp*@s)vtdZRDg_tbe-nCEOc<*Z-_0@Q0m<=lMk2xgeqE@^(hNl))XXZ5tv^A9^ zfnhLlK{et8@h}L#%dwN38k?he?GuZwsfv-%g|1zXDov426QZ9(r=AxNJr4rSwVQqe z-)n#3(D=m2dA!}`%^zzaM_sOkudk|mhxIaVEkrQ`qdHqNLr1j97heYD$X3|Da4&Ot zmZJ{gE@P`LQ`a_X)4Lj*6`rjG#`O;TwFbG7a~x$6ay3L0_LR07(sArqkk qx*|{?`@nE%lBuAfU!XnE-zHnz 0U3Nfq_f&PF8VGwM@|2D&kF=B9-ep;c zhy{rVP6+&?#=!LEPOy4Rr8P$gS|V=GBJ!%2786u*ASv@6$?F}6*jC7Yf(Jp-negd` zcpW&d4*Ko7`+_V2uBxOu`_jv#G!*F7auiEnDA>wK2GZ}+pw|}`s(Q*Dc!%HaU`P^) zjUvgP{shT0a((yo(T7T-ZMLS-`>tvBg`e=O{u|pA5y#{iy8M_Y%-QL3XkeH-4JN}` zv>nQeRS@$T@yT&66CG9>J3OXBnH>YHT(cj}F^C!^N&`MhtlEUAO=GjLr {%Z+%7hOPbS`d zEyMA;7L0*JuW&3bwtX+zZB72m_*s;6a*-%YP4uOA9AK$BE`z|1Z&7?zDYLxznLwCN zGThlba2#YTuI!kgUKkU>$vZi`l&&3tWSI^qnQfqWaR_7f5!VtxswTT8E?d**=do7r zLZl$LVre3S!lM7k^viEh=KWavcUuC@9FCLRTg6jZut^>dH|UAy)U#bXPGPT4t2JB$ zd7+~a{gPkvJ_@^QLzk*gv~h7tZlUa_X+rn`7uAHgwjiMo2~pK(Gl?(2cUT+Q!y@h5 zMw;e!dY{>kNWhBs@0ZgRHcuiKjgl=@-d?*R@YbV?v3HV3*zPWMcp{efQPk^*7M|ou zBPp9yESbk^Dqjd#>Q;MPTX;XELl1ZuQjW#pp8$X1(jTBh*Q+XfHJbB>-{H-sqiu^9 zJ|gea!XD2;hQdktNqGcnH%D$=>?j&$9U6+_+Jy#igjXs5wA}&Q7b7xAA}mM%vWmvV zN>G;Uhk(Au%W(Pe%oF#xRQGZO*_Nv6mj>ly37l@7br1_d0!3HWdUhGhhb5x83XV zoszcNZ&N !Qul@Y!=M6}&tbF^b?=Ke2ifDhe#eS}ckcJJ z7|@3pY87@p(*H&bB9P0yMn0LTLL%@R!kyXijZ!)tQ)1)+POX9Zj^n!qN4~?2ZwJj; z8*L$D&
2ISm&f1ntR^v!3uuv9JK!NL+bWWF8TEF&-FEbef?_?8 zPv(EjRo8cu8bk5lyBt)0a5?BQk4c{~Y3>%*KVi}2r$}TRoZxlUMOuEnM WwT3ZNU8|ZACf9+esz|Xl~Aq*91y-w zIX_msZOn^SX~TSZ_U=g~%Jx!Qr~mP7?Wd4MqH64Nmu86wGAZJL1Ty+yiH{)veXnZF zJb)xd%SFgg&H$Gy2}ahnH))qwa((9}S1lOpz9pn>slV1b3Ln`>4?q^J=X35e+0bRW zx3q5ilZ|rOia+w)jc+dUqWj+eFin0}Mv%5#1sPGY_1W(as{lCtqnjw{^?+rtEU?KL zX;>W?({4$z1?zyBT{zz1Q4wBDP-*w9aBI)vC`=7ReNI(paUE#~dRgXRWupD*$)$h~ zl^*=JY?p#0|H RfI>;03BEioGslukGhM*5Z zm8YfmFTST9Chs`?1dS#Wg4CC5ZpNPSAQ8D_$D!?U@D>gJ;WKq#+NAPg7YU^~->=Fw ze5-8Ori`TwLOGL9@lYn$K}?E!sxhZ?^MRr&^E1Q}=-hI xtxu{TZJVFEVH?~lcgsVoC2h<$%%@^_zF1ER7C&Id ztNGA`IGa C z&dhS7o+n^m#Kn%$ix7HJF13(DB(%1oGTOL+kh*Vmt@x<7b0*Tgc1R1J_m&u-j!A4F z#=?i0vDujx`F |3=zS8GI5jgOmd88gu2kqeX$N|=1nBM!dbTML2=2i*A`VUK;ZCl* zcnEUSD|XWmWsKXq0 VV6aIVo%DfJh82*7VEd0Rq1)UJ%%Sy3v5X z2Zdz4n7!2 +;$3#QJFNTg9lw}S?>N(je&<1~be4t}fWzkIEmEKvhT#7fkT z22u&*fedP*=#4tqid#T6)uL_dx4YHdlG!D+C@3IFL~%z4Ln_Nry~g(y7>dbKImuQ~ z=-s!TEBN^zyxh_nT}DXOxfYIkK3Pjuu$-O4llS!GD@wjFAb?o>v5w%ByM~V_?zv)A zsy0va#E$eL3-nBaH=0Lh5+SSm{6EZ&8NqtMmUJ{wZI;+&EBM@D@l9VGRM%HG@qoa= z((fBnC7(APqFmuWwL-J9Wx lbxswKK|TNU-|H@QM!i6@ zEpJhN&%(3_0wkxsc(Yo9%3d`}$f=gnIj^qa4bP&qQ?B)55ia1tZy8`P%af>Htiq-q z_tzNm7l7{^-#sp9?(CktWEShG^ES*oT$uv#fnUT6wXT+(N5AqEd?sM@6J*R-Q3e1= zpun65@R(-k)WD2!v4(f_)QLzW&S5;0#U}*O{ksb@$7>T&v_dtoWE=$qf`zPa1sFQD zi=(8@yI+Fz;}hJO=e;T;NHe@o;lyF0j+6!uC$#YPqih$W$-SdobFIq^=%O}#0mnUp z*JaHvKRfMbe+{+JH@i57V&`j?7nWqx0+)AV@!3A<0~s=8SHxsU6>f?Wv*d{N6JBuS zngqUkU%^mrqEUzj?tk!kxY2>TmXX-X#;$*%%Y0geRsjk2!%V^NIds(f0E)%G{R#g= zpSUj!d%1OZNwR%?eYVKK=qhx=kAj4F!>bqV(Ga8zU&Wi7AcWK(ojf24xEU4U+PNHg zHg*um?Hq;CMOXkz!01i@%M%3p<*a}IAp1RX6d&ztumN2^Ake@^1^TxT&;Kzd0^-f- zad={gsp&=h-=N@DG@uG71045XgEXNTnx-AFFQR>mFzU@u-K9&^ih%%}FX)%kF^!Y1 z>MA3(SJ@W?A?c-!nIZb*qAi%^HW++~uwaD+-Ioef(`txtr4!P{xSd?1`rEDdXJjFO zQ3f+mOEnI|N>f^;%7Pg@Zffcef4uKg?XD=Iatn+1idixTqiexeuk~`CHK~~Q9bJM5 ztBi{4!X#dn Kyb(9Y9oPu9m#%Xe1}A^b|i-3U(Q5hObt#u_Hnn`oKgoa`M@a zoK>oIj6D>lc)VX=GnJUPm^FyfrTw+h8Ft54{5*;i?u0749lmyB7BX-(BDH5bAKhyI z(6xRUpq3{eNWPPv6m!G(6z(u$=47^LM*5vt0#(JIpb^jb4T^`TnmP#ZD$Ncy7X0GV z7(XiMfdB~~)mh-`i|ojf9ysm_bgJDJ`JCbtL7<8RGirnP9;C2+JmtnqsY9_C++KW4 z#JuQ*m_R`H&iv_NE7j3OW2S9QQkcRgT}Gm!z5RS_Ms%iWS@$DDwz;5lHbxA&MVHgA zz_`ngai=p)ud=FS+hG`Sni`$iI0u<^+j~Qw&*B>JbSyo(tg(Rg)TMeO>!yK0e*N?> zKc_iIS2j|G_v=`MV-*)}ZGl$D-!3`VSKp%H*|oo3kT|>MM_Rm>OCUf4VS`OLO4gl8 z&CR*-F 7>c32m+wTyQhCo82CWQ2mxQw2!V$hRI QvC zi1~v-f>+iFeH$W&(jaCT0812qS}kA_3qco+W9<9?zs8!$pCD$lf;+=8xtpH!cP&S` zar~@h*{}a^irv&yh(~sQhnPB~#Kwp<+S}Kcu`Xua<{33m?jPXD3)nx%;?!3wELY;c z*P*0t*WA2d+%r#o^-w5^kBg+UI>w9azmF*V*Q9pS%0(Wj1&@@M0Lt!} ?%K72N#b%n9W#zW@X%9Hbwideltk?C%5IalWPdj@ zF18~c=Q1dD3^8Q1wG2HK!Je~lyEE6O3?C|s 0ByW`;`uA?lA2q&uc2Ijr=E%HjJa zhw6q@^INCqiRRj5?~}X-%NOVsVOS 4ra;24>ejBbKJ|SL=VLQb8XU zebm$X--!RQ40>kFIqSsGzt$@s*zEkHS3W%MvJr*2KLkoxoQ3pd4C>S1Xk%f2QgWPM zjYORCnLL8gjdJjtxhIUq!hY2@+LWYYh}|)BpKAhyb7uysNnbLOQBVf%)!Q!h4*+y% zaTQe+JQ?)b;qF|WS-YyF>|^sIyoJSSv 9cSe@l{y-l$Q(lz$Oc`1B(ky_Awx)Q029ysVhYg^wPH6nLQxI4Ou z5TDWmUf}8iXS+78dZXfR)VE&i!DxbV{Zef~3%5 jmu-{fXk=3F zVGFnkrkL32wcy7>TABml|IVewuB%H9wS3@v@K9%4w6PLwDm6zar0nq_!jg(?rXu$u zGh(fjEZ0|0G?l;?X(Yf{HyS95Mans0?@w$omHo}aCL4d1HD<9>>O3fnS3`zrZb8s5 zioR%VCH{#L04+qRfF|1+E_=fs<@EOn@jv2{3#O%w Mvx2j}Yx&oz6?{-->NqCN@`KGCSW_!n^Uj-cqBDHM2ATBKz zUy{~t^* zelHO76zgOfUR;5FoIQc5S=ew;QsW`B2s zV9F1n5%s%5CJ;f7jv1Gn+WkjQjy+kdy4KSvVc{x%UQrl$<_OS(=clh;HFZ5+`B0~Ad>Xx^ z3xy;S*p;_chgCv%z0ci^wD~QOy}nSNK$_T#?iz0G6Fr=DS31j%4icq3f H;1C5y)ZAu{$;5P6{{0X zy>7*^^R9(`klrhTLEJw3w^fT-Ko23_FcDrT&5;7;g&)qA4rgB9-+ibm3!(b9{;7Qw zIvTflb(wGDwZ5J7{yL6uNn5v5CjEjgYo#8g@;^aU5$W${kmdu3+y*^gYG}tay=(ON zb$JkNec&h#2@>jWJIPuoZr^Au`UAaTa8cXzQ!2~Z{MDt0+KOodZI8EfP4T9^DZCNp z-wrfQUW*n@QX0BbkO+anxR|=5!Zg8SMb6saH{GGqo6A)Zi+XkS1A~FzWOig_ZUAX3 zsY`X;Pf&xfOF(-iEl>25@bJ0Rm4A-+rwLW5FUQiHkD0E^<%fn08ciH{9yrXDu#;0t z-BRb3ujo`(gp!_LJS(YwoG*7G(;G KNWlzzNfNJ)QQ^Ov6AI*iW;bDR&gKeINl zOCKUA@%Sr`uKs)Fji9G~0T;lAT^VR3CZ4HUzF$P|JSbgsc*EiSjZ4Wg-I+oLpaErn zkU(Ubh|A<48xd=jf2+VFU$Ogs5dqb>III6d<#?bJ+)@_We7*}*QCf%G5LwRzNcjkH zb!hU;rox7;ay&G^NFGKQ6X5}T72FV`u-qh`60bzw+i>M;%~ }F?Ob1A!LNTBBF%H<;`wM;0| z;6nSM?eaE>U@foD)#CLs?*FWUzB|D9>D40s@*TR=BB{@6#_eq0g#_{9T=DY&0%aln zT NRQb)b3Q)$Q0pFO!_zD+Q*4<-BVS5a4)t^4^WNG3hw zi-X4{ph3d^1O@n9xMuTo>dj)L^@HVYrqT>0LNcFW4%V-i;t}%q8qKM?P-XL*(_FuT zqd1WJHuv>Q`z~61vsocluqEU=?i<&)nYtv>hc$kccE=e;n*LlP{H$42i=+xDf!Bb7 z6yC|EgyMKJ8o|$+BR9MgZ-}dblR{U0;8)WKVrz*D)Uf|ZB9H&<={e{GL7+uQo)LKp zz8l@9>uot>=gU*4(9Lu3zdGLj1o2`W#WEi#REcK1{}gXKz7qxxtVyyF-ccBcLlQ5w zAr=*{z{NOg3x~x4_*jr=lXC#}ri(?*vb_trjy}K7Y54^Un&8+;QZ4z7Yal&fH)l`D z=+ <%jW5Ow-^o*&&-qE&b(rJ~)>Xd>EF3ZL`tOp2@{ ziP^Z0FQl_Me~BPyTti$=Q?eL+eCicS6>hhckm+{{0 N&E=(F1 zsx22 |Q-7R7njk3_LIR+o<}YE&v{MWaau3)UWb=y7!Uko@#ot_x?lF zrKq(gahz5eTUYPZ-vmQkAw!=MBW(&`iUztb(nmlYwD G<>i1>n3GyLY@#T*J z>4ezd!L=>i25)>P3!7nF?6~LQqv%?PWBX!6e-8xy)D6Tuc*l;iI=kRQ3TnnAxE2P) z#K(v$wS6&k5&PSIK#i{Tm~-%<#gS-y51XFN0Ih%pQ5g1SO5|e!MQrZpsg8ZE5~(HG zYzDC8T1f}S%G}G%(4Qa$EO3cVE!|Yoc6Sn{QWcanjKge(Cn~3-yo}nvwrfqUKQ}8y zZZeni>jb{zS43{dAo#89(jqf}bS|Wz?};wiPf$08;H?Fu2+)+12RpY !cWb;7ngV zG%aE~{yH0&5e_XkfQRneeCvK=d&1_U(t8m@cBb?bBuZ<0y`MwKzogW{6UcFV*vAtM ziQ!ThwO_&$uRv5={m82~KUbjd=P(GK(tYdM@*0|(OS6p*#4w2^K Mu=$uV94tDJN zP6*RaSo~({CulrqEi%KE9%$ssVePapx$wjS4#A~zhLAL6ZJQu_n;`BNRE<$-IN(%J zw+A_ME&5WGv v4XjMH+{lPl(2e@mW*gnFUnk%`E&QYykNpWZO9?r<_t&(psqt~ MN>?N@p&rmq}5~9yDw?3Yic6RLQEQnoxi;&!(-%XColY0!|W* z^3*q2rMuhS1)87l=|EQMUeQC7Kw?tDTN+(M-WsWl^zfT+W?ypn`Opj4S!}kAp9m3? zVlik3Im(C+$j(Khz)qm@kdGlDmg9f9e+uVnr^VI9`w&>~IyvX-@`vY9PbVg#yWL#T zm`?8}h4W`-VsLgi8<%{RA7>MZ)jwdU*AEj=W#O2xMl`2Fn6{*7_9ffY+ug;gDkLCb z@#Y(QpBb|@{=J6C*Wu4}xOoo(1Kr?-=H8bt+3^uF&z9&2A|=sXD5*Ky`(fVxS{$qf zEDn95yBkKr09e%4NCICs58&Ckc$DT#qP#wvQ$Eaa5?eas_u~8Nmx}gZ5~n4Mk2iF1 z(>GjUMV#im+?>7K6qn*gje-zASC|r(GTU$bukvYfG9X2_VD?7~8Ul`U?Ql;*stK3% zJTC)JbGF~7AJx?(1ew82T@LRYRkgecL*a!_J1MBTryJk>F6Q{yqnctSVrR&fsp2EC z8JgQhn%f364sL>JNO3hx6ES<*!+K>xJQoO*Wh~6y`I22^eCU`F=$Jv{*-7Rj_f{Nt z{0#Xv%?EkSXX+ZFG>Emsy|v-pC1mvS$d2-wxJ_2ER-dtHEYMpev&UbWr;7^ZQMu2s z;{H{h3Qe*c3H6T2kpfn%3H57^BrUHta&JqYogV9-AiLlrSRZ{=7h-sZ Rbd-p=le?^C)1O|!H4^Y zrh@AkdLbWeR4C3oMUK6T`cwtS@yEE+ z=%sHEyX z8!r|w(E?b$o*s6f;)|=DNV+`32u)TXr2gUFf{=`3LDlxLM>~P)9RTnJobhf<<=5R~ z$8%Te**4dz!a1fUkwMY>H8BT-e#W?`^U%xf-hytP!AI(UZ<<2Z&04It@Tvuc9-ru< z+x`TZZge^FUD$k!LYf}`-9bp()#Iv&Q8)i}zix=05I(2N1$W`@(zOB!V@*`=yX_5! z=hq#MXXNqI-V=Ud{QI@XODKm+_s4oY{!p4 K>sk=Tgkj# zphKe+iFM)Ul!zLcFjU{Hv)_sli^9I^tZ2NK4n8Itiw$`^abB9Ivjw^a%lr27k3#I; z!SyUmKb4ADp~eFhDtzH%mFByNuaPzQOcDw-GsX*|)~n+wu7n?Oj2!D{=M_6i^aFr8 z#>lt~Yr-CL7w)iKC-1ucEo=C&l>X5BX}mYjj7s~Sl9um&G#_cfWwixJcH}%ieop^} zRb4KyzWpUL7q}{3lv3el!j`oHr`XvusXU9?qc5YH{Arx }R9hL_? zV*K|WF$kiecPh4Y`v#W*Di@ggbIypsJ9+XGbl8LHqcgpH3x4jME`ZMM1XH9nrrT=0 z_fk?r)WaDMZcn%wCBP|bkzJ~=|L`s`tcp>)WmZ|T41vvGFPf7)$&2|P8b!qbApS63 z_3!|iG{Dy$d{%RXsFFo$t!2%OGf<@}+_`Vmo1gkH7^t*V!@`UxixMC?K?^Mj%yPlR zD?*nesQV~)+ayzF9cJ!$6yjZR#crDZg_D9ovGAIE^>btcyAkl $$E(v>W+wt<}7vxqaHi$C48}tP%*`# z=xgmI(dr@Vx_G?vH;yBTmo|OwTCnB=^|1IA?@>zYW+g>+#*+B~9Mo;+;pe0OoHjHn zCdCzrn{XF)+iid@epX)A*wf(Cg}fu*)YJK|RLjHww4fzrfgO?`gu94AO@7{@R@HWj z#bqyIwaz @bQ)t(u#$C2ek70ZJ`cJ^5hVEyW@3G*XIIUOQM@5 z@B8az^%K;=e_i!sLH|Ve;lkcu&(+Ynm7%=bkgwEkmr!i^3M@@(74pMh$r2Rc&P(@) z_oo(L>L;Zq$F UAUsaSg_r0aJ7j-7}xSS z!Rv8-xcKWWR4I3gZFpIqt4GuJ3v3LImk9B)^UCV_d;nB>H%-d`Dn}mt1c0~1wR&6y zA5JZp<+FEvZ+?%c-C5#h{I?Hw>E4@g Vpl+X7`>p5d2%6Xw>6{d+d0Hl{pwI*^h1nbON))aq&3Ai5nI>w2it?Q^ zYq>Co7 %ji+U)5w=tK?c6tZi$w#|Dl>=H0bY(u=V9^#tx4S&@?HgJ=kP#G08 zr2O=ltkASk)VAd=bK%KAZz0ZVl>5T@TseHQy;CH{yq>FQ(lSckMSz9Z8ty{{d2qQp zO%!;pxaj%29uCX}Mv=$;=~@?@JnicUXR#f|uA}Sm)R$Et79p$VuPix~G_;F7*v$YY z`wYR$E-;25&)R|bB^O_dgS*8gkhk?<9j688A#}N_QK`FB;z!yCbWPG|OEplR)DcW# zKBYJQprs IrfYFtM$8QJVQSHO)ne_A9C_?p%J=Nf!7^%7q)U&tF=6~f- z(&zCtBk231q5qfK)pxpm@eu6Dh|}^}v1B<29Q2j@yH1H1oxZY=uMCONrin;k2{5k(l|Wu?ooT#mmQg(avL3 zF*<9Vyh(F{@ChpXMTj6&ARaKl>1u(%+qq9Ktx6J+X28mkl2Nyj%KoP5bbHC$xrcYo zXu(VXm#NHfz7c)+6 7Opxq**cDn<$3;wcC?RAoEV0 zDj_mT;iWwr$)XiCRT&WgoTBEHX8nWq@V8?d_}@j^b4rUs{z%=V6%92es24C9my|z2 z&Qx(f0{hJR?hX4(r)*)rB_Z9?HJx3!S;dpAH_Zl3MKVt%@m^$>1&Hj9($AiuY#X`( zp2Aa0#vnTY$0?;ZZeLT+W2{S@WzbC5MT|j!G4J!dp!=3yz5NV(_#&LIy@d9bIq;&5 z1|wK>v)Jr65ePWfcz=S(lSy@qIKa%;;-=n c{1>2Y*`5M>D*K(}2bv zuq2Ym_P&wRka}cOrdIV8P6HH%WPr+mZq656_5=KewWno_d8bPN83z?}3S1#LnRVYr z4b05A q8~fJ72}fz zzLptrK&X#=oMyEHu!G~42^7jc2QJ;}m~u4*j33a9w;L?h(07erKo?U%3Dlp_!Zw95 z`0&9D?>`0 d)(OG>SrSA~Wg5 0iFe@}xJ<*MMej&k)ESlP%PB z&o=Q1t;Yd{)Hp0N`dGNw=+aJLmfXIzFi$Mi$FTrXrB4RHNCob_&NboUE~JZJPpKTQ z&}q@bGb3d0gPuhgp^8CLh42d8)hgIS2D1H|jVVgNxFQz&4`B{dkcGS8Q|xCb`3oOS zrB$7vf$2C`vP fx<5H*~pccOo`k*6Y?>;a2_OLJ*pIsDQvPL!sgBz&V pjS)M^n@}$21xcG2F9fYYoLUgNnNEZx6quhy59Y8 zaQ?6|iYFjN>6HZy`-cQ*1dTwM(LX?Itt!b?YtBph2T2O%Z#^#Ni3Ps$gfb7qdk hGPXiEI;}g1@ zfk N-WsmouZ1Z|#){uVClu z^(fiVqxJaccC5 6F!YotbEMmxYyEwxb>4> zZ-t)GkuEA5Go0B@E)B<#oA6BK@c1kTrL>gr{Y4hYYP2#@QF&s_q`{Sk&C_+Zkv213 zL$`nBr2{dG5pKXo)dmpIG&f>d+cbe7qrwnlXHnlVGu`0fz?o|p9qDzpVXb*B2_=dq zn~3N_Yy`b5i5kBwvuOfe-F|uEP-B anE>jw~K zrt4|s#>2Rt;h6$-jEU|3#da33eWN4Y9pT@W#wkz7H}g1R=WqlPW8>rI9`wP-cc!XF z4#l7JT=@cdwd(|Ncj4f+{~vb?u6iqCDsHfWYw=Auk{iVWX+7U6U|Q1t4jupHSYz>F z#+y%h%w#}$zf8dys0CG-^~!3NXEdOzJPR-_tcngvI*?S~ihoG28}VmXbQle-fs`@8 zDTwD@c#gz+#(5+TgZvZZ&gF!KA=_^ro%>kO6sk11KJc``zgaDKPicHD97sYhP7xA_ ziD5E?hexBrs7LxuT#*v@%H1%qti}K+a0x?;obKe*ND=%4AB+v5TVfBQF-)Zx2w> z!@l{dCpSMlr+>zC#&D7;O|T+U$X;g!6aq0s*3{zJMHOa$&)Dg?O0!*EuTeGqqFmG- zmN4N!vWG&7fQ}&;sz73(pu6y3Ni71Z%3%6BK|BzD bIXs!q9de2f%b zmgx>5|6=3q+_8;XBY+V&PQme<^@dBGA5j&lE5ZMGOaHL~r9+n&?^LIp8ozk0aA{xZ zjbBO>L<_w(*dYnKF)_md&Cy;Jb5-;cl+#Nt6 6&uU z A*+MoozTUa~hS>9Z z?&S7HQ&(aRaCcY7x~Z91e%DL HmrWW2lhh2r5i;d{flk2!uz7a6?r& z;M0sb!HSAL$If}&XSQ^UP-UY_5a4A(7 y6Qo6nOx*ii= zd^*In3pS^JNj%=rw6zt6`x70bmHvJEcL<(Sxt(#};&KM(&+H8f6Qj}LB_jf@8F%zO z#6a$@EZNE(rBd#Hudvf(kTcy!(Pdi>-aD@7XvWN_<~n^YB5<-4d#os1C$<0?X?ssL zcsJ3A1U-|Rqkrs91x(cPR>VW0od(+LJUkkmp%7ba3@H$UTZDV}I4c(gtK7T&7*qT% zYS}>U4(X-Rn2An|It>iA@3j-Tzziaq<%%U#*-v0 ^`d2 zRo^?SXp3%DcxN~}dvbq27k{(0lwG}~o2GvXNV$-$cKnvd{J;w*R3G_<{mZ*cAc%wb zkh-K$opTjt^qA)Lx7+jn(4Ox6nYdI0-RQYQcdmUBp~h>ZGKT%xp_l!kVh~k`MPaqJ z`lt?moPV$BpF==Z<5z(5P0CWC3Vg3L =VnMV-O8%0YPT?-X*%tehZOQ6bqTOW|%w0r*D?2AM*jwl1EW+ zb{jWv%Uyd*(wPC;mcJ^xOeHG#bfZ1|q~cgZOH?)fl60#RVVrE)qi}J?pJWDwekq=I zw~r}sfS(<&C@kq$vdcao)EDpl#YR}R5p_yf%mxZKJylg3H%8Yqqgy@Hi|+sdedU-i zxIoJh<@|rn)ENZgJoZ~VNn2mb=9Ay#i@93FEaMuxyrFo}I56qz#55t;SkxO}`8o?X z)m*Ul)Mol?D+^DTbmZ|QSqoeL5!67nTFoAUESr#01dRKXiDVx+xk6uwgU;haf|w)m zWG4|O^;uLFjk9UIkAo0ccs>@VEs-kG%X|RFAs2I?(5+E{DHyK}M7}3j`wiml?+Tpp zc(w4Vq8hEfwfw )dT(_~|pK)UCa+lQF{+pMbJ8HCSh z?=w5re`U(V#|^e=KE{{Z@~%AZX91#E{}i?lX@hWsn-NnzL$mx3r}Vq(ifzchGE~o6 zJ!>mKH};Y`{ZDrdkOKR!?^8Kj30|BJ(h_o-q`1-jDU}_G;r;2qqX*I<6cMveXg1Eb zrlHFx{qpELLd~^$& RW)lgf8NUQcghmT{l%!709;enp|XrDts*F*46(p0-0P z4?m|mT<&lWM7Ah$;w^!jQ;@EXez1ksxuRHRnLx4gIBKK_e0^D?yT-92`PL7BiiA#a zV&&`K{?q@=C_J6{B|h#`EuJg+AnrRff)v!;4}riry3~A|48V7LGa^KOharGm-A4_N z2G&obarXe98$t}xcf2c;&29(bv0_?O=KMzYSIXk-b~ANvv6A|MYoNMyxO#OQ2PK7n z>S^A5ic{oFAca<4Z#Rmq>$+hecY-YKdE`ulQSI89E?PrLMEpuuGoY`c?|-FC?!l~@ zKXI