newsticker.el 1.7

classic Classic list List threaded Threaded
1 message Options
Reply | Threaded
Open this post in threaded view
|

newsticker.el 1.7

Ulf Jasper
This is version 1.7 of newsticker.el, a newsticker (RSS reader, RSS
aggregator) for Emacs.

Changes since version 1.6:

* Tool-bar support: most important commands can be called from tool-bar
  buttons.
* Auto-Narrowing introduced: *newsticker* buffer can be narrowed to a
  single item (bound to key `xi') or a single feed (bound to `xf').
* Enclosure support: enclosed items are shown (see
  `newsticker-enclosure-face') and can be (automatically) downloaded (see
  below). For those of you who read "podcasts".
* Added variable `newsticker-auto-mark-filter' for automatically marking
  items as immortal or old.
* Added hook variable `newsticker-new-item-functions' for handling new
  items.  Added sample functions `newsticker-download-images', and
  `newsticker-download-enclosures'.
* Added hook variable `newsticker-select-item-hook' which is run after
  `newsticker-(next|previous)-(new-)?-item'.
* Added hook variable `newsticker-select-feed-hook' which is run after
  `newsticker-(next|previous)-feed'.
* Added hook variable `newsticker-buffer-change-hook' which is run after
  the contents or visibility of the newsticker buffer has changed,
  e.g. after `newsticker-buffer-update' or `newsticker-show-feed-desc'.
* Added command `newsticker-handle-url' for interactively launching
  arbitrary programs for URLs, bound to `C-RET'.
* URLs in extra elements are clickable.
* Better support for w3, added command `newsticker-w3m-show-inline-images'
  for displaying all inline images.
* Insert an artificial headline which notifies about failed retrievals.
* Use pubDate element (RSS 2.0) instead of retrieval time when available.
* Customizable options grouped.
* Bugfixes: `newsticker--imenu-create-index'; strip whitespace from links;
  apply coding-system to extra-elements; time-comparison for obsolete
  items; and others which I have forgotten.
* Workaround for another bug in xml-parse-region -- thanks to anonymous for
  sending patch.
* Renamed invisible buffers ` *wget-newsticker-<feed>*' to
  ` *newsticker-wget-<feed>*'.
* Tested with GNU Emacs versions 21.3 and 22.0 and XEmacs 21.something.

For more information see the Commentary in the file, or newsticker's
homepage at savannah: http://www.nongnu.org/newsticker/.

Enjoy!

 ulf

;;; newsticker.el --- A Newsticker for Emacs.

;; Copyright (C) 2003-2005 by Ulf Jasper

;; This file is NOT part of GNU Emacs.

;; Author:      Ulf Jasper <[hidden email]>
;; Filename:    newsticker.el
;; URL:         http://www.nongnu.org/newsticker
;; Created:     17. June 2003
;; Keywords:    News, RSS
;; Time-stamp:  "25. Juni 2005, 18:36:16 (ulf)"
;; CVS-Version: $Id: newsticker.el,v 1.119 2005/06/25 16:36:55 u11 Exp $

(defconst newsticker-version "1.7" "Version number of newsticker.el.")

;; ======================================================================

;; This program 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.

;; This program 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 this program; if not, write to the Free Software
;; Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
;; USA

;; ======================================================================
;;; Commentary:

;; Overview
;; --------

;; Newsticker provides a newsticker for Emacs. A newsticker is a thing that
;; asynchronously retrieves headlines from a list of news sites, prepares
;; these headlines for reading, and allows for loading the corresponding
;; articles in a web browser.

;; Headlines consist of a title and (possibly) a small description. They
;; are contained in RSS (RDF Site Summary) files. Newsticker should work
;; with all RSS files that follow the RDF Rich Site Summary 1.0
;; specification. It should also work with version 2.0 as well as
;; other/older/alternative RSS formats (like 0.9<something> or such). In
;; other words: Newsticker is a "RSS reader" or "RSS aggregator".

;; Newsticker provides several commands for reading headlines, navigating
;; through them, marking them as read/unread, hiding old headlines
;; etc. Headlines can be displayed as plain text or as rendered HTML.

;; Headlines can be displayed in the echo area, either scrolling like
;; messages in a stock-quote ticker, or just changing.

;; Newsticker allows for automatic processing of headlines by providing
;; hooks and (sample) functions for automatically downloading images and
;; enclosed files (as delivered by podcasts, e.g.).



;; Requirements
;; ------------
;; Newsticker can be used with GNU Emacs version 21.1 or later as well as
;; XEmacs. It requires an XML-parser (`xml.el') which is part of GNU
;; Emacs. If you are using XEmacs you want to get the `net-utils' package
;; which contains `xml.el' for XEmacs.

;; Newsticker requires a program which can retrieve files via http and
;; prints them to stdout. By default Newsticker will use wget for this
;; task.

;; Installation
;; ------------
;; Place Newsticker in a directory where Emacs can find it. Add the
;; following line to your Emacs startup file (`~/.emacs').
;;   (add-to-list 'load-path "/path/to/newsticker/")
;;   (autoload 'newsticker-start "newsticker" "Emacs Newsticker" t)
;;   (autoload 'newsticker-show-news "newsticker" "Emacs Newsticker" t)

;; Newsticker-mode supports imenu. It allows for navigating with the help
;; of a menu. In order to use this feature you should also add the
;; following.
;;   (add-hook 'newsticker-mode-hook 'imenu-add-menubar-index)

;; That's it.

;; Usage
;; -----
;; The command newsticker-show-news will display all available headlines in
;; a special buffer, called `*newsticker*'. It will also start the
;; asynchronous download of headlines. The modeline in the `*newsticker*'
;; buffer informs whenever new headlines have arrived. Clicking
;; mouse-button 2 or pressing RET in this buffer on a headline will call
;; browse-url to load the corresponding news story in your favourite web
;; browser.

;; The scrolling, or flashing of headlines in the echo area, can be started
;; with the command newsticker-start-ticker. It can be stopped with
;; newsticker-stop-ticker.

;; If you just want to start the periodic download of headlines use the
;; command newsticker-start. Calling newsticker-stop will stop the periodic
;; download, but will call newsticker-stop-ticker as well.

;; Configuration
;; -------------
;; All Newsticker options are customizable, i.e. they can be changed with
;; Emacs customization methods: Call the command customize-group and enter
;; `newsticker' for the customization group.

;; All Newsticker options have reasonable default values, so that in most
;; cases it is not necessary to customize settings before starting
;; Newsticker for the first time.

;; Newsticker options are organized in the following groups.

;; * newsticker-feed contains options that define which news
;;   feeds are retrieved and how this is done.
;;   o newsticker-url-list defines the list of headlines which are
;;     retrieved.
;;   o newsticker-retrieval-interval defines how often headlines are
;;     retrieved.
;; * newsticker-headline-processing contains options that define how the
;;   retrieved headlines are processed.
;;   o newsticker-keep-obsolete-items decides whether unread headlines that
;;     have been removed from the feed are kept in the Newsticker cache.
;; * newsticker-layout contains options that define how the buffer for
;;   reading RSS headlines is formatted.
;;   o newsticker-item-format defines how the title of a headline is
;;     formatted.
;; * newsticker-ticker contains options that define how headlines are shown
;;   in the echo area.
;;   o newsticker-display-interval and newsticker-scroll-smoothly define
;;     how headlines are shown in the echo area.
;; * newsticker-hooks contains options for hooking other Emacs commands to
;;   newsticker functions.
;;   o newsticker-new-item-functions allows for automatic processing of
;;     headlines. See `newsticker-download-images', and
;;     `newsticker-download-enclosures' for sample functions.
;; * newsticker-miscellaneous contains other Newsticker options.

;; Please have a look at the customization buffers for the complete list of
;; options.

;; Remarks
;; -------
;; This newsticker is designed do its job silently in the background
;; without disturbing you.  However, it is probably impossible to prevent
;; such a tool from slightly attenuating your Editor's responsiveness every
;; once in a while.

;; Byte-compiling newsticker.el is recommended.

;; ======================================================================
;;; History:

;; 1.7 (2005-06-25)
;;     * Tool-bar support: most important commands can be called from
;;       tool-bar buttons.
;;     * Auto-Narrowing introduced: *newsticker* buffer can be narrowed to
;;       a single item (bound to key `xi') or a single feed (bound to `xf').
;;     * Enclosure support: enclosed items are shown (see
;;       `newsticker-enclosure-face') and can be (automatically) downloaded
;;       (see below). For those of you who read "podcasts".
;;     * Added variable `newsticker-auto-mark-filter' for automatically
;;       marking items as immortal or old.
;;     * Added hook variable `newsticker-new-item-functions' for handling
;;       new items.  Added sample functions `newsticker-download-images',
;;       and `newsticker-download-enclosures'.
;;     * Added hook variable `newsticker-select-item-hook' which is run
;;       after `newsticker-(next|previous)-(new-)?-item'.
;;     * Added hook variable `newsticker-select-feed-hook' which is run
;;       after `newsticker-(next|previous)-feed'.
;;     * Added hook variable `newsticker-buffer-change-hook' which is run
;;       after the contents or visibility of the newsticker buffer has
;;       changed, e.g. after `newsticker-buffer-update' or
;;       `newsticker-show-feed-desc'.
;;     * Added command `newsticker-handle-url' for interactively launching
;;       arbitrary programs for URLs, bound to `C-RET'.
;;     * URLs in extra elements are clickable.
;;     * Better support for w3, added command
;;       `newsticker-w3m-show-inline-images' for displaying all inline
;;       images.
;;     * Insert an artificial headline which notifies about failed retrievals.
;;     * Use pubDate element (RSS 2.0) instead of retrieval time when
;;       available.
;;     * Customizable options grouped.
;;     * Bugfixes: `newsticker--imenu-create-index'; strip whitespace
;;       from links; apply coding-system to extra-elements; time-comparison
;;       for obsolete items; and others which I have forgotten.
;;     * Workaround for another bug in xml-parse-region -- thanks to anonymous
;;       for sending patch.
;;     * Renamed invisible buffers ` *wget-newsticker-<feed>*' to
;;       ` *newsticker-wget-<feed>*'.
;;     * Tested with GNU Emacs versions 21.3 and 22.0 and XEmacs 21.something.

;; 1.6 * Support for (some) optional RSS elements: guid, dc:date. See
;;       `newsticker-show-all-rss-elements' `newsticker-extra-face'.
;;     * Better support for w3m -- `newsticker-default-face' is obsolete
;;       now, removed `newsticker-w3m-toggle-inline-image'.
;;     * Added `newsticker-desc-comp-max' -- comparison of item descriptions
;;       can take quite some time.
;;     * Added `newsticker--buffer-make-item-completely-visible' to
;;       ensure that the current item is fully visible.
;;     * Allow for non-positive retrieval-interval, which make newsticker
;;       get news only once.
;;     * Use :set for customizable variables.
;;     * Added `newsticker-buffer-force-update', bound to key `U'.
;;     * Added concept of obsolete items, see
;;       `newsticker-keep-obsolete-items', `newsticker-obsolete-item-face',
;;       `newsticker-obsolete-item-max-age'.
;;     * Added `newsticker-add-url'.
;;     * OPML export.
;;     * Save pre-formatted titles => even better performance!!
;;     * `newsticker-*-new-item' wraps at beginning/end of buffer.
;;     * Always sort obsolete items to end of item list.
;;     * Bugfixes:
;;       - newsticker-hide-entry,
;;       - changes of feed-titles led to duplicate feed items,
;;       - faces for rendered HTML texts,
;;       - length of ticker-text (for "exotic"/multibyte texts),
;;         Thanks to Hiroshi Maruyama.
;;       - suppress items with empty title and description
;;       - newsticker-sort-method was ignored!
;;       - prevent call of fill-region on HTML-rendered descriptions.

;; 1.5 * Rewrote the visibility stuff. newsticker does not inherit
;;       outline anymore.  Now you have complete freedom for
;;       `newsticker-*-format'.
;;     * Save pre-formatted descriptions => incredible performance boost!!
;;     * Introduced `newsticker-(start|stop)-ticker'.
;;     * Introduced statistics for heading-format and
;;       `newsticker-statistics-face'.
;;     * Introduced `newsticker-enable-logo-manipulations'.
;;     * Compare link of items (as well as title and desc).
;;     * Added `newsticker-start-hook' and `newsticker-stop-hook', thanks
;;       to mace.
;;     * Bugfixes -- thanks to Ryan Yeske, Jari Aalto, Bruce Ingalls.
;;     * Tested with Emacs 21.3.50, 21.3.1, 21.2, 21.1; XEmacs 21.4.15

;; 1.4 * Enabled HTML rendering, added `newsticker-html-renderer' to
;;       choose a HTML rendering engine, thanks to Greg Scott for testing
;;     * New Outline handling using text properties instead of "**"
;;       prefixes.
;;     * Added possibility to mark single item as old (bound to key
;;       `o' (`newsticker-mark-item-at-point-as-read').
;;     * Added possibility to mark single item as immortal (bound to key
;;       `i' (`newsticker-mark-item-at-point-as-immortal').
;;     * Added possibility to display feed logos.
;;     * Added `newsticker-heading-format', `newsticker-item-format'.
;;     * Added `newsticker-date-format'.
;;     * Added `newsticker-justification'.
;;     * Added `newsticker-automatically-mark-visited-items-as-old'.
;;     * Added `newsticker-w3m-toggle-inline-image' which calls
;;       `w3m-toggle-inline-image' if `newsticker-html-renderer' is
;;       `w3m-region'. Exists for convenience only (bound to key
;;       `RET').

;; 1.3 * Compare title AND desc to check whether item is old, except
;;       for feed desc
;;     * Mark as not-up-to-date only after new items have arrived.
;;     * Added XEmacs compatibility code, tested with XEmacs 21.4.13.
;;     * Tested with Emacs 21.3.50 and Emacs 21.2.something.
;;     * Bugfix: Apply coding-systems to feed title and description,
;;       thanks to OHASHI Akira
;;     * Bugfix: xml-parser-workaround did not work for japanese texts,
;;       thanks to OHASHI Akira
;;     * Kill wget-buffers unless newsticker-debug is not nil.
;;     * Bugfix: xml-parser-workaround for "DOCTYPE rdf:RDF"

;; 1.2 Peter S Galbraith <[hidden email]>
;;     * Added `newsticker-url-list-defaults', splitting the URLs into
;;       a customizable selection list, and a user add-on list.
;;     * Minor checkdoc fixes.

;; 1.1 * Introduced optional feed-specific wget-arguments.
;;     * Keep order of feeds as given in `newsticker-url-list' in
;;       *newsticker* buffer.
;;     * Ignore unsupported coding systems.

;; 1.0 * Introduced feed-specific retrieval-timers.
;;     * Removed dependency on 'cl (cddddr).
;;     * Thanks to Kevin Rodgers and T.V.  Raman for their help.
;;     * Use utf-8 for reading and writing cache data.
;;     * Reported to work with Emacs 21.3.50.

;; 0.99 * Minor tweaks.
;;      * Tested with Emacs 21.3.2

;; 0.98 * Check exit status of wget processes.  Keep cache data if
;;        something went wrong.  Throw error when old wget-processes
;;        are hanging around.
;;      * Introduced newsticker-specific faces.
;;      * Added `newsticker-show-descriptions-of-new-items'.
;;      * Added `newsticker-hide-old-items-in-newsticker-buffer'.
;;      * Added `newsticker-(hide|show)-old-items'.

;; 0.97 * Minor tweaks.

;; 0.96 * Added caching.
;;      * newsticker-mode inherits outline-mode.
;;      * newsticker-mode supports imenu.
;;      * Easy buffer-navigation with newsticker-mode's keymap.
;;      * Some bugs fixed.
;;      * Thanks to Moritz Epple for documentation tips.

;; 0.95 * Added newsticker-mode -- Thanks to T.V.  Raman.
;;      * Catch xml-parser errors -- Thanks to T.V.  Raman.
;;      * Remove stupid newlines in titles (headlines) -- Thanks to
;;        Jeff Rancier.

;; 0.94 * Added clickerability and description for channel headings.
;;      * Made it work for (at least some) rss 0.9<something> feeds.

;; 0.93 * Added some more sites.
;;      * Do not flood the *Messages* buffer.
;;      * First attempt at handling coding systems.

;; 0.92 * Added `newsticker-wget-name'.
;;      * Try to display message only if minibuffer and echo area are
;;        not in use already.
;;      * Dirty workaround for newer versions of xml.el: Remove
;;        whitespace in rdf.
;;      * Tested with Emacs 21.3.2 and CVS-snapshot of 2003-06-21.

;; 0.91 * First bugfix: *newsticker* is read-only.

;; 0.9  * First release.
;;      * Tested with Emacs 21.3.2 and wget 1.8.2.

;; ======================================================================
;;; To Do:

;; * Image handling for XEmacs (create-image does not exist)

;; ======================================================================
;;; Code:

(require 'derived)
(require 'xml)

;; ======================================================================
;;; Customizables
;; ======================================================================
(defgroup newsticker nil
  "RSS aggregator."
  :group 'applications)

(defconst newsticker--raw-url-list-defaults
  '(("CNET News.com"
     "http://export.cnet.com/export/feeds/news/rss/1,11176,,00.xml")
    ("Debian Security Advisories"
    "http://www.debian.org/security/dsa.en.rdf")
    ("Debian Security Advisories - Long format"
    "http://www.debian.org/security/dsa-long.en.rdf")
    ("Emacs Wiki"
    "http://www.emacswiki.org/cgi-bin/wiki.pl?action=rss"
    nil
    3600)
    ("Freshmeat.net"
    "http://freshmeat.net/backend/fm.rdf")
    ("Kuro5hin.org"
    "http://www.kuro5hin.org/backend.rdf")
    ("LWN (Linux Weekly News)"
    "http://lwn.net/headlines/rss")
    ("NewsForge"
    "http://newsforge.com/index.rss")
    ("NY Times: Technology"
    "http://partners.userland.com/nytRss/technology.xml")
    ("NY Times"
    "http://partners.userland.com/nytRss/nytHomepage.xml")
    ("Quote of the day"
    "http://www.quotationspage.com/data/qotd.rss"
    "07:00"
    86400)
    ("The Register"
    "http://www.theregister.co.uk/tonys/slashdot.rdf")
    ("slashdot"
    "http://slashdot.org/index.rss"
    nil
    3600)                        ;/. will ban you if under 3600 seconds!
    ("Wired News"
    "http://www.wired.com/news_drop/netcenter/netcenter.rdf")
    ("Heise News (german)"
    "http://www.heise.de/newsticker/heise.rdf")
    ("Tagesschau (german)"
    "http://www.tagesschau.de/newsticker.rdf"
    nil
    1800)
    ("Telepolis (german)"
    "http://www.heise.de/tp/news.rdf"))
  "Default URL list in raw form.
This list is fed into defcustom via `newsticker--splicer'.")

(defun newsticker--splicer (item)
  "Convert ITEM for splicing into `newsticker-url-list-defaults'."
  (let ((result (list 'list :tag (nth 0 item) (list 'const (nth 0 item))))
        (element (cdr item)))
    (while element
      (setq result (append result (list (list 'const (car element)))))
      (setq element (cdr element)))
    result))

;; ======================================================================
;;; Customization
;; ======================================================================
(defun newsticker--set-customvar (symbol value)
  "Set newsticker-variable SYMBOL value to VALUE.

Calls all necessary actions which are necessary in order to make
the new value effective.  Changing `newsticker-url-list', for example,
will re-start the retrieval-timers."
  (unless (condition-case nil
              (eq (symbol-value symbol) value)
            (error nil))
    (set symbol value)
    (cond ((eq symbol 'newsticker-sort-method)
           (when (fboundp 'newsticker--cache-sort)
             (message "Applying new sort method...")
             (newsticker--cache-sort)
             (newsticker--buffer-set-uptodate nil)
             (message "Applying new sort method...done")))
          ((memq symbol '(newsticker-url-list-defaults
                          newsticker-url-list
                          newsticker-retrieval-interval))
           (when (and (fboundp 'newsticker-running-p)
                      (newsticker-running-p))
             (message "Restarting newsticker")
             (newsticker-stop)
             (newsticker-start)))
          ((eq symbol 'newsticker-display-interval)
           (when (and (fboundp 'newsticker-running-p)
                      (newsticker-running-p))
             (message "Restarting ticker")
             (newsticker-stop-ticker)
             (newsticker-start-ticker)
             (message "")))
          ((memq symbol '(newsticker-hide-old-items-in-echo-area
                          newsticker-hide-obsolete-items-in-echo-area
                          newsticker-hide-immortal-items-in-echo-area))
           (when (and (fboundp 'newsticker-running-p)
                      (newsticker-running-p))
             (message "Restarting newsticker")
             (newsticker-stop-ticker)
             (newsticker--ticker-text-setup)
             (newsticker-start-ticker)
             (message "")))
          ((memq symbol '(newsticker-hide-old-items-in-newsticker-buffer
                          newsticker-show-descriptions-of-new-items))
           (when (fboundp 'newsticker--buffer-set-uptodate)
             (newsticker--buffer-set-uptodate nil)))
          ((memq symbol '(newsticker-heading-format
                          newsticker-item-format
                          newsticker-desc-format
                          newsticker-date-format
                          newsticker-statistics-format
                          newsticker-justification
                          newsticker-use-full-width
                          newsticker-html-renderer
                          newsticker-feed-face
                          newsticker-new-item-face
                          newsticker-old-item-face
                          newsticker-immortal-item-face
                          newsticker-obsolete-item-face
                          newsticker-date-face
                          newsticker-statistics-face
                          ;;newsticker-default-face
                          ))
           (when (fboundp 'newsticker--forget-preformatted)
             (newsticker--forget-preformatted)))
          (t
           (error "Ooops %s" symbol)))))

;; customization group feed
(defgroup newsticker-feed nil
  "Settings for the RSS feeds."
  :group 'newsticker)

(defcustom newsticker-url-list-defaults
 '(("Emacs Wiki"
    "http://www.emacswiki.org/cgi-bin/wiki.pl?action=rss"
    nil
    3600))
  "A customizable list of news feeds to select from.
These were mostly extracted from the Radio Community Server at
http://subhonker6.userland.com/rcsPublic/rssHotlist.

You may add other entries in `newsticker-url-list'."
  :type `(set ,@(mapcar `newsticker--splicer
                        newsticker--raw-url-list-defaults))
  :set 'newsticker--set-customvar
  :group 'newsticker-feed)

(defcustom newsticker-url-list nil
  "The news feeds which you like to watch.

This alist will be used in addition to selection made customizing
`newsticker-url-list-defaults'.

This is an alist.  Each element consists of two items: a LABEL and a URL,
optionally followed by a START-TIME, INTERVAL specifier and WGET-ARGUMENTS.

The LABEL gives the name of the news feed.  It can be an arbitrary string.

The URL gives the location of the news feed.  It must point to a valid
RSS file.  The RSS file is retrieved by calling wget, or whatever you
specify as `newsticker-wget-name'.

The START-TIME can be either a string, or nil.  If it is a string it
specifies a fixed time at which this feed shall be retrieved for the
first time.  (Examples: \"11:00pm\", \"23:00\").  If it is nil (or
unspecified), this feed will be retrieved immediately after calling
`newsticker-start'.

The INTERVAL specifies the time between retrievals for this feed.  If it
is nil (or unspecified) the default interval value as set in
`newsticker-retrieval-interval' is used.

\(newsticker.el calls `run-at-time'. The newsticker-parameters START-TIME
and INTERVAL correspond to the `run-at-time'-parameters TIME and REPEAT.)

WGET-ARGUMENTS specifies arguments for wget (see `newsticker-wget-name')
which apply for this feed only, overriding the value of
`newsticker-wget-arguments'."
  :type '(repeat (list :tag "News feed"
                       (string :tag "Label")
                       (string :tag "URI")
                       (choice :tag "Start"
                               (const   :tag "Default" nil)
                               (string  :tag "Fixed Time"))
                       (choice :tag "Interval"
                               (const   :tag "Default" nil)
                               (const   :tag "Hourly" 3600)
                               (const   :tag "Daily" 86400)
                               (integer :tag "Interval"))
                       (choice :tag "Wget Arguments"
                               (const  :tag "Default arguments" nil)
                               (repeat :tag "Special arguments" string))))
  :set 'newsticker--set-customvar
  :group 'newsticker-feed)

(defcustom newsticker-wget-name
  "wget"
  "Name of the program which is called to retrieve news from the web.
The canonical choice is wget but you may take any other program which is
able to return the contents of a news feed file on stdout."
  :type 'string
  :group 'newsticker-feed)

(defcustom newsticker-wget-arguments
  '("-q" "-O" "-")
  "Arguments which are passed to wget.
There is probably no reason to change the default settings, unless you
are living behind a firewall."
  :type '(repeat (string :tag "Argument"))
  :group 'newsticker-feed)

(defcustom newsticker-retrieval-interval
  3600
  "Time interval for retrieving new news items (seconds).
If this value is not positive (i.e. less than or equal to 0)
items are retrieved only once!
Please note that some feeds, e.g. Slashdot, will ban you if you
make it less than 1800 seconds (30 minutes)!"
  :type '(choice :tag "Interval"
                 (const   :tag "No automatic retrieval" 0)
                 (const   :tag "Hourly" 3600)
                 (const   :tag "Daily" 86400)
                 (integer :tag "Interval"))
  :set 'newsticker--set-customvar
  :group 'newsticker-feed)

(defcustom newsticker-desc-comp-max
  100
  "Relevant length of headline descriptions.
This value gives the maximum number of characters which will be
taken into account when newsticker compares two headline
descriptions."
  :type 'integer
  :group 'newsticker-feed)

;; customization group behaviour
(defgroup newsticker-headline-processing nil
  "Settings for the automatic processing of RSS headlines."
  :group 'newsticker)

(defcustom newsticker-automatically-mark-items-as-old
  t
  "Decides whether to automatically mark items as old.
If t a new item is considered as new only after its first retrieval.  As
soon as it is retrieved a second time, it becomes old.  If not t all
items stay new until you mark them as old.  This is done in the
*newsticker* buffer."
  :type 'boolean
  :group 'newsticker-headline-processing)

(defcustom newsticker-automatically-mark-visited-items-as-old
  t
  "Decides whether to automatically mark visited items as old.
If t an item is marked as old as soon as the associated link is
visited, i.e. after pressing RET or mouse2 on the item's
headline."

  :type 'boolean
  :group 'newsticker-headline-processing)

(defcustom newsticker-keep-obsolete-items
  t
  "Decides whether to keep unread items which have been removed from feed.
If t a new item, which has been removed from the feed, is kept in
the cache until it is marked as read."
  :type 'boolean
  :group 'newsticker-headline-processing)

(defcustom newsticker-obsolete-item-max-age
  (* 60 60 24)
  "Maximal age of obsolete items, in seconds.
Obsolete items which are older than this value will be silently
deleted at the next retrieval."
  :type 'integer
  :group 'newsticker-headline-processing)

(defcustom newsticker-auto-mark-filter
  nil
  "A filter for automatically marking headlines.

This is an alist of the form (FEED-NAME OLD-LIST IMMORTAL-LIST).  I.e. each
element consists of a FEED-NAME and two lists.  Each list consists a set of
regular expressions.  The first list contains patterns of headlines which
will be marked as old.  The second list contains patterns of headlines which
will be marked as immortal.

This filter is checked after a new headline has been retrieved.  If
FEED-NAME matches the name of the corresponding news feed, both sublists
are checked: If the title of the headline matches any of the regular
expressions in OLD-LIST, this headline is marked as old, if it matches any
of the expressions in IMMORTAL-LIST it is marked as immortal.

If, for example, `newsticker-auto-mark-filter' looks like
 \((slashdot (\"^Forget me!$\") (\"^Read me$\" \"important\")))
then all articles from slashdot are marked as old if they have the title
\"Forget me!\".  All articles which have the title \"Read me\" and all
articles which contain the string \"important\" in their title are marked
as immortal."
  :type '(repeat (list :tag "Feed filter rule"
                       (string :tag "Feed name")
                       ;;(choice ,@(mapcar (lambda (i)
                         ;;                  (list :tag (car i) (car i)))
                           ;;              newsticker-url-list))
                       (repeat :tag "Mark as old" string)
                       (repeat :tag "Mark as immortal" string)))
  :group 'newsticker-headline-processing)

;; customization group layout
(defgroup newsticker-layout nil
  "Settings for layout of the RSS reader."
  :group 'newsticker)

(defcustom newsticker-sort-method
  'sort-by-original-order
  "Sort method for news items.
The following sort methods are available:
* `sort-by-original-order' keeps the order in which the items
  appear in the RSS file (please note that for immortal items,
  which have been removed from the news feed, there is no original
  order),
* `sort-by-time' looks at the time at which an item has been seen
  the first time.  The most recent item is put at top,
* `sort-by-title' will put the items in an alphabetical order."
  :type '(choice
          (const :tag "Keep original order" sort-by-original-order)
          (const :tag "Sort by time"        sort-by-time)
          (const :tag "Sort by title"       sort-by-title))
  :set 'newsticker--set-customvar
  :group 'newsticker-layout)

(defcustom newsticker-hide-old-items-in-newsticker-buffer
  nil
  "Decides whether to automatically hide old items in the *newsticker* buffer.
If set to t old items will be completely folded and only new items
will show up in the *newsticker* buffer.  Otherwise old as well as new
items will be visible."
  :type 'boolean
  :set 'newsticker--set-customvar
  :group 'newsticker-layout)

(defcustom newsticker-show-descriptions-of-new-items
  t
  "Whether to automatically show descriptions of new items in *newsticker*.
If set to t old items will be folded and new items will be
unfolded.  Otherwise old as well as new items will be folded."
  :type 'boolean
  :set 'newsticker--set-customvar
  :group 'newsticker-layout)

(defcustom newsticker-heading-format
  "%l
%t %d %s"
  "Format string for feed headings.
The following printf-like specifiers can be used:
%d  The date the feed was retrieved.  See `newsticker-date-format'.
%l  The logo (image) of the feed.  Most RSS feeds provide a small
    image as logo.  Newsticker can display them, if Emacs can --
    see `image-types' for a list of supported image types.
%L  The logo (image) of the feed.  If the logo is not available
    the title of the feed is used.
%s  The statistical data of the feed.  See `newsticker-statistics-format'.
%t  The title of the feed, i.e. its name."
  :type 'string
  :set 'newsticker--set-customvar
  :group 'newsticker-layout)

(defcustom newsticker-item-format
  "%t %d"
  "Format string for news item headlines.
The following printf-like specifiers can be used:
%d  The date the item was (first) retrieved.  See `newsticker-date-format'.
%l  The logo (image) of the feed.  Most RSS feeds provide a small
    image as logo.  Newsticker can display them, if Emacs can --
    see `image-types' for a list of supported image types.
%L  The logo (image) of the feed.  If the logo is not available
    the title of the feed is used.
%t  The title of the item."
  :type 'string
  :set 'newsticker--set-customvar
  :group 'newsticker-layout)

(defcustom newsticker-desc-format
  "%d %c"
  "Format string for news descriptions (contents).
The following printf-like specifiers can be used:
%c  The contents (description) of the item.
%d  The date the item was (first) retrieved.  See `newsticker-date-format'."
  :type 'string
  :set 'newsticker--set-customvar
  :group 'newsticker-layout)

(defcustom newsticker-date-format
  "(%A, %H:%M)"
  "Format for the date part in item and feed lines.
See `format-time-string' for a list of valid specifiers."
  :type 'string
  :set 'newsticker--set-customvar
  :group 'newsticker-layout)

(defcustom newsticker-statistics-format
  "[%n + %i + %o + %O = %a]"
  "Format for the statistics part in feed lines.
The following printf-like specifiers can be used:
%a  The number of all items in the feed.
%i  The number of immortal items in the feed.
%n  The number of new items in the feed.
%o  The number of old items in the feed.
%O  The number of obsolete items in the feed."
  :type 'string
  :set 'newsticker--set-customvar
  :group 'newsticker-layout)

(defcustom newsticker-show-all-rss-elements
  t
  "Show all RSS elements."
  :type 'boolean
  ;;:set 'newsticker--set-customvar
  :group 'newsticker-layout)

;; image related things
(defcustom newsticker-enable-logo-manipulations
  t
  "If non-nil newsticker manipulates logo images.
This enables the following image properties: heuristic mask for all
logos, and laplace-conversion for images without new items."
  :type 'boolean
  :group 'newsticker-layout)


;; rendering
(defcustom newsticker-justification
  'left
  "How to fill item descriptions.
If non-nil newsticker calls `fill-region' to wrap long lines in
item descriptions.  However, if an item description contains HTML
text and `newsticker-html-renderer' is non-nil, filling is not
done."
  :type '(choice :tag "Justification"
                 (const :tag "No filling" nil)
                 (const :tag "Left"       left)
                 (const :tag "Right"      right)
                 (const :tag "Center"     center)
                 (const :tag "Full"       full))
  :set 'newsticker--set-customvar
  :group 'newsticker-layout)

(defcustom newsticker-use-full-width
  t
  "Decides whether to use the full window width when filling.
If non-nil newsticker sets `fill-column' so that the whole
window is used when filling.  See also `newsticker-justification'."
  :type 'boolean
  :set 'newsticker--set-customvar
  :group 'newsticker-layout)

(defcustom newsticker-html-renderer
  nil
  "Function for rendering HTML contents.
If non-nil, newsticker.el will call this function whenever it finds
HTML-like tags in item descriptions.  Possible functions are, for
example, `w3m-region', `w3-region', and (if you have htmlr.el installed)
`newsticker-htmlr-render'.

In order to make sure that the HTML renderer is loaded when you
run newsticker, you should add one of the following statements to
your .emacs.  If you use w3m,

  (autoload 'w3m-region \"w3m\"
    \"Render region in current buffer and replace with result.\" t)

or, if you use w3,

  (require 'w3-auto)

or, if you use htmlr

  (require 'htmlr)"
  :type '(choice :tag "Function"
                 (const :tag "None" nil)
                 (const :tag "w3" w3-region)
                 (const :tag "w3m" w3m-region)
                 (const :tag "htmlr" newsticker-htmlr-render))
  :set 'newsticker--set-customvar
  :group 'newsticker-layout)


;; faces
(defgroup newsticker-faces nil
  "Settings for the faces of the RSS reader."
  :group 'newsticker-layout)

(defface newsticker-feed-face
  '((((class color) (background dark))
     (:family "helvetica" :bold t :italic nil
              :foreground "misty rose"))
    (((class color) (background light))
     (:family "helvetica" :bold t :italic nil
              :foreground "black")))
  "Face for news feeds."
  ;;:set 'newsticker--set-customvar
  :group 'newsticker-faces)

(defface newsticker-new-item-face
  '((((class color) (background dark))
     (:bold t :foreground "orange"))
    (((class color) (background light))
     (:bold t :foreground "blue")))
  "Face for old news items."
  ;;:set 'newsticker--set-customvar
  :group 'newsticker-faces)

(defface newsticker-old-item-face
  '((((class color) (background dark))
     (:bold t))
    (((class color) (background light))
     (:bold t)))
  "Face for old news items."
  ;;:set 'newsticker--set-customvar
  :group 'newsticker-faces)

(defface newsticker-immortal-item-face
  '((((class color) (background dark))
     (:italic t :foreground "orange"))
    (((class color) (background light))
     (:italic t :foreground "blue")))
  "Face for immortal news items."
  ;;:set 'newsticker--set-customvar
  :group 'newsticker-faces)

(defface newsticker-obsolete-item-face
  '((((class color) (background dark))
     (:bold t :foreground "orange" :underline t))
    (((class color) (background light))
     (:bold t :foreground "blue2" :underline t)))
  "Face for old news items."
  ;;:set 'newsticker--set-customvar
  :group 'newsticker-faces)

(defface newsticker-date-face
  '((((class color) (background dark))
     (:italic t))
    (((class color) (background light))
     (:italic t)))
  "Face for newsticker dates."
  ;;:set 'newsticker--set-customvar
  :group 'newsticker-faces)

(defface newsticker-statistics-face
  '((((class color) (background dark))
     (:italic t))
    (((class color) (background light))
     (:italic t)))
  "Face for newsticker dates."
  ;;:set 'newsticker--set-customvar
  :group 'newsticker-faces)

(defface newsticker-enclosure-face
  '((((class color) (background dark))
     (:bold t :background "orange"))
    (((class color) (background light))
     (:bold t :background "orange")))
  "Face for enclosed elements."
  ;;:set 'newsticker--set-customvar
  :group 'newsticker-faces)

(defface newsticker-extra-face
  '((((class color) (background dark))
     (:italic t :foreground "gray50" :height 0.8))
    (((class color) (background light))
     (:italic t :foreground "gray50" :height 0.8)))
  "Face for newsticker dates."
  ;;:set 'newsticker--set-customvar
  :group 'newsticker-faces)

;; (defface newsticker-default-face
;;   '((((class color) (background dark))
;;      (:inherit default))
;;     (((class color) (background light))
;;      (:inherit default)))
;;   "Face for the description of news items."
;;   ;;:set 'newsticker--set-customvar
;;   :group 'newsticker-faces)


;; customization group ticker
(defgroup newsticker-ticker nil
  "Settings for the RSS ticker."
  :group 'newsticker)

(defcustom newsticker-display-interval
  0.3
  "Time interval for displaying news items in the echo area (seconds).
If equal or less than 0 no messages are shown in the echo area.  For
smooth display (see `newsticker-scroll-smoothly') a value of 0.3 seems
reasonable.  For non-smooth display a value of 10 is a good starting
point."
  :type 'number
  :set 'newsticker--set-customvar
  :group 'newsticker-ticker)

(defcustom newsticker-scroll-smoothly
  t
  "Decides whether to flash or scroll news items.
If t the news headlines are scrolled (more-or-less) smoothly in the echo
area.  If nil one headline after another is displayed in the echo area.
The variable `newsticker-display-interval' determines how fast this
display moves/changes and whether headlines are shown in the echo area
at all.  If you change `newsticker-scroll-smoothly' you should also change
`newsticker-display-interval'."
  :type 'boolean
  :group 'newsticker-ticker)

(defcustom newsticker-hide-immortal-items-in-echo-area
  t
  "Decides whether to show immortal/non-expiring news items in the ticker.
If t the echo area will not show immortal items.  See also
`newsticker-hide-old-items-in-echo-area."
  :type 'boolean
  :set 'newsticker--set-customvar
  :group 'newsticker-ticker)
 
(defcustom newsticker-hide-old-items-in-echo-area
  t
  "Decides whether to show only the newest news items in the ticker.
If t the echo area will show only new items, i.e. only items which have
been added between the last two retrievals."
  :type 'boolean
  :set 'newsticker--set-customvar
  :group 'newsticker-ticker)

(defcustom newsticker-hide-obsolete-items-in-echo-area
  t
  "Decides whether to show obsolete items items in the ticker.
If t the echo area will not show obsolete items.  See also
`newsticker-hide-old-items-in-echo-area."
  :type 'boolean
  :set 'newsticker--set-customvar
  :group 'newsticker-ticker)

(defgroup newsticker-hooks nil
  "Settings for newsticker hooks."
  :group 'newsticker)

(defcustom newsticker-start-hook
  nil
  "Hook run when starting newsticker.
This hook is run at the very end of `newsticker-start'."
  :options '(newsticker-start-ticker)
  :type 'hook
  :group 'newsticker-hooks)

(defcustom newsticker-stop-hook
  nil
  "Hook run when stopping newsticker.
This hook is run at the very end of `newsticker-stop'."
  :options nil
  :type 'hook
  :group 'newsticker-hooks)

(defcustom newsticker-new-item-functions
  nil
  "List of functions run after a new headline has been retrieved.
Each function is called with the following three arguments:
FEED  the name of the corresponding news feed,
TITLE the title of the headline,
DESC  the decoded description of the headline.

See `newsticker-download-images', and
`newsticker-download-enclosures' for sample functions.

Please note that these functions are called only once for a
headline after it has been retrieved for the first time."
  :type 'hook
  :options '(newsticker-download-images
             newsticker-download-enclosures)
  :group 'newsticker-hooks)

(defcustom newsticker-select-item-hook
  'newsticker--buffer-make-item-completely-visible
  "List of functions run after a headline has been selected.
Each function is called after one of `newsticker-next-item',
`newsticker-next-new-item', `newsticker-previous-item',
`newsticker-previous-new-item' has been called.

The default value 'newsticker--buffer-make-item-completely-visible
assures that the current item is always completely visible."
  :type 'hook
  :options '(newsticker--buffer-make-item-completely-visible)
  :group 'newsticker-hooks)

(defcustom newsticker-select-feed-hook
  'newsticker--buffer-make-item-completely-visible
  "List of functions run after a feed has been selected.
Each function is called after one of `newsticker-next-feed', and
`newsticker-previous-feed' has been called.

The default value 'newsticker--buffer-make-item-completely-visible
assures that the current feed is completely visible."
  :type 'hook
  :options '(newsticker--buffer-make-item-completely-visible)
  :group 'newsticker-hooks)

(defcustom newsticker-buffer-change-hook
  'newsticker-w3m-show-inline-images
  "List of functions run after the newsticker buffer has been updated.
Each function is called after `newsticker-buffer-update' has been called.

The default value '`newsticker-w3m-show-inline-images' loads inline
images."
  :type 'hook
  :group 'newsticker-hooks)

(defcustom newsticker-narrow-hook
  'newsticker-w3m-show-inline-images
  "List of functions run after narrowing in newsticker buffer has changed.
Each function is called after
`newsticker-toggle-auto-narrow-to-feed' or
`newsticker-toggle-auto-narrow-to-item' has been called.

The default value '`newsticker-w3m-show-inline-images' loads inline
images."
  :type 'hook
  :group 'newsticker-hooks)

(defgroup newsticker-miscellaneous nil
  "Miscellaneous newsticker settings."
  :group 'newsticker)

(defcustom newsticker-cache-filename
  "~/.newsticker-cache"
  "Name of the newsticker cache file."
  :type 'string
  :group 'newsticker-miscellaneous)

(defcustom newsticker-imagecache-dirname
  "~/.newsticker-images"
  "Name of the directory where newsticker stores cached images."
  :type 'string
  :group 'newsticker-miscellaneous)

;; debugging
(defcustom newsticker-debug
  nil
  "Enables some features needed for debugging newsticker.el.

If set to t newsticker.el will print lots of debugging messages, and the
buffers *newsticker-wget-<feed>* will not be closed."
  :type 'boolean
  ;;:set 'newsticker--set-customvar
  :group 'newsticker-miscellaneous)

;; ======================================================================
;;; Compatibility section, XEmacs, Emacs
;; ======================================================================
(unless (fboundp 'time-add)
  (require 'time-date);;FIXME
  (defun time-add (t1 t2)
    (seconds-to-time (+ (time-to-seconds t1) (time-to-seconds t2)))))

(unless (fboundp 'match-string-no-properties)
  (defalias 'match-string-no-properties 'match-string))

(unless (fboundp 'replace-regexp-in-string)
  (defun replace-regexp-in-string (re rp st)
    (save-match-data ;; apparently XEmacs needs save-match-data
      (replace-in-string st re rp))))

;; copied from subr.el
(unless (fboundp 'add-to-invisibility-spec)
  (defun add-to-invisibility-spec (arg)
    "Add elements to `buffer-invisibility-spec'.
See documentation for `buffer-invisibility-spec' for the kind of elements
that can be added."
    (if (eq buffer-invisibility-spec t)
        (setq buffer-invisibility-spec (list t)))
    (setq buffer-invisibility-spec
          (cons arg buffer-invisibility-spec))))

;; copied from subr.el
(unless (fboundp 'remove-from-invisibility-spec)
  (defun remove-from-invisibility-spec (arg)
    "Remove elements from `buffer-invisibility-spec'."
    (if (consp buffer-invisibility-spec)
        (setq buffer-invisibility-spec (delete arg buffer-invisibility-spec)))))

;; ======================================================================
;;; Internal variables
;; ======================================================================
(defvar newsticker--display-timer nil
  "Timer for newsticker display.")
(defvar newsticker--retrieval-timer-list nil
  "List of timers for news retrieval.
This is an alist, each element consisting of (feed-name . timer)")
(defvar newsticker--item-list nil
  "List of newsticker items.")
(defvar newsticker--item-position 0
  "Actual position in list of newsticker items.")
(defvar newsticker--prev-message "There was no previous message yet!"
  "Last message that the newsticker displayed.")
(defvar newsticker--scrollable-text ""
  "The text which is scrolled smoothly in the echo area.")
(defvar newsticker--buffer-uptodate-p nil
  "Tells whether the newsticker buffer is up to date.")
(defvar newsticker--latest-update-time (current-time)
  "The time at which the latest news arrived.")

(defvar newsticker--cache nil "Cached newsticker data.
This is a list of the form

 ((label1
   (title description link time age index preformatted-contents
    preformatted-title)
   ...)
  (label2
   (title description link time age index preformatted-contents
    preformatted-title)
   ...)
  ...)

where LABEL is a symbol.  TITLE, DESCRIPTION, and LINK are
strings.  TIME is a time value as returned by `current-time'.
AGE is a symbol: 'new, 'old, 'immortal, and 'obsolete denote
ordinary news items, whereas 'feed denotes an item which is not a
headline but describes the feed itself.  INDEX denotes the
original position of the item -- used for restoring the original
order.  PREFORMATTED-CONTENTS and PREFORMATTED-TITLE hold the
formatted contents of the item's description and title.  This
speeds things up if HTML rendering is used, which is rather
slow.")

(defvar newsticker--auto-narrow-to-feed nil
  "Automatically narrow to current news feed.
If non-nil only the items of the current news feed are visible.")

(defvar newsticker--auto-narrow-to-item nil
  "Automatically narrow to current news item.
If non-nil only the current headline is visible.")

(defconst newsticker--error-headline
  "[COULD NOT DOWNLOAD HEADLINES!]"
  "Title of error headline which will be inserted if news retrieval fails.")

;; ======================================================================
;;; Toolbar
;; ======================================================================
(defconst newsticker--next-item-image
  (if (fboundp 'create-image)
      (create-image "/* XPM */
static char * next_xpm[] = {
\"24 24 42 1\",
\" c None\",
\". c #000000\",
\"+ c #7EB6DE\",
\"@ c #82BBE2\",
\"# c #85BEE4\",
\"$ c #88C1E7\",
\"% c #8AC3E8\",
\"& c #87C1E6\",
\"* c #8AC4E9\",
\"= c #8CC6EA\",
\"- c #8CC6EB\",
\"; c #88C2E7\",
\"> c #8BC5E9\",
\", c #8DC7EB\",
\"' c #87C0E6\",
\") c #8AC4E8\",
\"! c #8BC5EA\",
\"~ c #8BC4E9\",
\"{ c #88C1E6\",
\"] c #89C3E8\",
\"^ c #86BFE5\",
\"/ c #83BBE2\",
\"( c #82BBE1\",
\"_ c #86C0E5\",
\": c #87C0E5\",
\"< c #83BCE2\",
\"[ c #81B9E0\",
\"} c #81BAE1\",
\"| c #78B0D9\",
\"1 c #7BB3DB\",
\"2 c #7DB5DD\",
\"3 c #7DB6DD\",
\"4 c #72A9D4\",
\"5 c #75ACD6\",
\"6 c #76AED7\",
\"7 c #77AFD8\",
\"8 c #6BA1CD\",
\"9 c #6EA4CF\",
\"0 c #6FA6D1\",
\"a c #6298C6\",
\"b c #659BC8\",
\"c c #5C91C0\",
\"                        \",
\"                        \",
\"       .                \",
\"       ..               \",
\"       .+.              \",
\"       .@#.             \",
\"       .#$%.            \",
\"       .&*=-.           \",
\"       .;>,,,.          \",
\"       .;>,,,=.         \",
\"       .')!==~;.        \",
\"       .#{]*%;^/.       \",
\"       .(#_':#<.        \",
\"       .+[@</}.         \",
\"       .|1232.          \",
\"       .4567.           \",
\"       .890.            \",
\"       .ab.             \",
\"       .c.              \",
\"       ..               \",
\"       .                \",
\"                        \",
\"                        \",
\"                        \"};
"
                 'xpm t)
   "Image for the next item button."))

(defconst newsticker--previous-item-image
  (if (fboundp 'create-image)
      (create-image "/* XPM */
static char * previous_xpm[] = {
\"24 24 39 1\",
\" c None\",
\". c #000000\",
\"+ c #7BB3DB\",
\"@ c #83BCE2\",
\"# c #7FB8DF\",
\"$ c #89C2E7\",
\"% c #86BFE5\",
\"& c #83BBE2\",
\"* c #8CC6EA\",
\"= c #8BC4E9\",
\"- c #88C2E7\",
\"; c #85BEE4\",
\"> c #8DC7EB\",
\", c #89C3E8\",
\"' c #8AC4E8\",
\") c #8BC5EA\",
\"! c #88C1E6\",
\"~ c #8AC4E9\",
\"{ c #8AC3E8\",
\"] c #86C0E5\",
\"^ c #87C0E6\",
\"/ c #87C0E5\",
\"( c #82BBE2\",
\"_ c #81BAE1\",
\": c #7FB7DF\",
\"< c #7DB6DD\",
\"[ c #7DB5DD\",
\"} c #7CB4DC\",
\"| c #79B1DA\",
\"1 c #76ADD7\",
\"2 c #77AFD8\",
\"3 c #73AAD4\",
\"4 c #70A7D1\",
\"5 c #6EA5D0\",
\"6 c #6CA2CE\",
\"7 c #689ECB\",
\"8 c #6399C7\",
\"9 c #6095C4\",
\"0 c #5C90C0\",
\"                        \",
\"                        \",
\"                .       \",
\"               ..       \",
\"              .+.       \",
\"             .@#.       \",
\"            .$%&.       \",
\"           .*=-;.       \",
\"          .>>*,%.       \",
\"         .>>>*,%.       \",
\"        .')**=-;.       \",
\"       .;!,~{-%&.       \",
\"        .;]^/;@#.       \",
\"         .(@&_:+.       \",
\"          .<[}|1.       \",
\"           .2134.       \",
\"            .567.       \",
\"             .89.       \",
\"              .0.       \",
\"               ..       \",
\"                .       \",
\"                        \",
\"                        \",
\"                        \"};
"
                 'xpm t)
   "Image for the previous item button."))

(defconst newsticker--previous-feed-image
  (if (fboundp 'create-image)
      (create-image "/* XPM */
static char * prev_feed_xpm[] = {
\"24 24 52 1\",
\" c None\",
\". c #000000\",
\"+ c #70A7D2\",
\"@ c #75ADD6\",
\"# c #71A8D3\",
\"$ c #79B1DA\",
\"% c #7BB3DB\",
\"& c #7DB5DD\",
\"* c #83BBE2\",
\"= c #7EB6DE\",
\"- c #78B0D9\",
\"; c #7FB7DE\",
\"> c #88C2E7\",
\", c #85BEE4\",
\"' c #80B9E0\",
\") c #80B8DF\",
\"! c #8CC6EA\",
\"~ c #89C3E8\",
\"{ c #86BFE5\",
\"] c #81BAE1\",
\"^ c #7CB4DC\",
\"/ c #7FB8DF\",
\"( c #8DC7EB\",
\"_ c #7BB3DC\",
\": c #7EB7DE\",
\"< c #8BC4E9\",
\"[ c #8AC4E9\",
\"} c #8AC3E8\",
\"| c #87C0E6\",
\"1 c #87C0E5\",
\"2 c #83BCE2\",
\"3 c #75ACD6\",
\"4 c #7FB7DF\",
\"5 c #77AED8\",
\"6 c #71A8D2\",
\"7 c #70A7D1\",
\"8 c #76ADD7\",
\"9 c #6CA2CE\",
\"0 c #699FCC\",
\"a c #73AAD4\",
\"b c #6BA1CD\",
\"c c #669CC9\",
\"d c #6298C5\",
\"e c #689ECB\",
\"f c #6499C7\",
\"g c #6095C3\",
\"h c #5C91C0\",
\"i c #5E93C2\",
\"j c #5B90C0\",
\"k c #588CBC\",
\"l c #578CBC\",
\"m c #5589BA\",
\"                        \",
\"                        \",
\"     ...          .     \",
\"     .+.         ..     \",
\"     .@.        .#.     \",
\"     .$.       .%@.     \",
\"     .&.      .*=-.     \",
\"     .;.     .>,'%.     \",
\"     .).    .!~{]^.     \",
\"     ./.   .(!~{]_.     \",
\"     .:.  .!!<>,'%.     \",
\"     .&. .~[}>{*=-.     \",
\"     .$.  .|1,2/%@.     \",
\"     .3.   .*]4%56.     \",
\"     .7.    .^$8#9.     \",
\"     .0.     .a7bc.     \",
\"     .d.      .efg.     \",
\"     .h.       .ij.     \",
\"     .k.        .l.     \",
\"     .m.         ..     \",
\"     ...          .     \",
\"                        \",
\"                        \",
\"                        \"};
"
                 'xpm t)
   "Image for the previous feed button."))

(defconst newsticker--next-feed-image
  (if (fboundp 'create-image)
      (create-image "/* XPM */
static char * next_feed_xpm[] = {
\"24 24 57 1\",
\" c None\",
\". c #000000\",
\"+ c #6CA2CE\",
\"@ c #75ADD6\",
\"# c #71A8D3\",
\"$ c #79B1DA\",
\"% c #7EB7DE\",
\"& c #7DB5DD\",
\"* c #81BAE1\",
\"= c #85BEE4\",
\"- c #78B0D9\",
\"; c #7FB7DE\",
\"> c #83BCE3\",
\", c #87C1E6\",
\"' c #8AC4E9\",
\") c #7BB3DB\",
\"! c #80B8DF\",
\"~ c #88C2E7\",
\"{ c #8BC5E9\",
\"] c #8DC7EB\",
\"^ c #7CB4DC\",
\"/ c #7FB8DF\",
\"( c #84BDE3\",
\"_ c #7BB3DC\",
\": c #83BCE2\",
\"< c #87C0E6\",
\"[ c #8AC4E8\",
\"} c #8BC5EA\",
\"| c #8CC6EA\",
\"1 c #88C1E6\",
\"2 c #89C3E8\",
\"3 c #8AC3E8\",
\"4 c #7EB6DE\",
\"5 c #82BBE1\",
\"6 c #86C0E5\",
\"7 c #87C0E5\",
\"8 c #75ACD6\",
\"9 c #7AB2DA\",
\"0 c #81B9E0\",
\"a c #82BBE2\",
\"b c #71A8D2\",
\"c c #70A7D1\",
\"d c #74ACD6\",
\"e c #699FCC\",
\"f c #6EA5D0\",
\"g c #72A9D4\",
\"h c #669CC9\",
\"i c #6298C5\",
\"j c #679DCA\",
\"k c #6BA1CD\",
\"l c #6095C3\",
\"m c #5C91C0\",
\"n c #5F94C2\",
\"o c #5B90C0\",
\"p c #588CBC\",
\"q c #578CBC\",
\"r c #5589BA\",
\"                        \",
\"                        \",
\"     .          ...     \",
\"     ..         .+.     \",
\"     .@.        .#.     \",
\"     .$%.       .@.     \",
\"     .&*=.      .-.     \",
\"     .;>,'.     .).     \",
\"     .!=~{].    .^.     \",
\"     ./(~{]].   ._.     \",
\"     .%:<[}||.  .).     \",
\"     .&*=12'3~. .-.     \",
\"     .$45=6<7.  .@.     \",
\"     .8940a:.   .b.     \",
\"     .cd-)&.    .+.     \",
\"     .efg8.     .h.     \",
\"     .ijk.      .l.     \",
\"     .mn.       .o.     \",
\"     .p.        .q.     \",
\"     ..         .r.     \",
\"     .          ...     \",
\"                        \",
\"                        \",
\"                        \"};
"
                 'xpm t)
   "Image for the next feed button."))

(defconst newsticker--mark-read-image
  (if (fboundp 'create-image)
      (create-image "/* XPM */
static char * mark_read_xpm[] = {
\"24 24 44 1\",
\" c None\",
\". c #C20000\",
\"+ c #BE0000\",
\"@ c #C70000\",
\"# c #CE0000\",
\"$ c #C90000\",
\"% c #BD0000\",
\"& c #CB0000\",
\"* c #D10000\",
\"= c #D70000\",
\"- c #D30000\",
\"; c #CD0000\",
\"> c #C60000\",
\", c #D40000\",
\"' c #DA0000\",
\") c #DE0000\",
\"! c #DB0000\",
\"~ c #D60000\",
\"{ c #D00000\",
\"] c #DC0000\",
\"^ c #E00000\",
\"/ c #E40000\",
\"( c #E10000\",
\"_ c #DD0000\",
\": c #D80000\",
\"< c #E50000\",
\"[ c #E70000\",
\"} c #E60000\",
\"| c #E20000\",
\"1 c #E90000\",
\"2 c #E80000\",
\"3 c #E30000\",
\"4 c #DF0000\",
\"5 c #D90000\",
\"6 c #CC0000\",
\"7 c #C10000\",
\"8 c #C30000\",
\"9 c #BF0000\",
\"0 c #B90000\",
\"a c #BC0000\",
\"b c #BB0000\",
\"c c #B80000\",
\"d c #B50000\",
\"e c #B70000\",
\"                        \",
\"                        \",
\"                        \",
\"    .              +    \",
\"   +@#            $.%   \",
\"    &*=          -;>    \",
\"     ,')        !~{     \",
\"      ]^/      (_:      \",
\"       (<[    }|)       \",
\"        <[1  2<|        \",
\"         }222[<         \",
\"          }}}<          \",
\"          333|          \",
\"         _4^4)]         \",
\"        ~:'  5=-        \",
\"       6{-    *#$       \",
\"      7>$      @89      \",
\"     0a+        %bc     \",
\"    ddc          edd    \",
\"   ddd            ddd   \",
\"    d              d    \",
\"                        \",
\"                        \",
\"                        \"};
"
                 'xpm t)
   "Image for the next feed button."))

(defconst newsticker--mark-immortal-image
  (if (fboundp 'create-image)
      (create-image "/* XPM */
static char * mark_immortal_xpm[] = {
\"24 24 93 2\",
\"   c None\",
\". c #171717\",
\"+ c #030303\",
\"@ c #000000\",
\"# c #181818\",
\"$ c #090909\",
\"% c #FFC960\",
\"& c #FFCB61\",
\"* c #FFCB62\",
\"= c #FFC961\",
\"- c #FFC75F\",
\"; c #FFC65E\",
\"> c #FFCA61\",
\", c #FFCD63\",
\"' c #FFCF65\",
\") c #FFD065\",
\"! c #FFCE64\",
\"~ c #FFC35C\",
\"{ c #FFC45D\",
\"] c #FFD166\",
\"^ c #FFD267\",
\"/ c #FFD368\",
\"( c #FFD167\",
\"_ c #FFC05A\",
\": c #010101\",
\"< c #040404\",
\"[ c #FFCC62\",
\"} c #FFD569\",
\"| c #FFD56A\",
\"1 c #FFC860\",
\"2 c #FFC25B\",
\"3 c #FFBB56\",
\"4 c #020202\",
\"5 c #060606\",
\"6 c #FFC15B\",
\"7 c #FFC85F\",
\"8 c #FFD469\",
\"9 c #FFD66A\",
\"0 c #FFBC57\",
\"a c #1B1B1B\",
\"b c #070707\",
\"c c #FFBA55\",
\"d c #FFB451\",
\"e c #FFB954\",
\"f c #FFB350\",
\"g c #FFB652\",
\"h c #FFBE58\",
\"i c #FFCD64\",
\"j c #FFD066\",
\"k c #FFC059\",
\"l c #FFB14E\",
\"m c #0B0B0B\",
\"n c #FFBB55\",
\"o c #FFC15A\",
\"p c #FFB552\",
\"q c #FFAD4B\",
\"r c #080808\",
\"s c #FFAF4C\",
\"t c #FFB853\",
\"u c #FFA948\",
\"v c #050505\",
\"w c #FFB04E\",
\"x c #FFB753\",
\"y c #FFBC56\",
\"z c #FFC55D\",
\"A c #FFC55E\",
\"B c #FFC45C\",
\"C c #FFBD57\",
\"D c #FFB854\",
\"E c #FFB34F\",
\"F c #FFAB4A\",
\"G c #FFA545\",
\"H c #FFAA49\",
\"I c #FFB04D\",
\"J c #FFB551\",
\"K c #FFBF58\",
\"L c #FFB24F\",
\"M c #FFAC4A\",
\"N c #FFA646\",
\"O c #FFA344\",
\"P c #FFA848\",
\"Q c #FFB14F\",
\"R c #FFAF4D\",
\"S c #FFA546\",
\"T c #FFA243\",
\"U c #FFA445\",
\"V c #FFAE4C\",
\"W c #FFA444\",
\"X c #FFA142\",
\"Y c #FF9F41\",
\"Z c #0A0A0A\",
\"` c #FF9E40\",
\" . c #FF9F40\",
\"                                                \",
\"                                                \",
\"                                                \",
\"                  . + @ @ + #                   \",
\"              $ @ % & * * = - + +               \",
\"            @ ; > , ' ) ' ! * - ~ @             \",
\"          @ { > ! ] ^ / / ( ' * ; _ :           \",
\"        < _ ; [ ) / } | } / ] , 1 2 3 4         \",
\"        5 6 7 , ] 8 9 9 9 } ^ ! = ~ 0 a         \",
\"      b c 6 - , ] 8 9 9 9 } ^ ! % ~ 0 d 5       \",
\"      : e _ ; * ) / 8 } } / ] , 1 2 3 f 5       \",
\"      : g h { = i j ^ / ^ ] ! * ; k e l m       \",
\"      : f n o ; > , ' ) ' ! * - 2 0 p q r       \",
\"      : s g 0 6 ; % > * * = - ~ h t l u r       \",
\"      v u w x y k ~ z A z B o C D E F G b       \",
\"        5 H I J e 0 h K h C c x L M N .         \",
\"        4 O P q Q d g x g J L R H S T <         \",
\"          @ T U P F q V q M H N W X +           \",
\"            @ Y T O W G G W O X Y @             \",
\"              4 Z ` Y Y Y  .` 4 4               \",
\"                  5 : : @ @ Z                   \",
\"                                                \",
\"                                                \",
\"                                                \"};
"
                 'xpm t)
   "Image for the next feed button."))


(defconst newsticker--narrow-image
  (if (fboundp 'create-image)
      (create-image "/* XPM */
static char * narrow_xpm[] = {
\"24 24 48 1\",
\" c None\",
\". c #000000\",
\"+ c #969696\",
\"@ c #9E9E9E\",
\"# c #A4A4A4\",
\"$ c #AAAAAA\",
\"% c #AEAEAE\",
\"& c #B1B1B1\",
\"* c #B3B3B3\",
\"= c #B4B4B4\",
\"- c #B2B2B2\",
\"; c #AFAFAF\",
\"> c #ABABAB\",
\", c #A6A6A6\",
\"' c #