├── __init__.py ├── cache ├── cache.lock └── cache.shelve.db ├── cron └── crontab ├── modules ├── __init__.py └── __init__.pyc ├── views ├── default │ ├── user.html │ ├── reset_password.html │ ├── new_password.html │ ├── profile.html │ ├── category.html │ ├── edit_comment.html │ ├── post_chrome.html │ ├── post.html │ ├── register.html │ ├── login_chrome.html │ ├── login.html │ ├── index.mobile.html │ ├── about.html │ ├── mylink.html │ ├── downlink.html │ ├── uplink.html │ ├── index.html │ ├── error.html │ └── comments.html ├── generic.html ├── layout_chrome.html ├── web2py_ajax.html ├── layout_mobile.html ├── layout_wide.html ├── layout.html └── appadmin.html ├── __init__.pyc ├── static ├── 404.png ├── eye.png ├── up.png ├── book.png ├── down.png ├── robots.txt ├── title.png ├── arrow_up.png ├── favicon.ico ├── arrow_down.png ├── google_btn.png ├── iphoneicon.png ├── img │ ├── glyphicons-halflings.png │ └── glyphicons-halflings-white.png ├── dropdown.js ├── bootstrap-dropdown.js ├── css │ ├── main_ori.css │ ├── bootstrap-responsive.css │ └── main.css ├── bootstrap-collapse.js ├── bootstrap-modal.js └── bootstrap-tooltip.js ├── languages ├── it.py ├── it-it.py ├── ko.py └── ko-kr.py ├── .gitignore ├── README.md ├── LICENSE ├── models ├── helper_timesince.py └── db.py └── controllers ├── appadmin.py └── default.py /__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /cache/cache.lock: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /cron/crontab: -------------------------------------------------------------------------------- 1 | #crontab -------------------------------------------------------------------------------- /modules/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /views/default/user.html: -------------------------------------------------------------------------------- 1 | {{=form}} -------------------------------------------------------------------------------- /__init__.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sungchi/feed9/HEAD/__init__.pyc -------------------------------------------------------------------------------- /static/404.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sungchi/feed9/HEAD/static/404.png -------------------------------------------------------------------------------- /static/eye.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sungchi/feed9/HEAD/static/eye.png -------------------------------------------------------------------------------- /static/up.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sungchi/feed9/HEAD/static/up.png -------------------------------------------------------------------------------- /views/generic.html: -------------------------------------------------------------------------------- 1 | {{extend 'layout.html'}} 2 | {{=BEAUTIFY(response._vars)}} -------------------------------------------------------------------------------- /static/book.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sungchi/feed9/HEAD/static/book.png -------------------------------------------------------------------------------- /static/down.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sungchi/feed9/HEAD/static/down.png -------------------------------------------------------------------------------- /static/robots.txt: -------------------------------------------------------------------------------- 1 | User-agent: * 2 | Disallow: /welcome 3 | Disallow: /admin 4 | -------------------------------------------------------------------------------- /static/title.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sungchi/feed9/HEAD/static/title.png -------------------------------------------------------------------------------- /static/arrow_up.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sungchi/feed9/HEAD/static/arrow_up.png -------------------------------------------------------------------------------- /static/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sungchi/feed9/HEAD/static/favicon.ico -------------------------------------------------------------------------------- /cache/cache.shelve.db: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sungchi/feed9/HEAD/cache/cache.shelve.db -------------------------------------------------------------------------------- /modules/__init__.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sungchi/feed9/HEAD/modules/__init__.pyc -------------------------------------------------------------------------------- /static/arrow_down.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sungchi/feed9/HEAD/static/arrow_down.png -------------------------------------------------------------------------------- /static/google_btn.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sungchi/feed9/HEAD/static/google_btn.png -------------------------------------------------------------------------------- /static/iphoneicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sungchi/feed9/HEAD/static/iphoneicon.png -------------------------------------------------------------------------------- /languages/it.py: -------------------------------------------------------------------------------- 1 | { 2 | 'Hello World':'Salve Mondo', 3 | 'Welcome to web2py':'Ciao da wek2py', 4 | } 5 | -------------------------------------------------------------------------------- /languages/it-it.py: -------------------------------------------------------------------------------- 1 | { 2 | 'Hello World':'Salve Mondo', 3 | 'Welcome to web2py':'Ciao da wek2py', 4 | } 5 | -------------------------------------------------------------------------------- /static/img/glyphicons-halflings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sungchi/feed9/HEAD/static/img/glyphicons-halflings.png -------------------------------------------------------------------------------- /static/img/glyphicons-halflings-white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sungchi/feed9/HEAD/static/img/glyphicons-halflings-white.png -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | *.bak 3 | *.swp 4 | sessions 5 | databases 6 | cache 7 | errors 8 | main_ori.css 9 | static/ui.datepicker.js 10 | static/ui.datepicker.css 11 | -------------------------------------------------------------------------------- /views/default/reset_password.html: -------------------------------------------------------------------------------- 1 | {{extend 'layout_wide.html'}} 2 | 3 | {{=form.custom.begin}} 4 |
{{=form.custom.widget.email}}
5 | {{=form.custom.submit}} 6 | {{=form.custom.end}} 7 | 8 | {{block page_name}} 9 | 비밀번호 찾기 10 | {{end}} 11 | -------------------------------------------------------------------------------- /views/default/new_password.html: -------------------------------------------------------------------------------- 1 | {{extend 'layout_wide.html'}} 2 | 3 | {{=form.custom.begin}} 4 |
{{=form.custom.widget.new_password}}
5 |
{{=form.custom.widget.new_password2}}
6 |
{{=form.custom.submit}}
7 | {{=form.custom.end}} 8 | 9 | {{block page_name}} 10 | 비밀번호 재설정 11 | {{end}} 12 | -------------------------------------------------------------------------------- /views/default/profile.html: -------------------------------------------------------------------------------- 1 | {{extend 'layout_wide.html'}} 2 | {{=form.custom.begin}} 3 |
{{=form.custom.widget.alias}}
4 |
{{=form.custom.widget.email}}
5 |
{{=form.custom.submit}}
6 | {{=form.custom.end}} 7 | {{block titlebar}} 8 | 프로필 - Feed9 9 | {{end}} 10 | {{block page_name}} 11 | 프로필 12 | {{end}} -------------------------------------------------------------------------------- /languages/ko.py: -------------------------------------------------------------------------------- 1 | # coding: utf8 2 | { 3 | 'one year':'일년', 4 | '%(n)d years':'%(n)d년', 5 | 'one month':'한달', 6 | '%(n)d months':'%(n)d달', 7 | 'one week':'일주일', 8 | '%(n)d weeks':'%(n)d주', 9 | 'one day':'하루', 10 | '%(n)d days':'%(n)d일', 11 | 'one hour':'한시간', 12 | '%(n)d hours':'%(n)d시간', 13 | 'one minute':'일분', 14 | '%(n)d minutes':'%(n)d분', 15 | 'an instant':'방금', 16 | '%(n)d seconds':'%(n)d초', 17 | } 18 | -------------------------------------------------------------------------------- /views/default/category.html: -------------------------------------------------------------------------------- 1 | {{extend 'layout_wide.html'}} 2 | {{ 3 | from urlparse import urlparse 4 | }} 5 | {{if cat_list:}} 6 |
7 | {{for category in cat_list:}} 8 | {{=A(category[0],_href=URL(r=request,f='index',args=[category[1]]))}} 9 | {{pass}} 10 |
11 | {{pass}} 12 | 13 | 14 | {{block page_name}} 15 | 카테고리 목록 16 | {{end}} 17 | -------------------------------------------------------------------------------- /languages/ko-kr.py: -------------------------------------------------------------------------------- 1 | # coding: utf8 2 | { 3 | 'one year':'일년', 4 | '%(n)d years':'%(n)d년', 5 | 'one month':'한달', 6 | '%(n)d months':'%(n)d달', 7 | 'one week':'일주일', 8 | '%(n)d weeks':'%(n)d주', 9 | 'one day':'하루', 10 | '%(n)d days':'%(n)d일', 11 | 'one hour':'한시간', 12 | '%(n)d hours':'%(n)d시간', 13 | 'one minute':'일분', 14 | '%(n)d minutes':'%(n)d분', 15 | 'an instant':'방금', 16 | '%(n)d seconds':'%(n)d초', 17 | } 18 | -------------------------------------------------------------------------------- /views/default/edit_comment.html: -------------------------------------------------------------------------------- 1 | {{extend 'layout_wide.html'}} 2 | 3 | {{if form:}} 4 | {{=form.custom.begin}} 5 |
{{=form.custom.widget.body}}
6 |
7 |
마크다운 문법 도움말 {{=form.custom.submit}}
8 | {{=form.custom.end}} 9 | {{pass}} 10 | 11 | {{block page_name}} 12 | 코멘트 수정 13 | {{end}} -------------------------------------------------------------------------------- /views/default/post_chrome.html: -------------------------------------------------------------------------------- 1 | {{extend 'layout_chrome.html'}} 2 | {{if form:}} 3 | {{=form.custom.begin}} 4 |
{{=form.custom.widget.url}}
5 |
{{=form.custom.widget.title}}
6 |
7 | 13 | 14 |
15 |
{{=form.custom.submit}}
16 | {{=form.custom.end}} 17 | {{else:}} 18 | 올라갔다능 19 | {{pass}} 20 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | FEED9 2 | ===== 3 | 4 | Feed9은 공유하는 링크들의 주소를 줄이고, 클릭횟수를 확인하고, 공유한 링크들을 관리하기 위해 만들어졌습니다. 누구나 회원가입해서 다른 사람의 링크를 보고 점수를 줄 수 있습니다. 5 | 6 | 회원가입 후에 제목(필수),링크,카테고리를 입력해서 링크를 올릴 수 있습니다. 각각의 링크는 Feed9의 주소가 부여되는데 그 주소를 짧은 주소로 이용해 외부에 공유하면 클릭 숫자가 집계됩니다. 7 | 8 | Feed9은 "투자와 인맥으로부터 자유로운 인디 웹서비스"입니다.(강제로 자유) 9 | 10 | 카테고리 신청, 피드백 11 | --------------------- 12 | 13 | admin@feed9.com, @sungchi 14 | 15 | web2py 소스 수정(이 저장소에는 web2py 소스가 없습니다): 16 | 17 | 1. gae_google_account.py : 사용자 model에 맞춰서 수정 18 | 2. routes.py : fancy URL 추가 19 | 3. gluon/tools.py : cas.get_user() 아랫부분 수정 -------------------------------------------------------------------------------- /views/default/post.html: -------------------------------------------------------------------------------- 1 | {{extend 'layout_wide.html'}} 2 | {{=form.custom.begin}} 3 |
{{=form.custom.widget.url}}
4 |
{{=form.custom.widget.title}}
5 |
6 | 7 | {{for item in cat_list:}} 8 | 10 | {{pass}} 11 |
12 |
{{=form.custom.submit}}
13 | {{=form.custom.end}} 14 | {{block page_name}} 15 | 새로 올리기 16 | {{end}} 17 | -------------------------------------------------------------------------------- /views/default/register.html: -------------------------------------------------------------------------------- 1 | {{extend 'layout_wide.html'}} 2 | 구글 아이디 로그인 3 | {{=form.custom.begin}} 4 |
닉네임{{=form.custom.widget.alias}}
5 |
이메일 (아이디){{=form.custom.widget.email}}
6 |
비밀번호{{=form.custom.widget.password}}
7 |
{{=form.custom.widget.password_two}}
8 |
{{=form.custom.submit}}
9 | {{=form.custom.end}} 10 | {{block page_name}} 11 | 회원가입 12 | {{end}} 13 | {{block titlebar}} 14 | 회원가입 - Feed9 15 | {{end}} 16 | -------------------------------------------------------------------------------- /views/default/login_chrome.html: -------------------------------------------------------------------------------- 1 | {{extend 'layout_chrome.html'}} 2 | 구글 아이디 로그인 3 | {{=login_form.custom.begin}} 4 |
5 |
{{=login_form.custom.widget.email}}
6 |
{{=login_form.custom.widget.password}}
7 |
{{=A('회원가입',_class="reset_link",_target="_blank",_href=URL(r=request,f='register'))}}
8 |
{{=login_form.custom.submit}}
9 |
10 | {{=login_form.custom.end}} 11 | -------------------------------------------------------------------------------- /views/default/login.html: -------------------------------------------------------------------------------- 1 | {{extend 'layout_wide.html'}} 2 | 구글 아이디 로그인 3 | {{=login_form.custom.begin}} 4 |
{{=login_form.custom.widget.email}}
5 |
{{=login_form.custom.widget.password}}
6 |
{{=A('비밀번호 찾기',_class="reset_link",_href=URL(r=request,f='reset_password'))}}
7 |
{{=login_form.custom.submit}}
8 | {{=login_form.custom.end}} 9 | 10 | 11 | {{block titlebar}} 12 | 로그인 - Feed9 13 | {{end}} 14 | {{block page_name}} 15 | 로그인 16 | {{end}} -------------------------------------------------------------------------------- /static/dropdown.js: -------------------------------------------------------------------------------- 1 | !function( $ ){ 2 | 3 | "use strict" 4 | 5 | /* DROPDOWN PLUGIN DEFINITION 6 | * ========================== */ 7 | 8 | $.fn.dropdown = function ( selector ) { 9 | return this.each(function () { 10 | $(this).delegate(selector || d, 'click', function (e) { 11 | var li = $(this).parent('li') 12 | , isActive = li.hasClass('open') 13 | 14 | clearMenus() 15 | !isActive && li.toggleClass('open') 16 | return false 17 | }) 18 | }) 19 | } 20 | 21 | /* APPLY TO STANDARD DROPDOWN ELEMENTS 22 | * =================================== */ 23 | 24 | var d = 'a.menu, .dropdown-toggle' 25 | 26 | function clearMenus() { 27 | $(d).parent('li').removeClass('open') 28 | } 29 | 30 | $(function () { 31 | 32 | $('body').dropdown( '[data-dropdown] a.menu, [data-dropdown] .dropdown-toggle' ) 33 | }) 34 | 35 | }( window.jQuery || window.ender ); 36 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | Copyright © 2012 sungchi, http://www.feed9.com/ 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 5 | 6 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 7 | 8 | THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 9 | -------------------------------------------------------------------------------- /models/helper_timesince.py: -------------------------------------------------------------------------------- 1 | import datetime, time 2 | 3 | def timesince(d0, t0): 4 | chunks = ( 5 | (60 * 60 * 24 * 365, lambda n: T('one year') if n==1 else T('%(n)d years',dict(n=n))), 6 | (60 * 60 * 24 * 30, lambda n: T('one month') if n==1 else T('%(n)d months',dict(n=n))), 7 | (60 * 60 * 24 * 7, lambda n: T('one week') if n==1 else T('%(n)d weeks',dict(n=n))), 8 | (60 * 60 * 24, lambda n: T('one day') if n==1 else T('%(n)d days',dict(n=n))), 9 | (60 * 60, lambda n: T('one hour') if n==1 else T('%(n)d hours',dict(n=n))), 10 | (60, lambda n: T('one minute') if n==1 else T('%(n)d minutes',dict(n=n))), 11 | (1, lambda n: T('an instant') if n==1 else T('%(n)d seconds',dict(n=n))), 12 | ) 13 | now = datetime.datetime.fromtimestamp(t0) 14 | d=datetime.datetime.fromtimestamp(d0) 15 | delta = now - (d - datetime.timedelta(0, 0, d.microsecond)) 16 | since = delta.days * 24 * 60 * 60 + delta.seconds 17 | if since <= 0: return T('an instant') 18 | for seconds, name in chunks: 19 | count = since // seconds 20 | if count != 0: break 21 | return name(count) 22 | -------------------------------------------------------------------------------- /views/layout_chrome.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | {{block titlebar}}Feed9{{end}} 10 | 23 | 24 | 25 | 26 |
27 | 28 |
29 |
30 |
31 | {{include}} 32 |
33 |
34 |
35 | 36 |
37 | 38 | 39 | -------------------------------------------------------------------------------- /views/default/index.mobile.html: -------------------------------------------------------------------------------- 1 | {{extend 'layout_mobile.html'}} 2 | {{ 3 | from urlparse import urlparse 4 | }} 5 | 6 | 28 | 35 | {{block page_name}} 36 | {{=alias}} 37 | {{end}} 38 | {{block titlebar}} 39 | {{=alias}} - Feed9 40 | {{end}} 41 | 42 | {{block footer_nav}} 43 |
  • {{=A('화제',_href=URL(r=request,args=[category,'hot',page]))}}
  • 44 |
  • {{=A('최근',_href=URL(r=request,args=[category,'new',page]))}}
  • 45 |
  • {{=A('인기',_href=URL(r=request,args=[category,'score',page]))}}
  • 46 | {{end}} -------------------------------------------------------------------------------- /static/bootstrap-dropdown.js: -------------------------------------------------------------------------------- 1 | !function( $ ){ 2 | 3 | "use strict" 4 | 5 | /* DROPDOWN CLASS DEFINITION 6 | * ========================= */ 7 | 8 | var toggle = '[data-toggle="dropdown"]' 9 | , Dropdown = function ( element ) { 10 | var $el = $(element).on('click.dropdown.data-api', this.toggle) 11 | $('html').on('click.dropdown.data-api', function () { 12 | $el.parent().removeClass('open') 13 | }) 14 | } 15 | 16 | Dropdown.prototype = { 17 | 18 | constructor: Dropdown 19 | 20 | , toggle: function ( e ) { 21 | var $this = $(this) 22 | , selector = $this.attr('data-target') 23 | , $parent 24 | , isActive 25 | 26 | if (!selector) { 27 | selector = $this.attr('href') 28 | selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') //strip for ie7 29 | } 30 | 31 | $parent = $(selector) 32 | $parent.length || ($parent = $this.parent()) 33 | 34 | isActive = $parent.hasClass('open') 35 | 36 | clearMenus() 37 | !isActive && $parent.toggleClass('open') 38 | 39 | return false 40 | } 41 | 42 | } 43 | 44 | function clearMenus() { 45 | $(toggle).parent().removeClass('open') 46 | } 47 | 48 | 49 | /* DROPDOWN PLUGIN DEFINITION 50 | * ========================== */ 51 | 52 | $.fn.dropdown = function ( option ) { 53 | return this.each(function () { 54 | var $this = $(this) 55 | , data = $this.data('dropdown') 56 | if (!data) $this.data('dropdown', (data = new Dropdown(this))) 57 | if (typeof option == 'string') data[option].call($this) 58 | }) 59 | } 60 | 61 | $.fn.dropdown.Constructor = Dropdown 62 | 63 | 64 | /* APPLY TO STANDARD DROPDOWN ELEMENTS 65 | * =================================== */ 66 | 67 | $(function () { 68 | 69 | $('body').on('click.dropdown.data-api', toggle, Dropdown.prototype.toggle) 70 | }) 71 | 72 | }( window.jQuery ) 73 | -------------------------------------------------------------------------------- /views/web2py_ajax.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 40 | -------------------------------------------------------------------------------- /views/default/about.html: -------------------------------------------------------------------------------- 1 | {{extend 'layout_wide.html'}} 2 | {{ 3 | from urlparse import urlparse 4 | }} 5 |
    6 |
    7 |

    Feed9은 공유하는 링크들의 주소를 줄이고, 클릭횟수를 확인하고, 공유한 링크들을 관리하기 위해 만들어졌습니다. 누구나 회원가입해서 다른 사람의 링크를 보고 점수를 줄 수 있습니다.

    8 |

    회원가입 후에 제목(필수),링크,카테고리를 입력해서 링크를 올릴 수 있습니다. 각각의 링크는 Feed9의 주소가 부여되는데 그 주소를 짧은 주소로 이용해 외부에 공유하면 클릭 숫자가 집계됩니다.

    9 |

    Feed9은 투자와 인맥으로부터 자유로운 인디 웹서비스입니다. (강제로 자유)

    10 |
    11 |

    카테고리 신청, 피드백: 12 |
    admin@feed9.com 13 |
    14 | 15 | 16 |
    17 | 18 | 19 |

    20 | 21 |

    협찬: 22 |
    github.com/reddit
    23 | twitter.github.com/bootstrap
    24 | web2py.com
    25 | appengine.google.com
    26 | somerandomdude.com/work/iconic

    27 | 28 |

    Feed9 github(소스코드): 29 |
    github.com/sungchi/feed9

    30 |
    31 |
    32 |
    33 | 34 |
    35 | 42 |
    43 | {{block page_name}} 44 | Feed9 소개 "인터넷을 모읍니다" 45 | {{end}} 46 | -------------------------------------------------------------------------------- /views/default/mylink.html: -------------------------------------------------------------------------------- 1 | {{extend 'layout_wide.html'}} 2 | {{ 3 | from urlparse import urlparse 4 | }} 5 | 6 | 10 | 11 |
    12 | 24 | {{for k,item in enumerate(news):}}{{if k==50: continue}} 25 |
    26 |
    27 |
    28 |
    29 | {{=item.score}} 30 |
    31 |
    32 | {{=item.clicks}} 33 |
    34 |
    35 |
    36 | vote up 37 | vote down 38 | 39 |
    40 |
    41 |
    42 |
    43 | {{if item.category:}} 44 | {{=A(item.category_alias,_href=URL(r=request,f='index',args=[item.category]))}} 45 | {{pass}} 46 | {{if item.url.strip().lower()=='self':}} 47 | {{=A(item.title,_href=URL(r=request,f='comments',args=[item.id]))}} 48 | {{else:}} 49 | {{=A(item.title,_href=URL(r=request,f='bookmark',args=[item.id]))}} 50 | {{url=urlparse(item.url)}}({{=url.netloc}}){{pass}} 51 |
    52 |
    53 | {{=A('%i 코멘트'%item.comments,_href=URL(r=request,f='comments',args=[item.id]))}} {{=A('신고',_href=URL(r=request,f='report',args=[item.id]))}} {{if item.author==auth.user_id:}} {{=A('삭제',_href=URL(r=request,f='delete',args=[item.id]))}} {{pass}} {{=timesince(item.post_time,now)}} 전 {{=A(item.author_alias,_href=URL(r=request,f='person',args=[item.author]))}} 54 |
    55 |
    56 |
    57 | {{pass}} 58 | 62 | {{block page_name}} 63 | 내 링크내가 올린 링크 목록입니다 64 | {{end}} 65 | -------------------------------------------------------------------------------- /views/default/downlink.html: -------------------------------------------------------------------------------- 1 | {{extend 'layout_wide.html'}} 2 | {{ 3 | from urlparse import urlparse 4 | }} 5 | 6 | 10 | 11 |
    12 | 24 | {{for k,it in enumerate(news):}}{{if k==50: continue}} 25 | {{item=it.parentv}} 26 |
    27 |
    28 |
    29 |
    30 | {{=item.score}} 31 |
    32 |
    33 | {{=item.clicks}} 34 |
    35 |
    36 |
    37 | vote up 38 | vote down 39 | 40 |
    41 |
    42 |
    43 |
    44 | {{if item.category:}} 45 | {{=A(item.category_alias,_href=URL(r=request,f='index',args=[item.category]))}} 46 | {{pass}} 47 | {{if item.url.strip().lower()=='self':}} 48 | {{=A(item.title,_href=URL(r=request,f='comments',args=[item.id]))}} 49 | {{else:}} 50 | {{=A(item.title,_href=URL(r=request,f='bookmark',args=[item.id]))}} 51 | {{url=urlparse(item.url)}}({{=url.netloc}}){{pass}} 52 |
    53 |
    54 | {{=A('%i 코멘트'%item.comments,_href=URL(r=request,f='comments',args=[item.id]))}} {{=A('신고',_href=URL(r=request,f='report',args=[item.id]))}} {{if item.author==auth.user_id:}} {{=A('삭제',_href=URL(r=request,f='delete',args=[item.id]))}} {{pass}} {{=timesince(item.post_time,now)}} 전 {{=A(item.author_alias,_href=URL(r=request,f='person',args=[item.author]))}} 55 |
    56 |
    57 |
    58 | {{pass}} 59 | 63 | {{block page_name}} 64 | 점수내림내가 점수를 내린 링크 목록입니다 65 | {{end}} 66 | -------------------------------------------------------------------------------- /views/default/uplink.html: -------------------------------------------------------------------------------- 1 | {{extend 'layout_wide.html'}} 2 | {{ 3 | from urlparse import urlparse 4 | }} 5 | 6 | 10 | 11 |
    12 | 24 | {{for k,it in enumerate(news):}}{{if k==50: continue}} 25 | {{item=it.parentv}} 26 |
    27 |
    28 |
    29 |
    30 | {{=item.score}} 31 |
    32 |
    33 | {{=item.clicks}} 34 |
    35 |
    36 |
    37 | vote up 38 | vote down 39 | 40 |
    41 |
    42 |
    43 |
    44 | {{if item.category:}} 45 | {{=A(item.category_alias,_href=URL(r=request,f='index',args=[item.category]))}} 46 | {{pass}} 47 | {{if item.url.strip().lower()=='self':}} 48 | {{=A(item.title,_href=URL(r=request,f='comments',args=[item.id]))}} 49 | {{else:}} 50 | {{=A(item.title,_href=URL(r=request,f='bookmark',args=[item.id]))}} 51 | {{url=urlparse(item.url)}}({{=url.netloc}}){{pass}} 52 |
    53 |
    54 | {{=A('%i 코멘트'%item.comments,_href=URL(r=request,f='comments',args=[item.id]))}} {{=A('신고',_href=URL(r=request,f='report',args=[item.id]))}} {{if item.author==auth.user_id:}} {{=A('삭제',_href=URL(r=request,f='delete',args=[item.id]))}} {{pass}} {{=timesince(item.post_time,now)}} 전 {{=A(item.author_alias,_href=URL(r=request,f='person',args=[item.author]))}} 55 |
    56 |
    57 |
    58 | {{pass}} 59 | 63 | {{block page_name}} 64 | 점수올림내가 점수를 올린 링크 목록입니다 65 | {{end}} 66 | -------------------------------------------------------------------------------- /views/layout_mobile.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | {{block titlebar}}Feed9{{end}} 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 17 | 28 | 29 | 30 | 31 |
    32 | 33 |
    34 | 35 |

    {{block page_name}}{{end}}

    36 | 카테고리 37 |
    38 | 39 |
    40 | {{include}} 41 |
    42 |
    43 |
    44 |
      45 | {{block footer_nav}} 46 | {{end}} 47 |
    48 |
    49 |
    50 | 51 |
    52 | 53 | 54 |
    55 |
    56 | 57 |

    카테고리

    58 |
    59 | 60 |
    61 | {{if cat_list:}} 62 |
    63 | {{for category in cat_list:}} 64 | {{=category[0]}} 65 | {{pass}} 66 |
    67 | {{pass}} 68 |

    69 | 메인화면 돌아가기 70 |

    71 | 72 |
    73 |
    74 | 75 | 76 | 95 | 96 | 97 | 98 | 99 | -------------------------------------------------------------------------------- /static/css/main_ori.css: -------------------------------------------------------------------------------- 1 | * {margin:0; padding:0;} 2 | body, div, span, p, a, img, ul, ol, li, caption, table, thead, tbody, tfoot, tr, th, td, form, fieldset, legend, label, dl, dt, dd, blockquote, applet, object, h1, h2, h3, h4, h5 {border:0;} 3 | body {font:0.8em/1.5 "arial",sans-serif; text-align:center;} 4 | h1, h2, h3, h4, h5, h6 {margin:15px 0 10px 0; font-family:"arial",sans-serif;} 5 | ul, ol, dl, fieldset {margin:15px 0;} 6 | textarea {height:50px; width:400px} 7 | table {margin: 0px; border:0 padding:0; spacing:0;} 8 | th {text-align:center; font-weight:bold;} 9 | th, td {padding:2px 2px;} 10 | ul, ol {margin-left:30px;} 11 | ul ul, ol ol {margin:0; margin-left:20px;} 12 | ol {list-style-type:decimal;} 13 | li {display:list-item;} 14 | tr, dt {text-align:left; vertical-alignment: top} 15 | dd {margin-left:30px;} 16 | fieldset {position:relative; padding:10px;} 17 | legend {position:absolute; top:-1em; margin:0; padding:5px 10px; font-size:100%; font-weight:bold;} 18 | .box {min-height:1px;} 19 | .box:after {display:block; visibility:hidden; clear:both; line-height:0; font-size:0; content:".";} 20 | .relative {position:relative;} 21 | .clear {clear:both;} 22 | .main {position:relative; width:960px; margin:0 auto; text-align:left;} 23 | .score {font-size:+1.2em; font-weight: bold; text-align: center; vertical-alignment: middle;} 24 | .article {font-size:+1.3em;} 25 | .error { background-color: red; color: white; padding: 3px} 26 | 27 | #header {padding:10px 0; overflow:hidden} 28 | 29 | #logo {margin:0; margin-bottom:3px; font:normal 260%/1.2 "arial",sans-serif; letter-spacing:-1px;} 30 | #logo span {font-weight:bold;} 31 | #logo a {text-decoration:none;} 32 | #slogan {margin:0;} 33 | 34 | #search {position:absolute; top:0; right:0;} 35 | #search #search-input {width:170px; padding:4px; font:normal 100%/1.2 "arial",sans-serif;} 36 | #search #search-submit {padding:3px 5px; font:bold 100%/1.2 "arial",sans-serif;} 37 | 38 | #nav {clear:both; background:url("../title.png") 0 0 repeat-x; height: 35px;} 39 | #nav ul {margin:0; padding:0; list-style:none;} 40 | #nav li {display:inline; margin:0; padding:0;} 41 | #nav li a {display:block; float:left; height: 22px; padding:5px 20px; text-decoration:none; font-weight:bold;} 42 | #nav li #nav-active a {font-weight:bold; text-decoration:none;} 43 | 44 | #cols .main {padding-bottom:15px; background:url("../design/aside.gif") 100% 0 repeat-y;} 45 | 46 | #content {float:left; width:680px; padding:15px; } 47 | #content p {text-align:justify;} 48 | 49 | #content h1 {margin:0; margin-bottom:10px; font-size:160%;} 50 | #content h2, #content h3, #content h4 {margin-bottom:0; margin-bottom:10px; font-size:140%;} 51 | #content h3, #content h4 {letter-spacing:0; font-size:120%;} 52 | 53 | #aside {float:right; width:244px; padding-right:1px; overflow:hidden;} 54 | #aside ul {margin:5px 0 15px 0; padding:0; list-style:none;} 55 | #aside ul li {margin:0; padding:4px 10px 4px 0;} 56 | 57 | #footer {clear:both; padding:15px 0;} 58 | #footer p {margin:0;} 59 | 60 | /* COLOR */ 61 | 62 | body {background: #2B99B2; color:#000;} 63 | a {color: #FF5C1F; text-decoration: none} 64 | a:hover {color: #FF5C1F; text-decoration: underline;} 65 | fieldset {border:1px solid #175966;} 66 | legend {background:#FFF; color:#175966;} 67 | 68 | #header {background:#000;} 69 | #logo {border-bottom:1px solid #464646; color:#FFF;} 70 | #logo a {color:#FF5C1F;} 71 | #slogan {color:#B0B0B0;} 72 | #search #search-input {border:1px solid #FFF;} 73 | #search #search-submit {background:#175966; color:#FFF;} 74 | 75 | #nav {background-color:#175966;} 76 | #nav li a {border-left:1px solid #175966; color:#FF5C1F;} 77 | #nav li.last a {border-right:1px solid #175966;} 78 | #nav li#nav-active a {background:#FFF; color:#FF5C1F;} 79 | #nav li a:hover {background:#FFF; color:#FF5C1F;} 80 | 81 | #cols .main {background-color:#FFF;} 82 | 83 | #content h2 {border-bottom:1px solid #175966} 84 | #content h2, h3, h4, h5, h6 { color:#175966;} 85 | 86 | #aside h3 {color:#175966;} 87 | #aside ul li {border-bottom:1px solid #175966;} 88 | 89 | #footer {background:#000; color:#B0B0B0;} 90 | #footer a {color:#FF5C1F;} 91 | #footer a:hover {text-decoration: underline;} 92 | 93 | .main_box {border: 0px solid #175966; vertical-alignment: middle; text-align: center;} 94 | 95 | #flash { margin: 0 auto; text-align: center; clear: both; border: 1px #000000; background-color: #FF0000; color: white; margin-top: 0.0em; margin-bottom: 1.0em; padding-top: 1.0em; padding-bottom: 1.0em; } -------------------------------------------------------------------------------- /static/bootstrap-collapse.js: -------------------------------------------------------------------------------- 1 | /* ============================================================= 2 | * bootstrap-collapse.js v2.0.0 3 | * http://twitter.github.com/bootstrap/javascript.html#collapse 4 | * ============================================================= 5 | * Copyright 2012 Twitter, Inc. 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | * ============================================================ */ 19 | 20 | !function( $ ){ 21 | 22 | "use strict" 23 | 24 | var Collapse = function ( element, options ) { 25 | this.$element = $(element) 26 | this.options = $.extend({}, $.fn.collapse.defaults, options) 27 | 28 | if (this.options["parent"]) { 29 | this.$parent = $(this.options["parent"]) 30 | } 31 | 32 | this.options.toggle && this.toggle() 33 | } 34 | 35 | Collapse.prototype = { 36 | 37 | constructor: Collapse 38 | 39 | , dimension: function () { 40 | var hasWidth = this.$element.hasClass('width') 41 | return hasWidth ? 'width' : 'height' 42 | } 43 | 44 | , show: function () { 45 | var dimension = this.dimension() 46 | , scroll = $.camelCase(['scroll', dimension].join('-')) 47 | , actives = this.$parent && this.$parent.find('.in') 48 | , hasData 49 | 50 | if (actives && actives.length) { 51 | hasData = actives.data('collapse') 52 | actives.collapse('hide') 53 | hasData || actives.data('collapse', null) 54 | } 55 | 56 | this.$element[dimension](0) 57 | this.transition('addClass', 'show', 'shown') 58 | this.$element[dimension](this.$element[0][scroll]) 59 | 60 | } 61 | 62 | , hide: function () { 63 | var dimension = this.dimension() 64 | this.reset(this.$element[dimension]()) 65 | this.transition('removeClass', 'hide', 'hidden') 66 | this.$element[dimension](0) 67 | } 68 | 69 | , reset: function ( size ) { 70 | var dimension = this.dimension() 71 | 72 | this.$element 73 | .removeClass('collapse') 74 | [dimension](size || 'auto') 75 | [0].offsetWidth 76 | 77 | this.$element.addClass('collapse') 78 | } 79 | 80 | , transition: function ( method, startEvent, completeEvent ) { 81 | var that = this 82 | , complete = function () { 83 | if (startEvent == 'show') that.reset() 84 | that.$element.trigger(completeEvent) 85 | } 86 | 87 | this.$element 88 | .trigger(startEvent) 89 | [method]('in') 90 | 91 | $.support.transition && this.$element.hasClass('collapse') ? 92 | this.$element.one($.support.transition.end, complete) : 93 | complete() 94 | } 95 | 96 | , toggle: function () { 97 | this[this.$element.hasClass('in') ? 'hide' : 'show']() 98 | } 99 | 100 | } 101 | 102 | /* COLLAPSIBLE PLUGIN DEFINITION 103 | * ============================== */ 104 | 105 | $.fn.collapse = function ( option ) { 106 | return this.each(function () { 107 | var $this = $(this) 108 | , data = $this.data('collapse') 109 | , options = typeof option == 'object' && option 110 | if (!data) $this.data('collapse', (data = new Collapse(this, options))) 111 | if (typeof option == 'string') data[option]() 112 | }) 113 | } 114 | 115 | $.fn.collapse.defaults = { 116 | toggle: true 117 | } 118 | 119 | $.fn.collapse.Constructor = Collapse 120 | 121 | 122 | /* COLLAPSIBLE DATA-API 123 | * ==================== */ 124 | 125 | $(function () { 126 | $('body').on('click.collapse.data-api', '[data-toggle=collapse]', function ( e ) { 127 | var $this = $(this), href 128 | , target = $this.attr('data-target') 129 | || e.preventDefault() 130 | || (href = $this.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '') //strip for ie7 131 | , option = $(target).data('collapse') ? 'toggle' : $this.data() 132 | $(target).collapse(option) 133 | }) 134 | }) 135 | 136 | }( window.jQuery ) 137 | -------------------------------------------------------------------------------- /views/default/index.html: -------------------------------------------------------------------------------- 1 | {{extend 'layout.html'}} 2 | {{ 3 | from urlparse import urlparse 4 | }} 5 | 6 | 11 | {{ if page>0 or (page<3 and len(news)>25):}} 12 | 16 | {{pass}} 17 |
    18 | 19 | 31 | 32 | {{for k,item in enumerate(news):}}{{if k==25: continue}} 33 |
    34 |
    35 |
    36 |
    37 | {{=item.score}} 38 |
    39 |
    40 | {{=item.clicks}} 41 |
    42 |
    43 |
    44 | vote up 45 | vote down 46 |
    47 |
    48 |
    49 |
    50 | {{if category=='all' and item.category:}} 51 | {{=A(item.category_alias,_href=URL(r=request,f='index',args=[item.category]))}} 52 | {{pass}} 53 | {{if item.url.strip().lower()=='self':}} 54 | {{=A(item.title,_href=URL(r=request,f='comments',args=[item.id]))}} 55 | {{else:}} 56 | {{=A(item.title,_href=URL(r=request,f='bookmark',args=[item.id]))}} 57 | {{url=urlparse(item.url)}}({{=url.netloc}}){{pass}} 58 |
    59 |
    60 | {{=A('%i 코멘트'%item.comments,_href=URL(r=request,f='comments',args=[item.id]))}} {{=timesince(item.post_time,now)}} 전 {{=A(item.author_alias,_href=URL(r=request,f='person',args=[item.author]))}} 61 |
    62 |
    63 |
    64 |
    65 | 댓글 66 | 67 | 68 | 69 | 73 |
    74 |
    75 |
    76 | {{pass}} 77 | 81 | {{block category_name}} 82 | {{=alias}}{{=dec}} 83 | {{end}} 84 | {{block titlebar}} 85 | {{=alias}} - Feed9 86 | {{end}} 87 | -------------------------------------------------------------------------------- /models/db.py: -------------------------------------------------------------------------------- 1 | if request.controller.endswith('_examples'): response.generic_patterns.append('*') 2 | 3 | import time 4 | from math import log 5 | now=time.time() 6 | 7 | from gluon.settings import settings 8 | from gluon.tools import Auth 9 | import mail_setting 10 | from gluon.contrib.login_methods.gae_google_account import GaeGoogleAccount 11 | from gluon.contrib.login_methods.extended_login_form import ExtendedLoginForm 12 | # if running on Google App Engine 13 | if settings.web2py_runtime_gae: 14 | from gluon.contrib.gql import * 15 | from gluon.contrib.gae_memcache import MemcacheClient 16 | from gluon.contrib.memdb import MEMDB 17 | cache.memcache = MemcacheClient(request) 18 | cache.ram = cache.disk = cache.memcache 19 | # connect to Google BigTable 20 | db = DAL('gae') 21 | # and store sessions there 22 | #session.connect(request, response, db=db) 23 | session.connect(request,response,MEMDB(cache.memcache)) 24 | else: 25 | # if not, use SQLite or other DB 26 | db = DAL('sqlite://storage.sqlite') 27 | 28 | auth = Auth(db) 29 | auth.settings.table_user_name = 'person' 30 | auth.settings.request_reset_password_next = URL('index') 31 | auth.settings.reset_password_next = URL('login') 32 | auth.settings.expiration = 3600*24*30 33 | auth.settings.long_expiration = 3600*24*30 # one month 34 | auth.settings.remember_me_form = True 35 | #auth.settings.login_next = URL('index') 36 | auth.messages.reset_password= "다음 링크를 클릭하시면 비밀번호 재설정 페이지로 이동합니다. http://"+request.env.http_host+URL(r=request,f='new_password')+'/%(key)s' 37 | auth.settings.formstyle='divs' 38 | mail = auth.settings.mailer 39 | mail.settings.server = 'gae' 40 | mail.settings.sender = mail_setting.sender() 41 | mail.settings.login = mail_setting.login() 42 | db.define_table( 43 | auth.settings.table_user_name, 44 | Field('alias', length=128, default='',unique=True), 45 | Field('email', length=128, default='', unique=True), 46 | Field('password', 'password', length=512, 47 | readable=False, label='Password'), 48 | Field('registration_key', length=512, 49 | writable=False, readable=False, default=''), 50 | Field('reset_password_key', length=512, 51 | writable=False, readable=False, default=''), 52 | Field('registration_id', length=512, 53 | writable=False, readable=False, default='')) 54 | 55 | custom_auth_table = db[auth.settings.table_user_name] 56 | custom_auth_table.password.requires = [IS_NOT_EMPTY(),CRYPT()] 57 | custom_auth_table.email.requires = [ 58 | IS_EMAIL(error_message=auth.messages.invalid_email), 59 | IS_NOT_IN_DB(db, custom_auth_table.email),IS_NOT_EMPTY()] 60 | 61 | auth.settings.table_user = custom_auth_table 62 | auth.define_tables(username=False) 63 | #auth.settings.login_form = ExtendedLoginForm(auth, GaeGoogleAccount()) 64 | 65 | db.define_table('category', 66 | Field('name'), 67 | Field('alias',default='새 카테고리'), 68 | Field('description')) 69 | 70 | db.category.name.requires=[IS_MATCH('[a-z_]+'), 71 | IS_NOT_IN_DB(db,db.category.name)] 72 | db.category.description.requires=IS_NOT_EMPTY() 73 | 74 | db.define_table('news', 75 | Field('post_time','double',default=now), 76 | Field('clicks','integer',default=1), 77 | Field('comments','integer',default=0), 78 | Field('score','integer',default=1), 79 | Field('hotness','double',compute=lambda r: log(r['clicks'],10)+log(r['score'],10)+log(max(r['comments'],1),10)+log(max((r['post_time']-(now-2592000.0)),1),10),default=1.0), 80 | Field('category'), 81 | Field('category_alias'), 82 | Field('author',db.person), 83 | Field('author_alias'), 84 | Field('url',length=2048), 85 | Field('title',length=2048), 86 | Field('flagged','boolean',default=False)) 87 | 88 | #db.news.url.requires=[IS_NOT_EMPTY()] 89 | db.news.title.requires=IS_NOT_EMPTY() 90 | 91 | db.define_table('comment', 92 | Field('score','integer',default=1), 93 | Field('post_time','double',default=now), 94 | Field('author',db.person), 95 | Field('author_alias'), 96 | Field('parente','integer',default=0), 97 | Field('news',db.news), 98 | Field('body','text'), 99 | Field('flagged','boolean',default=False)) 100 | 101 | db.comment.body.requires=IS_NOT_EMPTY() 102 | 103 | db.define_table('vote', 104 | Field('choice','integer',default=0), 105 | Field('parentv',db.news), 106 | Field('voter',db.person)) 107 | 108 | db.define_table('vote_cmt', 109 | Field('choice','integer',default=0), 110 | Field('parentv',db.comment), 111 | Field('voter',db.person)) 112 | 113 | if len(db().select(db.category.ALL))==0: 114 | db.category.insert(name='politics',alias='시사정치',description='최근 많이 이야기되는 시사, 정치 뉴스들') 115 | db.category.insert(name='programming',alias='프로그래밍',description='삶을 윤택하게 만드는 코드') 116 | db.category.insert(name='technology',alias='테크놀로지',description='새로운 기술과 신제품') 117 | db.category.insert(name='movie',alias='영화',description='새 예고편, 영화 소식, 좋은 리뷰들') 118 | db.category.insert(name='accident',alias='사건사고',description='') 119 | db.category.insert(name='diablo',alias='디아블로',description='그냥 디아블로가 좋아...') 120 | db.category.insert(name='game',alias='게임',description='게임은 사회를 좀먹게 하는 질병입니다') 121 | db.category.insert(name='drama',alias='미드',description='미드 소식, 동영상, 추천 정보들...') 122 | db.category.insert(name='funny',alias='유머',description='조금만 재미있어도 공유합니다.') 123 | db.category.insert(name='body',alias='사람사진',description='주로 여자 사진이 될 것 같지만') 124 | -------------------------------------------------------------------------------- /views/layout_wide.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 11 | 12 | 32 | 33 | 34 | {{block titlebar}}Feed9{{end}} 35 | 48 | 49 | 50 | 51 | 104 | 105 |
    106 | 107 |
    108 | 111 |
    112 |
    113 | {{if response.flash:}}
    {{=response.flash}}
    {{pass}} 114 | {{include}} 115 |
    116 |
    117 |
    118 | 119 | 122 | 123 |
    124 | 125 | {{include 'web2py_ajax.html'}} 126 | {{block comment_hide}} 127 | {{end}} 128 | 129 | 130 | -------------------------------------------------------------------------------- /views/default/error.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 11 | 12 | 32 | 33 | 34 | {{block titlebar}}Feed9{{end}} 35 | 48 | 49 | 50 | 51 | 104 | 105 |
    106 | 107 |
    108 | 111 |
    112 |
    113 |
    114 |

    page not found.

    115 |
    116 |
    117 |
    118 |
    119 | 120 | 123 | 124 |
    125 | 126 | {{include 'web2py_ajax.html'}} 127 | {{block comment_hide}} 128 | {{end}} 129 | 130 | 131 | -------------------------------------------------------------------------------- /views/layout.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 11 | 12 | 32 | 33 | 34 | {{block titlebar}}Feed9{{end}} 35 | 48 | 49 | 50 | 51 | 104 | 105 |
    106 | 107 |
    108 | 111 |
    112 |
    113 | {{if response.flash:}}
    {{=response.flash}}
    {{pass}} 114 | {{include}} 115 |
    116 | 130 |
    131 |
    132 | 133 | 136 | 137 |
    138 | 139 | {{include 'web2py_ajax.html'}} 140 | {{block comment_hide}} 141 | {{end}} 142 | 143 | 144 | -------------------------------------------------------------------------------- /views/default/comments.html: -------------------------------------------------------------------------------- 1 | {{extend 'layout.html'}} 2 | {{from gluon.contrib.markdown import WIKI}} 3 | {{ 4 | from urlparse import urlparse 5 | }} 6 | 7 | {{def listcomments(id):}} 8 | {{if not tree.has_key(id): return}} 9 | 10 | {{for item in tree[id]:}} 11 |
    12 |
    13 |
    14 |
    15 | {{=item.score}} 16 |
    17 |
    18 |
    19 | vote up 20 | vote down 21 |
    22 |
    23 | 24 |
    25 | {{=WIKI(item.body.strip())}} 26 | {{=A('고유주소',_href=URL(r=request,f='permalink',args=[item.id]))}} {{=A('신고',_href=URL(r=request,f='report_comment',args=[item.id]))}} {{=A('코멘트',_href="javascript:toggle(%i)"%item.id if auth.user_id else URL(r=request,f='login'))}} {{if item.author==auth.user_id:}}{{=A('수정',_href=URL(r=request,f='edit_comment',args=[item.id]))}} {{pass}} 27 | {{=timesince(item.post_time,now)}} 전 {{=A(item.author_alias,_href=URL(r=request,f='person',args=[item.author]))}} 28 |
    29 |
    30 | {{if forms:}} 31 | {{=forms[item.id].custom.begin}} 32 |
    33 |
    {{=forms[item.id].custom.widget.body}}
    34 |
    닫기 마크다운 문법 도움말 {{=forms[item.id].custom.submit}}
    35 | {{=forms[item.id].custom.end}} 36 |
    {{pass}} 37 |
    38 | {{listcomments(item.id)}} 39 |
    40 | 41 | {{pass}} 42 | {{return}} 43 | 44 |
    45 | 46 | 58 | 59 | {{if item:}} 60 |
    61 |
    62 |
    63 |
    64 | {{=item.score}} 65 |
    66 |
    67 | {{=item.clicks}} 68 |
    69 |
    70 |
    71 | vote up 72 | vote down 73 | 74 |
    75 |
    76 |
    77 |
    78 | {{if item.category:}} 79 | {{=A(item.category_alias,_href=URL(r=request,f='index',args=[item.category]))}} 80 | {{pass}} 81 | {{if item.url.strip().lower()=='self':}} 82 | {{=A(item.title,_href=URL(r=request,f='comments',args=[item.id]))}} 83 | {{else:}} 84 | {{=A(item.title,_href=URL(r=request,f='bookmark',args=[item.id]))}} 85 | {{url=urlparse(item.url)}}({{=url.netloc}}){{pass}} 86 |
    87 |
    88 | {{=A('%i 코멘트'%item.comments,_href=URL(r=request,f='comments',args=[item.id]))}} {{=A('신고',_href=URL(r=request,f='report',args=[item.id]))}} {{if item.author==auth.user_id:}} {{=A('삭제',_href=URL(r=request,f='delete',args=[item.id]))}} {{pass}} {{=timesince(item.post_time,now)}} 전 {{=A(item.author_alias,_href=URL(r=request,f='person',args=[item.author]))}} 89 |
    90 |
    91 |
    92 | {{pass}} 93 | 94 |

    코멘트

    95 |
    96 | 103 | 104 |
    105 | 106 | {{if form:}} 107 | {{=form.custom.begin}} 108 |
    {{=form.custom.widget.body}}
    109 |
    마크다운 문법 도움말 {{=form.custom.submit}}
    110 | {{=form.custom.end}} 111 | {{else:}} 112 |
    113 | {{=A('로그인',_class='btn',_href=URL(r=request,f='login'))}} {{=A('회원가입',_class='btn',_href=URL(r=request,f='register'))}} 114 |
    115 | {{pass}} 116 | 117 | {{listcomments(parent)}} 118 | {{block comment_hide}} 119 | 128 | 129 | {{end}} 130 | {{block titlebar}} 131 | {{if item:}}{{=item.title[:100]}}{{else:}}코멘트{{pass}} - Feed9 132 | {{end}} 133 | -------------------------------------------------------------------------------- /static/bootstrap-modal.js: -------------------------------------------------------------------------------- 1 | !function( $ ){ 2 | 3 | "use strict" 4 | 5 | /* CSS TRANSITION SUPPORT (https://gist.github.com/373874) 6 | * ======================================================= */ 7 | 8 | var transitionEnd 9 | 10 | $(document).ready(function () { 11 | 12 | $.support.transition = (function () { 13 | var thisBody = document.body || document.documentElement 14 | , thisStyle = thisBody.style 15 | , support = thisStyle.transition !== undefined || thisStyle.WebkitTransition !== undefined || thisStyle.MozTransition !== undefined || thisStyle.MsTransition !== undefined || thisStyle.OTransition !== undefined 16 | return support 17 | })() 18 | 19 | // set CSS transition event type 20 | if ( $.support.transition ) { 21 | transitionEnd = "TransitionEnd" 22 | if ( $.browser.webkit ) { 23 | transitionEnd = "webkitTransitionEnd" 24 | } else if ( $.browser.mozilla ) { 25 | transitionEnd = "transitionend" 26 | } else if ( $.browser.opera ) { 27 | transitionEnd = "oTransitionEnd" 28 | } 29 | } 30 | 31 | }) 32 | 33 | 34 | /* MODAL PUBLIC CLASS DEFINITION 35 | * ============================= */ 36 | 37 | var Modal = function ( content, options ) { 38 | this.settings = $.extend({}, $.fn.modal.defaults, options) 39 | this.$element = $(content) 40 | .delegate('.close', 'click.modal', $.proxy(this.hide, this)) 41 | 42 | if ( this.settings.show ) { 43 | this.show() 44 | } 45 | 46 | return this 47 | } 48 | 49 | Modal.prototype = { 50 | 51 | toggle: function () { 52 | return this[!this.isShown ? 'show' : 'hide']() 53 | } 54 | 55 | , show: function () { 56 | var that = this 57 | this.isShown = true 58 | this.$element.trigger('show') 59 | 60 | escape.call(this) 61 | backdrop.call(this, function () { 62 | var transition = $.support.transition && that.$element.hasClass('fade') 63 | 64 | that.$element 65 | .appendTo(document.body) 66 | .show() 67 | 68 | if (transition) { 69 | that.$element[0].offsetWidth // force reflow 70 | } 71 | 72 | that.$element.addClass('in') 73 | 74 | transition ? 75 | that.$element.one(transitionEnd, function () { that.$element.trigger('shown') }) : 76 | that.$element.trigger('shown') 77 | 78 | }) 79 | 80 | return this 81 | } 82 | 83 | , hide: function (e) { 84 | e && e.preventDefault() 85 | 86 | if ( !this.isShown ) { 87 | return this 88 | } 89 | 90 | var that = this 91 | this.isShown = false 92 | 93 | escape.call(this) 94 | 95 | this.$element 96 | .trigger('hide') 97 | .removeClass('in') 98 | 99 | $.support.transition && this.$element.hasClass('fade') ? 100 | hideWithTransition.call(this) : 101 | hideModal.call(this) 102 | 103 | return this 104 | } 105 | 106 | } 107 | 108 | 109 | /* MODAL PRIVATE METHODS 110 | * ===================== */ 111 | 112 | function hideWithTransition() { 113 | // firefox drops transitionEnd events :{o 114 | var that = this 115 | , timeout = setTimeout(function () { 116 | that.$element.unbind(transitionEnd) 117 | hideModal.call(that) 118 | }, 500) 119 | 120 | this.$element.one(transitionEnd, function () { 121 | clearTimeout(timeout) 122 | hideModal.call(that) 123 | }) 124 | } 125 | 126 | function hideModal (that) { 127 | this.$element 128 | .hide() 129 | .trigger('hidden') 130 | 131 | backdrop.call(this) 132 | } 133 | 134 | function backdrop ( callback ) { 135 | var that = this 136 | , animate = this.$element.hasClass('fade') ? 'fade' : '' 137 | if ( this.isShown && this.settings.backdrop ) { 138 | var doAnimate = $.support.transition && animate 139 | 140 | this.$backdrop = $(' 62 | {{pass}} 63 |

    {{=T("Import/Export")}}


    64 | [ {{=T("export as csv file")}} ] 65 | {{if table:}} 66 | {{=FORM(str(T('or import from csv file'))+" ",INPUT(_type='file',_name='csvfile'),INPUT(_type='hidden',_value=table,_name='table'),INPUT(_type='submit',_value='import'))}} 67 | {{pass}} 68 | 69 | 70 | {{elif request.function=='insert':}} 71 |

    {{=T("database")}} {{=A(request.args[0],_href=URL('index'))}} 72 | {{if hasattr(table,'_primarykey'):}} 73 | {{fieldname=table._primarykey[0]}} 74 | {{dbname=request.args[0]}} 75 | {{tablename=request.args[1]}} 76 | {{cond = table[fieldname].type in ['string','text'] and '!=""' or '>0'}} 77 | {{=T("table")}} {{=A(tablename,_href=URL('select',args=dbname,vars=dict(query='%s.%s.%s%s'%(dbname,tablename,fieldname,cond))))}} 78 | {{else:}} 79 | {{=T("table")}} {{=A(request.args[1],_href=URL('select',args=request.args[0],vars=dict(query='%s.%s.id>0'%tuple(request.args[:2]))))}} 80 | {{pass}} 81 |

    82 |

    {{=T("New Record")}}


    83 | {{=form}} 84 | {{elif request.function=='update':}} 85 |

    {{=T("database")}} {{=A(request.args[0],_href=URL('index'))}} 86 | {{if hasattr(table,'_primarykey'):}} 87 | {{fieldname=request.vars.keys()[0]}} 88 | {{dbname=request.args[0]}} 89 | {{tablename=request.args[1]}} 90 | {{cond = table[fieldname].type in ['string','text'] and '!=""' or '>0'}} 91 | {{=T("table")}} {{=A(tablename,_href=URL('select',args=dbname,vars=dict(query='%s.%s.%s%s'%(dbname,tablename,fieldname,cond))))}} 92 | {{=T("record")}} {{=A('%s=%s'%request.vars.items()[0],_href=URL('update',args=request.args[:2],vars=request.vars))}} 93 | {{else:}} 94 | {{=T("table")}} {{=A(request.args[1],_href=URL('select',args=request.args[0],vars=dict(query='%s.%s.id>0'%tuple(request.args[:2]))))}} 95 | {{=T("record id")}} {{=A(request.args[2],_href=URL('update',args=request.args[:3]))}} 96 | {{pass}} 97 |

    98 |

    {{=T("Edit current record")}}



    {{=form}} 99 | 100 | {{elif request.function=='state':}} 101 |

    {{=T("Internal State")}}

    102 |

    {{=T("Current request")}}

    103 | {{=BEAUTIFY(request)}} 104 |

    {{=T("Current response")}}

    105 | {{=BEAUTIFY(response)}} 106 |

    {{=T("Current session")}}

    107 | {{=BEAUTIFY(session)}} 108 | 109 | 110 | {{elif request.function == 'ccache':}} 111 |

    Cache

    112 |
    113 | 114 |
    115 |

    Statistics

    116 |
    117 | 118 |
    119 |

    Overview

    120 |

    Number of entries: {{=total['entries']}} 121 | {{if total['entries'] > 0:}} 122 |

    123 |

    124 | Hit Ratio: 125 | {{=total['ratio']}}% 126 | ({{=total['hits']}} hits 127 | and {{=total['misses']}} misses) 128 |

    129 |

    130 | Size of cache: 131 | {{if object_stats:}} 132 | {{=total['objects']}} items, 133 | {{=total['bytes']}} bytes 134 | {{if total['bytes'] > 524287:}} 135 | ({{="%.0d" % (total['bytes'] / 1048576)}} MB) 136 | {{pass}} 137 | {{else:}} not available (requires the Python guppy library) 138 | {{pass}} 139 |

    140 |

    141 | Cache contains items up to 142 | {{="%02d" % total['oldest'][0]}} hours 143 | {{="%02d" % total['oldest'][1]}} minutes 144 | {{="%02d" % total['oldest'][2]}} seconds old. 145 |

    146 | {{=BUTTON(T('Cache Keys'), _onclick='jQuery("#all_keys").toggle();')}} 147 | 150 |
    151 | {{pass}} 152 | 153 |

    RAM

    154 |

    Number of entries: {{=ram['entries']}} 155 | {{if ram['entries'] > 0:}}

    156 |

    157 | Hit Ratio: 158 | {{=ram['ratio']}}% 159 | ({{=ram['hits']}} hits 160 | and {{=ram['misses']}} misses) 161 |

    162 |

    163 | Size of cache: 164 | {{if object_stats:}} 165 | {{=ram['objects']}} items, 166 | {{=ram['bytes']}} bytes 167 | {{if ram['bytes'] > 524287:}} 168 | ({{=ram['bytes'] / 1048576}} MB) 169 | {{pass}} 170 | {{else:}} not available (requires the Python guppy library) 171 | {{pass}} 172 |

    173 |

    174 | RAM contains items up to 175 | {{="%02d" % ram['oldest'][0]}} hours 176 | {{="%02d" % ram['oldest'][1]}} minutes 177 | {{="%02d" % ram['oldest'][2]}} seconds old. 178 |

    179 | {{=BUTTON(T('RAM Cache Keys'), _onclick='jQuery("#ram_keys").toggle();')}} 180 | 183 |
    184 | {{pass}} 185 | 186 |

    DISK

    187 |

    Number of entries: {{=disk['entries']}} 188 | {{if disk['entries'] > 0:}} 189 |

    190 |

    191 | Hit Ratio: 192 | {{=disk['ratio']}}% 193 | ({{=disk['hits']}} hits 194 | and {{=disk['misses']}} misses) 195 |

    196 |

    197 | Size of cache: 198 | {{if object_stats:}} 199 | {{=disk['objects']}} items, 200 | {{=disk['bytes']}} bytes 201 | {{if disk['bytes'] > 524287:}} 202 | ({{=disk['bytes'] / 1048576}} MB) 203 | {{pass}} 204 | {{else:}} not available (requires the Python guppy library) 205 | {{pass}} 206 |

    207 |

    208 | DISK contains items up to 209 | {{="%02d" % disk['oldest'][0]}} hours 210 | {{="%02d" % disk['oldest'][1]}} minutes 211 | {{="%02d" % disk['oldest'][2]}} seconds old. 212 |

    213 | {{=BUTTON(T('Disk Cache Keys'), _onclick='jQuery("#disk_keys").toggle();')}} 214 | 217 |
    218 | {{pass}} 219 |
    220 | 221 |
    222 |

    Manage Cache

    223 |
    224 | 225 |
    226 |

    227 | {{=form}} 228 |

    229 |
    230 |
    231 |
    232 | {{pass}} 233 | -------------------------------------------------------------------------------- /static/css/bootstrap-responsive.css: -------------------------------------------------------------------------------- 1 | .hidden { 2 | display: none; 3 | visibility: hidden; 4 | } 5 | @media (max-width: 480px) { 6 | .nav-collapse { 7 | -webkit-transform: translate3d(0, 0, 0); 8 | } 9 | .page-header h1 small { 10 | display: block; 11 | line-height: 18px; 12 | } 13 | input[class*="span"], 14 | select[class*="span"], 15 | textarea[class*="span"], 16 | .uneditable-input { 17 | display: block; 18 | width: 100%; 19 | height: 28px; 20 | /* Make inputs at least the height of their button counterpart */ 21 | 22 | /* Makes inputs behave like true block-level elements */ 23 | 24 | -webkit-box-sizing: border-box; 25 | /* Older Webkit */ 26 | 27 | -moz-box-sizing: border-box; 28 | /* Older FF */ 29 | 30 | -ms-box-sizing: border-box; 31 | /* IE8 */ 32 | 33 | box-sizing: border-box; 34 | /* CSS3 spec*/ 35 | 36 | } 37 | .input-prepend input[class*="span"], .input-append input[class*="span"] { 38 | width: auto; 39 | } 40 | input[type="checkbox"], input[type="radio"] { 41 | border: 1px solid #ccc; 42 | } 43 | .form-horizontal .control-group > label { 44 | float: none; 45 | width: auto; 46 | padding-top: 0; 47 | text-align: left; 48 | } 49 | .form-horizontal .controls { 50 | margin-left: 0; 51 | } 52 | .form-horizontal .control-list { 53 | padding-top: 0; 54 | } 55 | .form-horizontal .form-actions { 56 | padding-left: 10px; 57 | padding-right: 10px; 58 | } 59 | .modal { 60 | position: absolute; 61 | top: 10px; 62 | left: 10px; 63 | right: 10px; 64 | width: auto; 65 | margin: 0; 66 | } 67 | .modal.fade.in { 68 | top: auto; 69 | } 70 | .modal-header .close { 71 | padding: 10px; 72 | margin: -10px; 73 | } 74 | .carousel-caption { 75 | position: static; 76 | } 77 | .register span { display:none; } 78 | .register input[type="text"], .register input[type="password"] { width:100%; } 79 | .nav-tabs, .nav-pills {padding-bottom: 3px;} 80 | .content div.span8, .content div.span3 {padding-top:10px;} 81 | } 82 | @media (max-width: 768px) { 83 | .container { 84 | width: auto; 85 | padding: 0 20px; 86 | } 87 | .row-fluid { 88 | width: 100%; 89 | } 90 | .row { 91 | margin-left: 0; 92 | } 93 | .row > [class*="span"], .row-fluid > [class*="span"] { 94 | float: none; 95 | display: block; 96 | width: auto; 97 | margin: 0; 98 | } 99 | div.navbar {margin-bottom:0px;} 100 | .stat , .rate, div.span3.sidebar, .share, .navbar .nav > li.addon,.span1.post-btn {display:none;} 101 | .article .row { padding-left: 0px;} 102 | .navbar .nav > li.cat-page {display:block;} 103 | .article .footing {font-size:13px;} 104 | h1 {font-size: 24px;} 105 | h1 small {font-size:14px;} 106 | .post_input #post_radio {width:90px;} 107 | .text.span11 { width:100%; } 108 | .sub_cmt .article, .cmt .article { padding-left:0px; } 109 | .row .span6.article {width:100%;} 110 | } 111 | @media (min-width: 768px) and (max-width: 980px) { 112 | .row { 113 | margin-left: -20px; 114 | *zoom: 1; 115 | } 116 | .row:before, .row:after { 117 | display: table; 118 | content: ""; 119 | } 120 | .row:after { 121 | clear: both; 122 | } 123 | [class*="span"] { 124 | float: left; 125 | margin-left: 20px; 126 | } 127 | .span1 { 128 | width: 42px; 129 | } 130 | .span2 { 131 | width: 104px; 132 | } 133 | .span3 { 134 | width: 166px; 135 | } 136 | .span4 { 137 | width: 228px; 138 | } 139 | .span5 { 140 | width: 290px; 141 | } 142 | .span6 { 143 | width: 352px; 144 | } 145 | .span7 { 146 | width: 414px; 147 | } 148 | .span8 { 149 | width: 476px; 150 | } 151 | .span9 { 152 | width: 538px; 153 | } 154 | .span10 { 155 | width: 600px; 156 | } 157 | .span11, .container { 158 | width: 662px; 159 | } 160 | .span12{ 161 | width: 724px; 162 | } 163 | .offset1 { 164 | margin-left: 82px; 165 | } 166 | .offset2 { 167 | margin-left: 144px; 168 | } 169 | .offset3 { 170 | margin-left: 206px; 171 | } 172 | .offset4 { 173 | margin-left: 268px; 174 | } 175 | .offset5 { 176 | margin-left: 330px; 177 | } 178 | .offset6 { 179 | margin-left: 392px; 180 | } 181 | .offset7 { 182 | margin-left: 454px; 183 | } 184 | .offset8 { 185 | margin-left: 516px; 186 | } 187 | .offset9 { 188 | margin-left: 578px; 189 | } 190 | .offset10 { 191 | margin-left: 640px; 192 | } 193 | .offset11 { 194 | margin-left: 702px; 195 | } 196 | 197 | input.span1, textarea.span1, .uneditable-input.span1 { 198 | width: 32px; 199 | } 200 | input.span2, textarea.span2, .uneditable-input.span2 { 201 | width: 94px; 202 | } 203 | input.span3, textarea.span3, .uneditable-input.span3 { 204 | width: 156px; 205 | } 206 | input.span4, textarea.span4, .uneditable-input.span4 { 207 | width: 218px; 208 | } 209 | input.span5, textarea.span5, .uneditable-input.span5 { 210 | width: 280px; 211 | } 212 | input.span6, textarea.span6, .uneditable-input.span6 { 213 | width: 342px; 214 | } 215 | input.span7, textarea.span7, .uneditable-input.span7 { 216 | width: 404px; 217 | } 218 | input.span8, textarea.span8, .uneditable-input.span8 { 219 | width: 466px; 220 | } 221 | input.span9, textarea.span9, .uneditable-input.span9 { 222 | width: 528px; 223 | } 224 | input.span10, textarea.span10, .uneditable-input.span10 { 225 | width: 590px; 226 | } 227 | input.span11, textarea.span11, .uneditable-input.span11 { 228 | width: 652px; 229 | } 230 | input.span12, textarea.span12, .uneditable-input.span12 { 231 | width: 714px; 232 | } 233 | } 234 | @media (max-width: 980px) { 235 | body { 236 | padding-top: 0; 237 | } 238 | .navbar-fixed-top { 239 | position: static; 240 | margin-bottom: 18px; 241 | } 242 | .navbar-fixed-top .navbar-inner { 243 | padding: 5px; 244 | } 245 | .navbar .container { 246 | width: auto; 247 | padding: 0; 248 | } 249 | .navbar .brand { 250 | padding-left: 10px; 251 | padding-right: 10px; 252 | margin: 0 0 0 -5px; 253 | } 254 | .navbar .nav-collapse { 255 | clear: left; 256 | } 257 | .navbar .nav { 258 | float: none; 259 | margin: 0 0 9px; 260 | } 261 | .navbar .nav > li { 262 | float: none; 263 | } 264 | .navbar .nav > li > a { 265 | margin-bottom: 2px; 266 | } 267 | .navbar .nav > .divider-vertical { 268 | display: none; 269 | } 270 | .navbar .nav > li > a, .navbar .dropdown-menu a { 271 | padding: 6px 15px; 272 | font-weight: bold; 273 | color: #999999; 274 | -webkit-border-radius: 3px; 275 | -moz-border-radius: 3px; 276 | border-radius: 3px; 277 | } 278 | .navbar .nav > li > a, .navbar .dropdown-menu a.google-btn {padding:0;color:#fff;} 279 | .navbar .dropdown-menu li + li a { 280 | margin-bottom: 2px; 281 | } 282 | .navbar .nav > li > a:hover, .navbar .dropdown-menu a:hover { 283 | background-color: #222222; 284 | } 285 | .navbar .dropdown-menu { 286 | position: static; 287 | top: auto; 288 | left: auto; 289 | float: none; 290 | display: block; 291 | max-width: none; 292 | margin: 0 15px; 293 | padding: 0; 294 | background-color: transparent; 295 | border: none; 296 | -webkit-border-radius: 0; 297 | -moz-border-radius: 0; 298 | border-radius: 0; 299 | -webkit-box-shadow: none; 300 | -moz-box-shadow: none; 301 | box-shadow: none; 302 | } 303 | .navbar .dropdown-menu:before, .navbar .dropdown-menu:after { 304 | display: none; 305 | } 306 | .navbar .dropdown-menu .divider { 307 | display: none; 308 | } 309 | .navbar-form, .navbar-search { 310 | float: none; 311 | padding: 9px 15px; 312 | margin: 9px 0; 313 | border-top: 1px solid #222222; 314 | border-bottom: 1px solid #222222; 315 | -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1); 316 | -moz-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1); 317 | box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1); 318 | } 319 | .navbar .nav.pull-right { 320 | float: none; 321 | margin-left: 0; 322 | } 323 | .navbar-static .navbar-inner { 324 | padding-left: 10px; 325 | padding-right: 10px; 326 | } 327 | .btn-navbar { 328 | display: block; 329 | } 330 | .nav-collapse { 331 | overflow: hidden; 332 | height: 0; 333 | } 334 | .drop-login .login-btn { float:left; } 335 | .login-row .span2 { width:150px; } 336 | .login .span2 { width: 300px; height: 25px; } 337 | .login .login_remember {line-height: 28px;} 338 | .login #auth_user_remember { display: inline; } 339 | .span1.post-btn { margin-left: 0px; width: 60px;} 340 | .btn-group .btn { display:none; } 341 | .span6.article {width:414px;} 342 | } 343 | @media (min-width: 980px) { 344 | .nav-collapse.collapse { 345 | height: auto !important; 346 | } 347 | .login .span2 { width: 300px; height: 25px; } 348 | .login .login_remember {line-height: 28px;} 349 | .login #auth_user_remember { display: inline; } 350 | .login-row .span2 {width:160px;} 351 | .row.heading { padding-right:5px; } 352 | } 353 | @media (min-width: 1200px) { 354 | .row { 355 | margin-left: -30px; 356 | *zoom: 1; 357 | } 358 | .row:before, .row:after { 359 | display: table; 360 | content: ""; 361 | } 362 | .row:after { 363 | clear: both; 364 | } 365 | [class*="span"] { 366 | float: left; 367 | margin-left: 30px; 368 | } 369 | .span1 { 370 | width: 70px; 371 | } 372 | .span2 { 373 | width: 170px; 374 | } 375 | .span3 { 376 | width: 270px; 377 | } 378 | .span4 { 379 | width: 370px; 380 | } 381 | .span5 { 382 | width: 470px; 383 | } 384 | .span6 { 385 | width: 570px; 386 | } 387 | .span7 { 388 | width: 670px; 389 | } 390 | .span8 { 391 | width: 770px; 392 | } 393 | .span9 { 394 | width: 870px; 395 | } 396 | .span10 { 397 | width: 970px; 398 | } 399 | .span11, .container { 400 | width: 1070px; 401 | } 402 | .span12 { 403 | width: 1170px; 404 | } 405 | .offset1 { 406 | margin-left: 130px; 407 | } 408 | .offset2 { 409 | margin-left: 230px; 410 | } 411 | .offset3 { 412 | margin-left: 330px; 413 | } 414 | .offset4 { 415 | margin-left: 430px; 416 | } 417 | .offset5 { 418 | margin-left: 530px; 419 | } 420 | .offset6 { 421 | margin-left: 630px; 422 | } 423 | .offset7 { 424 | margin-left: 730px; 425 | } 426 | .offset8 { 427 | margin-left: 830px; 428 | } 429 | .offset9 { 430 | margin-left: 930px; 431 | } 432 | .offset10 { 433 | margin-left: 1030px; 434 | } 435 | .offset11 { 436 | margin-left: 1130px; 437 | } 438 | 439 | input.span1, textarea.span1, .uneditable-input.span1 { 440 | width: 60px; 441 | } 442 | input.span2, textarea.span2, .uneditable-input.span2 { 443 | width: 160px; 444 | } 445 | input.span3, textarea.span3, .uneditable-input.span3 { 446 | width: 260px; 447 | } 448 | input.span4, textarea.span4, .uneditable-input.span4 { 449 | width: 360px; 450 | } 451 | input.span5, textarea.span5, .uneditable-input.span5 { 452 | width: 460px; 453 | } 454 | input.span6, textarea.span6, .uneditable-input.span6 { 455 | width: 560px; 456 | } 457 | input.span7, textarea.span7, .uneditable-input.span7 { 458 | width: 660px; 459 | } 460 | input.span8, textarea.span8, .uneditable-input.span8 { 461 | width: 760px; 462 | } 463 | input.span9, textarea.span9, .uneditable-input.span9 { 464 | width: 860px; 465 | } 466 | input.span10, textarea.span10, .uneditable-input.span10 { 467 | width: 960px; 468 | } 469 | input.span11, textarea.span11, .uneditable-input.span11 { 470 | width: 1060px; 471 | } 472 | input.span12, textarea.span12, .uneditable-input.span12 { 473 | width: 1160px; 474 | } 475 | .thumbnails { 476 | margin-left: -30px; 477 | } 478 | .thumbnails > li { 479 | margin-left: 30px; 480 | } 481 | .login .span2 { width: 300px; height: 25px; } 482 | .login .login_remember {line-height: 28px;} 483 | .login #auth_user_remember { display: inline; } 484 | } 485 | -------------------------------------------------------------------------------- /controllers/appadmin.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # ########################################################## 4 | # ## make sure administrator is on localhost 5 | # ########################################################### 6 | 7 | import os 8 | import socket 9 | import datetime 10 | import copy 11 | import gluon.contenttype 12 | import gluon.fileutils 13 | 14 | # ## critical --- make a copy of the environment 15 | 16 | global_env = copy.copy(globals()) 17 | global_env['datetime'] = datetime 18 | 19 | http_host = request.env.http_host.split(':')[0] 20 | remote_addr = request.env.remote_addr 21 | try: 22 | hosts = (http_host, socket.gethostname(), 23 | socket.gethostbyname(http_host), 24 | '::1','127.0.0.1','::ffff:127.0.0.1') 25 | except: 26 | hosts = (http_host, ) 27 | 28 | if request.env.http_x_forwarded_for or request.env.wsgi_url_scheme\ 29 | in ['https', 'HTTPS']: 30 | session.secure() 31 | elif (remote_addr not in hosts) and (remote_addr != "127.0.0.1"): 32 | raise HTTP(200, T('appadmin is disabled because insecure channel')) 33 | 34 | if (request.application=='admin' and not session.authorized) or \ 35 | (request.application!='admin' and not gluon.fileutils.check_credentials(request)): 36 | redirect(URL('admin', 'default', 'index', 37 | vars=dict(send=URL(args=request.args,vars=request.vars)))) 38 | 39 | ignore_rw = True 40 | response.view = 'appadmin.html' 41 | response.menu = [[T('design'), False, URL('admin', 'default', 'design', 42 | args=[request.application])], [T('db'), False, 43 | URL('index')], [T('state'), False, 44 | URL('state')], [T('cache'), False, 45 | URL('ccache')]] 46 | 47 | # ########################################################## 48 | # ## auxiliary functions 49 | # ########################################################### 50 | 51 | 52 | def get_databases(request): 53 | dbs = {} 54 | for (key, value) in global_env.items(): 55 | cond = False 56 | try: 57 | cond = isinstance(value, GQLDB) 58 | except: 59 | cond = isinstance(value, SQLDB) 60 | if cond: 61 | dbs[key] = value 62 | return dbs 63 | 64 | 65 | databases = get_databases(None) 66 | 67 | 68 | def eval_in_global_env(text): 69 | exec ('_ret=%s' % text, {}, global_env) 70 | return global_env['_ret'] 71 | 72 | 73 | def get_database(request): 74 | if request.args and request.args[0] in databases: 75 | return eval_in_global_env(request.args[0]) 76 | else: 77 | session.flash = T('invalid request') 78 | redirect(URL('index')) 79 | 80 | 81 | def get_table(request): 82 | db = get_database(request) 83 | if len(request.args) > 1 and request.args[1] in db.tables: 84 | return (db, request.args[1]) 85 | else: 86 | session.flash = T('invalid request') 87 | redirect(URL('index')) 88 | 89 | 90 | def get_query(request): 91 | try: 92 | return eval_in_global_env(request.vars.query) 93 | except Exception: 94 | return None 95 | 96 | 97 | def query_by_table_type(tablename,db,request=request): 98 | keyed = hasattr(db[tablename],'_primarykey') 99 | if keyed: 100 | firstkey = db[tablename][db[tablename]._primarykey[0]] 101 | cond = '>0' 102 | if firstkey.type in ['string', 'text']: 103 | cond = '!=""' 104 | qry = '%s.%s.%s%s' % (request.args[0], request.args[1], firstkey.name, cond) 105 | else: 106 | qry = '%s.%s.id>0' % tuple(request.args[:2]) 107 | return qry 108 | 109 | 110 | 111 | # ########################################################## 112 | # ## list all databases and tables 113 | # ########################################################### 114 | 115 | 116 | def index(): 117 | return dict(databases=databases) 118 | 119 | 120 | # ########################################################## 121 | # ## insert a new record 122 | # ########################################################### 123 | 124 | 125 | def insert(): 126 | (db, table) = get_table(request) 127 | form = SQLFORM(db[table], ignore_rw=ignore_rw) 128 | if form.accepts(request.vars, session): 129 | response.flash = T('new record inserted') 130 | return dict(form=form,table=db[table]) 131 | 132 | 133 | # ########################################################## 134 | # ## list all records in table and insert new record 135 | # ########################################################### 136 | 137 | 138 | def download(): 139 | import os 140 | db = get_database(request) 141 | return response.download(request,db) 142 | 143 | def csv(): 144 | import gluon.contenttype 145 | response.headers['Content-Type'] = \ 146 | gluon.contenttype.contenttype('.csv') 147 | db = get_database(request) 148 | query = get_query(request) 149 | if not query: 150 | return None 151 | response.headers['Content-disposition'] = 'attachment; filename=%s_%s.csv'\ 152 | % tuple(request.vars.query.split('.')[:2]) 153 | return str(db(query,ignore_common_filters=True).select()) 154 | 155 | 156 | def import_csv(table, file): 157 | table.import_from_csv_file(file) 158 | 159 | def select(): 160 | import re 161 | db = get_database(request) 162 | dbname = request.args[0] 163 | regex = re.compile('(?P\w+)\.(?P\w+)=(?P\d+)') 164 | if len(request.args)>1 and hasattr(db[request.args[1]],'_primarykey'): 165 | regex = re.compile('(?P
    \w+)\.(?P\w+)=(?P.+)') 166 | if request.vars.query: 167 | match = regex.match(request.vars.query) 168 | if match: 169 | request.vars.query = '%s.%s.%s==%s' % (request.args[0], 170 | match.group('table'), match.group('field'), 171 | match.group('value')) 172 | else: 173 | request.vars.query = session.last_query 174 | query = get_query(request) 175 | if request.vars.start: 176 | start = int(request.vars.start) 177 | else: 178 | start = 0 179 | nrows = 0 180 | stop = start + 100 181 | table = None 182 | rows = [] 183 | orderby = request.vars.orderby 184 | if orderby: 185 | orderby = dbname + '.' + orderby 186 | if orderby == session.last_orderby: 187 | if orderby[0] == '~': 188 | orderby = orderby[1:] 189 | else: 190 | orderby = '~' + orderby 191 | session.last_orderby = orderby 192 | session.last_query = request.vars.query 193 | form = FORM(TABLE(TR(T('Query:'), '', INPUT(_style='width:400px', 194 | _name='query', _value=request.vars.query or '', 195 | requires=IS_NOT_EMPTY(error_message=T("Cannot be empty")))), TR(T('Update:'), 196 | INPUT(_name='update_check', _type='checkbox', 197 | value=False), INPUT(_style='width:400px', 198 | _name='update_fields', _value=request.vars.update_fields 199 | or '')), TR(T('Delete:'), INPUT(_name='delete_check', 200 | _class='delete', _type='checkbox', value=False), ''), 201 | TR('', '', INPUT(_type='submit', _value='submit'))), 202 | _action=URL(r=request,args=request.args)) 203 | if request.vars.csvfile != None: 204 | try: 205 | import_csv(db[request.vars.table], 206 | request.vars.csvfile.file) 207 | response.flash = T('data uploaded') 208 | except Exception, e: 209 | response.flash = DIV(T('unable to parse csv file'),PRE(str(e))) 210 | if form.accepts(request.vars, formname=None): 211 | # regex = re.compile(request.args[0] + '\.(?P
    \w+)\.id\>0') 212 | regex = re.compile(request.args[0] + '\.(?P
    \w+)\..+') 213 | 214 | match = regex.match(form.vars.query.strip()) 215 | if match: 216 | table = match.group('table') 217 | try: 218 | nrows = db(query).count() 219 | if form.vars.update_check and form.vars.update_fields: 220 | db(query).update(**eval_in_global_env('dict(%s)' 221 | % form.vars.update_fields)) 222 | response.flash = T('%s rows updated', nrows) 223 | elif form.vars.delete_check: 224 | db(query).delete() 225 | response.flash = T('%s rows deleted', nrows) 226 | nrows = db(query).count() 227 | if orderby: 228 | rows = db(query,ignore_common_filters=True).select(limitby=(start, stop), orderby=eval_in_global_env(orderby)) 229 | else: 230 | rows = db(query,ignore_common_filters=True).select(limitby=(start, stop)) 231 | except Exception, e: 232 | (rows, nrows) = ([], 0) 233 | response.flash = DIV(T('Invalid Query'),PRE(str(e))) 234 | return dict( 235 | form=form, 236 | table=table, 237 | start=start, 238 | stop=stop, 239 | nrows=nrows, 240 | rows=rows, 241 | query=request.vars.query, 242 | ) 243 | 244 | 245 | # ########################################################## 246 | # ## edit delete one record 247 | # ########################################################### 248 | 249 | 250 | def update(): 251 | (db, table) = get_table(request) 252 | keyed = hasattr(db[table],'_primarykey') 253 | record = None 254 | if keyed: 255 | key = [f for f in request.vars if f in db[table]._primarykey] 256 | if key: 257 | record = db(db[table][key[0]] == request.vars[key[0]], ignore_common_filters=True).select().first() 258 | else: 259 | record = db(db[table].id == request.args(2),ignore_common_filters=True).select().first() 260 | 261 | if not record: 262 | qry = query_by_table_type(table, db) 263 | session.flash = T('record does not exist') 264 | redirect(URL('select', args=request.args[:1], 265 | vars=dict(query=qry))) 266 | 267 | if keyed: 268 | for k in db[table]._primarykey: 269 | db[table][k].writable=False 270 | 271 | form = SQLFORM(db[table], record, deletable=True, delete_label=T('Check to delete'), 272 | ignore_rw=ignore_rw and not keyed, 273 | linkto=URL('select', 274 | args=request.args[:1]), upload=URL(r=request, 275 | f='download', args=request.args[:1])) 276 | 277 | if form.accepts(request.vars, session): 278 | session.flash = T('done!') 279 | qry = query_by_table_type(table, db) 280 | redirect(URL('select', args=request.args[:1], 281 | vars=dict(query=qry))) 282 | return dict(form=form,table=db[table]) 283 | 284 | 285 | # ########################################################## 286 | # ## get global variables 287 | # ########################################################### 288 | 289 | 290 | def state(): 291 | return dict() 292 | 293 | def ccache(): 294 | form = FORM( 295 | P(TAG.BUTTON("Clear CACHE?", _type="submit", _name="yes", _value="yes")), 296 | P(TAG.BUTTON("Clear RAM", _type="submit", _name="ram", _value="ram")), 297 | P(TAG.BUTTON("Clear DISK", _type="submit", _name="disk", _value="disk")), 298 | ) 299 | 300 | if form.accepts(request.vars, session): 301 | clear_ram = False 302 | clear_disk = False 303 | session.flash = "" 304 | if request.vars.yes: 305 | clear_ram = clear_disk = True 306 | if request.vars.ram: 307 | clear_ram = True 308 | if request.vars.disk: 309 | clear_disk = True 310 | 311 | if clear_ram: 312 | cache.ram.clear() 313 | session.flash += "Ram Cleared " 314 | if clear_disk: 315 | cache.disk.clear() 316 | session.flash += "Disk Cleared" 317 | 318 | redirect(URL(r=request)) 319 | 320 | try: 321 | from guppy import hpy; hp=hpy() 322 | except ImportError: 323 | hp = False 324 | 325 | import shelve, os, copy, time, math 326 | from gluon import portalocker 327 | 328 | ram = { 329 | 'entries': 0, 330 | 'bytes': 0, 331 | 'objects': 0, 332 | 'hits': 0, 333 | 'misses': 0, 334 | 'ratio': 0, 335 | 'oldest': time.time(), 336 | 'keys': [] 337 | } 338 | disk = copy.copy(ram) 339 | total = copy.copy(ram) 340 | disk['keys'] = [] 341 | total['keys'] = [] 342 | 343 | def GetInHMS(seconds): 344 | hours = math.floor(seconds / 3600) 345 | seconds -= hours * 3600 346 | minutes = math.floor(seconds / 60) 347 | seconds -= minutes * 60 348 | seconds = math.floor(seconds) 349 | 350 | return (hours, minutes, seconds) 351 | 352 | for key, value in cache.ram.storage.items(): 353 | if isinstance(value, dict): 354 | ram['hits'] = value['hit_total'] - value['misses'] 355 | ram['misses'] = value['misses'] 356 | try: 357 | ram['ratio'] = ram['hits'] * 100 / value['hit_total'] 358 | except (KeyError, ZeroDivisionError): 359 | ram['ratio'] = 0 360 | else: 361 | if hp: 362 | ram['bytes'] += hp.iso(value[1]).size 363 | ram['objects'] += hp.iso(value[1]).count 364 | ram['entries'] += 1 365 | if value[0] < ram['oldest']: 366 | ram['oldest'] = value[0] 367 | ram['keys'].append((key, GetInHMS(time.time() - value[0]))) 368 | 369 | locker = open(os.path.join(request.folder, 370 | 'cache/cache.lock'), 'a') 371 | portalocker.lock(locker, portalocker.LOCK_EX) 372 | disk_storage = shelve.open(os.path.join(request.folder, 'cache/cache.shelve')) 373 | try: 374 | for key, value in disk_storage.items(): 375 | if isinstance(value, dict): 376 | disk['hits'] = value['hit_total'] - value['misses'] 377 | disk['misses'] = value['misses'] 378 | try: 379 | disk['ratio'] = disk['hits'] * 100 / value['hit_total'] 380 | except (KeyError, ZeroDivisionError): 381 | disk['ratio'] = 0 382 | else: 383 | if hp: 384 | disk['bytes'] += hp.iso(value[1]).size 385 | disk['objects'] += hp.iso(value[1]).count 386 | disk['entries'] += 1 387 | if value[0] < disk['oldest']: 388 | disk['oldest'] = value[0] 389 | disk['keys'].append((key, GetInHMS(time.time() - value[0]))) 390 | 391 | finally: 392 | portalocker.unlock(locker) 393 | locker.close() 394 | disk_storage.close() 395 | 396 | total['entries'] = ram['entries'] + disk['entries'] 397 | total['bytes'] = ram['bytes'] + disk['bytes'] 398 | total['objects'] = ram['objects'] + disk['objects'] 399 | total['hits'] = ram['hits'] + disk['hits'] 400 | total['misses'] = ram['misses'] + disk['misses'] 401 | total['keys'] = ram['keys'] + disk['keys'] 402 | try: 403 | total['ratio'] = total['hits'] * 100 / (total['hits'] + total['misses']) 404 | except (KeyError, ZeroDivisionError): 405 | total['ratio'] = 0 406 | 407 | if disk['oldest'] < ram['oldest']: 408 | total['oldest'] = disk['oldest'] 409 | else: 410 | total['oldest'] = ram['oldest'] 411 | 412 | ram['oldest'] = GetInHMS(time.time() - ram['oldest']) 413 | disk['oldest'] = GetInHMS(time.time() - disk['oldest']) 414 | total['oldest'] = GetInHMS(time.time() - total['oldest']) 415 | 416 | def key_table(keys): 417 | return TABLE( 418 | TR(TD(B('Key')), TD(B('Time in Cache (h:m:s)'))), 419 | *[TR(TD(k[0]), TD('%02d:%02d:%02d' % k[1])) for k in keys], 420 | **dict(_class='cache-keys', 421 | _style="border-collapse: separate; border-spacing: .5em;")) 422 | 423 | ram['keys'] = key_table(ram['keys']) 424 | disk['keys'] = key_table(disk['keys']) 425 | total['keys'] = key_table(total['keys']) 426 | 427 | return dict(form=form, total=total, 428 | ram=ram, disk=disk, object_stats=hp != False) 429 | 430 | 431 | 432 | -------------------------------------------------------------------------------- /controllers/default.py: -------------------------------------------------------------------------------- 1 | from urlparse import urlparse 2 | import time 3 | now=time.time() 4 | 5 | def author_func(): 6 | login_form=auth.login(next=request.env.http_referer) 7 | login_form.element('input[name=email]')['_class']='span2' 8 | login_form.element('input[name=email]')['_placeholder']='email' 9 | login_form.element('input[name=password]')['_class']='span2' 10 | login_form.element('input[name=password]')['_placeholder']='password' 11 | login_form.element('input[type=submit]')['_class']='btn' 12 | login_form.element('input[type=submit]')['_value']='로그인' 13 | session.old_referer = request.env.http_referer 14 | auth.settings.login_form=login_form 15 | return login_form 16 | 17 | def register(): 18 | if auth.user_id: 19 | redirect(URL(r=request,f='index')) 20 | login_form = author_func() 21 | form = auth.register() 22 | form.element('input[name=alias]')['_class']='span3' 23 | form.element('input[name=alias]')['_placeholder']='닉네임' 24 | form.element('input[name=email]')['_class']='span3' 25 | form.element('input[name=email]')['_placeholder']='이메일' 26 | form.element('input[name=password]')['_class']='span3' 27 | form.element('input[name=password]')['_placeholder']='비밀번호' 28 | form.element('input[name=password_two]')['_class']='span3' 29 | form.element('input[name=password_two]')['_placeholder']='비밀번호 확인' 30 | form.element('input[type=submit]')['_class']='btn' 31 | form.element('input[type=submit]')['_value']='회원가입' 32 | return dict(login_form=login_form,form=form) 33 | 34 | def profile(): 35 | if not auth.user_id: 36 | redirect(URL(r=request,f='login')) 37 | form=auth.profile() 38 | form.element('input[name=alias]')['_class']='span3' 39 | form.element('input[name=email]')['_class']='span3' 40 | form.element('input[type=submit]')['_class']='btn' 41 | form.element('input[type=submit]')['_value']='저장' 42 | return dict(form=form) 43 | 44 | #built-in user function 45 | def user(): 46 | auth.settings.login_form=GaeGoogleAccount() 47 | return dict(form=auth.login(next=URL(r=request, c='default', f='index'))) 48 | 49 | 50 | def login(): 51 | if auth.user_id: 52 | redirect(session.old_referer) 53 | cat_list=[[r.alias,r.name] for r in db().select(db.category.ALL)] 54 | login_form=author_func() 55 | return dict(cat_list=cat_list,login_form=login_form) 56 | 57 | 58 | def logout(): 59 | return auth.logout(next=request.env.http_referer) 60 | 61 | def index(): 62 | sorts={ 63 | 'hot':~db.news.hotness, 64 | 'score':~db.news.score, 65 | 'new':~db.news.post_time} 66 | try: page=int(request.args[2]) 67 | except: page=0 68 | try: sort=request.args[1] 69 | except: sort='new' 70 | orderby=sorts[sort] 71 | limitby=(25*page,25*(page+1)+1) 72 | try: 73 | cat=request.args[0] 74 | if sort == 'hot' or sort == 'score':#orderby 넣어야함 75 | news=db((db.news.category==cat) & (db.news.post_time>(now-2592000.0))).select(cache=(cache.ram,1800)) 76 | if sort=='hot': news=news.sort(lambda row: -row.hotness)[limitby[0]:limitby[1]] 77 | if sort=='score': news=news.sort(lambda row:~row.score)[limitby[0]:limitby[1]] 78 | else: 79 | news=db(db.news.category==cat).select(cache=(cache.ram,1800),orderby=orderby,limitby=limitby) #no cache 80 | #news=news.sort(lambda row: -row.post_time)[limitby[0]:limitby[1]] 81 | category=db(db.category.name==cat).select(cache=(cache.ram,1800))[0] 82 | alias=category.alias 83 | dec=category.description 84 | except: 85 | cat="all" 86 | alias='모든 이야기' 87 | dec='이것저것 인기순으로 모아놓습니다' 88 | 89 | if sort == 'hot' or sort == 'score': 90 | news=db(db.news.post_time>(now-2592000.0)).select(cache=(cache.ram,1800)) 91 | if sort=='hot': news=news.sort(lambda row: -row.hotness)[limitby[0]:limitby[1]] 92 | if sort=='score': news=news.sort(lambda row:~row.score)[limitby[0]:limitby[1]] 93 | else: 94 | news=db().select(db.news.ALL,cache=(cache.ram,1800),orderby=orderby,limitby=limitby) 95 | #news=news.sort(lambda row: -row.post_time)[limitby[0]:limitby[1]] 96 | 97 | db.person.email.requires=IS_NOT_EMPTY() 98 | form = author_func() 99 | cat_list=[[r.alias,r.name] for r in db().select(db.category.ALL,cache=(cache.ram,1800))] 100 | 101 | return response.render(dict(login_form=form,cat_list=cat_list,category=cat,alias=alias,news=news,dec=dec,sort=sort,page=page)) 102 | 103 | def bookmark(): 104 | try: item=db(db.news.id==request.args[0]).select()[0] 105 | except: redirect(URL(r=request,f='index')) 106 | item.update_record(clicks=item.clicks+1,score=item.score,comments=item.comments,post_time=item.post_time) 107 | redirect(item.url) 108 | 109 | def post(): 110 | if not auth.user_id: 111 | redirect(URL(r=request,f='login')) 112 | form=SQLFORM(db.news,fields=['url','title','category']) 113 | form.vars.author=auth.user_id 114 | form.vars.author_alias=auth.user.alias 115 | form.element('input[name=url]')['_class']='span11' 116 | form.element('input[name=url]')['_placeholder']='URL 주소 (입력하지 않으면 스스로를 가르키는 링크)' 117 | form.element('input[name=title]')['_class']='span11' 118 | form.element('input[name=title]')['_placeholder']='링크 설명을 입력하세요.' 119 | form.element('input[type=submit]')['_class']='btn large' 120 | form.element('input[type=submit]')['_value']='올리기' 121 | if request.vars.category: 122 | form.vars.category_alias=db(db.category.name==request.vars.category).select()[0].alias 123 | if not request.vars.url: 124 | request.vars.url='self' 125 | login_form = author_func() 126 | if form.accepts(request.vars,session): 127 | session.flash='news posted' 128 | if not form.vars.category: 129 | redirect(URL(r=request,f='mylink')) 130 | else: 131 | redirect(URL(r=request,f='index',args=[form.vars.category,'new'])) 132 | cat_list=[[r.alias,r.name] for r in db().select(db.category.ALL)] 133 | return dict(login_form=login_form,form=form,cat_list=cat_list) 134 | 135 | def report(): 136 | try: 137 | db(db.news.id==request.args[0]).update(flagged=True) 138 | session.flash='thanks for your feedback' 139 | except: 140 | session.flash='internal error' 141 | redirect(request.env.http_referer) 142 | 143 | def delete(): 144 | if not auth.user_id: redirect(request.env.http_referer) 145 | try: 146 | news=db(db.news.id==request.args[0]).select()[0] 147 | if news.author==auth.user_id: 148 | db(db.news.id==request.args[0]).delete() 149 | session.flash='news item deleted' 150 | except: 151 | session.flash='internal error' 152 | redirect(URL(r=request,f='index',args=[news.category])) 153 | 154 | def vote(): 155 | if not auth.user_id: redirect(request.env.http_referer) 156 | news=db(db.news.id==request.args[1]).select()[0] 157 | try: 158 | vote = db((db.vote.voter==auth.user_id) & (db.vote.parentv==news)).select()[0] 159 | except: 160 | vote = db.vote.insert(parentv=news,voter=auth.user_id) 161 | if request.args[0]=='up': 162 | if vote.choice == -1: 163 | vote.update_record(choice=1) 164 | news.update_record(score=news.score+2) 165 | elif vote.choice == 0: 166 | vote.update_record(choice=1) 167 | news.update_record(score=news.score+1) 168 | elif vote.choice == 1: 169 | vote.update_record(choice=0) 170 | news.update_record(score=news.score-1) 171 | elif request.args[0]=='down': 172 | if vote.choice == 1: 173 | vote.update_record(choice=-1) 174 | news.update_record(score=news.score-2) 175 | elif vote.choice == 0: 176 | vote.update_record(choice=-1) 177 | news.update_record(score=news.score-1) 178 | elif vote.choice == -1: 179 | vote.update_record(choice=0) 180 | news.update_record(score=news.score+1) 181 | # redirect(request.env.http_referer) 182 | return str(news.score) 183 | 184 | def permalink(): 185 | try: comment=db(db.comment.id==request.args[0]).select()[0] 186 | except: redirect(request.env.http_referer) 187 | comments=db(db.comment.news==comment.news).select(orderby=db.comment.score) 188 | news=comment.news 189 | items=[] 190 | tree={} 191 | forms={} 192 | pivot=None 193 | for c in comments: 194 | if not tree.has_key(c.parente): tree[c.parente]=[c] 195 | else: tree[c.parente].append(c) 196 | if c.id==comment.id: pivot=c.parente 197 | if auth.user_id: 198 | f=SQLFORM(db.comment,fields=['body'],labels={'body':''}) 199 | f.vars.author=auth.user_id 200 | f.vars.author_alias=auth.user.alias 201 | f.vars.news=news 202 | f.vars.parente=c.id 203 | if f.accepts(request.vars,formname=str(c.id)): 204 | session.flash='comment posted' 205 | redirect(URL(r=request,args=request.args)) 206 | forms[c.id]=f 207 | tree[pivot]=[comment] 208 | login_form = author_func() 209 | response.view='default/comments.html' 210 | cat_list=[[r.alias,r.name] for r in db().select(db.category.ALL)] 211 | return dict(cat_list=cat_list,item=None,login_form=login_form,form=None,tree=tree,forms=forms,parent=pivot) 212 | 213 | def vote_comment(): 214 | if not auth.user_id: redirect(request.env.http_referer) 215 | comment=db(db.comment.id==request.args[1]).select()[0] 216 | try: 217 | vote = db((db.vote_cmt.voter==auth.user_id) & (db.vote_cmt.parentv==comment)).select()[0] 218 | except: 219 | vote = db.vote_cmt.insert(parentv=comment,voter=auth.user_id) 220 | if request.args[0]=='up': 221 | if vote.choice == -1: 222 | vote.update_record(choice=1) 223 | comment.update_record(score=comment.score+2) 224 | elif vote.choice == 0: 225 | vote.update_record(choice=1) 226 | comment.update_record(score=comment.score+1) 227 | elif vote.choice == 1: 228 | vote.update_record(choice=0) 229 | comment.update_record(score=comment.score-1) 230 | elif request.args[0]=='down': 231 | if vote.choice == 1: 232 | vote.update_record(choice=-1) 233 | comment.update_record(score=comment.score-2) 234 | elif vote.choice == 0: 235 | vote.update_record(choice=-1) 236 | comment.update_record(score=comment.score-1) 237 | elif vote.choice == -1: 238 | vote.update_record(choice=0) 239 | comment.update_record(score=comment.score+1) 240 | return str(comment.score) 241 | 242 | def report_comment(): 243 | try: 244 | db(db.comment.id==request.args[0]).update(flagged=True) 245 | session.flash='thanks for your feedback' 246 | except: 247 | session.flash='internal error' 248 | redirect(request.env.http_referer) 249 | 250 | def person(): 251 | session.flash='sorry, not yet implemented' 252 | redirect(request.env.http_referer) 253 | 254 | 255 | def comments(): 256 | try: news=int(request.args[0]) 257 | except: redirect(URL(r=request,f='index')) 258 | try: 259 | item=db(db.news.id==news).select()[0] 260 | comments=db(db.comment.news==news).select(orderby=~db.comment.score) 261 | except: redirect(URL(r=request,f='index')) 262 | if auth.user_id: 263 | form=SQLFORM(db.comment,fields=['body'],labels={'body':''}) 264 | form.element('textarea[name=body]')['_class']='text span7' 265 | form.element('textarea[name=body]')['_cols']='70' 266 | form.element('textarea[name=body]')['_rows']='4' 267 | form.element('textarea[name=body]')['_placeholder']='코멘트 남기기...' 268 | form.element('input[type=submit]')['_class']='btn' 269 | form.element('input[type=submit]')['_value']='올리기' 270 | form.vars.author=auth.user_id 271 | form.vars.author_alias=auth.user.alias 272 | form.vars.news=news 273 | if form.accepts(request.vars,formname='0'): 274 | item.update_record(comments=item.comments+1) 275 | response.flash='comment posted' 276 | redirect(URL(r=request,args=request.args)) 277 | else: form=None 278 | items=[] 279 | tree={} 280 | forms={} 281 | for c in comments: 282 | if not tree.has_key(c.parente): tree[c.parente]=[c] 283 | else: tree[c.parente].append(c) 284 | if auth.user_id: 285 | f=SQLFORM(db.comment,fields=['body'],labels={'body':''}) 286 | f.element('textarea[name=body]')['_class']='text sub_cmt' 287 | f.element('textarea[name=body]')['_cols']='70' 288 | f.element('textarea[name=body]')['_rows']='4' 289 | f.element('textarea[name=body]')['_placeholder']='코멘트 남기기...' 290 | f.element('input[type=submit]')['_class']='btn' 291 | f.element('input[type=submit]')['_value']='올리기' 292 | f.vars.author=auth.user_id 293 | f.vars.author_alias=auth.user.alias 294 | f.vars.news=news 295 | f.vars.parente=c.id 296 | if f.accepts(request.vars,formname=str(c.id)): 297 | item.update_record(comments=item.comments+1) 298 | session.flash='comment posted' 299 | redirect(URL(r=request,args=request.args)) 300 | forms[c.id]=f 301 | login_form = author_func() 302 | cat_list=[[r.alias,r.name] for r in db().select(db.category.ALL)] 303 | return dict(cat_list=cat_list,item=item,login_form=login_form,form=form,tree=tree,forms=forms,parent=0) 304 | 305 | def edit_comment(): 306 | if not auth.user_id: redirect(request.env.http_referer) 307 | id=request.args[0] 308 | try: 309 | comment=db(db.comment.id==id).select()[0] 310 | if not comment.author==auth.user_id: raise Exception 311 | except: redirect(URL(r=request,f='index')) 312 | form=SQLFORM(db.comment,comment,fields=['body'],showid=False,deletable=True,labels={'body':'Comment'}) 313 | form.element('textarea[name=body]')['_class']='text span11' 314 | form.element('textarea[name=body]')['_cols']='70' 315 | form.element('textarea[name=body]')['_rows']='4' 316 | form.element('input[type=submit]')['_class']='btn' 317 | form.element('input[type=submit]')['_value']='올리기' 318 | if form.accepts(request.vars,session): 319 | session.flash='comment edited' 320 | redirect(URL(r=request,f='comments',args=[comment.news])) 321 | login_form = author_func() 322 | cat_list=[[r.alias,r.name] for r in db().select(db.category.ALL)] 323 | return dict(cat_list=cat_list,login_form=login_form,form=form) 324 | 325 | def about(): 326 | return dict(login_form=author_func()) 327 | 328 | def uplink(): 329 | try: page=int(request.args[1]) 330 | except: page=0 331 | limitby=(50*page,50*(page+1)+1) 332 | news=db((db.vote.voter==auth.user_id) & (db.vote.choice==1)).select(limitby=limitby) 333 | form = author_func() 334 | return dict(login_form=form,news=news,page=page) 335 | 336 | def downlink(): 337 | try: page=int(request.args[1]) 338 | except: page=0 339 | limitby=(50*page,50*(page+1)+1) 340 | news=db((db.vote.voter==auth.user_id) & (db.vote.choice==-1)).select(limitby=limitby) 341 | form = author_func() 342 | return dict(login_form=form,news=news,page=page) 343 | 344 | def mylink(): 345 | try: page=int(request.args[1]) 346 | except: page=0 347 | limitby=(50*page,50*(page+1)+1) 348 | news=db(db.news.author==auth.user_id).select(orderby=~db.news.post_time,limitby=limitby) 349 | form = author_func() 350 | return dict(login_form=form,news=news,page=page) 351 | def error(): 352 | return dict(login_form=author_func()) 353 | def reset_password(): 354 | form=auth.request_reset_password() 355 | form.element('input[name=email]')['_class']='span5' 356 | form.element('input[name=email]')['_placeholder']='email' 357 | form.element('input[type=submit]')['_class']='btn' 358 | form.element('input[type=submit]')['_value']='패스워드 리셋요청' 359 | return dict(login_form=author_func(),form=form) 360 | 361 | def new_password(): 362 | form=auth.reset_password() 363 | form.element('input[name=new_password]')['_class']='span3' 364 | form.element('input[name=new_password]')['_placeholder']='새 비밀번호' 365 | form.element('input[name=new_password2]')['_class']='span3' 366 | form.element('input[name=new_password2]')['_placeholder']='새 비밀번호 확인' 367 | form.element('input[type=submit]')['_class']='btn' 368 | form.element('input[type=submit]')['_value']='비밀번호 재설정' 369 | return dict(login_form=author_func(),form=form) 370 | ### todo: 371 | """ 372 | allow different types of news sorting 373 | """ 374 | 375 | ## test article upload 376 | def testukn(): 377 | if auth.user_id: 378 | for i in range(150): 379 | db.news.insert(category='movie',author=auth.user_id,author_alias=auth.user.alias,url="http://plan9.kr",title="테스트로 입력하는 글제목") 380 | redirect(request.env.http_referer) 381 | 382 | def post_chrome(): 383 | if not auth.user_id: 384 | redirect(URL(r=request,f='login_chrome')) 385 | form=SQLFORM(db.news,fields=['url','title','category']) 386 | form.vars.author=auth.user_id 387 | form.vars.author_alias=auth.user.alias 388 | form.element('input[name=url]')['_class']='span6' 389 | form.element('input[name=url]')['_placeholder']='URL 주소 (입력하지 않으면 스스로를 가르키는 링크)' 390 | #form.element('input[name=url]')['_value']='http://'+request.args[1] 391 | form.element('input[name=url]')['_value']=request.vars.url 392 | form.element('input[name=title]')['_class']='span6' 393 | form.element('input[name=title]')['_placeholder']='링크 설명을 입력하세요.' 394 | #form.element('input[name=title]')['_value']=request.args[0] 395 | form.element('input[name=title]')['_value']=request.vars.title 396 | form.element('input[type=submit]')['_class']='btn large' 397 | form.element('input[type=submit]')['_value']='올리기' 398 | form.element('input[type=submit]')['_action']=URL(r=request,args=request.args) 399 | if request.vars.category: 400 | form.vars.category_alias=db(db.category.name==request.vars.category).select()[0].alias 401 | if not request.vars.url: 402 | request.vars.url='self' 403 | login_form = author_func() 404 | if form.accepts(request,session): 405 | return "올라간듯"+' '+"업로드 페이지로 이동"+"" 406 | cat_list=[[r.alias,r.name] for r in db().select(db.category.ALL)] 407 | return dict(form=form,cat_list=cat_list) 408 | 409 | def login_chrome(): 410 | if auth.user_id: 411 | redirect(URL(r=request,f='post_chrome')) 412 | cat_list=[[r.alias,r.name] for r in db().select(db.category.ALL)] 413 | login_form=auth.login(next=URL(r=request,f='post_chrome')) 414 | login_form.element('form')['_name']='ext' 415 | login_form.element('input[name=email]')['_class']='span3' 416 | login_form.element('input[name=email]')['_placeholder']='email' 417 | login_form.element('input[name=password]')['_class']='span3' 418 | login_form.element('input[name=password]')['_placeholder']='password' 419 | login_form.element('input[type=submit]')['_class']='btn' 420 | login_form.element('input[type=submit]')['_value']='로그인' 421 | return dict(cat_list=cat_list,login_form=login_form) 422 | 423 | def category(): 424 | cat_list=[[r.alias,r.name] for r in db().select(db.category.ALL)] 425 | form = author_func() 426 | return dict(cat_list=cat_list,login_form=form) 427 | -------------------------------------------------------------------------------- /static/css/main.css: -------------------------------------------------------------------------------- 1 | html,body{margin:0;padding:0;} 2 | h1,h2,h3,h4,h5,h6,p,blockquote,pre,a,abbr,acronym,address,cite,code,del,dfn,em,img,q,s,samp,small,strike,strong,sub,sup,tt,var,dd,dl,dt,li,ol,ul,fieldset,form,label,legend,button,table,caption,tbody,tfoot,thead,tr,th,td{margin:0;padding:0;border:0;font-weight:normal;font-style:normal;font-size:100%;line-height:1;font-family:inherit;} 3 | table{border-collapse:collapse;border-spacing:0;} 4 | ol,ul{list-style:none;} 5 | q:before,q:after,blockquote:before,blockquote:after{content:"";} 6 | html{overflow-y:scroll;font-size:100%;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%;} 7 | a:focus{outline:thin dotted;} 8 | a:hover,a:active{outline:0;} 9 | article,aside,details,figcaption,figure,footer,header,hgroup,nav,section{display:block;} 10 | audio,canvas,video{display:inline-block;*display:inline;*zoom:1;} 11 | audio:not([controls]){display:none;} 12 | sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline;} 13 | sup{top:-0.5em;} 14 | sub{bottom:-0.25em;} 15 | img{border:0;-ms-interpolation-mode:bicubic;} 16 | button,input,select,textarea{font-size:100%;margin:0;vertical-align:baseline;*vertical-align:middle;} 17 | button,input{line-height:normal;*overflow:visible;} 18 | button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0;} 19 | button,input[type="button"],input[type="reset"],input[type="submit"]{cursor:pointer;-webkit-appearance:button;} 20 | input[type="search"]{-webkit-appearance:textfield;-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;} 21 | input[type="search"]::-webkit-search-decoration{-webkit-appearance:none;} 22 | textarea{overflow:auto;vertical-align:top;} 23 | body{background-color:#ffffff;margin:0;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:13px;font-weight:normal;line-height:18px;color:#404040;} 24 | .container{width:940px;margin-left:auto;margin-right:auto;zoom:1;}.container:before,.container:after{display:table;content:"";zoom:1;} 25 | .container:after{clear:both;} 26 | .container-fluid{position:relative;min-width:940px;padding-left:20px;padding-right:20px;zoom:1;}.container-fluid:before,.container-fluid:after{display:table;content:"";zoom:1;} 27 | .container-fluid:after{clear:both;} 28 | .container-fluid>.sidebar{position:absolute;top:0;left:20px;width:220px;} 29 | .container-fluid>.content{margin-left:240px;} 30 | a{color:#0069d6;text-decoration:none;line-height:inherit;font-weight:inherit;}a:hover{color:#00438a;text-decoration:underline;} 31 | .pull-right{float:right;} 32 | .pull-left{float:left;} 33 | .hide{display:none;} 34 | .show{display:block;} 35 | .row{zoom:1;margin-left:-20px;}.row:before,.row:after{display:table;content:"";zoom:1;} 36 | .row:after{clear:both;} 37 | .row>[class*="span"]{display:inline;float:left;margin-left:20px;} 38 | .span1{width:40px;} 39 | .span2{width:100px;} 40 | .span3{width:160px;} 41 | .span4{width:220px;} 42 | .span5{width:280px;} 43 | .span6{width:340px;} 44 | .span7{width:400px;} 45 | .span8{width:460px;} 46 | .span9{width:520px;} 47 | .span10{width:580px;} 48 | .span11{width:640px;} 49 | .span12{width:700px;} 50 | .span13{width:760px;} 51 | .span14{width:820px;} 52 | .span15{width:880px;} 53 | .span16{width:940px;} 54 | .span17{width:1000px;} 55 | .span18{width:1060px;} 56 | .span19{width:1120px;} 57 | .span20{width:1180px;} 58 | .span21{width:1240px;} 59 | .span22{width:1300px;} 60 | .span23{width:1360px;} 61 | .span24{width:1420px;} 62 | .row>.offset1{margin-left:80px;} 63 | .row>.offset2{margin-left:140px;} 64 | .row>.offset3{margin-left:200px;} 65 | .row>.offset4{margin-left:260px;} 66 | .row>.offset5{margin-left:320px;} 67 | .row>.offset6{margin-left:380px;} 68 | .row>.offset7{margin-left:440px;} 69 | .row>.offset8{margin-left:500px;} 70 | .row>.offset9{margin-left:560px;} 71 | .row>.offset10{margin-left:620px;} 72 | .row>.offset11{margin-left:680px;} 73 | .row>.offset12{margin-left:740px;} 74 | .span-one-third{width:300px;} 75 | .span-two-thirds{width:620px;} 76 | .row>.offset-one-third{margin-left:340px;} 77 | .row>.offset-two-thirds{margin-left:660px;} 78 | p{font-size:13px;font-weight:normal;line-height:18px;margin-bottom:9px;}p small{font-size:11px;color:#bfbfbf;} 79 | h1,h2,h3,h4,h5,h6{font-weight:bold;color:#404040;}h1 small,h2 small,h3 small,h4 small,h5 small,h6 small{color:#bfbfbf;} 80 | h1{margin-bottom:18px;font-size:30px;line-height:36px;}h1 small{font-size:18px;} 81 | h2{font-size:24px;line-height:36px;}h2 small{font-size:14px;} 82 | h3,h4,h5,h6{line-height:36px;} 83 | h3{font-size:18px;}h3 small{font-size:14px;} 84 | h4{font-size:16px;}h4 small{font-size:12px;} 85 | h5{font-size:14px;} 86 | h6{font-size:13px;color:#bfbfbf;text-transform:uppercase;} 87 | ul,ol{margin:0 0 18px 25px;} 88 | ul ul,ul ol,ol ol,ol ul{margin-bottom:0;} 89 | ul{list-style:disc;} 90 | ol{list-style:decimal;} 91 | li{line-height:18px;color:#808080;} 92 | ul.unstyled{list-style:none;margin-left:0;} 93 | dl{margin-bottom:18px;}dl dt,dl dd{line-height:18px;} 94 | dl dt{font-weight:bold;} 95 | dl dd{margin-left:9px;} 96 | hr{margin:20px 0 19px;border:0;border-bottom:1px solid #eee;} 97 | strong{font-style:inherit;font-weight:bold;} 98 | em{font-style:italic;font-weight:inherit;line-height:inherit;} 99 | .muted{color:#bfbfbf;} 100 | blockquote{margin-bottom:18px;border-left:5px solid #eee;padding-left:15px;}blockquote p{font-size:14px;font-weight:300;line-height:18px;margin-bottom:0;} 101 | blockquote small{display:block;font-size:12px;font-weight:300;line-height:18px;color:#bfbfbf;}blockquote small:before{content:'\2014 \00A0';} 102 | address{display:block;line-height:18px;margin-bottom:18px;} 103 | code,pre{padding:0 3px 2px;font-family:Monaco, Andale Mono, Courier New, monospace;font-size:12px;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;} 104 | code{background-color:#fee9cc;color:rgba(0, 0, 0, 0.75);padding:1px 3px;} 105 | pre{background-color:#f5f5f5;display:block;padding:8.5px;margin:0 0 18px;line-height:18px;font-size:12px;border:1px solid #ccc;border:1px solid rgba(0, 0, 0, 0.15);-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;white-space:pre;white-space:pre-wrap;word-wrap:break-word;} 106 | form{margin-bottom:18px;} 107 | fieldset{margin-bottom:18px;padding-top:18px;}fieldset legend{display:block;padding-left:150px;font-size:19.5px;line-height:1;color:#404040;*padding:0 0 5px 145px;*line-height:1.5;} 108 | form .clearfix{margin-bottom:18px;zoom:1;}form .clearfix:before,form .clearfix:after{display:table;content:"";zoom:1;} 109 | form .clearfix:after{clear:both;} 110 | label,input,select,textarea{font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:13px;font-weight:normal;line-height:normal;} 111 | label{padding-top:6px;font-size:13px;line-height:18px;float:left;width:130px;text-align:right;color:#404040;} 112 | form .input{margin-left:150px;} 113 | input[type=checkbox],input[type=radio]{cursor:pointer;} 114 | input,textarea,select,.uneditable-input{display:inline-block;width:210px;height:18px;padding:4px;font-size:13px;line-height:18px;color:#808080;border:1px solid #ccc;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;} 115 | select{padding:initial;} 116 | input[type=checkbox],input[type=radio]{width:auto;height:auto;padding:0;margin:3px 0;*margin-top:0;line-height:normal;border:none;} 117 | input[type=file]{background-color:#ffffff;padding:initial;border:initial;line-height:initial;-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none;} 118 | input[type=button],input[type=reset],input[type=submit]{width:auto;height:auto;} 119 | select,input[type=file]{height:27px;*height:auto;line-height:27px;*margin-top:4px;} 120 | select[multiple]{height:inherit;background-color:#ffffff;} 121 | textarea{height:auto;} 122 | .uneditable-input{background-color:#ffffff;display:block;border-color:#eee;-webkit-box-shadow:inset 0 1px 2px rgba(0, 0, 0, 0.025);-moz-box-shadow:inset 0 1px 2px rgba(0, 0, 0, 0.025);box-shadow:inset 0 1px 2px rgba(0, 0, 0, 0.025);cursor:not-allowed;} 123 | :-moz-placeholder{color:#bfbfbf;} 124 | ::-webkit-input-placeholder{color:#bfbfbf;} 125 | input,textarea{-webkit-transition:border linear 0.2s,box-shadow linear 0.2s;-moz-transition:border linear 0.2s,box-shadow linear 0.2s;-ms-transition:border linear 0.2s,box-shadow linear 0.2s;-o-transition:border linear 0.2s,box-shadow linear 0.2s;transition:border linear 0.2s,box-shadow linear 0.2s;-webkit-box-shadow:inset 0 1px 3px rgba(0, 0, 0, 0.1);-moz-box-shadow:inset 0 1px 3px rgba(0, 0, 0, 0.1);box-shadow:inset 0 1px 3px rgba(0, 0, 0, 0.1);} 126 | input:focus,textarea:focus{outline:0;border-color:rgba(82, 168, 236, 0.8);-webkit-box-shadow:inset 0 1px 3px rgba(0, 0, 0, 0.1),0 0 8px rgba(82, 168, 236, 0.6);-moz-box-shadow:inset 0 1px 3px rgba(0, 0, 0, 0.1),0 0 8px rgba(82, 168, 236, 0.6);box-shadow:inset 0 1px 3px rgba(0, 0, 0, 0.1),0 0 8px rgba(82, 168, 236, 0.6);} 127 | input[type=file]:focus,input[type=checkbox]:focus,select:focus{-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none;outline:1px dotted #666;} 128 | form .clearfix.error>label,form .clearfix.error .help-block,form .clearfix.error .help-inline{color:#b94a48;} 129 | form .clearfix.error input,form .clearfix.error textarea{color:#b94a48;border-color:#ee5f5b;}form .clearfix.error input:focus,form .clearfix.error textarea:focus{border-color:#e9322d;-webkit-box-shadow:0 0 6px #f8b9b7;-moz-box-shadow:0 0 6px #f8b9b7;box-shadow:0 0 6px #f8b9b7;} 130 | form .clearfix.error .input-prepend .add-on,form .clearfix.error .input-append .add-on{color:#b94a48;background-color:#fce6e6;border-color:#b94a48;} 131 | form .clearfix.warning>label,form .clearfix.warning .help-block,form .clearfix.warning .help-inline{color:#c09853;} 132 | form .clearfix.warning input,form .clearfix.warning textarea{color:#c09853;border-color:#ccae64;}form .clearfix.warning input:focus,form .clearfix.warning textarea:focus{border-color:#be9a3f;-webkit-box-shadow:0 0 6px #e5d6b1;-moz-box-shadow:0 0 6px #e5d6b1;box-shadow:0 0 6px #e5d6b1;} 133 | form .clearfix.warning .input-prepend .add-on,form .clearfix.warning .input-append .add-on{color:#c09853;background-color:#d2b877;border-color:#c09853;} 134 | form .clearfix.success>label,form .clearfix.success .help-block,form .clearfix.success .help-inline{color:#468847;} 135 | form .clearfix.success input,form .clearfix.success textarea{color:#468847;border-color:#57a957;}form .clearfix.success input:focus,form .clearfix.success textarea:focus{border-color:#458845;-webkit-box-shadow:0 0 6px #9acc9a;-moz-box-shadow:0 0 6px #9acc9a;box-shadow:0 0 6px #9acc9a;} 136 | form .clearfix.success .input-prepend .add-on,form .clearfix.success .input-append .add-on{color:#468847;background-color:#bcddbc;border-color:#468847;} 137 | .input-mini,input.mini,textarea.mini,select.mini{width:60px;} 138 | .input-small,input.small,textarea.small,select.small{width:90px;} 139 | .input-medium,input.medium,textarea.medium,select.medium{width:150px;} 140 | .input-large,input.large,textarea.large,select.large{width:210px;} 141 | .input-xlarge,input.xlarge,textarea.xlarge,select.xlarge{width:270px;} 142 | .input-xxlarge,input.xxlarge,textarea.xxlarge,select.xxlarge{width:530px;} 143 | textarea.xxlarge{overflow-y:auto;} 144 | input.span1,textarea.span1{display:inline-block;float:none;width:30px;margin-left:0;} 145 | input.span2,textarea.span2{display:inline-block;float:none;width:90px;margin-left:0;} 146 | input.span3,textarea.span3{display:inline-block;float:none;width:150px;margin-left:0;} 147 | input.span4,textarea.span4{display:inline-block;float:none;width:210px;margin-left:0;} 148 | input.span5,textarea.span5{display:inline-block;float:none;width:270px;margin-left:0;} 149 | input.span6,textarea.span6{display:inline-block;float:none;width:330px;margin-left:0;} 150 | input.span7,textarea.span7{display:inline-block;float:none;width:390px;margin-left:0;} 151 | input.span8,textarea.span8{display:inline-block;float:none;width:450px;margin-left:0;} 152 | input.span9,textarea.span9{display:inline-block;float:none;width:510px;margin-left:0;} 153 | input.span10,textarea.span10{display:inline-block;float:none;width:570px;margin-left:0;} 154 | input.span11,textarea.span11{display:inline-block;float:none;width:630px;margin-left:0;} 155 | input.span12,textarea.span12{display:inline-block;float:none;width:690px;margin-left:0;} 156 | input.span13,textarea.span13{display:inline-block;float:none;width:750px;margin-left:0;} 157 | input.span14,textarea.span14{display:inline-block;float:none;width:810px;margin-left:0;} 158 | input.span15,textarea.span15{display:inline-block;float:none;width:870px;margin-left:0;} 159 | input.span16,textarea.span16{display:inline-block;float:none;width:930px;margin-left:0;} 160 | input[disabled],select[disabled],textarea[disabled],input[readonly],select[readonly],textarea[readonly]{background-color:#f5f5f5;border-color:#ddd;cursor:not-allowed;} 161 | .actions{background:#f5f5f5;margin-top:18px;margin-bottom:18px;padding:17px 20px 18px 150px;border-top:1px solid #ddd;-webkit-border-radius:0 0 3px 3px;-moz-border-radius:0 0 3px 3px;border-radius:0 0 3px 3px;}.actions .secondary-action{float:right;}.actions .secondary-action a{line-height:30px;}.actions .secondary-action a:hover{text-decoration:underline;} 162 | .help-inline,.help-block{font-size:13px;line-height:18px;color:#bfbfbf;} 163 | .help-inline{padding-left:5px;*position:relative;*top:-5px;} 164 | .help-block{display:block;max-width:600px;} 165 | .inline-inputs{color:#808080;}.inline-inputs span{padding:0 2px 0 1px;} 166 | .input-prepend input,.input-append input{-webkit-border-radius:0 3px 3px 0;-moz-border-radius:0 3px 3px 0;border-radius:0 3px 3px 0;} 167 | .input-prepend .add-on,.input-append .add-on{position:relative;background:#f5f5f5;border:1px solid #ccc;z-index:2;float:left;display:block;width:auto;min-width:16px;height:18px;padding:4px 4px 4px 5px;margin-right:-1px;font-weight:normal;line-height:18px;color:#bfbfbf;text-align:center;text-shadow:0 1px 0 #ffffff;-webkit-border-radius:3px 0 0 3px;-moz-border-radius:3px 0 0 3px;border-radius:3px 0 0 3px;} 168 | .input-prepend .active,.input-append .active{background:#a9dba9;border-color:#46a546;} 169 | .input-prepend .add-on{*margin-top:1px;} 170 | .input-append input{float:left;-webkit-border-radius:3px 0 0 3px;-moz-border-radius:3px 0 0 3px;border-radius:3px 0 0 3px;} 171 | .input-append .add-on{-webkit-border-radius:0 3px 3px 0;-moz-border-radius:0 3px 3px 0;border-radius:0 3px 3px 0;margin-right:0;margin-left:-1px;} 172 | .inputs-list{margin:0 0 5px;width:100%;}.inputs-list li{display:block;padding:0;width:100%;} 173 | .inputs-list label{display:block;float:none;width:auto;padding:0;margin-left:20px;line-height:18px;text-align:left;white-space:normal;}.inputs-list label strong{color:#808080;} 174 | .inputs-list label small{font-size:11px;font-weight:normal;} 175 | .inputs-list .inputs-list{margin-left:25px;margin-bottom:10px;padding-top:0;} 176 | .inputs-list:first-child{padding-top:6px;} 177 | .inputs-list li+li{padding-top:2px;} 178 | .inputs-list input[type=radio],.inputs-list input[type=checkbox]{margin-bottom:0;margin-left:-20px;float:left;} 179 | .form-stacked{padding-left:20px;}.form-stacked fieldset{padding-top:9px;} 180 | .form-stacked legend{padding-left:0;} 181 | .form-stacked label{display:block;float:none;width:auto;font-weight:bold;text-align:left;line-height:20px;padding-top:0;} 182 | .form-stacked .clearfix{margin-bottom:9px;}.form-stacked .clearfix div.input{margin-left:0;} 183 | .form-stacked .inputs-list{margin-bottom:0;}.form-stacked .inputs-list li{padding-top:0;}.form-stacked .inputs-list li label{font-weight:normal;padding-top:0;} 184 | .form-stacked div.clearfix.error{padding-top:10px;padding-bottom:10px;padding-left:10px;margin-top:0;margin-left:-10px;} 185 | .form-stacked .actions{margin-left:-20px;padding-left:20px;} 186 | table{width:100%;margin-bottom:18px;padding:0;font-size:13px;border-collapse:collapse;}table th,table td{padding:10px 10px 9px;line-height:18px;text-align:left;} 187 | table th{padding-top:9px;font-weight:bold;vertical-align:middle;} 188 | table td{vertical-align:top;border-top:1px solid #ddd;} 189 | table tbody th{border-top:1px solid #ddd;vertical-align:top;} 190 | .condensed-table th,.condensed-table td{padding:5px 5px 4px;} 191 | .bordered-table{border:1px solid #ddd;border-collapse:separate;*border-collapse:collapse;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;}.bordered-table th+th,.bordered-table td+td,.bordered-table th+td{border-left:1px solid #ddd;} 192 | .bordered-table thead tr:first-child th:first-child,.bordered-table tbody tr:first-child td:first-child{-webkit-border-radius:4px 0 0 0;-moz-border-radius:4px 0 0 0;border-radius:4px 0 0 0;} 193 | .bordered-table thead tr:first-child th:last-child,.bordered-table tbody tr:first-child td:last-child{-webkit-border-radius:0 4px 0 0;-moz-border-radius:0 4px 0 0;border-radius:0 4px 0 0;} 194 | .bordered-table tbody tr:last-child td:first-child{-webkit-border-radius:0 0 0 4px;-moz-border-radius:0 0 0 4px;border-radius:0 0 0 4px;} 195 | .bordered-table tbody tr:last-child td:last-child{-webkit-border-radius:0 0 4px 0;-moz-border-radius:0 0 4px 0;border-radius:0 0 4px 0;} 196 | table .span1{width:20px;} 197 | table .span2{width:60px;} 198 | table .span3{width:100px;} 199 | table .span4{width:140px;} 200 | table .span5{width:180px;} 201 | table .span6{width:220px;} 202 | table .span7{width:260px;} 203 | table .span8{width:300px;} 204 | table .span9{width:340px;} 205 | table .span10{width:380px;} 206 | table .span11{width:420px;} 207 | table .span12{width:460px;} 208 | table .span13{width:500px;} 209 | table .span14{width:540px;} 210 | table .span15{width:580px;} 211 | table .span16{width:620px;} 212 | .zebra-striped tbody tr:nth-child(odd) td,.zebra-striped tbody tr:nth-child(odd) th{background-color:#f9f9f9;} 213 | .zebra-striped tbody tr:hover td,.zebra-striped tbody tr:hover th{background-color:#f5f5f5;} 214 | table .header{cursor:pointer;}table .header:after{content:"";float:right;margin-top:7px;border-width:0 4px 4px;border-style:solid;border-color:#000 transparent;visibility:hidden;} 215 | table .headerSortUp,table .headerSortDown{background-color:rgba(141, 192, 219, 0.25);text-shadow:0 1px 1px rgba(255, 255, 255, 0.75);} 216 | table .header:hover:after{visibility:visible;} 217 | table .headerSortDown:after,table .headerSortDown:hover:after{visibility:visible;filter:alpha(opacity=60);-khtml-opacity:0.6;-moz-opacity:0.6;opacity:0.6;} 218 | table .headerSortUp:after{border-bottom:none;border-left:4px solid transparent;border-right:4px solid transparent;border-top:4px solid #000;visibility:visible;-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none;filter:alpha(opacity=60);-khtml-opacity:0.6;-moz-opacity:0.6;opacity:0.6;} 219 | table .blue{color:#049cdb;border-bottom-color:#049cdb;} 220 | table .headerSortUp.blue,table .headerSortDown.blue{background-color:#ade6fe;} 221 | table .green{color:#46a546;border-bottom-color:#46a546;} 222 | table .headerSortUp.green,table .headerSortDown.green{background-color:#cdeacd;} 223 | table .red{color:#9d261d;border-bottom-color:#9d261d;} 224 | table .headerSortUp.red,table .headerSortDown.red{background-color:#f4c8c5;} 225 | table .yellow{color:#ffc40d;border-bottom-color:#ffc40d;} 226 | table .headerSortUp.yellow,table .headerSortDown.yellow{background-color:#fff6d9;} 227 | table .orange{color:#f89406;border-bottom-color:#f89406;} 228 | table .headerSortUp.orange,table .headerSortDown.orange{background-color:#fee9cc;} 229 | table .purple{color:#7a43b6;border-bottom-color:#7a43b6;} 230 | table .headerSortUp.purple,table .headerSortDown.purple{background-color:#e2d5f0;} 231 | .topbar{height:40px;position:fixed;top:0;left:0;right:0;z-index:10000;overflow:visible;}.topbar a{color:#bfbfbf;text-shadow:0 -1px 0 rgba(0, 0, 0, 0.25);} 232 | .topbar h3 a:hover,.topbar .brand:hover,.topbar ul .active>a{background-color:#333;background-color:rgba(255, 255, 255, 0.05);color:#ffffff;text-decoration:none;} 233 | .topbar h3{position:relative;} 234 | .topbar h3 a,.topbar .brand{float:left;display:block;padding:8px 20px 12px;margin-left:-20px;color:#ffffff;font-size:20px;font-weight:200;line-height:1;} 235 | .topbar p{margin:0;line-height:40px;}.topbar p a:hover{background-color:transparent;color:#ffffff;} 236 | .topbar form{float:left;margin:5px 0 0 0;position:relative;filter:alpha(opacity=100);-khtml-opacity:1;-moz-opacity:1;opacity:1;} 237 | .topbar form.pull-right{float:right;} 238 | .topbar input{background-color:#444;background-color:rgba(255, 255, 255, 0.3);font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:normal;font-weight:13px;line-height:1;padding:4px 9px;color:#ffffff;color:rgba(255, 255, 255, 0.75);border:1px solid #111;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;-webkit-box-shadow:inset 0 1px 2px rgba(0, 0, 0, 0.1),0 1px 0px rgba(255, 255, 255, 0.25);-moz-box-shadow:inset 0 1px 2px rgba(0, 0, 0, 0.1),0 1px 0px rgba(255, 255, 255, 0.25);box-shadow:inset 0 1px 2px rgba(0, 0, 0, 0.1),0 1px 0px rgba(255, 255, 255, 0.25);-webkit-transition:none;-moz-transition:none;-ms-transition:none;-o-transition:none;transition:none;}.topbar input:-moz-placeholder{color:#e6e6e6;} 239 | .topbar input::-webkit-input-placeholder{color:#e6e6e6;} 240 | .topbar input:hover{background-color:#bfbfbf;background-color:rgba(255, 255, 255, 0.5);color:#ffffff;} 241 | .topbar input:focus,.topbar input.focused{outline:0;background-color:#ffffff;color:#404040;text-shadow:0 1px 0 #ffffff;border:0;padding:5px 10px;-webkit-box-shadow:0 0 3px rgba(0, 0, 0, 0.15);-moz-box-shadow:0 0 3px rgba(0, 0, 0, 0.15);box-shadow:0 0 3px rgba(0, 0, 0, 0.15);} 242 | .topbar-inner,.topbar .fill{background-color:#222;background-color:#222222;background-repeat:repeat-x;background-image:-khtml-gradient(linear, left top, left bottom, from(#333333), to(#222222));background-image:-moz-linear-gradient(top, #333333, #222222);background-image:-ms-linear-gradient(top, #333333, #222222);background-image:-webkit-gradient(linear, left top, left bottom, color-stop(0%, #333333), color-stop(100%, #222222));background-image:-webkit-linear-gradient(top, #333333, #222222);background-image:-o-linear-gradient(top, #333333, #222222);background-image:linear-gradient(top, #333333, #222222);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#333333', endColorstr='#222222', GradientType=0);-webkit-box-shadow:0 1px 3px rgba(0, 0, 0, 0.25),inset 0 -1px 0 rgba(0, 0, 0, 0.1);-moz-box-shadow:0 1px 3px rgba(0, 0, 0, 0.25),inset 0 -1px 0 rgba(0, 0, 0, 0.1);box-shadow:0 1px 3px rgba(0, 0, 0, 0.25),inset 0 -1px 0 rgba(0, 0, 0, 0.1);} 243 | .topbar div>ul,.nav{display:block;float:left;margin:0 10px 0 0;position:relative;left:0;}.topbar div>ul>li,.nav>li{display:block;float:left;} 244 | .topbar div>ul a,.nav a{display:block;float:none;padding:10px 10px 11px;line-height:19px;text-decoration:none;}.topbar div>ul a:hover,.nav a:hover{color:#ffffff;text-decoration:none;} 245 | .topbar div>ul .active>a,.nav .active>a{background-color:#222;background-color:rgba(0, 0, 0, 0.5);} 246 | .topbar div>ul.secondary-nav,.nav.secondary-nav{float:right;margin-left:10px;margin-right:0;}.topbar div>ul.secondary-nav .menu-dropdown,.nav.secondary-nav .menu-dropdown,.topbar div>ul.secondary-nav .dropdown-menu,.nav.secondary-nav .dropdown-menu{right:0;border:0;} 247 | .topbar div>ul a.menu:hover,.nav a.menu:hover,.topbar div>ul li.open .menu,.nav li.open .menu,.topbar div>ul .dropdown-toggle:hover,.nav .dropdown-toggle:hover,.topbar div>ul .dropdown.open .dropdown-toggle,.nav .dropdown.open .dropdown-toggle{background:#444;background:rgba(255, 255, 255, 0.05);} 248 | .topbar div>ul .menu-dropdown,.nav .menu-dropdown,.topbar div>ul .dropdown-menu,.nav .dropdown-menu{background-color:#333;}.topbar div>ul .menu-dropdown a.menu,.nav .menu-dropdown a.menu,.topbar div>ul .dropdown-menu a.menu,.nav .dropdown-menu a.menu,.topbar div>ul .menu-dropdown .dropdown-toggle,.nav .menu-dropdown .dropdown-toggle,.topbar div>ul .dropdown-menu .dropdown-toggle,.nav .dropdown-menu .dropdown-toggle{color:#ffffff;}.topbar div>ul .menu-dropdown a.menu.open,.nav .menu-dropdown a.menu.open,.topbar div>ul .dropdown-menu a.menu.open,.nav .dropdown-menu a.menu.open,.topbar div>ul .menu-dropdown .dropdown-toggle.open,.nav .menu-dropdown .dropdown-toggle.open,.topbar div>ul .dropdown-menu .dropdown-toggle.open,.nav .dropdown-menu .dropdown-toggle.open{background:#444;background:rgba(255, 255, 255, 0.05);} 249 | .topbar div>ul .menu-dropdown li a,.nav .menu-dropdown li a,.topbar div>ul .dropdown-menu li a,.nav .dropdown-menu li a{color:#999;text-shadow:0 1px 0 rgba(0, 0, 0, 0.5);}.topbar div>ul .menu-dropdown li a:hover,.nav .menu-dropdown li a:hover,.topbar div>ul .dropdown-menu li a:hover,.nav .dropdown-menu li a:hover{background-color:#191919;background-repeat:repeat-x;background-image:-khtml-gradient(linear, left top, left bottom, from(#292929), to(#191919));background-image:-moz-linear-gradient(top, #292929, #191919);background-image:-ms-linear-gradient(top, #292929, #191919);background-image:-webkit-gradient(linear, left top, left bottom, color-stop(0%, #292929), color-stop(100%, #191919));background-image:-webkit-linear-gradient(top, #292929, #191919);background-image:-o-linear-gradient(top, #292929, #191919);background-image:linear-gradient(top, #292929, #191919);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#292929', endColorstr='#191919', GradientType=0);color:#ffffff;} 250 | .topbar div>ul .menu-dropdown .active a,.nav .menu-dropdown .active a,.topbar div>ul .dropdown-menu .active a,.nav .dropdown-menu .active a{color:#ffffff;} 251 | .topbar div>ul .menu-dropdown .divider,.nav .menu-dropdown .divider,.topbar div>ul .dropdown-menu .divider,.nav .dropdown-menu .divider{background-color:#222;border-color:#444;} 252 | .topbar ul .menu-dropdown li a,.topbar ul .dropdown-menu li a, .topbar ul .menu-dropdown form {padding:4px 15px;} 253 | li.menu,.dropdown{position:relative;} 254 | a.menu:after,.dropdown-toggle:after{width:0;height:0;display:inline-block;content:"↓";text-indent:-99999px;vertical-align:top;margin-top:8px;margin-left:4px;border-left:4px solid transparent;border-right:4px solid transparent;border-top:4px solid #ffffff;filter:alpha(opacity=50);-khtml-opacity:0.5;-moz-opacity:0.5;opacity:0.5;} 255 | .menu-dropdown,.dropdown-menu{background-color:#ffffff;float:left;display:none;position:absolute;top:40px;z-index:900;min-width:160px;max-width:220px;_width:160px;margin-left:0;margin-right:0;padding:6px 0;zoom:1;border-color:#999;border-color:rgba(0, 0, 0, 0.2);border-style:solid;border-width:0 1px 1px;-webkit-border-radius:0 0 6px 6px;-moz-border-radius:0 0 6px 6px;border-radius:0 0 6px 6px;-webkit-box-shadow:0 2px 4px rgba(0, 0, 0, 0.2);-moz-box-shadow:0 2px 4px rgba(0, 0, 0, 0.2);box-shadow:0 2px 4px rgba(0, 0, 0, 0.2);-webkit-background-clip:padding-box;-moz-background-clip:padding-box;background-clip:padding-box;}.menu-dropdown li,.dropdown-menu li{float:none;display:block;background-color:none;} 256 | .menu-dropdown .divider,.dropdown-menu .divider{height:1px;margin:5px 0;overflow:hidden;background-color:#eee;border-bottom:1px solid #ffffff;} 257 | .topbar .dropdown-menu a,.dropdown-menu a{display:block;padding:4px 15px;clear:both;font-weight:normal;line-height:18px;color:#808080;text-shadow:0 1px 0 #ffffff;}.topbar .dropdown-menu a:hover,.dropdown-menu a:hover,.topbar .dropdown-menu a.hover,.dropdown-menu a.hover{background-color:#dddddd;background-repeat:repeat-x;background-image:-khtml-gradient(linear, left top, left bottom, from(#eeeeee), to(#dddddd));background-image:-moz-linear-gradient(top, #eeeeee, #dddddd);background-image:-ms-linear-gradient(top, #eeeeee, #dddddd);background-image:-webkit-gradient(linear, left top, left bottom, color-stop(0%, #eeeeee), color-stop(100%, #dddddd));background-image:-webkit-linear-gradient(top, #eeeeee, #dddddd);background-image:-o-linear-gradient(top, #eeeeee, #dddddd);background-image:linear-gradient(top, #eeeeee, #dddddd);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#eeeeee', endColorstr='#dddddd', GradientType=0);color:#404040;text-decoration:none;-webkit-box-shadow:inset 0 1px 0 rgba(0, 0, 0, 0.025),inset 0 -1px rgba(0, 0, 0, 0.025);-moz-box-shadow:inset 0 1px 0 rgba(0, 0, 0, 0.025),inset 0 -1px rgba(0, 0, 0, 0.025);box-shadow:inset 0 1px 0 rgba(0, 0, 0, 0.025),inset 0 -1px rgba(0, 0, 0, 0.025);} 258 | .open .menu,.dropdown.open .menu,.open .dropdown-toggle,.dropdown.open .dropdown-toggle{color:#ffffff;background:#ccc;background:rgba(0, 0, 0, 0.3);} 259 | .open .menu-dropdown,.dropdown.open .menu-dropdown,.open .dropdown-menu,.dropdown.open .dropdown-menu{display:block;} 260 | .tabs,.pills{margin:0 0 18px;padding:0;list-style:none;zoom:1;}.tabs:before,.pills:before,.tabs:after,.pills:after{display:table;content:"";zoom:1;} 261 | .tabs:after,.pills:after{clear:both;} 262 | .tabs>li,.pills>li{float:left;}.tabs>li>a,.pills>li>a{display:block;} 263 | .tabs{border-color:#ddd;border-style:solid;border-width:0 0 1px;}.tabs>li{position:relative;margin-bottom:-1px;}.tabs>li>a{padding:0 15px;margin-right:2px;line-height:34px;border:1px solid transparent;-webkit-border-radius:4px 4px 0 0;-moz-border-radius:4px 4px 0 0;border-radius:4px 4px 0 0;}.tabs>li>a:hover{text-decoration:none;background-color:#eee;border-color:#eee #eee #ddd;} 264 | .tabs .active>a,.tabs .active>a:hover{color:#808080;background-color:#ffffff;border:1px solid #ddd;border-bottom-color:transparent;cursor:default;} 265 | .tabs .menu-dropdown,.tabs .dropdown-menu{top:35px;border-width:1px;-webkit-border-radius:0 6px 6px 6px;-moz-border-radius:0 6px 6px 6px;border-radius:0 6px 6px 6px;} 266 | .tabs a.menu:after,.tabs .dropdown-toggle:after{border-top-color:#999;margin-top:15px;margin-left:5px;} 267 | .tabs li.open.menu .menu,.tabs .open.dropdown .dropdown-toggle{border-color:#999;} 268 | .tabs li.open a.menu:after,.tabs .dropdown.open .dropdown-toggle:after{border-top-color:#555;} 269 | .pills a{margin:5px 3px 5px 0;padding:0 15px;line-height:30px;text-shadow:0 1px 1px #ffffff;-webkit-border-radius:15px;-moz-border-radius:15px;border-radius:15px;}.pills a:hover{color:#ffffff;text-decoration:none;text-shadow:0 1px 1px rgba(0, 0, 0, 0.25);background-color:#00438a;} 270 | .pills .active a{color:#ffffff;text-shadow:0 1px 1px rgba(0, 0, 0, 0.25);background-color:#0069d6;} 271 | .pills-vertical>li{float:none;} 272 | .tab-content>.tab-pane,.pill-content>.pill-pane,.tab-content>div,.pill-content>div{display:none;} 273 | .tab-content>.active,.pill-content>.active{display:block;} 274 | .breadcrumb{padding:7px 14px;margin:0 0 18px;background-color:#f5f5f5;background-repeat:repeat-x;background-image:-khtml-gradient(linear, left top, left bottom, from(#ffffff), to(#f5f5f5));background-image:-moz-linear-gradient(top, #ffffff, #f5f5f5);background-image:-ms-linear-gradient(top, #ffffff, #f5f5f5);background-image:-webkit-gradient(linear, left top, left bottom, color-stop(0%, #ffffff), color-stop(100%, #f5f5f5));background-image:-webkit-linear-gradient(top, #ffffff, #f5f5f5);background-image:-o-linear-gradient(top, #ffffff, #f5f5f5);background-image:linear-gradient(top, #ffffff, #f5f5f5);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#f5f5f5', GradientType=0);border:1px solid #ddd;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;-webkit-box-shadow:inset 0 1px 0 #ffffff;-moz-box-shadow:inset 0 1px 0 #ffffff;box-shadow:inset 0 1px 0 #ffffff;}.breadcrumb li{display:inline;text-shadow:0 1px 0 #ffffff;} 275 | .breadcrumb .divider{padding:0 5px;color:#bfbfbf;} 276 | .breadcrumb .active a{color:#404040;} 277 | .hero-unit{background-color:#f5f5f5;margin-bottom:30px;padding:60px;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;}.hero-unit h1{margin-bottom:0;font-size:60px;line-height:1;letter-spacing:-1px;} 278 | .hero-unit p{font-size:18px;font-weight:200;line-height:27px;} 279 | footer{margin-top:17px;padding-top:17px;border-top:1px solid #eee;} 280 | .page-header{margin-bottom:17px;border-bottom:1px solid #ddd;-webkit-box-shadow:0 1px 0 rgba(255, 255, 255, 0.5);-moz-box-shadow:0 1px 0 rgba(255, 255, 255, 0.5);box-shadow:0 1px 0 rgba(255, 255, 255, 0.5);}.page-header h1{margin-bottom:8px;} 281 | .btn.danger,.alert-message.danger,.btn.danger:hover,.alert-message.danger:hover,.btn.error,.alert-message.error,.btn.error:hover,.alert-message.error:hover,.btn.success,.alert-message.success,.btn.success:hover,.alert-message.success:hover,.btn.info,.alert-message.info,.btn.info:hover,.alert-message.info:hover{color:#ffffff;} 282 | .btn .close,.alert-message .close{font-family:Arial,sans-serif;line-height:18px;} 283 | .btn.danger,.alert-message.danger,.btn.error,.alert-message.error{background-color:#c43c35;background-repeat:repeat-x;background-image:-khtml-gradient(linear, left top, left bottom, from(#ee5f5b), to(#c43c35));background-image:-moz-linear-gradient(top, #ee5f5b, #c43c35);background-image:-ms-linear-gradient(top, #ee5f5b, #c43c35);background-image:-webkit-gradient(linear, left top, left bottom, color-stop(0%, #ee5f5b), color-stop(100%, #c43c35));background-image:-webkit-linear-gradient(top, #ee5f5b, #c43c35);background-image:-o-linear-gradient(top, #ee5f5b, #c43c35);background-image:linear-gradient(top, #ee5f5b, #c43c35);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ee5f5b', endColorstr='#c43c35', GradientType=0);text-shadow:0 -1px 0 rgba(0, 0, 0, 0.25);border-color:#c43c35 #c43c35 #882a25;border-color:rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);} 284 | .btn.success,.alert-message.success{background-color:#57a957;background-repeat:repeat-x;background-image:-khtml-gradient(linear, left top, left bottom, from(#62c462), to(#57a957));background-image:-moz-linear-gradient(top, #62c462, #57a957);background-image:-ms-linear-gradient(top, #62c462, #57a957);background-image:-webkit-gradient(linear, left top, left bottom, color-stop(0%, #62c462), color-stop(100%, #57a957));background-image:-webkit-linear-gradient(top, #62c462, #57a957);background-image:-o-linear-gradient(top, #62c462, #57a957);background-image:linear-gradient(top, #62c462, #57a957);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#62c462', endColorstr='#57a957', GradientType=0);text-shadow:0 -1px 0 rgba(0, 0, 0, 0.25);border-color:#57a957 #57a957 #3d773d;border-color:rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);} 285 | .btn.info,.alert-message.info{background-color:#339bb9;background-repeat:repeat-x;background-image:-khtml-gradient(linear, left top, left bottom, from(#5bc0de), to(#339bb9));background-image:-moz-linear-gradient(top, #5bc0de, #339bb9);background-image:-ms-linear-gradient(top, #5bc0de, #339bb9);background-image:-webkit-gradient(linear, left top, left bottom, color-stop(0%, #5bc0de), color-stop(100%, #339bb9));background-image:-webkit-linear-gradient(top, #5bc0de, #339bb9);background-image:-o-linear-gradient(top, #5bc0de, #339bb9);background-image:linear-gradient(top, #5bc0de, #339bb9);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#5bc0de', endColorstr='#339bb9', GradientType=0);text-shadow:0 -1px 0 rgba(0, 0, 0, 0.25);border-color:#339bb9 #339bb9 #22697d;border-color:rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);} 286 | .btn, .topbar input.btn {cursor:pointer;display:inline-block;background-color:#e6e6e6;background-repeat:no-repeat;background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#ffffff), color-stop(25%, #ffffff), to(#e6e6e6));background-image:-webkit-linear-gradient(#ffffff, #ffffff 25%, #e6e6e6);background-image:-moz-linear-gradient(top, #ffffff, #ffffff 25%, #e6e6e6);background-image:-ms-linear-gradient(#ffffff, #ffffff 25%, #e6e6e6);background-image:-o-linear-gradient(#ffffff, #ffffff 25%, #e6e6e6);background-image:linear-gradient(#ffffff, #ffffff 25%, #e6e6e6);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#e6e6e6', GradientType=0);padding:5px 14px 6px;text-shadow:0 1px 1px rgba(255, 255, 255, 0.75);color:#333;font-size:13px;line-height:normal;border:1px solid #ccc;border-bottom-color:#bbb;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;-webkit-box-shadow:inset 0 1px 0 rgba(255, 255, 255, 0.2),0 1px 2px rgba(0, 0, 0, 0.05);-moz-box-shadow:inset 0 1px 0 rgba(255, 255, 255, 0.2),0 1px 2px rgba(0, 0, 0, 0.05);box-shadow:inset 0 1px 0 rgba(255, 255, 255, 0.2),0 1px 2px rgba(0, 0, 0, 0.05);-webkit-transition:0.1s linear all;-moz-transition:0.1s linear all;-ms-transition:0.1s linear all;-o-transition:0.1s linear all;transition:0.1s linear all;}.btn:hover{background-position:0 -15px;color:#333;text-decoration:none;} 287 | .btn:focus{outline:1px dotted #666;} 288 | .btn.primary{color:#ffffff;background-color:#0064cd;background-repeat:repeat-x;background-image:-khtml-gradient(linear, left top, left bottom, from(#049cdb), to(#0064cd));background-image:-moz-linear-gradient(top, #049cdb, #0064cd);background-image:-ms-linear-gradient(top, #049cdb, #0064cd);background-image:-webkit-gradient(linear, left top, left bottom, color-stop(0%, #049cdb), color-stop(100%, #0064cd));background-image:-webkit-linear-gradient(top, #049cdb, #0064cd);background-image:-o-linear-gradient(top, #049cdb, #0064cd);background-image:linear-gradient(top, #049cdb, #0064cd);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#049cdb', endColorstr='#0064cd', GradientType=0);text-shadow:0 -1px 0 rgba(0, 0, 0, 0.25);border-color:#0064cd #0064cd #003f81;border-color:rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);} 289 | .btn.active,.btn:active{-webkit-box-shadow:inset 0 2px 4px rgba(0, 0, 0, 0.25),0 1px 2px rgba(0, 0, 0, 0.05);-moz-box-shadow:inset 0 2px 4px rgba(0, 0, 0, 0.25),0 1px 2px rgba(0, 0, 0, 0.05);box-shadow:inset 0 2px 4px rgba(0, 0, 0, 0.25),0 1px 2px rgba(0, 0, 0, 0.05);} 290 | .btn.disabled{cursor:default;background-image:none;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);filter:alpha(opacity=65);-khtml-opacity:0.65;-moz-opacity:0.65;opacity:0.65;-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none;} 291 | .btn[disabled]{cursor:default;background-image:none;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);filter:alpha(opacity=65);-khtml-opacity:0.65;-moz-opacity:0.65;opacity:0.65;-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none;} 292 | .btn.large{font-size:15px;line-height:normal;padding:9px 14px 9px;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;} 293 | .btn.small{padding:7px 9px 7px;font-size:11px;} 294 | :root .alert-message,:root .btn{border-radius:0 \0;} 295 | button.btn::-moz-focus-inner,input[type=submit].btn::-moz-focus-inner{padding:0;border:0;} 296 | .close{float:right;color:#000000;font-size:20px;font-weight:bold;line-height:13.5px;text-shadow:0 1px 0 #ffffff;filter:alpha(opacity=25);-khtml-opacity:0.25;-moz-opacity:0.25;opacity:0.25;}.close:hover{color:#000000;text-decoration:none;filter:alpha(opacity=40);-khtml-opacity:0.4;-moz-opacity:0.4;opacity:0.4;} 297 | .alert-message{position:relative;padding:7px 15px;margin-bottom:18px;color:#404040;background-color:#eedc94;background-repeat:repeat-x;background-image:-khtml-gradient(linear, left top, left bottom, from(#fceec1), to(#eedc94));background-image:-moz-linear-gradient(top, #fceec1, #eedc94);background-image:-ms-linear-gradient(top, #fceec1, #eedc94);background-image:-webkit-gradient(linear, left top, left bottom, color-stop(0%, #fceec1), color-stop(100%, #eedc94));background-image:-webkit-linear-gradient(top, #fceec1, #eedc94);background-image:-o-linear-gradient(top, #fceec1, #eedc94);background-image:linear-gradient(top, #fceec1, #eedc94);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fceec1', endColorstr='#eedc94', GradientType=0);text-shadow:0 -1px 0 rgba(0, 0, 0, 0.25);border-color:#eedc94 #eedc94 #e4c652;border-color:rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);text-shadow:0 1px 0 rgba(255, 255, 255, 0.5);border-width:1px;border-style:solid;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;-webkit-box-shadow:inset 0 1px 0 rgba(255, 255, 255, 0.25);-moz-box-shadow:inset 0 1px 0 rgba(255, 255, 255, 0.25);box-shadow:inset 0 1px 0 rgba(255, 255, 255, 0.25);}.alert-message .close{margin-top:1px;*margin-top:0;} 298 | .alert-message a{font-weight:bold;color:#404040;} 299 | .alert-message.danger p a,.alert-message.error p a,.alert-message.success p a,.alert-message.info p a{color:#ffffff;} 300 | .alert-message h5{line-height:18px;} 301 | .alert-message p{margin-bottom:0;} 302 | .alert-message div{margin-top:5px;margin-bottom:2px;line-height:28px;} 303 | .alert-message .btn{-webkit-box-shadow:0 1px 0 rgba(255, 255, 255, 0.25);-moz-box-shadow:0 1px 0 rgba(255, 255, 255, 0.25);box-shadow:0 1px 0 rgba(255, 255, 255, 0.25);} 304 | .alert-message.block-message{background-image:none;background-color:#fdf5d9;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);padding:14px;border-color:#fceec1;-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none;}.alert-message.block-message ul,.alert-message.block-message p{margin-right:30px;} 305 | .alert-message.block-message ul{margin-bottom:0;} 306 | .alert-message.block-message li{color:#404040;} 307 | .alert-message.block-message .alert-actions{margin-top:5px;} 308 | .alert-message.block-message.error,.alert-message.block-message.success,.alert-message.block-message.info{color:#404040;text-shadow:0 1px 0 rgba(255, 255, 255, 0.5);} 309 | .alert-message.block-message.error{background-color:#fddfde;border-color:#fbc7c6;} 310 | .alert-message.block-message.success{background-color:#d1eed1;border-color:#bfe7bf;} 311 | .alert-message.block-message.info{background-color:#ddf4fb;border-color:#c6edf9;} 312 | .alert-message.block-message.danger p a,.alert-message.block-message.error p a,.alert-message.block-message.success p a,.alert-message.block-message.info p a{color:#404040;} 313 | .pagination{height:36px;margin:18px 0;}.pagination ul{float:left;margin:0;border:1px solid #ddd;border:1px solid rgba(0, 0, 0, 0.15);-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;-webkit-box-shadow:0 1px 2px rgba(0, 0, 0, 0.05);-moz-box-shadow:0 1px 2px rgba(0, 0, 0, 0.05);box-shadow:0 1px 2px rgba(0, 0, 0, 0.05);} 314 | .pagination li{display:inline;} 315 | .pagination a{float:left;padding:0 14px;line-height:34px;border-right:1px solid;border-right-color:#ddd;border-right-color:rgba(0, 0, 0, 0.15);*border-right-color:#ddd;text-decoration:none;} 316 | .pagination a:hover,.pagination .active a{background-color:#c7eefe;} 317 | .pagination .disabled a,.pagination .disabled a:hover{background-color:transparent;color:#bfbfbf;} 318 | .pagination .next a{border:0;} 319 | .well{background-color:#f5f5f5;margin-bottom:20px;padding:19px;min-height:20px;border:1px solid #eee;border:1px solid rgba(0, 0, 0, 0.05);-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;-webkit-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.05);-moz-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.05);box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.05);}.well blockquote{border-color:#ddd;border-color:rgba(0, 0, 0, 0.15);} 320 | .modal-backdrop{background-color:#000000;position:fixed;top:0;left:0;right:0;bottom:0;z-index:10000;}.modal-backdrop.fade{opacity:0;} 321 | .modal-backdrop,.modal-backdrop.fade.in{filter:alpha(opacity=80);-khtml-opacity:0.8;-moz-opacity:0.8;opacity:0.8;} 322 | .modal{position:fixed;top:50%;left:50%;z-index:11000;width:550px;margin:-250px 0 0 -280px;background-color:#ffffff;border:1px solid #999;border:1px solid rgba(0, 0, 0, 0.3);*border:1px solid #999;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;-webkit-box-shadow:0 3px 7px rgba(0, 0, 0, 0.3);-moz-box-shadow:0 3px 7px rgba(0, 0, 0, 0.3);box-shadow:0 3px 7px rgba(0, 0, 0, 0.3);-webkit-background-clip:padding-box;-moz-background-clip:padding-box;background-clip:padding-box;}.modal .close{margin-top:7px;} 323 | .modal.fade{-webkit-transition:opacity .3s linear, top .3s ease-out;-moz-transition:opacity .3s linear, top .3s ease-out;-ms-transition:opacity .3s linear, top .3s ease-out;-o-transition:opacity .3s linear, top .3s ease-out;transition:opacity .3s linear, top .3s ease-out;top:-25%;} 324 | .modal.fade.in{top:50%;} 325 | .modal-header{border-bottom:1px solid #eee;padding:5px 15px;} 326 | .modal-body{padding:15px;} 327 | .modal-body form{margin-bottom:0;} 328 | .modal-footer{ font-size:30px;text-align:right;background-color:#f5f5f5;padding:14px 15px 15px;border-top:1px solid #ddd;-webkit-border-radius:0 0 6px 6px;-moz-border-radius:0 0 6px 6px;border-radius:0 0 6px 6px;-webkit-box-shadow:inset 0 1px 0 #ffffff;-moz-box-shadow:inset 0 1px 0 #ffffff;box-shadow:inset 0 1px 0 #ffffff;zoom:1;margin-bottom:0;}.modal-footer:before,.modal-footer:after{display:table;content:"";zoom:1;} 329 | .modal-footer:after{clear:both;} 330 | .modal-footer .btn{float:right;margin-left:5px;} 331 | .modal .popover,.modal .twipsy{z-index:12000;} 332 | .twipsy{display:block;position:absolute;visibility:visible;padding:5px;font-size:11px;z-index:1000;filter:alpha(opacity=80);-khtml-opacity:0.8;-moz-opacity:0.8;opacity:0.8;}.twipsy.fade.in{filter:alpha(opacity=80);-khtml-opacity:0.8;-moz-opacity:0.8;opacity:0.8;} 333 | .twipsy.above .twipsy-arrow{bottom:0;left:50%;margin-left:-5px;border-left:5px solid transparent;border-right:5px solid transparent;border-top:5px solid #000000;} 334 | .twipsy.left .twipsy-arrow{top:50%;right:0;margin-top:-5px;border-top:5px solid transparent;border-bottom:5px solid transparent;border-left:5px solid #000000;} 335 | .twipsy.below .twipsy-arrow{top:0;left:50%;margin-left:-5px;border-left:5px solid transparent;border-right:5px solid transparent;border-bottom:5px solid #000000;} 336 | .twipsy.right .twipsy-arrow{top:50%;left:0;margin-top:-5px;border-top:5px solid transparent;border-bottom:5px solid transparent;border-right:5px solid #000000;} 337 | .twipsy-inner{padding:3px 8px;background-color:#000000;color:white;text-align:center;max-width:200px;text-decoration:none;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;} 338 | .twipsy-arrow{position:absolute;width:0;height:0;} 339 | .popover{position:absolute;top:0;left:0;z-index:1000;padding:5px;display:none;}.popover.above .arrow{bottom:0;left:50%;margin-left:-5px;border-left:5px solid transparent;border-right:5px solid transparent;border-top:5px solid #000000;} 340 | .popover.right .arrow{top:50%;left:0;margin-top:-5px;border-top:5px solid transparent;border-bottom:5px solid transparent;border-right:5px solid #000000;} 341 | .popover.below .arrow{top:0;left:50%;margin-left:-5px;border-left:5px solid transparent;border-right:5px solid transparent;border-bottom:5px solid #000000;} 342 | .popover.left .arrow{top:50%;right:0;margin-top:-5px;border-top:5px solid transparent;border-bottom:5px solid transparent;border-left:5px solid #000000;} 343 | .popover .arrow{position:absolute;width:0;height:0;} 344 | .popover .inner{background:#000000;background:rgba(0, 0, 0, 0.8);padding:3px;overflow:hidden;width:280px;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;-webkit-box-shadow:0 3px 7px rgba(0, 0, 0, 0.3);-moz-box-shadow:0 3px 7px rgba(0, 0, 0, 0.3);box-shadow:0 3px 7px rgba(0, 0, 0, 0.3);} 345 | .popover .title{background-color:#f5f5f5;padding:9px 15px;line-height:1;-webkit-border-radius:3px 3px 0 0;-moz-border-radius:3px 3px 0 0;border-radius:3px 3px 0 0;border-bottom:1px solid #eee;} 346 | .popover .content{background-color:#ffffff;padding:14px;-webkit-border-radius:0 0 3px 3px;-moz-border-radius:0 0 3px 3px;border-radius:0 0 3px 3px;-webkit-background-clip:padding-box;-moz-background-clip:padding-box;background-clip:padding-box;}.popover .content p,.popover .content ul,.popover .content ol{margin-bottom:0;} 347 | .fade{-webkit-transition:opacity 0.15s linear;-moz-transition:opacity 0.15s linear;-ms-transition:opacity 0.15s linear;-o-transition:opacity 0.15s linear;transition:opacity 0.15s linear;opacity:0;}.fade.in{opacity:1;} 348 | .label{padding:1px 3px 2px;font-size:9.75px;font-weight:bold;color:#ffffff;text-transform:uppercase;white-space:nowrap;background-color:#bfbfbf;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;}.label.important{background-color:#c43c35;} 349 | .label.warning{background-color:#f89406;} 350 | .label.success{background-color:#46a546;} 351 | .label.notice{background-color:#62cffc;} 352 | .media-grid{margin-left:-20px;margin-bottom:0;zoom:1;}.media-grid:before,.media-grid:after{display:table;content:"";zoom:1;} 353 | .media-grid:after{clear:both;} 354 | .media-grid li{display:inline;} 355 | .media-grid a{float:left;padding:4px;margin:0 0 18px 20px;border:1px solid #ddd;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;-webkit-box-shadow:0 1px 1px rgba(0, 0, 0, 0.075);-moz-box-shadow:0 1px 1px rgba(0, 0, 0, 0.075);box-shadow:0 1px 1px rgba(0, 0, 0, 0.075);}.media-grid a img{display:block;} 356 | .media-grid a:hover{border-color:#0069d6;-webkit-box-shadow:0 1px 4px rgba(0, 105, 214, 0.25);-moz-box-shadow:0 1px 4px rgba(0, 105, 214, 0.25);box-shadow:0 1px 4px rgba(0, 105, 214, 0.25);} 357 | 358 | .post { padding-bottom: 10px; margin-bottom: 10px; border-bottom: solid 1px #e8e8e8; } 359 | .stat { width:70%; float:left; text-align: center; } 360 | .stat .score { font: bold 25px/33px arial; } 361 | .stat .click { } 362 | .rate { width:30%; float:left;} 363 | .rate .vote_up, .rate .vote_down {text-indent: -9999em; font-size: 1px; display: block; margin: 0 auto; width: 24px; height: 24px;} 364 | .rate .vote_up { background: url('../arrow_up.png') no-repeat; margin-bottom: 2px; } 365 | .rate .vote_down { background: url('../arrow_down.png') no-repeat; } 366 | .article .row { padding-left: 20px;} 367 | .src , .src a { color: #999; } 368 | .wide { min-height: 500px; } 369 | .all_cat a, .cat_list a { font-size: 12px; color: #E64B50; text-decoration: none; display: inline-block; border-radius: 10px; -moz-border-radius: 10px; -webkit-border-radius: 10px; background-color: white; border: 1px solid rgba(0, 0, 0, 0.1); padding: 5px 10px; line-height: 14px; margin-bottom: 4px; margin-right: 2px; } 370 | .all_cat a:hover, .cat_list a:hover{ color: #FFF; background-color: #E64B50; } 371 | .topbar div > ul a.post_btn { padding:0; margin-top: 8px; margin-right: 5px; width:21px; height:24px; background-image: url('../book.png'); background-position: top; text-indent: -9999px; } 372 | .topbar div > ul a.post_btn:hover { background-position: bottom; } 373 | footer a {text-decoration: none; color: #404040;} 374 | footer a:hover {text-decoration: none; color: #333;} 375 | .article .heading { min-height: 28px; margin-bottom: 5px; } 376 | .article .heading a { font-size:13px; text-decoration: none; font-weight: bold; } 377 | .article .footing { color: #666; font-size: 12px; } 378 | .article .footing a { color:#268BD2; } 379 | .article .footing a:hover { color:#195F91; text-decoration: none; } 380 | .article .heading .all_cat a {font-size: 11px; margin-bottom: 0; font-weight: lighter; border-radius: 7px; -moz-border-radius: 7px; -webkit-border-radius: 7px; padding: 2px 7px; } 381 | .drop-login .login-form { height: 98px; } 382 | .drop-login .login-row { margin-bottom: 5px; } 383 | .drop-login .remember { width: 90px; float: left; line-height: 22px;} 384 | .drop-login .remember span { padding-left: 5px; color: #ccc; } 385 | .drop-login .login-btn {width: 70px; float: right;} 386 | .page_nav { text-align: right;} 387 | #pn { margin-top: -47px; } 388 | .page_nav a,.cmt_util a { text-decoration: none; } 389 | .cmt_body { margin-bottom: 5px;} 390 | .cmt_util { text-align: right; } 391 | .sub_cmt {margin-left: 30px;} 392 | .span_cmt { width: 78px; } 393 | .span_cmt .rate { margin-right: 15px; } 394 | .span_cmt .stat { width: 40%; text-align: left; } 395 | .span_cmt .stat .score { font: bold 20px/50px arial; } 396 | .sub_cmt { width:94%; } 397 | .cmt_del label { width: 90px; } 398 | .login, .register, .new_pswd,.profile { margin-bottom: 10px; } 399 | .register span { display:inline-block; width: 100px; text-align: right; padding-right: 10px; } 400 | .login .span3 , .register .span3, .new_pswd .span3,.profile .span3 { height: 25px; width: 300px; } 401 | .login label { margin-right: 20px; } 402 | .login .reset_link { display:block; width: 90px; float:left; line-height: 30px; } 403 | .reset_password { float:left; margin-right: 10px; } 404 | .reset_password input {height: 20px; } 405 | .post_input { margin-bottom: 10px; } 406 | .post_input .span14 { height:25px; } 407 | .post_input #post_radio { text-align: left; width: 100px; } 408 | .post_submit { clear:both; margin-top: 20px; text-align: right; } 409 | .facebook_like { margin-top: 100px; } 410 | 411 | .chrome {padding-left: 100px; padding-top: 35px;} --------------------------------------------------------------------------------