├── .gitignore ├── facebook ├── djangofb │ ├── default_app │ │ ├── __init__.py │ │ ├── urls.py │ │ ├── templates │ │ │ └── canvas.fbml │ │ ├── models.py │ │ └── views.py │ ├── context_processors.py │ ├── models.py │ └── __init__.py ├── decorator.py ├── wsgi.py └── webappfb.py ├── static ├── img │ ├── favicon.ico │ ├── spinner.gif │ ├── appengine.gif │ └── ajax-loader.gif ├── blueprint │ ├── src │ │ ├── grid.png │ │ ├── reset.css │ │ ├── forms.css │ │ ├── print.css │ │ ├── ie.css │ │ ├── typography.css │ │ └── grid.css │ ├── plugins │ │ ├── buttons │ │ │ ├── icons │ │ │ │ ├── key.png │ │ │ │ ├── tick.png │ │ │ │ └── cross.png │ │ │ ├── readme.txt │ │ │ └── screen.css │ │ ├── link-icons │ │ │ ├── icons │ │ │ │ ├── doc.png │ │ │ │ ├── im.png │ │ │ │ ├── pdf.png │ │ │ │ ├── xls.png │ │ │ │ ├── email.png │ │ │ │ ├── feed.png │ │ │ │ ├── external.png │ │ │ │ └── visited.png │ │ │ ├── readme.txt │ │ │ └── screen.css │ │ ├── rtl │ │ │ ├── readme.txt │ │ │ └── screen.css │ │ └── fancy-type │ │ │ ├── readme.txt │ │ │ └── screen.css │ ├── print.css │ ├── ie.css │ └── screen.css ├── js │ ├── fbinit.js │ ├── main.js │ ├── sound.js │ ├── scriptaculous.js │ ├── builder.js │ ├── shell.js │ └── slider.js ├── xd_receiver.html └── css │ └── main.css ├── facebook.yaml ├── config.py ├── cron.yaml ├── templates ├── canvas │ ├── error_download.html │ ├── friend.html │ ├── invite.html │ ├── index.html │ ├── base.html │ └── graph.html ├── test.html ├── error │ └── download.html ├── fbconnect.html ├── graph │ ├── emotion.html │ └── index.html ├── index.html ├── latihan.html ├── testfb.html ├── trainning │ ├── smiley.html │ ├── status.html │ ├── index.html │ └── keyword.html ├── iframefb.html ├── shell.html └── base.html ├── exp └── test.py ├── loader.py ├── exporter.py ├── latihan.py ├── app.yaml ├── cron.py ├── graph.py ├── index.yaml ├── base.py ├── main.py ├── trainning.py ├── analysis.py ├── shell.py └── models.py /.gitignore: -------------------------------------------------------------------------------- 1 | *.py? 2 | -------------------------------------------------------------------------------- /facebook/djangofb/default_app/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /static/img/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ATA/emotiongraph/master/static/img/favicon.ico -------------------------------------------------------------------------------- /static/img/spinner.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ATA/emotiongraph/master/static/img/spinner.gif -------------------------------------------------------------------------------- /static/img/appengine.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ATA/emotiongraph/master/static/img/appengine.gif -------------------------------------------------------------------------------- /static/img/ajax-loader.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ATA/emotiongraph/master/static/img/ajax-loader.gif -------------------------------------------------------------------------------- /static/blueprint/src/grid.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ATA/emotiongraph/master/static/blueprint/src/grid.png -------------------------------------------------------------------------------- /facebook.yaml: -------------------------------------------------------------------------------- 1 | app_name: emograph 2 | api_key: ead88d005b9905d8e6d13282e0065b93 3 | secret_key: 44f7bb8680cd23a8268c2449c56828ce 4 | -------------------------------------------------------------------------------- /config.py: -------------------------------------------------------------------------------- 1 | TEMPLATE_DIR = 'templates' 2 | FB_API_KEY = 'ead88d005b9905d8e6d13282e0065b93' 3 | FB_SECRET_KEY = '9d12ee2ecccc2615fb817082befef760' 4 | -------------------------------------------------------------------------------- /static/blueprint/plugins/buttons/icons/key.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ATA/emotiongraph/master/static/blueprint/plugins/buttons/icons/key.png -------------------------------------------------------------------------------- /static/blueprint/plugins/buttons/icons/tick.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ATA/emotiongraph/master/static/blueprint/plugins/buttons/icons/tick.png -------------------------------------------------------------------------------- /static/blueprint/plugins/buttons/icons/cross.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ATA/emotiongraph/master/static/blueprint/plugins/buttons/icons/cross.png -------------------------------------------------------------------------------- /static/blueprint/plugins/link-icons/icons/doc.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ATA/emotiongraph/master/static/blueprint/plugins/link-icons/icons/doc.png -------------------------------------------------------------------------------- /static/blueprint/plugins/link-icons/icons/im.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ATA/emotiongraph/master/static/blueprint/plugins/link-icons/icons/im.png -------------------------------------------------------------------------------- /static/blueprint/plugins/link-icons/icons/pdf.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ATA/emotiongraph/master/static/blueprint/plugins/link-icons/icons/pdf.png -------------------------------------------------------------------------------- /static/blueprint/plugins/link-icons/icons/xls.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ATA/emotiongraph/master/static/blueprint/plugins/link-icons/icons/xls.png -------------------------------------------------------------------------------- /static/blueprint/plugins/link-icons/icons/email.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ATA/emotiongraph/master/static/blueprint/plugins/link-icons/icons/email.png -------------------------------------------------------------------------------- /static/blueprint/plugins/link-icons/icons/feed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ATA/emotiongraph/master/static/blueprint/plugins/link-icons/icons/feed.png -------------------------------------------------------------------------------- /static/blueprint/plugins/link-icons/icons/external.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ATA/emotiongraph/master/static/blueprint/plugins/link-icons/icons/external.png -------------------------------------------------------------------------------- /static/blueprint/plugins/link-icons/icons/visited.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ATA/emotiongraph/master/static/blueprint/plugins/link-icons/icons/visited.png -------------------------------------------------------------------------------- /cron.yaml: -------------------------------------------------------------------------------- 1 | cron: 2 | - description: list word 3 | url: /cron-words.php 4 | schedule: every 5 minutes 5 | - description: probabilitas 6 | url: /cron-probs.php 7 | schedule: every 5 minutes 8 | -------------------------------------------------------------------------------- /templates/canvas/error_download.html: -------------------------------------------------------------------------------- 1 | {% extends 'base.html' %} 2 | 3 | 4 | {% block content %} 5 | Error When downloading from facebook, Try Again 6 | {% endblock %} 7 | -------------------------------------------------------------------------------- /exp/test.py: -------------------------------------------------------------------------------- 1 | class Mahasiswa: 2 | 3 | @classmethod 4 | def m1(cls): 5 | cls.m2() 6 | @classmethod 7 | def m2(cls): 8 | print 'm2' 9 | 10 | Mahasiswa.m1() 11 | -------------------------------------------------------------------------------- /facebook/djangofb/default_app/urls.py: -------------------------------------------------------------------------------- 1 | from django.conf.urls.defaults import * 2 | 3 | urlpatterns = patterns('{{ project }}.{{ app }}.views', 4 | (r'^$', 'canvas'), 5 | # Define other pages you want to create here 6 | ) 7 | 8 | -------------------------------------------------------------------------------- /static/js/fbinit.js: -------------------------------------------------------------------------------- 1 | document.observe("dom:loaded", function() { 2 | FB.init("ead88d005b9905d8e6d13282e0065b93", "/xd_receiver.htm"); 3 | $$('table tbody > tr:nth-child(even)').each(function(e){e.addClassName('even')}) 4 | }); 5 | -------------------------------------------------------------------------------- /static/js/main.js: -------------------------------------------------------------------------------- 1 | document.observe("dom:loaded", function() { 2 | FB.init("ead88d005b9905d8e6d13282e0065b93", "/xd_receiver.htm"); 3 | $$('table tbody > tr:nth-child(even)').each(function(e){e.addClassName('even')}) 4 | }); 5 | -------------------------------------------------------------------------------- /templates/test.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | test 4 | 5 | 6 | 7 |
Hello World
8 | 9 | 10 | -------------------------------------------------------------------------------- /templates/error/download.html: -------------------------------------------------------------------------------- 1 | {% extends '../base.html' %} 2 | 3 | 4 | {% block content %} 5 |
6 | Failed when downloading status from facebook, Try Again 7 |
8 | 9 | {% endblock %} 10 | 11 | {% block sidebar %} 12 | 13 | {% endblock %} 14 | -------------------------------------------------------------------------------- /static/xd_receiver.html: -------------------------------------------------------------------------------- 1 | xd -------------------------------------------------------------------------------- /templates/canvas/friend.html: -------------------------------------------------------------------------------- 1 | {% extends 'base.html' %} 2 | 3 | 4 | {% block content %} 5 |

6 |

7 | 8 | 9 | 10 |

11 | {% endblock %} 12 | -------------------------------------------------------------------------------- /facebook/decorator.py: -------------------------------------------------------------------------------- 1 | import config 2 | from facebook import Facebook 3 | 4 | class BaseDecorator(object): 5 | self.fb = Facebook(config.FB_API_KEY, config.FB_SECRET_KEY) 6 | 7 | class FBConnect(BaseDecorator): 8 | def __init__(self, func): 9 | self.func = func 10 | def __call__(self): 11 | 12 | self.func(self) 13 | 14 | -------------------------------------------------------------------------------- /facebook/djangofb/context_processors.py: -------------------------------------------------------------------------------- 1 | def messages(request): 2 | """Returns messages similar to ``django.core.context_processors.auth``.""" 3 | if hasattr(request, 'facebook') and request.facebook.uid is not None: 4 | from models import Message 5 | messages = Message.objects.get_and_delete_all(uid=request.facebook.uid) 6 | return {'messages': messages} -------------------------------------------------------------------------------- /static/blueprint/plugins/rtl/readme.txt: -------------------------------------------------------------------------------- 1 | RTL 2 | * Mirrors Blueprint, so it can be used with Right-to-Left languages. 3 | 4 | By Ran Yaniv Hartstein, ranh.co.il 5 | 6 | Usage 7 | ---------------------------------------------------------------- 8 | 9 | 1) Add this line to your HTML: 10 | -------------------------------------------------------------------------------- /static/blueprint/plugins/fancy-type/readme.txt: -------------------------------------------------------------------------------- 1 | Fancy Type 2 | 3 | * Gives you classes to use if you'd like some 4 | extra fancy typography. 5 | 6 | Credits and instructions are specified above each class 7 | in the fancy-type.css file in this directory. 8 | 9 | 10 | Usage 11 | ---------------------------------------------------------------- 12 | 13 | 1) Add this plugin to lib/settings.yml. 14 | See compress.rb for instructions. 15 | -------------------------------------------------------------------------------- /static/blueprint/plugins/link-icons/readme.txt: -------------------------------------------------------------------------------- 1 | Link Icons 2 | * Icons for links based on protocol or file type. 3 | 4 | This is not supported in IE versions < 7. 5 | 6 | 7 | Credits 8 | ---------------------------------------------------------------- 9 | 10 | * Marc Morgan 11 | * Olav Bjorkoy [bjorkoy.com] 12 | 13 | 14 | Usage 15 | ---------------------------------------------------------------- 16 | 17 | 1) Add this line to your HTML: 18 | -------------------------------------------------------------------------------- /loader.py: -------------------------------------------------------------------------------- 1 | from google.appengine.ext import db 2 | from google.appengine.tools import bulkloader 3 | import analysis.models 4 | 5 | class FBUserLoader(bulkloader.Loader): 6 | def __init__(self): 7 | bulkloader.Loader.__init__(self, 'FBUser', 8 | [('uid', lambda x: x.decode('utf-8')), 9 | ('name', lambda x: x.decode('utf-8')), 10 | ('religion', lambda x: x.decode('utf-8')), 11 | ]) 12 | 13 | loaders = [FBUserLoader] 14 | -------------------------------------------------------------------------------- /exporter.py: -------------------------------------------------------------------------------- 1 | from google.appengine.ext import db 2 | from google.appengine.tools import bulkloader 3 | import analysis.models 4 | 5 | class FBUserExporter(bulkloader.Exporter): 6 | def __init__(self): 7 | bulkloader.Exporter.__init__(self, 'FBUser', 8 | [('uid', lambda x: x.decode('utf-8')), 9 | ('name', lambda x: x.decode('utf-8')), 10 | ('religion', lambda x: x.decode('utf-8')), 11 | ]) 12 | 13 | exporters = [FBUserExporter] 14 | -------------------------------------------------------------------------------- /templates/canvas/invite.html: -------------------------------------------------------------------------------- 1 | {% extends 'base.html' %} 2 | 3 | 4 | {% block content %} 5 | 12 | 15 | 16 | {% endblock %} 17 | -------------------------------------------------------------------------------- /templates/canvas/index.html: -------------------------------------------------------------------------------- 1 | {% extends 'base.html' %} 2 | 3 | 4 | {% block content %} 5 | 6 | 7 | 8 | 9 | 10 |

11 | 12 | 13 | 14 | 15 | 16 | 17 |

18 | {% endblock %} 19 | -------------------------------------------------------------------------------- /templates/fbconnect.html: -------------------------------------------------------------------------------- 1 | {% extends 'base.html' %} 2 | {% block addscript %} 3 | 4 | 5 | 11 | {% endblock %} 12 | 13 | {% block content %} 14 | Connect 15 | {% endblock %} 16 | 17 | {% block sidebar %} 18 | 19 | {% endblock %} 20 | -------------------------------------------------------------------------------- /templates/graph/emotion.html: -------------------------------------------------------------------------------- 1 | {% extends 'index.html' %} 2 | {% block content%} 3 | 4 |

5 | Emotion Graph - 6 |

7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | {% for status in states %} 18 | 19 | 22 | 25 | 26 | {% endfor %} 27 | 28 |
MessageEmotion Result
20 | {{status.message}} 21 | 23 | {{status.emotion}} 24 |
29 | 30 | {% endblock%} 31 | 32 | -------------------------------------------------------------------------------- /static/css/main.css: -------------------------------------------------------------------------------- 1 | #menu ul{ 2 | padding:0; 3 | margin:0; 4 | } 5 | #menu li{ 6 | display:inline 7 | } 8 | #menu a,#menu a:visited{ 9 | padding-right:20px; 10 | color:#777; 11 | font-weight:bold; 12 | text-decoration:none; 13 | } 14 | #menu a:hover{ 15 | text-decoration:underline; 16 | } 17 | 18 | #footer{ 19 | text-align:right; 20 | } 21 | 22 | ul#friends{ 23 | padding:0; 24 | margin:0 25 | } 26 | 27 | ul#friends li{ 28 | list-style:none; 29 | padding:0; 30 | margin:0 31 | } 32 | 33 | ul#friends a:link,ul#friends a:visited{ 34 | color:#777; 35 | font-size:small; 36 | text-decoration:none; 37 | line-height:20px; 38 | vertical-align:center; 39 | } 40 | ul#friends img{ 41 | height:20px; 42 | } 43 | table th a:link,table th a:visited{ 44 | text-decoration:none; 45 | } 46 | 47 | -------------------------------------------------------------------------------- /templates/canvas/base.html: -------------------------------------------------------------------------------- 1 | 8 | Emo Graph 9 | 10 | {{menu}} 11 | 12 | {% block content %} 13 | You 14 | {% endblock %} 15 | -------------------------------------------------------------------------------- /facebook/djangofb/default_app/templates/canvas.fbml: -------------------------------------------------------------------------------- 1 | 2 | {% comment %} 3 | We can use {{ fbuser }} to get at the current user. 4 | {{ fbuser.id }} will be the user's UID, and {{ fbuser.language }} 5 | is his/her favorite language (Python :-). 6 | {% endcomment %} 7 | Welcome, ! 8 | 9 | 10 |
11 | Your favorite language is {{ fbuser.language|escape }}. 12 |

13 | 14 |
15 |

16 | 17 |
18 | 19 | 20 |
21 |
22 |
23 | -------------------------------------------------------------------------------- /templates/index.html: -------------------------------------------------------------------------------- 1 | {% extends 'base.html' %} 2 | {% block content %} 3 |

Tranning data

4 |

Status : Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

5 |

6 | Keywords:
7 | jijik :
8 | sedih :
9 | takut :
10 | marah :
11 | senang :
12 | malu :
13 |

14 |

15 | keyword di isi 16 |

17 | {% endblock %} 18 | -------------------------------------------------------------------------------- /static/blueprint/plugins/buttons/readme.txt: -------------------------------------------------------------------------------- 1 | Buttons 2 | 3 | * Gives you great looking CSS buttons, for both and 25 | 26 | 27 | Change Password 28 | 29 | 30 | 31 | Cancel 32 | 33 | -------------------------------------------------------------------------------- /templates/canvas/graph.html: -------------------------------------------------------------------------------- 1 | {% extends 'base.html' %} 2 | 3 | 4 | {% block content %} 5 | 6 | 7 | - Emotion Status Result 8 | 9 | 10 | 11 |

