Kaynağa Gözat

Merge pull request #523 from 2DU/master

Master
Surplus_Up (2DU) 7 yıl önce
ebeveyn
işleme
ceb485218d

+ 18 - 0
.dockerignore

@@ -0,0 +1,18 @@
+.git
+.gitignore
+Dockerfile
+.dockerignore
+*.md
+
+set_mark/__pycache__
+/__pycache__
+/app_session
+.vscode
+
+*.db
+
+views/liberty
+views/yousoro
+views/super_lite
+views/buma
+views/before_namu

+ 1 - 4
.gitignore

@@ -5,10 +5,7 @@ set_mark/__pycache__
 /app_session
 .vscode
 
-study.db
-back_test2.db
-Test.db
-Test2.db
+*.db
 image
 robots.txt
 

+ 11 - 0
Docker-Install.md

@@ -0,0 +1,11 @@
+## Installation
+```
+docker pull hotococoa/opennamu
+```
+
+## Setting
+```
+export NAMU_PORT=port
+export NAMU_LANG=lang
+```
+Default: Port 3000, en-US

+ 15 - 0
Dockerfile

@@ -0,0 +1,15 @@
+FROM ubuntu:16.04
+
+MAINTAINER Hoto Cocoa <cocoa@hoto.us>
+
+ENV NAMU_PORT=3000
+ENV NAMU_LANG=en-US
+
+ADD . /app
+
+WORKDIR /app
+
+RUN apt update && apt install -y --no-install-recommends python3 python3-dev python3-pip python3-setuptools
+RUN python3 -m pip install pip --upgrade && python3 -m pip install -r requirements.txt
+
+CMD python3 app.py

+ 1 - 1
Readme-Ko.md

@@ -17,5 +17,5 @@
 set.json를 삭제하면 다시 새로 만들 수 있습니다.
 
 ## 기타
