Browse code
initial commit
fiddlerwoaroof authored on 14/07/2014 20:00:44
Showing 20 changed files
Showing 20 changed files
- __init__.py
- __main__.py
- blog_puller.py
- blogs.json
- jinja_filters.py
- main.py
- snippets/python.snippets
- static/images/apple-touch-icon-114x114.png
- static/images/apple-touch-icon-72x72.png
- static/images/apple-touch-icon.png
- static/images/favicon.ico
- static/stylesheets/base.css
- static/stylesheets/layout.css
- static/stylesheets/mystyles.css
- static/stylesheets/skeleton.css
- templates/frame.html
- templates/main.html
- templates/markdown.md
- templates/toolbar.html
- url_handler.py
1 | 3 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,195 @@ |
1 |
+import url_handler |
|
2 |
+import feedparser |
|
3 |
+import hashlib |
|
4 |
+import json |
|
5 |
+#import redis |
|
6 |
+ |
|
7 |
+class Feed(object): |
|
8 |
+ @property |
|
9 |
+ def url(self): |
|
10 |
+ return self._url |
|
11 |
+ @url.setter |
|
12 |
+ def url(self, url): |
|
13 |
+ self.urlhash = hashlib.md5(url.encode('utf-8')).hexdigest() |
|
14 |
+ self._url = url |
|
15 |
+ |
|
16 |
+ def __init__(self, title, link, url, etag=None, modified=None, status=0): |
|
17 |
+ self.urlhash = hashlib.md5(url.encode('utf-8')).hexdigest() |
|
18 |
+ self.title, self.link, self.url = title, link, url |
|
19 |
+ print('__init__', 'etag is', etag, 'modified is', modified) |
|
20 |
+ self.etag = etag |
|
21 |
+ self.modified = modified |
|
22 |
+ self.status = int(status) |
|
23 |
+ self.entries = [] |
|
24 |
+ def add_entry(self, entry): |
|
25 |
+ if self.entries: |
|
26 |
+ self.entries[-1].sep = False |
|
27 |
+ self.entries.append(entry) |
|
28 |
+ self.entries[-1].sep = True |
|
29 |
+ |
|
30 |
+ def to_redis(self, redis): |
|
31 |
+ feed_key = self.get_feed_key(self.url) |
|
32 |
+ object_prefix = '%s:%%s' % feed_key |
|
33 |
+ print(object_prefix) |
|
34 |
+ redis.set(feed_key, 'exists') |
|
35 |
+ redis.set(object_prefix % 'title', self.title) |
|
36 |
+ redis.set(object_prefix % 'link', self.link) |
|
37 |
+ redis.set(object_prefix % 'url', self.url) |
|
38 |
+ redis.set(object_prefix % 'etag', self.etag) |
|
39 |
+ redis.set(object_prefix % 'modified', self.modified) |
|
40 |
+ redis.set(object_prefix % 'status', self.status) |
|
41 |
+ self.put_entries(redis, object_prefix) |
|
42 |
+ |
|
43 |
+ def put_entries(self, redis, object_prefix): |
|
44 |
+ for entry in reversed(self.entries): |
|
45 |
+ eid = hashlib.md5(entry.id.encode('utf-8')).hexdigest() |
|
46 |
+ entry_key = object_prefix % ('entry:%s' % eid) |
|
47 |
+ redis.sadd(object_prefix % 'entries', eid) |
|
48 |
+ entry.to_redis(redis, entry_key) |
|
49 |
+ |
|
50 |
+ @classmethod |
|
51 |
+ def get_feed_key(cls, url): |
|
52 |
+ return 'feed:%s' % hashlib.md5(url.encode('utf-8')).hexdigest() |
|
53 |
+ |
|
54 |
+ @classmethod |
|
55 |
+ def from_redis(cls, redis, url): |
|
56 |
+ feed_key = cls.get_feed_key(url) |
|
57 |
+ if redis.get(feed_key): |
|
58 |
+ object_prefix = '%s:%%s' % feed_key |
|
59 |
+ title = redis.get(object_prefix % 'title').decode('utf-8') |
|
60 |
+ link = redis.get(object_prefix % 'link').decode('utf-8') |
|
61 |
+ url = redis.get(object_prefix % 'url').decode('utf-8') |
|
62 |
+ etag = redis.get(object_prefix % 'etag').decode('utf-8') |
|
63 |
+ modified = redis.get(object_prefix % 'modified').decode('utf-8') |
|
64 |
+ status = redis.get(object_prefix % 'status').decode('utf-8') |
|
65 |
+ self = cls(title, link, url) |
|
66 |
+ entries = redis.smembers(object_prefix % 'entries') |
|
67 |
+ for eid in entries: |
|
68 |
+ eid = eid.decode('utf-8') |
|
69 |
+ entry_key = object_prefix % ('entry:%s' % eid) |
|
70 |
+ hl = Headline.from_redis(redis, entry_key) |
|
71 |
+ if hl is None: break |
|
72 |
+ else: self.add_entry(hl) |
|
73 |
+ |
|
74 |
+ if self.entries != []: |
|
75 |
+ self.entries[-1].sep = False |
|
76 |
+ self.entries.sort(key=lambda x:x.date) |
|
77 |
+ self.entries[-1].sep = True |
|
78 |
+ return self |
|
79 |
+ |
|
80 |
+ @classmethod |
|
81 |
+ def pull_feed(cls, url, etag=None, modified=None): |
|
82 |
+ print('etag is', etag, 'modified is', modified) |
|
83 |
+ feed = url_handler.URLHandler.handle(url, etag=etag, modified=modified) |
|
84 |
+ return cls.from_parsed_feed(feed, url) |
|
85 |
+ |
|
86 |
+ @classmethod |
|
87 |
+ def from_parsed_feed(cls, data, url): |
|
88 |
+ title = data.feed.title |
|
89 |
+ url = url |
|
90 |
+ link = data.feed.link |
|
91 |
+ etag = data.etag if hasattr(data, 'etag') else 'No Etag' |
|
92 |
+ modified = data.modified if hasattr(data, 'modified') else 'No Last Modified' |
|
93 |
+ print('parsed_feed', 'etag is', etag, 'modified is', modified) |
|
94 |
+ status = data.status |
|
95 |
+ |
|
96 |
+ self = cls(title, link, url, etag=etag, modified=modified, status=status) |
|
97 |
+ |
|
98 |
+ for entry in data.entries: |
|
99 |
+ hl = Headline(entry.title, entry.link, date=entry.published_parsed, id=entry.id) |
|
100 |
+ self.add_entry(hl) |
|
101 |
+ return self |
|
102 |
+ |
|
103 |
+ @classmethod |
|
104 |
+ def get_feed(cls, url, redis=None): |
|
105 |
+ res = None |
|
106 |
+ update = False |
|
107 |
+ newfeed = None |
|
108 |
+ |
|
109 |
+ if redis is not None: |
|
110 |
+ res = cls.from_redis(redis, url) |
|
111 |
+ if res is not None: |
|
112 |
+ newfeed = url_handler.URLHandler.handle(url, etag=res.etag, modified=res.modified) |
|
113 |
+ update = newfeed.status != 304 |
|
114 |
+ print('newfeed.status is', newfeed.status, 'update is', update) |
|
115 |
+ |
|
116 |
+ print('res is', res, 'update is', update, 'url is', url) |
|
117 |
+ if update or res is None: |
|
118 |
+ if update: |
|
119 |
+ updates = cls.from_parsed_feed(newfeed, url) |
|
120 |
+ object_prefix = '%s:%%s' % cls.get_feed_key(url) |
|
121 |
+ updates.put_entries(redis, object_prefix) |
|
122 |
+ print('putting updates!') |
|
123 |
+ updates.to_redis(redis) |
|
124 |
+ res = cls.from_redis(redis, url) |
|
125 |
+ else: |
|
126 |
+ data = url_handler.URLHandler.handle(url) |
|
127 |
+ res = cls.from_parsed_feed(data, url) |
|
128 |
+ res.to_redis(redis) |
|
129 |
+ return res |
|
130 |
+ |
|
131 |
+ |
|
132 |
+class Headline(object): |
|
133 |
+ @property |
|
134 |
+ def url(self): |
|
135 |
+ return self._url |
|
136 |
+ @url.setter |
|
137 |
+ def url(self, url): |
|
138 |
+ self.urlhash = hashlib.md5(url.encode('utf-8')).hexdigest() |
|
139 |
+ self._url = url |
|
140 |
+ |
|
141 |
+ serialized_attributes = ['title', 'url', 'img', 'id', 'date'] |
|
142 |
+ def __init__(self, title, url, sep=False, img=None, id=None, date=None): |
|
143 |
+ for x in self.serialized_attributes: |
|
144 |
+ setattr(self, x, locals()[x]) |
|
145 |
+ self.date = list(self.date) |
|
146 |
+ self.sep = sep |
|
147 |
+ |
|
148 |
+ def __repr__(self): |
|
149 |
+ return '<%s>' % ', '.join(str(getattr(self,x)) for x in self.serialized_attributes) |
|
150 |
+ trans_map = dict(date=json.dumps) |
|
151 |
+ rtrans_map = { y:x for (x,y) in trans_map.items() } |
|
152 |
+ def to_redis(self, redis, entry_key): |
|
153 |
+ redis.set(entry_key, 'exists') |
|
154 |
+ object_prefix = '%s:%%s' % entry_key |
|
155 |
+ for x in self.serialized_attributes: |
|
156 |
+ redis.set(object_prefix % x, self.trans_map.get(x, lambda x:x)(getattr(self, x))) |
|
157 |
+ |
|
158 |
+ @classmethod |
|
159 |
+ def from_redis(cls, redis, entry_key): |
|
160 |
+ if redis.get(entry_key) is not None: |
|
161 |
+ object_prefix = '%s:%%s' % entry_key |
|
162 |
+ args = {} |
|
163 |
+ for x in cls.serialized_attributes: |
|
164 |
+ args[x] = redis.get(object_prefix % x).decode('utf-8') |
|
165 |
+ args[x] = cls.rtrans_map.get(x, lambda x:x)(args[x]) |
|
166 |
+ return cls(**args) |
|
167 |
+ |
|
168 |
+ @classmethod |
|
169 |
+ def from_rss(cls, entry): |
|
170 |
+ name_mapping = dict( |
|
171 |
+ url='link', |
|
172 |
+ date='published_parsed', |
|
173 |
+ ) |
|
174 |
+ self = cls(entry.title, entry.link, id=entry.id, date=entry.published_parsed) |
|
175 |
+ |
|
176 |
+ def to_json(self): |
|
177 |
+ return json.dumps([self.title, self.link, self.sep, self.img]) |
|
178 |
+ @classmethod |
|
179 |
+ def from_json(cls, enc): |
|
180 |
+ enc = json.loads(enc) |
|
181 |
+ self = cls(*json.loads(enc)) |
|
182 |
+ |
|
183 |
+class Feeds(object): |
|
184 |
+ def __init__(self, urls, redis=None): |
|
185 |
+ self.feeds = list(filter(None, (Feed.get_feed(url, redis) for url in urls))) |
|
186 |
+ print(self.feeds) |
|
187 |
+ |
|
188 |
+if __name__ == '__main__': |
|
189 |
+ import json |
|
190 |
+ import redis |
|
191 |
+ print('getting feeds . . .', end=' ') |
|
192 |
+ with open('blogs.json') as f: |
|
193 |
+ feeds = json.load(f) |
|
194 |
+ feeds = Feeds(feeds, redis.Redis()) |
|
195 |
+ print('done.') |
0 | 196 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,15 @@ |
1 |
+[ |
|
2 |
+ "http://thomism.wordpress.com/feed/", |
|
3 |
+ "http://www.adashofbitters.com/feed/", |
|
4 |
+ "http://feeds.feedburner.com/jlongster", |
|
5 |
+ "http://americandrink.net/rss", |
|
6 |
+ "http://www.cocktailnerd.com/feed/", |
|
7 |
+ "http://melissamccart.tumblr.com/rss", |
|
8 |
+ "http://xkcd.com/rss.xml", |
|
9 |
+ "http://www.reddit.com/r/roguelikes/", |
|
10 |
+ "http://www.reddit.com/r/roguelikedev/", |
|
11 |
+ "http://www.reddit.com/r/programming/", |
|
12 |
+ "http://www.reddit.com/r/dcss/", |
|
13 |
+ "http://www.reddit.com/r/nethack/", |
|
14 |
+ "http://www.reddit.com/r/python/" |
|
15 |
+] |
0 | 7 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,101 @@ |
1 |
+import feedparser |
|
2 |
+from flask import Flask, url_for, redirect, request, render_template, make_response |
|
3 |
+import jinja_filters |
|
4 |
+import json |
|
5 |
+import logging |
|
6 |
+import random |
|
7 |
+ |
|
8 |
+app = Flask(__name__) |
|
9 |
+app.template_filter('mesc')(jinja_filters.markdown_quote) |
|
10 |
+ |
|
11 |
+def count_chars(word): |
|
12 |
+ special = set('ijltf') |
|
13 |
+ return sum( (0.5 if l in special else 1) for l in word ) |
|
14 |
+ |
|
15 |
+def divide_entries(entries): |
|
16 |
+ def chars_to_lines(entry): |
|
17 |
+ title, _, __, is_head, _ = entry |
|
18 |
+ divisor = 30 if is_head else 43 |
|
19 |
+ char_count = len(title) |
|
20 |
+ line_count = char_count / divisor |
|
21 |
+ line_count = max(line_count, 1) # everything always takes at least one line |
|
22 |
+ return line_count |
|
23 |
+ |
|
24 |
+ tagged_entries = [(chars_to_lines(x), x) for x in entries] # 36: no. chars in line |
|
25 |
+ total_lines = sum(x for x,_ in tagged_entries) |
|
26 |
+ target_lines = total_lines / 3 |
|
27 |
+ |
|
28 |
+ #target_chars = total_chars / 3 |
|
29 |
+ #average_chars = total_chars // len(entries) |
|
30 |
+ |
|
31 |
+ #target_ents = len(entries) / 3 |
|
32 |
+ #average_target_chars = average_chars * target_ents |
|
33 |
+ |
|
34 |
+ #print(target_chars, average_target_chars) |
|
35 |
+ |
|
36 |
+ #target_chars = (target_chars*2 + average_target_chars*3) // 5 |
|
37 |
+ |
|
38 |
+ #print(target_chars) |
|
39 |
+ |
|
40 |
+ columns = [[]] |
|
41 |
+ accum = 0 |
|
42 |
+ print() |
|
43 |
+ for n, entry in tagged_entries: |
|
44 |
+ accum += n |
|
45 |
+ if ( |
|
46 |
+ (accum > target_lines and len(columns) < 3) |
|
47 |
+ ): |
|
48 |
+ columns.append([]) |
|
49 |
+ print(accum) |
|
50 |
+ accum = accum - target_lines |
|
51 |
+ columns[-1].append(entry) |
|
52 |
+ print(accum) |
|
53 |
+ return columns |
|
54 |
+ |
|
55 |
+import redis |
|
56 |
+import blog_puller |
|
57 |
+def get_columns(urls): |
|
58 |
+ r = redis.Redis() |
|
59 |
+ feeds = blog_puller.Feeds(urls, r) |
|
60 |
+ entries = [] |
|
61 |
+ for feed in feeds.feeds: |
|
62 |
+ entries.append( (feed.title, feed.link, False, True, None) ) |
|
63 |
+ for entry in feed.entries: |
|
64 |
+ entries.append( (entry.title, entry.url, entry.sep, False, None) ) |
|
65 |
+ |
|
66 |
+ return divide_entries(entries) |
|
67 |
+ |
|
68 |
+ |
|
69 |
+def get_blogs(): |
|
70 |
+ with open('blogs.json') as f: |
|
71 |
+ blogs = json.load(f) |
|
72 |
+ columns = get_columns(blogs) |
|
73 |
+ for x in columns: |
|
74 |
+ a,b,_,d, e = x.pop() |
|
75 |
+ x.append( (a,b,False,d, e) ) |
|
76 |
+ return columns |
|
77 |
+ |
|
78 |
+@app.route("/") |
|
79 |
+def main(idx=0): |
|
80 |
+ return render_template('main.html', columns=get_blogs()) |
|
81 |
+ |
|
82 |
+@app.route("/<fn>.md") |
|
83 |
+@app.route("/.md") |
|
84 |
+def markdown(idx=0, fn=None): |
|
85 |
+ return make_response(render_template('markdown.md', columns=get_blogs()), |
|
86 |
+ 200, {'Content-Type': 'text/markdown; charset=utf-8'}) |
|
87 |
+ |
|
88 |
+@app.route("/toolbar/<path:url>") |
|
89 |
+def toolbar(url): |
|
90 |
+ return render_template('toolbar.html', url=url) |
|
91 |
+ |
|
92 |
+@app.route("/show/<path:url>") |
|
93 |
+def ope(url=None): |
|
94 |
+ if url is not None: |
|
95 |
+ resp = make_response(render_template('frame.html', target_site=url), 200) |
|
96 |
+ resp.headers['X-Frame-Options'] = 'GOFORIT' |
|
97 |
+ return resp |
|
98 |
+ else: |
|
99 |
+ return 'not found' |
|
100 |
+ |
|
101 |
+app.run('172.16.1.2', debug=True) |
8 | 13 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,269 @@ |
1 |
+/* |
|
2 |
+* Skeleton V1.2 |
|
3 |
+* Copyright 2011, Dave Gamache |
|
4 |
+* www.getskeleton.com |
|
5 |
+* Free to use under the MIT license. |
|
6 |
+* http://www.opensource.org/licenses/mit-license.php |
|
7 |
+* 6/20/2012 |
|
8 |
+*/ |
|
9 |
+ |
|
10 |
+ |
|
11 |
+/* Table of Content |
|
12 |
+================================================== |
|
13 |
+ #Reset & Basics |
|
14 |
+ #Basic Styles |
|
15 |
+ #Site Styles |
|
16 |
+ #Typography |
|
17 |
+ #Links |
|
18 |
+ #Lists |
|
19 |
+ #Images |
|
20 |
+ #Buttons |
|
21 |
+ #Forms |
|
22 |
+ #Misc */ |
|
23 |
+ |
|
24 |
+ |
|
25 |
+/* #Reset & Basics (Inspired by E. Meyers) |
|
26 |
+================================================== */ |
|
27 |
+ html, body, div, span, applet, object, iframe, h1, h2, h3, h4, h5, h6, p, blockquote, pre, a, abbr, acronym, address, big, cite, code, del, dfn, em, img, ins, kbd, q, s, samp, small, strike, strong, sub, sup, tt, var, b, u, i, center, dl, dt, dd, ol, ul, li, fieldset, form, label, legend, table, caption, tbody, tfoot, thead, tr, th, td, article, aside, canvas, details, embed, figure, figcaption, footer, header, hgroup, menu, nav, output, ruby, section, summary, time, mark, audio, video { |
|
28 |
+ margin: 0; |
|
29 |
+ padding: 0; |
|
30 |
+ border: 0; |
|
31 |
+ font-size: 100%; |
|
32 |
+ font: inherit; |
|
33 |
+ vertical-align: baseline; } |
|
34 |
+ article, aside, details, figcaption, figure, footer, header, hgroup, menu, nav, section { |
|
35 |
+ display: block; } |
|
36 |
+ body { |
|
37 |
+ line-height: 1; } |
|
38 |
+ ol, ul { |
|
39 |
+ list-style: none; } |
|
40 |
+ blockquote, q { |
|
41 |
+ quotes: none; } |
|
42 |
+ blockquote:before, blockquote:after, |
|
43 |
+ q:before, q:after { |
|
44 |
+ content: ''; |
|
45 |
+ content: none; } |
|
46 |
+ table { |
|
47 |
+ border-collapse: collapse; |
|
48 |
+ border-spacing: 0; } |
|
49 |
+ |
|
50 |
+ |
|
51 |
+/* #Basic Styles |
|
52 |
+================================================== */ |
|
53 |
+ body { |
|
54 |
+ background: #fff; |
|
55 |
+ font: 14px/21px "HelveticaNeue", "Helvetica Neue", Helvetica, Arial, sans-serif; |
|
56 |
+ color: #444; |
|
57 |
+ -webkit-font-smoothing: antialiased; /* Fix for webkit rendering */ |
|
58 |
+ -webkit-text-size-adjust: 100%; |
|
59 |
+ } |
|
60 |
+ |
|
61 |
+ |
|
62 |
+/* #Typography |
|
63 |
+================================================== */ |
|
64 |
+ h1, h2, h3, h4, h5, h6 { |
|
65 |
+ color: #181818; |
|
66 |
+ font-family: "Georgia", "Times New Roman", serif; |
|
67 |
+ font-weight: normal; } |
|
68 |
+ h1 a, h2 a, h3 a, h4 a, h5 a, h6 a { font-weight: inherit; } |
|
69 |
+ h1 { font-size: 46px; line-height: 50px; margin-bottom: 14px;} |
|
70 |
+ h2 { font-size: 35px; line-height: 40px; margin-bottom: 10px; } |
|
71 |
+ h3 { font-size: 28px; line-height: 34px; margin-bottom: 8px; } |
|
72 |
+ h4 { font-size: 21px; line-height: 30px; margin-bottom: 4px; } |
|
73 |
+ h5 { font-size: 17px; line-height: 24px; } |
|
74 |
+ h6 { font-size: 14px; line-height: 21px; } |
|
75 |
+ .subheader { color: #777; } |
|
76 |
+ |
|
77 |
+ p { margin: 0 0 20px 0; } |
|
78 |
+ p img { margin: 0; } |
|
79 |
+ p.lead { font-size: 21px; line-height: 27px; color: #777; } |
|
80 |
+ |
|
81 |
+ em { font-style: italic; } |
|
82 |
+ strong { font-weight: bold; color: #333; } |
|
83 |
+ small { font-size: 80%; } |
|
84 |
+ |
|
85 |
+/* Blockquotes */ |
|
86 |
+ blockquote, blockquote p { font-size: 17px; line-height: 24px; color: #777; font-style: italic; } |
|
87 |
+ blockquote { margin: 0 0 20px; padding: 9px 20px 0 19px; border-left: 1px solid #ddd; } |
|
88 |
+ blockquote cite { display: block; font-size: 12px; color: #555; } |
|
89 |
+ blockquote cite:before { content: "\2014 \0020"; } |
|
90 |
+ blockquote cite a, blockquote cite a:visited, blockquote cite a:visited { color: #555; } |
|
91 |
+ |
|
92 |
+ hr { border: solid #ddd; border-width: 1px 0 0; clear: both; margin: 10px 0 30px; height: 0; } |
|
93 |
+ |
|
94 |
+ |
|
95 |
+/* #Links |
|
96 |
+================================================== */ |
|
97 |
+ a, a:visited { color: #333; text-decoration: underline; outline: 0; } |
|
98 |
+ a:hover, a:focus { color: #000; } |
|
99 |
+ p a, p a:visited { line-height: inherit; } |
|
100 |
+ |
|
101 |
+ |
|
102 |
+/* #Lists |
|
103 |
+================================================== */ |
|
104 |
+ ul, ol { margin-bottom: 20px; } |
|
105 |
+ ul { list-style: none outside; } |
|
106 |
+ ol { list-style: decimal; } |
|
107 |
+ ol, ul.square, ul.circle, ul.disc { margin-left: 30px; } |
|
108 |
+ ul.square { list-style: square outside; } |
|
109 |
+ ul.circle { list-style: circle outside; } |
|
110 |
+ ul.disc { list-style: disc outside; } |
|
111 |
+ ul ul, ul ol, |
|
112 |
+ ol ol, ol ul { margin: 4px 0 5px 30px; font-size: 90%; } |
|
113 |
+ ul ul li, ul ol li, |
|
114 |
+ ol ol li, ol ul li { margin-bottom: 6px; } |
|
115 |
+ li { line-height: 18px; margin-bottom: 12px; } |
|
116 |
+ ul.large li { line-height: 21px; } |
|
117 |
+ li p { line-height: 21px; } |
|
118 |
+ |
|
119 |
+/* #Images |
|
120 |
+================================================== */ |
|
121 |
+ |
|
122 |
+ img.scale-with-grid { |
|
123 |
+ max-width: 100%; |
|
124 |
+ height: auto; } |
|
125 |
+ |
|
126 |
+ |
|
127 |
+/* #Buttons |
|
128 |
+================================================== */ |
|
129 |
+ |
|
130 |
+ .button, |
|
131 |
+ button, |
|
132 |
+ input[type="submit"], |
|
133 |
+ input[type="reset"], |
|
134 |
+ input[type="button"] { |
|
135 |
+ background: #eee; /* Old browsers */ |
|
136 |
+ background: #eee -moz-linear-gradient(top, rgba(255,255,255,.2) 0%, rgba(0,0,0,.2) 100%); /* FF3.6+ */ |
|
137 |
+ background: #eee -webkit-gradient(linear, left top, left bottom, color-stop(0%,rgba(255,255,255,.2)), color-stop(100%,rgba(0,0,0,.2))); /* Chrome,Safari4+ */ |
|
138 |
+ background: #eee -webkit-linear-gradient(top, rgba(255,255,255,.2) 0%,rgba(0,0,0,.2) 100%); /* Chrome10+,Safari5.1+ */ |
|
139 |
+ background: #eee -o-linear-gradient(top, rgba(255,255,255,.2) 0%,rgba(0,0,0,.2) 100%); /* Opera11.10+ */ |
|
140 |
+ background: #eee -ms-linear-gradient(top, rgba(255,255,255,.2) 0%,rgba(0,0,0,.2) 100%); /* IE10+ */ |
|
141 |
+ background: #eee linear-gradient(top, rgba(255,255,255,.2) 0%,rgba(0,0,0,.2) 100%); /* W3C */ |
|
142 |
+ border: 1px solid #aaa; |
|
143 |
+ border-top: 1px solid #ccc; |
|
144 |
+ border-left: 1px solid #ccc; |
|
145 |
+ -moz-border-radius: 3px; |
|
146 |
+ -webkit-border-radius: 3px; |
|
147 |
+ border-radius: 3px; |
|
148 |
+ color: #444; |
|
149 |
+ display: inline-block; |
|
150 |
+ font-size: 11px; |
|
151 |
+ font-weight: bold; |
|
152 |
+ text-decoration: none; |
|
153 |
+ text-shadow: 0 1px rgba(255, 255, 255, .75); |
|
154 |
+ cursor: pointer; |
|
155 |
+ margin-bottom: 20px; |
|
156 |
+ line-height: normal; |
|
157 |
+ padding: 8px 10px; |
|
158 |
+ font-family: "HelveticaNeue", "Helvetica Neue", Helvetica, Arial, sans-serif; } |
|
159 |
+ |
|
160 |
+ .button:hover, |
|
161 |
+ button:hover, |
|
162 |
+ input[type="submit"]:hover, |
|
163 |
+ input[type="reset"]:hover, |
|
164 |
+ input[type="button"]:hover { |
|
165 |
+ color: #222; |
|
166 |
+ background: #ddd; /* Old browsers */ |
|
167 |
+ background: #ddd -moz-linear-gradient(top, rgba(255,255,255,.3) 0%, rgba(0,0,0,.3) 100%); /* FF3.6+ */ |
|
168 |
+ background: #ddd -webkit-gradient(linear, left top, left bottom, color-stop(0%,rgba(255,255,255,.3)), color-stop(100%,rgba(0,0,0,.3))); /* Chrome,Safari4+ */ |
|
169 |
+ background: #ddd -webkit-linear-gradient(top, rgba(255,255,255,.3) 0%,rgba(0,0,0,.3) 100%); /* Chrome10+,Safari5.1+ */ |
|
170 |
+ background: #ddd -o-linear-gradient(top, rgba(255,255,255,.3) 0%,rgba(0,0,0,.3) 100%); /* Opera11.10+ */ |
|
171 |
+ background: #ddd -ms-linear-gradient(top, rgba(255,255,255,.3) 0%,rgba(0,0,0,.3) 100%); /* IE10+ */ |
|
172 |
+ background: #ddd linear-gradient(top, rgba(255,255,255,.3) 0%,rgba(0,0,0,.3) 100%); /* W3C */ |
|
173 |
+ border: 1px solid #888; |
|
174 |
+ border-top: 1px solid #aaa; |
|
175 |
+ border-left: 1px solid #aaa; } |
|
176 |
+ |
|
177 |
+ .button:active, |
|
178 |
+ button:active, |
|
179 |
+ input[type="submit"]:active, |
|
180 |
+ input[type="reset"]:active, |
|
181 |
+ input[type="button"]:active { |
|
182 |
+ border: 1px solid #666; |
|
183 |
+ background: #ccc; /* Old browsers */ |
|
184 |
+ background: #ccc -moz-linear-gradient(top, rgba(255,255,255,.35) 0%, rgba(10,10,10,.4) 100%); /* FF3.6+ */ |
|
185 |
+ background: #ccc -webkit-gradient(linear, left top, left bottom, color-stop(0%,rgba(255,255,255,.35)), color-stop(100%,rgba(10,10,10,.4))); /* Chrome,Safari4+ */ |
|
186 |
+ background: #ccc -webkit-linear-gradient(top, rgba(255,255,255,.35) 0%,rgba(10,10,10,.4) 100%); /* Chrome10+,Safari5.1+ */ |
|
187 |
+ background: #ccc -o-linear-gradient(top, rgba(255,255,255,.35) 0%,rgba(10,10,10,.4) 100%); /* Opera11.10+ */ |
|
188 |
+ background: #ccc -ms-linear-gradient(top, rgba(255,255,255,.35) 0%,rgba(10,10,10,.4) 100%); /* IE10+ */ |
|
189 |
+ background: #ccc linear-gradient(top, rgba(255,255,255,.35) 0%,rgba(10,10,10,.4) 100%); /* W3C */ } |
|
190 |
+ |
|
191 |
+ .button.full-width, |
|
192 |
+ button.full-width, |
|
193 |
+ input[type="submit"].full-width, |
|
194 |
+ input[type="reset"].full-width, |
|
195 |
+ input[type="button"].full-width { |
|
196 |
+ width: 100%; |
|
197 |
+ padding-left: 0 !important; |
|
198 |
+ padding-right: 0 !important; |
|
199 |
+ text-align: center; } |
|
200 |
+ |
|
201 |
+ /* Fix for odd Mozilla border & padding issues */ |
|
202 |
+ button::-moz-focus-inner, |
|
203 |
+ input::-moz-focus-inner { |
|
204 |
+ border: 0; |
|
205 |
+ padding: 0; |
|
206 |
+ } |
|
207 |
+ |
|
208 |
+ |
|
209 |
+/* #Forms |
|
210 |
+================================================== */ |
|
211 |
+ |
|
212 |
+ form { |
|
213 |
+ margin-bottom: 20px; } |
|
214 |
+ fieldset { |
|
215 |
+ margin-bottom: 20px; } |
|
216 |
+ input[type="text"], |
|
217 |
+ input[type="password"], |
|
218 |
+ input[type="email"], |
|
219 |
+ textarea, |
|
220 |
+ select { |
|
221 |
+ border: 1px solid #ccc; |
|
222 |
+ padding: 6px 4px; |
|
223 |
+ outline: none; |
|
224 |
+ -moz-border-radius: 2px; |
|
225 |
+ -webkit-border-radius: 2px; |
|
226 |
+ border-radius: 2px; |
|
227 |
+ font: 13px "HelveticaNeue", "Helvetica Neue", Helvetica, Arial, sans-serif; |
|
228 |
+ color: #777; |
|
229 |
+ margin: 0; |
|
230 |
+ width: 210px; |
|
231 |
+ max-width: 100%; |
|
232 |
+ display: block; |
|
233 |
+ margin-bottom: 20px; |
|
234 |
+ background: #fff; } |
|
235 |
+ select { |
|
236 |
+ padding: 0; } |
|
237 |
+ input[type="text"]:focus, |
|
238 |
+ input[type="password"]:focus, |
|
239 |
+ input[type="email"]:focus, |
|
240 |
+ textarea:focus { |
|
241 |
+ border: 1px solid #aaa; |
|
242 |
+ color: #444; |
|
243 |
+ -moz-box-shadow: 0 0 3px rgba(0,0,0,.2); |
|
244 |
+ -webkit-box-shadow: 0 0 3px rgba(0,0,0,.2); |
|
245 |
+ box-shadow: 0 0 3px rgba(0,0,0,.2); } |
|
246 |
+ textarea { |
|
247 |
+ min-height: 60px; } |
|
248 |
+ label, |
|
249 |
+ legend { |
|
250 |
+ display: block; |
|
251 |
+ font-weight: bold; |
|
252 |
+ font-size: 13px; } |
|
253 |
+ select { |
|
254 |
+ width: 220px; } |
|
255 |
+ input[type="checkbox"] { |
|
256 |
+ display: inline; } |
|
257 |
+ label span, |
|
258 |
+ legend span { |
|
259 |
+ font-weight: normal; |
|
260 |
+ font-size: 13px; |
|
261 |
+ color: #444; } |
|
262 |
+ |
|
263 |
+/* #Misc |
|
264 |
+================================================== */ |
|
265 |
+ .remove-bottom { margin-bottom: 0 !important; } |
|
266 |
+ .half-bottom { margin-bottom: 10px !important; } |
|
267 |
+ .add-bottom { margin-bottom: 20px !important; } |
|
268 |
+ |
|
269 |
+ |
0 | 270 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,58 @@ |
1 |
+/* |
|
2 |
+* Skeleton V1.2 |
|
3 |
+* Copyright 2011, Dave Gamache |
|
4 |
+* www.getskeleton.com |
|
5 |
+* Free to use under the MIT license. |
|
6 |
+* http://www.opensource.org/licenses/mit-license.php |
|
7 |
+* 6/20/2012 |
|
8 |
+*/ |
|
9 |
+ |
|
10 |
+/* Table of Content |
|
11 |
+================================================== |
|
12 |
+ #Site Styles |
|
13 |
+ #Page Styles |
|
14 |
+ #Media Queries |
|
15 |
+ #Font-Face */ |
|
16 |
+ |
|
17 |
+/* #Site Styles |
|
18 |
+================================================== */ |
|
19 |
+ |
|
20 |
+/* #Page Styles |
|
21 |
+================================================== */ |
|
22 |
+ |
|
23 |
+/* #Media Queries |
|
24 |
+================================================== */ |
|
25 |
+ |
|
26 |
+ /* Smaller than standard 960 (devices and browsers) */ |
|
27 |
+ @media only screen and (max-width: 959px) {} |
|
28 |
+ |
|
29 |
+ /* Tablet Portrait size to standard 960 (devices and browsers) */ |
|
30 |
+ @media only screen and (min-width: 768px) and (max-width: 959px) {} |
|
31 |
+ |
|
32 |
+ /* All Mobile Sizes (devices and browser) */ |
|
33 |
+ @media only screen and (max-width: 767px) {} |
|
34 |
+ |
|
35 |
+ /* Mobile Landscape Size to Tablet Portrait (devices and browsers) */ |
|
36 |
+ @media only screen and (min-width: 480px) and (max-width: 767px) {} |
|
37 |
+ |
|
38 |
+ /* Mobile Portrait Size to Mobile Landscape Size (devices and browsers) */ |
|
39 |
+ @media only screen and (max-width: 479px) {} |
|
40 |
+ |
|
41 |
+ |
|
42 |
+/* #Font-Face |
|
43 |
+================================================== */ |
|
44 |
+/* This is the proper syntax for an @font-face file |
|
45 |
+ Just create a "fonts" folder at the root, |
|
46 |
+ copy your FontName into code below and remove |
|
47 |
+ comment brackets */ |
|
48 |
+ |
|
49 |
+/* @font-face { |
|
50 |
+ font-family: 'FontName'; |
|
51 |
+ src: url('../fonts/FontName.eot'); |
|
52 |
+ src: url('../fonts/FontName.eot?iefix') format('eot'), |
|
53 |
+ url('../fonts/FontName.woff') format('woff'), |
|
54 |
+ url('../fonts/FontName.ttf') format('truetype'), |
|
55 |
+ url('../fonts/FontName.svg#webfontZam02nTh') format('svg'); |
|
56 |
+ font-weight: normal; |
|
57 |
+ font-style: normal; } |
|
58 |
+*/ |
|
0 | 59 |
\ No newline at end of file |
0 | 8 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,242 @@ |
1 |
+/* |
|
2 |
+* Skeleton V1.2 |
|
3 |
+* Copyright 2011, Dave Gamache |
|
4 |
+* www.getskeleton.com |
|
5 |
+* Free to use under the MIT license. |
|
6 |
+* http://www.opensource.org/licenses/mit-license.php |
|
7 |
+* 6/20/2012 |
|
8 |
+*/ |
|
9 |
+ |
|
10 |
+ |
|
11 |
+/* Table of Contents |
|
12 |
+================================================== |
|
13 |
+ #Base 960 Grid |
|
14 |
+ #Tablet (Portrait) |
|
15 |
+ #Mobile (Portrait) |
|
16 |
+ #Mobile (Landscape) |
|
17 |
+ #Clearing */ |
|
18 |
+ |
|
19 |
+ |
|
20 |
+ |
|
21 |
+/* #Base 960 Grid |
|
22 |
+================================================== */ |
|
23 |
+ |
|
24 |
+ .container { position: relative; width: 960px; margin: 0 auto; padding: 0; } |
|
25 |
+ .container .column, |
|
26 |
+ .container .columns { float: left; display: inline; margin-left: 10px; margin-right: 10px; } |
|
27 |
+ .row { margin-bottom: 20px; } |
|
28 |
+ |
|
29 |
+ /* Nested Column Classes */ |
|
30 |
+ .column.alpha, .columns.alpha { margin-left: 0; } |
|
31 |
+ .column.omega, .columns.omega { margin-right: 0; } |
|
32 |
+ |
|
33 |
+ /* Base Grid */ |
|
34 |
+ .container .one.column, |
|
35 |
+ .container .one.columns { width: 40px; } |
|
36 |
+ .container .two.columns { width: 100px; } |
|
37 |
+ .container .three.columns { width: 160px; } |
|
38 |
+ .container .four.columns { width: 220px; } |
|
39 |
+ .container .five.columns { width: 280px; } |
|
40 |
+ .container .six.columns { width: 340px; } |
|
41 |
+ .container .seven.columns { width: 400px; } |
|
42 |
+ .container .eight.columns { width: 460px; } |
|
43 |
+ .container .nine.columns { width: 520px; } |
|
44 |
+ .container .ten.columns { width: 580px; } |
|
45 |
+ .container .eleven.columns { width: 640px; } |
|
46 |
+ .container .twelve.columns { width: 700px; } |
|
47 |
+ .container .thirteen.columns { width: 760px; } |
|
48 |
+ .container .fourteen.columns { width: 820px; } |
|
49 |
+ .container .fifteen.columns { width: 880px; } |
|
50 |
+ .container .sixteen.columns { width: 940px; } |
|
51 |
+ |
|
52 |
+ .container .one-third.column { width: 300px; } |
|
53 |
+ .container .two-thirds.column { width: 620px; } |
|
54 |
+ |
|
55 |
+ /* Offsets */ |
|
56 |
+ .container .offset-by-one { padding-left: 60px; } |
|
57 |
+ .container .offset-by-two { padding-left: 120px; } |
|
58 |
+ .container .offset-by-three { padding-left: 180px; } |
|
59 |
+ .container .offset-by-four { padding-left: 240px; } |
|
60 |
+ .container .offset-by-five { padding-left: 300px; } |
|
61 |
+ .container .offset-by-six { padding-left: 360px; } |
|
62 |
+ .container .offset-by-seven { padding-left: 420px; } |
|
63 |
+ .container .offset-by-eight { padding-left: 480px; } |
|
64 |
+ .container .offset-by-nine { padding-left: 540px; } |
|
65 |
+ .container .offset-by-ten { padding-left: 600px; } |
|
66 |
+ .container .offset-by-eleven { padding-left: 660px; } |
|
67 |
+ .container .offset-by-twelve { padding-left: 720px; } |
|
68 |
+ .container .offset-by-thirteen { padding-left: 780px; } |
|
69 |
+ .container .offset-by-fourteen { padding-left: 840px; } |
|
70 |
+ .container .offset-by-fifteen { padding-left: 900px; } |
|
71 |
+ |
|
72 |
+ |
|
73 |
+ |
|
74 |
+/* #Tablet (Portrait) |
|
75 |
+================================================== */ |
|
76 |
+ |
|
77 |
+ /* Note: Design for a width of 768px */ |
|
78 |
+ |
|
79 |
+ @media only screen and (min-width: 768px) and (max-width: 959px) { |
|
80 |
+ .container { width: 768px; } |
|
81 |
+ .container .column, |
|
82 |
+ .container .columns { margin-left: 10px; margin-right: 10px; } |
|
83 |
+ .column.alpha, .columns.alpha { margin-left: 0; margin-right: 10px; } |
|
84 |
+ .column.omega, .columns.omega { margin-right: 0; margin-left: 10px; } |
|
85 |
+ .alpha.omega { margin-left: 0; margin-right: 0; } |
|
86 |
+ |
|
87 |
+ .container .one.column, |
|
88 |
+ .container .one.columns { width: 28px; } |
|
89 |
+ .container .two.columns { width: 76px; } |
|
90 |
+ .container .three.columns { width: 124px; } |
|
91 |
+ .container .four.columns { width: 172px; } |
|
92 |
+ .container .five.columns { width: 220px; } |
|
93 |
+ .container .six.columns { width: 268px; } |
|
94 |
+ .container .seven.columns { width: 316px; } |
|
95 |
+ .container .eight.columns { width: 364px; } |
|
96 |
+ .container .nine.columns { width: 412px; } |
|
97 |
+ .container .ten.columns { width: 460px; } |
|
98 |
+ .container .eleven.columns { width: 508px; } |
|
99 |
+ .container .twelve.columns { width: 556px; } |
|
100 |
+ .container .thirteen.columns { width: 604px; } |
|
101 |
+ .container .fourteen.columns { width: 652px; } |
|
102 |
+ .container .fifteen.columns { width: 700px; } |
|
103 |
+ .container .sixteen.columns { width: 748px; } |
|
104 |
+ |
|
105 |
+ .container .one-third.column { width: 236px; } |
|
106 |
+ .container .two-thirds.column { width: 492px; } |
|
107 |
+ |
|
108 |
+ /* Offsets */ |
|
109 |
+ .container .offset-by-one { padding-left: 48px; } |
|
110 |
+ .container .offset-by-two { padding-left: 96px; } |
|
111 |
+ .container .offset-by-three { padding-left: 144px; } |
|
112 |
+ .container .offset-by-four { padding-left: 192px; } |
|
113 |
+ .container .offset-by-five { padding-left: 240px; } |
|
114 |
+ .container .offset-by-six { padding-left: 288px; } |
|
115 |
+ .container .offset-by-seven { padding-left: 336px; } |
|
116 |
+ .container .offset-by-eight { padding-left: 384px; } |
|
117 |
+ .container .offset-by-nine { padding-left: 432px; } |
|
118 |
+ .container .offset-by-ten { padding-left: 480px; } |
|
119 |
+ .container .offset-by-eleven { padding-left: 528px; } |
|
120 |
+ .container .offset-by-twelve { padding-left: 576px; } |
|
121 |
+ .container .offset-by-thirteen { padding-left: 624px; } |
|
122 |
+ .container .offset-by-fourteen { padding-left: 672px; } |
|
123 |
+ .container .offset-by-fifteen { padding-left: 720px; } |
|
124 |
+ } |
|
125 |
+ |
|
126 |
+ |
|
127 |
+/* #Mobile (Portrait) |
|
128 |
+================================================== */ |
|
129 |
+ |
|
130 |
+ /* Note: Design for a width of 320px */ |
|
131 |
+ |
|
132 |
+ @media only screen and (max-width: 767px) { |
|
133 |
+ .container { width: 300px; } |
|
134 |
+ .container .columns, |
|
135 |
+ .container .column { margin: 0; } |
|
136 |
+ |
|
137 |
+ .container .one.column, |
|
138 |
+ .container .one.columns, |
|
139 |
+ .container .two.columns, |
|
140 |
+ .container .three.columns, |
|
141 |
+ .container .four.columns, |
|
142 |
+ .container .five.columns, |
|
143 |
+ .container .six.columns, |
|
144 |
+ .container .seven.columns, |
|
145 |
+ .container .eight.columns, |
|
146 |
+ .container .nine.columns, |
|
147 |
+ .container .ten.columns, |
|
148 |
+ .container .eleven.columns, |
|
149 |
+ .container .twelve.columns, |
|
150 |
+ .container .thirteen.columns, |
|
151 |
+ .container .fourteen.columns, |
|
152 |
+ .container .fifteen.columns, |
|
153 |
+ .container .sixteen.columns, |
|
154 |
+ .container .one-third.column, |
|
155 |
+ .container .two-thirds.column { width: 300px; } |
|
156 |
+ |
|
157 |
+ /* Offsets */ |
|
158 |
+ .container .offset-by-one, |
|
159 |
+ .container .offset-by-two, |
|
160 |
+ .container .offset-by-three, |
|
161 |
+ .container .offset-by-four, |
|
162 |
+ .container .offset-by-five, |
|
163 |
+ .container .offset-by-six, |
|
164 |
+ .container .offset-by-seven, |
|
165 |
+ .container .offset-by-eight, |
|
166 |
+ .container .offset-by-nine, |
|
167 |
+ .container .offset-by-ten, |
|
168 |
+ .container .offset-by-eleven, |
|
169 |
+ .container .offset-by-twelve, |
|
170 |
+ .container .offset-by-thirteen, |
|
171 |
+ .container .offset-by-fourteen, |
|
172 |
+ .container .offset-by-fifteen { padding-left: 0; } |
|
173 |
+ |
|
174 |
+ } |
|
175 |
+ |
|
176 |
+ |
|
177 |
+/* #Mobile (Landscape) |
|
178 |
+================================================== */ |
|
179 |
+ |
|
180 |
+ /* Note: Design for a width of 480px */ |
|
181 |
+ |
|
182 |
+ @media only screen and (min-width: 480px) and (max-width: 767px) { |
|
183 |
+ .container { width: 420px; } |
|
184 |
+ .container .columns, |
|
185 |
+ .container .column { margin: 0; } |
|
186 |
+ |
|
187 |
+ .container .one.column, |
|
188 |
+ .container .one.columns, |
|
189 |
+ .container .two.columns, |
|
190 |
+ .container .three.columns, |
|
191 |
+ .container .four.columns, |
|
192 |
+ .container .five.columns, |
|
193 |
+ .container .six.columns, |
|
194 |
+ .container .seven.columns, |
|
195 |
+ .container .eight.columns, |
|
196 |
+ .container .nine.columns, |
|
197 |
+ .container .ten.columns, |
|
198 |
+ .container .eleven.columns, |
|
199 |
+ .container .twelve.columns, |
|
200 |
+ .container .thirteen.columns, |
|
201 |
+ .container .fourteen.columns, |
|
202 |
+ .container .fifteen.columns, |
|
203 |
+ .container .sixteen.columns, |
|
204 |
+ .container .one-third.column, |
|
205 |
+ .container .two-thirds.column { width: 420px; } |
|
206 |
+ } |
|
207 |
+ |
|
208 |
+ |
|
209 |
+/* #Clearing |
|
210 |
+================================================== */ |
|
211 |
+ |
|
212 |
+ /* Self Clearing Goodness */ |
|
213 |
+ .container:after { content: "\0020"; display: block; height: 0; clear: both; visibility: hidden; } |
|
214 |
+ |
|
215 |
+ /* Use clearfix class on parent to clear nested columns, |
|
216 |
+ or wrap each row of columns in a <div class="row"> */ |
|
217 |
+ .clearfix:before, |
|
218 |
+ .clearfix:after, |
|
219 |
+ .row:before, |
|
220 |
+ .row:after { |
|
221 |
+ content: '\0020'; |
|
222 |
+ display: block; |
|
223 |
+ overflow: hidden; |
|
224 |
+ visibility: hidden; |
|
225 |
+ width: 0; |
|
226 |
+ height: 0; } |
|
227 |
+ .row:after, |
|
228 |
+ .clearfix:after { |
|
229 |
+ clear: both; } |
|
230 |
+ .row, |
|
231 |
+ .clearfix { |
|
232 |
+ zoom: 1; } |
|
233 |
+ |
|
234 |
+ /* You can also use a <br class="clear" /> to clear columns */ |
|
235 |
+ .clear { |
|
236 |
+ clear: both; |
|
237 |
+ display: block; |
|
238 |
+ overflow: hidden; |
|
239 |
+ visibility: hidden; |
|
240 |
+ width: 0; |
|
241 |
+ height: 0; |
|
242 |
+ } |
0 | 243 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,11 @@ |
1 |
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/html4/frameset.dtd"> |
|
2 |
+<html> |
|
3 |
+ <head> |
|
4 |
+ <title>Article</title> |
|
5 |
+ </head> |
|
6 |
+ <frameset border="0" frameborder="0" framespacing="0" rows="20px, 100%"> |
|
7 |
+ <frame border="0" frameborder="0" name="reddit_top" noresize="1" scrolling="no" src="/toolbar/{{target_site}}"/> |
|
8 |
+ <frame border="0" frameborder="0" name="inner_toolbar" src="{{target_site}}""/> |
|
9 |
+ </frameset> |
|
10 |
+</html> |
|
11 |
+ |
0 | 12 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,101 @@ |
1 |
+<!DOCTYPE html> |
|
2 |
+<!--[if lt IE 7 ]><html class="ie ie6" lang="en"> <![endif]--> |
|
3 |
+<!--[if IE 7 ]><html class="ie ie7" lang="en"> <![endif]--> |
|
4 |
+<!--[if IE 8 ]><html class="ie ie8" lang="en"> <![endif]--> |
|
5 |
+<!--[if (gte IE 9)|!(IE)]><!--><html lang="en"> <!--<![endif]--> |
|
6 |
+<head> |
|
7 |
+ |
|
8 |
+ <!-- Basic Page Needs |
|
9 |
+ ================================================== --> |
|
10 |
+ <meta charset="utf-8"> |
|
11 |
+ <title>{{ title }}</title> |
|
12 |
+ <meta name="description" content=""> |
|
13 |
+ <meta name="author" content=""> |
|
14 |
+ |
|
15 |
+ <!-- Mobile Specific Metas |
|
16 |
+ ================================================== --> |
|
17 |
+ <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1"> |
|
18 |
+ |
|
19 |
+ <!-- CSS |
|
20 |
+ ================================================== --> |
|
21 |
+ <link rel="stylesheet" href="static/stylesheets/base.css"> |
|
22 |
+ <link rel="stylesheet" href="static/stylesheets/skeleton.css"> |
|
23 |
+ <link rel="stylesheet" href="static/stylesheets/layout.css"> |
|
24 |
+ <link rel="stylesheet" href="static/stylesheets/mystyles.css"> |
|
25 |
+ |
|
26 |
+ <!--[if lt IE 9]> |
|
27 |
+ <script src="http://html5shim.googlecode.com/svn/trunk/html5.js"></script> |
|
28 |
+ <![endif]--> |
|
29 |
+ |
|
30 |
+ <!-- Favicons |
|
31 |
+ ================================================== --> |
|
32 |
+ <link rel="shortcut icon" href="static/images/favicon.ico"> |
|
33 |
+ <link rel="apple-touch-icon" href="static/images/apple-touch-icon.png"> |
|
34 |
+ <link rel="apple-touch-icon" sizes="72x72" href="static/images/apple-touch-icon-72x72.png"> |
|
35 |
+ <link rel="apple-touch-icon" sizes="114x114" href="static/images/apple-touch-icon-114x114.png"> |
|
36 |
+ |
|
37 |
+ <style type="text/css"> |
|
38 |
+ h1 { |
|
39 |
+ text-align: center; |
|
40 |
+ } |
|
41 |
+ |
|
42 |
+ h4 { |
|
43 |
+ padding: 0.3em |
|
44 |
+ } |
|
45 |
+ |
|
46 |
+ p.entry { |
|
47 |
+ vertical-align: middle; |
|
48 |
+ padding: 0.25em 1em; |
|
49 |
+ padding-right: 0.5em; |
|
50 |
+ margin: 0em; |
|
51 |
+ } |
|
52 |
+ |
|
53 |
+ hr { |
|
54 |
+ margin: 0em 0em; |
|
55 |
+ margin-bottom: 0.5em; |
|
56 |
+ } |
|
57 |
+ |
|
58 |
+ section { |
|
59 |
+ min-height: 20em; |
|
60 |
+ } |
|
61 |
+ |
|
62 |
+ b { |
|
63 |
+ font-weight: bold; |
|
64 |
+ } |
|
65 |
+ |
|
66 |
+ .hil { |
|
67 |
+ background: hsl(60, 25%, 98%); |
|
68 |
+ } |
|
69 |
+ </style> |
|
70 |
+ |
|
71 |
+</head> |
|
72 |
+<body> |
|
73 |
+ |
|
74 |
+ |
|
75 |
+ |
|
76 |
+ <!-- Primary Page Layout |
|
77 |
+ ================================================== --> |
|
78 |
+ |
|
79 |
+ <!-- Delete everything in this .container and get started on your own site! --> |
|
80 |
+ |
|
81 |
+ <h1>My Links</h1> |
|
82 |
+ <div class="container"> |
|
83 |
+ {% for column in columns %} |
|
84 |
+ <section class="one-third column"> |
|
85 |
+ {% for title, link, sep, blog_title,img in column %} |
|
86 |
+ {% if blog_title %}<h4>{%else%}<p class='entry {{ loop.cycle('','hil') }}'>{%endif%} |
|
87 |
+ <a href="{{url_for('ope', url=link)}}">{{title}}</a> |
|
88 |
+ {% if blog_title %}</h4>{%else%}<p>{%endif%} |
|
89 |
+ {% if sep %}<hr /> |
|
90 |
+ {% endif %} |
|
91 |
+ {% endfor %} |
|
92 |
+ </section> |
|
93 |
+ {% endfor %} |
|
94 |
+ </div><!-- container --> |
|
95 |
+ |
|
96 |
+ |
|
97 |
+<!-- End Document |
|
98 |
+================================================== --> |
|
99 |
+</body> |
|
100 |
+</html> |
|
101 |
+ |
0 | 102 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,10 @@ |
1 |
+# Links |
|
2 |
+ |
|
3 |
+{% for column in columns %} |
|
4 |
+ {% for title, link, sep, blog_title, img in column %} |
|
5 |
+{% if blog_title %}## {{title | mesc}} -- <{{link}}> |
|
6 |
+{% else %}- {{title | mesc}} -- <{{link}}>{%endif%}{% if sep %} |
|
7 |
+ |
|
8 |
+ |
|
9 |
+{% endif %}{% endfor %} |
|
10 |
+{% endfor %} |
0 | 11 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,13 @@ |
1 |
+<html> |
|
2 |
+ <head> |
|
3 |
+ <title>Document Title</title> |
|
4 |
+ <link rel="stylesheet" href="static/stylesheets/base.css"> |
|
5 |
+ </head> |
|
6 |
+ <body style="margin: 0px !important"> |
|
7 |
+ <div style="margin:auto auto;width:10em;text-align:center;height:100%"> |
|
8 |
+ <a href="/" target="_top" style="color:olive;vertial-align:middle">Home</a> |
|
9 |
+ <a href="{{url}}" style="color:olive;vertial-align:middle" target="_top">Linked Page</a> |
|
10 |
+ </div> |
|
11 |
+ </body> |
|
12 |
+</html> |
|
13 |
+ |
0 | 14 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,75 @@ |
1 |
+import re |
|
2 |
+import time |
|
3 |
+import collections |
|
4 |
+import urllib.request |
|
5 |
+import urllib.parse |
|
6 |
+import feedparser |
|
7 |
+import json |
|
8 |
+ |
|
9 |
+def urlopen(url): |
|
10 |
+ headers = {'User-Agent': "the/edgent"} |
|
11 |
+ req = urllib.request.Request(url, headers=headers) |
|
12 |
+ return urllib.request.urlopen(req) |
|
13 |
+ |
|
14 |
+class URLHandler(object): |
|
15 |
+ registry = collections.OrderedDict() |
|
16 |
+ |
|
17 |
+ @classmethod |
|
18 |
+ def register(cls, pattern): |
|
19 |
+ def _inner(ncls): |
|
20 |
+ cls.registry[re.compile(pattern)] = ncls |
|
21 |
+ return ncls |
|
22 |
+ return _inner |
|
23 |
+ |
|
24 |
+ @classmethod |
|
25 |
+ def handle(cls, url, **args): |
|
26 |
+ print(args) |
|
27 |
+ for x in reversed(cls.registry): |
|
28 |
+ if x.match(url): |
|
29 |
+ return cls.registry[x](url).run(url, **args) |
|
30 |
+ |
|
31 |
+ def __init__(self, url): |
|
32 |
+ self.url = url |
|
33 |
+ |
|
34 |
+ def run(self, url, **args): |
|
35 |
+ data = self.get_data(url, **args) |
|
36 |
+ return self.postprocess(data) |
|
37 |
+ |
|
38 |
+ def get_data(self, url, **args): return urlopen(url) |
|
39 |
+ def postprocess(self, result): return result |
|
40 |
+ |
|
41 |
+@URLHandler.register('.') |
|
42 |
+class BasicHandler(URLHandler): |
|
43 |
+ def get_data(self, url, **args): |
|
44 |
+ return feedparser.parse(self.url, **args) |
|
45 |
+ |
|
46 |
+@URLHandler.register(r'^http[s]?://(www\.)?reddit.com/r/[^/]*/$') |
|
47 |
+class RedditJSONHandler(URLHandler): |
|
48 |
+ def get_data(self, url, **args): |
|
49 |
+ result = urlopen('%s.json' % url) |
|
50 |
+ result = result.read().decode(result.headers.get_content_charset()) |
|
51 |
+ return json.loads(result) |
|
52 |
+ def postprocess(self, data): |
|
53 |
+ result = feedparser.FeedParserDict() |
|
54 |
+ desc = urllib.parse.urljoin(self.url, 'about.json') |
|
55 |
+ desc = urlopen(desc) |
|
56 |
+ desc = json.loads(desc.read().decode(desc.headers.get_content_charset()))['data'] |
|
57 |
+ |
|
58 |
+ result['feed'] = feedparser.FeedParserDict() |
|
59 |
+ result.feed['title'] = desc['title'] |
|
60 |
+ result.feed['link'] = 'http://reddit.com/%s' % desc['url'] |
|
61 |
+ result['entries'] = [] |
|
62 |
+ result.etag = None |
|
63 |
+ result.modified = None |
|
64 |
+ result.status = 200 |
|
65 |
+ |
|
66 |
+ for x in data['data']['children']: |
|
67 |
+ result.entries.append(feedparser.FeedParserDict()) |
|
68 |
+ dat = x['data'] |
|
69 |
+ result.entries[-1]['title'] = dat['title'] |
|
70 |
+ result.entries[-1]['link'] = dat['url'] |
|
71 |
+ result.entries[-1]['published_parsed'] = time.gmtime(dat['created_utc']) |
|
72 |
+ result.entries[-1]['id'] = dat['id'] |
|
73 |
+ |
|
74 |
+ return result |
|
75 |
+ |