12 |
13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | {% for status in states %} 22 | 23 | 26 | 29 | 30 | {% endfor %} 31 | 32 |
MessageEmotion Result
24 | {{status.message}} 25 | 27 | {{status.emotion}} 28 |
33 |
34 | {% endblock %} 35 | -------------------------------------------------------------------------------- /latihan.py: -------------------------------------------------------------------------------- 1 | from google.appengine.ext import webapp 2 | from google.appengine.ext import db 3 | from google.appengine.ext.webapp import util 4 | from base import BaseRequestHandler 5 | from django.utils import simplejson 6 | 7 | class Article(db.Model): 8 | title = db.StringProperty() 9 | content = db.StringProperty(multiline=True) 10 | 11 | class ArticleListHandler(BaseRequestHandler): 12 | def get(self,key): 13 | if key != None: 14 | db.delete(key) 15 | 16 | self.render('latihan.html',{'articles':Article.all()}) 17 | 18 | def post(self,key): 19 | self.response.out.write('out') 20 | self.response.out.write(self.request.get_all('title')) 21 | #Article(title=self.request.get('title'), 22 | # content=self.request.get('content')).put() 23 | #self.get(key) 24 | 25 | def main(): 26 | application = webapp.WSGIApplication([ 27 | ('/latihan/?(?P\w+)?\.php',ArticleListHandler), 28 | ],debug=True) 29 | 30 | util.run_wsgi_app(application) 31 | 32 | 33 | if __name__ == '__main__': 34 | main() 35 | 36 | -------------------------------------------------------------------------------- /facebook/djangofb/models.py: -------------------------------------------------------------------------------- 1 | from django.db import models 2 | from django.utils.html import escape 3 | from django.utils.safestring import mark_safe 4 | 5 | FB_MESSAGE_STATUS = ( 6 | (0, 'Explanation'), 7 | (1, 'Error'), 8 | (2, 'Success'), 9 | ) 10 | 11 | class MessageManager(models.Manager): 12 | def get_and_delete_all(self, uid): 13 | messages = [] 14 | for m in self.filter(uid=uid): 15 | messages.append(m) 16 | m.delete() 17 | return messages 18 | 19 | class Message(models.Model): 20 | """Represents a message for a Facebook user.""" 21 | uid = models.CharField(max_length=25) 22 | status = models.IntegerField(choices=FB_MESSAGE_STATUS) 23 | message = models.CharField(max_length=300) 24 | objects = MessageManager() 25 | 26 | def __unicode__(self): 27 | return self.message 28 | 29 | def _fb_tag(self): 30 | return self.get_status_display().lower() 31 | 32 | def as_fbml(self): 33 | return mark_safe(u'' % ( 34 | self._fb_tag(), 35 | escape(self.message), 36 | )) 37 | -------------------------------------------------------------------------------- /static/blueprint/src/reset.css: -------------------------------------------------------------------------------- 1 | /* -------------------------------------------------------------- 2 | 3 | reset.css 4 | * Resets default browser CSS. 5 | 6 | -------------------------------------------------------------- */ 7 | 8 | html, body, div, span, object, iframe, 9 | h1, h2, h3, h4, h5, h6, p, blockquote, pre, 10 | a, abbr, acronym, address, code, 11 | del, dfn, em, img, q, dl, dt, dd, ol, ul, li, 12 | fieldset, form, label, legend, 13 | table, caption, tbody, tfoot, thead, tr, th, td { 14 | margin: 0; 15 | padding: 0; 16 | border: 0; 17 | font-weight: inherit; 18 | font-style: inherit; 19 | font-size: 100%; 20 | font-family: inherit; 21 | vertical-align: baseline; 22 | } 23 | 24 | body { 25 | line-height: 1.5; 26 | } 27 | 28 | /* Tables still need 'cellspacing="0"' in the markup. */ 29 | table { border-collapse: separate; border-spacing: 0; } 30 | caption, th, td { text-align: left; font-weight: normal; } 31 | table, td, th { vertical-align: middle; } 32 | 33 | /* Remove possible quote marks (") from ,
. */ 34 | blockquote:before, blockquote:after, q:before, q:after { content: ""; } 35 | blockquote, q { quotes: "" ""; } 36 | 37 | /* Remove annoying border on linked images. */ 38 | a img { border: none; } 39 | -------------------------------------------------------------------------------- /facebook/djangofb/default_app/models.py: -------------------------------------------------------------------------------- 1 | from django.db import models 2 | 3 | # get_facebook_client lets us get the current Facebook object 4 | # from outside of a view, which lets us have cleaner code 5 | from facebook.djangofb import get_facebook_client 6 | 7 | class UserManager(models.Manager): 8 | """Custom manager for a Facebook User.""" 9 | 10 | def get_current(self): 11 | """Gets a User object for the logged-in Facebook user.""" 12 | facebook = get_facebook_client() 13 | user, created = self.get_or_create(id=int(facebook.uid)) 14 | if created: 15 | # we could do some custom actions for new users here... 16 | pass 17 | return user 18 | 19 | class User(models.Model): 20 | """A simple User model for Facebook users.""" 21 | 22 | # We use the user's UID as the primary key in our database. 23 | id = models.IntegerField(primary_key=True) 24 | 25 | # TODO: The data that you want to store for each user would go here. 26 | # For this sample, we let users let people know their favorite progamming 27 | # language, in the spirit of Extended Info. 28 | language = models.CharField(maxlength=64, default='Python') 29 | 30 | # Add the custom manager 31 | objects = UserManager() 32 | -------------------------------------------------------------------------------- /templates/latihan.html: -------------------------------------------------------------------------------- 1 | {% extends 'base.html' %} 2 | {% block content %} 3 |
4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 |
Title
Content
 
15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 |
Title
Content
 