- * [테스트 서버](http://namu.ml/)
+ * [테스트 서버](http://namu.ml/) ([서브 도메인](http://kwee.ga))
  * 첫 번째 가입자에게 소유자 권한이 부여됩니다.

+ 5 - 4
Version-Ko.md

@@ -4,7 +4,7 @@
  * 랜덤 구현
 
 ## 0.2 ~ 0.9 (베타)
- * 그 외 엄청나게 많은 기능 구현 (기존 [오픈나무](https://github.com/2DU/Old-openNAMU) 기능에서 로그인 필요한 기능 빼고 구현)
+ * 그 외 엄청나게 많은 기능 구현 (기존 [오픈나무](https://github.com/2DU/Discard-openNAMU-Legacy) 기능에서 로그인 필요한 기능 빼고 구현)
 
 ## 1.0
  * 로그인 구현
@@ -154,10 +154,11 @@
  * [참조](https://github.com/2DU/openNAMU/commits/master)
 
 ----
-## 오픈나무 라이선스
+## 라이선스
+### 오픈나무
  * [BSD 3-Clause License](https://github.com/2DU/openNAMU/blob/master/license.md)
 
-## 외부 파일 라이선스
+### 외부 파일
  * 인용문 아이콘 [Dave Gandy](http://www.flaticon.com/free-icon/quote-left_25672) CC 3.0 BY
  * 구문 강조 [highlightjs](https://highlightjs.org/)
  * 수식 [MathJax](https://www.mathjax.org/)
@@ -173,7 +174,7 @@
 
 ----
 ## 기타
- * 현재 버전 : v3.0.4
+ * 현재 버전 : v3.0.6
 
 ----
 ## 개발 이념

Dosya farkı çok büyük olduğundan ihmal edildi
+ 193 - 203
app.py


+ 61 - 70
func.py

@@ -1,22 +1,3 @@
-# 모듈들 불러옴
-try:
-    import css_html_js_minify
-except:
-    def easy_minify(data):
-        data = re.sub('\n +', '\n', data)
-        
-        return data
-    
-    class css_html_js_minify:
-        def html_minify(data):
-            return easy_minify(data)
-            
-        def css_minify(data):
-            return easy_minify(data)
-            
-        def js_minify(data):
-            return easy_minify(data)
-    
 import flask
 import json
 import sqlite3
@@ -26,13 +7,9 @@ import re
 import html
 import os
 
-# 일부 툴 불러옴
 from set_mark.tool import *
-
-# 나무마크 불러옴
 from mark import *
 
-# 서브 언어팩 불러옴
 json_data = open(os.path.join('language', 'en-US.json'), 'rt', encoding='utf-8').read()
 else_lang = json.loads(json_data)
 
@@ -45,6 +22,11 @@ def load_conn(data):
 
     load_conn2(data)
 
+def easy_minify(data):
+    data = re.sub('\n +', '\n', data)
+    
+    return data
+
 def captcha_get():
     data = ''
 
@@ -60,42 +42,7 @@ def captcha_get():
     return data
 
 def update():
-    # 호환성 설정
-    try:        
-        curs.execute('select title, re from hidhi')
-        for rep in curs.fetchall():
-            curs.execute("update history set hide = 'O' where title = ? and id = ?", [rep[0], rep[1]])
-
-        curs.execute("drop table if exists hidhi")
-
-        print('move table hidhi')
-    except:
-        pass
-
-    try:
-        curs.execute("select title, acl from data where acl != ''")
-        for rep in curs.fetchall():
-            curs.execute("insert into acl (title, dec, dis, why) values (?, ?, '', '')", [rep[0], rep[1]])
-
-        curs.execute("alter table data drop acl")
-
-        print('data table delete column acl')
-    except:
-        pass
-
-    try:
-        curs.execute('select name, sub from filter where sub != "X" and sub != ""')
-        filter_name = curs.fetchall()
-        if filter_name:
-            for filter_delete in filter_name:
-                if filter_delete[1] != '' or filter_delete[1] != 'X':
-                    curs.execute("update filter set sub = '' where name = ?", [filter_delete[0]])
-
-            print('filter data fix')
-    except:
-        pass
-
-    # 3.0.5 사용자 문서, 파일 문서, 분류 문서 영어화
+    # v3.0.5 사용자 문서, 파일 문서, 분류 문서 영어화
     try:
         all_rep = [['사용자:', 'user:'], ['파일:', 'file:'], ['분류:', 'category:']]
         all_rep2 = ['data', 'history', 'acl', 'topic', 'back']
@@ -133,6 +80,13 @@ def update():
     except:
         pass
 
+    # v3.0.6 사용자 설정 분리
+    try:
+        curs.execute("alter table user drop email")
+        curs.execute("alter table user drop skin")
+    except:
+       pass
+
 def captcha_post(re_data, num = 1):
     if num == 1:
         if custom()[2] == 0 and captcha_get() != '':
@@ -207,7 +161,7 @@ def edit_help_button():
     </script>
     '''
 
-    insert_list = [['[[|]]', 'Link'], ['[()]', 'Macro'], ['{{{#!}}}', 'Middle'], ['||<>||', 'table']]
+    insert_list = [['[[|]]', 'Link'], ['[()]', 'Macro'], ['{{{#!}}}', 'Middle'], ['||<>||', 'Table']]
 
     data = ''
     for insert_data in insert_list:
@@ -232,7 +186,7 @@ def skin_check():
     skin = './views/acme/'
     
     try:
-        curs.execute('select skin from user where id = ?', [ip_check()])
+        curs.execute('select data from user_set where name = "skin" and id = ?', [ip_check()])
         skin_exist = curs.fetchall()
         if skin_exist and skin_exist[0][0] != '':
             if os.path.exists(os.path.abspath('./views/' + skin_exist[0][0] + '/index.html')) == 1:
@@ -393,7 +347,7 @@ def ip_pas(raw_ip):
             ip = '<a id="not_thing" href="/w/' + url_pas('user:' + raw_ip) + '">' + raw_ip + '</a>'
          
     if hide == 0:
-        ip += ' <a href="/record/' + url_pas('user:' + raw_ip) + '">(' + load_lang('record') + ')</a>'
+        ip += ' <a href="/record/' + url_pas(raw_ip) + '">(' + load_lang('record') + ')</a>'
 
     return ip
 
@@ -413,7 +367,7 @@ def custom():
         user_icon = 0
 
     if user_icon != 0:
-        curs.execute('select email from user where id = ?', [ip_check()])
+        curs.execute('select data from user_set where name = "email" and id = ?', [ip_check()])
         data = curs.fetchall()
         if data:
             email = data[0][0]
@@ -429,6 +383,37 @@ def custom():
 
     return ['', '', user_icon, user_head, email, user_name]
 
+def load_skin(data = ''):
+    div2 = ''
+
+    if data == '':
+        ip = ip_check()
+
+        curs.execute('select data from user_set where name = "skin" and id = ?', [ip])
+        data = curs.fetchall()
+        for skin_data in os.listdir(os.path.abspath('views')):
+            if not skin_data == 'main_css':
+                if not data:
+                    curs.execute('select data from other where name = "skin"')
+                    sql_data = curs.fetchall()
+                    if sql_data and sql_data[0][0] == skin_data:
+                        div2 = '<option value="' + skin_data + '">' + skin_data + '</option>' + div2
+                    else:
+                        div2 += '<option value="' + skin_data + '">' + skin_data + '</option>'
+                elif data[0][0] == skin_data:
+                    div2 = '<option value="' + skin_data + '">' + skin_data + '</option>' + div2
+                else:
+                    div2 += '<option value="' + skin_data + '">' + skin_data + '</option>'
+    else:
+        for skin_data in os.listdir(os.path.abspath('views')):
+            if not skin_data == 'main_css':
+                if data == skin_data:
+                    div2 = '<option value="' + skin_data + '">' + skin_data + '</option>' + div2
+                else:
+                    div2 += '<option value="' + skin_data + '">' + skin_data + '</option>'
+
+    return div2
+
 def acl_check(name):
     ip = ip_check()
 
@@ -563,11 +548,15 @@ def ban_insert(name, end, why, login, blocker):
         else:
             login = ''
 
-        if end != '':
-            end += ' 00:00:00'
+        if end != '0':
+            time = datetime.datetime.now()
+            plus = datetime.timedelta(seconds = int(end))
+            r_time = (time + plus).strftime("%Y-%m-%d %H:%M:%S")
+        else:
+            r_time = ''
 
-        curs.execute("insert into rb (block, end, today, blocker, why, band) values (?, ?, ?, ?, ?, ?)", [name, end, time, blocker, why, band])
-        curs.execute("insert into ban (block, end, why, band, login) values (?, ?, ?, ?, ?)", [name, end, why, band, login])
+        curs.execute("insert into rb (block, end, today, blocker, why, band) values (?, ?, ?, ?, ?, ?)", [name, r_time, time, blocker, why, band])
+        curs.execute("insert into ban (block, end, why, band, login) values (?, ?, ?, ?, ?)", [name, r_time, why, band, login])
     
     conn.commit()
 
@@ -597,7 +586,7 @@ def leng_check(first, second):
     return all_plus
 
 def redirect(data):
-    return '<meta http-equiv="refresh" content="0; url=' + data + '">'
+    return flask.redirect(data)
 
 def re_error(data):
     if data == '/ban':
@@ -636,7 +625,7 @@ def re_error(data):
                 if end_data[0][1] != '':
                     end += '<li>' + load_lang('why') + ' : ' + end_data[0][1] + '</li>'
 
-        return css_html_js_minify.html_minify(flask.render_template(skin_check(), 
+        return easy_minify(flask.render_template(skin_check(), 
             imp = ['Error', wiki_set(1), custom(), other2([0, 0])],
             data = '<h2>Error</h2><ul>' + end + '</ul>',
             menu = 0
@@ -653,6 +642,8 @@ def re_error(data):
                 data = load_lang('authority_error')
             elif num == 4:
                 data = load_lang('no_admin_block_error')
+            elif num == 5:
+                data = load_lang('skin_error')
             elif num == 6:
                 data = load_lang('same_id_exist_error')
             elif num == 7:
@@ -684,7 +675,7 @@ def re_error(data):
             else:
                 data = '???'
 
-            return css_html_js_minify.html_minify(flask.render_template(skin_check(), 
+            return easy_minify(flask.render_template(skin_check(), 
                 imp = ['Error', wiki_set(1), custom(), other2([0, 0])],
                 data = '<h2>Error</h2><ul><li>' + data + '</li></ul>',
                 menu = 0

+ 18 - 17
language/en-US.json

@@ -4,13 +4,13 @@
     "history" : "History",
     "delete" : "Delete",
     "logo" : "Logo",
-    "frontpage" : "Main Page",
-    "max_file_size" : "Max File Size",
-    "back_up_interval" : "Back Up Interval",
+    "frontpage" : "Front page",
+    "max_file_size" : "Max file size",
+    "back_up_interval" : "Backup interval",
     "default_acl" : "Default ACL",
     "port" : "Port",
-    "secret_key" : "Secret Key",
-    "update_branch" : "Update Branch",
+    "secret_key" : "Secret key",
+    "update_branch" : "Update branch",
     "main" : "Main",
     "set_text" : "Set up notices",
     "main_head" : "Global HEAD",
@@ -41,13 +41,13 @@
     "open" : "Open",
     "search" : "Search",
     "need" : "Needful",
-    "upload" : "File Upload",
+    "upload" : "File upload",
     "record" : "Record",
     "name" : "Name",
     "license" : "License",
     "interwiki" : "Inter Wiki",
     "update" : "Update",
-    "setting" : "Setting",
+    "setting" : "Set",
     "create" : "Create",
     "editor" : "Editor",
     "hour" : "Hour",
@@ -56,8 +56,8 @@
     "stop" : "Stop",
     "restart" : "Restart",
     "agreement" : "Agreement",
-    "backlink" : "Back Link",
-    "why" : "Why",
+    "backlink" : "Back link",
+    "why" : "Reason",
     "random" : "Random",
     "authority" : "Authority",
     "file" : "File",
@@ -68,26 +68,24 @@
     "user" : "User",
     "alarm" : "Alarm",
     "preview" : "Preview",
-    "watchlist" : "Watching List",
-    "my_info" : "About Me",
+    "watchlist" : "Watching list",
+    "my_info" : "User set",
     "state" : "State",
     "recent" : "Recent",
-    "discussion" : "Debates",
+    "discussion" : "Debate",
     "login" : "Login",
     "logout" : "Logout",
     "register" : "Register",
     "no_alarm" : "There is no alram available",
     "able" : "Able",
-    "year" : "Year",
-    "month" : "Month",
-    "day" : "Day",
+    "second": "Second",
     "normal" : "Normal",
     "subscriber" : "Registor",
     "admin" : "Admin",
     "next" : "Next",
     "previous" : "Previous",
     "owner" : "Owner",
-    "admin_group" : "MOD Group",
+    "admin_group" : "MOD group",
     "limitless" : "Limitless",
     "period" : "Period",
     "now" : "Now",
@@ -100,8 +98,10 @@
     "pass" : "Pass",
     "category" : "Category",
     "filter" : "Filter",
+    "send" : "Send",
+    "reload" : "Reload",
 
-    "user_css_warring" : "User's CSS will deleted if you close the browser or when you are editting as guest",
+    "user_head_warring" : "User's HEAD will deleted if you close the browser or when you are editting as guest",
     "http_warring" : "Warning : If you are not on HTTPS connection, your information can be leaked. We won't response to that.",
     "no_login_warring" : "Non-login status. IP is logged when working with non-login.",
     
@@ -109,6 +109,7 @@
     "no_login_error" : "Non-login status.",
     "no_exist_user_error" : "Account does not exist.",
     "no_admin_block_error" : "Administrators can not block, check.",
+    "skin_error" : "This skin is not support setting.",
     "same_id_exist_error" : "There are users with the same ID.",
     "long_id_error" : "ID must be shorter than 20 characters.",
     "id_char_error" : "Only hangul, alphabet and space are allowed for ID.",

+ 7 - 6
language/ko-KR.json

@@ -21,7 +21,7 @@
     "other": "기타",
     "tool": " 도구",
     "plus": "추가",
-    "open": "열",
+    "open": "열",
     "search": "검색",
     "user": "사용자",
     "alarm": "알림",
@@ -35,15 +35,13 @@
     "register": "회원가입",
     "no_alarm": " 알림이 없습니다.",
     "able": "가능",
-    "year": "년",
-    "month": "월",
-    "day": "일",
+    "second": "초",
     "normal": "일반",
     "subscriber": "가입자",
     "admin": "관리자",
     "owner": "소유자",
     "admin_group": "관리 그룹",
-    "user_css_warring": "비 로그인의 경우에는 사용자 CSS가 로그인하거나 브라우저 닫으면 날아갑니다.",
+    "user_head_warring": "비 로그인의 경우에는 사용자 HEAD가 로그인하거나 브라우저 닫으면 날아갑니다.",
     "http_warring": "주의 : 만 약 HTTPS 연결이 아닌 경우 데이터가 유출될 가능성이 있습니다. 이에 대해 책임지지 않습니다.",
     "new": "새",
     "need": "필요한",
@@ -60,7 +58,7 @@
     "time": "시각",
     "close": "닫기",
     "stop": "정지",
-    "restart": "재시작",
+    "restart": "재",
     "agreement": "합의",
     "backlink": "역링크",
     "why": "사유",
@@ -87,10 +85,13 @@
     "under": "하위",
     "pass": "통과",
     "category": "분류",
+    "send" : "전송",
+    "reload" : "새로고침",
     "authority_error": "권한이  부족합니다.",
     "no_login_error": "비 로그인 상태 입니다.",
     "no_exist_user_error": "계정이 없습니다.",
     "no_admin_block_error": "관리자는 차단, 검사 할 수 없습니다.",
+    "skin_error" : "이 스킨은 스킨 설정을 지원하지 않습니다.",
     "same_id_exist_error": "동일한 아이디의 사용자가 있습니다.",
     "long_id_error": "아이디는 20글자보다 짧아야 합니다.",
     "id_char_error": "아이디에는 한글과 알파벳과 공백만 허용 됩니다.",

+ 1 - 2
readme.md

@@ -17,8 +17,7 @@ NamuMark based wiki engine returns to Python. (3.5 and above)
 You can create a new set.json by deleting it.
 
 ## Other
- * [Test Server (Ko)](http://namu.ml/)
- * [Test Server (En)](http://en.namu.ml/)
+ * [Test Server](http://namu.ml) ([Sub Domain](http://kwee.ga))
  * The first registor is granted owner privileges.
 
 ## 한국어

+ 0 - 1
requirements.txt

@@ -1,4 +1,3 @@
-css-html-js-minify == 2.2.2
 tornado >= 4.5.2
 bcrypt >= 3.1.3
 requests >= 2.13.0

+ 192 - 167
set_mark/namu.py

@@ -162,157 +162,9 @@ def table_start(data):
             break
             
     return data
-    
-def link_fix(main_link):
-    if re.search('^:', main_link):
-        main_link = re.sub('^:', '', main_link)
-
-    main_link = re.sub('^사용자:', 'user:', main_link)
-    main_link = re.sub('^파일:', 'file:', main_link)
-    main_link = re.sub('^분류:', 'category:', main_link)
-
-    other_link = re.search('(#.+)$', main_link)
-    if other_link:
-        other_link = other_link.groups()[0]
-
-        main_link = re.sub('(#.+)$', '', main_link)
-    else:
-        other_link = ''
-        
-    return [main_link, other_link]
-
-def namu(conn, data, title, main_num):
-    # DB 지정
-    curs = conn.cursor()
-
-    # 초기 설정
-    data = '\n' + data + '\n'
-    backlink = []
-    plus_data = '''
-                <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.12.0/styles/default.min.css">
-                <script src="//cdnjs.cloudflare.com/ajax/libs/highlight.js/9.12.0/highlight.min.js"></script>
-                <script>
-                    hljs.initHighlightingOnLoad(); 
-                    function folding(num) { 
-                        var fol = document.getElementById('folding_' + num); 
-                        if(fol.style.display == 'inline-block' || fol.style.display == 'block') { 
-                            fol.style.display = 'none';
-                        } else {
-                            if(num % 2 == 0) { 
-                                fol.style.display = 'block'; 
-                            } else { 
-                                fol.style.display = 'inline-block'; 
-                            } 
-                        } 
-                    }
-                </script>
-                '''
-    end_data= []
-    
-    # XSS 이스케이프
-    data = html.escape(data)
-
-    # 포함 문법 처리
-    while 1:
-        include = re.search('\[include\(((?:(?!\)\]).)+)\)\]', data)
-        if include:
-            include = include.groups()[0]
-    
-            include_data = re.search('^((?:(?!,).)+)', include)
-            if include_data:
-                include_data = include_data.groups()[0]
-            else:
-                include_data = 'Test'
-
-            include_link = include_data
-
-            backlink += [[title, include_link, 'include']]
-
-            include = re.sub('^((?:(?!,).)+)', '', include)
-            
-            # 틀 NoWiki
-            num = 0
-            while 1:
-                include_one_nowiki = re.search('(?:\\\\){2}(.)', include)
-                if include_one_nowiki:
-                    include_one_nowiki = include_one_nowiki.groups()
-
-                    num += 1
-
-                    end_data += [['include_one_nowiki_' + str(num), include_one_nowiki[0], 'normal']]
-
-                    include = re.sub('(?:\\\\){2}(.)', '<span id="include_one_nowiki_' + str(num) + '"></span>', include, 1)
-                else:
-                    break
 
-            curs.execute("select data from data where title = ?", [include_data])
-            include_data = curs.fetchall()
-            if include_data:
-                include_parser = include_data[0][0]
-
-                while 1:
-                    include_plus = re.search(', ?((?:(?!=).)+)=((?:(?!,).)+)', include)
-                    if include_plus:
-                        include_plus = include_plus.groups()
-                        include_parser = re.sub('@' + include_plus[0] + '@', include_plus[1], include_parser)
-
-                        include = re.sub(', ?((?:(?!=).)+)=((?:(?!,).)+)', '', include, 1)
-                    else:
-                        break
-
-                include_parser = re.sub('\[\[(?:category|분류):(((?!\]\]|#include).)+)\]\]', '', include_parser)
-                include_parser = html.escape(include_parser)
-
-                data = re.sub('\[include\(((?:(?!\)\]).)+)\)\]', '<include>\n<a id="include_link" href="/w/' + tool.url_pas(include_link) + '">[' + include_link + ']</a>\n' + include_parser + '\n</include>', data, 1)
-            else:
-                data = re.sub('\[include\(((?:(?!\)\]).)+)\)\]', '<a id="not_thing" href="/w/' + tool.url_pas(include_link) + '">' + include_link + '</a>', data, 1)
-        else:
-            break
-
-    # 개행 정리
-    data = re.sub('\r\n', '\n', data)
-
-    # 기타 처리
-    data = re.sub('&amp;', '&', data)
-
-    # HTML 허용
-    curs.execute('select html from html_filter')
-    html_db = curs.fetchall()
-
-    src_list = ["www.youtube.com", "serviceapi.nmv.naver.com", "tv.kakao.com", "www.google.com", "serviceapi.rmcnmv.naver.com"]
-    html_list = ['div', 'span', 'embed', 'iframe', 'ruby', 'rp', 'rt']
-    
-    html_data = re.findall('&lt;(\/)?((?:(?!&gt;| ).)+)( (?:(?:(?!&gt;).)+)?)?&gt;', data)
-    for in_data in html_data:
-        if in_data[0] == '':
-            if in_data[1] in html_list or (html_db and in_data[1] in html_db[0]):
-                if re.search('&lt;\/' + in_data[1] + '&gt;', data):
-                    src = re.search('src=([^ ]*)', in_data[2])
-                    if src:
-                        v_src = re.search('http(?:s)?:\/\/([^/\'" ]*)', src.groups()[0])
-                        if v_src:
-                            if not v_src.groups()[0] in src_list:
-                                and_data = re.sub('&#x27;', '\'', re.sub('&quot;', '"', re.sub('src=([^ ]*)', '', in_data[2])))
-                            else:
-                                and_data = re.sub('&#x27;', '\'', re.sub('&quot;', '"', in_data[2]))
-                        else:
-                            and_data = re.sub('&#x27;', '\'', re.sub('&quot;', '"', re.sub('src=([^ ]*)', '', in_data[2])))
-                    else:
-                        and_data = re.sub('&#x27;', '\'', re.sub('&quot;', '"', in_data[2]))
-                        
-
-                    data = data.replace('&lt;' + in_data[1] + in_data[2] + '&gt;', '<' + in_data[1] + and_data + '>', 1)
-                    data = re.sub('&lt;\/' + in_data[1] + '&gt;', '</' + in_data[1] + '>', data, 1)
-
-    position = re.compile('position', re.I)
-    data = position.sub('', data)
-
-    # 표 정리
-    data = re.sub('\n( +)\|\|', '\n||', data)
-    data = re.sub('\|\|( +)\n', '||\n', data)
-
-    # 주석 처리
-    data = re.sub('\n##(((?!\n).)+)', '', data)
+def middle_parser(data):
+    global end_data
 
     # 중괄호 문법 처리
     middle_stack = 0
@@ -329,7 +181,7 @@ def namu(conn, data, title, main_num):
                     
                     data = re.sub('(?:{{{((?:(?! |{{{|}}}).)*)(?P<in> ?)|(}}}))', '&#123;&#123;&#123;' + middle_data[0] + '\g<in>', data, 1)
                 else:
-                    if re.search('^(#|@|\+|\-)', middle_data[0]):
+                    if re.search('^(#|@|\+|\-)', middle_data[0]) and not re.search('^(#|@|\+|\-){2}', middle_data[0]):
                         middle_search = re.search('^(#(?:[0-9a-f-A-F]{3}){1,2})', middle_data[0])
                         if middle_search:                            
                             middle_list += ['span']
@@ -406,7 +258,7 @@ def namu(conn, data, title, main_num):
                                                             else:
                                                                 folding_data = ['Test']
                                                             
-                                                            data = re.sub('{{{#!folding ?((?:(?!\n).)*)\n?', '<div>' + str(folding_data[0]) + ' <div style="display: inline-block;"><a href="javascript:void(0);" onclick="folding(' + str(fol_num) + ');">[0to1]</a></div_end><div id="folding_' + str(fol_num) + '" style="display: none;"><div id="wiki_div" style="">', data, 1)
+                                                            data = re.sub('{{{#!folding ?((?:(?!\n).)*)\n?', '<div>' + str(folding_data[0]) + ' <div style="display: inline-block;"><a href="javascript:void(0);" onclick="folding(' + str(fol_num) + ');">[Work]</a></div_end><div id="folding_' + str(fol_num) + '" style="display: none;"><div id="wiki_div" style="">', data, 1)
                                                             
                                                             fol_num += 1
                                                         else:
@@ -474,6 +326,169 @@ def namu(conn, data, title, main_num):
             data = re.sub('<code class="((?:(?!").)+)">((?:(?:(?:(?!<\/code>|<span id="syntax_)).)+\n*)+)<\/code>', '<code class="' + syntax_data[0] + '"><span id="syntax_' + str(num) + '"></span></code>', data, 1)
         else:
             break
+
+    return data
+    
+def link_fix(main_link):
+    if re.search('^:', main_link):
+        main_link = re.sub('^:', '', main_link)
+
+    main_link = re.sub('^사용자:', 'user:', main_link)
+    main_link = re.sub('^파일:', 'file:', main_link)
+    main_link = re.sub('^분류:', 'category:', main_link)
+
+    other_link = re.search('(#.+)$', main_link)
+    if other_link:
+        other_link = other_link.groups()[0]
+
+        main_link = re.sub('(#.+)$', '', main_link)
+    else:
+        other_link = ''
+        
+    return [main_link, other_link]
+
+def namu(conn, data, title, main_num):
+    # DB 지정
+    curs = conn.cursor()
+
+    # 초기 설정
+    data = '\n' + data + '\n'
+    backlink = []
+    plus_data = '''
+                <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.12.0/styles/default.min.css">
+                <script src="//cdnjs.cloudflare.com/ajax/libs/highlight.js/9.12.0/highlight.min.js"></script>
+                <script>
+                    hljs.initHighlightingOnLoad(); 
+                    function folding(num) { 
+                        var fol = document.getElementById('folding_' + num); 
+                        if(fol.style.display == 'inline-block' || fol.style.display == 'block') { 
+                            fol.style.display = 'none';
+                        } else {
+                            if(num % 2 == 0) { 
+                                fol.style.display = 'block'; 
+                            } else { 
+                                fol.style.display = 'inline-block'; 
+                            } 
+                        } 
+                    }
+                </script>
+                '''
+    global end_data
+    end_data = []
+    
+    # XSS 이스케이프
+    data = html.escape(data)
+
+    # 개행 정리 1
+    data = re.sub('\r\n', '\n', data)
+
+    # 중괄호 파싱 1
+    data = middle_parser(data)
+
+    # 포함 문법 처리
+    while 1:
+        include = re.search('\[include\(((?:(?!\)\]).)+)\)\]', data)
+        if include:
+            include = include.groups()[0]
+    
+            include_data = re.search('^((?:(?!,).)+)', include)
+            if include_data:
+                include_data = include_data.groups()[0]
+            else:
+                include_data = 'Test'
+
+            include_link = include_data
+
+            backlink += [[title, include_link, 'include']]
+
+            include = re.sub('^((?:(?!,).)+)', '', include)
+            
+            # 틀 NoWiki
+            num = 0
+            while 1:
+                include_one_nowiki = re.search('(?:\\\\){2}(.)', include)
+                if include_one_nowiki:
+                    include_one_nowiki = include_one_nowiki.groups()
+
+                    num += 1
+
+                    end_data += [['include_one_nowiki_' + str(num), include_one_nowiki[0], 'normal']]
+
+                    include = re.sub('(?:\\\\){2}(.)', '<span id="include_one_nowiki_' + str(num) + '"></span>', include, 1)
+                else:
+                    break
+
+            curs.execute("select data from data where title = ?", [include_data])
+            include_data = curs.fetchall()
+            if include_data:
+                include_parser = include_data[0][0]
+
+                while 1:
+                    include_plus = re.search(', ?((?:(?!=).)+)=((?:(?!,).)+)', include)
+                    if include_plus:
+                        include_plus = include_plus.groups()
+                        include_parser = re.sub('@' + include_plus[0] + '@', include_plus[1], include_parser)
+
+                        include = re.sub(', ?((?:(?!=).)+)=((?:(?!,).)+)', '', include, 1)
+                    else:
+                        break
+
+                include_parser = re.sub('\[\[(?:category|분류):(((?!\]\]|#include).)+)\]\]', '', include_parser)
+                include_parser = html.escape(include_parser)
+
+                data = re.sub('\[include\(((?:(?!\)\]).)+)\)\]', '<include>\n<a id="include_link" href="/w/' + tool.url_pas(include_link) + '">[' + include_link + ']</a>\n' + include_parser + '\n</include>', data, 1)
+            else:
+                data = re.sub('\[include\(((?:(?!\)\]).)+)\)\]', '<a id="not_thing" href="/w/' + tool.url_pas(include_link) + '">' + include_link + '</a>', data, 1)
+        else:
+            break
+
+    # 개행 정리 2
+    data = re.sub('\r\n', '\n', data)
+
+    # 중괄호 파싱 2
+    data = middle_parser(data)
+
+    # 기타 처리
+    data = re.sub('&amp;', '&', data)
+
+    # HTML 허용
+    curs.execute('select html from html_filter')
+    html_db = curs.fetchall()
+
+    src_list = ["www.youtube.com", "serviceapi.nmv.naver.com", "tv.kakao.com", "www.google.com", "serviceapi.rmcnmv.naver.com"]
+    html_list = ['div', 'span', 'embed', 'iframe', 'ruby', 'rp', 'rt']
+    
+    html_data = re.findall('&lt;(\/)?((?:(?!&gt;| ).)+)( (?:(?:(?!&gt;).)+)?)?&gt;', data)
+    for in_data in html_data:
+        if in_data[0] == '':
+            if in_data[1] in html_list or (html_db and in_data[1] in html_db[0]):
+                if re.search('&lt;\/' + in_data[1] + '&gt;', data):
+                    src = re.search('src=([^ ]*)', in_data[2])
+                    if src:
+                        v_src = re.search('http(?:s)?:\/\/([^/\'" ]*)', src.groups()[0])
+                        if v_src:
+                            if not v_src.groups()[0] in src_list:
+                                and_data = re.sub('&#x27;', '\'', re.sub('&quot;', '"', re.sub('src=([^ ]*)', '', in_data[2])))
+                            else:
+                                and_data = re.sub('&#x27;', '\'', re.sub('&quot;', '"', in_data[2]))
+                        else:
+                            and_data = re.sub('&#x27;', '\'', re.sub('&quot;', '"', re.sub('src=([^ ]*)', '', in_data[2])))
+                    else:
+                        and_data = re.sub('&#x27;', '\'', re.sub('&quot;', '"', in_data[2]))
+                        
+
+                    data = data.replace('&lt;' + in_data[1] + in_data[2] + '&gt;', '<' + in_data[1] + and_data + '>', 1)
+                    data = re.sub('&lt;\/' + in_data[1] + '&gt;', '</' + in_data[1] + '>', data, 1)
+
+    position = re.compile('position', re.I)
+    data = position.sub('', data)
+
+    # 표 정리
+    data = re.sub('\n( +)\|\|', '\n||', data)
+    data = re.sub('\|\|( +)\n', '||\n', data)
+
+    # 주석 처리
+    data = re.sub('\n##(((?!\n).)+)', '', data)
            
     # 이중 표 처리
     while 1:
@@ -532,6 +547,16 @@ def namu(conn, data, title, main_num):
         else:
             break
 
+    # 수평줄
+    while 1:
+        hr = re.search('\n-{4,9}\n', data)
+        if hr:
+            data = re.sub('\n-{4,9}\n', '\n<hr>\n', data, 1)
+        else:
+            break
+
+    data += '\n'
+
     # 추가 이스케이프
     data = data.replace('\\', '&#92;')
 
@@ -555,7 +580,7 @@ def namu(conn, data, title, main_num):
         
         backlink += [[title, main_link, 'redirect']]
         
-        data = re.sub('\n#(?:redirect|넘겨주기) (?P<in>(?:(?!\n).)+)\n', '<meta http-equiv="refresh" content="0; url=/w/' + tool.url_pas(main_link) + '?froms=' + tool.url_pas(title) + other_link + '">', data, 1)
+        data = re.sub('\n#(?:redirect|넘겨주기) (?P<in>(?:(?!\n).)+)\n', '<script>location.href="/w/' + tool.url_pas(main_link) + '?froms=' + tool.url_pas(title) + other_link + '";</script>', data, 1)
 
     # [목차(없음)] 처리
     if not re.search('\[(?:목차|tableofcontents)\((?:없음|no)\)\]\n', data):
@@ -604,23 +629,19 @@ def namu(conn, data, title, main_num):
             all_stack = re.sub('^0\.', '', all_stack)
             
             data = re.sub('\n(={1,6}) ?((?:(?!\n).)+) ?\n', '\n<h' + toc_number + ' id="s-' + re.sub('\.$', '', all_stack) + '"><a href="#toc">' + all_stack + '</a> ' + re.sub('=*$', '', toc[1]) + ' <span style="font-size: 12px"><a href="/edit/' + tool.url_pas(title) + '?section=' + str(edit_number) + '">(Edit)</a></span></h' + toc_number + '>\n', data, 1)
+
+            toc_main_data = toc[1]
+            toc_main_data = re.sub('=*$', '', toc_main_data)
+            toc_main_data = re.sub('\[\*((?:(?! |\]).)*)(?: ((?:(?!(\[\*(?:(?:(?!\]).)+)\]|\])).)+))?\]', '', toc_main_data)
+            toc_main_data = re.sub('<span id="math_[0-9]"><\/span>', '(수식)', toc_main_data)
             
-            toc_data += '<span style="margin-left: ' + str((toc_full - toc_top_stack) * 10) + 'px;"><a href="#s-' + re.sub('\.$', '', all_stack) + '">' + all_stack + '</a> ' + re.sub('\[\*((?:(?! |\]).)*)(?: ((?:(?!\]).)+))?\]', '', re.sub('=*$', '', toc[1])) + '</span>\n'
+            toc_data += '<span style="margin-left: ' + str((toc_full - toc_top_stack) * 10) + 'px;"><a href="#s-' + re.sub('\.$', '', all_stack) + '">' + all_stack + '</a> ' + toc_main_data + '</span>\n'
         else:
             break
 
     toc_data += '</div>'
     
     data = re.sub('\[(?:목차|tableofcontents)\]', toc_data, data)
-    
-    while 1:
-        hr = re.search('\n-{4,9}\n', data)
-        if hr:
-            data = re.sub('\n-{4,9}\n', '\n<hr>\n', data, 1)
-        else:
-            break
-
-    data += '\n'
 
     # 일부 매크로 처리
     data = tool.savemark(data)
@@ -730,6 +751,8 @@ def namu(conn, data, title, main_num):
         else:
             break
 
+    data = re.sub('(?P<in>\n +\* ?(?:(?:(?!\|\|).)+))\|\|', '\g<in>\n ||', data)
+
     # 리스트 구현
     while 1:
         li = re.search('(\n(?:(?: *)\* ?(?:(?:(?!\n).)+)\n)+)', data)
@@ -754,6 +777,8 @@ def namu(conn, data, title, main_num):
         else:
             break
 
+    data = re.sub('<\/ul>\n \|\|', '</ul>||', data)
+
     # 들여쓰기 구현
     while 1:
         indent = re.search('\n( +)', data)
@@ -929,7 +954,7 @@ def namu(conn, data, title, main_num):
     footnote_re = {}
     footdata_all = '\n<hr><ul id="footnote_data">'
     while 1:
-        footnote = re.search('(?:\[\*((?:(?! |\]).)*)(?: ((?:(?!\]).)+))?\]|(\[(?:각주|footnote)\]))', data)
+        footnote = re.search('(?:\[\*((?:(?! |\]).)*)(?: ((?:(?!(\[\*(?:(?:(?!\]).)+)\]|\])).)+))?\]|(\[(?:각주|footnote)\]))', data)
         if footnote:
             footnote_data = footnote.groups()
             if footnote_data[2]:
@@ -959,9 +984,9 @@ def namu(conn, data, title, main_num):
 
                         footnote_all += [[float(footshort), footshort, 0]]
 
-                        data = re.sub('(?:\[\*((?:(?! |\]).)*)(?: ((?:(?!\]).)+))?\]|(\[(?:각주|footnote)\]))', '<sup><a href="#fn-' + footshort + '" id="rfn-' + footshort + '">(' + footshort + ')</a></sup>', data, 1)
+                        data = re.sub('(?:\[\*((?:(?! |\]).)*)(?: ((?:(?!(\[\*(?:(?:(?!\]).)+)\]|\])).)+))?\]|(\[(?:각주|footnote)\]))', '<sup><a href="#fn-' + footshort + '" id="rfn-' + footshort + '">(' + footshort + ')</a></sup>', data, 1)
                     else:
-                        data = re.sub('(?:\[\*((?:(?! |\]).)*)(?: ((?:(?!\]).)+))?\]|(\[(?:각주|footnote)\]))', '<sup><a href="#">(' + footnote_name + ')</a></sup>', data, 1)
+                        data = re.sub('(?:\[\*((?:(?! |\]).)*)(?: ((?:(?!(\[\*(?:(?:(?!\]).)+)\]|\])).)+))?\]|(\[(?:각주|footnote)\]))', '<sup><a href="#">(' + footnote_name + ')</a></sup>', data, 1)
                 else:
                     footnote_number += 1
 
@@ -977,7 +1002,7 @@ def namu(conn, data, title, main_num):
 
                     footnote_all += [[footnote_number, footnote_name, footnote]]
                     
-                    data = re.sub('(?:\[\*((?:(?! |\]).)*)(?: ((?:(?!\]).)+))?\]|(\[(?:각주|footnote)\]))', '<sup><a href="#fn-' + str(footnote_number) + '" id="rfn-' + str(footnote_number) + '">(' + footnote_name + ')</a></sup>', data, 1)
+                    data = re.sub('(?:\[\*((?:(?! |\]).)*)(?: ((?:(?!(\[\*(?:(?:(?!\]).)+)\]|\])).)+))?\]|(\[(?:각주|footnote)\]))', '<sup><a href="#fn-' + str(footnote_number) + '" id="rfn-' + str(footnote_number) + '">(' + footnote_name + ')</a></sup>', data, 1)
         else:
             break
 

+ 141 - 3
views/acme/css/font-awesome/css/font-awesome.css

@@ -1,13 +1,13 @@
 /*!
- *  Font Awesome 4.6.3 by @davegandy - http://fontawesome.io - @fontawesome
+ *  Font Awesome 4.7.0 by @davegandy - http://fontawesome.io - @fontawesome
  *  License - http://fontawesome.io/license (Font: SIL OFL 1.1, CSS: MIT License)
  */
 /* FONT PATH
  * -------------------------- */
 @font-face {
   font-family: 'FontAwesome';
-  src: url('../fonts/fontawesome-webfont.eot?v=4.6.3');
-  src: url('../fonts/fontawesome-webfont.eot?#iefix&v=4.6.3') format('embedded-opentype'), url('../fonts/fontawesome-webfont.woff2?v=4.6.3') format('woff2'), url('../fonts/fontawesome-webfont.woff?v=4.6.3') format('woff'), url('../fonts/fontawesome-webfont.ttf?v=4.6.3') format('truetype'), url('../fonts/fontawesome-webfont.svg?v=4.6.3#fontawesomeregular') format('svg');
+  src: url('../fonts/fontawesome-webfont.eot?v=4.7.0');
+  src: url('../fonts/fontawesome-webfont.eot?#iefix&v=4.7.0') format('embedded-opentype'), url('../fonts/fontawesome-webfont.woff2?v=4.7.0') format('woff2'), url('../fonts/fontawesome-webfont.woff?v=4.7.0') format('woff'), url('../fonts/fontawesome-webfont.ttf?v=4.7.0') format('truetype'), url('../fonts/fontawesome-webfont.svg?v=4.7.0#fontawesomeregular') format('svg');
   font-weight: normal;
   font-style: normal;
 }
@@ -1832,6 +1832,7 @@
   content: "\f23e";
 }
 .fa-battery-4:before,
+.fa-battery:before,
 .fa-battery-full:before {
   content: "\f240";
 }
@@ -2178,6 +2179,143 @@
 .fa-font-awesome:before {
   content: "\f2b4";
 }
+.fa-handshake-o:before {
+  content: "\f2b5";
+}
+.fa-envelope-open:before {
+  content: "\f2b6";
+}
+.fa-envelope-open-o:before {
+  content: "\f2b7";
+}
+.fa-linode:before {
+  content: "\f2b8";
+}
+.fa-address-book:before {
+  content: "\f2b9";
+}
+.fa-address-book-o:before {
+  content: "\f2ba";
+}
+.fa-vcard:before,
+.fa-address-card:before {
+  content: "\f2bb";
+}
+.fa-vcard-o:before,
+.fa-address-card-o:before {
+  content: "\f2bc";
+}
+.fa-user-circle:before {
+  content: "\f2bd";
+}
+.fa-user-circle-o:before {
+  content: "\f2be";
+}
+.fa-user-o:before {
+  content: "\f2c0";
+}
+.fa-id-badge:before {
+  content: "\f2c1";
+}
+.fa-drivers-license:before,
+.fa-id-card:before {
+  content: "\f2c2";
+}
+.fa-drivers-license-o:before,
+.fa-id-card-o:before {
+  content: "\f2c3";
+}
+.fa-quora:before {
+  content: "\f2c4";
+}
+.fa-free-code-camp:before {
+  content: "\f2c5";
+}
+.fa-telegram:before {
+  content: "\f2c6";
+}
+.fa-thermometer-4:before,
+.fa-thermometer:before,
+.fa-thermometer-full:before {
+  content: "\f2c7";
+}
+.fa-thermometer-3:before,
+.fa-thermometer-three-quarters:before {
+  content: "\f2c8";
+}
+.fa-thermometer-2:before,
+.fa-thermometer-half:before {
+  content: "\f2c9";
+}
+.fa-thermometer-1:before,
+.fa-thermometer-quarter:before {
+  content: "\f2ca";
+}
+.fa-thermometer-0:before,
+.fa-thermometer-empty:before {
+  content: "\f2cb";
+}
+.fa-shower:before {
+  content: "\f2cc";
+}
+.fa-bathtub:before,
+.fa-s15:before,
+.fa-bath:before {
+  content: "\f2cd";
+}
+.fa-podcast:before {
+  content: "\f2ce";
+}
+.fa-window-maximize:before {
+  content: "\f2d0";
+}
+.fa-window-minimize:before {
+  content: "\f2d1";
+}
+.fa-window-restore:before {
+  content: "\f2d2";
+}
+.fa-times-rectangle:before,
+.fa-window-close:before {
+  content: "\f2d3";
+}
+.fa-times-rectangle-o:before,
+.fa-window-close-o:before {
+  content: "\f2d4";
+}
+.fa-bandcamp:before {
+  content: "\f2d5";
+}
+.fa-grav:before {
+  content: "\f2d6";
+}
+.fa-etsy:before {
+  content: "\f2d7";
+}
+.fa-imdb:before {
+  content: "\f2d8";
+}
+.fa-ravelry:before {
+  content: "\f2d9";
+}
+.fa-eercast:before {
+  content: "\f2da";
+}
+.fa-microchip:before {
+  content: "\f2db";
+}
+.fa-snowflake-o:before {
+  content: "\f2dc";
+}
+.fa-superpowers:before {
+  content: "\f2dd";
+}
+.fa-wpexplorer:before {
+  content: "\f2de";
+}
+.fa-meetup:before {
+  content: "\f2e0";
+}
 .sr-only {
   position: absolute;
   width: 1px;

Dosya farkı çok büyük olduğundan ihmal edildi
+ 1 - 1
views/acme/css/font-awesome/css/font-awesome.min.css


BIN
views/acme/css/font-awesome/fonts/FontAwesome.otf


BIN
views/acme/css/font-awesome/fonts/fontawesome-webfont.eot


Dosya farkı çok büyük olduğundan ihmal edildi
+ 6 - 193
views/acme/css/font-awesome/fonts/fontawesome-webfont.svg


BIN
views/acme/css/font-awesome/fonts/fontawesome-webfont.ttf


BIN
views/acme/css/font-awesome/fonts/fontawesome-webfont.woff


BIN
views/acme/css/font-awesome/fonts/fontawesome-webfont.woff2


+ 1 - 1
views/acme/css/font-awesome/less/font-awesome.less

@@ -1,5 +1,5 @@
 /*!
- *  Font Awesome 4.6.3 by @davegandy - http://fontawesome.io - @fontawesome
+ *  Font Awesome 4.7.0 by @davegandy - http://fontawesome.io - @fontawesome
  *  License - http://fontawesome.io/license (Font: SIL OFL 1.1, CSS: MIT License)
  */
 

+ 56 - 0
views/acme/css/font-awesome/less/icons.less

@@ -605,6 +605,7 @@
 .@{fa-css-prefix}-opencart:before { content: @fa-var-opencart; }
 .@{fa-css-prefix}-expeditedssl:before { content: @fa-var-expeditedssl; }
 .@{fa-css-prefix}-battery-4:before,
+.@{fa-css-prefix}-battery:before,
 .@{fa-css-prefix}-battery-full:before { content: @fa-var-battery-full; }
 .@{fa-css-prefix}-battery-3:before,
 .@{fa-css-prefix}-battery-three-quarters:before { content: @fa-var-battery-three-quarters; }
@@ -731,3 +732,58 @@
 .@{fa-css-prefix}-google-plus-official:before { content: @fa-var-google-plus-official; }
 .@{fa-css-prefix}-fa:before,
 .@{fa-css-prefix}-font-awesome:before { content: @fa-var-font-awesome; }
+.@{fa-css-prefix}-handshake-o:before { content: @fa-var-handshake-o; }
+.@{fa-css-prefix}-envelope-open:before { content: @fa-var-envelope-open; }
+.@{fa-css-prefix}-envelope-open-o:before { content: @fa-var-envelope-open-o; }
+.@{fa-css-prefix}-linode:before { content: @fa-var-linode; }
+.@{fa-css-prefix}-address-book:before { content: @fa-var-address-book; }
+.@{fa-css-prefix}-address-book-o:before { content: @fa-var-address-book-o; }
+.@{fa-css-prefix}-vcard:before,
+.@{fa-css-prefix}-address-card:before { content: @fa-var-address-card; }
+.@{fa-css-prefix}-vcard-o:before,
+.@{fa-css-prefix}-address-card-o:before { content: @fa-var-address-card-o; }
+.@{fa-css-prefix}-user-circle:before { content: @fa-var-user-circle; }
+.@{fa-css-prefix}-user-circle-o:before { content: @fa-var-user-circle-o; }
+.@{fa-css-prefix}-user-o:before { content: @fa-var-user-o; }
+.@{fa-css-prefix}-id-badge:before { content: @fa-var-id-badge; }
+.@{fa-css-prefix}-drivers-license:before,
+.@{fa-css-prefix}-id-card:before { content: @fa-var-id-card; }
+.@{fa-css-prefix}-drivers-license-o:before,
+.@{fa-css-prefix}-id-card-o:before { content: @fa-var-id-card-o; }
+.@{fa-css-prefix}-quora:before { content: @fa-var-quora; }
+.@{fa-css-prefix}-free-code-camp:before { content: @fa-var-free-code-camp; }
+.@{fa-css-prefix}-telegram:before { content: @fa-var-telegram; }
+.@{fa-css-prefix}-thermometer-4:before,
+.@{fa-css-prefix}-thermometer:before,
+.@{fa-css-prefix}-thermometer-full:before { content: @fa-var-thermometer-full; }
+.@{fa-css-prefix}-thermometer-3:before,
+.@{fa-css-prefix}-thermometer-three-quarters:before { content: @fa-var-thermometer-three-quarters; }
+.@{fa-css-prefix}-thermometer-2:before,
+.@{fa-css-prefix}-thermometer-half:before { content: @fa-var-thermometer-half; }
+.@{fa-css-prefix}-thermometer-1:before,
+.@{fa-css-prefix}-thermometer-quarter:before { content: @fa-var-thermometer-quarter; }
+.@{fa-css-prefix}-thermometer-0:before,
+.@{fa-css-prefix}-thermometer-empty:before { content: @fa-var-thermometer-empty; }
+.@{fa-css-prefix}-shower:before { content: @fa-var-shower; }
+.@{fa-css-prefix}-bathtub:before,
+.@{fa-css-prefix}-s15:before,
+.@{fa-css-prefix}-bath:before { content: @fa-var-bath; }
+.@{fa-css-prefix}-podcast:before { content: @fa-var-podcast; }
+.@{fa-css-prefix}-window-maximize:before { content: @fa-var-window-maximize; }
+.@{fa-css-prefix}-window-minimize:before { content: @fa-var-window-minimize; }
+.@{fa-css-prefix}-window-restore:before { content: @fa-var-window-restore; }
+.@{fa-css-prefix}-times-rectangle:before,
+.@{fa-css-prefix}-window-close:before { content: @fa-var-window-close; }
+.@{fa-css-prefix}-times-rectangle-o:before,
+.@{fa-css-prefix}-window-close-o:before { content: @fa-var-window-close-o; }
+.@{fa-css-prefix}-bandcamp:before { content: @fa-var-bandcamp; }
+.@{fa-css-prefix}-grav:before { content: @fa-var-grav; }
+.@{fa-css-prefix}-etsy:before { content: @fa-var-etsy; }
+.@{fa-css-prefix}-imdb:before { content: @fa-var-imdb; }
+.@{fa-css-prefix}-ravelry:before { content: @fa-var-ravelry; }
+.@{fa-css-prefix}-eercast:before { content: @fa-var-eercast; }
+.@{fa-css-prefix}-microchip:before { content: @fa-var-microchip; }
+.@{fa-css-prefix}-snowflake-o:before { content: @fa-var-snowflake-o; }
+.@{fa-css-prefix}-superpowers:before { content: @fa-var-superpowers; }
+.@{fa-css-prefix}-wpexplorer:before { content: @fa-var-wpexplorer; }
+.@{fa-css-prefix}-meetup:before { content: @fa-var-meetup; }

+ 58 - 2
views/acme/css/font-awesome/less/variables.less

@@ -4,14 +4,18 @@
 @fa-font-path:        "../fonts";
 @fa-font-size-base:   14px;
 @fa-line-height-base: 1;
-//@fa-font-path:        "//netdna.bootstrapcdn.com/font-awesome/4.6.3/fonts"; // for referencing Bootstrap CDN font files directly
+//@fa-font-path:        "//netdna.bootstrapcdn.com/font-awesome/4.7.0/fonts"; // for referencing Bootstrap CDN font files directly
 @fa-css-prefix:       fa;
-@fa-version:          "4.6.3";
+@fa-version:          "4.7.0";
 @fa-border-color:     #eee;
 @fa-inverse:          #fff;
 @fa-li-width:         (30em / 14);
 
 @fa-var-500px: "\f26e";
+@fa-var-address-book: "\f2b9";
+@fa-var-address-book-o: "\f2ba";
+@fa-var-address-card: "\f2bb";
+@fa-var-address-card-o: "\f2bc";
 @fa-var-adjust: "\f042";
 @fa-var-adn: "\f170";
 @fa-var-align-center: "\f037";
@@ -60,11 +64,15 @@
 @fa-var-backward: "\f04a";
 @fa-var-balance-scale: "\f24e";
 @fa-var-ban: "\f05e";
+@fa-var-bandcamp: "\f2d5";
 @fa-var-bank: "\f19c";
 @fa-var-bar-chart: "\f080";
 @fa-var-bar-chart-o: "\f080";
 @fa-var-barcode: "\f02a";
 @fa-var-bars: "\f0c9";
+@fa-var-bath: "\f2cd";
+@fa-var-bathtub: "\f2cd";
+@fa-var-battery: "\f240";
 @fa-var-battery-0: "\f244";
 @fa-var-battery-1: "\f243";
 @fa-var-battery-2: "\f242";
@@ -214,19 +222,25 @@
 @fa-var-dot-circle-o: "\f192";
 @fa-var-download: "\f019";
 @fa-var-dribbble: "\f17d";
+@fa-var-drivers-license: "\f2c2";
+@fa-var-drivers-license-o: "\f2c3";
 @fa-var-dropbox: "\f16b";
 @fa-var-drupal: "\f1a9";
 @fa-var-edge: "\f282";
 @fa-var-edit: "\f044";
+@fa-var-eercast: "\f2da";
 @fa-var-eject: "\f052";
 @fa-var-ellipsis-h: "\f141";
 @fa-var-ellipsis-v: "\f142";
 @fa-var-empire: "\f1d1";
 @fa-var-envelope: "\f0e0";
 @fa-var-envelope-o: "\f003";
+@fa-var-envelope-open: "\f2b6";
+@fa-var-envelope-open-o: "\f2b7";
 @fa-var-envelope-square: "\f199";
 @fa-var-envira: "\f299";
 @fa-var-eraser: "\f12d";
+@fa-var-etsy: "\f2d7";
 @fa-var-eur: "\f153";
 @fa-var-euro: "\f153";
 @fa-var-exchange: "\f0ec";
@@ -294,6 +308,7 @@
 @fa-var-forumbee: "\f211";
 @fa-var-forward: "\f04e";
 @fa-var-foursquare: "\f180";
+@fa-var-free-code-camp: "\f2c5";
 @fa-var-frown-o: "\f119";
 @fa-var-futbol-o: "\f1e3";
 @fa-var-gamepad: "\f11b";
@@ -326,6 +341,7 @@
 @fa-var-google-wallet: "\f1ee";
 @fa-var-graduation-cap: "\f19d";
 @fa-var-gratipay: "\f184";
+@fa-var-grav: "\f2d6";
 @fa-var-group: "\f0c0";
 @fa-var-h-square: "\f0fd";
 @fa-var-hacker-news: "\f1d4";
@@ -342,6 +358,7 @@
 @fa-var-hand-scissors-o: "\f257";
 @fa-var-hand-spock-o: "\f259";
 @fa-var-hand-stop-o: "\f256";
+@fa-var-handshake-o: "\f2b5";
 @fa-var-hard-of-hearing: "\f2a4";
 @fa-var-hashtag: "\f292";
 @fa-var-hdd-o: "\f0a0";
@@ -365,8 +382,12 @@
 @fa-var-houzz: "\f27c";
 @fa-var-html5: "\f13b";
 @fa-var-i-cursor: "\f246";
+@fa-var-id-badge: "\f2c1";
+@fa-var-id-card: "\f2c2";
+@fa-var-id-card-o: "\f2c3";
 @fa-var-ils: "\f20b";
 @fa-var-image: "\f03e";
+@fa-var-imdb: "\f2d8";
 @fa-var-inbox: "\f01c";
 @fa-var-indent: "\f03c";
 @fa-var-industry: "\f275";
@@ -404,6 +425,7 @@
 @fa-var-link: "\f0c1";
 @fa-var-linkedin: "\f0e1";
 @fa-var-linkedin-square: "\f08c";
+@fa-var-linode: "\f2b8";
 @fa-var-linux: "\f17c";
 @fa-var-list: "\f03a";
 @fa-var-list-alt: "\f022";
@@ -436,8 +458,10 @@
 @fa-var-meanpath: "\f20c";
 @fa-var-medium: "\f23a";
 @fa-var-medkit: "\f0fa";
+@fa-var-meetup: "\f2e0";
 @fa-var-meh-o: "\f11a";
 @fa-var-mercury: "\f223";
+@fa-var-microchip: "\f2db";
 @fa-var-microphone: "\f130";
 @fa-var-microphone-slash: "\f131";
 @fa-var-minus: "\f068";
@@ -502,6 +526,7 @@
 @fa-var-plus-circle: "\f055";
 @fa-var-plus-square: "\f0fe";
 @fa-var-plus-square-o: "\f196";
+@fa-var-podcast: "\f2ce";
 @fa-var-power-off: "\f011";
 @fa-var-print: "\f02f";
 @fa-var-product-hunt: "\f288";
@@ -511,10 +536,12 @@
 @fa-var-question: "\f128";
 @fa-var-question-circle: "\f059";
 @fa-var-question-circle-o: "\f29c";
+@fa-var-quora: "\f2c4";
 @fa-var-quote-left: "\f10d";
 @fa-var-quote-right: "\f10e";
 @fa-var-ra: "\f1d0";
 @fa-var-random: "\f074";
+@fa-var-ravelry: "\f2d9";
 @fa-var-rebel: "\f1d0";
 @fa-var-recycle: "\f1b8";
 @fa-var-reddit: "\f1a1";
@@ -541,6 +568,7 @@
 @fa-var-rub: "\f158";
 @fa-var-ruble: "\f158";
 @fa-var-rupee: "\f156";
+@fa-var-s15: "\f2cd";
 @fa-var-safari: "\f267";
 @fa-var-save: "\f0c7";
 @fa-var-scissors: "\f0c4";
@@ -565,6 +593,7 @@
 @fa-var-shopping-bag: "\f290";
 @fa-var-shopping-basket: "\f291";
 @fa-var-shopping-cart: "\f07a";
+@fa-var-shower: "\f2cc";
 @fa-var-sign-in: "\f090";
 @fa-var-sign-language: "\f2a7";
 @fa-var-sign-out: "\f08b";
@@ -581,6 +610,7 @@
 @fa-var-snapchat: "\f2ab";
 @fa-var-snapchat-ghost: "\f2ac";
 @fa-var-snapchat-square: "\f2ad";
+@fa-var-snowflake-o: "\f2dc";
 @fa-var-soccer-ball-o: "\f1e3";
 @fa-var-sort: "\f0dc";
 @fa-var-sort-alpha-asc: "\f15d";
@@ -626,6 +656,7 @@
 @fa-var-subway: "\f239";
 @fa-var-suitcase: "\f0f2";
 @fa-var-sun-o: "\f185";
+@fa-var-superpowers: "\f2dd";
 @fa-var-superscript: "\f12b";
 @fa-var-support: "\f1cd";
 @fa-var-table: "\f0ce";
@@ -635,6 +666,7 @@
 @fa-var-tags: "\f02c";
 @fa-var-tasks: "\f0ae";
 @fa-var-taxi: "\f1ba";
+@fa-var-telegram: "\f2c6";
 @fa-var-television: "\f26c";
 @fa-var-tencent-weibo: "\f1d5";
 @fa-var-terminal: "\f120";
@@ -644,6 +676,17 @@
 @fa-var-th-large: "\f009";
 @fa-var-th-list: "\f00b";
 @fa-var-themeisle: "\f2b2";
+@fa-var-thermometer: "\f2c7";
+@fa-var-thermometer-0: "\f2cb";
+@fa-var-thermometer-1: "\f2ca";
+@fa-var-thermometer-2: "\f2c9";
+@fa-var-thermometer-3: "\f2c8";
+@fa-var-thermometer-4: "\f2c7";
+@fa-var-thermometer-empty: "\f2cb";
+@fa-var-thermometer-full: "\f2c7";
+@fa-var-thermometer-half: "\f2c9";
+@fa-var-thermometer-quarter: "\f2ca";
+@fa-var-thermometer-three-quarters: "\f2c8";
 @fa-var-thumb-tack: "\f08d";
 @fa-var-thumbs-down: "\f165";
 @fa-var-thumbs-o-down: "\f088";
@@ -653,6 +696,8 @@
 @fa-var-times: "\f00d";
 @fa-var-times-circle: "\f057";
 @fa-var-times-circle-o: "\f05c";
+@fa-var-times-rectangle: "\f2d3";
+@fa-var-times-rectangle-o: "\f2d4";
 @fa-var-tint: "\f043";
 @fa-var-toggle-down: "\f150";
 @fa-var-toggle-left: "\f191";
@@ -693,11 +738,16 @@
 @fa-var-usb: "\f287";
 @fa-var-usd: "\f155";
 @fa-var-user: "\f007";
+@fa-var-user-circle: "\f2bd";
+@fa-var-user-circle-o: "\f2be";
 @fa-var-user-md: "\f0f0";
+@fa-var-user-o: "\f2c0";
 @fa-var-user-plus: "\f234";
 @fa-var-user-secret: "\f21b";
 @fa-var-user-times: "\f235";
 @fa-var-users: "\f0c0";
+@fa-var-vcard: "\f2bb";
+@fa-var-vcard-o: "\f2bc";
 @fa-var-venus: "\f221";
 @fa-var-venus-double: "\f226";
 @fa-var-venus-mars: "\f228";
@@ -722,10 +772,16 @@
 @fa-var-wheelchair-alt: "\f29b";
 @fa-var-wifi: "\f1eb";
 @fa-var-wikipedia-w: "\f266";
+@fa-var-window-close: "\f2d3";
+@fa-var-window-close-o: "\f2d4";
+@fa-var-window-maximize: "\f2d0";
+@fa-var-window-minimize: "\f2d1";
+@fa-var-window-restore: "\f2d2";
 @fa-var-windows: "\f17a";
 @fa-var-won: "\f159";
 @fa-var-wordpress: "\f19a";
 @fa-var-wpbeginner: "\f297";
+@fa-var-wpexplorer: "\f2de";
 @fa-var-wpforms: "\f298";
 @fa-var-wrench: "\f0ad";
 @fa-var-xing: "\f168";

+ 56 - 0
views/acme/css/font-awesome/scss/_icons.scss

@@ -605,6 +605,7 @@
 .#{$fa-css-prefix}-opencart:before { content: $fa-var-opencart; }
 .#{$fa-css-prefix}-expeditedssl:before { content: $fa-var-expeditedssl; }
 .#{$fa-css-prefix}-battery-4:before,
+.#{$fa-css-prefix}-battery:before,
 .#{$fa-css-prefix}-battery-full:before { content: $fa-var-battery-full; }
 .#{$fa-css-prefix}-battery-3:before,
 .#{$fa-css-prefix}-battery-three-quarters:before { content: $fa-var-battery-three-quarters; }
@@ -731,3 +732,58 @@
 .#{$fa-css-prefix}-google-plus-official:before { content: $fa-var-google-plus-official; }
 .#{$fa-css-prefix}-fa:before,
 .#{$fa-css-prefix}-font-awesome:before { content: $fa-var-font-awesome; }
+.#{$fa-css-prefix}-handshake-o:before { content: $fa-var-handshake-o; }
+.#{$fa-css-prefix}-envelope-open:before { content: $fa-var-envelope-open; }
+.#{$fa-css-prefix}-envelope-open-o:before { content: $fa-var-envelope-open-o; }
+.#{$fa-css-prefix}-linode:before { content: $fa-var-linode; }
+.#{$fa-css-prefix}-address-book:before { content: $fa-var-address-book; }
+.#{$fa-css-prefix}-address-book-o:before { content: $fa-var-address-book-o; }
+.#{$fa-css-prefix}-vcard:before,
+.#{$fa-css-prefix}-address-card:before { content: $fa-var-address-card; }
+.#{$fa-css-prefix}-vcard-o:before,
+.#{$fa-css-prefix}-address-card-o:before { content: $fa-var-address-card-o; }
+.#{$fa-css-prefix}-user-circle:before { content: $fa-var-user-circle; }
+.#{$fa-css-prefix}-user-circle-o:before { content: $fa-var-user-circle-o; }
+.#{$fa-css-prefix}-user-o:before { content: $fa-var-user-o; }
+.#{$fa-css-prefix}-id-badge:before { content: $fa-var-id-badge; }
+.#{$fa-css-prefix}-drivers-license:before,
+.#{$fa-css-prefix}-id-card:before { content: $fa-var-id-card; }
+.#{$fa-css-prefix}-drivers-license-o:before,
+.#{$fa-css-prefix}-id-card-o:before { content: $fa-var-id-card-o; }
+.#{$fa-css-prefix}-quora:before { content: $fa-var-quora; }
+.#{$fa-css-prefix}-free-code-camp:before { content: $fa-var-free-code-camp; }
+.#{$fa-css-prefix}-telegram:before { content: $fa-var-telegram; }
+.#{$fa-css-prefix}-thermometer-4:before,
+.#{$fa-css-prefix}-thermometer:before,
+.#{$fa-css-prefix}-thermometer-full:before { content: $fa-var-thermometer-full; }
+.#{$fa-css-prefix}-thermometer-3:before,
+.#{$fa-css-prefix}-thermometer-three-quarters:before { content: $fa-var-thermometer-three-quarters; }
+.#{$fa-css-prefix}-thermometer-2:before,
+.#{$fa-css-prefix}-thermometer-half:before { content: $fa-var-thermometer-half; }
+.#{$fa-css-prefix}-thermometer-1:before,
+.#{$fa-css-prefix}-thermometer-quarter:before { content: $fa-var-thermometer-quarter; }
+.#{$fa-css-prefix}-thermometer-0:before,
+.#{$fa-css-prefix}-thermometer-empty:before { content: $fa-var-thermometer-empty; }
+.#{$fa-css-prefix}-shower:before { content: $fa-var-shower; }
+.#{$fa-css-prefix}-bathtub:before,
+.#{$fa-css-prefix}-s15:before,
+.#{$fa-css-prefix}-bath:before { content: $fa-var-bath; }
+.#{$fa-css-prefix}-podcast:before { content: $fa-var-podcast; }
+.#{$fa-css-prefix}-window-maximize:before { content: $fa-var-window-maximize; }
+.#{$fa-css-prefix}-window-minimize:before { content: $fa-var-window-minimize; }
+.#{$fa-css-prefix}-window-restore:before { content: $fa-var-window-restore; }
+.#{$fa-css-prefix}-times-rectangle:before,
+.#{$fa-css-prefix}-window-close:before { content: $fa-var-window-close; }
+.#{$fa-css-prefix}-times-rectangle-o:before,
+.#{$fa-css-prefix}-window-close-o:before { content: $fa-var-window-close-o; }
+.#{$fa-css-prefix}-bandcamp:before { content: $fa-var-bandcamp; }
+.#{$fa-css-prefix}-grav:before { content: $fa-var-grav; }
+.#{$fa-css-prefix}-etsy:before { content: $fa-var-etsy; }
+.#{$fa-css-prefix}-imdb:before { content: $fa-var-imdb; }
+.#{$fa-css-prefix}-ravelry:before { content: $fa-var-ravelry; }
+.#{$fa-css-prefix}-eercast:before { content: $fa-var-eercast; }
+.#{$fa-css-prefix}-microchip:before { content: $fa-var-microchip; }
+.#{$fa-css-prefix}-snowflake-o:before { content: $fa-var-snowflake-o; }
+.#{$fa-css-prefix}-superpowers:before { content: $fa-var-superpowers; }
+.#{$fa-css-prefix}-wpexplorer:before { content: $fa-var-wpexplorer; }
+.#{$fa-css-prefix}-meetup:before { content: $fa-var-meetup; }

+ 58 - 2
views/acme/css/font-awesome/scss/_variables.scss

@@ -4,14 +4,18 @@
 $fa-font-path:        "../fonts" !default;
 $fa-font-size-base:   14px !default;
 $fa-line-height-base: 1 !default;
-//$fa-font-path:        "//netdna.bootstrapcdn.com/font-awesome/4.6.3/fonts" !default; // for referencing Bootstrap CDN font files directly
+//$fa-font-path:        "//netdna.bootstrapcdn.com/font-awesome/4.7.0/fonts" !default; // for referencing Bootstrap CDN font files directly
 $fa-css-prefix:       fa !default;
-$fa-version:          "4.6.3" !default;
+$fa-version:          "4.7.0" !default;
 $fa-border-color:     #eee !default;
 $fa-inverse:          #fff !default;
 $fa-li-width:         (30em / 14) !default;
 
 $fa-var-500px: "\f26e";
+$fa-var-address-book: "\f2b9";
+$fa-var-address-book-o: "\f2ba";
+$fa-var-address-card: "\f2bb";
+$fa-var-address-card-o: "\f2bc";
 $fa-var-adjust: "\f042";
 $fa-var-adn: "\f170";
 $fa-var-align-center: "\f037";
@@ -60,11 +64,15 @@ $fa-var-automobile: "\f1b9";
 $fa-var-backward: "\f04a";
 $fa-var-balance-scale: "\f24e";
 $fa-var-ban: "\f05e";
+$fa-var-bandcamp: "\f2d5";
 $fa-var-bank: "\f19c";
 $fa-var-bar-chart: "\f080";
 $fa-var-bar-chart-o: "\f080";
 $fa-var-barcode: "\f02a";
 $fa-var-bars: "\f0c9";
+$fa-var-bath: "\f2cd";
+$fa-var-bathtub: "\f2cd";
+$fa-var-battery: "\f240";
 $fa-var-battery-0: "\f244";
 $fa-var-battery-1: "\f243";
 $fa-var-battery-2: "\f242";
@@ -214,19 +222,25 @@ $fa-var-dollar: "\f155";
 $fa-var-dot-circle-o: "\f192";
 $fa-var-download: "\f019";
 $fa-var-dribbble: "\f17d";
+$fa-var-drivers-license: "\f2c2";
+$fa-var-drivers-license-o: "\f2c3";
 $fa-var-dropbox: "\f16b";
 $fa-var-drupal: "\f1a9";
 $fa-var-edge: "\f282";
 $fa-var-edit: "\f044";
+$fa-var-eercast: "\f2da";
 $fa-var-eject: "\f052";
 $fa-var-ellipsis-h: "\f141";
 $fa-var-ellipsis-v: "\f142";
 $fa-var-empire: "\f1d1";
 $fa-var-envelope: "\f0e0";
 $fa-var-envelope-o: "\f003";
+$fa-var-envelope-open: "\f2b6";
+$fa-var-envelope-open-o: "\f2b7";
 $fa-var-envelope-square: "\f199";
 $fa-var-envira: "\f299";
 $fa-var-eraser: "\f12d";
+$fa-var-etsy: "\f2d7";
 $fa-var-eur: "\f153";
 $fa-var-euro: "\f153";
 $fa-var-exchange: "\f0ec";
@@ -294,6 +308,7 @@ $fa-var-fort-awesome: "\f286";
 $fa-var-forumbee: "\f211";
 $fa-var-forward: "\f04e";
 $fa-var-foursquare: "\f180";
+$fa-var-free-code-camp: "\f2c5";
 $fa-var-frown-o: "\f119";
 $fa-var-futbol-o: "\f1e3";
 $fa-var-gamepad: "\f11b";
@@ -326,6 +341,7 @@ $fa-var-google-plus-square: "\f0d4";
 $fa-var-google-wallet: "\f1ee";
 $fa-var-graduation-cap: "\f19d";
 $fa-var-gratipay: "\f184";
+$fa-var-grav: "\f2d6";
 $fa-var-group: "\f0c0";
 $fa-var-h-square: "\f0fd";
 $fa-var-hacker-news: "\f1d4";
@@ -342,6 +358,7 @@ $fa-var-hand-rock-o: "\f255";
 $fa-var-hand-scissors-o: "\f257";
 $fa-var-hand-spock-o: "\f259";
 $fa-var-hand-stop-o: "\f256";
+$fa-var-handshake-o: "\f2b5";
 $fa-var-hard-of-hearing: "\f2a4";
 $fa-var-hashtag: "\f292";
 $fa-var-hdd-o: "\f0a0";
@@ -365,8 +382,12 @@ $fa-var-hourglass-start: "\f251";
 $fa-var-houzz: "\f27c";
 $fa-var-html5: "\f13b";
 $fa-var-i-cursor: "\f246";
+$fa-var-id-badge: "\f2c1";
+$fa-var-id-card: "\f2c2";
+$fa-var-id-card-o: "\f2c3";
 $fa-var-ils: "\f20b";
 $fa-var-image: "\f03e";
+$fa-var-imdb: "\f2d8";
 $fa-var-inbox: "\f01c";
 $fa-var-indent: "\f03c";
 $fa-var-industry: "\f275";
@@ -404,6 +425,7 @@ $fa-var-line-chart: "\f201";
 $fa-var-link: "\f0c1";
 $fa-var-linkedin: "\f0e1";
 $fa-var-linkedin-square: "\f08c";
+$fa-var-linode: "\f2b8";
 $fa-var-linux: "\f17c";
 $fa-var-list: "\f03a";
 $fa-var-list-alt: "\f022";
@@ -436,8 +458,10 @@ $fa-var-maxcdn: "\f136";
 $fa-var-meanpath: "\f20c";
 $fa-var-medium: "\f23a";
 $fa-var-medkit: "\f0fa";
+$fa-var-meetup: "\f2e0";
 $fa-var-meh-o: "\f11a";
 $fa-var-mercury: "\f223";
+$fa-var-microchip: "\f2db";
 $fa-var-microphone: "\f130";
 $fa-var-microphone-slash: "\f131";
 $fa-var-minus: "\f068";
@@ -502,6 +526,7 @@ $fa-var-plus: "\f067";
 $fa-var-plus-circle: "\f055";
 $fa-var-plus-square: "\f0fe";
 $fa-var-plus-square-o: "\f196";
+$fa-var-podcast: "\f2ce";
 $fa-var-power-off: "\f011";
 $fa-var-print: "\f02f";
 $fa-var-product-hunt: "\f288";
@@ -511,10 +536,12 @@ $fa-var-qrcode: "\f029";
 $fa-var-question: "\f128";
 $fa-var-question-circle: "\f059";
 $fa-var-question-circle-o: "\f29c";
+$fa-var-quora: "\f2c4";
 $fa-var-quote-left: "\f10d";
 $fa-var-quote-right: "\f10e";
 $fa-var-ra: "\f1d0";
 $fa-var-random: "\f074";
+$fa-var-ravelry: "\f2d9";
 $fa-var-rebel: "\f1d0";
 $fa-var-recycle: "\f1b8";
 $fa-var-reddit: "\f1a1";
@@ -541,6 +568,7 @@ $fa-var-rss-square: "\f143";
 $fa-var-rub: "\f158";
 $fa-var-ruble: "\f158";
 $fa-var-rupee: "\f156";
+$fa-var-s15: "\f2cd";
 $fa-var-safari: "\f267";
 $fa-var-save: "\f0c7";
 $fa-var-scissors: "\f0c4";
@@ -565,6 +593,7 @@ $fa-var-shirtsinbulk: "\f214";
 $fa-var-shopping-bag: "\f290";
 $fa-var-shopping-basket: "\f291";
 $fa-var-shopping-cart: "\f07a";
+$fa-var-shower: "\f2cc";
 $fa-var-sign-in: "\f090";
 $fa-var-sign-language: "\f2a7";
 $fa-var-sign-out: "\f08b";
@@ -581,6 +610,7 @@ $fa-var-smile-o: "\f118";
 $fa-var-snapchat: "\f2ab";
 $fa-var-snapchat-ghost: "\f2ac";
 $fa-var-snapchat-square: "\f2ad";
+$fa-var-snowflake-o: "\f2dc";
 $fa-var-soccer-ball-o: "\f1e3";
 $fa-var-sort: "\f0dc";
 $fa-var-sort-alpha-asc: "\f15d";
@@ -626,6 +656,7 @@ $fa-var-subscript: "\f12c";
 $fa-var-subway: "\f239";
 $fa-var-suitcase: "\f0f2";
 $fa-var-sun-o: "\f185";
+$fa-var-superpowers: "\f2dd";
 $fa-var-superscript: "\f12b";
 $fa-var-support: "\f1cd";
 $fa-var-table: "\f0ce";
@@ -635,6 +666,7 @@ $fa-var-tag: "\f02b";
 $fa-var-tags: "\f02c";
 $fa-var-tasks: "\f0ae";
 $fa-var-taxi: "\f1ba";
+$fa-var-telegram: "\f2c6";
 $fa-var-television: "\f26c";
 $fa-var-tencent-weibo: "\f1d5";
 $fa-var-terminal: "\f120";
@@ -644,6 +676,17 @@ $fa-var-th: "\f00a";
 $fa-var-th-large: "\f009";
 $fa-var-th-list: "\f00b";
 $fa-var-themeisle: "\f2b2";
+$fa-var-thermometer: "\f2c7";
+$fa-var-thermometer-0: "\f2cb";
+$fa-var-thermometer-1: "\f2ca";
+$fa-var-thermometer-2: "\f2c9";
+$fa-var-thermometer-3: "\f2c8";
+$fa-var-thermometer-4: "\f2c7";
+$fa-var-thermometer-empty: "\f2cb";
+$fa-var-thermometer-full: "\f2c7";
+$fa-var-thermometer-half: "\f2c9";
+$fa-var-thermometer-quarter: "\f2ca";
+$fa-var-thermometer-three-quarters: "\f2c8";
 $fa-var-thumb-tack: "\f08d";
 $fa-var-thumbs-down: "\f165";
 $fa-var-thumbs-o-down: "\f088";
@@ -653,6 +696,8 @@ $fa-var-ticket: "\f145";
 $fa-var-times: "\f00d";
 $fa-var-times-circle: "\f057";
 $fa-var-times-circle-o: "\f05c";
+$fa-var-times-rectangle: "\f2d3";
+$fa-var-times-rectangle-o: "\f2d4";
 $fa-var-tint: "\f043";
 $fa-var-toggle-down: "\f150";
 $fa-var-toggle-left: "\f191";
@@ -693,11 +738,16 @@ $fa-var-upload: "\f093";
 $fa-var-usb: "\f287";
 $fa-var-usd: "\f155";
 $fa-var-user: "\f007";
+$fa-var-user-circle: "\f2bd";
+$fa-var-user-circle-o: "\f2be";
 $fa-var-user-md: "\f0f0";
+$fa-var-user-o: "\f2c0";
 $fa-var-user-plus: "\f234";
 $fa-var-user-secret: "\f21b";
 $fa-var-user-times: "\f235";
 $fa-var-users: "\f0c0";
+$fa-var-vcard: "\f2bb";
+$fa-var-vcard-o: "\f2bc";
 $fa-var-venus: "\f221";
 $fa-var-venus-double: "\f226";
 $fa-var-venus-mars: "\f228";
@@ -722,10 +772,16 @@ $fa-var-wheelchair: "\f193";
 $fa-var-wheelchair-alt: "\f29b";
 $fa-var-wifi: "\f1eb";
 $fa-var-wikipedia-w: "\f266";
+$fa-var-window-close: "\f2d3";
+$fa-var-window-close-o: "\f2d4";
+$fa-var-window-maximize: "\f2d0";
+$fa-var-window-minimize: "\f2d1";
+$fa-var-window-restore: "\f2d2";
 $fa-var-windows: "\f17a";
 $fa-var-won: "\f159";
 $fa-var-wordpress: "\f19a";
 $fa-var-wpbeginner: "\f297";
+$fa-var-wpexplorer: "\f2de";
 $fa-var-wpforms: "\f298";
 $fa-var-wrench: "\f0ad";
 $fa-var-xing: "\f168";

+ 1 - 1
views/acme/css/font-awesome/scss/font-awesome.scss

@@ -1,5 +1,5 @@
 /*!
- *  Font Awesome 4.6.3 by @davegandy - http://fontawesome.io - @fontawesome
+ *  Font Awesome 4.7.0 by @davegandy - http://fontawesome.io - @fontawesome
  *  License - http://fontawesome.io/license (Font: SIL OFL 1.1, CSS: MIT License)
  */
 

+ 37 - 0
views/acme/css/set_css/dark.css

@@ -0,0 +1,37 @@
+body {
+    background: black;
+    color: white;
+}
+
+.head-section {
+    border-bottom: 1px solid black;
+}
+
+.head-section .navbar-default {
+    background-color: black;
+    color: white;
+}
+
+.head-section .nav li a, .head-section .nav li.active ul.dropdown-menu li a {
+    color: white;
+}
+
+.head-section .nav li .dropdown-menu {
+    background: black;
+}
+
+.navbar-default .navbar-brand {
+    color: white;
+}
+
+table {
+    color: #373a3c;
+}
+
+pre {
+    background: black;
+}
+
+textarea, input {
+    background: black;
+}

+ 1 - 62
views/acme/css/style-responsive.css

@@ -151,10 +151,6 @@ input {
     }
 }
 
-a:link {
-    color: #0093FF;
-}
-
 button {
     border: 1px solid deepskyblue;
     border-radius: 0.25rem;
@@ -197,13 +193,6 @@ input#searchInput:focus {
     word-break: break-all;
 }
 
-#in {
-    margin-left: 20px;
-}
-
-#out {
-    margin-left: 5px;
-}
 
 input {
     max-width: 100%;
@@ -368,20 +357,6 @@ td {
     margin-bottom: 20px;
 }
 
-#toc-name {
-    font-size: 18px;
-}
-
-s, strike, del {
-    color: gray;
-}
-
-s:hover, strike:hover, del:hover {
-    color: #666;
-    background-color: #eee;
-    text-decoration: none;
-}
-
 .scroll-buttons a:link, .scroll-buttons a:visited {
     color: white;
 }
@@ -449,26 +424,6 @@ div.scroll-buttons a {
     text-align: center;
 }
 
-#toron {
-    width: 100%;
-}
-
-#toron_color_green {
-    background-color: #B0D3AD;
-}
-
-#toron_color_red {
-    background-color: #f3c2c2;
-}
-
-#toron_color_blue {
-    background: #c1ebff;
-}
-
-#toron_color {
-    background-color: #d5d5d5;
-}
-
 @media (max-width: 768px) {
     table {
         min-width: 100%;
@@ -479,22 +434,6 @@ textarea {
     width: 100%;
 }
 
-#not_thing {
-    color: #bf4c4c;
-}
-
-#out_link {
-    color: #008000;
-}
-
-#out_link::before {
-    padding: 0px;
-    background: transparent;
-    color: green;
-    content: "\f14c";
-    font-family: FontAwesome;
-}
-
 h1, h2, h3, h4, h5, h6 {
     margin-bottom: 10px;
     margin-top: 10px;
@@ -552,4 +491,4 @@ ul#redirect {
 html, body { 
     max-width: 100%; 
     overflow-x: hidden; 
-} 
+}

+ 14 - 5
views/acme/index.html

@@ -3,12 +3,15 @@
     <head>
         <meta charset="utf-8">
         <title>{{imp[0]}} - {{imp[1][0]}}</title>
+        <link rel="stylesheet" href="/views/main_css/main.css">
         <link rel="stylesheet" href="/views/acme/css/bootstrap.min.css">
         <link rel="stylesheet" href="/views/acme/css/style.css">
         <link rel="stylesheet" href="/views/acme/css/style-responsive.css">
+        <link rel="stylesheet" href="/views/acme/css/font-awesome/css/font-awesome.min.css">
+        <link rel="stylesheet" href="/views/acme/css/set_css/dark.css" id="set_dark">
         <script src="/views/acme/js/jquery.min.js"></script>
         <script src="/views/acme/js/bootstrap.min.js"></script>
-        <link rel="stylesheet" href="/views/acme/css/font-awesome/css/font-awesome.min.css">
+        <script src="/views/acme/js/skin_set.js"></script>
         {{imp[1][5]|safe}}
         {{imp[2][3]|safe}}
         <meta name="twitter:creator" content="@{{imp[1][0]}}">
@@ -35,7 +38,7 @@
                     <ul class="nav navbar-nav">
                         <li id="right-search">
                             <form method="post" action="/search" id="searchform" role="search">
-                                <input style="display: inline-block;" class="form-control search" type="search" name="search" placeholder="Search" id="searchInput" autocomplete="off">
+                                <input style="display: inline-block;" class="form-control search" type="search" name="search" placeholder="{{'search'|load_lang}}" id="searchInput" autocomplete="off">
                             </form>                
                         </li>
                         <li class="dropdown">
@@ -74,10 +77,16 @@
                                 </li>
                                 <li>
                                     <a href="/other">
-                                        <i class="fa fa-cogs" aria-hidden="true"></i>
+                                        <i class="fa fa-wrench" aria-hidden="true"></i>
                                         {{'tool'|load_lang}}
                                     </a>
                                 </li>
+                                <li>
+                                    <a href="/skin_set">
+                                        <i class="fa fa-cog" aria-hidden="true"></i>
+                                        {{'skin'|load_lang}} {{'setting'|load_lang}}
+                                    </a>
+                                </li>
                             </ul>
                         </li>       
                         <li>
@@ -105,7 +114,7 @@
                 <div class="container">
                     <div class="row">
                         <div class="col-lg-4 col-sm-4">
-                            <h1>
+                            <h1 id="fix_title">
                                 {{imp[0]}}
                                 {% if imp[3][0] != 0 %}
                                     <sub>{{imp[3][0]}}</sub>
@@ -131,7 +140,7 @@
             </div>
             <div class="container">
                 <div class="row">
-                    <div class="col-md-10 col-md-offset-1 mar-b-30">
+                    <div id="fix_data" class="col-md-10 col-md-offset-1 mar-b-30">
                         {{data|safe}}
                     </div>
                 </div>

+ 79 - 0
views/acme/js/skin_set.js

@@ -0,0 +1,79 @@
+// 쿠키 생성
+function setCookie(name, value, expiredays) {
+    var cookie = name + "=" + escape(value) + "; path=/;"
+    if (typeof expiredays != 'undefined') {
+        var todayDate = new Date();
+        todayDate.setDate(todayDate.getDate() + expiredays);
+        cookie += "expires=" + todayDate.toGMTString() + ";"
+    }
+    document.cookie = cookie;
+}
+ 
+// 쿠키 획득
+function getCookie(name) {
+    name += "=";
+    var cookie = document.cookie;
+    var startIdx = cookie.indexOf(name);
+    if (startIdx != -1) {
+        startIdx += name.length;
+        var endIdx = cookie.indexOf(";", startIdx);
+        if (endIdx == -1) {
+            endIdx = cookie.length;
+            return unescape(cookie.substring(startIdx, endIdx));
+        }
+    }
+    return null;
+}
+ 
+// 쿠키 삭제
+function deleteCookie(name) {
+    setCookie(name, "", -1);
+}
+
+// http://vip00112.tistory.com/33
+
+function get_post() {
+    console.log("test");
+
+    check = document.getElementById('dark');
+    if(check.checked == true) {
+        setCookie("set_dark", "1");
+        console.log("check");
+    } else {
+        deleteCookie("set_dark");
+        console.log("delete");
+    }
+
+    console.log(getCookie("set_dark"));
+}
+
+if(getCookie("set_dark") != "1") {
+    document.getElementById('set_dark').disabled = true;
+}
+
+$(document).ready(function() {
+    if(window.location.pathname == "/skin_set") {
+        title = document.getElementById("fix_title");
+        data = document.getElementById("fix_data");
+        
+        get_title = "Skin Setting";
+
+        set_data = {};
+        set_data["dark"] = "";        
+
+        if(getCookie("set_dark") == "1") {
+            set_data["dark"] = "checked";
+        }
+
+        get_data =  ' \
+                        <input ' + set_data["dark"] + ' type="checkbox" id="dark" name="dark" value="dark"> Dark Mode \
+                        <hr> \
+                        <button onclick="get_post(); window.location.reload(true);">Save</button> \
+                    ';
+
+        document.title = document.title.replace(/.*(\- .*)$/, get_title + " $1");
+
+        title.innerHTML = get_title;
+        data.innerHTML = get_data;
+    }
+});

+ 31 - 0
views/main_css/main.css

@@ -0,0 +1,31 @@
+textarea { width: 100%; }
+input { width: 100%; }
+hr#last { margin-top: 30px; }
+div#toc { border: 1px solid; padding: 20px; width: fit-content; width: -moz-fit-content; margin-top: 10px; }
+#toc-name { font-size: 18px; }
+table { border-collapse: collapse; }
+td { border: 1px solid; padding: 5px; }
+a { text-decoration: none; }
+#not_thing { color: red; }
+#inside, #out_link, #open { color: green; }
+#out_link::before { background: green; color: white; content: "E"; }
+input[type="checkbox"] { width: auto; }
+.popup { position: fixed; bottom: 0; padding: 10px; left: 0; background: lightgray; width: 100%; }
+ul#list { padding: 10px; }
+#toron { width: 100%; }
+#toron_color { background: khaki; }
+#toron_color_green { background: darkseagreen; }
+#toron_color_blue { background: skyblue; }
+#toron_color_red { background: indianred; }
+#toron_color_grey { background: gainsboro; }
+div#cate { border: 1px solid; padding: 5px; }
+blockquote { border: 1px solid; padding: 15px; margin: 0; margin-top: 10px; }
+img, iframe { max-width: 100%; }
+pre { border: 1px solid; padding: 10px; white-space: pre-wrap; }
+#in { margin-left: 20px; }
+#out { margin-left: 5px; }
+s, strike, del { color: gray; }
+s:hover, strike:hover, del:hover { color: gray; background-color: gainsboro; text-decoration: none; }
+#main_table_set { width: 100%; text-align: center; }
+#main_table_width { width: 33.3%; }
+#main_table_width_half { width: 50%; }

Bu fark içinde çok fazla dosya değişikliği olduğu için bazı dosyalar gösterilmiyor