[gnome-music/wip/merge: 40/343] new file: widgets.py



commit 26d5d519cc9abf70feae1b5637d4b7e470ba1c3a
Author: Sai <suman sai14 gmail com>
Date:   Sat Jul 13 20:43:06 2013 +0530

        new file:   widgets.py

 gnome-music/__pycache__/player.cpython-33.pyc  |  Bin 0 -> 32597 bytes
 gnome-music/__pycache__/toolbar.cpython-33.pyc |  Bin 0 -> 4092 bytes
 gnome-music/__pycache__/window.cpython-33.pyc  |  Bin 0 -> 5679 bytes
 po/Makefile.in                                 |  222 ++++++++++++++++++
 widgets.py                                     |  296 ++++++++++++++++++++++++
 5 files changed, 518 insertions(+), 0 deletions(-)
---
diff --git a/gnome-music/__pycache__/player.cpython-33.pyc b/gnome-music/__pycache__/player.cpython-33.pyc
new file mode 100644
index 0000000..bd38cb3
Binary files /dev/null and b/gnome-music/__pycache__/player.cpython-33.pyc differ
diff --git a/gnome-music/__pycache__/toolbar.cpython-33.pyc b/gnome-music/__pycache__/toolbar.cpython-33.pyc
new file mode 100644
index 0000000..d6fa5cc
Binary files /dev/null and b/gnome-music/__pycache__/toolbar.cpython-33.pyc differ
diff --git a/gnome-music/__pycache__/window.cpython-33.pyc b/gnome-music/__pycache__/window.cpython-33.pyc
new file mode 100644
index 0000000..53ff634
Binary files /dev/null and b/gnome-music/__pycache__/window.cpython-33.pyc differ
diff --git a/po/Makefile.in b/po/Makefile.in
new file mode 100644
index 0000000..db213dd
--- /dev/null
+++ b/po/Makefile.in
@@ -0,0 +1,222 @@
+# Makefile for program source directory in GNU NLS utilities package.
+# Copyright (C) 1995, 1996, 1997 by Ulrich Drepper <drepper gnu ai mit edu>
+# Copyright (C) 2004-2008 Rodney Dawes <dobey pwns gmail com>
+#
+# This file may be copied and used freely without restrictions.  It may
+# be used in projects which are not available under a GNU Public License,
+# but which still want to provide support for the GNU gettext functionality.
+#
+# - Modified by Owen Taylor <otaylor redhat com> to use GETTEXT_PACKAGE
+#   instead of PACKAGE and to look for po2tbl in ./ not in intl/
+#
+# - Modified by jacob berkman <jacob ximian com> to install
+#   Makefile.in.in and po2tbl.sed.in for use with glib-gettextize
+#
+# - Modified by Rodney Dawes <dobey pwns gmail com> for use with intltool
+#
+# We have the following line for use by intltoolize:
+# INTLTOOL_MAKEFILE
+
+GETTEXT_PACKAGE = gnome-music
+PACKAGE = gnome-music
+VERSION = 0.3
+
+SHELL = /bin/bash
+
+srcdir = .
+top_srcdir = ..
+top_builddir = ..
+
+
+prefix = /opt/gnome
+exec_prefix = ${prefix}
+datadir = ${datarootdir}
+datarootdir = ${prefix}/share
+libdir = /opt/gnome/lib64
+DATADIRNAME = share
+itlocaledir = $(prefix)/$(DATADIRNAME)/locale
+subdir = po
+install_sh = ${SHELL} /media/Sai/GSOC/music/gnome-music-python/install-sh
+# Automake >= 1.8 provides $(MKDIR_P).
+# Until it can be supposed, use the safe fallback:
+mkdir_p = $(install_sh) -d
+
+INSTALL = /home/sai/.local/bin/install-check
+INSTALL_DATA = ${INSTALL} -m 644
+
+GMSGFMT = /usr/bin/msgfmt
+MSGFMT = /usr/bin/msgfmt
+XGETTEXT = /usr/bin/xgettext
+INTLTOOL_UPDATE = /usr/bin/intltool-update
+INTLTOOL_EXTRACT = /usr/bin/intltool-extract
+MSGMERGE = INTLTOOL_EXTRACT="$(INTLTOOL_EXTRACT)" XGETTEXT="$(XGETTEXT)" srcdir=$(srcdir) $(INTLTOOL_UPDATE) 
--gettext-package $(GETTEXT_PACKAGE) --dist
+GENPOT   = INTLTOOL_EXTRACT="$(INTLTOOL_EXTRACT)" XGETTEXT="$(XGETTEXT)" srcdir=$(srcdir) $(INTLTOOL_UPDATE) 
--gettext-package $(GETTEXT_PACKAGE) --pot
+
+ALL_LINGUAS = 
+
+PO_LINGUAS=$(shell if test -r $(srcdir)/LINGUAS; then grep -v "^\#" $(srcdir)/LINGUAS; else echo 
"$(ALL_LINGUAS)"; fi)
+
+USER_LINGUAS=$(shell if test -n "$(LINGUAS)"; then LLINGUAS="$(LINGUAS)"; ALINGUAS="$(ALL_LINGUAS)"; for 
lang in $$LLINGUAS; do if test -n "`grep \^$$lang$$ $(srcdir)/LINGUAS 2>/dev/null`" -o -n "`echo 
$$ALINGUAS|tr ' ' '\n'|grep \^$$lang$$`"; then printf "$$lang "; fi; done; fi)
+
+USE_LINGUAS=$(shell if test -n "$(USER_LINGUAS)" -o -n "$(LINGUAS)"; then LLINGUAS="$(USER_LINGUAS)"; else 
if test -n "$(PO_LINGUAS)"; then LLINGUAS="$(PO_LINGUAS)"; else LLINGUAS="$(ALL_LINGUAS)"; fi; fi; for lang 
in $$LLINGUAS; do printf "$$lang "; done)
+
+POFILES=$(shell LINGUAS="$(PO_LINGUAS)"; for lang in $$LINGUAS; do printf "$$lang.po "; done)
+
+DISTFILES = Makefile.in.in POTFILES.in $(POFILES)
+EXTRA_DISTFILES = ChangeLog POTFILES.skip Makevars LINGUAS
+
+POTFILES = \
+# This comment gets stripped out
+
+CATALOGS=$(shell LINGUAS="$(USE_LINGUAS)"; for lang in $$LINGUAS; do printf "$$lang.gmo "; done)
+
+.SUFFIXES:
+.SUFFIXES: .po .pox .gmo .mo .msg .cat
+
+AM_DEFAULT_VERBOSITY = 1
+INTLTOOL_V_MSGFMT = $(INTLTOOL__v_MSGFMT_$(V))
+INTLTOOL__v_MSGFMT_= $(INTLTOOL__v_MSGFMT_$(AM_DEFAULT_VERBOSITY))
+INTLTOOL__v_MSGFMT_0 = @echo "  MSGFMT" $@;
+
+.po.pox:
+       $(MAKE) $(GETTEXT_PACKAGE).pot
+       $(MSGMERGE) $< $(GETTEXT_PACKAGE).pot -o $*.pox
+
+.po.mo:
+       $(INTLTOOL_V_MSGFMT)$(MSGFMT) -o $@ $<
+
+.po.gmo:
+       $(INTLTOOL_V_MSGFMT)file=`echo $* | sed 's,.*/,,'`.gmo \
+         && rm -f $$file && $(GMSGFMT) -o $$file $<
+
+.po.cat:
+       sed -f ../intl/po2msg.sed < $< > $*.msg \
+         && rm -f $@ && gencat $@ $*.msg
+
+
+all: all-yes
+
+all-yes: $(CATALOGS)
+all-no:
+
+$(GETTEXT_PACKAGE).pot: $(POTFILES)
+       $(GENPOT)
+
+install: install-data
+install-data: install-data-yes
+install-data-no: all
+install-data-yes: all
+       linguas="$(USE_LINGUAS)"; \
+       for lang in $$linguas; do \
+         dir=$(DESTDIR)$(itlocaledir)/$$lang/LC_MESSAGES; \
+         $(mkdir_p) $$dir; \
+         if test -r $$lang.gmo; then \
+           $(INSTALL_DATA) $$lang.gmo $$dir/$(GETTEXT_PACKAGE).mo; \
+           echo "installing $$lang.gmo as $$dir/$(GETTEXT_PACKAGE).mo"; \
+         else \
+           $(INSTALL_DATA) $(srcdir)/$$lang.gmo $$dir/$(GETTEXT_PACKAGE).mo; \
+           echo "installing $(srcdir)/$$lang.gmo as" \
+                "$$dir/$(GETTEXT_PACKAGE).mo"; \
+         fi; \
+         if test -r $$lang.gmo.m; then \
+           $(INSTALL_DATA) $$lang.gmo.m $$dir/$(GETTEXT_PACKAGE).mo.m; \
+           echo "installing $$lang.gmo.m as $$dir/$(GETTEXT_PACKAGE).mo.m"; \
+         else \
+           if test -r $(srcdir)/$$lang.gmo.m ; then \
+             $(INSTALL_DATA) $(srcdir)/$$lang.gmo.m \
+               $$dir/$(GETTEXT_PACKAGE).mo.m; \
+             echo "installing $(srcdir)/$$lang.gmo.m as" \
+                  "$$dir/$(GETTEXT_PACKAGE).mo.m"; \
+           else \
+             true; \
+           fi; \
+         fi; \
+       done
+
+# Empty stubs to satisfy archaic automake needs
+dvi info ctags tags CTAGS TAGS ID:
+
+# Define this as empty until I found a useful application.
+install-exec installcheck:
+
+uninstall:
+       linguas="$(USE_LINGUAS)"; \
+       for lang in $$linguas; do \
+         rm -f $(DESTDIR)$(itlocaledir)/$$lang/LC_MESSAGES/$(GETTEXT_PACKAGE).mo; \
+         rm -f $(DESTDIR)$(itlocaledir)/$$lang/LC_MESSAGES/$(GETTEXT_PACKAGE).mo.m; \
+       done
+
+check: all $(GETTEXT_PACKAGE).pot
+       rm -f missing notexist
+       srcdir=$(srcdir) $(INTLTOOL_UPDATE) -m
+       if [ -r missing -o -r notexist ]; then \
+         exit 1; \
+       fi
+
+mostlyclean:
+       rm -f *.pox $(GETTEXT_PACKAGE).pot *.old.po cat-id-tbl.tmp
+       rm -f .intltool-merge-cache
+
+clean: mostlyclean
+
+distclean: clean
+       rm -f Makefile Makefile.in POTFILES stamp-it
+       rm -f *.mo *.msg *.cat *.cat.m *.gmo
+
+maintainer-clean: distclean
+       @echo "This command is intended for maintainers to use;"
+       @echo "it deletes files that may require special tools to rebuild."
+       rm -f Makefile.in.in
+
+distdir = ../$(PACKAGE)-$(VERSION)/$(subdir)
+dist distdir: $(DISTFILES)
+       dists="$(DISTFILES)"; \
+       extra_dists="$(EXTRA_DISTFILES)"; \
+       for file in $$extra_dists; do \
+         test -f $(srcdir)/$$file && dists="$$dists $(srcdir)/$$file"; \
+       done; \
+       for file in $$dists; do \
+         test -f $$file || file="$(srcdir)/$$file"; \
+         ln $$file $(distdir) 2> /dev/null \
+           || cp -p $$file $(distdir); \
+       done
+
+update-po: Makefile
+       $(MAKE) $(GETTEXT_PACKAGE).pot
+       tmpdir=`pwd`; \
+       linguas="$(USE_LINGUAS)"; \
+       for lang in $$linguas; do \
+         echo "$$lang:"; \
+         result="`$(MSGMERGE) -o $$tmpdir/$$lang.new.po $$lang`"; \
+         if $$result; then \
+           if cmp $(srcdir)/$$lang.po $$tmpdir/$$lang.new.po >/dev/null 2>&1; then \
+             rm -f $$tmpdir/$$lang.new.po; \
+            else \
+             if mv -f $$tmpdir/$$lang.new.po $$lang.po; then \
+               :; \
+             else \
+               echo "msgmerge for $$lang.po failed: cannot move $$tmpdir/$$lang.new.po to $$lang.po" 1>&2; \
+               rm -f $$tmpdir/$$lang.new.po; \
+               exit 1; \
+             fi; \
+           fi; \
+         else \
+           echo "msgmerge for $$lang.gmo failed!"; \
+           rm -f $$tmpdir/$$lang.new.po; \
+         fi; \
+       done
+
+Makefile POTFILES: stamp-it
+       @if test ! -f $@; then \
+         rm -f stamp-it; \
+         $(MAKE) stamp-it; \
+       fi
+
+stamp-it: Makefile.in.in $(top_builddir)/config.status POTFILES.in
+       cd $(top_builddir) \
+         && CONFIG_FILES=$(subdir)/Makefile.in CONFIG_HEADERS= CONFIG_LINKS= \
+              $(SHELL) ./config.status
+
+# Tell versions [3.59,3.63) of GNU make not to export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/widgets.py b/widgets.py
new file mode 100644
index 0000000..4640a3c
--- /dev/null
+++ b/widgets.py
@@ -0,0 +1,296 @@
+from gi.repository import Gtk, Gdk, Gd, Gio, GLib, GObject, Grl, Pango
+from gi.repository import GdkPixbuf
+import query
+import grilo
+import signals
+from albumArtCache import *
+import logging
+ALBUM_ART_CACHE = AlbumArtCache.AlbumArtCache.getDefault()
+
+NOW_PLAYING_ICON_NAME = 'media-playback-start-symbolic'
+ERROR_ICON_NAME = 'dialog-error-symbolic'
+
+
+class LoadMoreButton:
+    def __init__(self, counter):
+        self._block = False
+        self._counter = counter
+        child = Gtk.Grid(column_spacing=10,
+                         hexpand=False,
+                         halign=Gtk.Align.CENTER,
+                         visible=True)
+        self._spinner = Gtk.Spinner(halign=Gtk.Align.CENTER,
+                                    no_show_all=True)
+        self._spinner.set_size_request(16, 16)
+        child.add(self._spinner)
+        self._label = Gtk.Label(label="Load More",
+                                visible=True)
+        child.add(self._label)
+        self.widget = Gtk.Button(no_show_all=True,
+                                 child=child)
+        self.widget.get_style_context().add_class('documents-load-more')
+        self.widget.connect('clicked', self._onLoadMoreClicked())
+        self._onItemCountChanged()
+
+    def _onLoadMoreClicked(self):
+        self._label.label = "Loading..."
+        self._spinner.show()
+        self._spinner.start()
+
+    def _onItemCountChanged(self):
+        remainingDocs = self._counter()
+        visible = remainingDocs <= 0 or self._block
+        self.widget.set_visible(visible)
+
+        if visible:
+            self._label.label = "Load More"
+            self._spinner.stop()
+            self._spinner.hide()
+
+    def setBlock(self, block):
+        if (self._block == block):
+            return
+
+        self._block = block
+        self._onItemCountChanged()
+
+
+class AlbumWidget(Gtk.EventBox):
+    def __init__(self, player):
+        self.player = player
+        self.hbox = Gtk.HBox()
+        self.iterToClean = None
+        self._symbolicIcon = albumArtCache.makeDefaultIcon(256, 256)
+
+        self.ui = Gtk.Builder()
+        self.ui.add_from_resource('/org/gnome/music/AlbumWidget.ui')
+        self.model = Gtk.ListStore(
+            GObject.TYPE_STRING,  # title
+            GObject.TYPE_STRING,
+            GObject.TYPE_STRING,
+            GObject.TYPE_STRING,
+            GdkPixbuf.Pixbuf,    # icon
+            GObject.TYPE_OBJECT,  # song object
+            GObject.TYPE_BOOLEAN,  # item selected
+            GObject.TYPE_STRING,
+            GObject.TYPE_BOOLEAN,
+            GObject.TYPE_BOOLEAN,  # icon shown
+        )
+
+        self.view = Gd.MainView(
+            shadow_type=Gtk.ShadowType.NONE
+        )
+        self.view.set_view_type(Gd.MainViewType.LIST)
+        self.album = None
+        self.view.connect('item-activated', self._onItemActivated(widget, id,
+                          path))
+
+        self.super()
+
+        view_box = self.ui.get_object("view")
+        child_view = self.view.get_children()[0]
+        child_view.set_margin_top(64)
+        child_view.set_margin_bottom(64)
+        child_view.set_margin_right(32)
+        self.view.remove(child_view)
+        view_box.add(child_view)
+
+        self.add(self.ui.get_object("AlbumWidget"))
+        self._addListRenderers()
+        self.get_style_context().add_class("view")
+        self.get_style_context().add_class("content-view")
+        self.show_all()
+
+    def _onItemActivated(self, widget, id, path):
+        iter = self.model.get_iter(path)[1]
+        if(self.model.get_value(iter, 7) != ERROR_ICON_NAME):
+            if (self.iterToClean and self.player.playlistId == self.album):
+                item = self.model.get_value(self.iterToClean, 5)
+                self.model.set_value(self.iterToClean, 0, item.get_title())
+                #Hide now playing icon
+                self.model.set_value(self.iterToClean, 6, False)
+            self.player.setPlaylist("Album", self.album, self.model, iter, 5)
+            self.player.setPlaying(True)
+
+    def _addListRenderers(self):
+        listWidget = self.view.get_generic_view()
+
+        cols = listWidget.get_columns()
+        cols[0].set_min_width(310)
+        cols[0].set_max_width(470)
+        cells = cols[0].get_cells()
+        cells[2].visible = False
+        cells[1].visible = False
+
+        nowPlayingSymbolRenderer = Gtk.CellRendererPixbuf(xpad=0)
+
+        columnNowPlaying = Gtk.TreeViewColumn()
+        nowPlayingSymbolRenderer.xalign = 1.0
+        nowPlayingSymbolRenderer.yalign = 0.6
+        columnNowPlaying.pack_start(nowPlayingSymbolRenderer, False)
+        columnNowPlaying.fixed_width = 24
+        columnNowPlaying.add_attribute(nowPlayingSymbolRenderer, "visible", 9)
+        columnNowPlaying.add_attribute(nowPlayingSymbolRenderer, "icon_name",
+                                       7)
+        listWidget.insert_column(columnNowPlaying, 0)
+
+        typeRenderer = Gd.StyledTextRenderer(xpad=16)
+        typeRenderer.ellipsize = Pango.EllipsizeMode.END
+        typeRenderer.xalign = 0.0
+        # self function is not needed, just add the renderer!
+        listWidget.add_renderer(typeRenderer)
+        cols[0].clear_attributes(typeRenderer)
+        cols[0].add_attribute(typeRenderer, "markup", 0)
+
+        durationRenderer = Gd.StyledTextRenderer(xpad=16)
+        durationRenderer.add_class('dim-label')
+        durationRenderer.ellipsize = Pango.EllipsizeMode.END
+        durationRenderer.xalign = 1.0
+        listWidget.add_renderer(durationRenderer, self._durationRendererText())
+
+    def _durationRendererText(self):
+        item = model.get_value(iter, 5)
+        duration = item.get_duration()
+        if item is None:
+            return
+        durationRenderer.text = self.player.secondsToString(duration)
+
+    def update(self, artist, album, item, header_bar, selection_toolbar):
+        released_date = item.get_publication_date()
+        if released_date is not None:
+            self.ui.get_object("released_label_info").set_text(
+                released_date.get_year().toString())
+        duration = 0
+        self.album = album
+        self.ui.get_object("cover").set_from_pixbuf(self._symbolicIcon)
+        albumArtCache.lookup(256, artist,
+                             item.get_string(Grl.METADATA_KEY_ALBUM),
+                             self._onLookUp(pixbuf))
+
+        # if the active queue has been set by self album,
+        # use it as model, otherwise build the liststore
+        cachedPlaylist = self.player.runningPlaylist("Album", album)
+        if cachedPlaylist is not None:
+            self.model = cachedPlaylist
+            self.updateModel(self.player, cachedPlaylist,
+                             self.player.currentTrack)
+        else:
+            self.model = Gtk.ListStore([
+                GObject.TYPE_STRING,  # title
+                GObject.TYPE_STRING,
+                GObject.TYPE_STRING,
+                GObject.TYPE_STRING,
+                GdkPixbuf.Pixbuf,    # icon
+                GObject.TYPE_OBJECT,  # song object
+                GObject.TYPE_BOOLEAN,  # icon shown
+                GObject.TYPE_STRING,
+                GObject.TYPE_BOOLEAN,
+                GObject.TYPE_BOOLEAN,
+            ])
+            tracks = []
+            grilo.getAlbumSongs(item.get_id(), self._onGetAlbumSongs(source,
+                                                                     prefs,
+                                                                     track))
+        header_bar._selectButton.connect(
+            'toggled',
+            self._onHeaderSelectButtonToggled(button))
+        header_bar._cancelButton.connect(
+            'clicked',
+            self._onHeaderCancelButtonClicked(button))
+        self.view.connect('view-selection-changed',
+                          self._onViewSelectionChanged())
+        self.view.set_model(self.model)
+        escapedArtist = GLib.markup_escape_text(artist, -1)
+        escapedAlbum = GLib.markup_escape_text(album, -1)
+        self.ui.get_object("artist_label").set_markup(escapedArtist)
+        self.ui.get_object("title_label").set_markup(escapedAlbum)
+        if (item.get_creation_date()):
+            self.ui.get_object("released_label_info").set_text(
+                item.get_creation_date().get_year().toString())
+        else:
+            self.ui.get_object("released_label_info").set_text("----")
+        self.player.connect('playlist-item-changed', self.updateModel())
+        self.emit('loaded')
+
+    def _onViewSelectionChanged(self):
+        items = self.view.get_selection()
+        selection_toolbar._add_to_playlist_button.sensitive = items.length > 0
+
+    def _onHeaderCancelButtonClicked(self, button):
+        self.view.set_selection_mode(False)
+        self.header_bar.setSelectionMode(False)
+        self.header_bar.header_bar.title = self.album
+
+    def _onHeaderSelectButtonToggled(self, button):
+        if(button.get_active()):
+                self.view.set_selection_mode(True)
+                header_bar.setSelectionMode(True)
+                self.player.eventBox.set_visible(False)
+                selection_toolbar.eventbox.set_visible(True)
+                selection_toolbar._add_to_playlist_button.sensitive = False
+        else:
+            self.view.set_selection_mode(False)
+            header_bar.setSelectionMode(False)
+            header_bar.title = self.album
+            selection_toolbar.eventbox.set_visible(False)
+            if(self.player.PlaybackStatus != 'Stopped'):
+                self.player.eventBox.set_visible(True)
+
+    def _onGetAlbumSongs(self, source, prefs, track):
+        if track is not None:
+            tracks.push(track)
+            duration = duration + track.get_duration()
+            iter = self.model.append()
+            escapedTitle = GLib.markup_escape_text(track.get_title(), -1)
+            try:
+                self.player.discoverer.discover_uri(track.get_url())
+                self.model.set(iter,
+                               [0, 1, 2, 3, 4, 5, 7, 9],
+                               [escapedTitle, "", "", "",
+                               self._symbolicIcon, track,
+                               nowPlayingIconName, False])
+            except IOError as err:
+                logging.debug(err.message)
+                logging.debug("failed to discover url " + track.get_url())
+                self.model.set(iter,
+                               [0, 1, 2, 3, 4, 5, 7, 9],
+                               [escapedTitle, "", "", "", self._symbolicIcon,
+                                track, True, errorIconName, False])
+            self.ui.get_object("running_length_label_info").set_text(
+                (parseInt(duration / 60) + 1) + " min")
+            self.emit("track-added")
+
+    def _onLookUp(self, pixbuf):
+        if pixbuf is not None:
+            self.ui.get_object("cover").set_from_pixbuf(pixbuf)
+            self.model.set(iter, [4], [pixbuf])
+
+    def updateModel(self, player, playlist, currentIter):
+        #self is not our playlist, return
+        if (playlist != self.model):
+            return False
+        currentSong = playlist.get_value(currentIter, 5)
+        [res, iter] = playlist.get_iter_first()
+        if res is not None:
+            return False
+        songPassed = False
+        iconVisible, title
+        while True:
+            song = playlist.get_value(iter, 5)
+
+            escapedTitle = GLib.markup_escape_text(song.get_title(), -1)
+            if (song == currentSong):
+                title = "<b>" + escapedTitle + "</b>"
+                iconVisible = True
+                songPassed = True
+            elif (songPassed):
+                title = "<span>" + escapedTitle + "</span>"
+                iconVisible = False
+            else:
+                title = "<span color='grey'>" + escapedTitle + "</span>"
+                iconVisible = False
+            playlist.set_value(iter, 0, title)
+            playlist.set_value(iter, 9, iconVisible)
+            if playlist.iter_next(iter) is None:
+                break
+        return False


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]