27 | 28 |
29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | {% for article in articles %} 37 | 38 | 39 | 40 | 43 | 44 | {% endfor %} 45 | 46 |
TitleContentAction
{{article.title}}{{article.content}} 41 | delete 42 |
47 | {% endblock %} 48 | -------------------------------------------------------------------------------- /static/blueprint/print.css: -------------------------------------------------------------------------------- 1 | /* ----------------------------------------------------------------------- 2 | 3 | 4 | Blueprint CSS Framework 0.9 5 | http://blueprintcss.org 6 | 7 | * Copyright (c) 2007-Present. See LICENSE for more info. 8 | * See README for instructions on how to use Blueprint. 9 | * For credits and origins, see AUTHORS. 10 | * This is a compressed file. See the sources in the 'src' directory. 11 | 12 | ----------------------------------------------------------------------- */ 13 | 14 | /* print.css */ 15 | body {line-height:1.5;font-family:"Helvetica Neue", Arial, Helvetica, sans-serif;color:#000;background:none;font-size:10pt;} 16 | .container {background:none;} 17 | hr {background:#ccc;color:#ccc;width:100%;height:2px;margin:2em 0;padding:0;border:none;} 18 | hr.space {background:#fff;color:#fff;visibility:hidden;} 19 | h1, h2, h3, h4, h5, h6 {font-family:"Helvetica Neue", Arial, "Lucida Grande", sans-serif;} 20 | code {font:.9em "Courier New", Monaco, Courier, monospace;} 21 | a img {border:none;} 22 | p img.top {margin-top:0;} 23 | blockquote {margin:1.5em;padding:1em;font-style:italic;font-size:.9em;} 24 | .small {font-size:.9em;} 25 | .large {font-size:1.1em;} 26 | .quiet {color:#999;} 27 | .hide {display:none;} 28 | a:link, a:visited {background:transparent;font-weight:700;text-decoration:underline;} 29 | a:link:after, a:visited:after {content:" (" attr(href) ")";font-size:90%;} -------------------------------------------------------------------------------- /app.yaml: -------------------------------------------------------------------------------- 1 | application: emotiongraph 2 | version: 1 3 | runtime: python 4 | api_version: 1 5 | 6 | handlers: 7 | - url: /xd_receiver.htm 8 | static_files: static/xd_receiver.html 9 | upload: static/xd_receiver.html 10 | 11 | 12 | - url: /xd_receiver.html 13 | static_files: static/xd_receiver.html 14 | upload: static/xd_receiver.html 15 | 16 | - url: /blueprint 17 | static_dir: static/blueprint 18 | 19 | - url: /admin.* 20 | script: $PYTHON_LIB/google/appengine/ext/admin/__init__.py 21 | login: admin 22 | 23 | - url: /admin 24 | static_dir: $PYTHON_LIB/google/appengine/ext/admin/template 25 | 26 | - url: /(.*\.(gif|png|jpg|ico)) 27 | static_files: static/img/\1 28 | upload: static/img/(.*\.(gif|png|jpg|ico)) 29 | 30 | - url: /(.*\.js) 31 | static_files: static/js/\1 32 | upload: static/js/(.*\.js) 33 | 34 | - url: /(.*\.css) 35 | static_files: static/css/\1 36 | upload: static/css/(.*\.css) 37 | 38 | - url: /latihan.* 39 | script: latihan.py 40 | login: required 41 | 42 | - url: /trainning.* 43 | script: trainning.py 44 | login: admin 45 | 46 | - url: /graph.* 47 | script: graph.py 48 | login: required 49 | 50 | 51 | - url: /shell.* 52 | script: shell.py 53 | login: admin 54 | 55 | - url: /remote_api 56 | script: $PYTHON_LIB/google/appengine/ext/remote_api/handler.py 57 | login: admin 58 | 59 | - url: /cron.* 60 | script: cron.py 61 | 62 | - url: /.* 63 | script: main.py 64 | -------------------------------------------------------------------------------- /templates/testfb.html: -------------------------------------------------------------------------------- 1 | {% extends 'base.html' %} 2 | {% block content %} 3 | 5 | 7 | 35 | 36 | 37 | {% endblock %} 38 | -------------------------------------------------------------------------------- /facebook/djangofb/default_app/views.py: -------------------------------------------------------------------------------- 1 | from django.http import HttpResponse 2 | from django.views.generic.simple import direct_to_template 3 | #uncomment the following two lines and the one below 4 | #if you dont want to use a decorator instead of the middleware 5 | #from django.utils.decorators import decorator_from_middleware 6 | #from facebook.djangofb import FacebookMiddleware 7 | 8 | # Import the Django helpers 9 | import facebook.djangofb as facebook 10 | 11 | # The User model defined in models.py 12 | from models import User 13 | 14 | # We'll require login for our canvas page. This 15 | # isn't necessarily a good idea, as we might want 16 | # to let users see the page without granting our app 17 | # access to their info. See the wiki for details on how 18 | # to do this. 19 | #@decorator_from_middleware(FacebookMiddleware) 20 | @facebook.require_login() 21 | def canvas(request): 22 | # Get the User object for the currently logged in user 23 | user = User.objects.get_current() 24 | 25 | # Check if we were POSTed the user's new language of choice 26 | if 'language' in request.POST: 27 | user.language = request.POST['language'][:64] 28 | user.save() 29 | 30 | # User is guaranteed to be logged in, so pass canvas.fbml 31 | # an extra 'fbuser' parameter that is the User object for 32 | # the currently logged in user. 33 | return direct_to_template(request, 'canvas.fbml', extra_context={'fbuser': user}) 34 | 35 | @facebook.require_login() 36 | def ajax(request): 37 | return HttpResponse('hello world') 38 | -------------------------------------------------------------------------------- /static/blueprint/plugins/link-icons/screen.css: -------------------------------------------------------------------------------- 1 | /* -------------------------------------------------------------- 2 | 3 | link-icons.css 4 | * Icons for links based on protocol or file type. 5 | 6 | See the Readme file in this folder for additional instructions. 7 | 8 | -------------------------------------------------------------- */ 9 | 10 | /* Use this class if a link gets an icon when it shouldn't. */ 11 | body a.noicon { 12 | background:transparent none !important; 13 | padding:0 !important; 14 | margin:0 !important; 15 | } 16 | 17 | /* Make sure the icons are not cut */ 18 | a[href^="http:"], a[href^="mailto:"], a[href^="http:"]:visited, 19 | a[href$=".pdf"], a[href$=".doc"], a[href$=".xls"], a[href$=".rss"], 20 | a[href$=".rdf"], a[href^="aim:"] { 21 | padding:2px 22px 2px 0; 22 | margin:-2px 0; 23 | background-repeat: no-repeat; 24 | background-position: right center; 25 | } 26 | 27 | /* External links */ 28 | a[href^="http:"] { background-image: url(icons/external.png); } 29 | a[href^="mailto:"] { background-image: url(icons/email.png); } 30 | a[href^="http:"]:visited { background-image: url(icons/visited.png); } 31 | 32 | /* Files */ 33 | a[href$=".pdf"] { background-image: url(icons/pdf.png); } 34 | a[href$=".doc"] { background-image: url(icons/doc.png); } 35 | a[href$=".xls"] { background-image: url(icons/xls.png); } 36 | 37 | /* Misc */ 38 | a[href$=".rss"], 39 | a[href$=".rdf"] { background-image: url(icons/feed.png); } 40 | a[href^="aim:"] { background-image: url(icons/im.png); } -------------------------------------------------------------------------------- /cron.py: -------------------------------------------------------------------------------- 1 | from google.appengine.ext import webapp 2 | from google.appengine.ext import db 3 | from google.appengine.ext.webapp import util 4 | from models import * 5 | from google.appengine.api import memcache 6 | 7 | import base 8 | import analysis 9 | 10 | class CronProbsHandler(base.BaseRequestHandler): 11 | def get(self): 12 | 13 | last_emotion_index = memcache.get('last_cron_emotion_index') 14 | 15 | if last_emotion_index is None: 16 | memcache.set('last_cron_emotion_index', 0, 3600 * 24) 17 | last_emotion_index = 0 18 | 19 | emotion = ['senang','sedih','marah','malu', 20 | 'jijik','takut','bersalah'] 21 | 22 | if Keyword.generate_probs_cache(emotion[last_emotion_index]): 23 | self.response.out.write("Ok => %s" % (emotion[last_emotion_index])) 24 | last_emotion_index += 1 25 | if last_emotion_index == 7: 26 | last_emotion_index = 0 27 | memcache.set('last_cron_emotion_index', last_emotion_index, 3600 * 24) 28 | 29 | 30 | 31 | 32 | class CronWordsHandler(base.BaseRequestHandler): 33 | def get(self): 34 | Keyword.generate_list_cache() 35 | #analysis.trainning_smiley() 36 | self.response.out.write("Ok") 37 | 38 | def main(): 39 | application = webapp.WSGIApplication([ 40 | (r'/cron-probs.php',CronProbsHandler), 41 | (r'/cron-words.php',CronWordsHandler) 42 | ],debug=True) 43 | 44 | util.run_wsgi_app(application) 45 | 46 | if __name__ == '__main__': 47 | main() 48 | -------------------------------------------------------------------------------- /graph.py: -------------------------------------------------------------------------------- 1 | from google.appengine.ext import webapp 2 | from google.appengine.ext import db 3 | from google.appengine.ext.webapp import util 4 | from google.appengine.api import urlfetch 5 | from google.appengine.api import memcache 6 | from models import * 7 | from analysis import * 8 | 9 | import base 10 | 11 | class IndexHander(base.FacebookConnectHandler): 12 | 13 | def connected(self): 14 | self.redirect('/graph/emotion/%d.php' % self.user.uid) 15 | 16 | class CheckEmotionHandler(base.FacebookConnectHandler): 17 | def connected(self,uid = None): 18 | uid = int(uid) 19 | try: 20 | 21 | friends = get_fbfriends_cache(self.facebook,1000) 22 | states = get_fbstates_cache(self.facebook,uid) 23 | chart = get_chart(states) 24 | 25 | self.render('graph/emotion.html',{'states':states, 26 | 'friends':friends, 27 | 'user':self.user, 28 | 'uid':uid, 29 | 'chart':chart}) 30 | except urlfetch.DownloadError: 31 | self.render('error/download.html',{'uri': self.request.uri}) 32 | 33 | def post(self,uid = None): 34 | uid = self.request.get('uid') 35 | self.redirect('/graph/emotion/%s.php' % uid) 36 | 37 | def main(): 38 | application = webapp.WSGIApplication([ 39 | (r'/graph/index.php',IndexHander), 40 | (r'/graph/emotion/(?P\d+).php',CheckEmotionHandler), 41 | (r'/graph/emotion.php',CheckEmotionHandler), 42 | ],debug=True) 43 | 44 | util.run_wsgi_app(application) 45 | 46 | if __name__ == '__main__': 47 | main() 48 | -------------------------------------------------------------------------------- /templates/trainning/smiley.html: -------------------------------------------------------------------------------- 1 | {% extends '../base.html' %} 2 | {% block content%} 3 | 4 |
5 |
6 | Smiley | Custome Keyword 7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 | 16 |

17 | 18 |

List of Smiley/Custume Keyword

19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | {% for smiley in smiles %} 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 49 | 50 | {% endfor %} 51 | 52 | 53 |
IdsmileysenangsedihtakutmarahjijikmalubersalahAction
{{smiley.key.id}}{{smiley.word}}{{smiley.senang}}{{smiley.sedih}}{{smiley.takut}}{{smiley.marah}}{{smiley.jijik}}{{smiley.malu}}{{smiley.bersalah}} 47 | delete 48 |
54 | 55 | {% endblock%} 56 | 57 | -------------------------------------------------------------------------------- /templates/trainning/status.html: -------------------------------------------------------------------------------- 1 | {% extends 'index.html' %} 2 | {% block content%} 3 |
4 |

5 | Trainning Status - 6 | 7 |

8 |
9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | {% for status in states %} 18 | 19 | 23 | 35 | 36 | {% endfor %} 37 | 38 | 39 | 40 | 41 | 42 | 43 |
MessageCategory
20 | {{status.message}} 21 | 22 | 24 | 34 |
44 |
45 |
46 | 47 |

48 | 49 | 50 | {% endblock%} 51 | 52 | 53 | -------------------------------------------------------------------------------- /templates/graph/index.html: -------------------------------------------------------------------------------- 1 | {% extends '../base.html' %} 2 | {% block addscript %} 3 | 4 | 10 | {% endblock %} 11 | 12 | {% block content %} 13 | 14 |

15 | Emotion Graph - 16 |

17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | {% for status in states %} 28 | 29 | 32 | 35 | 36 | {% endfor %} 37 | 38 |
MessageEmotion Result
30 | {{status.message}} 31 | 33 | {{status.emotion}} 34 |
39 | {% endblock %} 40 | 41 | {% block sidebar %} 42 | 43 |
44 | 56 | 57 |
58 | {% endblock %} 59 | -------------------------------------------------------------------------------- /static/blueprint/ie.css: -------------------------------------------------------------------------------- 1 | /* ----------------------------------------------------------------------- 2 | 3 | 4 | Blueprint CSS Framework 0.9 5 | http://blueprintcss.org 6 | 7 | * Copyright (c) 2007-Present. See LICENSE for more info. 8 | * See README for instructions on how to use Blueprint. 9 | * For credits and origins, see AUTHORS. 10 | * This is a compressed file. See the sources in the 'src' directory. 11 | 12 | ----------------------------------------------------------------------- */ 13 | 14 | /* ie.css */ 15 | body {text-align:center;} 16 | .container {text-align:left;} 17 | * html .column, * html div.span-1, * html div.span-2, * html div.span-3, * html div.span-4, * html div.span-5, * html div.span-6, * html div.span-7, * html div.span-8, * html div.span-9, * html div.span-10, * html div.span-11, * html div.span-12, * html div.span-13, * html div.span-14, * html div.span-15, * html div.span-16, * html div.span-17, * html div.span-18, * html div.span-19, * html div.span-20, * html div.span-21, * html div.span-22, * html div.span-23, * html div.span-24 {display:inline;overflow-x:hidden;} 18 | * html legend {margin:0px -8px 16px 0;padding:0;} 19 | sup {vertical-align:text-top;} 20 | sub {vertical-align:text-bottom;} 21 | html>body p code {*white-space:normal;} 22 | hr {margin:-8px auto 11px;} 23 | img {-ms-interpolation-mode:bicubic;} 24 | .clearfix, .container {display:inline-block;} 25 | * html .clearfix, * html .container {height:1%;} 26 | fieldset {padding-top:0;} 27 | textarea {overflow:auto;} 28 | input.text, input.title, textarea {background-color:#fff;border:1px solid #bbb;} 29 | input.text:focus, input.title:focus {border-color:#666;} 30 | input.text, input.title, textarea, select {margin:0.5em 0;} 31 | input.checkbox, input.radio {position:relative;top:.25em;} 32 | form.inline div, form.inline p {vertical-align:middle;} 33 | form.inline label {position:relative;top:-0.25em;} 34 | form.inline input.checkbox, form.inline input.radio, form.inline input.button, form.inline button {margin:0.5em 0;} 35 | button, input.button {position:relative;top:0.25em;} -------------------------------------------------------------------------------- /static/blueprint/src/forms.css: -------------------------------------------------------------------------------- 1 | /* -------------------------------------------------------------- 2 | 3 | forms.css 4 | * Sets up some default styling for forms 5 | * Gives you classes to enhance your forms 6 | 7 | Usage: 8 | * For text fields, use class .title or .text 9 | * For inline forms, use .inline (even when using columns) 10 | 11 | -------------------------------------------------------------- */ 12 | 13 | label { font-weight: bold; } 14 | fieldset { padding:1.4em; margin: 0 0 1.5em 0; border: 1px solid #ccc; } 15 | legend { font-weight: bold; font-size:1.2em; } 16 | 17 | 18 | /* Form fields 19 | -------------------------------------------------------------- */ 20 | 21 | input[type=text], input[type=password], 22 | input.text, input.title, 23 | textarea, select { 24 | background-color:#fff; 25 | border:1px solid #bbb; 26 | } 27 | input[type=text]:focus, input[type=password]:focus, 28 | input.text:focus, input.title:focus, 29 | textarea:focus, select:focus { 30 | border-color:#666; 31 | } 32 | 33 | input[type=text], input[type=password], 34 | input.text, input.title, 35 | textarea, select { 36 | margin:0.5em 0; 37 | } 38 | 39 | input.text, 40 | input.title { width: 300px; padding:5px; } 41 | input.title { font-size:1.5em; } 42 | textarea { width: 390px; height: 250px; padding:5px; } 43 | 44 | input[type=checkbox], input[type=radio], 45 | input.checkbox, input.radio { 46 | position:relative; top:.25em; 47 | } 48 | 49 | form.inline { line-height:3; } 50 | form.inline p { margin-bottom:0; } 51 | 52 | 53 | /* Success, notice and error boxes 54 | -------------------------------------------------------------- */ 55 | 56 | .error, 57 | .notice, 58 | .success { padding: .8em; margin-bottom: 1em; border: 2px solid #ddd; } 59 | 60 | .error { background: #FBE3E4; color: #8a1f11; border-color: #FBC2C4; } 61 | .notice { background: #FFF6BF; color: #514721; border-color: #FFD324; } 62 | .success { background: #E6EFC2; color: #264409; border-color: #C6D880; } 63 | .error a { color: #8a1f11; } 64 | .notice a { color: #514721; } 65 | .success a { color: #264409; } 66 | -------------------------------------------------------------------------------- /static/blueprint/src/print.css: -------------------------------------------------------------------------------- 1 | /* -------------------------------------------------------------- 2 | 3 | print.css 4 | * Gives you some sensible styles for printing pages. 5 | * See Readme file in this directory for further instructions. 6 | 7 | Some additions you'll want to make, customized to your markup: 8 | #header, #footer, #navigation { display:none; } 9 | 10 | -------------------------------------------------------------- */ 11 | 12 | body { 13 | line-height: 1.5; 14 | font-family: "Helvetica Neue", Arial, Helvetica, sans-serif; 15 | color:#000; 16 | background: none; 17 | font-size: 10pt; 18 | } 19 | 20 | 21 | /* Layout 22 | -------------------------------------------------------------- */ 23 | 24 | .container { 25 | background: none; 26 | } 27 | 28 | hr { 29 | background:#ccc; 30 | color:#ccc; 31 | width:100%; 32 | height:2px; 33 | margin:2em 0; 34 | padding:0; 35 | border:none; 36 | } 37 | hr.space { 38 | background: #fff; 39 | color: #fff; 40 | visibility: hidden; 41 | } 42 | 43 | 44 | /* Text 45 | -------------------------------------------------------------- */ 46 | 47 | h1,h2,h3,h4,h5,h6 { font-family: "Helvetica Neue", Arial, "Lucida Grande", sans-serif; } 48 | code { font:.9em "Courier New", Monaco, Courier, monospace; } 49 | 50 | a img { border:none; } 51 | p img.top { margin-top: 0; } 52 | 53 | blockquote { 54 | margin:1.5em; 55 | padding:1em; 56 | font-style:italic; 57 | font-size:.9em; 58 | } 59 | 60 | .small { font-size: .9em; } 61 | .large { font-size: 1.1em; } 62 | .quiet { color: #999; } 63 | .hide { display:none; } 64 | 65 | 66 | /* Links 67 | -------------------------------------------------------------- */ 68 | 69 | a:link, a:visited { 70 | background: transparent; 71 | font-weight:700; 72 | text-decoration: underline; 73 | } 74 | 75 | a:link:after, a:visited:after { 76 | content: " (" attr(href) ")"; 77 | font-size: 90%; 78 | } 79 | 80 | /* If you're having trouble printing relative links, uncomment and customize this: 81 | (note: This is valid CSS3, but it still won't go through the W3C CSS Validator) */ 82 | 83 | /* a[href^="/"]:after { 84 | content: " (http://www.yourdomain.com" attr(href) ") "; 85 | } */ 86 | -------------------------------------------------------------------------------- /index.yaml: -------------------------------------------------------------------------------- 1 | indexes: 2 | 3 | # AUTOGENERATED 4 | 5 | # This index.yaml is automatically updated whenever the dev_appserver 6 | # detects that a new type of query is run. If you want to manage the 7 | # index.yaml file manually, remove the above marker line (the line 8 | # saying "# AUTOGENERATED"). If you want to manage some indexes 9 | # manually, move them above the marker line. The index.yaml file is 10 | # automatically uploaded to the admin console when you next deploy 11 | # your application using appcfg.py. 12 | 13 | - kind: Keyword 14 | properties: 15 | - name: __key__ 16 | direction: desc 17 | 18 | - kind: Keyword 19 | properties: 20 | - name: valid 21 | - name: bersalah 22 | 23 | - kind: Keyword 24 | properties: 25 | - name: valid 26 | - name: bersalah 27 | direction: desc 28 | 29 | - kind: Keyword 30 | properties: 31 | - name: valid 32 | - name: jijik 33 | 34 | - kind: Keyword 35 | properties: 36 | - name: valid 37 | - name: jijik 38 | direction: desc 39 | 40 | - kind: Keyword 41 | properties: 42 | - name: valid 43 | - name: malu 44 | 45 | - kind: Keyword 46 | properties: 47 | - name: valid 48 | - name: malu 49 | direction: desc 50 | 51 | - kind: Keyword 52 | properties: 53 | - name: valid 54 | - name: marah 55 | 56 | - kind: Keyword 57 | properties: 58 | - name: valid 59 | - name: marah 60 | direction: desc 61 | 62 | - kind: Keyword 63 | properties: 64 | - name: valid 65 | - name: sedih 66 | 67 | - kind: Keyword 68 | properties: 69 | - name: valid 70 | - name: sedih 71 | direction: desc 72 | 73 | - kind: Keyword 74 | properties: 75 | - name: valid 76 | - name: senang 77 | 78 | - kind: Keyword 79 | properties: 80 | - name: valid 81 | - name: senang 82 | direction: desc 83 | 84 | - kind: Keyword 85 | properties: 86 | - name: valid 87 | - name: takut 88 | 89 | - kind: Keyword 90 | properties: 91 | - name: valid 92 | - name: takut 93 | direction: desc 94 | 95 | - kind: Keyword 96 | properties: 97 | - name: valid 98 | - name: word 99 | 100 | - kind: Keyword 101 | properties: 102 | - name: valid 103 | - name: word 104 | direction: desc 105 | -------------------------------------------------------------------------------- /templates/iframefb.html: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | Emo Graph - {% block title %}{% endblock %} 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 27 | 30 |
31 |
32 | {% block content %} 33 |

This is content

34 | {% endblock %} 35 |
36 | 37 | 40 |
41 |
42 | 45 |
46 | 47 | 48 | -------------------------------------------------------------------------------- /static/blueprint/plugins/buttons/screen.css: -------------------------------------------------------------------------------- 1 | /* -------------------------------------------------------------- 2 | 3 | buttons.css 4 | * Gives you some great CSS-only buttons. 5 | 6 | Created by Kevin Hale [particletree.com] 7 | * particletree.com/features/rediscovering-the-button-element 8 | 9 | See Readme.txt in this folder for instructions. 10 | 11 | -------------------------------------------------------------- */ 12 | 13 | a.button, button { 14 | display:block; 15 | float:left; 16 | margin: 0.7em 0.5em 0.7em 0; 17 | padding:5px 10px 5px 7px; /* Links */ 18 | 19 | border:1px solid #dedede; 20 | border-top:1px solid #eee; 21 | border-left:1px solid #eee; 22 | 23 | background-color:#f5f5f5; 24 | font-family:"Lucida Grande", Tahoma, Arial, Verdana, sans-serif; 25 | font-size:100%; 26 | line-height:130%; 27 | text-decoration:none; 28 | font-weight:bold; 29 | color:#565656; 30 | cursor:pointer; 31 | } 32 | button { 33 | width:auto; 34 | overflow:visible; 35 | padding:4px 10px 3px 7px; /* IE6 */ 36 | } 37 | button[type] { 38 | padding:4px 10px 4px 7px; /* Firefox */ 39 | line-height:17px; /* Safari */ 40 | } 41 | *:first-child+html button[type] { 42 | padding:4px 10px 3px 7px; /* IE7 */ 43 | } 44 | button img, a.button img{ 45 | margin:0 3px -3px 0 !important; 46 | padding:0; 47 | border:none; 48 | width:16px; 49 | height:16px; 50 | float:none; 51 | } 52 | 53 | 54 | /* Button colors 55 | -------------------------------------------------------------- */ 56 | 57 | /* Standard */ 58 | button:hover, a.button:hover{ 59 | background-color:#dff4ff; 60 | border:1px solid #c2e1ef; 61 | color:#336699; 62 | } 63 | a.button:active{ 64 | background-color:#6299c5; 65 | border:1px solid #6299c5; 66 | color:#fff; 67 | } 68 | 69 | /* Positive */ 70 | body .positive { 71 | color:#529214; 72 | } 73 | a.positive:hover, button.positive:hover { 74 | background-color:#E6EFC2; 75 | border:1px solid #C6D880; 76 | color:#529214; 77 | } 78 | a.positive:active { 79 | background-color:#529214; 80 | border:1px solid #529214; 81 | color:#fff; 82 | } 83 | 84 | /* Negative */ 85 | body .negative { 86 | color:#d12f19; 87 | } 88 | a.negative:hover, button.negative:hover { 89 | background-color:#fbe3e4; 90 | border:1px solid #fbc2c4; 91 | color:#d12f19; 92 | } 93 | a.negative:active { 94 | background-color:#d12f19; 95 | border:1px solid #d12f19; 96 | color:#fff; 97 | } 98 | -------------------------------------------------------------------------------- /static/blueprint/plugins/fancy-type/screen.css: -------------------------------------------------------------------------------- 1 | /* -------------------------------------------------------------- 2 | 3 | fancy-type.css 4 | * Lots of pretty advanced classes for manipulating text. 5 | 6 | See the Readme file in this folder for additional instructions. 7 | 8 | -------------------------------------------------------------- */ 9 | 10 | /* Indentation instead of line shifts for sibling paragraphs. */ 11 | p + p { text-indent:2em; margin-top:-1.5em; } 12 | form p + p { text-indent: 0; } /* Don't want this in forms. */ 13 | 14 | 15 | /* For great looking type, use this code instead of asdf: 16 | asdf 17 | Best used on prepositions and ampersands. */ 18 | 19 | .alt { 20 | color: #666; 21 | font-family: "Warnock Pro", "Goudy Old Style","Palatino","Book Antiqua", Georgia, serif; 22 | font-style: italic; 23 | font-weight: normal; 24 | } 25 | 26 | 27 | /* For great looking quote marks in titles, replace "asdf" with: 28 | asdf” 29 | (That is, when the title starts with a quote mark). 30 | (You may have to change this value depending on your font size). */ 31 | 32 | .dquo { margin-left: -.5em; } 33 | 34 | 35 | /* Reduced size type with incremental leading 36 | (http://www.markboulton.co.uk/journal/comments/incremental_leading/) 37 | 38 | This could be used for side notes. For smaller type, you don't necessarily want to 39 | follow the 1.5x vertical rhythm -- the line-height is too much. 40 | 41 | Using this class, it reduces your font size and line-height so that for 42 | every four lines of normal sized type, there is five lines of the sidenote. eg: 43 | 44 | New type size in em's: 45 | 10px (wanted side note size) / 12px (existing base size) = 0.8333 (new type size in ems) 46 | 47 | New line-height value: 48 | 12px x 1.5 = 18px (old line-height) 49 | 18px x 4 = 72px 50 | 72px / 5 = 14.4px (new line height) 51 | 14.4px / 10px = 1.44 (new line height in em's) */ 52 | 53 | p.incr, .incr p { 54 | font-size: 10px; 55 | line-height: 1.44em; 56 | margin-bottom: 1.5em; 57 | } 58 | 59 | 60 | /* Surround uppercase words and abbreviations with this class. 61 | Based on work by Jørgen Arnor Gårdsø Lom [http://twistedintellect.com/] */ 62 | 63 | .caps { 64 | font-variant: small-caps; 65 | letter-spacing: 1px; 66 | text-transform: lowercase; 67 | font-size:1.2em; 68 | line-height:1%; 69 | font-weight:bold; 70 | padding:0 2px; 71 | } 72 | -------------------------------------------------------------------------------- /templates/trainning/index.html: -------------------------------------------------------------------------------- 1 | {% extends '../base.html' %} 2 | 3 | {% block addscript %} 4 | 5 | 11 | {% endblock %} 12 | 13 | {% block content %} 14 | 15 | 16 |

Graph result Trainning without Uncategory

17 | 18 |
19 |
20 |
21 |
22 |
23 |

Graph result Trainning with Uncategory

24 | 25 |
26 |
27 |
28 |
29 |
30 | 31 |
32 |

Static Trainning

33 | Total Trainning: {{static.total}}
34 | senang: {{static.senang}}
35 | sedih: {{static.sedih}}
36 | marah: {{static.marah}}
37 | jijik: {{static.jijik}}
38 | malu: {{static.malu}}
39 | takut: {{static.takut}}
40 | bersalah: {{static.bersalah}}
41 | uncategory: {{static.uncategory}} 42 |
43 | 44 | 45 | {% endblock %} 46 | 47 | {% block sidebar %} 48 | 49 | 50 |
51 | 63 | 64 |
65 |
66 |
67 |
68 |
69 |

Static Trainning

70 | Total Trainning: {{static.total}}
71 | senang: {{static.senang}}
72 | sedih: {{static.sedih}}
73 | marah: {{static.marah}}
74 | jijik: {{static.jijik}}
75 | malu: {{static.malu}}
76 | takut: {{static.takut}}
77 | bersalah: {{static.bersalah}}
78 | uncategory: {{static.uncategory}} 79 |
80 | 81 | 82 | {% endblock %} 83 | -------------------------------------------------------------------------------- /static/js/sound.js: -------------------------------------------------------------------------------- 1 | // script.aculo.us sound.js v1.8.3, Thu Oct 08 11:23:33 +0200 2009 2 | 3 | // Copyright (c) 2005-2009 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us) 4 | // 5 | // Based on code created by Jules Gravinese (http://www.webveteran.com/) 6 | // 7 | // script.aculo.us is freely distributable under the terms of an MIT-style license. 8 | // For details, see the script.aculo.us web site: http://script.aculo.us/ 9 | 10 | Sound = { 11 | tracks: {}, 12 | _enabled: true, 13 | template: 14 | new Template(''), 15 | enable: function(){ 16 | Sound._enabled = true; 17 | }, 18 | disable: function(){ 19 | Sound._enabled = false; 20 | }, 21 | play: function(url){ 22 | if(!Sound._enabled) return; 23 | var options = Object.extend({ 24 | track: 'global', url: url, replace: false 25 | }, arguments[1] || {}); 26 | 27 | if(options.replace && this.tracks[options.track]) { 28 | $R(0, this.tracks[options.track].id).each(function(id){ 29 | var sound = $('sound_'+options.track+'_'+id); 30 | sound.Stop && sound.Stop(); 31 | sound.remove(); 32 | }); 33 | this.tracks[options.track] = null; 34 | } 35 | 36 | if(!this.tracks[options.track]) 37 | this.tracks[options.track] = { id: 0 }; 38 | else 39 | this.tracks[options.track].id++; 40 | 41 | options.id = this.tracks[options.track].id; 42 | $$('body')[0].insert( 43 | Prototype.Browser.IE ? new Element('bgsound',{ 44 | id: 'sound_'+options.track+'_'+options.id, 45 | src: options.url, loop: 1, autostart: true 46 | }) : Sound.template.evaluate(options)); 47 | } 48 | }; 49 | 50 | if(Prototype.Browser.Gecko && navigator.userAgent.indexOf("Win") > 0){ 51 | if(navigator.plugins && $A(navigator.plugins).detect(function(p){ return p.name.indexOf('QuickTime') != -1 })) 52 | Sound.template = new Template(''); 53 | else if(navigator.plugins && $A(navigator.plugins).detect(function(p){ return p.name.indexOf('Windows Media') != -1 })) 54 | Sound.template = new Template(''); 55 | else if(navigator.plugins && $A(navigator.plugins).detect(function(p){ return p.name.indexOf('RealPlayer') != -1 })) 56 | Sound.template = new Template(''); 57 | else 58 | Sound.play = function(){}; 59 | } -------------------------------------------------------------------------------- /templates/shell.html: -------------------------------------------------------------------------------- 1 | {% extends 'base.html' %} 2 | 3 | {% block addscript %} 4 | 5 | 61 | {% endblock %} 62 | 63 | 64 | {% block content %} 65 | 66 |

Interactive server-side Python shell for 67 | Google App Engine. 68 | (source) 69 |

70 | 71 | 75 | 76 |
77 | 78 | 81 | 82 | 84 | 85 | 86 | 87 |
88 | 89 |

90 |
91 | 92 | 95 | {% endblock %} 96 | 97 | -------------------------------------------------------------------------------- /static/blueprint/src/ie.css: -------------------------------------------------------------------------------- 1 | /* -------------------------------------------------------------- 2 | 3 | ie.css 4 | 5 | Contains every hack for Internet Explorer, 6 | so that our core files stay sweet and nimble. 7 | 8 | -------------------------------------------------------------- */ 9 | 10 | /* Make sure the layout is centered in IE5 */ 11 | body { text-align: center; } 12 | .container { text-align: left; } 13 | 14 | /* Fixes IE margin bugs */ 15 | * html .column, * html div.span-1, * html div.span-2, 16 | * html div.span-3, * html div.span-4, * html div.span-5, 17 | * html div.span-6, * html div.span-7, * html div.span-8, 18 | * html div.span-9, * html div.span-10, * html div.span-11, 19 | * html div.span-12, * html div.span-13, * html div.span-14, 20 | * html div.span-15, * html div.span-16, * html div.span-17, 21 | * html div.span-18, * html div.span-19, * html div.span-20, 22 | * html div.span-21, * html div.span-22, * html div.span-23, 23 | * html div.span-24 { display:inline; overflow-x: hidden; } 24 | 25 | 26 | /* Elements 27 | -------------------------------------------------------------- */ 28 | 29 | /* Fixes incorrect styling of legend in IE6. */ 30 | * html legend { margin:0px -8px 16px 0; padding:0; } 31 | 32 | /* Fixes wrong line-height on sup/sub in IE. */ 33 | sup { vertical-align:text-top; } 34 | sub { vertical-align:text-bottom; } 35 | 36 | /* Fixes IE7 missing wrapping of code elements. */ 37 | html>body p code { *white-space: normal; } 38 | 39 | /* IE 6&7 has problems with setting proper
margins. */ 40 | hr { margin:-8px auto 11px; } 41 | 42 | /* Explicitly set interpolation, allowing dynamically resized images to not look horrible */ 43 | img { -ms-interpolation-mode:bicubic; } 44 | 45 | /* Clearing 46 | -------------------------------------------------------------- */ 47 | 48 | /* Makes clearfix actually work in IE */ 49 | .clearfix, .container { display:inline-block; } 50 | * html .clearfix, 51 | * html .container { height:1%; } 52 | 53 | 54 | /* Forms 55 | -------------------------------------------------------------- */ 56 | 57 | /* Fixes padding on fieldset */ 58 | fieldset { padding-top:0; } 59 | 60 | /* Makes classic textareas in IE 6 resemble other browsers */ 61 | textarea { overflow:auto; } 62 | 63 | /* Fixes rule that IE 6 ignores */ 64 | input.text, input.title, textarea { background-color:#fff; border:1px solid #bbb; } 65 | input.text:focus, input.title:focus { border-color:#666; } 66 | input.text, input.title, textarea, select { margin:0.5em 0; } 67 | input.checkbox, input.radio { position:relative; top:.25em; } 68 | 69 | /* Fixes alignment of inline form elements */ 70 | form.inline div, form.inline p { vertical-align:middle; } 71 | form.inline label { position:relative;top:-0.25em; } 72 | form.inline input.checkbox, form.inline input.radio, 73 | form.inline input.button, form.inline button { 74 | margin:0.5em 0; 75 | } 76 | button, input.button { position:relative;top:0.25em; } -------------------------------------------------------------------------------- /templates/base.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Emo Graph - {% block title %}{% endblock %} 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 16 | 17 | {% block addscript %} 18 | 23 | {% endblock %} 24 | 25 | 26 | 27 | 28 | 29 |
30 | 35 |
36 | {% ifequal login_label 'logout'%} 37 | {{nickname}} | 38 | {% else %} 39 | Guest User | 40 | {% endifequal %} 41 | {{login_label}} 42 |
43 | {% if admin %} 44 | 53 | {% endif %} 54 |
55 | 56 |
57 | {% block content %} 58 |

This is content

59 | {% endblock %} 60 |
61 | 62 | 67 |
68 |
69 | 72 |
73 | 74 | 75 | -------------------------------------------------------------------------------- /static/js/scriptaculous.js: -------------------------------------------------------------------------------- 1 | // script.aculo.us scriptaculous.js v1.8.3, Thu Oct 08 11:23:33 +0200 2009 2 | 3 | // Copyright (c) 2005-2009 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us) 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining 6 | // a copy of this software and associated documentation files (the 7 | // "Software"), to deal in the Software without restriction, including 8 | // without limitation the rights to use, copy, modify, merge, publish, 9 | // distribute, sublicense, and/or sell copies of the Software, and to 10 | // permit persons to whom the Software is furnished to do so, subject to 11 | // the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be 14 | // included in all copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 19 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 20 | // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 21 | // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 22 | // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 | // 24 | // For details, see the script.aculo.us web site: http://script.aculo.us/ 25 | 26 | var Scriptaculous = { 27 | Version: '1.8.3', 28 | require: function(libraryName) { 29 | try{ 30 | // inserting via DOM fails in Safari 2.0, so brute force approach 31 | document.write('' % url) 29 | else: 30 | return HttpResponseRedirect(url) 31 | 32 | 33 | def get_facebook_client(): 34 | """ 35 | Get the current Facebook object for the calling thread. 36 | 37 | """ 38 | try: 39 | return _thread_locals.facebook 40 | except AttributeError: 41 | raise ImproperlyConfigured('Make sure you have the Facebook middleware installed.') 42 | 43 | 44 | def require_login(next=None, internal=None): 45 | """ 46 | Decorator for Django views that requires the user to be logged in. 47 | The FacebookMiddleware must be installed. 48 | 49 | Standard usage: 50 | @require_login() 51 | def some_view(request): 52 | ... 53 | 54 | Redirecting after login: 55 | To use the 'next' parameter to redirect to a specific page after login, a callable should 56 | return a path relative to the Post-add URL. 'next' can also be an integer specifying how many 57 | parts of request.path to strip to find the relative URL of the canvas page. If 'next' is None, 58 | settings.callback_path and settings.app_name are checked to redirect to the same page after logging 59 | in. (This is the default behavior.) 60 | @require_login(next=some_callable) 61 | def some_view(request): 62 | ... 63 | """ 64 | def decorator(view): 65 | def newview(request, *args, **kwargs): 66 | next = newview.next 67 | internal = newview.internal 68 | 69 | try: 70 | fb = request.facebook 71 | except: 72 | raise ImproperlyConfigured('Make sure you have the Facebook middleware installed.') 73 | 74 | if internal is None: 75 | internal = request.facebook.internal 76 | 77 | if callable(next): 78 | next = next(request.path) 79 | elif isinstance(next, int): 80 | next = '/'.join(request.path.split('/')[next + 1:]) 81 | elif next is None and fb.callback_path and request.path.startswith(fb.callback_path): 82 | next = request.path[len(fb.callback_path):] 83 | elif not isinstance(next, str): 84 | next = '' 85 | 86 | if not fb.check_session(request): 87 | #If user has never logged in before, the get_login_url will redirect to the TOS page 88 | return fb.redirect(fb.get_login_url(next=next)) 89 | 90 | if internal and request.method == 'GET' and fb.app_name: 91 | return fb.redirect('%s%s' % (fb.get_app_url(), next)) 92 | 93 | return view(request, *args, **kwargs) 94 | newview.next = next 95 | newview.internal = internal 96 | return newview 97 | return decorator 98 | 99 | 100 | def require_add(next=None, internal=None, on_install=None): 101 | """ 102 | Decorator for Django views that requires application installation. 103 | The FacebookMiddleware must be installed. 104 | 105 | Standard usage: 106 | @require_add() 107 | def some_view(request): 108 | ... 109 | 110 | Redirecting after installation: 111 | To use the 'next' parameter to redirect to a specific page after login, a callable should 112 | return a path relative to the Post-add URL. 'next' can also be an integer specifying how many 113 | parts of request.path to strip to find the relative URL of the canvas page. If 'next' is None, 114 | settings.callback_path and settings.app_name are checked to redirect to the same page after logging 115 | in. (This is the default behavior.) 116 | @require_add(next=some_callable) 117 | def some_view(request): 118 | ... 119 | 120 | Post-install processing: 121 | Set the on_install parameter to a callable in order to handle special post-install processing. 122 | The callable should take a request object as the parameter. 123 | @require_add(on_install=some_callable) 124 | def some_view(request): 125 | ... 126 | """ 127 | def decorator(view): 128 | def newview(request, *args, **kwargs): 129 | next = newview.next 130 | internal = newview.internal 131 | 132 | try: 133 | fb = request.facebook 134 | except: 135 | raise ImproperlyConfigured('Make sure you have the Facebook middleware installed.') 136 | 137 | if internal is None: 138 | internal = request.facebook.internal 139 | 140 | if callable(next): 141 | next = next(request.path) 142 | elif isinstance(next, int): 143 | next = '/'.join(request.path.split('/')[next + 1:]) 144 | elif next is None and fb.callback_path and request.path.startswith(fb.callback_path): 145 | next = request.path[len(fb.callback_path):] 146 | else: 147 | next = '' 148 | 149 | if not fb.check_session(request): 150 | if fb.added: 151 | if request.method == 'GET' and fb.app_name: 152 | return fb.redirect('%s%s' % (fb.get_app_url(), next)) 153 | return fb.redirect(fb.get_login_url(next=next)) 154 | else: 155 | return fb.redirect(fb.get_add_url(next=next)) 156 | 157 | if not fb.added: 158 | return fb.redirect(fb.get_add_url(next=next)) 159 | 160 | if 'installed' in request.GET and callable(on_install): 161 | on_install(request) 162 | 163 | if internal and request.method == 'GET' and fb.app_name: 164 | return fb.redirect('%s%s' % (fb.get_app_url(), next)) 165 | 166 | return view(request, *args, **kwargs) 167 | newview.next = next 168 | newview.internal = internal 169 | return newview 170 | return decorator 171 | 172 | # try to preserve the argspecs 173 | try: 174 | import decorator 175 | except ImportError: 176 | pass 177 | else: 178 | def updater(f): 179 | def updated(*args, **kwargs): 180 | original = f(*args, **kwargs) 181 | def newdecorator(view): 182 | return decorator.new_wrapper(original(view), view) 183 | return decorator.new_wrapper(newdecorator, original) 184 | return decorator.new_wrapper(updated, f) 185 | require_login = updater(require_login) 186 | require_add = updater(require_add) 187 | 188 | class FacebookMiddleware(object): 189 | """ 190 | Middleware that attaches a Facebook object to every incoming request. 191 | The Facebook object created can also be accessed from models for the 192 | current thread by using get_facebook_client(). 193 | 194 | """ 195 | 196 | def __init__(self, api_key=None, secret_key=None, app_name=None, callback_path=None, internal=None): 197 | self.api_key = api_key or settings.FACEBOOK_API_KEY 198 | self.secret_key = secret_key or settings.FACEBOOK_SECRET_KEY 199 | self.app_name = app_name or getattr(settings, 'FACEBOOK_APP_NAME', None) 200 | self.callback_path = callback_path or getattr(settings, 'FACEBOOK_CALLBACK_PATH', None) 201 | self.internal = internal or getattr(settings, 'FACEBOOK_INTERNAL', True) 202 | self.proxy = None 203 | if getattr(settings, 'USE_HTTP_PROXY', False): 204 | self.proxy = settings.HTTP_PROXY 205 | 206 | def process_request(self, request): 207 | _thread_locals.facebook = request.facebook = Facebook(self.api_key, self.secret_key, app_name=self.app_name, callback_path=self.callback_path, internal=self.internal, proxy=self.proxy) 208 | if not self.internal and 'facebook_session_key' in request.session and 'facebook_user_id' in request.session: 209 | request.facebook.session_key = request.session['facebook_session_key'] 210 | request.facebook.uid = request.session['facebook_user_id'] 211 | 212 | def process_response(self, request, response): 213 | if not self.internal and request.facebook.session_key and request.facebook.uid: 214 | request.session['facebook_session_key'] = request.facebook.session_key 215 | request.session['facebook_user_id'] = request.facebook.uid 216 | return response 217 | -------------------------------------------------------------------------------- /templates/trainning/keyword.html: -------------------------------------------------------------------------------- 1 | {% extends '../base.html' %} 2 | {% block content%} 3 |
4 | 5 | 10 | 11 | 18 | 19 |
20 | 21 | 22 | 23 | 24 | 25 | 39 | 40 | 41 | 42 | 43 | 44 | {% ifequal order 'word'%} 45 | 46 | {% else%}{% ifequal order '-word'%} 47 | 48 | {% else %} 49 | 50 | {% endifequal %}{% endifequal %} 51 | 52 | {% ifequal order 'senang'%} 53 | 54 | {% else %}{% ifequal order '-senang'%} 55 | 56 | {% else %} 57 | 58 | {% endifequal %}{% endifequal %} 59 | 60 | {% ifequal order 'sedih'%} 61 | 62 | {% else %}{% ifequal order '-sedih'%} 63 | 64 | {% else %} 65 | 66 | {% endifequal %}{% endifequal %} 67 | 68 | {% ifequal order 'takut'%} 69 | 70 | {% else %}{% ifequal order '-takut'%} 71 | 72 | {% else %} 73 | 74 | {% endifequal %}{% endifequal %} 75 | 76 | {% ifequal order 'marah'%} 77 | 78 | {% else %}{% ifequal order '-marah'%} 79 | 80 | {% else %} 81 | 82 | {% endifequal %}{% endifequal %} 83 | 84 | {% ifequal order 'jijik'%} 85 | 86 | {% else %}{% ifequal order '-jijik'%} 87 | 88 | {% else %} 89 | 90 | {% endifequal %}{% endifequal %} 91 | 92 | {% ifequal order 'malu'%} 93 | 94 | {% else %}{% ifequal order '-malu'%} 95 | 96 | {% else %} 97 | 98 | {% endifequal %}{% endifequal %} 99 | 100 | {% ifequal order 'bersalah'%} 101 | 102 | {% else %}{% ifequal order '-bersalah'%} 103 | 104 | {% else %} 105 | 106 | {% endifequal %}{% endifequal %} 107 | 108 | 109 | 110 | 111 | 112 | 113 | {% for keyword in keywords %} 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 132 | 133 | {% endfor %} 134 | 135 | 136 | 137 | 138 | 141 | 155 | 156 | 157 | 158 | 161 | 162 | 163 |
26 | {% if first %} 27 | <<prev-{{count}} 28 | {% else %} 29 | <<prev-{{count}} 30 | {% endif %} 31 | | {{current}} | 32 | 33 | {% if last %} 34 | next-{{count}}>> 35 | {% else %} 36 | next-{{count}}>> 37 | {% endif %} 38 |
Idword ↑word ↓wordsenang ↓senang ↑senangsedih ↓sedih ↑sedihtakut ↓takut ↑takutmarah ↓marah ↑marahjijik ↓jijik ↑jijikmalu ↓malu ↑malubersalah ↓bersalah ↑bersalahaction
{{keyword.key.id}}{{keyword.word}}{{keyword.senang}}{{keyword.sedih}}{{keyword.takut}}{{keyword.marah}}{{keyword.jijik}}{{keyword.malu}}{{keyword.bersalah}} 126 | {% if keyword.valid %} 127 | invalid 128 | {% else %} 129 | valid 130 | {% endif %} 131 |
139 | 140 | 142 | {% if first %} 143 | <<prev-{{count}} 144 | {% else %} 145 | <<prev-{{count}} 146 | {% endif %} 147 | | {{current}} | 148 | 149 | {% if last %} 150 | next-{{count}}>> 151 | {% else %} 152 | next-{{count}}>> 153 | {% endif %} 154 |
159 | 160 |
164 | {% endblock%} 165 | 166 | {% block sidebar %} 167 |
168 |

Keyword Stats

169 | Total : {{stats.total.count}} / {{stats.total.sum}}
170 | Senang : {{stats.senang.count}} / {{stats.senang.sum}}
171 | Sedih : {{stats.sedih.count}} / {{stats.sedih.sum}}
172 | Marah : {{stats.marah.count}} / {{stats.marah.sum}}
173 | Malu : {{stats.malu.count}} / {{stats.malu.sum}}
174 | Jijik : {{stats.jijik.count}} / {{stats.jijik.sum}}
175 | takut : {{stats.takut.count}} / {{stats.takut.sum}}
176 | bersalah : {{stats.bersalah.count}} / {{stats.bersalah.sum}}
177 | 178 |
179 | 180 | {% endblock %} 181 | 182 | -------------------------------------------------------------------------------- /static/blueprint/src/grid.css: -------------------------------------------------------------------------------- 1 | /* -------------------------------------------------------------- 2 | grid.css 3 | * Sets up an easy-to-use grid of 24 columns. 4 | 5 | By default, the grid is 950px wide, with 24 columns 6 | spanning 30px, and a 10px margin between columns. 7 | 8 | If you need fewer or more columns, namespaces or semantic 9 | element names, use the compressor script (lib/compress.rb) 10 | 11 | Note: Changes made in this file will not be applied when 12 | using the compressor: make changes in lib/blueprint/grid.css.rb 13 | -------------------------------------------------------------- */ 14 | 15 | /* A container should group all your columns. */ 16 | .container { 17 | width: 950px; 18 | margin: 0 auto; 19 | } 20 | 21 | /* Use this class on any div.span / container to see the grid. */ 22 | .showgrid { 23 | background: url(src/grid.png); 24 | } 25 | 26 | 27 | /* Columns 28 | -------------------------------------------------------------- */ 29 | 30 | /* Sets up basic grid floating and margin. */ 31 | .column, div.span-1, div.span-2, div.span-3, div.span-4, div.span-5, div.span-6, div.span-7, div.span-8, div.span-9, div.span-10, div.span-11, div.span-12, div.span-13, div.span-14, div.span-15, div.span-16, div.span-17, div.span-18, div.span-19, div.span-20, div.span-21, div.span-22, div.span-23, div.span-24 { 32 | float: left; 33 | margin-right: 10px; 34 | } 35 | 36 | /* The last column in a row needs this class. */ 37 | .last, div.last { margin-right: 0; } 38 | 39 | /* Use these classes to set the width of a column. */ 40 | .span-1 {width: 30px;} 41 | 42 | .span-2 {width: 70px;} 43 | .span-3 {width: 110px;} 44 | .span-4 {width: 150px;} 45 | .span-5 {width: 190px;} 46 | .span-6 {width: 230px;} 47 | .span-7 {width: 270px;} 48 | .span-8 {width: 310px;} 49 | .span-9 {width: 350px;} 50 | .span-10 {width: 390px;} 51 | .span-11 {width: 430px;} 52 | .span-12 {width: 470px;} 53 | .span-13 {width: 510px;} 54 | .span-14 {width: 550px;} 55 | .span-15 {width: 590px;} 56 | .span-16 {width: 630px;} 57 | .span-17 {width: 670px;} 58 | .span-18 {width: 710px;} 59 | .span-19 {width: 750px;} 60 | .span-20 {width: 790px;} 61 | .span-21 {width: 830px;} 62 | .span-22 {width: 870px;} 63 | .span-23 {width: 910px;} 64 | .span-24, div.span-24 { width:950px; margin-right:0; } 65 | 66 | /* Use these classes to set the width of an input. */ 67 | input.span-1, textarea.span-1, input.span-2, textarea.span-2, input.span-3, textarea.span-3, input.span-4, textarea.span-4, input.span-5, textarea.span-5, input.span-6, textarea.span-6, input.span-7, textarea.span-7, input.span-8, textarea.span-8, input.span-9, textarea.span-9, input.span-10, textarea.span-10, input.span-11, textarea.span-11, input.span-12, textarea.span-12, input.span-13, textarea.span-13, input.span-14, textarea.span-14, input.span-15, textarea.span-15, input.span-16, textarea.span-16, input.span-17, textarea.span-17, input.span-18, textarea.span-18, input.span-19, textarea.span-19, input.span-20, textarea.span-20, input.span-21, textarea.span-21, input.span-22, textarea.span-22, input.span-23, textarea.span-23, input.span-24, textarea.span-24 { 68 | border-left-width: 1px!important; 69 | border-right-width: 1px!important; 70 | padding-left: 5px!important; 71 | padding-right: 5px!important; 72 | } 73 | 74 | input.span-1, textarea.span-1 { width: 18px!important; } 75 | input.span-2, textarea.span-2 { width: 58px!important; } 76 | input.span-3, textarea.span-3 { width: 98px!important; } 77 | input.span-4, textarea.span-4 { width: 138px!important; } 78 | input.span-5, textarea.span-5 { width: 178px!important; } 79 | input.span-6, textarea.span-6 { width: 218px!important; } 80 | input.span-7, textarea.span-7 { width: 258px!important; } 81 | input.span-8, textarea.span-8 { width: 298px!important; } 82 | input.span-9, textarea.span-9 { width: 338px!important; } 83 | input.span-10, textarea.span-10 { width: 378px!important; } 84 | input.span-11, textarea.span-11 { width: 418px!important; } 85 | input.span-12, textarea.span-12 { width: 458px!important; } 86 | input.span-13, textarea.span-13 { width: 498px!important; } 87 | input.span-14, textarea.span-14 { width: 538px!important; } 88 | input.span-15, textarea.span-15 { width: 578px!important; } 89 | input.span-16, textarea.span-16 { width: 618px!important; } 90 | input.span-17, textarea.span-17 { width: 658px!important; } 91 | input.span-18, textarea.span-18 { width: 698px!important; } 92 | input.span-19, textarea.span-19 { width: 738px!important; } 93 | input.span-20, textarea.span-20 { width: 778px!important; } 94 | input.span-21, textarea.span-21 { width: 818px!important; } 95 | input.span-22, textarea.span-22 { width: 858px!important; } 96 | input.span-23, textarea.span-23 { width: 898px!important; } 97 | input.span-24, textarea.span-24 { width: 938px!important; } 98 | 99 | /* Add these to a column to append empty cols. */ 100 | 101 | .append-1 { padding-right: 40px;} 102 | .append-2 { padding-right: 80px;} 103 | .append-3 { padding-right: 120px;} 104 | .append-4 { padding-right: 160px;} 105 | .append-5 { padding-right: 200px;} 106 | .append-6 { padding-right: 240px;} 107 | .append-7 { padding-right: 280px;} 108 | .append-8 { padding-right: 320px;} 109 | .append-9 { padding-right: 360px;} 110 | .append-10 { padding-right: 400px;} 111 | .append-11 { padding-right: 440px;} 112 | .append-12 { padding-right: 480px;} 113 | .append-13 { padding-right: 520px;} 114 | .append-14 { padding-right: 560px;} 115 | .append-15 { padding-right: 600px;} 116 | .append-16 { padding-right: 640px;} 117 | .append-17 { padding-right: 680px;} 118 | .append-18 { padding-right: 720px;} 119 | .append-19 { padding-right: 760px;} 120 | .append-20 { padding-right: 800px;} 121 | .append-21 { padding-right: 840px;} 122 | .append-22 { padding-right: 880px;} 123 | .append-23 { padding-right: 920px;} 124 | 125 | /* Add these to a column to prepend empty cols. */ 126 | 127 | .prepend-1 { padding-left: 40px;} 128 | .prepend-2 { padding-left: 80px;} 129 | .prepend-3 { padding-left: 120px;} 130 | .prepend-4 { padding-left: 160px;} 131 | .prepend-5 { padding-left: 200px;} 132 | .prepend-6 { padding-left: 240px;} 133 | .prepend-7 { padding-left: 280px;} 134 | .prepend-8 { padding-left: 320px;} 135 | .prepend-9 { padding-left: 360px;} 136 | .prepend-10 { padding-left: 400px;} 137 | .prepend-11 { padding-left: 440px;} 138 | .prepend-12 { padding-left: 480px;} 139 | .prepend-13 { padding-left: 520px;} 140 | .prepend-14 { padding-left: 560px;} 141 | .prepend-15 { padding-left: 600px;} 142 | .prepend-16 { padding-left: 640px;} 143 | .prepend-17 { padding-left: 680px;} 144 | .prepend-18 { padding-left: 720px;} 145 | .prepend-19 { padding-left: 760px;} 146 | .prepend-20 { padding-left: 800px;} 147 | .prepend-21 { padding-left: 840px;} 148 | .prepend-22 { padding-left: 880px;} 149 | .prepend-23 { padding-left: 920px;} 150 | 151 | 152 | /* Border on right hand side of a column. */ 153 | div.border { 154 | padding-right: 4px; 155 | margin-right: 5px; 156 | border-right: 1px solid #eee; 157 | } 158 | 159 | /* Border with more whitespace, spans one column. */ 160 | div.colborder { 161 | padding-right: 24px; 162 | margin-right: 25px; 163 | border-right: 1px solid #eee; 164 | } 165 | 166 | 167 | /* Use these classes on an element to push it into the 168 | next column, or to pull it into the previous column. */ 169 | 170 | 171 | .pull-1 { margin-left: -40px; } 172 | .pull-2 { margin-left: -80px; } 173 | .pull-3 { margin-left: -120px; } 174 | .pull-4 { margin-left: -160px; } 175 | .pull-5 { margin-left: -200px; } 176 | .pull-6 { margin-left: -240px; } 177 | .pull-7 { margin-left: -280px; } 178 | .pull-8 { margin-left: -320px; } 179 | .pull-9 { margin-left: -360px; } 180 | .pull-10 { margin-left: -400px; } 181 | .pull-11 { margin-left: -440px; } 182 | .pull-12 { margin-left: -480px; } 183 | .pull-13 { margin-left: -520px; } 184 | .pull-14 { margin-left: -560px; } 185 | .pull-15 { margin-left: -600px; } 186 | .pull-16 { margin-left: -640px; } 187 | .pull-17 { margin-left: -680px; } 188 | .pull-18 { margin-left: -720px; } 189 | .pull-19 { margin-left: -760px; } 190 | .pull-20 { margin-left: -800px; } 191 | .pull-21 { margin-left: -840px; } 192 | .pull-22 { margin-left: -880px; } 193 | .pull-23 { margin-left: -920px; } 194 | .pull-24 { margin-left: -960px; } 195 | 196 | .pull-1, .pull-2, .pull-3, .pull-4, .pull-5, .pull-6, .pull-7, .pull-8, .pull-9, .pull-10, .pull-11, .pull-12, .pull-13, .pull-14, .pull-15, .pull-16, .pull-17, .pull-18, .pull-19, .pull-20, .pull-21, .pull-22, .pull-23, .pull-24 {float: left; position:relative;} 197 | 198 | 199 | .push-1 { margin: 0 -40px 1.5em 40px; } 200 | .push-2 { margin: 0 -80px 1.5em 80px; } 201 | .push-3 { margin: 0 -120px 1.5em 120px; } 202 | .push-4 { margin: 0 -160px 1.5em 160px; } 203 | .push-5 { margin: 0 -200px 1.5em 200px; } 204 | .push-6 { margin: 0 -240px 1.5em 240px; } 205 | .push-7 { margin: 0 -280px 1.5em 280px; } 206 | .push-8 { margin: 0 -320px 1.5em 320px; } 207 | .push-9 { margin: 0 -360px 1.5em 360px; } 208 | .push-10 { margin: 0 -400px 1.5em 400px; } 209 | .push-11 { margin: 0 -440px 1.5em 440px; } 210 | .push-12 { margin: 0 -480px 1.5em 480px; } 211 | .push-13 { margin: 0 -520px 1.5em 520px; } 212 | .push-14 { margin: 0 -560px 1.5em 560px; } 213 | .push-15 { margin: 0 -600px 1.5em 600px; } 214 | .push-16 { margin: 0 -640px 1.5em 640px; } 215 | .push-17 { margin: 0 -680px 1.5em 680px; } 216 | .push-18 { margin: 0 -720px 1.5em 720px; } 217 | .push-19 { margin: 0 -760px 1.5em 760px; } 218 | .push-20 { margin: 0 -800px 1.5em 800px; } 219 | .push-21 { margin: 0 -840px 1.5em 840px; } 220 | .push-22 { margin: 0 -880px 1.5em 880px; } 221 | .push-23 { margin: 0 -920px 1.5em 920px; } 222 | .push-24 { margin: 0 -960px 1.5em 960px; } 223 | 224 | .push-1, .push-2, .push-3, .push-4, .push-5, .push-6, .push-7, .push-8, .push-9, .push-10, .push-11, .push-12, .push-13, .push-14, .push-15, .push-16, .push-17, .push-18, .push-19, .push-20, .push-21, .push-22, .push-23, .push-24 {float: right; position:relative;} 225 | 226 | 227 | /* Misc classes and elements 228 | -------------------------------------------------------------- */ 229 | 230 | /* In case you need to add a gutter above/below an element */ 231 | .prepend-top { 232 | margin-top:1.5em; 233 | } 234 | .append-bottom { 235 | margin-bottom:1.5em; 236 | } 237 | 238 | /* Use a .box to create a padded box inside a column. */ 239 | .box { 240 | padding: 1.5em; 241 | margin-bottom: 1.5em; 242 | background: #E5ECF9; 243 | } 244 | 245 | /* Use this to create a horizontal ruler across a column. */ 246 | hr { 247 | background: #ddd; 248 | color: #ddd; 249 | clear: both; 250 | float: none; 251 | width: 100%; 252 | height: .1em; 253 | margin: 0 0 1.45em; 254 | border: none; 255 | } 256 | 257 | hr.space { 258 | background: #fff; 259 | color: #fff; 260 | visibility: hidden; 261 | } 262 | 263 | 264 | /* Clearing floats without extra markup 265 | Based on How To Clear Floats Without Structural Markup by PiE 266 | [http://www.positioniseverything.net/easyclearing.html] */ 267 | 268 | .clearfix:after, .container:after { 269 | content: "\0020"; 270 | display: block; 271 | height: 0; 272 | clear: both; 273 | visibility: hidden; 274 | overflow:hidden; 275 | } 276 | .clearfix, .container {display: block;} 277 | 278 | /* Regular clearing 279 | apply to column that should drop below previous ones. */ 280 | 281 | .clear { clear:both; } 282 | -------------------------------------------------------------------------------- /static/js/slider.js: -------------------------------------------------------------------------------- 1 | // script.aculo.us slider.js v1.8.3, Thu Oct 08 11:23:33 +0200 2009 2 | 3 | // Copyright (c) 2005-2009 Marty Haught, Thomas Fuchs 4 | // 5 | // script.aculo.us is freely distributable under the terms of an MIT-style license. 6 | // For details, see the script.aculo.us web site: http://script.aculo.us/ 7 | 8 | if (!Control) var Control = { }; 9 | 10 | // options: 11 | // axis: 'vertical', or 'horizontal' (default) 12 | // 13 | // callbacks: 14 | // onChange(value) 15 | // onSlide(value) 16 | Control.Slider = Class.create({ 17 | initialize: function(handle, track, options) { 18 | var slider = this; 19 | 20 | if (Object.isArray(handle)) { 21 | this.handles = handle.collect( function(e) { return $(e) }); 22 | } else { 23 | this.handles = [$(handle)]; 24 | } 25 | 26 | this.track = $(track); 27 | this.options = options || { }; 28 | 29 | this.axis = this.options.axis || 'horizontal'; 30 | this.increment = this.options.increment || 1; 31 | this.step = parseInt(this.options.step || '1'); 32 | this.range = this.options.range || $R(0,1); 33 | 34 | this.value = 0; // assure backwards compat 35 | this.values = this.handles.map( function() { return 0 }); 36 | this.spans = this.options.spans ? this.options.spans.map(function(s){ return $(s) }) : false; 37 | this.options.startSpan = $(this.options.startSpan || null); 38 | this.options.endSpan = $(this.options.endSpan || null); 39 | 40 | this.restricted = this.options.restricted || false; 41 | 42 | this.maximum = this.options.maximum || this.range.end; 43 | this.minimum = this.options.minimum || this.range.start; 44 | 45 | // Will be used to align the handle onto the track, if necessary 46 | this.alignX = parseInt(this.options.alignX || '0'); 47 | this.alignY = parseInt(this.options.alignY || '0'); 48 | 49 | this.trackLength = this.maximumOffset() - this.minimumOffset(); 50 | 51 | this.handleLength = this.isVertical() ? 52 | (this.handles[0].offsetHeight != 0 ? 53 | this.handles[0].offsetHeight : this.handles[0].style.height.replace(/px$/,"")) : 54 | (this.handles[0].offsetWidth != 0 ? this.handles[0].offsetWidth : 55 | this.handles[0].style.width.replace(/px$/,"")); 56 | 57 | this.active = false; 58 | this.dragging = false; 59 | this.disabled = false; 60 | 61 | if (this.options.disabled) this.setDisabled(); 62 | 63 | // Allowed values array 64 | this.allowedValues = this.options.values ? this.options.values.sortBy(Prototype.K) : false; 65 | if (this.allowedValues) { 66 | this.minimum = this.allowedValues.min(); 67 | this.maximum = this.allowedValues.max(); 68 | } 69 | 70 | this.eventMouseDown = this.startDrag.bindAsEventListener(this); 71 | this.eventMouseUp = this.endDrag.bindAsEventListener(this); 72 | this.eventMouseMove = this.update.bindAsEventListener(this); 73 | 74 | // Initialize handles in reverse (make sure first handle is active) 75 | this.handles.each( function(h,i) { 76 | i = slider.handles.length-1-i; 77 | slider.setValue(parseFloat( 78 | (Object.isArray(slider.options.sliderValue) ? 79 | slider.options.sliderValue[i] : slider.options.sliderValue) || 80 | slider.range.start), i); 81 | h.makePositioned().observe("mousedown", slider.eventMouseDown); 82 | }); 83 | 84 | this.track.observe("mousedown", this.eventMouseDown); 85 | document.observe("mouseup", this.eventMouseUp); 86 | document.observe("mousemove", this.eventMouseMove); 87 | 88 | this.initialized = true; 89 | }, 90 | dispose: function() { 91 | var slider = this; 92 | Event.stopObserving(this.track, "mousedown", this.eventMouseDown); 93 | Event.stopObserving(document, "mouseup", this.eventMouseUp); 94 | Event.stopObserving(document, "mousemove", this.eventMouseMove); 95 | this.handles.each( function(h) { 96 | Event.stopObserving(h, "mousedown", slider.eventMouseDown); 97 | }); 98 | }, 99 | setDisabled: function(){ 100 | this.disabled = true; 101 | }, 102 | setEnabled: function(){ 103 | this.disabled = false; 104 | }, 105 | getNearestValue: function(value){ 106 | if (this.allowedValues){ 107 | if (value >= this.allowedValues.max()) return(this.allowedValues.max()); 108 | if (value <= this.allowedValues.min()) return(this.allowedValues.min()); 109 | 110 | var offset = Math.abs(this.allowedValues[0] - value); 111 | var newValue = this.allowedValues[0]; 112 | this.allowedValues.each( function(v) { 113 | var currentOffset = Math.abs(v - value); 114 | if (currentOffset <= offset){ 115 | newValue = v; 116 | offset = currentOffset; 117 | } 118 | }); 119 | return newValue; 120 | } 121 | if (value > this.range.end) return this.range.end; 122 | if (value < this.range.start) return this.range.start; 123 | return value; 124 | }, 125 | setValue: function(sliderValue, handleIdx){ 126 | if (!this.active) { 127 | this.activeHandleIdx = handleIdx || 0; 128 | this.activeHandle = this.handles[this.activeHandleIdx]; 129 | this.updateStyles(); 130 | } 131 | handleIdx = handleIdx || this.activeHandleIdx || 0; 132 | if (this.initialized && this.restricted) { 133 | if ((handleIdx>0) && (sliderValuethis.values[handleIdx+1])) 136 | sliderValue = this.values[handleIdx+1]; 137 | } 138 | sliderValue = this.getNearestValue(sliderValue); 139 | this.values[handleIdx] = sliderValue; 140 | this.value = this.values[0]; // assure backwards compat 141 | 142 | this.handles[handleIdx].style[this.isVertical() ? 'top' : 'left'] = 143 | this.translateToPx(sliderValue); 144 | 145 | this.drawSpans(); 146 | if (!this.dragging || !this.event) this.updateFinished(); 147 | }, 148 | setValueBy: function(delta, handleIdx) { 149 | this.setValue(this.values[handleIdx || this.activeHandleIdx || 0] + delta, 150 | handleIdx || this.activeHandleIdx || 0); 151 | }, 152 | translateToPx: function(value) { 153 | return Math.round( 154 | ((this.trackLength-this.handleLength)/(this.range.end-this.range.start)) * 155 | (value - this.range.start)) + "px"; 156 | }, 157 | translateToValue: function(offset) { 158 | return ((offset/(this.trackLength-this.handleLength) * 159 | (this.range.end-this.range.start)) + this.range.start); 160 | }, 161 | getRange: function(range) { 162 | var v = this.values.sortBy(Prototype.K); 163 | range = range || 0; 164 | return $R(v[range],v[range+1]); 165 | }, 166 | minimumOffset: function(){ 167 | return(this.isVertical() ? this.alignY : this.alignX); 168 | }, 169 | maximumOffset: function(){ 170 | return(this.isVertical() ? 171 | (this.track.offsetHeight != 0 ? this.track.offsetHeight : 172 | this.track.style.height.replace(/px$/,"")) - this.alignY : 173 | (this.track.offsetWidth != 0 ? this.track.offsetWidth : 174 | this.track.style.width.replace(/px$/,"")) - this.alignX); 175 | }, 176 | isVertical: function(){ 177 | return (this.axis == 'vertical'); 178 | }, 179 | drawSpans: function() { 180 | var slider = this; 181 | if (this.spans) 182 | $R(0, this.spans.length-1).each(function(r) { slider.setSpan(slider.spans[r], slider.getRange(r)) }); 183 | if (this.options.startSpan) 184 | this.setSpan(this.options.startSpan, 185 | $R(0, this.values.length>1 ? this.getRange(0).min() : this.value )); 186 | if (this.options.endSpan) 187 | this.setSpan(this.options.endSpan, 188 | $R(this.values.length>1 ? this.getRange(this.spans.length-1).max() : this.value, this.maximum)); 189 | }, 190 | setSpan: function(span, range) { 191 | if (this.isVertical()) { 192 | span.style.top = this.translateToPx(range.start); 193 | span.style.height = this.translateToPx(range.end - range.start + this.range.start); 194 | } else { 195 | span.style.left = this.translateToPx(range.start); 196 | span.style.width = this.translateToPx(range.end - range.start + this.range.start); 197 | } 198 | }, 199 | updateStyles: function() { 200 | this.handles.each( function(h){ Element.removeClassName(h, 'selected') }); 201 | Element.addClassName(this.activeHandle, 'selected'); 202 | }, 203 | startDrag: function(event) { 204 | if (Event.isLeftClick(event)) { 205 | if (!this.disabled){ 206 | this.active = true; 207 | 208 | var handle = Event.element(event); 209 | var pointer = [Event.pointerX(event), Event.pointerY(event)]; 210 | var track = handle; 211 | if (track==this.track) { 212 | var offsets = this.track.cumulativeOffset(); 213 | this.event = event; 214 | this.setValue(this.translateToValue( 215 | (this.isVertical() ? pointer[1]-offsets[1] : pointer[0]-offsets[0])-(this.handleLength/2) 216 | )); 217 | var offsets = this.activeHandle.cumulativeOffset(); 218 | this.offsetX = (pointer[0] - offsets[0]); 219 | this.offsetY = (pointer[1] - offsets[1]); 220 | } else { 221 | // find the handle (prevents issues with Safari) 222 | while((this.handles.indexOf(handle) == -1) && handle.parentNode) 223 | handle = handle.parentNode; 224 | 225 | if (this.handles.indexOf(handle)!=-1) { 226 | this.activeHandle = handle; 227 | this.activeHandleIdx = this.handles.indexOf(this.activeHandle); 228 | this.updateStyles(); 229 | 230 | var offsets = this.activeHandle.cumulativeOffset(); 231 | this.offsetX = (pointer[0] - offsets[0]); 232 | this.offsetY = (pointer[1] - offsets[1]); 233 | } 234 | } 235 | } 236 | Event.stop(event); 237 | } 238 | }, 239 | update: function(event) { 240 | if (this.active) { 241 | if (!this.dragging) this.dragging = true; 242 | this.draw(event); 243 | if (Prototype.Browser.WebKit) window.scrollBy(0,0); 244 | Event.stop(event); 245 | } 246 | }, 247 | draw: function(event) { 248 | var pointer = [Event.pointerX(event), Event.pointerY(event)]; 249 | var offsets = this.track.cumulativeOffset(); 250 | pointer[0] -= this.offsetX + offsets[0]; 251 | pointer[1] -= this.offsetY + offsets[1]; 252 | this.event = event; 253 | this.setValue(this.translateToValue( this.isVertical() ? pointer[1] : pointer[0] )); 254 | if (this.initialized && this.options.onSlide) 255 | this.options.onSlide(this.values.length>1 ? this.values : this.value, this); 256 | }, 257 | endDrag: function(event) { 258 | if (this.active && this.dragging) { 259 | this.finishDrag(event, true); 260 | Event.stop(event); 261 | } 262 | this.active = false; 263 | this.dragging = false; 264 | }, 265 | finishDrag: function(event, success) { 266 | this.active = false; 267 | this.dragging = false; 268 | this.updateFinished(); 269 | }, 270 | updateFinished: function() { 271 | if (this.initialized && this.options.onChange) 272 | this.options.onChange(this.values.length>1 ? this.values : this.value, this); 273 | this.event = null; 274 | } 275 | }); -------------------------------------------------------------------------------- /shell.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # 3 | # Copyright 2007 Google Inc. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | """ 18 | An interactive, stateful AJAX shell that runs Python code on the server. 19 | 20 | Part of http://code.google.com/p/google-app-engine-samples/. 21 | 22 | May be run as a standalone app or in an existing app as an admin-only handler. 23 | Can be used for system administration tasks, as an interactive way to try out 24 | APIs, or as a debugging aid during development. 25 | 26 | The logging, os, sys, db, and users modules are imported automatically. 27 | 28 | Interpreter state is stored in the datastore so that variables, function 29 | definitions, and other values in the global and local namespaces can be used 30 | across commands. 31 | 32 | To use the shell in your app, copy shell.py, static/*, and templates/* into 33 | your app's source directory. Then, copy the URL handlers from app.yaml into 34 | your app.yaml. 35 | 36 | TODO: unit tests! 37 | """ 38 | 39 | import logging 40 | import new 41 | import os 42 | import pickle 43 | import sys 44 | import traceback 45 | import types 46 | import wsgiref.handlers 47 | 48 | try: 49 | from google.appengine.api import users 50 | from google.appengine.ext import db 51 | from google.appengine.ext import webapp 52 | from google.appengine.ext.webapp import template 53 | INITIAL_UNPICKLABLES = [ 54 | 'from google.appengine.ext import db', 55 | 'from google.appengine.api import users', 56 | ] 57 | except ImportError: 58 | from google3.apphosting.api import users 59 | from google3.apphosting.ext import db 60 | from google3.apphosting.ext import webapp 61 | from google3.apphosting.ext.webapp import template 62 | INITIAL_UNPICKLABLES = [ 63 | 'from google3.apphosting.ext import db', 64 | 'from google3.apphosting.api import users', 65 | ] 66 | 67 | 68 | # Set to True if stack traces should be shown in the browser, etc. 69 | _DEBUG = True 70 | 71 | # The entity kind for shell sessions. Feel free to rename to suit your app. 72 | _SESSION_KIND = '_Shell_Session' 73 | 74 | # Types that can't be pickled. 75 | UNPICKLABLE_TYPES = ( 76 | types.ModuleType, 77 | types.TypeType, 78 | types.ClassType, 79 | types.FunctionType, 80 | ) 81 | 82 | # Unpicklable statements to seed new sessions with. 83 | INITIAL_UNPICKLABLES += [ 84 | 'import logging', 85 | 'import os', 86 | 'import sys', 87 | 'class Foo(db.Expando):\n pass', 88 | ] 89 | 90 | 91 | class Session(db.Model): 92 | """A shell session. Stores the session's globals. 93 | 94 | Each session globals is stored in one of two places: 95 | 96 | If the global is picklable, it's stored in the parallel globals and 97 | global_names list properties. (They're parallel lists to work around the 98 | unfortunate fact that the datastore can't store dictionaries natively.) 99 | 100 | If the global is not picklable (e.g. modules, classes, and functions), or if 101 | it was created by the same statement that created an unpicklable global, 102 | it's not stored directly. Instead, the statement is stored in the 103 | unpicklables list property. On each request, before executing the current 104 | statement, the unpicklable statements are evaluated to recreate the 105 | unpicklable globals. 106 | 107 | The unpicklable_names property stores all of the names of globals that were 108 | added by unpicklable statements. When we pickle and store the globals after 109 | executing a statement, we skip the ones in unpicklable_names. 110 | 111 | Using Text instead of string is an optimization. We don't query on any of 112 | these properties, so they don't need to be indexed. 113 | """ 114 | global_names = db.ListProperty(db.Text) 115 | globals = db.ListProperty(db.Blob) 116 | unpicklable_names = db.ListProperty(db.Text) 117 | unpicklables = db.ListProperty(db.Text) 118 | 119 | def set_global(self, name, value): 120 | """Adds a global, or updates it if it already exists. 121 | 122 | Also removes the global from the list of unpicklable names. 123 | 124 | Args: 125 | name: the name of the global to remove 126 | value: any picklable value 127 | """ 128 | blob = db.Blob(pickle.dumps(value)) 129 | 130 | if name in self.global_names: 131 | index = self.global_names.index(name) 132 | self.globals[index] = blob 133 | else: 134 | self.global_names.append(db.Text(name)) 135 | self.globals.append(blob) 136 | 137 | self.remove_unpicklable_name(name) 138 | 139 | def remove_global(self, name): 140 | """Removes a global, if it exists. 141 | 142 | Args: 143 | name: string, the name of the global to remove 144 | """ 145 | if name in self.global_names: 146 | index = self.global_names.index(name) 147 | del self.global_names[index] 148 | del self.globals[index] 149 | 150 | def globals_dict(self): 151 | """Returns a dictionary view of the globals. 152 | """ 153 | return dict((name, pickle.loads(val)) 154 | for name, val in zip(self.global_names, self.globals)) 155 | 156 | def add_unpicklable(self, statement, names): 157 | """Adds a statement and list of names to the unpicklables. 158 | 159 | Also removes the names from the globals. 160 | 161 | Args: 162 | statement: string, the statement that created new unpicklable global(s). 163 | names: list of strings; the names of the globals created by the statement. 164 | """ 165 | self.unpicklables.append(db.Text(statement)) 166 | 167 | for name in names: 168 | self.remove_global(name) 169 | if name not in self.unpicklable_names: 170 | self.unpicklable_names.append(db.Text(name)) 171 | 172 | def remove_unpicklable_name(self, name): 173 | """Removes a name from the list of unpicklable names, if it exists. 174 | 175 | Args: 176 | name: string, the name of the unpicklable global to remove 177 | """ 178 | if name in self.unpicklable_names: 179 | self.unpicklable_names.remove(name) 180 | 181 | 182 | class FrontPageHandler(webapp.RequestHandler): 183 | """Creates a new session and renders the shell.html template. 184 | """ 185 | 186 | def get(self): 187 | # set up the session. TODO: garbage collect old shell sessions 188 | session_key = self.request.get('session') 189 | if session_key: 190 | session = Session.get(session_key) 191 | else: 192 | # create a new session 193 | session = Session() 194 | session.unpicklables = [db.Text(line) for line in INITIAL_UNPICKLABLES] 195 | session_key = session.put() 196 | 197 | template_file = os.path.join(os.path.dirname(__file__), 'templates', 198 | 'shell.html') 199 | session_url = '/?session=%s' % session_key 200 | vars = { 'server_software': os.environ['SERVER_SOFTWARE'], 201 | 'python_version': sys.version, 202 | 'session': str(session_key), 203 | 'user': users.get_current_user() 204 | } 205 | 206 | user = users.get_current_user() 207 | if user == None: 208 | vars.update({'login_url': users.create_login_url(self.request.uri), 209 | 'admin': users.is_current_user_admin(), 210 | 'login_label':'login'}) 211 | else: 212 | vars.update({'login_url': users.create_logout_url(self.request.uri), 213 | 'login_label':'logout', 214 | 'admin': users.is_current_user_admin(), 215 | 'nickname':user.nickname()}) 216 | 217 | 218 | rendered = webapp.template.render(template_file, vars, debug=_DEBUG) 219 | self.response.out.write(rendered) 220 | 221 | 222 | class StatementHandler(webapp.RequestHandler): 223 | """Evaluates a python statement in a given session and returns the result. 224 | """ 225 | 226 | def get(self): 227 | self.response.headers['Content-Type'] = 'text/plain' 228 | 229 | # extract the statement to be run 230 | statement = self.request.get('statement') 231 | if not statement: 232 | return 233 | 234 | # the python compiler doesn't like network line endings 235 | statement = statement.replace('\r\n', '\n') 236 | 237 | # add a couple newlines at the end of the statement. this makes 238 | # single-line expressions such as 'class Foo: pass' evaluate happily. 239 | statement += '\n\n' 240 | 241 | # log and compile the statement up front 242 | try: 243 | logging.info('Compiling and evaluating:\n%s' % statement) 244 | compiled = compile(statement, '', 'single') 245 | except: 246 | self.response.out.write(traceback.format_exc()) 247 | return 248 | 249 | # create a dedicated module to be used as this statement's __main__ 250 | statement_module = new.module('__main__') 251 | 252 | # use this request's __builtin__, since it changes on each request. 253 | # this is needed for import statements, among other things. 254 | import __builtin__ 255 | statement_module.__builtins__ = __builtin__ 256 | 257 | # load the session from the datastore 258 | session = Session.get(self.request.get('session')) 259 | 260 | # swap in our custom module for __main__. then unpickle the session 261 | # globals, run the statement, and re-pickle the session globals, all 262 | # inside it. 263 | old_main = sys.modules.get('__main__') 264 | try: 265 | sys.modules['__main__'] = statement_module 266 | statement_module.__name__ = '__main__' 267 | 268 | # re-evaluate the unpicklables 269 | for code in session.unpicklables: 270 | exec code in statement_module.__dict__ 271 | 272 | # re-initialize the globals 273 | for name, val in session.globals_dict().items(): 274 | try: 275 | statement_module.__dict__[name] = val 276 | except: 277 | msg = 'Dropping %s since it could not be unpickled.\n' % name 278 | self.response.out.write(msg) 279 | logging.warning(msg + traceback.format_exc()) 280 | session.remove_global(name) 281 | 282 | # run! 283 | old_globals = dict(statement_module.__dict__) 284 | try: 285 | old_stdout = sys.stdout 286 | old_stderr = sys.stderr 287 | try: 288 | sys.stdout = self.response.out 289 | sys.stderr = self.response.out 290 | exec compiled in statement_module.__dict__ 291 | finally: 292 | sys.stdout = old_stdout 293 | sys.stderr = old_stderr 294 | except: 295 | self.response.out.write(traceback.format_exc()) 296 | return 297 | 298 | # extract the new globals that this statement added 299 | new_globals = {} 300 | for name, val in statement_module.__dict__.items(): 301 | if name not in old_globals or val != old_globals[name]: 302 | new_globals[name] = val 303 | 304 | if True in [isinstance(val, UNPICKLABLE_TYPES) 305 | for val in new_globals.values()]: 306 | # this statement added an unpicklable global. store the statement and 307 | # the names of all of the globals it added in the unpicklables. 308 | session.add_unpicklable(statement, new_globals.keys()) 309 | logging.debug('Storing this statement as an unpicklable.') 310 | 311 | else: 312 | # this statement didn't add any unpicklables. pickle and store the 313 | # new globals back into the datastore. 314 | for name, val in new_globals.items(): 315 | if not name.startswith('__'): 316 | session.set_global(name, val) 317 | 318 | finally: 319 | sys.modules['__main__'] = old_main 320 | 321 | session.put() 322 | 323 | 324 | def main(): 325 | application = webapp.WSGIApplication( 326 | [('/shell\.php', FrontPageHandler), 327 | ('/shell\.do', StatementHandler)], debug=_DEBUG) 328 | wsgiref.handlers.CGIHandler().run(application) 329 | 330 | 331 | if __name__ == '__main__': 332 | main() 333 | -------------------------------------------------------------------------------- /static/blueprint/screen.css: -------------------------------------------------------------------------------- 1 | /* ----------------------------------------------------------------------- 2 | 3 | 4 | Blueprint CSS Framework 0.9 5 | http://blueprintcss.org 6 | 7 | * Copyright (c) 2007-Present. See LICENSE for more info. 8 | * See README for instructions on how to use Blueprint. 9 | * For credits and origins, see AUTHORS. 10 | * This is a compressed file. See the sources in the 'src' directory. 11 | 12 | ----------------------------------------------------------------------- */ 13 | 14 | /* reset.css */ 15 | html, body, div, span, object, iframe, h1, h2, h3, h4, h5, h6, p, blockquote, pre, a, abbr, acronym, address, code, del, dfn, em, img, q, dl, dt, dd, ol, ul, li, fieldset, form, label, legend, table, caption, tbody, tfoot, thead, tr, th, td {margin:0;padding:0;border:0;font-weight:inherit;font-style:inherit;font-size:100%;font-family:inherit;vertical-align:baseline;} 16 | body {line-height:1.5;} 17 | table {border-collapse:separate;border-spacing:0;} 18 | caption, th, td {text-align:left;font-weight:normal;} 19 | table, td, th {vertical-align:middle;} 20 | blockquote:before, blockquote:after, q:before, q:after {content:"";} 21 | blockquote, q {quotes:"" "";} 22 | a img {border:none;} 23 | 24 | /* typography.css */ 25 | html {font-size:100.01%;} 26 | body {font-size:75%;color:#222;background:#fff;font-family:"Helvetica Neue", Arial, Helvetica, sans-serif;} 27 | h1, h2, h3, h4, h5, h6 {font-weight:normal;color:#111;} 28 | h1 {font-size:3em;line-height:1;margin-bottom:0.5em;} 29 | h2 {font-size:2em;margin-bottom:0.75em;} 30 | h3 {font-size:1.5em;line-height:1;margin-bottom:1em;} 31 | h4 {font-size:1.2em;line-height:1.25;margin-bottom:1.25em;} 32 | h5 {font-size:1em;font-weight:bold;margin-bottom:1.5em;} 33 | h6 {font-size:1em;font-weight:bold;} 34 | h1 img, h2 img, h3 img, h4 img, h5 img, h6 img {margin:0;} 35 | p {margin:0 0 1.5em;} 36 | p img.left {float:left;margin:1.5em 1.5em 1.5em 0;padding:0;} 37 | p img.right {float:right;margin:1.5em 0 1.5em 1.5em;} 38 | a:focus, a:hover {color:#000;} 39 | a {color:#009;text-decoration:underline;} 40 | blockquote {margin:1.5em;color:#666;font-style:italic;} 41 | strong {font-weight:bold;} 42 | em, dfn {font-style:italic;} 43 | dfn {font-weight:bold;} 44 | sup, sub {line-height:0;} 45 | abbr, acronym {border-bottom:1px dotted #666;} 46 | address {margin:0 0 1.5em;font-style:italic;} 47 | del {color:#666;} 48 | pre {margin:1.5em 0;white-space:pre;} 49 | pre, code, tt {font:1em 'andale mono', 'lucida console', monospace;line-height:1.5;} 50 | li ul, li ol {margin:0;} 51 | ul, ol {margin:0 1.5em 1.5em 0;padding-left:3.333em;} 52 | ul {list-style-type:disc;} 53 | ol {list-style-type:decimal;} 54 | dl {margin:0 0 1.5em 0;} 55 | dl dt {font-weight:bold;} 56 | dd {margin-left:1.5em;} 57 | table {margin-bottom:1.4em;width:100%;} 58 | th {font-weight:bold;} 59 | thead th {background:#c3d9ff;} 60 | th, td, caption {padding:4px 10px 4px 5px;} 61 | tr.even td {background:#e5ecf9;} 62 | tfoot {font-style:italic;} 63 | caption {background:#eee;} 64 | .small {font-size:.8em;margin-bottom:1.875em;line-height:1.875em;} 65 | .large {font-size:1.2em;line-height:2.5em;margin-bottom:1.25em;} 66 | .hide {display:none;} 67 | .quiet {color:#666;} 68 | .loud {color:#000;} 69 | .highlight {background:#ff0;} 70 | .added {background:#060;color:#fff;} 71 | .removed {background:#900;color:#fff;} 72 | .first {margin-left:0;padding-left:0;} 73 | .last {margin-right:0;padding-right:0;} 74 | .top {margin-top:0;padding-top:0;} 75 | .bottom {margin-bottom:0;padding-bottom:0;} 76 | 77 | /* forms.css */ 78 | label {font-weight:bold;} 79 | fieldset {padding:1.4em;margin:0 0 1.5em 0;border:1px solid #ccc;} 80 | legend {font-weight:bold;font-size:1.2em;} 81 | input[type=text], input[type=password], input.text, input.title, textarea, select {background-color:#fff;border:1px solid #bbb;} 82 | input[type=text]:focus, input[type=password]:focus, input.text:focus, input.title:focus, textarea:focus, select:focus {border-color:#666;} 83 | input[type=text], input[type=password], input.text, input.title, textarea, select {margin:0.5em 0;} 84 | input.text, input.title {width:300px;padding:5px;} 85 | input.title {font-size:1.5em;} 86 | textarea {width:390px;height:250px;padding:5px;} 87 | input[type=checkbox], input[type=radio], input.checkbox, input.radio {position:relative;top:.25em;} 88 | form.inline {line-height:3;} 89 | form.inline p {margin-bottom:0;} 90 | .error, .notice, .success {padding:.8em;margin-bottom:1em;border:2px solid #ddd;} 91 | .error {background:#FBE3E4;color:#8a1f11;border-color:#FBC2C4;} 92 | .notice {background:#FFF6BF;color:#514721;border-color:#FFD324;} 93 | .success {background:#E6EFC2;color:#264409;border-color:#C6D880;} 94 | .error a {color:#8a1f11;} 95 | .notice a {color:#514721;} 96 | .success a {color:#264409;} 97 | 98 | /* grid.css */ 99 | .container {width:950px;margin:0 auto;} 100 | .showgrid {background:url(src/grid.png);} 101 | .column, div.span-1, div.span-2, div.span-3, div.span-4, div.span-5, div.span-6, div.span-7, div.span-8, div.span-9, div.span-10, div.span-11, div.span-12, div.span-13, div.span-14, div.span-15, div.span-16, div.span-17, div.span-18, div.span-19, div.span-20, div.span-21, div.span-22, div.span-23, div.span-24 {float:left;margin-right:10px;} 102 | .last, div.last {margin-right:0;} 103 | .span-1 {width:30px;} 104 | .span-2 {width:70px;} 105 | .span-3 {width:110px;} 106 | .span-4 {width:150px;} 107 | .span-5 {width:190px;} 108 | .span-6 {width:230px;} 109 | .span-7 {width:270px;} 110 | .span-8 {width:310px;} 111 | .span-9 {width:350px;} 112 | .span-10 {width:390px;} 113 | .span-11 {width:430px;} 114 | .span-12 {width:470px;} 115 | .span-13 {width:510px;} 116 | .span-14 {width:550px;} 117 | .span-15 {width:590px;} 118 | .span-16 {width:630px;} 119 | .span-17 {width:670px;} 120 | .span-18 {width:710px;} 121 | .span-19 {width:750px;} 122 | .span-20 {width:790px;} 123 | .span-21 {width:830px;} 124 | .span-22 {width:870px;} 125 | .span-23 {width:910px;} 126 | .span-24, div.span-24 {width:950px;margin-right:0;} 127 | input.span-1, textarea.span-1, input.span-2, textarea.span-2, input.span-3, textarea.span-3, input.span-4, textarea.span-4, input.span-5, textarea.span-5, input.span-6, textarea.span-6, input.span-7, textarea.span-7, input.span-8, textarea.span-8, input.span-9, textarea.span-9, input.span-10, textarea.span-10, input.span-11, textarea.span-11, input.span-12, textarea.span-12, input.span-13, textarea.span-13, input.span-14, textarea.span-14, input.span-15, textarea.span-15, input.span-16, textarea.span-16, input.span-17, textarea.span-17, input.span-18, textarea.span-18, input.span-19, textarea.span-19, input.span-20, textarea.span-20, input.span-21, textarea.span-21, input.span-22, textarea.span-22, input.span-23, textarea.span-23, input.span-24, textarea.span-24 {border-left-width:1px!important;border-right-width:1px!important;padding-left:5px!important;padding-right:5px!important;} 128 | input.span-1, textarea.span-1 {width:18px!important;} 129 | input.span-2, textarea.span-2 {width:58px!important;} 130 | input.span-3, textarea.span-3 {width:98px!important;} 131 | input.span-4, textarea.span-4 {width:138px!important;} 132 | input.span-5, textarea.span-5 {width:178px!important;} 133 | input.span-6, textarea.span-6 {width:218px!important;} 134 | input.span-7, textarea.span-7 {width:258px!important;} 135 | input.span-8, textarea.span-8 {width:298px!important;} 136 | input.span-9, textarea.span-9 {width:338px!important;} 137 | input.span-10, textarea.span-10 {width:378px!important;} 138 | input.span-11, textarea.span-11 {width:418px!important;} 139 | input.span-12, textarea.span-12 {width:458px!important;} 140 | input.span-13, textarea.span-13 {width:498px!important;} 141 | input.span-14, textarea.span-14 {width:538px!important;} 142 | input.span-15, textarea.span-15 {width:578px!important;} 143 | input.span-16, textarea.span-16 {width:618px!important;} 144 | input.span-17, textarea.span-17 {width:658px!important;} 145 | input.span-18, textarea.span-18 {width:698px!important;} 146 | input.span-19, textarea.span-19 {width:738px!important;} 147 | input.span-20, textarea.span-20 {width:778px!important;} 148 | input.span-21, textarea.span-21 {width:818px!important;} 149 | input.span-22, textarea.span-22 {width:858px!important;} 150 | input.span-23, textarea.span-23 {width:898px!important;} 151 | input.span-24, textarea.span-24 {width:938px!important;} 152 | .append-1 {padding-right:40px;} 153 | .append-2 {padding-right:80px;} 154 | .append-3 {padding-right:120px;} 155 | .append-4 {padding-right:160px;} 156 | .append-5 {padding-right:200px;} 157 | .append-6 {padding-right:240px;} 158 | .append-7 {padding-right:280px;} 159 | .append-8 {padding-right:320px;} 160 | .append-9 {padding-right:360px;} 161 | .append-10 {padding-right:400px;} 162 | .append-11 {padding-right:440px;} 163 | .append-12 {padding-right:480px;} 164 | .append-13 {padding-right:520px;} 165 | .append-14 {padding-right:560px;} 166 | .append-15 {padding-right:600px;} 167 | .append-16 {padding-right:640px;} 168 | .append-17 {padding-right:680px;} 169 | .append-18 {padding-right:720px;} 170 | .append-19 {padding-right:760px;} 171 | .append-20 {padding-right:800px;} 172 | .append-21 {padding-right:840px;} 173 | .append-22 {padding-right:880px;} 174 | .append-23 {padding-right:920px;} 175 | .prepend-1 {padding-left:40px;} 176 | .prepend-2 {padding-left:80px;} 177 | .prepend-3 {padding-left:120px;} 178 | .prepend-4 {padding-left:160px;} 179 | .prepend-5 {padding-left:200px;} 180 | .prepend-6 {padding-left:240px;} 181 | .prepend-7 {padding-left:280px;} 182 | .prepend-8 {padding-left:320px;} 183 | .prepend-9 {padding-left:360px;} 184 | .prepend-10 {padding-left:400px;} 185 | .prepend-11 {padding-left:440px;} 186 | .prepend-12 {padding-left:480px;} 187 | .prepend-13 {padding-left:520px;} 188 | .prepend-14 {padding-left:560px;} 189 | .prepend-15 {padding-left:600px;} 190 | .prepend-16 {padding-left:640px;} 191 | .prepend-17 {padding-left:680px;} 192 | .prepend-18 {padding-left:720px;} 193 | .prepend-19 {padding-left:760px;} 194 | .prepend-20 {padding-left:800px;} 195 | .prepend-21 {padding-left:840px;} 196 | .prepend-22 {padding-left:880px;} 197 | .prepend-23 {padding-left:920px;} 198 | div.border {padding-right:4px;margin-right:5px;border-right:1px solid #eee;} 199 | div.colborder {padding-right:24px;margin-right:25px;border-right:1px solid #eee;} 200 | .pull-1 {margin-left:-40px;} 201 | .pull-2 {margin-left:-80px;} 202 | .pull-3 {margin-left:-120px;} 203 | .pull-4 {margin-left:-160px;} 204 | .pull-5 {margin-left:-200px;} 205 | .pull-6 {margin-left:-240px;} 206 | .pull-7 {margin-left:-280px;} 207 | .pull-8 {margin-left:-320px;} 208 | .pull-9 {margin-left:-360px;} 209 | .pull-10 {margin-left:-400px;} 210 | .pull-11 {margin-left:-440px;} 211 | .pull-12 {margin-left:-480px;} 212 | .pull-13 {margin-left:-520px;} 213 | .pull-14 {margin-left:-560px;} 214 | .pull-15 {margin-left:-600px;} 215 | .pull-16 {margin-left:-640px;} 216 | .pull-17 {margin-left:-680px;} 217 | .pull-18 {margin-left:-720px;} 218 | .pull-19 {margin-left:-760px;} 219 | .pull-20 {margin-left:-800px;} 220 | .pull-21 {margin-left:-840px;} 221 | .pull-22 {margin-left:-880px;} 222 | .pull-23 {margin-left:-920px;} 223 | .pull-24 {margin-left:-960px;} 224 | .pull-1, .pull-2, .pull-3, .pull-4, .pull-5, .pull-6, .pull-7, .pull-8, .pull-9, .pull-10, .pull-11, .pull-12, .pull-13, .pull-14, .pull-15, .pull-16, .pull-17, .pull-18, .pull-19, .pull-20, .pull-21, .pull-22, .pull-23, .pull-24 {float:left;position:relative;} 225 | .push-1 {margin:0 -40px 1.5em 40px;} 226 | .push-2 {margin:0 -80px 1.5em 80px;} 227 | .push-3 {margin:0 -120px 1.5em 120px;} 228 | .push-4 {margin:0 -160px 1.5em 160px;} 229 | .push-5 {margin:0 -200px 1.5em 200px;} 230 | .push-6 {margin:0 -240px 1.5em 240px;} 231 | .push-7 {margin:0 -280px 1.5em 280px;} 232 | .push-8 {margin:0 -320px 1.5em 320px;} 233 | .push-9 {margin:0 -360px 1.5em 360px;} 234 | .push-10 {margin:0 -400px 1.5em 400px;} 235 | .push-11 {margin:0 -440px 1.5em 440px;} 236 | .push-12 {margin:0 -480px 1.5em 480px;} 237 | .push-13 {margin:0 -520px 1.5em 520px;} 238 | .push-14 {margin:0 -560px 1.5em 560px;} 239 | .push-15 {margin:0 -600px 1.5em 600px;} 240 | .push-16 {margin:0 -640px 1.5em 640px;} 241 | .push-17 {margin:0 -680px 1.5em 680px;} 242 | .push-18 {margin:0 -720px 1.5em 720px;} 243 | .push-19 {margin:0 -760px 1.5em 760px;} 244 | .push-20 {margin:0 -800px 1.5em 800px;} 245 | .push-21 {margin:0 -840px 1.5em 840px;} 246 | .push-22 {margin:0 -880px 1.5em 880px;} 247 | .push-23 {margin:0 -920px 1.5em 920px;} 248 | .push-24 {margin:0 -960px 1.5em 960px;} 249 | .push-1, .push-2, .push-3, .push-4, .push-5, .push-6, .push-7, .push-8, .push-9, .push-10, .push-11, .push-12, .push-13, .push-14, .push-15, .push-16, .push-17, .push-18, .push-19, .push-20, .push-21, .push-22, .push-23, .push-24 {float:right;position:relative;} 250 | .prepend-top {margin-top:1.5em;} 251 | .append-bottom {margin-bottom:1.5em;} 252 | .box {padding:1.5em;margin-bottom:1.5em;background:#E5ECF9;} 253 | hr {background:#ddd;color:#ddd;clear:both;float:none;width:100%;height:.1em;margin:0 0 1.45em;border:none;} 254 | hr.space {background:#fff;color:#fff;visibility:hidden;} 255 | .clearfix:after, .container:after {content:"\0020";display:block;height:0;clear:both;visibility:hidden;overflow:hidden;} 256 | .clearfix, .container {display:block;} 257 | .clear {clear:both;} -------------------------------------------------------------------------------- /models.py: -------------------------------------------------------------------------------- 1 | from google.appengine.ext import db 2 | from google.appengine.api import memcache 3 | from datetime import datetime 4 | import re 5 | 6 | 7 | class User(db.Model): 8 | uid = db.IntegerProperty() 9 | name = db.StringProperty() 10 | login = db.UserProperty(auto_current_user_add = True) 11 | pic = db.StringProperty() 12 | pic_square = db.StringProperty() 13 | def save(self): 14 | if User.all().filter('uid = ', self.uid).count() == 0: 15 | self.put() 16 | 17 | class Friend(db.Model): 18 | user = db.ReferenceProperty(reference_class = User, collection_name = 'friends') 19 | uid = uid = db.IntegerProperty(required=True) 20 | name = db.StringProperty() 21 | pic_square = db.StringProperty() 22 | trainning = db.BooleanProperty() 23 | 24 | def save(self): 25 | if Friend.all().filter('uid = ', self.uid).count() == 0: 26 | self.put() 27 | 28 | @classmethod 29 | def get_trainnings(cls,user, count = 20, offset = 0): 30 | query = Friend.all().filter('user = ',user).filter('trainning = ',True) 31 | if query.count() == 0: 32 | return False 33 | else: 34 | return query.fetch(count, offset) 35 | 36 | 37 | 38 | class Keyword(db.Model): 39 | word = db.StringProperty(required = True) 40 | marah = db.IntegerProperty(default = 0) 41 | senang = db.IntegerProperty(default = 0) 42 | jijik = db.IntegerProperty(default = 0) 43 | takut = db.IntegerProperty(default = 0) 44 | malu = db.IntegerProperty(default = 0) 45 | bersalah = db.IntegerProperty(default = 0) 46 | sedih = db.IntegerProperty(default = 0) 47 | valid = db.BooleanProperty(default = True) 48 | custome = db.BooleanProperty(default = False) 49 | 50 | def save_custome(self): 51 | if db.Query(Keyword).filter('word = ', self.word).count() == 0: 52 | self.word = self.word.strip() 53 | self.custome = True 54 | self.put() 55 | 56 | @classmethod 57 | def update(cls, status): 58 | #keyword smiley 59 | #custume = re.findall(r'%s' % (CustumeKeyword.get_rstring()), status.message) 60 | 61 | # Keyword string 62 | words = re.findall(r'[a-zA-Z]+', status.message) 63 | 64 | keywords = words #+ custume 65 | 66 | for word in keywords: 67 | query = db.Query(Keyword).filter('word = ',word.lower()) 68 | 69 | if query.count() == 0: 70 | keyword = Keyword(word = word.lower()) 71 | exec("keyword.%s = 1" % (status.category)) 72 | keyword.put() 73 | 74 | else: 75 | keyword = query.fetch(1)[0] 76 | exec("keyword.%s += 1" % (status.category)) 77 | keyword.put() 78 | 79 | @classmethod 80 | def update_custome(cls, status): 81 | 82 | words = status.message.split() 83 | 84 | for word in words: 85 | query = cls.all().filter('custome = ',True).filter('word = ',word) 86 | keyword = query.get() 87 | if keyword is not None: 88 | exec('keyword.%s += 1' % (status.category)) 89 | keyword.put() 90 | 91 | @classmethod 92 | def get_list_keyword_custome_cache(cls,category = None): 93 | data = None 94 | if category is not None: 95 | data = memcache.get('list_keyword_custome_cache_%s' % (category)) 96 | if data is not None: 97 | return data 98 | else: 99 | data = [] 100 | query = cls.all() 101 | query.filter('custome = ', True) 102 | query.filter('%s > ' % (category),0) 103 | for k in query.fetch(1000): 104 | data.append(k.word) 105 | memcache.set('list_keyword_custome_cache_%s' % (category),data,3600) 106 | return data 107 | 108 | else: 109 | data = memcache.get('list_keyword_custome_cache') 110 | if data is not None: 111 | return data 112 | else: 113 | data = [] 114 | query = cls.all() 115 | query.filter('custome = ', True) 116 | for k in query.fetch(1000): 117 | data.append(k.word) 118 | memcache.set('list_keyword_custome_cache',data,3600) 119 | return data 120 | 121 | 122 | 123 | 124 | 125 | @classmethod 126 | def get_regex(cls,category): 127 | regex = '' 128 | query = Keyword.all() 129 | query.filter('%s > ' %(category),0) 130 | query.filter('valid = ',True) 131 | query.order('-%s' % (category)) 132 | for k in query.fetch(1000): 133 | regex += "%s|" % (k.word) 134 | return (regex.strip('|')) 135 | 136 | @classmethod 137 | def generate_cache(cls): 138 | pass 139 | 140 | 141 | @classmethod 142 | def generate_probs_cache(cls, category): 143 | 144 | words = cls.get_word_valid_cache(category) 145 | for word in words: 146 | cls.get_prob(category,word) 147 | 148 | return True 149 | 150 | @classmethod 151 | def generate_list_cache(cls): 152 | emotion = ['senang','sedih','marah','malu', 153 | 'jijik','takut','bersalah'] 154 | for e in emotion: 155 | cls.get_word_valid_cache(e) 156 | 157 | return True 158 | 159 | @classmethod 160 | def get_regex_cache(cls,category): 161 | data = memcache.get('regex_keyword_%s' % (category)) 162 | if data is not None: 163 | return data 164 | else: 165 | data = cls.get_regex(category) 166 | memcache.add('regex_keyword_%s' % (category),data,3600) 167 | return data 168 | 169 | @classmethod 170 | def count_all(cls,**filter): 171 | """ 172 | Count *all* of the rows (without maxing out at 1000) 173 | """ 174 | count = 0 175 | query = cls.all().filter('valid = ',True) 176 | 177 | 178 | for k,v in filter.items(): 179 | query.filter('%s = ' % (k),v) 180 | 181 | query.order('__key__') 182 | 183 | while count % 1000 == 0: 184 | current_count = query.count() 185 | count += current_count 186 | 187 | if current_count == 1000: 188 | last_key = query.fetch(1, 999)[0].key() 189 | query = query.filter('__key__ > ', last_key) 190 | 191 | return count 192 | 193 | @classmethod 194 | def get_all(cls,**filter): 195 | """ 196 | Count *all* of the rows (without maxing out at 1000) 197 | """ 198 | count = 0 199 | result = [] 200 | query = cls.all().order('__key__') 201 | query.filter('valid = ', True) 202 | 203 | 204 | for k,v in filter.items(): 205 | query.filter('%s = ' % (k),v) 206 | 207 | while count % 1000 == 0: 208 | current_count = query.count() 209 | count += current_count 210 | result += query.fetch(1000) 211 | 212 | if current_count == 1000: 213 | last_key = query.fetch(1, 999)[0].key() 214 | query = query.filter('__key__ > ', last_key) 215 | 216 | return result 217 | 218 | @classmethod 219 | def count_all_category(cls,category): 220 | populate = 1 221 | results = 0 222 | 223 | query = cls.all() 224 | query.filter('valid = ',True) 225 | query.filter('%s >= ' % (category),populate) 226 | count = query.count() 227 | while count == 1000: 228 | exec('results += cls.count_all(%s = populate)' % (category)) 229 | populate += 1 230 | query = cls.all() 231 | query.filter('valid = ',True) 232 | query.filter('%s >= ' % (category),populate) 233 | count = query.count() 234 | results += query.count() 235 | return results 236 | 237 | 238 | @classmethod 239 | def get_all_category(cls,category): 240 | populate = 1 241 | results = [] 242 | 243 | query = cls.all() 244 | query.filter('valid = ',True) 245 | query.filter('%s >= ' % (category),populate) 246 | count = query.count() 247 | 248 | while count == 1000: 249 | exec('results += cls.get_all(%s = populate)' % (category)) 250 | #results += cls.get_all(category = populate) 251 | populate += 1 252 | query = cls.all() 253 | query.filter('valid = ',True) 254 | query.filter('%s >= ' % (category),populate) 255 | count = query.count() 256 | 257 | results += query.fetch(1000) 258 | return results 259 | 260 | @classmethod 261 | def get_word_valid_cache(cls,category): 262 | data = memcache.get('keyword_valid_list_%s' % (category)) 263 | if data is not None: 264 | return data 265 | else: 266 | words = [] 267 | for word in cls.get_all_category(category): 268 | words.append(word.word) 269 | 270 | memcache.add('keyword_valid_list_%s' % (category),words,3600) 271 | return words 272 | 273 | 274 | @classmethod 275 | def get_prob(cls,category,word): 276 | word = word.lower() 277 | data = memcache.get('prob_%s_%s' % (category, word)) 278 | if data is not None: 279 | return data 280 | else: 281 | word_in_category = cls.get_word_sum_in_category(category) 282 | keyword = cls.all().filter('word = ',word).get() 283 | word_count = 0 284 | exec('word_count = keyword.%s' % (category)) 285 | data = float(word_count) / float(word_in_category) 286 | memcache.add('prob_%s_%s' % (category, word), data, 3600) 287 | return data 288 | 289 | @classmethod 290 | def get_word_sum_in_category(cls,category): 291 | 292 | data = memcache.get('word_sum_%s' % (category)) 293 | if data is not None: 294 | return data 295 | else: 296 | sum = 0 297 | for word in cls.get_all_category(category): 298 | exec('sum += word.%s' % (category)) 299 | 300 | memcache.add('word_sum_%s' % (category),sum,3600) 301 | 302 | return sum 303 | 304 | 305 | 306 | class CustumeKeyword(db.Model): 307 | plain = db.StringProperty(required = True) 308 | escape = db.StringProperty() 309 | def save(self): 310 | if db.Query(CustumeKeyword).filter('plain = ', self.plain).count() == 0: 311 | self.escape = re.escape(self.plain) 312 | self.put() 313 | 314 | @classmethod 315 | def get_rstring(cls): 316 | rstring = '' 317 | for s in CustumeKeyword.all().fetch(1000): 318 | rstring += "%s|" % (s.escape) 319 | 320 | return rstring.strip('|') 321 | 322 | @classmethod 323 | def add(cls, *args): 324 | for custume in args: 325 | CustumeKeyword(plain = custume).save() 326 | 327 | class Status(db.Model): 328 | user = db.ReferenceProperty(reference_class = User, collection_name = 'states') 329 | status_id = db.IntegerProperty() 330 | message = db.StringProperty(multiline=True) 331 | time = db.DateTimeProperty() 332 | uid = db.IntegerProperty() 333 | category = db.StringProperty(choices=('marah','senang','jijik','takut','malu', 334 | 'bersalah','sedih','uncategory')) 335 | 336 | def save(self): 337 | if db.Query(Status).filter('status_id = ', self.status_id).count() == 0: 338 | self.put() 339 | 340 | def set_time(self,time): 341 | self.time = datetime.fromtimestamp(time) 342 | 343 | 344 | @classmethod 345 | def count_all(cls, **filter): 346 | """ 347 | Count *all* of the rows (without maxing out at 1000) 348 | """ 349 | count = 0 350 | query = cls.all().order('__key__') 351 | 352 | for k,v in filter.items(): 353 | query.filter('%s = ' % (k),v) 354 | 355 | while count % 1000 == 0: 356 | current_count = query.count() 357 | count += current_count 358 | 359 | if current_count == 1000: 360 | last_key = query.fetch(1, 999)[0].key() 361 | query = query.filter('__key__ > ', last_key) 362 | 363 | return count 364 | 365 | @classmethod 366 | def get_probs(cls,message): 367 | 368 | words = re.findall(r'\w+',message) 369 | probs = {'senang':0.0,'sedih':0.0,'marah':0.0,'malu':0.0, 370 | 'jijik':0.0,'takut':0.0,'bersalah':0.0} 371 | 372 | for category in probs.keys(): 373 | valids = Keyword.get_word_valid_cache(category) 374 | for word in words: 375 | word = word.lower() 376 | if word in valids: 377 | probs[category] += Keyword.get_prob(category,word) 378 | 379 | 380 | #smiles = message.split() 381 | #smiley_valids = Keyword.get_custome_keyword_cache() 382 | 383 | 384 | 385 | 386 | 387 | 388 | probs.update({'uncategory':0.0}) 389 | 390 | return probs 391 | 392 | @classmethod 393 | def check_emotion(cls,message): 394 | probs = cls.get_probs(message) 395 | 396 | hight = 'uncategory' 397 | 398 | for category in probs: 399 | if probs[category] > probs[hight]: 400 | hight = category 401 | 402 | return hight 403 | 404 | --------------------------------------------------------------------------------