diff --git a/.gitignore b/.gitignore new file mode 100644 --- /dev/null +++ b/.gitignore @@ -0,0 +1,8 @@ +.bundle/ +.jekyll-cache/ +.jekyll-metadata +planet.db +_posts/ +.sass-cache/ +_site/ +vendor/ diff --git a/Gemfile b/Gemfile new file mode 100644 --- /dev/null +++ b/Gemfile @@ -0,0 +1,9 @@ +source "https://rubygems.org" +gem 'jekyll' +gem 'pluto' +gem 'pluto-models' +gem 'nokogiri' +gem 'faraday' +gem 'rake' +gem 'jekyll-paginate-v2' +gem "jekyll-kde-theme", :git => 'https://invent.kde.org/websites/jekyll-kde-theme.git' diff --git a/Gemfile.lock b/Gemfile.lock new file mode 100644 --- /dev/null +++ b/Gemfile.lock @@ -0,0 +1,169 @@ +GIT + remote: https://invent.kde.org/websites/jekyll-kde-theme.git + revision: c2ad1f31702d3865d9ab55a46f005e7b8ef2e742 + specs: + jekyll-kde-theme (0.4.0) + jekyll (~> 3.8) + jekyll-paginate + +GEM + remote: https://rubygems.org/ + specs: + activemodel (6.0.2.1) + activesupport (= 6.0.2.1) + activerecord (6.0.2.1) + activemodel (= 6.0.2.1) + activesupport (= 6.0.2.1) + activerecord-utils (0.4.1) + activerecord + logutils + activesupport (6.0.2.1) + concurrent-ruby (~> 1.0, >= 1.0.2) + i18n (>= 0.7, < 2) + minitest (~> 5.1) + tzinfo (~> 1.1) + zeitwerk (~> 2.2) + activityutils (0.1.2) + logutils (>= 0.6.1) + addressable (2.7.0) + public_suffix (>= 2.0.2, < 5.0) + colorator (1.1.0) + concurrent-ruby (1.1.6) + date-formatter (0.1.1) + em-websocket (0.5.1) + eventmachine (>= 0.12.9) + http_parser.rb (~> 0.6.0) + eventmachine (1.2.7) + faraday (1.0.0) + multipart-post (>= 1.2, < 3) + feedfilter (1.1.1) + textutils (>= 1.0.1) + feedparser (2.1.2) + logutils (>= 0.6.1) + textutils (>= 1.0.0) + fetcher (0.4.5) + logutils (>= 0.6) + ffi (1.12.2) + forwardable-extended (2.6.0) + gli (2.19.0) + http_parser.rb (0.6.0) + i18n (0.9.5) + concurrent-ruby (~> 1.0) + iniparser (1.0.1) + jekyll (3.8.6) + addressable (~> 2.4) + colorator (~> 1.0) + em-websocket (~> 0.5) + i18n (~> 0.7) + jekyll-sass-converter (~> 1.0) + jekyll-watch (~> 2.0) + kramdown (~> 1.14) + liquid (~> 4.0) + mercenary (~> 0.3.3) + pathutil (~> 0.9) + rouge (>= 1.7, < 4) + safe_yaml (~> 1.0) + jekyll-paginate (1.1.0) + jekyll-paginate-v2 (3.0.0) + jekyll (>= 3.0, < 5.0) + jekyll-sass-converter (1.5.2) + sass (~> 3.4) + jekyll-watch (2.2.1) + listen (~> 3.0) + kramdown (1.17.0) + liquid (4.0.3) + listen (3.2.1) + rb-fsevent (~> 0.10, >= 0.10.3) + rb-inotify (~> 0.9, >= 0.9.10) + logutils (0.6.1) + logutils-activerecord (0.2.1) + activerecord + logutils (>= 0.6.1) + mercenary (0.3.6) + mini_portile2 (2.4.0) + minitest (5.14.0) + multipart-post (2.1.1) + nokogiri (1.10.9) + mini_portile2 (~> 2.4.0) + pakman (1.1.0) + fetcher (>= 0.4.5) + liquid (>= 4.0.0) + logutils (>= 0.6.1) + pathutil (0.16.2) + forwardable-extended (~> 2.6) + pluto (1.3.4) + gli (>= 2.12.2) + pluto-merge (>= 1.1.0) + pluto-models (>= 1.5.4) + pluto-tasks (>= 1.5.3) + pluto-update (>= 1.6.3) + sqlite3 + pluto-feedfetcher (0.1.4) + fetcher (>= 0.4.5) + pluto-models (>= 1.5.4) + pluto-merge (1.1.0) + fetcher (>= 0.4.4) + pakman (>= 0.5.0) + pluto-models (>= 1.2.2) + pluto-models (1.6.1) + activerecord + activerecord-utils (>= 0.4.0) + activityutils (>= 0.1.1) + date-formatter (>= 0.1.1) + feedfilter (>= 1.1.1) + feedparser (>= 2.1.2) + logutils (>= 0.6.1) + logutils-activerecord (>= 0.2.1) + props (>= 1.2.0) + props-activerecord (>= 0.2.0) + textutils (>= 1.4.0) + pluto-tasks (1.5.3) + pluto-models (>= 1.4.0) + pluto-update (>= 1.6.0) + pluto-update (1.6.3) + pluto-feedfetcher (>= 0.1.4) + pluto-models (>= 1.5.4) + props (1.2.0) + iniparser (>= 0.1.0) + props-activerecord (0.2.0) + activerecord + props (>= 1.2.0) + public_suffix (4.0.3) + rake (13.0.1) + rb-fsevent (0.10.3) + rb-inotify (0.10.1) + ffi (~> 1.0) + rouge (3.16.0) + rubyzip (2.2.0) + safe_yaml (1.0.5) + sass (3.7.4) + sass-listen (~> 4.0.0) + sass-listen (4.0.0) + rb-fsevent (~> 0.9, >= 0.9.4) + rb-inotify (~> 0.9, >= 0.9.7) + sqlite3 (1.4.2) + textutils (1.4.0) + activesupport + logutils (>= 0.6.1) + props (>= 1.1.2) + rubyzip (>= 1.0.0) + thread_safe (0.3.6) + tzinfo (1.2.6) + thread_safe (~> 0.1) + zeitwerk (2.3.0) + +PLATFORMS + ruby + +DEPENDENCIES + faraday + jekyll + jekyll-kde-theme! + jekyll-paginate-v2 + nokogiri + pluto + pluto-models + rake + +BUNDLED WITH + 2.1.0 diff --git a/README b/README deleted file mode 100644 --- a/README +++ /dev/null @@ -1,164 +0,0 @@ -Planet KDE uses rawdog - -To add your blog edit planetkde/config and add your photo head to website/hackergotchi/myname.png - -To run locally edit planetkde/config and set outputfile and outputxml to the right directory. - -Run it with - - ./rawdog -d planetkde --update - ./rawdog -d planetkde --write - -will write to website/index.html and website/rss20.xml - -Jonathan Riddell, 10-2008 - ---- - -rawdog: RSS Aggregator Without Delusions Of Grandeur -Adam Sampson - -rawdog is an RSS (and other) feed aggregator, based on Mark Pilgrim's flexible -feed parser. It's just an aggregator; it's not a weblog authoring tool, nor is -it an NNTP gateway, outliner, mailserver or anything else. rawdog probably -only runs on Unix-like systems. - -(Important: If you're upgrading from rawdog 1.x to rawdog 2.x, please -read the NEWS file to find out how to convert your rawdog state file.) - -rawdog requires Python 2.2 or later. rawdog itself doesn't need any -additional modules to be installed, but it uses distutils for -installation, so if you're on a Debian system you'll need to install the -"python-dev" package first. - -rawdog reads articles from a number of feeds and writes out a single -HTML file, based on a template either provided by the user or generated -by rawdog, containing the latest articles it's seen. It uses the ETags -and Last-Modified headers to avoid fetching a file that hasn't changed, -and supports gzip compression to reduce bandwidth when it has. It is -configured from a simple text file; the only state kept between -invocations that can't be reconstructed from the feeds is the ordering -of articles. - -To install rawdog on your system, use distutils -- "python setup.py install". -This will install the library modules that rawdog needs, and will install the -"rawdog" binary that you can use to run it. (If you want to install to a -non-standard prefix, read the help provided by "python setup.py install ---help".) - -rawdog needs a config file to function. Make the directory ".rawdog" in your -$HOME directory, copy the provided file "config" into that directory, and edit -it to suit your preferences. (Comments in that file describe what each of the -options does.) You should copy the provided file "style.css" into the same -directory that you've told rawdog to write its HTML output to. (rawdog should -be usable from a browser that doesn't support CSS, but it won't be very -pretty.) - -When you invoke rawdog from the command line, you give it a series of actions -to perform -- for instance, "rawdog --update --write" tells it to do the -"--update" action, then the "--write" action. The actions supported are -as follows: - -"--update" (or "-u"): Fetch data from the feeds and store it. This could -take some time if you've got lots of feeds. - -"--write" (or "-w"): Write out the HTML output file. - -"--list" (or "-l"): List brief information about each of the feeds that -was known about when "--update" was last done. - -"--update-feed SOMEURL" (or "-f SOMEURL"), where SOMEURL is the URL of a -known feed: Update that feed immediately, even if its period hasn't -elapsed since it was last updated. This is useful if you're trying to -debug your own feed. - -"--config FILE" (or "-c FILE"), where FILE is an absolute path or a path -relative to your .rawdog directory: Read FILE as an additional config -file; any options provided in FILE will override those already set in -the main config file (with the exception of "feed", which is -cumulative). Note that $HOME/.rawdog/config will still be read first -even if you specify this option. This is useful if you want rawdog to -write two different output files with different sets of options ("rawdog --u -w -c config2 -w" will first update and write with the main config -file, then read config2, then write again). - -"--show-template" (or "-t"): Print the template currently in use to -stdout. This is useful as a starting point if you want to modify your -own template: do "rawdog -t >~/.rawdog/mytemplate" with "template -default" in your config file, and you'll get a copy of the default -template to edit. - -"--show-itemtemplate" (or "-T"): As for "--show-template", but for the -item template. - -"--add URL" (or "-a URL"): Add a new feed to the config file. This uses -Mark Pilgrim's "feedfinder" module to try to figure out a feed for any -given URL, so you can usually just give it the URL of a blog's main -page, and it'll automatically detect the appropriate feed. (It'll tell -you if it can't guess a feed for the URL you give it.) - -There are also the following options which may only be supplied once -(they're read before any of the actions are performed): - -"--help": Provide a brief summary of all the options rawdog supports, -and exit. - -"--dir DIR" (or "-d DIR"), where DIR is a directory: Use DIR instead of -the $HOME/.rawdog directory. This is useful if you want to have two or -more completely different rawdog setups with different sets of feeds; -just create a directory for each. - -"--verbose" (or "-v"): Print more information about what rawdog's doing -while it's working. This is useful for tracking down problems. - -"--no-locking" (or "-N"): Don't attempt to lock the state file. rawdog -usually claims a lock on the state file so that you can't have more than -one instance of rawdog running at the same time. Unfortunately, some -operating systems and filesystems don't support file locking; you can -use this option to disable locking if you're in that situation. - -"--no-lock-wait" (or "-W"): If the state file lock can't be claimed -immediately, exit silently. Normally, rawdog will wait until it can -claim the lock, then run as usual; however, if you've got a very large -number of feeds and a slow machine or network connection, and you run -rawdog periodically from cron, then you may find you often have a number -of rawdog processes competing for the lock. In that situation, use this -option so that you've really only ever got one rawdog process running at -once. - -"--upgrade OLDDIR NEWDIR": This option can be used to convert your state -file when upgrading from rawdog 1.x to rawdog 2.x; see the NEWS file for -more information. If you're not doing this, then it won't be of any use -to you. - -You will want to run "rawdog -uw" periodically to fetch data and write -the output file. The easiest way to do this is to add a crontab entry -that looks something like this: - -0,10,20,30,40,50 * * * * /path/to/rawdog -uw - -(If you don't know how to use cron, then "man crontab" is probably a good -start.) This will run rawdog every ten minutes. - -If you want rawdog to fetch URLs through a proxy server, then set your -"http_proxy" environment variable appropriately; depending on your version of -cron, putting something like: - -http_proxy=http://myproxy.mycompany.com:3128/ - -at the top of your crontab should be appropriate. (The http_proxy variable will -work for many other programs too.) - -In the event that rawdog gets horribly confused (for instance, if your system -clock has a huge jump and it thinks it won't need to fetch anything for the -next thirty years), you can forcibly clear its state by removing the -~/.rawdog/state file (and the ~/.rawdog/feeds/*.state files, if you've -got the "splitstate" option turned on). - -If you don't like the appearance of rawdog, then customise the style.css file. -If you come up with one that looks much better than the existing one, please -send it to me! - -This should, hopefully, be all you need to know. If rawdog breaks in -interesting ways, please tell me at the email address at the top of this file. - diff --git a/README.md b/README.md new file mode 100644 --- /dev/null +++ b/README.md @@ -0,0 +1,84 @@ +# 🌎 [Planet KDE](https://planet.kde.org) + +Planet KDE is a web feed aggregator that collects blog posts from people who contribute to KDE. + +If you are a KDE contributor you can have your blog on Planet KDE. Blog content should be mostly +KDE themed and not liable to offend. If you have a general blog you may want to set up a tag and +subscribe the feed for that tag only to Planet KDE. + +## Adding your feed +If you want to get your feed added, we prefer Merge Requests via [invent.kde.org](https://invent.kde.org/websites/planet-kde-org). + +* Fork this repository +* Edit [planet.ini](https://invent.kde.org/websites/planet-kde-org/tree/master/planet.ini) and add: + +```ini +[id] # replace id with your feed's unique identifier (a-z0-9-_) (eg. kde-dot) + title = # title of your feed (eg. KDE Dot) + feed = # url to your rss/atom feed (eg. https://dot.kde.org/rss.xml) + link = # link to the main page of your website (eg. https://dot.kde.org) + location = # two letter language code (eg. en) + avatar = # (optional) filename or url of your avatar (eg. kde.png) + author = # (optional) includes various space separated tags about the author: + # irc:freenode_nickname (eg. irc:myircnickname) + # gsoc +``` + +* Upload your avatar to [hackergotchi directory](https://invent.kde.org/websites/planet-kde-org/tree/master/hackergotchi) +* Send a Pull Request + +If you do not have a Git account, file +a bug in Bugzilla listing your name, Git account (if you have one), IRC nick (if you have one), RSS or +Atom feed and what you do in KDE. Attach a photo of your face for hackergotchi. + +## Planet KDE Guidelines + +Planet KDE is one of the public faces of the KDE project and is read by millions of users and potential +contributors. The content aggregated at Planet KDE is the opinions of its authors, but the sum of that +content gives an impression of the project. Please keep in mind the following guidelines for your blog +content and read the [KDE Code of Conduct](https://www.kde.org/code-of-conduct/). The KDE project +reserves the right to remove an inappropriate blog from the Planet. If that happens multiple times, the +Community Working Group can be asked to consider what needs to happen to get your blog aggregated again. + +If you are unsure or have queries about what is appropriate contact the KDE Community Working Group. + +### Blogs should be KDE themed + +The majority of content in your blog should be about KDE and your work on KDE. Blog posts about personal +subjects are also encouraged since Planet KDE is a chance to learn more about the developers behind KDE. +However blog feeds should not be entirely personal, if in doubt set up a tag for Planet KDE and subscribe +the feed from that tag so you can control what gets posted. + +### Posts should be constructive + +Posts can be positive and promote KDE, they can be constructive and lay out issues which need to be +addressed, but blog feeds should not contain useless, destructive and negative material. Constructive +criticism is welcome and the occasional rant is understandable, but a feed where every post is critical +and negative is unsuitable. This helps to keep KDE overall a happy project. + +### You must be a KDE contributor + +Only have your blog on Planet KDE if you actively contribute to KDE, for example through code, user +support, documentation etc. + +### It must be a personal blog, or in a blog class + +Planet KDE is a collection of blogs from KDE contributors. + +### Do not inflame + +KDE covers a wide variety of people and cultures. Profanities, prejudice, lewd comments and content +likely to offend are to be avoided. Do not make personal attacks or attacks against other projects on +your blog. + +For further guidance on good practice see the KDE Code of Conduct. + +## Development environment +To run this website locally, use the following commands: +```sh +bundler install +bundler exec rake build +bundler exec jekyll serve +``` +and visit [127.0.0.1:4000](http://127.0.0.1:4000) + diff --git a/Rakefile b/Rakefile new file mode 100644 --- /dev/null +++ b/Rakefile @@ -0,0 +1,11 @@ +task default: %w[build] + +task :build do + system 'pluto update planet.ini' + ruby 'bin/jekyll-planet.rb' + sh "for post in _posts/*; do sed -i '/title:/s/\\\\o/\\\\\\o/g' \"$post\"; done" +end + +task :test do + ruby 'tests/feedcheck.rb' +end diff --git a/_config.yml b/_config.yml new file mode 100644 --- /dev/null +++ b/_config.yml @@ -0,0 +1,51 @@ +title: Planet KDE +email: kde-www@kde.org +description: >- + Planet KDE site providing newest news from the KDE Project +baseurl: "" +url: "https://planet.kde.org" +sourcecode: "https://invent.kde.org/websites/planet-kde-org" + +markdown: kramdown +plugins: + - jekyll-paginate-v2 + +autopages: + enabled: true + collections: + enabled: false + categories: + enabled: false + tags: + layouts: + - 'language.html' + title: ':tag' + permalink: '/:tag' + +defaults: + - + scope: + path: "" # an empty string here means all files in the project + values: + layout: "post" + +theme: jekyll-kde-theme +sass: + style: compressed + +pagination: + enabled: true + per_page: 10 + permalink: '/:num/' + sort_reverse: true + sort_field: 'created_at' + trail: + before: 2 + after: 2 + +exclude: [README.md, Gemfile, Gemfile.lock, planet.ini, planet.db, LICENSE, vendor, tests, bin, Rakefile] + +navigation: {} + +not_made_by_kde: true +use-kde-logo: true diff --git a/_data/language.yml b/_data/language.yml new file mode 100644 --- /dev/null +++ b/_data/language.yml @@ -0,0 +1,36 @@ +en: + name: English + img: en.svg +pl: + name: Polish + img: pl.svg +fr: + name: French + img: fr.svg +es: + name: Spanish + img: es.svg +de: + name: German + img: de.svg +cs: + name: Czech + img: cs.svg +gr: + name: Greek + img: gr.svg +id: + name: Indonesian + img: id.svg +ja: + name: Japanese + img: ja.svg +tw: + name: Taiwanese + img: tw.svg +pt: + name: Portugese + img: pt.svg +ru: + name: Russian + img: ru.svg diff --git a/_includes/avatar.html b/_includes/avatar.html new file mode 100644 diff --git a/_includes/calendar.html b/_includes/calendar.html new file mode 100644 --- /dev/null +++ b/_includes/calendar.html @@ -0,0 +1,8 @@ +{% if post.previous == false or post.previous.date != post.date %} +
+
+

{{ post.date | date: "%A" }}

+

{{ post.date | date: "%-d %B, %Y" }}

+
+
+{% endif %} diff --git a/_includes/main-info.html b/_includes/main-info.html new file mode 100644 --- /dev/null +++ b/_includes/main-info.html @@ -0,0 +1,32 @@ + +
+
+
+ + + +
+
+
+ Planet KDE logo +
+
+

Welcome to Planet KDE

+
This is a feed aggregator that collects what the contributors to the KDE Project are writing on their respective blogs
+
+
+ {% assign sorted = site.tags | sort %} + {% for tag in sorted %} + {% assign lang = site.data.language[tag.first] %} + {{ lang.name }} + {% endfor %} + Mastodon + r/kde +
+
+
+
+
+
To have your blog added to this aggregator, please read the instructions +
+
diff --git a/_includes/pagination.html b/_includes/pagination.html new file mode 100644 --- /dev/null +++ b/_includes/pagination.html @@ -0,0 +1,51 @@ +{% if paginator.total_pages > 1 %} +
+ +
+{% endif %} diff --git a/_includes/single-post.html b/_includes/single-post.html new file mode 100644 --- /dev/null +++ b/_includes/single-post.html @@ -0,0 +1,31 @@ +{% assign lang = site.data.language[post.tags.first] %} +
+
+
+
+
+
+ +
+

+ {{ post.title }} +

+ + {{ post.author }} + posted at + {{ post.created_at | date: "%H:%M" }} + {% if post.irc %} + {{ post.irc }} + {% endif %} + +
+ +
+
+
+
+ {{ post.content }} +
+
+
+
diff --git a/_layouts/atom.xml b/_layouts/atom.xml new file mode 100644 --- /dev/null +++ b/_layouts/atom.xml @@ -0,0 +1,32 @@ +--- +--- + +{% assign lang = site.data.language[page.title] %} + + + Planet KDE + Planet KDE{% if lang.name %} | {{ lang.name }}{% endif %} + {{ site.baseurl }}/images/planet.svg + {{ site.baseurl }}/images/planet.svg + + {{ site.time | date_to_xmlschema }} + https://planet.kde.org/ + Pluto +{% for post in paginator.posts %} + + {{ post.guid }} + + {{ post.author }} + {{ post.link }} + + {{ post.created_at | date_to_xmlschema }} + {{ post.updated_at | date_to_xmlschema }} + {{ post.title | xml_escape }} + {% if post.summary %} + {{ post.summary | xml_escape }} + {% endif %} + + {{ post.content | xml_escape }} + +{% endfor %} + diff --git a/_layouts/index.html b/_layouts/index.html new file mode 100644 --- /dev/null +++ b/_layouts/index.html @@ -0,0 +1,13 @@ +--- +layout: default +language: true +--- + + +
+ {% for post in paginator.posts %} + {% include calendar.html %} + {% include single-post.html %} + {% endfor %} + {% include pagination.html %} +
diff --git a/_layouts/language.html b/_layouts/language.html new file mode 100644 --- /dev/null +++ b/_layouts/language.html @@ -0,0 +1,30 @@ +--- +layout: default +language: true +--- + + +{%- if page.language -%} + {% assign lang = site.data.language[page.title] %} +
+ +
+{%- endif -%} + +
+ {% for post in paginator.posts %} + {% include calendar.html %} + {% include single-post.html %} + {% endfor %} + {% include pagination.html %} +
diff --git a/_layouts/rss20.xml b/_layouts/rss20.xml new file mode 100644 --- /dev/null +++ b/_layouts/rss20.xml @@ -0,0 +1,20 @@ +--- +--- +{% assign lang = site.data.language[page.title] %} + + + Planet KDE + https://planet.kde.org{% if lang.name %}/{{ page.title }}{% endif %} + Planet KDE{% if lang.name %} | {{ lang.name }}{% endif %} + +{% for post in paginator.posts %} + + {{ post.guid }} + {{ post.title | xml_escape }} + {{ post.created_at }} + {{ post.original_link }} + {{ post.content | xml_escape }} + +{% endfor %} + + diff --git a/_plugins/tag_indexes.rb b/_plugins/tag_indexes.rb new file mode 100644 --- /dev/null +++ b/_plugins/tag_indexes.rb @@ -0,0 +1,29 @@ +Jekyll::Hooks.register :site, :post_read do |site| + site.posts.docs.map { |p| p.data['tags'] }.reduce(&:|)&.each do |tag| + site.pages << TagFeed.new(site, site.source, tag, 'rss20', '.xml', 1) + site.pages << TagFeed.new(site, site.source, tag, 'atom', '.xml', 1) + # This will not be needed when the autopages are fixed + site.pages << TagFeed.new(site, site.source, tag, 'index', '.html', 0) + end +end + +class TagFeed < Jekyll::Page + def initialize(site, base, tag, feed, ext, limit) + @site = site + @name = "_layouts/#{feed}#{ext}" + @ext = ext + + self.read_yaml(File.join(base, '_layouts'), "#{feed}#{ext}") + self.data['layout'] = feed + self.data['permalink'] = "/#{Jekyll::Utils.slugify(tag)}/#{feed + ext unless limit != 1}" + self.data['title'] = tag + self.data['pagination'] = { + 'enabled' => true, + 'sort_field' => 'created_at', + 'sort_reverse' => true, + 'tag' => tag, + 'limit' => limit, + 'title' => ':title' + } + end +end diff --git a/assets/img/planetkde.svg b/assets/img/planetkde.svg new file mode 100644 --- /dev/null +++ b/assets/img/planetkde.svg @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/atom.xml b/atom.xml new file mode 100644 --- /dev/null +++ b/atom.xml @@ -0,0 +1,10 @@ +--- +layout: atom +permalink: /global/atom.xml +pagination: + enabled: true + collection: posts + sort_field: date + sort_reverse: true + limit: 1 +--- diff --git a/bin/jekyll-planet.rb b/bin/jekyll-planet.rb new file mode 100644 --- /dev/null +++ b/bin/jekyll-planet.rb @@ -0,0 +1,100 @@ +# encoding: utf-8 +require 'pluto/models' +require 'nokogiri' + +puts "db settings:" +@db_config = { + adapter: 'sqlite3', + database: './planet.db' +} + +pp @db_config + + +def run( args ) + unless File.exists?( @db_config[:database]) + puts "** error: database #{@db_config[:database]} missing; please check pluto documention for importing feeds etc." + exit 1; + end + + Pluto.connect( @db_config ) + + Pluto::Model::Item.latest.where.not(title: '', published: nil).limit(1000).each_with_index do |item,i| + puts "[#{i+1}] #{item.title}" + + generate_blog_post( item ) + end +end + +def generate_frontmatter( data ) + + frontmatter = '' + data.each do |key, value| + spaces = ' ' * (data.keys.map(&:length).max + 1 - key.length) unless value.is_a?(Array) + output = value + output = "\"#{value}\"" if value.is_a?(String) + output = "\n - \"#{value.join("\"\n - \"")}\"" if value.is_a?(Array) + frontmatter += "#{key}:#{spaces}#{output}\n" + end + frontmatter + +end + +def generate_blog_post( item ) + + posts_root = "./_posts" + + FileUtils.mkdir_p( posts_root ) ## make sure path exists + + ## Note: + ## Jekyll pattern for blogs must follow + ## 2014-12-21- e.g. must include trailing dash (-) + fn = "#{posts_root}/#{item.published.strftime('%Y-%m-%d')}-#{item.title.parameterize}.html" + # Check for author tags + + data = {} + data["title"] = item.title.gsub('"','\"') unless item.title.empty? + data["created_at"] = item.published if item.published + data["updated_at"] = item.updated if item.updated + data["guid"] = item.guid unless item.guid.empty? + data["author"] = item.feed.title unless item.feed.title.empty? + data["avatar"] = item.feed.avatar if item.feed.avatar + data["link"] = item.feed.link unless item.feed.link.empty? + data["rss"] = item.feed.feed unless item.feed.feed.empty? + data["tags"] = [ item.feed.location ? item.feed.location : "en" ] + data["original_link"] = item.url if item.url + item.feed.author.split.each do |contact| + if contact.include?(':') + part = contact.split(':') + data[part.shift] = part.join(':') + else + data[contact] = true + end + end if item.feed.author + frontmatter = generate_frontmatter(data) + + File.open( fn, 'w' ) do |f| + f.write "---\n" + f.write frontmatter + f.write "---\n" + + # There were a few issues of incomplete html documents, nokogiri fixes that + html = "" + if item.content + html = Nokogiri::HTML::DocumentFragment.parse(item.content).to_html + elsif item.summary + html = Nokogiri::HTML::DocumentFragment.parse(item.summary).to_html + else + ## warn: not content found for feed + end + # Liquid complains about curly braces + html.gsub!("{", "{") + html.gsub!("{", "}") + html.gsub!(/(?<=src=[\"\'])\/(?!\/)/, "#{/\/\/.*?(?=\/|$)/.match(item.feed.link)[0]}/") + html.gsub!(/(?<=src=[\"\'])https?:/, "") + f.write html + end +end + +run( ARGV ) + diff --git a/css/main.scss b/css/main.scss new file mode 100644 --- /dev/null +++ b/css/main.scss @@ -0,0 +1,29 @@ +--- +# Only the main Sass file needs front matter (the dashes are enough) +--- + +@charset "utf-8"; + +.markdown { + img { + max-width: 100%; + height: auto; + } + + h1 { + font-size: 1.5rem; + } + h2 { + font-size: 1.4rem; + } +} + +@media (prefers-color-scheme: dark) { + .bg-light { + background-color: rgba(0,0,0,.03) !important; + } + .breadcrumb-item.active { + color: white; + } +} + diff --git a/website/hackergotchi/.directory b/hackergotchi/.directory rename from website/hackergotchi/.directory rename to hackergotchi/.directory diff --git a/website/hackergotchi/Aarsee-Aeron.jpg b/hackergotchi/Aarsee-Aeron.jpg rename from website/hackergotchi/Aarsee-Aeron.jpg rename to hackergotchi/Aarsee-Aeron.jpg diff --git a/website/hackergotchi/Andreas-Kainz.jpg b/hackergotchi/Andreas-Kainz.jpg rename from website/hackergotchi/Andreas-Kainz.jpg rename to hackergotchi/Andreas-Kainz.jpg diff --git a/website/hackergotchi/Aniketh-Girish.jpg b/hackergotchi/Aniketh-Girish.jpg rename from website/hackergotchi/Aniketh-Girish.jpg rename to hackergotchi/Aniketh-Girish.jpg diff --git a/website/hackergotchi/Daniel-Pastushchak.png b/hackergotchi/Daniel-Pastushchak.png rename from website/hackergotchi/Daniel-Pastushchak.png rename to hackergotchi/Daniel-Pastushchak.png diff --git a/website/hackergotchi/Furkan-Tokac.png b/hackergotchi/Furkan-Tokac.png rename from website/hackergotchi/Furkan-Tokac.png rename to hackergotchi/Furkan-Tokac.png diff --git a/website/hackergotchi/Granjow.png b/hackergotchi/Granjow.png rename from website/hackergotchi/Granjow.png rename to hackergotchi/Granjow.png diff --git a/website/hackergotchi/Kshitij-Gupta.png b/hackergotchi/Kshitij-Gupta.png rename from website/hackergotchi/Kshitij-Gupta.png rename to hackergotchi/Kshitij-Gupta.png diff --git a/website/hackergotchi/Prakriti_Bhardwaj.jpg b/hackergotchi/Prakriti_Bhardwaj.jpg rename from website/hackergotchi/Prakriti_Bhardwaj.jpg rename to hackergotchi/Prakriti_Bhardwaj.jpg diff --git a/website/hackergotchi/Ranveer-Aggarwal.jpg b/hackergotchi/Ranveer-Aggarwal.jpg rename from website/hackergotchi/Ranveer-Aggarwal.jpg rename to hackergotchi/Ranveer-Aggarwal.jpg diff --git a/website/hackergotchi/RoneyGomes.jpg b/hackergotchi/RoneyGomes.jpg rename from website/hackergotchi/RoneyGomes.jpg rename to hackergotchi/RoneyGomes.jpg diff --git a/website/hackergotchi/Sai-Krishna.jpg b/hackergotchi/Sai-Krishna.jpg rename from website/hackergotchi/Sai-Krishna.jpg rename to hackergotchi/Sai-Krishna.jpg diff --git a/website/hackergotchi/Shivaraman-Aiyer.png b/hackergotchi/Shivaraman-Aiyer.png rename from website/hackergotchi/Shivaraman-Aiyer.png rename to hackergotchi/Shivaraman-Aiyer.png diff --git a/website/hackergotchi/Shubham.png b/hackergotchi/Shubham.png rename from website/hackergotchi/Shubham.png rename to hackergotchi/Shubham.png diff --git a/website/hackergotchi/Souvik-Das.jpg b/hackergotchi/Souvik-Das.jpg rename from website/hackergotchi/Souvik-Das.jpg rename to hackergotchi/Souvik-Das.jpg diff --git a/website/hackergotchi/Svyatoslav-Kuzmich.jpg b/hackergotchi/Svyatoslav-Kuzmich.jpg rename from website/hackergotchi/Svyatoslav-Kuzmich.jpg rename to hackergotchi/Svyatoslav-Kuzmich.jpg diff --git a/website/es/hackergotchi/TSDgeos.png b/hackergotchi/TSDgeos.png rename from website/es/hackergotchi/TSDgeos.png rename to hackergotchi/TSDgeos.png diff --git a/website/hackergotchi/Utkarsh-Simha.jpg b/hackergotchi/Utkarsh-Simha.jpg rename from website/hackergotchi/Utkarsh-Simha.jpg rename to hackergotchi/Utkarsh-Simha.jpg diff --git a/website/hackergotchi/Wolthera.png b/hackergotchi/Wolthera.png rename from website/hackergotchi/Wolthera.png rename to hackergotchi/Wolthera.png diff --git a/website/hackergotchi/aakriti-gotchi.png b/hackergotchi/aakriti-gotchi.png rename from website/hackergotchi/aakriti-gotchi.png rename to hackergotchi/aakriti-gotchi.png diff --git a/website/hackergotchi/abaecker.png b/hackergotchi/abaecker.png rename from website/hackergotchi/abaecker.png rename to hackergotchi/abaecker.png diff --git a/website/hackergotchi/abhijeet2096.png b/hackergotchi/abhijeet2096.png rename from website/hackergotchi/abhijeet2096.png rename to hackergotchi/abhijeet2096.png diff --git a/website/hackergotchi/abhimanyushekhawat.png b/hackergotchi/abhimanyushekhawat.png rename from website/hackergotchi/abhimanyushekhawat.png rename to hackergotchi/abhimanyushekhawat.png diff --git a/website/hackergotchi/abhishek.png b/hackergotchi/abhishek.png rename from website/hackergotchi/abhishek.png rename to hackergotchi/abhishek.png diff --git a/website/hackergotchi/abinader.png b/hackergotchi/abinader.png rename from website/hackergotchi/abinader.png rename to hackergotchi/abinader.png diff --git a/website/hackergotchi/ach.png b/hackergotchi/ach.png rename from website/hackergotchi/ach.png rename to hackergotchi/ach.png diff --git a/website/hackergotchi/aclemens.png b/hackergotchi/aclemens.png rename from website/hackergotchi/aclemens.png rename to hackergotchi/aclemens.png diff --git a/website/hackergotchi/acrouthamel.png b/hackergotchi/acrouthamel.png rename from website/hackergotchi/acrouthamel.png rename to hackergotchi/acrouthamel.png diff --git a/website/hackergotchi/adamc.jpg b/hackergotchi/adamc.jpg rename from website/hackergotchi/adamc.jpg rename to hackergotchi/adamc.jpg diff --git a/website/hackergotchi/adamrakowski.png b/hackergotchi/adamrakowski.png rename from website/hackergotchi/adamrakowski.png rename to hackergotchi/adamrakowski.png diff --git a/website/hackergotchi/ademmer.png b/hackergotchi/ademmer.png rename from website/hackergotchi/ademmer.png rename to hackergotchi/ademmer.png diff --git a/website/hackergotchi/adenilson-cavalcanti.png b/hackergotchi/adenilson-cavalcanti.png rename from website/hackergotchi/adenilson-cavalcanti.png rename to hackergotchi/adenilson-cavalcanti.png diff --git a/website/hackergotchi/aditya-dev-sharma.jpg b/hackergotchi/aditya-dev-sharma.jpg rename from website/hackergotchi/aditya-dev-sharma.jpg rename to hackergotchi/aditya-dev-sharma.jpg diff --git a/website/hackergotchi/aditya.jpg b/hackergotchi/aditya.jpg rename from website/hackergotchi/aditya.jpg rename to hackergotchi/aditya.jpg diff --git a/website/hackergotchi/adjam.png b/hackergotchi/adjam.png rename from website/hackergotchi/adjam.png rename to hackergotchi/adjam.png diff --git a/website/hackergotchi/adrianb.png b/hackergotchi/adrianb.png rename from website/hackergotchi/adrianb.png rename to hackergotchi/adrianb.png diff --git a/website/hackergotchi/adridg.png b/hackergotchi/adridg.png rename from website/hackergotchi/adridg.png rename to hackergotchi/adridg.png diff --git a/website/hackergotchi/afedoskin.png b/hackergotchi/afedoskin.png rename from website/hackergotchi/afedoskin.png rename to hackergotchi/afedoskin.png diff --git a/website/hackergotchi/afiestas.png b/hackergotchi/afiestas.png rename from website/hackergotchi/afiestas.png rename to hackergotchi/afiestas.png diff --git a/website/hackergotchi/ahmed-ghonim.png b/hackergotchi/ahmed-ghonim.png rename from website/hackergotchi/ahmed-ghonim.png rename to hackergotchi/ahmed-ghonim.png diff --git a/website/hackergotchi/ahoneybun.png b/hackergotchi/ahoneybun.png rename from website/hackergotchi/ahoneybun.png rename to hackergotchi/ahoneybun.png diff --git a/website/hackergotchi/ahuggel.png b/hackergotchi/ahuggel.png rename from website/hackergotchi/ahuggel.png rename to hackergotchi/ahuggel.png diff --git a/website/hackergotchi/akapustin.png b/hackergotchi/akapustin.png rename from website/hackergotchi/akapustin.png rename to hackergotchi/akapustin.png diff --git a/website/hackergotchi/akhilkgangadharan.png b/hackergotchi/akhilkgangadharan.png rename from website/hackergotchi/akhilkgangadharan.png rename to hackergotchi/akhilkgangadharan.png diff --git a/website/hackergotchi/akshaychd.png b/hackergotchi/akshaychd.png rename from website/hackergotchi/akshaychd.png rename to hackergotchi/akshaychd.png diff --git a/website/hackergotchi/akshayratan.png b/hackergotchi/akshayratan.png rename from website/hackergotchi/akshayratan.png rename to hackergotchi/akshayratan.png diff --git a/website/hackergotchi/akssps011.png b/hackergotchi/akssps011.png rename from website/hackergotchi/akssps011.png rename to hackergotchi/akssps011.png diff --git a/website/hackergotchi/akulichalexandr.png b/hackergotchi/akulichalexandr.png rename from website/hackergotchi/akulichalexandr.png rename to hackergotchi/akulichalexandr.png diff --git a/website/hackergotchi/alan-alvarez.png b/hackergotchi/alan-alvarez.png rename from website/hackergotchi/alan-alvarez.png rename to hackergotchi/alan-alvarez.png diff --git a/website/hackergotchi/alanpope.png b/hackergotchi/alanpope.png rename from website/hackergotchi/alanpope.png rename to hackergotchi/alanpope.png diff --git a/website/hackergotchi/albert-cervera-areny.png b/hackergotchi/albert-cervera-areny.png rename from website/hackergotchi/albert-cervera-areny.png rename to hackergotchi/albert-cervera-areny.png diff --git a/website/hackergotchi/alberto-mardegan.png b/hackergotchi/alberto-mardegan.png rename from website/hackergotchi/alberto-mardegan.png rename to hackergotchi/alberto-mardegan.png diff --git a/website/hackergotchi/albertoefg.png b/hackergotchi/albertoefg.png rename from website/hackergotchi/albertoefg.png rename to hackergotchi/albertoefg.png diff --git a/website/hackergotchi/albertvaka.png b/hackergotchi/albertvaka.png rename from website/hackergotchi/albertvaka.png rename to hackergotchi/albertvaka.png diff --git a/website/hackergotchi/alessandro-sivieri.png b/hackergotchi/alessandro-sivieri.png rename from website/hackergotchi/alessandro-sivieri.png rename to hackergotchi/alessandro-sivieri.png diff --git a/website/hackergotchi/alexis-menard.jpg b/hackergotchi/alexis-menard.jpg rename from website/hackergotchi/alexis-menard.jpg rename to hackergotchi/alexis-menard.jpg diff --git a/website/hackergotchi/alexl.png b/hackergotchi/alexl.png rename from website/hackergotchi/alexl.png rename to hackergotchi/alexl.png diff --git a/website/hackergotchi/alexraymond.jpg b/hackergotchi/alexraymond.jpg rename from website/hackergotchi/alexraymond.jpg rename to hackergotchi/alexraymond.jpg diff --git a/website/hackergotchi/amandacsi.jpg b/hackergotchi/amandacsi.jpg rename from website/hackergotchi/amandacsi.jpg rename to hackergotchi/amandacsi.jpg diff --git a/website/hackergotchi/amankumargupta.jpg b/hackergotchi/amankumargupta.jpg rename from website/hackergotchi/amankumargupta.jpg rename to hackergotchi/amankumargupta.jpg diff --git a/website/hackergotchi/amezin.png b/hackergotchi/amezin.png rename from website/hackergotchi/amezin.png rename to hackergotchi/amezin.png diff --git a/website/hackergotchi/amit.jpg b/hackergotchi/amit.jpg rename from website/hackergotchi/amit.jpg rename to hackergotchi/amit.jpg diff --git a/website/hackergotchi/anaselli.png b/hackergotchi/anaselli.png rename from website/hackergotchi/anaselli.png rename to hackergotchi/anaselli.png diff --git a/website/hackergotchi/andreas-huettel.png b/hackergotchi/andreas-huettel.png rename from website/hackergotchi/andreas-huettel.png rename to hackergotchi/andreas-huettel.png diff --git a/website/hackergotchi/andreas-marschke.png b/hackergotchi/andreas-marschke.png rename from website/hackergotchi/andreas-marschke.png rename to hackergotchi/andreas-marschke.png diff --git a/website/hackergotchi/andres-betts.jpg b/hackergotchi/andres-betts.jpg rename from website/hackergotchi/andres-betts.jpg rename to hackergotchi/andres-betts.jpg diff --git a/website/hackergotchi/andrewcoles.jpg b/hackergotchi/andrewcoles.jpg rename from website/hackergotchi/andrewcoles.jpg rename to hackergotchi/andrewcoles.jpg diff --git a/website/hackergotchi/andreyc.png b/hackergotchi/andreyc.png rename from website/hackergotchi/andreyc.png rename to hackergotchi/andreyc.png diff --git a/website/hackergotchi/andrunko.png b/hackergotchi/andrunko.png rename from website/hackergotchi/andrunko.png rename to hackergotchi/andrunko.png diff --git a/website/hackergotchi/andy-coder.jpg b/hackergotchi/andy-coder.jpg rename from website/hackergotchi/andy-coder.jpg rename to hackergotchi/andy-coder.jpg diff --git a/website/hackergotchi/animtim.png b/hackergotchi/animtim.png rename from website/hackergotchi/animtim.png rename to hackergotchi/animtim.png diff --git a/website/hackergotchi/ankitw.jpg b/hackergotchi/ankitw.jpg rename from website/hackergotchi/ankitw.jpg rename to hackergotchi/ankitw.jpg diff --git a/website/hackergotchi/anmolgautam.png b/hackergotchi/anmolgautam.png rename from website/hackergotchi/anmolgautam.png rename to hackergotchi/anmolgautam.png diff --git a/website/hackergotchi/annew.png b/hackergotchi/annew.png rename from website/hackergotchi/annew.png rename to hackergotchi/annew.png diff --git a/website/hackergotchi/anniec.jpg b/hackergotchi/anniec.jpg rename from website/hackergotchi/anniec.jpg rename to hackergotchi/anniec.jpg diff --git a/website/hackergotchi/annma.jpg b/hackergotchi/annma.jpg rename from website/hackergotchi/annma.jpg rename to hackergotchi/annma.jpg diff --git a/website/hackergotchi/anschneider.png b/hackergotchi/anschneider.png rename from website/hackergotchi/anschneider.png rename to hackergotchi/anschneider.png diff --git a/website/hackergotchi/antlarr.png b/hackergotchi/antlarr.png rename from website/hackergotchi/antlarr.png rename to hackergotchi/antlarr.png diff --git a/website/hackergotchi/anuj.png b/hackergotchi/anuj.png rename from website/hackergotchi/anuj.png rename to hackergotchi/anuj.png diff --git a/website/hackergotchi/anum.png b/hackergotchi/anum.png rename from website/hackergotchi/anum.png rename to hackergotchi/anum.png diff --git a/website/hackergotchi/aoszkar.jpg b/hackergotchi/aoszkar.jpg rename from website/hackergotchi/aoszkar.jpg rename to hackergotchi/aoszkar.jpg diff --git a/website/hackergotchi/apachelogger.jpg b/hackergotchi/apachelogger.jpg rename from website/hackergotchi/apachelogger.jpg rename to hackergotchi/apachelogger.jpg diff --git a/website/hackergotchi/apokryphos.png b/hackergotchi/apokryphos.png rename from website/hackergotchi/apokryphos.png rename to hackergotchi/apokryphos.png diff --git a/website/hackergotchi/araceletorres.jpg b/hackergotchi/araceletorres.jpg rename from website/hackergotchi/araceletorres.jpg rename to hackergotchi/araceletorres.jpg diff --git a/website/hackergotchi/aracnus.png b/hackergotchi/aracnus.png rename from website/hackergotchi/aracnus.png rename to hackergotchi/aracnus.png diff --git a/website/hackergotchi/arjun-basu.jpg b/hackergotchi/arjun-basu.jpg rename from website/hackergotchi/arjun-basu.jpg rename to hackergotchi/arjun-basu.jpg diff --git a/website/hackergotchi/arjun.jpg b/hackergotchi/arjun.jpg rename from website/hackergotchi/arjun.jpg rename to hackergotchi/arjun.jpg diff --git a/website/hackergotchi/arnaud-dupuis.jpg b/hackergotchi/arnaud-dupuis.jpg rename from website/hackergotchi/arnaud-dupuis.jpg rename to hackergotchi/arnaud-dupuis.jpg diff --git a/website/hackergotchi/arnavdhamija.jpg b/hackergotchi/arnavdhamija.jpg rename from website/hackergotchi/arnavdhamija.jpg rename to hackergotchi/arnavdhamija.jpg diff --git a/website/hackergotchi/aroonav.jpg b/hackergotchi/aroonav.jpg rename from website/hackergotchi/aroonav.jpg rename to hackergotchi/aroonav.jpg diff --git a/website/hackergotchi/arthurribeiro.jpg b/hackergotchi/arthurribeiro.jpg rename from website/hackergotchi/arthurribeiro.jpg rename to hackergotchi/arthurribeiro.jpg diff --git a/website/hackergotchi/asaoutkin.png b/hackergotchi/asaoutkin.png rename from website/hackergotchi/asaoutkin.png rename to hackergotchi/asaoutkin.png diff --git a/website/hackergotchi/aseigo.png b/hackergotchi/aseigo.png rename from website/hackergotchi/aseigo.png rename to hackergotchi/aseigo.png diff --git a/website/hackergotchi/ashwins.png b/hackergotchi/ashwins.png rename from website/hackergotchi/ashwins.png rename to hackergotchi/ashwins.png diff --git a/website/hackergotchi/asimha.png b/hackergotchi/asimha.png rename from website/hackergotchi/asimha.png rename to hackergotchi/asimha.png diff --git a/website/hackergotchi/asoliverez.png b/hackergotchi/asoliverez.png rename from website/hackergotchi/asoliverez.png rename to hackergotchi/asoliverez.png diff --git a/website/hackergotchi/asommer.png b/hackergotchi/asommer.png rename from website/hackergotchi/asommer.png rename to hackergotchi/asommer.png diff --git a/website/hackergotchi/aspotashev.png b/hackergotchi/aspotashev.png rename from website/hackergotchi/aspotashev.png rename to hackergotchi/aspotashev.png diff --git a/website/hackergotchi/astromme.png b/hackergotchi/astromme.png rename from website/hackergotchi/astromme.png rename to hackergotchi/astromme.png diff --git a/website/hackergotchi/atakanz.png b/hackergotchi/atakanz.png rename from website/hackergotchi/atakanz.png rename to hackergotchi/atakanz.png diff --git a/website/hackergotchi/atuljha.jpeg b/hackergotchi/atuljha.jpeg rename from website/hackergotchi/atuljha.jpeg rename to hackergotchi/atuljha.jpeg diff --git a/website/hackergotchi/avilla.png b/hackergotchi/avilla.png rename from website/hackergotchi/avilla.png rename to hackergotchi/avilla.png diff --git a/website/hackergotchi/ayushshah.jpg b/hackergotchi/ayushshah.jpg rename from website/hackergotchi/ayushshah.jpg rename to hackergotchi/ayushshah.jpg diff --git a/website/hackergotchi/bbalazs.png b/hackergotchi/bbalazs.png rename from website/hackergotchi/bbalazs.png rename to hackergotchi/bbalazs.png diff --git a/website/hackergotchi/bbroeksema.png b/hackergotchi/bbroeksema.png rename from website/hackergotchi/bbroeksema.png rename to hackergotchi/bbroeksema.png diff --git a/website/hackergotchi/bdoin.png b/hackergotchi/bdoin.png rename from website/hackergotchi/bdoin.png rename to hackergotchi/bdoin.png diff --git a/website/hackergotchi/behindkde.png b/hackergotchi/behindkde.png rename from website/hackergotchi/behindkde.png rename to hackergotchi/behindkde.png diff --git a/website/hackergotchi/beineri.png b/hackergotchi/beineri.png rename from website/hackergotchi/beineri.png rename to hackergotchi/beineri.png diff --git a/website/hackergotchi/benjamin-kaiser.jpg b/hackergotchi/benjamin-kaiser.jpg rename from website/hackergotchi/benjamin-kaiser.jpg rename to hackergotchi/benjamin-kaiser.jpg diff --git a/website/hackergotchi/benk.png b/hackergotchi/benk.png rename from website/hackergotchi/benk.png rename to hackergotchi/benk.png diff --git a/website/hackergotchi/bergie.png b/hackergotchi/bergie.png rename from website/hackergotchi/bergie.png rename to hackergotchi/bergie.png diff --git a/website/hackergotchi/bernkastel.png b/hackergotchi/bernkastel.png rename from website/hackergotchi/bernkastel.png rename to hackergotchi/bernkastel.png diff --git a/website/hackergotchi/bgupta.png b/hackergotchi/bgupta.png rename from website/hackergotchi/bgupta.png rename to hackergotchi/bgupta.png diff --git a/website/hackergotchi/bharath.png b/hackergotchi/bharath.png rename from website/hackergotchi/bharath.png rename to hackergotchi/bharath.png diff --git a/website/hackergotchi/blackie.png b/hackergotchi/blackie.png rename from website/hackergotchi/blackie.png rename to hackergotchi/blackie.png diff --git a/website/hackergotchi/bport.png b/hackergotchi/bport.png rename from website/hackergotchi/bport.png rename to hackergotchi/bport.png diff --git a/website/hackergotchi/brute4s99.png b/hackergotchi/brute4s99.png rename from website/hackergotchi/brute4s99.png rename to hackergotchi/brute4s99.png diff --git a/website/hackergotchi/bshah.jpg b/hackergotchi/bshah.jpg rename from website/hackergotchi/bshah.jpg rename to hackergotchi/bshah.jpg diff --git a/website/hackergotchi/caiojcarvalho.png b/hackergotchi/caiojcarvalho.png rename from website/hackergotchi/caiojcarvalho.png rename to hackergotchi/caiojcarvalho.png diff --git a/website/hackergotchi/calligra.png b/hackergotchi/calligra.png rename from website/hackergotchi/calligra.png rename to hackergotchi/calligra.png diff --git a/website/hackergotchi/camilaayres.png b/hackergotchi/camilaayres.png rename from website/hackergotchi/camilaayres.png rename to hackergotchi/camilaayres.png diff --git a/website/hackergotchi/canllaith.png b/hackergotchi/canllaith.png rename from website/hackergotchi/canllaith.png rename to hackergotchi/canllaith.png diff --git a/website/hackergotchi/cantor.svg b/hackergotchi/cantor.svg rename from website/hackergotchi/cantor.svg rename to hackergotchi/cantor.svg diff --git a/website/hackergotchi/capriotti.png b/hackergotchi/capriotti.png rename from website/hackergotchi/capriotti.png rename to hackergotchi/capriotti.png diff --git a/website/hackergotchi/capzilla.png b/hackergotchi/capzilla.png rename from website/hackergotchi/capzilla.png rename to hackergotchi/capzilla.png diff --git a/website/hackergotchi/cberger.png b/hackergotchi/cberger.png rename from website/hackergotchi/cberger.png rename to hackergotchi/cberger.png diff --git a/website/hackergotchi/cfeck.png b/hackergotchi/cfeck.png rename from website/hackergotchi/cfeck.png rename to hackergotchi/cfeck.png diff --git a/website/hackergotchi/cgilles.png b/hackergotchi/cgilles.png rename from website/hackergotchi/cgilles.png rename to hackergotchi/cgilles.png diff --git a/website/hackergotchi/chakra-shield.png b/hackergotchi/chakra-shield.png rename from website/hackergotchi/chakra-shield.png rename to hackergotchi/chakra-shield.png diff --git a/website/hackergotchi/chandankumar.jpg b/hackergotchi/chandankumar.jpg rename from website/hackergotchi/chandankumar.jpg rename to hackergotchi/chandankumar.jpg diff --git a/website/hackergotchi/chicao.png b/hackergotchi/chicao.png rename from website/hackergotchi/chicao.png rename to hackergotchi/chicao.png diff --git a/website/hackergotchi/chinmoy.png b/hackergotchi/chinmoy.png rename from website/hackergotchi/chinmoy.png rename to hackergotchi/chinmoy.png diff --git a/website/hackergotchi/choqok.png b/hackergotchi/choqok.png rename from website/hackergotchi/choqok.png rename to hackergotchi/choqok.png diff --git a/website/hackergotchi/chouimat.png b/hackergotchi/chouimat.png rename from website/hackergotchi/chouimat.png rename to hackergotchi/chouimat.png diff --git a/website/hackergotchi/chowells.png b/hackergotchi/chowells.png rename from website/hackergotchi/chowells.png rename to hackergotchi/chowells.png diff --git a/website/hackergotchi/clauschr.png b/hackergotchi/clauschr.png rename from website/hackergotchi/clauschr.png rename to hackergotchi/clauschr.png diff --git a/website/hackergotchi/clee.png b/hackergotchi/clee.png rename from website/hackergotchi/clee.png rename to hackergotchi/clee.png diff --git a/website/hackergotchi/coling.png b/hackergotchi/coling.png rename from website/hackergotchi/coling.png rename to hackergotchi/coling.png diff --git a/website/hackergotchi/colinger.png b/hackergotchi/colinger.png rename from website/hackergotchi/colinger.png rename to hackergotchi/colinger.png diff --git a/website/hackergotchi/cornelius.png b/hackergotchi/cornelius.png rename from website/hackergotchi/cornelius.png rename to hackergotchi/cornelius.png diff --git a/website/hackergotchi/cosenal.png b/hackergotchi/cosenal.png rename from website/hackergotchi/cosenal.png rename to hackergotchi/cosenal.png diff --git a/website/hackergotchi/ctonetti.png b/hackergotchi/ctonetti.png rename from website/hackergotchi/ctonetti.png rename to hackergotchi/ctonetti.png diff --git a/website/hackergotchi/cullmann.png b/hackergotchi/cullmann.png rename from website/hackergotchi/cullmann.png rename to hackergotchi/cullmann.png diff --git a/website/hackergotchi/dMaggot.png b/hackergotchi/dMaggot.png rename from website/hackergotchi/dMaggot.png rename to hackergotchi/dMaggot.png diff --git a/website/hackergotchi/d_ed.png b/hackergotchi/d_ed.png rename from website/hackergotchi/d_ed.png rename to hackergotchi/d_ed.png diff --git a/website/hackergotchi/danimo-qt.jpg b/hackergotchi/danimo-qt.jpg rename from website/hackergotchi/danimo-qt.jpg rename to hackergotchi/danimo-qt.jpg diff --git a/website/hackergotchi/danimo.png b/hackergotchi/danimo.png rename from website/hackergotchi/danimo.png rename to hackergotchi/danimo.png diff --git a/website/hackergotchi/dannya.png b/hackergotchi/dannya.png rename from website/hackergotchi/dannya.png rename to hackergotchi/dannya.png diff --git a/website/hackergotchi/dantti.png b/hackergotchi/dantti.png rename from website/hackergotchi/dantti.png rename to hackergotchi/dantti.png diff --git a/website/hackergotchi/darioandresr.png b/hackergotchi/darioandresr.png rename from website/hackergotchi/darioandresr.png rename to hackergotchi/darioandresr.png diff --git a/website/hackergotchi/davide-riva.png b/hackergotchi/davide-riva.png rename from website/hackergotchi/davide-riva.png rename to hackergotchi/davide-riva.png diff --git a/website/hackergotchi/davigno.png b/hackergotchi/davigno.png rename from website/hackergotchi/davigno.png rename to hackergotchi/davigno.png diff --git a/website/hackergotchi/ddomenichelli.png b/hackergotchi/ddomenichelli.png rename from website/hackergotchi/ddomenichelli.png rename to hackergotchi/ddomenichelli.png diff --git a/website/hackergotchi/declan.jpg b/hackergotchi/declan.jpg rename from website/hackergotchi/declan.jpg rename to hackergotchi/declan.jpg diff --git a/hackergotchi/default.svg b/hackergotchi/default.svg new file mode 100644 --- /dev/null +++ b/hackergotchi/default.svg @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/website/hackergotchi/dener.jpg b/hackergotchi/dener.jpg rename from website/hackergotchi/dener.jpg rename to hackergotchi/dener.jpg diff --git a/website/hackergotchi/denis-Kuplyakov.jpg b/hackergotchi/denis-Kuplyakov.jpg rename from website/hackergotchi/denis-Kuplyakov.jpg rename to hackergotchi/denis-Kuplyakov.jpg diff --git a/website/hackergotchi/devanshuagarwal.png b/hackergotchi/devanshuagarwal.png rename from website/hackergotchi/devanshuagarwal.png rename to hackergotchi/devanshuagarwal.png diff --git a/website/hackergotchi/dhaumann.png b/hackergotchi/dhaumann.png rename from website/hackergotchi/dhaumann.png rename to hackergotchi/dhaumann.png diff --git a/website/hackergotchi/digikam.png b/hackergotchi/digikam.png rename from website/hackergotchi/digikam.png rename to hackergotchi/digikam.png diff --git a/website/hackergotchi/dileepsankhla.png b/hackergotchi/dileepsankhla.png rename from website/hackergotchi/dileepsankhla.png rename to hackergotchi/dileepsankhla.png diff --git a/website/hackergotchi/dimitrios-tanis.jpg b/hackergotchi/dimitrios-tanis.jpg rename from website/hackergotchi/dimitrios-tanis.jpg rename to hackergotchi/dimitrios-tanis.jpg diff --git a/website/hackergotchi/dinkar.png b/hackergotchi/dinkar.png rename from website/hackergotchi/dinkar.png rename to hackergotchi/dinkar.png diff --git a/website/hackergotchi/dipak.jpg b/hackergotchi/dipak.jpg rename from website/hackergotchi/dipak.jpg rename to hackergotchi/dipak.jpg diff --git a/website/hackergotchi/divyamMadaan.jpg b/hackergotchi/divyamMadaan.jpg rename from website/hackergotchi/divyamMadaan.jpg rename to hackergotchi/divyamMadaan.jpg diff --git a/website/hackergotchi/dkardarakos.png b/hackergotchi/dkardarakos.png rename from website/hackergotchi/dkardarakos.png rename to hackergotchi/dkardarakos.png diff --git a/website/hackergotchi/dmitripopov.png b/hackergotchi/dmitripopov.png rename from website/hackergotchi/dmitripopov.png rename to hackergotchi/dmitripopov.png diff --git a/website/hackergotchi/don.jpg b/hackergotchi/don.jpg rename from website/hackergotchi/don.jpg rename to hackergotchi/don.jpg diff --git a/website/hackergotchi/donkeyshot.png b/hackergotchi/donkeyshot.png rename from website/hackergotchi/donkeyshot.png rename to hackergotchi/donkeyshot.png diff --git a/website/hackergotchi/dot-news.png b/hackergotchi/dot-news.png rename from website/hackergotchi/dot-news.png rename to hackergotchi/dot-news.png diff --git a/website/hackergotchi/drf.png b/hackergotchi/drf.png rename from website/hackergotchi/drf.png rename to hackergotchi/drf.png diff --git a/website/hackergotchi/dvratil.png b/hackergotchi/dvratil.png rename from website/hackergotchi/dvratil.png rename to hackergotchi/dvratil.png diff --git a/website/hackergotchi/dymo.png b/hackergotchi/dymo.png rename from website/hackergotchi/dymo.png rename to hackergotchi/dymo.png diff --git a/website/hackergotchi/echidnaman.png b/hackergotchi/echidnaman.png rename from website/hackergotchi/echidnaman.png rename to hackergotchi/echidnaman.png diff --git a/website/hackergotchi/eean.jpg b/hackergotchi/eean.jpg rename from website/hackergotchi/eean.jpg rename to hackergotchi/eean.jpg diff --git a/website/hackergotchi/effqt-bird.png b/hackergotchi/effqt-bird.png rename from website/hackergotchi/effqt-bird.png rename to hackergotchi/effqt-bird.png diff --git a/website/hackergotchi/egerasimov.png b/hackergotchi/egerasimov.png rename from website/hackergotchi/egerasimov.png rename to hackergotchi/egerasimov.png diff --git a/website/hackergotchi/ehamberg.png b/hackergotchi/ehamberg.png rename from website/hackergotchi/ehamberg.png rename to hackergotchi/ehamberg.png diff --git a/website/hackergotchi/eike-hein.jpg b/hackergotchi/eike-hein.jpg rename from website/hackergotchi/eike-hein.jpg rename to hackergotchi/eike-hein.jpg diff --git a/website/hackergotchi/eliakincosta.jpg b/hackergotchi/eliakincosta.jpg rename from website/hackergotchi/eliakincosta.jpg rename to hackergotchi/eliakincosta.jpg diff --git a/website/hackergotchi/elvis.png b/hackergotchi/elvis.png rename from website/hackergotchi/elvis.png rename to hackergotchi/elvis.png diff --git a/website/hackergotchi/ematirov.jpg b/hackergotchi/ematirov.jpg rename from website/hackergotchi/ematirov.jpg rename to hackergotchi/ematirov.jpg diff --git a/website/hackergotchi/emgosp.jpg b/hackergotchi/emgosp.jpg rename from website/hackergotchi/emgosp.jpg rename to hackergotchi/emgosp.jpg diff --git a/website/hackergotchi/ereslibre.png b/hackergotchi/ereslibre.png rename from website/hackergotchi/ereslibre.png rename to hackergotchi/ereslibre.png diff --git a/website/hackergotchi/eros.png b/hackergotchi/eros.png rename from website/hackergotchi/eros.png rename to hackergotchi/eros.png diff --git a/website/hackergotchi/esben.png b/hackergotchi/esben.png rename from website/hackergotchi/esben.png rename to hackergotchi/esben.png diff --git a/website/hackergotchi/estan.png b/hackergotchi/estan.png rename from website/hackergotchi/estan.png rename to hackergotchi/estan.png diff --git a/website/hackergotchi/fab.png b/hackergotchi/fab.png rename from website/hackergotchi/fab.png rename to hackergotchi/fab.png diff --git a/website/hackergotchi/fabo.png b/hackergotchi/fabo.png rename from website/hackergotchi/fabo.png rename to hackergotchi/fabo.png diff --git a/website/hackergotchi/falit.png b/hackergotchi/falit.png rename from website/hackergotchi/falit.png rename to hackergotchi/falit.png diff --git a/website/hackergotchi/falkon.png b/hackergotchi/falkon.png rename from website/hackergotchi/falkon.png rename to hackergotchi/falkon.png diff --git a/website/hackergotchi/fania_jock.jpg b/hackergotchi/fania_jock.jpg rename from website/hackergotchi/fania_jock.jpg rename to hackergotchi/fania_jock.jpg diff --git a/website/hackergotchi/faridb.png b/hackergotchi/faridb.png rename from website/hackergotchi/faridb.png rename to hackergotchi/faridb.png diff --git a/website/hackergotchi/ferencz_kovacs.png b/hackergotchi/ferencz_kovacs.png rename from website/hackergotchi/ferencz_kovacs.png rename to hackergotchi/ferencz_kovacs.png diff --git a/website/hackergotchi/fernandoteles.png b/hackergotchi/fernandoteles.png rename from website/hackergotchi/fernandoteles.png rename to hackergotchi/fernandoteles.png diff --git a/website/hackergotchi/filipe_cabecinha.png b/hackergotchi/filipe_cabecinha.png rename from website/hackergotchi/filipe_cabecinha.png rename to hackergotchi/filipe_cabecinha.png diff --git a/website/hackergotchi/filipf.png b/hackergotchi/filipf.png rename from website/hackergotchi/filipf.png rename to hackergotchi/filipf.png diff --git a/website/hackergotchi/fkpulz.png b/hackergotchi/fkpulz.png rename from website/hackergotchi/fkpulz.png rename to hackergotchi/fkpulz.png diff --git a/website/hackergotchi/flocati.png b/hackergotchi/flocati.png rename from website/hackergotchi/flocati.png rename to hackergotchi/flocati.png diff --git a/website/hackergotchi/fmontesi.png b/hackergotchi/fmontesi.png rename from website/hackergotchi/fmontesi.png rename to hackergotchi/fmontesi.png diff --git a/website/hackergotchi/foerster.png b/hackergotchi/foerster.png rename from website/hackergotchi/foerster.png rename to hackergotchi/foerster.png diff --git a/website/hackergotchi/fred87.png b/hackergotchi/fred87.png rename from website/hackergotchi/fred87.png rename to hackergotchi/fred87.png diff --git a/website/hackergotchi/frederik_gladhorn.jpeg b/hackergotchi/frederik_gladhorn.jpeg rename from website/hackergotchi/frederik_gladhorn.jpeg rename to hackergotchi/frederik_gladhorn.jpeg diff --git a/website/hackergotchi/freitag75.png b/hackergotchi/freitag75.png rename from website/hackergotchi/freitag75.png rename to hackergotchi/freitag75.png diff --git a/website/hackergotchi/frinring.png b/hackergotchi/frinring.png rename from website/hackergotchi/frinring.png rename to hackergotchi/frinring.png diff --git a/website/hackergotchi/gabriel-poesia.jpg b/hackergotchi/gabriel-poesia.jpg rename from website/hackergotchi/gabriel-poesia.jpg rename to hackergotchi/gabriel-poesia.jpg diff --git a/website/hackergotchi/gamaral.gif b/hackergotchi/gamaral.gif rename from website/hackergotchi/gamaral.gif rename to hackergotchi/gamaral.gif diff --git a/website/hackergotchi/garvit-khatri.png b/hackergotchi/garvit-khatri.png rename from website/hackergotchi/garvit-khatri.png rename to hackergotchi/garvit-khatri.png diff --git a/website/hackergotchi/gaurav.jpg b/hackergotchi/gaurav.jpg rename from website/hackergotchi/gaurav.jpg rename to hackergotchi/gaurav.jpg diff --git a/website/hackergotchi/gcompris.png b/hackergotchi/gcompris.png rename from website/hackergotchi/gcompris.png rename to hackergotchi/gcompris.png diff --git a/website/hackergotchi/gdebure.png b/hackergotchi/gdebure.png rename from website/hackergotchi/gdebure.png rename to hackergotchi/gdebure.png diff --git a/website/hackergotchi/geiseri.png b/hackergotchi/geiseri.png rename from website/hackergotchi/geiseri.png rename to hackergotchi/geiseri.png diff --git a/website/hackergotchi/giannis-konstantinidis.jpeg b/hackergotchi/giannis-konstantinidis.jpeg rename from website/hackergotchi/giannis-konstantinidis.jpeg rename to hackergotchi/giannis-konstantinidis.jpeg diff --git a/website/hackergotchi/gkulzer.png b/hackergotchi/gkulzer.png rename from website/hackergotchi/gkulzer.png rename to hackergotchi/gkulzer.png diff --git a/website/hackergotchi/gnumdk.png b/hackergotchi/gnumdk.png rename from website/hackergotchi/gnumdk.png rename to hackergotchi/gnumdk.png diff --git a/website/hackergotchi/gokmen.png b/hackergotchi/gokmen.png rename from website/hackergotchi/gokmen.png rename to hackergotchi/gokmen.png diff --git a/website/hackergotchi/gomex.png b/hackergotchi/gomex.png rename from website/hackergotchi/gomex.png rename to hackergotchi/gomex.png diff --git a/website/hackergotchi/gopala.png b/hackergotchi/gopala.png rename from website/hackergotchi/gopala.png rename to hackergotchi/gopala.png diff --git a/website/hackergotchi/gopalakrishna-bhat.jpg b/hackergotchi/gopalakrishna-bhat.jpg rename from website/hackergotchi/gopalakrishna-bhat.jpg rename to hackergotchi/gopalakrishna-bhat.jpg diff --git a/website/hackergotchi/gsteinert.png b/hackergotchi/gsteinert.png rename from website/hackergotchi/gsteinert.png rename to hackergotchi/gsteinert.png diff --git a/website/hackergotchi/gulino.png b/hackergotchi/gulino.png rename from website/hackergotchi/gulino.png rename to hackergotchi/gulino.png diff --git a/website/hackergotchi/guoyunhe.jpg b/hackergotchi/guoyunhe.jpg rename from website/hackergotchi/guoyunhe.jpg rename to hackergotchi/guoyunhe.jpg diff --git a/website/hackergotchi/gurgese.png b/hackergotchi/gurgese.png rename from website/hackergotchi/gurgese.png rename to hackergotchi/gurgese.png diff --git a/website/hackergotchi/gvoicu.png b/hackergotchi/gvoicu.png rename from website/hackergotchi/gvoicu.png rename to hackergotchi/gvoicu.png diff --git a/website/hackergotchi/hades.png b/hackergotchi/hades.png rename from website/hackergotchi/hades.png rename to hackergotchi/hades.png diff --git a/website/hackergotchi/hdevalence.png b/hackergotchi/hdevalence.png rename from website/hackergotchi/hdevalence.png rename to hackergotchi/hdevalence.png diff --git a/website/hackergotchi/hefee.png b/hackergotchi/hefee.png rename from website/hackergotchi/hefee.png rename to hackergotchi/hefee.png diff --git a/website/hackergotchi/helio_castro.png b/hackergotchi/helio_castro.png rename from website/hackergotchi/helio_castro.png rename to hackergotchi/helio_castro.png diff --git a/website/hackergotchi/hellozee.png b/hackergotchi/hellozee.png rename from website/hackergotchi/hellozee.png rename to hackergotchi/hellozee.png diff --git a/website/hackergotchi/hjain.jpg b/hackergotchi/hjain.jpg rename from website/hackergotchi/hjain.jpg rename to hackergotchi/hjain.jpg diff --git a/website/hackergotchi/holehan.png b/hackergotchi/holehan.png rename from website/hackergotchi/holehan.png rename to hackergotchi/holehan.png diff --git a/website/hackergotchi/hook.png b/hackergotchi/hook.png rename from website/hackergotchi/hook.png rename to hackergotchi/hook.png diff --git a/website/hackergotchi/horrendus.jpg b/hackergotchi/horrendus.jpg rename from website/hackergotchi/horrendus.jpg rename to hackergotchi/horrendus.jpg diff --git a/website/hackergotchi/hscott.png b/hackergotchi/hscott.png rename from website/hackergotchi/hscott.png rename to hackergotchi/hscott.png diff --git a/website/hackergotchi/htietze.png b/hackergotchi/htietze.png rename from website/hackergotchi/htietze.png rename to hackergotchi/htietze.png diff --git a/website/hackergotchi/hubner.png b/hackergotchi/hubner.png rename from website/hackergotchi/hubner.png rename to hackergotchi/hubner.png diff --git a/website/hackergotchi/hugo.png b/hackergotchi/hugo.png rename from website/hackergotchi/hugo.png rename to hackergotchi/hugo.png diff --git a/website/hackergotchi/iammarco11.png b/hackergotchi/iammarco11.png rename from website/hackergotchi/iammarco11.png rename to hackergotchi/iammarco11.png diff --git a/website/hackergotchi/illogic-al.png b/hackergotchi/illogic-al.png rename from website/hackergotchi/illogic-al.png rename to hackergotchi/illogic-al.png diff --git a/website/hackergotchi/ilya_b.png b/hackergotchi/ilya_b.png rename from website/hackergotchi/ilya_b.png rename to hackergotchi/ilya_b.png diff --git a/website/hackergotchi/inoki.jpg b/hackergotchi/inoki.jpg rename from website/hackergotchi/inoki.jpg rename to hackergotchi/inoki.jpg diff --git a/website/hackergotchi/ivan.png b/hackergotchi/ivan.png rename from website/hackergotchi/ivan.png rename to hackergotchi/ivan.png diff --git a/website/hackergotchi/ivana.jpg b/hackergotchi/ivana.jpg rename from website/hackergotchi/ivana.jpg rename to hackergotchi/ivana.jpg diff --git a/website/hackergotchi/ivanyossi.png b/hackergotchi/ivanyossi.png rename from website/hackergotchi/ivanyossi.png rename to hackergotchi/ivanyossi.png diff --git a/website/hackergotchi/jaiva.png b/hackergotchi/jaiva.png rename from website/hackergotchi/jaiva.png rename to hackergotchi/jaiva.png diff --git a/website/hackergotchi/jamboarder.png b/hackergotchi/jamboarder.png rename from website/hackergotchi/jamboarder.png rename to hackergotchi/jamboarder.png diff --git a/website/hackergotchi/james-cain.jpg b/hackergotchi/james-cain.jpg rename from website/hackergotchi/james-cain.jpg rename to hackergotchi/james-cain.jpg diff --git a/website/hackergotchi/jayson-rowe.jpg b/hackergotchi/jayson-rowe.jpg rename from website/hackergotchi/jayson-rowe.jpg rename to hackergotchi/jayson-rowe.jpg diff --git a/website/hackergotchi/jbaptiste.png b/hackergotchi/jbaptiste.png rename from website/hackergotchi/jbaptiste.png rename to hackergotchi/jbaptiste.png diff --git a/website/hackergotchi/jbb.png b/hackergotchi/jbb.png rename from website/hackergotchi/jbb.png rename to hackergotchi/jbb.png diff --git a/website/hackergotchi/jdonenfeld.png b/hackergotchi/jdonenfeld.png rename from website/hackergotchi/jdonenfeld.png rename to hackergotchi/jdonenfeld.png diff --git a/website/hackergotchi/je4d.png b/hackergotchi/je4d.png rename from website/hackergotchi/je4d.png rename to hackergotchi/je4d.png diff --git a/website/hackergotchi/jehrichs.png b/hackergotchi/jehrichs.png rename from website/hackergotchi/jehrichs.png rename to hackergotchi/jehrichs.png diff --git a/website/hackergotchi/jensreuterberg.png b/hackergotchi/jensreuterberg.png rename from website/hackergotchi/jensreuterberg.png rename to hackergotchi/jensreuterberg.png diff --git a/website/hackergotchi/jesperht.png b/hackergotchi/jesperht.png rename from website/hackergotchi/jesperht.png rename to hackergotchi/jesperht.png diff --git a/website/hackergotchi/jigar.jpg b/hackergotchi/jigar.jpg rename from website/hackergotchi/jigar.jpg rename to hackergotchi/jigar.jpg diff --git a/website/hackergotchi/jkeel.png b/hackergotchi/jkeel.png rename from website/hackergotchi/jkeel.png rename to hackergotchi/jkeel.png diff --git a/website/hackergotchi/jlp.png b/hackergotchi/jlp.png rename from website/hackergotchi/jlp.png rename to hackergotchi/jlp.png diff --git a/website/hackergotchi/jmaceachern.png b/hackergotchi/jmaceachern.png rename from website/hackergotchi/jmaceachern.png rename to hackergotchi/jmaceachern.png diff --git a/website/hackergotchi/jmueller.png b/hackergotchi/jmueller.png rename from website/hackergotchi/jmueller.png rename to hackergotchi/jmueller.png diff --git a/website/hackergotchi/jnarboux.png b/hackergotchi/jnarboux.png rename from website/hackergotchi/jnarboux.png rename to hackergotchi/jnarboux.png diff --git a/website/hackergotchi/johannes-huber.jpg b/hackergotchi/johannes-huber.jpg rename from website/hackergotchi/johannes-huber.jpg rename to hackergotchi/johannes-huber.jpg diff --git a/website/hackergotchi/johnflux.png b/hackergotchi/johnflux.png rename from website/hackergotchi/johnflux.png rename to hackergotchi/johnflux.png diff --git a/website/hackergotchi/jonan.png b/hackergotchi/jonan.png rename from website/hackergotchi/jonan.png rename to hackergotchi/jonan.png diff --git a/website/hackergotchi/jordipolo.png b/hackergotchi/jordipolo.png rename from website/hackergotchi/jordipolo.png rename to hackergotchi/jordipolo.png diff --git a/website/hackergotchi/joselb.png b/hackergotchi/joselb.png rename from website/hackergotchi/joselb.png rename to hackergotchi/joselb.png diff --git a/website/hackergotchi/josephsimon.png b/hackergotchi/josephsimon.png rename from website/hackergotchi/josephsimon.png rename to hackergotchi/josephsimon.png diff --git a/website/hackergotchi/jospoortvliet.png b/hackergotchi/jospoortvliet.png rename from website/hackergotchi/jospoortvliet.png rename to hackergotchi/jospoortvliet.png diff --git a/website/hackergotchi/jperichon.png b/hackergotchi/jperichon.png rename from website/hackergotchi/jperichon.png rename to hackergotchi/jperichon.png diff --git a/website/hackergotchi/jpetso.png b/hackergotchi/jpetso.png rename from website/hackergotchi/jpetso.png rename to hackergotchi/jpetso.png diff --git a/website/hackergotchi/jpwhiting.jpg b/hackergotchi/jpwhiting.jpg rename from website/hackergotchi/jpwhiting.jpg rename to hackergotchi/jpwhiting.jpg diff --git a/website/hackergotchi/jstaniek.png b/hackergotchi/jstaniek.png rename from website/hackergotchi/jstaniek.png rename to hackergotchi/jstaniek.png diff --git a/website/hackergotchi/jucato.png b/hackergotchi/jucato.png rename from website/hackergotchi/jucato.png rename to hackergotchi/jucato.png diff --git a/website/hackergotchi/jussi.jpg b/hackergotchi/jussi.jpg rename from website/hackergotchi/jussi.jpg rename to hackergotchi/jussi.jpg diff --git a/website/hackergotchi/kai.jpg b/hackergotchi/kai.jpg rename from website/hackergotchi/kai.jpg rename to hackergotchi/kai.jpg diff --git a/website/hackergotchi/kaidan.png b/hackergotchi/kaidan.png rename from website/hackergotchi/kaidan.png rename to hackergotchi/kaidan.png diff --git a/website/hackergotchi/karina.jpeg b/hackergotchi/karina.jpeg rename from website/hackergotchi/karina.jpeg rename to hackergotchi/karina.jpeg diff --git a/website/hackergotchi/karli.png b/hackergotchi/karli.png rename from website/hackergotchi/karli.png rename to hackergotchi/karli.png diff --git a/website/hackergotchi/kash.png b/hackergotchi/kash.png rename from website/hackergotchi/kash.png rename to hackergotchi/kash.png diff --git a/website/hackergotchi/kate.png b/hackergotchi/kate.png rename from website/hackergotchi/kate.png rename to hackergotchi/kate.png diff --git a/website/hackergotchi/kcoyle.png b/hackergotchi/kcoyle.png rename from website/hackergotchi/kcoyle.png rename to hackergotchi/kcoyle.png diff --git a/website/hackergotchi/kdab.png b/hackergotchi/kdab.png rename from website/hackergotchi/kdab.png rename to hackergotchi/kdab.png diff --git a/website/hackergotchi/kdeblog.png b/hackergotchi/kdeblog.png rename from website/hackergotchi/kdeblog.png rename to hackergotchi/kdeblog.png diff --git a/website/hackergotchi/kdebrasil.png b/hackergotchi/kdebrasil.png rename from website/hackergotchi/kdebrasil.png rename to hackergotchi/kdebrasil.png diff --git a/website/hackergotchi/kdeforum.png b/hackergotchi/kdeforum.png rename from website/hackergotchi/kdeforum.png rename to hackergotchi/kdeforum.png diff --git a/website/hackergotchi/kdegames.png b/hackergotchi/kdegames.png rename from website/hackergotchi/kdegames.png rename to hackergotchi/kdegames.png diff --git a/website/hackergotchi/kdein.png b/hackergotchi/kdein.png rename from website/hackergotchi/kdein.png rename to hackergotchi/kdein.png diff --git a/website/hackergotchi/kdenlive.png b/hackergotchi/kdenlive.png rename from website/hackergotchi/kdenlive.png rename to hackergotchi/kdenlive.png diff --git a/website/hackergotchi/kdeok.png b/hackergotchi/kdeok.png rename from website/hackergotchi/kdeok.png rename to hackergotchi/kdeok.png diff --git a/website/hackergotchi/kdevelop.png b/hackergotchi/kdevelop.png rename from website/hackergotchi/kdevelop.png rename to hackergotchi/kdevelop.png diff --git a/website/hackergotchi/kecsap.jpg b/hackergotchi/kecsap.jpg rename from website/hackergotchi/kecsap.jpg rename to hackergotchi/kecsap.jpg diff --git a/website/hackergotchi/kfunk.png b/hackergotchi/kfunk.png rename from website/hackergotchi/kfunk.png rename to hackergotchi/kfunk.png diff --git a/website/hackergotchi/kleag.png b/hackergotchi/kleag.png rename from website/hackergotchi/kleag.png rename to hackergotchi/kleag.png diff --git a/website/hackergotchi/kmix.png b/hackergotchi/kmix.png rename from website/hackergotchi/kmix.png rename to hackergotchi/kmix.png diff --git a/website/hackergotchi/kmymoney.png b/hackergotchi/kmymoney.png rename from website/hackergotchi/kmymoney.png rename to hackergotchi/kmymoney.png diff --git a/website/hackergotchi/koldavid.png b/hackergotchi/koldavid.png rename from website/hackergotchi/koldavid.png rename to hackergotchi/koldavid.png diff --git a/website/hackergotchi/konradzemek.png b/hackergotchi/konradzemek.png rename from website/hackergotchi/konradzemek.png rename to hackergotchi/konradzemek.png diff --git a/website/hackergotchi/koushik-s.jpg b/hackergotchi/koushik-s.jpg rename from website/hackergotchi/koushik-s.jpg rename to hackergotchi/koushik-s.jpg diff --git a/website/hackergotchi/kowalewski.png b/hackergotchi/kowalewski.png rename from website/hackergotchi/kowalewski.png rename to hackergotchi/kowalewski.png diff --git a/website/hackergotchi/krajsz.png b/hackergotchi/krajsz.png rename from website/hackergotchi/krajsz.png rename to hackergotchi/krajsz.png diff --git a/website/hackergotchi/kreuter.png b/hackergotchi/kreuter.png rename from website/hackergotchi/kreuter.png rename to hackergotchi/kreuter.png diff --git a/website/hackergotchi/krita.png b/hackergotchi/krita.png rename from website/hackergotchi/krita.png rename to hackergotchi/krita.png diff --git a/website/hackergotchi/kromain.jpg b/hackergotchi/kromain.jpg rename from website/hackergotchi/kromain.jpg rename to hackergotchi/kromain.jpg diff --git a/website/hackergotchi/kstplot.png b/hackergotchi/kstplot.png rename from website/hackergotchi/kstplot.png rename to hackergotchi/kstplot.png diff --git a/website/hackergotchi/kubuntu-logo.png b/hackergotchi/kubuntu-logo.png rename from website/hackergotchi/kubuntu-logo.png rename to hackergotchi/kubuntu-logo.png diff --git a/website/hackergotchi/kubuntu-wire.png b/hackergotchi/kubuntu-wire.png rename from website/hackergotchi/kubuntu-wire.png rename to hackergotchi/kubuntu-wire.png diff --git a/website/hackergotchi/kumar.png b/hackergotchi/kumar.png rename from website/hackergotchi/kumar.png rename to hackergotchi/kumar.png diff --git a/website/hackergotchi/kunalghosh.png b/hackergotchi/kunalghosh.png rename from website/hackergotchi/kunalghosh.png rename to hackergotchi/kunalghosh.png diff --git a/website/hackergotchi/kver.png b/hackergotchi/kver.png rename from website/hackergotchi/kver.png rename to hackergotchi/kver.png diff --git a/website/hackergotchi/ladeia.png b/hackergotchi/ladeia.png rename from website/hackergotchi/ladeia.png rename to hackergotchi/ladeia.png diff --git a/website/hackergotchi/lamarque.png b/hackergotchi/lamarque.png rename from website/hackergotchi/lamarque.png rename to hackergotchi/lamarque.png diff --git a/website/hackergotchi/landswellsong.png b/hackergotchi/landswellsong.png rename from website/hackergotchi/landswellsong.png rename to hackergotchi/landswellsong.png diff --git a/website/hackergotchi/languitar.png b/hackergotchi/languitar.png rename from website/hackergotchi/languitar.png rename to hackergotchi/languitar.png diff --git a/website/hackergotchi/laszlo_papp-80x80.png b/hackergotchi/laszlo_papp-80x80.png rename from website/hackergotchi/laszlo_papp-80x80.png rename to hackergotchi/laszlo_papp-80x80.png diff --git a/website/hackergotchi/lays.png b/hackergotchi/lays.png rename from website/hackergotchi/lays.png rename to hackergotchi/lays.png diff --git a/website/hackergotchi/leinir.png b/hackergotchi/leinir.png rename from website/hackergotchi/leinir.png rename to hackergotchi/leinir.png diff --git a/website/hackergotchi/lespitallier.png b/hackergotchi/lespitallier.png rename from website/hackergotchi/lespitallier.png rename to hackergotchi/lespitallier.png diff --git a/website/hackergotchi/leu.jpg b/hackergotchi/leu.jpg rename from website/hackergotchi/leu.jpg rename to hackergotchi/leu.jpg diff --git a/website/hackergotchi/lgr.png b/hackergotchi/lgr.png rename from website/hackergotchi/lgr.png rename to hackergotchi/lgr.png diff --git a/website/hackergotchi/lieroz.jpeg b/hackergotchi/lieroz.jpeg rename from website/hackergotchi/lieroz.jpeg rename to hackergotchi/lieroz.jpeg diff --git a/website/hackergotchi/lombra.jpg b/hackergotchi/lombra.jpg rename from website/hackergotchi/lombra.jpg rename to hackergotchi/lombra.jpg diff --git a/website/hackergotchi/lpapp.png b/hackergotchi/lpapp.png rename from website/hackergotchi/lpapp.png rename to hackergotchi/lpapp.png diff --git a/website/hackergotchi/luca-ferrari.png b/hackergotchi/luca-ferrari.png rename from website/hackergotchi/luca-ferrari.png rename to hackergotchi/luca-ferrari.png diff --git a/website/hackergotchi/lucas.jpg b/hackergotchi/lucas.jpg rename from website/hackergotchi/lucas.jpg rename to hackergotchi/lucas.jpg diff --git a/website/hackergotchi/lucashn.png b/hackergotchi/lucashn.png rename from website/hackergotchi/lucashn.png rename to hackergotchi/lucashn.png diff --git a/website/hackergotchi/lucasliragomes.png b/hackergotchi/lucasliragomes.png rename from website/hackergotchi/lucasliragomes.png rename to hackergotchi/lucasliragomes.png diff --git a/website/hackergotchi/lucatringali.png b/hackergotchi/lucatringali.png rename from website/hackergotchi/lucatringali.png rename to hackergotchi/lucatringali.png diff --git a/website/hackergotchi/luhe.png b/hackergotchi/luhe.png rename from website/hackergotchi/luhe.png rename to hackergotchi/luhe.png diff --git a/website/hackergotchi/luis-augusto-fretes-cuevas.jpg b/hackergotchi/luis-augusto-fretes-cuevas.jpg rename from website/hackergotchi/luis-augusto-fretes-cuevas.jpg rename to hackergotchi/luis-augusto-fretes-cuevas.jpg diff --git a/website/hackergotchi/luis.jpeg b/hackergotchi/luis.jpeg rename from website/hackergotchi/luis.jpeg rename to hackergotchi/luis.jpeg diff --git a/website/hackergotchi/luizromario.jpg b/hackergotchi/luizromario.jpg rename from website/hackergotchi/luizromario.jpg rename to hackergotchi/luizromario.jpg diff --git a/website/hackergotchi/macaw-movies.png b/hackergotchi/macaw-movies.png rename from website/hackergotchi/macaw-movies.png rename to hackergotchi/macaw-movies.png diff --git a/website/hackergotchi/madeti.png b/hackergotchi/madeti.png rename from website/hackergotchi/madeti.png rename to hackergotchi/madeti.png diff --git a/website/hackergotchi/magda.png b/hackergotchi/magda.png rename from website/hackergotchi/magda.png rename to hackergotchi/magda.png diff --git a/website/hackergotchi/mahfuz.png b/hackergotchi/mahfuz.png rename from website/hackergotchi/mahfuz.png rename to hackergotchi/mahfuz.png diff --git a/website/hackergotchi/mailson.png b/hackergotchi/mailson.png rename from website/hackergotchi/mailson.png rename to hackergotchi/mailson.png diff --git a/website/hackergotchi/majewsky.png b/hackergotchi/majewsky.png rename from website/hackergotchi/majewsky.png rename to hackergotchi/majewsky.png diff --git a/website/hackergotchi/mamarok.png b/hackergotchi/mamarok.png rename from website/hackergotchi/mamarok.png rename to hackergotchi/mamarok.png diff --git a/website/hackergotchi/mansona.png b/hackergotchi/mansona.png rename from website/hackergotchi/mansona.png rename to hackergotchi/mansona.png diff --git a/website/hackergotchi/manyoso.png b/hackergotchi/manyoso.png rename from website/hackergotchi/manyoso.png rename to hackergotchi/manyoso.png diff --git a/website/hackergotchi/marcuzzo.png b/hackergotchi/marcuzzo.png rename from website/hackergotchi/marcuzzo.png rename to hackergotchi/marcuzzo.png diff --git a/website/hackergotchi/mariusoc.png b/hackergotchi/mariusoc.png rename from website/hackergotchi/mariusoc.png rename to hackergotchi/mariusoc.png diff --git a/website/hackergotchi/markey_gotchi.png b/hackergotchi/markey_gotchi.png rename from website/hackergotchi/markey_gotchi.png rename to hackergotchi/markey_gotchi.png diff --git a/website/hackergotchi/marti_de.png b/hackergotchi/marti_de.png rename from website/hackergotchi/marti_de.png rename to hackergotchi/marti_de.png diff --git a/website/hackergotchi/matthias_ximion.png b/hackergotchi/matthias_ximion.png rename from website/hackergotchi/matthias_ximion.png rename to hackergotchi/matthias_ximion.png diff --git a/website/hackergotchi/mattr.png b/hackergotchi/mattr.png rename from website/hackergotchi/mattr.png rename to hackergotchi/mattr.png diff --git a/website/hackergotchi/maugotchi_new.png b/hackergotchi/maugotchi_new.png rename from website/hackergotchi/maugotchi_new.png rename to hackergotchi/maugotchi_new.png diff --git a/website/hackergotchi/maurochehab.png b/hackergotchi/maurochehab.png rename from website/hackergotchi/maurochehab.png rename to hackergotchi/maurochehab.png diff --git a/website/hackergotchi/mbatle.jpg b/hackergotchi/mbatle.jpg rename from website/hackergotchi/mbatle.jpg rename to hackergotchi/mbatle.jpg diff --git a/website/hackergotchi/mck182.png b/hackergotchi/mck182.png rename from website/hackergotchi/mck182.png rename to hackergotchi/mck182.png diff --git a/website/hackergotchi/melandory.jpg b/hackergotchi/melandory.jpg rename from website/hackergotchi/melandory.jpg rename to hackergotchi/melandory.jpg diff --git a/website/hackergotchi/meven.png b/hackergotchi/meven.png rename from website/hackergotchi/meven.png rename to hackergotchi/meven.png diff --git a/website/hackergotchi/mgallien.png b/hackergotchi/mgallien.png rename from website/hackergotchi/mgallien.png rename to hackergotchi/mgallien.png diff --git a/website/hackergotchi/mghansen.png b/hackergotchi/mghansen.png rename from website/hackergotchi/mghansen.png rename to hackergotchi/mghansen.png diff --git a/website/hackergotchi/michael-krog.png b/hackergotchi/michael-krog.png rename from website/hackergotchi/michael-krog.png rename to hackergotchi/michael-krog.png diff --git a/website/hackergotchi/minhchu.png b/hackergotchi/minhchu.png rename from website/hackergotchi/minhchu.png rename to hackergotchi/minhchu.png diff --git a/website/hackergotchi/mirkoboehm.png b/hackergotchi/mirkoboehm.png rename from website/hackergotchi/mirkoboehm.png rename to hackergotchi/mirkoboehm.png diff --git a/website/hackergotchi/mklapetek.png b/hackergotchi/mklapetek.png rename from website/hackergotchi/mklapetek.png rename to hackergotchi/mklapetek.png diff --git a/website/hackergotchi/mohamed-anwer.png b/hackergotchi/mohamed-anwer.png rename from website/hackergotchi/mohamed-anwer.png rename to hackergotchi/mohamed-anwer.png diff --git a/website/hackergotchi/mohamedmalik.png b/hackergotchi/mohamedmalik.png rename from website/hackergotchi/mohamedmalik.png rename to hackergotchi/mohamedmalik.png diff --git a/website/hackergotchi/mohammed-nafees.jpg b/hackergotchi/mohammed-nafees.jpg rename from website/hackergotchi/mohammed-nafees.jpg rename to hackergotchi/mohammed-nafees.jpg diff --git a/website/hackergotchi/momeny.png b/hackergotchi/momeny.png rename from website/hackergotchi/momeny.png rename to hackergotchi/momeny.png diff --git a/website/fr/hackergotchi/morice.png b/hackergotchi/morice.png rename from website/fr/hackergotchi/morice.png rename to hackergotchi/morice.png diff --git a/website/hackergotchi/mpyne.png b/hackergotchi/mpyne.png rename from website/hackergotchi/mpyne.png rename to hackergotchi/mpyne.png diff --git a/website/hackergotchi/msadityan.png b/hackergotchi/msadityan.png rename from website/hackergotchi/msadityan.png rename to hackergotchi/msadityan.png diff --git a/website/hackergotchi/mtijink.jpg b/hackergotchi/mtijink.jpg rename from website/hackergotchi/mtijink.jpg rename to hackergotchi/mtijink.jpg diff --git a/website/hackergotchi/muesli.jpg b/hackergotchi/muesli.jpg rename from website/hackergotchi/muesli.jpg rename to hackergotchi/muesli.jpg diff --git a/website/hackergotchi/mujji.png b/hackergotchi/mujji.png rename from website/hackergotchi/mujji.png rename to hackergotchi/mujji.png diff --git a/website/hackergotchi/murrant.png b/hackergotchi/murrant.png rename from website/hackergotchi/murrant.png rename to hackergotchi/murrant.png diff --git a/website/hackergotchi/mutlaqja.png b/hackergotchi/mutlaqja.png rename from website/hackergotchi/mutlaqja.png rename to hackergotchi/mutlaqja.png diff --git a/website/hackergotchi/mvlabat.png b/hackergotchi/mvlabat.png rename from website/hackergotchi/mvlabat.png rename to hackergotchi/mvlabat.png diff --git a/website/hackergotchi/mwiesweg.png b/hackergotchi/mwiesweg.png rename from website/hackergotchi/mwiesweg.png rename to hackergotchi/mwiesweg.png diff --git a/website/hackergotchi/mwolff.png b/hackergotchi/mwolff.png rename from website/hackergotchi/mwolff.png rename to hackergotchi/mwolff.png diff --git a/website/hackergotchi/nadeem.png b/hackergotchi/nadeem.png rename from website/hackergotchi/nadeem.png rename to hackergotchi/nadeem.png diff --git a/website/hackergotchi/najmi.png b/hackergotchi/najmi.png rename from website/hackergotchi/najmi.png rename to hackergotchi/najmi.png diff --git a/website/hackergotchi/neofytosk.png b/hackergotchi/neofytosk.png rename from website/hackergotchi/neofytosk.png rename to hackergotchi/neofytosk.png diff --git a/website/hackergotchi/neomantra.jpeg b/hackergotchi/neomantra.jpeg rename from website/hackergotchi/neomantra.jpeg rename to hackergotchi/neomantra.jpeg diff --git a/website/hackergotchi/neon.png b/hackergotchi/neon.png rename from website/hackergotchi/neon.png rename to hackergotchi/neon.png diff --git a/website/hackergotchi/ngraham.png b/hackergotchi/ngraham.png rename from website/hackergotchi/ngraham.png rename to hackergotchi/ngraham.png diff --git a/website/hackergotchi/nicolasfella.png b/hackergotchi/nicolasfella.png rename from website/hackergotchi/nicolasfella.png rename to hackergotchi/nicolasfella.png diff --git a/website/hackergotchi/nielsvm.png b/hackergotchi/nielsvm.png rename from website/hackergotchi/nielsvm.png rename to hackergotchi/nielsvm.png diff --git a/website/hackergotchi/nienhueser.png b/hackergotchi/nienhueser.png rename from website/hackergotchi/nienhueser.png rename to hackergotchi/nienhueser.png diff --git a/website/hackergotchi/nightrose.png b/hackergotchi/nightrose.png rename from website/hackergotchi/nightrose.png rename to hackergotchi/nightrose.png diff --git a/website/hackergotchi/nil1511.jpg b/hackergotchi/nil1511.jpg rename from website/hackergotchi/nil1511.jpg rename to hackergotchi/nil1511.jpg diff --git a/website/hackergotchi/nimmy.png b/hackergotchi/nimmy.png rename from website/hackergotchi/nimmy.png rename to hackergotchi/nimmy.png diff --git a/website/hackergotchi/nitish.jpg b/hackergotchi/nitish.jpg rename from website/hackergotchi/nitish.jpg rename to hackergotchi/nitish.jpg diff --git a/website/hackergotchi/nituldatt.png b/hackergotchi/nituldatt.png rename from website/hackergotchi/nituldatt.png rename to hackergotchi/nituldatt.png diff --git a/website/hackergotchi/nixternal.png b/hackergotchi/nixternal.png rename from website/hackergotchi/nixternal.png rename to hackergotchi/nixternal.png diff --git a/website/hackergotchi/njaard.png b/hackergotchi/njaard.png rename from website/hackergotchi/njaard.png rename to hackergotchi/njaard.png diff --git a/website/hackergotchi/nlecureil.png b/hackergotchi/nlecureil.png rename from website/hackergotchi/nlecureil.png rename to hackergotchi/nlecureil.png diff --git a/website/hackergotchi/nlminhtl.png b/hackergotchi/nlminhtl.png rename from website/hackergotchi/nlminhtl.png rename to hackergotchi/nlminhtl.png diff --git a/website/hackergotchi/notmart.png b/hackergotchi/notmart.png rename from website/hackergotchi/notmart.png rename to hackergotchi/notmart.png diff --git a/website/hackergotchi/noughmad.png b/hackergotchi/noughmad.png rename from website/hackergotchi/noughmad.png rename to hackergotchi/noughmad.png diff --git a/website/hackergotchi/nowicki.jpeg b/hackergotchi/nowicki.jpeg rename from website/hackergotchi/nowicki.jpeg rename to hackergotchi/nowicki.jpeg diff --git a/website/hackergotchi/nwoki.png b/hackergotchi/nwoki.png rename from website/hackergotchi/nwoki.png rename to hackergotchi/nwoki.png diff --git a/website/hackergotchi/ochurlaud.jpg b/hackergotchi/ochurlaud.jpg rename from website/hackergotchi/ochurlaud.jpg rename to hackergotchi/ochurlaud.jpg diff --git a/website/hackergotchi/ognarb.png b/hackergotchi/ognarb.png rename from website/hackergotchi/ognarb.png rename to hackergotchi/ognarb.png diff --git a/website/hackergotchi/oini.jpg b/hackergotchi/oini.jpg rename from website/hackergotchi/oini.jpg rename to hackergotchi/oini.jpg diff --git a/website/hackergotchi/ojschmidt.png b/hackergotchi/ojschmidt.png rename from website/hackergotchi/ojschmidt.png rename to hackergotchi/ojschmidt.png diff --git a/website/hackergotchi/orepoala.png b/hackergotchi/orepoala.png rename from website/hackergotchi/orepoala.png rename to hackergotchi/orepoala.png diff --git a/website/hackergotchi/ovidiu-florin.jpeg b/hackergotchi/ovidiu-florin.jpeg rename from website/hackergotchi/ovidiu-florin.jpeg rename to hackergotchi/ovidiu-florin.jpeg diff --git a/website/hackergotchi/oy.png b/hackergotchi/oy.png rename from website/hackergotchi/oy.png rename to hackergotchi/oy.png diff --git a/website/hackergotchi/ozan.png b/hackergotchi/ozan.png rename from website/hackergotchi/ozan.png rename to hackergotchi/ozan.png diff --git a/website/hackergotchi/packo.png b/hackergotchi/packo.png rename from website/hackergotchi/packo.png rename to hackergotchi/packo.png diff --git a/website/hackergotchi/padams.png b/hackergotchi/padams.png rename from website/hackergotchi/padams.png rename to hackergotchi/padams.png diff --git a/website/hackergotchi/pano.png b/hackergotchi/pano.png rename from website/hackergotchi/pano.png rename to hackergotchi/pano.png diff --git a/website/hackergotchi/patrickelectric.png b/hackergotchi/patrickelectric.png rename from website/hackergotchi/patrickelectric.png rename to hackergotchi/patrickelectric.png diff --git a/website/hackergotchi/paulbro666.jpg b/hackergotchi/paulbro666.jpg rename from website/hackergotchi/paulbro666.jpg rename to hackergotchi/paulbro666.jpg diff --git a/website/hackergotchi/pdamsten.png b/hackergotchi/pdamsten.png rename from website/hackergotchi/pdamsten.png rename to hackergotchi/pdamsten.png diff --git a/website/hackergotchi/pedrol.png b/hackergotchi/pedrol.png rename from website/hackergotchi/pedrol.png rename to hackergotchi/pedrol.png diff --git a/website/hackergotchi/peifengyu.jpg b/hackergotchi/peifengyu.jpg rename from website/hackergotchi/peifengyu.jpg rename to hackergotchi/peifengyu.jpg diff --git a/website/hackergotchi/petrm.jpg b/hackergotchi/petrm.jpg rename from website/hackergotchi/petrm.jpg rename to hackergotchi/petrm.jpg diff --git a/website/hackergotchi/pfeiffer.png b/hackergotchi/pfeiffer.png rename from website/hackergotchi/pfeiffer.png rename to hackergotchi/pfeiffer.png diff --git a/website/hackergotchi/pgabor.png b/hackergotchi/pgabor.png rename from website/hackergotchi/pgabor.png rename to hackergotchi/pgabor.png diff --git a/website/hackergotchi/pgquiles.png b/hackergotchi/pgquiles.png rename from website/hackergotchi/pgquiles.png rename to hackergotchi/pgquiles.png diff --git a/website/hackergotchi/pgrasch.png b/hackergotchi/pgrasch.png rename from website/hackergotchi/pgrasch.png rename to hackergotchi/pgrasch.png diff --git a/website/hackergotchi/phillip.png b/hackergotchi/phillip.png rename from website/hackergotchi/phillip.png rename to hackergotchi/phillip.png diff --git a/website/hackergotchi/pierre-stirnweiss.jpg b/hackergotchi/pierre-stirnweiss.jpg rename from website/hackergotchi/pierre-stirnweiss.jpg rename to hackergotchi/pierre-stirnweiss.jpg diff --git a/website/hackergotchi/pijoan.jpg b/hackergotchi/pijoan.jpg rename from website/hackergotchi/pijoan.jpg rename to hackergotchi/pijoan.jpg diff --git a/website/hackergotchi/pinak.png b/hackergotchi/pinak.png rename from website/hackergotchi/pinak.png rename to hackergotchi/pinak.png diff --git a/website/hackergotchi/pinheiro.png b/hackergotchi/pinheiro.png rename from website/hackergotchi/pinheiro.png rename to hackergotchi/pinheiro.png diff --git a/website/hackergotchi/pipesmoker.jpg b/hackergotchi/pipesmoker.jpg rename from website/hackergotchi/pipesmoker.jpg rename to hackergotchi/pipesmoker.jpg diff --git a/website/hackergotchi/plasma-mobile.png b/hackergotchi/plasma-mobile.png rename from website/hackergotchi/plasma-mobile.png rename to hackergotchi/plasma-mobile.png diff --git a/website/hackergotchi/plfiorini.jpg b/hackergotchi/plfiorini.jpg rename from website/hackergotchi/plfiorini.jpg rename to hackergotchi/plfiorini.jpg diff --git a/website/hackergotchi/polentino.png b/hackergotchi/polentino.png rename from website/hackergotchi/polentino.png rename to hackergotchi/polentino.png diff --git a/website/hackergotchi/ppenz.png b/hackergotchi/ppenz.png rename from website/hackergotchi/ppenz.png rename to hackergotchi/ppenz.png diff --git a/website/hackergotchi/prakash.png b/hackergotchi/prakash.png rename from website/hackergotchi/prakash.png rename to hackergotchi/prakash.png diff --git a/website/hackergotchi/promulo.png b/hackergotchi/promulo.png rename from website/hackergotchi/promulo.png rename to hackergotchi/promulo.png diff --git a/website/hackergotchi/pulkit.png b/hackergotchi/pulkit.png rename from website/hackergotchi/pulkit.png rename to hackergotchi/pulkit.png diff --git a/website/hackergotchi/puneetgoyal.png b/hackergotchi/puneetgoyal.png rename from website/hackergotchi/puneetgoyal.png rename to hackergotchi/puneetgoyal.png diff --git a/website/hackergotchi/punit-mehta.png b/hackergotchi/punit-mehta.png rename from website/hackergotchi/punit-mehta.png rename to hackergotchi/punit-mehta.png diff --git a/website/hackergotchi/qt_logo.png b/hackergotchi/qt_logo.png rename from website/hackergotchi/qt_logo.png rename to hackergotchi/qt_logo.png diff --git a/website/hackergotchi/rahul.png b/hackergotchi/rahul.png rename from website/hackergotchi/rahul.png rename to hackergotchi/rahul.png diff --git a/website/hackergotchi/rahulyadav.png b/hackergotchi/rahulyadav.png rename from website/hackergotchi/rahulyadav.png rename to hackergotchi/rahulyadav.png diff --git a/website/hackergotchi/rajeesh.png b/hackergotchi/rajeesh.png rename from website/hackergotchi/rajeesh.png rename to hackergotchi/rajeesh.png diff --git a/website/hackergotchi/rakuco.png b/hackergotchi/rakuco.png rename from website/hackergotchi/rakuco.png rename to hackergotchi/rakuco.png diff --git a/website/hackergotchi/randomguy3.png b/hackergotchi/randomguy3.png rename from website/hackergotchi/randomguy3.png rename to hackergotchi/randomguy3.png diff --git a/website/hackergotchi/raphael.png b/hackergotchi/raphael.png rename from website/hackergotchi/raphael.png rename to hackergotchi/raphael.png diff --git a/website/hackergotchi/rdieter.png b/hackergotchi/rdieter.png rename from website/hackergotchi/rdieter.png rename to hackergotchi/rdieter.png diff --git a/website/hackergotchi/rezza.png b/hackergotchi/rezza.png rename from website/hackergotchi/rezza.png rename to hackergotchi/rezza.png diff --git a/website/hackergotchi/rgupta.png b/hackergotchi/rgupta.png rename from website/hackergotchi/rgupta.png rename to hackergotchi/rgupta.png diff --git a/website/hackergotchi/richih.png b/hackergotchi/richih.png rename from website/hackergotchi/richih.png rename to hackergotchi/richih.png diff --git a/website/hackergotchi/riddell.png b/hackergotchi/riddell.png rename from website/hackergotchi/riddell.png rename to hackergotchi/riddell.png diff --git a/website/hackergotchi/riosa.png b/hackergotchi/riosa.png rename from website/hackergotchi/riosa.png rename to hackergotchi/riosa.png diff --git a/website/hackergotchi/rishab-arora.png b/hackergotchi/rishab-arora.png rename from website/hackergotchi/rishab-arora.png rename to hackergotchi/rishab-arora.png diff --git a/website/hackergotchi/rizzitello.png b/hackergotchi/rizzitello.png rename from website/hackergotchi/rizzitello.png rename to hackergotchi/rizzitello.png diff --git a/website/hackergotchi/rku.png b/hackergotchi/rku.png rename from website/hackergotchi/rku.png rename to hackergotchi/rku.png diff --git a/website/hackergotchi/rkulaga.png b/hackergotchi/rkulaga.png rename from website/hackergotchi/rkulaga.png rename to hackergotchi/rkulaga.png diff --git a/website/hackergotchi/rohan.png b/hackergotchi/rohan.png rename from website/hackergotchi/rohan.png rename to hackergotchi/rohan.png diff --git a/website/hackergotchi/rohanp.jpg b/hackergotchi/rohanp.jpg rename from website/hackergotchi/rohanp.jpg rename to hackergotchi/rohanp.jpg diff --git a/website/hackergotchi/romain-perier.png b/hackergotchi/romain-perier.png rename from website/hackergotchi/romain-perier.png rename to hackergotchi/romain-perier.png diff --git a/website/hackergotchi/roman-gilg.png b/hackergotchi/roman-gilg.png rename from website/hackergotchi/roman-gilg.png rename to hackergotchi/roman-gilg.png diff --git a/website/es/hackergotchi/ronnyml.png b/hackergotchi/ronnyml.png rename from website/es/hackergotchi/ronnyml.png rename to hackergotchi/ronnyml.png diff --git a/website/hackergotchi/roozbeh.jpeg b/hackergotchi/roozbeh.jpeg rename from website/hackergotchi/roozbeh.jpeg rename to hackergotchi/roozbeh.jpeg diff --git a/website/hackergotchi/rriemannt.png b/hackergotchi/rriemannt.png rename from website/hackergotchi/rriemannt.png rename to hackergotchi/rriemannt.png diff --git a/website/hackergotchi/rthomsen.png b/hackergotchi/rthomsen.png rename from website/hackergotchi/rthomsen.png rename to hackergotchi/rthomsen.png diff --git a/website/hackergotchi/ruberg.png b/hackergotchi/ruberg.png rename from website/hackergotchi/ruberg.png rename to hackergotchi/ruberg.png diff --git a/website/hackergotchi/rudra.jpg b/hackergotchi/rudra.jpg rename from website/hackergotchi/rudra.jpg rename to hackergotchi/rudra.jpg diff --git a/website/hackergotchi/ruedigergad.png b/hackergotchi/ruedigergad.png rename from website/hackergotchi/ruedigergad.png rename to hackergotchi/ruedigergad.png diff --git a/website/hackergotchi/rullzer.png b/hackergotchi/rullzer.png rename from website/hackergotchi/rullzer.png rename to hackergotchi/rullzer.png diff --git a/website/hackergotchi/ruphy.png b/hackergotchi/ruphy.png rename from website/hackergotchi/ruphy.png rename to hackergotchi/ruphy.png diff --git a/website/hackergotchi/ruthemann.png b/hackergotchi/ruthemann.png rename from website/hackergotchi/ruthemann.png rename to hackergotchi/ruthemann.png diff --git a/website/hackergotchi/ruurd.png b/hackergotchi/ruurd.png rename from website/hackergotchi/ruurd.png rename to hackergotchi/ruurd.png diff --git a/website/hackergotchi/rysin.png b/hackergotchi/rysin.png rename from website/hackergotchi/rysin.png rename to hackergotchi/rysin.png diff --git a/website/hackergotchi/sacha.png b/hackergotchi/sacha.png rename from website/hackergotchi/sacha.png rename to hackergotchi/sacha.png diff --git a/website/hackergotchi/sagar.png b/hackergotchi/sagar.png rename from website/hackergotchi/sagar.png rename to hackergotchi/sagar.png diff --git a/website/hackergotchi/sagarhani.png b/hackergotchi/sagarhani.png rename from website/hackergotchi/sagarhani.png rename to hackergotchi/sagarhani.png diff --git a/website/hackergotchi/sahebpreet.png b/hackergotchi/sahebpreet.png rename from website/hackergotchi/sahebpreet.png rename to hackergotchi/sahebpreet.png diff --git a/website/hackergotchi/saidinesh5.png b/hackergotchi/saidinesh5.png rename from website/hackergotchi/saidinesh5.png rename to hackergotchi/saidinesh5.png diff --git a/website/hackergotchi/sandroandrade.png b/hackergotchi/sandroandrade.png rename from website/hackergotchi/sandroandrade.png rename to hackergotchi/sandroandrade.png diff --git a/website/hackergotchi/sandsmark.png b/hackergotchi/sandsmark.png rename from website/hackergotchi/sandsmark.png rename to hackergotchi/sandsmark.png diff --git a/website/hackergotchi/sanjibanbairagya.png b/hackergotchi/sanjibanbairagya.png rename from website/hackergotchi/sanjibanbairagya.png rename to hackergotchi/sanjibanbairagya.png diff --git a/website/hackergotchi/sascha-manns.png b/hackergotchi/sascha-manns.png rename from website/hackergotchi/sascha-manns.png rename to hackergotchi/sascha-manns.png diff --git a/website/hackergotchi/saschpe.png b/hackergotchi/saschpe.png rename from website/hackergotchi/saschpe.png rename to hackergotchi/saschpe.png diff --git a/website/hackergotchi/sayakb.png b/hackergotchi/sayakb.png rename from website/hackergotchi/sayakb.png rename to hackergotchi/sayakb.png diff --git a/website/hackergotchi/sayan.png b/hackergotchi/sayan.png rename from website/hackergotchi/sayan.png rename to hackergotchi/sayan.png diff --git a/website/hackergotchi/scummos.png b/hackergotchi/scummos.png rename from website/hackergotchi/scummos.png rename to hackergotchi/scummos.png diff --git a/website/hackergotchi/sebas.png b/hackergotchi/sebas.png rename from website/hackergotchi/sebas.png rename to hackergotchi/sebas.png diff --git a/website/hackergotchi/sebascolor.png b/hackergotchi/sebascolor.png rename from website/hackergotchi/sebascolor.png rename to hackergotchi/sebascolor.png diff --git a/website/hackergotchi/sebr.png b/hackergotchi/sebr.png rename from website/hackergotchi/sebr.png rename to hackergotchi/sebr.png diff --git a/website/hackergotchi/seele.png b/hackergotchi/seele.png rename from website/hackergotchi/seele.png rename to hackergotchi/seele.png diff --git a/website/hackergotchi/seiflotfy.png b/hackergotchi/seiflotfy.png rename from website/hackergotchi/seiflotfy.png rename to hackergotchi/seiflotfy.png diff --git a/website/hackergotchi/sergio.png b/hackergotchi/sergio.png rename from website/hackergotchi/sergio.png rename to hackergotchi/sergio.png diff --git a/website/hackergotchi/sgclark.png b/hackergotchi/sgclark.png rename from website/hackergotchi/sgclark.png rename to hackergotchi/sgclark.png diff --git a/website/hackergotchi/sgielen.png b/hackergotchi/sgielen.png rename from website/hackergotchi/sgielen.png rename to hackergotchi/sgielen.png diff --git a/website/hackergotchi/sh_zam.png b/hackergotchi/sh_zam.png rename from website/hackergotchi/sh_zam.png rename to hackergotchi/sh_zam.png diff --git a/website/hackergotchi/shaforostoff.png b/hackergotchi/shaforostoff.png rename from website/hackergotchi/shaforostoff.png rename to hackergotchi/shaforostoff.png diff --git a/website/hackergotchi/shantanu.png b/hackergotchi/shantanu.png rename from website/hackergotchi/shantanu.png rename to hackergotchi/shantanu.png diff --git a/website/hackergotchi/shashankSingh.png b/hackergotchi/shashankSingh.png rename from website/hackergotchi/shashankSingh.png rename to hackergotchi/shashankSingh.png diff --git a/website/hackergotchi/shaza-ismail.png b/hackergotchi/shaza-ismail.png rename from website/hackergotchi/shaza-ismail.png rename to hackergotchi/shaza-ismail.png diff --git a/website/hackergotchi/shocklateboy92.png b/hackergotchi/shocklateboy92.png rename from website/hackergotchi/shocklateboy92.png rename to hackergotchi/shocklateboy92.png diff --git a/website/hackergotchi/shourya.jpg b/hackergotchi/shourya.jpg rename from website/hackergotchi/shourya.jpg rename to hackergotchi/shourya.jpg diff --git a/website/hackergotchi/shreya.jpg b/hackergotchi/shreya.jpg rename from website/hackergotchi/shreya.jpg rename to hackergotchi/shreya.jpg diff --git a/website/hackergotchi/siddharth.jpg b/hackergotchi/siddharth.jpg rename from website/hackergotchi/siddharth.jpg rename to hackergotchi/siddharth.jpg diff --git a/website/hackergotchi/simeir.png b/hackergotchi/simeir.png rename from website/hackergotchi/simeir.png rename to hackergotchi/simeir.png diff --git a/website/hackergotchi/simon-esneault.png b/hackergotchi/simon-esneault.png rename from website/hackergotchi/simon-esneault.png rename to hackergotchi/simon-esneault.png diff --git a/website/hackergotchi/sinny.png b/hackergotchi/sinny.png rename from website/hackergotchi/sinny.png rename to hackergotchi/sinny.png diff --git a/website/hackergotchi/sirgienko.png b/hackergotchi/sirgienko.png rename from website/hackergotchi/sirgienko.png rename to hackergotchi/sirgienko.png diff --git a/website/hackergotchi/skelet.png b/hackergotchi/skelet.png rename from website/hackergotchi/skelet.png rename to hackergotchi/skelet.png diff --git a/website/hackergotchi/smankowski.png b/hackergotchi/smankowski.png rename from website/hackergotchi/smankowski.png rename to hackergotchi/smankowski.png diff --git a/website/hackergotchi/somsubhra.png b/hackergotchi/somsubhra.png rename from website/hackergotchi/somsubhra.png rename to hackergotchi/somsubhra.png diff --git a/website/hackergotchi/songeon_hackergotchi.png b/hackergotchi/songeon_hackergotchi.png rename from website/hackergotchi/songeon_hackergotchi.png rename to hackergotchi/songeon_hackergotchi.png diff --git a/website/hackergotchi/spstarr.png b/hackergotchi/spstarr.png rename from website/hackergotchi/spstarr.png rename to hackergotchi/spstarr.png diff --git a/website/hackergotchi/sredman.png b/hackergotchi/sredman.png rename from website/hackergotchi/sredman.png rename to hackergotchi/sredman.png diff --git a/website/hackergotchi/sreich.png b/hackergotchi/sreich.png rename from website/hackergotchi/sreich.png rename to hackergotchi/sreich.png diff --git a/website/hackergotchi/srijan.jpg b/hackergotchi/srijan.jpg rename from website/hackergotchi/srijan.jpg rename to hackergotchi/srijan.jpg diff --git a/website/hackergotchi/stalcup.jpeg b/hackergotchi/stalcup.jpeg rename from website/hackergotchi/stalcup.jpeg rename to hackergotchi/stalcup.jpeg diff --git a/website/hackergotchi/stefan.png b/hackergotchi/stefan.png rename from website/hackergotchi/stefan.png rename to hackergotchi/stefan.png diff --git a/website/hackergotchi/stephanie.jpg b/hackergotchi/stephanie.jpg rename from website/hackergotchi/stephanie.jpg rename to hackergotchi/stephanie.jpg diff --git a/website/hackergotchi/stikonas.png b/hackergotchi/stikonas.png rename from website/hackergotchi/stikonas.png rename to hackergotchi/stikonas.png diff --git a/website/hackergotchi/strohel.png b/hackergotchi/strohel.png rename from website/hackergotchi/strohel.png rename to hackergotchi/strohel.png diff --git a/website/hackergotchi/stuart-jarvis.png b/hackergotchi/stuart-jarvis.png rename from website/hackergotchi/stuart-jarvis.png rename to hackergotchi/stuart-jarvis.png diff --git a/website/hackergotchi/stuartmd.png b/hackergotchi/stuartmd.png rename from website/hackergotchi/stuartmd.png rename to hackergotchi/stuartmd.png diff --git a/website/hackergotchi/subhajitmukherjee.png b/hackergotchi/subhajitmukherjee.png rename from website/hackergotchi/subhajitmukherjee.png rename to hackergotchi/subhajitmukherjee.png diff --git a/website/hackergotchi/sujithh.png b/hackergotchi/sujithh.png rename from website/hackergotchi/sujithh.png rename to hackergotchi/sujithh.png diff --git a/website/hackergotchi/svenassmann.png b/hackergotchi/svenassmann.png rename from website/hackergotchi/svenassmann.png rename to hackergotchi/svenassmann.png diff --git a/website/hackergotchi/svuorela.png b/hackergotchi/svuorela.png rename from website/hackergotchi/svuorela.png rename to hackergotchi/svuorela.png diff --git a/website/hackergotchi/sysadmins.png b/hackergotchi/sysadmins.png rename from website/hackergotchi/sysadmins.png rename to hackergotchi/sysadmins.png diff --git a/website/hackergotchi/tabthorpe.png b/hackergotchi/tabthorpe.png rename from website/hackergotchi/tabthorpe.png rename to hackergotchi/tabthorpe.png diff --git a/website/hackergotchi/tandon.png b/hackergotchi/tandon.png rename from website/hackergotchi/tandon.png rename to hackergotchi/tandon.png diff --git a/website/hackergotchi/tbaumgart.png b/hackergotchi/tbaumgart.png rename from website/hackergotchi/tbaumgart.png rename to hackergotchi/tbaumgart.png diff --git a/website/hackergotchi/tchance.png b/hackergotchi/tchance.png rename from website/hackergotchi/tchance.png rename to hackergotchi/tchance.png diff --git a/website/hackergotchi/teo.png b/hackergotchi/teo.png rename from website/hackergotchi/teo.png rename to hackergotchi/teo.png diff --git a/website/hackergotchi/thehayro.png b/hackergotchi/thehayro.png rename from website/hackergotchi/thehayro.png rename to hackergotchi/thehayro.png diff --git a/website/hackergotchi/theobroma.png b/hackergotchi/theobroma.png rename from website/hackergotchi/theobroma.png rename to hackergotchi/theobroma.png diff --git a/website/hackergotchi/theonering.png b/hackergotchi/theonering.png rename from website/hackergotchi/theonering.png rename to hackergotchi/theonering.png diff --git a/website/hackergotchi/thiago.png b/hackergotchi/thiago.png rename from website/hackergotchi/thiago.png rename to hackergotchi/thiago.png diff --git a/website/hackergotchi/thomas-pfeiffer.jpg b/hackergotchi/thomas-pfeiffer.jpg rename from website/hackergotchi/thomas-pfeiffer.jpg rename to hackergotchi/thomas-pfeiffer.jpg diff --git a/website/hackergotchi/thomas-thum.jpg b/hackergotchi/thomas-thum.jpg rename from website/hackergotchi/thomas-thum.jpg rename to hackergotchi/thomas-thum.jpg diff --git a/website/hackergotchi/thomasfischer.png b/hackergotchi/thomasfischer.png rename from website/hackergotchi/thomasfischer.png rename to hackergotchi/thomasfischer.png diff --git a/website/hackergotchi/tiar.png b/hackergotchi/tiar.png rename from website/hackergotchi/tiar.png rename to hackergotchi/tiar.png diff --git a/website/hackergotchi/tina.png b/hackergotchi/tina.png rename from website/hackergotchi/tina.png rename to hackergotchi/tina.png diff --git a/website/hackergotchi/tittiatcoke.jpg b/hackergotchi/tittiatcoke.jpg rename from website/hackergotchi/tittiatcoke.jpg rename to hackergotchi/tittiatcoke.jpg diff --git a/website/hackergotchi/tmt.png b/hackergotchi/tmt.png rename from website/hackergotchi/tmt.png rename to hackergotchi/tmt.png diff --git a/website/hackergotchi/tolszak.png b/hackergotchi/tolszak.png rename from website/hackergotchi/tolszak.png rename to hackergotchi/tolszak.png diff --git a/website/hackergotchi/tomaz-canabrava.png b/hackergotchi/tomaz-canabrava.png rename from website/hackergotchi/tomaz-canabrava.png rename to hackergotchi/tomaz-canabrava.png diff --git a/website/hackergotchi/tomaz.png b/hackergotchi/tomaz.png rename from website/hackergotchi/tomaz.png rename to hackergotchi/tomaz.png diff --git a/website/hackergotchi/trueg.jpg b/hackergotchi/trueg.jpg rename from website/hackergotchi/trueg.jpg rename to hackergotchi/trueg.jpg diff --git a/website/hackergotchi/tuliom.png b/hackergotchi/tuliom.png rename from website/hackergotchi/tuliom.png rename to hackergotchi/tuliom.png diff --git a/website/hackergotchi/tusooa.png b/hackergotchi/tusooa.png rename from website/hackergotchi/tusooa.png rename to hackergotchi/tusooa.png diff --git a/website/hackergotchi/utkarshtiwari.jpg b/hackergotchi/utkarshtiwari.jpg rename from website/hackergotchi/utkarshtiwari.jpg rename to hackergotchi/utkarshtiwari.jpg diff --git a/website/hackergotchi/valerio-pilo.jpg b/hackergotchi/valerio-pilo.jpg rename from website/hackergotchi/valerio-pilo.jpg rename to hackergotchi/valerio-pilo.jpg diff --git a/website/hackergotchi/valir.png b/hackergotchi/valir.png rename from website/hackergotchi/valir.png rename to hackergotchi/valir.png diff --git a/website/hackergotchi/valorie.png b/hackergotchi/valorie.png rename from website/hackergotchi/valorie.png rename to hackergotchi/valorie.png diff --git a/website/hackergotchi/vandenoever.png b/hackergotchi/vandenoever.png rename from website/hackergotchi/vandenoever.png rename to hackergotchi/vandenoever.png diff --git a/website/hackergotchi/vasudha.jpg b/hackergotchi/vasudha.jpg rename from website/hackergotchi/vasudha.jpg rename to hackergotchi/vasudha.jpg diff --git a/website/hackergotchi/veaceslavm.png b/hackergotchi/veaceslavm.png rename from website/hackergotchi/veaceslavm.png rename to hackergotchi/veaceslavm.png diff --git a/website/hackergotchi/vedant-agarwala.png b/hackergotchi/vedant-agarwala.png rename from website/hackergotchi/vedant-agarwala.png rename to hackergotchi/vedant-agarwala.png diff --git a/website/hackergotchi/veggero.png b/hackergotchi/veggero.png rename from website/hackergotchi/veggero.png rename to hackergotchi/veggero.png diff --git a/website/hackergotchi/vhanda.png b/hackergotchi/vhanda.png rename from website/hackergotchi/vhanda.png rename to hackergotchi/vhanda.png diff --git a/website/hackergotchi/vineet-garg.png b/hackergotchi/vineet-garg.png rename from website/hackergotchi/vineet-garg.png rename to hackergotchi/vineet-garg.png diff --git a/website/hackergotchi/viniciusazevedo.jpg b/hackergotchi/viniciusazevedo.jpg rename from website/hackergotchi/viniciusazevedo.jpg rename to hackergotchi/viniciusazevedo.jpg diff --git a/website/hackergotchi/vir.png b/hackergotchi/vir.png rename from website/hackergotchi/vir.png rename to hackergotchi/vir.png diff --git a/website/hackergotchi/viranch-mehta.jpg b/hackergotchi/viranch-mehta.jpg rename from website/hackergotchi/viranch-mehta.jpg rename to hackergotchi/viranch-mehta.jpg diff --git a/website/hackergotchi/viranch.png b/hackergotchi/viranch.png rename from website/hackergotchi/viranch.png rename to hackergotchi/viranch.png diff --git a/website/hackergotchi/vitochiarella.jpg b/hackergotchi/vitochiarella.jpg rename from website/hackergotchi/vitochiarella.jpg rename to hackergotchi/vitochiarella.jpg diff --git a/website/hackergotchi/vitor.png b/hackergotchi/vitor.png rename from website/hackergotchi/vitor.png rename to hackergotchi/vitor.png diff --git a/website/hackergotchi/vmatyushin.png b/hackergotchi/vmatyushin.png rename from website/hackergotchi/vmatyushin.png rename to hackergotchi/vmatyushin.png diff --git a/website/hackergotchi/volker-lanz.png b/hackergotchi/volker-lanz.png rename from website/hackergotchi/volker-lanz.png rename to hackergotchi/volker-lanz.png diff --git a/website/hackergotchi/vourlakos.png b/hackergotchi/vourlakos.png rename from website/hackergotchi/vourlakos.png rename to hackergotchi/vourlakos.png diff --git a/website/hackergotchi/wagner.png b/hackergotchi/wagner.png rename from website/hackergotchi/wagner.png rename to hackergotchi/wagner.png diff --git a/website/hackergotchi/webcamreceive.png b/hackergotchi/webcamreceive.png rename from website/hackergotchi/webcamreceive.png rename to hackergotchi/webcamreceive.png diff --git a/website/hackergotchi/wheels.png b/hackergotchi/wheels.png rename from website/hackergotchi/wheels.png rename to hackergotchi/wheels.png diff --git a/website/hackergotchi/wkai.jpeg b/hackergotchi/wkai.jpeg rename from website/hackergotchi/wkai.jpeg rename to hackergotchi/wkai.jpeg diff --git a/website/hackergotchi/wojak.jpg b/hackergotchi/wojak.jpg rename from website/hackergotchi/wojak.jpg rename to hackergotchi/wojak.jpg diff --git a/website/hackergotchi/wrix.jpg b/hackergotchi/wrix.jpg rename from website/hackergotchi/wrix.jpg rename to hackergotchi/wrix.jpg diff --git a/website/hackergotchi/wtlemblem.png b/hackergotchi/wtlemblem.png rename from website/hackergotchi/wtlemblem.png rename to hackergotchi/wtlemblem.png diff --git a/website/hackergotchi/wyuka.png b/hackergotchi/wyuka.png rename from website/hackergotchi/wyuka.png rename to hackergotchi/wyuka.png diff --git a/website/hackergotchi/xuetianweng.png b/hackergotchi/xuetianweng.png rename from website/hackergotchi/xuetianweng.png rename to hackergotchi/xuetianweng.png diff --git a/website/hackergotchi/xyquadrat.png b/hackergotchi/xyquadrat.png rename from website/hackergotchi/xyquadrat.png rename to hackergotchi/xyquadrat.png diff --git a/website/hackergotchi/yang-qiao.jpg b/hackergotchi/yang-qiao.jpg rename from website/hackergotchi/yang-qiao.jpg rename to hackergotchi/yang-qiao.jpg diff --git a/website/hackergotchi/yashshah.jpg b/hackergotchi/yashshah.jpg rename from website/hackergotchi/yashshah.jpg rename to hackergotchi/yashshah.jpg diff --git a/website/hackergotchi/yuenhoe.jpg b/hackergotchi/yuenhoe.jpg rename from website/hackergotchi/yuenhoe.jpg rename to hackergotchi/yuenhoe.jpg diff --git a/website/hackergotchi/yuvraj-tomar.jpg b/hackergotchi/yuvraj-tomar.jpg rename from website/hackergotchi/yuvraj-tomar.jpg rename to hackergotchi/yuvraj-tomar.jpg diff --git a/website/hackergotchi/zahl.png b/hackergotchi/zahl.png rename from website/hackergotchi/zahl.png rename to hackergotchi/zahl.png diff --git a/website/hackergotchi/zajec.png b/hackergotchi/zajec.png rename from website/hackergotchi/zajec.png rename to hackergotchi/zajec.png diff --git a/website/hackergotchi/zander.png b/hackergotchi/zander.png rename from website/hackergotchi/zander.png rename to hackergotchi/zander.png diff --git a/images/flags/cs.svg b/images/flags/cs.svg new file mode 100644 --- /dev/null +++ b/images/flags/cs.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/images/flags/de.svg b/images/flags/de.svg new file mode 100644 --- /dev/null +++ b/images/flags/de.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/images/flags/en.svg b/images/flags/en.svg new file mode 100644 --- /dev/null +++ b/images/flags/en.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/images/flags/es.svg b/images/flags/es.svg new file mode 100644 --- /dev/null +++ b/images/flags/es.svg @@ -0,0 +1,409 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/images/flags/fr.svg b/images/flags/fr.svg new file mode 100644 --- /dev/null +++ b/images/flags/fr.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/images/flags/gr.svg b/images/flags/gr.svg new file mode 100644 --- /dev/null +++ b/images/flags/gr.svg @@ -0,0 +1,4 @@ + + + + diff --git a/images/flags/id.svg b/images/flags/id.svg new file mode 100644 --- /dev/null +++ b/images/flags/id.svg @@ -0,0 +1,4 @@ + + + + diff --git a/images/flags/ja.svg b/images/flags/ja.svg new file mode 100644 --- /dev/null +++ b/images/flags/ja.svg @@ -0,0 +1,4 @@ + + + + diff --git a/images/flags/pl.svg b/images/flags/pl.svg new file mode 100644 --- /dev/null +++ b/images/flags/pl.svg @@ -0,0 +1,4 @@ + + + + diff --git a/images/flags/pt.svg b/images/flags/pt.svg new file mode 100644 --- /dev/null +++ b/images/flags/pt.svg @@ -0,0 +1,66 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/images/flags/ru.svg b/images/flags/ru.svg new file mode 100644 --- /dev/null +++ b/images/flags/ru.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/images/flags/tw.svg b/images/flags/tw.svg new file mode 100644 --- /dev/null +++ b/images/flags/tw.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/images/planet.svg b/images/planet.svg new file mode 100644 --- /dev/null +++ b/images/planet.svg @@ -0,0 +1,212 @@ + + Planet openSUSE + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/images/profile/gsoc.svg b/images/profile/gsoc.svg new file mode 100644 --- /dev/null +++ b/images/profile/gsoc.svg @@ -0,0 +1,8 @@ + + Group + + + + + + diff --git a/images/profile/irc.svg b/images/profile/irc.svg new file mode 100644 --- /dev/null +++ b/images/profile/irc.svg @@ -0,0 +1,3 @@ + + + diff --git a/index.html b/index.html new file mode 100644 --- /dev/null +++ b/index.html @@ -0,0 +1,16 @@ +--- +layout: default +pagination: + enabled: true +--- + +{% if paginator.page == 1 %} +{% include main-info.html %} +{% endif %} +
+ {% for post in paginator.posts %} + {% include calendar.html %} + {% include single-post.html language="true" %} + {% endfor %} + {% include pagination.html %} +
diff --git a/patches/articles-need-a-date.diff b/patches/articles-need-a-date.diff deleted file mode 100644 --- a/patches/articles-need-a-date.diff +++ /dev/null @@ -1,14 +0,0 @@ ---- orig/rawdog-2.12/rawdoglib/rawdog.py 2010-07-21 16:44:03.679987002 +0100 -+++ rawdog-2.12/rawdoglib/rawdog.py 2010-07-21 16:39:31.479987001 +0100 -@@ -1577,8 +1577,9 @@ - for (date, feed, seq, hash) in article_list: - a = found.get(hash) - if a is not None: -- articles.append(a) -- article_dates[a] = -date -+ if a.date is not None: #Added jriddell 2008-09-15, we don't want to show articles with no date -+ articles.append(a) -+ article_dates[a] = -date - - twitterArticles = [] - normalArticles = [] diff --git a/patches/blog-link-text.diff b/patches/blog-link-text.diff deleted file mode 100644 --- a/patches/blog-link-text.diff +++ /dev/null @@ -1,13 +0,0 @@ -Index: rawdoglib/rawdog.py -=================================================================== ---- planetkde/rawdoglib/rawdog.py (revision 1210327) -+++ planetkde/rawdoglib/rawdog.py (working copy) -@@ -480,7 +480,7 @@ - return r - - def get_html_link(self, config): -- s = self.get_html_name(config) -+ s = unicode(self.args['define_name'], 'utf-8').encode('ascii', 'xmlcharrefreplace') - if self.feed_info.has_key("link"): - return '' + s + '' - else: diff --git a/patches/blogurl.diff b/patches/blogurl.diff deleted file mode 100644 --- a/patches/blogurl.diff +++ /dev/null @@ -1,12 +0,0 @@ -Index: rawdoglib/rawdog.py -=================================================================== ---- planet/rawdoglib/rawdog.py (revision 1210312) -+++ planet/rawdoglib/rawdog.py (working copy) -@@ -1366,6 +1366,7 @@ - itembits["feed_hash"] = short_hash(feed.url) - itembits["feed_id"] = feed.get_id(config) - itembits["hash"] = short_hash(article.hash) -+ itembits["blogurl"] = feed_info.links[0]['href'] - - if description is not None: - itembits["description"] = description diff --git a/patches/microblog.diff b/patches/microblog.diff deleted file mode 100644 --- a/patches/microblog.diff +++ /dev/null @@ -1,112 +0,0 @@ ---- orig/rawdog-2.12/rawdoglib/rawdog.py 2009-02-06 17:41:58.000000000 +0000 -+++ rawdog-2.12/rawdoglib/rawdog.py 2010-07-21 15:08:47.659987002 +0100 -@@ -435,6 +435,10 @@ - sequence = 0 - for entry_info in p["entries"]: - article = Article(feed, entry_info, now, sequence) -+ for feedconfig in config["feedslist"]: -+ if feedconfig[0] == feed: -+ if feedconfig[2].has_key("define_microblog") and feedconfig[2]["define_microblog"] == "true": -+ article.twitter = True - ignore = plugins.Box(False) - plugins.call_hook("article_seen", rawdog, config, article, ignore) - if ignore.value: -@@ -502,6 +506,7 @@ - self.feed = feed - self.entry_info = entry_info - self.sequence = sequence -+ self.twitter = False - - modified = entry_info.get("modified_parsed") - self.date = None -@@ -1322,7 +1327,23 @@ - else: - title = "Link" - -- itembits["title_no_link"] = title -+ if 'twitter' in dir(article) and article.twitter: -+ split = title.split(":", 1) -+ text = split[0] + "" -+ split[1] = split[1].lstrip() -+ if split[1].startswith("@"): -+ atSplit = split[1].split(" ", 1) -+ twitterLink = atSplit[0].lstrip("@") -+ twitterLink = twitterLink.rstrip(":") -+ if len(atSplit) >= 2: -+ text = text + " " + atSplit[0] + "" + " " + atSplit[1] -+ else: -+ text = text + " " + atSplit[0] + "" -+ else: -+ text = text + " " + split[1] -+ itembits["title_no_link"] = text -+ else: -+ itembits["title_no_link"] = title - if link is not None: - itembits["url"] = string_to_html(link, config) - else: -@@ -1361,7 +1382,10 @@ - itembits["date"] = "" - - plugins.call_hook("output_item_bits", self, config, feed, article, itembits) -- itemtemplate = self.get_itemtemplate(config) -+ if 'twitter' in dir(article) and article.twitter: -+ itemtemplate = load_file("microblogitemtemplate") -+ else: -+ itemtemplate = self.get_itemtemplate(config) - f.write(fill_template(itemtemplate, itembits)) - - def write_remove_dups(self, articles, config, now): -@@ -1445,7 +1469,7 @@ - - return bits - -- def write_output_file(self, articles, article_dates, config): -+ def write_output_file(self, articles, twitterArticles, article_dates, config): - """Write a regular rawdog HTML output file.""" - f = StringIO() - dw = DayWriter(f, config) -@@ -1464,6 +1488,19 @@ - bits["items"] = f.getvalue() - f.close() - bits["num_items"] = str(len(articles)) -+ -+ #TWITTER -+ f = StringIO() -+ dw = DayWriter(f, config) -+ -+ for article in twitterArticles[:60]: -+ self.write_article(f, article, config) -+ -+ dw.close() -+ -+ bits["twitter"] = f.getvalue() -+ #end of TWITTER -+ - plugins.call_hook("output_bits", self, config, bits) - s = fill_template(self.get_template(config), bits) - outputfile = config["outputfile"] -@@ -1530,6 +1567,15 @@ - articles.append(a) - article_dates[a] = -date - -+ twitterArticles = [] -+ normalArticles = [] -+ for article in articles: -+ if 'twitter' in dir(article) and article.twitter == True: -+ twitterArticles.append(article) -+ else: -+ normalArticles.append(article) -+ articles = normalArticles -+ - plugins.call_hook("output_write", self, config, articles) - - if not plugins.call_hook("output_sorted_filter", self, config, articles): -@@ -1540,7 +1586,7 @@ - config.log("Selected ", len(articles), " of ", numarticles, " articles to write; ignored ", dup_count, " duplicates") - - if not plugins.call_hook("output_write_files", self, config, articles, article_dates): -- self.write_output_file(articles, article_dates, config) -+ self.write_output_file(articles, twitterArticles, article_dates, config) - - config.log("Finished write") - diff --git a/patches/multiple-pages.diff b/patches/multiple-pages.diff deleted file mode 100644 --- a/patches/multiple-pages.diff +++ /dev/null @@ -1,82 +0,0 @@ ---- orig/rawdog-2.12/rawdoglib/rawdog.py 2010-07-21 16:41:25.629987002 +0100 -+++ rawdog-2.12/rawdoglib/rawdog.py 2010-07-21 16:39:31.479987001 +0100 -@@ -662,6 +662,7 @@ - "feeddefaults" : {}, - "defines" : {}, - "outputfile" : "output.html", -+ "oldpages" : 5, - "maxarticles" : 200, - "maxage" : 0, - "expireage" : 24 * 60 * 60, -@@ -756,6 +757,8 @@ - plugins.load_plugins(dir, self) - elif l[0] == "outputfile": - self["outputfile"] = l[1] -+ elif l[0] == "oldpages": -+ self["oldpages"] = l[1] - elif l[0] == "maxarticles": - self["maxarticles"] = int(l[1]) - elif l[0] == "maxage": -@@ -1469,7 +1472,7 @@ - - return bits - -- def write_output_file(self, articles, twitterArticles, article_dates, config): -+ def write_output_file(self, articles, twitterArticles, article_dates, config, oldpage=0): - """Write a regular rawdog HTML output file.""" - f = StringIO() - dw = DayWriter(f, config) -@@ -1484,6 +1487,12 @@ - dw.close() - plugins.call_hook("output_items_end", self, config, f) - -+ if oldpage != config["oldpages"]: -+ filename = config["outputfile"].split("/")[-1:][0] # get the filename only -+ filename = filename.split(".html") -+ outputfile = filename[0] + str(oldpage+1) + ".html" -+ f.write('

Older blog entries

') -+ - bits = self.get_main_template_bits(config) - bits["items"] = f.getvalue() - f.close() -@@ -1503,7 +1511,11 @@ - - plugins.call_hook("output_bits", self, config, bits) - s = fill_template(self.get_template(config), bits) -- outputfile = config["outputfile"] -+ if oldpage > 0: -+ filename = config["outputfile"].split(".html") -+ outputfile = filename[0] + str(oldpage) + ".html" -+ else: -+ outputfile = config["outputfile"] - if outputfile == "-": - write_ascii(sys.stdout, s, config) - else: -@@ -1534,8 +1546,9 @@ - if not plugins.call_hook("output_sort_articles", self, config, article_list): - article_list.sort() - -- if config["maxarticles"] != 0: -- article_list = article_list[:config["maxarticles"]] -+#for multiple pages split further down -+# if config["maxarticles"] != 0: -+# article_list = article_list[:config["maxarticles"]] - - if config["splitstate"]: - wanted = {} -@@ -1586,8 +1599,13 @@ - - config.log("Selected ", len(articles), " of ", numarticles, " articles to write; ignored ", dup_count, " duplicates") - -- if not plugins.call_hook("output_write_files", self, config, articles, article_dates): -- self.write_output_file(articles, twitterArticles, article_dates, config) -+ for page in range(0, config["oldpages"]+1): -+ print "on page: " + str(page) -+ if config["maxarticles"] != 0: -+ pageArticles = articles[config["maxarticles"]*page:config["maxarticles"]*(page+1)] -+ -+ if not plugins.call_hook("output_write_files", self, config, pageArticles, article_dates): -+ self.write_output_file(pageArticles, twitterArticles, article_dates, config, page) - - config.log("Finished write") - diff --git a/patches/no_feedclass_rss_feed.diff b/patches/no_feedclass_rss_feed.diff deleted file mode 100644 --- a/patches/no_feedclass_rss_feed.diff +++ /dev/null @@ -1,24 +0,0 @@ ---- planetkde/plugins/rss.py~ 2010-08-13 11:00:45.506801003 +0100 -+++ planetkde/plugins/rss.py 2010-08-16 09:42:49.582541002 +0100 -@@ -162,8 +153,19 @@ - except ValueError: - maxarticles = len(articles) - for article in articles[:maxarticles]: -- xml_article = channel.newChild(None, 'item', None) -- self.article_to_xml(xml_article, rawdog, config, article) -+ #Planet KDE addition, don't include articles in a feedclass -+ feed = rawdog.feeds[article.feed] -+ itembits = {} -+ toAdd = True; -+ for name, value in feed.args.items(): -+ if name.startswith("define_"): -+ itembits[name[7:]] = value -+ if "feedclass" in itembits: -+ toAdd = False; -+ -+ if toAdd: -+ xml_article = channel.newChild(None, 'item', None) -+ self.article_to_xml(xml_article, rawdog, config, article) - - doc.saveFormatFile(self.options["outputxml"], 1) - doc.freeDoc() diff --git a/patches/readme.patch b/patches/readme.patch deleted file mode 100644 --- a/patches/readme.patch +++ /dev/null @@ -1,23 +0,0 @@ ---- ../orig/rawdog-2.12/README 2008-02-23 22:42:33.000000000 +0000 -+++ README 2010-07-22 09:15:30.206327001 +0100 -@@ -1,3 +1,20 @@ -+Planet KDE uses rawdog -+ -+To add your blog edit planetkde/config and add your photo head to website/hackergotchi/myname.png -+ -+To run locally edit planetkde/config and set outputfile and outputxml to the right directory. -+ -+Run it with -+ -+ ./rawdog -d planetkde --update -+ ./rawdog -d planetkde --write -+ -+will write to website/index.html and website/rss20.xml -+ -+Jonathan Riddell, 10-2008 -+ -+--- -+ - rawdog: RSS Aggregator Without Delusions Of Grandeur - Adam Sampson - diff --git a/patches/rss-author.diff b/patches/rss-author.diff deleted file mode 100644 --- a/patches/rss-author.diff +++ /dev/null @@ -1,18 +0,0 @@ -Index: planetkde/plugins/rss.py -=================================================================== ---- planet/planetkde/plugins/rss.py (revision 1210312) -+++ planet/planetkde/plugins/rss.py (working copy) -@@ -110,9 +110,12 @@ - title = escape(self.feed_name(rawdog.feeds[article.feed], config)) - s = detail_to_html(entry_info.get("title_detail"), True, config) - if s is not None: -- title += ": " + s.encode('utf8') -+ title = s.encode('utf8') - xml_article.newChild(None, 'title', title) - -+ author = escape(self.feed_name(rawdog.feeds[article.feed], config)) -+ xml_article.newChild(None, 'author', author) -+ - if article.date is not None: - date = rfc822_date(gmtime(article.date)) - xml_article.newChild(None, 'pubDate', date) diff --git a/patches/unicode.diff b/patches/unicode.diff deleted file mode 100644 --- a/patches/unicode.diff +++ /dev/null @@ -1,12 +0,0 @@ ---- ../../planet/rawdoglib/rawdog.py 2010-12-30 17:26:46.265332000 +0000 -+++ rawdoglib/rawdog.py 2010-12-30 17:25:34.593332001 +0000 -@@ -1390,6 +1390,9 @@ - itemtemplate = load_file("microblogitemtemplate") - else: - itemtemplate = self.get_itemtemplate(config) -+ -+ itembits['name'] = unicode(itembits['name'], 'utf-8').encode("ascii", "xmlcharrefreplace") -+ - f.write(fill_template(itemtemplate, itembits)) - - def write_remove_dups(self, articles, config, now): diff --git a/planet.ini b/planet.ini new file mode 100644 --- /dev/null +++ b/planet.ini @@ -0,0 +1,4236 @@ +title = Planet KDE + +[ujithhsujithh] + title = Sujith H (sujith_h) + feed = http://sujithh.info/feed/?tag=KDE-dev%2CPlasma-dev + link = http://sujithh.info + location = en + avatar = sujithh.png + +[jasonadonenfeldzx2c4jdonenfeld] + title = Jason A. Donenfeld (zx2c4/jdonenfeld) + feed = https://www.zx2c4.com/feed.xml + link = https://www.zx2c4.com/ + location = en + avatar = jdonenfeld.png + +[michaelpynempyne] + title = Michael Pyne (mpyne) + feed = https://www.purinchu.net/wp/feed/ + link = https://www.purinchu.net/wp/ + location = en + avatar = mpyne.png + +[maksimorlovichsadeagle] + title = Maksim Orlovich (SadEagle) + feed = https://blogs.kde.org/blog/11/feed + link = https://blogs.kde.org/blog/11 + location = en + +[boudewijnremptboud] + title = Boudewijn Rempt (boud) + feed = https://valdyas.org/fading/category/planet/feed/ + link = https://valdyas.org/ + location = en + +[petersimonssonpsn] + title = Peter Simonsson (psn) + feed = http://ramblingsofpsn.blogspot.com/feeds/posts/default + link = http://ramblingsofpsn.blogspot.com + location = en + +[derekkitedkite] + title = Derek Kite (dkite) + feed = http://digested.blogspot.com/atom.xml + link = http://digested.blogspot.com + location = en + +[annemariemahfoufannma] + title = Anne-Marie Mahfouf (annma) + feed = http://annma.blogspot.com/feeds/posts/default/-/KDE + link = http://annma.blogspot.com + location = en + avatar = annma.jpg + +[lukastinkl] + title = Lukas Tinkl + feed = http://ltinkl.blogspot.com/atom.xml + link = http://ltinkl.blogspot.com + location = en + +[richarddale] + title = Richard Dale + feed = https://blogs.kde.org/blog/89/feed + link = https://blogs.kde.org/blog/89 + location = en + +[garygreenegreeneg] + title = Gary Greene (greeneg) + feed = http://greeneg.blogspot.com/feeds/posts/default/-/KDE + link = http://greeneg.blogspot.com + location = en + +[scottwheelerwheels] + title = Scott Wheeler (wheels) + feed = https://blogs.kde.org/blog/72/feed + link = https://blogs.kde.org/blog/72 + location = en + avatar = wheels.png + +[richardmoorerichmoore2] + title = Richard Moore (richmoore2) + feed = https://blogs.kde.org/blog/9/feed + link = https://blogs.kde.org/blog/9 + location = en + +[mathieuchouinardchouimat] + title = Mathieu Chouinard (chouimat) + feed = https://blogs.kde.org/blog/35/feed + link = https://blogs.kde.org/blog/35 + location = en + avatar = chouimat.png + +[iangeisergeiseri] + title = Ian Geiser (geiseri) + feed = https://blogs.kde.org/blog/2/feed + link = https://blogs.kde.org/blog/2 + location = en + avatar = geiseri.png + +[tobiaskoenigtokoe] + title = Tobias Koenig (tokoe) + feed = http://tokoe-kde.blogspot.com/rss.xml + link = http://tokoe-kde.blogspot.com + location = en + +[zackrusinzrusin] + title = Zack Rusin (zrusin) + feed = http://zrusin.blogspot.com/rss.xml + link = http://zrusin.blogspot.com + location = en + +[heliocastroheliocastro] + title = Helio Castro (heliocastro) + feed = https://www.heliocastro.info/feeds/opensource.atom.xml + link = https://www.heliocastro.info + location = en + avatar = helio_castro.png + +[waldobastianzogje] + title = Waldo Bastian (zogje) + feed = https://blogs.kde.org/blog/70/feed + link = https://blogs.kde.org/blog/70 + location = en + +[corneliusschumacher] + title = Cornelius Schumacher + feed = https://blog.cornelius-schumacher.de/feeds/posts/default + link = https://blog.cornelius-schumacher.de + location = en + avatar = cornelius.png + +[jarosławstaniekjstaniek] + title = Jarosław Staniek (jstaniek) + feed = https://blogs.kde.org/blog/104/feed + link = https://blogs.kde.org/blog/104 + location = en + avatar = jstaniek.png + +[johnratke] + title = John Ratke + feed = https://blogs.kde.org/blog/395/feed + link = https://blogs.kde.org/blog/395 + location = en + +[jonathanriddellriddell_blog] + title = Jonathan Riddell (riddell) + feed = https://blogs.kde.org/blog/57/feed + link = https://blogs.kde.org/blog/57 + location = en + avatar = riddell.png + +[jonathanriddellriddell] + title = Jonathan Riddell (riddell) + feed = https://jriddell.org/feed/?tag=planetkde + link = https://jriddell.org + location = en + avatar = riddell.png + +[tilladam] + title = Till Adam + feed = https://blogs.kde.org/blog/432/feed + link = https://blogs.kde.org/blog/432 + location = en + +[stephanbinnerbeineri] + title = Stephan Binner (Beineri) + feed = https://blogs.kde.org/blog/457/feed + link = https://blogs.kde.org/blog/457 + location = en + avatar = beineri.png + +[bradhardsbradh] + title = Brad Hards (bradh) + feed = https://blogs.kde.org/blog/102/feed + link = https://blogs.kde.org/blog/102 + location = en + +[carstenniehauscarsten] + title = Carsten Niehaus (carsten) + feed = https://cniehaus.livejournal.com/data/atom + link = https://cniehaus.livejournal.com/ + location = en + +[adamtreatmanyoso] + title = Adam Treat (manyoso) + feed = https://blogs.kde.org/blog/105/feed + link = https://blogs.kde.org/blog/105 + location = en + avatar = manyoso.png + +[petridamstén] + title = Petri Damstén + feed = http://pdamsten.blogspot.com/feeds/posts/default/-/kde + link = http://pdamsten.blogspot.com + location = en + avatar = pdamsten.png + +[kurtpfeiflepipitas] + title = Kurt Pfeifle (pipitas) + feed = https://blogs.kde.org/blog/418/feed + link = https://blogs.kde.org/blog/418 + location = en + +[markkretschmannmarkey] + title = Mark Kretschmann (markey) + feed = http://mark-kretschmann.blogspot.com/feeds/posts/default + link = http://mark-kretschmann.blogspot.com + location = en + avatar = markey_gotchi.png + +[stephankulowcoolo] + title = Stephan Kulow (coolo) + feed = https://blogs.kde.org/blog/124/feed + link = https://blogs.kde.org/blog/124 + location = en + +[alexanderdymoadymo] + title = Alexander Dymo (adymo) + feed = http://www.alexdymo.com/blog/feed/kde.xml + link = http://www.alexdymo.com/blog/ + location = en + avatar = dymo.png + +[nadeemhasan] + title = Nadeem Hasan + feed = http://nhasan.blogspot.com/atom.xml + link = http://nhasan.blogspot.com + location = en + avatar = nadeem.png + +[philiprodriguesphilrod] + title = Philip Rodrigues (PhilRod) + feed = http://accentgrave.blogspot.com/atom.xml + link = http://accentgrave.blogspot.com + location = en + +[allenwinter] + title = Allen Winter + feed = https://blogs.kde.org/blog/1451/feed + link = https://blogs.kde.org/blog/1451 + location = en + +[carlosleonhardwoelzcwoelz] + title = Carlos Leonhard Woelz (cwoelz) + feed = https://blogs.kde.org/blog/225/feed + link = https://blogs.kde.org/blog/225 + location = en + +[henriquepinto] + title = Henrique Pinto + feed = https://blogs.kde.org/blog/299/feed + link = https://blogs.kde.org/blog/299 + location = en + +[albertastalscidtsdgeos] + title = Albert Astals Cid (TSDgeos) + feed = https://tsdgeos.blogspot.com/feeds/posts/default?alt=atom + link = https://tsdgeos.blogspot.com + location = en + avatar = TSDgeos.png + +[tomazcanabravatomaz] + title = Tomaz Canabrava (tomaz) + feed = https://tcanabrava.github.io/feed.xml + link = https://tcanabrava.github.io + location = en + avatar = tomaz-canabrava.png + +[lucijanbuschlucijan] + title = Lucijan Busch (lucijan) + feed = https://blogs.kde.org/blog/55/feed + link = https://blogs.kde.org/blog/55 + location = en + +[marccramdal] + title = Marc Cramdal + feed = http://marccramdal.blogspot.com/atom.xml + link = http://marccramdal.blogspot.com + location = en + +[allansandfeldjensencarewolf] + title = Allan Sandfeld Jensen (carewolf) + feed = https://blogs.kde.org/blog/278/feed + link = https://blogs.kde.org/blog/278 + location = en + +[janettheobromatheobroma] + title = Janet Theobroma (theobroma) + feed = http://theobromas.blogspot.com/atom.xml + link = http://theobromas.blogspot.com + location = en + avatar = theobroma.png + +[kurthindenburg] + title = Kurt Hindenburg + feed = https://blogs.kde.org/blog/460/feed + link = https://blogs.kde.org/blog/460 + location = en + +[adriaandegrootade] + title = Adriaan de Groot ([ade]) + feed = https://euroquis.nl/feed.xml + link = https://euroquis.nl + location = en + avatar = adridg.png + +[andrasmantia] + title = Andras Mantia + feed = https://blogs.kde.org/blog/20/feed + link = https://blogs.kde.org/blog/20 + location = en + +[josefspillner] + title = Josef Spillner + feed = http://www.kuarepoti-dju.net/tags/community:desktop/index.rss + link = http://www.kuarepoti-dju.net/ + location = en + +[willstephenson] + title = Will Stephenson + feed = https://blogs.kde.org/blog/77/feed + link = https://blogs.kde.org/blog/77 + location = en + +[christianloose] + title = Christian Loose + feed = http://www.christian-loose.de/wordpress/category/kde/feed/ + link = http://www.christian-loose.de/wordpress/ + location = en + +[janmuehligjanushead] + title = Jan Muehlig (janushead) + feed = https://blogs.kde.org/blog/938/feed + link = https://blogs.kde.org/blog/938 + location = en + +[tinatrillitzsch] + title = Tina Trillitzsch + feed = http://tina-t.blogspot.com/atom.xml + link = http://tina-t.blogspot.com + location = en + avatar = tina.png + +[fabricemousfab] + title = Fabrice Mous + feed = https://blogs.kde.org/blog/175/feed + link = https://blogs.kde.org/blog/175 + location = en + avatar = fab.png + author = irc:fab + +[cristiantibirnainorog] + title = Cristian Tibirna (Inorog) + feed = https://blogs.kde.org/blog/311/feed + link = https://blogs.kde.org/blog/311 + location = en + +[nikolaszimmermannwildfox] + title = Nikolas Zimmermann (WildFox) + feed = https://blogs.kde.org/blog/1088/feed + link = https://blogs.kde.org/blog/1088 + location = en + +[frankosterfeldfosterfeld] + title = Frank Osterfeld (fosterfeld) + feed = https://blogs.kde.org/blog/699/feed + link = https://blogs.kde.org/blog/699 + location = en + +[robbuisrwlbuis] + title = Rob Buis (rwlbuis) + feed = https://blogs.kde.org/blog/1089/feed + link = https://blogs.kde.org/blog/1089 + location = en + +[christophcullmanncullmann] + title = Christoph Cullmann (cullmann) + feed = https://cullmann.io/index.xml + link = https://cullmann.io + location = en + avatar = cullmann.png + +[katenews] + title = Kate News + feed = https://kate-editor.org/index.xml + link = https://kate-editor.org + location = news + avatar = kate.png + +[reinholdkainhofer] + title = Reinhold Kainhofer + feed = https://blogs.kde.org/blog/16/feed + link = https://blogs.kde.org/blog/16 + location = en + +[markusslopiankamarkuss] + title = Markus Slopianka (markuss) + feed = https://kamikazow.wordpress.com/feed/?mrss=off + link = https://kamikazow.wordpress.com + location = en + +[rolandwoltersliquidat] + title = Roland Wolters (liquidat) + feed = https://liquidat.wordpress.com/category/kde/feed/?mrss=off + link = https://liquidat.wordpress.com/ + location = en + +[jasonharrislmcboy] + title = Jason Harris (LMCboy) + feed = https://blogs.kde.org/blog/38/feed + link = https://blogs.kde.org/blog/38 + location = en + +[stefanteleman] + title = Stefan Teleman + feed = https://blogs.kde.org/blog/242/feed + link = https://blogs.kde.org/blog/242 + location = en + +[antoniolarrosajimenezantlarr] + title = Antonio Larrosa Jimenez (antlarr) + feed = https://blogs.kde.org/blog/1186/feed + link = https://blogs.kde.org/blog/1186 + location = en + +[alexanderneundorf] + title = Alexander Neundorf + feed = https://blogs.kde.org/blog/531/feed + link = https://blogs.kde.org/blog/531 + location = en + +[martijnklingens] + title = Martijn Klingens + feed = https://blogs.kde.org/blog/1192/feed + link = https://blogs.kde.org/blog/1192 + location = en + +[ashleywinters] + title = Ashley Winters + feed = https://jahqueel.blogspot.com/atom.xml + link = https://jahqueel.blogspot.com + location = en + +[gregoriaskievitch] + title = Gregor Iaskievitch + feed = https://blogs.kde.org/blog/41/feed + link = https://blogs.kde.org/blog/41 + location = en + +[nunopinheiropinheiro] + title = Nuno Pinheiro (pinheiro) + feed = https://pinheiro-kde.blogspot.com/rss.xml + link = https://pinheiro-kde.blogspot.com + location = en + avatar = pinheiro.png + +[sebastianküglersebas] + title = Sebastian Kügler + feed = https://vizZzion.org/blog/category/english/feed/ + link = https://vizZzion.org/blog/category/english/ + location = en + avatar = sebascolor.png + author = irc:sebas + +[danleinirturthrajensenleinir] + title = Dan Leinir Turthra Jensen + feed = https://kath-leinir.blogspot.com/feeds/posts/default/-/kde + link = https://kath-leinir.blogspot.com + location = en + avatar = leinir.png + author = irc:leinir + +[jamesots] + title = James Ots + feed = http://jamesots.blogspot.com/atom.xml + link = http://jamesots.blogspot.com + location = en + +[ciesbreijscies] + title = Cies Breijs (cies) + feed = http://ciesbreijs.blogspot.com/atom.xml + link = http://ciesbreijs.blogspot.com + location = en + +[kevinkrammer] + title = Kevin Krammer + feed = https://blogs.kde.org/blog/83/feed + link = https://blogs.kde.org/blog/83 + location = en + +[simonedwards] + title = Simon Edwards + feed = https://blogs.kde.org/blog/1195/feed + link = https://blogs.kde.org/blog/1195 + location = en + +[dariomassarin] + title = Dario Massarin + feed = https://blogs.kde.org/blog/838/feed + link = https://blogs.kde.org/blog/838 + location = en + +[robertmathiasmarmorsteinrobertm] + title = Robert Mathias Marmorstein (robertm) + feed = https://blogs.kde.org/blog/7440/feed + link = https://blogs.kde.org/blog/7440 + location = en + +[mattbroadstone] + title = Matt Broadstone + feed = http://mbroadst.blogspot.com/atom.xml + link = http://mbroadst.blogspot.com + location = en + +[johanthelin] + title = Johan Thelin + feed = http://www.thelins.se/johan/blog/feed/ + link = http://www.thelins.se/johan/blog + location = en + +[kennethwimerkwwii] + title = Kenneth Wimer (kwwii) + feed = http://kwwii.blogspot.com/feeds/posts/default/-/KDE + link = http://kwwii.blogspot.com + location = en + +[lubošluňákllunak] + title = Luboš Luňák (llunak) + feed = http://llunak.blogspot.com/feeds/posts/default/-/kde + link = http://llunak.blogspot.com + location = en + +[martinkonoldmortimer] + title = Martin Konold (Mortimer) + feed = https://blogs.kde.org/blog/952/feed + link = https://blogs.kde.org/blog/952 + location = en + +[ingewalliningwa] + title = Inge Wallin (ingwa) + feed = http://ingwa2.blogspot.com/atom.xml + link = http://ingwa2.blogspot.com + location = en + +[mojtabashahisenobarimoji] + title = Mojtaba Shahi Senobari + feed = http://moji-shahi.blogspot.com/atom.xml + link = http://moji-shahi.blogspot.com + location = en + author = irc:moji + +[deniskuplyakovdenerkup_calligra] + title = Denis Kuplyakov + feed = http://calligra-author-outliner.blogspot.ru/atom.xml + link = http://calligra-author-outliner.blogspot.ru + author = irc:denerkup + location = en + +[jesperkpedersenblackie] + title = Jesper K. Pedersen (blackie) + feed = https://blogs.kde.org/blog/1397/feed + link = https://blogs.kde.org/blog/1397 + location = en + avatar = blackie.png + +[torstenrahntackat] + title = Torsten Rahn (tackat) + feed = https://blogs.kde.org/blog/551/feed + link = https://blogs.kde.org/blog/551 + location = en + +[fredrikhoumlglund] + title = Fredrik Höglund + feed = http://fredrikh.blogspot.com/atom.xml + link = http://fredrikh.blogspot.com + location = en + +[cyrilleberger] + title = Cyrille Berger + feed = http://blog.cberger.net/category/open-source/feed/?mrss=off + link = http://blog.cberger.net/category/open-source + location = en + avatar = cberger.png + +[clarencedang] + title = Clarence Dang + feed = http://clarencedang.blogspot.com/atom.xml + link = http://clarencedang.blogspot.com + location = en + +[vladimirprus] + title = Vladimir Prus + feed = http://blog.vladimirprus.com/feeds/posts/default/-/kde + link = http://blog.vladimirprus.com + location = en + +[aureliengateau] + title = Aurelien Gateau + feed = https://agateau.com/tags/pko/feed + link = https://agateau.com/tags/pko + location = en + +[sanderkoning] + title = Sander Koning + feed = http://delftblueramblings.blogspot.com/atom.xml + link = http://delftblueramblings.blogspot.com + location = en + +[jeffmitchelljefferai] + title = Jeff Mitchell (jefferai) + feed = http://jefferai.org/atom.xml + link = http://jefferai.org + location = en + +[mirkoboehmmiroslavblog] + title = Mirko Boehm (miroslav) + feed = https://blogs.kde.org/blog/1813/feed + link = https://blogs.kde.org/blog/1813 + location = en + +[davidfauredfaure] + title = David Faure (dfaure) + feed = https://blogs.kde.org/blog/326/feed + link = https://blogs.kde.org/blog/326 + location = en + +[cboemannboemann] + title = C. Boemann (boemann) + feed = https://blogs.kde.org/blog/1236/feed + link = https://blogs.kde.org/blog/1236 + location = en + +[fransenglichfranse] + title = Frans Englich (FransE) + feed = https://englich.wordpress.com/feed/?mrss=off + link = https://englich.wordpress.com + location = en + +[friedrichkossebaufrinring] + title = Friedrich Kossebau (frinring) + feed = https://frinring.wordpress.com/category/kde/feed/?mrss=off&category_name=kde + link = https://frinring.wordpress.com/category/kde + location = en + avatar = frinring.png + +[sebastiansauerdipesh] + title = Sebastian Sauer (dipesh) + feed = https://blogs.kde.org/blog/477/feed + link = https://blogs.kde.org/blog/477 + location = en + +[bartcoppensbcoppens] + title = Bart Coppens (BCoppens) + feed = https://blogs.kde.org/blog/1471/feed + link = https://blogs.kde.org/blog/1471 + location = en + +[chaniarmitagechani] + title = Chani Armitage (Chani) + feed = https://chani.wordpress.com/category/planet/feed/?mrss=off&category_name=planet + link = https://chani.wordpress.com/category/planet + location = en + +[hamishroddablackarrow] + title = Hamish Rodda (blackarrow) + feed = https://blogs.kde.org/blog/56/feed + link = https://blogs.kde.org/blog/56 + location = en + +[josvandenoevervandenoever] + title = Jos van den Oever (vandenoever) + feed = https://www.vandenoever.info/index.atom + link = https://www.vandenoever.info + location = en + avatar = vandenoever.png + +[egonwillighagen] + title = Egon Willighagen + feed = http://kemistry-desktop.blogspot.com/atom.xml + link = http://kemistry-desktop.blogspot.com + location = en + +[dannykukawka] + title = Danny Kukawka + feed = https://blog.bisect.de/feeds/posts/default?alt=atom + link = https://blog.bisect.de + location = en + +[evabrucherseifer] + title = Eva Brucherseifer + feed = http://transloid.blogspot.com/feeds/posts/default + link = http://transloid.blogspot.com + location = en + +[remivillatel] + title = Remi Villatel + feed = http://maxilys.blogspot.com/rss.xml + link = http://maxilys.blogspot.com + location = en + +[wadeolson] + title = Wade Olson + feed = https://wadejolson.wordpress.com/feed/?mrss=off + link = https://wadejolson.wordpress.com + location = en + +[robertknight] + title = Robert Knight + feed = http://kdemonkey.blogspot.com/feeds/posts/default + link = http://kdemonkey.blogspot.com + location = en + +[ivančukićivan] + title = Ivan Čukić (ivan) + feed = https://cukic.co/feeds/tag-planetkde.xml + link = https://cukic.co + location = en + avatar = ivan.png + +[vladimirkuznetsov] + title = Vladimir Kuznetsov + feed = http://ksvladimir.blogspot.com/atom.xml + link = http://ksvladimir.blogspot.com + location = en + +[jarleakselsen] + title = Jarle Akselsen + feed = http://jarlesdraw-log.blogspot.com/atom.xml + link = http://jarlesdraw-log.blogspot.com + location = en + +[jospoortvliet] + title = Jos Poortvliet + feed = http://blog.jospoortvliet.com/feeds/posts/default/-/kde/?alt=rss + link = http://blog.jospoortvliet.com + location = en + avatar = jospoortvliet.png + +[bartcerneelsstecchino] + title = Bart Cerneels (Stecchino) + feed = http://commonideas.blogspot.com/feeds/posts/default/-/KDE + link = http://commonideas.blogspot.com + location = en + +[kevinottenservin] + title = Kevin Ottens (ervin) + feed = https://ervin.ipsquad.net/atom.xml + link = https://ervin.ipsquad.net + location = en + +[zanshinannouncements] + title = Zanshin Announcements + feed = https://zanshin.kde.org/atom.xml + link = https://zanshin.kde.org + location = en + +[aleixpolapol] + title = Aleix Pol + feed = http://www.proli.net/feed/ + link = http://www.proli.net + location = en + author = irc:apol + +[marcushanwellcryos] + title = Marcus Hanwell (cryos) + feed = https://cryos.net/categories/kde/index.xml + link = https://cryos.net/categories/kde + location = en + author = irc:cryos + +[martyncircus] + title = Martyn Circus + feed = https://ksounds.wordpress.com/feed/?mrss=off + link = https://ksounds.wordpress.com + location = en + +[rivolaks] + title = Rivo Laks + feed = http://rivolaks.blogspot.com/feeds/posts/default + link = http://rivolaks.blogspot.com + location = en + +[janhambrechtjaham] + title = Jan Hambrecht (jaham) + feed = https://jaham.wordpress.com/category/kde/feed/?mrss=off&category_name=kde + link = https://jaham.wordpress.com/category/kde + location = en + +[dominikseichter] + title = Dominik Seichter + feed = http://domseichter.blogspot.com/feeds/posts/default + link = http://domseichter.blogspot.com + location = en + +[christianehrlicher] + title = Christian Ehrlicher + feed = http://chehrlic.blogspot.com/rss.xml + link = http://chehrlic.blogspot.com + location = en + +[alexandrgoncearenco] + title = Alexandr Goncearenco + feed = http://neksa.blogspot.com/rss.xml + link = http://neksa.blogspot.com + location = en + +[andreaspakulat] + title = Andreas Pakulat + feed = https://apaku.wordpress.com/feed/?mrss=off + link = https://apaku.wordpress.com + location = en + +[haraldsitterapachelogger] + title = Harald Sitter (apachelogger) + feed = https://apachelog.wordpress.com/category/kde/feed/?mrss=off&category_name=kde + link = https://apachelog.wordpress.com/category/kde + location = en + avatar = apachelogger.jpg + +[mauriziomonge] + title = Maurizio Monge + feed = https://myrizio.wordpress.com/feed/?mrss=off + link = https://myrizio.wordpress.com + location = en + +[piyushverma] + title = Piyush Verma + feed = https://meson10.wordpress.com/feed/?mrss=off + link = https://meson10.wordpress.com + location = en + +[alexismenarddarktears] + title = Alexis Menard (darktears) + feed = https://darktears.wordpress.com/category/kde/feed/?mrss=off&category_name=kde + link = https://darktears.wordpress.com/category/kde + location = en + avatar = alexis-menard.jpg + +[sriramadossmamachu] + title = Sri Ramadoss M (amachu) + feed = https://amachu.wordpress.com/feed/?mrss=off&category_name=kde + link = https://amachu.wordpress.com + location = en + +[davidmiller] + title = David Miller + feed = https://kdedmiller.wordpress.com/feed/?mrss=off + link = https://kdedmiller.wordpress.com + location = en + +[sebastianpippingsping] + title = Sebastian Pipping (sping) + feed = http://blog.hartwork.org/?feed=rss2&cat=23 + link = http://blog.hartwork.org/ + location = en + +[jeremywhitingjpwhiting] + title = Jeremy Whiting (jpwhiting) + feed = http://jpwhiting.blogspot.com/feeds/posts/default/-/kde + link = http://jpwhiting.blogspot.com + location = en + avatar = jpwhiting.jpg + +[petergrasch] + title = Peter Grasch + feed = http://simon-listens.blogspot.com/rss.xml + link = http://simon-listens.blogspot.com + location = en + avatar = pgrasch.png + +[shawnstarrspstarr] + title = Shawn Starr (spstarr) + feed = https://blogs.kde.org/blog/4267/feed + link = https://blogs.kde.org/blog/4267 + location = en + avatar = spstarr.png + +[frederikgladhornfregl] + title = Frederik Gladhorn + feed = https://blogs.kde.org/blog/4326/feed + link = https://blogs.kde.org/blog/4326 + author = irc:fregl + location = en + avatar = frederik_gladhorn.jpeg + +[frederikgladhornfregl_fsfe] + title = Frederik Gladhorn + feed = https://blogs.fsfe.org/gladhorn/category/kde/feed/ + link = https://blogs.fsfe.org/gladhorn/ + location = en + author = irc:fregl + avatar = frederik_gladhorn.jpeg + +[andreasrammpsychobrain] + title = Andreas Ramm (psychobrain) + feed = http://psychobrain.blogspot.com/rss.xml + link = http://psychobrain.blogspot.com + location = en + +[alexmerry] + title = Alex Merry + feed = https://randomguy3.wordpress.com/tag/kde/feed/?mrss=off + link = https://randomguy3.wordpress.com/tag/kde + location = en + avatar = randomguy3.png + +[pradeeptobhattacharya] + title = Pradeepto Bhattacharya + feed = http://www.livejournal.com/users/pradeepto/data/rss + link = http://www.livejournal.com/users/pradeepto + location = en + +[lydiapintschernightrose] + title = Lydia Pintscher (Nightrose) + feed = http://blog.lydiapintscher.de/category/PlanetKDE/feed/ + link = http://blog.lydiapintscher.de/category/PlanetKDE + location = en + avatar = nightrose.png + +[roozbehshafiee] + title = Roozbeh Shafiee + feed = http://feeds.feedburner.com/slashrosha/en/kde + link = http://feeds.feedburner.com/slashrosha/en/kde + location = en + avatar = roozbeh.jpeg + +[diegoiastrubni] + title = Diego Iastrubni + feed = http://elcuco2.blogspot.com/feeds/posts/default + link = http://elcuco2.blogspot.com + location = en + +[holgerfreytherzecke] + title = Holger Freyther (zecke) + feed = http://www.moiji-mobile.com/tag/kde/feed/ + link = http://www.moiji-mobile.com/tag/kde + location = en + +[fathiboudrafabo] + title = Fathi Boudra (fabo) + feed = http://fboudra.free.fr/wordpress/wp-rss2.php?cat=6 + link = http://fboudra.free.fr/wordpress/wp-rss2.php + location = en + avatar = fabo.png + +[sunevuorelasvuorela] + title = Sune Vuorela (svuorela) + feed = https://pusling.com/blog/?feed=rss2&cat=4 + link = https://pusling.com/blog/ + location = en + avatar = svuorela.png + +[davidnolden] + title = David Nolden + feed = https://zwabel.wordpress.com/feed/?mrss=off + link = https://zwabel.wordpress.com + location = en + +[jankundrátjkt] + title = Jan Kundrát (jkt) + feed = http://jkt.flaska.net/blog/tags/kde/kde.rss + link = http://jkt.flaska.net/blog/tags/kde + location = en + +[lukasappelhans] + title = Lukas Appelhans + feed = https://boom1992.wordpress.com/feed/?mrss=off + link = https://boom1992.wordpress.com + location = en + +[dmitrysuzdalevdimsuz] + title = Dmitry Suzdalev (dimsuz) + feed = https://dimsuz.wordpress.com/feed/?mrss=off + link = https://dimsuz.wordpress.com + location = en + +[ryanbitanga] + title = Ryan Bitanga + feed = http://rbitanga.blogspot.com/rss.xml + link = http://rbitanga.blogspot.com + location = en + +[vladcodrea] + title = Vlad Codrea + feed = http://vladcodrea.blogspot.com/rss.xml + link = http://vladcodrea.blogspot.com + location = en + +[rolfeikebeerdakon] + title = Rolf Eike Beer (Dakon) + feed = http://der-dakon.net/blog/kde.xml + link = http://der-dakon.net/blog + location = en + +[carloslicea] + title = Carlos Licea + feed = http://carloslicea.blogspot.com/feeds/posts/default/-/planetkde + link = http://carloslicea.blogspot.com + location = en + +[patrickspendrinsaroengels] + title = Patrick Spendrin (SaroEngels) + feed = http://saroengels.blogspot.com/feeds/posts/default + link = http://saroengels.blogspot.com + location = en + +[bartoszwadolowski] + title = Bartosz Wadolowski + feed = http://feeds.feedburner.com/LamersCorner + link = http://feeds.feedburner.com/LamersCorner + location = en + +[richardjohnsonnixternal] + title = Richard Johnson (nixternal) + feed = http://feeds.feedburner.com/nixternal-kde + link = http://feeds.feedburner.com/nixternal-kde + location = en + avatar = nixternal.png + +[sebastiantrueg] + title = Sebastian Trueg + feed = https://blogs.kde.org/blog/2904/feed + link = https://blogs.kde.org/blog/2904 + location = en + +[marcomartinnotmart] + title = Marco Martin (notmart) + feed = http://notmart.org/blog/tag/kde/feed/ + link = http://notmart.org/blog/tag/kde + location = en + avatar = notmart.png + +[georgegoldberggrundleborg] + title = George Goldberg (grundleborg) + feed = https://grundleborg.wordpress.com/feed/?mrss=off&category_name=kde + link = https://grundleborg.wordpress.com + location = en + +[peterpenz] + title = Peter Penz + feed = http://ppenz.blogspot.com/feeds/posts/default/-/KDE + link = http://ppenz.blogspot.com + location = en + avatar = ppenz.png + +[paulpachecopaulpach] + title = Paul Pacheco (paulpach) + feed = http://paul-pach.blogspot.com/rss.xml + link = http://paul-pach.blogspot.com + location = en + +[alspehrblauzahl] + title = A. L. Spehr (blauzahl) + feed = https://blauzahl.livejournal.com/data/rss?tag=kde + link = https://blauzahl.livejournal.com + location = en + avatar = zahl.png + +[arindamghosh] + title = Arindam Ghosh + feed = https://arindamghosh.wordpress.com/category/kde/feed/?mrss=off&category_name=kde + link = https://arindamghosh.wordpress.com/category/kde + location = en + +[robscheepmakerpinda] + title = Rob Scheepmaker (pinda) + feed = https://pindablog.wordpress.com/feed/?mrss=off + link = https://pindablog.wordpress.com + location = en + +[eduardorobleselviraedulix] + title = Eduardo Robles Elvira (Edulix) + feed = https://edulix.wordpress.com/category/kde/feed/?mrss=off&category_name=kde + link = https://edulix.wordpress.com/category/kde + location = en + +[alexandraleissetroubalex] + title = Alexandra Leisse (troubalex) + feed = http://untangled.biz/category/kde/feed/ + link = http://untangled.biz/category/kde + location = en + +[vyacheslavtokarevvtokarev] + title = Vyacheslav Tokarev (vtokarev) + feed = https://vtokarev.wordpress.com/feed/?mrss=off + link = https://vtokarev.wordpress.com + location = en + +[marijnkruisselbrink] + title = Marijn Kruisselbrink + feed = https://blogs.kde.org/blog/2892/feed + link = https://blogs.kde.org/blog/2892 + location = en + +[haraldhvaalmetellius] + title = Harald Hvaal (metellius) + feed = https://metelliuscode.wordpress.com/feed/?mrss=off + link = https://metelliuscode.wordpress.com + location = en + +[alessandrodiaferiaalediaferia] + title = Alessandro Diaferia (alediaferia) + feed = http://alediaferia.blogspot.com/feeds/posts/default + link = http://alediaferia.blogspot.com + location = en + +[simonstjamesssjgz] + title = Simon St James (SSJ_GZ) + feed = http://ssj-gz.blogspot.com/feeds/posts/default + link = http://ssj-gz.blogspot.com + location = en + +[danieljones] + title = Daniel Jones + feed = http://kopophex.blogspot.com/feeds/posts/default + link = http://kopophex.blogspot.com + location = en + +[teomrnjavacteo] + title = Teo Mrnjavac (teo-) + feed = http://teom.org/feed/?mrss=off&category_name=kde + link = http://teom.org + location = en + avatar = teo.png + +[alejandrowainzingerxevix] + title = Alejandro Wainzinger (xevix) + feed = http://awainzin-foss.blogspot.com/feeds/posts/default/-/KDE?alt=rss + link = http://awainzin-foss.blogspot.com + location = en + +[paugarciaiquilespgquiles] + title = Pau Garcia i Quiles (pgquiles) + feed = http://www.elpauer.org/category/kde/feed/ + link = http://www.elpauer.org/category/kde + location = en + avatar = pgquiles.png + +[fabriziomontesifmontesi] + title = Fabrizio Montesi (fmontesi) + feed = http://fmontesi.blogspot.com/feeds/posts/default/-/kde + link = http://fmontesi.blogspot.com + location = en + avatar = fmontesi.png + +[frankkarlitschekkarli] + title = Frank Karlitschek (karli) + feed = https://karlitschek.de/category/kde/feed/ + link = https://karlitschek.de/category/kde + location = en + avatar = karli.png + +[stefanmajewskymajewsky] + title = Stefan Majewsky (majewsky) + feed = https://majewsky.wordpress.com/feed/?mrss=off + link = https://majewsky.wordpress.com + location = en + avatar = majewsky.png + +[michaeljansen] + title = Michael Jansen + feed = http://michael-jansen.name/feeds/all.atom.xml + link = http://michael-jansen.name + location = en + +[dariofreddidrf] + title = Dario Freddi (drf__) + feed = https://drfav.wordpress.com/tag/kde/feed/?mrss=off&tag=kde + link = https://drfav.wordpress.com/tag/kde + location = en + avatar = drf.png + +[martingräßlin] + title = Martin Gräßlin + feed = http://blog.martin-graesslin.com/blog/kategorien/kde/planetkde/feed/ + link = http://blog.martin-graesslin.com/blog/kategorien/kde/planetkde + location = en + +[germaingarand] + title = Germain Garand + feed = https://blogs.kde.org/blog/6425/feed + link = https://blogs.kde.org/blog/6425 + location = en + +[nickshaforostoffshaforostoff] + title = Nick Shaforostoff (shaforostoff) + feed = http://shaforostoff.blogspot.com/atom.xml + link = http://shaforostoff.blogspot.com + location = en + avatar = shaforostoff.png + +[annewilsonannew] + title = Anne Wilson (annew) + feed = http://lydgate.org/blogs/tag/kde/feed/ + link = http://lydgate.org/blogs/tag/kde + location = en + avatar = annew.png + +[akarshsimhakstar] + title = Akarsh Simha (kstar) + feed = https://kstars.wordpress.com/feed/?mrss=off&category_name=gnulinuxfoss%2Fkde%2Fplanetkde-kde-gnulinuxfoss + link = https://kstars.wordpress.com + location = en + avatar = asimha.png + +[tejasdinkargja] + title = Tejas Dinkar (gja) + feed = https://tejasd.livejournal.com/data/rss?tag=kde + link = https://tejasd.livejournal.com + location = en + avatar = dinkar.png + +[xaviervelloxvello] + title = Xavier Vello (xvello) + feed = https://xvello.wordpress.com/tag/kde/feed/?mrss=off&tag=kde + link = https://xvello.wordpress.com/tag/kde + location = en + +[saschapeilickesaschpe] + title = Sascha Peilicke (saschpe) + feed = https://saschpe.wordpress.com/category/opensource/kde/feed/?mrss=off&category_name=opensource%2Fkde + link = https://saschpe.wordpress.com/category/opensource/kde + location = en + avatar = saschpe.png + +[evgeniyivanovpowerfoxpfx] + title = Evgeniy Ivanov (powerfox/pfx) + feed = http://www.eivanov.com/feeds/posts/default/-/planetkde + link = http://www.eivanov.com + location = en + +[johnpaulstanfordjp] + title = John-Paul Stanford (jp) + feed = http://shield008.blogspot.com/feeds/posts/default/-/KDE + link = http://shield008.blogspot.com + location = en + +[detlevcasanovacazou] + title = Detlev Casanova (Cazou) + feed = http://cazou.blogspot.com/feeds/posts/default/-/kde + link = http://cazou.blogspot.com + location = en + +[jaroslavřezníkjreznik] + title = Jaroslav Řezník (jreznik) + feed = http://borntobeopen.blogspot.com/feeds/posts/default/-/KDE + link = http://borntobeopen.blogspot.com + location = en + avatar = rezza.png + +[klaasfreitagdragotin] + title = Klaas Freitag (dragotin) + feed = https://dragotin.wordpress.com/feed/?mrss=off + link = https://dragotin.wordpress.com + location = en + avatar = freitag75.png + +[danielmeltzerhydrogen] + title = Daniel Meltzer (hydrogen) + feed = https://amarok.kde.org/en/blog/7/feed + link = https://amarok.kde.org/en/blog/7 + location = en + +[rexdieterrdieter] + title = Rex Dieter (rdieter) + feed = http://rdieter.blogspot.com/feeds/posts/default/-/kde + link = http://rdieter.blogspot.com + location = en + avatar = rdieter.png + +[lukastvrdylukast] + title = Lukas Tvrdy (lukast) + feed = http://lukast.mediablog.sk/log/?feed=rss2 + link = http://lukast.mediablog.sk/log/ + location = en + +[svenlangkampslangkamp] + title = Sven Langkamp (slangkamp) + feed = https://slangkamp.wordpress.com/feed/?mrss=off + link = https://slangkamp.wordpress.com + location = en + +[lucabeltrameeinar77] + title = Luca Beltrame (einar77) + feed = https://www.dennogumi.org/category/kde/feed/atom.xml + link = https://www.dennogumi.org/category/kde + location = en + +[ingomalchowneverendingo] + title = Ingo Malchow (neverendingo) + feed = http://blog.neverendingo.de/category/kde/feed/ + link = http://blog.neverendingo.de/category/kde + location = en + +[andreadiamantiniadjam] + title = Andrea Diamantini (adjam) + feed = https://adjamblog.wordpress.com/category/international/feed/?mrss=off&category_name=international + link = https://adjamblog.wordpress.com/category/international + location = en + avatar = adjam.png + +[valeriopiloamroth] + title = Valerio Pilo (Amroth) + feed = http://amroth.coldshock.net/kmess/blog/feed/ + link = http://amroth.coldshock.net/kmess/blog + location = en + avatar = valerio-pilo.jpg + +[christophfeckkdepepo] + title = Christoph Feck (kdepepo) + feed = https://kdepepo.wordpress.com/category/kde/feed/?mrss=off&category_name=kde + link = https://kdepepo.wordpress.com/category/kde + location = en + avatar = cfeck.png + +[sebastiantruegtrueg] + title = Sebastian Trueg (trueg) + feed = https://trueg.wordpress.com/feed/?mrss=off + link = https://trueg.wordpress.com + location = en + avatar = trueg.jpg + +[wanghoiwkai] + title = Wang Hoi (wkai) + feed = http://qiacat.blogspot.com/feeds/posts/default/-/planetKDE + link = http://qiacat.blogspot.com + location = en + avatar = wkai.jpeg + +[johannesbergmeierjoselb] + title = Johannes Bergmeier (joselb) + feed = http://joselb.blogspot.com/rss.xml + link = http://joselb.blogspot.com + location = en + avatar = joselb.png + +[mauroiazziiazzi] + title = Mauro Iazzi (iazzi) + feed = http://mauroiazzi.blogspot.com/feeds/posts/default/-/KDE + link = http://mauroiazzi.blogspot.com + location = en + +[ahmedghonim] + title = Ahmed Ghonim + feed = http://zrchrn.blogspot.com/feeds/posts/default + link = http://zrchrn.blogspot.com + location = en + avatar = ahmed-ghonim.png + +[jonathanthomasjontheechidna] + title = Jonathan Thomas (JontheEchidna) + feed = https://jontheechidna.wordpress.com/feed/?mrss=off&category_name=kde + link = https://jontheechidna.wordpress.com + location = en + avatar = echidnaman.png + +[stephenkellysteveire] + title = Stephen Kelly (steveire) + feed = https://steveire.wordpress.com/feed/?mrss=off + link = https://steveire.wordpress.com + location = en + +[thomasthymungethym] + title = Thomas Thym (ungethym) + feed = http://ungethym.blogspot.com/feeds/posts/default/-/planetkde + link = http://ungethym.blogspot.com + location = en + avatar = thomas-thum.jpg + +[sandroandradesandroandrade] + title = Sandro Andrade (sandroandrade) + feed = https://sandroandrade.org/tag/planet-kde/rss/ + link = https://sandroandrade.org/tag/planet-kde + location = en + avatar = sandroandrade.png + +[mahfuz062] + title = Mahfuz062 + feed = https://mahfuz062.wordpress.com/feed/?mrss=off + link = https://mahfuz062.wordpress.com + location = en + avatar = mahfuz.png + +[georgekiagiadakisgkiagia] + title = George Kiagiadakis (gkiagia) + feed = https://gkiagia.wordpress.com/category/kde/feed/?mrss=off&category_name=kde + link = https://gkiagia.wordpress.com/category/kde + location = en + +[bastianholstbholst] + title = Bastian Holst (bholst) + feed = https://blogs.kde.org/blog/6843/feed + link = https://blogs.kde.org/blog/6843 + location = en + +[prakashmohanpraksh] + title = Prakash Mohan (praksh) + feed = https://praksh.wordpress.com/category/kde/gsoc/feed/?mrss=off&category_name=kde%2Fgsoc + link = https://praksh.wordpress.com/category/kde/gsoc + location = en + avatar = prakash.png + +[jeremiasepperlein] + title = Jeremias Epperlein + feed = http://algebraicallyclosed.blogspot.com/feeds/posts/default + link = http://algebraicallyclosed.blogspot.com + location = en + +[jordipolojordl] + title = Jordi Polo (jordl) + feed = http://rubots.blogspot.com/atom.xml + link = http://rubots.blogspot.com + location = en + avatar = jordipolo.png + +[martinsandsmarksandsmark] + title = Martin Sandsmark (sandsmark) + feed = https://martinsandsmark.wordpress.com/feed/?mrss=off + link = https://martinsandsmark.wordpress.com + location = en + avatar = sandsmark.png + +[thomasmcguire] + title = Thomas McGuire + feed = https://thomasmcguire.wordpress.com/feed/?mrss=off + link = https://thomasmcguire.wordpress.com + location = en + +[dmitrykazakovdmitryk] + title = Dmitry Kazakov (dmitryK) + feed = http://dimula73.blogspot.com/feeds/posts/default/-/KDE + link = http://dimula73.blogspot.com + location = en + +[keithruslercomawhite] + title = Keith Rusler (comawhite) + feed = http://zekecoma.blogspot.com/feeds/posts/default/-/kde + link = http://zekecoma.blogspot.com + location = en + +[andrewmansonmansonaakarealate] + title = Andrew Manson ( mansona aka real_ate ) + feed = http://realate.blogspot.com/feeds/posts/default + link = http://realate.blogspot.com + location = en + avatar = mansona.png + +[matthiasfuchsmat69] + title = Matthias Fuchs (mat69) + feed = https://mat69.wordpress.com/feed/?mrss=off + link = https://mat69.wordpress.com + location = en + +[arnorehnpumphaus] + title = Arno Rehn (pumphaus) + feed = https://www.arnorehn.de/blog/feed/ + link = https://www.arnorehn.de/blog + location = en + +[ramonzarazuakillerfox] + title = Ramon Zarazua (_killerfox_) + feed = https://blogs.kde.org/blog/7020/feed + link = https://blogs.kde.org/blog/7020 + location = en + +[hanschenmogger] + title = Hans Chen (Mogger) + feed = https://blog.hanschen.org/category/planetkde/feed/?mrss=off&category_name=planetkde + link = https://blog.hanschen.org/category/planetkde + location = en + +[constantinberzanexit] + title = Constantin Berzan (exit) + feed = https://ascending.wordpress.com/feed/?mrss=off&tag=planetkde + link = https://ascending.wordpress.com + location = en + +[andreasschneidergladiac] + title = Andreas Schneider (gladiac) + feed = http://blog.cryptomilk.org/category/kde/feed/ + link = http://blog.cryptomilk.org/category/kde + location = en + avatar = anschneider.png + +[mehrdadmomenymtux] + title = Mehrdad Momeny (mtux) + feed = https://momeny.wordpress.com/category/planetkde/feed/?mrss=off&category_name=planetkde + link = https://momeny.wordpress.com/category/planetkde + location = en + avatar = momeny.png + +[mariofuxunormal] + title = Mario Fux (unormal) + feed = https://blogs.kde.org/blog/10441/feed + link = https://blogs.kde.org/blog/10441 + location = en + +[felixlemkehobbyblobby] + title = Felix Lemke (HobbyBlobby) + feed = https://hobbyblobby.wordpress.com/category/planet/feed/?mrss=off&category_name=planet + link = https://hobbyblobby.wordpress.com/category/planet + location = en + +[rafałmiłeckizajec] + title = Rafał Miłecki (Zajec) + feed = http://zajec.net/blog/atom/kde + link = http://zajec.net/blog/atom/kde + location = en + avatar = zajec.png + +[tonymurraymurrant] + title = Tony Murray (murrant) + feed = https://blogs.kde.org/blog/7193/feed + link = https://blogs.kde.org/blog/7193 + location = en + avatar = murrant.png + +[adenilsoncavalcantisavago] + title = Adenilson Cavalcanti (Savago) + feed = https://savago.wordpress.com/feed/?mrss=off + link = https://savago.wordpress.com + location = en + avatar = adenilson-cavalcanti.png + +[andrewlake] + title = Andrew Lake + feed = http://ontheoutsidedesign.blogspot.com/feeds/posts/default/-/KDE + link = http://ontheoutsidedesign.blogspot.com + location = en + avatar = jamboarder.png + +[alanalvarezclsk] + title = Alan Alvarez (clsk) + feed = http://blog.aliensoft.net/feeds/posts/default/-/planetkde + link = http://blog.aliensoft.net + location = en + avatar = alan-alvarez.png + +[danielnicolettidantti] + title = Daniel Nicoletti (dantti) + feed = https://dantti.wordpress.com/feed/?mrss=off + link = https://dantti.wordpress.com + location = en + avatar = dantti.png + +[stuartjarvis] + title = Stuart Jarvis + feed = https://www.asinen.org/feed/ + link = https://www.asinen.org + location = en + avatar = stuart-jarvis.png + +[alexanderriederarieder] + title = Alexander Rieder (arieder) + feed = https://arieder.wordpress.com/feed/?mrss=off + link = https://arieder.wordpress.com + location = en + +[benmartinmonkeyiq] + title = Ben Martin (monkeyiq) + feed = http://monkeyiq.blogspot.com/feeds/posts/default/-/kde + link = http://monkeyiq.blogspot.com + location = en + +[dmitryivanovvonami] + title = Dmitry Ivanov (vonami) + feed = https://vonami.wordpress.com/feed/?mrss=off + link = https://vonami.wordpress.com + location = en + +[raphaelkubodacostarakuco] + title = Raphael Kubo da Costa (rakuco) + feed = https://blogs.kde.org/blog/7305/feed + link = https://blogs.kde.org/blog/7305 + location = en + avatar = rakuco.png + +[boudewijnremptskritablog] + title = Boudewijn Rempt's Krita blog + feed = http://feeds.feedburner.com/ThisWeekInKrita + link = http://feeds.feedburner.com/ThisWeekInKrita + location = en + +[kaushiksaurabhroide] + title = Kaushik Saurabh (roide) + feed = http://roideuniverse.blogspot.com/feeds/posts/default/-/kde + link = http://roideuniverse.blogspot.com + location = en + +[michałmałekmmalek] + title = Michał Małek (mmalek) + feed = https://michalm.wordpress.com/tag/kde/feed/?mrss=off&tag=kde + link = https://michalm.wordpress.com/tag/kde + location = en + +[darioandresrodriguezdarioandres] + title = Dario Andres Rodriguez (Dario_Andres) + feed = https://darioandreskde.wordpress.com/feed/?mrss=off + link = https://darioandreskde.wordpress.com + location = en + avatar = darioandresr.png + +[pedrolopezcabanillas] + title = Pedro Lopez-Cabanillas + feed = http://midi-clorianos.blogspot.com/feeds/posts/default/-/KDE + link = http://midi-clorianos.blogspot.com + location = en + avatar = pedrol.png + +[romainpokrzywkakromain] + title = Romain Pokrzywka (kromain) + feed = http://c2143.blogspot.com/feeds/posts/default/-/KDE + link = http://c2143.blogspot.com + location = en + avatar = kromain.jpg + +[edwardtoroshchinhades] + title = Edward Toroshchin (hades) + feed = http://feeds.feedburner.com/HadesBlagPlanetKDE + link = http://feeds.feedburner.com/HadesBlagPlanetKDE + location = en + avatar = hades.png + +[johntapselljohnflux] + title = John Tapsell (JohnFlux) + feed = http://johnflux.blogspot.com/atom.xml + link = http://johnflux.blogspot.com + location = en + avatar = johnflux.png + +[kunalghoshkunalghosh] + title = kunal ghosh (kunalghosh) + feed = https://kunalghosh.wordpress.com/tag/kde/feed/ + link = https://kunalghosh.wordpress.com/tag/kde + location = en + avatar = kunalghosh.png + +[aaronreichmanareichman] + title = Aaron Reichman (areichman) + feed = http://owncloudtest.blogspot.com/feeds/posts/default + link = http://owncloudtest.blogspot.com + location = en + +[vitorboschiklanticus] + title = Vitor Boschi (Klanticus) + feed = https://liveblue.wordpress.com/category/vitor-planetkde/feed/?mrss=off&category_name=vitor-planetkde + link = https://liveblue.wordpress.com/category/vitor-planetkde + location = en + avatar = vitor.png + +[valoriezimmermanvalorie] + title = Valorie Zimmerman (valorie) + feed = http://linuxgrandma.blogspot.com/feeds/posts/default/-/KDE + link = http://linuxgrandma.blogspot.com + location = en + avatar = valorie.png + +[björnrubergruberg] + title = Björn Ruberg (ruberg) + feed = https://btux1984.wordpress.com/category/kde/feed/ + link = https://btux1984.wordpress.com/category/kde + location = en + avatar = ruberg.png + +[araceletorresaraceletorres] + title = Aracele Torres (araceletorres) + feed = https://cibermundi.wordpress.com/category/planetkde-araceletorres/feed/ + link = https://cibermundi.wordpress.com/category/planetkde-araceletorres + location = en + avatar = araceletorres.jpg + +[franciscofernandeschicao] + title = Francisco Fernandes (chicao) + feed = http://pedepinico.blogspot.com/feeds/posts/default/-/kde + link = http://pedepinico.blogspot.com + location = en + avatar = chicao.png + +[wagnerreckwiglot] + title = Wagner Reck (wiglot) + feed = https://kders.wordpress.com/category/planetkde-wagner/feed/?mrss=off&category_name=planetkde-wagner + link = https://kders.wordpress.com/category/planetkde-wagner + location = en + avatar = wagner.png + +[camilaayrescamilasan] + title = Camila Ayres (camilasan) + feed = https://kders.wordpress.com/category/planetkde-camila/feed/?mrss=off&category_name=planetkde-camila + link = https://kders.wordpress.com/category/planetkde-camila + location = en + avatar = camilaayres.png + +[filipesaraivafilipesaraiva] + title = Filipe Saraiva + feed = http://blog.filipesaraiva.info/?tag=planetkde-english&feed=rss2 + link = http://blog.filipesaraiva.info/ + location = en + author = irc:filipesaraiva + avatar = filipe_cabecinha.png + +[filipesaraivafilipesaraiva_pt] + title = Filipe Saraiva + feed = http://blog.filipesaraiva.info/?tag=planetkde-portugues&feed=rss2 + link = http://blog.filipesaraiva.info/ + location = pt + author = irc:filipesaraiva + avatar = filipe_cabecinha.png + +[andreascarpinoilpianista] + title = Andrea Scarpino (ilpianista) + feed = https://scarpino.dev/feed.xml + link = https://scarpino.dev + location = en + +[ronnyyabarronnyml] + title = Ronny Yabar (ronnyml) + feed = https://ronnyml.wordpress.com/category/planet-kde/feed/?mrss=off&category_name=planet-kde + link = https://ronnyml.wordpress.com/category/planet-kde + location = en + avatar = ronnyml.png + +[dineshsaidinesh5] + title = Dinesh (saidinesh5) + feed = https://saidinesh5.wordpress.com/tag/kde-planet/feed/?mrss=off&tag=kde-planet + link = https://saidinesh5.wordpress.com/tag/kde-planet + location = en + avatar = saidinesh5.png + +[shantanutusharshantanu] + title = Shantanu Tushar (shantanu) + feed = https://blog.shantanu.io/tag/kde/feed/ + link = https://blog.shantanu.io/tag/kde + location = en + avatar = shantanu.png + +[harshitjainhjain] + title = Harshit Jain (hjain) + feed = https://blogs.kde.org/blog/7735/feed + link = https://blogs.kde.org/blog/7735 + location = en + avatar = hjain.jpg + +[paulorômulopromulo] + title = Paulo Rômulo (promulo) + feed = http://pauloromulo.blogspot.com/feeds/posts/default?alt=rss + link = http://pauloromulo.blogspot.com + location = en + avatar = promulo.png + +[siddharthsrivastavaakssps011] + title = Siddharth Srivastava (akssps011) + feed = http://siddharthgsoc.blogspot.com/feeds/posts/default?alt=rss + link = http://siddharthgsoc.blogspot.com + location = en + avatar = akssps011.png + +[lamarquesouzalamarqueorlvsouza] + title = Lamarque Souza (lamarque or lvsouza) + feed = http://lamarque-lvs.blogspot.com/feeds/posts/default/-/kde + link = http://lamarque-lvs.blogspot.com + location = en + avatar = lamarque.png + +[peterschifferaceton] + title = Peter Schiffer (aceton) + feed = http://acetonik.blogspot.com/feeds/posts/default/-/KDE + link = http://acetonik.blogspot.com + location = en + +[adamcelarekadamce] + title = Adam Celarek (adamce) + feed = http://celarek.at/category/kde/feed/ + link = http://celarek.at/category/kde + location = en + avatar = adamc.jpg + +[raymondwoonincktittiatcoke] + title = Raymond Wooninck (tittiatcoke) + feed = https://tittiatcoke.wordpress.com/category/kde-2/feed/?mrss=off&category_name=kde-2 + link = https://tittiatcoke.wordpress.com/category/kde-2 + location = en + avatar = tittiatcoke.jpg + +[svenburmeisterrabauke] + title = Sven Burmeister (rabauke) + feed = https://kdeatopensuse.wordpress.com/feed/?mrss=off&category_name=kde + link = https://kdeatopensuse.wordpress.com + location = en + +[andreasdemmerademmer] + title = Andreas Demmer (ademmer) + feed = http://feeds.feedburner.com/andreas-demmer/kde + link = http://feeds.feedburner.com/andreas-demmer/kde + location = en + avatar = ademmer.png + +[diegocasellapolentino] + title = Diego Casella ([Po]lentino) + feed = https://polentino911.wordpress.com/tag/planetkde/feed/?mrss=off&tag=planetkde + link = https://polentino911.wordpress.com/tag/planetkde + location = en + avatar = polentino.png + +[hugopereiradacosta] + title = Hugo Pereira Da Costa + feed = http://hugo-kde.blogspot.com/rss.xml + link = http://hugo-kde.blogspot.com + location = en + avatar = hugo.png + +[siddharthsharmasiddvicious] + title = Siddharth Sharma (siddvicious) + feed = https://siddharthkde.wordpress.com/feed/?mrss=off + link = https://siddharthkde.wordpress.com + location = en + avatar = siddharth.jpg + +[nicolaslécureuilneoclust] + title = Nicolas Lécureuil (neoclust) + feed = http://mageia.nicolaslecureuil.fr/category/kde-en/feed/ + link = http://mageia.nicolaslecureuil.fr/category/kde-en + location = en + +[marcpegonmpeg] + title = Marc Pegon (mpeg) + feed = https://blogs.kde.org/blog/7783/feed + link = https://blogs.kde.org/blog/7783 + location = en + +[jeannicolasartaudmoricenet] + title = Jean-Nicolas Artaud (morice-net) + feed = https://morice.ipsquad.net/blog/?cat=3&feed=rss2 + link = https://morice.ipsquad.net/blog/ + location = en + avatar = morice.png + +[henribergiusbergie] + title = Henri Bergius (bergie) + feed = https://bergie.iki.fi/blog/category/kde/rss.xml + link = https://bergie.iki.fi/blog/category/kde + location = en + avatar = bergie.png + +[adamrakowskifooscriptefes] + title = Adam Rakowski (foo-script/efes) + feed = https://blogs.kde.org/blog/7855/feed + link = https://blogs.kde.org/blog/7855 + location = en + avatar = adamrakowski.png + +[marcmutz] + title = Marc Mutz + feed = https://marcmutz.wordpress.com/tag/planetkde/feed/?mrss=off&tag=planetkde + link = https://marcmutz.wordpress.com/tag/planetkde + location = en + avatar = effqt-bird.png + +[juanluisbaptistemaeztro] + title = Juan Luis Baptiste (Maeztro) + feed = http://not403.blogspot.com/feeds/posts/default/-/kde + link = http://not403.blogspot.com + location = en + avatar = jbaptiste.png + +[petrmrázekpetrm] + title = Petr Mrázek (petrm) + feed = http://dev-peterix.blogspot.com/feeds/posts/default/-/kde + link = http://dev-peterix.blogspot.com + location = en + avatar = petrm.jpg + +[kdedotnews] + title = KDE Dot News + feed = https://dot.kde.org/rss.xml + link = https://dot.kde.org + location = en + avatar = dot-news.png + +[kdereleaseservice] + title = KDE Release Service + feed = https://kde.org/announcements/releases/index.xml + link = https://kde.org/announcements/releases + location = en + avatar = dot-news.png + +[kritanews] + title = Krita News + feed = https://krita.org/en/feed/ + link = https://krita.org/en + location = en + avatar = krita.png + +[agustínbenitobethencourttoscalix] + title = Agustín Benito Bethencourt (toscalix) + feed = https://toscalix.com/feed/ + link = https://toscalix.com + location = en + +[kdeblogbaltasarortega] + title = KDE Blog - Baltasar Ortega + feed = https://www.kdeblog.com/feed + link = https://www.kdeblog.com + location = es + avatar = kdeblog.png + +[pedrolópezcabanillas] + title = Pedro López-Cabanillas + feed = http://midi-clorianos.blogspot.com/feeds/posts/default/-/KDE-ES + link = http://midi-clorianos.blogspot.com + location = es + +[cristinayenyxegonzálezgarcía] + title = Cristina Yenyxe González García + feed = https://arklad.wordpress.com/category/informatica/software-libre/kde/feed/ + link = https://arklad.wordpress.com/category/informatica/software-libre/kde + location = es + +[albertastalscidtsdgeoses] + title = Albert Astals Cid (TSDgeos) + feed = https://tsdgeos-es.blogspot.com/atom.xml + link = https://tsdgeos-es.blogspot.com + location = es + avatar = TSDgeos.png + +[kubuntunews] + title = Kubuntu News + feed = https://kubuntu.org/news/feed + link = https://kubuntu.org/news + location = en + avatar = kubuntu-logo.png + +[freofficekofficebasedopenmobileofficesuite] + title = Freoffice: KOffice based Open Mobile Office Suite + feed = http://freoffice.blogspot.com/feeds/posts/default + link = http://freoffice.blogspot.com + location = en + +[hayribakicithehayro] + title = Hayri Bakici (thehayro) + feed = http://thehayro.blogspot.com/feeds/posts/default/-/kde + link = http://thehayro.blogspot.com + location = en + +[mateubatlembatle] + title = Mateu Batle (mbatle) + feed = https://mbatle.wordpress.com/category/kde/feed/?mrss=off&category_name=kde + link = https://mbatle.wordpress.com/category/kde + location = en + avatar = mbatle.jpg + +[andriyrysinrysin] + title = Andriy Rysin (rysin) + feed = http://codersgrumble.blogspot.com/feeds/posts/default/-/kde + link = http://codersgrumble.blogspot.com + location = en + avatar = rysin.png + +[bernhardbeschowshentey] + title = Bernhard Beschow (shentey) + feed = https://shentey.wordpress.com/category/kde/feed/?mrss=off&category_name=kde + link = https://shentey.wordpress.com/category/kde + location = en + +[matteoagostinelliagostinelli] + title = Matteo Agostinelli (agostinelli) + feed = https://sciencekde.wordpress.com/tag/kde/feed/?mrss=off&tag=kde + link = https://sciencekde.wordpress.com/tag/kde + location = en + +[gaëldechalendarkleag] + title = Gaël de Chalendar (kleag) + feed = http://k-de-leag.blogspot.com/feeds/posts/default?alt=rss + link = http://k-de-leag.blogspot.com + location = en + avatar = kleag.png + +[davidedmundsonded] + title = David Edmundson (d_ed) + feed = http://blog.davidedmundson.co.uk/blog/category/kde/feed/ + link = http://blog.davidedmundson.co.uk/blog/category/kde + location = en + avatar = d_ed.png + +[javierllorente] + title = Javier Llorente + feed = http://www.javierllorente.com/category/english/feed/ + link = http://www.javierllorente.com/category/english + location = en + +[martarybczyńska] + title = Marta Rybczyńska + feed = https://mrybczynska.wordpress.com/category/english/feed/?mrss=off&category_name=english + link = https://mrybczynska.wordpress.com/category/english + location = po + +[bencooksleybcooksley] + title = Ben Cooksley (bcooksley) + feed = http://bcooksley.blogspot.com/feeds/posts/default + link = http://bcooksley.blogspot.com + location = en + +[wagnerreckwiglotpt] + title = Wagner Reck (wiglot) + feed = https://kders.wordpress.com/category/planetkde-pt-wagner/feed/ + link = https://kders.wordpress.com/category/planetkde-pt-wagner + location = pt + avatar = wagner.png + +[thorstenzachmann] + title = Thorsten Zachmann + feed = https://www.calligra.org/blogs/thorstenzachmann/feed/ + link = https://www.calligra.org/blogs/thorstenzachmann + location = en + +[konstantinossmanisksmanis] + title = Konstantinos Smanis (ksmanis) + feed = https://ksmanis.wordpress.com/feed/?mrss=off&category_name=planet-kde + link = https://ksmanis.wordpress.com + location = en + +[christophegiboudeauxkrop] + title = Christophe Giboudeaux (krop) + feed = https://cgbdx.wordpress.com/feed/?mrss=off + link = https://cgbdx.wordpress.com + location = en + +[jonanderpeñalbajonan] + title = Jon Ander Peñalba (jonan) + feed = https://jonanp.wordpress.com/feed/ + link = https://jonanp.wordpress.com + location = en + avatar = jonan.png + +[srikanthtiyyagura] + title = Srikanth Tiyyagura + feed = https://sri13atkritadevel.wordpress.com/feed/?mrss=off + link = https://sri13atkritadevel.wordpress.com + location = en + +[sinnykumariksinny] + title = Sinny Kumari (ksinny) + feed = https://sinny.io/tag/kde/feed/ + link = https://sinny.io/tag/kde + location = en + avatar = sinny.png + +[lucasliragomesmaskmaster] + title = Lucas Lira Gomes (MaskMaster) + feed = http://feeds.feedburner.com/kdeLucasRefuge + link = http://feeds.feedburner.com/kdeLucasRefuge + location = en + avatar = lucasliragomes.png + +[pranavravichandranpranavrcmas] + title = Pranav Ravichandran (Pranav_rcmas) + feed = https://pranavrc.wordpress.com/category/kde/feed/?mrss=off&category_name=kde + link = https://pranavrc.wordpress.com/category/kde + location = en + +[cédricbellegardegnumdk] + title = Cédric Bellegarde (gnumdk) + feed = http://gnumdk.blogspot.com/atom.xml + link = http://gnumdk.blogspot.com + location = en + avatar = gnumdk.png + +[rafałkułagarkulaga] + title = Rafał Kułaga (rkulaga) + feed = https://rkulaga.wordpress.com/feed/?mrss=off&category_name=PlanetKDE + link = https://rkulaga.wordpress.com + location = en + avatar = rkulaga.png + +[radoslawwicikrockford] + title = Radoslaw Wicik (rockford_) + feed = http://rockfordsone.blogspot.com/feeds/posts/default + link = http://rockfordsone.blogspot.com + location = en + +[tirthachatterjeewyuka] + title = Tirtha Chatterjee (wyuka) + feed = https://thebengaliheart.wordpress.com/feed/?mrss=off&tag=KDE + link = https://thebengaliheart.wordpress.com + location = en + avatar = wyuka.png + +[lukasdzikaraslukaslt2] + title = Lukas Dzikaras (LukasLt2) + feed = http://lukaslt.blogspot.com/feeds/posts/default + link = http://lukaslt.blogspot.com + location = en + +[sergiomartinssergio] + title = Sergio Martins (sergio) + feed = https://blogs.kde.org/blog/8251/feed + link = https://blogs.kde.org/blog/8251 + location = en + avatar = sergio.png + +[michałzającquintasan] + title = Michał Zając (Quintasan) + feed = http://quintasan.blogspot.com/feeds/posts/default/-/kde-planet + link = http://quintasan.blogspot.com + location = en + +[christianmollekopfcmollekopf] + title = Christian Mollekopf (cmollekopf) + feed = https://cmollekopf.wordpress.com/category/kde/feed/?mrss=off&category_name=kde + link = https://cmollekopf.wordpress.com/category/kde + location = en + +[dakerdakerfp] + title = Daker (dakerfp) + feed = http://codecereal.blogspot.com/feeds/posts/default/-/kde + link = http://codecereal.blogspot.com + location = en + +[stefanderkitshorushorrendus] + title = Stefan Derkits (HorusHorrendus) + feed = http://stefan.derkits.at/blog/category/opensource/feed/ + link = http://stefan.derkits.at/blog/category/opensource + location = en + avatar = horrendus.jpg + +[francesconwokekanwoki] + title = Francesco Nwokeka (nwoki) + feed = https://nwoki.wordpress.com/feed/?category_name=kde + link = https://nwoki.wordpress.com + location = en + avatar = nwoki.png + +[paulmendezpaulm] + title = Paul Mendez (paul_m) + feed = http://paulm-byte.blogspot.com/feeds/posts/default + link = http://paulm-byte.blogspot.com + location = en + +[andreascordlandwehrcola] + title = Andreas Cord-Landwehr (CoLa) + feed = https://cordlandwehr.wordpress.com/feed/?mrss=off&tag=kde + link = https://cordlandwehr.wordpress.com + location = en + +[samikshanbairagyasamxan] + title = Samikshan Bairagya (samxan) + feed = https://samxan.wordpress.com/tag/kde/feed/?mrss=off&tag=kde + link = https://samxan.wordpress.com/tag/kde + location = en + +[kdenlive] + title = Kdenlive + feed = https://kdenlive.org/en/category/news/feed/ + link = https://kdenlive.org/en/category/news + location = en + avatar = kdenlive.png + +[niklaslaxströmnikerabbit] + title = Niklas Laxström (Nikerabbit) + feed = https://laxstrom.name/blag/category/kde/feed/ + link = https://laxstrom.name/blag/category/kde + location = en + +[laszlopapplpapp] + title = Laszlo Papp (lpapp) + feed = http://lpapp.blogspot.com/feeds/posts/default/-/KDE + link = http://lpapp.blogspot.com + location = en + avatar = laszlo_papp-80x80.png + +[smitshah] + title = Smit Shah + feed = https://who828.wordpress.com/category/planet-kde/feed/?mrss=off + link = https://who828.wordpress.com/category/planet-kde + location = en + +[clauschristensenclauschr] + title = Claus Christensen (Claus_chr) + feed = https://clauschr.wordpress.com/feed/?mrss=off + link = https://clauschr.wordpress.com + location = en + avatar = clauschr.png + +[philipmuškovacyofel] + title = Philip Muškovac (yofel) + feed = https://kyofel.wordpress.com/category/KDE/feed/?mrss=off + link = https://kyofel.wordpress.com/category/KDE + location = en + +[danielvrátildvratil] + title = Daniel Vrátil (dvratil) + feed = https://www.dvratil.cz/tag/kde/feed/ + link = https://www.dvratil.cz/tag/kde + location = en + avatar = dvratil.png + +[rohangargshadeslayer] + title = Rohan Garg (shadeslayer) + feed = https://kshadeslayer.wordpress.com/category/KDE/feed/?mrss=off + link = https://kshadeslayer.wordpress.com/category/KDE + location = en + avatar = rohan.png + +[svenbrauch] + title = Sven Brauch + feed = http://blog.svenbrauch.de/tag/planetkde/feed/ + link = http://blog.svenbrauch.de/tag/planetkde + location = en + avatar = scummos.png + +[swairshahswair] + title = Swair Shah (swair) + feed = http://swairshah.blogspot.com/feeds/posts/default + link = http://swairshah.blogspot.com + location = en + +[felixrohrbachfxrh] + title = Felix Rohrbach (fxrh) + feed = https://fxrh.wordpress.com/category/kdeplanet/feed/?mrss=off + link = https://fxrh.wordpress.com/category/kdeplanet + location = en + +[yuvrajtomaryuvrajtomar] + title = Yuvraj Tomar (yuvrajtomar) + feed = http://yuvrajtomar.blogspot.com/feeds/posts/default + link = http://yuvrajtomar.blogspot.com + location = en + avatar = yuvraj-tomar.jpg + +[faniajöckfjoe] + title = Fania Jöck (fjoe) + feed = https://contourproject.wordpress.com/feed/?mrss=off + link = https://contourproject.wordpress.com + location = en + avatar = fania_jock.jpg + +[kmixthekdemultimediamixer] + title = KMix - the KDE Multimedia Mixer + feed = https://kmix5.wordpress.com/feed/?mrss=off + link = https://kmix5.wordpress.com + location = en + avatar = kmix.png + +[torgnynyblomtnyblom] + title = Torgny Nyblom (tnyblom) + feed = https://blogs.kde.org/blog/8457/feed/ + link = https://blogs.kde.org/blog/8457 + location = en + +[łukaszjaśkiewiczljaskiewicz] + title = Łukasz Jaśkiewicz (ljaskiewicz) + feed = https://ljaskiewicz.wordpress.com/feed/?mrss=0ff&category_name=planetkde + link = https://ljaskiewicz.wordpress.com + location = en + +[davidjarviedjarvie] + title = David Jarvie (djarvie) + feed = https://djarvie.wordpress.com/category/kde,planetkde/feed/?mrss=off + link = https://djarvie.wordpress.com/category/kde,planetkde + location = en + +[sebastiandörner] + title = Sebastian Dörner + feed = http://sebastian-doerner.de/?cat=4&feed=rss2&mrss=off + link = http://sebastian-doerner.de/ + location = en + +[matthiasklumppximion] + title = Matthias Klumpp (ximion) + feed = https://blog.tenstral.net/category/planet/planetkde/feed + link = https://blog.tenstral.net/category/planet/planetkde + location = en + avatar = matthias_ximion.png + +[lucatringalilucatringali] + title = Luca Tringali (lucatringali) + feed = http://letsfollowthewhiterabbit.blogspot.com/feeds/posts/default + link = http://letsfollowthewhiterabbit.blogspot.com + location = en + avatar = lucatringali.png + +[andreaskhütteldilfridge] + title = Andreas K. Hüttel (dilfridge) + feed = http://dilfridge.blogspot.com/feeds/posts/default/-/kde + link = http://dilfridge.blogspot.com + location = en + avatar = andreas-huettel.png + +[friedrichpülzfkpulz] + title = Friedrich Pülz (fkpulz) + feed = http://fpuelz-kde.blogspot.com/feeds/posts/default + link = http://fpuelz-kde.blogspot.com + location = en + avatar = fkpulz.png + +[dimitriosttanisdiggy] + title = Dimitrios T. Tanis (diggy) + feed = https://diggy128.wordpress.com/tag/kde/feed/ + link = https://diggy128.wordpress.com/tag/kde + location = en + avatar = dimitrios-tanis.jpg + +[davidenarváezdmaggot] + title = David E. Narváez (dMaggot) + feed = http://blog.dmaggot.org/tag/kde/feed/ + link = http://blog.dmaggot.org/tag/kde + location = en + avatar = dMaggot.png + +[philippknechtgesd1saster] + title = Philipp Knechtges (d1saster) + feed = http://philipp.knechtges.com/?cat=3&feed=rss2 + link = http://philipp.knechtges.com/ + location = en + +[florentinamusatchrome] + title = Florentina Musat (chrome) + feed = http://deepsky28.blogspot.com/feeds/posts/default?alt=rss + link = http://deepsky28.blogspot.com + location = en + +[gianniskonstantinidisgiannisk] + title = Giannis Konstantinidis (giannisk) + feed = https://konstantinidis.wordpress.com/category/kde/feed/ + link = https://konstantinidis.wordpress.com/category/kde + location = en + avatar = giannis-konstantinidis.jpeg + +[giorgostsiapaliokasterietor] + title = Giorgos Tsiapaliokas (terietor) + feed = https://terietor.wordpress.com/tag/planetkde/feed/ + link = https://terietor.wordpress.com/tag/planetkde + location = en + +[johanneshuberjohu] + title = Johannes Huber (johu) + feed = https://blogs.gentoo.org/johu/category/kde/feed/ + link = https://blogs.gentoo.org/johu/category/kde + location = en + avatar = johannes-huber.jpg + +[pierrestirnweisspierrest] + title = Pierre Stirnweiss (PierreSt) + feed = https://blogs.kde.org/blog/8948/feed + link = https://blogs.kde.org/blog/8948 + location = en + avatar = pierre-stirnweiss.jpg + +[jörgehrichs] + title = Jörg Ehrichs + feed = http://joerg-weblog.blogspot.com/feeds/posts/default/-/KDE + link = http://joerg-weblog.blogspot.com + location = en + avatar = jehrichs.png + +[ignatsemenovisemenov] + title = Ignat Semenov (isemenov) + feed = http://isemenov.blogspot.com/feeds/posts/default?alt=rss + link = http://isemenov.blogspot.com + location = en + +[frankreininghaus] + title = Frank Reininghaus + feed = https://freininghaus.wordpress.com/category/kde/feed/?mrss=off + link = https://freininghaus.wordpress.com/category/kde + location = en + +[jangrulichjgrulich] + title = Jan Grulich (jgrulich) + feed = http://jgrulich.cz/category/kde/feed/ + link = http://jgrulich.cz/category/kde + location = en + +[claudiodesiderisnizzo] + title = Claudio Desideri (snizzo) + feed = http://playgfx.blogspot.com/feeds/posts/default/-/kdestuff + link = http://playgfx.blogspot.com + location = en + +[arjunbasuultimatrix] + title = Arjun Basu (ultimatrix) + feed = https://boringtalk.wordpress.com/feed/ + link = https://boringtalk.wordpress.com + location = en + +[matějlaitlstrohel] + title = Matěj Laitl (strohel) + feed = http://strohel.blogspot.com/feeds/posts/default/-/kde + link = http://strohel.blogspot.com + location = en + avatar = strohel.png + +[kdabonqt] + title = KDAB on Qt + feed = https://www.kdab.com/category/blogs/technical/feed/ + link = https://www.kdab.com/category/blogs/technical + location = en + avatar = kdab.png + +[calligranews] + title = Calligra News + feed = https://www.calligra.org/feed/ + link = https://www.calligra.org + location = en + avatar = calligra.png + +[amandeepsinghamandeepsingh] + title = Amandeep Singh (amandeepsingh) + feed = http://amanonit.blogspot.com/feeds/posts/default/-/kde?alt=rss + link = http://amanonit.blogspot.com + location = en + +[rishabaroraspacetime] + title = Rishab Arora (spacetime) + feed = http://blog.rishab.in/feeds/kde.rss.xml + link = http://blog.rishab.in + location = en + avatar = rishab-arora.png + +[arthurribeiroarthurribeiro] + title = Arthur Ribeiro (arthurribeiro) + feed = http://arthursribeiro.blogspot.com.br/feeds/posts/default/-/kde + link = http://arthursribeiro.blogspot.com.br + location = en + avatar = arthurribeiro.jpg + +[timotheegietanimtim] + title = Timothee Giet (Animtim) + feed = https://timotheegiet.com/blog/tag/kde/feed + link = https://timotheegiet.com/blog/tag/kde + location = en + avatar = animtim.png + +[martinküttlermkuettler] + title = Martin Küttler (mkuettler) + feed = http://mkuettler.blogspot.com/feeds/posts/default/-/planetkde + link = http://mkuettler.blogspot.com + location = en + +[antonistsiapaliokaskokeroulis] + title = Antonis Tsiapaliokas (kokeroulis) + feed = https://kokeroulis.wordpress.com/tag/planetkde/feed/ + link = https://kokeroulis.wordpress.com/tag/planetkde + location = en + +[josephsimonjsimon3] + title = Joseph Simon (jsimon3) + feed = https://jsimon3.wordpress.com/category/kde/feed/ + link = https://jsimon3.wordpress.com/category/kde + location = en + avatar = josephsimon.png + +[casianvalentinandreiskelet] + title = Casian-Valentin Andrei (skelet) + feed = https://skeletdev.wordpress.com/category/kde/feed/ + link = https://skeletdev.wordpress.com/category/kde + location = en + avatar = skelet.png + +[jigarraisinghanijigar] + title = Jigar Raisinghani (jigar) + feed = http://jigarraisinghani.blogspot.com/feeds/posts/default/-/KDE?alt=rss + link = http://jigarraisinghani.blogspot.com + location = en + avatar = jigar.jpg + +[utkuaydınutku] + title = Utku Aydın (utku) + feed = https://utkuaydin.wordpress.com/category/kde-2/feed/ + link = https://utkuaydin.wordpress.com/category/kde-2 + location = en + +[roneygomesroney] + title = Roney Gomes (roney) + feed = http://logofn.blogspot.com/feeds/posts/default + link = http://logofn.blogspot.com + location = en + avatar = RoneyGomes.jpg + +[cezarmocancezarmocan] + title = Cezar Mocan (CezarMocan) + feed = https://cezarmocan.wordpress.com/feed/ + link = https://cezarmocan.wordpress.com + location = en + +[anantkamathflak37] + title = Anant Kamath (flak37) + feed = https://hashpling.wordpress.com/tag/planetkde/feed/?mrss=off&tag=planetkde + link = https://hashpling.wordpress.com/tag/planetkde + location = en + +[jasemmutlaqknro] + title = Jasem Mutlaq (KNRO) + feed = http://knro.blogspot.com/feeds/posts/default/-/KDE + link = http://knro.blogspot.com + location = en + avatar = mutlaqja.png + +[brijeshpatelerione] + title = Brijesh Patel (erione) + feed = http://erionism.blogspot.in/feeds/posts/default + link = http://erionism.blogspot.in + location = en + +[sebastiangottfriedsebasgo] + title = Sebastian Gottfried (sebasgo) + feed = https://blog.sebasgo.net/tag/kde/rss/ + link = https://blog.sebasgo.net/tag/kde + location = en + +[behindkde] + title = Behind KDE + feed = https://behindkde.org/rss.xml + link = https://behindkde.org + location = en + avatar = behindkde.png + +[marcocalignanomarcuzzo] + title = Marco Calignano (marcuzzo) + feed = http://marcuzzokde.blogspot.com/feeds/posts/default?alt=rss + link = http://marcuzzokde.blogspot.com + location = en + avatar = marcuzzo.png + +[ruedigergadrcg] + title = Ruediger Gad (rcg) + feed = https://ruedigergad.com/tag/planetkde/feed/?mrss=off&tag=planetkde + link = https://ruedigergad.com/tag/planetkde + location = en + avatar = ruedigergad.png + +[ilyakowalewskitucnak] + title = Ilya Kowalewski (tucnak) + feed = http://kovalevskyy.tumblr.com/tagged/planetkde/rss + link = http://kovalevskyy.tumblr.com/tagged/planetkde + location = en + avatar = kowalewski.png + +[emmanuellepagevalleeelv13] + title = Emmanuel Lepage Vallee (Elv13) + feed = https://elv13.wordpress.com/category/kde/feed/?mrss=off + link = https://elv13.wordpress.com/category/kde + location = en + +[mayankmadanmayankmadan] + title = Mayank Madan (mayankmadan) + feed = http://mayankmadanon.blogspot.in/feeds/posts/default?alt=rss + link = http://mayankmadanon.blogspot.in + location = en + +[gabrielpoesiagpoesia] + title = Gabriel Poesia (gpoesia) + feed = http://g-poesia.blogspot.com/feeds/posts/default/-/kde + link = http://g-poesia.blogspot.com + location = en + avatar = gabriel-poesia.jpg + +[stuartdicksonstuartmd] + title = Stuart Dickson (stuartmd) + feed = http://stuartmd2.blogspot.com/feeds/posts/default + link = http://stuartmd2.blogspot.com + location = en + avatar = stuartmd.png + +[randameetings] + title = Randa Meetings + feed = https://randa-meetings.ch/category/english/feed/ + link = https://randa-meetings.ch/category/english + location = en + +[thomaspfeiffercolomar] + title = Thomas Pfeiffer (colomar) + feed = http://sessellift.eu/category/kde/feed/?mrss=off + link = http://sessellift.eu/category/kde + location = en + avatar = thomas-pfeiffer.jpg + +[tomaszolszaktolszak] + title = Tomasz Olszak (tolszak) + feed = http://tolszak-dev.blogspot.com/feeds/posts/default/-/planetkde + link = http://tolszak-dev.blogspot.com + location = en + avatar = tolszak.png + +[martinbřízambriza] + title = Martin Bříza (mbriza) + feed = https://martinbriza.wordpress.com/tag/kde/feed/?mrss=off + link = https://martinbriza.wordpress.com/tag/kde + location = en + +[gopalakrishnabhat] + title = Gopalakrishna Bhat + feed = http://gkbhat.blogspot.in/feeds/posts/default/-/KDE + link = http://gkbhat.blogspot.in + location = en + avatar = sysadmins.png + +[andreasschilling] + title = Andreas Schilling + feed = http://andreasschilling.tumblr.com/search/kde/rss + link = http://andreasschilling.tumblr.com/search/kde + location = en + +[michaelbohlendermbohlender] + title = Michael Bohlender (mbohlender) + feed = https://mbohlender.wordpress.com/feed/atom/ + link = https://mbohlender.wordpress.com + location = en + +[adriandraghiciadrianb] + title = Adrian Draghici (adrianb) + feed = https://adrianbd.wordpress.com/feed/?mrss=off + link = https://adrianbd.wordpress.com + location = en + avatar = adrianb.png + +[magdakonkiewicz] + title = Magda Konkiewicz + feed = https://konkiewiczm.wordpress.com/feed/?mrss=off + link = https://konkiewiczm.wordpress.com + location = en + avatar = magda.png + +[oindrilaguptaoini] + title = Oindrila Gupta (oini) + feed = https://oinig.wordpress.com/tag/kde/feed/?mrss=off&tag=kde + link = https://oinig.wordpress.com/tag/kde + location = en + avatar = oini.jpg + +[deniskuplyakovdenerkup] + title = Denis Kuplyakov + feed = http://kreversiqml.blogspot.com/feeds/posts/default + link = http://kreversiqml.blogspot.com + location = en + author = irc:dener.kup + avatar = dener.jpg + +[chandankumarchandankumar] + title = Chandan Kumar (chandankumar) + feed = https://ciypro.wordpress.com/category/kde-gsoc2013/feed/?mrss=off + link = https://ciypro.wordpress.com/category/kde-gsoc2013 + location = en + avatar = chandankumar.jpg + +[anmolahujadarthcodus] + title = Anmol Ahuja (DarthCodus) + feed = http://gsoc2013.anmolahuja.com/feeds/posts/default?alt=rss + link = http://gsoc2013.anmolahuja.com + location = en + +[danielkreuterxardas008] + title = Daniel Kreuter (xardas008) + feed = https://xardas008.wordpress.com/category/kde/feed/?mrss=off + link = https://xardas008.wordpress.com/category/kde + location = en + avatar = kreuter.png + +[akshayratanakshayr] + title = Akshay Ratan (akshay_r) + feed = http://akshaycode.blogspot.com/feeds/posts/default/-/KDE?alt=rss + link = http://akshaycode.blogspot.com + location = en + +[sahilnagpalsahil] + title = Sahil Nagpal (sahil) + feed = https://nagpalsahil.wordpress.com/feed/?mrss=off + link = https://nagpalsahil.wordpress.com + location = en + +[ahmedabouelhamayedthemonster] + title = Ahmed AbouElhamayed (TheMonster) + feed = https://ahmedabouelhamayed.wordpress.com/category/kde/feed/?mrss=off + link = https://ahmedabouelhamayed.wordpress.com/category/kde + location = en + +[eikeheinsho] + title = Eike Hein (Sho) + feed = https://blogs.kde.org/blog/193/feed + link = https://blogs.kde.org/blog/193 + location = en + avatar = eike-hein.jpg + +[akshaypraveennairiammarco] + title = Akshay Praveen Nair (iammarco) + feed = https://iammarco11.github.io/feed.xml + link = https://iammarco11.github.io + location = en + avatar = iammarco11.png + +[albertvacaalbertvaka] + title = Albert Vaca (albertvaka) + feed = https://albertvaka.wordpress.com/feed/?mrss=off + link = https://albertvaka.wordpress.com + location = en + avatar = albertvaka.png + +[mojtabashahisenobarimoji1] + title = Mojtaba Shahi Senobari + feed = https://shahimoji.wordpress.com/feed/?mrss=off + link = https://shahimoji.wordpress.com + location = en + author = irc:moji + +[wengxuetiancsslayer] + title = Weng Xuetian (csslayer) + feed = https://www.csslayer.info/wordpress/tag/planetkde/feed/ + link = https://www.csslayer.info/wordpress/tag/planetkde + location = en + avatar = xuetianweng.png + +[csslayer] + title = CS Slayer + feed = https://www.csslayer.info/wordpress/category/kde/feed/ + link = https://www.csslayer.info/wordpress/category/kde + location = cn + avatar = xuetianweng.png + +[bhushanshahbshah] + title = Bhushan Shah (bshah) + feed = https://blog.bshah.in/feed.xml + link = https://blog.bshah.in + location = en + avatar = bshah.jpg + +[punitmehtapunit9462] + title = Punit Mehta (punit9462) + feed = https://punit9462.wordpress.com/category/planetkde/feed/ + link = https://punit9462.wordpress.com/category/planetkde + location = en + avatar = punit-mehta.png + +[dianetroutdetrout] + title = Diane Trout (detrout) + feed = http://ghic.org/~diane/feeds/kde.atom.xml + link = http://ghic.org/~diane + location = en + +[mihailivchenkoegormatirov] + title = Mihail Ivchenko (EgorMatirov) + feed = http://ematirov.blogspot.com/feeds/posts/default/-/kde + link = http://ematirov.blogspot.com + location = en + avatar = ematirov.jpg + +[jensreuterbergjensreuterberg] + title = Jens Reuterberg (jensreuterberg) + feed = http://wheeldesign.blogspot.com/feeds/posts/default?alt=rss + link = http://wheeldesign.blogspot.com + location = en + avatar = jensreuterberg.png + +[alexturbovzaufi] + title = Alex Turbov (zaufi) + feed = http://zaufi.github.io/rss-kde.xml + link = http://zaufi.github.io + location = en + +[ekaterinagerasimovakittykat] + title = Ekaterina Gerasimova (kittykat) + feed = https://blogs.gnome.org/kittykat/tag/kde/feed/ + link = https://blogs.gnome.org/kittykat/tag/kde + location = en + avatar = egerasimova.png + +[sanjibanbairagyafewcha] + title = Sanjiban Bairagya (fewcha) + feed = https://sanjibandotme.wordpress.com/tag/kde/feed/ + link = https://sanjibandotme.wordpress.com/tag/kde + location = en + avatar = sanjibanbairagya.png + +[kevinfunkkfunk] + title = Kevin Funk (kfunk) + feed = http://kfunk.org/tag/kde/rss/ + link = http://kfunk.org/tag/kde + location = en + avatar = kfunk.png + +[kdevelop] + title = KDevelop + feed = https://www.kdevelop.org/news/feed + link = https://www.kdevelop.org/news + location = en + avatar = kdevelop.png + +[sergeykalinichevklins] + title = Sergey Kalinichev (klins) + feed = https://sklin0.wordpress.com/tag/gsoc/ + link = https://sklin0.wordpress.com/tag/gsoc/ + location = en + +[abhinavgangwar] + title = Abhinav Gangwar + feed = https://abhgangwar.wordpress.com/feed/ + link = https://abhgangwar.wordpress.com + location = en + +[bharathmsbrat197] + title = Bharath M S (brat197) + feed = https://bharathbrat.wordpress.com/category/gsoc-2014-kde/feed/ + link = https://bharathbrat.wordpress.com/category/gsoc-2014-kde + location = en + avatar = bharath.png + +[călincrucerucrucerucalin] + title = Călin Cruceru (crucerucalin) + feed = https://calincruceru.wordpress.com/feed/ + link = https://calincruceru.wordpress.com + location = en + +[abhijeetnikamnikam08] + title = Abhijeet Nikam (nikam08) + feed = https://n1kam.wordpress.com/feed/ + link = https://n1kam.wordpress.com + location = en + +[rupanjanamitramrupanjana] + title = Rupanjana Mitra (mrupanjana) + feed = https://mrupanjana.wordpress.com/feed/ + link = https://mrupanjana.wordpress.com + location = en + +[marcinzieminski] + title = Marcin Zieminski + feed = https://ziemin.wordpress.com/feed/ + link = https://ziemin.wordpress.com + location = en + +[alexandrakulich] + title = Alexandr Akulich + feed = https://akulichalexandr.wordpress.com/feed/ + link = https://akulichalexandr.wordpress.com + location = en + avatar = akulichalexandr.png + +[deniskuplyakov] + title = Denis Kuplyakov + feed = http://calligra-author-outliner.blogspot.ru/feeds/posts/default + link = http://calligra-author-outliner.blogspot.ru + location = en + avatar = denis-Kuplyakov.jpg + +[mohitgoyalmohit] + title = Mohit Goyal (mohit) + feed = https://kritawithmohit.wordpress.com/feed/ + link = https://kritawithmohit.wordpress.com + location = en + +[timothéegietanimtim] + title = Timothée Giet (animtim) + feed = https://gcompris.wordpress.com/category/KDE/feed/ + link = https://gcompris.wordpress.com/category/KDE + location = en + avatar = gcompris.png + +[nileshsutharnil1511] + title = Nilesh Suthar (nil1511) + feed = https://nil1511.wordpress.com/feed/ + link = https://nil1511.wordpress.com + location = en + avatar = nil1511.jpg + +[debjitmondaldebjit] + title = Debjit Mondal (debjit) + feed = http://debjitmondal.blogspot.in/feeds/posts/default/-/kde + link = http://debjitmondal.blogspot.in + location = en + +[aniketanvitpacko] + title = Aniket Anvit (packo) + feed = https://aniketanvit.wordpress.com/tag/planetkde/feed/ + link = https://aniketanvit.wordpress.com/tag/planetkde + location = en + avatar = packo.png + +[mohamedanwertootis] + title = Mohamed Anwer (tootis) + feed = https://mohamedanwer.wordpress.com/tag/kde/feed/ + link = https://mohamedanwer.wordpress.com/tag/kde + location = en + avatar = mohamed-anwer.png + +[yangqiaoyangqiao] + title = YANG Qiao (yangqiao) + feed = https://yangqiao.wordpress.com/category/kdeconnect/feed/ + link = https://yangqiao.wordpress.com/category/kdeconnect + location = en + +[olafschmidtwischhöferojschmidt] + title = Olaf Schmidt-Wischhöfer (ojschmidt) + feed = http://www.olafsw.de/category/software/feed/ + link = http://www.olafsw.de/category/software + location = en + avatar = ojschmidt.png + +[pierluigifioriniplfiorini] + title = Pier Luigi Fiorini (plfiorini) + feed = http://plfiorini.blogspot.com/feeds/posts/default/-/kde + link = http://plfiorini.blogspot.com + location = en + avatar = plfiorini.jpg + +[scarlettmooresgclark] + title = Scarlett Moore (sgclark) + feed = https://scarlettgatelymoore.com/tag/opensource/feed/ + link = https://scarlettgatelymoore.com/tag/opensource + location = en + avatar = sgclark.png + +[hannahvonreththeonering] + title = Hannah von Reth (TheOneRing) + feed = https://the2ring.blogspot.de/feeds/posts/default + link = https://the2ring.blogspot.de + location = en + avatar = theonering.png + +[matijašukljesilverhook] + title = Matija Šuklje (silver_hook) + feed = http://matija.suklje.name/feeds/kde.atom.xml + link = http://matija.suklje.name + location = en + avatar = hook.png + +[andreaskainzandreask] + title = Andreas Kainz (Andreas_k) + feed = https://kdeonlinux.wordpress.com/feed/ + link = https://kdeonlinux.wordpress.com + location = en + avatar = Andreas-Kainz.jpg + +[kenvermettekver] + title = Ken Vermette (kver) + feed = https://kver.wordpress.com/tag/kde/feed/ + link = https://kver.wordpress.com/tag/kde + location = en + avatar = kver.png + +[oliviergoffartgof] + title = Olivier Goffart (Gof) + feed = https://woboq.com/feed/planetkde.rss + link = https://woboq.com + location = en + +[rahulchowdhuryrahulch] + title = Rahul Chowdhury (rahulch) + feed = https://rahulc93.wordpress.com/tag/kde/feed/ + link = https://rahulc93.wordpress.com/tag/kde + location = en + avatar = rahul.png + +[dinukumarasirisandarumk] + title = Dinu Kumarasiri (sandarumk) + feed = https://sinceeverybodyhasablog.wordpress.com/category/KDE/feed/ + link = https://sinceeverybodyhasablog.wordpress.com/category/KDE + location = en + +[sayanbiswas] + title = Sayan Biswas + feed = http://alltypesofhacking.blogspot.in/feeds/posts/default + link = http://alltypesofhacking.blogspot.in + location = en + avatar = sayan.png + +[koushiksskoushik] + title = Koushik S (skoushik) + feed = https://skoushik.wordpress.com/tag/kde/feed/ + link = https://skoushik.wordpress.com/tag/kde + location = en + avatar = koushik-s.jpg + +[subhajitmukherjeebukai] + title = Subhajit Mukherjee (bukai) + feed = https://subhajitmukherjee.wordpress.com/feed/ + link = https://subhajitmukherjee.wordpress.com + location = en + avatar = subhajitmukherjee.png + +[saikrishnasaikrishna17394] + title = Sai Krishna (saikrishna17394) + feed = http://saikrishna17394.github.io/feed.xml + link = http://saikrishna17394.github.io + location = en + avatar = Sai-Krishna.jpg + +[kshitijguptakshitij8] + title = Kshitij Gupta (kshitij8) + feed = http://kshitijblogs.blogspot.com/feeds/posts/default/-/SoK%2714 + link = http://kshitijblogs.blogspot.com + location = en + avatar = Kshitij-Gupta.png + +[anumittalanum] + title = Anu Mittal (anuM) + feed = https://anumittal.in/tag/PlanetKDE/ + link = https://anumittal.in/tag/PlanetKDE/ + location = en + avatar = anum.png + +[souvikdassd] + title = Souvik Das (sd__) + feed = https://dassouvik.wordpress.com/feed/ + link = https://dassouvik.wordpress.com + location = en + avatar = Souvik-Das.jpg + +[utkarshsimhausimha] + title = Utkarsh Simha (usimha) + feed = https://thegreatercode.wordpress.com/feed/ + link = https://thegreatercode.wordpress.com + location = en + avatar = Utkarsh-Simha.jpg + +[aarseeaeronaarsee] + title = Aarsee Aeron (aarsee) + feed = https://aarseeaeron.wordpress.com/feed/ + link = https://aarseeaeron.wordpress.com + location = en + avatar = Aarsee-Aeron.jpg + +[davidroscanowrep] + title = David Rosca (nowrep) + feed = http://davidrosca.blogspot.com/feeds/posts/default/-/planetkde + link = http://davidrosca.blogspot.com + location = en + +[kstnews] + title = Kst News + feed = http://kstplot.blogspot.com/feeds/posts/default/ + link = http://kstplot.blogspot.com + location = en + avatar = kstplot.png + +[elvisangelaccioelvisangelaccio] + title = Elvis Angelaccio (elvisangelaccio) + feed = https://eang.it/planetkde.xml + link = https://eang.it + location = en + avatar = elvis.png + +[kaiuwebroulikkbroulik] + title = Kai Uwe Broulik (kbroulik) + feed = https://blog.broulik.de/category/planetkde/feed/ + link = https://blog.broulik.de/category/planetkde + location = en + avatar = kai.jpg + +[rajeeshknambiarrajeesh] + title = Rajeesh K Nambiar (rajeesh) + feed = https://rajeeshknambiar.wordpress.com/feed/ + link = https://rajeeshknambiar.wordpress.com + location = en + avatar = rajeesh.png + +[alexandersemke] + title = Alexander Semke + feed = https://labplot.kde.org/feed/ + link = https://labplot.kde.org + location = en + +[dfighter] + title = dfighter + feed = https://dfighter1985.wordpress.com/category/planetkde/feed/ + link = https://dfighter1985.wordpress.com/category/planetkde + location = en + +[gregormigregormi] + title = gregormi (gregormi) + feed = http://feinstaub.github.io/blog/feed.kde.xml + link = http://feinstaub.github.io/blog + location = en + +[jounipentikäinentyyppi] + title = Jouni Pentikäinen (tyyppi) + feed = http://kritaanimation.blogspot.com/feeds/posts/default + link = http://kritaanimation.blogspot.com + location = en + +[woltheravanhövelltotwesterflierwolthera] + title = Wolthera van Hövell tot Westerflier (Wolthera) + feed = https://wolthera.info/category/coding/kde/feed/ + link = https://wolthera.info/category/coding/kde + location = en + avatar = Wolthera.png + +[francescowoffordwoffy] + title = Francesco Wofford (woffy) + feed = http://wolfcliff.blogspot.com/feeds/posts/default/-/kdestuff + link = http://wolfcliff.blogspot.com + location = en + +[msadityandrawkward] + title = M.S.Adityan (drawkward) + feed = http://www.msadityan.com/feed/?cat=kde + link = http://www.msadityan.com + location = en + avatar = msadityan.png + +[sahebpreetsinghsahebpreet] + title = Saheb Preet Singh (sahebpreet) + feed = http://sahebpreet-kde.blogspot.in/atom.xml + link = http://sahebpreet-kde.blogspot.in + location = en + avatar = sahebpreet.png + +[aroonavmishraroguedragon] + title = Aroonav Mishra (roguedragon) + feed = http://binaryspring.blogspot.com/feeds/posts/default/-/kde + link = http://binaryspring.blogspot.com + location = en + avatar = aroonav.jpg + +[davidkolozsvarikoldavid] + title = David Kolozsvari (koldavid) + feed = http://koldavidgsoc.blogspot.com/feeds/posts/default + link = http://koldavidgsoc.blogspot.com + location = en + avatar = koldavid.png + +[mariusstanciustancium] + title = Marius Stanciu (stancium) + feed = http://mariusoc.blogspot.com/feeds/posts/default + link = http://mariusoc.blogspot.com + location = en + avatar = mariusoc.png + +[gáborpéterffypgabor] + title = Gábor Péterffy (pgabor) + feed = http://pgabor.blogspot.com/feeds/posts/default/-/GSOC + link = http://pgabor.blogspot.com + location = en + avatar = pgabor.png + +[danielleudanielleu] + title = Daniel Leu (daniel_leu) + feed = https://danielgsoc.wordpress.com/feed/?mrss=off + link = https://danielgsoc.wordpress.com + location = en + avatar = leu.jpg + +[vineetgargvineet] + title = Vineet Garg (vineet) + feed = https://thebinarybin.wordpress.com/tag/kde/feed/ + link = https://thebinarybin.wordpress.com/tag/kde + location = en + avatar = vineet-garg.png + +[alexandermezinamezin] + title = Alexander Mezin (amezin) + feed = https://amezin.github.io/feed.xml + link = https://amezin.github.io + location = en + avatar = amezin.png + +[ragnarthomsenrthomsen] + title = Ragnar Thomsen (rthomsen) + feed = https://rthomsen6.wordpress.com/tag/kde/feed/ + link = https://rthomsen6.wordpress.com/tag/kde + location = en + avatar = rthomsen.png + +[aaronhoneycutahoneybun] + title = Aaron Honeycut (ahoneybun) + feed = http://usefoss.com/index.php/tag/kde/feed/ + link = http://usefoss.com/index.php/tag/kde + location = en + avatar = ahoneybun.png + +[ankitwagadreankitw] + title = Ankit Wagadre (ankitw) + feed = http://datapicker.blogspot.in/feeds/posts/default + link = http://datapicker.blogspot.in + location = en + avatar = ankitw.jpg + +[boudhayanguptabaloneygeek] + title = Boudhayan Gupta (BaloneyGeek) + feed = https://blog.baloneygeek.com/feeds/rss.xml + link = https://blog.baloneygeek.com + location = en + avatar = bgupta.png + +[vyacheslavmatyushinabiogenesis] + title = Vyacheslav Matyushin (abiogenesis) + feed = https://vyacheslav-matyushin.blogspot.ru/feeds/posts/default/-/kde + link = https://vyacheslav-matyushin.blogspot.ru + location = en + avatar = vmatyushin.png + +[laysrodrigues] + title = Lays Rodrigues + feed = https://laysrodriguesdev.wordpress.com/author/lays147/feed/ + link = https://laysrodriguesdev.wordpress.com/author/lays147 + location = en + avatar = lays.png + +[shouryasinghgupta] + title = Shourya Singh Gupta + feed = http://support-kde-randa.blogspot.com/feeds/posts/default + link = http://support-kde-randa.blogspot.com + location = en + avatar = shourya.jpg + +[chrisrizzitello] + title = Chris Rizzitello + feed = https://rizzitello.wordpress.com/author/sithlord48/feed/ + link = https://rizzitello.wordpress.com/author/sithlord48 + location = en + avatar = rizzitello.png + +[heikotietzehtietze] + title = Heiko Tietze (htietze) + feed = https://blogs.kde.org/blog/10432/feed + link = https://blogs.kde.org/blog/10432 + location = en + avatar = htietze.png + +[olivierchurlaudochurlaud] + title = Olivier Churlaud (ochurlaud) + feed = https://blogs.churlaud.com/somefoobar/tag/kde/feed/ + link = https://blogs.churlaud.com/somefoobar/tag/kde + location = en + avatar = ochurlaud.jpg + +[fernandoteles] + title = Fernando Teles + feed = https://phernandotelles.wordpress.com/category/english/planetkde/feed/ + link = https://phernandotelles.wordpress.com/category/english/planetkde + location = en + avatar = fernandoteles.png + +[russellgreene] + title = Russell Greene + feed = http://inandoutkde.blogspot.com/feeds/posts/default + link = http://inandoutkde.blogspot.com + location = en + +[divitgulati] + title = Divit Gulati + feed = http://divitgulati.blogspot.com/feeds/posts/default + link = http://divitgulati.blogspot.com + location = en + +[hristiyankyosev] + title = Hristiyan Kyosev + feed = http://experiencewithkde.blogspot.de/feeds/posts/default + link = http://experiencewithkde.blogspot.de + location = en + +[thomasfischer] + title = Thomas Fischer + feed = https://t-fischer.dreamwidth.org/data/rss?tag=kde + link = https://t-fischer.dreamwidth.org + location = en + avatar = thomasfischer.png + +[stanfordlin] + title = Stanford Lin + feed = https://stanfordlin.wordpress.com/feed/ + link = https://stanfordlin.wordpress.com + location = en + +[nunohultberg] + title = Nuno Hultberg + feed = https://hultnuno.wordpress.com/feed/ + link = https://hultnuno.wordpress.com + location = en + +[gilbertassaf] + title = Gilbert Assaf + feed = http://programmer-pit.de/?feed=rss2&cat=2 + link = http://programmer-pit.de/ + location = en + +[adityadevsharmag33kyaditya] + title = Aditya Dev Sharma (g33kyaditya) + feed = https://g33kyaditya.wordpress.com/tag/kde/feed/ + link = https://g33kyaditya.wordpress.com/tag/kde + location = en + avatar = aditya-dev-sharma.jpg + +[andreadelsarto] + title = Andrea Del Sarto + feed = https://delsalife.wordpress.com/feed/ + link = https://delsalife.wordpress.com + location = en + +[arnavdhamijashortstheory] + title = Arnav Dhamija (shortstheory) + feed = https://arnavdhamija.com/tag/kde/rss/ + link = https://arnavdhamija.com/tag/kde + location = en + avatar = arnavdhamija.jpg + +[alessandrotundo] + title = Alessandro Tundo + feed = http://alittledeveloper.blogspot.com/feeds/posts/default/?q=label:KDE + link = http://alittledeveloper.blogspot.com + location = en + +[danielepannozzo] + title = Daniele Pannozzo + feed = https://atakanzblog.wordpress.com/tag/wikitolearn/feed/ + link = https://atakanzblog.wordpress.com/tag/wikitolearn + location = en + avatar = atakanz.png + +[lucatoma] + title = Luca Toma + feed = https://blog.lucatoma.eu/category/kde-planet/feed/ + link = https://blog.lucatoma.eu/category/kde-planet + location = en + +[martinadestefani] + title = Martina De Stefani + feed = http://martinadestefani.blogspot.com/feeds/posts/default/-/KDE/?alt=rss + link = http://martinadestefani.blogspot.com + location = en + avatar = marti_de.png + +[vincenzoeduardopadulano] + title = Vincenzo Eduardo Padulano + feed = https://blogs.wikitolearn.org/author/vincenzo/feed/ + link = https://blogs.wikitolearn.org/author/vincenzo + location = en + +[lodovicofilipporavizza] + title = Lodovico Filippo Ravizza + feed = https://blogs.wikitolearn.org/author/lodo_ravi/feed/ + link = https://blogs.wikitolearn.org/author/lodo_ravi + location = en + +[filippoquarenghi] + title = Filippo Quarenghi + feed = https://blogs.wikitolearn.org/author/f.quarenghi/feed/ + link = https://blogs.wikitolearn.org/author/f.quarenghi + location = en + +[jonamotta] + title = Jona Motta + feed = https://blogs.wikitolearn.org/author/jmotta1/feed/ + link = https://blogs.wikitolearn.org/author/jmotta1 + location = en + +[lucieferretti] + title = Lucie Ferretti + feed = https://blogs.wikitolearn.org/author/Lucieferr/feed/ + link = https://blogs.wikitolearn.org/author/Lucieferr + location = en + +[matteobonanomi] + title = Matteo Bonanomi + feed = https://blogs.wikitolearn.org/author/m.bona/feed/ + link = https://blogs.wikitolearn.org/author/m.bona + location = en + +[ayushshahayushshah] + title = Ayush Shah (ayushshah) + feed = https://ayushashah.wordpress.com/feed/ + link = https://ayushashah.wordpress.com + location = en + avatar = ayushshah.jpg + +[matteomarcoli] + title = Matteo Marcoli + feed = https://blogs.wikitolearn.org/author/matteo_marcoli/feed/ + link = https://blogs.wikitolearn.org/author/matteo_marcoli + location = en + +[riccardoiaconelliruphy] + title = Riccardo Iaconelli (ruphy) + feed = https://blogs.wikitolearn.org/author/ruphy/feed/ + link = https://blogs.wikitolearn.org/author/ruphy + location = en + avatar = ruphy.png + +[riccardoagilardi] + title = Riccardo A Gilardi + feed = https://blogs.wikitolearn.org/author/scimmiaspaziale/feed/ + link = https://blogs.wikitolearn.org/author/scimmiaspaziale + location = en + +[sofialiguori] + title = Sofia Liguori + feed = https://blogs.wikitolearn.org/author/Xadhoom/feed/ + link = https://blogs.wikitolearn.org/author/Xadhoom + location = en + +[cristianbaldi] + title = Cristian Baldi + feed = http://baldi.me/blog/feed-kde.xml + link = http://baldi.me/blog + location = en + +[irenedaloia] + title = Irene D'aloia + feed = https://blogs.wikitolearn.org/author/irenedaloia/feed/ + link = https://blogs.wikitolearn.org/author/irenedaloia + location = en + +[demetriocarrara] + title = Demetrio Carrara + feed = https://blogs.wikitolearn.org/author/dcarrara/feed/ + link = https://blogs.wikitolearn.org/author/dcarrara + location = en + +[wikitolearncommunity] + title = WikiToLearn Community + feed = https://blogs.wikitolearn.org/author/wikitolearn/feed/ + link = https://blogs.wikitolearn.org/author/wikitolearn + location = en + avatar = wtlemblem.png + +[pulkitguptapulkit] + title = Pulkit Gupta (pulkit) + feed = http://gsoc16.pulkitgupta.net/feed/ + link = http://gsoc16.pulkitgupta.net + location = en + avatar = pulkit.png + +[artemfedoskinpolaris] + title = Artem Fedoskin (polaris) + feed = http://thelastpolaris.blogspot.com/feeds/posts/default + link = http://thelastpolaris.blogspot.com + location = en + avatar = afedoskin.png + +[krzysztofnowicki] + title = Krzysztof Nowicki + feed = https://micreabog.wordpress.com/category/kde/feed/ + link = https://micreabog.wordpress.com/category/kde + location = en + avatar = nowicki.jpeg + +[minhchuminhchu] + title = Minh Chu (minhchu) + feed = https://scsilver.wordpress.com/feed/?tag=kde + link = https://scsilver.wordpress.com + location = en + avatar = minhchu.png + +[sagarhanisagarhani] + title = Sagar Hani (sagarhani) + feed = https://sagarhani.wordpress.com/feed/atom/?tag=kde + link = https://sagarhani.wordpress.com + location = en + avatar = sagarhani.png + +[stefantoncustefant] + title = Stefan Toncu (StefanT) + feed = https://stefantoncu29.wordpress.com/feed/?tag=kde + link = https://stefantoncu29.wordpress.com + location = en + avatar = stefan.png + +[falitjainfalitjain] + title = Falit Jain (falitjain) + feed = http://falit94.blogspot.com/feeds/posts/default?alt=rss + link = http://falit94.blogspot.com + location = en + avatar = falit.png + +[raphaelcojocaruraphael29] + title = Raphael Cojocaru (raphael29) + feed = https://raphaelcojocaru.wordpress.com/feed/?tag=kde + link = https://raphaelcojocaru.wordpress.com + location = en + avatar = raphael.png + +[ivanlakhtanovvaness] + title = Ivan Lakhtanov (vaness) + feed = https://juliacantor.blogspot.ru/feeds/posts/default?alt=rss + link = https://juliacantor.blogspot.ru + location = en + +[abhimanyushekhawatabhimanyushekhawat] + title = Abhimanyu Shekhawat (abhimanyushekhawat) + feed = https://keenlearner.wordpress.com/feed/?tag=kde + link = https://keenlearner.wordpress.com + location = en + avatar = abhimanyushekhawat.png + +[julianthijssennimmy] + title = Julian Thijssen (nimmy) + feed = http://kritadev.blogspot.com/feeds/posts/default?alt=rss + link = http://kritadev.blogspot.com + location = en + avatar = nimmy.png + +[akshattandontandon] + title = Akshat Tandon (tandon) + feed = http://droftware.github.io/feed.kde.xml + link = http://droftware.github.io + location = en + avatar = tandon.png + +[vladyslavbatyrenkomvlabat] + title = Vladyslav Batyrenko (mvlabat) + feed = http://mvlabat.github.io/ark-gsoc-2016/feed.xml + link = http://mvlabat.github.io/ark-gsoc-2016 + location = en + avatar = mvlabat.png + +[chantaratithtctara] + title = Chantara Tith (tctara) + feed = http://tctara.github.io/gsoc/feed.xml + link = http://tctara.github.io/gsoc + location = en + +[prakritibhardwajkupy] + title = Prakriti Bhardwaj (kupy) + feed = https://prakritibhardwajblog.wordpress.com/tag/kde/feed/ + link = https://prakritibhardwajblog.wordpress.com/tag/kde + location = en + avatar = Prakriti_Bhardwaj.jpg + +[bhavishadhruvebdhruve] + title = Bhavisha Dhruve (bdhruve) + feed = https://bhavishadhruve.wordpress.com/feed/ + link = https://bhavishadhruve.wordpress.com + location = en + +[fábiánkristófkrajsz] + title = Fábián Kristóf (krajsz) + feed = http://krajszgsoc.blogspot.com/feeds/posts/default?alt=rss + link = http://krajszgsoc.blogspot.com + location = en + avatar = krajsz.png + +[swatilodhaswati27] + title = Swati Lodha (swati_27) + feed = https://swatilodha.wordpress.com/feed/ + link = https://swatilodha.wordpress.com + location = en + +[alexanderpotashevaspotashev] + title = Alexander Potashev (aspotashev) + feed = http://aspotashev.blogspot.com/feeds/posts/default?alt=rss + link = http://aspotashev.blogspot.com + location = en + avatar = aspotashev.png + +[juditbarthabernkastel] + title = Judit Bartha (bernkastel) + feed = https://bernkastelsgsoc.blogspot.com/feeds/posts/default?alt=rss + link = https://bernkastelsgsoc.blogspot.com + location = en + avatar = bernkastel.png + +[qtdevloop] + title = Qt Dev Loop + feed = https://www.qt.io/blog/tag/loop/rss.xml + link = https://www.qt.io/blog/tag/loop + location = en + avatar = qt_logo.png + +[choqok] + title = Choqok + feed = https://choqok.kde.org/feed.xml + link = https://choqok.kde.org + location = en + avatar = choqok.png + +[michailvourlakospsifidotos] + title = Michail Vourlakos (psifidotos) + feed = https://psifidotos.blogspot.com/feeds/posts/default/-/kde + link = https://psifidotos.blogspot.com + location = en + avatar = vourlakos.png + +[divyammadaandmadaan] + title = Divyam Madaan (dmadaan_) + feed = https://divyam3897.github.io/feed.xml + link = https://divyam3897.github.io + location = en + avatar = divyamMadaan.jpg + +[rahulyadavrahulyadav] + title = Rahul Yadav + feed = http://rahulyadav170923.blogspot.com/feeds/posts/default/ + link = http://rahulyadav170923.blogspot.com + location = en + avatar = rahulyadav.png + author = irc:rahulyadav + +[romangilg] + title = Roman Gilg + feed = https://subdiff.org/blog/feed.xml + link = https://subdiff.org/blog + location = en + avatar = roman-gilg.png + +[guoyunhe] + title = Guo Yunhe + feed = https://guoyunhe.me/en/t/kde/feed/ + link = https://guoyunhe.me/en/t/kde + location = en + avatar = guoyunhe.jpg + +[utkarshtiwariiamutkarshtiwari] + title = Utkarsh Tiwari (iamutkarshtiwari) + feed = https://iamutkarshtiwari.wordpress.com/season-of-kde-2016/feed/ + link = https://iamutkarshtiwari.wordpress.com/season-of-kde-2016 + location = en + avatar = utkarshtiwari.jpg + +[nitishchauhannitish2] + title = Nitish Chauhan (nitish) + feed = https://nitish18blog.wordpress.com/2017/03/08/feed/ + link = https://nitish18blog.wordpress.com/2017/03/08 + location = en + avatar = nitish.jpg + +[matthieugallienmgallien] + title = Matthieu Gallien (mgallien) + feed = https://mgallienkde.wordpress.com/feed/ + link = https://mgallienkde.wordpress.com + location = en + avatar = mgallien.png + +[limyuenhoemoofang] + title = Lim Yuen Hoe (moofang) + feed = https://yuenhoe.com/blog/tag/planetkde/feed/ + link = https://yuenhoe.com/blog/tag/planetkde + location = en + avatar = yuenhoe.jpg + +[chinmoyranjanpradhanchinmoy] + title = Chinmoy Ranjan Pradhan (chinmoy) + feed = http://blog.chinmoyrp.com/feed.xml + link = http://blog.chinmoyrp.com + location = en + avatar = chinmoy.png + +[kapustinalexeyakapblog] + title = Kapustin Alexey (akap) + feed = https://akapust1n.wordpress.com/feed/?mrss=off + link = https://akapust1n.wordpress.com + location = en + avatar = akapustin.png + +[eliakincostaeliakincosta] + title = Eliakin Costa (eliakincosta) + feed = https://eliakincosta.github.io/feed.xml + link = https://eliakincosta.github.io + location = en + avatar = eliakincosta.jpg + +[anikethgirishaniketh] + title = Aniketh Girish (aniketh___) + feed = https://anikethfoss.wordpress.com/category/kde/feed/?mrss=off&category_name=kde + link = https://anikethfoss.wordpress.com/category/kde + location = en + avatar = Aniketh-Girish.jpg + +[rishabhguptarishabh] + title = Rishabh Gupta (rishabh) + feed = https://rish9511.wordpress.com/category/kde/feed/ + link = https://rish9511.wordpress.com/category/kde + location = en + avatar = rgupta.png + +[digikam] + title = digiKam + feed = https://www.digikam.org/index.xml + link = https://www.digikam.org + location = en + avatar = digikam.png + +[emmagospodinovaxstyle] + title = Emma Gospodinova (xstyle) + feed = https://perplexinglyemma.blogspot.co.uk/feeds/posts/default/-/kde?alt=rss + link = https://perplexinglyemma.blogspot.co.uk + location = en + avatar = emgosp.jpg + +[kdeneonblog] + title = KDE neon Blog + feed = https://blog.neon.kde.org/index.php/feed/ + link = https://blog.neon.kde.org/index.php + location = en + avatar = neon.png + +[chakra] + title = Chakra + feed = https://community.chakralinux.org/tags/curated.rss + link = https://community.chakralinux.org/tags + location = en + avatar = chakra-shield.png + +[kecsapgsoc2017] + title = kecsap (GSOC 2017) + feed = http://kecsapgsoc2017.blogspot.com/feeds/posts/default?alt=rss + link = http://kecsapgsoc2017.blogspot.com + location = en + avatar = kecsap.jpg + +[nitishchauhannitish1] + title = Nitish Chauhan (nitish) + feed = https://nitish18blog.wordpress.com/2017/06/14/feed/ + link = https://nitish18blog.wordpress.com/2017/06/14 + location = en + avatar = nitish.jpg + +[kapustinalexeyakap] + title = Kapustin Alexey (akap) + feed = https://akapust1n.github.io/feed.xml + link = https://akapust1n.github.io + location = en + avatar = akapustin.png + +[zoltanpadrah] + title = Zoltan Padrah + feed = https://zoltanp.github.io/category/kde_feed.xml + link = https://zoltanp.github.io/ + location = en + +[shazaismailkaoudshazaismailkaoud] + title = Shaza Ismail Kaoud (shazaismailkaoud) + feed = https://shazaismailkaoud.wordpress.com/tag/kde/feed/ + link = https://shazaismailkaoud.wordpress.com/ + location = en + avatar = shaza-ismail.png + +[tantsevovgrigorytantsevov] + title = Tantsevov Grigory (tantsevov) + feed = https://tantsevov.wordpress.com/feed/?mrss=off + link = https://tantsevov.wordpress.com + location = en + avatar = tantsevov.png + +[andresbettsanditosan] + title = Andres Betts (anditosan) + feed = https://anditosan.wordpress.com/feed/?mrss=off + link = https://anditosan.wordpress.com + location = en + avatar = andres-betts.jpg + +[vasudhavasudhamathur] + title = Vasudha (vasudhamathur) + feed = https://vasudhamathur.wordpress.com/category/KDE/feed/ + link = https://vasudhamathur.wordpress.com/ + location = en + avatar = vasudha.jpg + +[franklinweng] + title = Franklin Weng + feed = http://good-horse.blogspot.com/feeds/posts/default/-/KDE + link = http://good-horse.blogspot.com + location = en + +[thomasbaumgartipwizard] + title = Thomas Baumgart (ipwizard) + feed = https://blog.bembel.net/category/kde/feed/ + link = https://blog.bembel.net/category/kde + location = en + avatar = tbaumgart.png + +[paulbro666] + title = Paul (Bro666) + feed = https://quickfix.es/author/paul/feed/ + link = https://quickfix.es/author/paul + location = en + avatar = paulbro666.jpg + +[ivanaskadinna] + title = Ivana (skadinna) + feed = https://quickfix.es/author/skadinna/feed/ + link = https://quickfix.es/author/skadinna + location = en + avatar = ivana.jpg + +[nategrahamngraham] + title = Nate Graham (ngraham) + feed = https://pointieststick.com/feed/ + link = https://pointieststick.com + location = en + avatar = ngraham.png + +[neofytoskolokotronistetris4] + title = Neofytos Kolokotronis (tetris4) + feed = http://neofytosk.com/categories/kde/index.xml + link = http://neofytosk.com/categories/kde + location = en + avatar = neofytosk.png + +[amankumarguptagupta2140m] + title = Aman Kumar Gupta (gupta2140[m]) + feed = https://amankumargupta.wordpress.com/category/kde/feed/?mrss=off + link = https://amankumargupta.wordpress.com/category/kde + location = en + avatar = amankumargupta.jpg + +[lucaferrari] + title = Luca Ferrari + feed = https://fluca1978.github.io/atom/planet-kde-org + link = https://fluca1978.github.io + location = en + avatar = luca-ferrari.png + +[amitsagtaniamit] + title = Amit Sagtani (amit__) + feed = https://amitsagtani97.wordpress.com/feed/ + link = https://amitsagtani97.wordpress.com + location = en + avatar = amit.jpg + +[antoniolarrosaantlarr] + title = Antonio Larrosa (antlarr) + feed = https://antlarr.io/feed/ + link = https://antlarr.io + location = en + avatar = antlarr.png + +[stéphanemankowskismankowski] + title = Stéphane MANKOWSKI (smankowski) + feed = https://skrooge.org/rss.xml + link = https://skrooge.org + location = en + avatar = smankowski.png + +[jamescainronnoc] + title = James Cain (ronnoc) + feed = http://www.kdedigest.com/feeds/posts/default/-/[planetkde]?alt=rss + link = http://www.kdedigest.com + location = en + avatar = james-cain.png + +[kdiff3] + title = KDiff3 + feed = https://kdiff3.blogspot.com/feeds/posts/default + link = https://kdiff3.blogspot.com + location = en + +[matthijstijinkmtijink] + title = Matthijs Tijink (mtijink) + feed = https://matthijstijink.nl/static/feed_kde.xml + link = https://matthijstijink.nl/static + location = en + avatar = mtijink.jpg + +[nicolasfellanicofee] + title = Nicolas Fella + feed = https://nicolasfella.wordpress.com/category/kde/feed/ + link = https://nicolasfella.wordpress.com/category/kde + location = en + avatar = nicolasfella.png + author = irc:nicofee + +[martinkacejmkacej] + title = Martin Kacej + feed = https://mkacej.wordpress.com/category/kde/feed/ + link = https://mkacej.wordpress.com/category/kde + location = en + author = irc:mkacej + +[łukaszsawickillucas] + title = Łukasz Sawicki + feed = https://medium.com/feed/kdeok + link = https://medium.com + location = en + author = irc:llucas + avatar = lucas.jpg + +[falkon] + title = Falkon + feed = https://www.falkon.org/atom.xml + link = https://www.falkon.org + location = en + avatar = falkon.png + +[furkantokacftdev] + title = Furkan Tokac (ftDev) + feed = https://furkantokac.com/categories/kde/index.xml + link = https://furkantokac.com/categories/kde + location = en + avatar = Furkan-Tokac.png + +[iványossisantamaríaivanyossi] + title = Iván Yossi Santa María (ivanyossi) + feed = https://colorathis.wordpress.com/tag/kde/feed/ + link = https://colorathis.wordpress.com/tag/kde + location = en + avatar = ivanyossi.png + +[michaelzhousimeir] + title = Michael Zhou (simeir) + feed = https://simeir.github.io/feeds/kdefeed.atom + link = https://simeir.github.io + location = en + avatar = simeir.png + +[ferenczkovacsferenczkovacs] + title = Ferencz Kovacs (ferenczkovacs) + feed = https://kfereneczgsoc2018.blogspot.com/feeds/posts/default + link = https://kfereneczgsoc2018.blogspot.com + location = en + avatar = ferencz_kovacs.png + +[andreycygankovandreyc] + title = Andrey Cygankov (andreyc) + feed = https://andreycyg.blogspot.com/feeds/posts/default + link = https://andreycyg.blogspot.com + location = en + avatar = andreyc.png + +[gunparkgpark] + title = Gun Park (gpark) + feed = https://medium.com/feed/@mujjingun_23509 + link = https://medium.com + location = en + avatar = mujji.png + +[ilyabizyaevilyab] + title = Ilya Bizyaev (ilya_b) + feed = https://ilyabiz.com/category/kde/feed/ + link = https://ilyabiz.com/category/kde + location = en + avatar = ilya_b.png + +[volkerkrause] + title = Volker Krause + feed = https://www.volkerkrause.eu/feed.xml + link = https://www.volkerkrause.eu + location = en + +[luislavaire] + title = Luis Lavaire + feed = https://luis692397029.wordpress.com/feed/ + link = https://luis692397029.wordpress.com + location = en + avatar = luis.jpeg + +[andrewcrouthamelandrewcrouthamel] + title = Andrew Crouthamel (AndrewCrouthamel) + feed = https://andrewcrouthamel.wordpress.com/category/kde/feed/ + link = https://andrewcrouthamel.wordpress.com/category/kde + location = en + avatar = acrouthamel.png + +[ashwinsamudreashwins] + title = Ashwin Samudre (ashwins) + feed = https://kiryteo7.wordpress.com/category/kde/ + link = https://kiryteo7.wordpress.com/category/kde/ + location = en + avatar = ashwins.png + +[mirkoboehmmiroslav] + title = Mirko Boehm (miroslav) + feed = https://www.creative-destruction.org/tags/foss/index.xml + link = https://www.creative-destruction.org/tags/foss + location = en + avatar = mirkoboehm.png + +[albertomardeganmardy] + title = Alberto Mardegan + feed = http://www.mardy.it/categories/kdeplanet.xml + link = http://www.mardy.it + location = en + author = irc:mardy + avatar = alberto-mardegan.png + +[jonahbrüchertjbb] + title = Jonah Brüchert (JBB) + feed = https://jbbgameich.github.io/feed.xml + link = https://jbbgameich.github.io + location = en + avatar = jbb.png + +[juancarlostorresjucato] + title = Juan Carlos Torres + feed = https://jucato.wordpress.com/tag/kde/feed/ + link = https://jucato.wordpress.com/ + location = en + author = irc:jucato + avatar = jucato.png + +[kuntalmajumderhellozee] + title = Kuntal Majumder + feed = https://www.hellozee.dev/tags/kde/index.xml + link = https://www.hellozee.dev/ + author = irc:hellozee + location = en + avatar = hellozee.png + +[piyushaggarwalbrute4s99] + title = Piyush Aggarwal + feed = https://brute4s99.news.blog/category/kde/feed/ + link = https://brute4s99.news.blog/ + location = en + author = irc:brute4s99 + avatar = brute4s99.png + +[filipfila] + title = Filip Fila + feed = https://filipfila.wordpress.com/tag/planet-kde/feed/ + link = https://filipfila.wordpress.com/ + location = en + avatar = filipf.png + +[kaidannews] + title = Kaidan News + feed = https://www.kaidan.im/atom.xml + link = https://www.kaidan.im + location = en + avatar = kaidan.png + +[weixuanxiaoinokinoki] + title = Weixuan XIAO (Inokinoki) + feed = https://kde.inoki.cc/atom.xml + link = https://kde.inoki.cc + location = en + avatar = inoki.jpg + +[ritukapatwalorepoala] + title = Rituka Patwal (orepoala) + feed = https://orepoala.home.blog/category/kde/feed/ + link = https://orepoala.home.blog/category/kde + location = en + avatar = orepoala.png + +[sirgienkonikitasirgienko] + title = Sirgienko Nikita (sirgienko) + feed = https://sirgienkogsoc2019.blogspot.com/feeds/posts/default + link = https://sirgienkogsoc2019.blogspot.com + location = en + avatar = sirgienko.png + +[devanshuagarwalagdeva8] + title = Devanshu Agarwal (agdeva8) + feed = https://agdeva8labplot.blogspot.com/rss.xml + link = https://agdeva8labplot.blogspot.com + location = en + avatar = devanshuagarwal.png + +[sharafzamanshzam] + title = Sharaf Zaman (sh_zam) + feed = https://www.sh-zam.com/feeds/posts/default/-/kde + link = https://www.sh-zam.com + location = en + avatar = sh_zam.png + +[tusooa] + title = tusooa + feed = https://tusooa.github.io/tags/kde/atom.xml + link = https://tusooa.github.io/tags/kde + location = en + avatar = tusooa.png + +[faridboudedjafaridb] + title = Farid Boudedja (faridb) + feed = https://fbgsoc.home.blog/feed/ + link = https://fbgsoc.home.blog + location = en + avatar = faridb.png + +[asaoutkinfeverfew] + title = A Saoutkin (feverfew) + feed = https://feverfew.home.blog/feed/ + link = https://feverfew.home.blog + location = en + avatar = asaoutkin.png + +[akhilkgangadharanakhilkg] + title = Akhil K Gangadharan (akhilkg_) + feed = https://akhilam512.github.io/blog/feed.jekyll.xml + link = https://akhilam512.github.io/blog + location = en + avatar = akhilkgangadharan.png + +[akshaykumarakshaychd] + title = Akshay Kumar (akshaychd) + feed = https://akshaychd.blogspot.com/feeds/posts/default + link = https://akshaychd.blogspot.com + location = en + avatar = akshaychd.png + +[caiotonettictonetti] + title = Caio Tonetti (ctonetti) + feed = https://chst.dev/feed.xml + link = https://chst.dev + location = en + avatar = ctonetti.png + +[dimitriskardarakosdkardarakos] + title = Dimitris Kardarakos (dkardarakos) + feed = https://dimitris.cc/feed/kde.xml + link = https://dimitris.cc + location = en + avatar = dkardarakos.png + +[songeonjen6] + title = SonGeon (jen6) + feed = https://jen6.github.io/feed_kde.xml + link = https://jen6.github.io + location = en + avatar = songeon_hackergotchi.png + +[karinapassoskarinapassos] + title = Karina Passos (karinapassos) + feed = https://karinappassos.home.blog/feed/ + link = https://karinappassos.home.blog + location = en + avatar = karina.jpeg + +[carlschwanognarb] + title = Carl Schwan + feed = https://carlschwan.eu/feed.xml + link = https://carlschwan.eu + location = en + author = irc:CarlSchwan + avatar = ognarb.png + +[joãonettojoaonetto] + title = João Netto (joaonetto) + feed = https://gsocokular2019.home.blog/feed/?mrss=off + link = https://gsocokular2019.home.blog + location = en + +[shubhamshubham] + title = Shubham (shubham) + feed = https://coderunner99.blogspot.com/feeds/posts/default + link = https://coderunner99.blogspot.com + location = en + +[caiojordãocarvalhocjlcarvalho] + title = Caio Jordão Carvalho (cjlcarvalho) + feed = https://caiojcarvalho.wordpress.com/category/kde/feed/ + link = https://caiojcarvalho.wordpress.com/category/kde + location = en + avatar = caiojcarvalho.png + +[davidredondodavidredondo] + title = David Redondo (DavidRedondo) + feed = https://blog.david-redondo.de/feed.xml + link = https://blog.david-redondo.de + location = en + +[simonredmansredman] + title = Simon Redman (sredman) + feed = https://simonredman.wordpress.com/category/kde/feed/ + link = https://simonredman.wordpress.com/category/kde + location = en + avatar = sredman.png + +[mévencarmeven] + title = Méven Car (meven) + feed = http://www.bivouak.fr/feed/tag/kde/atom + link = http://www.bivouak.fr + location = en + avatar = meven.png + +[plasmamobileblog] + title = Plasma Mobile blog + feed = https://www.plasma-mobile.org/feed-kde-planet.xml + link = https://www.plasma-mobile.org + location = en + avatar = plasma-mobile.png + +[thiagomasatocostasueto] + title = Thiago Masato Costa Sueto + feed = https://rabbitictranslator.com/wordpress/index.php/tag/planetkde/feed/ + link = https://rabbitictranslator.com/wordpress/index.php/tag/planetkde + location = en + avatar = thiago.png + +[jurajoravecsgorava] + title = Juraj Oravec (SGOrava) + feed = https://sgorava.github.io/feed/KDE.xml + link = https://sgorava.github.io + location = en + +[agatacackotiar] + title = Agata Cacko (tiar) + feed = https://outsideofinfinity.wordpress.com/category/planet/feed/ + link = https://outsideofinfinity.wordpress.com + location = en + avatar = tiar.png + +[sandroknaußhefee] + title = Sandro Knauß (hefee) + feed = https://sandroknauss.de/blog/categories/kde/feed.xml + link = https://sandroknauss.de/blog + location = en + avatar = hefee.png + +[cantor] + title = Cantor + feed = https://cantor.kde.org/feed.xml + link = https://cantor.kde.org + location = en + avatar = cantor.svg + +[kennycoylekcoyle] + title = Kenny Coyle (kcoyle) + feed = https://journal.heloo.net/tag/kde/rss2.xml + link = https://journal.heloo.net/tag/kde + location = en + avatar = kcoyle.png + +[tharjun] + title = T.H.Arjun + feed = https://arjunth2001.github.io/kdeblog/feed.xml + link = https://arjunth2001.github.io/kdeblog + location = en + avatar = arjun.jpg + +[anujbansal] + title = Anuj Bansal + feed = https://ab63.github.io/feed.xml + link = https://ab63.github.io + location = en + avatar = anuj.png + +[shubhammishra] + title = Shubham Mishra + feed = https://shivam8287.github.io/feed.xml + link = https://shivam8287.github.io + location = en + avatar = Shubham.png + +[deepakkumardekumar] + title = Deepak Kumar + feed = https://politepol.com/fd/KhzJaKPDKtvZ + link = https://politepol.com/fd/KhzJaKPDKtvZ + location = en + author = irc:dekumar + avatar = dipak.jpg + +[deepakkumardekumar2] + title = Deepak Kumar + feed = https://politepol.com/fd/HZdrGp730QQQ + link = https://politepol.com/fd/HZdrGp730QQQ + location = en + author = irc:dekumar + avatar = dipak.jpg + diff --git a/planetkde/config b/planetkde/config deleted file mode 100644 --- a/planetkde/config +++ /dev/null @@ -1,3406 +0,0 @@ -# Planet KDE config fil - -# Add your blog - -#If you are a KDE contributor you can have your blog on Planet -#KDE. Blog content should be mostly KDE themed, English language and -#not liable to offend. If you have a general blog you may want to set -#up a tag and subscribe the feed for that tag only to Planet KDE. - -#To have your blog added file a bug in Bugzilla listing your name, KDE Identity -#account (if you have one), IRC nick (if you have one), RSS or Atom -#feed and what you do in KDE. Attach a photo of your face for -#hackergotchi. - -#Alternatively, Planet KDE is kept in KDE's GIT. If you have an -#account you can add or edit your own feed: - -#git clone git@git.kde.org:websites/planet-kde-org -#Put your hackergotchi in planetkde/website/hackergotchi/. A hackergotchi should be a photo of -#your face smaller than 80x80 pixels with a transparent background. git add the file. -#At the end of the planetkde/config file add your details (the name in brackets is your IRC nick): - -#feed 15m http://path.to/my/feed.rss -# define_name Konqi Konqueror (konqi) -# define_face hackergotchi/konqi.png -# define_facewidth 80 -# define_faceheight 80 - -#If you want to add a Twitter microblog to the Microblogging sidebar -#add define_microblog true and follow your name with -#[twitter]. Currently only Twitter is known to work, please contact -#Jonathan Riddell before adding non-Twitter microblogs to check it -#works. - -#Planet KDE Guidelines - -#Planet KDE is one of the public faces of the KDE project and is read -#by millions of users and potential contributors. The content -#aggregated at Planet KDE is the opinions of its authors, but the sum -#of that content gives an impression of the project. Please keep in -#mind the following guidelines for your blog content and read the -#[http://www.kde.org/code-of-conduct/ KDE Code of Conduct]. The KDE -#project reserves the right to remove an inappropriate blog from the -#Planet. If that happens multiple times, the Community Working Group -#can be asked to consider what needs to happen to get your blog -#aggregated again. - -#If you are unsure or have queries about what is appropriate contact -#the KDE Community Working Group. - -#Blogs should be KDE themed - -#The majority of content in your blog should be about KDE and your -#work on KDE. Blog posts about personal subjects are also encouraged -#since Planet KDE is a chance to learn more about the developers -#behind KDE. However blog feeds should not be entirely personal, if in -#doubt set up a tag for Planet KDE and subscribe the feed from that -#tag so you can control what gets posted. - -#Posts should be constructive - -#Posts can be positive and promote KDE, they can be constructive and -#lay out issues which need to be addressed, but blog feeds should not -#contain useless, destructive and negative material. Constructive -#criticism is welcome and the occasional rant is understandable, but a -#feed where every post is critical and negative is unsuitable. This -#helps to keep KDE overall a happy project. - -#You must be a KDE contributor - -#Only have your blog on Planet KDE if you actively contribute to KDE, -#for example through code, user support, documentation etc. - -#Do not inflame - -#KDE covers a wide variety of people and cultures. Profanities, -#prejudice, lewd comments and content likely to offend are to be -#avoided. Do not make personal attacks or attacks against other -#projects on your blog. - -#For further guidance on good practice see the KDE Code of Conduct. - -#################################### - -# Times in this file are specified as a value and a unit (for instance, -# "4h"). Units available are "s" (seconds), "m" (minutes), "h" (hours), -# "d" (days) and "w" (weeks). If no unit is specified, rawdog will -# assume minutes. -# Boolean (yes/no) values in this file are specified as "true" or "false". - -# rawdog can be extended using plugin modules written in Python. This -# option specifies the directories to search for plugins to load. If a -# directory does not exist or cannot be read, it will be ignored. This -# option must appear before any options that are implemented by plugins. -plugindirs plugins - -# Whether to split rawdog's state amongst multiple files. -# To use this option, you must first "mkdir ~/.rawdog/feeds". -# If this is turned on, rawdog will use significantly less memory, but -# will do more disk IO -- probably a good idea if you read a lot of -# feeds. -splitstate true - -# The maximum number of articles to show on the generated page. -# Set this to 0 for no limit. -maxarticles 30 - -# The maximum age of articles to show on the generated page. -# Set this to 0 for no limit. -maxage 0 - -# The age after which articles will be discarded if they do not appear -# in a feed. Set this to a larger value if you want your rawdog output -# to cover more than a day's worth of articles. -expireage 1d - -# The minimum number of articles from each feed to keep around in the history. -# Set this to 0 to only keep articles that were returned the last time the feed -# was fetched. (If this is set to 0, or "currentonly" below is set to true, -# then rawdog will not send the RFC3229+feed "A-IM: feed" header when making -# HTTP requests, since it can't tell from the response to such a request -# whether any articles have been removed from the feed; this makes rawdog -# slightly less bandwidth-efficient.) -keepmin 3 - -# Whether to only display articles that are currently included in a feed -# (useful for "planet" pages where you only want to display the current -# articles from several feeds). If this is false, rawdog will keep a -# history of older articles. -currentonly true - -# Whether to divide the articles up by day, writing a "dayformat" heading -# before each set. -daysections true - -# The format to write day headings in. See "man strftime" for more -# information; for example: -# %A, %d %B Wednesday, 21 January -# %Y-%m-%d 2004-01-21 (ISO 8601 format) -dayformat %B %d, %Y - -# Whether to divide the articles up by time, writing a "timeformat" heading -# before each set. -timesections false - -# The format to write time headings in. For example: -# %H:%M 18:07 (ISO 8601 format) -# %I:%M %p 06:07 PM -# timeformat %H:%M - -# The format to display feed update and article times in. For example: -# %H:%M, %A, %d %B 18:07, Wednesday, 21 January -# %Y-%m-%d %H:%M 2004-01-21 18:07 (ISO 8601 format) -datetimeformat %H:%M, %A, %d %B - -# The template file to use, or "default" to use the built-in template -# (which is probably sufficient for most users). Use "rawdog -t" to show -# the template currently in use as a starting-point for customisation. -# The following strings will be replaced in the output: -# __version__ The rawdog version in use -# __refresh__ The HTML 4 header -# __items__ The aggregated items -# __num_items__ The number of items on the page -# __feeds__ The listing of feeds -# __num_feeds__ The number of feeds listed -# You can define additional strings using "define" in this config file; for -# example, if you say "define myname Adam Sampson", then "__myname__" will be -# replaced by "Adam Sampson" in the output. -template planet_template - -# Similarly, the template used for each item shown. Use "rawdog -T" to -# show the template currently in use as a starting-point for -# customisation. The following strings will be replaced in the output: -# __title__ The item title (as an HTML link, if possible) -# __title_no_link__ The item title (as text) -# __url__ The item's URL, or the empty string if it doesn't -# have one -# __guid__ The item's GUID, or the empty string if it doesn't -# have one -# __description__ The item's descriptive text, or the empty string -# if it doesn't have a description -# __date__ The item's date as provided by the feed -# __added__ The date the article was received by rawdog -# __hash__ A hash of the article (useful for summary pages) -# __feed_title__ The feed title (as an HTML link, if possible) -# __feed_title_no_link__ -# The feed title (as text) -# __feed_url__ The feed URL -# __feed_hash__ A hash of the feed URL (useful for per-feed styles) -# __feed_id__ The feed's title with non-alphanumeric characters -# (and HTML markup) removed (useful for per-feed -# styles); you can use the "id" feed option below to -# set a custom ID if you prefer -# You can define additional strings on a per-feed basis by using the -# "define_X" feed option; see the description of "feed" below for more -# details. -# Simple conditional expansion is possible by saying something like -# "__if_items__ hello __endif__"; the text between the if and endif will -# only be included if __items__ would expand to something other than -# the empty string. Ifs can be nested, and __else__ is supported. (This also -# works for the "template" option, but it's more useful for item -# templates.) -itemtemplate itemplate - -# Where to write the output HTML to. You should place style.css in the same -# directory. Specify this as "-" to write the HTML to stdout. -# (You will probably want to make this an absolute path, else rawdog will write -# to a file in your ~/.rawdog directory.) -#outputfile output.html -outputfile ../website/index.html - -outputxml ../website/rss20.xml -outputfoaf ../website/foafroll.xml -outputopml ../website/opml.xml -xmlmaxarticles 30 - -# Whether to use a tag in the generated -# HTML to indicate that the page should be refreshed automatically. If -# this is turned on, then the page will refresh every N minutes, where N -# is the shortest feed period value specified below. -# (This works by controlling whether the default template includes -# __refresh__; if you use a custom template, __refresh__ is always -# available.) -userefresh true - -# Whether to show the list of active feeds in the generated HTML. -# (This works by controlling whether the default template includes -# __feeds__; if you use a custom template, __feeds__ is always -# available.) -showfeeds true - -# The number of concurrent threads that rawdog will use when fetching -# feeds -- i.e. the number of feeds that rawdog will attempt to fetch at -# the same time. If you have a lot of feeds, setting this to be 20 or -# so will significantly speed up updates. If this is set to 0, rawdog -# will not use threads at all. -numthreads 3 - -# The time that rawdog will wait before considering a feed unreachable -# when trying to connect. If you're getting lots of timeout errors and -# are on a slow connection, increase this. -# (Unlike other times in this file, this will be assumed to be in -# seconds if no unit is specified.) -timeout 30s - -# Whether to ignore timeouts. If this is false, timeouts will be reported as -# errors; if this is true, rawdog will silently ignore them. -ignoretimeouts false - -# Whether to display verbose status messages saying what rawdog's doing -# while it runs. Specifying -v or --verbose on the command line is -# equivalent to saying "verbose true" here. -verbose false - -# Whether to attempt to fix bits of HTML that should start with a -# block-level element (such as article descriptions) by prepending "

" -# if they don't already start with a block-level element. -blocklevelhtml true - -# Whether to attempt to turn feed-provided HTML into valid HTML. -# The most common problem that this solves is a non-closed element in an -# article causing formatting problems for the rest of the page. -# If this option is turned on, you must have the mx.Tidy Python module -# installed. -##tidyhtml true - -# Whether the articles displayed should be sorted first by the date -# provided in the feed (useful for "planet" pages, where you're -# displaying several feeds and want new articles to appear in the right -# chronological place). If this is false, then articles will first be -# sorted by the time that rawdog first saw them. -sortbyfeeddate true - -# Whether to consider articles' unique IDs or GUIDs when updating rawdog's -# database. If you turn this off, then rawdog will create a new article in its -# database when it sees an updated version of an existing article in a feed. -# You probably want this turned on. -# useids true - -# The fields to use when detecting duplicate articles: "id" is the article's -# unique ID or GUID; "link" is the article's link. rawdog will find the first -# one of these that's present in the article, and ignore the article if it's -# seen an article before (in any feed) that had the same value. For example, -# specifying "hideduplicates id link" will first look for id/guid, then for -# link. -# Note that some feeds use the same link for all their articles; if you specify -# "link" here, you will probably want to specify the "allowduplicates" feed -# argument (see below) for those feeds. -hideduplicates id - -# The period to use for new feeds added to the config file via the -a|--add -# option. -newfeedperiod 3h - -# Whether rawdog should automatically update this config file (and its -# internal state) if feed URLs change (for instance, if a feed URL -# results in a permanent HTTP redirect). If this is false, then rawdog -# will ask you to make the necessary change by hand. -changeconfig true - -# The feeds you want to watch, in the format "feed period url [args]". -# The period is the minimum time between updates; if less than period -# minutes have passed, "rawdog update" will skip that feed. Specifying -# a period less than 30 minutes is considered to be bad manners; it is -# suggested that you make the period as long as possible. -# Arguments are optional, and can be given in two ways: either on the end of -# the "feed" line in the form "key=value", separated by spaces, or as extra -# indented lines after the feed line. -# possible arguments are: -# id Value for the __feed_id__ value in the item -# template for items in this feed (defaults to the -# feed title with non-alphanumeric characters and -# HTML markup removed) -# user User for HTTP basic authentication -# password Password for HTTP basic authentication -# format "text" to indicate that the descriptions in this feed -# are unescaped plain text (rather than the usual HTML), -# and should be escaped and wrapped in a

 element
-# X_proxy             Proxy URL for protocol X (for instance, "http_proxy")
-# proxyuser           User for proxy basic authentication
-# proxypassword       Password for proxy basic authentication
-# allowduplicates     "true" to disable duplicate detection for this feed
-# maxage              Override the global "maxage" value for this feed
-# keepmin             Override the global "keepmin" value for this feed
-# define_X            Equivalent to "define X ..." for item templates
-#                     when displaying items from this feed
-# You can provide a default set of arguments for all feeds using
-# "feeddefaults". You can specify as many feeds as you like.
-# (These examples have been commented out; remove the leading "#" on each line
-# to use them.)
-#feeddefaults
-#	http_proxy http://proxy.example.com:3128/
-#feed 1h http://example.com/feed.rss
-#feed 15m http://example.com/feed2.rss id=newsfront
-#feed 3h http://example.com/feed3.rss keepmin=5
-#feed 3h http://example.com/secret.rss user=bob password=secret
-#feed 3h http://example.com/broken.rss
-#	format text
-#	define_myclass broken
-#feed 3h http://proxyfeed.example.com/proxied.rss http_proxy=http://localhost:1234/
-#feed 3h http://dupsfeed.example.com/duplicated.rss allowduplicates=true
-
-feed 15m http://afiestas.org/category/floss/kde/feed/
-    define_name Alex Fiestas (afiestas)
-    define_face hackergotchi/afiestas.png
-    define_facewidth 59
-    define_faceheight 79
-
-feed 15m http://sujithh.info/feed/?tag=KDE-dev%2CPlasma-dev
-    define_name Sujith H (sujith_h)
-    define_face hackergotchi/sujithh.png
-    define_facewidth 64
-    define_faceheight 81
-
-feed 15m http://blog.zx2c4.com/planetkde
-    define_name Jason A. Donenfeld (zx2c4/jdonenfeld)
-    define_face hackergotchi/jdonenfeld.png
-    define_facewidth 61
-    define_faceheight 70
-
-feed 15m http://www.purinchu.net/wp/feed/
-    define_name Michael Pyne (mpyne)
-    define_face hackergotchi/mpyne.png
-    define_facewidth 64
-    define_faceheight 80
-
-feed 15m https://blogs.kde.org/blog/11/feed
-    define_name Maksim Orlovich (SadEagle)
-
-feed 15m https://valdyas.org/fading/category/planet/feed/
-    define_name Boudewijn Rempt (boud)
-
-feed 15m http://ramblingsofpsn.blogspot.com/feeds/posts/default
-    define_name Peter Simonsson (psn)
-
-feed 15m http://digested.blogspot.com/atom.xml
-    define_name Derek Kite (dkite)
-
-feed 15m http://annma.blogspot.com/feeds/posts/default/-/KDE
-    define_name Anne-Marie Mahfouf (annma)
-    define_face hackergotchi/annma.jpg
-    define_facewidth 80
-    define_faceheight 80
-
-feed 15m http://ltinkl.blogspot.com/atom.xml
-    define_name Lukas Tinkl
-
-feed 15m https://blogs.kde.org/blog/89/feed
-    define_name Richard Dale
-
-feed 15m http://greeneg.blogspot.com/feeds/posts/default/-/KDE
-    define_name Gary Greene (greeneg)
-
-feed 15m https://blogs.kde.org/blog/72/feed
-    define_name Scott Wheeler (wheels)
-    define_face hackergotchi/wheels.png
-    define_facewidth 66
-    define_faceheight 80
-
-feed 15m https://blogs.kde.org/blog/9/feed
-    define_name Richard Moore (richmoore2)
-
-feed 15m https://blogs.kde.org/blog/35/feed
-    define_name Mathieu Chouinard (chouimat)
-    define_face hackergotchi/chouimat.png
-    define_facewidth 64
-    define_faceheight 78
-
-feed 15m https://blogs.kde.org/blog/2/feed
-    define_name Ian Geiser (geiseri)
-    define_face hackergotchi/geiseri.png
-    define_facewidth 64
-    define_faceheight 79
-
-feed 15m http://tokoe-kde.blogspot.com/rss.xml
-    define_name Tobias Koenig (tokoe)
-
-feed 15m http://zrusin.blogspot.com/rss.xml
-    define_name Zack Rusin (zrusin)
-
-feed 30m https://www.heliocastro.info/feeds/opensource.atom.xml
-    define_name Helio Castro (heliocastro)
-    define_face hackergotchi/helio_castro.png
-    define_facewidth 64
-    define_faceheight 64
-
-feed 15m https://blogs.kde.org/blog/70/feed
-    define_name Waldo Bastian (zogje)
-
-feed 15m https://blog.cornelius-schumacher.de/feeds/posts/default
-    define_name Cornelius Schumacher
-    define_face hackergotchi/cornelius.png
-    define_facewidth 59
-    define_faceheight 85
-
-feed 15m https://blogs.kde.org/blog/104/feed
-    define_name Jarosław Staniek (jstaniek)
-    define_face hackergotchi/jstaniek.png
-
-feed 15m https://blogs.kde.org/blog/395/feed
-    define_name John Ratke
-
-feed 15m https://blogs.kde.org/blog/57/feed
-    define_name Jonathan Riddell (riddell)
-    define_face hackergotchi/riddell.png
-    define_facewidth 68
-    define_faceheight 97
-
-feed 15m https://jriddell.org/feed/?tag=planetkde
-    define_name Jonathan Riddell (riddell)
-    define_face hackergotchi/riddell.png
-    define_facewidth 68
-    define_faceheight 97
-
-feed 15m https://blogs.kde.org/blog/432/feed
-    define_name Till Adam
-
-feed 15m https://blogs.kde.org/blog/457/feed
-    define_name Stephan Binner (Beineri)
-    define_face hackergotchi/beineri.png
-    define_facewidth 70
-    define_faceheight 70
-
-feed 15m https://blogs.kde.org/blog/102/feed
-    define_name Brad Hards (bradh)
-
-feed 15m http://www.livejournal.com/users/cniehaus/data/rss
-    define_name Carsten Niehaus (carsten)
-
-feed 15m https://blogs.kde.org/blog/105/feed
-    define_name Adam Treat (manyoso)
-    define_face hackergotchi/manyoso.png
-    define_facewidth 85
-    define_faceheight 85
-
-feed 15m http://pdamsten.blogspot.com/feeds/posts/default/-/kde
-    define_name Petri Damstén
-    define_face hackergotchi/pdamsten.png
-    define_facewidth 80
-    define_faceheight 80
-
-feed 15m https://blogs.kde.org/blog/418/feed
-    define_name Kurt Pfeifle (pipitas)
-
-feed 15m http://mark-kretschmann.blogspot.com/feeds/posts/default
-    define_name Mark Kretschmann (markey)
-    define_face hackergotchi/markey_gotchi.png
-    define_facewidth 80
-    define_faceheight 80
-
-feed 15m https://blogs.kde.org/blog/124/feed
-    define_name Stephan Kulow (coolo)
-
-feed 15m http://www.alexdymo.com/blog/feed/kde.xml
-    define_name Alexander Dymo (adymo)
-    define_face hackergotchi/dymo.png
-    define_facewidth 80
-    define_faceheight 80
-
-feed 15m http://nhasan.blogspot.com/atom.xml
-    define_name Nadeem Hasan
-    define_face hackergotchi/nadeem.png
-    define_facewidth 64
-    define_faceheight 80
-
-feed 15m http://accentgrave.blogspot.com/atom.xml
-    define_name Philip Rodrigues (PhilRod)
-
-feed 15m https://blogs.kde.org/blog/1451/feed
-    define_name Allen Winter
-
-feed 15m https://blogs.kde.org/blog/225/feed
-    define_name Carlos Leonhard Woelz (cwoelz)
-
-feed 15m https://blogs.kde.org/blog/299/feed
-    define_name Henrique Pinto
-
-feed 15m https://tsdgeos.blogspot.com/feeds/posts/default?alt=atom
-    define_name Albert Astals Cid (TSDgeos)
-    define_face hackergotchi/TSDgeos.png
-    define_facewidth 80
-    define_faceheight 80
-
-feed 45m https://tcanabrava.github.io/feed.xml
-    define_name Tomaz Canabrava (tomaz)
-    define_face hackergotchi/tomaz-canabrava.png
-    define_facewidth 80
-    define_faceheight 80
-
-feed 15m https://blogs.kde.org/blog/55/feed
-    define_name Lucijan Busch (lucijan)
-
-feed 15m http://marccramdal.blogspot.com/atom.xml
-    define_name Marc Cramdal
-
-feed 15m https://blogs.kde.org/blog/278/feed
-    define_name Allan Sandfeld Jensen (carewolf)
-
-feed 15m http://theobromas.blogspot.com/atom.xml
-    define_name Janet Theobroma (theobroma)
-    define_face hackergotchi/theobroma.png
-    define_facewidth 80
-    define_faceheight 80
-
-feed 15m https://blogs.kde.org/blog/460/feed
-    define_name Kurt Hindenburg
-
-feed 45m https://euroquis.nl/feed.xml
-    define_name Adriaan de Groot ([ade])
-    define_face hackergotchi/adridg.png
-    define_facewidth 72
-    define_faceheight 65
-
-feed 15m https://blogs.kde.org/blog/20/feed
-    define_name Andras Mantia
-
-feed 15m http://www.kuarepoti-dju.net/tags/community:desktop/index.rss
-    define_name Josef Spillner
-
-feed 15m https://blogs.kde.org/blog/77/feed
-    define_name Will Stephenson
-
-feed 15m http://www.christian-loose.de/wordpress/category/kde/feed/
-    define_name Christian Loose
-
-feed 15m https://blogs.kde.org/blog/938/feed
-    define_name Jan Muehlig (janushead)
-
-feed 15m http://tina-t.blogspot.com/atom.xml
-    define_name Tina Trillitzsch
-    define_face hackergotchi/tina.png
-    define_facewidth 74
-    define_faceheight 76
-
-feed 15m https://blogs.kde.org/blog/175/feed
-    define_name Fabrice Mous (fab)
-    define_face hackergotchi/fab.png
-    define_facewidth 77
-    define_faceheight 85
-
-feed 15m https://blogs.kde.org/blog/311/feed
-    define_name Cristian Tibirna (Inorog)
-
-feed 15m https://blogs.kde.org/blog/1088/feed
-    define_name Nikolas Zimmermann (WildFox)
-
-feed 15m https://blogs.kde.org/blog/699/feed
-    define_name Frank Osterfeld (fosterfeld)
-
-feed 15m https://blogs.kde.org/blog/1089/feed
-    define_name Rob Buis (rwlbuis)
-
-feed 15m https://cullmann.io/index.xml
-    define_name Christoph Cullmann (cullmann)
-    define_face hackergotchi/cullmann.png
-    define_facewidth 80
-    define_faceheight 80
-
-feed 15m https://kate-editor.org/index.xml
-    define_name Kate News
-    define_face hackergotchi/kate.png
-    define_facewidth 80
-    define_faceheight 80
-
-feed 15m https://blogs.kde.org/blog/16/feed
-    define_name Reinhold Kainhofer
-
-feed 15m https://kamikazow.wordpress.com/feed/?mrss=off
-    define_name Markus Slopianka (markuss)
-
-feed 15m https://macieira.org/blog/author/thiago/feed/
-    define_name Thiago Macieira (thiago)
-
-feed 15m https://liquidat.wordpress.com/category/kde/feed/?mrss=off
-    define_name Roland Wolters (liquidat)
-
-feed 15m https://blogs.kde.org/blog/38/feed
-    define_name Jason Harris (LMCboy)
-
-feed 15m https://blogs.kde.org/blog/242/feed
-    define_name Stefan Teleman
-
-feed 15m https://blogs.kde.org/blog/1186/feed
-    define_name Antonio Larrosa Jimenez (antlarr)
-
-feed 15m https://blogs.kde.org/blog/531/feed
-    define_name Alexander Neundorf
-
-feed 15m https://blogs.kde.org/blog/1192/feed
-    define_name Martijn Klingens
-
-feed 15m http://jahqueel.blogspot.com/atom.xml
-    define_name Ashley Winters
-
-feed 15m https://blogs.kde.org/blog/41/feed
-    define_name Gregor Iaskievitch
-
-feed 15m http://pinheiro-kde.blogspot.com/rss.xml
-    define_name Nuno Pinheiro (pinheiro)
-    define_face hackergotchi/pinheiro.png
-    define_facewidth 80
-    define_faceheight 80
-
-feed 15m https://vizZzion.org/blog/category/english/feed/
-    define_name Sebastian Kügler (sebas)
-    define_face hackergotchi/sebascolor.png
-    define_facewidth 80
-    define_faceheight 80
-
-feed 15m http://kath-leinir.blogspot.com/feeds/posts/default/-/kde
-    define_name Dan Leinir Turthra Jensen (leinir)
-    define_face hackergotchi/leinir.png
-    define_facewidth 80
-    define_faceheight 80
-
-feed 15m http://jamesots.blogspot.com/atom.xml
-    define_name James Ots
-
-feed 15m http://ciesbreijs.blogspot.com/atom.xml
-    define_name Cies Breijs (cies)
-
-feed 15m https://blogs.kde.org/blog/83/feed
-    define_name Kevin Krammer
-
-feed 15m https://blogs.kde.org/blog/1195/feed
-    define_name Simon Edwards
-
-feed 15m https://blogs.kde.org/blog/838/feed
-    define_name Dario Massarin
-
-feed 15m https://blogs.kde.org/blog/7440/feed
-    define_name Robert Mathias Marmorstein (robertm)
-
-feed 15m http://mbroadst.blogspot.com/atom.xml
-    define_name Matt Broadstone
-
-feed 15m http://www.thelins.se/johan/blog/feed/
-    define_name Johan Thelin
-
-feed 15m http://kwwii.blogspot.com/feeds/posts/default/-/KDE
-    define_name Kenneth Wimer (kwwii)
-
-feed 15m http://llunak.blogspot.com/feeds/posts/default/-/kde
-    define_name Luboš Luňák (llunak)
-
-feed 15m https://blogs.kde.org/blog/952/feed
-    define_name Martin Konold (Mortimer)
-
-feed 15m http://ingwa2.blogspot.com/atom.xml
-    define_name Inge Wallin (ingwa)
-
-feed 15m http://moji-shahi.blogspot.com/atom.xml
-    define_name Mojtaba Shahi Senobari (moji)
-
-feed 15m http://calligra-author-outliner.blogspot.ru/atom.xml
-    define_name Denis Kuplyakov (denerkup)
-
-feed 15m https://blogs.kde.org/blog/1397/feed
-    define_name Jesper K. Pedersen (blackie)
-    define_face hackergotchi/blackie.png
-    define_facewidth 80
-    define_faceheight 53
-
-feed 15m https://blogs.kde.org/blog/551/feed
-    define_name Torsten Rahn (tackat)
-
-feed 15m http://fredrikh.blogspot.com/atom.xml
-    define_name Fredrik Höglund
-
-feed 15m http://blog.cberger.net/category/open-source/feed/?mrss=off
-    define_name Cyrille Berger
-    define_face hackergotchi/cberger.png
-    define_facewidth 80
-    define_faceheight 80
-
-feed 15m http://clarencedang.blogspot.com/atom.xml
-    define_name Clarence Dang
-
-feed 15m http://blog.vladimirprus.com/feeds/posts/default/-/kde
-    define_name Vladimir Prus
-
-feed 15m https://agateau.com/tags/pko/feed
-    define_name Aurelien Gateau
-
-feed 15m http://delftblueramblings.blogspot.com/atom.xml
-    define_name Sander Koning
-
-feed 15m http://jefferai.org/atom.xml
-    define_name Jeff Mitchell (jefferai)
-
-feed 15m https://blogs.kde.org/blog/1813/feed
-    define_name Mirko Boehm (miroslav)
-
-feed 15m https://blogs.kde.org/blog/326/feed
-    define_name David Faure (dfaure)
-
-feed 15m https://blogs.kde.org/blog/1236/feed
-    define_name C. Boemann (boemann)
-
-feed 15m https://englich.wordpress.com/feed/?mrss=off
-    define_name Frans Englich (FransE)
-
-feed 15m https://frinring.wordpress.com/category/kde/feed/?mrss=off&category_name=kde
-    define_name Friedrich Kossebau (frinring)
-    define_face hackergotchi/frinring.png
-    define_facewidth 64
-    define_faceheight 64
-
-feed 15m https://blogs.kde.org/blog/477/feed
-    define_name Sebastian Sauer (dipesh)
-
-feed 15m https://blogs.kde.org/blog/1471/feed
-    define_name Bart Coppens (BCoppens)
-
-feed 15m https://chani.wordpress.com/category/planet/feed/?mrss=off&category_name=planet
-    define_name Chani Armitage (Chani)
-
-feed 15m https://blogs.kde.org/blog/56/feed
-    define_name Hamish Rodda (blackarrow)
-
-feed 15m https://www.vandenoever.info/index.atom
-    define_name Jos van den Oever (vandenoever)
-    define_face hackergotchi/vandenoever.png
-    define_facewidth 80
-    define_faceheight 57
-
-feed 15m http://kemistry-desktop.blogspot.com/atom.xml
-    define_name Egon Willighagen
-
-feed 15m https://blog.bisect.de/feeds/posts/default?alt=atom
-    define_name Danny Kukawka
-
-feed 15m http://transloid.blogspot.com/feeds/posts/default
-    define_name Eva Brucherseifer
-
-feed 15m http://maxilys.blogspot.com/rss.xml
-    define_name Remi Villatel
-
-feed 15m https://wadejolson.wordpress.com/feed/?mrss=off
-    define_name Wade Olson
-
-feed 15m http://kdemonkey.blogspot.com/feeds/posts/default
-    define_name Robert Knight
-
-feed 15m https://cukic.co/feeds/tag-planetkde.xml
-    define_name Ivan Čukić (ivan)
-    define_face hackergotchi/ivan.png
-    define_facewidth 80
-    define_faceheight 80
-
-feed 15m http://ksvladimir.blogspot.com/atom.xml
-    define_name Vladimir Kuznetsov
-
-feed 15m http://jarlesdraw-log.blogspot.com/atom.xml
-    define_name Jarle Akselsen
-
-feed 15m http://blog.jospoortvliet.com/feeds/posts/default/-/kde/?alt=rss
-    define_name Jos Poortvliet
-    define_face hackergotchi/jospoortvliet.png
-    define_facewidth 65
-    define_faceheight 80
-
-feed 15m http://commonideas.blogspot.com/feeds/posts/default/-/KDE
-    define_name Bart Cerneels (Stecchino)
-
-feed 15m https://ervin.ipsquad.net/atom.xml
-    define_name Kevin Ottens (ervin)
-
-feed 15m https://zanshin.kde.org/atom.xml
-    define_name Zanshin Announcements
-    define_feedclass news
-
-feed 15m http://www.proli.net/feed/
-    define_name Aleix Pol (apol)
-
-feed 15m https://cryos.net/categories/kde/index.xml
-    define_name Marcus Hanwell (cryos)
-
-feed 15m https://ksounds.wordpress.com/feed/?mrss=off
-    define_name Martyn Circus
-
-feed 15m http://rivolaks.blogspot.com/feeds/posts/default
-    define_name Rivo Laks
-
-feed 15m https://jaham.wordpress.com/category/kde/feed/?mrss=off&category_name=kde
-    define_name Jan Hambrecht (jaham)
-
-feed 15m http://domseichter.blogspot.com/feeds/posts/default
-    define_name Dominik Seichter
-
-feed 15m http://chehrlic.blogspot.com/rss.xml
-    define_name Christian Ehrlicher
-
-feed 15m http://neksa.blogspot.com/rss.xml
-    define_name Alexandr Goncearenco
-
-feed 15m https://apaku.wordpress.com/feed/?mrss=off
-    define_name Andreas Pakulat
-
-feed 15m https://apachelog.wordpress.com/category/kde/feed/?mrss=off&category_name=kde
-    define_name Harald Sitter (apachelogger)
-    define_face hackergotchi/apachelogger.jpg
-
-feed 15m https://myrizio.wordpress.com/feed/?mrss=off
-    define_name Maurizio Monge
-
-feed 15m https://meson10.wordpress.com/feed/?mrss=off
-    define_name Piyush Verma
-
-feed 15m https://darktears.wordpress.com/category/kde/feed/?mrss=off&category_name=kde
-    define_name Alexis Menard (darktears)
-    define_face hackergotchi/alexis-menard.jpg
-    define_facewidth 80
-    define_faceheight 80
-
-feed 15m https://amachu.wordpress.com/feed/?mrss=off&category_name=kde
-    define_name Sri Ramadoss M (amachu)
-
-feed 15m https://kdedmiller.wordpress.com/feed/?mrss=off
-    define_name David Miller
-
-feed 15m http://blog.hartwork.org/?feed=rss2&cat=23
-    define_name Sebastian Pipping (sping)
-
-feed 15m http://jpwhiting.blogspot.com/feeds/posts/default/-/kde
-    define_name Jeremy Whiting (jpwhiting)
-    define_face hackergotchi/jpwhiting.jpg
-    define_facewidth 80
-
-feed 15m http://simon-listens.blogspot.com/rss.xml
-    define_name Peter Grasch
-    define_face hackergotchi/pgrasch.png
-    define_facewidth 80
-    define_faceheight 80
-
-feed 15m https://blogs.kde.org/blog/4267/feed
-    define_name Shawn Starr (spstarr)
-    define_face hackergotchi/spstarr.png
-    define_facewidth 59
-    define_faceheight 85
-
-feed 15m https://blogs.kde.org/blog/4326/feed
-    define_name Frederik Gladhorn (fregl)
-
-feed 45m https://blogs.fsfe.org/gladhorn/category/kde/feed/
-    define_name Frederik Gladhorn (fregl)
-    define_face hackergotchi/frederik_gladhorn.jpeg
-    define_facewidth 80
-    define_faceheight 80
-
-feed 15m http://psychobrain.blogspot.com/rss.xml
-    define_name Andreas Ramm (psychobrain)
-
-feed 15m https://randomguy3.wordpress.com/tag/kde/feed/?mrss=off
-    define_name Alex Merry
-    define_face hackergotchi/randomguy3.png
-    define_facewidth 80
-    define_faceheight 80
-
-feed 15m http://www.livejournal.com/users/pradeepto/data/rss
-    define_name Pradeepto Bhattacharya
-
-feed 15m http://blog.lydiapintscher.de/category/PlanetKDE/feed/
-    define_name Lydia Pintscher (Nightrose)
-    define_face hackergotchi/nightrose.png
-    define_facewidth 78
-    define_faceheight 76
-
-feed 15m http://feeds.feedburner.com/slashrosha/en/kde
-    define_name Roozbeh Shafiee
-    define_face hackergotchi/roozbeh.jpeg
-    define_facewidth 96
-    define_faceheight 96
-
-feed 15m http://elcuco2.blogspot.com/feeds/posts/default
-    define_name Diego Iastrubni
-
-feed 15m http://www.moiji-mobile.com/tag/kde/feed/
-    define_name Holger Freyther (zecke)
-
-feed 15m http://fboudra.free.fr/wordpress/wp-rss2.php?cat=6
-    define_name Fathi Boudra (fabo)
-    define_face hackergotchi/fabo.png
-    define_facewidth 60
-    define_faceheight 80
-
-feed 15m https://pusling.com/blog/?feed=rss2&cat=4
-    define_name Sune Vuorela (svuorela)
-    define_face hackergotchi/svuorela.png
-    define_facewidth 72
-    define_faceheight 100
-
-feed 15m https://zwabel.wordpress.com/feed/?mrss=off
-    define_name David Nolden
-
-feed 15m http://jkt.flaska.net/blog/tags/kde/kde.rss
-    define_name Jan Kundrát (jkt)
-
-feed 15m https://boom1992.wordpress.com/feed/?mrss=off
-    define_name Lukas Appelhans
-
-feed 15m https://yarpen.cz/rants/?feed=rss2
-    define_name Petr Vanek
-
-feed 15m https://dimsuz.wordpress.com/feed/?mrss=off
-    define_name Dmitry Suzdalev (dimsuz)
-
-feed 15m http://rbitanga.blogspot.com/rss.xml
-    define_name Ryan Bitanga
-
-feed 15m http://vladcodrea.blogspot.com/rss.xml
-    define_name Vlad Codrea
-
-feed 15m http://der-dakon.net/blog/kde.xml
-    define_name Rolf Eike Beer (Dakon)
-
-feed 15m http://carloslicea.blogspot.com/feeds/posts/default/-/planetkde
-    define_name Carlos Licea
-
-feed 15m http://saroengels.blogspot.com/feeds/posts/default
-    define_name Patrick Spendrin (SaroEngels)
-
-feed 15m http://feeds.feedburner.com/LamersCorner
-    define_name Bartosz Wadolowski
-
-feed 15m http://feeds.feedburner.com/nixternal-kde
-    define_name Richard Johnson (nixternal)
-    define_face hackergotchi/nixternal.png
-    define_facewidth 58
-    define_faceheight 80
-
-feed 15m https://blogs.kde.org/blog/2904/feed
-    define_name Sebastian Trueg
-
-feed 15m http://notmart.org/blog/tag/kde/feed/
-    define_name Marco Martin (notmart)
-    define_face hackergotchi/notmart.png
-    define_facewidth 80
-    define_faceheight 80
-
-feed 15m https://grundleborg.wordpress.com/feed/?mrss=off&category_name=kde
-    define_name George Goldberg (grundleborg)
-
-feed 15m http://ppenz.blogspot.com/feeds/posts/default/-/KDE
-    define_name Peter Penz
-    define_face hackergotchi/ppenz.png
-    define_facewidth 64
-    define_faceheight 64
-
-feed 15m http://paul-pach.blogspot.com/rss.xml
-    define_name Paul Pacheco (paulpach)
-
-feed 15m https://blauzahl.livejournal.com/data/rss?tag=kde
-    define_name A. L. Spehr (blauzahl)
-    define_face hackergotchi/zahl.png
-    define_facewidth 58
-    define_faceheight 80
-
-#feed 15m http://www.gnuton.org/blog/category/myprojects/kde-dev/feed/atom/
-#    define_name Antonio Aloisio
-
-feed 15m https://arindamghosh.wordpress.com/category/kde/feed/?mrss=off&category_name=kde
-    define_name Arindam Ghosh
-
-feed 15m https://pindablog.wordpress.com/feed/?mrss=off
-    define_name Rob Scheepmaker (pinda)
-
-feed 15m https://edulix.wordpress.com/category/kde/feed/?mrss=off&category_name=kde
-    define_name Eduardo Robles Elvira (Edulix)
-
-feed 15m http://untangled.biz/category/kde/feed/
-    define_name Alexandra Leisse (troubalex)
-
-feed 15m https://vtokarev.wordpress.com/feed/?mrss=off
-    define_name Vyacheslav Tokarev (vtokarev)
-
-feed 15m https://blogs.kde.org/blog/2892/feed
-    define_name Marijn Kruisselbrink
-
-feed 15m https://metelliuscode.wordpress.com/feed/?mrss=off
-    define_name Harald Hvaal (metellius)
-
-feed 15m http://alediaferia.blogspot.com/feeds/posts/default
-    define_name Alessandro Diaferia (alediaferia)
-
-feed 15m http://ssj-gz.blogspot.com/feeds/posts/default
-    define_name Simon St James (SSJ_GZ)
-
-feed 15m http://kopophex.blogspot.com/feeds/posts/default
-    define_name Daniel Jones
-
-feed 15m http://teom.org/feed/?mrss=off&category_name=kde
-    define_name Teo Mrnjavac (teo-)
-    define_face hackergotchi/teo.png
-    define_facewidth 80
-    define_faceheight 80
-
-feed 15m http://awainzin-foss.blogspot.com/feeds/posts/default/-/KDE?alt=rss
-    define_name Alejandro Wainzinger (xevix)
-
-feed 15m http://www.elpauer.org/category/kde/feed/
-    define_name Pau Garcia i Quiles (pgquiles)
-    define_face hackergotchi/pgquiles.png
-    define_facewidth 65
-    define_faceheight 82
-
-feed 15m http://fmontesi.blogspot.com/feeds/posts/default/-/kde
-    define_name Fabrizio Montesi (fmontesi)
-    define_face hackergotchi/fmontesi.png
-    define_facewidth 64
-    define_faceheight 80
-
-feed 15m https://karlitschek.de/category/kde/feed/
-    define_name Frank Karlitschek (karli)
-    define_face hackergotchi/karli.png
-    define_facewidth 80
-    define_faceheight 80
-
-feed 15m https://majewsky.wordpress.com/feed/?mrss=off
-    define_name Stefan Majewsky (majewsky)
-    define_face hackergotchi/majewsky.png
-    define_facewidth 59
-    define_faceheight 80
-
-feed 15m http://michael-jansen.name/feeds/all.atom.xml
-    define_name Michael Jansen
-
-# Here's my old one. Keeping it just in case.
-feed 15m https://drfav.wordpress.com/tag/kde/feed/?mrss=off&tag=kde
-    define_name Dario Freddi (drf__)
-    define_face hackergotchi/drf.png
-    define_facewidth 80
-    define_faceheight 76
-
-feed 15m http://blog.martin-graesslin.com/blog/kategorien/kde/planetkde/feed/
-    define_name Martin Gräßlin
-
-feed 15m https://blogs.kde.org/blog/6425/feed
-    define_name Germain Garand
-
-feed 15m http://shaforostoff.blogspot.com/atom.xml
-    define_name Nick Shaforostoff (shaforostoff)
-    define_face hackergotchi/shaforostoff.png
-    define_facewidth 65
-    define_faceheight 80
-
-feed 15m http://lydgate.org/blogs/tag/kde/feed/
-    define_name Anne Wilson (annew)
-    define_face hackergotchi/annew.png
-    define_facewidth 79
-    define_faceheight 79
-
-feed 15m https://kstars.wordpress.com/feed/?mrss=off&category_name=gnulinuxfoss%2Fkde%2Fplanetkde-kde-gnulinuxfoss
-    define_name Akarsh Simha (kstar)
-    define_face hackergotchi/asimha.png
-    define_facewidth 80
-    define_faceheight 80
-
-feed 15m https://tejasd.livejournal.com/data/rss?tag=kde
-    define_name Tejas Dinkar (gja)
-    define_face hackergotchi/dinkar.png
-    define_facewidth 63
-    define_faceheight 80
-
-feed 15m https://xvello.wordpress.com/tag/kde/feed/?mrss=off&tag=kde
-    define_name Xavier Vello (xvello)
-
-feed 15m https://saschpe.wordpress.com/category/opensource/kde/feed/?mrss=off&category_name=opensource%2Fkde
-    define_name Sascha Peilicke (saschpe)
-    define_face hackergotchi/saschpe.png
-    define_facewidth 67
-    define_faceheight 80
-
-feed 15m http://www.eivanov.com/feeds/posts/default/-/planetkde
-    define_name Evgeniy Ivanov (powerfox/pfx)
-
-feed 15m http://shield008.blogspot.com/feeds/posts/default/-/KDE
-    define_name John-Paul Stanford (jp)
-
-feed 15m http://cazou.blogspot.com/feeds/posts/default/-/kde
-    define_name Detlev Casanova (Cazou)
-
-feed 15m http://borntobeopen.blogspot.com/feeds/posts/default/-/KDE
-    define_name Jaroslav Řezník (jreznik)
-    define_face hackergotchi/rezza.png
-    define_facewidth 60
-    define_faceheight 80
-
-feed 15m https://dragotin.wordpress.com/feed/?mrss=off
-    define_name Klaas Freitag (dragotin)
-    define_face hackergotchi/freitag75.png
-    define_facewidth 75
-    define_faceheight 75
-
-feed 15m https://amarok.kde.org/en/blog/7/feed
-    define_name Daniel Meltzer (hydrogen)
-
-feed 15m http://rdieter.blogspot.com/feeds/posts/default/-/kde
-    define_name Rex Dieter (rdieter)
-    define_face hackergotchi/rdieter.png
-    define_facewidth 80
-    define_faceheight 80
-
-feed 15m http://lukast.mediablog.sk/log/?feed=rss2
-    define_name Lukas Tvrdy (lukast)
-
-feed 15m https://slangkamp.wordpress.com/feed/?mrss=off
-    define_name Sven Langkamp (slangkamp)
-
-feed 15m https://www.dennogumi.org/category/kde/feed/atom.xml
-    define_name Luca Beltrame (einar77)
-
-feed 15m http://blog.neverendingo.de/category/kde/feed/
-    define_name Ingo Malchow (neverendingo)
-
-feed 15m https://adjamblog.wordpress.com/category/international/feed/?mrss=off&category_name=international
-    define_name Andrea Diamantini (adjam)
-    define_face hackergotchi/adjam.png
-    define_facewidth 46
-    define_faceheight 48
-
-feed 15m http://amroth.coldshock.net/kmess/blog/feed/
-    define_name Valerio Pilo (Amroth)
-    define_face hackergotchi/valerio-pilo.jpg
-    define_facewidth 67
-    define_faceheight 80
-
-feed 15m https://kdepepo.wordpress.com/category/kde/feed/?mrss=off&category_name=kde
-    define_name Christoph Feck (kdepepo)
-    define_face hackergotchi/cfeck.png
-    define_facewidth 80
-    define_faceheight 80
-
-feed 15m https://trueg.wordpress.com/feed/?mrss=off
-    define_name Sebastian Trueg (trueg)
-    define_face hackergotchi/trueg.jpg
-    define_facewidth 80
-    define_faceheight 80
-
-feed 15m http://qiacat.blogspot.com/feeds/posts/default/-/planetKDE
-    define_name Wang Hoi (wkai)
-    define_face hackergotchi/wkai.jpeg
-    define_facewidth 80
-    define_faceheight 80
-
-feed 15m http://joselb.blogspot.com/rss.xml
-    define_name Johannes Bergmeier (joselb)
-    define_face hackergotchi/joselb.png
-    define_facewidth 80
-    define_faceheight 80
-
-feed 15m http://mauroiazzi.blogspot.com/feeds/posts/default/-/KDE
-    define_name Mauro Iazzi (iazzi)
-
-feed 15m http://zrchrn.blogspot.com/feeds/posts/default
-    define_name Ahmed Ghonim
-    define_face hackergotchi/ahmed-ghonim.png
-    define_facewidth 80
-    define_faceheight 76
-
-feed 15m https://jontheechidna.wordpress.com/feed/?mrss=off&category_name=kde
-    define_name Jonathan Thomas (JontheEchidna)
-    define_face hackergotchi/echidnaman.png
-    define_facewidth 80
-    define_faceheight 80
-
-feed 15m https://steveire.wordpress.com/feed/?mrss=off
-    define_name Stephen Kelly (steveire)
-
-feed 15m http://ungethym.blogspot.com/feeds/posts/default/-/planetkde
-    define_name Thomas Thym (ungethym)
-    define_face hackergotchi/thomas-thum.jpg
-    define_facewidth 80
-    define_faceheight 80
-
-feed 15m https://sandroandrade.org/tag/planet-kde/rss/
-    define_name Sandro Andrade (sandroandrade)
-    define_face hackergotchi/sandroandrade.png
-    define_facewidth 80 define_faceheight 80
-
-feed 15m https://mahfuz062.wordpress.com/feed/?mrss=off
-    define_name Mahfuz062
-    define_face hackergotchi/mahfuz.png
-    define_facewidth 80 define_faceheight 80
-
-feed 15m https://gkiagia.wordpress.com/category/kde/feed/?mrss=off&category_name=kde
-    define_name George Kiagiadakis (gkiagia)
-
-feed 15m https://blogs.kde.org/blog/6843/feed
-    define_name Bastian Holst (bholst)
-
-feed 15m https://praksh.wordpress.com/category/kde/gsoc/feed/?mrss=off&category_name=kde%2Fgsoc
-    define_name Prakash Mohan (praksh)
-    define_face hackergotchi/prakash.png
-    define_facewidth 70
-    define_faceheight 80
-
-feed 15m http://algebraicallyclosed.blogspot.com/feeds/posts/default
-    define_name Jeremias Epperlein
-
-feed 15m http://rubots.blogspot.com/atom.xml
-    define_name Jordi Polo (jordl)
-    define_face hackergotchi/jordipolo.png
-    define_facewidth 60
-    define_faceheight 80
-
-feed 15m https://martinsandsmark.wordpress.com/feed/?mrss=off
-    define_name Martin Sandsmark (sandsmark)
-    define_face hackergotchi/sandsmark.png
-    define_facewidth 63
-    define_faceheight 80
-
-feed 15m https://thomasmcguire.wordpress.com/feed/?mrss=off
-    define_name Thomas McGuire
-
-feed 15m http://dimula73.blogspot.com/feeds/posts/default/-/KDE
-    define_name Dmitry Kazakov (dmitryK)
-
-feed 15m http://zekecoma.blogspot.com/feeds/posts/default/-/kde
-    define_name Keith Rusler (comawhite)
-
-feed 15m http://realate.blogspot.com/feeds/posts/default
-    define_name Andrew Manson ( mansona aka real_ate )
-    define_face hackergotchi/mansona.png
-    define_facewidth 80
-    define_faceheight 83
-
-feed 15m https://mat69.wordpress.com/feed/?mrss=off
-    define_name Matthias Fuchs (mat69)
-
-feed 15m https://www.arnorehn.de/blog/feed/
-    define_name Arno Rehn (pumphaus)
-
-feed 15m https://blogs.kde.org/blog/7020/feed
-    define_name Ramon Zarazua (_killerfox_)
-
-feed 15m https://blog.hanschen.org/category/planetkde/feed/?mrss=off&category_name=planetkde
-    define_name Hans Chen (Mogger)
-
-feed 15m https://ascending.wordpress.com/feed/?mrss=off&tag=planetkde
-    define_name Constantin Berzan (exit)
-
-feed 15m http://blog.cryptomilk.org/category/kde/feed/
-    define_name Andreas Schneider (gladiac)
-    define_face hackergotchi/anschneider.png
-    define_facewidth 80
-    define_faceheight 80
-
-feed 15m https://momeny.wordpress.com/category/planetkde/feed/?mrss=off&category_name=planetkde
-    define_name Mehrdad Momeny (mtux)
-    define_face hackergotchi/momeny.png
-    define_facewidth 68
-    define_faceheight 80
-
-feed 15m https://blogs.kde.org/blog/10441/feed
-    define_name Mario Fux (unormal)
-
-feed 15m https://hobbyblobby.wordpress.com/category/planet/feed/?mrss=off&category_name=planet
-    define_name Felix Lemke (HobbyBlobby)
-
-feed 15m http://zajec.net/blog/atom/kde
-    define_name Rafał Miłecki (Zajec)
-    define_face hackergotchi/zajec.png
-    define_facewidth 77
-    define_faceheight 80
-
-feed 15m https://blogs.kde.org/blog/7193/feed
-    define_name Tony Murray (murrant)
-    define_face hackergotchi/murrant.png
-    define_facewidth 80
-    define_faceheight 80
-
-feed 15m https://savago.wordpress.com/feed/?mrss=off
-    define_name Adenilson Cavalcanti (Savago)
-    define_face hackergotchi/adenilson-cavalcanti.png
-    define_facewidth 80
-    define_faceheight 80
-
-feed 15m http://ontheoutsidedesign.blogspot.com/feeds/posts/default/-/KDE
-    define_name Andrew Lake
-    define_face hackergotchi/jamboarder.png
-    define_facewidth 80
-    define_faceheight 80
-
-feed 15m http://blog.aliensoft.net/feeds/posts/default/-/planetkde
-    define_name Alan Alvarez (clsk)
-    define_face hackergotchi/alan-alvarez.png
-    define_facewidth 75
-    define_faceheight 75
-
-feed 15m https://dantti.wordpress.com/feed/?mrss=off
-    define_name Daniel Nicoletti (dantti)
-    define_face hackergotchi/dantti.png
-    define_facewidth 96
-    define_faceheight 96
-
-feed 15m https://www.asinen.org/feed/
-    define_name Stuart Jarvis
-    define_face hackergotchi/stuart-jarvis.png
-    define_facewidth 67
-    define_faceheight 80
-
-feed 15m https://arieder.wordpress.com/feed/?mrss=off
-    define_name Alexander Rieder (arieder)
-
-feed 15m http://monkeyiq.blogspot.com/feeds/posts/default/-/kde
-    define_name Ben Martin (monkeyiq)
-
-feed 15m https://vonami.wordpress.com/feed/?mrss=off
-    define_name Dmitry Ivanov (vonami)
-
-feed 15m https://blogs.kde.org/blog/7305/feed
-    define_name Raphael Kubo da Costa (rakuco)
-    define_face hackergotchi/rakuco.png
-    define_facewidth 80
-    define_faceheight 80
-
-feed 15m http://feeds.feedburner.com/ThisWeekInKrita
-    define_name Boudewijn Rempt's Krita blog
-
-feed 15m http://roideuniverse.blogspot.com/feeds/posts/default/-/kde
-    define_name Kaushik Saurabh (roide)
-
-feed 15m https://michalm.wordpress.com/tag/kde/feed/?mrss=off&tag=kde
-    define_name Michał Małek (mmalek)
-
-feed 15m https://darioandreskde.wordpress.com/feed/?mrss=off
-    define_name Dario Andres Rodriguez (Dario_Andres)
-    define_face hackergotchi/darioandresr.png
-    define_facewidth 80
-    define_faceheight 80
-
-feed 15m http://midi-clorianos.blogspot.com/feeds/posts/default/-/KDE
-    define_name Pedro Lopez-Cabanillas
-    define_face hackergotchi/pedrol.png
-    define_facewidth 57
-    define_faceheight 80
-
-feed 15m http://c2143.blogspot.com/feeds/posts/default/-/KDE
-    define_name Romain Pokrzywka (kromain)
-    define_face hackergotchi/kromain.jpg
-    define_facewidth 70
-    define_faceheight 80
-
-feed 15m http://feeds.feedburner.com/HadesBlagPlanetKDE
-    define_name Edward Toroshchin (hades)
-    define_face hackergotchi/hades.png
-    define_facewidth 80
-    define_faceheight 80
-
-feed 15m http://johnflux.blogspot.com/atom.xml
-    define_name John Tapsell (JohnFlux)
-    define_face hackergotchi/johnflux.png
-    define_facewidth 63
-    define_faceheight 80
-
-feed 15m https://kunalghosh.wordpress.com/tag/kde/feed/
-    define_name kunal ghosh (kunalghosh)
-    define_face hackergotchi/kunalghosh.png
-    define_facewidth 62
-    define_faceheight 80
-
-feed 15m http://owncloudtest.blogspot.com/feeds/posts/default
-    define_name Aaron Reichman (areichman)
-
-feed 15m https://liveblue.wordpress.com/category/vitor-planetkde/feed/?mrss=off&category_name=vitor-planetkde
-    define_name Vitor Boschi (Klanticus)
-    define_face hackergotchi/vitor.png
-    define_facewidth 80
-    define_faceheight 77
-
-feed 15m http://linuxgrandma.blogspot.com/feeds/posts/default/-/KDE
-    define_name Valorie Zimmerman (valorie)
-    define_face hackergotchi/valorie.png
-    define_facewidth 65
-    define_faceheight 100
-
-feed 15m https://btux1984.wordpress.com/category/kde/feed/
-    define_name Björn Ruberg (ruberg)
-    define_face hackergotchi/ruberg.png
-    define_facewidth 70
-    define_faceheight 80
-
-feed 15m https://cibermundi.wordpress.com/category/planetkde-araceletorres/feed/
-    define_name Aracele Torres (araceletorres)
-    define_face hackergotchi/araceletorres.jpg
-    define_facewidth 75
-    define_faceheight 80
-
-feed 15m http://pedepinico.blogspot.com/feeds/posts/default/-/kde
-    define_name Francisco Fernandes (chicao)
-    define_face hackergotchi/chicao.png
-    define_facewidth 80
-    define_faceheight 80
-
-feed 15m https://kders.wordpress.com/category/planetkde-wagner/feed/?mrss=off&category_name=planetkde-wagner
-    define_name Wagner Reck (wiglot)
-    define_face hackergotchi/wagner.png
-    define_facewidth 80
-    define_faceheight 80
-
-feed 15m https://kders.wordpress.com/category/planetkde-camila/feed/?mrss=off&category_name=planetkde-camila
-    define_name Camila Ayres (camilasan)
-    define_face hackergotchi/camilaayres.png
-    define_facewidth 80
-    define_faceheight 80
-
-feed 15m http://blog.filipesaraiva.info/?tag=planetkde-english&feed=rss2
-    define_name Filipe Saraiva (filipesaraiva)
-    define_face hackergotchi/filipe_cabecinha.png
-    define_facewidth 80
-    define_faceheight 80
-
-feed 30m http://blog.filipesaraiva.info/?tag=planetkde-portugues&feed=rss2
-    define_name Filipe Saraiva (filipesaraiva)
-    define_face hackergotchi/filipe_cabecinha.png
-    define_facewidth 80
-    define_faceheight 80
-    define_feedclass portuguese
-
-feed 15m https://scarpino.dev/feed.xml
-    define_name Andrea Scarpino (ilpianista)
-
-feed 15m https://ronnyml.wordpress.com/category/planet-kde/feed/?mrss=off&category_name=planet-kde
-    define_name Ronny Yabar (ronnyml)
-    define_face hackergotchi/ronnyml.png
-    define_facewidth 80
-    define_faceheight 80
-
-feed 15m https://saidinesh5.wordpress.com/tag/kde-planet/feed/?mrss=off&tag=kde-planet
-    define_name Dinesh (saidinesh5)
-    define_face hackergotchi/saidinesh5.png
-    define_facewidth 79
-    define_faceheight 72
-
-feed 15m https://blog.shantanu.io/tag/kde/feed/
-    define_name Shantanu Tushar (shantanu)
-    define_face hackergotchi/shantanu.png
-    define_facewidth 64
-    define_faceheight 80
-
-feed 15m https://blogs.kde.org/blog/7735/feed
-    define_name Harshit Jain (hjain)
-    define_face hackergotchi/hjain.jpg
-    define_facewidth 80
-    define_faceheight 79
-
-feed 15m http://pauloromulo.blogspot.com/feeds/posts/default?alt=rss
-    define_name Paulo Rômulo (promulo)
-    define_face hackergotchi/promulo.png
-    define_facewidth 80
-    define_faceheight 80
-
-feed 15m http://siddharthgsoc.blogspot.com/feeds/posts/default?alt=rss
-    define_name Siddharth Srivastava (akssps011)
-    define_face hackergotchi/akssps011.png
-    define_facewidth 80
-    define_faceheight 80
-
-feed 15m http://lamarque-lvs.blogspot.com/feeds/posts/default/-/kde
-    define_name Lamarque Souza (lamarque or lvsouza)
-    define_face hackergotchi/lamarque.png
-    define_facewidth 74
-    define_faceheight 80
-
-feed 15m http://acetonik.blogspot.com/feeds/posts/default/-/KDE
-    define_name Peter Schiffer (aceton)
-
-feed 15m http://celarek.at/category/kde/feed/
-    define_name Adam Celarek (adamce)
-    define_face hackergotchi/adamc.jpg
-    define_facewidth 80
-    define_faceheight 80
-
-feed 15m https://tittiatcoke.wordpress.com/category/kde-2/feed/?mrss=off&category_name=kde-2
-    define_name Raymond Wooninck (tittiatcoke)
-    define_face hackergotchi/tittiatcoke.jpg
-    define_facewidth 80
-    define_faceheight 80
-
-feed 15m https://kdeatopensuse.wordpress.com/feed/?mrss=off&category_name=kde
-    define_name Sven Burmeister (rabauke)
-
-feed 15m http://feeds.feedburner.com/andreas-demmer/kde
-    define_name Andreas Demmer (ademmer)
-    define_face hackergotchi/ademmer.png
-    define_facewidth 80
-    define_faceheight 80
-
-feed 15m https://polentino911.wordpress.com/tag/planetkde/feed/?mrss=off&tag=planetkde
-    define_name Diego Casella ([Po]lentino)
-    define_face hackergotchi/polentino.png
-    define_facewidth 80
-    define_faceheight 80
-
-feed 15m http://hugo-kde.blogspot.com/rss.xml
-    define_name Hugo Pereira Da Costa
-    define_face hackergotchi/hugo.png
-    define_facewidth 80
-    define_faceheight 80
-
-
-feed 15m https://siddharthkde.wordpress.com/feed/?mrss=off
-    define_name Siddharth Sharma (siddvicious)
-    define_face hackergotchi/siddharth.jpg
-    define_facewidth 57
-    define_faceheight 73
-
-feed 15m http://mageia.nicolaslecureuil.fr/category/kde-en/feed/
-    define_name Nicolas Lécureuil (neoclust)
-
-feed 15m https://blogs.kde.org/blog/7783/feed
-    define_name Marc Pegon (mpeg)
-
-feed 15m https://morice.ipsquad.net/blog/?cat=3&feed=rss2
-    define_name Jean-Nicolas Artaud (morice-net)
-    define_face hackergotchi/morice.png
-    define_facewidth 80
-    define_faceheight 80
-
-feed 15m https://bergie.iki.fi/blog/category/kde/rss.xml
-    define_name Henri Bergius (bergie)
-    define_face hackergotchi/bergie.png
-    define_facewidth 101
-    define_faceheight 103
-
-feed 15m https://blogs.kde.org/blog/7855/feed
-    define_name Adam Rakowski (foo-script/efes)
-    define_face hackergotchi/adamrakowski.png
-    define_facewidth 79
-    define_faceheight 79
-
-feed 15m https://marcmutz.wordpress.com/tag/planetkde/feed/?mrss=off&tag=planetkde
-    define_name Marc Mutz
-    define_face hackergotchi/effqt-bird.png
-    define_facewidth 80
-    define_faceheight 80
-
-feed 15m http://not403.blogspot.com/feeds/posts/default/-/kde
-    define_name Juan Luis Baptiste (Maeztro)
-    define_face hackergotchi/jbaptiste.png
-    define_facewidth 80
-    define_faceheight 80
-
-feed 15m http://dev-peterix.blogspot.com/feeds/posts/default/-/kde
-    define_name Petr Mrázek (petrm)
-    define_face hackergotchi/petrm.jpg
-    define_facewidth 80
-    define_faceheight 80
-
-feed 15m https://dot.kde.org/rss.xml
-    define_name KDE Dot News
-    define_feedclass dot
-    define_face hackergotchi/dot-news.png
-    define_facewidth 80
-    define_faceheight 80
-
-feed 15m https://kde.org/announcements/releases/index.xml
-    define_name KDE Release Service
-    define_feedclass dot
-    define_face hackergotchi/dot-news.png
-    define_facewidth 80
-    define_faceheight 80
-
-feed 15m https://krita.org/en/feed/
-    define_name Krita News
-    define_feedclass news
-    define_face hackergotchi/krita.png
-    define_facewidth 80
-    define_faceheight 80
-
-feed 15m https://toscalix.com/feed/
-    define_name Agustín Benito Bethencourt (toscalix)
-
-feed 15m https://www.kdeblog.com/feed
-    define_name KDE Blog - Baltasar Ortega
-    define_feedclass spanish
-    define_face hackergotchi/kdeblog.png
-    define_facewidth 80
-    define_faceheight 19
-
-feed 15m http://midi-clorianos.blogspot.com/feeds/posts/default/-/KDE-ES
-    define_name Pedro López-Cabanillas
-    define_feedclass spanish
-
-feed 15m https://arklad.wordpress.com/category/informatica/software-libre/kde/feed/
-    define_name Cristina Yenyxe González García
-    define_feedclass spanish
-
-feed 15m http://tsdgeos-es.blogspot.com/atom.xml
-    define_name Albert Astals Cid (TSDgeos)
-    define_face hackergotchi/TSDgeos.png
-    define_facewidth 80
-    define_faceheight 80
-    define_feedclass spanish
-
-feed 15m https://kubuntu.org/news/feed
-    define_name Kubuntu News
-    define_feedclass news
-    define_face hackergotchi/kubuntu-logo.png
-    define_facewidth 100
-    define_faceheight 20
-
-feed 15m http://freoffice.blogspot.com/feeds/posts/default
-    define_name Freoffice: KOffice based Open Mobile Office Suite
-    define_feedclass news
-
-feed 15m http://thehayro.blogspot.com/feeds/posts/default/-/kde
-    define_name Hayri Bakici (thehayro)
-
-feed 15m https://mbatle.wordpress.com/category/kde/feed/?mrss=off&category_name=kde
-    define_name Mateu Batle (mbatle)
-    define_face hackergotchi/mbatle.jpg
-    define_facewidth 80
-    define_faceheight 80
-
-feed 15m http://codersgrumble.blogspot.com/feeds/posts/default/-/kde
-    define_name Andriy Rysin (rysin)
-    define_face hackergotchi/rysin.png
-    define_facewidth 74
-    define_faceheight 74
-
-feed 15m https://shentey.wordpress.com/category/kde/feed/?mrss=off&category_name=kde
-    define_name Bernhard Beschow (shentey)
-
-feed 15m https://sciencekde.wordpress.com/tag/kde/feed/?mrss=off&tag=kde
-    define_name Matteo Agostinelli (agostinelli)
-
-feed 15m http://k-de-leag.blogspot.com/feeds/posts/default?alt=rss
-    define_name Gaël de Chalendar (kleag)
-    define_face hackergotchi/kleag.png
-    define_facewidth 80
-    define_faceheight 80
-
-feed 15m http://blog.davidedmundson.co.uk/blog/category/kde/feed/
-    define_name David Edmundson (d_ed)
-    define_face hackergotchi/d_ed.png
-    define_facewidth 64
-    define_faceheight 80
-
-feed 15m http://www.javierllorente.com/category/english/feed/
-    define_name Javier Llorente
-
-feed 15m https://mrybczynska.wordpress.com/category/english/feed/?mrss=off&category_name=english
-    define_name Marta Rybczyńska
-    define_feedclass polish
-
-feed 15m http://bcooksley.blogspot.com/feeds/posts/default
-    define_name Ben Cooksley (bcooksley)
-
-feed 15m https://kders.wordpress.com/category/planetkde-pt-wagner/feed/
-    define_name Wagner Reck (wiglot)
-    define_face hackergotchi/wagner.png
-    define_facewidth 80
-    define_faceheight 80
-    define_feedclass portuguese
-
-feed 15m https://www.calligra.org/blogs/thorstenzachmann/feed/
-    define_name Thorsten Zachmann
-
-feed 15m https://ksmanis.wordpress.com/feed/?mrss=off&category_name=planet-kde
-    define_name Konstantinos Smanis (ksmanis)
-
-feed 15m https://cgbdx.wordpress.com/feed/?mrss=off
-    define_name Christophe Giboudeaux (krop)
-
-feed 15m https://jonanp.wordpress.com/feed/
-    define_name Jon Ander Peñalba (jonan)
-    define_face hackergotchi/jonan.png
-    define_facewidth 80
-    define_faceheight 80
-
-feed 15m https://sri13atkritadevel.wordpress.com/feed/?mrss=off
-    define_name Srikanth Tiyyagura
-
-feed 15m https://sinny.io/tag/kde/feed/
-    define_name Sinny Kumari (ksinny)
-    define_face hackergotchi/sinny.png
-    define_facewidth 80
-    define_faceheight 80
-
-feed 15m http://feeds.feedburner.com/kdeLucasRefuge
-    define_name Lucas Lira Gomes (MaskMaster)
-    define_face hackergotchi/lucasliragomes.png
-    define_facewidth 80
-    define_faceheight 80
-
-feed 15m https://pranavrc.wordpress.com/category/kde/feed/?mrss=off&category_name=kde
-    define_name Pranav Ravichandran (Pranav_rcmas)
-
-feed 15m http://gnumdk.blogspot.com/atom.xml
-    define_name Cédric Bellegarde (gnumdk)
-    define_face hackergotchi/gnumdk.png
-    define_facewidth 80
-    define_faceheight 80
-
-feed 15m https://rkulaga.wordpress.com/feed/?mrss=off&category_name=PlanetKDE
-    define_name Rafał Kułaga (rkulaga)
-    define_face hackergotchi/rkulaga.png
-    define_facewidth 80
-    define_faceheight 80
-
-feed 15m http://rockfordsone.blogspot.com/feeds/posts/default
-    define_name Radoslaw Wicik (rockford_)
-
-feed 15m https://thebengaliheart.wordpress.com/feed/?mrss=off&tag=KDE
-    define_name Tirtha Chatterjee (wyuka)
-    define_face hackergotchi/wyuka.png
-    define_facewidth 79
-    define_faceheight 80
-
-feed 15m http://lukaslt.blogspot.com/feeds/posts/default
-    define_name Lukas Dzikaras (LukasLt2)
-
-feed 15m https://blogs.kde.org/blog/8251/feed
-    define_name Sergio Martins (sergio)
-    define_face hackergotchi/sergio.png
-    define_facewidth 80
-    define_faceheight 80
-
-feed 15m http://quintasan.blogspot.com/feeds/posts/default/-/kde-planet
-    define_name Michał Zając (Quintasan)
-
-feed 15m https://cmollekopf.wordpress.com/category/kde/feed/?mrss=off&category_name=kde
-    define_name Christian Mollekopf (cmollekopf)
-
-feed 15m http://codecereal.blogspot.com/feeds/posts/default/-/kde
-    define_name Daker (dakerfp)
-
-feed 15m http://stefan.derkits.at/blog/category/opensource/feed/
-    define_name Stefan Derkits (HorusHorrendus)
-    define_face hackergotchi/horrendus.jpg
-    define_facewidth 80
-    define_faceheight 80
-
-feed 15m https://nwoki.wordpress.com/feed/?category_name=kde
-    define_name Francesco Nwokeka (nwoki)
-    define_face hackergotchi/nwoki.png
-    define_facewidth 80
-    define_faceheight 80
-
-feed 15m http://paulm-byte.blogspot.com/feeds/posts/default
-    define_name Paul Mendez (paul_m)
-
-feed 15m https://cordlandwehr.wordpress.com/feed/?mrss=off&tag=kde
-    define_name Andreas Cord-Landwehr (CoLa)
-
-feed 15m https://samxan.wordpress.com/tag/kde/feed/?mrss=off&tag=kde
-    define_name Samikshan Bairagya (samxan)
-
-feed 15m https://kdenlive.org/en/category/news/feed/
-    define_name Kdenlive
-    define_face hackergotchi/kdenlive.png
-    define_facewidth 100
-    define_faceheight 75
-
-feed 15m https://laxstrom.name/blag/category/kde/feed/
-    define_name Niklas Laxström (Nikerabbit)
-
-feed 15m http://lpapp.blogspot.com/feeds/posts/default/-/KDE
-    define_name Laszlo Papp (lpapp)
-    define_face hackergotchi/laszlo_papp-80x80.png
-    define_facewidth 80
-    define_faceheight 80
-
-feed 15m https://who828.wordpress.com/category/planet-kde/feed/?mrss=off
-    define_name Smit Shah
-
-feed 15m https://clauschr.wordpress.com/feed/?mrss=off
-    define_name Claus Christensen (Claus_chr)
-    define_face hackergotchi/clauschr.png
-    define_facewidth 80
-    define_faceheight 78
-
-feed 15m https://kyofel.wordpress.com/category/KDE/feed/?mrss=off
-    define_name Philip Muškovac (yofel)
-
-feed 15m https://www.dvratil.cz/tag/kde/feed/
-    define_name Daniel Vrátil (dvratil)
-    define_face hackergotchi/dvratil.png
-    define_facewidth 80
-    define_faceheight 80
-
-feed 15m https://kshadeslayer.wordpress.com/category/KDE/feed/?mrss=off
-    define_name Rohan Garg (shadeslayer)
-    define_face hackergotchi/rohan.png
-    define_facewidth 80
-    define_faceheight 84
-
-feed 15m http://blog.svenbrauch.de/tag/planetkde/feed/
-    define_name Sven Brauch
-    define_face hackergotchi/scummos.png
-    define_facewidth 80
-    define_faceheight 78
-
-feed 15m http://swairshah.blogspot.com/feeds/posts/default
-    define_name Swair Shah (swair)
-
-feed 15m https://fxrh.wordpress.com/category/kdeplanet/feed/?mrss=off
-    define_name Felix Rohrbach (fxrh)
-
-feed 15m http://yuvrajtomar.blogspot.com/feeds/posts/default
-    define_name Yuvraj Tomar (yuvrajtomar)
-    define_face hackergotchi/yuvraj-tomar.jpg
-    define_facewidth 80
-    define_faceheight 90
-
-feed 15m https://contourproject.wordpress.com/feed/?mrss=off
-    define_name Fania Jöck (fjoe)
-    define_face hackergotchi/fania_jock.jpg
-    define_facewidth 80
-    define_faceheight 80
-
-feed 15m https://kmix5.wordpress.com/feed/?mrss=off
-    define_name KMix - the KDE Multimedia Mixer
-    define_face hackergotchi/kmix.png
-    define_facewidth 64
-    define_faceheight 64
-    define_feedclass news
-
-feed 15m https://blogs.kde.org/blog/8457/feed/
-    define_name Torgny Nyblom (tnyblom)
-
-feed 15m https://ljaskiewicz.wordpress.com/feed/?mrss=0ff&category_name=planetkde
-    define_name Łukasz Jaśkiewicz (ljaskiewicz)
-
-feed 15m https://djarvie.wordpress.com/category/kde,planetkde/feed/?mrss=off
-    define_name David Jarvie (djarvie)
-
-feed 15m http://sebastian-doerner.de/?cat=4&feed=rss2&mrss=off
-    define_name Sebastian Dörner
-
-feed 15m https://blog.tenstral.net/category/planet/planetkde/feed
-    define_name Matthias Klumpp (ximion)
-    define_face hackergotchi/matthias_ximion.png
-    define_facewidth 80
-    define_faceheight 75
-
-feed 15m http://letsfollowthewhiterabbit.blogspot.com/feeds/posts/default
-    define_name Luca Tringali (lucatringali)
-    define_face hackergotchi/lucatringali.png
-    define_facewidth 80
-    define_faceheight 80
-
-feed 15m http://dilfridge.blogspot.com/feeds/posts/default/-/kde
-    define_face hackergotchi/andreas-huettel.png
-    define_facewidth 80
-    define_faceheight 80
-    define_name Andreas K. Hüttel (dilfridge)
-
-feed 15m http://fpuelz-kde.blogspot.com/feeds/posts/default
-    define_name Friedrich Pülz (fkpulz)
-    define_face hackergotchi/fkpulz.png
-    define_facewidth 64
-    define_faceheight 80
-
-feed 15m https://diggy128.wordpress.com/tag/kde/feed/
-    define_name Dimitrios T. Tanis (diggy)
-    define_face hackergotchi/dimitrios-tanis.jpg
-    define_facewidth 80
-    define_faceheight 80
-
-feed 24h http://blog.dmaggot.org/tag/kde/feed/
-    define_name David E. Narváez (dMaggot)
-    define_face hackergotchi/dMaggot.png
-    define_facewidth 80
-    define_faceheight 80
-
-feed 15m http://philipp.knechtges.com/?cat=3&feed=rss2
-    define_name Philipp Knechtges (d1saster)
-
-feed 15m http://deepsky28.blogspot.com/feeds/posts/default?alt=rss
-    define_name Florentina Musat (chrome)
-
-feed 15m https://konstantinidis.wordpress.com/category/kde/feed/
-    define_name Giannis Konstantinidis (giannisk)
-    define_face hackergotchi/giannis-konstantinidis.jpeg
-    define_facewidth 76
-    define_faceheight 80
-
-feed 15m https://terietor.wordpress.com/tag/planetkde/feed/
-    define_name Giorgos Tsiapaliokas (terietor)
-
-feed 15m https://blogs.gentoo.org/johu/category/kde/feed/
-    define_name Johannes Huber (johu)
-    define_face hackergotchi/johannes-huber.jpg
-    define_facewidth 60
-    define_faceheight 68
-
-feed 15m https://blogs.kde.org/blog/8948/feed
-    define_name Pierre Stirnweiss (PierreSt)
-    define_face hackergotchi/pierre-stirnweiss.jpg
-    define_facewidth 58
-    define_faceheight 85
-
-feed 15m http://joerg-weblog.blogspot.com/feeds/posts/default/-/KDE
-    define_name Jörg Ehrichs
-    define_face hackergotchi/jehrichs.png
-    define_facewidth 80
-    define_faceheight 80
-
-feed 15m http://isemenov.blogspot.com/feeds/posts/default?alt=rss
-    define_name Ignat Semenov (isemenov)
-
-feed 15m https://freininghaus.wordpress.com/category/kde/feed/?mrss=off
-    define_name Frank Reininghaus
-
-feed 15m http://jgrulich.cz/category/kde/feed/
-    define_name Jan Grulich (jgrulich)
-
-feed 15m http://playgfx.blogspot.com/feeds/posts/default/-/kdestuff
-    define_name Claudio Desideri (snizzo)
-
-feed 15m https://boringtalk.wordpress.com/feed/
-    define_name Arjun Basu (ultimatrix)
-
-feed 15m http://strohel.blogspot.com/feeds/posts/default/-/kde
-    define_name Matěj Laitl (strohel)
-    define_face hackergotchi/strohel.png
-    define_facewidth 80
-    define_faceheight 80
-
-feed 15m https://www.kdab.com/category/blogs/technical/feed/
-    define_name KDAB on Qt
-    define_feedclass news
-    define_face hackergotchi/kdab.png
-    define_facewidth 80
-    define_faceheight 80
-
-feed 15m https://www.calligra.org/feed/
-    define_name Calligra News
-    define_feedclass news
-    define_face hackergotchi/calligra.png
-    define_facewidth 80
-    define_faceheight 57
-
-feed 15m http://amanonit.blogspot.com/feeds/posts/default/-/kde?alt=rss
-    define_name Amandeep Singh (amandeepsingh)
-
-feed 15m http://blog.rishab.in/feeds/kde.rss.xml
-    define_name Rishab Arora (spacetime)
-    define_face hackergotchi/rishab-arora.png
-    define_facewidth 79
-    define_faceheight 83
-
-feed 15m http://arthursribeiro.blogspot.com.br/feeds/posts/default/-/kde
-    define_name Arthur Ribeiro (arthurribeiro)
-    define_face hackergotchi/arthurribeiro.jpg
-    define_facewidth 62
-    define_faceheight 80
-
-feed 15m https://timotheegiet.com/blog/tag/kde/feed
-    define_name Timothee Giet (Animtim)
-    define_face hackergotchi/animtim.png
-    define_facewidth 80
-    define_faceheight 80
-
-feed 15m http://mkuettler.blogspot.com/feeds/posts/default/-/planetkde
-    define_name Martin Küttler (mkuettler)
-
-feed 15m https://kokeroulis.wordpress.com/tag/planetkde/feed/
-    define_name Antonis Tsiapaliokas (kokeroulis)
-
-feed 15m https://jsimon3.wordpress.com/category/kde/feed/
-    define_name Joseph Simon (jsimon3)
-    define_face hackergotchi/josephsimon.png
-    define_facewidth 80
-    define_faceheight 80
-
-feed 15m https://skeletdev.wordpress.com/category/kde/feed/
-    define_name Casian-Valentin Andrei (skelet)
-    define_face hackergotchi/skelet.png
-    define_facewidth 80
-    define_faceheight 80
-
-feed 15m http://jigarraisinghani.blogspot.com/feeds/posts/default/-/KDE?alt=rss
-    define_name Jigar Raisinghani (jigar)
-    define_face hackergotchi/jigar.jpg
-    define_facewidth 57
-    define_faceheight 80
-
-feed 15m https://utkuaydin.wordpress.com/category/kde-2/feed/
-    define_name Utku Aydın (utku)
-    define_facewidth 80
-    define_faceheight 80
-
-feed 15m http://logofn.blogspot.com/feeds/posts/default
-    define_name Roney Gomes (roney)
-    define_face hackergotchi/RoneyGomes.jpg
-    define_facewidth 80
-    define_faceheight 64
-
-feed 15m https://cezarmocan.wordpress.com/feed/
-    define_name Cezar Mocan (CezarMocan)
-
-feed 15m https://hashpling.wordpress.com/tag/planetkde/feed/?mrss=off&tag=planetkde
-    define_name Anant Kamath (flak37)
-
-feed 15m http://knro.blogspot.com/feeds/posts/default/-/KDE
-    define_name Jasem Mutlaq (KNRO)
-    define_face hackergotchi/mutlaqja.png
-    define_facewidth 65
-    define_faceheight 78
-
-feed 15m http://erionism.blogspot.in/feeds/posts/default
-    define_name Brijesh Patel (erione)
-
-feed 15m https://blog.sebasgo.net/tag/kde/rss/
-    define_name Sebastian Gottfried (sebasgo)
-
-feed 15m https://behindkde.org/rss.xml
-    define_name Behind KDE
-    define_face hackergotchi/behindkde.png
-    define_facewidth 43
-    define_faceheight 43
-
-feed 15m http://marcuzzokde.blogspot.com/feeds/posts/default?alt=rss
-    define_name Marco Calignano (marcuzzo)
-    define_face hackergotchi/marcuzzo.png
-    define_facewidth 80
-    define_faceheight 80
-
-feed 15m https://ruedigergad.com/tag/planetkde/feed/?mrss=off&tag=planetkde
-    define_name Ruediger Gad (rcg)
-    define_face hackergotchi/ruedigergad.png
-    define_facewidth 72
-    define_faceheight 80
-
-feed 15m http://kovalevskyy.tumblr.com/tagged/planetkde/rss
-    define_name Ilya Kowalewski (tucnak)
-    define_face hackergotchi/kowalewski.png
-    define_facewidth 80
-    define_faceheight 80
-
-feed 15m https://elv13.wordpress.com/category/kde/feed/?mrss=off
-    define_name Emmanuel Lepage Vallee (Elv13)
-
-feed 15m http://mayankmadanon.blogspot.in/feeds/posts/default?alt=rss
-    define_name Mayank Madan (mayankmadan)
-
-feed 15m http://g-poesia.blogspot.com/feeds/posts/default/-/kde
-    define_name Gabriel Poesia (gpoesia)
-    define_face hackergotchi/gabriel-poesia.jpg
-    define_facewidth 49
-    define_faceheight 80
-
-feed 15m http://stuartmd2.blogspot.com/feeds/posts/default
-    define_name Stuart Dickson (stuartmd)
-    define_face hackergotchi/stuartmd.png
-    define_facewidth 80
-    define_faceheight 80
-
-feed 15m https://randa-meetings.ch/category/english/feed/
-    define_name Randa Meetings
-    define_feedclass news
-
-feed 15m http://sessellift.eu/category/kde/feed/?mrss=off
-    define_name Thomas Pfeiffer (colomar)
-    define_face hackergotchi/thomas-pfeiffer.jpg
-    define_facewidth 75
-    define_faceheight 80
-
-feed 15m http://tolszak-dev.blogspot.com/feeds/posts/default/-/planetkde
-    define_name Tomasz Olszak (tolszak)
-    define_face hackergotchi/tolszak.png
-    define_facewidth 70
-    define_faceheight 79
-
-feed 15m https://martinbriza.wordpress.com/tag/kde/feed/?mrss=off
-    define_name Martin Bříza (mbriza)
-
-feed 15m http://gkbhat.blogspot.in/feeds/posts/default/-/KDE
-    define_name Gopalakrishna Bhat
-    define_face hackergotchi/sysadmins.png
-    define_facewidth 80
-    define_faceheight 80
-
-feed 15m http://andreasschilling.tumblr.com/search/kde/rss
-    define_name Andreas Schilling
-
-feed 15m https://mbohlender.wordpress.com/feed/atom/
-    define_name Michael Bohlender (mbohlender)
-
-feed 15m https://adrianbd.wordpress.com/feed/?mrss=off
-    define_name Adrian Draghici (adrianb)
-    define_face hackergotchi/adrianb.png
-    define_facewidth 57
-    define_faceheight 80
-
-feed 15m https://konkiewiczm.wordpress.com/feed/?mrss=off
-    define_name Magda Konkiewicz
-    define_face hackergotchi/magda.png
-    define_facewidth 100
-    define_faceheight 127
-
-feed 15m https://oinig.wordpress.com/tag/kde/feed/?mrss=off&tag=kde
-    define_name Oindrila Gupta (oini)
-    define_face hackergotchi/oini.jpg
-    define_facewidth 70
-    define_faceheight 80
-
-feed 15m http://kreversiqml.blogspot.com/feeds/posts/default
-    define_name Denis Kuplyakov (dener.kup)
-    define_face hackergotchi/dener.jpg
-    define_facewidth 80
-    define_faceheight 80
-
-feed 15m https://ciypro.wordpress.com/category/kde-gsoc2013/feed/?mrss=off
-    define_name Chandan Kumar (chandankumar)
-    define_face hackergotchi/chandankumar.jpg
-    define_facewidth 80
-    define_faceheight 69
-
-feed 15m http://gsoc2013.anmolahuja.com/feeds/posts/default?alt=rss
-    define_name Anmol Ahuja (DarthCodus)
-
-feed 15m https://xardas008.wordpress.com/category/kde/feed/?mrss=off
-    define_name Daniel Kreuter (xardas008)
-    define_face hackergotchi/kreuter.png
-    define_facewidth 61
-    define_faceheight 79
-
-feed 15m http://akshaycode.blogspot.com/feeds/posts/default/-/KDE?alt=rss
-    define_name Akshay Ratan (akshay_r)
-
-feed 15m https://nagpalsahil.wordpress.com/feed/?mrss=off
-    define_name Sahil Nagpal (sahil)
-
-feed 15m https://ahmedabouelhamayed.wordpress.com/category/kde/feed/?mrss=off
-    define_name Ahmed AbouElhamayed (TheMonster)
-
-feed 15m https://blogs.kde.org/blog/193/feed
-    define_name Eike Hein (Sho)
-    define_face hackergotchi/eike-hein.jpg
-    define_facewidth 80
-    define_faceheight 80
-
-feed 15m https://iammarco11.github.io/feed.xml
-    define_name Akshay Praveen Nair (iammarco)
-    define_face hackergotchi/iammarco11.png
-    define_facewidth 80
-    define_faceheight 80
-
-feed 15m https://albertvaka.wordpress.com/feed/?mrss=off
-    define_name Albert Vaca (albertvaka)
-    define_face hackergotchi/albertvaka.png
-    define_facewidth 80
-    define_faceheight 80
-
-feed 15m https://shahimoji.wordpress.com/feed/?mrss=off
-    define_name Mojtaba Shahi Senobari (moji)
-
-feed 45m https://www.csslayer.info/wordpress/tag/planetkde/feed/
-    define_name Weng Xuetian (csslayer)
-    define_face hackergotchi/xuetianweng.png
-    define_facewidth 80
-    define_faceheight 80
-
-feed 45m https://www.csslayer.info/wordpress/category/kde/feed/
-    define_name CS Slayer
-    define_face hackergotchi/xuetianweng.png
-    define_facewidth 80
-    define_faceheight 80
-    define_feedclass chinese
-
-feed 15m https://blog.bshah.in/feed.xml
-    define_name Bhushan Shah (bshah)
-    define_face hackergotchi/bshah.jpg
-    define_facewidth 80
-    define_faceheight 80
-
-feed 15m https://punit9462.wordpress.com/category/planetkde/feed/
-    define_name Punit Mehta (punit9462)
-    define_face hackergotchi/punit-mehta.png
-    define_facewidth 80
-    define_faceheight 80
-
-feed 15m http://ghic.org/~diane/feeds/kde.atom.xml
-    define_name Diane Trout (detrout)
-
-feed 15m http://ematirov.blogspot.com/feeds/posts/default/-/kde
-    define_name Mihail Ivchenko (EgorMatirov)
-    define_face hackergotchi/ematirov.jpg
-    define_facewidth 64
-    define_faceheight 80
-
-feed 15m http://wheeldesign.blogspot.com/feeds/posts/default?alt=rss
-    define_name Jens Reuterberg (jensreuterberg)
-    define_face hackergotchi/jensreuterberg.png
-    define_facewidth 80
-    define_faceheight 80
-
-feed 15m http://zaufi.github.io/rss-kde.xml
-    define_name Alex Turbov (zaufi)
-
-feed 15m https://blogs.gnome.org/kittykat/tag/kde/feed/
-    define_name Ekaterina Gerasimova (kittykat)
-    define_face hackergotchi/egerasimova.png
-    define_facewidth 80
-    define_faceheight 80
-
-feed 15m https://sanjibandotme.wordpress.com/tag/kde/feed/
-    define_name Sanjiban Bairagya (fewcha)
-    define_face hackergotchi/sanjibanbairagya.png
-    define_facewidth 80
-    define_faceheight 77
-
-feed 15m http://kfunk.org/tag/kde/rss/
-    define_name Kevin Funk (kfunk)
-    define_face hackergotchi/kfunk.png
-    define_facewidth 80
-    define_faceheight 80
-
-feed 15m https://www.kdevelop.org/news/feed
-    define_name KDevelop
-    define_face hackergotchi/kdevelop.png
-    define_facewidth 80
-    define_faceheight 80
-
-feed 15m https://sklin0.wordpress.com/tag/gsoc/
-    define_name Sergey Kalinichev (klins)
-
-feed 15m https://abhgangwar.wordpress.com/feed/
-    define_name Abhinav Gangwar
-
-feed 15m https://bharathbrat.wordpress.com/category/gsoc-2014-kde/feed/
-    define_name Bharath M S (brat197)
-    define_face hackergotchi/bharath.png
-    define_facewidth 80
-    define_faceheight 79
-
-feed 15m https://calincruceru.wordpress.com/feed/
-    define_name Călin Cruceru (crucerucalin)
-
-feed 15m https://n1kam.wordpress.com/feed/
-    define_name Abhijeet Nikam (nikam08)
-
-feed 15m https://mrupanjana.wordpress.com/feed/
-    define_name Rupanjana Mitra (mrupanjana)
-
-feed 15m https://ziemin.wordpress.com/feed/
-    define_name Marcin Zieminski
-
-feed 15m https://akulichalexandr.wordpress.com/feed/
-    define_name Alexandr Akulich
-    define_face hackergotchi/akulichalexandr.png
-    define_facewidth 47
-    define_faceheight 80
-
-feed 15m http://calligra-author-outliner.blogspot.ru/feeds/posts/default
-    define_name Denis Kuplyakov
-    define_face hackergotchi/denis-Kuplyakov.jpg
-    define_facewidth 64
-    define_faceheight 64
-
-feed 15m https://kritawithmohit.wordpress.com/feed/
-    define_name Mohit Goyal (mohit)
-
-feed 15m https://gcompris.wordpress.com/category/KDE/feed/
-    define_name Timothée Giet (animtim)
-    define_face hackergotchi/gcompris.png
-    define_facewidth 80
-    define_faceheight 80
-
-feed 15m https://nil1511.wordpress.com/feed/
-    define_name Nilesh Suthar (nil1511)
-    define_face hackergotchi/nil1511.jpg
-    define_facewidth 57
-    define_faceheight 80
-
-feed 15m http://debjitmondal.blogspot.in/feeds/posts/default/-/kde
-    define_name Debjit Mondal (debjit)
-
-feed 15m https://aniketanvit.wordpress.com/tag/planetkde/feed/
-    define_name Aniket Anvit (packo)
-    define_face hackergotchi/packo.png
-    define_facewidth 67
-    define_faceheight 80
-
-feed 15m https://mohamedanwer.wordpress.com/tag/kde/feed/
-    define_name Mohamed Anwer (tootis)
-    define_face hackergotchi/mohamed-anwer.png
-    define_facewidth 53
-    define_faceheight 80
-
-feed 15m https://yangqiao.wordpress.com/category/kdeconnect/feed/
-    define_name YANG Qiao (yangqiao)
-
-feed 15m http://www.olafsw.de/category/software/feed/
-    define_name Olaf Schmidt-Wischhöfer (ojschmidt)
-    define_face hackergotchi/ojschmidt.png
-    define_facewidth 59
-    define_faceheight 80
-
-feed 15m http://plfiorini.blogspot.com/feeds/posts/default/-/kde
-    define_name Pier Luigi Fiorini (plfiorini)
-    define_face hackergotchi/plfiorini.jpg
-    define_facewidth 80
-    define_faceheight 80
-
-feed 15m https://scarlettgatelymoore.com/tag/opensource/feed/
-    define_name Scarlett Moore (sgclark)
-    define_face hackergotchi/sgclark.png
-    define_facewidth 80
-    define_faceheight 80
-
-feed 15m https://the2ring.blogspot.de/feeds/posts/default
-    define_name Hannah von Reth (TheOneRing)
-    define_face hackergotchi/theonering.png
-    define_facewidth 64
-    define_faceheight 64
-
-feed 15m http://matija.suklje.name/feeds/kde.atom.xml
-    define_name Matija Šuklje (silver_hook)
-    define_face hackergotchi/hook.png
-    define_facewidth 80
-    define_faceheight 80
-
-feed 15m https://kdeonlinux.wordpress.com/feed/
-    define_name Andreas Kainz (Andreas_k)
-    define_face hackergotchi/Andreas-Kainz.jpg
-    define_facewidth 80
-    define_faceheight 80
-
-feed 15m https://kver.wordpress.com/tag/kde/feed/
-    define_name Ken Vermette (kver)
-    define_face hackergotchi/kver.png
-    define_facewidth 80
-    define_faceheight 80
-
-feed 45m https://woboq.com/feed/planetkde.rss
-    define_name Olivier Goffart (Gof)
-
-feed 15m https://rahulc93.wordpress.com/tag/kde/feed/
-    define_name Rahul Chowdhury (rahulch)
-    define_face hackergotchi/rahul.png
-    define_facewidth 80
-    define_faceheight 80
-
-feed 15m https://sinceeverybodyhasablog.wordpress.com/category/KDE/feed/
-    define_name Dinu Kumarasiri (sandarumk)
-
-feed 15m http://alltypesofhacking.blogspot.in/feeds/posts/default
-    define_name Sayan Biswas
-    define_face hackergotchi/sayan.png
-    define_facewidth 80
-    define_faceheight 80
-
-feed 15m https://skoushik.wordpress.com/tag/kde/feed/
-    define_name Koushik S (skoushik)
-    define_face hackergotchi/koushik-s.jpg
-    define_facewidth 80
-    define_faceheight 80
-
-feed 15m https://subhajitmukherjee.wordpress.com/feed/
-    define_name Subhajit Mukherjee (bukai)
-    define_face hackergotchi/subhajitmukherjee.png
-    define_facewidth 80
-    define_faceheight 80
-
-feed 15m http://saikrishna17394.github.io/feed.xml
-    define_name Sai Krishna (saikrishna17394)
-    define_face hackergotchi/Sai-Krishna.jpg
-    define_facewidth 50
-    define_faceheight 80
-
-feed 15m http://kshitijblogs.blogspot.com/feeds/posts/default/-/SoK%2714
-    define_name Kshitij Gupta (kshitij8)
-    define_face hackergotchi/Kshitij-Gupta.png
-    define_facewidth 56
-    define_faceheight 80
-
-feed 15m https://anumittal.in/tag/PlanetKDE/
-    define_name Anu Mittal (anuM)
-    define_face hackergotchi/anum.png
-    define_facewidth 80
-    define_faceheight 80
-
-feed 15m https://dassouvik.wordpress.com/feed/
-    define_name Souvik Das (sd__)
-    define_face hackergotchi/Souvik-Das.jpg
-    define_facewidth 70
-    define_faceheight 76
-
-feed 15m https://thegreatercode.wordpress.com/feed/
-    define_name Utkarsh Simha (usimha)
-    define_face hackergotchi/Utkarsh-Simha.jpg
-    define_facewidth 80
-    define_faceheight 80
-
-feed 15m https://aarseeaeron.wordpress.com/feed/
-    define_name Aarsee Aeron (aarsee)
-    define_face hackergotchi/Aarsee-Aeron.jpg
-    define_facewidth 78
-    define_faceheight 80
-
-feed 15m http://davidrosca.blogspot.com/feeds/posts/default/-/planetkde
-    define_name David Rosca (nowrep)
-
-feed 15m http://kstplot.blogspot.com/feeds/posts/default/
-    define_name Kst News
-    define_face hackergotchi/kstplot.png
-    define_facewidth 80
-    define_faceheight 80
-    define_feedclass news
-
-feed 15m https://eang.it/planetkde.xml
-    define_name Elvis Angelaccio (elvisangelaccio)
-    define_face hackergotchi/elvis.png
-    define_facewidth 80
-    define_faceheight 80
-
-feed 15m https://blog.broulik.de/category/planetkde/feed/
-    define_name Kai Uwe Broulik (kbroulik)
-    define_face hackergotchi/kai.jpg
-    define_facewidth 75
-    define_faceheight 75
-
-feed 15m https://rajeeshknambiar.wordpress.com/feed/
-    define_name Rajeesh K Nambiar (rajeesh)
-    define_face hackergotchi/rajeesh.png
-    define_facewidth 80
-    define_faceheight 80
-
-feed 60m https://labplot.kde.org/feed/
-    define_name Alexander Semke
-    define_facewidth 80
-    define_faceheight 80
-    define_feedclass news
-
-feed 60m https://dfighter1985.wordpress.com/category/planetkde/feed/
-    define_name dfighter
-
-feed 3h http://feinstaub.github.io/blog/feed.kde.xml
-    define_name gregormi (gregormi)
-
-feed 60m http://kritaanimation.blogspot.com/feeds/posts/default
-    define_name Jouni Pentikäinen (tyyppi)
-
-feed 60m https://wolthera.info/category/coding/kde/feed/
-    define_name Wolthera van Hövell tot Westerflier (Wolthera)
-    define_face hackergotchi/Wolthera.png
-    define_facewidth 80
-    define_faceheight 80
-
-feed 15m http://wolfcliff.blogspot.com/feeds/posts/default/-/kdestuff
-    define_name Francesco Wofford (woffy)
-
-feed 45m http://www.msadityan.com/feed/?cat=kde
-    define_name M.S.Adityan (drawkward)
-    define_face hackergotchi/msadityan.png
-    define_facewidth 80
-    define_faceheight 80
-
-feed 45m http://sahebpreet-kde.blogspot.in/atom.xml
-    define_name Saheb Preet Singh (sahebpreet)
-    define_face hackergotchi/sahebpreet.png
-    define_facewidth 80
-    define_faceheight 80
-
-feed 45m http://binaryspring.blogspot.com/feeds/posts/default/-/kde
-    define_name Aroonav Mishra (roguedragon)
-    define_face hackergotchi/aroonav.jpg
-    define_facewidth 80
-    define_faceheight 80
-
-feed 45m http://koldavidgsoc.blogspot.com/feeds/posts/default
-    define_name David Kolozsvari (koldavid)
-    define_face hackergotchi/koldavid.png
-    define_facewidth 80
-    define_faceheight 80
-
-feed 45m http://mariusoc.blogspot.com/feeds/posts/default
-    define_name Marius Stanciu (stancium)
-    define_face hackergotchi/mariusoc.png
-    define_facewidth 80
-    define_faceheight 80
-
-feed 45m http://pgabor.blogspot.com/feeds/posts/default/-/GSOC
-    define_name Gábor Péterffy (pgabor)
-    define_face hackergotchi/pgabor.png
-    define_facewidth 80
-    define_faceheight 80
-
-feed 45m https://danielgsoc.wordpress.com/feed/?mrss=off
-    define_name Daniel Leu (daniel_leu)
-    define_face hackergotchi/leu.jpg
-    define_facewidth 80
-    define_faceheight 80
-
-feed 45m https://thebinarybin.wordpress.com/tag/kde/feed/
-    define_name Vineet Garg (vineet)
-    define_face hackergotchi/vineet-garg.png
-    define_facewidth 76
-    define_faceheight 75
-
-feed 45m https://amezin.github.io/feed.xml
-    define_name Alexander Mezin (amezin)
-    define_face hackergotchi/amezin.png
-    define_facewidth 70
-    define_faceheight 80
-
-feed 45m https://rthomsen6.wordpress.com/tag/kde/feed/
-    define_name Ragnar Thomsen (rthomsen)
-    define_face hackergotchi/rthomsen.png
-    define_facewidth 80
-    define_faceheight 80
-
-feed 45m http://usefoss.com/index.php/tag/kde/feed/
-    define_name Aaron Honeycut (ahoneybun)
-    define_face hackergotchi/ahoneybun.png
-    define_facewidth 80
-    define_faceheight 80
-
-feed 45m http://datapicker.blogspot.in/feeds/posts/default
-    define_name Ankit Wagadre (ankitw)
-    define_face hackergotchi/ankitw.jpg
-    define_facewidth 80
-    define_faceheight 80
-
-feed 30m https://blog.baloneygeek.com/feeds/rss.xml
-    define_name Boudhayan Gupta (BaloneyGeek)
-    define_face hackergotchi/bgupta.png
-    define_facewidth 80
-    define_faceheight 80
-
-feed 15m https://vyacheslav-matyushin.blogspot.ru/feeds/posts/default/-/kde
-    define_name Vyacheslav Matyushin (abiogenesis)
-    define_face hackergotchi/vmatyushin.png
-    define_facewidth 80
-    define_faceheight 80
-
-feed 45 https://laysrodriguesdev.wordpress.com/author/lays147/feed/
-    define_name Lays Rodrigues
-    define_face hackergotchi/lays.png
-    define_facewidth 55
-    define_faceheight 80
-
-feed 45m http://support-kde-randa.blogspot.com/feeds/posts/default
-    define_name Shourya Singh Gupta
-    define_face hackergotchi/shourya.jpg
-    define_facewidth 60
-    define_faceheight 80
-
-feed 45m https://rizzitello.wordpress.com/author/sithlord48/feed/
-    define_name Chris Rizzitello
-    define_face hackergotchi/rizzitello.png
-    define_facewidth 80
-    define_faceheight 80
-
-feed 15m https://blogs.kde.org/blog/10432/feed
-    define_name Heiko Tietze (htietze)
-    define_face hackergotchi/htietze.png
-    define_facewidth 67
-    define_faceheight 67
-
-feed 15m https://blogs.churlaud.com/somefoobar/tag/kde/feed/
-    define_name Olivier Churlaud (ochurlaud)
-    define_face hackergotchi/ochurlaud.jpg
-    define_facewidth 67
-    define_faceheight 67
-
-feed 30m https://phernandotelles.wordpress.com/category/english/planetkde/feed/
-    define_name Fernando Teles
-    define_face hackergotchi/fernandoteles.png
-    define_facewidth 80
-    define_faceheight 80
-
-feed 15m http://inandoutkde.blogspot.com/feeds/posts/default
-    define_name Russell Greene
-
-feed 15m http://divitgulati.blogspot.com/feeds/posts/default
-    define_name Divit Gulati
-
-feed 15m http://experiencewithkde.blogspot.de/feeds/posts/default
-    define_name Hristiyan Kyosev
-
-feed 23m https://t-fischer.dreamwidth.org/data/rss?tag=kde
-    define_name Thomas Fischer
-    define_face hackergotchi/thomasfischer.png
-    define_facewidth 80
-    define_faceheight 80
-
-feed 18m https://stanfordlin.wordpress.com/feed/
-    define_name Stanford Lin
-
-feed 15m https://hultnuno.wordpress.com/feed/
-    define_name Nuno Hultberg
-
-feed 45m http://programmer-pit.de/?feed=rss2&cat=2
-    define_name Gilbert Assaf
-
-feed 15m https://g33kyaditya.wordpress.com/tag/kde/feed/
-    define_name Aditya Dev Sharma (g33kyaditya)
-    define_face hackergotchi/aditya-dev-sharma.jpg
-    define_facewidth 68
-    define_faceheight 80
-
-feed 30m https://delsalife.wordpress.com/feed/
-    define_name Andrea Del Sarto
-
-feed 45m https://arnavdhamija.com/tag/kde/rss/
-    define_name Arnav Dhamija (shortstheory)
-    define_face hackergotchi/arnavdhamija.jpg
-    define_facewidth 80
-    define_faceheight 80
-
-feed 15m http://alittledeveloper.blogspot.com/feeds/posts/default/?q=label:KDE
-    define_name Alessandro Tundo
-
-feed 15m https://atakanzblog.wordpress.com/tag/wikitolearn/feed/
-    define_name Daniele Pannozzo
-    define_face hackergotchi/atakanz.png
-    define_facewidth 80
-    define_faceheight 80
-
-feed 30m https://blog.lucatoma.eu/category/kde-planet/feed/
-    define_name Luca Toma
-
-feed 16m http://martinadestefani.blogspot.com/feeds/posts/default/-/KDE/?alt=rss
-    define_name Martina De Stefani
-    define_face hackergotchi/marti_de.png
-    define_facewidth 80
-    define_faceheight 80
-
-feed 17m https://blogs.wikitolearn.org/author/vincenzo/feed/
-    define_name Vincenzo Eduardo Padulano
-
-feed 17m https://blogs.wikitolearn.org/author/lodo_ravi/feed/
-    define_name Lodovico Filippo Ravizza
-
-feed 17m https://blogs.wikitolearn.org/author/f.quarenghi/feed/
-    define_name Filippo Quarenghi
-
-feed 17m https://blogs.wikitolearn.org/author/jmotta1/feed/
-    define_name Jona Motta
-
-feed 17m https://blogs.wikitolearn.org/author/Lucieferr/feed/
-    define_name Lucie Ferretti
-
-feed 17m https://blogs.wikitolearn.org/author/m.bona/feed/
-    define_name Matteo Bonanomi
-
-feed 45m https://ayushashah.wordpress.com/feed/
-    define_name Ayush Shah (ayushshah)
-    define_face hackergotchi/ayushshah.jpg
-    define_facewidth 80 define_faceheight 80
-
-feed 17m https://blogs.wikitolearn.org/author/matteo_marcoli/feed/
-    define_name Matteo Marcoli
-
-feed 14m https://blogs.wikitolearn.org/author/ruphy/feed/
-    define_name Riccardo Iaconelli (ruphy)
-    define_face hackergotchi/ruphy.png
-    define_facewidth 80
-    define_faceheight 80
-
-feed 17m https://blogs.wikitolearn.org/author/scimmiaspaziale/feed/
-    define_name Riccardo A Gilardi
-
-feed 17m https://blogs.wikitolearn.org/author/Xadhoom/feed/
-    define_name Sofia Liguori
-
-feed 17m http://baldi.me/blog/feed-kde.xml
-    define_name Cristian Baldi
-
-feed 17m https://blogs.wikitolearn.org/author/irenedaloia/feed/
-    define_name Irene D'aloia
-
-feed 17m https://blogs.wikitolearn.org/author/dcarrara/feed/
-    define_name Demetrio Carrara
-
-feed 15m https://blogs.wikitolearn.org/author/wikitolearn/feed/
-    define_name WikiToLearn Community
-    define_face hackergotchi/wtlemblem.png
-    define_facewidth 80
-    define_faceheight 80
-
-feed 15m http://gsoc16.pulkitgupta.net/feed/
-    define_name Pulkit Gupta (pulkit)
-    define_face hackergotchi/pulkit.png
-    define_facewidth 44
-    define_faceheight 80
-
-feed 45m http://thelastpolaris.blogspot.com/feeds/posts/default
-	define_name Artem Fedoskin (polaris)
-    define_face hackergotchi/afedoskin.png
-    define_facewidth 80
-    define_faceheight 80
-
-feed 60m https://micreabog.wordpress.com/category/kde/feed/
-    define_name Krzysztof Nowicki
-    define_face hackergotchi/nowicki.jpeg
-    define_facewidth 80
-    define_faceheight 80
-
-feed 60m https://scsilver.wordpress.com/feed/?tag=kde
-    define_name Minh Chu (minhchu)
-    define_face hackergotchi/minhchu.png
-    define_facewidth 80
-    define_faceheight 80
-
-feed 15m https://sagarhani.wordpress.com/feed/atom/?tag=kde
-    define_name Sagar Hani (sagarhani)
-    define_face hackergotchi/sagarhani.png
-    define_facewidth 80
-    define_faceheight 80
-
-feed 45m https://stefantoncu29.wordpress.com/feed/?tag=kde
-	define_name Stefan Toncu (StefanT)
-    define_face hackergotchi/stefan.png
-    define_facewidth 80
-    define_faceheight 80
-
-feed 45m http://falit94.blogspot.com/feeds/posts/default?alt=rss
-      define_name Falit Jain (falitjain)
-      define_face hackergotchi/falit.png
-      define_facewidth 80
-      define_faceheight 80
-
-feed 45m https://raphaelcojocaru.wordpress.com/feed/?tag=kde
-    define_name Raphael Cojocaru (raphael29)
-    define_face hackergotchi/raphael.png
-    define_facewidth 80
-    define_faceheight 80
-
-feed 45m https://juliacantor.blogspot.ru/feeds/posts/default?alt=rss
-	define_name Ivan Lakhtanov (vaness)
-
-feed 45m https://keenlearner.wordpress.com/feed/?tag=kde
-	define_name Abhimanyu Shekhawat (abhimanyushekhawat)
-    define_face hackergotchi/abhimanyushekhawat.png
-    define_facewidth 80
-    define_faceheight 80
-
-feed 45m http://kritadev.blogspot.com/feeds/posts/default?alt=rss
-    define_name Julian Thijssen (nimmy)
-    define_face hackergotchi/nimmy.png
-    define_facewidth 80
-    define_faceheight 80
-
-feed 45m http://droftware.github.io/feed.kde.xml
-    define_name Akshat Tandon (tandon)
-    define_face hackergotchi/tandon.png
-    define_facewidth 80
-    define_faceheight 80
-
-feed 45m http://mvlabat.github.io/ark-gsoc-2016/feed.xml
-	define_name Vladyslav Batyrenko (mvlabat)
-	define_face hackergotchi/mvlabat.png
-	define_facewidth 80
-	define_faceheight 80
-
-feed 45m http://tctara.github.io/gsoc/feed.xml
-	define_name Chantara Tith (tctara)
-
-feed 45m https://prakritibhardwajblog.wordpress.com/tag/kde/feed/
-	define_name Prakriti Bhardwaj (kupy)
-	define_face hackergotchi/Prakriti_Bhardwaj.jpg
-	define_facewidth 80
-	define_faceheight 80
-
-feed 45m https://bhavishadhruve.wordpress.com/feed/
-    define_name Bhavisha Dhruve (bdhruve)
-
-feed 45m http://krajszgsoc.blogspot.com/feeds/posts/default?alt=rss
-    define_name Fábián Kristóf (krajsz)
-    define_face hackergotchi/krajsz.png
-    define_facewidth 79
-    define_faceheight 69
-
-feed 45m https://swatilodha.wordpress.com/feed/
-	    define_name Swati Lodha (swati_27)
-
-feed 15m http://aspotashev.blogspot.com/feeds/posts/default?alt=rss
-    define_name Alexander Potashev (aspotashev)
-    define_face hackergotchi/aspotashev.png
-    define_facewidth 80
-    define_faceheight 80
-
-feed 45m https://bernkastelsgsoc.blogspot.com/feeds/posts/default?alt=rss
-    define_name Judit Bartha (bernkastel)
-    define_face hackergotchi/bernkastel.png
-    define_facewidth 80
-    define_faceheight 80
-
-feed 15m https://www.qt.io/blog/tag/loop/rss.xml
-    define_name Qt Dev Loop
-    define_feedclass news
-    define_face hackergotchi/qt_logo.png
-    define_facewidth 80
-    define_faceheight 58
-
-feed 15m https://choqok.kde.org/feed.xml
-    define_name Choqok
-    define_face hackergotchi/choqok.png
-
-feed 15m https://psifidotos.blogspot.com/feeds/posts/default/-/kde
-    define_name Michail Vourlakos (psifidotos)
-    define_face hackergotchi/vourlakos.png
-    define_facewidth 80
-    define_faceheight 80
-
-feed 45m https://divyam3897.github.io/feed.xml
-    define_name Divyam Madaan (dmadaan_)
-    define_face hackergotchi/divyamMadaan.jpg
-    define_facewidth 80
-    define_faceheight 80
-
-feed 45m http://rahulyadav170923.blogspot.com/feeds/posts/default/
-    define_name Rahul Yadav (rahulyadav)
-    define_face hackergotchi/rahulyadav.png
-    define_facewidth 80
-    define_faceheight 80
-
-feed 45m http://rahulyadav170923.blogspot.com/feeds/posts/default/
-    define_name Rahul Yadav (rahulyadav)
-    define_face hackergotchi/rahulyadav.png
-    define_facewidth 80
-    define_faceheight 80
-
-feed 15m https://subdiff.org/blog/feed.xml
-    define_name Roman Gilg
-    define_face hackergotchi/roman-gilg.png
-    define_facewidth 80
-    define_faceheight 80
-
-feed 30m https://guoyunhe.me/en/t/kde/feed/
-    define_name Guo Yunhe
-    define_face hackergotchi/guoyunhe.jpg
-    define_facewidth 80
-    define_faceheight 80
-
-feed 30m https://guoyunhe.me/zh/t/kde/feed/
-    define_name Guo Yunhe
-    define_feedclass chinese
-    define_face hackergotchi/guoyunhe.jpg
-    define_facewidth 80
-    define_faceheight 80
-
-feed 45m https://iamutkarshtiwari.wordpress.com/season-of-kde-2016/feed/
-    define_name Utkarsh Tiwari (iamutkarshtiwari)
-    define_face hackergotchi/utkarshtiwari.jpg
-    define_facewidth 80
-    define_faceheight 80
-
-feed 45m https://nitish18blog.wordpress.com/2017/03/08/feed/
-    define_name Nitish Chauhan (nitish)
-    define_face hackergotchi/nitish.jpg
-    define_facewidth 80
-    define_faceheight 80
-
-feed 45m https://mgallienkde.wordpress.com/feed/
-    define_name Matthieu Gallien (mgallien)
-    define_face hackergotchi/mgallien.png
-    define_facewidth 80
-    define_faceheight 80
-
-feed 45m https://yuenhoe.com/blog/tag/planetkde/feed/
-    define_name Lim Yuen Hoe (moofang)
-    define_face hackergotchi/yuenhoe.jpg
-    define_facewidth 80
-    define_faceheight 80
-
-feed 15m http://blog.chinmoyrp.com/feed.xml
-    define_name Chinmoy Ranjan Pradhan (chinmoy)
-    define_face hackergotchi/chinmoy.png
-    define_facewidth 75
-    define_faceheight 75
-
-feed 45m https://akapust1n.wordpress.com/feed/?mrss=off
-    define_name Kapustin Alexey (akap)
-    define_face hackergotchi/akapustin.png
-    define_facewidth 80
-    define_faceheight 80
-
-feed 45m https://eliakincosta.github.io/feed.xml
-    define_name Eliakin Costa (eliakincosta)
-    define_face hackergotchi/eliakincosta.jpg
-    define_facewidth 80
-    define_faceheight 80
-
-feed 15m https://anikethfoss.wordpress.com/category/kde/feed/?mrss=off&category_name=kde
-    define_name Aniketh Girish (aniketh___)
-    define_face hackergotchi/Aniketh-Girish.jpg
-    define_facewidth 80
-    define_faceheight 80
-
-
-feed 45m https://rish9511.wordpress.com/category/kde/feed/
-	define_name Rishabh Gupta (rishabh)
-        define_face hackergotchi/rgupta.png
-        define_facewidth 80
-        define_faceheight 80
-
-feed 60m https://www.digikam.org/index.xml
-    define_name digiKam
-    define_face hackergotchi/digikam.png
-    define_facewidth 80
-    define_faceheight 80
-
-feed 45m https://perplexinglyemma.blogspot.co.uk/feeds/posts/default/-/kde?alt=rss
-    define_name Emma Gospodinova (xstyle)
-    define_face hackergotchi/emgosp.jpg
-    define_facewidth 80
-    define_faceheight 80
-
-feed 45m https://blog.neon.kde.org/index.php/feed/
-    define_name KDE neon Blog
-    define_feedclass news
-    define_face hackergotchi/neon.png
-    define_facewidth 80
-    define_faceheight 80
-
-feed 45m https://community.chakralinux.org/tags/curated.rss
-    define_name Chakra
-    define_feedclass news
-    define_face hackergotchi/chakra-shield.png
-    define_facewidth 80
-    define_faceheight 80
-
-feed 45m http://kecsapgsoc2017.blogspot.com/feeds/posts/default?alt=rss
-    define_name kecsap (GSOC 2017)
-    define_face hackergotchi/kecsap.jpg
-    define_facewidth 80
-    define_faceheight 80
-
-feed 45m https://nitish18blog.wordpress.com/2017/06/14/feed/
-    define_name Nitish Chauhan (nitish)
-    define_face hackergotchi/nitish.jpg
-    define_facewidth 80
-    define_faceheight 80
-
-feed 45m https://akapust1n.github.io/feed.xml
-    define_name Kapustin Alexey (akap)
-    define_face hackergotchi/akapustin.png
-    define_facewidth 80
-    define_faceheight 80
-
-feed 45m https://zoltanp.github.io/category/kde_feed.xml
-    define_name Zoltan Padrah
-
-feed 45m https://shazaismailkaoud.wordpress.com/tag/kde/feed/
-    define_name Shaza Ismail Kaoud (shazaismailkaoud)
-    define_face hackergotchi/shaza-ismail.png
-    define_facewidth 53
-    define_faceheight 80
-
-feed 45m https://tantsevov.wordpress.com/feed/?mrss=off
-    define_name Tantsevov Grigory (tantsevov)
-    define_face hackergotchi/tantsevov.png
-    define_facewidth 80
-    define_faceheight 80
-
-feed 45m https://anditosan.wordpress.com/feed/?mrss=off
-    define_name Andres Betts (anditosan)
-    define_face hackergotchi/andres-betts.jpg
-    define_facewidth 80
-    define_faceheight 80
-
-feed 15m https://vasudhamathur.wordpress.com/category/KDE/feed/
-        define_name Vasudha (vasudhamathur)
-        define_face hackergotchi/vasudha.jpg
-        define_facewidth 73
-        define_faceheight 80
-
-feed 15m http://good-horse.blogspot.com/feeds/posts/default/-/KDE
-        define_name Franklin Weng
-
-feed 60m https://blog.bembel.net/category/kde/feed/
-    define_name Thomas Baumgart (ipwizard)
-    define_face hackergotchi/tbaumgart.png
-    define_facewidth 80
-    define_faceheight 80
-
-feed 60m https://quickfix.es/author/paul/feed/
-    define_name Paul (Bro666)
-    define_face hackergotchi/paulbro666.jpg
-    define_facewidth 80
-    define_faceheight 80
-
-feed 60m https://quickfix.es/author/skadinna/feed/
-    define_name Ivana (skadinna)
-    define_face hackergotchi/ivana.jpg
-    define_facewidth 80
-    define_faceheight 80
-
-feed 45m https://pointieststick.com/feed/
-    define_name Nate Graham (ngraham)
-    define_face hackergotchi/ngraham.png
-    define_facewidth 59
-    define_faceheight 80
-
-feed 60m http://neofytosk.com/categories/kde/index.xml
-    define_name Neofytos Kolokotronis (tetris4)
-    define_face hackergotchi/neofytosk.png
-    define_facewidth 80
-    define_faceheight 80
-
-feed 45m https://amankumargupta.wordpress.com/category/kde/feed/?mrss=off
-    define_name Aman Kumar Gupta (gupta2140[m])
-    define_face hackergotchi/amankumargupta.jpg
-    define_facewidth 55
-    define_faceheight 80
-
-
-feed 45m https://fluca1978.github.io/atom/planet-kde-org
-    define_name Luca Ferrari
-    define_face hackergotchi/luca-ferrari.png
-    define_facewidth 80
-    define_faceheight 80
-    define_feedclass user
-
-feed 15m https://amitsagtani97.wordpress.com/feed/
-        define_name Amit Sagtani (amit__)
-        define_face hackergotchi/amit.jpg
-        define_facewidth 80
-        define_faceheight 80
-
-feed 45m https://antlarr.io/feed/
-	define_name Antonio Larrosa (antlarr)
-        define_face hackergotchi/antlarr.png
-        define_facewidth 80
-        define_faceheight 80
-
-feed 15m https://skrooge.org/rss.xml
-    define_name Stéphane MANKOWSKI (smankowski)
-    define_face hackergotchi/smankowski.png
-
-feed 45m http://www.kdedigest.com/feeds/posts/default/-/[planetkde]?alt=rss
-	define_name James Cain (ronnoc)
-        define_face hackergotchi/james-cain.png
-        define_facewidth 80
-        define_faceheight 65
-
-feed 60m https://kdiff3.blogspot.com/feeds/posts/default
-    define_name KDiff3
-
-feed 60m https://matthijstijink.nl/static/feed_kde.xml
-    define_name Matthijs Tijink (mtijink)
-    define_face hackergotchi/mtijink.jpg
-    define_facewidth 80
-    define_faceheight 80
-
-feed 45m https://nicolasfella.wordpress.com/category/kde/feed/
-	define_name Nicolas Fella (nicofee)
-        define_face hackergotchi/nicolasfella.png
-        define_facewidth 80
-        define_faceheight 80
-
-feed 45m https://mkacej.wordpress.com/category/kde/feed/
-    define_name Martin Kacej (mkacej)
-
-feed 45m https://medium.com/feed/kdeok
-    define_name Łukasz Sawicki (llucas)
-    define_face hackergotchi/lucas.jpg
-    define_facewidth 58
-    define_faceheight 80
-    define_feedclass user
-
-feed 45m https://www.falkon.org/atom.xml
-    define_name Falkon
-    define_feedclass news
-    define_face hackergotchi/falkon.png
-    define_facewidth 64
-    define_faceheight 64
-
-feed 45m https://furkantokac.com/categories/kde/index.xml
-    define_name Furkan Tokac (ftDev)
-    define_face hackergotchi/Furkan-Tokac.png
-    define_facewidth 80
-    define_faceheight 80
-
-feed 45m https://colorathis.wordpress.com/tag/kde/feed/
-    define_name Iván Yossi Santa María (ivanyossi)
-    define_face hackergotchi/ivanyossi.png
-    define_facewidth 80
-    define_faceheight 80
-
-feed 45m https://simeir.github.io/feeds/kdefeed.atom
-    define_name Michael Zhou (simeir)
-    define_face hackergotchi/simeir.png
-    define_facewidth 80
-    define_faceheight 80
-
-feed 45m https://kfereneczgsoc2018.blogspot.com/feeds/posts/default
-    define_name Ferencz Kovacs (ferenczkovacs)
-    define_face hackergotchi/ferencz_kovacs.png
-    define_facewidth 62
-    define_faceheight 80
-
-feed 45m https://andreycyg.blogspot.com/feeds/posts/default
-    define_name Andrey Cygankov (andreyc)
-    define_face hackergotchi/andreyc.png
-    define_facewidth 80
-    define_faceheight 80
-
-feed 45m https://medium.com/feed/@mujjingun_23509
-    define_name Gun Park (gpark)
-    define_face hackergotchi/mujji.png
-    define_facewidth 80
-    define_faceheight 80
-
-feed 45m https://ilyabiz.com/category/kde/feed/
-    define_name Ilya Bizyaev (ilya_b)
-    define_face hackergotchi/ilya_b.png
-    define_facewidth 80
-    define_faceheight 80
-
-feed 30m https://www.volkerkrause.eu/feed.xml
-    define_name Volker Krause
-
-feed 45m https://luis692397029.wordpress.com/feed/
-    define_name Luis Lavaire
-    define_face hackergotchi/luis.jpeg
-    define_facewidth 80
-    define_faceheight 80
-
-feed 45m https://andrewcrouthamel.wordpress.com/category/kde/feed/
-    define_name Andrew Crouthamel (AndrewCrouthamel)
-    define_face hackergotchi/acrouthamel.png
-    define_facewidth 80
-    define_faceheight 80
-
-feed 45m https://kiryteo7.wordpress.com/category/kde/
-    define_name Ashwin Samudre (ashwins)
-    define_face hackergotchi/ashwins.png
-    define_facewidth 80
-    define_faceheight 80
-
-feed 45m https://www.creative-destruction.org/tags/foss/index.xml
-    define_name Mirko Boehm (miroslav)
-    define_face hackergotchi/mirkoboehm.png
-    define_facewidth 80
-    define_faceheight 80
-
-feed 45m http://www.mardy.it/categories/kdeplanet.xml
-        define_name Alberto Mardegan (mardy)
-        define_face hackergotchi/alberto-mardegan.png
-        define_facewidth 80
-        define_faceheight 80
-        define_feedclass user
-
-feed 45m https://jbbgameich.github.io/feed.xml
-    define_name Jonah Brüchert (JBB)
-    define_face hackergotchi/jbb.png
-    define_facewidth 80
-    define_faceheight 80
-
-feed 45m https://jucato.wordpress.com/tag/kde/feed/
-	define_name Juan Carlos Torres (jucato)
-    define_face hackergotchi/jucato.png
-    define_facewidth 80
-    define_faceheight 80
-
-feed 45m https://www.hellozee.dev/tags/kde/index.xml
-	define_name Kuntal Majumder (hellozee)
-    define_face hackergotchi/hellozee.png
-    define_facewidth 80
-    define_faceheight 80
-
-feed 45m https://brute4s99.news.blog/category/kde/feed/
-    define_name Piyush Aggarwal | brute4s99
-    define_face hackergotchi/brute4s99.png
-    define_facewidth 80
-    define_faceheight 80
-
-feed 45m https://filipfila.wordpress.com/tag/planet-kde/feed/
-    define_name Filip Fila
-    define_face hackergotchi/filipf.png
-    define_facewidth 80
-    define_faceheight 80
-
-feed 15m https://www.kaidan.im/atom.xml
-    define_name Kaidan News
-    define_face hackergotchi/kaidan.png
-    define_facewidth 80
-    define_faceheight 80
-
-feed 45m https://kde.inoki.cc/atom.xml
-    define_name Weixuan XIAO (Inokinoki)
-    define_face hackergotchi/inoki.jpg
-    define_facewidth 80
-    define_faceheight 80
-
-feed 45m https://orepoala.home.blog/category/kde/feed/
-    define_name Rituka Patwal (orepoala)
-    define_face hackergotchi/orepoala.png
-    define_facewidth 80
-    define_faceheight 80
-
-feed 45m https://sirgienkogsoc2019.blogspot.com/feeds/posts/default
-    define_name Sirgienko Nikita (sirgienko)
-    define_face hackergotchi/sirgienko.png
-    define_facewidth 54
-    define_faceheight 80
-
-feed 45m https://agdeva8labplot.blogspot.com/rss.xml
-    define_name Devanshu Agarwal (agdeva8)
-    define_face hackergotchi/devanshuagarwal.png
-    define_facewidth 78
-    define_faceheight 80
-
-feed 45m https://www.sh-zam.com/feeds/posts/default/-/kde
-    define_name Sharaf Zaman (sh_zam)
-    define_face hackergotchi/sh_zam.png
-    define_facewidth 80
-    define_faceheight 80
-
-feed 45m https://tusooa.github.io/tags/kde/atom.xml
-    define_name tusooa
-    define_face hackergotchi/tusooa.png
-    define_facewidth 79
-    define_faceheight 80
-
-feed 45m https://fbgsoc.home.blog/feed/
-    define_name Farid Boudedja (faridb)
-    define_face hackergotchi/faridb.png
-    define_facewidth 80
-    define_faceheight 80
-
-feed 45m https://feverfew.home.blog/feed/
-    define_name A Saoutkin (feverfew)
-    define_face hackergotchi/asaoutkin.png
-    define_facewidth 80
-    define_faceheight 80
-
-feed 45m https://akhilam512.github.io/blog/feed.jekyll.xml
-    define_name Akhil K Gangadharan (akhilkg_)
-    define_face hackergotchi/akhilkgangadharan.png
-    define_facewidth 61
-    define_faceheight 80
-
-feed 45m https://akshaychd.blogspot.com/feeds/posts/default
-    define_name Akshay Kumar (akshaychd)
-    define_face hackergotchi/akshaychd.png
-    define_facewidth 80
-    define_faceheight 80
-
-feed 45m https://chst.dev/feed.xml
-    define_name Caio Tonetti (ctonetti)
-    define_face hackergotchi/ctonetti.png
-    define_facewidth 80
-    define_faceheight 80
-
-feed 45m https://dimitris.cc/feed/kde.xml
-    define_name Dimitris Kardarakos (dkardarakos)
-    define_face hackergotchi/dkardarakos.png
-    define_facewidth 80
-    define_faceheight 80
-
-feed 15m https://jen6.github.io/feed_kde.xml
-        define_name SonGeon (jen6)
-        define_face hackergotchi/songeon_hackergotchi.png
-        define_facewidth 80
-        define_faceheight 80
-
-feed 45m https://karinappassos.home.blog/feed/
-    define_name Karina Passos (karinapassos)
-    define_face hackergotchi/karina.jpeg
-    define_facewidth 80
-    define_faceheight 80
-
-feed 45m https://carlschwan.eu/feed.xml
-    define_name Carl Schwan (ognarb)
-    define_face hackergotchi/ognarb.png
-    define_facewidth 80
-    define_faceheight 80
-
-feed 45m https://gsocokular2019.home.blog/feed/?mrss=off
-    define_name João Netto (joaonetto)
-
-feed 45m https://coderunner99.blogspot.com/feeds/posts/default
-	define_name Shubham (shubham)
-
-feed 45m https://caiojcarvalho.wordpress.com/category/kde/feed/
-    define_name Caio Jordão Carvalho (cjlcarvalho)
-    define_face hackergotchi/caiojcarvalho.png
-    define_facewidth 80
-    define_faceheight 80
-
-feed 45m https://blog.david-redondo.de/feed.xml
-    define_name David Redondo (DavidRedondo)
-
-feed 45m https://simonredman.wordpress.com/category/kde/feed/
-    define_name Simon Redman (sredman)
-    define_face hackergotchi/sredman.png
-    define_facewidth 80
-    define_faceheight 80
-
-feed 45m http://www.bivouak.fr/feed/tag/kde/atom
-    define_name Méven Car (meven)
-    define_face hackergotchi/meven.png
-    define_facewidth 80
-    define_faceheight 80
-
-feed 15m https://www.plasma-mobile.org/feed-kde-planet.xml
-    define_name Plasma Mobile blog
-    define_face hackergotchi/plasma-mobile.png
-    define_facewidth 80
-    define_faceheight 30
-    define_feedclass news
-
-feed 45m https://rabbitictranslator.com/wordpress/index.php/tag/planetkde/feed/
-    define_name Thiago Masato Costa Sueto
-    define_face hackergotchi/thiago.png
-    define_facewidth 80
-    define_faceheight 80
-
-feed 45m https://sgorava.github.io/feed/KDE.xml
-    define_name Juraj Oravec (SGOrava)
-
-feed 15m https://outsideofinfinity.wordpress.com/category/planet/feed/
-    define_name Agata Cacko (tiar)
-    define_face hackergotchi/tiar.png
-    define_facewidth 80
-    define_faceheight 80
-
-feed 15m https://sandroknauss.de/blog/categories/kde/feed.xml
-    define_name Sandro Knauß (hefee)
-    define_face hackergotchi/hefee.png
-    define_facewidth 89
-    define_faceheight 72
-
-feed 45m https://cantor.kde.org/feed.xml
-    define_name Cantor
-    define_face hackergotchi/cantor.svg
-    define_facewidth 80
-    define_faceheight 80
-
-feed 45m https://journal.heloo.net/tag/kde/rss2.xml
-    define_name Kenny Coyle (kcoyle)
-    define_face hackergotchi/kcoyle.png
-    define_facewidth 80
-    define_faceheight 80
-
-feed 45m https://arjunth2001.github.io/kdeblog/feed.xml
-    define_name T.H.Arjun
-    define_face hackergotchi/arjun.jpg
-    define_facewidth 80
-    define_faceheight 80
-
-feed 45m https://ab63.github.io/feed.xml
-    define_name Anuj Bansal
-    define_face hackergotchi/anuj.png
-    define_facewidth 80
-    define_faceheight 80
-
-feed 45m https://shivam8287.github.io/feed.xml
-    define_name Shubham Mishra
-    define_face hackergotchi/Shubham.png
-    define_facewidth 80
-    define_faceheight 80
-
-feed 45m https://politepol.com/fd/KhzJaKPDKtvZ
-	define_name Deepak Kumar (dekumar)
-        define_face hackergotchi/dipak.jpg
-        define_facewidth 80
-        define_faceheight 80
-
-feed 45m https://politepol.com/fd/HZdrGp730QQQ
-	define_name Deepak Kumar (dekumar)
-        define_face hackergotchi/dipak.jpg
-        define_facewidth 80
-        define_faceheight 80
-
diff --git a/planetkde/defconfig b/planetkde/defconfig
deleted file mode 100644
--- a/planetkde/defconfig
+++ /dev/null
@@ -1,246 +0,0 @@
-# Sample rawdog config file. Copy this into your ~/.rawdog/ directory, and edit
-# it to suit your preferences.
-# All paths in this file should be either absolute, or relative to your .rawdog
-# directory.
-# If you want to include another config file, then use "include FILENAME".
-
-# Times in this file are specified as a value and a unit (for instance,
-# "4h").  Units available are "s" (seconds), "m" (minutes), "h" (hours),
-# "d" (days) and "w" (weeks). If no unit is specified, rawdog will
-# assume minutes.
-# Boolean (yes/no) values in this file are specified as "true" or "false".
-
-# rawdog can be extended using plugin modules written in Python. This
-# option specifies the directories to search for plugins to load. If a
-# directory does not exist or cannot be read, it will be ignored.  This
-# option must appear before any options that are implemented by plugins.
-plugindirs plugins
-
-# The maximum number of articles to show on the generated page.
-# Set this to 0 for no limit.
-maxarticles 30
-
-# The maximum age of articles to show on the generated page.
-# Set this to 0 for no limit.
-maxage 0
-
-# The age after which articles will be discarded if they do not appear
-# in a feed. Set this to a larger value if you want your rawdog output
-# to cover more than a day's worth of articles.
-expireage 1d
-
-# The minimum number of articles from each feed to keep around in the history.
-# Set this to 0 to only keep articles that were returned the last time the feed
-# was fetched. (If this is set to 0, or "currentonly" below is set to true,
-# then rawdog will not send the RFC3229+feed "A-IM: feed" header when making
-# HTTP requests, since it can't tell from the response to such a request
-# whether any articles have been removed from the feed; this makes rawdog
-# slightly less bandwidth-efficient.)
-keepmin 3
-
-# Whether to only display articles that are currently included in a feed
-# (useful for "planet" pages where you only want to display the current
-# articles from several feeds). If this is false, rawdog will keep a
-# history of older articles.
-currentonly true
-
-# Whether to divide the articles up by day, writing a "dayformat" heading
-# before each set.
-daysections true
-
-# The format to write day headings in. See "man strftime" for more
-# information; for example:
-# %A, %d %B           Wednesday, 21 January
-# %Y-%m-%d            2004-01-21 (ISO 8601 format)
-dayformat %B %d, %Y
-
-# Whether to divide the articles up by time, writing a "timeformat" heading
-# before each set.
-timesections false
-
-# The format to write time headings in. For example:
-# %H:%M               18:07 (ISO 8601 format)
-# %I:%M %p            06:07 PM
-# timeformat %H:%M
-
-# The format to display feed update and article times in. For example:
-# %H:%M, %A, %d %B    18:07, Wednesday, 21 January
-# %Y-%m-%d %H:%M      2004-01-21 18:07 (ISO 8601 format)
-datetimeformat %H:%M, %A, %d %B
-
-# The template file to use, or "default" to use the built-in template
-# (which is probably sufficient for most users). Use "rawdog -t" to show
-# the template currently in use as a starting-point for customisation.
-# The following strings will be replaced in the output:
-# __version__         The rawdog version in use
-# __refresh__         The HTML 4  header
-# __items__           The aggregated items
-# __num_items__       The number of items on the page
-# __feeds__           The listing of feeds
-# __num_feeds__       The number of feeds listed
-# You can define additional strings using "define" in this config file; for
-# example, if you say "define myname Adam Sampson", then "__myname__" will be
-# replaced by "Adam Sampson" in the output.
-template planet_template
-
-# Similarly, the template used for each item shown. Use "rawdog -T" to
-# show the template currently in use as a starting-point for
-# customisation. The following strings will be replaced in the output:
-# __title__           The item title (as an HTML link, if possible)
-# __title_no_link__   The item title (as text)
-# __url__             The item's URL, or the empty string if it doesn't
-#                     have one
-# __guid__            The item's GUID, or the empty string if it doesn't
-#                     have one
-# __description__     The item's descriptive text, or the empty string
-#                     if it doesn't have a description
-# __date__            The item's date as provided by the feed
-# __added__           The date the article was received by rawdog
-# __hash__            A hash of the article (useful for summary pages)
-# __feed_title__      The feed title (as an HTML link, if possible)
-# __feed_title_no_link__
-#                     The feed title (as text)
-# __feed_url__        The feed URL
-# __feed_hash__       A hash of the feed URL (useful for per-feed styles)
-# __feed_id__         The feed's title with non-alphanumeric characters
-#                     (and HTML markup) removed (useful for per-feed
-#                     styles); you can use the "id" feed option below to
-#                     set a custom ID if you prefer
-# You can define additional strings on a per-feed basis by using the
-# "define_X" feed option; see the description of "feed" below for more
-# details.
-# Simple conditional expansion is possible by saying something like
-# "__if_items__ hello __endif__"; the text between the if and endif will
-# only be included if __items__ would expand to something other than
-# the empty string. Ifs can be nested, and __else__ is supported. (This also
-# works for the "template" option, but it's more useful for item
-# templates.)
-itemtemplate itemplate
-
-# Where to write the output HTML to. You should place style.css in the same
-# directory. Specify this as "-" to write the HTML to stdout.
-# (You will probably want to make this an absolute path, else rawdog will write
-# to a file in your ~/.rawdog directory.)
-#outputfile output.html
-outputfile /home/clee/public_html/rawdog.html
-
-# Whether to use a  tag in the generated
-# HTML to indicate that the page should be refreshed automatically. If
-# this is turned on, then the page will refresh every N minutes, where N
-# is the shortest feed period value specified below.
-# (This works by controlling whether the default template includes
-# __refresh__; if you use a custom template, __refresh__ is always
-# available.)
-userefresh true
-
-# Whether to show the list of active feeds in the generated HTML.
-# (This works by controlling whether the default template includes
-# __feeds__; if you use a custom template, __feeds__ is always
-# available.)
-showfeeds true
-
-# The number of concurrent threads that rawdog will use when fetching
-# feeds -- i.e. the number of feeds that rawdog will attempt to fetch at
-# the same time.  If you have a lot of feeds, setting this to be 20 or
-# so will significantly speed up updates. If this is set to 0, rawdog
-# will not use threads at all.
-numthreads 24
-
-# The time that rawdog will wait before considering a feed unreachable
-# when trying to connect. If you're getting lots of timeout errors and
-# are on a slow connection, increase this.
-# (Unlike other times in this file, this will be assumed to be in
-# seconds if no unit is specified.)
-timeout 30s
-
-# Whether to ignore timeouts. If this is false, timeouts will be reported as
-# errors; if this is true, rawdog will silently ignore them.
-ignoretimeouts false
-
-# Whether to display verbose status messages saying what rawdog's doing
-# while it runs. Specifying -v or --verbose on the command line is
-# equivalent to saying "verbose true" here.
-verbose false
-
-# Whether to attempt to fix bits of HTML that should start with a
-# block-level element (such as article descriptions) by prepending "

" -# if they don't already start with a block-level element. -blocklevelhtml true - -# Whether to attempt to turn feed-provided HTML into valid HTML. -# The most common problem that this solves is a non-closed element in an -# article causing formatting problems for the rest of the page. -# If this option is turned on, you must have the mx.Tidy Python module -# installed. -tidyhtml false - -# Whether the articles displayed should be sorted first by the date -# provided in the feed (useful for "planet" pages, where you're -# displaying several feeds and want new articles to appear in the right -# chronological place). If this is false, then articles will first be -# sorted by the time that rawdog first saw them. -sortbyfeeddate true - -# The fields to use when detecting duplicate articles: "id" is the article's -# unique ID or GUID; "link" is the article's link. rawdog will find the first -# one of these that's present in the article, and ignore the article if it's -# seen an article before (in any feed) that had the same value. For example, -# specifying "hideduplicates id link" will first look for id/guid, then for -# link. -# Note that some feeds use the same link for all their articles; if you specify -# "link" here, you will probably want to specify the "allowduplicates" feed -# argument (see below) for those feeds. -hideduplicates id - -# The period to use for new feeds added to the config file via the -a|--add -# option. -newfeedperiod 3h - -# Whether rawdog should automatically update this config file (and its -# internal state) if feed URLs change (for instance, if a feed URL -# results in a permanent HTTP redirect). If this is false, then rawdog -# will ask you to make the necessary change by hand. -changeconfig true - -# The feeds you want to watch, in the format "feed period url [args]". -# The period is the minimum time between updates; if less than period -# minutes have passed, "rawdog update" will skip that feed. Specifying -# a period less than 30 minutes is considered to be bad manners; it is -# suggested that you make the period as long as possible. -# Arguments are optional, and can be given in two ways: either on the end of -# the "feed" line in the form "key=value", separated by spaces, or as extra -# indented lines after the feed line. -# possible arguments are: -# id Value for the __feed_id__ value in the item -# template for items in this feed (defaults to the -# feed title with non-alphanumeric characters and -# HTML markup removed) -# user User for HTTP basic authentication -# password Password for HTTP basic authentication -# format "text" to indicate that the descriptions in this feed -# are unescaped plain text (rather than the usual HTML), -# and should be escaped and wrapped in a

 element
-# X_proxy             Proxy URL for protocol X (for instance, "http_proxy")
-# proxyuser           User for proxy basic authentication
-# proxypassword       Password for proxy basic authentication
-# allowduplicates     "true" to disable duplicate detection for this feed
-# maxage              Override the global "maxage" value for this feed
-# keepmin             Override the global "keepmin" value for this feed
-# define_X            Equivalent to "define X ..." for item templates
-#                     when displaying items from this feed
-# You can provide a default set of arguments for all feeds using
-# "feeddefaults". You can specify as many feeds as you like.
-# (These examples have been commented out; remove the leading "#" on each line
-# to use them.)
-#feeddefaults
-#	http_proxy http://proxy.example.com:3128/
-#feed 1h http://example.com/feed.rss
-#feed 30m http://example.com/feed2.rss id=newsfront
-#feed 3h http://example.com/feed3.rss keepmin=5
-#feed 3h http://example.com/secret.rss user=bob password=secret
-#feed 3h http://example.com/broken.rss
-#	format text
-#	define_myclass broken
-#feed 3h http://proxyfeed.example.com/proxied.rss http_proxy=http://localhost:1234/
-#feed 3h http://dupsfeed.example.com/duplicated.rss allowduplicates=true
-
diff --git a/planetkde/itemplate b/planetkde/itemplate
deleted file mode 100644
--- a/planetkde/itemplate
+++ /dev/null
@@ -1,26 +0,0 @@
-
-
-
-
- __if_face__ - __else__ - __endif__ -
- -
-
- __description__ -
-
diff --git a/planetkde/microblogitemtemplate b/planetkde/microblogitemtemplate deleted file mode 100644 --- a/planetkde/microblogitemtemplate +++ /dev/null @@ -1,2 +0,0 @@ - - diff --git a/planetkde/planet_template b/planetkde/planet_template deleted file mode 100644 --- a/planetkde/planet_template +++ /dev/null @@ -1,350 +0,0 @@ - - - - - - - - - Planet KDE - - - - - - - - - - - - - - - - - - - - - - - -
- -
- -
-
-
- __items__ -
-
- -

 

- - -
-
-
- -
-

Planet KDE is made from the blogs of KDE's contributors. The opinions it contains are those of the contributor. This site is powered by Rawdog and Rawdog RSS. Feed readers can read Planet KDE with RSS, FOAF or OPML.

-
- - - - - - - - - - - diff --git a/planetkde/plugins/rss.py b/planetkde/plugins/rss.py deleted file mode 100644 --- a/planetkde/plugins/rss.py +++ /dev/null @@ -1,241 +0,0 @@ -# -*- coding: utf-8 -*- -# -# rawdog plugin to generate RSS, OPML and FOAF output -# Copyright 2008 Jonathan Riddell -# Copyright 2009 Adam Sampson -# Copyright 2009 Kurt McKee -# -# rawdog_rss is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. -# -# rawdog_rss is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License along -# with rawdog_rss; if not, write to the Free Software Foundation, Inc., -# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -# You can also visit http://www.gnu.org/ . -# -# --- -# -# This plugin supports the following configuration options: -# -# outputxml RSS output filename -# outputfoaf FOAF output filename -# outputopml OPML output filename -# xmltitle Feed title (e.g. "Planet Foo") -# xmllink Feed link (e.g. "http://planet-foo.example.com/") -# xmllanguage Feed language (e.g. "en") -# xmlurl URL of the generated RSS (e.g. "http://planet-foo.example.com/rss20.xml") -# xmldescription Feed description (e.g. "People who work on foo") -# xmlownername Feed owner's name -# xmlowneremail Feed owner's email address -# xmlmaxarticles Maximum number of articles to include in the feed -# (defaults to maxarticles if not specified) -# -# If you're using rawdog to produce a planet page, you'll probably want to have -# "sortbyfeeddate true" in your config file too. - -import os, time, cgi -import htmlentitydefs -import rawdoglib.plugins, rawdoglib.rawdog -import libxml2 - -from rawdoglib.rawdog import detail_to_html, string_to_html -from time import gmtime, strftime -from xml.sax.saxutils import escape, unescape - -# Prepare dictionary of conversions for unescape(). -# These conversions allow people to use HTML character entities such as -# á in define_name if they don't know how to input Unicode characters. -# HACK: The unicode characters currently must be re-encoded as utf-8. -htmlchars = {} -for k, v in htmlentitydefs.name2codepoint.items(): - htmlchars['&%s;' % k] = unichr(v).encode('utf8') - -def rfc822_date(tm): - """Format a GMT timestamp as returned by time.gmtime() in RFC822 format. - (This is insensitive to the current locale.)""" - days = ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"] - months = [ - "Jan", "Feb", "Mar", "Apr", "May", "Jun", - "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", - ] - return "%s, %02d %s %04d %02d:%02d:%02d GMT" % \ - (days[tm[6]], tm[2], months[tm[1] - 1], tm[0], tm[3], tm[4], tm[5]) - -class RSS_Feed: - def __init__(self): - self.options = { - "outputxml": "rss20.xml", - "outputfoaf": "foafroll.xml", - "outputopml": "opml.xml", - "xmltitle": "Planet KDE", - "xmllink": "http://planetKDE.org/", - "xmllanguage": "en", - "xmlurl": "http://planetKDE.org/rss20.xml", - "xmldescription": "Planet KDE - http://planetKDE.org/", - "xmlownername": "Jonathan Riddell", - "xmlowneremail": "", - "xmlmaxarticles": "", - } - - def config_option(self, config, name, value): - if name in self.options: - self.options[name] = value - return False - else: - return True - - def feed_name(self, feed, config): - """Return the label used for a feed. If it has a "name" define, use - that; otherwise, use the feed title.""" - - if "define_name" in feed.args: - return unescape(feed.args["define_name"], htmlchars) - else: - return feed.get_html_name(config) - - def article_to_xml(self, xml_article, rawdog, config, article): - entry_info = article.entry_info - - id = entry_info.get("id", self.options["xmlurl"] + "#id" + article.hash) - guid = xml_article.newChild(None, 'guid', string_to_html(id, config)) - guid.setProp('isPermaLink', 'false') - - title = escape(self.feed_name(rawdog.feeds[article.feed], config)) - s = detail_to_html(entry_info.get("title_detail"), True, config) - if s is not None: - title = s.encode('utf8') - xml_article.newChild(None, 'title', title) - - author = escape(self.feed_name(rawdog.feeds[article.feed], config)) - xml_article.newChild(None, 'author', author) - - if article.date is not None: - date = rfc822_date(gmtime(article.date)) - xml_article.newChild(None, 'pubDate', date) - - s = entry_info.get("link") - if s is not None and s != "": - xml_article.newChild(None, 'link', string_to_html(s, config)) - - for key in ["content", "summary_detail"]: - s = detail_to_html(entry_info.get(key), False, config) - if s is not None: - xml_article.newChild(None, 'description', escape(s)) - break - - return True - - def write_rss(self, rawdog, config, articles): - doc = libxml2.newDoc("1.0") - - rss = doc.newChild(None, 'rss', None) - rss.setProp('version', "2.0") - rss.setProp('xmlns:dc', "http://purl.org/dc/elements/1.1/") - rss.setProp('xmlns:atom', 'http://www.w3.org/2005/Atom') - - channel = rss.newChild(None, 'channel', None) - channel.newChild(None, 'title', escape(self.options["xmltitle"])) - channel.newChild(None, 'link', escape(self.options["xmllink"])) - channel.newChild(None, 'language', escape(self.options["xmllanguage"])) - channel.newChild(None, 'description', escape(self.options["xmldescription"])) - - atom_link = channel.newChild(None, 'atom:link', None) - atom_link.setProp('href', self.options["xmlurl"]) - atom_link.setProp('rel', 'self') - atom_link.setProp('type', 'application/rss+xml') - - try: - maxarticles = int(self.options["xmlmaxarticles"]) - except ValueError: - maxarticles = len(articles) - for article in articles[:maxarticles]: - #Planet KDE addition, don't include articles in a feedclass - feed = rawdog.feeds[article.feed] - itembits = {} - toAdd = True; - for name, value in feed.args.items(): - if name.startswith("define_"): - itembits[name[7:]] = value - if "feedclass" in itembits: - toAdd = False - #ervin thinks we should have project news in the feed - if itembits["feedclass"] == "news": - toAdd = True - - if toAdd: - xml_article = channel.newChild(None, 'item', None) - self.article_to_xml(xml_article, rawdog, config, article) - - doc.saveFormatFile(self.options["outputxml"], 1) - doc.freeDoc() - - def write_foaf(self, rawdog, config): - doc = libxml2.newDoc("1.0") - - xml = doc.newChild(None, 'rdf:RDF', None) - xml.setProp('xmlns:rdf', "http://www.w3.org/1999/02/22-rdf-syntax-ns#") - xml.setProp('xmlns:rdfs', "http://www.w3.org/2000/01/rdf-schema#") - xml.setProp('xmlns:foaf', "http://xmlns.com/foaf/0.1/") - xml.setProp('xmlns:rss', "http://purl.org/rss/1.0/") - xml.setProp('xmlns:dc', "http://purl.org/dc/elements/1.1/") - - group = xml.newChild(None, 'foaf:Group', None) - group.newChild(None, 'foaf:name', escape(self.options["xmltitle"])) - group.newChild(None, 'foaf:homepage', escape(self.options["xmllink"])) - - for url in sorted(rawdog.feeds.keys()): - member = group.newChild(None, 'foaf:member', None) - - agent = member.newChild(None, 'foaf:Agent', None) - agent.newChild(None, 'foaf:name', escape(self.feed_name(rawdog.feeds[url], config))) - weblog = agent.newChild(None, 'foaf:weblog', None) - document = weblog.newChild(None, 'foaf:Document', None) - if rawdog.feeds[url].feed_info.get('link', ''): - document.setProp('rdf:about', rawdog.feeds[url].feed_info['link']) - seealso = document.newChild(None, 'rdfs:seeAlso', None) - channel = seealso.newChild(None, 'rss:channel', None) - channel.setProp('rdf:about', url) - - doc.saveFormatFile(self.options["outputfoaf"], 1) - doc.freeDoc() - - def write_opml(self, rawdog, config): - doc = libxml2.newDoc("1.0") - - xml = doc.newChild(None, 'opml', None) - xml.setProp('version', "2.0") - - head = xml.newChild(None, 'head', None) - head.newChild(None, 'title', escape(self.options["xmltitle"])) - now = rfc822_date(gmtime()) - head.newChild(None, 'dateCreated', escape(now)) - head.newChild(None, 'dateModified', escape(now)) - head.newChild(None, 'ownerName', escape(self.options["xmlownername"])) - head.newChild(None, 'ownerEmail', escape(self.options["xmlowneremail"])) - - body = xml.newChild(None, 'body', None) - for url in sorted(rawdog.feeds.keys()): - outline = body.newChild(None, 'outline', None) - outline.setProp('text', self.feed_name(rawdog.feeds[url], config)) - outline.setProp('xmlUrl', url) - - doc.saveFormatFile(self.options["outputopml"], 1) - doc.freeDoc() - - def output_write(self, rawdog, config, articles): - self.write_rss(rawdog, config, articles) - self.write_foaf(rawdog, config) - self.write_opml(rawdog, config) - - return True - -rss_feed = RSS_Feed() -rawdoglib.plugins.attach_hook("config_option", rss_feed.config_option) -rawdoglib.plugins.attach_hook("output_write", rss_feed.output_write) diff --git a/rawdog b/rawdog deleted file mode 100755 --- a/rawdog +++ /dev/null @@ -1,32 +0,0 @@ -#!/usr/bin/env python -# rawdog: RSS aggregator without delusions of grandeur. -# Copyright 2003, 2004, 2005, 2006 Adam Sampson -# -# rawdog is free software; you can redistribute and/or modify it -# under the terms of that license as published by the Free Software -# Foundation; either version 2 of the License, or (at your option) -# any later version. -# -# rawdog is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with rawdog; see the file COPYING. If not, write to the Free -# Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, -# MA 02110-1301, USA, or see http://www.gnu.org/. - -from rawdoglib.rawdog import main -import sys, os - -def launch(): - sys.exit(main(sys.argv[1:])) - -if __name__ == "__main__": - if os.getenv("RAWDOG_PROFILE") is not None: - import profile - profile.run("launch()") - else: - launch() - diff --git a/rawdoglib/__init__.py b/rawdoglib/__init__.py deleted file mode 100644 --- a/rawdoglib/__init__.py +++ /dev/null @@ -1 +0,0 @@ -__all__ = ['feedparser', 'feedfinder', 'timeoutsocket', 'rawdog', 'persister', 'upgrade_1_2'] diff --git a/rawdoglib/feedfinder.py b/rawdoglib/feedfinder.py deleted file mode 100644 --- a/rawdoglib/feedfinder.py +++ /dev/null @@ -1,366 +0,0 @@ -"""feedfinder: Find the Web feed for a Web page -http://www.aaronsw.com/2002/feedfinder/ - -Usage: - feed(uri) - returns feed found for a URI - feeds(uri) - returns all feeds found for a URI - - >>> import feedfinder - >>> feedfinder.feed('scripting.com') - 'http://scripting.com/rss.xml' - >>> - >>> feedfinder.feeds('scripting.com') - ['http://delong.typepad.com/sdj/atom.xml', - 'http://delong.typepad.com/sdj/index.rdf', - 'http://delong.typepad.com/sdj/rss.xml'] - >>> - -Can also use from the command line. Feeds are returned one per line: - - $ python feedfinder.py diveintomark.org - http://diveintomark.org/xml/atom.xml - -How it works: - 0. At every step, feeds are minimally verified to make sure they are really feeds. - 1. If the URI points to a feed, it is simply returned; otherwise - the page is downloaded and the real fun begins. - 2. Feeds pointed to by LINK tags in the header of the page (autodiscovery) - 3. links to feeds on the same server ending in ".rss", ".rdf", ".xml", or - ".atom" - 4. links to feeds on the same server containing "rss", "rdf", "xml", or "atom" - 5. links to feeds on external servers ending in ".rss", ".rdf", ".xml", or - ".atom" - 6. links to feeds on external servers containing "rss", "rdf", "xml", or "atom" - 7. Try some guesses about common places for feeds (index.xml, atom.xml, etc.). - 8. As a last ditch effort, we search Syndic8 for feeds matching the URI -""" - -__version__ = "1.371" -__date__ = "2006-04-24" -__maintainer__ = "Aaron Swartz (me@aaronsw.com)" -__author__ = "Mark Pilgrim (http://diveintomark.org)" -__copyright__ = "Copyright 2002-4, Mark Pilgrim; 2006 Aaron Swartz" -__license__ = "Python" -__credits__ = """Abe Fettig for a patch to sort Syndic8 feeds by popularity -Also Jason Diamond, Brian Lalor for bug reporting and patches""" - -_debug = 0 - -import sgmllib, urllib, urlparse, re, sys, robotparser - -import threading -class TimeoutError(Exception): pass -def timelimit(timeout): - """borrowed from web.py""" - def _1(function): - def _2(*args, **kw): - class Dispatch(threading.Thread): - def __init__(self): - threading.Thread.__init__(self) - self.result = None - self.error = None - - self.setDaemon(True) - self.start() - - def run(self): - try: - self.result = function(*args, **kw) - except: - self.error = sys.exc_info() - - c = Dispatch() - c.join(timeout) - if c.isAlive(): - raise TimeoutError, 'took too long' - if c.error: - raise c.error[0], c.error[1] - return c.result - return _2 - return _1 - -# XML-RPC support allows feedfinder to query Syndic8 for possible matches. -# Python 2.3 now comes with this module by default, otherwise you can download it -try: - import xmlrpclib # http://www.pythonware.com/products/xmlrpc/ -except ImportError: - xmlrpclib = None - -if not dict: - def dict(aList): - rc = {} - for k, v in aList: - rc[k] = v - return rc - -def _debuglog(message): - if _debug: print message - -class URLGatekeeper: - """a class to track robots.txt rules across multiple servers""" - def __init__(self): - self.rpcache = {} # a dictionary of RobotFileParser objects, by domain - self.urlopener = urllib.FancyURLopener() - self.urlopener.version = "feedfinder/" + __version__ + " " + self.urlopener.version + " +http://www.aaronsw.com/2002/feedfinder/" - _debuglog(self.urlopener.version) - self.urlopener.addheaders = [('User-agent', self.urlopener.version)] - robotparser.URLopener.version = self.urlopener.version - robotparser.URLopener.addheaders = self.urlopener.addheaders - - def _getrp(self, url): - protocol, domain = urlparse.urlparse(url)[:2] - if self.rpcache.has_key(domain): - return self.rpcache[domain] - baseurl = '%s://%s' % (protocol, domain) - robotsurl = urlparse.urljoin(baseurl, 'robots.txt') - _debuglog('fetching %s' % robotsurl) - rp = robotparser.RobotFileParser(robotsurl) - try: - rp.read() - except: - pass - self.rpcache[domain] = rp - return rp - - def can_fetch(self, url): - rp = self._getrp(url) - allow = rp.can_fetch(self.urlopener.version, url) - _debuglog("gatekeeper of %s says %s" % (url, allow)) - return allow - - @timelimit(10) - def get(self, url, check=True): - if check and not self.can_fetch(url): return '' - try: - return self.urlopener.open(url).read() - except: - return '' - -_gatekeeper = URLGatekeeper() - -class BaseParser(sgmllib.SGMLParser): - def __init__(self, baseuri): - sgmllib.SGMLParser.__init__(self) - self.links = [] - self.baseuri = baseuri - - def normalize_attrs(self, attrs): - def cleanattr(v): - v = sgmllib.charref.sub(lambda m: unichr(int(m.groups()[0])), v) - v = v.strip() - v = v.replace('<', '<').replace('>', '>').replace(''', "'").replace('"', '"').replace('&', '&') - return v - attrs = [(k.lower(), cleanattr(v)) for k, v in attrs] - attrs = [(k, k in ('rel','type') and v.lower() or v) for k, v in attrs] - return attrs - - def do_base(self, attrs): - attrsD = dict(self.normalize_attrs(attrs)) - if not attrsD.has_key('href'): return - self.baseuri = attrsD['href'] - - def error(self, *a, **kw): pass # we're not picky - -class LinkParser(BaseParser): - FEED_TYPES = ('application/rss+xml', - 'text/xml', - 'application/atom+xml', - 'application/x.atom+xml', - 'application/x-atom+xml') - def do_link(self, attrs): - attrsD = dict(self.normalize_attrs(attrs)) - if not attrsD.has_key('rel'): return - rels = attrsD['rel'].split() - if 'alternate' not in rels: return - if attrsD.get('type') not in self.FEED_TYPES: return - if not attrsD.has_key('href'): return - self.links.append(urlparse.urljoin(self.baseuri, attrsD['href'])) - -class ALinkParser(BaseParser): - def start_a(self, attrs): - attrsD = dict(self.normalize_attrs(attrs)) - if not attrsD.has_key('href'): return - self.links.append(urlparse.urljoin(self.baseuri, attrsD['href'])) - -def makeFullURI(uri): - uri = uri.strip() - if uri.startswith('feed://'): - uri = 'http://' + uri.split('feed://', 1).pop() - for x in ['http', 'https']: - if uri.startswith('%s://' % x): - return uri - return 'http://%s' % uri - -def getLinks(data, baseuri): - p = LinkParser(baseuri) - p.feed(data) - return p.links - -def getALinks(data, baseuri): - p = ALinkParser(baseuri) - p.feed(data) - return p.links - -def getLocalLinks(links, baseuri): - baseuri = baseuri.lower() - urilen = len(baseuri) - return [l for l in links if l.lower().startswith(baseuri)] - -def isFeedLink(link): - return link[-4:].lower() in ('.rss', '.rdf', '.xml', '.atom') - -def isXMLRelatedLink(link): - link = link.lower() - return link.count('rss') + link.count('rdf') + link.count('xml') + link.count('atom') - -r_brokenRedirect = re.compile(']*>(.*?)', re.S) -def tryBrokenRedirect(data): - if ' links that point to feeds - _debuglog('no LINK tags, looking at A tags') - try: - links = getALinks(data, fulluri) - except: - links = [] - locallinks = getLocalLinks(links, fulluri) - # look for obvious feed links on the same server - outfeeds.extend(filter(isFeed, filter(isFeedLink, locallinks))) - if all or not outfeeds: - # look harder for feed links on the same server - outfeeds.extend(filter(isFeed, filter(isXMLRelatedLink, locallinks))) - if all or not outfeeds: - # look for obvious feed links on another server - outfeeds.extend(filter(isFeed, filter(isFeedLink, links))) - if all or not outfeeds: - # look harder for feed links on another server - outfeeds.extend(filter(isFeed, filter(isXMLRelatedLink, links))) - if all or not outfeeds: - _debuglog('no A tags, guessing') - suffixes = [ # filenames used by popular software: - 'atom.xml', # blogger, TypePad - 'index.atom', # MT, apparently - 'index.rdf', # MT - 'rss.xml', # Dave Winer/Manila - 'index.xml', # MT - 'index.rss' # Slash - ] - outfeeds.extend(filter(isFeed, [urlparse.urljoin(fulluri, x) for x in suffixes])) - if (all or not outfeeds) and querySyndic8: - # still no luck, search Syndic8 for feeds (requires xmlrpclib) - _debuglog('still no luck, searching Syndic8') - outfeeds.extend(getFeedsFromSyndic8(uri)) - if hasattr(__builtins__, 'set') or __builtins__.has_key('set'): - outfeeds = list(set(outfeeds)) - return outfeeds - -getFeeds = feeds # backwards-compatibility - -def feed(uri): - #todo: give preference to certain feed formats - feedlist = feeds(uri) - if feedlist: - return feedlist[0] - else: - return None - -##### test harness ###### - -def test(): - uri = 'http://diveintomark.org/tests/client/autodiscovery/html4-001.html' - failed = [] - count = 0 - while 1: - data = _gatekeeper.get(uri) - if data.find('Atom autodiscovery test') == -1: break - sys.stdout.write('.') - sys.stdout.flush() - count += 1 - links = getLinks(data, uri) - if not links: - print '\n*** FAILED ***', uri, 'could not find link' - failed.append(uri) - elif len(links) > 1: - print '\n*** FAILED ***', uri, 'found too many links' - failed.append(uri) - else: - atomdata = urllib.urlopen(links[0]).read() - if atomdata.find(' for rawdog: -- provide _raw versions of text content -- handle file: URLs -- fix startElementNS/endElementNS namespace mangling bug -- save the traceback from parser exceptions -- allow auth credentials to be provided as an argument -- make A-IM header in HTTP requests optional - -Handles RSS 0.9x, RSS 1.0, RSS 2.0, CDF, Atom 0.3, and Atom 1.0 feeds - -Visit http://feedparser.org/ for the latest version -Visit http://feedparser.org/docs/ for the latest documentation - -Required: Python 2.1 or later -Recommended: Python 2.3 or later -Recommended: CJKCodecs and iconv_codec -""" - -__version__ = "4.2-pre-" + "$Revision: 291 $"[11:14] + "-svn" -__license__ = """Copyright (c) 2002-2008, Mark Pilgrim, All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: - -* Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. -* Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS' -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE -LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -POSSIBILITY OF SUCH DAMAGE.""" -__author__ = "Mark Pilgrim " -__contributors__ = ["Jason Diamond ", - "John Beimler ", - "Fazal Majid ", - "Aaron Swartz ", - "Kevin Marks ", - "Sam Ruby "] -_debug = 0 - -# HTTP "User-Agent" header to send to servers when downloading feeds. -# If you are embedding feedparser in a larger application, you should -# change this to your application name and URL. -USER_AGENT = "UniversalFeedParser/%s +http://feedparser.org/" % __version__ - -# HTTP "Accept" header to send to servers when downloading feeds. If you don't -# want to send an Accept header, set this to None. -ACCEPT_HEADER = "application/atom+xml,application/rdf+xml,application/rss+xml,application/x-netcdf,application/xml;q=0.9,text/xml;q=0.2,*/*;q=0.1" - -# List of preferred XML parsers, by SAX driver name. These will be tried first, -# but if they're not installed, Python will keep searching through its own list -# of pre-installed parsers until it finds one that supports everything we need. -PREFERRED_XML_PARSERS = ["drv_libxml2"] - -# If you want feedparser to automatically run HTML markup through HTML Tidy, set -# this to 1. Requires mxTidy -# or utidylib . -TIDY_MARKUP = 0 - -# List of Python interfaces for HTML Tidy, in order of preference. Only useful -# if TIDY_MARKUP = 1 -PREFERRED_TIDY_INTERFACES = ["uTidy", "mxTidy"] - -# If you want feedparser to automatically resolve all relative URIs, set this -# to 1. -RESOLVE_RELATIVE_URIS = 1 - -# If you want feedparser to automatically sanitize all potentially unsafe -# HTML content, set this to 1. -SANITIZE_HTML = 1 - -# ---------- required modules (should come with any Python distribution) ---------- -import sgmllib, re, sys, copy, urlparse, time, rfc822, types, cgi -try: - from cStringIO import StringIO as _StringIO -except: - from StringIO import StringIO as _StringIO - -# ---------- optional modules (feedparser will work without these, but with reduced functionality) ---------- - -# gzip is included with most Python distributions, but may not be available if you compiled your own -try: - import gzip -except: - gzip = None -try: - import zlib -except: - zlib = None - -# timeoutsocket allows feedparser to time out rather than hang forever on ultra-slow servers. -# Python 2.3 now has this functionality available in the standard socket library, so under -# 2.3 or later you don't need to install anything. In fact, under Python 2.4, timeoutsocket -# write all sorts of crazy errors to stderr while running my unit tests, so it's probably -# outlived its usefulness. -import socket -if hasattr(socket, 'setdefaulttimeout'): - socket.setdefaulttimeout(20) -else: - try: - import timeoutsocket # http://www.timo-tasi.org/python/timeoutsocket.py - timeoutsocket.setDefaultSocketTimeout(20) - except ImportError: - pass -import urllib, urllib2 - -# If a real XML parser is available, feedparser will attempt to use it. feedparser has -# been tested with the built-in SAX parser, PyXML, and libxml2. On platforms where the -# Python distribution does not come with an XML parser (such as Mac OS X 10.2 and some -# versions of FreeBSD), feedparser will quietly fall back on regex-based parsing. -try: - import xml.sax - xml.sax.make_parser(PREFERRED_XML_PARSERS) # test for valid parsers - from xml.sax.saxutils import escape as _xmlescape - _XML_AVAILABLE = 1 -except: - _XML_AVAILABLE = 0 - def _xmlescape(data,entities={}): - data = data.replace('&', '&') - data = data.replace('>', '>') - data = data.replace('<', '<') - for char, entity in entities: - data = data.replace(char, entity) - return data - -# base64 support for Atom feeds that contain embedded binary data -try: - import base64, binascii -except: - base64 = binascii = None - -# cjkcodecs and iconv_codec provide support for more character encodings. -# Both are available from http://cjkpython.i18n.org/ -try: - import cjkcodecs.aliases -except: - pass -try: - import iconv_codec -except: - pass - -# chardet library auto-detects character encodings -# Download from http://chardet.feedparser.org/ -try: - import chardet - if _debug: - import chardet.constants - chardet.constants._debug = 1 -except: - chardet = None - -# reversable htmlentitydefs mappings for Python 2.2 -try: - from htmlentitydefs import name2codepoint, codepoint2name -except: - import htmlentitydefs - name2codepoint={} - codepoint2name={} - for (name,codepoint) in htmlentitydefs.entitydefs.iteritems(): - if codepoint.startswith('&#'): codepoint=unichr(int(codepoint[2:-1])) - name2codepoint[name]=ord(codepoint) - codepoint2name[ord(codepoint)]=name - -# BeautifulSoup parser used for parsing microformats from embedded HTML content -# http://www.crummy.com/software/BeautifulSoup/ -# feedparser is tested with BeautifulSoup 3.0.x, but it might work with the -# older 2.x series. If it doesn't, and you can figure out why, I'll accept a -# patch and modify the compatibility statement accordingly. -try: - import BeautifulSoup -except: - BeautifulSoup = None - -# ---------- don't touch these ---------- -class ThingsNobodyCaresAboutButMe(Exception): pass -class CharacterEncodingOverride(ThingsNobodyCaresAboutButMe): pass -class CharacterEncodingUnknown(ThingsNobodyCaresAboutButMe): pass -class NonXMLContentType(ThingsNobodyCaresAboutButMe): pass -class UndeclaredNamespace(Exception): pass - -sgmllib.tagfind = re.compile('[a-zA-Z][-_.:a-zA-Z0-9]*') -sgmllib.special = re.compile(']|"[^"]*"(?=>|/|\s|\w+=)|'[^']*'(?=>|/|\s|\w+=))*(?=[<>])|.*?(?=[<>])''') - def search(self,string,index=0): - self.match = self.endbracket.match(string,index) - if self.match: return self - def start(self,n): - return self.match.end(n) - sgmllib.endbracket = EndBracketMatch() - -SUPPORTED_VERSIONS = {'': 'unknown', - 'rss090': 'RSS 0.90', - 'rss091n': 'RSS 0.91 (Netscape)', - 'rss091u': 'RSS 0.91 (Userland)', - 'rss092': 'RSS 0.92', - 'rss093': 'RSS 0.93', - 'rss094': 'RSS 0.94', - 'rss20': 'RSS 2.0', - 'rss10': 'RSS 1.0', - 'rss': 'RSS (unknown version)', - 'atom01': 'Atom 0.1', - 'atom02': 'Atom 0.2', - 'atom03': 'Atom 0.3', - 'atom10': 'Atom 1.0', - 'atom': 'Atom (unknown version)', - 'cdf': 'CDF', - 'hotrss': 'Hot RSS' - } - -try: - UserDict = dict -except NameError: - # Python 2.1 does not have dict - from UserDict import UserDict - def dict(aList): - rc = {} - for k, v in aList: - rc[k] = v - return rc - -class FeedParserDict(UserDict): - keymap = {'channel': 'feed', - 'items': 'entries', - 'guid': 'id', - 'date': 'updated', - 'date_parsed': 'updated_parsed', - 'description': ['subtitle', 'summary'], - 'url': ['href'], - 'modified': 'updated', - 'modified_parsed': 'updated_parsed', - 'issued': 'published', - 'issued_parsed': 'published_parsed', - 'copyright': 'rights', - 'copyright_detail': 'rights_detail', - 'tagline': 'subtitle', - 'tagline_detail': 'subtitle_detail'} - def __getitem__(self, key): - if key == 'category': - return UserDict.__getitem__(self, 'tags')[0]['term'] - if key == 'enclosures': - norel = lambda link: FeedParserDict([(name,value) for (name,value) in link.items() if name!='rel']) - return [norel(link) for link in UserDict.__getitem__(self, 'links') if link['rel']=='enclosure'] - if key == 'license': - for link in UserDict.__getitem__(self, 'links'): - if link['rel']=='license' and link.has_key('href'): - return link['href'] - if key == 'categories': - return [(tag['scheme'], tag['term']) for tag in UserDict.__getitem__(self, 'tags')] - realkey = self.keymap.get(key, key) - if type(realkey) == types.ListType: - for k in realkey: - if UserDict.has_key(self, k): - return UserDict.__getitem__(self, k) - if UserDict.has_key(self, key): - return UserDict.__getitem__(self, key) - return UserDict.__getitem__(self, realkey) - - def __setitem__(self, key, value): - for k in self.keymap.keys(): - if key == k: - key = self.keymap[k] - if type(key) == types.ListType: - key = key[0] - return UserDict.__setitem__(self, key, value) - - def get(self, key, default=None): - if self.has_key(key): - return self[key] - else: - return default - - def setdefault(self, key, value): - if not self.has_key(key): - self[key] = value - return self[key] - - def has_key(self, key): - try: - return hasattr(self, key) or UserDict.has_key(self, key) - except AttributeError: - return False - - def __getattr__(self, key): - try: - return self.__dict__[key] - except KeyError: - pass - try: - assert not key.startswith('_') - return self.__getitem__(key) - except: - raise AttributeError, "object has no attribute '%s'" % key - - def __setattr__(self, key, value): - if key.startswith('_') or key == 'data': - self.__dict__[key] = value - else: - return self.__setitem__(key, value) - - def __contains__(self, key): - return self.has_key(key) - -def zopeCompatibilityHack(): - global FeedParserDict - del FeedParserDict - def FeedParserDict(aDict=None): - rc = {} - if aDict: - rc.update(aDict) - return rc - -_ebcdic_to_ascii_map = None -def _ebcdic_to_ascii(s): - global _ebcdic_to_ascii_map - if not _ebcdic_to_ascii_map: - emap = ( - 0,1,2,3,156,9,134,127,151,141,142,11,12,13,14,15, - 16,17,18,19,157,133,8,135,24,25,146,143,28,29,30,31, - 128,129,130,131,132,10,23,27,136,137,138,139,140,5,6,7, - 144,145,22,147,148,149,150,4,152,153,154,155,20,21,158,26, - 32,160,161,162,163,164,165,166,167,168,91,46,60,40,43,33, - 38,169,170,171,172,173,174,175,176,177,93,36,42,41,59,94, - 45,47,178,179,180,181,182,183,184,185,124,44,37,95,62,63, - 186,187,188,189,190,191,192,193,194,96,58,35,64,39,61,34, - 195,97,98,99,100,101,102,103,104,105,196,197,198,199,200,201, - 202,106,107,108,109,110,111,112,113,114,203,204,205,206,207,208, - 209,126,115,116,117,118,119,120,121,122,210,211,212,213,214,215, - 216,217,218,219,220,221,222,223,224,225,226,227,228,229,230,231, - 123,65,66,67,68,69,70,71,72,73,232,233,234,235,236,237, - 125,74,75,76,77,78,79,80,81,82,238,239,240,241,242,243, - 92,159,83,84,85,86,87,88,89,90,244,245,246,247,248,249, - 48,49,50,51,52,53,54,55,56,57,250,251,252,253,254,255 - ) - import string - _ebcdic_to_ascii_map = string.maketrans( \ - ''.join(map(chr, range(256))), ''.join(map(chr, emap))) - return s.translate(_ebcdic_to_ascii_map) - -_cp1252 = { - unichr(128): unichr(8364), # euro sign - unichr(130): unichr(8218), # single low-9 quotation mark - unichr(131): unichr( 402), # latin small letter f with hook - unichr(132): unichr(8222), # double low-9 quotation mark - unichr(133): unichr(8230), # horizontal ellipsis - unichr(134): unichr(8224), # dagger - unichr(135): unichr(8225), # double dagger - unichr(136): unichr( 710), # modifier letter circumflex accent - unichr(137): unichr(8240), # per mille sign - unichr(138): unichr( 352), # latin capital letter s with caron - unichr(139): unichr(8249), # single left-pointing angle quotation mark - unichr(140): unichr( 338), # latin capital ligature oe - unichr(142): unichr( 381), # latin capital letter z with caron - unichr(145): unichr(8216), # left single quotation mark - unichr(146): unichr(8217), # right single quotation mark - unichr(147): unichr(8220), # left double quotation mark - unichr(148): unichr(8221), # right double quotation mark - unichr(149): unichr(8226), # bullet - unichr(150): unichr(8211), # en dash - unichr(151): unichr(8212), # em dash - unichr(152): unichr( 732), # small tilde - unichr(153): unichr(8482), # trade mark sign - unichr(154): unichr( 353), # latin small letter s with caron - unichr(155): unichr(8250), # single right-pointing angle quotation mark - unichr(156): unichr( 339), # latin small ligature oe - unichr(158): unichr( 382), # latin small letter z with caron - unichr(159): unichr( 376)} # latin capital letter y with diaeresis - -_urifixer = re.compile('^([A-Za-z][A-Za-z0-9+-.]*://)(/*)(.*?)') -def _urljoin(base, uri): - uri = _urifixer.sub(r'\1\3', uri) - try: - return urlparse.urljoin(base, uri) - except: - uri = urlparse.urlunparse([urllib.quote(part) for part in urlparse.urlparse(uri)]) - return urlparse.urljoin(base, uri) - -class _FeedParserMixin: - namespaces = {'': '', - 'http://backend.userland.com/rss': '', - 'http://blogs.law.harvard.edu/tech/rss': '', - 'http://purl.org/rss/1.0/': '', - 'http://my.netscape.com/rdf/simple/0.9/': '', - 'http://example.com/newformat#': '', - 'http://example.com/necho': '', - 'http://purl.org/echo/': '', - 'uri/of/echo/namespace#': '', - 'http://purl.org/pie/': '', - 'http://purl.org/atom/ns#': '', - 'http://www.w3.org/2005/Atom': '', - 'http://purl.org/rss/1.0/modules/rss091#': '', - - 'http://webns.net/mvcb/': 'admin', - 'http://purl.org/rss/1.0/modules/aggregation/': 'ag', - 'http://purl.org/rss/1.0/modules/annotate/': 'annotate', - 'http://media.tangent.org/rss/1.0/': 'audio', - 'http://backend.userland.com/blogChannelModule': 'blogChannel', - 'http://web.resource.org/cc/': 'cc', - 'http://backend.userland.com/creativeCommonsRssModule': 'creativeCommons', - 'http://purl.org/rss/1.0/modules/company': 'co', - 'http://purl.org/rss/1.0/modules/content/': 'content', - 'http://my.theinfo.org/changed/1.0/rss/': 'cp', - 'http://purl.org/dc/elements/1.1/': 'dc', - 'http://purl.org/dc/terms/': 'dcterms', - 'http://purl.org/rss/1.0/modules/email/': 'email', - 'http://purl.org/rss/1.0/modules/event/': 'ev', - 'http://rssnamespace.org/feedburner/ext/1.0': 'feedburner', - 'http://freshmeat.net/rss/fm/': 'fm', - 'http://xmlns.com/foaf/0.1/': 'foaf', - 'http://www.w3.org/2003/01/geo/wgs84_pos#': 'geo', - 'http://postneo.com/icbm/': 'icbm', - 'http://purl.org/rss/1.0/modules/image/': 'image', - 'http://www.itunes.com/DTDs/PodCast-1.0.dtd': 'itunes', - 'http://example.com/DTDs/PodCast-1.0.dtd': 'itunes', - 'http://purl.org/rss/1.0/modules/link/': 'l', - 'http://search.yahoo.com/mrss': 'media', - 'http://madskills.com/public/xml/rss/module/pingback/': 'pingback', - 'http://prismstandard.org/namespaces/1.2/basic/': 'prism', - 'http://www.w3.org/1999/02/22-rdf-syntax-ns#': 'rdf', - 'http://www.w3.org/2000/01/rdf-schema#': 'rdfs', - 'http://purl.org/rss/1.0/modules/reference/': 'ref', - 'http://purl.org/rss/1.0/modules/richequiv/': 'reqv', - 'http://purl.org/rss/1.0/modules/search/': 'search', - 'http://purl.org/rss/1.0/modules/slash/': 'slash', - 'http://schemas.xmlsoap.org/soap/envelope/': 'soap', - 'http://purl.org/rss/1.0/modules/servicestatus/': 'ss', - 'http://hacks.benhammersley.com/rss/streaming/': 'str', - 'http://purl.org/rss/1.0/modules/subscription/': 'sub', - 'http://purl.org/rss/1.0/modules/syndication/': 'sy', - 'http://schemas.pocketsoap.com/rss/myDescModule/': 'szf', - 'http://purl.org/rss/1.0/modules/taxonomy/': 'taxo', - 'http://purl.org/rss/1.0/modules/threading/': 'thr', - 'http://purl.org/rss/1.0/modules/textinput/': 'ti', - 'http://madskills.com/public/xml/rss/module/trackback/':'trackback', - 'http://wellformedweb.org/commentAPI/': 'wfw', - 'http://purl.org/rss/1.0/modules/wiki/': 'wiki', - 'http://www.w3.org/1999/xhtml': 'xhtml', - 'http://www.w3.org/1999/xlink': 'xlink', - 'http://www.w3.org/XML/1998/namespace': 'xml' -} - _matchnamespaces = {} - - can_be_relative_uri = ['link', 'id', 'wfw_comment', 'wfw_commentrss', 'docs', 'url', 'href', 'comments', 'icon', 'logo'] - can_contain_relative_uris = ['content', 'title', 'summary', 'info', 'tagline', 'subtitle', 'copyright', 'rights', 'description'] - can_contain_dangerous_markup = ['content', 'title', 'summary', 'info', 'tagline', 'subtitle', 'copyright', 'rights', 'description'] - html_types = ['text/html', 'application/xhtml+xml'] - - def __init__(self, baseuri=None, baselang=None, encoding='utf-8'): - if _debug: sys.stderr.write('initializing FeedParser\n') - if not self._matchnamespaces: - for k, v in self.namespaces.items(): - self._matchnamespaces[k.lower()] = v - self.feeddata = FeedParserDict() # feed-level data - self.encoding = encoding # character encoding - self.entries = [] # list of entry-level data - self.version = '' # feed type/version, see SUPPORTED_VERSIONS - self.namespacesInUse = {} # dictionary of namespaces defined by the feed - - # the following are used internally to track state; - # this is really out of control and should be refactored - self.infeed = 0 - self.inentry = 0 - self.incontent = 0 - self.intextinput = 0 - self.inimage = 0 - self.inauthor = 0 - self.incontributor = 0 - self.inpublisher = 0 - self.insource = 0 - self.sourcedata = FeedParserDict() - self.contentparams = FeedParserDict() - self._summaryKey = None - self.namespacemap = {} - self.elementstack = [] - self.basestack = [] - self.langstack = [] - self.baseuri = baseuri or '' - self.lang = baselang or None - self.svgOK = 0 - self.hasTitle = 0 - if baselang: - self.feeddata['language'] = baselang.replace('_','-') - - def unknown_starttag(self, tag, attrs): - if _debug: sys.stderr.write('start %s with %s\n' % (tag, attrs)) - # normalize attrs - attrs = [(k.lower(), v) for k, v in attrs] - attrs = [(k, k in ('rel', 'type') and v.lower() or v) for k, v in attrs] - - # track xml:base and xml:lang - attrsD = dict(attrs) - baseuri = attrsD.get('xml:base', attrsD.get('base')) or self.baseuri - if type(baseuri) != type(u''): - try: - baseuri = unicode(baseuri, self.encoding) - except: - baseuri = unicode(baseuri, 'iso-8859-1') - self.baseuri = _urljoin(self.baseuri, baseuri) - lang = attrsD.get('xml:lang', attrsD.get('lang')) - if lang == '': - # xml:lang could be explicitly set to '', we need to capture that - lang = None - elif lang is None: - # if no xml:lang is specified, use parent lang - lang = self.lang - if lang: - if tag in ('feed', 'rss', 'rdf:RDF'): - self.feeddata['language'] = lang.replace('_','-') - self.lang = lang - self.basestack.append(self.baseuri) - self.langstack.append(lang) - - # track namespaces - for prefix, uri in attrs: - if prefix.startswith('xmlns:'): - self.trackNamespace(prefix[6:], uri) - elif prefix == 'xmlns': - self.trackNamespace(None, uri) - - # track inline content - if self.incontent and self.contentparams.has_key('type') and not self.contentparams.get('type', 'xml').endswith('xml'): - if tag in ['xhtml:div', 'div']: return # typepad does this 10/2007 - # element declared itself as escaped markup, but it isn't really - self.contentparams['type'] = 'application/xhtml+xml' - if self.incontent and self.contentparams.get('type') == 'application/xhtml+xml': - if tag.find(':') <> -1: - prefix, tag = tag.split(':', 1) - namespace = self.namespacesInUse.get(prefix, '') - if tag=='math' and namespace=='http://www.w3.org/1998/Math/MathML': - attrs.append(('xmlns',namespace)) - if tag=='svg' and namespace=='http://www.w3.org/2000/svg': - attrs.append(('xmlns',namespace)) - if tag == 'svg': self.svgOK += 1 - return self.handle_data('<%s%s>' % (tag, self.strattrs(attrs)), escape=0) - - # match namespaces - if tag.find(':') <> -1: - prefix, suffix = tag.split(':', 1) - else: - prefix, suffix = '', tag - prefix = self.namespacemap.get(prefix, prefix) - if prefix: - prefix = prefix + '_' - - # special hack for better tracking of empty textinput/image elements in illformed feeds - if (not prefix) and tag not in ('title', 'link', 'description', 'name'): - self.intextinput = 0 - if (not prefix) and tag not in ('title', 'link', 'description', 'url', 'href', 'width', 'height'): - self.inimage = 0 - - # call special handler (if defined) or default handler - methodname = '_start_' + prefix + suffix - try: - method = getattr(self, methodname) - return method(attrsD) - except AttributeError: - return self.push(prefix + suffix, 1) - - def unknown_endtag(self, tag): - if _debug: sys.stderr.write('end %s\n' % tag) - # match namespaces - if tag.find(':') <> -1: - prefix, suffix = tag.split(':', 1) - else: - prefix, suffix = '', tag - prefix = self.namespacemap.get(prefix, prefix) - if prefix: - prefix = prefix + '_' - if suffix == 'svg' and self.svgOK: self.svgOK -= 1 - - # call special handler (if defined) or default handler - methodname = '_end_' + prefix + suffix - try: - if self.svgOK: raise AttributeError() - method = getattr(self, methodname) - method() - except AttributeError: - self.pop(prefix + suffix) - - # track inline content - if self.incontent and self.contentparams.has_key('type') and not self.contentparams.get('type', 'xml').endswith('xml'): - # element declared itself as escaped markup, but it isn't really - if tag in ['xhtml:div', 'div']: return # typepad does this 10/2007 - self.contentparams['type'] = 'application/xhtml+xml' - if self.incontent and self.contentparams.get('type') == 'application/xhtml+xml': - tag = tag.split(':')[-1] - self.handle_data('' % tag, escape=0) - - # track xml:base and xml:lang going out of scope - if self.basestack: - self.basestack.pop() - if self.basestack and self.basestack[-1]: - self.baseuri = self.basestack[-1] - if self.langstack: - self.langstack.pop() - if self.langstack: # and (self.langstack[-1] is not None): - self.lang = self.langstack[-1] - - def handle_charref(self, ref): - # called for each character reference, e.g. for ' ', ref will be '160' - if not self.elementstack: return - ref = ref.lower() - if ref in ('34', '38', '39', '60', '62', 'x22', 'x26', 'x27', 'x3c', 'x3e'): - text = '&#%s;' % ref - else: - if ref[0] == 'x': - c = int(ref[1:], 16) - else: - c = int(ref) - text = unichr(c).encode('utf-8') - self.elementstack[-1][2].append(text) - - def handle_entityref(self, ref): - # called for each entity reference, e.g. for '©', ref will be 'copy' - if not self.elementstack: return - if _debug: sys.stderr.write('entering handle_entityref with %s\n' % ref) - if ref in ('lt', 'gt', 'quot', 'amp', 'apos'): - text = '&%s;' % ref - elif ref in self.entities.keys(): - text = self.entities[ref] - if text.startswith('&#') and text.endswith(';'): - return self.handle_entityref(text) - else: - try: name2codepoint[ref] - except KeyError: text = '&%s;' % ref - else: text = unichr(name2codepoint[ref]).encode('utf-8') - self.elementstack[-1][2].append(text) - - def handle_data(self, text, escape=1): - # called for each block of plain text, i.e. outside of any tag and - # not containing any character or entity references - if not self.elementstack: return - if escape and self.contentparams.get('type') == 'application/xhtml+xml': - text = _xmlescape(text) - self.elementstack[-1][2].append(text) - - def handle_comment(self, text): - # called for each comment, e.g. - pass - - def handle_pi(self, text): - # called for each processing instruction, e.g. - pass - - def handle_decl(self, text): - pass - - def parse_declaration(self, i): - # override internal declaration handler to handle CDATA blocks - if _debug: sys.stderr.write('entering parse_declaration\n') - if self.rawdata[i:i+9] == '', i) - if k == -1: k = len(self.rawdata) - self.handle_data(_xmlescape(self.rawdata[i+9:k]), 0) - return k+3 - else: - k = self.rawdata.find('>', i) - return k+1 - - def mapContentType(self, contentType): - contentType = contentType.lower() - if contentType == 'text': - contentType = 'text/plain' - elif contentType == 'html': - contentType = 'text/html' - elif contentType == 'xhtml': - contentType = 'application/xhtml+xml' - return contentType - - def trackNamespace(self, prefix, uri): - loweruri = uri.lower() - if (prefix, loweruri) == (None, 'http://my.netscape.com/rdf/simple/0.9/') and not self.version: - self.version = 'rss090' - if loweruri == 'http://purl.org/rss/1.0/' and not self.version: - self.version = 'rss10' - if loweruri == 'http://www.w3.org/2005/atom' and not self.version: - self.version = 'atom10' - if loweruri.find('backend.userland.com/rss') <> -1: - # match any backend.userland.com namespace - uri = 'http://backend.userland.com/rss' - loweruri = uri - if self._matchnamespaces.has_key(loweruri): - self.namespacemap[prefix] = self._matchnamespaces[loweruri] - self.namespacesInUse[self._matchnamespaces[loweruri]] = uri - else: - self.namespacesInUse[prefix or ''] = uri - - def resolveURI(self, uri): - return _urljoin(self.baseuri or '', uri) - - def decodeEntities(self, element, data): - return data - - def strattrs(self, attrs): - return ''.join([' %s="%s"' % (t[0],_xmlescape(t[1],{'"':'"'})) for t in attrs]) - - def push(self, element, expectingText): - self.elementstack.append([element, expectingText, []]) - - def pop(self, element, stripWhitespace=1): - if not self.elementstack: return - if self.elementstack[-1][0] != element: return - - element, expectingText, pieces = self.elementstack.pop() - - if self.version == 'atom10' and self.contentparams.get('type','text') == 'application/xhtml+xml': - # remove enclosing child element, but only if it is a
and - # only if all the remaining content is nested underneath it. - # This means that the divs would be retained in the following: - #
foo
bar
- while pieces and len(pieces)>1 and not pieces[-1].strip(): - del pieces[-1] - while pieces and len(pieces)>1 and not pieces[0].strip(): - del pieces[0] - if pieces and (pieces[0] == '
' or pieces[0].startswith('
': - depth = 0 - for piece in pieces[:-1]: - if piece.startswith(''): - depth += 1 - else: - pieces = pieces[1:-1] - - output = ''.join(pieces) - if stripWhitespace: - output = output.strip() - if not expectingText: return output - - if self.encoding: - enc = self.encoding - else: - enc = "UTF-8" - if type(output) == types.StringType: - try: - output_raw = unicode(output, enc) - except: - # Invalid encoding, but we need to turn it into a valid Unicode - # string of some kind. - output_raw = unicode(output, "ISO-8859-1") - else: - output_raw = output - - # decode base64 content - if base64 and self.contentparams.get('base64', 0): - try: - output = base64.decodestring(output) - except binascii.Error: - pass - except binascii.Incomplete: - pass - - # resolve relative URIs - if (element in self.can_be_relative_uri) and output: - output = self.resolveURI(output) - - # decode entities within embedded markup - if not self.contentparams.get('base64', 0): - output = self.decodeEntities(element, output) - - if self.lookslikehtml(output): - self.contentparams['type']='text/html' - - # remove temporary cruft from contentparams - try: - del self.contentparams['mode'] - except KeyError: - pass - try: - del self.contentparams['base64'] - except KeyError: - pass - - is_htmlish = self.mapContentType(self.contentparams.get('type', 'text/html')) in self.html_types - # resolve relative URIs within embedded markup - if is_htmlish and RESOLVE_RELATIVE_URIS: - if element in self.can_contain_relative_uris: - output = _resolveRelativeURIs(output, self.baseuri, self.encoding, self.contentparams.get('type', 'text/html')) - - # parse microformats - # (must do this before sanitizing because some microformats - # rely on elements that we sanitize) - if is_htmlish and element in ['content', 'description', 'summary']: - mfresults = _parseMicroformats(output, self.baseuri, self.encoding) - if mfresults: - for tag in mfresults.get('tags', []): - self._addTag(tag['term'], tag['scheme'], tag['label']) - for enclosure in mfresults.get('enclosures', []): - self._start_enclosure(enclosure) - for xfn in mfresults.get('xfn', []): - self._addXFN(xfn['relationships'], xfn['href'], xfn['name']) - vcard = mfresults.get('vcard') - if vcard: - self._getContext()['vcard'] = vcard - - # sanitize embedded markup - if is_htmlish and SANITIZE_HTML: - if element in self.can_contain_dangerous_markup: - output = _sanitizeHTML(output, self.encoding, self.contentparams.get('type', 'text/html')) - - if self.encoding and type(output) != type(u''): - try: - output = unicode(output, self.encoding) - except: - pass - - # address common error where people take data that is already - # utf-8, presume that it is iso-8859-1, and re-encode it. - if self.encoding=='utf-8' and type(output) == type(u''): - try: - output = unicode(output.encode('iso-8859-1'), 'utf-8') - except: - pass - - # map win-1252 extensions to the proper code points - if type(output) == type(u''): - output = u''.join([c in _cp1252.keys() and _cp1252[c] or c for c in output]) - - # categories/tags/keywords/whatever are handled in _end_category - if element == 'category': - return output - - if element == 'title' and self.hasTitle: - return output - - # store output in appropriate place(s) - if self.inentry and not self.insource: - if element == 'content': - self.entries[-1].setdefault(element, []) - contentparams = copy.deepcopy(self.contentparams) - contentparams['value'] = output - contentparams['value_raw'] = output_raw - self.entries[-1][element].append(contentparams) - elif element == 'link': - self.entries[-1][element] = output - if output: - self.entries[-1]['links'][-1]['href'] = output - self.entries[-1]['links'][-1]['href_raw'] = output_raw - else: - if element == 'description': - element = 'summary' - self.entries[-1][element] = output - self.entries[-1][element + '_raw'] = output_raw - if self.incontent: - contentparams = copy.deepcopy(self.contentparams) - contentparams['value'] = output - contentparams['value_raw'] = output_raw - self.entries[-1][element + '_detail'] = contentparams - elif (self.infeed or self.insource):# and (not self.intextinput) and (not self.inimage): - context = self._getContext() - if element == 'description': - element = 'subtitle' - context[element] = output - context[element + '_raw'] = output_raw - if element == 'link': - context['links'][-1]['href'] = output - context['links'][-1]['href_raw'] = output_raw - elif self.incontent: - contentparams = copy.deepcopy(self.contentparams) - contentparams['value'] = output - contentparams['value_raw'] = output_raw - context[element + '_detail'] = contentparams - return output - - def pushContent(self, tag, attrsD, defaultContentType, expectingText): - self.incontent += 1 - if self.lang: self.lang=self.lang.replace('_','-') - self.contentparams = FeedParserDict({ - 'type': self.mapContentType(attrsD.get('type', defaultContentType)), - 'language': self.lang, - 'base': self.baseuri}) - self.contentparams['base64'] = self._isBase64(attrsD, self.contentparams) - self.push(tag, expectingText) - - def popContent(self, tag): - value = self.pop(tag) - self.incontent -= 1 - self.contentparams.clear() - return value - - # a number of elements in a number of RSS variants are nominally plain - # text, but this is routinely ignored. This is an attempt to detect - # the most common cases. As false positives often result in silent - # data loss, this function errs on the conservative side. - def lookslikehtml(self, str): - if self.version.startswith('atom'): return - if self.contentparams.get('type','text/html') != 'text/plain': return - - # must have a close tag or a entity reference to qualify - if not (re.search(r'',str) or re.search("&#?\w+;",str)): return - - # all tags must be in a restricted subset of valid HTML tags - if filter(lambda t: t.lower() not in _HTMLSanitizer.acceptable_elements, - re.findall(r' -1: - prefix = name[:colonpos] - suffix = name[colonpos+1:] - prefix = self.namespacemap.get(prefix, prefix) - name = prefix + ':' + suffix - return name - - def _getAttribute(self, attrsD, name): - return attrsD.get(self._mapToStandardPrefix(name)) - - def _isBase64(self, attrsD, contentparams): - if attrsD.get('mode', '') == 'base64': - return 1 - if self.contentparams['type'].startswith('text/'): - return 0 - if self.contentparams['type'].endswith('+xml'): - return 0 - if self.contentparams['type'].endswith('/xml'): - return 0 - return 1 - - def _itsAnHrefDamnIt(self, attrsD): - href = attrsD.get('url', attrsD.get('uri', attrsD.get('href', None))) - if href: - try: - del attrsD['url'] - except KeyError: - pass - try: - del attrsD['uri'] - except KeyError: - pass - attrsD['href'] = href - return attrsD - - def _save(self, key, value): - context = self._getContext() - context.setdefault(key, value) - - def _start_rss(self, attrsD): - versionmap = {'0.91': 'rss091u', - '0.92': 'rss092', - '0.93': 'rss093', - '0.94': 'rss094'} - if not self.version: - attr_version = attrsD.get('version', '') - version = versionmap.get(attr_version) - if version: - self.version = version - elif attr_version.startswith('2.'): - self.version = 'rss20' - else: - self.version = 'rss' - - def _start_dlhottitles(self, attrsD): - self.version = 'hotrss' - - def _start_channel(self, attrsD): - self.infeed = 1 - self._cdf_common(attrsD) - _start_feedinfo = _start_channel - - def _cdf_common(self, attrsD): - if attrsD.has_key('lastmod'): - self._start_modified({}) - self.elementstack[-1][-1] = attrsD['lastmod'] - self._end_modified() - if attrsD.has_key('href'): - self._start_link({}) - self.elementstack[-1][-1] = attrsD['href'] - self._end_link() - - def _start_feed(self, attrsD): - self.infeed = 1 - versionmap = {'0.1': 'atom01', - '0.2': 'atom02', - '0.3': 'atom03'} - if not self.version: - attr_version = attrsD.get('version') - version = versionmap.get(attr_version) - if version: - self.version = version - else: - self.version = 'atom' - - def _end_channel(self): - self.infeed = 0 - _end_feed = _end_channel - - def _start_image(self, attrsD): - context = self._getContext() - context.setdefault('image', FeedParserDict()) - self.inimage = 1 - self.hasTitle = 0 - self.push('image', 0) - - def _end_image(self): - self.pop('image') - self.inimage = 0 - - def _start_textinput(self, attrsD): - context = self._getContext() - context.setdefault('textinput', FeedParserDict()) - self.intextinput = 1 - self.hasTitle = 0 - self.push('textinput', 0) - _start_textInput = _start_textinput - - def _end_textinput(self): - self.pop('textinput') - self.intextinput = 0 - _end_textInput = _end_textinput - - def _start_author(self, attrsD): - self.inauthor = 1 - self.push('author', 1) - _start_managingeditor = _start_author - _start_dc_author = _start_author - _start_dc_creator = _start_author - _start_itunes_author = _start_author - - def _end_author(self): - self.pop('author') - self.inauthor = 0 - self._sync_author_detail() - _end_managingeditor = _end_author - _end_dc_author = _end_author - _end_dc_creator = _end_author - _end_itunes_author = _end_author - - def _start_itunes_owner(self, attrsD): - self.inpublisher = 1 - self.push('publisher', 0) - - def _end_itunes_owner(self): - self.pop('publisher') - self.inpublisher = 0 - self._sync_author_detail('publisher') - - def _start_contributor(self, attrsD): - self.incontributor = 1 - context = self._getContext() - context.setdefault('contributors', []) - context['contributors'].append(FeedParserDict()) - self.push('contributor', 0) - - def _end_contributor(self): - self.pop('contributor') - self.incontributor = 0 - - def _start_dc_contributor(self, attrsD): - self.incontributor = 1 - context = self._getContext() - context.setdefault('contributors', []) - context['contributors'].append(FeedParserDict()) - self.push('name', 0) - - def _end_dc_contributor(self): - self._end_name() - self.incontributor = 0 - - def _start_name(self, attrsD): - self.push('name', 0) - _start_itunes_name = _start_name - - def _end_name(self): - value = self.pop('name') - if self.inpublisher: - self._save_author('name', value, 'publisher') - elif self.inauthor: - self._save_author('name', value) - elif self.incontributor: - self._save_contributor('name', value) - elif self.intextinput: - context = self._getContext() - context['name'] = value - _end_itunes_name = _end_name - - def _start_width(self, attrsD): - self.push('width', 0) - - def _end_width(self): - value = self.pop('width') - try: - value = int(value) - except: - value = 0 - if self.inimage: - context = self._getContext() - context['width'] = value - - def _start_height(self, attrsD): - self.push('height', 0) - - def _end_height(self): - value = self.pop('height') - try: - value = int(value) - except: - value = 0 - if self.inimage: - context = self._getContext() - context['height'] = value - - def _start_url(self, attrsD): - self.push('href', 1) - _start_homepage = _start_url - _start_uri = _start_url - - def _end_url(self): - value = self.pop('href') - if self.inauthor: - self._save_author('href', value) - elif self.incontributor: - self._save_contributor('href', value) - _end_homepage = _end_url - _end_uri = _end_url - - def _start_email(self, attrsD): - self.push('email', 0) - _start_itunes_email = _start_email - - def _end_email(self): - value = self.pop('email') - if self.inpublisher: - self._save_author('email', value, 'publisher') - elif self.inauthor: - self._save_author('email', value) - elif self.incontributor: - self._save_contributor('email', value) - _end_itunes_email = _end_email - - def _getContext(self): - if self.insource: - context = self.sourcedata - elif self.inimage: - context = self.feeddata['image'] - elif self.intextinput: - context = self.feeddata['textinput'] - elif self.inentry: - context = self.entries[-1] - else: - context = self.feeddata - return context - - def _save_author(self, key, value, prefix='author'): - context = self._getContext() - context.setdefault(prefix + '_detail', FeedParserDict()) - context[prefix + '_detail'][key] = value - self._sync_author_detail() - - def _save_contributor(self, key, value): - context = self._getContext() - context.setdefault('contributors', [FeedParserDict()]) - context['contributors'][-1][key] = value - - def _sync_author_detail(self, key='author'): - context = self._getContext() - detail = context.get('%s_detail' % key) - if detail: - name = detail.get('name') - email = detail.get('email') - if name and email: - context[key] = '%s (%s)' % (name, email) - elif name: - context[key] = name - elif email: - context[key] = email - else: - author, email = context.get(key), None - if not author: return - emailmatch = re.search(r'''(([a-zA-Z0-9\_\-\.\+]+)@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.)|(([a-zA-Z0-9\-]+\.)+))([a-zA-Z]{2,4}|[0-9]{1,3})(\]?))(\?subject=\S+)?''', author) - if emailmatch: - email = emailmatch.group(0) - # probably a better way to do the following, but it passes all the tests - author = author.replace(email, '') - author = author.replace('()', '') - author = author.replace('<>', '') - author = author.replace('<>', '') - author = author.strip() - if author and (author[0] == '('): - author = author[1:] - if author and (author[-1] == ')'): - author = author[:-1] - author = author.strip() - if author or email: - context.setdefault('%s_detail' % key, FeedParserDict()) - if author: - context['%s_detail' % key]['name'] = author - if email: - context['%s_detail' % key]['email'] = email - - def _start_subtitle(self, attrsD): - self.pushContent('subtitle', attrsD, 'text/plain', 1) - _start_tagline = _start_subtitle - _start_itunes_subtitle = _start_subtitle - - def _end_subtitle(self): - self.popContent('subtitle') - _end_tagline = _end_subtitle - _end_itunes_subtitle = _end_subtitle - - def _start_rights(self, attrsD): - self.pushContent('rights', attrsD, 'text/plain', 1) - _start_dc_rights = _start_rights - _start_copyright = _start_rights - - def _end_rights(self): - self.popContent('rights') - _end_dc_rights = _end_rights - _end_copyright = _end_rights - - def _start_item(self, attrsD): - self.entries.append(FeedParserDict()) - self.push('item', 0) - self.inentry = 1 - self.guidislink = 0 - self.hasTitle = 0 - id = self._getAttribute(attrsD, 'rdf:about') - if id: - context = self._getContext() - context['id'] = id - self._cdf_common(attrsD) - _start_entry = _start_item - _start_product = _start_item - - def _end_item(self): - self.pop('item') - self.inentry = 0 - _end_entry = _end_item - - def _start_dc_language(self, attrsD): - self.push('language', 1) - _start_language = _start_dc_language - - def _end_dc_language(self): - self.lang = self.pop('language') - _end_language = _end_dc_language - - def _start_dc_publisher(self, attrsD): - self.push('publisher', 1) - _start_webmaster = _start_dc_publisher - - def _end_dc_publisher(self): - self.pop('publisher') - self._sync_author_detail('publisher') - _end_webmaster = _end_dc_publisher - - def _start_published(self, attrsD): - self.push('published', 1) - _start_dcterms_issued = _start_published - _start_issued = _start_published - - def _end_published(self): - value = self.pop('published') - self._save('published_parsed', _parse_date(value)) - _end_dcterms_issued = _end_published - _end_issued = _end_published - - def _start_updated(self, attrsD): - self.push('updated', 1) - _start_modified = _start_updated - _start_dcterms_modified = _start_updated - _start_pubdate = _start_updated - _start_dc_date = _start_updated - - def _end_updated(self): - value = self.pop('updated') - parsed_value = _parse_date(value) - self._save('updated_parsed', parsed_value) - _end_modified = _end_updated - _end_dcterms_modified = _end_updated - _end_pubdate = _end_updated - _end_dc_date = _end_updated - - def _start_created(self, attrsD): - self.push('created', 1) - _start_dcterms_created = _start_created - - def _end_created(self): - value = self.pop('created') - self._save('created_parsed', _parse_date(value)) - _end_dcterms_created = _end_created - - def _start_expirationdate(self, attrsD): - self.push('expired', 1) - - def _end_expirationdate(self): - self._save('expired_parsed', _parse_date(self.pop('expired'))) - - def _start_cc_license(self, attrsD): - context = self._getContext() - value = self._getAttribute(attrsD, 'rdf:resource') - attrsD = FeedParserDict() - attrsD['rel']='license' - if value: attrsD['href']=value - context.setdefault('links', []).append(attrsD) - - def _start_creativecommons_license(self, attrsD): - self.push('license', 1) - _start_creativeCommons_license = _start_creativecommons_license - - def _end_creativecommons_license(self): - value = self.pop('license') - context = self._getContext() - attrsD = FeedParserDict() - attrsD['rel']='license' - if value: attrsD['href']=value - context.setdefault('links', []).append(attrsD) - del context['license'] - _end_creativeCommons_license = _end_creativecommons_license - - def _addXFN(self, relationships, href, name): - context = self._getContext() - xfn = context.setdefault('xfn', []) - value = FeedParserDict({'relationships': relationships, 'href': href, 'name': name}) - if value not in xfn: - xfn.append(value) - - def _addTag(self, term, scheme, label): - context = self._getContext() - tags = context.setdefault('tags', []) - if (not term) and (not scheme) and (not label): return - value = FeedParserDict({'term': term, 'scheme': scheme, 'label': label}) - if value not in tags: - tags.append(value) - - def _start_category(self, attrsD): - if _debug: sys.stderr.write('entering _start_category with %s\n' % repr(attrsD)) - term = attrsD.get('term') - scheme = attrsD.get('scheme', attrsD.get('domain')) - label = attrsD.get('label') - self._addTag(term, scheme, label) - self.push('category', 1) - _start_dc_subject = _start_category - _start_keywords = _start_category - - def _end_itunes_keywords(self): - for term in self.pop('itunes_keywords').split(): - self._addTag(term, 'http://www.itunes.com/', None) - - def _start_itunes_category(self, attrsD): - self._addTag(attrsD.get('text'), 'http://www.itunes.com/', None) - self.push('category', 1) - - def _end_category(self): - value = self.pop('category') - if not value: return - context = self._getContext() - tags = context['tags'] - if value and len(tags) and not tags[-1]['term']: - tags[-1]['term'] = value - else: - self._addTag(value, None, None) - _end_dc_subject = _end_category - _end_keywords = _end_category - _end_itunes_category = _end_category - - def _start_cloud(self, attrsD): - self._getContext()['cloud'] = FeedParserDict(attrsD) - - def _start_link(self, attrsD): - attrsD.setdefault('rel', 'alternate') - if attrsD['rel'] == 'self': - attrsD.setdefault('type', 'application/atom+xml') - else: - attrsD.setdefault('type', 'text/html') - context = self._getContext() - attrsD = self._itsAnHrefDamnIt(attrsD) - if attrsD.has_key('href'): - attrsD['href'] = self.resolveURI(attrsD['href']) - if attrsD.get('rel')=='enclosure' and not context.get('id'): - context['id'] = attrsD.get('href') - expectingText = self.infeed or self.inentry or self.insource - context.setdefault('links', []) - context['links'].append(FeedParserDict(attrsD)) - if attrsD.has_key('href'): - expectingText = 0 - if (attrsD.get('rel') == 'alternate') and (self.mapContentType(attrsD.get('type')) in self.html_types): - context['link'] = attrsD['href'] - else: - self.push('link', expectingText) - _start_producturl = _start_link - - def _end_link(self): - value = self.pop('link') - context = self._getContext() - _end_producturl = _end_link - - def _start_guid(self, attrsD): - self.guidislink = (attrsD.get('ispermalink', 'true') == 'true') - self.push('id', 1) - - def _end_guid(self): - value = self.pop('id') - self._save('guidislink', self.guidislink and not self._getContext().has_key('link')) - if self.guidislink: - # guid acts as link, but only if 'ispermalink' is not present or is 'true', - # and only if the item doesn't already have a link element - self._save('link', value) - - def _start_title(self, attrsD): - if self.svgOK: return self.unknown_starttag('title', attrsD.items()) - self.pushContent('title', attrsD, 'text/plain', self.infeed or self.inentry or self.insource) - _start_dc_title = _start_title - _start_media_title = _start_title - - def _end_title(self): - if self.svgOK: return - value = self.popContent('title') - if not value: return - context = self._getContext() - self.hasTitle = 1 - _end_dc_title = _end_title - - def _end_media_title(self): - hasTitle = self.hasTitle - self._end_title() - self.hasTitle = hasTitle - - def _start_description(self, attrsD): - context = self._getContext() - if context.has_key('summary'): - self._summaryKey = 'content' - self._start_content(attrsD) - else: - self.pushContent('description', attrsD, 'text/html', self.infeed or self.inentry or self.insource) - _start_dc_description = _start_description - - def _start_abstract(self, attrsD): - self.pushContent('description', attrsD, 'text/plain', self.infeed or self.inentry or self.insource) - - def _end_description(self): - if self._summaryKey == 'content': - self._end_content() - else: - value = self.popContent('description') - self._summaryKey = None - _end_abstract = _end_description - _end_dc_description = _end_description - - def _start_info(self, attrsD): - self.pushContent('info', attrsD, 'text/plain', 1) - _start_feedburner_browserfriendly = _start_info - - def _end_info(self): - self.popContent('info') - _end_feedburner_browserfriendly = _end_info - - def _start_generator(self, attrsD): - if attrsD: - attrsD = self._itsAnHrefDamnIt(attrsD) - if attrsD.has_key('href'): - attrsD['href'] = self.resolveURI(attrsD['href']) - self._getContext()['generator_detail'] = FeedParserDict(attrsD) - self.push('generator', 1) - - def _end_generator(self): - value = self.pop('generator') - context = self._getContext() - if context.has_key('generator_detail'): - context['generator_detail']['name'] = value - - def _start_admin_generatoragent(self, attrsD): - self.push('generator', 1) - value = self._getAttribute(attrsD, 'rdf:resource') - if value: - self.elementstack[-1][2].append(value) - self.pop('generator') - self._getContext()['generator_detail'] = FeedParserDict({'href': value}) - - def _start_admin_errorreportsto(self, attrsD): - self.push('errorreportsto', 1) - value = self._getAttribute(attrsD, 'rdf:resource') - if value: - self.elementstack[-1][2].append(value) - self.pop('errorreportsto') - - def _start_summary(self, attrsD): - context = self._getContext() - if context.has_key('summary'): - self._summaryKey = 'content' - self._start_content(attrsD) - else: - self._summaryKey = 'summary' - self.pushContent(self._summaryKey, attrsD, 'text/plain', 1) - _start_itunes_summary = _start_summary - - def _end_summary(self): - if self._summaryKey == 'content': - self._end_content() - else: - self.popContent(self._summaryKey or 'summary') - self._summaryKey = None - _end_itunes_summary = _end_summary - - def _start_enclosure(self, attrsD): - attrsD = self._itsAnHrefDamnIt(attrsD) - context = self._getContext() - attrsD['rel']='enclosure' - context.setdefault('links', []).append(FeedParserDict(attrsD)) - href = attrsD.get('href') - if href and not context.get('id'): - context['id'] = href - - def _start_source(self, attrsD): - self.insource = 1 - self.hasTitle = 0 - - def _end_source(self): - self.insource = 0 - self._getContext()['source'] = copy.deepcopy(self.sourcedata) - self.sourcedata.clear() - - def _start_content(self, attrsD): - self.pushContent('content', attrsD, 'text/plain', 1) - src = attrsD.get('src') - if src: - self.contentparams['src'] = src - self.push('content', 1) - - def _start_prodlink(self, attrsD): - self.pushContent('content', attrsD, 'text/html', 1) - - def _start_body(self, attrsD): - self.pushContent('content', attrsD, 'application/xhtml+xml', 1) - _start_xhtml_body = _start_body - - def _start_content_encoded(self, attrsD): - self.pushContent('content', attrsD, 'text/html', 1) - _start_fullitem = _start_content_encoded - - def _end_content(self): - copyToDescription = self.mapContentType(self.contentparams.get('type')) in (['text/plain'] + self.html_types) - value = self.popContent('content') - if copyToDescription: - self._save('description', value) - - _end_body = _end_content - _end_xhtml_body = _end_content - _end_content_encoded = _end_content - _end_fullitem = _end_content - _end_prodlink = _end_content - - def _start_itunes_image(self, attrsD): - self.push('itunes_image', 0) - self._getContext()['image'] = FeedParserDict({'href': attrsD.get('href')}) - _start_itunes_link = _start_itunes_image - - def _end_itunes_block(self): - value = self.pop('itunes_block', 0) - self._getContext()['itunes_block'] = (value == 'yes') and 1 or 0 - - def _end_itunes_explicit(self): - value = self.pop('itunes_explicit', 0) - self._getContext()['itunes_explicit'] = (value == 'yes') and 1 or 0 - -if _XML_AVAILABLE: - class _StrictFeedParser(_FeedParserMixin, xml.sax.handler.ContentHandler): - def __init__(self, baseuri, baselang, encoding): - if _debug: sys.stderr.write('trying StrictFeedParser\n') - xml.sax.handler.ContentHandler.__init__(self) - _FeedParserMixin.__init__(self, baseuri, baselang, encoding) - self.bozo = 0 - self.exc = None - - def startPrefixMapping(self, prefix, uri): - self.trackNamespace(prefix, uri) - - def startElementNS(self, name, qname, attrs): - namespace, localname = name - lowernamespace = str(namespace or '').lower() - if lowernamespace.find('backend.userland.com/rss') <> -1: - # match any backend.userland.com namespace - namespace = 'http://backend.userland.com/rss' - lowernamespace = namespace - if qname and qname.find(':') > 0: - givenprefix = qname.split(':')[0] - else: - givenprefix = None - prefix = self._matchnamespaces.get(lowernamespace, givenprefix) - if givenprefix and (prefix == None or (prefix == '' and lowernamespace == '')) and not self.namespacesInUse.has_key(givenprefix): - raise UndeclaredNamespace, "'%s' is not associated with a namespace" % givenprefix - localname = str(localname).lower() - - # qname implementation is horribly broken in Python 2.1 (it - # doesn't report any), and slightly broken in Python 2.2 (it - # doesn't report the xml: namespace). So we match up namespaces - # with a known list first, and then possibly override them with - # the qnames the SAX parser gives us (if indeed it gives us any - # at all). Thanks to MatejC for helping me test this and - # tirelessly telling me that it didn't work yet. - attrsD = {} - if localname=='math' and namespace=='http://www.w3.org/1998/Math/MathML': - attrsD['xmlns']=namespace - if localname=='svg' and namespace=='http://www.w3.org/2000/svg': - attrsD['xmlns']=namespace - - if prefix: - localname = prefix.lower() + ':' + localname - elif namespace and not qname: #Expat - for name,value in self.namespacesInUse.items(): - if name and value == namespace: - localname = name + ':' + localname - break - if _debug: sys.stderr.write('startElementNS: qname = %s, namespace = %s, givenprefix = %s, prefix = %s, attrs = %s, localname = %s\n' % (qname, namespace, givenprefix, prefix, attrs.items(), localname)) - - for (namespace, attrlocalname), attrvalue in attrs._attrs.items(): - lowernamespace = (namespace or '').lower() - prefix = self._matchnamespaces.get(lowernamespace, '') - if prefix: - attrlocalname = prefix + ':' + attrlocalname - attrsD[str(attrlocalname).lower()] = attrvalue - for qname in attrs.getQNames(): - attrsD[str(qname).lower()] = attrs.getValueByQName(qname) - self.unknown_starttag(localname, attrsD.items()) - - def characters(self, text): - self.handle_data(text) - - def endElementNS(self, name, qname): - namespace, localname = name - lowernamespace = str(namespace or '').lower() - if qname and qname.find(':') > 0: - givenprefix = qname.split(':')[0] - else: - givenprefix = '' - prefix = self._matchnamespaces.get(lowernamespace, givenprefix) - if prefix: - localname = prefix + ':' + localname - elif namespace and not qname: #Expat - for name,value in self.namespacesInUse.items(): - if name and value == namespace: - localname = name + ':' + localname - break - localname = str(localname).lower() - self.unknown_endtag(localname) - - def error(self, exc): - self.bozo = 1 - self.exc = exc - - def fatalError(self, exc): - self.error(exc) - raise exc - -class _BaseHTMLProcessor(sgmllib.SGMLParser): - special = re.compile('''[<>'"]''') - bare_ampersand = re.compile("&(?!#\d+;|#x[0-9a-fA-F]+;|\w+;)") - elements_no_end_tag = ['area', 'base', 'basefont', 'br', 'col', 'frame', 'hr', - 'img', 'input', 'isindex', 'link', 'meta', 'param'] - - def __init__(self, encoding, type): - self.encoding = encoding - self.type = type - if _debug: sys.stderr.write('entering BaseHTMLProcessor, encoding=%s\n' % self.encoding) - sgmllib.SGMLParser.__init__(self) - - def reset(self): - self.pieces = [] - sgmllib.SGMLParser.reset(self) - - def _shorttag_replace(self, match): - tag = match.group(1) - if tag in self.elements_no_end_tag: - return '<' + tag + ' />' - else: - return '<' + tag + '>' - - def parse_starttag(self,i): - j=sgmllib.SGMLParser.parse_starttag(self, i) - if self.type == 'application/xhtml+xml': - if j>2 and self.rawdata[j-2:j]=='/>': - self.unknown_endtag(self.lasttag) - return j - - def feed(self, data): - data = re.compile(r'', self._shorttag_replace, data) # bug [ 1399464 ] Bad regexp for _shorttag_replace - data = re.sub(r'<([^<\s]+?)\s*/>', self._shorttag_replace, data) - data = data.replace(''', "'") - data = data.replace('"', '"') - if self.encoding and type(data) == type(u''): - data = data.encode(self.encoding) - sgmllib.SGMLParser.feed(self, data) - sgmllib.SGMLParser.close(self) - - def normalize_attrs(self, attrs): - if not attrs: return attrs - # utility method to be called by descendants - attrs = dict([(k.lower(), v) for k, v in attrs]).items() - attrs = [(k, k in ('rel', 'type') and v.lower() or v) for k, v in attrs] - attrs.sort() - return attrs - - def unknown_starttag(self, tag, attrs): - # called for each start tag - # attrs is a list of (attr, value) tuples - # e.g. for
, tag='pre', attrs=[('class', 'screen')]
-        if _debug: sys.stderr.write('_BaseHTMLProcessor, unknown_starttag, tag=%s\n' % tag)
-        uattrs = []
-        strattrs=''
-        if attrs:
-            for key, value in attrs:
-                value=value.replace('>','>').replace('<','<').replace('"','"')
-                value = self.bare_ampersand.sub("&", value)
-                # thanks to Kevin Marks for this breathtaking hack to deal with (valid) high-bit attribute values in UTF-8 feeds
-                if type(value) != type(u''):
-                    try:
-                        value = unicode(value, self.encoding)
-                    except:
-                        value = unicode(value, 'iso-8859-1')
-                uattrs.append((unicode(key, self.encoding), value))
-            strattrs = u''.join([u' %s="%s"' % (key, value) for key, value in uattrs])
-            if self.encoding:
-                try:
-                    strattrs=strattrs.encode(self.encoding)
-                except:
-                    pass
-        if tag in self.elements_no_end_tag:
-            self.pieces.append('<%(tag)s%(strattrs)s />' % locals())
-        else:
-            self.pieces.append('<%(tag)s%(strattrs)s>' % locals())
-
-    def unknown_endtag(self, tag):
-        # called for each end tag, e.g. for 
, tag will be 'pre' - # Reconstruct the original end tag. - if tag not in self.elements_no_end_tag: - self.pieces.append("" % locals()) - - def handle_charref(self, ref): - # called for each character reference, e.g. for ' ', ref will be '160' - # Reconstruct the original character reference. - if ref.startswith('x'): - value = unichr(int(ref[1:],16)) - else: - value = unichr(int(ref)) - - if value in _cp1252.keys(): - self.pieces.append('&#%s;' % hex(ord(_cp1252[value]))[1:]) - else: - self.pieces.append('&#%(ref)s;' % locals()) - - def handle_entityref(self, ref): - # called for each entity reference, e.g. for '©', ref will be 'copy' - # Reconstruct the original entity reference. - if name2codepoint.has_key(ref): - self.pieces.append('&%(ref)s;' % locals()) - else: - self.pieces.append('&%(ref)s' % locals()) - - def handle_data(self, text): - # called for each block of plain text, i.e. outside of any tag and - # not containing any character or entity references - # Store the original text verbatim. - if _debug: sys.stderr.write('_BaseHTMLProcessor, handle_text, text=%s\n' % text) - self.pieces.append(text) - - def handle_comment(self, text): - # called for each HTML comment, e.g. - # Reconstruct the original comment. - self.pieces.append('' % locals()) - - def handle_pi(self, text): - # called for each processing instruction, e.g. - # Reconstruct original processing instruction. - self.pieces.append('' % locals()) - - def handle_decl(self, text): - # called for the DOCTYPE, if present, e.g. - # - # Reconstruct original DOCTYPE - self.pieces.append('' % locals()) - - _new_declname_match = re.compile(r'[a-zA-Z][-_.a-zA-Z0-9:]*\s*').match - def _scan_name(self, i, declstartpos): - rawdata = self.rawdata - n = len(rawdata) - if i == n: - return None, -1 - m = self._new_declname_match(rawdata, i) - if m: - s = m.group() - name = s.strip() - if (i + len(s)) == n: - return None, -1 # end of buffer - return name.lower(), m.end() - else: - self.handle_data(rawdata) -# self.updatepos(declstartpos, i) - return None, -1 - - def convert_charref(self, name): - return '&#%s;' % name - - def convert_entityref(self, name): - return '&%s;' % name - - def output(self): - '''Return processed HTML as a single string''' - return ''.join([str(p) for p in self.pieces]) - -class _LooseFeedParser(_FeedParserMixin, _BaseHTMLProcessor): - def __init__(self, baseuri, baselang, encoding, entities): - sgmllib.SGMLParser.__init__(self) - _FeedParserMixin.__init__(self, baseuri, baselang, encoding) - _BaseHTMLProcessor.__init__(self, encoding, 'application/xhtml+xml') - self.entities=entities - - def decodeEntities(self, element, data): - data = data.replace('<', '<') - data = data.replace('<', '<') - data = data.replace('<', '<') - data = data.replace('>', '>') - data = data.replace('>', '>') - data = data.replace('>', '>') - data = data.replace('&', '&') - data = data.replace('&', '&') - data = data.replace('"', '"') - data = data.replace('"', '"') - data = data.replace(''', ''') - data = data.replace(''', ''') - if self.contentparams.has_key('type') and not self.contentparams.get('type', 'xml').endswith('xml'): - data = data.replace('<', '<') - data = data.replace('>', '>') - data = data.replace('&', '&') - data = data.replace('"', '"') - data = data.replace(''', "'") - return data - - def strattrs(self, attrs): - return ''.join([' %s="%s"' % (n,v.replace('"','"')) for n,v in attrs]) - -class _MicroformatsParser: - STRING = 1 - DATE = 2 - URI = 3 - NODE = 4 - EMAIL = 5 - - known_xfn_relationships = ['contact', 'acquaintance', 'friend', 'met', 'co-worker', 'coworker', 'colleague', 'co-resident', 'coresident', 'neighbor', 'child', 'parent', 'sibling', 'brother', 'sister', 'spouse', 'wife', 'husband', 'kin', 'relative', 'muse', 'crush', 'date', 'sweetheart', 'me'] - known_binary_extensions = ['zip','rar','exe','gz','tar','tgz','tbz2','bz2','z','7z','dmg','img','sit','sitx','hqx','deb','rpm','bz2','jar','rar','iso','bin','msi','mp2','mp3','ogg','ogm','mp4','m4v','m4a','avi','wma','wmv'] - - def __init__(self, data, baseuri, encoding): - self.document = BeautifulSoup.BeautifulSoup(data) - self.baseuri = baseuri - self.encoding = encoding - if type(data) == type(u''): - data = data.encode(encoding) - self.tags = [] - self.enclosures = [] - self.xfn = [] - self.vcard = None - - def vcardEscape(self, s): - if type(s) in (type(''), type(u'')): - s = s.replace(',', '\\,').replace(';', '\\;').replace('\n', '\\n') - return s - - def vcardFold(self, s): - s = re.sub(';+$', '', s) - sFolded = '' - iMax = 75 - sPrefix = '' - while len(s) > iMax: - sFolded += sPrefix + s[:iMax] + '\n' - s = s[iMax:] - sPrefix = ' ' - iMax = 74 - sFolded += sPrefix + s - return sFolded - - def normalize(self, s): - return re.sub(r'\s+', ' ', s).strip() - - def unique(self, aList): - results = [] - for element in aList: - if element not in results: - results.append(element) - return results - - def toISO8601(self, dt): - return time.strftime('%Y-%m-%dT%H:%M:%SZ', dt) - - def getPropertyValue(self, elmRoot, sProperty, iPropertyType=4, bAllowMultiple=0, bAutoEscape=0): - all = lambda x: 1 - sProperty = sProperty.lower() - bFound = 0 - bNormalize = 1 - propertyMatch = {'class': re.compile(r'\b%s\b' % sProperty)} - if bAllowMultiple and (iPropertyType != self.NODE): - snapResults = [] - containers = elmRoot(['ul', 'ol'], propertyMatch) - for container in containers: - snapResults.extend(container('li')) - bFound = (len(snapResults) != 0) - if not bFound: - snapResults = elmRoot(all, propertyMatch) - bFound = (len(snapResults) != 0) - if (not bFound) and (sProperty == 'value'): - snapResults = elmRoot('pre') - bFound = (len(snapResults) != 0) - bNormalize = not bFound - if not bFound: - snapResults = [elmRoot] - bFound = (len(snapResults) != 0) - arFilter = [] - if sProperty == 'vcard': - snapFilter = elmRoot(all, propertyMatch) - for node in snapFilter: - if node.findParent(all, propertyMatch): - arFilter.append(node) - arResults = [] - for node in snapResults: - if node not in arFilter: - arResults.append(node) - bFound = (len(arResults) != 0) - if not bFound: - if bAllowMultiple: return [] - elif iPropertyType == self.STRING: return '' - elif iPropertyType == self.DATE: return None - elif iPropertyType == self.URI: return '' - elif iPropertyType == self.NODE: return None - else: return None - arValues = [] - for elmResult in arResults: - sValue = None - if iPropertyType == self.NODE: - if bAllowMultiple: - arValues.append(elmResult) - continue - else: - return elmResult - sNodeName = elmResult.name.lower() - if (iPropertyType == self.EMAIL) and (sNodeName == 'a'): - sValue = (elmResult.get('href') or '').split('mailto:').pop().split('?')[0] - if sValue: - sValue = bNormalize and self.normalize(sValue) or sValue.strip() - if (not sValue) and (sNodeName == 'abbr'): - sValue = elmResult.get('title') - if sValue: - sValue = bNormalize and self.normalize(sValue) or sValue.strip() - if (not sValue) and (iPropertyType == self.URI): - if sNodeName == 'a': sValue = elmResult.get('href') - elif sNodeName == 'img': sValue = elmResult.get('src') - elif sNodeName == 'object': sValue = elmResult.get('data') - if sValue: - sValue = bNormalize and self.normalize(sValue) or sValue.strip() - if (not sValue) and (sNodeName == 'img'): - sValue = elmResult.get('alt') - if sValue: - sValue = bNormalize and self.normalize(sValue) or sValue.strip() - if not sValue: - sValue = elmResult.renderContents() - sValue = re.sub(r'<\S[^>]*>', '', sValue) - sValue = sValue.replace('\r\n', '\n') - sValue = sValue.replace('\r', '\n') - if sValue: - sValue = bNormalize and self.normalize(sValue) or sValue.strip() - if not sValue: continue - if iPropertyType == self.DATE: - sValue = _parse_date_iso8601(sValue) - if bAllowMultiple: - arValues.append(bAutoEscape and self.vcardEscape(sValue) or sValue) - else: - return bAutoEscape and self.vcardEscape(sValue) or sValue - return arValues - - def findVCards(self, elmRoot, bAgentParsing=0): - sVCards = '' - - if not bAgentParsing: - arCards = self.getPropertyValue(elmRoot, 'vcard', bAllowMultiple=1) - else: - arCards = [elmRoot] - - for elmCard in arCards: - arLines = [] - - def processSingleString(sProperty): - sValue = self.getPropertyValue(elmCard, sProperty, self.STRING, bAutoEscape=1) - if sValue: - arLines.append(self.vcardFold(sProperty.upper() + ':' + sValue)) - return sValue or '' - - def processSingleURI(sProperty): - sValue = self.getPropertyValue(elmCard, sProperty, self.URI) - if sValue: - sContentType = '' - sEncoding = '' - sValueKey = '' - if sValue.startswith('data:'): - sEncoding = ';ENCODING=b' - sContentType = sValue.split(';')[0].split('/').pop() - sValue = sValue.split(',', 1).pop() - else: - elmValue = self.getPropertyValue(elmCard, sProperty) - if elmValue: - if sProperty != 'url': - sValueKey = ';VALUE=uri' - sContentType = elmValue.get('type', '').strip().split('/').pop().strip() - sContentType = sContentType.upper() - if sContentType == 'OCTET-STREAM': - sContentType = '' - if sContentType: - sContentType = ';TYPE=' + sContentType.upper() - arLines.append(self.vcardFold(sProperty.upper() + sEncoding + sContentType + sValueKey + ':' + sValue)) - - def processTypeValue(sProperty, arDefaultType, arForceType=None): - arResults = self.getPropertyValue(elmCard, sProperty, bAllowMultiple=1) - for elmResult in arResults: - arType = self.getPropertyValue(elmResult, 'type', self.STRING, 1, 1) - if arForceType: - arType = self.unique(arForceType + arType) - if not arType: - arType = arDefaultType - sValue = self.getPropertyValue(elmResult, 'value', self.EMAIL, 0) - if sValue: - arLines.append(self.vcardFold(sProperty.upper() + ';TYPE=' + ','.join(arType) + ':' + sValue)) - - # AGENT - # must do this before all other properties because it is destructive - # (removes nested class="vcard" nodes so they don't interfere with - # this vcard's other properties) - arAgent = self.getPropertyValue(elmCard, 'agent', bAllowMultiple=1) - for elmAgent in arAgent: - if re.compile(r'\bvcard\b').search(elmAgent.get('class')): - sAgentValue = self.findVCards(elmAgent, 1) + '\n' - sAgentValue = sAgentValue.replace('\n', '\\n') - sAgentValue = sAgentValue.replace(';', '\\;') - if sAgentValue: - arLines.append(self.vcardFold('AGENT:' + sAgentValue)) - elmAgent['class'] = '' - elmAgent.contents = [] - else: - sAgentValue = self.getPropertyValue(elmAgent, 'value', self.URI, bAutoEscape=1); - if sAgentValue: - arLines.append(self.vcardFold('AGENT;VALUE=uri:' + sAgentValue)) - - # FN (full name) - sFN = processSingleString('fn') - - # N (name) - elmName = self.getPropertyValue(elmCard, 'n') - if elmName: - sFamilyName = self.getPropertyValue(elmName, 'family-name', self.STRING, bAutoEscape=1) - sGivenName = self.getPropertyValue(elmName, 'given-name', self.STRING, bAutoEscape=1) - arAdditionalNames = self.getPropertyValue(elmName, 'additional-name', self.STRING, 1, 1) + self.getPropertyValue(elmName, 'additional-names', self.STRING, 1, 1) - arHonorificPrefixes = self.getPropertyValue(elmName, 'honorific-prefix', self.STRING, 1, 1) + self.getPropertyValue(elmName, 'honorific-prefixes', self.STRING, 1, 1) - arHonorificSuffixes = self.getPropertyValue(elmName, 'honorific-suffix', self.STRING, 1, 1) + self.getPropertyValue(elmName, 'honorific-suffixes', self.STRING, 1, 1) - arLines.append(self.vcardFold('N:' + sFamilyName + ';' + - sGivenName + ';' + - ','.join(arAdditionalNames) + ';' + - ','.join(arHonorificPrefixes) + ';' + - ','.join(arHonorificSuffixes))) - elif sFN: - # implied "N" optimization - # http://microformats.org/wiki/hcard#Implied_.22N.22_Optimization - arNames = self.normalize(sFN).split() - if len(arNames) == 2: - bFamilyNameFirst = (arNames[0].endswith(',') or - len(arNames[1]) == 1 or - ((len(arNames[1]) == 2) and (arNames[1].endswith('.')))) - if bFamilyNameFirst: - arLines.append(self.vcardFold('N:' + arNames[0] + ';' + arNames[1])) - else: - arLines.append(self.vcardFold('N:' + arNames[1] + ';' + arNames[0])) - - # SORT-STRING - sSortString = self.getPropertyValue(elmCard, 'sort-string', self.STRING, bAutoEscape=1) - if sSortString: - arLines.append(self.vcardFold('SORT-STRING:' + sSortString)) - - # NICKNAME - arNickname = self.getPropertyValue(elmCard, 'nickname', self.STRING, 1, 1) - if arNickname: - arLines.append(self.vcardFold('NICKNAME:' + ','.join(arNickname))) - - # PHOTO - processSingleURI('photo') - - # BDAY - dtBday = self.getPropertyValue(elmCard, 'bday', self.DATE) - if dtBday: - arLines.append(self.vcardFold('BDAY:' + self.toISO8601(dtBday))) - - # ADR (address) - arAdr = self.getPropertyValue(elmCard, 'adr', bAllowMultiple=1) - for elmAdr in arAdr: - arType = self.getPropertyValue(elmAdr, 'type', self.STRING, 1, 1) - if not arType: - arType = ['intl','postal','parcel','work'] # default adr types, see RFC 2426 section 3.2.1 - sPostOfficeBox = self.getPropertyValue(elmAdr, 'post-office-box', self.STRING, 0, 1) - sExtendedAddress = self.getPropertyValue(elmAdr, 'extended-address', self.STRING, 0, 1) - sStreetAddress = self.getPropertyValue(elmAdr, 'street-address', self.STRING, 0, 1) - sLocality = self.getPropertyValue(elmAdr, 'locality', self.STRING, 0, 1) - sRegion = self.getPropertyValue(elmAdr, 'region', self.STRING, 0, 1) - sPostalCode = self.getPropertyValue(elmAdr, 'postal-code', self.STRING, 0, 1) - sCountryName = self.getPropertyValue(elmAdr, 'country-name', self.STRING, 0, 1) - arLines.append(self.vcardFold('ADR;TYPE=' + ','.join(arType) + ':' + - sPostOfficeBox + ';' + - sExtendedAddress + ';' + - sStreetAddress + ';' + - sLocality + ';' + - sRegion + ';' + - sPostalCode + ';' + - sCountryName)) - - # LABEL - processTypeValue('label', ['intl','postal','parcel','work']) - - # TEL (phone number) - processTypeValue('tel', ['voice']) - - # EMAIL - processTypeValue('email', ['internet'], ['internet']) - - # MAILER - processSingleString('mailer') - - # TZ (timezone) - processSingleString('tz') - - # GEO (geographical information) - elmGeo = self.getPropertyValue(elmCard, 'geo') - if elmGeo: - sLatitude = self.getPropertyValue(elmGeo, 'latitude', self.STRING, 0, 1) - sLongitude = self.getPropertyValue(elmGeo, 'longitude', self.STRING, 0, 1) - arLines.append(self.vcardFold('GEO:' + sLatitude + ';' + sLongitude)) - - # TITLE - processSingleString('title') - - # ROLE - processSingleString('role') - - # LOGO - processSingleURI('logo') - - # ORG (organization) - elmOrg = self.getPropertyValue(elmCard, 'org') - if elmOrg: - sOrganizationName = self.getPropertyValue(elmOrg, 'organization-name', self.STRING, 0, 1) - if not sOrganizationName: - # implied "organization-name" optimization - # http://microformats.org/wiki/hcard#Implied_.22organization-name.22_Optimization - sOrganizationName = self.getPropertyValue(elmCard, 'org', self.STRING, 0, 1) - if sOrganizationName: - arLines.append(self.vcardFold('ORG:' + sOrganizationName)) - else: - arOrganizationUnit = self.getPropertyValue(elmOrg, 'organization-unit', self.STRING, 1, 1) - arLines.append(self.vcardFold('ORG:' + sOrganizationName + ';' + ';'.join(arOrganizationUnit))) - - # CATEGORY - arCategory = self.getPropertyValue(elmCard, 'category', self.STRING, 1, 1) + self.getPropertyValue(elmCard, 'categories', self.STRING, 1, 1) - if arCategory: - arLines.append(self.vcardFold('CATEGORIES:' + ','.join(arCategory))) - - # NOTE - processSingleString('note') - - # REV - processSingleString('rev') - - # SOUND - processSingleURI('sound') - - # UID - processSingleString('uid') - - # URL - processSingleURI('url') - - # CLASS - processSingleString('class') - - # KEY - processSingleURI('key') - - if arLines: - arLines = ['BEGIN:vCard','VERSION:3.0'] + arLines + ['END:vCard'] - sVCards += '\n'.join(arLines) + '\n' - - return sVCards.strip() - - def isProbablyDownloadable(self, elm): - attrsD = elm.attrMap - if not attrsD.has_key('href'): return 0 - linktype = attrsD.get('type', '').strip() - if linktype.startswith('audio/') or \ - linktype.startswith('video/') or \ - (linktype.startswith('application/') and not linktype.endswith('xml')): - return 1 - path = urlparse.urlparse(attrsD['href'])[2] - if path.find('.') == -1: return 0 - fileext = path.split('.').pop().lower() - return fileext in self.known_binary_extensions - - def findTags(self): - all = lambda x: 1 - for elm in self.document(all, {'rel': re.compile(r'\btag\b')}): - href = elm.get('href') - if not href: continue - urlscheme, domain, path, params, query, fragment = \ - urlparse.urlparse(_urljoin(self.baseuri, href)) - segments = path.split('/') - tag = segments.pop() - if not tag: - tag = segments.pop() - tagscheme = urlparse.urlunparse((urlscheme, domain, '/'.join(segments), '', '', '')) - if not tagscheme.endswith('/'): - tagscheme += '/' - self.tags.append(FeedParserDict({"term": tag, "scheme": tagscheme, "label": elm.string or ''})) - - def findEnclosures(self): - all = lambda x: 1 - enclosure_match = re.compile(r'\benclosure\b') - for elm in self.document(all, {'href': re.compile(r'.+')}): - if not enclosure_match.search(elm.get('rel', '')) and not self.isProbablyDownloadable(elm): continue - if elm.attrMap not in self.enclosures: - self.enclosures.append(elm.attrMap) - if elm.string and not elm.get('title'): - self.enclosures[-1]['title'] = elm.string - - def findXFN(self): - all = lambda x: 1 - for elm in self.document(all, {'rel': re.compile('.+'), 'href': re.compile('.+')}): - rels = elm.get('rel', '').split() - xfn_rels = [] - for rel in rels: - if rel in self.known_xfn_relationships: - xfn_rels.append(rel) - if xfn_rels: - self.xfn.append({"relationships": xfn_rels, "href": elm.get('href', ''), "name": elm.string}) - -def _parseMicroformats(htmlSource, baseURI, encoding): - if not BeautifulSoup: return - if _debug: sys.stderr.write('entering _parseMicroformats\n') - p = _MicroformatsParser(htmlSource, baseURI, encoding) - p.vcard = p.findVCards(p.document) - p.findTags() - p.findEnclosures() - p.findXFN() - return {"tags": p.tags, "enclosures": p.enclosures, "xfn": p.xfn, "vcard": p.vcard} - -class _RelativeURIResolver(_BaseHTMLProcessor): - relative_uris = [('a', 'href'), - ('applet', 'codebase'), - ('area', 'href'), - ('blockquote', 'cite'), - ('body', 'background'), - ('del', 'cite'), - ('form', 'action'), - ('frame', 'longdesc'), - ('frame', 'src'), - ('iframe', 'longdesc'), - ('iframe', 'src'), - ('head', 'profile'), - ('img', 'longdesc'), - ('img', 'src'), - ('img', 'usemap'), - ('input', 'src'), - ('input', 'usemap'), - ('ins', 'cite'), - ('link', 'href'), - ('object', 'classid'), - ('object', 'codebase'), - ('object', 'data'), - ('object', 'usemap'), - ('q', 'cite'), - ('script', 'src')] - - def __init__(self, baseuri, encoding, type): - _BaseHTMLProcessor.__init__(self, encoding, type) - self.baseuri = baseuri - - def resolveURI(self, uri): - return _urljoin(self.baseuri, uri.strip()) - - def unknown_starttag(self, tag, attrs): - attrs = self.normalize_attrs(attrs) - attrs = [(key, ((tag, key) in self.relative_uris) and self.resolveURI(value) or value) for key, value in attrs] - _BaseHTMLProcessor.unknown_starttag(self, tag, attrs) - -def _resolveRelativeURIs(htmlSource, baseURI, encoding, type): - if _debug: sys.stderr.write('entering _resolveRelativeURIs\n') - p = _RelativeURIResolver(baseURI, encoding, type) - p.feed(htmlSource) - return p.output() - -class _HTMLSanitizer(_BaseHTMLProcessor): - acceptable_elements = ['a', 'abbr', 'acronym', 'address', 'area', 'article', - 'aside', 'audio', 'b', 'big', 'blockquote', 'br', 'button', 'canvas', - 'caption', 'center', 'cite', 'code', 'col', 'colgroup', 'command', - 'datagrid', 'datalist', 'dd', 'del', 'details', 'dfn', 'dialog', 'dir', - 'div', 'dl', 'dt', 'em', 'event-source', 'fieldset', 'figure', 'footer', - 'font', 'form', 'header', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'hr', 'i', - 'img', 'input', 'ins', 'keygen', 'kbd', 'label', 'legend', 'li', 'm', 'map', - 'menu', 'meter', 'multicol', 'nav', 'nextid', 'ol', 'output', 'optgroup', - 'option', 'p', 'pre', 'progress', 'q', 's', 'samp', 'section', 'select', - 'small', 'sound', 'source', 'spacer', 'span', 'strike', 'strong', 'sub', - 'sup', 'table', 'tbody', 'td', 'textarea', 'time', 'tfoot', 'th', 'thead', - 'tr', 'tt', 'u', 'ul', 'var', 'video', 'noscript', 'iframe'] - - acceptable_attributes = ['abbr', 'accept', 'accept-charset', 'accesskey', - 'action', 'align', 'allowfullscreen', 'alt', 'autoplay', 'autocomplete', 'autofocus', 'axis', - 'background', 'balance', 'bgcolor', 'bgproperties', 'border', - 'bordercolor', 'bordercolordark', 'bordercolorlight', 'bottompadding', - 'cellpadding', 'cellspacing', 'ch', 'challenge', 'char', 'charoff', - 'choff', 'charset', 'checked', 'cite', 'class', 'clear', 'color', 'cols', - 'colspan', 'compact', 'contenteditable', 'coords', 'data', 'datafld', - 'datapagesize', 'datasrc', 'datetime', 'default', 'delay', 'dir', - 'disabled', 'draggable', 'dynsrc', 'enctype', 'end', 'face', 'for', - 'form', 'frame', 'galleryimg', 'gutter', 'headers', 'height', 'hidefocus', - 'hidden', 'high', 'href', 'hreflang', 'hspace', 'icon', 'id', 'inputmode', - 'ismap', 'keytype', 'label', 'leftspacing', 'lang', 'list', 'longdesc', - 'loop', 'loopcount', 'loopend', 'loopstart', 'low', 'lowsrc', 'max', - 'maxlength', 'media', 'method', 'min', 'multiple', 'name', 'nohref', - 'noshade', 'nowrap', 'open', 'optimum', 'pattern', 'ping', 'point-size', - 'prompt', 'pqg', 'radiogroup', 'readonly', 'rel', 'repeat-max', - 'repeat-min', 'replace', 'required', 'rev', 'rightspacing', 'rows', - 'rowspan', 'rules', 'scope', 'selected', 'shape', 'size', 'span', 'src', - 'start', 'step', 'summary', 'suppress', 'tabindex', 'target', 'template', - 'title', 'toppadding', 'type', 'unselectable', 'usemap', 'urn', 'valign', - 'value', 'variable', 'volume', 'vspace', 'vrml', 'width', 'wrap', - 'xml:lang', 'controls'] - - unacceptable_elements_with_end_tag = ['script', 'applet', 'style'] - - acceptable_css_properties = ['azimuth', 'background-color', - 'border-bottom-color', 'border-collapse', 'border-color', - 'border-left-color', 'border-right-color', 'border-top-color', 'clear', - 'color', 'cursor', 'direction', 'display', 'elevation', 'float', 'font', - 'font-family', 'font-size', 'font-style', 'font-variant', 'font-weight', - 'height', 'letter-spacing', 'line-height', 'overflow', 'pause', - 'pause-after', 'pause-before', 'pitch', 'pitch-range', 'richness', - 'speak', 'speak-header', 'speak-numeral', 'speak-punctuation', - 'speech-rate', 'stress', 'text-align', 'text-decoration', 'text-indent', - 'unicode-bidi', 'vertical-align', 'voice-family', 'volume', - 'white-space', 'width'] - - # survey of common keywords found in feeds - acceptable_css_keywords = ['auto', 'aqua', 'black', 'block', 'blue', - 'bold', 'both', 'bottom', 'brown', 'center', 'collapse', 'dashed', - 'dotted', 'fuchsia', 'gray', 'green', '!important', 'italic', 'left', - 'lime', 'maroon', 'medium', 'none', 'navy', 'normal', 'nowrap', 'olive', - 'pointer', 'purple', 'red', 'right', 'solid', 'silver', 'teal', 'top', - 'transparent', 'underline', 'white', 'yellow'] - - valid_css_values = re.compile('^(#[0-9a-f]+|rgb\(\d+%?,\d*%?,?\d*%?\)?|' + - '\d{0,2}\.?\d{0,2}(cm|em|ex|in|mm|pc|pt|px|%|,|\))?)$') - - mathml_elements = ['annotation', 'annotation-xml', 'maction', 'math', - 'merror', 'mfenced', 'mfrac', 'mi', 'mmultiscripts', 'mn', 'mo', 'mover', 'mpadded', - 'mphantom', 'mprescripts', 'mroot', 'mrow', 'mspace', 'msqrt', 'mstyle', - 'msub', 'msubsup', 'msup', 'mtable', 'mtd', 'mtext', 'mtr', 'munder', - 'munderover', 'none', 'semantics'] - - mathml_attributes = ['actiontype', 'align', 'columnalign', 'columnalign', - 'columnalign', 'close', 'columnlines', 'columnspacing', 'columnspan', 'depth', - 'display', 'displaystyle', 'encoding', 'equalcolumns', 'equalrows', - 'fence', 'fontstyle', 'fontweight', 'frame', 'height', 'linethickness', - 'lspace', 'mathbackground', 'mathcolor', 'mathvariant', 'mathvariant', - 'maxsize', 'minsize', 'open', 'other', 'rowalign', 'rowalign', 'rowalign', - 'rowlines', 'rowspacing', 'rowspan', 'rspace', 'scriptlevel', 'selection', - 'separator', 'separators', 'stretchy', 'width', 'width', 'xlink:href', - 'xlink:show', 'xlink:type', 'xmlns', 'xmlns:xlink'] - - # svgtiny - foreignObject + linearGradient + radialGradient + stop - svg_elements = ['a', 'animate', 'animateColor', 'animateMotion', - 'animateTransform', 'circle', 'defs', 'desc', 'ellipse', 'foreignObject', - 'font-face', 'font-face-name', 'font-face-src', 'g', 'glyph', 'hkern', - 'linearGradient', 'line', 'marker', 'metadata', 'missing-glyph', 'mpath', - 'path', 'polygon', 'polyline', 'radialGradient', 'rect', 'set', 'stop', - 'svg', 'switch', 'text', 'title', 'tspan', 'use'] - - # svgtiny + class + opacity + offset + xmlns + xmlns:xlink - svg_attributes = ['accent-height', 'accumulate', 'additive', 'alphabetic', - 'arabic-form', 'ascent', 'attributeName', 'attributeType', - 'baseProfile', 'bbox', 'begin', 'by', 'calcMode', 'cap-height', - 'class', 'color', 'color-rendering', 'content', 'cx', 'cy', 'd', 'dx', - 'dy', 'descent', 'display', 'dur', 'end', 'fill', 'fill-opacity', - 'fill-rule', 'font-family', 'font-size', 'font-stretch', 'font-style', - 'font-variant', 'font-weight', 'from', 'fx', 'fy', 'g1', 'g2', - 'glyph-name', 'gradientUnits', 'hanging', 'height', 'horiz-adv-x', - 'horiz-origin-x', 'id', 'ideographic', 'k', 'keyPoints', 'keySplines', - 'keyTimes', 'lang', 'mathematical', 'marker-end', 'marker-mid', - 'marker-start', 'markerHeight', 'markerUnits', 'markerWidth', 'max', - 'min', 'name', 'offset', 'opacity', 'orient', 'origin', - 'overline-position', 'overline-thickness', 'panose-1', 'path', - 'pathLength', 'points', 'preserveAspectRatio', 'r', 'refX', 'refY', - 'repeatCount', 'repeatDur', 'requiredExtensions', 'requiredFeatures', - 'restart', 'rotate', 'rx', 'ry', 'slope', 'stemh', 'stemv', - 'stop-color', 'stop-opacity', 'strikethrough-position', - 'strikethrough-thickness', 'stroke', 'stroke-dasharray', - 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', - 'stroke-miterlimit', 'stroke-opacity', 'stroke-width', 'systemLanguage', - 'target', 'text-anchor', 'to', 'transform', 'type', 'u1', 'u2', - 'underline-position', 'underline-thickness', 'unicode', 'unicode-range', - 'units-per-em', 'values', 'version', 'viewBox', 'visibility', 'width', - 'widths', 'x', 'x-height', 'x1', 'x2', 'xlink:actuate', 'xlink:arcrole', - 'xlink:href', 'xlink:role', 'xlink:show', 'xlink:title', 'xlink:type', - 'xml:base', 'xml:lang', 'xml:space', 'xmlns', 'xmlns:xlink', 'y', 'y1', - 'y2', 'zoomAndPan'] - - svg_attr_map = None - svg_elem_map = None - - acceptable_svg_properties = [ 'fill', 'fill-opacity', 'fill-rule', - 'stroke', 'stroke-width', 'stroke-linecap', 'stroke-linejoin', - 'stroke-opacity'] - - def reset(self): - _BaseHTMLProcessor.reset(self) - self.unacceptablestack = 0 - self.mathmlOK = 0 - self.svgOK = 0 - - def unknown_starttag(self, tag, attrs): - acceptable_attributes = self.acceptable_attributes - keymap = {} - if not tag in self.acceptable_elements or self.svgOK: - if tag in self.unacceptable_elements_with_end_tag: - self.unacceptablestack += 1 - - # not otherwise acceptable, perhaps it is MathML or SVG? - if tag=='math' and ('xmlns','http://www.w3.org/1998/Math/MathML') in attrs: - self.mathmlOK += 1 - if tag=='svg' and ('xmlns','http://www.w3.org/2000/svg') in attrs: - self.svgOK += 1 - - # chose acceptable attributes based on tag class, else bail - if self.mathmlOK and tag in self.mathml_elements: - acceptable_attributes = self.mathml_attributes - elif self.svgOK and tag in self.svg_elements: - # for most vocabularies, lowercasing is a good idea. Many - # svg elements, however, are camel case - if not self.svg_attr_map: - lower=[attr.lower() for attr in self.svg_attributes] - mix=[a for a in self.svg_attributes if a not in lower] - self.svg_attributes = lower - self.svg_attr_map = dict([(a.lower(),a) for a in mix]) - - lower=[attr.lower() for attr in self.svg_elements] - mix=[a for a in self.svg_elements if a not in lower] - self.svg_elements = lower - self.svg_elem_map = dict([(a.lower(),a) for a in mix]) - acceptable_attributes = self.svg_attributes - tag = self.svg_elem_map.get(tag,tag) - keymap = self.svg_attr_map - elif not tag in self.acceptable_elements: - return - - # declare xlink namespace, if needed - if self.mathmlOK or self.svgOK: - if filter(lambda (n,v): n.startswith('xlink:'),attrs): - if not ('xmlns:xlink','http://www.w3.org/1999/xlink') in attrs: - attrs.append(('xmlns:xlink','http://www.w3.org/1999/xlink')) - - clean_attrs = [] - for key, value in self.normalize_attrs(attrs): - if key in acceptable_attributes: - key=keymap.get(key,key) - clean_attrs.append((key,value)) - elif key=='style': - clean_value = self.sanitize_style(value) - if clean_value: clean_attrs.append((key,clean_value)) - _BaseHTMLProcessor.unknown_starttag(self, tag, clean_attrs) - - def unknown_endtag(self, tag): - if not tag in self.acceptable_elements: - if tag in self.unacceptable_elements_with_end_tag: - self.unacceptablestack -= 1 - if self.mathmlOK and tag in self.mathml_elements: - if tag == 'math' and self.mathmlOK: self.mathmlOK -= 1 - elif self.svgOK and tag in self.svg_elements: - tag = self.svg_elem_map.get(tag,tag) - if tag == 'svg' and self.svgOK: self.svgOK -= 1 - else: - return - _BaseHTMLProcessor.unknown_endtag(self, tag) - - def handle_pi(self, text): - pass - - def handle_decl(self, text): - pass - - def handle_data(self, text): - if not self.unacceptablestack: - _BaseHTMLProcessor.handle_data(self, text) - - def sanitize_style(self, style): - # disallow urls - style=re.compile('url\s*\(\s*[^\s)]+?\s*\)\s*').sub(' ',style) - - # gauntlet - if not re.match("""^([:,;#%.\sa-zA-Z0-9!]|\w-\w|'[\s\w]+'|"[\s\w]+"|\([\d,\s]+\))*$""", style): return '' - if not re.match("^(\s*[-\w]+\s*:\s*[^:;]*(;|$))*$", style): return '' - - clean = [] - for prop,value in re.findall("([-\w]+)\s*:\s*([^:;]*)",style): - if not value: continue - if prop.lower() in self.acceptable_css_properties: - clean.append(prop + ': ' + value + ';') - elif prop.split('-')[0].lower() in ['background','border','margin','padding']: - for keyword in value.split(): - if not keyword in self.acceptable_css_keywords and \ - not self.valid_css_values.match(keyword): - break - else: - clean.append(prop + ': ' + value + ';') - elif self.svgOK and prop.lower() in self.acceptable_svg_properties: - clean.append(prop + ': ' + value + ';') - - return ' '.join(clean) - - -def _sanitizeHTML(htmlSource, encoding, type): - p = _HTMLSanitizer(encoding, type) - p.feed(htmlSource) - data = p.output() - if TIDY_MARKUP: - # loop through list of preferred Tidy interfaces looking for one that's installed, - # then set up a common _tidy function to wrap the interface-specific API. - _tidy = None - for tidy_interface in PREFERRED_TIDY_INTERFACES: - try: - if tidy_interface == "uTidy": - from tidy import parseString as _utidy - def _tidy(data, **kwargs): - return str(_utidy(data, **kwargs)) - break - elif tidy_interface == "mxTidy": - from mx.Tidy import Tidy as _mxtidy - def _tidy(data, **kwargs): - nerrors, nwarnings, data, errordata = _mxtidy.tidy(data, **kwargs) - return data - break - except: - pass - if _tidy: - utf8 = type(data) == type(u'') - if utf8: - data = data.encode('utf-8') - data = _tidy(data, output_xhtml=1, numeric_entities=1, wrap=0, char_encoding="utf8") - if utf8: - data = unicode(data, 'utf-8') - if data.count(''): - data = data.split('>', 1)[1] - if data.count('= '2.3.3' - assert base64 != None - user, passw = base64.decodestring(req.headers['Authorization'].split(' ')[1]).split(':') - realm = re.findall('realm="([^"]*)"', headers['WWW-Authenticate'])[0] - self.add_password(realm, host, user, passw) - retry = self.http_error_auth_reqed('www-authenticate', host, req, headers) - self.reset_retry_count() - return retry - except: - return self.http_error_default(req, fp, code, msg, headers) - -def _open_resource(url_file_stream_or_string, etag, modified, agent, referrer, handlers, auth_creds, use_im): - """URL, filename, or string --> stream - - This function lets you define parsers that take any input source - (URL, pathname to local or network file, or actual data as a string) - and deal with it in a uniform manner. Returned object is guaranteed - to have all the basic stdio read methods (read, readline, readlines). - Just .close() the object when you're done with it. - - If the etag argument is supplied, it will be used as the value of an - If-None-Match request header. - - If the modified argument is supplied, it can be a tuple of 9 integers - (as returned by gmtime() in the standard Python time module) or a date - string in any format supported by feedparser. Regardless, it MUST - be in GMT (Greenwich Mean Time). It will be reformatted into an - RFC 1123-compliant date and used as the value of an If-Modified-Since - request header. - - If the agent argument is supplied, it will be used as the value of a - User-Agent request header. - - If the referrer argument is supplied, it will be used as the value of a - Referer[sic] request header. - - If handlers is supplied, it is a list of handlers used to build a - urllib2 opener. - - If auth_creds is suppled, it is a tuple (username, password) to be used for - Basic or Digest authentication. - """ - - if hasattr(url_file_stream_or_string, 'read'): - return url_file_stream_or_string - - if url_file_stream_or_string == '-': - return sys.stdin - - if url_file_stream_or_string.startswith("file:"): - url_file_stream_or_string = url_file_stream_or_string[5:] - - if urlparse.urlparse(url_file_stream_or_string)[0] in ('http', 'https', 'ftp'): - if not agent: - agent = USER_AGENT - # test for user:password for basic auth - auth = None - if auth_creds: - auth = base64.encodestring('%s:%s' % auth_creds).strip() - elif base64: - urltype, rest = urllib.splittype(url_file_stream_or_string) - realhost, rest = urllib.splithost(rest) - if realhost: - user_passwd, realhost = urllib.splituser(realhost) - if user_passwd: - url_file_stream_or_string = '%s://%s%s' % (urltype, realhost, rest) - auth = base64.encodestring(user_passwd).strip() - - # iri support - try: - if isinstance(url_file_stream_or_string,unicode): - url_file_stream_or_string = url_file_stream_or_string.encode('idna') - else: - url_file_stream_or_string = url_file_stream_or_string.decode('utf-8').encode('idna') - except: - pass - - # try to open with urllib2 (to use optional headers) - request = urllib2.Request(url_file_stream_or_string) - request.add_header('User-Agent', agent) - if etag: - request.add_header('If-None-Match', etag) - if type(modified) == type(''): - modified = _parse_date(modified) - if modified: - # format into an RFC 1123-compliant timestamp. We can't use - # time.strftime() since the %a and %b directives can be affected - # by the current locale, but RFC 2616 states that dates must be - # in English. - short_weekdays = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'] - months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'] - request.add_header('If-Modified-Since', '%s, %02d %s %04d %02d:%02d:%02d GMT' % (short_weekdays[modified[6]], modified[2], months[modified[1] - 1], modified[0], modified[3], modified[4], modified[5])) - if referrer: - request.add_header('Referer', referrer) - if gzip and zlib: - request.add_header('Accept-encoding', 'gzip, deflate') - elif gzip: - request.add_header('Accept-encoding', 'gzip') - elif zlib: - request.add_header('Accept-encoding', 'deflate') - else: - request.add_header('Accept-encoding', '') - if auth: - request.add_header('Authorization', 'Basic %s' % auth) - if ACCEPT_HEADER: - request.add_header('Accept', ACCEPT_HEADER) - if use_im: - request.add_header('A-IM', 'feed') # RFC 3229 support - opener = apply(urllib2.build_opener, tuple([_FeedURLHandler()] + handlers)) - opener.addheaders = [] # RMK - must clear so we only send our custom User-Agent - try: - return opener.open(request) - finally: - opener.close() # JohnD - - # try to open with native open function (if url_file_stream_or_string is a filename) - try: - return open(url_file_stream_or_string) - except: - pass - - # treat url_file_stream_or_string as string - return _StringIO(str(url_file_stream_or_string)) - -_date_handlers = [] -def registerDateHandler(func): - '''Register a date handler function (takes string, returns 9-tuple date in GMT)''' - _date_handlers.insert(0, func) - -# ISO-8601 date parsing routines written by Fazal Majid. -# The ISO 8601 standard is very convoluted and irregular - a full ISO 8601 -# parser is beyond the scope of feedparser and would be a worthwhile addition -# to the Python library. -# A single regular expression cannot parse ISO 8601 date formats into groups -# as the standard is highly irregular (for instance is 030104 2003-01-04 or -# 0301-04-01), so we use templates instead. -# Please note the order in templates is significant because we need a -# greedy match. -_iso8601_tmpl = ['YYYY-?MM-?DD', 'YYYY-0MM?-?DD', 'YYYY-MM', 'YYYY-?OOO', - 'YY-?MM-?DD', 'YY-?OOO', 'YYYY', - '-YY-?MM', '-OOO', '-YY', - '--MM-?DD', '--MM', - '---DD', - 'CC', ''] -_iso8601_re = [ - tmpl.replace( - 'YYYY', r'(?P\d{4})').replace( - 'YY', r'(?P\d\d)').replace( - 'MM', r'(?P[01]\d)').replace( - 'DD', r'(?P[0123]\d)').replace( - 'OOO', r'(?P[0123]\d\d)').replace( - 'CC', r'(?P\d\d$)') - + r'(T?(?P\d{2}):(?P\d{2})' - + r'(:(?P\d{2}(\.\d*)?))?' - + r'(?P[+-](?P\d{2})(:(?P\d{2}))?|Z)?)?' - for tmpl in _iso8601_tmpl] -del tmpl -_iso8601_matches = [re.compile(regex).match for regex in _iso8601_re] -del regex -def _parse_date_iso8601(dateString): - '''Parse a variety of ISO-8601-compatible formats like 20040105''' - m = None - for _iso8601_match in _iso8601_matches: - m = _iso8601_match(dateString) - if m: break - if not m: return - if m.span() == (0, 0): return - params = m.groupdict() - ordinal = params.get('ordinal', 0) - if ordinal: - ordinal = int(ordinal) - else: - ordinal = 0 - year = params.get('year', '--') - if not year or year == '--': - year = time.gmtime()[0] - elif len(year) == 2: - # ISO 8601 assumes current century, i.e. 93 -> 2093, NOT 1993 - year = 100 * int(time.gmtime()[0] / 100) + int(year) - else: - year = int(year) - month = params.get('month', '-') - if not month or month == '-': - # ordinals are NOT normalized by mktime, we simulate them - # by setting month=1, day=ordinal - if ordinal: - month = 1 - else: - month = time.gmtime()[1] - month = int(month) - day = params.get('day', 0) - if not day: - # see above - if ordinal: - day = ordinal - elif params.get('century', 0) or \ - params.get('year', 0) or params.get('month', 0): - day = 1 - else: - day = time.gmtime()[2] - else: - day = int(day) - # special case of the century - is the first year of the 21st century - # 2000 or 2001 ? The debate goes on... - if 'century' in params.keys(): - year = (int(params['century']) - 1) * 100 + 1 - # in ISO 8601 most fields are optional - for field in ['hour', 'minute', 'second', 'tzhour', 'tzmin']: - if not params.get(field, None): - params[field] = 0 - hour = int(params.get('hour', 0)) - minute = int(params.get('minute', 0)) - second = int(float(params.get('second', 0))) - # weekday is normalized by mktime(), we can ignore it - weekday = 0 - daylight_savings_flag = -1 - tm = [year, month, day, hour, minute, second, weekday, - ordinal, daylight_savings_flag] - # ISO 8601 time zone adjustments - tz = params.get('tz') - if tz and tz != 'Z': - if tz[0] == '-': - tm[3] += int(params.get('tzhour', 0)) - tm[4] += int(params.get('tzmin', 0)) - elif tz[0] == '+': - tm[3] -= int(params.get('tzhour', 0)) - tm[4] -= int(params.get('tzmin', 0)) - else: - return None - # Python's time.mktime() is a wrapper around the ANSI C mktime(3c) - # which is guaranteed to normalize d/m/y/h/m/s. - # Many implementations have bugs, but we'll pretend they don't. - return time.localtime(time.mktime(tm)) -registerDateHandler(_parse_date_iso8601) - -# 8-bit date handling routines written by ytrewq1. -_korean_year = u'\ub144' # b3e2 in euc-kr -_korean_month = u'\uc6d4' # bff9 in euc-kr -_korean_day = u'\uc77c' # c0cf in euc-kr -_korean_am = u'\uc624\uc804' # bfc0 c0fc in euc-kr -_korean_pm = u'\uc624\ud6c4' # bfc0 c8c4 in euc-kr - -_korean_onblog_date_re = \ - re.compile('(\d{4})%s\s+(\d{2})%s\s+(\d{2})%s\s+(\d{2}):(\d{2}):(\d{2})' % \ - (_korean_year, _korean_month, _korean_day)) -_korean_nate_date_re = \ - re.compile(u'(\d{4})-(\d{2})-(\d{2})\s+(%s|%s)\s+(\d{,2}):(\d{,2}):(\d{,2})' % \ - (_korean_am, _korean_pm)) -def _parse_date_onblog(dateString): - '''Parse a string according to the OnBlog 8-bit date format''' - m = _korean_onblog_date_re.match(dateString) - if not m: return - w3dtfdate = '%(year)s-%(month)s-%(day)sT%(hour)s:%(minute)s:%(second)s%(zonediff)s' % \ - {'year': m.group(1), 'month': m.group(2), 'day': m.group(3),\ - 'hour': m.group(4), 'minute': m.group(5), 'second': m.group(6),\ - 'zonediff': '+09:00'} - if _debug: sys.stderr.write('OnBlog date parsed as: %s\n' % w3dtfdate) - return _parse_date_w3dtf(w3dtfdate) -registerDateHandler(_parse_date_onblog) - -def _parse_date_nate(dateString): - '''Parse a string according to the Nate 8-bit date format''' - m = _korean_nate_date_re.match(dateString) - if not m: return - hour = int(m.group(5)) - ampm = m.group(4) - if (ampm == _korean_pm): - hour += 12 - hour = str(hour) - if len(hour) == 1: - hour = '0' + hour - w3dtfdate = '%(year)s-%(month)s-%(day)sT%(hour)s:%(minute)s:%(second)s%(zonediff)s' % \ - {'year': m.group(1), 'month': m.group(2), 'day': m.group(3),\ - 'hour': hour, 'minute': m.group(6), 'second': m.group(7),\ - 'zonediff': '+09:00'} - if _debug: sys.stderr.write('Nate date parsed as: %s\n' % w3dtfdate) - return _parse_date_w3dtf(w3dtfdate) -registerDateHandler(_parse_date_nate) - -_mssql_date_re = \ - re.compile('(\d{4})-(\d{2})-(\d{2})\s+(\d{2}):(\d{2}):(\d{2})(\.\d+)?') -def _parse_date_mssql(dateString): - '''Parse a string according to the MS SQL date format''' - m = _mssql_date_re.match(dateString) - if not m: return - w3dtfdate = '%(year)s-%(month)s-%(day)sT%(hour)s:%(minute)s:%(second)s%(zonediff)s' % \ - {'year': m.group(1), 'month': m.group(2), 'day': m.group(3),\ - 'hour': m.group(4), 'minute': m.group(5), 'second': m.group(6),\ - 'zonediff': '+09:00'} - if _debug: sys.stderr.write('MS SQL date parsed as: %s\n' % w3dtfdate) - return _parse_date_w3dtf(w3dtfdate) -registerDateHandler(_parse_date_mssql) - -# Unicode strings for Greek date strings -_greek_months = \ - { \ - u'\u0399\u03b1\u03bd': u'Jan', # c9e1ed in iso-8859-7 - u'\u03a6\u03b5\u03b2': u'Feb', # d6e5e2 in iso-8859-7 - u'\u039c\u03ac\u03ce': u'Mar', # ccdcfe in iso-8859-7 - u'\u039c\u03b1\u03ce': u'Mar', # cce1fe in iso-8859-7 - u'\u0391\u03c0\u03c1': u'Apr', # c1f0f1 in iso-8859-7 - u'\u039c\u03ac\u03b9': u'May', # ccdce9 in iso-8859-7 - u'\u039c\u03b1\u03ca': u'May', # cce1fa in iso-8859-7 - u'\u039c\u03b1\u03b9': u'May', # cce1e9 in iso-8859-7 - u'\u0399\u03bf\u03cd\u03bd': u'Jun', # c9effded in iso-8859-7 - u'\u0399\u03bf\u03bd': u'Jun', # c9efed in iso-8859-7 - u'\u0399\u03bf\u03cd\u03bb': u'Jul', # c9effdeb in iso-8859-7 - u'\u0399\u03bf\u03bb': u'Jul', # c9f9eb in iso-8859-7 - u'\u0391\u03cd\u03b3': u'Aug', # c1fde3 in iso-8859-7 - u'\u0391\u03c5\u03b3': u'Aug', # c1f5e3 in iso-8859-7 - u'\u03a3\u03b5\u03c0': u'Sep', # d3e5f0 in iso-8859-7 - u'\u039f\u03ba\u03c4': u'Oct', # cfeaf4 in iso-8859-7 - u'\u039d\u03bf\u03ad': u'Nov', # cdefdd in iso-8859-7 - u'\u039d\u03bf\u03b5': u'Nov', # cdefe5 in iso-8859-7 - u'\u0394\u03b5\u03ba': u'Dec', # c4e5ea in iso-8859-7 - } - -_greek_wdays = \ - { \ - u'\u039a\u03c5\u03c1': u'Sun', # caf5f1 in iso-8859-7 - u'\u0394\u03b5\u03c5': u'Mon', # c4e5f5 in iso-8859-7 - u'\u03a4\u03c1\u03b9': u'Tue', # d4f1e9 in iso-8859-7 - u'\u03a4\u03b5\u03c4': u'Wed', # d4e5f4 in iso-8859-7 - u'\u03a0\u03b5\u03bc': u'Thu', # d0e5ec in iso-8859-7 - u'\u03a0\u03b1\u03c1': u'Fri', # d0e1f1 in iso-8859-7 - u'\u03a3\u03b1\u03b2': u'Sat', # d3e1e2 in iso-8859-7 - } - -_greek_date_format_re = \ - re.compile(u'([^,]+),\s+(\d{2})\s+([^\s]+)\s+(\d{4})\s+(\d{2}):(\d{2}):(\d{2})\s+([^\s]+)') - -def _parse_date_greek(dateString): - '''Parse a string according to a Greek 8-bit date format.''' - m = _greek_date_format_re.match(dateString) - if not m: return - try: - wday = _greek_wdays[m.group(1)] - month = _greek_months[m.group(3)] - except: - return - rfc822date = '%(wday)s, %(day)s %(month)s %(year)s %(hour)s:%(minute)s:%(second)s %(zonediff)s' % \ - {'wday': wday, 'day': m.group(2), 'month': month, 'year': m.group(4),\ - 'hour': m.group(5), 'minute': m.group(6), 'second': m.group(7),\ - 'zonediff': m.group(8)} - if _debug: sys.stderr.write('Greek date parsed as: %s\n' % rfc822date) - return _parse_date_rfc822(rfc822date) -registerDateHandler(_parse_date_greek) - -# Unicode strings for Hungarian date strings -_hungarian_months = \ - { \ - u'janu\u00e1r': u'01', # e1 in iso-8859-2 - u'febru\u00e1ri': u'02', # e1 in iso-8859-2 - u'm\u00e1rcius': u'03', # e1 in iso-8859-2 - u'\u00e1prilis': u'04', # e1 in iso-8859-2 - u'm\u00e1ujus': u'05', # e1 in iso-8859-2 - u'j\u00fanius': u'06', # fa in iso-8859-2 - u'j\u00falius': u'07', # fa in iso-8859-2 - u'augusztus': u'08', - u'szeptember': u'09', - u'okt\u00f3ber': u'10', # f3 in iso-8859-2 - u'november': u'11', - u'december': u'12', - } - -_hungarian_date_format_re = \ - re.compile(u'(\d{4})-([^-]+)-(\d{,2})T(\d{,2}):(\d{2})((\+|-)(\d{,2}:\d{2}))') - -def _parse_date_hungarian(dateString): - '''Parse a string according to a Hungarian 8-bit date format.''' - m = _hungarian_date_format_re.match(dateString) - if not m: return - try: - month = _hungarian_months[m.group(2)] - day = m.group(3) - if len(day) == 1: - day = '0' + day - hour = m.group(4) - if len(hour) == 1: - hour = '0' + hour - except: - return - w3dtfdate = '%(year)s-%(month)s-%(day)sT%(hour)s:%(minute)s%(zonediff)s' % \ - {'year': m.group(1), 'month': month, 'day': day,\ - 'hour': hour, 'minute': m.group(5),\ - 'zonediff': m.group(6)} - if _debug: sys.stderr.write('Hungarian date parsed as: %s\n' % w3dtfdate) - return _parse_date_w3dtf(w3dtfdate) -registerDateHandler(_parse_date_hungarian) - -# W3DTF-style date parsing adapted from PyXML xml.utils.iso8601, written by -# Drake and licensed under the Python license. Removed all range checking -# for month, day, hour, minute, and second, since mktime will normalize -# these later -def _parse_date_w3dtf(dateString): - def __extract_date(m): - year = int(m.group('year')) - if year < 100: - year = 100 * int(time.gmtime()[0] / 100) + int(year) - if year < 1000: - return 0, 0, 0 - julian = m.group('julian') - if julian: - julian = int(julian) - month = julian / 30 + 1 - day = julian % 30 + 1 - jday = None - while jday != julian: - t = time.mktime((year, month, day, 0, 0, 0, 0, 0, 0)) - jday = time.gmtime(t)[-2] - diff = abs(jday - julian) - if jday > julian: - if diff < day: - day = day - diff - else: - month = month - 1 - day = 31 - elif jday < julian: - if day + diff < 28: - day = day + diff - else: - month = month + 1 - return year, month, day - month = m.group('month') - day = 1 - if month is None: - month = 1 - else: - month = int(month) - day = m.group('day') - if day: - day = int(day) - else: - day = 1 - return year, month, day - - def __extract_time(m): - if not m: - return 0, 0, 0 - hours = m.group('hours') - if not hours: - return 0, 0, 0 - hours = int(hours) - minutes = int(m.group('minutes')) - seconds = m.group('seconds') - if seconds: - seconds = int(seconds) - else: - seconds = 0 - return hours, minutes, seconds - - def __extract_tzd(m): - '''Return the Time Zone Designator as an offset in seconds from UTC.''' - if not m: - return 0 - tzd = m.group('tzd') - if not tzd: - return 0 - if tzd == 'Z': - return 0 - hours = int(m.group('tzdhours')) - minutes = m.group('tzdminutes') - if minutes: - minutes = int(minutes) - else: - minutes = 0 - offset = (hours*60 + minutes) * 60 - if tzd[0] == '+': - return -offset - return offset - - __date_re = ('(?P\d\d\d\d)' - '(?:(?P-|)' - '(?:(?P\d\d\d)' - '|(?P\d\d)(?:(?P=dsep)(?P\d\d))?))?') - __tzd_re = '(?P[-+](?P\d\d)(?::?(?P\d\d))|Z)' - __tzd_rx = re.compile(__tzd_re) - __time_re = ('(?P\d\d)(?P:|)(?P\d\d)' - '(?:(?P=tsep)(?P\d\d(?:[.,]\d+)?))?' - + __tzd_re) - __datetime_re = '%s(?:T%s)?' % (__date_re, __time_re) - __datetime_rx = re.compile(__datetime_re) - m = __datetime_rx.match(dateString) - if (m is None) or (m.group() != dateString): return - gmt = __extract_date(m) + __extract_time(m) + (0, 0, 0) - if gmt[0] == 0: return - return time.gmtime(time.mktime(gmt) + __extract_tzd(m) - time.timezone) -registerDateHandler(_parse_date_w3dtf) - -def _parse_date_rfc822(dateString): - '''Parse an RFC822, RFC1123, RFC2822, or asctime-style date''' - data = dateString.split() - if data[0][-1] in (',', '.') or data[0].lower() in rfc822._daynames: - del data[0] - if len(data) == 4: - s = data[3] - i = s.find('+') - if i > 0: - data[3:] = [s[:i], s[i+1:]] - else: - data.append('') - dateString = " ".join(data) - if len(data) < 5: - dateString += ' 00:00:00 GMT' - tm = rfc822.parsedate_tz(dateString) - if tm: - return time.gmtime(rfc822.mktime_tz(tm)) -# rfc822.py defines several time zones, but we define some extra ones. -# 'ET' is equivalent to 'EST', etc. -_additional_timezones = {'AT': -400, 'ET': -500, 'CT': -600, 'MT': -700, 'PT': -800} -rfc822._timezones.update(_additional_timezones) -registerDateHandler(_parse_date_rfc822) - -def _parse_date_perforce(aDateString): - """parse a date in yyyy/mm/dd hh:mm:ss TTT format""" - # Fri, 2006/09/15 08:19:53 EDT - _my_date_pattern = re.compile( \ - r'(\w{,3}), (\d{,4})/(\d{,2})/(\d{2}) (\d{,2}):(\d{2}):(\d{2}) (\w{,3})') - - dow, year, month, day, hour, minute, second, tz = \ - _my_date_pattern.search(aDateString).groups() - months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'] - dateString = "%s, %s %s %s %s:%s:%s %s" % (dow, day, months[int(month) - 1], year, hour, minute, second, tz) - tm = rfc822.parsedate_tz(dateString) - if tm: - return time.gmtime(rfc822.mktime_tz(tm)) -registerDateHandler(_parse_date_perforce) - -def _parse_date(dateString): - '''Parses a variety of date formats into a 9-tuple in GMT''' - for handler in _date_handlers: - try: - date9tuple = handler(dateString) - if not date9tuple: continue - if len(date9tuple) != 9: - if _debug: sys.stderr.write('date handler function must return 9-tuple\n') - raise ValueError - map(int, date9tuple) - return date9tuple - except Exception, e: - if _debug: sys.stderr.write('%s raised %s\n' % (handler.__name__, repr(e))) - pass - return None - -def _getCharacterEncoding(http_headers, xml_data): - '''Get the character encoding of the XML document - - http_headers is a dictionary - xml_data is a raw string (not Unicode) - - This is so much trickier than it sounds, it's not even funny. - According to RFC 3023 ('XML Media Types'), if the HTTP Content-Type - is application/xml, application/*+xml, - application/xml-external-parsed-entity, or application/xml-dtd, - the encoding given in the charset parameter of the HTTP Content-Type - takes precedence over the encoding given in the XML prefix within the - document, and defaults to 'utf-8' if neither are specified. But, if - the HTTP Content-Type is text/xml, text/*+xml, or - text/xml-external-parsed-entity, the encoding given in the XML prefix - within the document is ALWAYS IGNORED and only the encoding given in - the charset parameter of the HTTP Content-Type header should be - respected, and it defaults to 'us-ascii' if not specified. - - Furthermore, discussion on the atom-syntax mailing list with the - author of RFC 3023 leads me to the conclusion that any document - served with a Content-Type of text/* and no charset parameter - must be treated as us-ascii. (We now do this.) And also that it - must always be flagged as non-well-formed. (We now do this too.) - - If Content-Type is unspecified (input was local file or non-HTTP source) - or unrecognized (server just got it totally wrong), then go by the - encoding given in the XML prefix of the document and default to - 'iso-8859-1' as per the HTTP specification (RFC 2616). - - Then, assuming we didn't find a character encoding in the HTTP headers - (and the HTTP Content-type allowed us to look in the body), we need - to sniff the first few bytes of the XML data and try to determine - whether the encoding is ASCII-compatible. Section F of the XML - specification shows the way here: - http://www.w3.org/TR/REC-xml/#sec-guessing-no-ext-info - - If the sniffed encoding is not ASCII-compatible, we need to make it - ASCII compatible so that we can sniff further into the XML declaration - to find the encoding attribute, which will tell us the true encoding. - - Of course, none of this guarantees that we will be able to parse the - feed in the declared character encoding (assuming it was declared - correctly, which many are not). CJKCodecs and iconv_codec help a lot; - you should definitely install them if you can. - http://cjkpython.i18n.org/ - ''' - - def _parseHTTPContentType(content_type): - '''takes HTTP Content-Type header and returns (content type, charset) - - If no charset is specified, returns (content type, '') - If no content type is specified, returns ('', '') - Both return parameters are guaranteed to be lowercase strings - ''' - content_type = content_type or '' - content_type, params = cgi.parse_header(content_type) - return content_type, params.get('charset', '').replace("'", '') - - sniffed_xml_encoding = '' - xml_encoding = '' - true_encoding = '' - http_content_type, http_encoding = _parseHTTPContentType(http_headers.get('content-type')) - # Must sniff for non-ASCII-compatible character encodings before - # searching for XML declaration. This heuristic is defined in - # section F of the XML specification: - # http://www.w3.org/TR/REC-xml/#sec-guessing-no-ext-info - try: - if xml_data[:4] == '\x4c\x6f\xa7\x94': - # EBCDIC - xml_data = _ebcdic_to_ascii(xml_data) - elif xml_data[:4] == '\x00\x3c\x00\x3f': - # UTF-16BE - sniffed_xml_encoding = 'utf-16be' - xml_data = unicode(xml_data, 'utf-16be').encode('utf-8') - elif (len(xml_data) >= 4) and (xml_data[:2] == '\xfe\xff') and (xml_data[2:4] != '\x00\x00'): - # UTF-16BE with BOM - sniffed_xml_encoding = 'utf-16be' - xml_data = unicode(xml_data[2:], 'utf-16be').encode('utf-8') - elif xml_data[:4] == '\x3c\x00\x3f\x00': - # UTF-16LE - sniffed_xml_encoding = 'utf-16le' - xml_data = unicode(xml_data, 'utf-16le').encode('utf-8') - elif (len(xml_data) >= 4) and (xml_data[:2] == '\xff\xfe') and (xml_data[2:4] != '\x00\x00'): - # UTF-16LE with BOM - sniffed_xml_encoding = 'utf-16le' - xml_data = unicode(xml_data[2:], 'utf-16le').encode('utf-8') - elif xml_data[:4] == '\x00\x00\x00\x3c': - # UTF-32BE - sniffed_xml_encoding = 'utf-32be' - xml_data = unicode(xml_data, 'utf-32be').encode('utf-8') - elif xml_data[:4] == '\x3c\x00\x00\x00': - # UTF-32LE - sniffed_xml_encoding = 'utf-32le' - xml_data = unicode(xml_data, 'utf-32le').encode('utf-8') - elif xml_data[:4] == '\x00\x00\xfe\xff': - # UTF-32BE with BOM - sniffed_xml_encoding = 'utf-32be' - xml_data = unicode(xml_data[4:], 'utf-32be').encode('utf-8') - elif xml_data[:4] == '\xff\xfe\x00\x00': - # UTF-32LE with BOM - sniffed_xml_encoding = 'utf-32le' - xml_data = unicode(xml_data[4:], 'utf-32le').encode('utf-8') - elif xml_data[:3] == '\xef\xbb\xbf': - # UTF-8 with BOM - sniffed_xml_encoding = 'utf-8' - xml_data = unicode(xml_data[3:], 'utf-8').encode('utf-8') - else: - # ASCII-compatible - pass - xml_encoding_match = re.compile('^<\?.*encoding=[\'"](.*?)[\'"].*\?>').match(xml_data) - except: - xml_encoding_match = None - if xml_encoding_match: - xml_encoding = xml_encoding_match.groups()[0].lower() - if sniffed_xml_encoding and (xml_encoding in ('iso-10646-ucs-2', 'ucs-2', 'csunicode', 'iso-10646-ucs-4', 'ucs-4', 'csucs4', 'utf-16', 'utf-32', 'utf_16', 'utf_32', 'utf16', 'u16')): - xml_encoding = sniffed_xml_encoding - acceptable_content_type = 0 - application_content_types = ('application/xml', 'application/xml-dtd', 'application/xml-external-parsed-entity') - text_content_types = ('text/xml', 'text/xml-external-parsed-entity') - if (http_content_type in application_content_types) or \ - (http_content_type.startswith('application/') and http_content_type.endswith('+xml')): - acceptable_content_type = 1 - true_encoding = http_encoding or xml_encoding or 'utf-8' - elif (http_content_type in text_content_types) or \ - (http_content_type.startswith('text/')) and http_content_type.endswith('+xml'): - acceptable_content_type = 1 - true_encoding = http_encoding or 'us-ascii' - elif http_content_type.startswith('text/'): - true_encoding = http_encoding or 'us-ascii' - elif http_headers and (not http_headers.has_key('content-type')): - true_encoding = xml_encoding or 'iso-8859-1' - else: - true_encoding = xml_encoding or 'utf-8' - # some feeds claim to be gb2312 but are actually gb18030. - # apparently MSIE and Firefox both do the following switch: - if true_encoding.lower() == 'gb2312': - true_encoding = 'gb18030' - return true_encoding, http_encoding, xml_encoding, sniffed_xml_encoding, acceptable_content_type - -def _toUTF8(data, encoding): - '''Changes an XML data stream on the fly to specify a new encoding - - data is a raw sequence of bytes (not Unicode) that is presumed to be in %encoding already - encoding is a string recognized by encodings.aliases - ''' - if _debug: sys.stderr.write('entering _toUTF8, trying encoding %s\n' % encoding) - # strip Byte Order Mark (if present) - if (len(data) >= 4) and (data[:2] == '\xfe\xff') and (data[2:4] != '\x00\x00'): - if _debug: - sys.stderr.write('stripping BOM\n') - if encoding != 'utf-16be': - sys.stderr.write('trying utf-16be instead\n') - encoding = 'utf-16be' - data = data[2:] - elif (len(data) >= 4) and (data[:2] == '\xff\xfe') and (data[2:4] != '\x00\x00'): - if _debug: - sys.stderr.write('stripping BOM\n') - if encoding != 'utf-16le': - sys.stderr.write('trying utf-16le instead\n') - encoding = 'utf-16le' - data = data[2:] - elif data[:3] == '\xef\xbb\xbf': - if _debug: - sys.stderr.write('stripping BOM\n') - if encoding != 'utf-8': - sys.stderr.write('trying utf-8 instead\n') - encoding = 'utf-8' - data = data[3:] - elif data[:4] == '\x00\x00\xfe\xff': - if _debug: - sys.stderr.write('stripping BOM\n') - if encoding != 'utf-32be': - sys.stderr.write('trying utf-32be instead\n') - encoding = 'utf-32be' - data = data[4:] - elif data[:4] == '\xff\xfe\x00\x00': - if _debug: - sys.stderr.write('stripping BOM\n') - if encoding != 'utf-32le': - sys.stderr.write('trying utf-32le instead\n') - encoding = 'utf-32le' - data = data[4:] - newdata = unicode(data, encoding) - if _debug: sys.stderr.write('successfully converted %s data to unicode\n' % encoding) - declmatch = re.compile('^<\?xml[^>]*?>') - newdecl = '''''' - if declmatch.search(newdata): - newdata = declmatch.sub(newdecl, newdata) - else: - newdata = newdecl + u'\n' + newdata - return newdata.encode('utf-8') - -def _stripDoctype(data): - '''Strips DOCTYPE from XML document, returns (rss_version, stripped_data) - - rss_version may be 'rss091n' or None - stripped_data is the same XML document, minus the DOCTYPE - ''' - start = re.search('<\w',data) - start = start and start.start() or -1 - head,data = data[:start+1], data[start+1:] - - entity_pattern = re.compile(r'^\s*]*?)>', re.MULTILINE) - entity_results=entity_pattern.findall(head) - head = entity_pattern.sub('', head) - doctype_pattern = re.compile(r'^\s*]*?)>', re.MULTILINE) - doctype_results = doctype_pattern.findall(head) - doctype = doctype_results and doctype_results[0] or '' - if doctype.lower().count('netscape'): - version = 'rss091n' - else: - version = None - - # only allow in 'safe' inline entity definitions - replacement='' - if len(doctype_results)==1 and entity_results: - safe_pattern=re.compile('\s+(\w+)\s+"(&#\w+;|[^&"]*)"') - safe_entities=filter(lambda e: safe_pattern.match(e),entity_results) - if safe_entities: - replacement='\n]>' % '>\n -# -# persister is free software; you can redistribute it and/or modify it -# under the terms of the GNU Lesser General Public License as -# published by the Free Software Foundation; either version 2.1 of the -# License, or (at your option) any later version. -# -# persister is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with persister; see the file COPYING.LGPL. If not, -# write to the Free Software Foundation, Inc., 51 Franklin Street, -# Fifth Floor, Boston, MA 02110-1301, USA, or see http://www.gnu.org/. - -import fcntl, os, errno -import cPickle as pickle - -class Persistable: - """Something which can be persisted. When a subclass of this wants to - indicate that it has been modified, it should call - self.modified().""" - def __init__(self): self._modified = False - def modified(self, state = True): self._modified = state - def is_modified(self): return self._modified - -class Persister: - """Persist another class to a file, safely. The class being persisted - must derive from Persistable (although this isn't enforced).""" - - def __init__(self, filename, klass, use_locking = True): - self.filename = filename - self.klass = klass - self.use_locking = use_locking - self.file = None - self.object = None - - def load(self, no_block = True): - """Load the persisted object from the file, or create a new one - if this isn't possible. Returns the loaded object.""" - - def get_lock(): - if not self.use_locking: - return True - mode = fcntl.LOCK_EX - if no_block: - mode |= fcntl.LOCK_NB - try: - fcntl.lockf(self.file.fileno(), mode) - except IOError, e: - if no_block and e.errno in (errno.EACCES, errno.EAGAIN): - return False - raise e - return True - - try: - self.file = open(self.filename, "r+") - if not get_lock(): - return None - self.object = pickle.load(self.file) - self.object.modified(False) - except IOError: - self.file = open(self.filename, "w+") - if not get_lock(): - return None - self.object = self.klass() - self.object.modified() - return self.object - - def save(self): - """Save the persisted object back to the file if necessary.""" - if self.object.is_modified(): - newname = "%s.new-%d" % (self.filename, os.getpid()) - newfile = open(newname, "w") - try: - pickle.dump(self.object, newfile, pickle.HIGHEST_PROTOCOL) - except AttributeError: - # Python 2.2 doesn't have the protocol - # argument. - pickle.dump(self.object, newfile, True) - newfile.close() - os.rename(newname, self.filename) - self.file.close() - diff --git a/rawdoglib/plugins.py b/rawdoglib/plugins.py deleted file mode 100644 --- a/rawdoglib/plugins.py +++ /dev/null @@ -1,73 +0,0 @@ -# plugins: handle add-on modules for rawdog. -# Copyright 2004, 2005 Adam Sampson -# -# rawdog is free software; you can redistribute and/or modify it -# under the terms of that license as published by the Free Software -# Foundation; either version 2 of the License, or (at your option) -# any later version. -# -# rawdog is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with rawdog; see the file COPYING. If not, write to the Free -# Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, -# MA 02110-1301, USA, or see http://www.gnu.org/. - -import os, imp - -class Box: - """Utility class that holds a mutable value. Useful for passing - immutable types by reference.""" - def __init__(self, value = None): - self.value = value - -plugin_count = 0 - -def load_plugins(dir, config): - global plugin_count - - try: - files = os.listdir(dir) - except OSError: - # Ignore directories that can't be read. - return - - for file in files: - if file == "" or file[0] == ".": - continue - - desc = None - for d in imp.get_suffixes(): - if file.endswith(d[0]) and d[2] == imp.PY_SOURCE: - desc = d - if desc is None: - continue - - fn = os.path.join(dir, file) - config.log("Loading plugin ", fn) - f = open(fn, "r") - mod = imp.load_module("plugin%d" % (plugin_count,), f, fn, desc) - plugin_count += 1 - f.close() - -attached = {} - -def attach_hook(hookname, func): - """Attach a function to a hook. The function should take the - appropriate arguments for the hook, and should return either True or - False to indicate whether further functions should be processed.""" - attached.setdefault(hookname, []).append(func) - -def call_hook(hookname, *args): - """Call all the functions attached to a hook with the given - arguments, in the order they were added, stopping if a hook function - returns False. Returns True if any hook function returned False (i.e. - returns True if any hook function handled the request).""" - for func in attached.get(hookname, []): - if not func(*args): - return True - return False - diff --git a/rawdoglib/rawdog.py b/rawdoglib/rawdog.py deleted file mode 100644 --- a/rawdoglib/rawdog.py +++ /dev/null @@ -1,1788 +0,0 @@ -# rawdog: RSS aggregator without delusions of grandeur. -# Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Adam Sampson -# -# rawdog is free software; you can redistribute and/or modify it -# under the terms of that license as published by the Free Software -# Foundation; either version 2 of the License, or (at your option) -# any later version. -# -# rawdog is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with rawdog; see the file COPYING. If not, write to the Free -# Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, -# MA 02110-1301, USA, or see http://www.gnu.org/. - -VERSION = "2.12" -STATE_VERSION = 2 -import feedparser, plugins -from persister import Persistable, Persister -import os, time, getopt, sys, re, cgi, socket, urllib2, calendar -import string, locale -from StringIO import StringIO -import types - -try: - import threading - have_threading = 1 -except: - have_threading = 0 - -try: - import hashlib -except: - hashlib = None - import sha - -try: - import feedfinder -except: - feedfinder = None - -def new_sha1(s = ""): - """Return a new SHA1 hash object.""" - if hashlib is None: - return sha.new(s) - else: - return hashlib.sha1(s) - -def set_socket_timeout(n): - """Set the system socket timeout.""" - if hasattr(socket, "setdefaulttimeout"): - socket.setdefaulttimeout(n) - else: - # Python 2.2 and earlier need to use an external module. - import timeoutsocket - timeoutsocket.setDefaultSocketTimeout(n) - -system_encoding = None -def get_system_encoding(): - """Get the system encoding.""" - return system_encoding - -def safe_ftime(format, t): - """Format a time value into a string in the current locale (as - time.strftime), but encode the result as ASCII HTML.""" - u = unicode(time.strftime(format, t), get_system_encoding()) - return encode_references(u) - -def format_time(secs, config): - """Format a time and date nicely.""" - t = time.localtime(secs) - format = config["datetimeformat"] - if format is None: - format = config["timeformat"] + ", " + config["dayformat"] - return safe_ftime(format, t) - -high_char_re = re.compile(r'[^\000-\177]') -def encode_references(s): - """Encode characters in a Unicode string using HTML references.""" - def encode(m): - return "&#" + str(ord(m.group(0))) + ";" - return high_char_re.sub(encode, s) - -# This list of block-level elements came from the HTML 4.01 specification. -block_level_re = re.compile(r'^\s*<(p|h1|h2|h3|h4|h5|h6|ul|ol|pre|dl|div|noscript|blockquote|form|hr|table|fieldset|address)[^a-z]', re.I) -def sanitise_html(html, baseurl, inline, config): - """Attempt to turn arbitrary feed-provided HTML into something - suitable for safe inclusion into the rawdog output. The inline - parameter says whether to expect a fragment of inline text, or a - sequence of block-level elements.""" - if html is None: - return None - - html = encode_references(html) - type = "text/html" - - # sgmllib handles "
/" as a SHORTTAG; this workaround from - # feedparser. - html = re.sub(r'(\S)/>', r'\1 />', html) - html = feedparser._resolveRelativeURIs(html, baseurl, "UTF-8", type) - p = feedparser._HTMLSanitizer("UTF-8", type) - p.feed(html) - html = p.output() - - if not inline and config["blocklevelhtml"]: - # If we're after some block-level HTML and the HTML doesn't - # start with a block-level element, then insert a

tag - # before it. This still fails when the HTML contains text, then - # a block-level element, then more text, but it's better than - # nothing. - if block_level_re.match(html) is None: - html = "

" + html - - if config["tidyhtml"]: - import mx.Tidy - args = { "wrap": 0, "numeric_entities": 1 } - plugins.call_hook("mxtidy_args", config, args, baseurl, inline) - output = mx.Tidy.tidy(html, None, None, - **args)[2] - html = output[output.find("") + 6 - : output.rfind("")].strip() - - html = html.decode("UTF-8") - box = plugins.Box(html) - plugins.call_hook("clean_html", config, box, baseurl, inline) - return box.value - -def select_detail(details): - """Pick the preferred type of detail from a list of details. (If the - argument isn't a list, treat it as a list of one.)""" - types = {"text/html": 30, - "application/xhtml+xml": 20, - "text/plain": 10} - - if details is None: - return None - if type(details) is not list: - details = [details] - - ds = [] - for detail in details: - ctype = detail.get("type", None) - if ctype is None: - continue - if types.has_key(ctype): - score = types[ctype] - else: - score = 0 - if detail["value"] != "": - ds.append((score, detail)) - ds.sort() - - if len(ds) == 0: - return None - else: - return ds[-1][1] - -def detail_to_html(details, inline, config, force_preformatted = False): - """Convert a detail hash or list of detail hashes as returned by - feedparser into HTML.""" - detail = select_detail(details) - if detail is None: - return None - - if force_preformatted: - html = "

" + cgi.escape(detail["value"]) + "
" - elif detail["type"] == "text/plain": - html = cgi.escape(detail["value"]) - else: - html = detail["value"] - - return sanitise_html(html, detail["base"], inline, config) - -def author_to_html(entry, feedurl, config): - """Convert feedparser author information to HTML.""" - author_detail = entry.get("author_detail") - - if author_detail is not None and author_detail.has_key("name"): - name = author_detail["name"] - else: - name = entry.get("author") - - url = None - fallback = "author" - if author_detail is not None: - if author_detail.has_key("url"): - url = author_detail["url"] - elif author_detail.has_key("email") and author_detail["email"] is not None: - url = "mailto:" + author_detail["email"] - if author_detail.has_key("email") and author_detail["email"] is not None: - fallback = author_detail["email"] - elif author_detail.has_key("url") and author_detail["url"] is not None: - fallback = author_detail["url"] - - if name == "": - name = fallback - - if url is None: - html = name - else: - html = "
" + cgi.escape(name) + "" - - # We shouldn't need a base URL here anyway. - return sanitise_html(html, feedurl, True, config) - -def string_to_html(s, config): - """Convert a string to HTML.""" - return sanitise_html(cgi.escape(s), "", True, config) - -template_re = re.compile(r'(__.*?__)') -def fill_template(template, bits): - """Expand a template, replacing __x__ with bits["x"], and only - including sections bracketed by __if_x__ .. [__else__ ..] - __endif__ if bits["x"] is not "". If not bits.has_key("x"), - __x__ expands to "".""" - result = plugins.Box() - plugins.call_hook("fill_template", template, bits, result) - if result.value is not None: - return result.value - - encoding = get_system_encoding() - - f = StringIO() - if_stack = [] - def write(s): - if not False in if_stack: - f.write(s) - for part in template_re.split(template): - if part.startswith("__") and part.endswith("__"): - key = part[2:-2] - if key.startswith("if_"): - k = key[3:] - if_stack.append(bits.has_key(k) and bits[k] != "") - elif key == "endif": - if if_stack != []: - if_stack.pop() - elif key == "else": - if if_stack != []: - if_stack.append(not if_stack.pop()) - elif bits.has_key(key): - if type(bits[key]) == types.UnicodeType: - write(bits[key].encode(encoding)) - else: - write(bits[key]) - else: - write(part) - v = f.getvalue() - f.close() - return unicode(v, 'utf-8').encode('ascii', 'xmlcharrefreplace') - -file_cache = {} -def load_file(name): - """Read the contents of a file, caching the result so we don't have to - read the file multiple times.""" - if not file_cache.has_key(name): - f = open(name) - file_cache[name] = f.read() - f.close() - return file_cache[name] - -def write_ascii(f, s, config): - """Write the string s, which should only contain ASCII characters, to - file f; if it isn't encodable in ASCII, then print a warning message - and write UTF-8.""" - try: - f.write(s) - except UnicodeEncodeError, e: - config.bug("Error encoding output as ASCII; UTF-8 has been written instead.\n", e) - f.write(s.encode("UTF-8")) - -def short_hash(s): - """Return a human-manipulatable 'short hash' of a string.""" - return new_sha1(s).hexdigest()[-8:] - -def decode_structure(struct, encoding): - """Walk through a structure returned by feedparser, decoding any - strings that haven't already been converted to Unicode.""" - def is_dict(t): - return (t is dict) or (t is feedparser.FeedParserDict) - for (key, value) in struct.items(): - if type(value) is str: - try: - struct[key] = value.decode(encoding) - except: - # If the encoding's invalid, at least preserve - # the byte stream. - struct[key] = value.decode("ISO-8859-1") - elif is_dict(type(value)): - decode_structure(value, encoding) - elif type(value) is list: - for item in value: - if is_dict(type(item)): - decode_structure(item, encoding) - -non_alphanumeric_re = re.compile(r'<[^>]*>|\&[^\;]*\;|[^a-z0-9]') -class Feed: - """An RSS feed.""" - - def __init__(self, url): - self.url = url - self.period = 30 * 60 - self.args = {} - self.etag = None - self.modified = None - self.last_update = 0 - self.feed_info = {} - - def needs_update(self, now): - """Return 1 if it's time to update this feed, or 0 if its - update period has not yet elapsed.""" - if (now - self.last_update) < self.period: - return 0 - else: - return 1 - - def get_state_filename(self): - return "feeds/%s.state" % (short_hash(self.url),) - - def fetch(self, rawdog, config): - """Fetch the current set of articles from the feed.""" - - handlers = [] - - proxies = {} - for key, arg in self.args.items(): - if key.endswith("_proxy"): - proxies[key[:-6]] = arg - if len(proxies) != 0: - handlers.append(urllib2.ProxyHandler(proxies)) - - if self.args.has_key("proxyuser") and self.args.has_key("proxypassword"): - mgr = DummyPasswordMgr((self.args["proxyuser"], self.args["proxypassword"])) - handlers.append(urllib2.ProxyBasicAuthHandler(mgr)) - - plugins.call_hook("add_urllib2_handlers", rawdog, config, self, handlers) - - auth_creds = None - if self.args.has_key("user") and self.args.has_key("password"): - auth_creds = (self.args["user"], self.args["password"]) - - use_im = True - if self.get_keepmin(config) == 0 or config["currentonly"]: - use_im = False - - try: - return feedparser.parse(self.url, - etag = self.etag, - modified = self.modified, - agent = "rawdog/" + VERSION, - handlers = handlers, - auth_creds = auth_creds, - use_im = use_im) - except: - return None - - def update(self, rawdog, now, config, articles, p): - """Add new articles from a feed to the collection. - Returns True if any articles were read, False otherwise.""" - - status = None - if p is not None: - status = p.get("status") - self.last_update = now - - error = None - non_fatal = False - old_url = self.url - if p is None: - error = "Error fetching or parsing feed." - elif status is None and len(p["feed"]) == 0: - if config["ignoretimeouts"]: - return False - else: - error = "Timeout while reading feed." - elif status is None: - # Fetched by some protocol that doesn't have status. - pass - elif status == 301: - # Permanent redirect. The feed URL needs changing. - - error = "New URL: " + p["url"] + "\n" - error += "The feed has moved permanently to a new URL.\n" - if config["changeconfig"]: - rawdog.change_feed_url(self.url, p["url"], config) - error += "The config file has been updated automatically." - else: - error += "You should update its entry in your config file." - non_fatal = True - elif status in [403, 410]: - # The feed is disallowed or gone. The feed should be unsubscribed. - error = "The feed has gone.\n" - error += "You should remove it from your config file." - elif status / 100 in [4, 5]: - # Some sort of client or server error. The feed may need unsubscribing. - error = "The feed returned an error.\n" - error += "If this condition persists, you should remove it from your config file." - - plugins.call_hook("feed_fetched", rawdog, config, self, p, error, non_fatal) - - if error is not None: - print >>sys.stderr, "Feed: " + old_url - if status is not None: - print >>sys.stderr, "HTTP Status: " + str(status) - print >>sys.stderr, error - print >>sys.stderr - if not non_fatal: - return False - - decode_structure(p, p.get("encoding") or "UTF-8") - - # In the event that the feed hasn't changed, then both channel - # and feed will be empty. In this case we return 0 so that - # we know not to expire articles that came from this feed. - if len(p["entries"]) == 0: - return False - - self.etag = p.get("etag") - self.modified = p.get("modified") - - self.feed_info = p["feed"] - feed = self.url - - article_ids = {} - if config["useids"]: - # Find IDs for existing articles. - for (hash, a) in articles.items(): - id = a.entry_info.get("id") - if a.feed == feed and id is not None: - article_ids[id] = a - - seen = {} - sequence = 0 - for entry_info in p["entries"]: - article = Article(feed, entry_info, now, sequence) - for feedconfig in config["feedslist"]: - if feedconfig[0] == feed: - if feedconfig[2].has_key("define_microblog") and feedconfig[2]["define_microblog"] == "true": - article.twitter = True - ignore = plugins.Box(False) - plugins.call_hook("article_seen", rawdog, config, article, ignore) - if ignore.value: - continue - seen[article.hash] = True - sequence += 1 - - id = entry_info.get("id") - if id in article_ids: - existing_article = article_ids[id] - elif article.hash in articles: - existing_article = articles[article.hash] - else: - existing_article = None - - if existing_article is not None: - existing_article.update_from(article, now) - plugins.call_hook("article_updated", rawdog, config, existing_article, now) - else: - articles[article.hash] = article - plugins.call_hook("article_added", rawdog, config, article, now) - - if config["currentonly"]: - for (hash, a) in articles.items(): - if a.feed == feed and not seen.has_key(hash): - del articles[hash] - - return True - - def get_html_name(self, config): - if self.feed_info.has_key("title_detail"): - r = detail_to_html(self.feed_info["title_detail"], True, config) - elif self.feed_info.has_key("link"): - r = string_to_html(self.feed_info["link"], config) - else: - r = string_to_html(self.url, config) - if r is None: - r = "" - return r - - def get_html_link(self, config): - s = unicode(self.args['define_name'], 'utf-8').encode('ascii', 'xmlcharrefreplace') - if self.feed_info.has_key("link"): - return '' + s + '' - else: - return s - - def get_id(self, config): - if self.args.has_key("id"): - return self.args["id"] - else: - r = self.get_html_name(config).lower() - return non_alphanumeric_re.sub('', r) - - def get_keepmin(self, config): - try: - return int(self.args["keepmin"]) - except: - return config["keepmin"] - -class Article: - """An article retrieved from an RSS feed.""" - - def __init__(self, feed, entry_info, now, sequence): - self.feed = feed - self.entry_info = entry_info - self.sequence = sequence - self.twitter = False - - modified = entry_info.get("modified_parsed") - self.date = None - if modified is not None: - try: - self.date = calendar.timegm(modified) - except OverflowError: - pass - - self.hash = self.compute_initial_hash() - - self.last_seen = now - self.added = now - - def compute_initial_hash(self): - """Compute an initial unique hash for an article. - The generated hash must be unique amongst all articles in the - system (i.e. it can't just be the article ID, because that - would collide if more than one feed included the same - article).""" - h = new_sha1() - def add_hash(s): - h.update(s.encode("UTF-8")) - - add_hash(self.feed) - entry_info = self.entry_info - if entry_info.has_key("title_raw"): - add_hash(entry_info["title_raw"]) - if entry_info.has_key("link"): - add_hash(entry_info["link"]) - if entry_info.has_key("content"): - for content in entry_info["content"]: - add_hash(content["value_raw"]) - if entry_info.has_key("summary_detail"): - add_hash(entry_info["summary_detail"]["value_raw"]) - - return h.hexdigest() - - def update_from(self, new_article, now): - """Update this article's contents from a newer article that's - been identified to be the same.""" - self.entry_info = new_article.entry_info - self.sequence = new_article.sequence - self.date = new_article.date - self.last_seen = now - - def can_expire(self, now, config): - return ((now - self.last_seen) > config["expireage"]) - - def get_sort_date(self, config): - if config["sortbyfeeddate"]: - return self.date or self.added - else: - return self.added - -class DayWriter: - """Utility class for writing day sections into a series of articles.""" - - def __init__(self, file, config): - self.lasttime = [-1, -1, -1, -1, -1] - self.file = file - self.counter = 0 - self.config = config - - def start_day(self, tm): - print >>self.file, '
' - day = safe_ftime(self.config["dayformat"], tm) - print >>self.file, '

' + day + '

' - self.counter += 1 - - def start_time(self, tm): - print >>self.file, '
' - clock = safe_ftime(self.config["timeformat"], tm) - print >>self.file, '

' + clock + '

' - self.counter += 1 - - def time(self, s): - tm = time.localtime(s) - if tm[:3] != self.lasttime[:3] and self.config["daysections"]: - self.close(0) - self.start_day(tm) - if tm[:6] != self.lasttime[:6] and self.config["timesections"]: - if self.config["daysections"]: - self.close(1) - else: - self.close(0) - self.start_time(tm) - self.lasttime = tm - - def close(self, n = 0): - while self.counter > n: - print >>self.file, "
" - self.counter -= 1 - -def parse_time(value, default = "m"): - """Parse a time period with optional units (s, m, h, d, w) into a time - in seconds. If no unit is specified, use minutes by default; specify - the default argument to change this. Raises ValueError if the format - isn't recognised.""" - units = { "s" : 1, "m" : 60, "h" : 3600, "d" : 86400, "w" : 604800 } - for unit, size in units.items(): - if value.endswith(unit): - return int(value[:-len(unit)]) * size - return int(value) * units[default] - -def parse_bool(value): - """Parse a boolean value (0, 1, false or true). Raise ValueError if - the value isn't recognised.""" - value = value.strip().lower() - if value == "0" or value == "false": - return 0 - elif value == "1" or value == "true": - return 1 - else: - raise ValueError("Bad boolean value: " + value) - -def parse_list(value): - """Parse a list of keywords separated by whitespace.""" - return value.strip().split(None) - -def parse_feed_args(argparams, arglines): - """Parse a list of feed arguments. Raise ConfigError if the syntax is invalid.""" - args = {} - for p in argparams: - ps = p.split("=", 1) - if len(ps) != 2: - raise ConfigError("Bad feed argument in config: " + p) - args[ps[0]] = ps[1] - for p in arglines: - ps = p.split(None, 1) - if len(ps) != 2: - raise ConfigError("Bad argument line in config: " + p) - args[ps[0]] = ps[1] - if "maxage" in args: - args["maxage"] = parse_time(args["maxage"]) - return args - -class ConfigError(Exception): pass - -class Config: - """The aggregator's configuration.""" - - def __init__(self, locking): - self.locking = locking - self.files_loaded = [] - if have_threading: - self.loglock = threading.Lock() - self.reset() - - def reset(self): - self.config = { - "feedslist" : [], - "feeddefaults" : {}, - "defines" : {}, - "outputfile" : "output.html", - "oldpages" : 5, - "maxarticles" : 200, - "maxage" : 0, - "expireage" : 24 * 60 * 60, - "keepmin" : 0, - "dayformat" : "%A, %d %B %Y", - "timeformat" : "%I:%M %p", - "datetimeformat" : None, - "userefresh" : 0, - "showfeeds" : 1, - "timeout" : 30, - "template" : "default", - "itemtemplate" : "default", - "verbose" : 0, - "ignoretimeouts" : 0, - "daysections" : 1, - "timesections" : 1, - "blocklevelhtml" : 1, - "tidyhtml" : 0, - "sortbyfeeddate" : 0, - "currentonly" : 0, - "hideduplicates" : "", - "newfeedperiod" : "3h", - "changeconfig": 0, - "numthreads": 0, - "splitstate": 0, - "useids": 0, - } - - def __getitem__(self, key): return self.config[key] - def __setitem__(self, key, value): self.config[key] = value - - def reload(self): - self.log("Reloading config files") - self.reset() - for filename in self.files_loaded: - self.load(filename, False) - - def load(self, filename, explicitly_loaded = True): - """Load configuration from a config file.""" - if explicitly_loaded: - self.files_loaded.append(filename) - - lines = [] - try: - f = open(filename, "r") - for line in f.xreadlines(): - stripped = line.strip() - if stripped == "" or stripped[0] == "#": - continue - if line[0] in string.whitespace: - if lines == []: - raise ConfigError("First line in config cannot be an argument") - lines[-1][1].append(stripped) - else: - lines.append((stripped, [])) - f.close() - except IOError: - raise ConfigError("Can't read config file: " + filename) - - for line, arglines in lines: - try: - self.load_line(line, arglines) - except ValueError: - raise ConfigError("Bad value in config: " + line) - - def load_line(self, line, arglines): - """Process a configuration directive.""" - - l = line.split(None, 1) - if len(l) == 1 and l[0] == "feeddefaults": - l.append("") - elif len(l) != 2: - raise ConfigError("Bad line in config: " + line) - - handled_arglines = False - if l[0] == "feed": - l = l[1].split(None) - if len(l) < 2: - raise ConfigError("Bad line in config: " + line) - self["feedslist"].append((l[1], parse_time(l[0]), parse_feed_args(l[2:], arglines))) - handled_arglines = True - elif l[0] == "feeddefaults": - self["feeddefaults"] = parse_feed_args(l[1].split(None), arglines) - handled_arglines = True - elif l[0] == "define": - l = l[1].split(None, 1) - if len(l) != 2: - raise ConfigError("Bad line in config: " + line) - self["defines"][l[0]] = l[1] - elif l[0] == "plugindirs": - for dir in parse_list(l[1]): - plugins.load_plugins(dir, self) - elif l[0] == "outputfile": - self["outputfile"] = l[1] - elif l[0] == "oldpages": - self["oldpages"] = l[1] - elif l[0] == "maxarticles": - self["maxarticles"] = int(l[1]) - elif l[0] == "maxage": - self["maxage"] = parse_time(l[1]) - elif l[0] == "expireage": - self["expireage"] = parse_time(l[1]) - elif l[0] == "keepmin": - self["keepmin"] = int(l[1]) - elif l[0] == "dayformat": - self["dayformat"] = l[1] - elif l[0] == "timeformat": - self["timeformat"] = l[1] - elif l[0] == "datetimeformat": - self["datetimeformat"] = l[1] - elif l[0] == "userefresh": - self["userefresh"] = parse_bool(l[1]) - elif l[0] == "showfeeds": - self["showfeeds"] = parse_bool(l[1]) - elif l[0] == "timeout": - self["timeout"] = parse_time(l[1], "s") - elif l[0] == "template": - self["template"] = l[1] - elif l[0] == "itemtemplate": - self["itemtemplate"] = l[1] - elif l[0] == "verbose": - self["verbose"] = parse_bool(l[1]) - elif l[0] == "ignoretimeouts": - self["ignoretimeouts"] = parse_bool(l[1]) - elif l[0] == "daysections": - self["daysections"] = parse_bool(l[1]) - elif l[0] == "timesections": - self["timesections"] = parse_bool(l[1]) - elif l[0] == "blocklevelhtml": - self["blocklevelhtml"] = parse_bool(l[1]) - elif l[0] == "tidyhtml": - self["tidyhtml"] = parse_bool(l[1]) - elif l[0] == "sortbyfeeddate": - self["sortbyfeeddate"] = parse_bool(l[1]) - elif l[0] == "currentonly": - self["currentonly"] = parse_bool(l[1]) - elif l[0] == "hideduplicates": - self["hideduplicates"] = parse_list(l[1]) - elif l[0] == "newfeedperiod": - self["newfeedperiod"] = l[1] - elif l[0] == "changeconfig": - self["changeconfig"] = parse_bool(l[1]) - elif l[0] == "numthreads": - self["numthreads"] = int(l[1]) - elif l[0] == "splitstate": - self["splitstate"] = parse_bool(l[1]) - elif l[0] == "useids": - self["useids"] = parse_bool(l[1]) - elif l[0] == "include": - self.load(l[1], False) - elif plugins.call_hook("config_option_arglines", self, l[0], l[1], arglines): - handled_arglines = True - elif plugins.call_hook("config_option", self, l[0], l[1]): - pass - else: - raise ConfigError("Unknown config command: " + l[0]) - - if arglines != [] and not handled_arglines: - raise ConfigError("Bad argument lines in config after: " + line) - - def log(self, *args): - """If running in verbose mode, print a status message.""" - if self["verbose"]: - if have_threading: - self.loglock.acquire() - print >>sys.stderr, "".join(map(str, args)) - if have_threading: - self.loglock.release() - - def bug(self, *args): - """Report detection of a bug in rawdog.""" - print >>sys.stderr, "Internal error detected in rawdog:" - print >>sys.stderr, "".join(map(str, args)) - print >>sys.stderr, "This could be caused by a bug in rawdog itself or in a plugin." - print >>sys.stderr, "Please send this error message and your config file to the rawdog author." - -def edit_file(filename, editfunc): - """Edit a file in place: for each line in the input file, call - editfunc(line, outputfile), then rename the output file over the input - file.""" - newname = "%s.new-%d" % (filename, os.getpid()) - oldfile = open(filename, "r") - newfile = open(newname, "w") - editfunc(oldfile, newfile) - newfile.close() - oldfile.close() - os.rename(newname, filename) - -class AddFeedEditor: - def __init__(self, feedline): - self.feedline = feedline - def edit(self, inputfile, outputfile): - d = inputfile.read() - outputfile.write(d) - if not d.endswith("\n"): - outputfile.write("\n") - outputfile.write(self.feedline) - -def add_feed(filename, url, rawdog, config): - """Try to add a feed to the config file.""" - if feedfinder is None: - feeds = [url] - else: - feeds = feedfinder.feeds(url) - if feeds == []: - print >>sys.stderr, "Cannot find any feeds in " + url - else: - feed = feeds[0] - if feed in rawdog.feeds: - print >>sys.stderr, "Feed " + feed + " is already in the config file" - else: - print >>sys.stderr, "Adding feed " + feed - feedline = "feed %s %s\n" % (config["newfeedperiod"], feed) - edit_file(filename, AddFeedEditor(feedline).edit) - -class ChangeFeedEditor: - def __init__(self, oldurl, newurl): - self.oldurl = oldurl - self.newurl = newurl - def edit(self, inputfile, outputfile): - for line in inputfile.xreadlines(): - ls = line.strip().split(None) - if len(ls) > 2 and ls[0] == "feed" and ls[2] == self.oldurl: - line = line.replace(self.oldurl, self.newurl, 1) - outputfile.write(line) - -class RemoveFeedEditor: - def __init__(self, url): - self.url = url - def edit(self, inputfile, outputfile): - while 1: - l = inputfile.readline() - if l == "": - break - ls = l.strip().split(None) - if len(ls) > 2 and ls[0] == "feed" and ls[2] == self.url: - while 1: - l = inputfile.readline() - if l == "": - break - elif l[0] == "#": - outputfile.write(l) - elif l[0] not in string.whitespace: - outputfile.write(l) - break - else: - outputfile.write(l) - -def remove_feed(filename, url, config): - """Try to remove a feed from the config file.""" - if url not in [f[0] for f in config["feedslist"]]: - print >>sys.stderr, "Feed " + url + " is not in the config file" - else: - print >>sys.stderr, "Removing feed " + url - edit_file(filename, RemoveFeedEditor(url).edit) - -class FeedFetcher: - """Class that will handle fetching a set of feeds in parallel.""" - - def __init__(self, rawdog, feedlist, config): - self.rawdog = rawdog - self.config = config - self.lock = threading.Lock() - self.jobs = {} - for feed in feedlist: - self.jobs[feed] = 1 - self.results = {} - - def worker(self, num): - rawdog = self.rawdog - config = self.config - - config.log("Thread ", num, " starting") - while 1: - self.lock.acquire() - if self.jobs == {}: - job = None - else: - job = self.jobs.keys()[0] - del self.jobs[job] - self.lock.release() - if job is None: - break - - config.log("Thread ", num, " fetching feed: ", job) - feed = rawdog.feeds[job] - plugins.call_hook("pre_update_feed", rawdog, config, feed) - self.results[job] = feed.fetch(rawdog, config) - config.log("Thread ", num, " done") - - def run(self, numworkers): - self.config.log("Thread farm starting with ", len(self.jobs), " jobs") - workers = [] - for i in range(numworkers): - self.lock.acquire() - isempty = (self.jobs == {}) - self.lock.release() - if isempty: - # No jobs left in the queue -- don't bother - # starting any more workers. - break - - t = threading.Thread(target = self.worker, args = (i,)) - t.start() - workers.append(t) - for worker in workers: - worker.join() - self.config.log("Thread farm finished with ", len(self.results), " results") - return self.results - -class FeedState(Persistable): - """The collection of articles in a feed.""" - - def __init__(self): - self.articles = {} - -class Rawdog(Persistable): - """The aggregator itself.""" - - def __init__(self): - self.feeds = {} - self.articles = {} - self.plugin_storage = {} - self.state_version = STATE_VERSION - self.using_splitstate = None - - def get_plugin_storage(self, plugin): - try: - st = self.plugin_storage.setdefault(plugin, {}) - except AttributeError: - # rawdog before 2.5 didn't have plugin storage. - st = {} - self.plugin_storage = {plugin: st} - return st - - def check_state_version(self): - """Check the version of the state file.""" - try: - version = self.state_version - except AttributeError: - # rawdog 1.x didn't keep track of this. - version = 1 - return version == STATE_VERSION - - def change_feed_url(self, oldurl, newurl, config): - """Change the URL of a feed.""" - - assert self.feeds.has_key(oldurl) - if self.feeds.has_key(newurl): - print >>sys.stderr, "Error: New feed URL is already subscribed; please remove the old one" - print >>sys.stderr, "from the config file by hand." - return - - edit_file("config", ChangeFeedEditor(oldurl, newurl).edit) - - feed = self.feeds[oldurl] - old_state = feed.get_state_filename() - feed.url = newurl - del self.feeds[oldurl] - self.feeds[newurl] = feed - - if config["splitstate"]: - persister, feedstate = load_persisted(feed.get_state_filename(), FeedState, config) - for article in feedstate.articles.values(): - article.feed = newurl - feedstate.modified() - save_persisted(persister, config) - os.rename(old_state, feed.get_state_filename()) - else: - for article in self.articles.values(): - if article.feed == oldurl: - article.feed = newurl - - print >>sys.stderr, "Feed URL automatically changed." - - def list(self, config): - """List the configured feeds.""" - for url, feed in self.feeds.items(): - feed_info = feed.feed_info - print url - print " ID:", feed.get_id(config) - print " Hash:", short_hash(url) - print " Title:", feed.get_html_name(config) - print " Link:", feed_info.get("link") - - def sync_from_config(self, config): - """Update rawdog's internal state to match the - configuration.""" - - try: - u = self.using_splitstate - except: - # We were last run with a version of rawdog that didn't - # have this variable -- so we must have a single state - # file. - u = False - if u is None: - self.using_splitstate = config["splitstate"] - elif u != config["splitstate"]: - if config["splitstate"]: - config.log("Converting to split state files") - for feed_hash, feed in self.feeds.items(): - persister, feedstate = load_persisted(feed.get_state_filename(), FeedState, config) - feedstate.articles = {} - for article_hash, article in self.articles.items(): - if article.feed == feed_hash: - feedstate.articles[article_hash] = article - feedstate.modified() - save_persisted(persister, config) - self.articles = {} - else: - config.log("Converting to single state file") - self.articles = {} - for feed_hash, feed in self.feeds.items(): - persister, feedstate = load_persisted(feed.get_state_filename(), FeedState, config) - for article_hash, article in feedstate.articles.items(): - self.articles[article_hash] = article - feedstate.articles = {} - feedstate.modified() - save_persisted(persister, config) - os.unlink(feed.get_state_filename()) - self.modified() - self.using_splitstate = config["splitstate"] - - seenfeeds = {} - for (url, period, args) in config["feedslist"]: - seenfeeds[url] = 1 - if not self.feeds.has_key(url): - config.log("Adding new feed: ", url) - self.feeds[url] = Feed(url) - self.modified() - feed = self.feeds[url] - if feed.period != period: - config.log("Changed feed period: ", url) - feed.period = period - self.modified() - newargs = {} - newargs.update(config["feeddefaults"]) - newargs.update(args) - if feed.args != newargs: - config.log("Changed feed options: ", url) - feed.args = newargs - self.modified() - for url in self.feeds.keys(): - if not seenfeeds.has_key(url): - config.log("Removing feed: ", url) - if config["splitstate"]: - try: - os.unlink(self.feeds[url].get_state_filename()) - except OSError: - pass - else: - for key, article in self.articles.items(): - if article.feed == url: - del self.articles[key] - del self.feeds[url] - self.modified() - - def update(self, config, feedurl = None): - """Perform the update action: check feeds for new articles, and - expire old ones.""" - config.log("Starting update") - now = time.time() - - feedparser._FeedParserMixin.can_contain_relative_uris = ["url"] - feedparser._FeedParserMixin.can_contain_dangerous_markup = [] - set_socket_timeout(config["timeout"]) - - if feedurl is None: - update_feeds = [url for url in self.feeds.keys() - if self.feeds[url].needs_update(now)] - elif self.feeds.has_key(feedurl): - update_feeds = [feedurl] - self.feeds[feedurl].etag = None - self.feeds[feedurl].modified = None - else: - print "No such feed: " + feedurl - update_feeds = [] - - numfeeds = len(update_feeds) - config.log("Will update ", numfeeds, " feeds") - - if have_threading and config["numthreads"] > 0: - fetcher = FeedFetcher(self, update_feeds, config) - prefetched = fetcher.run(config["numthreads"]) - else: - prefetched = {} - - seen_some_items = {} - def do_expiry(articles): - feedcounts = {} - for key, article in articles.items(): - url = article.feed - feedcounts[url] = feedcounts.get(url, 0) + 1 - - expiry_list = [] - feedcounts = {} - for key, article in articles.items(): - url = article.feed - feedcounts[url] = feedcounts.get(url, 0) + 1 - expiry_list.append((article.added, article.sequence, key, article)) - expiry_list.sort() - - count = 0 - for date, seq, key, article in expiry_list: - url = article.feed - if url not in self.feeds: - config.log("Expired article for nonexistent feed: ", url) - count += 1 - del articles[key] - continue - if (seen_some_items.has_key(url) - and self.feeds.has_key(url) - and article.can_expire(now, config) - and feedcounts[url] > self.feeds[url].get_keepmin(config)): - plugins.call_hook("article_expired", self, config, article, now) - count += 1 - feedcounts[url] -= 1 - del articles[key] - config.log("Expired ", count, " articles, leaving ", len(articles)) - - count = 0 - for url in update_feeds: - count += 1 - config.log("Updating feed ", count, " of " , numfeeds, ": ", url) - feed = self.feeds[url] - - if config["splitstate"]: - persister, feedstate = load_persisted(feed.get_state_filename(), FeedState, config) - articles = feedstate.articles - else: - articles = self.articles - - if url in prefetched: - content = prefetched[url] - else: - plugins.call_hook("pre_update_feed", self, config, feed) - content = feed.fetch(self, config) - plugins.call_hook("mid_update_feed", self, config, feed, content) - rc = feed.update(self, now, config, articles, content) - url = feed.url - plugins.call_hook("post_update_feed", self, config, feed, rc) - if rc: - seen_some_items[url] = 1 - if config["splitstate"]: - feedstate.modified() - - if config["splitstate"]: - do_expiry(articles) - save_persisted(persister, config) - - if config["splitstate"]: - self.articles = {} - else: - do_expiry(self.articles) - - self.modified() - config.log("Finished update") - - def get_template(self, config): - """Get the main template.""" - if config["template"] != "default": - return load_file(config["template"]) - - template = """ - - - - -""" - if config["userefresh"]: - template += """__refresh__ -""" - template += """ - rawdog - - - -
-__items__ -
-""" - if config["showfeeds"]: - template += """

Feeds

-
-__feeds__ -
-""" - template += """ - - -""" - return template - - def get_itemtemplate(self, config): - """Get the item template.""" - if config["itemtemplate"] != "default": - return load_file(config["itemtemplate"]) - - template = """
-

-__title__ -[__feed_title__] -

-__if_description__
-__description__ -
__endif__ -
- -""" - return template - - def show_template(self, config): - """Show the configured main template.""" - print self.get_template(config) - - def show_itemtemplate(self, config): - """Show the configured item template.""" - print self.get_itemtemplate(config) - - def write_article(self, f, article, config): - """Write an article to the given file.""" - feed = self.feeds[article.feed] - feed_info = feed.feed_info - entry_info = article.entry_info - - link = entry_info.get("link") - if link == "": - link = None - - guid = entry_info.get("id") - if guid == "": - guid = None - - itembits = {} - for name, value in feed.args.items(): - if name.startswith("define_"): - itembits[name[7:]] = value - - title = detail_to_html(entry_info.get("title_detail"), True, config) - - key = None - for k in ["content", "summary_detail"]: - if entry_info.has_key(k): - key = k - break - if key is None: - description = None - else: - force_preformatted = feed.args.has_key("format") and (feed.args["format"] == "text") - description = detail_to_html(entry_info[key], False, config, force_preformatted) - - date = article.date - if title is None: - if link is None: - title = "Article" - else: - title = "Link" - - if 'twitter' in dir(article) and article.twitter: - split = title.split(":", 1) - text = split[0] + "" - split[1] = split[1].lstrip() - if split[1].startswith("@"): - atSplit = split[1].split(" ", 1) - twitterLink = atSplit[0].lstrip("@") - twitterLink = twitterLink.rstrip(":") - if len(atSplit) >= 2: - text = text + " " + atSplit[0] + "" + " " + atSplit[1] - else: - text = text + " " + atSplit[0] + "" - else: - text = text + " " + split[1] - itembits["title_no_link"] = text - else: - itembits["title_no_link"] = title - if link is not None: - itembits["url"] = string_to_html(link, config) - else: - itembits["url"] = "" - if guid is not None: - itembits["guid"] = string_to_html(guid, config) - else: - itembits["guid"] = "" - if link is None: - itembits["title"] = title - else: - itembits["title"] = '' + title + '' - - itembits["feed_title_no_link"] = detail_to_html(feed_info.get("title_detail"), True, config) - itembits["feed_title"] = feed.get_html_link(config) - itembits["feed_url"] = string_to_html(feed.url, config) - itembits["feed_hash"] = short_hash(feed.url) - itembits["feed_id"] = feed.get_id(config) - itembits["hash"] = short_hash(article.hash) - - if hasattr(feed_info, 'links'): - itembits["blogurl"] = feed_info.links[0]['href'] - else: - itembits["blogurl"] = "" - - if description is not None: - itembits["description"] = description - else: - itembits["description"] = "" - - author = author_to_html(entry_info, feed.url, config) - if author is not None: - itembits["author"] = author - else: - itembits["author"] = "" - - itembits["added"] = format_time(article.added, config) - if date is not None: - itembits["date"] = format_time(date, config) - else: - itembits["date"] = "" - - plugins.call_hook("output_item_bits", self, config, feed, article, itembits) - if 'twitter' in dir(article) and article.twitter: - itemtemplate = load_file("microblogitemtemplate") - else: - itemtemplate = self.get_itemtemplate(config) - - itembits['name'] = unicode(itembits['name'], 'utf-8').encode("ascii", "xmlcharrefreplace") - - f.write(fill_template(itemtemplate, itembits)) - - def write_remove_dups(self, articles, config, now): - """Filter the list of articles to remove articles that are too - old or are duplicates.""" - kept_articles = [] - seen_links = {} - seen_guids = {} - dup_count = 0 - for article in articles: - feed = self.feeds[article.feed] - age = now - article.added - - maxage = config["maxage"] - if "maxage" in feed.args: - maxage = feed.args["maxage"] - if maxage != 0 and age > maxage: - continue - - entry_info = article.entry_info - - link = entry_info.get("link") - if link == "": - link = None - - guid = entry_info.get("id") - if guid == "": - guid = None - - if feed.args.get("allowduplicates") != "true": - is_dup = False - for key in config["hideduplicates"]: - if key == "id" and guid is not None: - if seen_guids.has_key(guid): - is_dup = True - seen_guids[guid] = 1 - break - elif key == "link" and link is not None: - if seen_links.has_key(link): - is_dup = True - seen_links[link] = 1 - break - if is_dup: - dup_count += 1 - continue - - kept_articles.append(article) - return (kept_articles, dup_count) - - def get_main_template_bits(self, config): - """Get the bits that are used in the default main template, - with the exception of items and num_items.""" - bits = { "version" : VERSION } - bits.update(config["defines"]) - - refresh = config["expireage"] - for feed in self.feeds.values(): - if feed.period < refresh: refresh = feed.period - - bits["refresh"] = """""" - - f = StringIO() - print >>f, """ - - -""" - feeds = [(feed.get_html_name(config).lower(), feed) - for feed in self.feeds.values()] - feeds.sort() - for (key, feed) in feeds: - print >>f, '' - print >>f, '' - print >>f, '' - print >>f, '' - print >>f, '' - print >>f, '' - print >>f, """
FeedRSSLast fetchedNext fetched after
' + feed.get_html_link(config) + 'XML' + format_time(feed.last_update, config) + '' + format_time(feed.last_update + feed.period, config) + '
""" - bits["feeds"] = f.getvalue() - f.close() - bits["num_feeds"] = str(len(feeds)) - - return bits - - def write_output_file(self, articles, twitterArticles, article_dates, config, oldpage=0): - """Write a regular rawdog HTML output file.""" - f = StringIO() - dw = DayWriter(f, config) - plugins.call_hook("output_items_begin", self, config, f) - - for article in articles: - if not plugins.call_hook("output_items_heading", self, config, f, article, article_dates[article]): - dw.time(article_dates[article]) - - self.write_article(f, article, config) - - dw.close() - plugins.call_hook("output_items_end", self, config, f) - - if oldpage != config["oldpages"]: - filename = config["outputfile"].split("/")[-1:][0] # get the filename only - filename = filename.split(".html") - outputfile = filename[0] + str(oldpage+1) + ".html" - f.write('

Older blog entries

') - - bits = self.get_main_template_bits(config) - bits["items"] = f.getvalue() - f.close() - bits["num_items"] = str(len(articles)) - - #TWITTER - f = StringIO() - dw = DayWriter(f, config) - - for article in twitterArticles[:60]: - self.write_article(f, article, config) - - dw.close() - - bits["twitter"] = f.getvalue() - #end of TWITTER - - plugins.call_hook("output_bits", self, config, bits) - s = fill_template(self.get_template(config), bits) - if oldpage > 0: - filename = config["outputfile"].split(".html") - outputfile = filename[0] + str(oldpage) + ".html" - else: - outputfile = config["outputfile"] - if outputfile == "-": - write_ascii(sys.stdout, s, config) - else: - config.log("Writing output file: ", outputfile) - f = open(outputfile + ".new", "w") - write_ascii(f, s, config) - f.close() - os.rename(outputfile + ".new", outputfile) - - def write(self, config): - """Perform the write action: write articles to the output - file.""" - config.log("Starting write") - now = time.time() - - def list_articles(articles): - return [(-a.get_sort_date(config), a.feed, a.sequence, a.hash) for a in articles.values()] - if config["splitstate"]: - article_list = [] - for feed in self.feeds.values(): - persister, feedstate = load_persisted(feed.get_state_filename(), FeedState, config) - article_list += list_articles(feedstate.articles) - save_persisted(persister, config) - else: - article_list = list_articles(self.articles) - numarticles = len(article_list) - - if not plugins.call_hook("output_sort_articles", self, config, article_list): - article_list.sort() - -#for multiple pages split further down -# if config["maxarticles"] != 0: -# article_list = article_list[:config["maxarticles"]] - - if config["splitstate"]: - wanted = {} - for (date, feed_url, seq, hash) in article_list: - if not feed_url in self.feeds: - # This can happen if you've managed to - # kill rawdog between it updating a - # split state file and the main state - # -- so just ignore the article and - # it'll expire eventually. - continue - wanted.setdefault(feed_url, []).append(hash) - - found = {} - for (feed_url, article_hashes) in wanted.items(): - feed = self.feeds[feed_url] - persister, feedstate = load_persisted(feed.get_state_filename(), FeedState, config) - for hash in article_hashes: - found[hash] = feedstate.articles[hash] - save_persisted(persister, config) - else: - found = self.articles - - articles = [] - article_dates = {} - for (date, feed, seq, hash) in article_list: - a = found.get(hash) - if a is not None: - if a.date is not None: #Added jriddell 2008-09-15, we don't want to show articles with no date - articles.append(a) - article_dates[a] = -date - - twitterArticles = [] - normalArticles = [] - for article in articles: - if 'twitter' in dir(article) and article.twitter == True: - twitterArticles.append(article) - else: - normalArticles.append(article) - articles = normalArticles - - plugins.call_hook("output_write", self, config, articles) - - if not plugins.call_hook("output_sorted_filter", self, config, articles): - (articles, dup_count) = self.write_remove_dups(articles, config, now) - else: - dup_count = 0 - - config.log("Selected ", len(articles), " of ", numarticles, " articles to write; ignored ", dup_count, " duplicates") - - for page in range(0, config["oldpages"]+1): - if config["maxarticles"] != 0: - pageArticles = articles[config["maxarticles"]*page:config["maxarticles"]*(page+1)] - - if not plugins.call_hook("output_write_files", self, config, pageArticles, article_dates): - self.write_output_file(pageArticles, twitterArticles, article_dates, config, page) - - config.log("Finished write") - -def usage(): - """Display usage information.""" - print """rawdog, version """ + VERSION + """ -Usage: rawdog [OPTION]... - -General options (use only once): --d|--dir DIR Use DIR instead of ~/.rawdog --v, --verbose Print more detailed status information --N, --no-locking Do not lock the state file --W, --no-lock-wait Exit silently if state file is locked ---help Display this help and exit - -Actions (performed in order given): --u, --update Fetch data from feeds and store it --l, --list List feeds known at time of last update --w, --write Write out HTML output --f|--update-feed URL Force an update on the single feed URL --c|--config FILE Read additional config file FILE --t, --show-template Print the template currently in use --T, --show-itemtemplate Print the item template currently in use --a|--add URL Try to find a feed associated with URL and - add it to the config file --r|--remove URL Remove feed URL from the config file - -Special actions (all other options are ignored if one of these is specified): ---upgrade OLDDIR NEWDIR Import feed state from rawdog 1.x directory - OLDDIR into rawdog 2.x directory NEWDIR - -Report bugs to .""" - -def load_persisted(fn, klass, config, no_block = False): - """Attempt to load a persisted object. Returns the persister and the - object.""" - config.log("Loading state file: ", fn) - persister = Persister(fn, klass, config.locking) - try: - obj = persister.load(no_block = no_block) - except KeyboardInterrupt: - sys.exit(1) - except: - print "An error occurred while reading state from " + os.getcwd() + "/" + fn + "." - print "This usually means the file is corrupt, and removing it will fix the problem." - sys.exit(1) - return (persister, obj) - -def save_persisted(persister, config): - if persister.object.is_modified(): - config.log("Saving state file: ", persister.filename) - persister.save() - -def main(argv): - """The command-line interface to the aggregator.""" - - locale.setlocale(locale.LC_ALL, "") - - global system_encoding - try: - # This doesn't exist on Python 2.2. - # It's also quite expensive, which is why we do it on startup - # and cache the result. - system_encoding = locale.getpreferredencoding() - except: - system_encoding = "UTF-8" - - try: - (optlist, args) = getopt.getopt(argv, "ulwf:c:tTd:va:r:NW", ["update", "list", "write", "update-feed=", "help", "config=", "show-template", "dir=", "show-itemtemplate", "verbose", "upgrade", "add=", "remove=", "no-locking", "no-lock-wait"]) - except getopt.GetoptError, s: - print s - usage() - return 1 - - for o, a in optlist: - if o == "--upgrade" and len(args) == 2: - import upgrade_1_2 - return upgrade_1_2.upgrade(args[0], args[1]) - - if len(args) != 0: - usage() - return 1 - - if "HOME" in os.environ: - statedir = os.environ["HOME"] + "/.rawdog" - else: - statedir = None - verbose = 0 - locking = 1 - no_lock_wait = 0 - for o, a in optlist: - if o == "--help": - usage() - return 0 - elif o in ("-d", "--dir"): - statedir = a - elif o in ("-v", "--verbose"): - verbose = 1 - elif o in ("-N", "--no-locking"): - locking = 0 - elif o in ("-W", "--no-lock-wait"): - no_lock_wait = 1 - if statedir is None: - print "$HOME not set and state dir not explicitly specified; please use -d/--dir" - return 1 - - try: - os.chdir(statedir) - except OSError: - print "No " + statedir + " directory" - return 1 - - sys.path.append(".") - - config = Config(locking) - try: - config.load("config") - except ConfigError, err: - print >>sys.stderr, "In config:" - print >>sys.stderr, err - return 1 - if verbose: - config["verbose"] = True - - persister, rawdog = load_persisted("state", Rawdog, config, no_lock_wait) - if rawdog is None: - return 0 - if not rawdog.check_state_version(): - print "The state file " + statedir + "/state was created by an older" - print "version of rawdog, and cannot be read by this version." - print "Removing the state file will fix it." - return 1 - - rawdog.sync_from_config(config) - - plugins.call_hook("startup", rawdog, config) - - for o, a in optlist: - if o in ("-u", "--update"): - rawdog.update(config) - elif o in ("-f", "--update-feed"): - rawdog.update(config, a) - elif o in ("-l", "--list"): - rawdog.list(config) - elif o in ("-w", "--write"): - rawdog.write(config) - elif o in ("-c", "--config"): - try: - config.load(a) - except ConfigError, err: - print >>sys.stderr, "In " + a + ":" - print >>sys.stderr, err - return 1 - elif o in ("-t", "--show-template"): - rawdog.show_template(config) - elif o in ("-T", "--show-itemtemplate"): - rawdog.show_itemtemplate(config) - elif o in ("-a", "--add"): - add_feed("config", a, rawdog, config) - config.reload() - rawdog.sync_from_config(config) - elif o in ("-r", "--remove"): - remove_feed("config", a, config) - config.reload() - rawdog.sync_from_config(config) - - plugins.call_hook("shutdown", rawdog, config) - - save_persisted(persister, config) - - return 0 - diff --git a/rawdoglib/timeoutsocket.py b/rawdoglib/timeoutsocket.py deleted file mode 100644 --- a/rawdoglib/timeoutsocket.py +++ /dev/null @@ -1,424 +0,0 @@ - -#### -# Copyright 2000,2001 by Timothy O'Malley -# -# All Rights Reserved -# -# Permission to use, copy, modify, and distribute this software -# and its documentation for any purpose and without fee is hereby -# granted, provided that the above copyright notice appear in all -# copies and that both that copyright notice and this permission -# notice appear in supporting documentation, and that the name of -# Timothy O'Malley not be used in advertising or publicity -# pertaining to distribution of the software without specific, written -# prior permission. -# -# Timothy O'Malley DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS -# SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY -# AND FITNESS, IN NO EVENT SHALL Timothy O'Malley BE LIABLE FOR -# ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, -# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS -# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR -# PERFORMANCE OF THIS SOFTWARE. -# -#### - -"""Timeout Socket - -This module enables a timeout mechanism on all TCP connections. It -does this by inserting a shim into the socket module. After this module -has been imported, all socket creation goes through this shim. As a -result, every TCP connection will support a timeout. - -The beauty of this method is that it immediately and transparently -enables the entire python library to support timeouts on TCP sockets. -As an example, if you wanted to SMTP connections to have a 20 second -timeout: - - import timeoutsocket - import smtplib - timeoutsocket.setDefaultSocketTimeout(20) - - -The timeout applies to the socket functions that normally block on -execution: read, write, connect, and accept. If any of these -operations exceeds the specified timeout, the exception Timeout -will be raised. - -The default timeout value is set to None. As a result, importing -this module does not change the default behavior of a socket. The -timeout mechanism only activates when the timeout has been set to -a numeric value. (This behavior mimics the behavior of the -select.select() function.) - -This module implements two classes: TimeoutSocket and TimeoutFile. - -The TimeoutSocket class defines a socket-like object that attempts to -avoid the condition where a socket may block indefinitely. The -TimeoutSocket class raises a Timeout exception whenever the -current operation delays too long. - -The TimeoutFile class defines a file-like object that uses the TimeoutSocket -class. When the makefile() method of TimeoutSocket is called, it returns -an instance of a TimeoutFile. - -Each of these objects adds two methods to manage the timeout value: - - get_timeout() --> returns the timeout of the socket or file - set_timeout() --> sets the timeout of the socket or file - - -As an example, one might use the timeout feature to create httplib -connections that will timeout after 30 seconds: - - import timeoutsocket - import httplib - H = httplib.HTTP("www.python.org") - H.sock.set_timeout(30) - -Note: When used in this manner, the connect() routine may still -block because it happens before the timeout is set. To avoid -this, use the 'timeoutsocket.setDefaultSocketTimeout()' function. - -Good Luck! - -""" - -__version__ = "$Revision: 1.1 $" -__author__ = "Timothy O'Malley " - -# -# Imports -# -import select, string -import socket -if not hasattr(socket, "_no_timeoutsocket"): - _socket = socket.socket -else: - _socket = socket._no_timeoutsocket - - -# -# Set up constants to test for Connected and Blocking operations. -# We delete 'os' and 'errno' to keep our namespace clean(er). -# Thanks to Alex Martelli and G. Li for the Windows error codes. -# -import os -if os.name == "nt": - _IsConnected = ( 10022, 10056 ) - _ConnectBusy = ( 10035, ) - _AcceptBusy = ( 10035, ) -else: - import errno - _IsConnected = ( errno.EISCONN, ) - _ConnectBusy = ( errno.EINPROGRESS, errno.EALREADY, errno.EWOULDBLOCK ) - _AcceptBusy = ( errno.EAGAIN, errno.EWOULDBLOCK ) - del errno -del os - - -# -# Default timeout value for ALL TimeoutSockets -# -_DefaultTimeout = None -def setDefaultSocketTimeout(timeout): - global _DefaultTimeout - _DefaultTimeout = timeout -def getDefaultSocketTimeout(): - return _DefaultTimeout - -# -# Exceptions for socket errors and timeouts -# -Error = socket.error -class Timeout(Exception): - pass - - -# -# Factory function -# -from socket import AF_INET, SOCK_STREAM -def timeoutsocket(family=AF_INET, type=SOCK_STREAM, proto=None): - if family != AF_INET or type != SOCK_STREAM: - if proto: - return _socket(family, type, proto) - else: - return _socket(family, type) - return TimeoutSocket( _socket(family, type), _DefaultTimeout ) -# end timeoutsocket - -# -# The TimeoutSocket class definition -# -class TimeoutSocket: - """TimeoutSocket object - Implements a socket-like object that raises Timeout whenever - an operation takes too long. - The definition of 'too long' can be changed using the - set_timeout() method. - """ - - _copies = 0 - _blocking = 1 - - def __init__(self, sock, timeout): - self._sock = sock - self._timeout = timeout - # end __init__ - - def __getattr__(self, key): - return getattr(self._sock, key) - # end __getattr__ - - def get_timeout(self): - return self._timeout - # end set_timeout - - def set_timeout(self, timeout=None): - self._timeout = timeout - # end set_timeout - - def setblocking(self, blocking): - self._blocking = blocking - return self._sock.setblocking(blocking) - # end set_timeout - - def connect_ex(self, addr): - errcode = 0 - try: - self.connect(addr) - except Error, why: - errcode = why[0] - return errcode - # end connect_ex - - def connect(self, addr, port=None, dumbhack=None): - # In case we were called as connect(host, port) - if port != None: addr = (addr, port) - - # Shortcuts - sock = self._sock - timeout = self._timeout - blocking = self._blocking - - # First, make a non-blocking call to connect - try: - sock.setblocking(0) - sock.connect(addr) - sock.setblocking(blocking) - return - except Error, why: - # Set the socket's blocking mode back - sock.setblocking(blocking) - - # If we are not blocking, re-raise - if not blocking: - raise - - # If we are already connected, then return success. - # If we got a genuine error, re-raise it. - errcode = why[0] - if dumbhack and errcode in _IsConnected: - return - elif errcode not in _ConnectBusy: - raise - - # Now, wait for the connect to happen - # ONLY if dumbhack indicates this is pass number one. - # If select raises an error, we pass it on. - # Is this the right behavior? - if not dumbhack: - r,w,e = select.select([], [sock], [], timeout) - if w: - return self.connect(addr, dumbhack=1) - - # If we get here, then we should raise Timeout - raise Timeout("Attempted connect to %s timed out." % str(addr) ) - # end connect - - def accept(self, dumbhack=None): - # Shortcuts - sock = self._sock - timeout = self._timeout - blocking = self._blocking - - # First, make a non-blocking call to accept - # If we get a valid result, then convert the - # accept'ed socket into a TimeoutSocket. - # Be carefult about the blocking mode of ourselves. - try: - sock.setblocking(0) - newsock, addr = sock.accept() - sock.setblocking(blocking) - timeoutnewsock = self.__class__(newsock, timeout) - timeoutnewsock.setblocking(blocking) - return (timeoutnewsock, addr) - except Error, why: - # Set the socket's blocking mode back - sock.setblocking(blocking) - - # If we are not supposed to block, then re-raise - if not blocking: - raise - - # If we got a genuine error, re-raise it. - errcode = why[0] - if errcode not in _AcceptBusy: - raise - - # Now, wait for the accept to happen - # ONLY if dumbhack indicates this is pass number one. - # If select raises an error, we pass it on. - # Is this the right behavior? - if not dumbhack: - r,w,e = select.select([sock], [], [], timeout) - if r: - return self.accept(dumbhack=1) - - # If we get here, then we should raise Timeout - raise Timeout("Attempted accept timed out.") - # end accept - - def send(self, data, flags=0): - sock = self._sock - if self._blocking: - r,w,e = select.select([],[sock],[], self._timeout) - if not w: - raise Timeout("Send timed out") - return sock.send(data, flags) - # end send - - def recv(self, bufsize, flags=0): - sock = self._sock - if self._blocking: - r,w,e = select.select([sock], [], [], self._timeout) - if not r: - raise Timeout("Recv timed out") - return sock.recv(bufsize, flags) - # end recv - - def makefile(self, flags="r", bufsize=-1): - self._copies = self._copies +1 - return TimeoutFile(self, flags, bufsize) - # end makefile - - def close(self): - if self._copies <= 0: - self._sock.close() - else: - self._copies = self._copies -1 - # end close - -# end TimeoutSocket - - -class TimeoutFile: - """TimeoutFile object - Implements a file-like object on top of TimeoutSocket. - """ - - def __init__(self, sock, mode="r", bufsize=4096): - self._sock = sock - self._bufsize = 4096 - if bufsize > 0: self._bufsize = bufsize - if not hasattr(sock, "_inqueue"): self._sock._inqueue = "" - - # end __init__ - - def __getattr__(self, key): - return getattr(self._sock, key) - # end __getattr__ - - def close(self): - self._sock.close() - self._sock = None - # end close - - def write(self, data): - self.send(data) - # end write - - def read(self, size=-1): - _sock = self._sock - _bufsize = self._bufsize - while 1: - datalen = len(_sock._inqueue) - if datalen >= size >= 0: - break - bufsize = _bufsize - if size > 0: - bufsize = min(bufsize, size - datalen ) - buf = self.recv(bufsize) - if not buf: - break - _sock._inqueue = _sock._inqueue + buf - data = _sock._inqueue - _sock._inqueue = "" - if size > 0 and datalen > size: - _sock._inqueue = data[size:] - data = data[:size] - return data - # end read - - def readline(self, size=-1): - _sock = self._sock - _bufsize = self._bufsize - while 1: - idx = string.find(_sock._inqueue, "\n") - if idx >= 0: - break - datalen = len(_sock._inqueue) - if datalen >= size >= 0: - break - bufsize = _bufsize - if size > 0: - bufsize = min(bufsize, size - datalen ) - buf = self.recv(bufsize) - if not buf: - break - _sock._inqueue = _sock._inqueue + buf - - data = _sock._inqueue - _sock._inqueue = "" - if idx >= 0: - idx = idx + 1 - _sock._inqueue = data[idx:] - data = data[:idx] - elif size > 0 and datalen > size: - _sock._inqueue = data[size:] - data = data[:size] - return data - # end readline - - def readlines(self, sizehint=-1): - result = [] - data = self.read() - while data: - idx = string.find(data, "\n") - if idx >= 0: - idx = idx + 1 - result.append( data[:idx] ) - data = data[idx:] - else: - result.append( data ) - data = "" - return result - # end readlines - - def flush(self): pass - -# end TimeoutFile - - -# -# Silently replace the socket() builtin function with -# our timeoutsocket() definition. -# -if not hasattr(socket, "_no_timeoutsocket"): - socket._no_timeoutsocket = socket.socket - socket.socket = timeoutsocket -del socket -socket = timeoutsocket -# Finis diff --git a/rawdoglib/upgrade_1_2.py b/rawdoglib/upgrade_1_2.py deleted file mode 100644 --- a/rawdoglib/upgrade_1_2.py +++ /dev/null @@ -1,114 +0,0 @@ -# upgrade_1_2: import state from rawdog 1.x state files to rawdog 2.x -# Copyright 2003, 2004, 2005 Adam Sampson -# -# rawdog is free software; you can redistribute and/or modify it -# under the terms of that license as published by the Free Software -# Foundation; either version 2 of the License, or (at your option) -# any later version. -# -# rawdog is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with rawdog; see the file COPYING. If not, write to the Free -# Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, -# MA 02110-1301, USA, or see http://www.gnu.org/. - -import os, time, difflib -import cPickle as pickle -from rawdog import Rawdog -from persister import Persister - -def format_time(secs): - """Turn a Unix time into a human-readable string.""" - return time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(secs)) - -def approximately_equal(a, b): - """Return whether two strings are approximately equal.""" - if a == b: - return True - return difflib.get_close_matches(a, [b], 1, 0.6) != [] - -def upgrade(olddir, newdir): - """Given a rawdog 1.x state directory and a rawdog 2.x state directory, - copy the ordering information from the old one into the new one. Since - rawdog 2.0 mangles articles in a slightly different way, this needs to - do approximate matching to find corresponding articles.""" - print "Importing state from " + olddir + " into " + newdir - - print "Loading old state" - f = open(olddir + "/state") - oldrawdog = pickle.load(f) - - print "Loading new state" - os.chdir(newdir) - persister = Persister("state", Rawdog) - newrawdog = persister.load() - - print "Copying feed state" - oldfeeds = {} - newfeeds = {} - for url, oldfeed in oldrawdog.feeds.items(): - if newrawdog.feeds.has_key(url): - last_update = oldfeed.last_update - print "Setting feed", url, "last update time to", format_time(last_update) - newrawdog.feeds[url].last_update = last_update - oldfeeds[url] = {} - newfeeds[url] = {} - else: - print "Old feed", url, "not in new state" - - print "Copying article state" - - # Seperate out the articles by feed. - for oldhash, oldarticle in oldrawdog.articles.items(): - if oldfeeds.has_key(oldarticle.feed): - oldfeeds[oldarticle.feed][oldhash] = oldarticle - for newhash, newarticle in newrawdog.articles.items(): - if newfeeds.has_key(newarticle.feed): - newfeeds[newarticle.feed][newhash] = newarticle - - # Now fuzzily match articles. - for url, oldarticles in oldfeeds.items(): - for newhash, newarticle in newfeeds[url].items(): - matches = [] - for oldhash, oldarticle in oldarticles.items(): - score = 0 - - olink = oldarticle.link - nlink = newarticle.entry_info.get("link") - if olink is not None and nlink is not None and olink == nlink: - score += 1 - - otitle = oldarticle.title - ntitle = newarticle.entry_info.get("title") - if otitle is not None and ntitle is not None and approximately_equal(otitle, ntitle): - score += 1 - - odesc = oldarticle.description - ndesc = newarticle.entry_info.get("description") - if odesc is not None and ndesc is not None and approximately_equal(odesc, ndesc): - score += 1 - - matches.append((score, oldhash)) - - matches.sort() - if matches != [] and matches[-1][0] > 1: - oldhash = matches[-1][1] - oldarticle = oldarticles[oldhash] - newarticle.sequence = oldarticle.sequence - newarticle.last_seen = oldarticle.last_seen - newarticle.added = oldarticle.added - print "Matched new", newhash, "to old", oldhash, "in", url - else: - print "No match for", newhash, "in", url - - - print "Saving new state" - newrawdog.modified() - persister.save() - - print "Done" - diff --git a/rss20.xml b/rss20.xml new file mode 100644 --- /dev/null +++ b/rss20.xml @@ -0,0 +1,10 @@ +--- +layout: rss20 +permalink: /global/rss20.xml +pagination: + enabled: true + collection: posts + sort_field: date + sort_reverse: true + limit: 1 +--- diff --git a/tests/feedcheck.rb b/tests/feedcheck.rb new file mode 100644 --- /dev/null +++ b/tests/feedcheck.rb @@ -0,0 +1,46 @@ +require 'iniparser' +require 'faraday' +require 'nokogiri' + +hash = INI.load_file( 'planet.ini' ) +av_dir = 'hackergotchi' + +avatars = [] + +hash.each do |key, section| + if section.is_a?(Hash) + print ":: #{key} => " + feed = section['feed'] if section.has_key?('feed') + avatar = section['avatar'] if section.has_key?('avatar') + url_arr = [] + url_arr << section['link'] if section.has_key?('link') + url_arr << feed if feed + # Check if avatar exists + if avatar.include? '//' + url_arr << avatar + else + abort("✗\nAvatar not found: hackergotchi/#{avatar}") unless File.file?("#{av_dir}/#{avatar}") + avatars << avatar + end if avatar + print '✓ ' + # Check if URLs return 200 status + url_arr.each do |url| + res = Faraday.get(URI(url)) + error = "✗\nNon successful status code #{res.status} when trying to access `#{url}`" + abort("#{error}\nTry using `#{res.headers['location']}` instead") if res.status.to_i.between?(300, 399) && res.headers.has_key?('location') + abort(error) unless res.status.to_i == 200 + end + print '✓ ' + # Check is the XML actually parses as XML + xml = Faraday.get(URI(feed)).body + xml_err = Nokogiri::XML(xml).errors + abort("✗\nUnusable XML syntax: #{feed}\n#{xml_err}") unless xml_err.empty? + puts '✓ ' + end +end + +avatars << "default.png" +avatars.uniq! +hackergotchis = Dir.foreach(av_dir).select { |f| File.file?("#{av_dir}/#{f}") } +diff = (hackergotchis - avatars).sort +abort "There are unused files in hackergotchis:\n#{diff.join(', ')}" unless diff.empty? diff --git a/website/bootstrap.css b/website/bootstrap.css deleted file mode 100644 --- a/website/bootstrap.css +++ /dev/null @@ -1,6496 +0,0 @@ -@import url("//fonts.googleapis.com/css?family=Oxygen:400,300,700"); -/*! - * bootswatch v3.3.1+2 - * Homepage: http://bootswatch.com - * Copyright 2012-2014 Thomas Park - * Licensed under MIT - * Based on Bootstrap -*/ -/*! normalize.css v3.0.2 | MIT License | git.io/normalize */ -html { - font-family: 'Oxygen', sans-serif; - -ms-text-size-adjust: 100%; - -webkit-text-size-adjust: 100%; -} -body { - margin: 0; -} -article, -aside, -details, -figcaption, -figure, -footer, -header, -hgroup, -main, -menu, -nav, -section, -summary { - display: block; -} -audio, -canvas, -progress, -video { - display: inline-block; - vertical-align: baseline; -} -audio:not([controls]) { - display: none; - height: 0; -} -[hidden], -template { - display: none; -} -a { - background-color: transparent; -} -a:active, -a:hover { - outline: 0; -} -abbr[title] { - border-bottom: 1px dotted; -} -b, -strong { - font-weight: bold; -} -dfn { - font-style: italic; -} -h1 { - font-size: 2em; - margin: 0.67em 0; -} -mark { - background: #ff0; - color: #000; -} -small { - font-size: 80%; -} -sub, -sup { - font-size: 75%; - line-height: 0; - position: relative; - vertical-align: baseline; -} -sup { - top: -0.5em; -} -sub { - bottom: -0.25em; -} -img { - border: 0; -} -svg:not(:root) { - overflow: hidden; -} -figure { - margin: 1em 40px; -} -hr { - -moz-box-sizing: content-box; - -webkit-box-sizing: content-box; - box-sizing: content-box; - height: 0; -} -pre { - overflow: auto; -} -code, -kbd, -pre, -samp { - font-family: monospace, monospace; - font-size: 1em; -} -button, -input, -optgroup, -select, -textarea { - color: inherit; - font: inherit; - margin: 0; -} -button { - overflow: visible; -} -button, -select { - text-transform: none; -} -button, -html input[type="button"], -input[type="reset"], -input[type="submit"] { - -webkit-appearance: button; - cursor: pointer; -} -button[disabled], -html input[disabled] { - cursor: default; -} -button::-moz-focus-inner, -input::-moz-focus-inner { - border: 0; - padding: 0; -} -input { - line-height: normal; -} -input[type="checkbox"], -input[type="radio"] { - -webkit-box-sizing: border-box; - -moz-box-sizing: border-box; - box-sizing: border-box; - padding: 0; -} -input[type="number"]::-webkit-inner-spin-button, -input[type="number"]::-webkit-outer-spin-button { - height: auto; -} -input[type="search"] { - -webkit-appearance: textfield; - -moz-box-sizing: content-box; - -webkit-box-sizing: content-box; - box-sizing: content-box; -} -input[type="search"]::-webkit-search-cancel-button, -input[type="search"]::-webkit-search-decoration { - -webkit-appearance: none; -} -fieldset { - border: 1px solid #c0c0c0; - margin: 0 2px; - padding: 0.35em 0.625em 0.75em; -} -legend { - border: 0; - padding: 0; -} -textarea { - overflow: auto; -} -optgroup { - font-weight: bold; -} -table { - border-collapse: collapse; - border-spacing: 0; -} -td, -th { - padding: 0; -} -/*! Source: https://github.com/h5bp/html5-boilerplate/blob/master/src/css/main.css */ -@media print { - *, - *:before, - *:after { - background: transparent !important; - color: #000 !important; - -webkit-box-shadow: none !important; - box-shadow: none !important; - text-shadow: none !important; - } - a, - a:visited { - text-decoration: underline; - } - a[href]:after { - content: " (" attr(href) ")"; - } - abbr[title]:after { - content: " (" attr(title) ")"; - } - a[href^="#"]:after, - a[href^="javascript:"]:after { - content: ""; - } - pre, - blockquote { - border: 1px solid #999; - page-break-inside: avoid; - } - thead { - display: table-header-group; - } - tr, - img { - page-break-inside: avoid; - } - img { - max-width: 100% !important; - } - p, - h2, - h3 { - orphans: 3; - widows: 3; - } - h2, - h3 { - page-break-after: avoid; - } - select { - background: #fff !important; - } - .navbar { - display: none; - } - .btn > .caret, - .dropup > .btn > .caret { - border-top-color: #000 !important; - } - .label { - border: 1px solid #000; - } - .table { - border-collapse: collapse !important; - } - .table td, - .table th { - background-color: #fff !important; - } - .table-bordered th, - .table-bordered td { - border: 1px solid #ddd !important; - } -} -@font-face { - font-family: 'Glyphicons Halflings'; - src: url('../fonts/glyphicons-halflings-regular.eot'); - src: url('../fonts/glyphicons-halflings-regular.eot?#iefix') format('embedded-opentype'), url('../fonts/glyphicons-halflings-regular.woff') format('woff'), url('../fonts/glyphicons-halflings-regular.ttf') format('truetype'), url('../fonts/glyphicons-halflings-regular.svg#glyphicons_halflingsregular') format('svg'); -} -.glyphicon { - position: relative; - top: 1px; - display: inline-block; - font-family: 'Glyphicons Halflings'; - font-style: normal; - font-weight: normal; - line-height: 1; - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; -} -.glyphicon-asterisk:before { - content: "\2a"; -} -.glyphicon-plus:before { - content: "\2b"; -} -.glyphicon-euro:before, -.glyphicon-eur:before { - content: "\20ac"; -} -.glyphicon-minus:before { - content: "\2212"; -} -.glyphicon-cloud:before { - content: "\2601"; -} -.glyphicon-envelope:before { - content: "\2709"; -} -.glyphicon-pencil:before { - content: "\270f"; -} -.glyphicon-glass:before { - content: "\e001"; -} -.glyphicon-music:before { - content: "\e002"; -} -.glyphicon-search:before { - content: "\e003"; -} -.glyphicon-heart:before { - content: "\e005"; -} -.glyphicon-star:before { - content: "\e006"; -} -.glyphicon-star-empty:before { - content: "\e007"; -} -.glyphicon-user:before { - content: "\e008"; -} -.glyphicon-film:before { - content: "\e009"; -} -.glyphicon-th-large:before { - content: "\e010"; -} -.glyphicon-th:before { - content: "\e011"; -} -.glyphicon-th-list:before { - content: "\e012"; -} -.glyphicon-ok:before { - content: "\e013"; -} -.glyphicon-remove:before { - content: "\e014"; -} -.glyphicon-zoom-in:before { - content: "\e015"; -} -.glyphicon-zoom-out:before { - content: "\e016"; -} -.glyphicon-off:before { - content: "\e017"; -} -.glyphicon-signal:before { - content: "\e018"; -} -.glyphicon-cog:before { - content: "\e019"; -} -.glyphicon-trash:before { - content: "\e020"; -} -.glyphicon-home:before { - content: "\e021"; -} -.glyphicon-file:before { - content: "\e022"; -} -.glyphicon-time:before { - content: "\e023"; -} -.glyphicon-road:before { - content: "\e024"; -} -.glyphicon-download-alt:before { - content: "\e025"; -} -.glyphicon-download:before { - content: "\e026"; -} -.glyphicon-upload:before { - content: "\e027"; -} -.glyphicon-inbox:before { - content: "\e028"; -} -.glyphicon-play-circle:before { - content: "\e029"; -} -.glyphicon-repeat:before { - content: "\e030"; -} -.glyphicon-refresh:before { - content: "\e031"; -} -.glyphicon-list-alt:before { - content: "\e032"; -} -.glyphicon-lock:before { - content: "\e033"; -} -.glyphicon-flag:before { - content: "\e034"; -} -.glyphicon-headphones:before { - content: "\e035"; -} -.glyphicon-volume-off:before { - content: "\e036"; -} -.glyphicon-volume-down:before { - content: "\e037"; -} -.glyphicon-volume-up:before { - content: "\e038"; -} -.glyphicon-qrcode:before { - content: "\e039"; -} -.glyphicon-barcode:before { - content: "\e040"; -} -.glyphicon-tag:before { - content: "\e041"; -} -.glyphicon-tags:before { - content: "\e042"; -} -.glyphicon-book:before { - content: "\e043"; -} -.glyphicon-bookmark:before { - content: "\e044"; -} -.glyphicon-print:before { - content: "\e045"; -} -.glyphicon-camera:before { - content: "\e046"; -} -.glyphicon-font:before { - content: "\e047"; -} -.glyphicon-bold:before { - content: "\e048"; -} -.glyphicon-italic:before { - content: "\e049"; -} -.glyphicon-text-height:before { - content: "\e050"; -} -.glyphicon-text-width:before { - content: "\e051"; -} -.glyphicon-align-left:before { - content: "\e052"; -} -.glyphicon-align-center:before { - content: "\e053"; -} -.glyphicon-align-right:before { - content: "\e054"; -} -.glyphicon-align-justify:before { - content: "\e055"; -} -.glyphicon-list:before { - content: "\e056"; -} -.glyphicon-indent-left:before { - content: "\e057"; -} -.glyphicon-indent-right:before { - content: "\e058"; -} -.glyphicon-facetime-video:before { - content: "\e059"; -} -.glyphicon-picture:before { - content: "\e060"; -} -.glyphicon-map-marker:before { - content: "\e062"; -} -.glyphicon-adjust:before { - content: "\e063"; -} -.glyphicon-tint:before { - content: "\e064"; -} -.glyphicon-edit:before { - content: "\e065"; -} -.glyphicon-share:before { - content: "\e066"; -} -.glyphicon-check:before { - content: "\e067"; -} -.glyphicon-move:before { - content: "\e068"; -} -.glyphicon-step-backward:before { - content: "\e069"; -} -.glyphicon-fast-backward:before { - content: "\e070"; -} -.glyphicon-backward:before { - content: "\e071"; -} -.glyphicon-play:before { - content: "\e072"; -} -.glyphicon-pause:before { - content: "\e073"; -} -.glyphicon-stop:before { - content: "\e074"; -} -.glyphicon-forward:before { - content: "\e075"; -} -.glyphicon-fast-forward:before { - content: "\e076"; -} -.glyphicon-step-forward:before { - content: "\e077"; -} -.glyphicon-eject:before { - content: "\e078"; -} -.glyphicon-chevron-left:before { - content: "\e079"; -} -.glyphicon-chevron-right:before { - content: "\e080"; -} -.glyphicon-plus-sign:before { - content: "\e081"; -} -.glyphicon-minus-sign:before { - content: "\e082"; -} -.glyphicon-remove-sign:before { - content: "\e083"; -} -.glyphicon-ok-sign:before { - content: "\e084"; -} -.glyphicon-question-sign:before { - content: "\e085"; -} -.glyphicon-info-sign:before { - content: "\e086"; -} -.glyphicon-screenshot:before { - content: "\e087"; -} -.glyphicon-remove-circle:before { - content: "\e088"; -} -.glyphicon-ok-circle:before { - content: "\e089"; -} -.glyphicon-ban-circle:before { - content: "\e090"; -} -.glyphicon-arrow-left:before { - content: "\e091"; -} -.glyphicon-arrow-right:before { - content: "\e092"; -} -.glyphicon-arrow-up:before { - content: "\e093"; -} -.glyphicon-arrow-down:before { - content: "\e094"; -} -.glyphicon-share-alt:before { - content: "\e095"; -} -.glyphicon-resize-full:before { - content: "\e096"; -} -.glyphicon-resize-small:before { - content: "\e097"; -} -.glyphicon-exclamation-sign:before { - content: "\e101"; -} -.glyphicon-gift:before { - content: "\e102"; -} -.glyphicon-leaf:before { - content: "\e103"; -} -.glyphicon-fire:before { - content: "\e104"; -} -.glyphicon-eye-open:before { - content: "\e105"; -} -.glyphicon-eye-close:before { - content: "\e106"; -} -.glyphicon-warning-sign:before { - content: "\e107"; -} -.glyphicon-plane:before { - content: "\e108"; -} -.glyphicon-calendar:before { - content: "\e109"; -} -.glyphicon-random:before { - content: "\e110"; -} -.glyphicon-comment:before { - content: "\e111"; -} -.glyphicon-magnet:before { - content: "\e112"; -} -.glyphicon-chevron-up:before { - content: "\e113"; -} -.glyphicon-chevron-down:before { - content: "\e114"; -} -.glyphicon-retweet:before { - content: "\e115"; -} -.glyphicon-shopping-cart:before { - content: "\e116"; -} -.glyphicon-folder-close:before { - content: "\e117"; -} -.glyphicon-folder-open:before { - content: "\e118"; -} -.glyphicon-resize-vertical:before { - content: "\e119"; -} -.glyphicon-resize-horizontal:before { - content: "\e120"; -} -.glyphicon-hdd:before { - content: "\e121"; -} -.glyphicon-bullhorn:before { - content: "\e122"; -} -.glyphicon-bell:before { - content: "\e123"; -} -.glyphicon-certificate:before { - content: "\e124"; -} -.glyphicon-thumbs-up:before { - content: "\e125"; -} -.glyphicon-thumbs-down:before { - content: "\e126"; -} -.glyphicon-hand-right:before { - content: "\e127"; -} -.glyphicon-hand-left:before { - content: "\e128"; -} -.glyphicon-hand-up:before { - content: "\e129"; -} -.glyphicon-hand-down:before { - content: "\e130"; -} -.glyphicon-circle-arrow-right:before { - content: "\e131"; -} -.glyphicon-circle-arrow-left:before { - content: "\e132"; -} -.glyphicon-circle-arrow-up:before { - content: "\e133"; -} -.glyphicon-circle-arrow-down:before { - content: "\e134"; -} -.glyphicon-globe:before { - content: "\e135"; -} -.glyphicon-wrench:before { - content: "\e136"; -} -.glyphicon-tasks:before { - content: "\e137"; -} -.glyphicon-filter:before { - content: "\e138"; -} -.glyphicon-briefcase:before { - content: "\e139"; -} -.glyphicon-fullscreen:before { - content: "\e140"; -} -.glyphicon-dashboard:before { - content: "\e141"; -} -.glyphicon-paperclip:before { - content: "\e142"; -} -.glyphicon-heart-empty:before { - content: "\e143"; -} -.glyphicon-link:before { - content: "\e144"; -} -.glyphicon-phone:before { - content: "\e145"; -} -.glyphicon-pushpin:before { - content: "\e146"; -} -.glyphicon-usd:before { - content: "\e148"; -} -.glyphicon-gbp:before { - content: "\e149"; -} -.glyphicon-sort:before { - content: "\e150"; -} -.glyphicon-sort-by-alphabet:before { - content: "\e151"; -} -.glyphicon-sort-by-alphabet-alt:before { - content: "\e152"; -} -.glyphicon-sort-by-order:before { - content: "\e153"; -} -.glyphicon-sort-by-order-alt:before { - content: "\e154"; -} -.glyphicon-sort-by-attributes:before { - content: "\e155"; -} -.glyphicon-sort-by-attributes-alt:before { - content: "\e156"; -} -.glyphicon-unchecked:before { - content: "\e157"; -} -.glyphicon-expand:before { - content: "\e158"; -} -.glyphicon-collapse-down:before { - content: "\e159"; -} -.glyphicon-collapse-up:before { - content: "\e160"; -} -.glyphicon-log-in:before { - content: "\e161"; -} -.glyphicon-flash:before { - content: "\e162"; -} -.glyphicon-log-out:before { - content: "\e163"; -} -.glyphicon-new-window:before { - content: "\e164"; -} -.glyphicon-record:before { - content: "\e165"; -} -.glyphicon-save:before { - content: "\e166"; -} -.glyphicon-open:before { - content: "\e167"; -} -.glyphicon-saved:before { - content: "\e168"; -} -.glyphicon-import:before { - content: "\e169"; -} -.glyphicon-export:before { - content: "\e170"; -} -.glyphicon-send:before { - content: "\e171"; -} -.glyphicon-floppy-disk:before { - content: "\e172"; -} -.glyphicon-floppy-saved:before { - content: "\e173"; -} -.glyphicon-floppy-remove:before { - content: "\e174"; -} -.glyphicon-floppy-save:before { - content: "\e175"; -} -.glyphicon-floppy-open:before { - content: "\e176"; -} -.glyphicon-credit-card:before { - content: "\e177"; -} -.glyphicon-transfer:before { - content: "\e178"; -} -.glyphicon-cutlery:before { - content: "\e179"; -} -.glyphicon-header:before { - content: "\e180"; -} -.glyphicon-compressed:before { - content: "\e181"; -} -.glyphicon-earphone:before { - content: "\e182"; -} -.glyphicon-phone-alt:before { - content: "\e183"; -} -.glyphicon-tower:before { - content: "\e184"; -} -.glyphicon-stats:before { - content: "\e185"; -} -.glyphicon-sd-video:before { - content: "\e186"; -} -.glyphicon-hd-video:before { - content: "\e187"; -} -.glyphicon-subtitles:before { - content: "\e188"; -} -.glyphicon-sound-stereo:before { - content: "\e189"; -} -.glyphicon-sound-dolby:before { - content: "\e190"; -} -.glyphicon-sound-5-1:before { - content: "\e191"; -} -.glyphicon-sound-6-1:before { - content: "\e192"; -} -.glyphicon-sound-7-1:before { - content: "\e193"; -} -.glyphicon-copyright-mark:before { - content: "\e194"; -} -.glyphicon-registration-mark:before { - content: "\e195"; -} -.glyphicon-cloud-download:before { - content: "\e197"; -} -.glyphicon-cloud-upload:before { - content: "\e198"; -} -.glyphicon-tree-conifer:before { - content: "\e199"; -} -.glyphicon-tree-deciduous:before { - content: "\e200"; -} -* { - -webkit-box-sizing: border-box; - -moz-box-sizing: border-box; - box-sizing: border-box; -} -*:before, -*:after { - -webkit-box-sizing: border-box; - -moz-box-sizing: border-box; - box-sizing: border-box; -} -html { - font-size: 10px; - -webkit-tap-highlight-color: rgba(0, 0, 0, 0); -} -body { - font-family: 'Oxygen', sans-serif; - font-size: 14px; - line-height: 1.42857143; - color: #475057; - background-color: #ffffff; -} -input, -button, -select, -textarea { - font-family: inherit; - font-size: inherit; - line-height: inherit; -} -a { - color: #3daee9; - text-decoration: none; -} -a:hover, -a:focus { - color: #1a86db; - text-decoration: underline; -} -a:focus { - outline: thin dotted; - outline: 5px auto -webkit-focus-ring-color; - outline-offset: -2px; -} -figure { - margin: 0; -} -img { - vertical-align: middle; -} -.img-responsive, -.thumbnail > img, -.thumbnail a > img, -.carousel-inner > .item > img, -.carousel-inner > .item > a > img { - display: block; - max-width: 100%; - height: auto; -} -.img-rounded { - border-radius: 6px; -} -.img-thumbnail { - padding: 4px; - line-height: 1.42857143; - background-color: #eff0f1; - border: 1px solid #dfd7ca; - border-radius: 4px; - -webkit-transition: all 0.2s ease-in-out; - -o-transition: all 0.2s ease-in-out; - transition: all 0.2s ease-in-out; - display: inline-block; - max-width: 100%; - height: auto; -} -.img-circle { - border-radius: 50%; -} -hr { - margin-top: 20px; - margin-bottom: 20px; - border: 0; - border-top: 1px solid #eff0f1; -} -.sr-only { - position: absolute; - width: 1px; - height: 1px; - margin: -1px; - padding: 0; - overflow: hidden; - clip: rect(0, 0, 0, 0); - border: 0; -} -.sr-only-focusable:active, -.sr-only-focusable:focus { - position: static; - width: auto; - height: auto; - margin: 0; - overflow: visible; - clip: auto; -} -h1, -h2, -h3, -h4, -h5, -h6, -.h1, -.h2, -.h3, -.h4, -.h5, -.h6 { - font-family: inherit; - font-weight: 400; - line-height: 1.1; - color: inherit; -} -h1 small, -h2 small, -h3 small, -h4 small, -h5 small, -h6 small, -.h1 small, -.h2 small, -.h3 small, -.h4 small, -.h5 small, -.h6 small, -h1 .small, -h2 .small, -h3 .small, -h4 .small, -h5 .small, -h6 .small, -.h1 .small, -.h2 .small, -.h3 .small, -.h4 .small, -.h5 .small, -.h6 .small { - font-weight: normal; - line-height: 1; - color: #98978b; -} -h1, -.h1, -h2, -.h2, -h3, -.h3 { - margin-top: 20px; - margin-bottom: 10px; -} -h1 small, -.h1 small, -h2 small, -.h2 small, -h3 small, -.h3 small, -h1 .small, -.h1 .small, -h2 .small, -.h2 .small, -h3 .small, -.h3 .small { - font-size: 65%; -} -h4, -.h4, -h5, -.h5, -h6, -.h6 { - margin-top: 10px; - margin-bottom: 10px; -} -h4 small, -.h4 small, -h5 small, -.h5 small, -h6 small, -.h6 small, -h4 .small, -.h4 .small, -h5 .small, -.h5 .small, -h6 .small, -.h6 .small { - font-size: 75%; -} -h1, -.h1 { - font-size: 36px; -} -h2, -.h2 { - font-size: 30px; -} -h3, -.h3 { - font-size: 24px; -} -h4, -.h4 { - font-size: 18px; -} -h5, -.h5 { - font-size: 14px; -} -h6, -.h6 { - font-size: 12px; -} -p { - margin: 0 0 10px; -} -.lead { - margin-bottom: 20px; - font-size: 16px; - font-weight: 300; - line-height: 1.4; -} -@media (min-width: 768px) { - .lead { - font-size: 21px; - } -} -small, -.small { - font-size: 85%; -} -mark, -.mark { - background-color: #fcf8e3; - padding: .2em; -} -.text-left { - text-align: left; -} -.text-right { - text-align: right; -} -.text-center { - text-align: center; -} -.text-justify { - text-align: justify; -} -.text-nowrap { - white-space: nowrap; -} -.text-lowercase { - text-transform: lowercase; -} -.text-uppercase { - text-transform: uppercase; -} -.text-capitalize { - text-transform: capitalize; -} -.text-muted { - color: #98978b; -} -.text-primary { - color: #325d88; -} -a.text-primary:hover { - color: #244363; -} -.text-success { - color: #3daee9; -} -a.text-success:hover { - color: #1a86db; -} -.text-info { - color: #29abe0; -} -a.text-info:hover { - color: #1b8dbb; -} -.text-warning { - color: #f47c3c; -} -a.text-warning:hover { - color: #ef5c0e; -} -.text-danger { - color: #d9534f; -} -a.text-danger:hover { - color: #c9302c; -} -.bg-primary { - color: #fff; - background-color: #325d88; -} -a.bg-primary:hover { - background-color: #244363; -} -.bg-success { - background-color: #dff0d8; -} -a.bg-success:hover { - background-color: #c1e2b3; -} -.bg-info { - background-color: #d9edf7; -} -a.bg-info:hover { - background-color: #afd9ee; -} -.bg-warning { - background-color: #fcf8e3; -} -a.bg-warning:hover { - background-color: #f7ecb5; -} -.bg-danger { - background-color: #f2dede; -} -a.bg-danger:hover { - background-color: #e4b9b9; -} -.page-header { - padding-bottom: 9px; - margin: 40px 0 20px; - border-bottom: 1px solid #eff0f1; -} -ul, -ol { - margin-top: 0; - margin-bottom: 10px; -} -ul ul, -ol ul, -ul ol, -ol ol { - margin-bottom: 0; -} -.list-unstyled { - padding-left: 0; - list-style: none; -} -.list-inline { - padding-left: 0; - list-style: none; - margin-left: -5px; -} -.list-inline > li { - display: inline-block; - padding-left: 5px; - padding-right: 5px; -} -dl { - margin-top: 0; - margin-bottom: 20px; -} -dt, -dd { - line-height: 1.42857143; -} -dt { - font-weight: bold; -} -dd { - margin-left: 0; -} -@media (min-width: 768px) { - .dl-horizontal dt { - float: left; - width: 160px; - clear: left; - text-align: right; - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; - } - .dl-horizontal dd { - margin-left: 180px; - } -} -abbr[title], -abbr[data-original-title] { - cursor: help; - border-bottom: 1px dotted #98978b; -} -.initialism { - font-size: 90%; - text-transform: uppercase; -} -blockquote { - padding: 10px 20px; - margin: 0 0 20px; - font-size: 17.5px; - border-left: 5px solid #dfd7ca; -} -blockquote p:last-child, -blockquote ul:last-child, -blockquote ol:last-child { - margin-bottom: 0; -} -blockquote footer, -blockquote small, -blockquote .small { - display: block; - font-size: 80%; - line-height: 1.42857143; - color: #475057; -} -blockquote footer:before, -blockquote small:before, -blockquote .small:before { - content: '\2014 \00A0'; -} -.blockquote-reverse, -blockquote.pull-right { - padding-right: 15px; - padding-left: 0; - border-right: 5px solid #dfd7ca; - border-left: 0; - text-align: right; -} -.blockquote-reverse footer:before, -blockquote.pull-right footer:before, -.blockquote-reverse small:before, -blockquote.pull-right small:before, -.blockquote-reverse .small:before, -blockquote.pull-right .small:before { - content: ''; -} -.blockquote-reverse footer:after, -blockquote.pull-right footer:after, -.blockquote-reverse small:after, -blockquote.pull-right small:after, -.blockquote-reverse .small:after, -blockquote.pull-right .small:after { - content: '\00A0 \2014'; -} -address { - margin-bottom: 20px; - font-style: normal; - line-height: 1.42857143; -} -code, -kbd, -pre, -samp { - font-family: Menlo, Monaco, Consolas, "Courier New", monospace; -} -code { - padding: 2px 4px; - font-size: 90%; - color: #c7254e; - background-color: #f9f2f4; - border-radius: 4px; -} -kbd { - padding: 2px 4px; - font-size: 90%; - color: #ffffff; - background-color: #333333; - border-radius: 3px; - -webkit-box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.25); - box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.25); -} -kbd kbd { - padding: 0; - font-size: 100%; - font-weight: bold; - -webkit-box-shadow: none; - box-shadow: none; -} -pre { - display: block; - padding: 9.5px; - margin: 0 0 10px; - font-size: 13px; - line-height: 1.42857143; - word-break: break-all; - word-wrap: break-word; - color: #8e8c84; - background-color: #f5f5f5; - border: 1px solid #cccccc; - border-radius: 4px; -} -pre code { - padding: 0; - font-size: inherit; - color: inherit; - white-space: pre-wrap; - background-color: transparent; - border-radius: 0; -} -.pre-scrollable { - max-height: 340px; - overflow-y: scroll; -} -.container { - margin-right: auto; - margin-left: auto; - padding-left: 15px; - padding-right: 15px; -} -@media (min-width: 768px) { - .container { - width: 750px; - } -} -@media (min-width: 992px) { - .container { - width: 970px; - } -} -@media (min-width: 1200px) { - .container { - width: 1170px; - } -} -.container-fluid { - margin-right: auto; - margin-left: auto; - padding-left: 15px; - padding-right: 15px; -} -.row { - margin-left: -15px; - margin-right: -15px; -} -.col-xs-1, .col-sm-1, .col-md-1, .col-lg-1, .col-xs-2, .col-sm-2, .col-md-2, .col-lg-2, .col-xs-3, .col-sm-3, .col-md-3, .col-lg-3, .col-xs-4, .col-sm-4, .col-md-4, .col-lg-4, .col-xs-5, .col-sm-5, .col-md-5, .col-lg-5, .col-xs-6, .col-sm-6, .col-md-6, .col-lg-6, .col-xs-7, .col-sm-7, .col-md-7, .col-lg-7, .col-xs-8, .col-sm-8, .col-md-8, .col-lg-8, .col-xs-9, .col-sm-9, .col-md-9, .col-lg-9, .col-xs-10, .col-sm-10, .col-md-10, .col-lg-10, .col-xs-11, .col-sm-11, .col-md-11, .col-lg-11, .col-xs-12, .col-sm-12, .col-md-12, .col-lg-12 { - position: relative; - min-height: 1px; - padding-left: 15px; - padding-right: 15px; -} -.col-xs-1, .col-xs-2, .col-xs-3, .col-xs-4, .col-xs-5, .col-xs-6, .col-xs-7, .col-xs-8, .col-xs-9, .col-xs-10, .col-xs-11, .col-xs-12 { - float: left; -} -.col-xs-12 { - width: 100%; -} -.col-xs-11 { - width: 91.66666667%; -} -.col-xs-10 { - width: 83.33333333%; -} -.col-xs-9 { - width: 75%; -} -.col-xs-8 { - width: 66.66666667%; -} -.col-xs-7 { - width: 58.33333333%; -} -.col-xs-6 { - width: 50%; -} -.col-xs-5 { - width: 41.66666667%; -} -.col-xs-4 { - width: 33.33333333%; -} -.col-xs-3 { - width: 25%; -} -.col-xs-2 { - width: 16.66666667%; -} -.col-xs-1 { - width: 8.33333333%; -} -.col-xs-pull-12 { - right: 100%; -} -.col-xs-pull-11 { - right: 91.66666667%; -} -.col-xs-pull-10 { - right: 83.33333333%; -} -.col-xs-pull-9 { - right: 75%; -} -.col-xs-pull-8 { - right: 66.66666667%; -} -.col-xs-pull-7 { - right: 58.33333333%; -} -.col-xs-pull-6 { - right: 50%; -} -.col-xs-pull-5 { - right: 41.66666667%; -} -.col-xs-pull-4 { - right: 33.33333333%; -} -.col-xs-pull-3 { - right: 25%; -} -.col-xs-pull-2 { - right: 16.66666667%; -} -.col-xs-pull-1 { - right: 8.33333333%; -} -.col-xs-pull-0 { - right: auto; -} -.col-xs-push-12 { - left: 100%; -} -.col-xs-push-11 { - left: 91.66666667%; -} -.col-xs-push-10 { - left: 83.33333333%; -} -.col-xs-push-9 { - left: 75%; -} -.col-xs-push-8 { - left: 66.66666667%; -} -.col-xs-push-7 { - left: 58.33333333%; -} -.col-xs-push-6 { - left: 50%; -} -.col-xs-push-5 { - left: 41.66666667%; -} -.col-xs-push-4 { - left: 33.33333333%; -} -.col-xs-push-3 { - left: 25%; -} -.col-xs-push-2 { - left: 16.66666667%; -} -.col-xs-push-1 { - left: 8.33333333%; -} -.col-xs-push-0 { - left: auto; -} -.col-xs-offset-12 { - margin-left: 100%; -} -.col-xs-offset-11 { - margin-left: 91.66666667%; -} -.col-xs-offset-10 { - margin-left: 83.33333333%; -} -.col-xs-offset-9 { - margin-left: 75%; -} -.col-xs-offset-8 { - margin-left: 66.66666667%; -} -.col-xs-offset-7 { - margin-left: 58.33333333%; -} -.col-xs-offset-6 { - margin-left: 50%; -} -.col-xs-offset-5 { - margin-left: 41.66666667%; -} -.col-xs-offset-4 { - margin-left: 33.33333333%; -} -.col-xs-offset-3 { - margin-left: 25%; -} -.col-xs-offset-2 { - margin-left: 16.66666667%; -} -.col-xs-offset-1 { - margin-left: 8.33333333%; -} -.col-xs-offset-0 { - margin-left: 0%; -} -@media (min-width: 768px) { - .col-sm-1, .col-sm-2, .col-sm-3, .col-sm-4, .col-sm-5, .col-sm-6, .col-sm-7, .col-sm-8, .col-sm-9, .col-sm-10, .col-sm-11, .col-sm-12 { - float: left; - } - .col-sm-12 { - width: 100%; - } - .col-sm-11 { - width: 91.66666667%; - } - .col-sm-10 { - width: 83.33333333%; - } - .col-sm-9 { - width: 75%; - } - .col-sm-8 { - width: 66.66666667%; - } - .col-sm-7 { - width: 58.33333333%; - } - .col-sm-6 { - width: 50%; - } - .col-sm-5 { - width: 41.66666667%; - } - .col-sm-4 { - width: 33.33333333%; - } - .col-sm-3 { - width: 25%; - } - .col-sm-2 { - width: 16.66666667%; - } - .col-sm-1 { - width: 8.33333333%; - } - .col-sm-pull-12 { - right: 100%; - } - .col-sm-pull-11 { - right: 91.66666667%; - } - .col-sm-pull-10 { - right: 83.33333333%; - } - .col-sm-pull-9 { - right: 75%; - } - .col-sm-pull-8 { - right: 66.66666667%; - } - .col-sm-pull-7 { - right: 58.33333333%; - } - .col-sm-pull-6 { - right: 50%; - } - .col-sm-pull-5 { - right: 41.66666667%; - } - .col-sm-pull-4 { - right: 33.33333333%; - } - .col-sm-pull-3 { - right: 25%; - } - .col-sm-pull-2 { - right: 16.66666667%; - } - .col-sm-pull-1 { - right: 8.33333333%; - } - .col-sm-pull-0 { - right: auto; - } - .col-sm-push-12 { - left: 100%; - } - .col-sm-push-11 { - left: 91.66666667%; - } - .col-sm-push-10 { - left: 83.33333333%; - } - .col-sm-push-9 { - left: 75%; - } - .col-sm-push-8 { - left: 66.66666667%; - } - .col-sm-push-7 { - left: 58.33333333%; - } - .col-sm-push-6 { - left: 50%; - } - .col-sm-push-5 { - left: 41.66666667%; - } - .col-sm-push-4 { - left: 33.33333333%; - } - .col-sm-push-3 { - left: 25%; - } - .col-sm-push-2 { - left: 16.66666667%; - } - .col-sm-push-1 { - left: 8.33333333%; - } - .col-sm-push-0 { - left: auto; - } - .col-sm-offset-12 { - margin-left: 100%; - } - .col-sm-offset-11 { - margin-left: 91.66666667%; - } - .col-sm-offset-10 { - margin-left: 83.33333333%; - } - .col-sm-offset-9 { - margin-left: 75%; - } - .col-sm-offset-8 { - margin-left: 66.66666667%; - } - .col-sm-offset-7 { - margin-left: 58.33333333%; - } - .col-sm-offset-6 { - margin-left: 50%; - } - .col-sm-offset-5 { - margin-left: 41.66666667%; - } - .col-sm-offset-4 { - margin-left: 33.33333333%; - } - .col-sm-offset-3 { - margin-left: 25%; - } - .col-sm-offset-2 { - margin-left: 16.66666667%; - } - .col-sm-offset-1 { - margin-left: 8.33333333%; - } - .col-sm-offset-0 { - margin-left: 0%; - } -} -@media (min-width: 992px) { - .col-md-1, .col-md-2, .col-md-3, .col-md-4, .col-md-5, .col-md-6, .col-md-7, .col-md-8, .col-md-9, .col-md-10, .col-md-11, .col-md-12 { - float: left; - } - .col-md-12 { - width: 100%; - } - .col-md-11 { - width: 91.66666667%; - } - .col-md-10 { - width: 83.33333333%; - } - .col-md-9 { - width: 75%; - } - .col-md-8 { - width: 66.66666667%; - } - .col-md-7 { - width: 58.33333333%; - } - .col-md-6 { - width: 50%; - } - .col-md-5 { - width: 41.66666667%; - } - .col-md-4 { - width: 33.33333333%; - } - .col-md-3 { - width: 25%; - } - .col-md-2 { - width: 16.66666667%; - } - .col-md-1 { - width: 8.33333333%; - } - .col-md-pull-12 { - right: 100%; - } - .col-md-pull-11 { - right: 91.66666667%; - } - .col-md-pull-10 { - right: 83.33333333%; - } - .col-md-pull-9 { - right: 75%; - } - .col-md-pull-8 { - right: 66.66666667%; - } - .col-md-pull-7 { - right: 58.33333333%; - } - .col-md-pull-6 { - right: 50%; - } - .col-md-pull-5 { - right: 41.66666667%; - } - .col-md-pull-4 { - right: 33.33333333%; - } - .col-md-pull-3 { - right: 25%; - } - .col-md-pull-2 { - right: 16.66666667%; - } - .col-md-pull-1 { - right: 8.33333333%; - } - .col-md-pull-0 { - right: auto; - } - .col-md-push-12 { - left: 100%; - } - .col-md-push-11 { - left: 91.66666667%; - } - .col-md-push-10 { - left: 83.33333333%; - } - .col-md-push-9 { - left: 75%; - } - .col-md-push-8 { - left: 66.66666667%; - } - .col-md-push-7 { - left: 58.33333333%; - } - .col-md-push-6 { - left: 50%; - } - .col-md-push-5 { - left: 41.66666667%; - } - .col-md-push-4 { - left: 33.33333333%; - } - .col-md-push-3 { - left: 25%; - } - .col-md-push-2 { - left: 16.66666667%; - } - .col-md-push-1 { - left: 8.33333333%; - } - .col-md-push-0 { - left: auto; - } - .col-md-offset-12 { - margin-left: 100%; - } - .col-md-offset-11 { - margin-left: 91.66666667%; - } - .col-md-offset-10 { - margin-left: 83.33333333%; - } - .col-md-offset-9 { - margin-left: 75%; - } - .col-md-offset-8 { - margin-left: 66.66666667%; - } - .col-md-offset-7 { - margin-left: 58.33333333%; - } - .col-md-offset-6 { - margin-left: 50%; - } - .col-md-offset-5 { - margin-left: 41.66666667%; - } - .col-md-offset-4 { - margin-left: 33.33333333%; - } - .col-md-offset-3 { - margin-left: 25%; - } - .col-md-offset-2 { - margin-left: 16.66666667%; - } - .col-md-offset-1 { - margin-left: 8.33333333%; - } - .col-md-offset-0 { - margin-left: 0%; - } -} -@media (min-width: 1200px) { - .col-lg-1, .col-lg-2, .col-lg-3, .col-lg-4, .col-lg-5, .col-lg-6, .col-lg-7, .col-lg-8, .col-lg-9, .col-lg-10, .col-lg-11, .col-lg-12 { - float: left; - } - .col-lg-12 { - width: 100%; - } - .col-lg-11 { - width: 91.66666667%; - } - .col-lg-10 { - width: 83.33333333%; - } - .col-lg-9 { - width: 75%; - } - .col-lg-8 { - width: 66.66666667%; - } - .col-lg-7 { - width: 58.33333333%; - } - .col-lg-6 { - width: 50%; - } - .col-lg-5 { - width: 41.66666667%; - } - .col-lg-4 { - width: 33.33333333%; - } - .col-lg-3 { - width: 25%; - } - .col-lg-2 { - width: 16.66666667%; - } - .col-lg-1 { - width: 8.33333333%; - } - .col-lg-pull-12 { - right: 100%; - } - .col-lg-pull-11 { - right: 91.66666667%; - } - .col-lg-pull-10 { - right: 83.33333333%; - } - .col-lg-pull-9 { - right: 75%; - } - .col-lg-pull-8 { - right: 66.66666667%; - } - .col-lg-pull-7 { - right: 58.33333333%; - } - .col-lg-pull-6 { - right: 50%; - } - .col-lg-pull-5 { - right: 41.66666667%; - } - .col-lg-pull-4 { - right: 33.33333333%; - } - .col-lg-pull-3 { - right: 25%; - } - .col-lg-pull-2 { - right: 16.66666667%; - } - .col-lg-pull-1 { - right: 8.33333333%; - } - .col-lg-pull-0 { - right: auto; - } - .col-lg-push-12 { - left: 100%; - } - .col-lg-push-11 { - left: 91.66666667%; - } - .col-lg-push-10 { - left: 83.33333333%; - } - .col-lg-push-9 { - left: 75%; - } - .col-lg-push-8 { - left: 66.66666667%; - } - .col-lg-push-7 { - left: 58.33333333%; - } - .col-lg-push-6 { - left: 50%; - } - .col-lg-push-5 { - left: 41.66666667%; - } - .col-lg-push-4 { - left: 33.33333333%; - } - .col-lg-push-3 { - left: 25%; - } - .col-lg-push-2 { - left: 16.66666667%; - } - .col-lg-push-1 { - left: 8.33333333%; - } - .col-lg-push-0 { - left: auto; - } - .col-lg-offset-12 { - margin-left: 100%; - } - .col-lg-offset-11 { - margin-left: 91.66666667%; - } - .col-lg-offset-10 { - margin-left: 83.33333333%; - } - .col-lg-offset-9 { - margin-left: 75%; - } - .col-lg-offset-8 { - margin-left: 66.66666667%; - } - .col-lg-offset-7 { - margin-left: 58.33333333%; - } - .col-lg-offset-6 { - margin-left: 50%; - } - .col-lg-offset-5 { - margin-left: 41.66666667%; - } - .col-lg-offset-4 { - margin-left: 33.33333333%; - } - .col-lg-offset-3 { - margin-left: 25%; - } - .col-lg-offset-2 { - margin-left: 16.66666667%; - } - .col-lg-offset-1 { - margin-left: 8.33333333%; - } - .col-lg-offset-0 { - margin-left: 0%; - } -} -table { - background-color: transparent; -} -caption { - padding-top: 8px; - padding-bottom: 8px; - color: #98978b; - text-align: left; -} -th { - text-align: left; -} -.table { - width: 100%; - max-width: 100%; - margin-bottom: 20px; -} -.table > thead > tr > th, -.table > tbody > tr > th, -.table > tfoot > tr > th, -.table > thead > tr > td, -.table > tbody > tr > td, -.table > tfoot > tr > td { - padding: 8px; - line-height: 1.42857143; - vertical-align: top; - border-top: 1px solid #dfd7ca; -} -.table > thead > tr > th { - vertical-align: bottom; - border-bottom: 2px solid #dfd7ca; -} -.table > caption + thead > tr:first-child > th, -.table > colgroup + thead > tr:first-child > th, -.table > thead:first-child > tr:first-child > th, -.table > caption + thead > tr:first-child > td, -.table > colgroup + thead > tr:first-child > td, -.table > thead:first-child > tr:first-child > td { - border-top: 0; -} -.table > tbody + tbody { - border-top: 2px solid #dfd7ca; -} -.table .table { - background-color: #ffffff; -} -.table-condensed > thead > tr > th, -.table-condensed > tbody > tr > th, -.table-condensed > tfoot > tr > th, -.table-condensed > thead > tr > td, -.table-condensed > tbody > tr > td, -.table-condensed > tfoot > tr > td { - padding: 5px; -} -.table-bordered { - border: 1px solid #dfd7ca; -} -.table-bordered > thead > tr > th, -.table-bordered > tbody > tr > th, -.table-bordered > tfoot > tr > th, -.table-bordered > thead > tr > td, -.table-bordered > tbody > tr > td, -.table-bordered > tfoot > tr > td { - border: 1px solid #dfd7ca; -} -.table-bordered > thead > tr > th, -.table-bordered > thead > tr > td { - border-bottom-width: 2px; -} -.table-striped > tbody > tr:nth-child(odd) { - background-color: #eff0f1; -} -.table-hover > tbody > tr:hover { - background-color: #eff0f1; -} -table col[class*="col-"] { - position: static; - float: none; - display: table-column; -} -table td[class*="col-"], -table th[class*="col-"] { - position: static; - float: none; - display: table-cell; -} -.table > thead > tr > td.active, -.table > tbody > tr > td.active, -.table > tfoot > tr > td.active, -.table > thead > tr > th.active, -.table > tbody > tr > th.active, -.table > tfoot > tr > th.active, -.table > thead > tr.active > td, -.table > tbody > tr.active > td, -.table > tfoot > tr.active > td, -.table > thead > tr.active > th, -.table > tbody > tr.active > th, -.table > tfoot > tr.active > th { - background-color: #eff0f1; -} -.table-hover > tbody > tr > td.active:hover, -.table-hover > tbody > tr > th.active:hover, -.table-hover > tbody > tr.active:hover > td, -.table-hover > tbody > tr:hover > .active, -.table-hover > tbody > tr.active:hover > th { - background-color: #f0e9df; -} -.table > thead > tr > td.success, -.table > tbody > tr > td.success, -.table > tfoot > tr > td.success, -.table > thead > tr > th.success, -.table > tbody > tr > th.success, -.table > tfoot > tr > th.success, -.table > thead > tr.success > td, -.table > tbody > tr.success > td, -.table > tfoot > tr.success > td, -.table > thead > tr.success > th, -.table > tbody > tr.success > th, -.table > tfoot > tr.success > th { - background-color: #dff0d8; -} -.table-hover > tbody > tr > td.success:hover, -.table-hover > tbody > tr > th.success:hover, -.table-hover > tbody > tr.success:hover > td, -.table-hover > tbody > tr:hover > .success, -.table-hover > tbody > tr.success:hover > th { - background-color: #d0e9c6; -} -.table > thead > tr > td.info, -.table > tbody > tr > td.info, -.table > tfoot > tr > td.info, -.table > thead > tr > th.info, -.table > tbody > tr > th.info, -.table > tfoot > tr > th.info, -.table > thead > tr.info > td, -.table > tbody > tr.info > td, -.table > tfoot > tr.info > td, -.table > thead > tr.info > th, -.table > tbody > tr.info > th, -.table > tfoot > tr.info > th { - background-color: #d9edf7; -} -.table-hover > tbody > tr > td.info:hover, -.table-hover > tbody > tr > th.info:hover, -.table-hover > tbody > tr.info:hover > td, -.table-hover > tbody > tr:hover > .info, -.table-hover > tbody > tr.info:hover > th { - background-color: #c4e3f3; -} -.table > thead > tr > td.warning, -.table > tbody > tr > td.warning, -.table > tfoot > tr > td.warning, -.table > thead > tr > th.warning, -.table > tbody > tr > th.warning, -.table > tfoot > tr > th.warning, -.table > thead > tr.warning > td, -.table > tbody > tr.warning > td, -.table > tfoot > tr.warning > td, -.table > thead > tr.warning > th, -.table > tbody > tr.warning > th, -.table > tfoot > tr.warning > th { - background-color: #fcf8e3; -} -.table-hover > tbody > tr > td.warning:hover, -.table-hover > tbody > tr > th.warning:hover, -.table-hover > tbody > tr.warning:hover > td, -.table-hover > tbody > tr:hover > .warning, -.table-hover > tbody > tr.warning:hover > th { - background-color: #faf2cc; -} -.table > thead > tr > td.danger, -.table > tbody > tr > td.danger, -.table > tfoot > tr > td.danger, -.table > thead > tr > th.danger, -.table > tbody > tr > th.danger, -.table > tfoot > tr > th.danger, -.table > thead > tr.danger > td, -.table > tbody > tr.danger > td, -.table > tfoot > tr.danger > td, -.table > thead > tr.danger > th, -.table > tbody > tr.danger > th, -.table > tfoot > tr.danger > th { - background-color: #f2dede; -} -.table-hover > tbody > tr > td.danger:hover, -.table-hover > tbody > tr > th.danger:hover, -.table-hover > tbody > tr.danger:hover > td, -.table-hover > tbody > tr:hover > .danger, -.table-hover > tbody > tr.danger:hover > th { - background-color: #ebcccc; -} -.table-responsive { - overflow-x: auto; - min-height: 0.01%; -} -@media screen and (max-width: 767px) { - .table-responsive { - width: 100%; - margin-bottom: 15px; - overflow-y: hidden; - -ms-overflow-style: -ms-autohiding-scrollbar; - border: 1px solid #dfd7ca; - } - .table-responsive > .table { - margin-bottom: 0; - } - .table-responsive > .table > thead > tr > th, - .table-responsive > .table > tbody > tr > th, - .table-responsive > .table > tfoot > tr > th, - .table-responsive > .table > thead > tr > td, - .table-responsive > .table > tbody > tr > td, - .table-responsive > .table > tfoot > tr > td { - white-space: nowrap; - } - .table-responsive > .table-bordered { - border: 0; - } - .table-responsive > .table-bordered > thead > tr > th:first-child, - .table-responsive > .table-bordered > tbody > tr > th:first-child, - .table-responsive > .table-bordered > tfoot > tr > th:first-child, - .table-responsive > .table-bordered > thead > tr > td:first-child, - .table-responsive > .table-bordered > tbody > tr > td:first-child, - .table-responsive > .table-bordered > tfoot > tr > td:first-child { - border-left: 0; - } - .table-responsive > .table-bordered > thead > tr > th:last-child, - .table-responsive > .table-bordered > tbody > tr > th:last-child, - .table-responsive > .table-bordered > tfoot > tr > th:last-child, - .table-responsive > .table-bordered > thead > tr > td:last-child, - .table-responsive > .table-bordered > tbody > tr > td:last-child, - .table-responsive > .table-bordered > tfoot > tr > td:last-child { - border-right: 0; - } - .table-responsive > .table-bordered > tbody > tr:last-child > th, - .table-responsive > .table-bordered > tfoot > tr:last-child > th, - .table-responsive > .table-bordered > tbody > tr:last-child > td, - .table-responsive > .table-bordered > tfoot > tr:last-child > td { - border-bottom: 0; - } -} -fieldset { - padding: 0; - margin: 0; - border: 0; - min-width: 0; -} -legend { - display: block; - width: 100%; - padding: 0; - margin-bottom: 20px; - font-size: 21px; - line-height: inherit; - color: inherit; - border: 0; - border-bottom: 1px solid transparent; -} -label { - display: inline-block; - max-width: 100%; - margin-bottom: 5px; - font-weight: bold; -} -input[type="search"] { - -webkit-box-sizing: border-box; - -moz-box-sizing: border-box; - box-sizing: border-box; -} -input[type="radio"], -input[type="checkbox"] { - margin: 4px 0 0; - margin-top: 1px \9; - line-height: normal; -} -input[type="file"] { - display: block; -} -input[type="range"] { - display: block; - width: 100%; -} -select[multiple], -select[size] { - height: auto; -} -input[type="file"]:focus, -input[type="radio"]:focus, -input[type="checkbox"]:focus { - outline: thin dotted; - outline: 5px auto -webkit-focus-ring-color; - outline-offset: -2px; -} -output { - display: block; - padding-top: 13px; - font-size: 14px; - line-height: 1.42857143; - color: #475057; -} -.form-control { - display: block; - width: 100%; - height: 46px; - padding: 12px 16px; - font-size: 14px; - line-height: 1.42857143; - color: #475057; - background-color: #ffffff; - background-image: none; - border: 1px solid #dfd7ca; - border-radius: 4px; - -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); - box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); - -webkit-transition: border-color ease-in-out .15s, -webkit-box-shadow ease-in-out .15s; - -o-transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s; - transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s; -} -.form-control:focus { - border-color: transparent; - outline: 0; - -webkit-box-shadow: inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(0, 0, 0, 0.6); - box-shadow: inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(0, 0, 0, 0.6); -} -.form-control::-moz-placeholder { - color: #dfd7ca; - opacity: 1; -} -.form-control:-ms-input-placeholder { - color: #dfd7ca; -} -.form-control::-webkit-input-placeholder { - color: #dfd7ca; -} -.form-control[disabled], -.form-control[readonly], -fieldset[disabled] .form-control { - cursor: not-allowed; - background-color: #eff0f1; - opacity: 1; -} -textarea.form-control { - height: auto; -} -input[type="search"] { - -webkit-appearance: none; -} -@media screen and (-webkit-min-device-pixel-ratio: 0) { - input[type="date"], - input[type="time"], - input[type="datetime-local"], - input[type="month"] { - line-height: 46px; - } - input[type="date"].input-sm, - input[type="time"].input-sm, - input[type="datetime-local"].input-sm, - input[type="month"].input-sm { - line-height: 30px; - } - input[type="date"].input-lg, - input[type="time"].input-lg, - input[type="datetime-local"].input-lg, - input[type="month"].input-lg { - line-height: 66px; - } -} -.form-group { - margin-bottom: 15px; -} -.radio, -.checkbox { - position: relative; - display: block; - margin-top: 10px; - margin-bottom: 10px; -} -.radio label, -.checkbox label { - min-height: 20px; - padding-left: 20px; - margin-bottom: 0; - font-weight: normal; - cursor: pointer; -} -.radio input[type="radio"], -.radio-inline input[type="radio"], -.checkbox input[type="checkbox"], -.checkbox-inline input[type="checkbox"] { - position: absolute; - margin-left: -20px; - margin-top: 4px \9; -} -.radio + .radio, -.checkbox + .checkbox { - margin-top: -5px; -} -.radio-inline, -.checkbox-inline { - display: inline-block; - padding-left: 20px; - margin-bottom: 0; - vertical-align: middle; - font-weight: normal; - cursor: pointer; -} -.radio-inline + .radio-inline, -.checkbox-inline + .checkbox-inline { - margin-top: 0; - margin-left: 10px; -} -input[type="radio"][disabled], -input[type="checkbox"][disabled], -input[type="radio"].disabled, -input[type="checkbox"].disabled, -fieldset[disabled] input[type="radio"], -fieldset[disabled] input[type="checkbox"] { - cursor: not-allowed; -} -.radio-inline.disabled, -.checkbox-inline.disabled, -fieldset[disabled] .radio-inline, -fieldset[disabled] .checkbox-inline { - cursor: not-allowed; -} -.radio.disabled label, -.checkbox.disabled label, -fieldset[disabled] .radio label, -fieldset[disabled] .checkbox label { - cursor: not-allowed; -} -.form-control-static { - padding-top: 13px; - padding-bottom: 13px; - margin-bottom: 0; -} -.form-control-static.input-lg, -.form-control-static.input-sm { - padding-left: 0; - padding-right: 0; -} -.input-sm, -.form-group-sm .form-control { - height: 30px; - padding: 5px 10px; - font-size: 12px; - line-height: 1.5; - border-radius: 3px; -} -select.input-sm, -select.form-group-sm .form-control { - height: 30px; - line-height: 30px; -} -textarea.input-sm, -textarea.form-group-sm .form-control, -select[multiple].input-sm, -select[multiple].form-group-sm .form-control { - height: auto; -} -.input-lg, -.form-group-lg .form-control { - height: 66px; - padding: 20px 30px; - font-size: 18px; - line-height: 1.33; - border-radius: 6px; -} -select.input-lg, -select.form-group-lg .form-control { - height: 66px; - line-height: 66px; -} -textarea.input-lg, -textarea.form-group-lg .form-control, -select[multiple].input-lg, -select[multiple].form-group-lg .form-control { - height: auto; -} -.has-feedback { - position: relative; -} -.has-feedback .form-control { - padding-right: 57.5px; -} -.form-control-feedback { - position: absolute; - top: 0; - right: 0; - z-index: 2; - display: block; - width: 46px; - height: 46px; - line-height: 46px; - text-align: center; - pointer-events: none; -} -.input-lg + .form-control-feedback { - width: 66px; - height: 66px; - line-height: 66px; -} -.input-sm + .form-control-feedback { - width: 30px; - height: 30px; - line-height: 30px; -} -.has-success .help-block, -.has-success .control-label, -.has-success .radio, -.has-success .checkbox, -.has-success .radio-inline, -.has-success .checkbox-inline, -.has-success.radio label, -.has-success.checkbox label, -.has-success.radio-inline label, -.has-success.checkbox-inline label { - color: #3daee9; -} -.has-success .form-control { - border-color: #3daee9; - -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); - box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); -} -.has-success .form-control:focus { - border-color: #1a86db; - -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #c1de98; - box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #c1de98; -} -.has-success .input-group-addon { - color: #3daee9; - border-color: #3daee9; - background-color: #dff0d8; -} -.has-success .form-control-feedback { - color: #3daee9; -} -.has-warning .help-block, -.has-warning .control-label, -.has-warning .radio, -.has-warning .checkbox, -.has-warning .radio-inline, -.has-warning .checkbox-inline, -.has-warning.radio label, -.has-warning.checkbox label, -.has-warning.radio-inline label, -.has-warning.checkbox-inline label { - color: #f47c3c; -} -.has-warning .form-control { - border-color: #f47c3c; - -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); - box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); -} -.has-warning .form-control:focus { - border-color: #ef5c0e; - -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #f9bd9d; - box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #f9bd9d; -} -.has-warning .input-group-addon { - color: #f47c3c; - border-color: #f47c3c; - background-color: #fcf8e3; -} -.has-warning .form-control-feedback { - color: #f47c3c; -} -.has-error .help-block, -.has-error .control-label, -.has-error .radio, -.has-error .checkbox, -.has-error .radio-inline, -.has-error .checkbox-inline, -.has-error.radio label, -.has-error.checkbox label, -.has-error.radio-inline label, -.has-error.checkbox-inline label { - color: #d9534f; -} -.has-error .form-control { - border-color: #d9534f; - -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); - box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); -} -.has-error .form-control:focus { - border-color: #c9302c; - -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #eba5a3; - box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #eba5a3; -} -.has-error .input-group-addon { - color: #d9534f; - border-color: #d9534f; - background-color: #f2dede; -} -.has-error .form-control-feedback { - color: #d9534f; -} -.has-feedback label ~ .form-control-feedback { - top: 25px; -} -.has-feedback label.sr-only ~ .form-control-feedback { - top: 0; -} -.help-block { - display: block; - margin-top: 5px; - margin-bottom: 10px; - color: #7f8177; -} -@media (min-width: 768px) { - .form-inline .form-group { - display: inline-block; - margin-bottom: 0; - vertical-align: middle; - } - .form-inline .form-control { - display: inline-block; - width: auto; - vertical-align: middle; - } - .form-inline .form-control-static { - display: inline-block; - } - .form-inline .input-group { - display: inline-table; - vertical-align: middle; - } - .form-inline .input-group .input-group-addon, - .form-inline .input-group .input-group-btn, - .form-inline .input-group .form-control { - width: auto; - } - .form-inline .input-group > .form-control { - width: 100%; - } - .form-inline .control-label { - margin-bottom: 0; - vertical-align: middle; - } - .form-inline .radio, - .form-inline .checkbox { - display: inline-block; - margin-top: 0; - margin-bottom: 0; - vertical-align: middle; - } - .form-inline .radio label, - .form-inline .checkbox label { - padding-left: 0; - } - .form-inline .radio input[type="radio"], - .form-inline .checkbox input[type="checkbox"] { - position: relative; - margin-left: 0; - } - .form-inline .has-feedback .form-control-feedback { - top: 0; - } -} -.form-horizontal .radio, -.form-horizontal .checkbox, -.form-horizontal .radio-inline, -.form-horizontal .checkbox-inline { - margin-top: 0; - margin-bottom: 0; - padding-top: 13px; -} -.form-horizontal .radio, -.form-horizontal .checkbox { - min-height: 33px; -} -.form-horizontal .form-group { - margin-left: -15px; - margin-right: -15px; -} -@media (min-width: 768px) { - .form-horizontal .control-label { - text-align: right; - margin-bottom: 0; - padding-top: 13px; - } -} -.form-horizontal .has-feedback .form-control-feedback { - right: 15px; -} -@media (min-width: 768px) { - .form-horizontal .form-group-lg .control-label { - padding-top: 27.6px; - } -} -@media (min-width: 768px) { - .form-horizontal .form-group-sm .control-label { - padding-top: 6px; - } -} -.btn { - display: inline-block; - margin-bottom: 0; - font-weight: normal; - text-align: center; - vertical-align: middle; - -ms-touch-action: manipulation; - touch-action: manipulation; - cursor: pointer; - background-image: none; - border: 1px solid transparent; - white-space: nowrap; - padding: 12px 16px; - font-size: 14px; - line-height: 1.42857143; - border-radius: 4px; - -webkit-user-select: none; - -moz-user-select: none; - -ms-user-select: none; - user-select: none; -} -.btn:focus, -.btn:active:focus, -.btn.active:focus, -.btn.focus, -.btn:active.focus, -.btn.active.focus { - outline: thin dotted; - outline: 5px auto -webkit-focus-ring-color; - outline-offset: -2px; -} -.btn:hover, -.btn:focus, -.btn.focus { - color: #ffffff; - text-decoration: none; -} -.btn:active, -.btn.active { - outline: 0; - background-image: none; - -webkit-box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125); - box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125); -} -.btn.disabled, -.btn[disabled], -fieldset[disabled] .btn { - cursor: not-allowed; - pointer-events: none; - opacity: 0.65; - filter: alpha(opacity=65); - -webkit-box-shadow: none; - box-shadow: none; -} -.btn-default { - color: #ffffff; - background-color: #475057; - border-color: transparent; -} -.btn-default:hover, -.btn-default:focus, -.btn-default.focus, -.btn-default:active, -.btn-default.active, -.open > .dropdown-toggle.btn-default { - color: #ffffff; - background-color: #242422; - border-color: rgba(0, 0, 0, 0); -} -.btn-default:active, -.btn-default.active, -.open > .dropdown-toggle.btn-default { - background-image: none; -} -.btn-default.disabled, -.btn-default[disabled], -fieldset[disabled] .btn-default, -.btn-default.disabled:hover, -.btn-default[disabled]:hover, -fieldset[disabled] .btn-default:hover, -.btn-default.disabled:focus, -.btn-default[disabled]:focus, -fieldset[disabled] .btn-default:focus, -.btn-default.disabled.focus, -.btn-default[disabled].focus, -fieldset[disabled] .btn-default.focus, -.btn-default.disabled:active, -.btn-default[disabled]:active, -fieldset[disabled] .btn-default:active, -.btn-default.disabled.active, -.btn-default[disabled].active, -fieldset[disabled] .btn-default.active { - background-color: #475057; - border-color: transparent; -} -.btn-default .badge { - color: #475057; - background-color: #ffffff; -} -.btn-primary { - color: #ffffff; - background-color: #325d88; - border-color: transparent; -} -.btn-primary:hover, -.btn-primary:focus, -.btn-primary.focus, -.btn-primary:active, -.btn-primary.active, -.open > .dropdown-toggle.btn-primary { - color: #ffffff; - background-color: #244363; - border-color: rgba(0, 0, 0, 0); -} -.btn-primary:active, -.btn-primary.active, -.open > .dropdown-toggle.btn-primary { - background-image: none; -} -.btn-primary.disabled, -.btn-primary[disabled], -fieldset[disabled] .btn-primary, -.btn-primary.disabled:hover, -.btn-primary[disabled]:hover, -fieldset[disabled] .btn-primary:hover, -.btn-primary.disabled:focus, -.btn-primary[disabled]:focus, -fieldset[disabled] .btn-primary:focus, -.btn-primary.disabled.focus, -.btn-primary[disabled].focus, -fieldset[disabled] .btn-primary.focus, -.btn-primary.disabled:active, -.btn-primary[disabled]:active, -fieldset[disabled] .btn-primary:active, -.btn-primary.disabled.active, -.btn-primary[disabled].active, -fieldset[disabled] .btn-primary.active { - background-color: #325d88; - border-color: transparent; -} -.btn-primary .badge { - color: #325d88; - background-color: #ffffff; -} -.btn-success { - color: #ffffff; - background-color: #3daee9; - border-color: transparent; -} -.btn-success:hover, -.btn-success:focus, -.btn-success.focus, -.btn-success:active, -.btn-success.active, -.open > .dropdown-toggle.btn-success { - color: #ffffff; - background-color: #1a86db; - border-color: rgba(0, 0, 0, 0); -} -.btn-success:active, -.btn-success.active, -.open > .dropdown-toggle.btn-success { - background-image: none; -} -.btn-success.disabled, -.btn-success[disabled], -fieldset[disabled] .btn-success, -.btn-success.disabled:hover, -.btn-success[disabled]:hover, -fieldset[disabled] .btn-success:hover, -.btn-success.disabled:focus, -.btn-success[disabled]:focus, -fieldset[disabled] .btn-success:focus, -.btn-success.disabled.focus, -.btn-success[disabled].focus, -fieldset[disabled] .btn-success.focus, -.btn-success.disabled:active, -.btn-success[disabled]:active, -fieldset[disabled] .btn-success:active, -.btn-success.disabled.active, -.btn-success[disabled].active, -fieldset[disabled] .btn-success.active { - background-color: #3daee9; - border-color: transparent; -} -.btn-success .badge { - color: #3daee9; - background-color: #ffffff; -} -.btn-info { - color: #ffffff; - background-color: #29abe0; - border-color: transparent; -} -.btn-info:hover, -.btn-info:focus, -.btn-info.focus, -.btn-info:active, -.btn-info.active, -.open > .dropdown-toggle.btn-info { - color: #ffffff; - background-color: #1b8dbb; - border-color: rgba(0, 0, 0, 0); -} -.btn-info:active, -.btn-info.active, -.open > .dropdown-toggle.btn-info { - background-image: none; -} -.btn-info.disabled, -.btn-info[disabled], -fieldset[disabled] .btn-info, -.btn-info.disabled:hover, -.btn-info[disabled]:hover, -fieldset[disabled] .btn-info:hover, -.btn-info.disabled:focus, -.btn-info[disabled]:focus, -fieldset[disabled] .btn-info:focus, -.btn-info.disabled.focus, -.btn-info[disabled].focus, -fieldset[disabled] .btn-info.focus, -.btn-info.disabled:active, -.btn-info[disabled]:active, -fieldset[disabled] .btn-info:active, -.btn-info.disabled.active, -.btn-info[disabled].active, -fieldset[disabled] .btn-info.active { - background-color: #29abe0; - border-color: transparent; -} -.btn-info .badge { - color: #29abe0; - background-color: #ffffff; -} -.btn-warning { - color: #ffffff; - background-color: #f47c3c; - border-color: transparent; -} -.btn-warning:hover, -.btn-warning:focus, -.btn-warning.focus, -.btn-warning:active, -.btn-warning.active, -.open > .dropdown-toggle.btn-warning { - color: #ffffff; - background-color: #ef5c0e; - border-color: rgba(0, 0, 0, 0); -} -.btn-warning:active, -.btn-warning.active, -.open > .dropdown-toggle.btn-warning { - background-image: none; -} -.btn-warning.disabled, -.btn-warning[disabled], -fieldset[disabled] .btn-warning, -.btn-warning.disabled:hover, -.btn-warning[disabled]:hover, -fieldset[disabled] .btn-warning:hover, -.btn-warning.disabled:focus, -.btn-warning[disabled]:focus, -fieldset[disabled] .btn-warning:focus, -.btn-warning.disabled.focus, -.btn-warning[disabled].focus, -fieldset[disabled] .btn-warning.focus, -.btn-warning.disabled:active, -.btn-warning[disabled]:active, -fieldset[disabled] .btn-warning:active, -.btn-warning.disabled.active, -.btn-warning[disabled].active, -fieldset[disabled] .btn-warning.active { - background-color: #f47c3c; - border-color: transparent; -} -.btn-warning .badge { - color: #f47c3c; - background-color: #ffffff; -} -.btn-danger { - color: #ffffff; - background-color: #d9534f; - border-color: transparent; -} -.btn-danger:hover, -.btn-danger:focus, -.btn-danger.focus, -.btn-danger:active, -.btn-danger.active, -.open > .dropdown-toggle.btn-danger { - color: #ffffff; - background-color: #c9302c; - border-color: rgba(0, 0, 0, 0); -} -.btn-danger:active, -.btn-danger.active, -.open > .dropdown-toggle.btn-danger { - background-image: none; -} -.btn-danger.disabled, -.btn-danger[disabled], -fieldset[disabled] .btn-danger, -.btn-danger.disabled:hover, -.btn-danger[disabled]:hover, -fieldset[disabled] .btn-danger:hover, -.btn-danger.disabled:focus, -.btn-danger[disabled]:focus, -fieldset[disabled] .btn-danger:focus, -.btn-danger.disabled.focus, -.btn-danger[disabled].focus, -fieldset[disabled] .btn-danger.focus, -.btn-danger.disabled:active, -.btn-danger[disabled]:active, -fieldset[disabled] .btn-danger:active, -.btn-danger.disabled.active, -.btn-danger[disabled].active, -fieldset[disabled] .btn-danger.active { - background-color: #d9534f; - border-color: transparent; -} -.btn-danger .badge { - color: #d9534f; - background-color: #ffffff; -} -.btn-link { - color: #3daee9; - font-weight: normal; - border-radius: 0; -} -.btn-link, -.btn-link:active, -.btn-link.active, -.btn-link[disabled], -fieldset[disabled] .btn-link { - background-color: transparent; - -webkit-box-shadow: none; - box-shadow: none; -} -.btn-link, -.btn-link:hover, -.btn-link:focus, -.btn-link:active { - border-color: transparent; -} -.btn-link:hover, -.btn-link:focus { - color: #1a86db; - text-decoration: underline; - background-color: transparent; -} -.btn-link[disabled]:hover, -fieldset[disabled] .btn-link:hover, -.btn-link[disabled]:focus, -fieldset[disabled] .btn-link:focus { - color: #dfd7ca; - text-decoration: none; -} -.btn-lg, -.btn-group-lg > .btn { - padding: 20px 30px; - font-size: 18px; - line-height: 1.33; - border-radius: 6px; -} -.btn-sm, -.btn-group-sm > .btn { - padding: 5px 10px; - font-size: 12px; - line-height: 1.5; - border-radius: 3px; -} -.btn-xs, -.btn-group-xs > .btn { - padding: 1px 5px; - font-size: 12px; - line-height: 1.5; - border-radius: 3px; -} -.btn-block { - display: block; - width: 100%; -} -.btn-block + .btn-block { - margin-top: 5px; -} -input[type="submit"].btn-block, -input[type="reset"].btn-block, -input[type="button"].btn-block { - width: 100%; -} -.fade { - opacity: 0; - -webkit-transition: opacity 0.15s linear; - -o-transition: opacity 0.15s linear; - transition: opacity 0.15s linear; -} -.fade.in { - opacity: 1; -} -.collapse { - display: none; - visibility: hidden; -} -.collapse.in { - display: block; - visibility: visible; -} -tr.collapse.in { - display: table-row; -} -tbody.collapse.in { - display: table-row-group; -} -.collapsing { - position: relative; - height: 0; - overflow: hidden; - -webkit-transition-property: height, visibility; - -o-transition-property: height, visibility; - transition-property: height, visibility; - -webkit-transition-duration: 0.35s; - -o-transition-duration: 0.35s; - transition-duration: 0.35s; - -webkit-transition-timing-function: ease; - -o-transition-timing-function: ease; - transition-timing-function: ease; -} -.caret { - display: inline-block; - width: 0; - height: 0; - margin-left: 2px; - vertical-align: middle; - border-top: 4px solid; - border-right: 4px solid transparent; - border-left: 4px solid transparent; -} -.dropdown { - position: relative; -} -.dropdown-toggle:focus { - outline: 0; -} -.dropdown-menu { - position: absolute; - top: 100%; - left: 0; - z-index: 1000; - display: none; - float: left; - min-width: 160px; - padding: 5px 0; - margin: 2px 0 0; - list-style: none; - font-size: 14px; - text-align: left; - background-color: #ffffff; - border: 1px solid #dfd7ca; - border-radius: 4px; - -webkit-box-shadow: 0 6px 12px rgba(0, 0, 0, 0.175); - box-shadow: 0 6px 12px rgba(0, 0, 0, 0.175); - -webkit-background-clip: padding-box; - background-clip: padding-box; -} -.dropdown-menu.pull-right { - right: 0; - left: auto; -} -.dropdown-menu .divider { - height: 1px; - margin: 9px 0; - overflow: hidden; - background-color: #eff0f1; -} -.dropdown-menu > li > a { - display: block; - padding: 3px 20px; - clear: both; - font-weight: normal; - line-height: 1.42857143; - color: #98978b; - white-space: nowrap; -} -.dropdown-menu > li > a:hover, -.dropdown-menu > li > a:focus { - text-decoration: none; - color: #98978b; - background-color: #eff0f1; -} -.dropdown-menu > .active > a, -.dropdown-menu > .active > a:hover, -.dropdown-menu > .active > a:focus { - color: #98978b; - text-decoration: none; - outline: 0; - background-color: #eff0f1; -} -.dropdown-menu > .disabled > a, -.dropdown-menu > .disabled > a:hover, -.dropdown-menu > .disabled > a:focus { - color: #dfd7ca; -} -.dropdown-menu > .disabled > a:hover, -.dropdown-menu > .disabled > a:focus { - text-decoration: none; - background-color: transparent; - background-image: none; - filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); - cursor: not-allowed; -} -.open > .dropdown-menu { - display: block; -} -.open > a { - outline: 0; -} -.dropdown-menu-right { - left: auto; - right: 0; -} -.dropdown-menu-left { - left: 0; - right: auto; -} -.dropdown-header { - display: block; - padding: 3px 20px; - font-size: 12px; - line-height: 1.42857143; - color: #dfd7ca; - white-space: nowrap; -} -.dropdown-backdrop { - position: fixed; - left: 0; - right: 0; - bottom: 0; - top: 0; - z-index: 990; -} -.pull-right > .dropdown-menu { - right: 0; - left: auto; -} -.dropup .caret, -.navbar-fixed-bottom .dropdown .caret { - border-top: 0; - border-bottom: 4px solid; - content: ""; -} -.dropup .dropdown-menu, -.navbar-fixed-bottom .dropdown .dropdown-menu { - top: auto; - bottom: 100%; - margin-bottom: 1px; -} -@media (min-width: 1000px) { - .navbar-right .dropdown-menu { - left: auto; - right: 0; - } - .navbar-right .dropdown-menu-left { - left: 0; - right: auto; - } -} -.btn-group, -.btn-group-vertical { - position: relative; - display: inline-block; - vertical-align: middle; -} -.btn-group > .btn, -.btn-group-vertical > .btn { - position: relative; - float: left; -} -.btn-group > .btn:hover, -.btn-group-vertical > .btn:hover, -.btn-group > .btn:focus, -.btn-group-vertical > .btn:focus, -.btn-group > .btn:active, -.btn-group-vertical > .btn:active, -.btn-group > .btn.active, -.btn-group-vertical > .btn.active { - z-index: 2; -} -.btn-group .btn + .btn, -.btn-group .btn + .btn-group, -.btn-group .btn-group + .btn, -.btn-group .btn-group + .btn-group { - margin-left: -1px; -} -.btn-toolbar { - margin-left: -5px; -} -.btn-toolbar .btn-group, -.btn-toolbar .input-group { - float: left; -} -.btn-toolbar > .btn, -.btn-toolbar > .btn-group, -.btn-toolbar > .input-group { - margin-left: 5px; -} -.btn-group > .btn:not(:first-child):not(:last-child):not(.dropdown-toggle) { - border-radius: 0; -} -.btn-group > .btn:first-child { - margin-left: 0; -} -.btn-group > .btn:first-child:not(:last-child):not(.dropdown-toggle) { - border-bottom-right-radius: 0; - border-top-right-radius: 0; -} -.btn-group > .btn:last-child:not(:first-child), -.btn-group > .dropdown-toggle:not(:first-child) { - border-bottom-left-radius: 0; - border-top-left-radius: 0; -} -.btn-group > .btn-group { - float: left; -} -.btn-group > .btn-group:not(:first-child):not(:last-child) > .btn { - border-radius: 0; -} -.btn-group > .btn-group:first-child > .btn:last-child, -.btn-group > .btn-group:first-child > .dropdown-toggle { - border-bottom-right-radius: 0; - border-top-right-radius: 0; -} -.btn-group > .btn-group:last-child > .btn:first-child { - border-bottom-left-radius: 0; - border-top-left-radius: 0; -} -.btn-group .dropdown-toggle:active, -.btn-group.open .dropdown-toggle { - outline: 0; -} -.btn-group > .btn + .dropdown-toggle { - padding-left: 8px; - padding-right: 8px; -} -.btn-group > .btn-lg + .dropdown-toggle { - padding-left: 12px; - padding-right: 12px; -} -.btn-group.open .dropdown-toggle { - -webkit-box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125); - box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125); -} -.btn-group.open .dropdown-toggle.btn-link { - -webkit-box-shadow: none; - box-shadow: none; -} -.btn .caret { - margin-left: 0; -} -.btn-lg .caret { - border-width: 5px 5px 0; - border-bottom-width: 0; -} -.dropup .btn-lg .caret { - border-width: 0 5px 5px; -} -.btn-group-vertical > .btn, -.btn-group-vertical > .btn-group, -.btn-group-vertical > .btn-group > .btn { - display: block; - float: none; - width: 100%; - max-width: 100%; -} -.btn-group-vertical > .btn-group > .btn { - float: none; -} -.btn-group-vertical > .btn + .btn, -.btn-group-vertical > .btn + .btn-group, -.btn-group-vertical > .btn-group + .btn, -.btn-group-vertical > .btn-group + .btn-group { - margin-top: -1px; - margin-left: 0; -} -.btn-group-vertical > .btn:not(:first-child):not(:last-child) { - border-radius: 0; -} -.btn-group-vertical > .btn:first-child:not(:last-child) { - border-top-right-radius: 4px; - border-bottom-right-radius: 0; - border-bottom-left-radius: 0; -} -.btn-group-vertical > .btn:last-child:not(:first-child) { - border-bottom-left-radius: 4px; - border-top-right-radius: 0; - border-top-left-radius: 0; -} -.btn-group-vertical > .btn-group:not(:first-child):not(:last-child) > .btn { - border-radius: 0; -} -.btn-group-vertical > .btn-group:first-child:not(:last-child) > .btn:last-child, -.btn-group-vertical > .btn-group:first-child:not(:last-child) > .dropdown-toggle { - border-bottom-right-radius: 0; - border-bottom-left-radius: 0; -} -.btn-group-vertical > .btn-group:last-child:not(:first-child) > .btn:first-child { - border-top-right-radius: 0; - border-top-left-radius: 0; -} -.btn-group-justified { - display: table; - width: 100%; - table-layout: fixed; - border-collapse: separate; -} -.btn-group-justified > .btn, -.btn-group-justified > .btn-group { - float: none; - display: table-cell; - width: 1%; -} -.btn-group-justified > .btn-group .btn { - width: 100%; -} -.btn-group-justified > .btn-group .dropdown-menu { - left: auto; -} -[data-toggle="buttons"] > .btn input[type="radio"], -[data-toggle="buttons"] > .btn-group > .btn input[type="radio"], -[data-toggle="buttons"] > .btn input[type="checkbox"], -[data-toggle="buttons"] > .btn-group > .btn input[type="checkbox"] { - position: absolute; - clip: rect(0, 0, 0, 0); - pointer-events: none; -} -.input-group { - position: relative; - display: table; - border-collapse: separate; -} -.input-group[class*="col-"] { - float: none; - padding-left: 0; - padding-right: 0; -} -.input-group .form-control { - position: relative; - z-index: 2; - float: left; - width: 100%; - margin-bottom: 0; -} -.input-group-lg > .form-control, -.input-group-lg > .input-group-addon, -.input-group-lg > .input-group-btn > .btn { - height: 66px; - padding: 20px 30px; - font-size: 18px; - line-height: 1.33; - border-radius: 6px; -} -select.input-group-lg > .form-control, -select.input-group-lg > .input-group-addon, -select.input-group-lg > .input-group-btn > .btn { - height: 66px; - line-height: 66px; -} -textarea.input-group-lg > .form-control, -textarea.input-group-lg > .input-group-addon, -textarea.input-group-lg > .input-group-btn > .btn, -select[multiple].input-group-lg > .form-control, -select[multiple].input-group-lg > .input-group-addon, -select[multiple].input-group-lg > .input-group-btn > .btn { - height: auto; -} -.input-group-sm > .form-control, -.input-group-sm > .input-group-addon, -.input-group-sm > .input-group-btn > .btn { - height: 30px; - padding: 5px 10px; - font-size: 12px; - line-height: 1.5; - border-radius: 3px; -} -select.input-group-sm > .form-control, -select.input-group-sm > .input-group-addon, -select.input-group-sm > .input-group-btn > .btn { - height: 30px; - line-height: 30px; -} -textarea.input-group-sm > .form-control, -textarea.input-group-sm > .input-group-addon, -textarea.input-group-sm > .input-group-btn > .btn, -select[multiple].input-group-sm > .form-control, -select[multiple].input-group-sm > .input-group-addon, -select[multiple].input-group-sm > .input-group-btn > .btn { - height: auto; -} -.input-group-addon, -.input-group-btn, -.input-group .form-control { - display: table-cell; -} -.input-group-addon:not(:first-child):not(:last-child), -.input-group-btn:not(:first-child):not(:last-child), -.input-group .form-control:not(:first-child):not(:last-child) { - border-radius: 0; -} -.input-group-addon, -.input-group-btn { - width: 1%; - white-space: nowrap; - vertical-align: middle; -} -.input-group-addon { - padding: 12px 16px; - font-size: 14px; - font-weight: normal; - line-height: 1; - color: #475057; - text-align: center; - background-color: #eff0f1; - border: 1px solid #dfd7ca; - border-radius: 4px; -} -.input-group-addon.input-sm { - padding: 5px 10px; - font-size: 12px; - border-radius: 3px; -} -.input-group-addon.input-lg { - padding: 20px 30px; - font-size: 18px; - border-radius: 6px; -} -.input-group-addon input[type="radio"], -.input-group-addon input[type="checkbox"] { - margin-top: 0; -} -.input-group .form-control:first-child, -.input-group-addon:first-child, -.input-group-btn:first-child > .btn, -.input-group-btn:first-child > .btn-group > .btn, -.input-group-btn:first-child > .dropdown-toggle, -.input-group-btn:last-child > .btn:not(:last-child):not(.dropdown-toggle), -.input-group-btn:last-child > .btn-group:not(:last-child) > .btn { - border-bottom-right-radius: 0; - border-top-right-radius: 0; -} -.input-group-addon:first-child { - border-right: 0; -} -.input-group .form-control:last-child, -.input-group-addon:last-child, -.input-group-btn:last-child > .btn, -.input-group-btn:last-child > .btn-group > .btn, -.input-group-btn:last-child > .dropdown-toggle, -.input-group-btn:first-child > .btn:not(:first-child), -.input-group-btn:first-child > .btn-group:not(:first-child) > .btn { - border-bottom-left-radius: 0; - border-top-left-radius: 0; -} -.input-group-addon:last-child { - border-left: 0; -} -.input-group-btn { - position: relative; - font-size: 0; - white-space: nowrap; -} -.input-group-btn > .btn { - position: relative; -} -.input-group-btn > .btn + .btn { - margin-left: -1px; -} -.input-group-btn > .btn:hover, -.input-group-btn > .btn:focus, -.input-group-btn > .btn:active { - z-index: 2; -} -.input-group-btn:first-child > .btn, -.input-group-btn:first-child > .btn-group { - margin-right: -1px; -} -.input-group-btn:last-child > .btn, -.input-group-btn:last-child > .btn-group { - margin-left: -1px; -} -.nav { - margin-bottom: 0; - padding-left: 0; - list-style: none; -} -.nav > li { - position: relative; - display: block; -} -.nav > li > a { - position: relative; - display: block; - padding: 10px 15px; -} -.nav > li > a:hover, -.nav > li > a:focus { - text-decoration: none; - background-color: #eff0f1; -} -.nav > li.disabled > a { - color: #dfd7ca; -} -.nav > li.disabled > a:hover, -.nav > li.disabled > a:focus { - color: #dfd7ca; - text-decoration: none; - background-color: transparent; - cursor: not-allowed; -} -.nav .open > a, -.nav .open > a:hover, -.nav .open > a:focus { - background-color: #eff0f1; - border-color: #3daee9; -} -.nav .nav-divider { - height: 1px; - margin: 9px 0; - overflow: hidden; - background-color: #e5e5e5; -} -.nav > li > a > img { - max-width: none; -} -.nav-tabs { - border-bottom: 1px solid #dfd7ca; -} -.nav-tabs > li { - float: left; - margin-bottom: -1px; -} -.nav-tabs > li > a { - margin-right: 2px; - line-height: 1.42857143; - border: 1px solid transparent; - border-radius: 4px 4px 0 0; -} -.nav-tabs > li > a:hover { - border-color: #dfd7ca #dfd7ca #dfd7ca; -} -.nav-tabs > li.active > a, -.nav-tabs > li.active > a:hover, -.nav-tabs > li.active > a:focus { - color: #98978b; - background-color: #ffffff; - border: 1px solid #dfd7ca; - border-bottom-color: transparent; - cursor: default; -} -.nav-tabs.nav-justified { - width: 100%; - border-bottom: 0; -} -.nav-tabs.nav-justified > li { - float: none; -} -.nav-tabs.nav-justified > li > a { - text-align: center; - margin-bottom: 5px; -} -.nav-tabs.nav-justified > .dropdown .dropdown-menu { - top: auto; - left: auto; -} -@media (min-width: 768px) { - .nav-tabs.nav-justified > li { - display: table-cell; - width: 1%; - } - .nav-tabs.nav-justified > li > a { - margin-bottom: 0; - } -} -.nav-tabs.nav-justified > li > a { - margin-right: 0; - border-radius: 4px; -} -.nav-tabs.nav-justified > .active > a, -.nav-tabs.nav-justified > .active > a:hover, -.nav-tabs.nav-justified > .active > a:focus { - border: 1px solid #dfd7ca; -} -@media (min-width: 768px) { - .nav-tabs.nav-justified > li > a { - border-bottom: 1px solid #dfd7ca; - border-radius: 4px 4px 0 0; - } - .nav-tabs.nav-justified > .active > a, - .nav-tabs.nav-justified > .active > a:hover, - .nav-tabs.nav-justified > .active > a:focus { - border-bottom-color: #ffffff; - } -} -.nav-pills > li { - float: left; -} -.nav-pills > li > a { - border-radius: 4px; -} -.nav-pills > li + li { - margin-left: 2px; -} -.nav-pills > li.active > a, -.nav-pills > li.active > a:hover, -.nav-pills > li.active > a:focus { - color: #98978b; - background-color: #eff0f1; -} -.nav-stacked > li { - float: none; -} -.nav-stacked > li + li { - margin-top: 2px; - margin-left: 0; -} -.nav-justified { - width: 100%; -} -.nav-justified > li { - float: none; -} -.nav-justified > li > a { - text-align: center; - margin-bottom: 5px; -} -.nav-justified > .dropdown .dropdown-menu { - top: auto; - left: auto; -} -@media (min-width: 768px) { - .nav-justified > li { - display: table-cell; - width: 1%; - } - .nav-justified > li > a { - margin-bottom: 0; - } -} -.nav-tabs-justified { - border-bottom: 0; -} -.nav-tabs-justified > li > a { - margin-right: 0; - border-radius: 4px; -} -.nav-tabs-justified > .active > a, -.nav-tabs-justified > .active > a:hover, -.nav-tabs-justified > .active > a:focus { - border: 1px solid #dfd7ca; -} -@media (min-width: 768px) { - .nav-tabs-justified > li > a { - border-bottom: 1px solid #dfd7ca; - border-radius: 4px 4px 0 0; - } - .nav-tabs-justified > .active > a, - .nav-tabs-justified > .active > a:hover, - .nav-tabs-justified > .active > a:focus { - border-bottom-color: #ffffff; - } -} -.tab-content > .tab-pane { - display: none; - visibility: hidden; -} -.tab-content > .active { - display: block; - visibility: visible; -} -.nav-tabs .dropdown-menu { - margin-top: -1px; - border-top-right-radius: 0; - border-top-left-radius: 0; -} -.navbar { - position: relative; - min-height: 60px; - margin-bottom: 20px; - border: 1px solid transparent; -} -@media (min-width: 1000px) { - .navbar { - border-radius: 4px; - } -} -@media (min-width: 1000px) { - .navbar-header { - float: left; - } -} -.navbar-collapse { - overflow-x: visible; - padding-right: 15px; - padding-left: 15px; - border-top: 1px solid transparent; - -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1); - box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1); - -webkit-overflow-scrolling: touch; -} -.navbar-collapse.in { - overflow-y: auto; -} -@media (min-width: 1000px) { - .navbar-collapse { - width: auto; - border-top: 0; - -webkit-box-shadow: none; - box-shadow: none; - } - .navbar-collapse.collapse { - display: block !important; - visibility: visible !important; - height: auto !important; - padding-bottom: 0; - overflow: visible !important; - } - .navbar-collapse.in { - overflow-y: visible; - } - .navbar-fixed-top .navbar-collapse, - .navbar-static-top .navbar-collapse, - .navbar-fixed-bottom .navbar-collapse { - padding-left: 0; - padding-right: 0; - } -} -.navbar-fixed-top .navbar-collapse, -.navbar-fixed-bottom .navbar-collapse { - max-height: 340px; -} -@media (max-device-width: 480px) and (orientation: landscape) { - .navbar-fixed-top .navbar-collapse, - .navbar-fixed-bottom .navbar-collapse { - max-height: 200px; - } -} -.container > .navbar-header, -.container-fluid > .navbar-header, -.container > .navbar-collapse, -.container-fluid > .navbar-collapse { - margin-right: -15px; - margin-left: -15px; -} -@media (min-width: 1000px) { - .container > .navbar-header, - .container-fluid > .navbar-header, - .container > .navbar-collapse, - .container-fluid > .navbar-collapse { - margin-right: 0; - margin-left: 0; - } -} -.navbar-static-top { - z-index: 1000; - border-width: 0 0 1px; -} -@media (min-width: 1000px) { - .navbar-static-top { - border-radius: 0; - } -} -.navbar-fixed-top, -.navbar-fixed-bottom { - position: fixed; - right: 0; - left: 0; - z-index: 1030; -} -@media (min-width: 1000px) { - .navbar-fixed-top, - .navbar-fixed-bottom { - border-radius: 0; - } -} -.navbar-fixed-top { - top: 0; - border-width: 0 0 1px; -} -.navbar-fixed-bottom { - bottom: 0; - margin-bottom: 0; - border-width: 1px 0 0; -} -.navbar-brand { - float: left; - padding: 20px 15px; - font-size: 18px; - line-height: 20px; - height: 60px; -} -.navbar-brand:hover, -.navbar-brand:focus { - text-decoration: none; -} -.navbar-brand > img { - display: block; -} -@media (min-width: 1000px) { - .navbar > .container .navbar-brand, - .navbar > .container-fluid .navbar-brand { - margin-left: -15px; - } -} -.navbar-toggle { - position: relative; - float: right; - margin-right: 15px; - padding: 9px 10px; - margin-top: 13px; - margin-bottom: 13px; - background-color: transparent; - background-image: none; - border: 1px solid transparent; - border-radius: 4px; -} -.navbar-toggle:focus { - outline: 0; -} -.navbar-toggle .icon-bar { - display: block; - width: 22px; - height: 2px; - border-radius: 1px; -} -.navbar-toggle .icon-bar + .icon-bar { - margin-top: 4px; -} -@media (min-width: 1000px) { - .navbar-toggle { - display: none; - } -} -.navbar-nav { - margin: 10px -15px; -} -.navbar-nav > li > a { - padding-top: 10px; - padding-bottom: 10px; - line-height: 20px; -} -@media (max-width: 767px) { - .navbar-nav .open .dropdown-menu { - position: static; - float: none; - width: auto; - margin-top: 0; - background-color: transparent; - border: 0; - -webkit-box-shadow: none; - box-shadow: none; - } - .navbar-nav .open .dropdown-menu > li > a, - .navbar-nav .open .dropdown-menu .dropdown-header { - padding: 5px 15px 5px 25px; - } - .navbar-nav .open .dropdown-menu > li > a { - line-height: 20px; - } - .navbar-nav .open .dropdown-menu > li > a:hover, - .navbar-nav .open .dropdown-menu > li > a:focus { - background-image: none; - } -} -@media (min-width: 1000px) { - .navbar-nav { - float: left; - margin: 0; - } - .navbar-nav > li { - float: left; - } - .navbar-nav > li > a { - padding-top: 20px; - padding-bottom: 20px; - } -} -.navbar-form { - margin-left: -15px; - margin-right: -15px; - padding: 10px 15px; - border-top: 1px solid transparent; - border-bottom: 1px solid transparent; - -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1); - box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1); - margin-top: 7px; - margin-bottom: 7px; -} -@media (min-width: 1000px) { - .navbar-form .form-group { - display: inline-block; - margin-bottom: 0; - vertical-align: middle; - } - .navbar-form .form-control { - display: inline-block; - width: auto; - vertical-align: middle; - } - .navbar-form .form-control-static { - display: inline-block; - } - .navbar-form .input-group { - display: inline-table; - vertical-align: middle; - } - .navbar-form .input-group .input-group-addon, - .navbar-form .input-group .input-group-btn, - .navbar-form .input-group .form-control { - width: auto; - } - .navbar-form .input-group > .form-control { - width: 100%; - } - .navbar-form .control-label { - margin-bottom: 0; - vertical-align: middle; - } - .navbar-form .radio, - .navbar-form .checkbox { - display: inline-block; - margin-top: 0; - margin-bottom: 0; - vertical-align: middle; - } - .navbar-form .radio label, - .navbar-form .checkbox label { - padding-left: 0; - } - .navbar-form .radio input[type="radio"], - .navbar-form .checkbox input[type="checkbox"] { - position: relative; - margin-left: 0; - } - .navbar-form .has-feedback .form-control-feedback { - top: 0; - } -} -@media (max-width: 767px) { - .navbar-form .form-group { - margin-bottom: 5px; - } - .navbar-form .form-group:last-child { - margin-bottom: 0; - } -} -@media (min-width: 1000px) { - .navbar-form { - width: auto; - border: 0; - margin-left: 0; - margin-right: 0; - padding-top: 0; - padding-bottom: 0; - -webkit-box-shadow: none; - box-shadow: none; - } -} -.navbar-nav > li > .dropdown-menu { - margin-top: 0; - border-top-right-radius: 0; - border-top-left-radius: 0; -} -.navbar-fixed-bottom .navbar-nav > li > .dropdown-menu { - border-top-right-radius: 4px; - border-top-left-radius: 4px; - border-bottom-right-radius: 0; - border-bottom-left-radius: 0; -} -.navbar-btn { - margin-top: 7px; - margin-bottom: 7px; -} -.navbar-btn.btn-sm { - margin-top: 15px; - margin-bottom: 15px; -} -.navbar-btn.btn-xs { - margin-top: 19px; - margin-bottom: 19px; -} -.navbar-text { - margin-top: 20px; - margin-bottom: 20px; -} -@media (min-width: 1000px) { - .navbar-text { - float: left; - margin-left: 15px; - margin-right: 15px; - } -} -@media (min-width: 1000px) { - .navbar-left { - float: left !important; - } - .navbar-right { - float: right !important; - margin-right: -15px; - } - .navbar-right ~ .navbar-right { - margin-right: 0; - } -} -.navbar-default { - background-color: #475057; - border-color: #475057; -} -.navbar-default .navbar-brand { - color: #ffffff; -} -.navbar-default .navbar-brand:hover, -.navbar-default .navbar-brand:focus { - color: #ffffff; - background-color: transparent; -} -.navbar-default .navbar-text { - color: #8e8c84; -} -.navbar-default .navbar-nav > li > a { - color: #bdc3c7; -} -.navbar-default .navbar-nav > li > a:hover, -.navbar-default .navbar-nav > li > a:focus { - color: #ffffff; - background-color: transparent; -} -.navbar-default .navbar-nav > .active > a, -.navbar-default .navbar-nav > .active > a:hover, -.navbar-default .navbar-nav > .active > a:focus { - color: #ffffff; - background-color: #393a35; -} -.navbar-default .navbar-nav > .disabled > a, -.navbar-default .navbar-nav > .disabled > a:hover, -.navbar-default .navbar-nav > .disabled > a:focus { - color: #cccccc; - background-color: transparent; -} -.navbar-default .navbar-toggle { - border-color: transparent; -} -.navbar-default .navbar-toggle:hover, -.navbar-default .navbar-toggle:focus { - background-color: #393a35; -} -.navbar-default .navbar-toggle .icon-bar { - background-color: #98978b; -} -.navbar-default .navbar-collapse, -.navbar-default .navbar-form { - border-color: #475057; -} -.navbar-default .navbar-nav > .open > a, -.navbar-default .navbar-nav > .open > a:hover, -.navbar-default .navbar-nav > .open > a:focus { - background-color: #393a35; - color: #ffffff; -} -@media (max-width: 767px) { - .navbar-default .navbar-nav .open .dropdown-menu > li > a { - color: #bdc3c7; - } - .navbar-default .navbar-nav .open .dropdown-menu > li > a:hover, - .navbar-default .navbar-nav .open .dropdown-menu > li > a:focus { - color: #ffffff; - background-color: transparent; - } - .navbar-default .navbar-nav .open .dropdown-menu > .active > a, - .navbar-default .navbar-nav .open .dropdown-menu > .active > a:hover, - .navbar-default .navbar-nav .open .dropdown-menu > .active > a:focus { - color: #ffffff; - background-color: #393a35; - } - .navbar-default .navbar-nav .open .dropdown-menu > .disabled > a, - .navbar-default .navbar-nav .open .dropdown-menu > .disabled > a:hover, - .navbar-default .navbar-nav .open .dropdown-menu > .disabled > a:focus { - color: #cccccc; - background-color: transparent; - } -} -.navbar-default .navbar-link { - color: #bdc3c7; -} -.navbar-default .navbar-link:hover { - color: #ffffff; -} -.navbar-default .btn-link { - color: #bdc3c7; -} -.navbar-default .btn-link:hover, -.navbar-default .btn-link:focus { - color: #ffffff; -} -.navbar-default .btn-link[disabled]:hover, -fieldset[disabled] .navbar-default .btn-link:hover, -.navbar-default .btn-link[disabled]:focus, -fieldset[disabled] .navbar-default .btn-link:focus { - color: #cccccc; -} -.navbar-inverse { - background-color: #3daee9; - border-color: #3daee9; -} -.navbar-inverse .navbar-brand { - color: #ffffff; -} -.navbar-inverse .navbar-brand:hover, -.navbar-inverse .navbar-brand:focus { - color: #ffffff; - background-color: transparent; -} -.navbar-inverse .navbar-text { - color: #dfd7ca; -} -.navbar-inverse .navbar-nav > li > a { - color: #6b9430; -} -.navbar-inverse .navbar-nav > li > a:hover, -.navbar-inverse .navbar-nav > li > a:focus { - color: #ffffff; - background-color: transparent; -} -.navbar-inverse .navbar-nav > .active > a, -.navbar-inverse .navbar-nav > .active > a:hover, -.navbar-inverse .navbar-nav > .active > a:focus { - color: #ffffff; - background-color: #89be3d; -} -.navbar-inverse .navbar-nav > .disabled > a, -.navbar-inverse .navbar-nav > .disabled > a:hover, -.navbar-inverse .navbar-nav > .disabled > a:focus { - color: #444444; - background-color: transparent; -} -.navbar-inverse .navbar-toggle { - border-color: transparent; -} -.navbar-inverse .navbar-toggle:hover, -.navbar-inverse .navbar-toggle:focus { - background-color: #89be3d; -} -.navbar-inverse .navbar-toggle .icon-bar { - background-color: #6b9430; -} -.navbar-inverse .navbar-collapse, -.navbar-inverse .navbar-form { - border-color: #81b33a; -} -.navbar-inverse .navbar-nav > .open > a, -.navbar-inverse .navbar-nav > .open > a:hover, -.navbar-inverse .navbar-nav > .open > a:focus { - background-color: #89be3d; - color: #ffffff; -} -@media (max-width: 767px) { - .navbar-inverse .navbar-nav .open .dropdown-menu > .dropdown-header { - border-color: #3daee9; - } - .navbar-inverse .navbar-nav .open .dropdown-menu .divider { - background-color: #3daee9; - } - .navbar-inverse .navbar-nav .open .dropdown-menu > li > a { - color: #6b9430; - } - .navbar-inverse .navbar-nav .open .dropdown-menu > li > a:hover, - .navbar-inverse .navbar-nav .open .dropdown-menu > li > a:focus { - color: #ffffff; - background-color: transparent; - } - .navbar-inverse .navbar-nav .open .dropdown-menu > .active > a, - .navbar-inverse .navbar-nav .open .dropdown-menu > .active > a:hover, - .navbar-inverse .navbar-nav .open .dropdown-menu > .active > a:focus { - color: #ffffff; - background-color: #89be3d; - } - .navbar-inverse .navbar-nav .open .dropdown-menu > .disabled > a, - .navbar-inverse .navbar-nav .open .dropdown-menu > .disabled > a:hover, - .navbar-inverse .navbar-nav .open .dropdown-menu > .disabled > a:focus { - color: #444444; - background-color: transparent; - } -} -.navbar-inverse .navbar-link { - color: #6b9430; -} -.navbar-inverse .navbar-link:hover { - color: #ffffff; -} -.navbar-inverse .btn-link { - color: #6b9430; -} -.navbar-inverse .btn-link:hover, -.navbar-inverse .btn-link:focus { - color: #ffffff; -} -.navbar-inverse .btn-link[disabled]:hover, -fieldset[disabled] .navbar-inverse .btn-link:hover, -.navbar-inverse .btn-link[disabled]:focus, -fieldset[disabled] .navbar-inverse .btn-link:focus { - color: #444444; -} -.breadcrumb { - padding: 8px 15px; - margin-bottom: 20px; - list-style: none; - background-color: #eff0f1; - border-radius: 4px; -} -.breadcrumb > li { - display: inline-block; -} -.breadcrumb > li + li:before { - content: "/\00a0"; - padding: 0 5px; - color: #dfd7ca; -} -.breadcrumb > .active { - color: #98978b; -} -.pagination { - display: inline-block; - padding-left: 0; - margin: 20px 0; - border-radius: 4px; -} -.pagination > li { - display: inline; -} -.pagination > li > a, -.pagination > li > span { - position: relative; - float: left; - padding: 12px 16px; - line-height: 1.42857143; - text-decoration: none; - color: #98978b; - background-color: #eff0f1; - border: 1px solid #dfd7ca; - margin-left: -1px; -} -.pagination > li:first-child > a, -.pagination > li:first-child > span { - margin-left: 0; - border-bottom-left-radius: 4px; - border-top-left-radius: 4px; -} -.pagination > li:last-child > a, -.pagination > li:last-child > span { - border-bottom-right-radius: 4px; - border-top-right-radius: 4px; -} -.pagination > li > a:hover, -.pagination > li > span:hover, -.pagination > li > a:focus, -.pagination > li > span:focus { - color: #8e8c84; - background-color: #dfd7ca; - border-color: #dfd7ca; -} -.pagination > .active > a, -.pagination > .active > span, -.pagination > .active > a:hover, -.pagination > .active > span:hover, -.pagination > .active > a:focus, -.pagination > .active > span:focus { - z-index: 2; - color: #8e8c84; - background-color: #dfd7ca; - border-color: #dfd7ca; - cursor: default; -} -.pagination > .disabled > span, -.pagination > .disabled > span:hover, -.pagination > .disabled > span:focus, -.pagination > .disabled > a, -.pagination > .disabled > a:hover, -.pagination > .disabled > a:focus { - color: #dfd7ca; - background-color: #eff0f1; - border-color: #dfd7ca; - cursor: not-allowed; -} -.pagination-lg > li > a, -.pagination-lg > li > span { - padding: 20px 30px; - font-size: 18px; -} -.pagination-lg > li:first-child > a, -.pagination-lg > li:first-child > span { - border-bottom-left-radius: 6px; - border-top-left-radius: 6px; -} -.pagination-lg > li:last-child > a, -.pagination-lg > li:last-child > span { - border-bottom-right-radius: 6px; - border-top-right-radius: 6px; -} -.pagination-sm > li > a, -.pagination-sm > li > span { - padding: 5px 10px; - font-size: 12px; -} -.pagination-sm > li:first-child > a, -.pagination-sm > li:first-child > span { - border-bottom-left-radius: 3px; - border-top-left-radius: 3px; -} -.pagination-sm > li:last-child > a, -.pagination-sm > li:last-child > span { - border-bottom-right-radius: 3px; - border-top-right-radius: 3px; -} -.pager { - padding-left: 0; - margin: 20px 0; - list-style: none; - text-align: center; -} -.pager li { - display: inline; -} -.pager li > a, -.pager li > span { - display: inline-block; - padding: 5px 14px; - background-color: #eff0f1; - border: 1px solid #dfd7ca; - border-radius: 15px; -} -.pager li > a:hover, -.pager li > a:focus { - text-decoration: none; - background-color: #dfd7ca; -} -.pager .next > a, -.pager .next > span { - float: right; -} -.pager .previous > a, -.pager .previous > span { - float: left; -} -.pager .disabled > a, -.pager .disabled > a:hover, -.pager .disabled > a:focus, -.pager .disabled > span { - color: #dfd7ca; - background-color: #eff0f1; - cursor: not-allowed; -} -.label { - display: inline; - padding: .2em .6em .3em; - font-size: 75%; - font-weight: bold; - line-height: 1; - color: #ffffff; - text-align: center; - white-space: nowrap; - vertical-align: baseline; - border-radius: .25em; -} -a.label:hover, -a.label:focus { - color: #ffffff; - text-decoration: none; - cursor: pointer; -} -.label:empty { - display: none; -} -.btn .label { - position: relative; - top: -1px; -} -.label-default { - background-color: #475057; -} -.label-default[href]:hover, -.label-default[href]:focus { - background-color: #242422; -} -.label-primary { - background-color: #325d88; -} -.label-primary[href]:hover, -.label-primary[href]:focus { - background-color: #244363; -} -.label-success { - background-color: #3daee9; -} -.label-success[href]:hover, -.label-success[href]:focus { - background-color: #1a86db; -} -.label-info { - background-color: #29abe0; -} -.label-info[href]:hover, -.label-info[href]:focus { - background-color: #1b8dbb; -} -.label-warning { - background-color: #f47c3c; -} -.label-warning[href]:hover, -.label-warning[href]:focus { - background-color: #ef5c0e; -} -.label-danger { - background-color: #d9534f; -} -.label-danger[href]:hover, -.label-danger[href]:focus { - background-color: #c9302c; -} -.badge { - display: inline-block; - min-width: 10px; - padding: 3px 7px; - font-size: 12px; - font-weight: normal; - color: #ffffff; - line-height: 1; - vertical-align: baseline; - white-space: nowrap; - text-align: center; - background-color: #3daee9; - border-radius: 10px; -} -.badge:empty { - display: none; -} -.btn .badge { - position: relative; - top: -1px; -} -.btn-xs .badge { - top: 0; - padding: 1px 5px; -} -a.badge:hover, -a.badge:focus { - color: #ffffff; - text-decoration: none; - cursor: pointer; -} -.list-group-item.active > .badge, -.nav-pills > .active > a > .badge { - color: #ffffff; - background-color: #3daee9; -} -.list-group-item > .badge { - float: right; -} -.list-group-item > .badge + .badge { - margin-right: 5px; -} -.nav-pills > li > a > .badge { - margin-left: 3px; -} -.jumbotron { - padding: 30px 15px; - margin-bottom: 30px; - color: inherit; - background-color: #eff0f1; -} -.jumbotron h1, -.jumbotron .h1 { - color: inherit; -} -.jumbotron p { - margin-bottom: 15px; - font-size: 21px; - font-weight: 200; -} -.jumbotron > hr { - border-top-color: #e8decd; -} -.container .jumbotron, -.container-fluid .jumbotron { - border-radius: 6px; -} -.jumbotron .container { - max-width: 100%; -} -@media screen and (min-width: 768px) { - .jumbotron { - padding: 48px 0; - } - .container .jumbotron, - .container-fluid .jumbotron { - padding-left: 60px; - padding-right: 60px; - } - .jumbotron h1, - .jumbotron .h1 { - font-size: 63px; - } -} -.thumbnail { - display: block; - padding: 4px; - margin-bottom: 20px; - line-height: 1.42857143; - background-color: #eff0f1; - border: 1px solid #dfd7ca; - border-radius: 4px; - -webkit-transition: border 0.2s ease-in-out; - -o-transition: border 0.2s ease-in-out; - transition: border 0.2s ease-in-out; -} -.thumbnail > img, -.thumbnail a > img { - margin-left: auto; - margin-right: auto; -} -a.thumbnail:hover, -a.thumbnail:focus, -a.thumbnail.active { - border-color: #3daee9; -} -.thumbnail .caption { - padding: 9px; - color: #475057; -} -.alert { - padding: 15px; - margin-bottom: 20px; - border: 1px solid transparent; - border-radius: 4px; -} -.alert h4 { - margin-top: 0; - color: inherit; -} -.alert .alert-link { - font-weight: bold; -} -.alert > p, -.alert > ul { - margin-bottom: 0; -} -.alert > p + p { - margin-top: 5px; -} -.alert-dismissable, -.alert-dismissible { - padding-right: 35px; -} -.alert-dismissable .close, -.alert-dismissible .close { - position: relative; - top: -2px; - right: -21px; - color: inherit; -} -.alert-success { - background-color: #3daee9; - border-color: transparent; - color: #ffffff; -} -.alert-success hr { - border-top-color: rgba(0, 0, 0, 0); -} -.alert-success .alert-link { - color: #e6e6e6; -} -.alert-info { - background-color: #29abe0; - border-color: transparent; - color: #ffffff; -} -.alert-info hr { - border-top-color: rgba(0, 0, 0, 0); -} -.alert-info .alert-link { - color: #e6e6e6; -} -.alert-warning { - background-color: #f47c3c; - border-color: transparent; - color: #ffffff; -} -.alert-warning hr { - border-top-color: rgba(0, 0, 0, 0); -} -.alert-warning .alert-link { - color: #e6e6e6; -} -.alert-danger { - background-color: #d9534f; - border-color: transparent; - color: #ffffff; -} -.alert-danger hr { - border-top-color: rgba(0, 0, 0, 0); -} -.alert-danger .alert-link { - color: #e6e6e6; -} -@-webkit-keyframes progress-bar-stripes { - from { - background-position: 40px 0; - } - to { - background-position: 0 0; - } -} -@-o-keyframes progress-bar-stripes { - from { - background-position: 40px 0; - } - to { - background-position: 0 0; - } -} -@keyframes progress-bar-stripes { - from { - background-position: 40px 0; - } - to { - background-position: 0 0; - } -} -.progress { - overflow: hidden; - height: 20px; - margin-bottom: 20px; - background-color: #f5f5f5; - border-radius: 4px; - -webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1); - box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1); -} -.progress-bar { - float: left; - width: 0%; - height: 100%; - font-size: 12px; - line-height: 20px; - color: #ffffff; - text-align: center; - background-color: #325d88; - -webkit-box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15); - box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15); - -webkit-transition: width 0.6s ease; - -o-transition: width 0.6s ease; - transition: width 0.6s ease; -} -.progress-striped .progress-bar, -.progress-bar-striped { - background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); - background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); - background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); - -webkit-background-size: 40px 40px; - background-size: 40px 40px; -} -.progress.active .progress-bar, -.progress-bar.active { - -webkit-animation: progress-bar-stripes 2s linear infinite; - -o-animation: progress-bar-stripes 2s linear infinite; - animation: progress-bar-stripes 2s linear infinite; -} -.progress-bar-success { - background-color: #3daee9; -} -.progress-striped .progress-bar-success { - background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); - background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); - background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); -} -.progress-bar-info { - background-color: #29abe0; -} -.progress-striped .progress-bar-info { - background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); - background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); - background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); -} -.progress-bar-warning { - background-color: #f47c3c; -} -.progress-striped .progress-bar-warning { - background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); - background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); - background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); -} -.progress-bar-danger { - background-color: #d9534f; -} -.progress-striped .progress-bar-danger { - background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); - background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); - background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); -} -.media { - margin-top: 15px; -} -.media:first-child { - margin-top: 0; -} -.media-right, -.media > .pull-right { - padding-left: 10px; -} -.media-left, -.media > .pull-left { - padding-right: 10px; -} -.media-left, -.media-right, -.media-body { - display: table-cell; - vertical-align: top; -} -.media-middle { - vertical-align: middle; -} -.media-bottom { - vertical-align: bottom; -} -.media-heading { - margin-top: 0; - margin-bottom: 5px; -} -.media-list { - padding-left: 0; - list-style: none; -} -.list-group { - margin-bottom: 20px; - padding-left: 0; -} -.list-group-item { - position: relative; - display: block; - padding: 10px 15px; - margin-bottom: -1px; - background-color: #ffffff; - border: 1px solid #dfd7ca; -} -.list-group-item:first-child { - border-top-right-radius: 4px; - border-top-left-radius: 4px; -} -.list-group-item:last-child { - margin-bottom: 0; - border-bottom-right-radius: 4px; - border-bottom-left-radius: 4px; -} -a.list-group-item { - color: #475057; -} -a.list-group-item .list-group-item-heading { - color: inherit; -} -a.list-group-item:hover, -a.list-group-item:focus { - text-decoration: none; - color: #475057; - background-color: #eff0f1; -} -.list-group-item.disabled, -.list-group-item.disabled:hover, -.list-group-item.disabled:focus { - background-color: #eff0f1; - color: #dfd7ca; - cursor: not-allowed; -} -.list-group-item.disabled .list-group-item-heading, -.list-group-item.disabled:hover .list-group-item-heading, -.list-group-item.disabled:focus .list-group-item-heading { - color: inherit; -} -.list-group-item.disabled .list-group-item-text, -.list-group-item.disabled:hover .list-group-item-text, -.list-group-item.disabled:focus .list-group-item-text { - color: #dfd7ca; -} -.list-group-item.active, -.list-group-item.active:hover, -.list-group-item.active:focus { - z-index: 2; - color: #475057; - background-color: #eff0f1; - border-color: #dfd7ca; -} -.list-group-item.active .list-group-item-heading, -.list-group-item.active:hover .list-group-item-heading, -.list-group-item.active:focus .list-group-item-heading, -.list-group-item.active .list-group-item-heading > small, -.list-group-item.active:hover .list-group-item-heading > small, -.list-group-item.active:focus .list-group-item-heading > small, -.list-group-item.active .list-group-item-heading > .small, -.list-group-item.active:hover .list-group-item-heading > .small, -.list-group-item.active:focus .list-group-item-heading > .small { - color: inherit; -} -.list-group-item.active .list-group-item-text, -.list-group-item.active:hover .list-group-item-text, -.list-group-item.active:focus .list-group-item-text { - color: #475057; -} -.list-group-item-success { - color: #3daee9; - background-color: #dff0d8; -} -a.list-group-item-success { - color: #3daee9; -} -a.list-group-item-success .list-group-item-heading { - color: inherit; -} -a.list-group-item-success:hover, -a.list-group-item-success:focus { - color: #3daee9; - background-color: #d0e9c6; -} -a.list-group-item-success.active, -a.list-group-item-success.active:hover, -a.list-group-item-success.active:focus { - color: #fff; - background-color: #3daee9; - border-color: #3daee9; -} -.list-group-item-info { - color: #29abe0; - background-color: #d9edf7; -} -a.list-group-item-info { - color: #29abe0; -} -a.list-group-item-info .list-group-item-heading { - color: inherit; -} -a.list-group-item-info:hover, -a.list-group-item-info:focus { - color: #29abe0; - background-color: #c4e3f3; -} -a.list-group-item-info.active, -a.list-group-item-info.active:hover, -a.list-group-item-info.active:focus { - color: #fff; - background-color: #29abe0; - border-color: #29abe0; -} -.list-group-item-warning { - color: #f47c3c; - background-color: #fcf8e3; -} -a.list-group-item-warning { - color: #f47c3c; -} -a.list-group-item-warning .list-group-item-heading { - color: inherit; -} -a.list-group-item-warning:hover, -a.list-group-item-warning:focus { - color: #f47c3c; - background-color: #faf2cc; -} -a.list-group-item-warning.active, -a.list-group-item-warning.active:hover, -a.list-group-item-warning.active:focus { - color: #fff; - background-color: #f47c3c; - border-color: #f47c3c; -} -.list-group-item-danger { - color: #d9534f; - background-color: #f2dede; -} -a.list-group-item-danger { - color: #d9534f; -} -a.list-group-item-danger .list-group-item-heading { - color: inherit; -} -a.list-group-item-danger:hover, -a.list-group-item-danger:focus { - color: #d9534f; - background-color: #ebcccc; -} -a.list-group-item-danger.active, -a.list-group-item-danger.active:hover, -a.list-group-item-danger.active:focus { - color: #fff; - background-color: #d9534f; - border-color: #d9534f; -} -.list-group-item-heading { - margin-top: 0; - margin-bottom: 5px; -} -.list-group-item-text { - margin-bottom: 0; - line-height: 1.3; -} -.panel { - margin-bottom: 20px; - background-color: #ffffff; - border: 1px solid transparent; - border-radius: 4px; - -webkit-box-shadow: 0 1px 1px rgba(0, 0, 0, 0.05); - box-shadow: 0 1px 1px rgba(0, 0, 0, 0.05); -} -.panel-body { - padding: 15px; -} -.panel-heading { - padding: 10px 15px; - border-bottom: 1px solid transparent; - border-top-right-radius: 3px; - border-top-left-radius: 3px; -} -.panel-heading > .dropdown .dropdown-toggle { - color: inherit; -} -.panel-title { - margin-top: 0; - margin-bottom: 0; - font-size: 16px; - color: inherit; -} -.panel-title > a { - color: inherit; -} -.panel-footer { - padding: 10px 15px; - background-color: #eff0f1; - border-top: 1px solid #dfd7ca; - border-bottom-right-radius: 3px; - border-bottom-left-radius: 3px; -} -.panel > .list-group, -.panel > .panel-collapse > .list-group { - margin-bottom: 0; -} -.panel > .list-group .list-group-item, -.panel > .panel-collapse > .list-group .list-group-item { - border-width: 1px 0; - border-radius: 0; -} -.panel > .list-group:first-child .list-group-item:first-child, -.panel > .panel-collapse > .list-group:first-child .list-group-item:first-child { - border-top: 0; - border-top-right-radius: 3px; - border-top-left-radius: 3px; -} -.panel > .list-group:last-child .list-group-item:last-child, -.panel > .panel-collapse > .list-group:last-child .list-group-item:last-child { - border-bottom: 0; - border-bottom-right-radius: 3px; - border-bottom-left-radius: 3px; -} -.panel-heading + .list-group .list-group-item:first-child { - border-top-width: 0; -} -.list-group + .panel-footer { - border-top-width: 0; -} -.panel > .table, -.panel > .table-responsive > .table, -.panel > .panel-collapse > .table { - margin-bottom: 0; -} -.panel > .table caption, -.panel > .table-responsive > .table caption, -.panel > .panel-collapse > .table caption { - padding-left: 15px; - padding-right: 15px; -} -.panel > .table:first-child, -.panel > .table-responsive:first-child > .table:first-child { - border-top-right-radius: 3px; - border-top-left-radius: 3px; -} -.panel > .table:first-child > thead:first-child > tr:first-child, -.panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child, -.panel > .table:first-child > tbody:first-child > tr:first-child, -.panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child { - border-top-left-radius: 3px; - border-top-right-radius: 3px; -} -.panel > .table:first-child > thead:first-child > tr:first-child td:first-child, -.panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child td:first-child, -.panel > .table:first-child > tbody:first-child > tr:first-child td:first-child, -.panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child td:first-child, -.panel > .table:first-child > thead:first-child > tr:first-child th:first-child, -.panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child th:first-child, -.panel > .table:first-child > tbody:first-child > tr:first-child th:first-child, -.panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child th:first-child { - border-top-left-radius: 3px; -} -.panel > .table:first-child > thead:first-child > tr:first-child td:last-child, -.panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child td:last-child, -.panel > .table:first-child > tbody:first-child > tr:first-child td:last-child, -.panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child td:last-child, -.panel > .table:first-child > thead:first-child > tr:first-child th:last-child, -.panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child th:last-child, -.panel > .table:first-child > tbody:first-child > tr:first-child th:last-child, -.panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child th:last-child { - border-top-right-radius: 3px; -} -.panel > .table:last-child, -.panel > .table-responsive:last-child > .table:last-child { - border-bottom-right-radius: 3px; - border-bottom-left-radius: 3px; -} -.panel > .table:last-child > tbody:last-child > tr:last-child, -.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child, -.panel > .table:last-child > tfoot:last-child > tr:last-child, -.panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child { - border-bottom-left-radius: 3px; - border-bottom-right-radius: 3px; -} -.panel > .table:last-child > tbody:last-child > tr:last-child td:first-child, -.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child td:first-child, -.panel > .table:last-child > tfoot:last-child > tr:last-child td:first-child, -.panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child td:first-child, -.panel > .table:last-child > tbody:last-child > tr:last-child th:first-child, -.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child th:first-child, -.panel > .table:last-child > tfoot:last-child > tr:last-child th:first-child, -.panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child th:first-child { - border-bottom-left-radius: 3px; -} -.panel > .table:last-child > tbody:last-child > tr:last-child td:last-child, -.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child td:last-child, -.panel > .table:last-child > tfoot:last-child > tr:last-child td:last-child, -.panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child td:last-child, -.panel > .table:last-child > tbody:last-child > tr:last-child th:last-child, -.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child th:last-child, -.panel > .table:last-child > tfoot:last-child > tr:last-child th:last-child, -.panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child th:last-child { - border-bottom-right-radius: 3px; -} -.panel > .panel-body + .table, -.panel > .panel-body + .table-responsive, -.panel > .table + .panel-body, -.panel > .table-responsive + .panel-body { - border-top: 1px solid #dfd7ca; -} -.panel > .table > tbody:first-child > tr:first-child th, -.panel > .table > tbody:first-child > tr:first-child td { - border-top: 0; -} -.panel > .table-bordered, -.panel > .table-responsive > .table-bordered { - border: 0; -} -.panel > .table-bordered > thead > tr > th:first-child, -.panel > .table-responsive > .table-bordered > thead > tr > th:first-child, -.panel > .table-bordered > tbody > tr > th:first-child, -.panel > .table-responsive > .table-bordered > tbody > tr > th:first-child, -.panel > .table-bordered > tfoot > tr > th:first-child, -.panel > .table-responsive > .table-bordered > tfoot > tr > th:first-child, -.panel > .table-bordered > thead > tr > td:first-child, -.panel > .table-responsive > .table-bordered > thead > tr > td:first-child, -.panel > .table-bordered > tbody > tr > td:first-child, -.panel > .table-responsive > .table-bordered > tbody > tr > td:first-child, -.panel > .table-bordered > tfoot > tr > td:first-child, -.panel > .table-responsive > .table-bordered > tfoot > tr > td:first-child { - border-left: 0; -} -.panel > .table-bordered > thead > tr > th:last-child, -.panel > .table-responsive > .table-bordered > thead > tr > th:last-child, -.panel > .table-bordered > tbody > tr > th:last-child, -.panel > .table-responsive > .table-bordered > tbody > tr > th:last-child, -.panel > .table-bordered > tfoot > tr > th:last-child, -.panel > .table-responsive > .table-bordered > tfoot > tr > th:last-child, -.panel > .table-bordered > thead > tr > td:last-child, -.panel > .table-responsive > .table-bordered > thead > tr > td:last-child, -.panel > .table-bordered > tbody > tr > td:last-child, -.panel > .table-responsive > .table-bordered > tbody > tr > td:last-child, -.panel > .table-bordered > tfoot > tr > td:last-child, -.panel > .table-responsive > .table-bordered > tfoot > tr > td:last-child { - border-right: 0; -} -.panel > .table-bordered > thead > tr:first-child > td, -.panel > .table-responsive > .table-bordered > thead > tr:first-child > td, -.panel > .table-bordered > tbody > tr:first-child > td, -.panel > .table-responsive > .table-bordered > tbody > tr:first-child > td, -.panel > .table-bordered > thead > tr:first-child > th, -.panel > .table-responsive > .table-bordered > thead > tr:first-child > th, -.panel > .table-bordered > tbody > tr:first-child > th, -.panel > .table-responsive > .table-bordered > tbody > tr:first-child > th { - border-bottom: 0; -} -.panel > .table-bordered > tbody > tr:last-child > td, -.panel > .table-responsive > .table-bordered > tbody > tr:last-child > td, -.panel > .table-bordered > tfoot > tr:last-child > td, -.panel > .table-responsive > .table-bordered > tfoot > tr:last-child > td, -.panel > .table-bordered > tbody > tr:last-child > th, -.panel > .table-responsive > .table-bordered > tbody > tr:last-child > th, -.panel > .table-bordered > tfoot > tr:last-child > th, -.panel > .table-responsive > .table-bordered > tfoot > tr:last-child > th { - border-bottom: 0; -} -.panel > .table-responsive { - border: 0; - margin-bottom: 0; -} -.panel-group { - margin-bottom: 20px; -} -.panel-group .panel { - margin-bottom: 0; - border-radius: 4px; -} -.panel-group .panel + .panel { - margin-top: 5px; -} -.panel-group .panel-heading { - border-bottom: 0; -} -.panel-group .panel-heading + .panel-collapse > .panel-body, -.panel-group .panel-heading + .panel-collapse > .list-group { - border-top: 1px solid #dfd7ca; -} -.panel-group .panel-footer { - border-top: 0; -} -.panel-group .panel-footer + .panel-collapse .panel-body { - border-bottom: 1px solid #dfd7ca; -} -.panel-default { - border-color: #dfd7ca; -} -.panel-default > .panel-heading { - color: #475057; - background-color: #eff0f1; - border-color: #dfd7ca; -} -.panel-default > .panel-heading + .panel-collapse > .panel-body { - border-top-color: #dfd7ca; -} -.panel-default > .panel-heading .badge { - color: #eff0f1; - background-color: #475057; -} -.panel-default > .panel-footer + .panel-collapse > .panel-body { - border-bottom-color: #dfd7ca; -} -.panel-primary { - border-color: #325d88; -} -.panel-primary > .panel-heading { - color: #ffffff; - background-color: #325d88; - border-color: #325d88; -} -.panel-primary > .panel-heading + .panel-collapse > .panel-body { - border-top-color: #325d88; -} -.panel-primary > .panel-heading .badge { - color: #325d88; - background-color: #ffffff; -} -.panel-primary > .panel-footer + .panel-collapse > .panel-body { - border-bottom-color: #325d88; -} -.panel-success { - border-color: #d6e9c6; -} -.panel-success > .panel-heading { - color: #3daee9; - background-color: #3daee9; - border-color: #d6e9c6; -} -.panel-success > .panel-heading + .panel-collapse > .panel-body { - border-top-color: #d6e9c6; -} -.panel-success > .panel-heading .badge { - color: #3daee9; - background-color: #3daee9; -} -.panel-success > .panel-footer + .panel-collapse > .panel-body { - border-bottom-color: #d6e9c6; -} -.panel-info { - border-color: #bce8f1; -} -.panel-info > .panel-heading { - color: #29abe0; - background-color: #29abe0; - border-color: #bce8f1; -} -.panel-info > .panel-heading + .panel-collapse > .panel-body { - border-top-color: #bce8f1; -} -.panel-info > .panel-heading .badge { - color: #29abe0; - background-color: #29abe0; -} -.panel-info > .panel-footer + .panel-collapse > .panel-body { - border-bottom-color: #bce8f1; -} -.panel-warning { - border-color: #faebcc; -} -.panel-warning > .panel-heading { - color: #f47c3c; - background-color: #f47c3c; - border-color: #faebcc; -} -.panel-warning > .panel-heading + .panel-collapse > .panel-body { - border-top-color: #faebcc; -} -.panel-warning > .panel-heading .badge { - color: #f47c3c; - background-color: #f47c3c; -} -.panel-warning > .panel-footer + .panel-collapse > .panel-body { - border-bottom-color: #faebcc; -} -.panel-danger { - border-color: #ebccd1; -} -.panel-danger > .panel-heading { - color: #d9534f; - background-color: #d9534f; - border-color: #ebccd1; -} -.panel-danger > .panel-heading + .panel-collapse > .panel-body { - border-top-color: #ebccd1; -} -.panel-danger > .panel-heading .badge { - color: #d9534f; - background-color: #d9534f; -} -.panel-danger > .panel-footer + .panel-collapse > .panel-body { - border-bottom-color: #ebccd1; -} -.embed-responsive { - position: relative; - display: block; - height: 0; - padding: 0; - overflow: hidden; -} -.embed-responsive .embed-responsive-item, -.embed-responsive iframe, -.embed-responsive embed, -.embed-responsive object, -.embed-responsive video { - position: absolute; - top: 0; - left: 0; - bottom: 0; - height: 100%; - width: 100%; - border: 0; -} -.embed-responsive.embed-responsive-16by9 { - padding-bottom: 56.25%; -} -.embed-responsive.embed-responsive-4by3 { - padding-bottom: 75%; -} -.well { - min-height: 20px; - padding: 19px; - margin-bottom: 20px; - background-color: #eff0f1; - border: 1px solid transparent; - border-radius: 4px; - -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05); - box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05); -} -.well blockquote { - border-color: #ddd; - border-color: rgba(0, 0, 0, 0.15); -} -.well-lg { - padding: 24px; - border-radius: 6px; -} -.well-sm { - padding: 9px; - border-radius: 3px; -} -.close { - float: right; - font-size: 21px; - font-weight: bold; - line-height: 1; - color: #000000; - text-shadow: 0 0 0 transparent; - opacity: 0.2; - filter: alpha(opacity=20); -} -.close:hover, -.close:focus { - color: #000000; - text-decoration: none; - cursor: pointer; - opacity: 0.5; - filter: alpha(opacity=50); -} -button.close { - padding: 0; - cursor: pointer; - background: transparent; - border: 0; - -webkit-appearance: none; -} -.modal-open { - overflow: hidden; -} -.modal { - display: none; - overflow: hidden; - position: fixed; - top: 0; - right: 0; - bottom: 0; - left: 0; - z-index: 1040; - -webkit-overflow-scrolling: touch; - outline: 0; -} -.modal.fade .modal-dialog { - -webkit-transform: translate(0, -25%); - -ms-transform: translate(0, -25%); - -o-transform: translate(0, -25%); - transform: translate(0, -25%); - -webkit-transition: -webkit-transform 0.3s ease-out; - -o-transition: -o-transform 0.3s ease-out; - transition: transform 0.3s ease-out; -} -.modal.in .modal-dialog { - -webkit-transform: translate(0, 0); - -ms-transform: translate(0, 0); - -o-transform: translate(0, 0); - transform: translate(0, 0); -} -.modal-open .modal { - overflow-x: hidden; - overflow-y: auto; -} -.modal-dialog { - position: relative; - width: auto; - margin: 10px; -} -.modal-content { - position: relative; - background-color: #ffffff; - border: 1px solid #eff0f1; - border-radius: 6px; - -webkit-box-shadow: 0 3px 9px rgba(0, 0, 0, 0.5); - box-shadow: 0 3px 9px rgba(0, 0, 0, 0.5); - -webkit-background-clip: padding-box; - background-clip: padding-box; - outline: 0; -} -.modal-backdrop { - position: absolute; - top: 0; - right: 0; - left: 0; - background-color: #000000; -} -.modal-backdrop.fade { - opacity: 0; - filter: alpha(opacity=0); -} -.modal-backdrop.in { - opacity: 0.5; - filter: alpha(opacity=50); -} -.modal-header { - padding: 15px; - border-bottom: 1px solid #eff0f1; - min-height: 16.42857143px; -} -.modal-header .close { - margin-top: -2px; -} -.modal-title { - margin: 0; - line-height: 1.42857143; -} -.modal-body { - position: relative; - padding: 15px; -} -.modal-footer { - padding: 15px; - text-align: right; - border-top: 1px solid #eff0f1; -} -.modal-footer .btn + .btn { - margin-left: 5px; - margin-bottom: 0; -} -.modal-footer .btn-group .btn + .btn { - margin-left: -1px; -} -.modal-footer .btn-block + .btn-block { - margin-left: 0; -} -.modal-scrollbar-measure { - position: absolute; - top: -9999px; - width: 50px; - height: 50px; - overflow: scroll; -} -@media (min-width: 768px) { - .modal-dialog { - width: 600px; - margin: 30px auto; - } - .modal-content { - -webkit-box-shadow: 0 5px 15px rgba(0, 0, 0, 0.5); - box-shadow: 0 5px 15px rgba(0, 0, 0, 0.5); - } - .modal-sm { - width: 300px; - } -} -@media (min-width: 992px) { - .modal-lg { - width: 900px; - } -} -.tooltip { - position: absolute; - z-index: 1070; - display: block; - visibility: visible; - font-family: 'Oxygen', sans-serif; - font-size: 12px; - font-weight: normal; - line-height: 1.4; - opacity: 0; - filter: alpha(opacity=0); -} -.tooltip.in { - opacity: 1; - filter: alpha(opacity=100); -} -.tooltip.top { - margin-top: -3px; - padding: 5px 0; -} -.tooltip.right { - margin-left: 3px; - padding: 0 5px; -} -.tooltip.bottom { - margin-top: 3px; - padding: 5px 0; -} -.tooltip.left { - margin-left: -3px; - padding: 0 5px; -} -.tooltip-inner { - max-width: 200px; - padding: 3px 8px; - color: #ffffff; - text-align: center; - text-decoration: none; - background-color: #475057; - border-radius: 4px; -} -.tooltip-arrow { - position: absolute; - width: 0; - height: 0; - border-color: transparent; - border-style: solid; -} -.tooltip.top .tooltip-arrow { - bottom: 0; - left: 50%; - margin-left: -5px; - border-width: 5px 5px 0; - border-top-color: #475057; -} -.tooltip.top-left .tooltip-arrow { - bottom: 0; - right: 5px; - margin-bottom: -5px; - border-width: 5px 5px 0; - border-top-color: #475057; -} -.tooltip.top-right .tooltip-arrow { - bottom: 0; - left: 5px; - margin-bottom: -5px; - border-width: 5px 5px 0; - border-top-color: #475057; -} -.tooltip.right .tooltip-arrow { - top: 50%; - left: 0; - margin-top: -5px; - border-width: 5px 5px 5px 0; - border-right-color: #475057; -} -.tooltip.left .tooltip-arrow { - top: 50%; - right: 0; - margin-top: -5px; - border-width: 5px 0 5px 5px; - border-left-color: #475057; -} -.tooltip.bottom .tooltip-arrow { - top: 0; - left: 50%; - margin-left: -5px; - border-width: 0 5px 5px; - border-bottom-color: #475057; -} -.tooltip.bottom-left .tooltip-arrow { - top: 0; - right: 5px; - margin-top: -5px; - border-width: 0 5px 5px; - border-bottom-color: #475057; -} -.tooltip.bottom-right .tooltip-arrow { - top: 0; - left: 5px; - margin-top: -5px; - border-width: 0 5px 5px; - border-bottom-color: #475057; -} -.popover { - position: absolute; - top: 0; - left: 0; - z-index: 1060; - display: none; - max-width: 276px; - padding: 1px; - font-family: "Roboto", "Helvetica Neue", Helvetica, Arial, sans-serif; - font-size: 14px; - font-weight: normal; - line-height: 1.42857143; - text-align: left; - background-color: #ffffff; - -webkit-background-clip: padding-box; - background-clip: padding-box; - border: 1px solid #dfd7ca; - border-radius: 6px; - -webkit-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2); - box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2); - white-space: normal; -} -.popover.top { - margin-top: -10px; -} -.popover.right { - margin-left: 10px; -} -.popover.bottom { - margin-top: 10px; -} -.popover.left { - margin-left: -10px; -} -.popover-title { - margin: 0; - padding: 8px 14px; - font-size: 14px; - background-color: #eff0f1; - border-bottom: 1px solid #f0e9df; - border-radius: 5px 5px 0 0; -} -.popover-content { - padding: 9px 14px; -} -.popover > .arrow, -.popover > .arrow:after { - position: absolute; - display: block; - width: 0; - height: 0; - border-color: transparent; - border-style: solid; -} -.popover > .arrow { - border-width: 11px; -} -.popover > .arrow:after { - border-width: 10px; - content: ""; -} -.popover.top > .arrow { - left: 50%; - margin-left: -11px; - border-bottom-width: 0; - border-top-color: #b9a78a; - border-top-color: #dfd7ca; - bottom: -11px; -} -.popover.top > .arrow:after { - content: " "; - bottom: 1px; - margin-left: -10px; - border-bottom-width: 0; - border-top-color: #ffffff; -} -.popover.right > .arrow { - top: 50%; - left: -11px; - margin-top: -11px; - border-left-width: 0; - border-right-color: #b9a78a; - border-right-color: #dfd7ca; -} -.popover.right > .arrow:after { - content: " "; - left: 1px; - bottom: -10px; - border-left-width: 0; - border-right-color: #ffffff; -} -.popover.bottom > .arrow { - left: 50%; - margin-left: -11px; - border-top-width: 0; - border-bottom-color: #b9a78a; - border-bottom-color: #dfd7ca; - top: -11px; -} -.popover.bottom > .arrow:after { - content: " "; - top: 1px; - margin-left: -10px; - border-top-width: 0; - border-bottom-color: #ffffff; -} -.popover.left > .arrow { - top: 50%; - right: -11px; - margin-top: -11px; - border-right-width: 0; - border-left-color: #b9a78a; - border-left-color: #dfd7ca; -} -.popover.left > .arrow:after { - content: " "; - right: 1px; - border-right-width: 0; - border-left-color: #ffffff; - bottom: -10px; -} -.carousel { - position: relative; -} -.carousel-inner { - position: relative; - overflow: hidden; - width: 100%; -} -.carousel-inner > .item { - display: none; - position: relative; - -webkit-transition: 0.6s ease-in-out left; - -o-transition: 0.6s ease-in-out left; - transition: 0.6s ease-in-out left; -} -.carousel-inner > .item > img, -.carousel-inner > .item > a > img { - line-height: 1; -} -@media all and (transform-3d), (-webkit-transform-3d) { - .carousel-inner > .item { - -webkit-transition: -webkit-transform 0.6s ease-in-out; - -o-transition: -o-transform 0.6s ease-in-out; - transition: transform 0.6s ease-in-out; - -webkit-backface-visibility: hidden; - backface-visibility: hidden; - -webkit-perspective: 1000; - perspective: 1000; - } - .carousel-inner > .item.next, - .carousel-inner > .item.active.right { - -webkit-transform: translate3d(100%, 0, 0); - transform: translate3d(100%, 0, 0); - left: 0; - } - .carousel-inner > .item.prev, - .carousel-inner > .item.active.left { - -webkit-transform: translate3d(-100%, 0, 0); - transform: translate3d(-100%, 0, 0); - left: 0; - } - .carousel-inner > .item.next.left, - .carousel-inner > .item.prev.right, - .carousel-inner > .item.active { - -webkit-transform: translate3d(0, 0, 0); - transform: translate3d(0, 0, 0); - left: 0; - } -} -.carousel-inner > .active, -.carousel-inner > .next, -.carousel-inner > .prev { - display: block; -} -.carousel-inner > .active { - left: 0; -} -.carousel-inner > .next, -.carousel-inner > .prev { - position: absolute; - top: 0; - width: 100%; -} -.carousel-inner > .next { - left: 100%; -} -.carousel-inner > .prev { - left: -100%; -} -.carousel-inner > .next.left, -.carousel-inner > .prev.right { - left: 0; -} -.carousel-inner > .active.left { - left: -100%; -} -.carousel-inner > .active.right { - left: 100%; -} -.carousel-control { - position: absolute; - top: 0; - left: 0; - bottom: 0; - width: 15%; - opacity: 0.5; - filter: alpha(opacity=50); - font-size: 20px; - color: #ffffff; - text-align: center; - text-shadow: 0 1px 2px rgba(0, 0, 0, 0.6); -} -.carousel-control.left { - background-image: -webkit-linear-gradient(left, rgba(0, 0, 0, 0.5) 0%, rgba(0, 0, 0, 0.0001) 100%); - background-image: -o-linear-gradient(left, rgba(0, 0, 0, 0.5) 0%, rgba(0, 0, 0, 0.0001) 100%); - background-image: -webkit-gradient(linear, left top, right top, from(rgba(0, 0, 0, 0.5)), to(rgba(0, 0, 0, 0.0001))); - background-image: linear-gradient(to right, rgba(0, 0, 0, 0.5) 0%, rgba(0, 0, 0, 0.0001) 100%); - background-repeat: repeat-x; - filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#80000000', endColorstr='#00000000', GradientType=1); -} -.carousel-control.right { - left: auto; - right: 0; - background-image: -webkit-linear-gradient(left, rgba(0, 0, 0, 0.0001) 0%, rgba(0, 0, 0, 0.5) 100%); - background-image: -o-linear-gradient(left, rgba(0, 0, 0, 0.0001) 0%, rgba(0, 0, 0, 0.5) 100%); - background-image: -webkit-gradient(linear, left top, right top, from(rgba(0, 0, 0, 0.0001)), to(rgba(0, 0, 0, 0.5))); - background-image: linear-gradient(to right, rgba(0, 0, 0, 0.0001) 0%, rgba(0, 0, 0, 0.5) 100%); - background-repeat: repeat-x; - filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#00000000', endColorstr='#80000000', GradientType=1); -} -.carousel-control:hover, -.carousel-control:focus { - outline: 0; - color: #ffffff; - text-decoration: none; - opacity: 0.9; - filter: alpha(opacity=90); -} -.carousel-control .icon-prev, -.carousel-control .icon-next, -.carousel-control .glyphicon-chevron-left, -.carousel-control .glyphicon-chevron-right { - position: absolute; - top: 50%; - z-index: 5; - display: inline-block; -} -.carousel-control .icon-prev, -.carousel-control .glyphicon-chevron-left { - left: 50%; - margin-left: -10px; -} -.carousel-control .icon-next, -.carousel-control .glyphicon-chevron-right { - right: 50%; - margin-right: -10px; -} -.carousel-control .icon-prev, -.carousel-control .icon-next { - width: 20px; - height: 20px; - margin-top: -10px; - font-family: serif; -} -.carousel-control .icon-prev:before { - content: '\2039'; -} -.carousel-control .icon-next:before { - content: '\203a'; -} -.carousel-indicators { - position: absolute; - bottom: 10px; - left: 50%; - z-index: 15; - width: 60%; - margin-left: -30%; - padding-left: 0; - list-style: none; - text-align: center; -} -.carousel-indicators li { - display: inline-block; - width: 10px; - height: 10px; - margin: 1px; - text-indent: -999px; - border: 1px solid #ffffff; - border-radius: 10px; - cursor: pointer; - background-color: #000 \9; - background-color: rgba(0, 0, 0, 0); -} -.carousel-indicators .active { - margin: 0; - width: 12px; - height: 12px; - background-color: #ffffff; -} -.carousel-caption { - position: absolute; - left: 15%; - right: 15%; - bottom: 20px; - z-index: 10; - padding-top: 20px; - padding-bottom: 20px; - color: #ffffff; - text-align: center; - text-shadow: 0 1px 2px rgba(0, 0, 0, 0.6); -} -.carousel-caption .btn { - text-shadow: none; -} -@media screen and (min-width: 768px) { - .carousel-control .glyphicon-chevron-left, - .carousel-control .glyphicon-chevron-right, - .carousel-control .icon-prev, - .carousel-control .icon-next { - width: 30px; - height: 30px; - margin-top: -15px; - font-size: 30px; - } - .carousel-control .glyphicon-chevron-left, - .carousel-control .icon-prev { - margin-left: -15px; - } - .carousel-control .glyphicon-chevron-right, - .carousel-control .icon-next { - margin-right: -15px; - } - .carousel-caption { - left: 20%; - right: 20%; - padding-bottom: 30px; - } - .carousel-indicators { - bottom: 20px; - } -} -.clearfix:before, -.clearfix:after, -.dl-horizontal dd:before, -.dl-horizontal dd:after, -.container:before, -.container:after, -.container-fluid:before, -.container-fluid:after, -.row:before, -.row:after, -.form-horizontal .form-group:before, -.form-horizontal .form-group:after, -.btn-toolbar:before, -.btn-toolbar:after, -.btn-group-vertical > .btn-group:before, -.btn-group-vertical > .btn-group:after, -.nav:before, -.nav:after, -.navbar:before, -.navbar:after, -.navbar-header:before, -.navbar-header:after, -.navbar-collapse:before, -.navbar-collapse:after, -.pager:before, -.pager:after, -.panel-body:before, -.panel-body:after, -.modal-footer:before, -.modal-footer:after { - content: " "; - display: table; -} -.clearfix:after, -.dl-horizontal dd:after, -.container:after, -.container-fluid:after, -.row:after, -.form-horizontal .form-group:after, -.btn-toolbar:after, -.btn-group-vertical > .btn-group:after, -.nav:after, -.navbar:after, -.navbar-header:after, -.navbar-collapse:after, -.pager:after, -.panel-body:after, -.modal-footer:after { - clear: both; -} -.center-block { - display: block; - margin-left: auto; - margin-right: auto; -} -.pull-right { - float: right !important; -} -.pull-left { - float: left !important; -} -.hide { - display: none !important; -} -.show { - display: block !important; -} -.invisible { - visibility: hidden; -} -.text-hide { - font: 0/0 a; - color: transparent; - text-shadow: none; - background-color: transparent; - border: 0; -} -.hidden { - display: none !important; - visibility: hidden !important; -} -.affix { - position: fixed; -} -@-ms-viewport { - width: device-width; -} -.visible-xs, -.visible-sm, -.visible-md, -.visible-lg { - display: none !important; -} -.visible-xs-block, -.visible-xs-inline, -.visible-xs-inline-block, -.visible-sm-block, -.visible-sm-inline, -.visible-sm-inline-block, -.visible-md-block, -.visible-md-inline, -.visible-md-inline-block, -.visible-lg-block, -.visible-lg-inline, -.visible-lg-inline-block { - display: none !important; -} -@media (max-width: 767px) { - .visible-xs { - display: block !important; - } - table.visible-xs { - display: table; - } - tr.visible-xs { - display: table-row !important; - } - th.visible-xs, - td.visible-xs { - display: table-cell !important; - } -} -@media (max-width: 767px) { - .visible-xs-block { - display: block !important; - } -} -@media (max-width: 767px) { - .visible-xs-inline { - display: inline !important; - } -} -@media (max-width: 767px) { - .visible-xs-inline-block { - display: inline-block !important; - } -} -@media (min-width: 768px) and (max-width: 991px) { - .visible-sm { - display: block !important; - } - table.visible-sm { - display: table; - } - tr.visible-sm { - display: table-row !important; - } - th.visible-sm, - td.visible-sm { - display: table-cell !important; - } -} -@media (min-width: 768px) and (max-width: 991px) { - .visible-sm-block { - display: block !important; - } -} -@media (min-width: 768px) and (max-width: 991px) { - .visible-sm-inline { - display: inline !important; - } -} -@media (min-width: 768px) and (max-width: 991px) { - .visible-sm-inline-block { - display: inline-block !important; - } -} -@media (min-width: 992px) and (max-width: 1199px) { - .visible-md { - display: block !important; - } - table.visible-md { - display: table; - } - tr.visible-md { - display: table-row !important; - } - th.visible-md, - td.visible-md { - display: table-cell !important; - } -} -@media (min-width: 992px) and (max-width: 1199px) { - .visible-md-block { - display: block !important; - } -} -@media (min-width: 992px) and (max-width: 1199px) { - .visible-md-inline { - display: inline !important; - } -} -@media (min-width: 992px) and (max-width: 1199px) { - .visible-md-inline-block { - display: inline-block !important; - } -} -@media (min-width: 1200px) { - .visible-lg { - display: block !important; - } - table.visible-lg { - display: table; - } - tr.visible-lg { - display: table-row !important; - } - th.visible-lg, - td.visible-lg { - display: table-cell !important; - } -} -@media (min-width: 1200px) { - .visible-lg-block { - display: block !important; - } -} -@media (min-width: 1200px) { - .visible-lg-inline { - display: inline !important; - } -} -@media (min-width: 1200px) { - .visible-lg-inline-block { - display: inline-block !important; - } -} -@media (max-width: 767px) { - .hidden-xs { - display: none !important; - } -} -@media (min-width: 768px) and (max-width: 991px) { - .hidden-sm { - display: none !important; - } -} -@media (min-width: 992px) and (max-width: 1199px) { - .hidden-md { - display: none !important; - } -} -@media (min-width: 1200px) { - .hidden-lg { - display: none !important; - } -} -.visible-print { - display: none !important; -} -@media print { - .visible-print { - display: block !important; - } - table.visible-print { - display: table; - } - tr.visible-print { - display: table-row !important; - } - th.visible-print, - td.visible-print { - display: table-cell !important; - } -} -.visible-print-block { - display: none !important; -} -@media print { - .visible-print-block { - display: block !important; - } -} -.visible-print-inline { - display: none !important; -} -@media print { - .visible-print-inline { - display: inline !important; - } -} -.visible-print-inline-block { - display: none !important; -} -@media print { - .visible-print-inline-block { - display: inline-block !important; - } -} -@media print { - .hidden-print { - display: none !important; - } -} -.sandstone { - font-size: 11px; - line-height: 22px; - font-weight: 500; - text-transform: uppercase; -} -.navbar .nav > li > a { - font-size: 12px; - line-height: 22px; - font-weight: 500; -} -.navbar-form input, -.navbar-form .form-control { - border: none; -} -.btn { - border: none; - font-size: 11px; - line-height: 22px; - font-weight: 500; - text-transform: uppercase; -} -.btn:hover { - border-color: transparent; -} -.btn-lg { - line-height: 26px; -} -.btn-default:hover { - background-color: #393a35; -} -input, -.form-control { - -webkit-box-shadow: none; - box-shadow: none; -} -input:focus, -.form-control:focus { - border-color: #dfd7ca; - -webkit-box-shadow: none; - box-shadow: none; -} -.nav { - font-size: 14px; - line-height: 22px; - font-weight: 500; -} -.nav .open > a, -.nav .open > a:hover, -.nav .open > a:focus { - border-color: #dfd7ca; -} -.nav-tabs > li > a { - background-color: #eff0f1; - border-color: #dfd7ca; - color: #98978b; -} -.nav-tabs > li.disabled > a:hover { - background-color: #eff0f1; -} -.nav-pills a { - color: #98978b; -} -.nav-pills li > a { - border: 1px solid transparent; -} -.nav-pills li.active > a, -.nav-pills li > a:hover { - border-color: #dfd7ca; -} -.nav-pills li.disabled > a { - border-color: transparent; -} -.breadcrumb { - font-size: 11px; - line-height: 22px; - font-weight: 500; - text-transform: uppercase; - border: 1px solid #dfd7ca; -} -.breadcrumb a { - color: #98978b; -} -.pagination { - font-size: 11px; - line-height: 22px; - font-weight: 500; - text-transform: uppercase; -} -.pager { - font-size: 11px; - line-height: 22px; - font-weight: 500; - text-transform: uppercase; -} -.pager li > a { - color: #98978b; -} -.dropdown-menu > li > a { - font-size: 11px; - line-height: 22px; - font-weight: 500; - text-transform: uppercase; -} -.alert a, -.alert .alert-link { - color: #fff; -} -.tooltip { - font-size: 11px; - line-height: 22px; - font-weight: 500; - text-transform: uppercase; -} -.progress { - border-radius: 10px; - background-color: #dfd7ca; - -webkit-box-shadow: none; - box-shadow: none; -} -.progress-bar { - -webkit-box-shadow: none; - box-shadow: none; -} -.list-group-item { - padding: 16px 24px; -} -.well { - -webkit-box-shadow: none; - box-shadow: none; -} -.panel { - -webkit-box-shadow: none; - box-shadow: none; -} -.panel .panel-heading, -.panel .panel-title, -.panel .panel-footer { - font-size: 11px; - line-height: 22px; - font-weight: 500; - text-transform: uppercase; - color: #fff; -} -.panel-default .panel-heading, -.panel-default .panel-title, -.panel-default .panel-footer { - color: #98978b; -} - -#donateLink -{ - border-radius: 3px; - box-shadow: 1px 1px 0.5px rgba(0, 0, 0, 0.2); - color: #000; - font-weight: bold; - transition: all 0.5s ease 0s; - border: 1px solid rgba(0, 0, 0, 0.2); - padding: 10px 20px; - background-color: #FDBC4B; - margin-top: 8px; - background-clip: padding-box; - margin-right: 11px; - margin-left: 11px; -} - -#donateLink:hover -{ - background-color: #f67400; - color: #FFF; -} \ No newline at end of file diff --git a/website/bootstrap.min.js b/website/bootstrap.min.js deleted file mode 100644 --- a/website/bootstrap.min.js +++ /dev/null @@ -1,7 +0,0 @@ -/*! - * Bootstrap v3.3.2 (http://getbootstrap.com) - * Copyright 2011-2015 Twitter, Inc. - * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) - */ -if("undefined"==typeof jQuery)throw new Error("Bootstrap's JavaScript requires jQuery");+function(a){"use strict";var b=a.fn.jquery.split(" ")[0].split(".");if(b[0]<2&&b[1]<9||1==b[0]&&9==b[1]&&b[2]<1)throw new Error("Bootstrap's JavaScript requires jQuery version 1.9.1 or higher")}(jQuery),+function(a){"use strict";function b(){var a=document.createElement("bootstrap"),b={WebkitTransition:"webkitTransitionEnd",MozTransition:"transitionend",OTransition:"oTransitionEnd otransitionend",transition:"transitionend"};for(var c in b)if(void 0!==a.style[c])return{end:b[c]};return!1}a.fn.emulateTransitionEnd=function(b){var c=!1,d=this;a(this).one("bsTransitionEnd",function(){c=!0});var e=function(){c||a(d).trigger(a.support.transition.end)};return setTimeout(e,b),this},a(function(){a.support.transition=b(),a.support.transition&&(a.event.special.bsTransitionEnd={bindType:a.support.transition.end,delegateType:a.support.transition.end,handle:function(b){return a(b.target).is(this)?b.handleObj.handler.apply(this,arguments):void 0}})})}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var c=a(this),e=c.data("bs.alert");e||c.data("bs.alert",e=new d(this)),"string"==typeof b&&e[b].call(c)})}var c='[data-dismiss="alert"]',d=function(b){a(b).on("click",c,this.close)};d.VERSION="3.3.2",d.TRANSITION_DURATION=150,d.prototype.close=function(b){function c(){g.detach().trigger("closed.bs.alert").remove()}var e=a(this),f=e.attr("data-target");f||(f=e.attr("href"),f=f&&f.replace(/.*(?=#[^\s]*$)/,""));var g=a(f);b&&b.preventDefault(),g.length||(g=e.closest(".alert")),g.trigger(b=a.Event("close.bs.alert")),b.isDefaultPrevented()||(g.removeClass("in"),a.support.transition&&g.hasClass("fade")?g.one("bsTransitionEnd",c).emulateTransitionEnd(d.TRANSITION_DURATION):c())};var e=a.fn.alert;a.fn.alert=b,a.fn.alert.Constructor=d,a.fn.alert.noConflict=function(){return a.fn.alert=e,this},a(document).on("click.bs.alert.data-api",c,d.prototype.close)}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.button"),f="object"==typeof b&&b;e||d.data("bs.button",e=new c(this,f)),"toggle"==b?e.toggle():b&&e.setState(b)})}var c=function(b,d){this.$element=a(b),this.options=a.extend({},c.DEFAULTS,d),this.isLoading=!1};c.VERSION="3.3.2",c.DEFAULTS={loadingText:"loading..."},c.prototype.setState=function(b){var c="disabled",d=this.$element,e=d.is("input")?"val":"html",f=d.data();b+="Text",null==f.resetText&&d.data("resetText",d[e]()),setTimeout(a.proxy(function(){d[e](null==f[b]?this.options[b]:f[b]),"loadingText"==b?(this.isLoading=!0,d.addClass(c).attr(c,c)):this.isLoading&&(this.isLoading=!1,d.removeClass(c).removeAttr(c))},this),0)},c.prototype.toggle=function(){var a=!0,b=this.$element.closest('[data-toggle="buttons"]');if(b.length){var c=this.$element.find("input");"radio"==c.prop("type")&&(c.prop("checked")&&this.$element.hasClass("active")?a=!1:b.find(".active").removeClass("active")),a&&c.prop("checked",!this.$element.hasClass("active")).trigger("change")}else this.$element.attr("aria-pressed",!this.$element.hasClass("active"));a&&this.$element.toggleClass("active")};var d=a.fn.button;a.fn.button=b,a.fn.button.Constructor=c,a.fn.button.noConflict=function(){return a.fn.button=d,this},a(document).on("click.bs.button.data-api",'[data-toggle^="button"]',function(c){var d=a(c.target);d.hasClass("btn")||(d=d.closest(".btn")),b.call(d,"toggle"),c.preventDefault()}).on("focus.bs.button.data-api blur.bs.button.data-api",'[data-toggle^="button"]',function(b){a(b.target).closest(".btn").toggleClass("focus",/^focus(in)?$/.test(b.type))})}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.carousel"),f=a.extend({},c.DEFAULTS,d.data(),"object"==typeof b&&b),g="string"==typeof b?b:f.slide;e||d.data("bs.carousel",e=new c(this,f)),"number"==typeof b?e.to(b):g?e[g]():f.interval&&e.pause().cycle()})}var c=function(b,c){this.$element=a(b),this.$indicators=this.$element.find(".carousel-indicators"),this.options=c,this.paused=this.sliding=this.interval=this.$active=this.$items=null,this.options.keyboard&&this.$element.on("keydown.bs.carousel",a.proxy(this.keydown,this)),"hover"==this.options.pause&&!("ontouchstart"in document.documentElement)&&this.$element.on("mouseenter.bs.carousel",a.proxy(this.pause,this)).on("mouseleave.bs.carousel",a.proxy(this.cycle,this))};c.VERSION="3.3.2",c.TRANSITION_DURATION=600,c.DEFAULTS={interval:5e3,pause:"hover",wrap:!0,keyboard:!0},c.prototype.keydown=function(a){if(!/input|textarea/i.test(a.target.tagName)){switch(a.which){case 37:this.prev();break;case 39:this.next();break;default:return}a.preventDefault()}},c.prototype.cycle=function(b){return b||(this.paused=!1),this.interval&&clearInterval(this.interval),this.options.interval&&!this.paused&&(this.interval=setInterval(a.proxy(this.next,this),this.options.interval)),this},c.prototype.getItemIndex=function(a){return this.$items=a.parent().children(".item"),this.$items.index(a||this.$active)},c.prototype.getItemForDirection=function(a,b){var c=this.getItemIndex(b),d="prev"==a&&0===c||"next"==a&&c==this.$items.length-1;if(d&&!this.options.wrap)return b;var e="prev"==a?-1:1,f=(c+e)%this.$items.length;return this.$items.eq(f)},c.prototype.to=function(a){var b=this,c=this.getItemIndex(this.$active=this.$element.find(".item.active"));return a>this.$items.length-1||0>a?void 0:this.sliding?this.$element.one("slid.bs.carousel",function(){b.to(a)}):c==a?this.pause().cycle():this.slide(a>c?"next":"prev",this.$items.eq(a))},c.prototype.pause=function(b){return b||(this.paused=!0),this.$element.find(".next, .prev").length&&a.support.transition&&(this.$element.trigger(a.support.transition.end),this.cycle(!0)),this.interval=clearInterval(this.interval),this},c.prototype.next=function(){return this.sliding?void 0:this.slide("next")},c.prototype.prev=function(){return this.sliding?void 0:this.slide("prev")},c.prototype.slide=function(b,d){var e=this.$element.find(".item.active"),f=d||this.getItemForDirection(b,e),g=this.interval,h="next"==b?"left":"right",i=this;if(f.hasClass("active"))return this.sliding=!1;var j=f[0],k=a.Event("slide.bs.carousel",{relatedTarget:j,direction:h});if(this.$element.trigger(k),!k.isDefaultPrevented()){if(this.sliding=!0,g&&this.pause(),this.$indicators.length){this.$indicators.find(".active").removeClass("active");var l=a(this.$indicators.children()[this.getItemIndex(f)]);l&&l.addClass("active")}var m=a.Event("slid.bs.carousel",{relatedTarget:j,direction:h});return a.support.transition&&this.$element.hasClass("slide")?(f.addClass(b),f[0].offsetWidth,e.addClass(h),f.addClass(h),e.one("bsTransitionEnd",function(){f.removeClass([b,h].join(" ")).addClass("active"),e.removeClass(["active",h].join(" ")),i.sliding=!1,setTimeout(function(){i.$element.trigger(m)},0)}).emulateTransitionEnd(c.TRANSITION_DURATION)):(e.removeClass("active"),f.addClass("active"),this.sliding=!1,this.$element.trigger(m)),g&&this.cycle(),this}};var d=a.fn.carousel;a.fn.carousel=b,a.fn.carousel.Constructor=c,a.fn.carousel.noConflict=function(){return a.fn.carousel=d,this};var e=function(c){var d,e=a(this),f=a(e.attr("data-target")||(d=e.attr("href"))&&d.replace(/.*(?=#[^\s]+$)/,""));if(f.hasClass("carousel")){var g=a.extend({},f.data(),e.data()),h=e.attr("data-slide-to");h&&(g.interval=!1),b.call(f,g),h&&f.data("bs.carousel").to(h),c.preventDefault()}};a(document).on("click.bs.carousel.data-api","[data-slide]",e).on("click.bs.carousel.data-api","[data-slide-to]",e),a(window).on("load",function(){a('[data-ride="carousel"]').each(function(){var c=a(this);b.call(c,c.data())})})}(jQuery),+function(a){"use strict";function b(b){var c,d=b.attr("data-target")||(c=b.attr("href"))&&c.replace(/.*(?=#[^\s]+$)/,"");return a(d)}function c(b){return this.each(function(){var c=a(this),e=c.data("bs.collapse"),f=a.extend({},d.DEFAULTS,c.data(),"object"==typeof b&&b);!e&&f.toggle&&"show"==b&&(f.toggle=!1),e||c.data("bs.collapse",e=new d(this,f)),"string"==typeof b&&e[b]()})}var d=function(b,c){this.$element=a(b),this.options=a.extend({},d.DEFAULTS,c),this.$trigger=a(this.options.trigger).filter('[href="#'+b.id+'"], [data-target="#'+b.id+'"]'),this.transitioning=null,this.options.parent?this.$parent=this.getParent():this.addAriaAndCollapsedClass(this.$element,this.$trigger),this.options.toggle&&this.toggle()};d.VERSION="3.3.2",d.TRANSITION_DURATION=350,d.DEFAULTS={toggle:!0,trigger:'[data-toggle="collapse"]'},d.prototype.dimension=function(){var a=this.$element.hasClass("width");return a?"width":"height"},d.prototype.show=function(){if(!this.transitioning&&!this.$element.hasClass("in")){var b,e=this.$parent&&this.$parent.children(".panel").children(".in, .collapsing");if(!(e&&e.length&&(b=e.data("bs.collapse"),b&&b.transitioning))){var f=a.Event("show.bs.collapse");if(this.$element.trigger(f),!f.isDefaultPrevented()){e&&e.length&&(c.call(e,"hide"),b||e.data("bs.collapse",null));var g=this.dimension();this.$element.removeClass("collapse").addClass("collapsing")[g](0).attr("aria-expanded",!0),this.$trigger.removeClass("collapsed").attr("aria-expanded",!0),this.transitioning=1;var h=function(){this.$element.removeClass("collapsing").addClass("collapse in")[g](""),this.transitioning=0,this.$element.trigger("shown.bs.collapse")};if(!a.support.transition)return h.call(this);var i=a.camelCase(["scroll",g].join("-"));this.$element.one("bsTransitionEnd",a.proxy(h,this)).emulateTransitionEnd(d.TRANSITION_DURATION)[g](this.$element[0][i])}}}},d.prototype.hide=function(){if(!this.transitioning&&this.$element.hasClass("in")){var b=a.Event("hide.bs.collapse");if(this.$element.trigger(b),!b.isDefaultPrevented()){var c=this.dimension();this.$element[c](this.$element[c]())[0].offsetHeight,this.$element.addClass("collapsing").removeClass("collapse in").attr("aria-expanded",!1),this.$trigger.addClass("collapsed").attr("aria-expanded",!1),this.transitioning=1;var e=function(){this.transitioning=0,this.$element.removeClass("collapsing").addClass("collapse").trigger("hidden.bs.collapse")};return a.support.transition?void this.$element[c](0).one("bsTransitionEnd",a.proxy(e,this)).emulateTransitionEnd(d.TRANSITION_DURATION):e.call(this)}}},d.prototype.toggle=function(){this[this.$element.hasClass("in")?"hide":"show"]()},d.prototype.getParent=function(){return a(this.options.parent).find('[data-toggle="collapse"][data-parent="'+this.options.parent+'"]').each(a.proxy(function(c,d){var e=a(d);this.addAriaAndCollapsedClass(b(e),e)},this)).end()},d.prototype.addAriaAndCollapsedClass=function(a,b){var c=a.hasClass("in");a.attr("aria-expanded",c),b.toggleClass("collapsed",!c).attr("aria-expanded",c)};var e=a.fn.collapse;a.fn.collapse=c,a.fn.collapse.Constructor=d,a.fn.collapse.noConflict=function(){return a.fn.collapse=e,this},a(document).on("click.bs.collapse.data-api",'[data-toggle="collapse"]',function(d){var e=a(this);e.attr("data-target")||d.preventDefault();var f=b(e),g=f.data("bs.collapse"),h=g?"toggle":a.extend({},e.data(),{trigger:this});c.call(f,h)})}(jQuery),+function(a){"use strict";function b(b){b&&3===b.which||(a(e).remove(),a(f).each(function(){var d=a(this),e=c(d),f={relatedTarget:this};e.hasClass("open")&&(e.trigger(b=a.Event("hide.bs.dropdown",f)),b.isDefaultPrevented()||(d.attr("aria-expanded","false"),e.removeClass("open").trigger("hidden.bs.dropdown",f)))}))}function c(b){var c=b.attr("data-target");c||(c=b.attr("href"),c=c&&/#[A-Za-z]/.test(c)&&c.replace(/.*(?=#[^\s]*$)/,""));var d=c&&a(c);return d&&d.length?d:b.parent()}function d(b){return this.each(function(){var c=a(this),d=c.data("bs.dropdown");d||c.data("bs.dropdown",d=new g(this)),"string"==typeof b&&d[b].call(c)})}var e=".dropdown-backdrop",f='[data-toggle="dropdown"]',g=function(b){a(b).on("click.bs.dropdown",this.toggle)};g.VERSION="3.3.2",g.prototype.toggle=function(d){var e=a(this);if(!e.is(".disabled, :disabled")){var f=c(e),g=f.hasClass("open");if(b(),!g){"ontouchstart"in document.documentElement&&!f.closest(".navbar-nav").length&&a('